All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] mmc: sdhci: Minor fixes
@ 2016-10-05  9:11 Adrian Hunter
  2016-10-05  9:11 ` [PATCH 1/4] mmc: sdhci: Fix SDHCI_QUIRK2_STOP_WITH_TC Adrian Hunter
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Adrian Hunter @ 2016-10-05  9:11 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, Adrian Hunter

Hi

Here are a couple of minor fixes.  While it would be good to have them in
4.9 or a 4.9-rc, they are not urgent.


Adrian Hunter (4):
      mmc: sdhci: Fix SDHCI_QUIRK2_STOP_WITH_TC
      mmc: sdhci: Rename sdhci_set_power() to sdhci_set_power_noreg()
      mmc: sdhci-pci: Let devices define their own sdhci_ops
      mmc: sdhci-pci: Fix bus power failing to enable for some Intel controllers

 drivers/mmc/host/sdhci-pci-core.c | 54 ++++++++++++++++++++++++++++++++++++++-
 drivers/mmc/host/sdhci-pci.h      |  2 ++
 drivers/mmc/host/sdhci-pxav3.c    |  2 +-
 drivers/mmc/host/sdhci.c          | 40 ++++++++++++++---------------
 drivers/mmc/host/sdhci.h          |  2 ++
 5 files changed, 77 insertions(+), 23 deletions(-)


Regards
Adrian

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/4] mmc: sdhci: Fix SDHCI_QUIRK2_STOP_WITH_TC
  2016-10-05  9:11 [PATCH 0/4] mmc: sdhci: Minor fixes Adrian Hunter
@ 2016-10-05  9:11 ` Adrian Hunter
  2016-10-05  9:11 ` [PATCH 2/4] mmc: sdhci: Rename sdhci_set_power() to sdhci_set_power_noreg() Adrian Hunter
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Adrian Hunter @ 2016-10-05  9:11 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, Adrian Hunter, Giuseppe Cavallaro

Multi-block data transfers can specify the number of blocks either using a
Set Block Count command (CMD23) or by sending a STOP command (CMD12) after
the required number of blocks has transferred. CMD23 is preferred, but some
cards don't support it. CMD12 with R1b response is used for writes, and
R1 response for reads.

Some SDHCI host controllers give a Transfer Complete (TC) interrupt for the
STOP command (CMD12) whether or not a R1b response has been specified. The
quirk SDHCI_QUIRK2_STOP_WITH_TC identifies those host controllers, but the
implementation only considers the case where the TC interrupt arrives at
the same time as the Command Complete (CC) interrupt. However,
occasionally TC arrives before CC. That is harmless, but does generate an
error message "Got data interrupt 0x00000002 even though no data operation
was in progress".

A simpler approach is to force R1b response onto all STOP commands, because
SDHCI will handle TC before CC in the general case, so do that.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
 drivers/mmc/host/sdhci.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 48055666c655..3711813f5654 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1077,6 +1077,10 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 	/* Initially, a command has no error */
 	cmd->error = 0;
 
+	if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) &&
+	    cmd->opcode == MMC_STOP_TRANSMISSION)
+		cmd->flags |= MMC_RSP_BUSY;
+
 	/* Wait max 10 ms */
 	timeout = 10;
 
@@ -2409,7 +2413,7 @@ static void sdhci_timeout_data_timer(unsigned long data)
  *                                                                           *
 \*****************************************************************************/
 
-static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
+static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
 {
 	if (!host->cmd) {
 		/*
@@ -2453,11 +2457,6 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
 		return;
 	}
 
-	if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) &&
-	    !(host->cmd->flags & MMC_RSP_BUSY) && !host->data &&
-	    host->cmd->opcode == MMC_STOP_TRANSMISSION)
-		*mask &= ~SDHCI_INT_DATA_END;
-
 	if (intmask & SDHCI_INT_RESPONSE)
 		sdhci_finish_command(host);
 }
@@ -2680,8 +2679,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 		}
 
 		if (intmask & SDHCI_INT_CMD_MASK)
-			sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK,
-				      &intmask);
+			sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
 
 		if (intmask & SDHCI_INT_DATA_MASK)
 			sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/4] mmc: sdhci: Rename sdhci_set_power() to sdhci_set_power_noreg()
  2016-10-05  9:11 [PATCH 0/4] mmc: sdhci: Minor fixes Adrian Hunter
  2016-10-05  9:11 ` [PATCH 1/4] mmc: sdhci: Fix SDHCI_QUIRK2_STOP_WITH_TC Adrian Hunter
