linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3 v2] mmc: mmci: clean up header defines
@ 2016-10-25  9:06 Linus Walleij
  2016-10-25  9:06 ` [PATCH 2/3 v2] mmc: mmci: refactor ST Micro busy detection Linus Walleij
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Linus Walleij @ 2016-10-25  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

There was some confusion in the CPSM (Command Path State Machine)
and DPSM (Data Path State Machine) regarding the naming of the
registers, clarify the meaning of this acronym so the naming is
understandable, and consistently use BIT() to define these fields.

Consequently name the register bit defines MCI_[C|D]PSM_* and
adjust the driver as well.

Include new definitions for a few bits found in a patch from
Srinivas Kandagatla.

Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v1->v2:
- Use more consequent register naming.
---
 drivers/mmc/host/mmci.c | 16 ++++++------
 drivers/mmc/host/mmci.h | 69 +++++++++++++++++++++++++++----------------------
 2 files changed, 46 insertions(+), 39 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index df990bb8c873..6a8ea9c633d4 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -137,7 +137,7 @@ static struct variant_data variant_u300 = {
 	.clkreg_enable		= MCI_ST_U300_HWFCEN,
 	.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
 	.datalength_bits	= 16,
-	.datactrl_mask_sdio	= MCI_ST_DPSM_SDIOEN,
+	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,
 	.st_sdio			= true,
 	.pwrreg_powerup		= MCI_PWR_ON,
 	.f_max			= 100000000,
@@ -152,7 +152,7 @@ static struct variant_data variant_nomadik = {
 	.clkreg			= MCI_CLK_ENABLE,
 	.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
 	.datalength_bits	= 24,
-	.datactrl_mask_sdio	= MCI_ST_DPSM_SDIOEN,
+	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,
 	.st_sdio		= true,
 	.st_clkdiv		= true,
 	.pwrreg_powerup		= MCI_PWR_ON,
@@ -170,7 +170,7 @@ static struct variant_data variant_ux500 = {
 	.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
 	.clkreg_neg_edge_enable	= MCI_ST_UX500_NEG_EDGE,
 	.datalength_bits	= 24,
-	.datactrl_mask_sdio	= MCI_ST_DPSM_SDIOEN,
+	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,
 	.st_sdio		= true,
 	.st_clkdiv		= true,
 	.pwrreg_powerup		= MCI_PWR_ON,
@@ -188,9 +188,9 @@ static struct variant_data variant_ux500v2 = {
 	.clkreg_enable		= MCI_ST_UX500_HWFCEN,
 	.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
 	.clkreg_neg_edge_enable	= MCI_ST_UX500_NEG_EDGE,
-	.datactrl_mask_ddrmode	= MCI_ST_DPSM_DDRMODE,
+	.datactrl_mask_ddrmode	= MCI_DPSM_ST_DDRMODE,
 	.datalength_bits	= 24,
-	.datactrl_mask_sdio	= MCI_ST_DPSM_SDIOEN,
+	.datactrl_mask_sdio	= MCI_DPSM_ST_SDIOEN,
 	.st_sdio		= true,
 	.st_clkdiv		= true,
 	.blksz_datactrl16	= true,
@@ -210,7 +210,7 @@ static struct variant_data variant_qcom = {
 				  MCI_QCOM_CLK_SELECT_IN_FBCLK,
 	.clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8,
 	.datactrl_mask_ddrmode	= MCI_QCOM_CLK_SELECT_IN_DDR_MODE,
-	.data_cmd_enable	= MCI_QCOM_CSPM_DATCMD,
+	.data_cmd_enable	= MCI_CPSM_QCOM_DATCMD,
 	.blksz_datactrl4	= true,
 	.datalength_bits	= 24,
 	.pwrreg_powerup		= MCI_PWR_UP,
@@ -295,7 +295,7 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
 static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
 {
 	/* Keep ST Micro busy mode if enabled */
-	datactrl |= host->datactrl_reg & MCI_ST_DPSM_BUSYMODE;
+	datactrl |= host->datactrl_reg & MCI_DPSM_ST_BUSYMODE;
 
 	if (host->datactrl_reg != datactrl) {
 		host->datactrl_reg = datactrl;
@@ -1614,7 +1614,7 @@ static int mmci_probe(struct amba_device *dev,
 
 	if (variant->busy_detect) {
 		mmci_ops.card_busy = mmci_card_busy;
-		mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);
+		mmci_write_datactrlreg(host, MCI_DPSM_ST_BUSYMODE);
 		mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
 		mmc->max_busy_timeout = 0;
 	}
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index a1f5e4f49e2a..7cabf270050b 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -51,25 +51,27 @@
 #define MCI_QCOM_CLK_SELECT_IN_DDR_MODE	(BIT(14) | BIT(15))
 
 #define MMCIARGUMENT		0x008
-#define MMCICOMMAND		0x00c
-#define MCI_CPSM_RESPONSE	(1 << 6)
-#define MCI_CPSM_LONGRSP	(1 << 7)
-#define MCI_CPSM_INTERRUPT	(1 << 8)
-#define MCI_CPSM_PENDING	(1 << 9)
-#define MCI_CPSM_ENABLE		(1 << 10)
-/* Argument flag extenstions in the ST Micro versions */
-#define MCI_ST_SDIO_SUSP	(1 << 11)
-#define MCI_ST_ENCMD_COMPL	(1 << 12)
-#define MCI_ST_NIEN		(1 << 13)
-#define MCI_ST_CE_ATACMD	(1 << 14)
 
-/* Modified on Qualcomm Integrations */
-#define MCI_QCOM_CSPM_DATCMD		BIT(12)
-#define MCI_QCOM_CSPM_MCIABORT		BIT(13)
-#define MCI_QCOM_CSPM_CCSENABLE		BIT(14)
-#define MCI_QCOM_CSPM_CCSDISABLE	BIT(15)
-#define MCI_QCOM_CSPM_AUTO_CMD19	BIT(16)
-#define MCI_QCOM_CSPM_AUTO_CMD21	BIT(21)
+/* The command register controls the Command Path State Machine (CPSM) */
+#define MMCICOMMAND		0x00c
+#define MCI_CPSM_RESPONSE	BIT(6)
+#define MCI_CPSM_LONGRSP	BIT(7)
+#define MCI_CPSM_INTERRUPT	BIT(8)
+#define MCI_CPSM_PENDING	BIT(9)
+#define MCI_CPSM_ENABLE		BIT(10)
+/* Command register flag extenstions in the ST Micro versions */
+#define MCI_CPSM_ST_SDIO_SUSP		BIT(11)
+#define MCI_CPSM_ST_ENCMD_COMPL		BIT(12)
+#define MCI_CPSM_ST_NIEN		BIT(13)
+#define MCI_CPSM_ST_CE_ATACMD		BIT(14)
+/* Command register flag extensions in the Qualcomm versions */
+#define MCI_CPSM_QCOM_PROGENA		BIT(11)
+#define MCI_CPSM_QCOM_DATCMD		BIT(12)
+#define MCI_CPSM_QCOM_MCIABORT		BIT(13)
+#define MCI_CPSM_QCOM_CCSENABLE		BIT(14)
+#define MCI_CPSM_QCOM_CCSDISABLE	BIT(15)
+#define MCI_CPSM_QCOM_AUTO_CMD19	BIT(16)
+#define MCI_CPSM_QCOM_AUTO_CMD21	BIT(21)
 
 #define MMCIRESPCMD		0x010
 #define MMCIRESPONSE0		0x014
@@ -78,22 +80,27 @@
 #define MMCIRESPONSE3		0x020
 #define MMCIDATATIMER		0x024
 #define MMCIDATALENGTH		0x028
+
+/* The data control register controls the Data Path State Machine (DPSM) */
 #define MMCIDATACTRL		0x02c
-#define MCI_DPSM_ENABLE		(1 << 0)
-#define MCI_DPSM_DIRECTION	(1 << 1)
-#define MCI_DPSM_MODE		(1 << 2)
-#define MCI_DPSM_DMAENABLE	(1 << 3)
-#define MCI_DPSM_BLOCKSIZE	(1 << 4)
+#define MCI_DPSM_ENABLE		BIT(0)
+#define MCI_DPSM_DIRECTION	BIT(1)
+#define MCI_DPSM_MODE		BIT(2)
+#define MCI_DPSM_DMAENABLE	BIT(3)
+#define MCI_DPSM_BLOCKSIZE	BIT(4)
 /* Control register extensions in the ST Micro U300 and Ux500 versions */
-#define MCI_ST_DPSM_RWSTART	(1 << 8)
-#define MCI_ST_DPSM_RWSTOP	(1 << 9)
-#define MCI_ST_DPSM_RWMOD	(1 << 10)
-#define MCI_ST_DPSM_SDIOEN	(1 << 11)
+#define MCI_DPSM_ST_RWSTART	BIT(8)
+#define MCI_DPSM_ST_RWSTOP	BIT(9)
+#define MCI_DPSM_ST_RWMOD	BIT(10)
+#define MCI_DPSM_ST_SDIOEN	BIT(11)
 /* Control register extensions in the ST Micro Ux500 versions */
-#define MCI_ST_DPSM_DMAREQCTL	(1 << 12)
-#define MCI_ST_DPSM_DBOOTMODEEN	(1 << 13)
-#define MCI_ST_DPSM_BUSYMODE	(1 << 14)
-#define MCI_ST_DPSM_DDRMODE	(1 << 15)
+#define MCI_DPSM_ST_DMAREQCTL	BIT(12)
+#define MCI_DPSM_ST_DBOOTMODEEN	BIT(13)
+#define MCI_DPSM_ST_BUSYMODE	BIT(14)
+#define MCI_DPSM_ST_DDRMODE	BIT(15)
+/* Control register extensions in the Qualcomm versions */
+#define MCI_DPSM_QCOM_DATA_PEND	BIT(17)
+#define MCI_DPSM_QCOM_RX_DATA_PEND BIT(20)
 
 #define MMCIDATACNT		0x030
 #define MMCISTATUS		0x034
-- 
2.7.4

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

* [PATCH 2/3 v2] mmc: mmci: refactor ST Micro busy detection
  2016-10-25  9:06 [PATCH 1/3 v2] mmc: mmci: clean up header defines Linus Walleij
@ 2016-10-25  9:06 ` Linus Walleij
  2016-11-07 12:43   ` Ulf Hansson
  2016-10-25  9:06 ` [PATCH 3/3 v2] RFC: mmc: mmci: add qcom specific program end support Linus Walleij
  2016-11-07 12:43 ` [PATCH 1/3 v2] mmc: mmci: clean up header defines Ulf Hansson
  2 siblings, 1 reply; 5+ messages in thread
From: Linus Walleij @ 2016-10-25  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

The ST Micro-specific busy detection was made after the assumption
that only this variant supports busy detection. So when doing busy
detection, the host immediately tries to use some ST-specific
register bits.

Since the qualcomm variant also supports some busy detection
schemes, encapsulate the variant flags better in the variant struct
and prepare to add more variants by just providing some bitmasks
to the logic.

Put the entire busy detection logic within an if()-clause in the
mmci_cmd_irq() function so the code is only executed when busy
detection is enabled, and so that it is kept in (almost) one
place, and add comments describing what is going on so the
code can be understood.

Tested on the Ux500 by introducing some prints in the busy
detection path and noticing how the IRQ is enabled, used and
disabled successfully.

Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v1->v2:
- Rebase on new register naming.
---
 drivers/mmc/host/mmci.c | 113 +++++++++++++++++++++++++++++++++++-------------
 drivers/mmc/host/mmci.h |   2 +-
 2 files changed, 85 insertions(+), 30 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 6a8ea9c633d4..7f68fa7a961e 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -71,7 +71,12 @@ static unsigned int fmax = 515633;
  * @f_max: maximum clk frequency supported by the controller.
  * @signal_direction: input/out direction of bus signals can be indicated
  * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
- * @busy_detect: true if busy detection on dat0 is supported
+ * @busy_detect: true if the variant supports busy detection on DAT0.
+ * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
+ * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
+ * 	 	      indicating that the card is busy
+ * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
+ * 	  	      getting busy end detection interrupts
  * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
  * @explicit_mclk_control: enable explicit mclk control in driver.
  * @qcom_fifo: enables qcom specific fifo pio read logic.
@@ -98,6 +103,9 @@ struct variant_data {
 	bool			signal_direction;
 	bool			pwrreg_clkgate;
 	bool			busy_detect;
+	u32			busy_dpsm_flag;
+	u32			busy_detect_flag;
+	u32			busy_detect_mask;
 	bool			pwrreg_nopower;
 	bool			explicit_mclk_control;
 	bool			qcom_fifo;
@@ -178,6 +186,9 @@ static struct variant_data variant_ux500 = {
 	.signal_direction	= true,
 	.pwrreg_clkgate		= true,
 	.busy_detect		= true,
+	.busy_dpsm_flag		= MCI_DPSM_ST_BUSYMODE,
+	.busy_detect_flag	= MCI_ST_CARDBUSY,
+	.busy_detect_mask	= MCI_ST_BUSYENDMASK,
 	.pwrreg_nopower		= true,
 };
 
@@ -199,6 +210,9 @@ static struct variant_data variant_ux500v2 = {
 	.signal_direction	= true,
 	.pwrreg_clkgate		= true,
 	.busy_detect		= true,
+	.busy_dpsm_flag		= MCI_DPSM_ST_BUSYMODE,
+	.busy_detect_flag	= MCI_ST_CARDBUSY,
+	.busy_detect_mask	= MCI_ST_BUSYENDMASK,
 	.pwrreg_nopower		= true,
 };
 
@@ -220,6 +234,7 @@ static struct variant_data variant_qcom = {
 	.qcom_dml		= true,
 };
 
+/* Busy detection for the ST Micro variant */
 static int mmci_card_busy(struct mmc_host *mmc)
 {
 	struct mmci_host *host = mmc_priv(mmc);
@@ -227,7 +242,7 @@ static int mmci_card_busy(struct mmc_host *mmc)
 	int busy = 0;
 
 	spin_lock_irqsave(&host->lock, flags);
-	if (readl(host->base + MMCISTATUS) & MCI_ST_CARDBUSY)
+	if (readl(host->base + MMCISTATUS) & host->variant->busy_detect_flag)
 		busy = 1;
 	spin_unlock_irqrestore(&host->lock, flags);
 
@@ -294,8 +309,8 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
  */
 static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
 {
-	/* Keep ST Micro busy mode if enabled */
-	datactrl |= host->datactrl_reg & MCI_DPSM_ST_BUSYMODE;
+	/* Keep busy mode in DPSM if enabled */
+	datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag;
 
 	if (host->datactrl_reg != datactrl) {
 		host->datactrl_reg = datactrl;
@@ -973,37 +988,66 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
 	     unsigned int status)
 {
 	void __iomem *base = host->base;
-	bool sbc, busy_resp;
+	bool sbc;
 
 	if (!cmd)
 		return;
 
 	sbc = (cmd == host->mrq->sbc);
-	busy_resp = host->variant->busy_detect && (cmd->flags & MMC_RSP_BUSY);
 
-	if (!((status|host->busy_status) & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|
-		MCI_CMDSENT|MCI_CMDRESPEND)))
+	/*
+	 * We need to be one of these interrupts to be considered worth
+	 * handling. Note that we tag on any latent IRQs postponed
+	 * due to waiting for busy status.
+	 */
+	if (!((status|host->busy_status) &
+	      (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND)))
 		return;
 
-	/* Check if we need to wait for busy completion. */
-	if (host->busy_status && (status & MCI_ST_CARDBUSY))
-		return;
+	/*
+	 * ST Micro variant: handle busy detection.
+	 */
+	if (host->variant->busy_detect) {
+		bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY);
 
-	/* Enable busy completion if needed and supported. */
-	if (!host->busy_status && busy_resp &&
-		!(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&
-		(readl(base + MMCISTATUS) & MCI_ST_CARDBUSY)) {
-		writel(readl(base + MMCIMASK0) | MCI_ST_BUSYEND,
-			base + MMCIMASK0);
-		host->busy_status = status & (MCI_CMDSENT|MCI_CMDRESPEND);
-		return;
-	}
+		/* We are busy with a command, return */
+		if (host->busy_status &&
+		    (status & host->variant->busy_detect_flag))
+			return;
+
+		/*
+		 * We were not busy, but we now got a busy response on
+		 * something that was not an error, and we double-check
+		 * that the special busy status bit is still set before
+		 * proceeding.
+		 */
+		if (!host->busy_status && busy_resp &&
+		    !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&
+		    (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) {
+			/* Unmask the busy IRQ */
+			writel(readl(base + MMCIMASK0) |
+			       host->variant->busy_detect_mask,
+			       base + MMCIMASK0);
+			/*
+			 * Now cache the last response status code (until
+			 * the busy bit goes low), and return.
+			 */
+			host->busy_status =
+				status & (MCI_CMDSENT|MCI_CMDRESPEND);
+			return;
+		}
 
-	/* At busy completion, mask the IRQ and complete the request. */
-	if (host->busy_status) {
-		writel(readl(base + MMCIMASK0) & ~MCI_ST_BUSYEND,
-			base + MMCIMASK0);
-		host->busy_status = 0;
+		/*
+		 * At this point we are not busy with a command, we have
+		 * not recieved a new busy request, mask the busy IRQ and
+		 * fall through to process the IRQ.
+		 */
+		if (host->busy_status) {
+			writel(readl(base + MMCIMASK0) &
+			       ~host->variant->busy_detect_mask,
+			       base + MMCIMASK0);
+			host->busy_status = 0;
+		}
 	}
 
 	host->cmd = NULL;
@@ -1257,9 +1301,11 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
 			mmci_data_irq(host, host->data, status);
 		}
 
-		/* Don't poll for busy completion in irq context. */
-		if (host->busy_status)
-			status &= ~MCI_ST_CARDBUSY;
+		/*
+		 * Don't poll for busy completion in irq context.
+		 */
+		if (host->variant->busy_detect && host->busy_status)
+			status &= ~host->variant->busy_detect_flag;
 
 		ret = 1;
 	} while (status);
@@ -1612,9 +1658,18 @@ static int mmci_probe(struct amba_device *dev,
 	/* We support these capabilities. */
 	mmc->caps |= MMC_CAP_CMD23;
 
+	/*
+	 * Enable busy detection.
+	 */
 	if (variant->busy_detect) {
 		mmci_ops.card_busy = mmci_card_busy;
-		mmci_write_datactrlreg(host, MCI_DPSM_ST_BUSYMODE);
+		/*
+		 * Not all variants have a flag to enable busy detection
+		 * in the DPSM, but if they do, set it here.
+		 */
+		if (variant->busy_dpsm_flag)
+			mmci_write_datactrlreg(host,
+					       host->variant->busy_dpsm_flag);
 		mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
 		mmc->max_busy_timeout = 0;
 	}
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 7cabf270050b..56322c6afba4 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -174,7 +174,7 @@
 /* Extended status bits for the ST Micro variants */
 #define MCI_ST_SDIOITMASK	(1 << 22)
 #define MCI_ST_CEATAENDMASK	(1 << 23)
-#define MCI_ST_BUSYEND		(1 << 24)
+#define MCI_ST_BUSYENDMASK	(1 << 24)
 
 #define MMCIMASK1		0x040
 #define MMCIFIFOCNT		0x048
-- 
2.7.4

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

* [PATCH 3/3 v2] RFC: mmc: mmci: add qcom specific program end support
  2016-10-25  9:06 [PATCH 1/3 v2] mmc: mmci: clean up header defines Linus Walleij
  2016-10-25  9:06 ` [PATCH 2/3 v2] mmc: mmci: refactor ST Micro busy detection Linus Walleij
