Skip to contentSkip to conversation

ARM: MXC: mxcmmc: misc cleanups

PATCH New Daniel Mack 3 participants 9 messages Apr 1, 2010 – Apr 14, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/3 ARM: MXC: mxcmmc: misc cleanups

Be more verbose on error messages and add one debug message.

Cc Sascha Hauer <[email protected]>
Cc Dan Williams <[email protected]>
Cc Volker Ernst <[email protected]>
Cc Jiri Kosina <[email protected]>
Cc Micha? Miros?aw <[email protected]>
---
 drivers/mmc/host/mxcmmc.c |   17 +++++++++++++----
 1 files changed, 13 insertions(+), 4 deletions(-)
drivers/mmc/host/mxcmmc.c +13 -4
index 2df9041..44a53ee 100644
@@ -151,6 +151,8 @@ static void mxcmci_softreset(struct mxcmci_host *host)
 {
 	int i;
 
+	dev_dbg(mmc_dev(host->mmc), "mxcmci_softreset\n");
+
 	/* reset sequence */
 	writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK);
 	writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
@@ -290,16 +292,25 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
 		dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",
 				stat);
 		if (stat & STATUS_CRC_READ_ERR) {
+			dev_err(mmc_dev(host->mmc), "%s: -EILSEQ\n", __func__);
 			data->error = -EILSEQ;
 		} else if (stat & STATUS_CRC_WRITE_ERR) {
 			u32 err_code = (stat >> 9) & 0x3;
-			if (err_code == 2) /* No CRC response */
+			if (err_code == 2) { /* No CRC response */
+				dev_err(mmc_dev(host->mmc),
+					"%s: No CRC -ETIMEDOUT\n", __func__);
 				data->error = -ETIMEDOUT;
-			else
+			} else {
+				dev_err(mmc_dev(host->mmc),
+					"%s: -EILSEQ\n", __func__);
 				data->error = -EILSEQ;
+			}
 		} else if (stat & STATUS_TIME_OUT_READ) {
+			dev_err(mmc_dev(host->mmc),
+				"%s: read -ETIMEDOUT\n", __func__);
 			data->error = -ETIMEDOUT;
 		} else {
+			dev_err(mmc_dev(host->mmc), "%s: -EIO\n", __func__);
 			data->error = -EIO;
 		}
 	} else {
@@ -433,8 +444,6 @@ static int mxcmci_transfer_data(struct mxcmci_host *host)
 	struct scatterlist *sg;
 	int stat, i;
 
-	host->datasize = 0;
-
 	host->data = data;
 	host->datasize = 0;
 
Signature · 1 line
1.7.0
#1 lore raw

PATCH 1/3 ARM: MXC: mxcmmc: misc cleanups

Is this series ok to go in?
Sascha, will this go thru your tree?

Thanks,
Daniel

Quoted 65 lines · Daniel Mack

Be more verbose on error messages and add one debug message.

Cc Sascha Hauer <[email protected]>
Cc Dan Williams <[email protected]>
Cc Volker Ernst <[email protected]>
Cc Jiri Kosina <[email protected]>
Cc Micha? Miros?aw <[email protected]>
---
 drivers/mmc/host/mxcmmc.c |   17 +++++++++++++----
 1 files changed, 13 insertions(+), 4 deletions(-)
drivers/mmc/host/mxcmmc.c +13 -4
index 2df9041..44a53ee 100644
@@ -151,6 +151,8 @@ static void mxcmci_softreset(struct mxcmci_host *host)
 {
 	int i;
 
+	dev_dbg(mmc_dev(host->mmc), "mxcmci_softreset\n");
+
 	/* reset sequence */
 	writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK);
 	writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
@@ -290,16 +292,25 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
 		dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",
 				stat);
 		if (stat & STATUS_CRC_READ_ERR) {
+			dev_err(mmc_dev(host->mmc), "%s: -EILSEQ\n", __func__);
 			data->error = -EILSEQ;
 		} else if (stat & STATUS_CRC_WRITE_ERR) {
 			u32 err_code = (stat >> 9) & 0x3;
-			if (err_code == 2) /* No CRC response */
+			if (err_code == 2) { /* No CRC response */
+				dev_err(mmc_dev(host->mmc),
+					"%s: No CRC -ETIMEDOUT\n", __func__);
 				data->error = -ETIMEDOUT;
-			else
+			} else {
+				dev_err(mmc_dev(host->mmc),
+					"%s: -EILSEQ\n", __func__);
 				data->error = -EILSEQ;
+			}
 		} else if (stat & STATUS_TIME_OUT_READ) {
+			dev_err(mmc_dev(host->mmc),
+				"%s: read -ETIMEDOUT\n", __func__);
 			data->error = -ETIMEDOUT;
 		} else {
+			dev_err(mmc_dev(host->mmc), "%s: -EIO\n", __func__);
 			data->error = -EIO;
 		}
 	} else {
@@ -433,8 +444,6 @@ static int mxcmci_transfer_data(struct mxcmci_host *host)
 	struct scatterlist *sg;
 	int stat, i;
 
-	host->datasize = 0;
-
 	host->data = data;
 	host->datasize = 0;
 
Signature · 1 line
1.7.0
maintainer
#2 lore raw

PATCH 1/3 ARM: MXC: mxcmmc: misc cleanups

Quoted 2 lines · Daniel Mack

Is this series ok to go in?
Sascha, will this go thru your tree?

Can do. One of your patches touches the generic SDIO layer. Can I have an acked-by from someone involved in it?

Sascha

Signature · 4 lines
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
#3 lore raw

PATCH 1/3 ARM: MXC: mxcmmc: misc cleanups

Quoted 6 lines · Sascha Hauer
Quoted 2 lines · Daniel Mack

Is this series ok to go in?
Sascha, will this go thru your tree?

Can do. One of your patches touches the generic SDIO layer. Can I have an acked-by from someone involved in it?

AFAIK, there is currently no active maintainer for that.

Daniel

#4 lore raw

PATCH 1/3 ARM: MXC: mxcmmc: misc cleanups

In reply to Sascha Hauer
Quoted 6 lines · Sascha Hauer
Quoted 2 lines · Daniel Mack

Is this series ok to go in?
Sascha, will this go thru your tree?

Can do. One of your patches touches the generic SDIO layer. Can I have an acked-by from someone involved in it?

I think you can get a Tested-by: from Volker Ernst and Andy Green and a Reviewed-by: from Micha? Miros?aw who was guiding me thru the locking bits. Can anyone give some thumbs-up, please?

Thanks,
Daniel

maintainer
#5 lore raw

PATCH 1/3 ARM: MXC: mxcmmc: misc cleanups

Quoted 11 lines · Daniel Mack
Quoted 6 lines · Sascha Hauer
Quoted 2 lines · Daniel Mack

Is this series ok to go in?
Sascha, will this go thru your tree?

Can do. One of your patches touches the generic SDIO layer. Can I have an acked-by from someone involved in it?

I think you can get a Tested-by: from Volker Ernst and Andy Green and a Reviewed-by: from Micha? Miros?aw who was guiding me thru the locking bits. Can anyone give some thumbs-up, please?

Ok, I think it's been enough time for someone to complain. Applied to mxc-master.

Sascha

Signature · 4 lines
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
#6 lore raw

PATCH 1/3 ARM: MXC: mxcmmc: misc cleanups

Quoted 8 lines · Sascha Hauer
Quoted 6 lines · Daniel Mack
Quoted 5 lines · Sascha Hauer
Quoted 2 lines · Daniel Mack

Is this series ok to go in?
Sascha, will this go thru your tree?

Can do. One of your patches touches the generic SDIO layer. Can I

have

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

an acked-by from someone involved in it?

I think you can get a Tested-by: from Volker Ernst and Andy Green and a Reviewed-by: from Micha? Miros?aw who was guiding me thru the locking bits. Can anyone give some thumbs-up, please?

Ok, I think it's been enough time for someone to complain. Applied to mxc-master.

Sorry I was travelling yesterday. The patch is definitely worth having.

We've been running a variation of this patch for several days, however not 100% the same since Volker has ported the iMX31 SDMA engine from the freescale tree for a few weeks now on our tree, and now has the SDIO working through SDMA (and a second channel with SD Card also on SDMA) FWIW.

We're not planning to do the work to get that into mainline but I think Daniel expressed an interest.

-Andy

#7 lore raw

PATCH 2/3 ARM: MXC: mxcmmc: Teach the driver SDIO operations

In reply to Daniel Mack

Successfully tested on MX31 hardware using libertas SDIO peripherals.

Cc Sascha Hauer <[email protected]>
Cc Dan Williams <[email protected]>
Cc Volker Ernst <[email protected]>
Cc Jiri Kosina <[email protected]>
Cc Micha? Miros?aw <[email protected]>
---
 drivers/mmc/host/mxcmmc.c |   70 +++++++++++++++++++++++++++++++++++++-------
 1 files changed, 59 insertions(+), 11 deletions(-)
drivers/mmc/host/mxcmmc.c +59 -11
index 44a53ee..51e880c 100644
@@ -119,6 +119,7 @@ struct mxcmci_host {
 	int			detect_irq;
 	int			dma;
 	int			do_dma;
+	int			use_sdio;
 	unsigned int		power_mode;
 	struct imxmmc_platform_data *pdata;
 
@@ -138,6 +139,7 @@ struct mxcmci_host {
 	int			clock;
 
 	struct work_struct	datawork;
+	spinlock_t		lock;
 };
 
 static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
@@ -226,6 +228,9 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
 static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
 		unsigned int cmdat)
 {
+	u32 int_cntr;
+	unsigned long flags;
+
 	WARN_ON(host->cmd != NULL);
 	host->cmd = cmd;
 
@@ -249,12 +254,16 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
 		return -EINVAL;
 	}
 
+	int_cntr = INT_END_CMD_RES_EN;
+
 	if (mxcmci_use_dma(host))
-		writel(INT_READ_OP_EN | INT_WRITE_OP_DONE_EN |
-				INT_END_CMD_RES_EN,
-				host->base + MMC_REG_INT_CNTR);
-	else
-		writel(INT_END_CMD_RES_EN, host->base + MMC_REG_INT_CNTR);
+		int_cntr |= INT_READ_OP_EN | INT_WRITE_OP_DONE_EN;
+
+	spin_lock_irqsave(&host->lock, flags);
+	if (host->use_sdio)
+		int_cntr |= INT_SDIO_IRQ_EN;
+	writel(int_cntr, host->base + MMC_REG_INT_CNTR);
+	spin_unlock_irqrestore(&host->lock, flags);
 
 	writew(cmd->opcode, host->base + MMC_REG_CMD);
 	writel(cmd->arg, host->base + MMC_REG_ARG);
@@ -266,7 +275,14 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
 static void mxcmci_finish_request(struct mxcmci_host *host,
 		struct mmc_request *req)
 {
-	writel(0, host->base + MMC_REG_INT_CNTR);
+	u32 int_cntr = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	if (host->use_sdio)
+		int_cntr |= INT_SDIO_IRQ_EN;
+	writel(int_cntr, host->base + MMC_REG_INT_CNTR);
+	spin_unlock_irqrestore(&host->lock, flags);
 
 	host->req = NULL;
 	host->cmd = NULL;
@@ -532,15 +548,27 @@ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
 static irqreturn_t mxcmci_irq(int irq, void *devid)
 {
 	struct mxcmci_host *host = devid;
+	unsigned long flags;
+	bool sdio_irq;
 	u32 stat;
 
 	stat = readl(host->base + MMC_REG_STATUS);
-	writel(stat, host->base + MMC_REG_STATUS);
+	writel(stat & ~STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS);
 
 	dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
 
+	spin_lock_irqsave(&host->lock, flags);
+	sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio;
+	spin_unlock_irqrestore(&host->lock, flags);
+
+	if (sdio_irq) {
+		writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS);
+		mmc_signal_sdio_irq(host->mmc);
+	}
+
 	if (stat & STATUS_END_CMD_RESP)
 		mxcmci_cmd_done(host, stat);
+
 #ifdef HAS_DMA
 	if (mxcmci_use_dma(host) &&
 		  (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE)))
@@ -677,11 +705,30 @@ static int mxcmci_get_ro(struct mmc_host *mmc)
 	return -ENOSYS;
 }
 