@ 2016-10-05  9:11 ` Adrian Hunter
  2016-10-05  9:11 ` [PATCH 3/4] mmc: sdhci-pci: Let devices define their own sdhci_ops Adrian Hunter
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Adrian Hunter @ 2016-10-05  9:11 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, Adrian Hunter, Jisheng Zhang

Unlike other cases, sdhci_set_power() does not reflect the default
implementation of the ->set_power() callback. Rename it and create
sdhci_set_power() that is the default implementation.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jisheng Zhang <jszhang@marvell.com>
---
 drivers/mmc/host/sdhci-pxav3.c |  2 +-
 drivers/mmc/host/sdhci.c       | 26 +++++++++++++-------------
 drivers/mmc/host/sdhci.h       |  2 ++
 3 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index dd1938d341f7..d0f5c05fbc19 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -315,7 +315,7 @@ static void pxav3_set_power(struct sdhci_host *host, unsigned char mode,
 	struct mmc_host *mmc = host->mmc;
 	u8 pwr = host->pwr;
 
-	sdhci_set_power(host, mode, vdd);
+	sdhci_set_power_noreg(host, mode, vdd);
 
 	if (host->pwr == pwr)
 		return;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3711813f5654..223a91e039dc 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1394,8 +1394,8 @@ static void sdhci_set_power_reg(struct sdhci_host *host, unsigned char mode,
 		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
 }
 
-void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
-		     unsigned short vdd)
+void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
+			   unsigned short vdd)
 {
 	u8 pwr = 0;
 
@@ -1459,20 +1459,17 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
 			mdelay(10);
 	}
 }
-EXPORT_SYMBOL_GPL(sdhci_set_power);
+EXPORT_SYMBOL_GPL(sdhci_set_power_noreg);
 
-static void __sdhci_set_power(struct sdhci_host *host, unsigned char mode,
-			      unsigned short vdd)
+void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+		     unsigned short vdd)
 {
-	struct mmc_host *mmc = host->mmc;
-
-	if (host->ops->set_power)
-		host->ops->set_power(host, mode, vdd);
-	else if (!IS_ERR(mmc->supply.vmmc))
-		sdhci_set_power_reg(host, mode, vdd);
+	if (IS_ERR(host->mmc->supply.vmmc))
+		sdhci_set_power_noreg(host, mode, vdd);
 	else
-		sdhci_set_power(host, mode, vdd);
+		sdhci_set_power_reg(host, mode, vdd);
 }