@ 2016-10-25  9:06 ` Linus Walleij
  2016-11-07 12:43 ` [PATCH 1/3 v2] mmc: mmci: clean up header defines Ulf Hansson
  2 siblings, 0 replies; 5+ messages in thread
From: Linus Walleij @ 2016-10-25  9:06 UTC (permalink / raw)
  To: linux-arm-kernel

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

This patch adds support to programend interrupt which is very
specific to QCOM integration. This interrupt is use as busy signal
when a command forces the card to enter into programming state
like CMD6 writing to ext_csd registers.

Hopefully, this also fixes the __mmc_switch timeout issue reproted
with latest versions of the eMMC used on DB600c board.

This patch is based on a WIP patch from Srinivas Kandagatla and
augmented by Linus Walleij for another approach.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v1->v2:
- Rebase on new register naming.

Srinivas: please test to see if this fixes your problems. Sadly
it does *NOT* solve my APQ8060 issues, but it would be nice if
the common code path works for the busy detection on your
DB600c.
---
 drivers/mmc/host/mmci.c | 21 +++++++++++++++++++--
 drivers/mmc/host/mmci.h |  6 ++++++
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 7f68fa7a961e..580ca89d33dc 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -72,7 +72,10 @@ static unsigned int fmax = 515633;
  * @signal_direction: input/out direction of bus signals can be indicated
  * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
  * @busy_detect: true if the variant supports busy detection on DAT0.
- * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
+ * @busy_cpsm_flag: bitmask enabling busy detection in the CPSM (command
+ *		    path state machine)
+ * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM (data path
+ *		    state machine)
  * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
  * 	 	      indicating that the card is busy
  * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
@@ -103,6 +106,7 @@ struct variant_data {
 	bool			signal_direction;
 	bool			pwrreg_clkgate;
 	bool			busy_detect;
+	u32			busy_cpsm_flag;
 	u32			busy_dpsm_flag;
 	u32			busy_detect_flag;
 	u32			busy_detect_mask;
@@ -229,6 +233,10 @@ static struct variant_data variant_qcom = {
 	.datalength_bits	= 24,
 	.pwrreg_powerup		= MCI_PWR_UP,
 	.f_max			= 208000000,
+	.busy_detect		= true,
+	.busy_cpsm_flag		= MCI_CPSM_QCOM_PROGENA,
+	.busy_detect_flag	= MCI_QCOM_PROGDONE,
+	.busy_detect_mask	= MCI_QCOM_PROGDONEMASK,
 	.explicit_mclk_control	= true,
 	.qcom_fifo		= true,
 	.qcom_dml		= true,
@@ -903,6 +911,15 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
 	if (/*interrupt*/0)
 		c |= MCI_CPSM_INTERRUPT;
 
+	/*
+	 * Enable the program end interrupt for specific commands
+	 * used for busy detection.
+	 */
+	if (host->variant->busy_detect &&
+	    (cmd->flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
+		c |= host->variant->busy_cpsm_flag;
+	}
+
 	if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
 		c |= host->variant->data_cmd_enable;
 
@@ -1005,7 +1022,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
 		return;
 
 	/*
-	 * ST Micro variant: handle busy detection.
+	 * ST Micro and Qualcomm variants: handle busy detection.
 	 */
 	if (host->variant->busy_detect) {
 		bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 56322c6afba4..355259b0a24b 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -130,6 +130,8 @@
 #define MCI_ST_SDIOIT		(1 << 22)
 #define MCI_ST_CEATAEND		(1 << 23)
 #define MCI_ST_CARDBUSY		(1 << 24)
+/* Extended status bits for the QCOM variants */
+#define MCI_QCOM_PROGDONE	(1 << 23)
 
 #define MMCICLEAR		0x038
 #define MCI_CMDCRCFAILCLR	(1 << 0)
@@ -147,6 +149,8 @@
 #define MCI_ST_SDIOITC		(1 << 22)
 #define MCI_ST_CEATAENDC	(1 << 23)
 #define MCI_ST_BUSYENDC		(1 << 24)
+/* Extended status bits for the QCOM variants */
+#define MCI_QCOM_PROGDONECLR	(1 << 23)
 
 #define MMCIMASK0		0x03c
 #define MCI_CMDCRCFAILMASK	(1 << 0)
@@ -175,6 +179,8 @@
 #define MCI_ST_SDIOITMASK	(1 << 22)
 #define MCI_ST_CEATAENDMASK	(1 << 23)
 #define MCI_ST_BUSYENDMASK	(1 << 24)
+/* Extended status bits for the Qualcomm variants */
+#define MCI_QCOM_PROGDONEMASK	(1 << 23)
 
 #define MMCIMASK1		0x040
 #define MMCIFIFOCNT		0x048
-- 
2.7.4

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

* [PATCH 1/3 v2] mmc: mmci: clean up header defines
  2016-10-25  9:06 [PATCH 1/3 v2] mmc: mmci: clean up header defines Linus Walleij
  2016-10-25  9:06 ` [PATCH 2/3 v2] mmc: mmci: refactor ST Micro busy detection Linus Walleij
  2016-10-25  9:06 ` [PATCH 3/3 v2] RFC: mmc: mmci: add qcom specific program end support Linus Walleij
@ 2016-11-07 12:43 ` Ulf Hansson
  2 siblings, 0 replies; 5+ messages in thread
From: Ulf Hansson @ 2016-11-07 12:43 UTC (permalink / raw)
  To: linux-arm-kernel

On 25 October 2016 at 11:06, Linus Walleij <linus.walleij@linaro.org> wrote:
> There was some confusion in the CPSM (Command Path State Machine)
> and DPSM (Data Path State Machine) regarding the naming of the
> registers, clarify the meaning of this acronym so the naming is
> understandable, and consistently use BIT() to define these fields.
>
> Consequently name the register bit defines MCI_[C|D]PSM_* and
> adjust the driver as well.
>
> Include new definitions for a few bits found in a patch from
> Srinivas Kandagatla.
>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

Thanks, applied for next!

Kind regards
Uffe

> ---
> ChangeLog v1->v2:
> - Use more consequent register naming.
> ---
>  drivers/mmc/host/mmci.c | 16 ++++++------
>  drivers/mmc/host/mmci.h | 69 +++++++++++++++++++++++++++----------------------
>  2 files changed, 46 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
> index df990bb8c873..6a8ea9c633d4 100644
> --- a/drivers/mmc/host/mmci.c
> +++ b/drivers/mmc/host/mmci.c
> @@ -137,7 +137,7 @@ static struct variant_data variant_u300 = {
>         .clkreg_enable          = MCI_ST_U300_HWFCEN,
>         .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
>         .datalength_bits        = 16,
> -       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
> +       .datactrl_mask_sdio     = MCI_DPSM_ST_SDIOEN,
>         .st_sdio                        = true,
>         .pwrreg_powerup         = MCI_PWR_ON,
>         .f_max                  = 100000000,
> @@ -152,7 +152,7 @@ static struct variant_data variant_nomadik = {
>         .clkreg                 = MCI_CLK_ENABLE,
>         .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
>         .datalength_bits        = 24,
> -       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
> +       .datactrl_mask_sdio     = MCI_DPSM_ST_SDIOEN,
>         .st_sdio                = true,
>         .st_clkdiv              = true,
>         .pwrreg_powerup         = MCI_PWR_ON,
> @@ -170,7 +170,7 @@ static struct variant_data variant_ux500 = {
>         .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
>         .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
>         .datalength_bits        = 24,
> -       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
> +       .datactrl_mask_sdio     = MCI_DPSM_ST_SDIOEN,
>         .st_sdio                = true,
>         .st_clkdiv              = true,
>         .pwrreg_powerup         = MCI_PWR_ON,
> @@ -188,9 +188,9 @@ static struct variant_data variant_ux500v2 = {
>         .clkreg_enable          = MCI_ST_UX500_HWFCEN,
>         .clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
>         .clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
> -       .datactrl_mask_ddrmode  = MCI_ST_DPSM_DDRMODE,
> +       .datactrl_mask_ddrmode  = MCI_DPSM_ST_DDRMODE,
>         .datalength_bits        = 24,
> -       .datactrl_mask_sdio     = MCI_ST_DPSM_SDIOEN,
> +       .datactrl_mask_sdio     = MCI_DPSM_ST_SDIOEN,
>         .st_sdio                = true,
>         .st_clkdiv              = true,
>         .blksz_datactrl16       = true,
> @@ -210,7 +210,7 @@ static struct variant_data variant_qcom = {
>                                   MCI_QCOM_CLK_SELECT_IN_FBCLK,
>         .clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8,
>         .datactrl_mask_ddrmode  = MCI_QCOM_CLK_SELECT_IN_DDR_MODE,
> -       .data_cmd_enable        = MCI_QCOM_CSPM_DATCMD,
> +       .data_cmd_enable        = MCI_CPSM_QCOM_DATCMD,
>         .blksz_datactrl4        = true,
>         .datalength_bits        = 24,
>         .pwrreg_powerup         = MCI_PWR_UP,
> @@ -295,7 +295,7 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
>  static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
>  {
>         /* Keep ST Micro busy mode if enabled */
> -       datactrl |= host->datactrl_reg & MCI_ST_DPSM_BUSYMODE;
> +       datactrl |= host->datactrl_reg & MCI_DPSM_ST_BUSYMODE;
>
>         if (host->datactrl_reg != datactrl) {
>                 host->datactrl_reg = datactrl;
> @@ -1614,7 +1614,7 @@ static int mmci_probe(struct amba_device *dev,
>
>         if (variant->busy_detect) {
>                 mmci_ops.card_busy = mmci_card_busy;
> -               mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);
> +               mmci_write_datactrlreg(host, MCI_DPSM_ST_BUSYMODE);
>                 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
>                 mmc->max_busy_timeout = 0;
>         }
> diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
> index a1f5e4f49e2a..7cabf270050b 100644
> --- a/drivers/mmc/host/mmci.h
> +++ b/drivers/mmc/host/mmci.h
> @@ -51,25 +51,27 @@
>  #define MCI_QCOM_CLK_SELECT_IN_DDR_MODE        (BIT(14) | BIT(15))
>
>  #define MMCIARGUMENT           0x008
> -#define MMCICOMMAND            0x00c
> -#define MCI_CPSM_RESPONSE      (1 << 6)
> -#define MCI_CPSM_LONGRSP       (1 << 7)
> -#define MCI_CPSM_INTERRUPT     (1 << 8)
> -#define MCI_CPSM_PENDING       (1 << 9)
> -#define MCI_CPSM_ENABLE                (1 << 10)
> -/* Argument flag extenstions in the ST Micro versions */
> -#define MCI_ST_SDIO_SUSP       (1 << 11)
> -#define MCI_ST_ENCMD_COMPL     (1 << 12)
> -#define MCI_ST_NIEN            (1 << 13)
> -#define MCI_ST_CE_ATACMD       (1 << 14)
>
> -/* Modified on Qualcomm Integrations */
> -#define MCI_QCOM_CSPM_DATCMD           BIT(12)
> -#define MCI_QCOM_CSPM_MCIABORT         BIT(13)
> -#define MCI_QCOM_CSPM_CCSENABLE                BIT(14)
> -#define MCI_QCOM_CSPM_CCSDISABLE       BIT(15)
> -#define MCI_QCOM_CSPM_AUTO_CMD19       BIT(16)
> -#define MCI_QCOM_CSPM_AUTO_CMD21       BIT(21)
> +/* The command register controls the Command Path State Machine (CPSM) */
> +#define MMCICOMMAND            0x00c
> +#define MCI_CPSM_RESPONSE      BIT(6)
> +#define MCI_CPSM_LONGRSP       BIT(7)
> +#define MCI_CPSM_INTERRUPT     BIT(8)
> +#define MCI_CPSM_PENDING       BIT(9)
> +#define MCI_CPSM_ENABLE                BIT(10)
> +/* Command register flag extenstions in the ST Micro versions */
> +#define MCI_CPSM_ST_SDIO_SUSP          BIT(11)
> +#define MCI_CPSM_ST_ENCMD_COMPL                BIT(12)
> +#define MCI_CPSM_ST_NIEN               BIT(13)
> +#define MCI_CPSM_ST_CE_ATACMD          BIT(14)
> +/* Command register flag extensions in the Qualcomm versions */
> +#define MCI_CPSM_QCOM_PROGENA          BIT(11)
> +#define MCI_CPSM_QCOM_DATCMD           BIT(12)
> +#define MCI_CPSM_QCOM_MCIABORT         BIT(13)
> +#define MCI_CPSM_QCOM_CCSENABLE                BIT(14)
> +#define MCI_CPSM_QCOM_CCSDISABLE       BIT(15)
> +#define MCI_CPSM_QCOM_AUTO_CMD19       BIT(16)
> +#define MCI_CPSM_QCOM_AUTO_CMD21       BIT(21)
>
>  #define MMCIRESPCMD            0x010
>  #define MMCIRESPONSE0          0x014
> @@ -78,22 +80,27 @@
>  #define MMCIRESPONSE3          0x020
>  #define MMCIDATATIMER          0x024
>  #define MMCIDATALENGTH         0x028
> +
> +/* The data control register controls the Data Path State Machine (DPSM) */
>  #define MMCIDATACTRL           0x02c
> -#define MCI_DPSM_ENABLE                (1 << 0)
> -#define MCI_DPSM_DIRECTION     (1 << 1)
> -#define MCI_DPSM_MODE          (1 << 2)
> -#define MCI_DPSM_DMAENABLE     (1 << 3)
> -#define MCI_DPSM_BLOCKSIZE     (1 << 4)
> +#define MCI_DPSM_ENABLE                BIT(0)
> +#define MCI_DPSM_DIRECTION     BIT(1)
> +#define MCI_DPSM_MODE          BIT(2)
> +#define MCI_DPSM_DMAENABLE     BIT(3)
> +#define MCI_DPSM_BLOCKSIZE     BIT(4)
>  /* Control register extensions in the ST Micro U300 and Ux500 versions */
> -#define MCI_ST_DPSM_RWSTART    (1 << 8)
> -#define MCI_ST_DPSM_RWSTOP     (1 << 9)
> -#define MCI_ST_DPSM_RWMOD      (1 << 10)
> -#define MCI_ST_DPSM_SDIOEN     (1 << 11)
> +#define MCI_DPSM_ST_RWSTART    BIT(8)
> +#define MCI_DPSM_ST_RWSTOP     BIT(9)
> +#define MCI_DPSM_ST_RWMOD      BIT(10)
> +#define MCI_DPSM_ST_SDIOEN     BIT(11)
>  /* Control register extensions in the ST Micro Ux500 versions */
> -#define MCI_ST_DPSM_DMAREQCTL  (1 << 12)
> -#define MCI_ST_DPSM_DBOOTMODEEN        (1 << 13)
> -#define MCI_ST_DPSM_BUSYMODE   (1 << 14)
> -#define MCI_ST_DPSM_DDRMODE    (1 << 15)
> +#define MCI_DPSM_ST_DMAREQCTL  BIT(12)
> +#define MCI_DPSM_ST_DBOOTMODEEN        BIT(13)
> +#define MCI_DPSM_ST_BUSYMODE   BIT(14)
> +#define MCI_DPSM_ST_DDRMODE    BIT(15)
> +/* Control register extensions in the Qualcomm versions */
> +#define MCI_DPSM_QCOM_DATA_PEND        BIT(17)
> +#define MCI_DPSM_QCOM_RX_DATA_PEND BIT(20)
>
>  #define MMCIDATACNT            0x030
>  #define MMCISTATUS             0x034
> --
> 2.7.4
>

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

* [PATCH 2/3 v2] mmc: mmci: refactor ST Micro busy detection
  2016-10-25  9:06 ` [PATCH 2/3 v2] mmc: mmci: refactor ST Micro busy detection Linus Walleij
@ 2016-11-07 12:43   ` Ulf Hansson
  0 siblings, 0 replies; 5+ messages in thread
From: Ulf Hansson @ 2016-11-07 12:43 UTC (permalink / raw)
  To: linux-arm-kernel

On 25 October 2016 at 11:06, Linus Walleij <linus.walleij@linaro.org> wrote:
> The ST Micro-specific busy detection was made after the assumption
> that only this variant supports busy detection. So when doing busy
> detection, the host immediately tries to use some ST-specific
> register bits.
>
> Since the qualcomm variant also supports some busy detection
> schemes, encapsulate the variant flags better in the variant struct
> and prepare to add more variants by just providing some bitmasks
> to the logic.
>
> Put the entire busy detection logic within an if()-clause in the
> mmci_cmd_irq() function so the code is only executed when busy
> detection is enabled, and so that it is kept in (almost) one
> place, and add comments describing what is going on so the
> code can be understood.
>
> Tested on the Ux500 by introducing some prints in the busy
> detection path and noticing how the IRQ is enabled, used and
> disabled successfully.
>
> Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

Thanks, applied for next!

Kind regards
Uffe

> ---
> ChangeLog v1->v2:
> - Rebase on new register naming.
> ---
>  drivers/mmc/host/mmci.c | 113 +++++++++++++++++++++++++++++++++++-------------
>  drivers/mmc/host/mmci.h |   2 +-
>  2 files changed, 85 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
> index 6a8ea9c633d4..7f68fa7a961e 100644
> --- a/drivers/mmc/host/mmci.c
> +++ b/drivers/mmc/host/mmci.c
> @@ -71,7 +71,12 @@ static unsigned int fmax = 515633;
>   * @f_max: maximum clk frequency supported by the controller.
>   * @signal_direction: input/out direction of bus signals can be indicated
>   * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
> - * @busy_detect: true if busy detection on dat0 is supported
> + * @busy_detect: true if the variant supports busy detection on DAT0.
> + * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
> + * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
> + *                   indicating that the card is busy
> + * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
> + *                   getting busy end detection interrupts
>   * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
>   * @explicit_mclk_control: enable explicit mclk control in driver.
>   * @qcom_fifo: enables qcom specific fifo pio read logic.
> @@ -98,6 +103,9 @@ struct variant_data {
>         bool                    signal_direction;
>         bool                    pwrreg_clkgate;
>         bool                    busy_detect;
> +       u32                     busy_dpsm_flag;
> +       u32                     busy_detect_flag;
> +       u32                     busy_detect_mask;
>         bool                    pwrreg_nopower;
>         bool                    explicit_mclk_control;
>         bool                    qcom_fifo;
> @@ -178,6 +186,9 @@ static struct variant_data variant_ux500 = {
>         .signal_direction       = true,
>         .pwrreg_clkgate         = true,
>         .busy_detect            = true,
> +       .busy_dpsm_flag         = MCI_DPSM_ST_BUSYMODE,
> +       .busy_detect_flag       = MCI_ST_CARDBUSY,
> +       .busy_detect_mask       = MCI_ST_BUSYENDMASK,
>         .pwrreg_nopower         = true,
>  };
>
> @@ -199,6 +210,9 @@ static struct variant_data variant_ux500v2 = {
>         .signal_direction       = true,
>         .pwrreg_clkgate         = true,
>         .busy_detect            = true,
> +       .busy_dpsm_flag         = MCI_DPSM_ST_BUSYMODE,
> +       .busy_detect_flag       = MCI_ST_CARDBUSY,
> +       .busy_detect_mask       = MCI_ST_BUSYENDMASK,
>         .pwrreg_nopower         = true,
>  };
>
> @@ -220,6 +234,7 @@ static struct variant_data variant_qcom = {
>         .qcom_dml               = true,
>  };
>
> +/* Busy detection for the ST Micro variant */
>  static int mmci_card_busy(struct mmc_host *mmc)
>  {
>         struct mmci_host *host = mmc_priv(mmc);
> @@ -227,7 +242,7 @@ static int mmci_card_busy(struct mmc_host *mmc)
>         int busy = 0;
>
>         spin_lock_irqsave(&host->lock, flags);
> -       if (readl(host->base + MMCISTATUS) & MCI_ST_CARDBUSY)
> +       if (readl(host->base + MMCISTATUS) & host->variant->busy_detect_flag)
>                 busy = 1;
>         spin_unlock_irqrestore(&host->lock, flags);
>
> @@ -294,8 +309,8 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
>   */
>  static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
>  {
> -       /* Keep ST Micro busy mode if enabled */
> -       datactrl |= host->datactrl_reg & MCI_DPSM_ST_BUSYMODE;
> +       /* Keep busy mode in DPSM if enabled */
> +       datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag;
>
>         if (host->datactrl_reg != datactrl) {
>                 host->datactrl_reg = datactrl;
> @@ -973,37 +988,66 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
>              unsigned int status)
>  {
>         void __iomem *base = host->base;
> -       bool sbc, busy_resp;
> +       bool sbc;
>
>         if (!cmd)
>                 return;
>
>         sbc = (cmd == host->mrq->sbc);
> -       busy_resp = host->variant->busy_detect && (cmd->flags & MMC_RSP_BUSY);
>
> -       if (!((status|host->busy_status) & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|
> -               MCI_CMDSENT|MCI_CMDRESPEND)))
> +       /*
> +        * We need to be one of these interrupts to be considered worth
> +        * handling. Note that we tag on any latent IRQs postponed
> +        * due to waiting for busy status.
> +        */
> +       if (!((status|host->busy_status) &
> +             (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND)))
>                 return;
>
> -       /* Check if we need to wait for busy completion. */
> -       if (host->busy_status && (status & MCI_ST_CARDBUSY))
> -               return;
> +       /*
> +        * ST Micro variant: handle busy detection.
> +        */
> +       if (host->variant->busy_detect) {
> +               bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY);
>
> -       /* Enable busy completion if needed and supported. */
> -       if (!host->busy_status && busy_resp &&
> -               !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&
> -               (readl(base + MMCISTATUS) & MCI_ST_CARDBUSY)) {
> -               writel(readl(base + MMCIMASK0) | MCI_ST_BUSYEND,
> -                       base + MMCIMASK0);
> -               host->busy_status = status & (MCI_CMDSENT|MCI_CMDRESPEND);
> -               return;
> -       }
> +               /* We are busy with a command, return */
> +               if (host->busy_status &&
> +                   (status & host->variant->busy_detect_flag))
> +                       return;
> +
> +               /*
> +                * We were not busy, but we now got a busy response on
> +                * something that was not an error, and we double-check
> +                * that the special busy status bit is still set before
> +                * proceeding.
> +                */
> +               if (!host->busy_status && busy_resp &&
> +                   !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&
> +                   (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) {
> +                       /* Unmask the busy IRQ */
> +                       writel(readl(base + MMCIMASK0) |
> +                              host->variant->busy_detect_mask,
> +                              base + MMCIMASK0);
> +                       /*
> +                        * Now cache the last response status code (until
> +                        * the busy bit goes low), and return.
> +                        */
> +                       host->busy_status =
> +                               status & (MCI_CMDSENT|MCI_CMDRESPEND);
> +                       return;
> +               }
>
> -       /* At busy completion, mask the IRQ and complete the request. */
> -       if (host->busy_status) {
> -               writel(readl(base + MMCIMASK0) & ~MCI_ST_BUSYEND,
> -                       base + MMCIMASK0);
> -               host->busy_status = 0;
> +               /*
> +                * At this point we are not busy with a command, we have
> +                * not recieved a new busy request, mask the busy IRQ and
> +                * fall through to process the IRQ.
> +                */
> +               if (host->busy_status) {
> +                       writel(readl(base + MMCIMASK0) &
> +                              ~host->variant->busy_detect_mask,
> +                              base + MMCIMASK0);
> +                       host->busy_status = 0;
> +               }
>         }
>
>         host->cmd = NULL;
> @@ -1257,9 +1301,11 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
>                         mmci_data_irq(host, host->data, status);
>                 }
>
> -               /* Don't poll for busy completion in irq context. */
> -               if (host->busy_status)
> -                       status &= ~MCI_ST_CARDBUSY;
> +               /*
> +                * Don't poll for busy completion in irq context.
> +                */
> +               if (host->variant->busy_detect && host->busy_status)
> +                       status &= ~host->variant->busy_detect_flag;
>
>                 ret = 1;
>         } while (status);
> @@ -1612,9 +1658,18 @@ static int mmci_probe(struct amba_device *dev,
>         /* We support these capabilities. */
>         mmc->caps |= MMC_CAP_CMD23;
>
> +       /*
> +        * Enable busy detection.
> +        */
>         if (variant->busy_detect) {
>                 mmci_ops.card_busy = mmci_card_busy;
> -               mmci_write_datactrlreg(host, MCI_DPSM_ST_BUSYMODE);
> +               /*
> +                * Not all variants have a flag to enable busy detection
> +                * in the DPSM, but if they do, set it here.
> +                */
> +               if (variant->busy_dpsm_flag)
> +                       mmci_write_datactrlreg(host,
> +                                              host->variant->busy_dpsm_flag);
>                 mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
>                 mmc->max_busy_timeout = 0;
>         }
> diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
> index 7cabf270050b..56322c6afba4 100644
> --- a/drivers/mmc/host/mmci.h
> +++ b/drivers/mmc/host/mmci.h
> @@ -174,7 +174,7 @@
>  /* Extended status bits for the ST Micro variants */
>  #define MCI_ST_SDIOITMASK      (1 << 22)
>  #define MCI_ST_CEATAENDMASK    (1 << 23)
> -#define MCI_ST_BUSYEND         (1 << 24)
> +#define MCI_ST_BUSYENDMASK     (1 << 24)
>
>  #define MMCIMASK1              0x040
>  #define MMCIFIFOCNT            0x048
> --
> 2.7.4
>

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

end of thread, other threads:[~2016-11-07 12:43 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-10-25  9:06 [PATCH 1/3 v2] mmc: mmci: clean up header defines Linus Walleij
2016-10-25  9:06 ` [PATCH 2/3 v2] mmc: mmci: refactor ST Micro busy detection Linus Walleij
2016-11-07 12:43   ` Ulf Hansson
2016-10-25  9:06 ` [PATCH 3/3 v2] RFC: mmc: mmci: add qcom specific program end support Linus Walleij
2016-11-07 12:43 ` [PATCH 1/3 v2] mmc: mmci: clean up header defines Ulf Hansson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).