+static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+	struct mxcmci_host *host = mmc_priv(mmc);
+	unsigned long flags;
+	u32 int_cntr;
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->use_sdio = enable;
+	int_cntr = readl(host->base + MMC_REG_INT_CNTR);
+
+	if (enable)
+		int_cntr |= INT_SDIO_IRQ_EN;
+	else
+		int_cntr &= ~INT_SDIO_IRQ_EN;
+
+	writel(int_cntr, host->base + MMC_REG_INT_CNTR);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
 
 static const struct mmc_host_ops mxcmci_ops = {
-	.request	= mxcmci_request,
-	.set_ios	= mxcmci_set_ios,
-	.get_ro		= mxcmci_get_ro,
+	.request		= mxcmci_request,
+	.set_ios		= mxcmci_set_ios,
+	.get_ro			= mxcmci_get_ro,
+	.enable_sdio_irq	= mxcmci_enable_sdio_irq,
 };
 
 static int mxcmci_probe(struct platform_device *pdev)
@@ -709,7 +756,7 @@ static int mxcmci_probe(struct platform_device *pdev)
 	}
 
 	mmc->ops = &mxcmci_ops;
-	mmc->caps = MMC_CAP_4_BIT_DATA;
+	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 
 	/* MMC core transfer sizes tunable parameters */
 	mmc->max_hw_segs = 64;