+EXPORT_SYMBOL_GPL(sdhci_set_power);
 
 /*****************************************************************************\
  *                                                                           *
@@ -1613,7 +1610,10 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		}
 	}
 
-	__sdhci_set_power(host, ios->power_mode, ios->vdd);
+	if (host->ops->set_power)
+		host->ops->set_power(host, ios->power_mode, ios->vdd);
+	else
+		sdhci_set_power(host, ios->power_mode, ios->vdd);
 
 	if (host->ops->platform_send_init_74_clocks)
 		host->ops->platform_send_init_74_clocks(host, ios->power_mode);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index c722cd23205c..766df17fb7eb 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -683,6 +683,8 @@ u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
 void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
 void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
 		     unsigned short vdd);
+void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
+			   unsigned short vdd);
 void sdhci_set_bus_width(struct sdhci_host *host, int width);
 void sdhci_reset(struct sdhci_host *host, u8 mask);
 void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/4] mmc: sdhci-pci: Let devices define their own sdhci_ops
  2016-10-05  9:11 [PATCH 0/4] mmc: sdhci: Minor fixes Adrian Hunter
  2016-10-05  9:11 ` [PATCH 1/4] mmc: sdhci: Fix SDHCI_QUIRK2_STOP_WITH_TC Adrian Hunter
  2016-10-05  9:11 ` [PATCH 2/4] mmc: sdhci: Rename sdhci_set_power() to sdhci_set_power_noreg() Adrian Hunter
@ 2016-10-05  9:11 ` Adrian Hunter
  2016-10-05  9:11 ` [PATCH 4/4] mmc: sdhci-pci: Fix bus power failing to enable for some Intel controllers Adrian Hunter
  2016-10-10 12:38 ` [PATCH 0/4] mmc: sdhci: Minor fixes Ulf Hansson
  4 siblings, 0 replies; 6+ messages in thread
From: Adrian Hunter @ 2016-10-05  9:11 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, Adrian Hunter

Let devices define their own sdhci_ops so that device-specific variations
can be implemented without adding quirks.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci-pci-core.c | 4 +++-
 drivers/mmc/host/sdhci-pci.h      | 2 ++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 72a1f1f5180a..5e11e0e3be63 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -1648,7 +1648,9 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
 	}
 
 	host->hw_name = "PCI";
-	host->ops = &sdhci_pci_ops;
+	host->ops = chip->fixes && chip->fixes->ops ?
+		    chip->fixes->ops :
+		    &sdhci_pci_ops;
 	host->quirks = chip->quirks;
 	host->quirks2 = chip->quirks2;
 
diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h
index 9c7c08b93223..6bccf56bc5ff 100644
--- a/drivers/mmc/host/sdhci-pci.h
+++ b/drivers/mmc/host/sdhci-pci.h
@@ -65,6 +65,8 @@ struct sdhci_pci_fixes {
 
 	int			(*suspend) (struct sdhci_pci_chip *);
 	int			(*resume) (struct sdhci_pci_chip *);
+
+	const struct sdhci_ops	*ops;
 };
 
 struct sdhci_pci_slot {
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/4] mmc: sdhci-pci: Fix bus power failing to enable for some Intel controllers
  2016-10-05  9:11 [PATCH 0/4] mmc: sdhci: Minor fixes Adrian Hunter
                   ` (2 preceding siblings ...)
  2016-10-05  9:11 ` [PATCH 3/4] mmc: sdhci-pci: Let devices define their own sdhci_ops Adrian Hunter
@ 2016-10-05  9:11 ` Adrian Hunter
  2016-10-10 12:38 ` [PATCH 0/4] mmc: sdhci: Minor fixes Ulf Hansson
  4 siblings, 0 replies; 6+ messages in thread
From: Adrian Hunter @ 2016-10-05  9:11 UTC (permalink / raw)
  To: Ulf Hansson; +Cc: linux-mmc, Adrian Hunter

Some Intel controllers (e.g. BXT) might fail to set bus power after a
D3 -> D0 transition due to the present state not yet having propagated.
Retry for up to 2 milliseconds.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/mmc/host/sdhci-pci-core.c | 50 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 5e11e0e3be63..1d9e00a00e9f 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -32,6 +32,14 @@
 #include "sdhci-pci.h"
 #include "sdhci-pci-o2micro.h"
 
+static int sdhci_pci_enable_dma(struct sdhci_host *host);
+static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width);
+static void sdhci_pci_hw_reset(struct sdhci_host *host);
+static int sdhci_pci_select_drive_strength(struct sdhci_host *host,
+					   struct mmc_card *card,
+					   unsigned int max_dtr, int host_drv,
+					   int card_drv, int *drv_type);
+
 /*****************************************************************************\
  *                                                                           *
  * Hardware specific quirk handling                                          *
@@ -390,6 +398,45 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
 	return 0;
 }
 
+#define SDHCI_INTEL_PWR_TIMEOUT_CNT	20
+#define SDHCI_INTEL_PWR_TIMEOUT_UDELAY	100
+
+static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode,
+				  unsigned short vdd)
+{
+	int cntr;
+	u8 reg;
+
+	sdhci_set_power(host, mode, vdd);
+
+	if (mode == MMC_POWER_OFF)
+		return;
+
+	/*
+	 * Bus power might not enable after D3 -> D0 transition due to the
+	 * present state not yet having propagated. Retry for up to 2ms.
+	 */
+	for (cntr = 0; cntr < SDHCI_INTEL_PWR_TIMEOUT_CNT; cntr++) {
+		reg = sdhci_readb(host, SDHCI_POWER_CONTROL);
+		if (reg & SDHCI_POWER_ON)
+			break;
+		udelay(SDHCI_INTEL_PWR_TIMEOUT_UDELAY);
+		reg |= SDHCI_POWER_ON;
+		sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
+	}
+}
+
+static const struct sdhci_ops sdhci_intel_byt_ops = {
+	.set_clock		= sdhci_set_clock,
+	.set_power		= sdhci_intel_set_power,
+	.enable_dma		= sdhci_pci_enable_dma,
+	.set_bus_width		= sdhci_pci_set_bus_width,
+	.reset			= sdhci_reset,
+	.set_uhs_signaling	= sdhci_set_uhs_signaling,
+	.hw_reset		= sdhci_pci_hw_reset,
+	.select_drive_strength	= sdhci_pci_select_drive_strength,
+};
+
 static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
 	.allow_runtime_pm = true,
 	.probe_slot	= byt_emmc_probe_slot,