@@ -728,6 +775,7 @@ static int mxcmci_probe(struct platform_device *pdev)
 
 	host->mmc = mmc;
 	host->pdata = pdev->dev.platform_data;
+	spin_lock_init(&host->lock);
 
 	if (host->pdata && host->pdata->ocr_avail)
 		mmc->ocr_avail = host->pdata->ocr_avail;
Signature · 1 line
1.7.0
#8 lore raw

PATCH 3/3 ARM: MXC: mxcmmc: work around a bug in the SDHC busy line handling

In reply to Daniel Mack

MX3 SoCs have a silicon bug which corrupts CRC calculation of multi-block transfers when connected SDIO peripheral doesn't drive the BUSY line as required by the specs.

One way to prevent this is to only allow 1-bit transfers.

Another way is playing tricks with the DMA engine, but this isn't mainline yet. So for now, we live with the performance drawback of 1-bit transfers until a nicer solution is found.

This patch introduces a new host controller callback 'init_card' which is for now only called from mmc_sdio_init_card().

Cc Sascha Hauer <[email protected]>
Cc Dan Williams <[email protected]>
Cc Volker Ernst <[email protected]>
Cc Jiri Kosina <[email protected]>
Cc Micha? Miros?aw <[email protected]>
---
 drivers/mmc/core/sdio.c   |    6 ++++++
 drivers/mmc/host/mxcmmc.c |   16 ++++++++++++++++
 include/linux/mmc/host.h  |    3 +++
 3 files changed, 25 insertions(+), 0 deletions(-)
drivers/mmc/core/sdio.c +6 -0
index 2dd4cfe..b9dee28 100644
@@ -296,6 +296,12 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
 	card->type = MMC_TYPE_SDIO;
 
 	/*
+	 * Call the optional HC's init_card function to handle quirks.
+	 */
+	if (host->ops->init_card)
+		host->ops->init_card(host, card);
+
+	/*
 	 * For native busses:  set card RCA and quit open drain mode.
 	 */
 	if (!powered_resume && !mmc_host_is_spi(host)) {
drivers/mmc/host/mxcmmc.c +16 -0
index 51e880c..2c53024 100644
@@ -724,11 +724,27 @@ static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
+static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card)
+{
+	/*
+	 * MX3 SoCs have a silicon bug which corrupts CRC calculation of
+	 * multi-block transfers when connected SDIO peripheral doesn't
+	 * drive the BUSY line as required by the specs.
+	 * One way to prevent this is to only allow 1-bit transfers.
+	 */
+
+	if (cpu_is_mx3() && card->type == MMC_TYPE_SDIO)
+		host->caps &= ~MMC_CAP_4_BIT_DATA;
+	else
+		host->caps |= MMC_CAP_4_BIT_DATA;
+}
+
 static const struct mmc_host_ops mxcmci_ops = {
 	.request		= mxcmci_request,
 	.set_ios		= mxcmci_set_ios,
 	.get_ro			= mxcmci_get_ro,
 	.enable_sdio_irq	= mxcmci_enable_sdio_irq,
+	.init_card		= mxcmci_init_card,
 };
 
 static int mxcmci_probe(struct platform_device *pdev)
include/linux/mmc/host.h +3 -0
index 43eaf5c..3196c84 100644
@@ -108,6 +108,9 @@ struct mmc_host_ops {
 	int	(*get_cd)(struct mmc_host *host);
 
 	void	(*enable_sdio_irq)(struct mmc_host *host, int enable);
+
+	/* optional callback for HC quirks */
+	void	(*init_card)(struct mmc_host *host, struct mmc_card *card);
 };
 
 struct mmc_card;
Signature · 1 line
1.7.0