@@ -397,6 +444,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
 	.quirks2	= SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
 			  SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 |
 			  SDHCI_QUIRK2_STOP_WITH_TC,
+	.ops		= &sdhci_intel_byt_ops,
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
@@ -405,6 +453,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
 			SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
 	.allow_runtime_pm = true,
 	.probe_slot	= byt_sdio_probe_slot,
+	.ops		= &sdhci_intel_byt_ops,
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
@@ -415,6 +464,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
 	.allow_runtime_pm = true,
 	.own_cd_for_runtime_pm = true,
 	.probe_slot	= byt_sd_probe_slot,
+	.ops		= &sdhci_intel_byt_ops,
 };
 
 /* Define Host controllers for Intel Merrifield platform */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/4] mmc: sdhci: Minor fixes
  2016-10-05  9:11 [PATCH 0/4] mmc: sdhci: Minor fixes Adrian Hunter
                   ` (3 preceding siblings ...)
  2016-10-05  9:11 ` [PATCH 4/4] mmc: sdhci-pci: Fix bus power failing to enable for some Intel controllers Adrian Hunter
@ 2016-10-10 12:38 ` Ulf Hansson
  4 siblings, 0 replies; 6+ messages in thread
From: Ulf Hansson @ 2016-10-10 12:38 UTC (permalink / raw)
  To: Adrian Hunter; +Cc: linux-mmc

On 5 October 2016 at 11:11, Adrian Hunter <adrian.hunter@intel.com> wrote:
> Hi
>
> Here are a couple of minor fixes.  While it would be good to have them in
> 4.9 or a 4.9-rc, they are not urgent.
>
>
> Adrian Hunter (4):
>       mmc: sdhci: Fix SDHCI_QUIRK2_STOP_WITH_TC
>       mmc: sdhci: Rename sdhci_set_power() to sdhci_set_power_noreg()
>       mmc: sdhci-pci: Let devices define their own sdhci_ops
>       mmc: sdhci-pci: Fix bus power failing to enable for some Intel controllers
>
>  drivers/mmc/host/sdhci-pci-core.c | 54 ++++++++++++++++++++++++++++++++++++++-
>  drivers/mmc/host/sdhci-pci.h      |  2 ++
>  drivers/mmc/host/sdhci-pxav3.c    |  2 +-
>  drivers/mmc/host/sdhci.c          | 40 ++++++++++++++---------------
>  drivers/mmc/host/sdhci.h          |  2 ++
>  5 files changed, 77 insertions(+), 23 deletions(-)
>
>
> Regards
> Adrian


Thanks, applied for fixes!

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-10-10 12:46 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-05  9:11 [PATCH 0/4] mmc: sdhci: Minor fixes Adrian Hunter
2016-10-05  9:11 ` [PATCH 1/4] mmc: sdhci: Fix SDHCI_QUIRK2_STOP_WITH_TC Adrian Hunter
2016-10-05  9:11 ` [PATCH 2/4] mmc: sdhci: Rename sdhci_set_power() to sdhci_set_power_noreg() Adrian Hunter
2016-10-05  9:11 ` [PATCH 3/4] mmc: sdhci-pci: Let devices define their own sdhci_ops Adrian Hunter
2016-10-05  9:11 ` [PATCH 4/4] mmc: sdhci-pci: Fix bus power failing to enable for some Intel controllers Adrian Hunter
2016-10-10 12:38 ` [PATCH 0/4] mmc: sdhci: Minor fixes Ulf Hansson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.