devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/5] mmc: mxcmmc: add mpc512x support
@ 2013-04-08 21:28 Anatolij Gustschin
       [not found] ` <1365456489-13152-1-git-send-email-agust-ynQEQJNshbs@public.gmane.org>
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Anatolij Gustschin @ 2013-04-08 21:28 UTC (permalink / raw)
  To: linux-mmc, Chris Ball
  Cc: devicetree-discuss, Sascha Hauer, Markus Pargmann,
	Anatolij Gustschin

The SDHC controller on mpc512x is compatible with i.MX31 SDHC
controller, the existing MMC host driver can be used on
mpc512x with some modifications, the patch series extends
the existing driver. It is based on the following v3 mxcmmc DT
support patch:

   https://patchwork.kernel.org/patch/2368631

Changes in v3 series are mentioned in each patch

Anatolij Gustschin (5):
  mmc: mxcmmc: fix race conditions for host->req and host->data access
  mmc: mxcmmc: add mpc512x SDHC support
  mmc: mxcmmc: use slot-gpio API for write-protect detection
  mmc: mxcmmc: constify mxcmci_devtype
  mmc: mxcmmc: enable DMA support on mpc512x

 arch/powerpc/boot/dts/mpc5121.dtsi |    2 +
 drivers/mmc/host/Kconfig           |   10 +-
 drivers/mmc/host/mxcmmc.c          |  209 ++++++++++++++++++++++++++----------
 3 files changed, 159 insertions(+), 62 deletions(-)

-- 
1.7.5.4


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

* [PATCH v3 1/5] mmc: mxcmmc: fix race conditions for host->req and host->data access
       [not found] ` <1365456489-13152-1-git-send-email-agust-ynQEQJNshbs@public.gmane.org>
@ 2013-04-08 21:28   ` Anatolij Gustschin
  0 siblings, 0 replies; 7+ messages in thread
From: Anatolij Gustschin @ 2013-04-08 21:28 UTC (permalink / raw)
  To: linux-mmc-u79uwXL29TY76Z2rM5mHXA, Chris Ball
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ, Sascha Hauer

mxcmci_dma_callback() is invoked by DMA drivers in soft-irq
context and can be interrupted by the mxcmci_irq() interrupt
which can finish the mmc request or data transfer and set
host->req or host->data pointers to NULL. Then mxcmci_data_done()
crashes with a null pointer dereferences. Protect all accesses
to host->req and host->data by spin locks.

Also check host->data pointer in mxcmci_watchdog() before
dereferencing it.

Signed-off-by: Anatolij Gustschin <agust-ynQEQJNshbs@public.gmane.org>
Acked-by: Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
v3:
 - move to first patch in the series as asked by Sascha
 - add Acked-by

v2:
 - only rebased

 drivers/mmc/host/mxcmmc.c |   31 ++++++++++++++++++++++++-------
 1 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index ff9e496..8ae7cf5 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -623,24 +623,40 @@ static void mxcmci_datawork(struct work_struct *work)
 
 static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat)
 {
-	struct mmc_data *data = host->data;
+	struct mmc_request *req;
 	int data_error;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
 
-	if (!data)
+	if (!host->data) {
+		spin_unlock_irqrestore(&host->lock, flags);
 		return;
+	}
+
+	if (!host->req) {
+		spin_unlock_irqrestore(&host->lock, flags);
+		return;
+	}
+
+	req = host->req;
+	if (!req->stop)
+		host->req = NULL; /* we will handle finish req below */
 
 	data_error = mxcmci_finish_data(host, stat);
 
+	spin_unlock_irqrestore(&host->lock, flags);
+
 	mxcmci_read_response(host, stat);
 	host->cmd = NULL;
 
-	if (host->req->stop) {
-		if (mxcmci_start_cmd(host, host->req->stop, 0)) {
-			mxcmci_finish_request(host, host->req);
+	if (req->stop) {
+		if (mxcmci_start_cmd(host, req->stop, 0)) {
+			mxcmci_finish_request(host, req);
 			return;
 		}
 	} else {
-		mxcmci_finish_request(host, host->req);
+		mxcmci_finish_request(host, req);
 	}
 }
 
@@ -931,7 +947,8 @@ static void mxcmci_watchdog(unsigned long data)
 
 	/* Mark transfer as erroneus and inform the upper layers */
 
-	host->data->error = -ETIMEDOUT;
+	if (host->data)
+		host->data->error = -ETIMEDOUT;
 	host->req = NULL;
 	host->cmd = NULL;
 	host->data = NULL;
-- 
1.7.5.4

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

* [PATCH v3 2/5] mmc: mxcmmc: add mpc512x SDHC support
  2013-04-08 21:28 [PATCH v3 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin
       [not found] ` <1365456489-13152-1-git-send-email-agust-ynQEQJNshbs@public.gmane.org>
@ 2013-04-08 21:28 ` Anatolij Gustschin
  2013-04-08 21:28 ` [PATCH v3 3/5] mmc: mxcmmc: use slot-gpio API for write-protect detection Anatolij Gustschin
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Anatolij Gustschin @ 2013-04-08 21:28 UTC (permalink / raw)
  To: linux-mmc, Chris Ball
  Cc: devicetree-discuss, Sascha Hauer, Markus Pargmann,
	Anatolij Gustschin

The SDHC controller on mpc512x is compatible with i.MX31 SDHC,
so the mxcmmc driver can be used on mpc512x, too. Extend the
driver to support mpc512x as well.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
---
v3:
 - no changes, only add Acked-by tag

v2:
 - change to select register accessors at build time
   and use ioread32be() and iowrite32be() accessors
 - drop 512x specific clk_get() changes for now
 - rebase on top of v3 mxcmmc DT support patch from
   Markus https://patchwork.kernel.org/patch/2368631

 drivers/mmc/host/Kconfig  |   10 ++--
 drivers/mmc/host/mxcmmc.c |  133 ++++++++++++++++++++++++++++++---------------
 2 files changed, 94 insertions(+), 49 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index f83f245..9ab8f8d 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -320,12 +320,12 @@ config MMC_MSM
 	  support for SDIO devices.
 
 config MMC_MXC
-	tristate "Freescale i.MX21/27/31 Multimedia Card Interface support"
-	depends on ARCH_MXC
+	tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support"
+	depends on ARCH_MXC || PPC_MPC512x
 	help
-	  This selects the Freescale i.MX21, i.MX27 and i.MX31 Multimedia card
-	  Interface. If you have a i.MX platform with a Multimedia Card slot,
-	  say Y or M here.
+	  This selects the Freescale i.MX21, i.MX27, i.MX31 or MPC512x
+	  Multimedia Card Interface. If you have an i.MX or MPC512x platform
+	  with a Multimedia Card slot, say Y or M here.
 
 	  If unsure, say N.
 
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 8ae7cf5..9845b2d 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -41,7 +41,6 @@
 
 #include <asm/dma.h>
 #include <asm/irq.h>
-#include <asm/sizes.h>
 #include <linux/platform_data/mmc-mxcmmc.h>
 
 #include <linux/platform_data/dma-imx.h>
@@ -119,6 +118,7 @@
 enum mxcmci_type {
 	IMX21_MMC,
 	IMX31_MMC,
+	MPC512X_MMC,
 };
 
 struct mxcmci_host {
@@ -172,6 +172,9 @@ static struct platform_device_id mxcmci_devtype[] = {
 		.name = "imx31-mmc",
 		.driver_data = IMX31_MMC,
 	}, {
+		.name = "mpc512x-sdhc",
+		.driver_data = MPC512X_MMC,
+	}, {
 		/* sentinel */
 	}
 };
@@ -185,6 +188,9 @@ static const struct of_device_id mxcmci_of_match[] = {
 		.compatible = "fsl,imx31-mmc",
 		.data = &mxcmci_devtype[IMX31_MMC],
 	}, {
+		.compatible = "fsl,mpc5121-sdhc",
+		.data = &mxcmci_devtype[MPC512X_MMC],
+	}, {
 		/* sentinel */
 	}
 };
@@ -195,6 +201,43 @@ static inline int is_imx31_mmc(struct mxcmci_host *host)
 	return host->devtype == IMX31_MMC;
 }
 
+static inline int is_mpc512x_mmc(struct mxcmci_host *host)
+{
+	return host->devtype == MPC512X_MMC;
+}
+
+static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg)
+{
+	if (IS_ENABLED(CONFIG_PPC_MPC512x))
+		return ioread32be(host->base + reg);
+	else
+		return readl(host->base + reg);
+}
+
+static inline void mxcmci_writel(struct mxcmci_host *host, u32 val, int reg)
+{
+	if (IS_ENABLED(CONFIG_PPC_MPC512x))
+		iowrite32be(val, host->base + reg);
+	else
+		writel(val, host->base + reg);
+}
+
+static inline u16 mxcmci_readw(struct mxcmci_host *host, int reg)
+{
+	if (IS_ENABLED(CONFIG_PPC_MPC512x))
+		return ioread32be(host->base + reg);
+	else
+		return readw(host->base + reg);
+}
+
+static inline void mxcmci_writew(struct mxcmci_host *host, u16 val, int reg)
+{
+	if (IS_ENABLED(CONFIG_PPC_MPC512x))
+		iowrite32be(val, host->base + reg);
+	else
+		writew(val, host->base + reg);
+}
+
 static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
 
 static inline void mxcmci_init_ocr(struct mxcmci_host *host)
@@ -246,14 +289,14 @@ static void mxcmci_softreset(struct mxcmci_host *host)
 	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,
-			host->base + MMC_REG_STR_STP_CLK);
+	mxcmci_writew(host, STR_STP_CLK_RESET, MMC_REG_STR_STP_CLK);
+	mxcmci_writew(host, STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
+			MMC_REG_STR_STP_CLK);
 
 	for (i = 0; i < 8; i++)
-		writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
+		mxcmci_writew(host, STR_STP_CLK_START_CLK, MMC_REG_STR_STP_CLK);
 
-	writew(0xff, host->base + MMC_REG_RES_TO);
+	mxcmci_writew(host, 0xff, MMC_REG_RES_TO);
 }
 static int mxcmci_setup_dma(struct mmc_host *mmc);
 
@@ -272,8 +315,8 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
 	host->data = data;
 	data->bytes_xfered = 0;
 
-	writew(nob, host->base + MMC_REG_NOB);
-	writew(blksz, host->base + MMC_REG_BLK_LEN);
+	mxcmci_writew(host, nob, MMC_REG_NOB);
+	mxcmci_writew(host, blksz, MMC_REG_BLK_LEN);
 	host->datasize = datasize;
 
 	if (!mxcmci_use_dma(host))
@@ -329,13 +372,13 @@ static void mxcmci_dma_callback(void *data)
 
 	del_timer(&host->watchdog);
 
-	stat = readl(host->base + MMC_REG_STATUS);
-	writel(stat & ~STATUS_DATA_TRANS_DONE, host->base + MMC_REG_STATUS);
+	stat = mxcmci_readl(host, MMC_REG_STATUS);
+	mxcmci_writel(host, stat & ~STATUS_DATA_TRANS_DONE, MMC_REG_STATUS);
 
 	dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
 
 	if (stat & STATUS_READ_OP_DONE)
-		writel(STATUS_READ_OP_DONE, host->base + MMC_REG_STATUS);
+		mxcmci_writel(host, STATUS_READ_OP_DONE, MMC_REG_STATUS);
 
 	mxcmci_data_done(host, stat);
 }
@@ -383,12 +426,12 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
 	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);
+	mxcmci_writel(host, int_cntr, 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);
-	writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT);
+	mxcmci_writew(host, cmd->opcode, MMC_REG_CMD);
+	mxcmci_writel(host, cmd->arg, MMC_REG_ARG);
+	mxcmci_writew(host, cmdat, MMC_REG_CMD_DAT_CONT);
 
 	return 0;
 }
@@ -402,7 +445,7 @@ static void mxcmci_finish_request(struct mxcmci_host *host,
 	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);
+	mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR);
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	host->req = NULL;
@@ -477,14 +520,14 @@ static void mxcmci_read_response(struct mxcmci_host *host, unsigned int stat)
 	if (cmd->flags & MMC_RSP_PRESENT) {
 		if (cmd->flags & MMC_RSP_136) {
 			for (i = 0; i < 4; i++) {
-				a = readw(host->base + MMC_REG_RES_FIFO);
-				b = readw(host->base + MMC_REG_RES_FIFO);
+				a = mxcmci_readw(host, MMC_REG_RES_FIFO);
+				b = mxcmci_readw(host, MMC_REG_RES_FIFO);
 				cmd->resp[i] = a << 16 | b;
 			}
 		} else {
-			a = readw(host->base + MMC_REG_RES_FIFO);
-			b = readw(host->base + MMC_REG_RES_FIFO);
-			c = readw(host->base + MMC_REG_RES_FIFO);
+			a = mxcmci_readw(host, MMC_REG_RES_FIFO);
+			b = mxcmci_readw(host, MMC_REG_RES_FIFO);
+			c = mxcmci_readw(host, MMC_REG_RES_FIFO);
 			cmd->resp[0] = a << 24 | b << 8 | c >> 8;
 		}
 	}
@@ -496,7 +539,7 @@ static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)
 	unsigned long timeout = jiffies + HZ;
 
 	do {
-		stat = readl(host->base + MMC_REG_STATUS);
+		stat = mxcmci_readl(host, MMC_REG_STATUS);
 		if (stat & STATUS_ERR_MASK)
 			return stat;
 		if (time_after(jiffies, timeout)) {
@@ -520,7 +563,7 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
 				STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
 		if (stat)
 			return stat;
-		*buf++ = readl(host->base + MMC_REG_BUFFER_ACCESS);
+		*buf++ = cpu_to_le32(mxcmci_readl(host, MMC_REG_BUFFER_ACCESS));
 		bytes -= 4;
 	}
 
@@ -532,7 +575,7 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
 				STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
 		if (stat)
 			return stat;
-		tmp = readl(host->base + MMC_REG_BUFFER_ACCESS);
+		tmp = cpu_to_le32(mxcmci_readl(host, MMC_REG_BUFFER_ACCESS));
 		memcpy(b, &tmp, bytes);
 	}
 
@@ -548,7 +591,7 @@ static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
 		stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
 		if (stat)
 			return stat;
-		writel(*buf++, host->base + MMC_REG_BUFFER_ACCESS);
+		mxcmci_writel(host, cpu_to_le32(*buf++), MMC_REG_BUFFER_ACCESS);
 		bytes -= 4;
 	}
 
@@ -561,7 +604,7 @@ static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
 			return stat;
 
 		memcpy(&tmp, b, bytes);
-		writel(tmp, host->base + MMC_REG_BUFFER_ACCESS);
+		mxcmci_writel(host, cpu_to_le32(tmp), MMC_REG_BUFFER_ACCESS);
 	}
 
 	stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
@@ -607,8 +650,8 @@ static void mxcmci_datawork(struct work_struct *work)
 						  datawork);
 	int datastat = mxcmci_transfer_data(host);
 
-	writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
-		host->base + MMC_REG_STATUS);
+	mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
+		MMC_REG_STATUS);
 	mxcmci_finish_data(host, datastat);
 
 	if (host->req->stop) {
@@ -686,9 +729,11 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
 	bool sdio_irq;
 	u32 stat;
 
-	stat = readl(host->base + MMC_REG_STATUS);
-	writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE |
-			STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS);
+	stat = mxcmci_readl(host, MMC_REG_STATUS);
+	mxcmci_writel(host,
+		stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE |
+			 STATUS_WRITE_OP_DONE),
+		MMC_REG_STATUS);
 
 	dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
 
@@ -698,11 +743,11 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
 
 	if (mxcmci_use_dma(host) &&
 	    (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE)))
-		writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
-			host->base + MMC_REG_STATUS);
+		mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
+			MMC_REG_STATUS);
 
 	if (sdio_irq) {
-		writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS);
+		mxcmci_writel(host, STATUS_SDIO_INT_ACTIVE, MMC_REG_STATUS);
 		mmc_signal_sdio_irq(host->mmc);
 	}
 
@@ -784,7 +829,7 @@ static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios)
 			prescaler <<= 1;
 	}
 
-	writew((prescaler << 4) | divider, host->base + MMC_REG_CLK_RATE);
+	mxcmci_writew(host, (prescaler << 4) | divider, MMC_REG_CLK_RATE);
 
 	dev_dbg(mmc_dev(host->mmc), "scaler: %d divider: %d in: %d out: %d\n",
 			prescaler, divider, clk_in, clk_ios);
@@ -847,9 +892,9 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
 	if (ios->clock) {
 		mxcmci_set_clk_rate(host, ios->clock);
-		writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
+		mxcmci_writew(host, STR_STP_CLK_START_CLK, MMC_REG_STR_STP_CLK);
 	} else {
-		writew(STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK);
+		mxcmci_writew(host, STR_STP_CLK_STOP_CLK, MMC_REG_STR_STP_CLK);
 	}
 
 	host->clock = ios->clock;
@@ -886,14 +931,14 @@ static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 
 	spin_lock_irqsave(&host->lock, flags);
 	host->use_sdio = enable;
-	int_cntr = readl(host->base + MMC_REG_INT_CNTR);
+	int_cntr = mxcmci_readl(host, 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);
+	mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR);
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -931,7 +976,7 @@ static void mxcmci_watchdog(unsigned long data)
 	struct mmc_host *mmc = (struct mmc_host *)data;
 	struct mxcmci_host *host = mmc_priv(mmc);
 	struct mmc_request *req = host->req;
-	unsigned int stat = readl(host->base + MMC_REG_STATUS);
+	unsigned int stat = mxcmci_readl(host, MMC_REG_STATUS);
 
 	if (host->dma_dir == DMA_FROM_DEVICE) {
 		dmaengine_terminate_all(host->dma);
@@ -974,7 +1019,7 @@ static int mxcmci_probe(struct platform_device *pdev)
 	const struct of_device_id *of_id;
 	struct imxmmc_platform_data *pdata = pdev->dev.platform_data;
 
-	pr_info("i.MX SDHC driver\n");
+	pr_info("i.MX/MPC512x SDHC driver\n");
 
 	of_id = of_match_device(mxcmci_of_match, &pdev->dev);
 
@@ -1060,7 +1105,7 @@ static int mxcmci_probe(struct platform_device *pdev)
 
 	mxcmci_softreset(host);
 
-	host->rev_no = readw(host->base + MMC_REG_REV_NO);
+	host->rev_no = mxcmci_readw(host, MMC_REG_REV_NO);
 	if (host->rev_no != 0x400) {
 		ret = -ENODEV;
 		dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
@@ -1072,9 +1117,9 @@ static int mxcmci_probe(struct platform_device *pdev)
 	mmc->f_max = clk_get_rate(host->clk_per) >> 1;
 
 	/* recommended in data sheet */
-	writew(0x2db4, host->base + MMC_REG_READ_TO);
+	mxcmci_writew(host, 0x2db4, MMC_REG_READ_TO);
 
-	writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR);
+	mxcmci_writel(host, host->default_irq_mask, MMC_REG_INT_CNTR);
 
 	if (!host->pdata) {
 		host->dma = dma_request_slave_channel(&pdev->dev, "rx-tx");
-- 
1.7.5.4


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

* [PATCH v3 3/5] mmc: mxcmmc: use slot-gpio API for write-protect detection
  2013-04-08 21:28 [PATCH v3 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin
       [not found] ` <1365456489-13152-1-git-send-email-agust-ynQEQJNshbs@public.gmane.org>
  2013-04-08 21:28 ` [PATCH v3 2/5] mmc: mxcmmc: add mpc512x SDHC support Anatolij Gustschin
@ 2013-04-08 21:28 ` Anatolij Gustschin
  2013-04-08 21:28 ` [PATCH v3 4/5] mmc: mxcmmc: constify mxcmci_devtype Anatolij Gustschin
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Anatolij Gustschin @ 2013-04-08 21:28 UTC (permalink / raw)
  To: linux-mmc, Chris Ball
  Cc: devicetree-discuss, Sascha Hauer, Markus Pargmann,
	Anatolij Gustschin

slot-gpio API suppors read-only detection when "wp-gpios"
property is present in the device tree mmc node. Use this
API for write-protect detection.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
---
v3:
 - add Acked-by line

v2:
 - no changes

 drivers/mmc/host/mxcmmc.c |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 9845b2d..eb45bf0 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -38,6 +38,7 @@
 #include <linux/of_device.h>
 #include <linux/of_dma.h>
 #include <linux/of_gpio.h>
+#include <linux/mmc/slot-gpio.h>
 
 #include <asm/dma.h>
 #include <asm/irq.h>
@@ -917,10 +918,11 @@ static int mxcmci_get_ro(struct mmc_host *mmc)
 	if (host->pdata && host->pdata->get_ro)
 		return !!host->pdata->get_ro(mmc_dev(mmc));
 	/*
-	 * Board doesn't support read only detection; let the mmc core
-	 * decide what to do.
+	 * If board doesn't support read only detection (no mmc_gpio
+	 * context or gpio is invalid), then let the mmc core decide
+	 * what to do.
 	 */
-	return -ENOSYS;
+	return mmc_gpio_get_ro(mmc);
 }
 
 static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-- 
1.7.5.4


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

* [PATCH v3 4/5] mmc: mxcmmc: constify mxcmci_devtype
  2013-04-08 21:28 [PATCH v3 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin
                   ` (2 preceding siblings ...)
  2013-04-08 21:28 ` [PATCH v3 3/5] mmc: mxcmmc: use slot-gpio API for write-protect detection Anatolij Gustschin
@ 2013-04-08 21:28 ` Anatolij Gustschin
  2013-04-08 21:28 ` [PATCH v3 5/5] mmc: mxcmmc: enable DMA support on mpc512x Anatolij Gustschin
  2013-04-12 19:14 ` [PATCH v3 0/5] mmc: mxcmmc: add mpc512x support Chris Ball
  5 siblings, 0 replies; 7+ messages in thread
From: Anatolij Gustschin @ 2013-04-08 21:28 UTC (permalink / raw)
  To: linux-mmc, Chris Ball
  Cc: devicetree-discuss, Sascha Hauer, Markus Pargmann,
	Anatolij Gustschin

mxcmci_devtype struct contains constant data, so
constify this struct.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
---
v3:
 - add Acked-by line

v2:
 - remove build warning fix (already fixed elsewhere) and
   change commit log

 drivers/mmc/host/mxcmmc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index eb45bf0..9b01acb 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -165,7 +165,7 @@ struct mxcmci_host {
 	enum mxcmci_type	devtype;
 };
 
-static struct platform_device_id mxcmci_devtype[] = {
+static const struct platform_device_id mxcmci_devtype[] = {
 	{
 		.name = "imx21-mmc",
 		.driver_data = IMX21_MMC,
-- 
1.7.5.4


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

* [PATCH v3 5/5] mmc: mxcmmc: enable DMA support on mpc512x
  2013-04-08 21:28 [PATCH v3 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin
                   ` (3 preceding siblings ...)
  2013-04-08 21:28 ` [PATCH v3 4/5] mmc: mxcmmc: constify mxcmci_devtype Anatolij Gustschin
@ 2013-04-08 21:28 ` Anatolij Gustschin
  2013-04-12 19:14 ` [PATCH v3 0/5] mmc: mxcmmc: add mpc512x support Chris Ball
  5 siblings, 0 replies; 7+ messages in thread
From: Anatolij Gustschin @ 2013-04-08 21:28 UTC (permalink / raw)
  To: linux-mmc, Chris Ball
  Cc: devicetree-discuss, Sascha Hauer, Markus Pargmann,
	Anatolij Gustschin

Add SDHC DMA channel description to the mpc512x device
tree to enable slave channel requesting in the mxcmmc
driver.

mpc512x DMA engine doesn't support endianness conversion
when reading/writing data from peripheral's FIFO, so we
have to swap data buffers before each DMA write and after
each DMA read transfer manually.

Since chained SDHC DMA transfers are not supported on
mpc512x, limit 'max_segs' tunable parameter to one and
initialise it to 64 only when running on i.MX platforms.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
---
v3:
 - change swapping function name to mxcmci_swap_buffers()
 - add Acked-by line

v2:
 - only rebased

 arch/powerpc/boot/dts/mpc5121.dtsi |    2 ++
 drivers/mmc/host/mxcmmc.c          |   35 +++++++++++++++++++++++++++++++++--
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
index 723e292..710aae6 100644
--- a/arch/powerpc/boot/dts/mpc5121.dtsi
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -152,6 +152,8 @@
 			compatible = "fsl,mpc5121-sdhc";
 			reg = <0x1500 0x100>;
 			interrupts = <8 0x8>;
+			dmas = <&dma0 30>;
+			dma-names = "rx-tx";
 		};
 
 		i2c@1700 {
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 9b01acb..b937407 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -301,6 +301,29 @@ static void mxcmci_softreset(struct mxcmci_host *host)
 }
 static int mxcmci_setup_dma(struct mmc_host *mmc);
 
+#if IS_ENABLED(CONFIG_PPC_MPC512x)
+static inline void buffer_swap32(u32 *buf, int len)
+{
+	int i;
+
+	for (i = 0; i < ((len + 3) / 4); i++) {
+		st_le32(buf, *buf);
+		buf++;
+	}
+}
+
+static void mxcmci_swap_buffers(struct mmc_data *data)
+{
+	struct scatterlist *sg;
+	int i;
+
+	for_each_sg(data->sg, sg, data->sg_len, i)
+		buffer_swap32(sg_virt(sg), sg->length);
+}
+#else
+static inline void mxcmci_swap_buffers(struct mmc_data *data) {}
+#endif
+
 static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
 {
 	unsigned int nob = data->blocks;
@@ -336,6 +359,8 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
 	} else {
 		host->dma_dir = DMA_TO_DEVICE;
 		slave_dirn = DMA_MEM_TO_DEV;
+
+		mxcmci_swap_buffers(data);
 	}
 
 	nents = dma_map_sg(host->dma->device->dev, data->sg,
@@ -461,9 +486,11 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
 	struct mmc_data *data = host->data;
 	int data_error;
 
-	if (mxcmci_use_dma(host))
+	if (mxcmci_use_dma(host)) {
 		dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len,
 				host->dma_dir);
+		mxcmci_swap_buffers(data);
+	}
 
 	if (stat & STATUS_ERR_MASK) {
 		dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",
@@ -1050,7 +1077,6 @@ static int mxcmci_probe(struct platform_device *pdev)
 		mmc->caps |= MMC_CAP_SDIO_IRQ;
 
 	/* MMC core transfer sizes tunable parameters */
-	mmc->max_segs = 64;
 	mmc->max_blk_size = 2048;
 	mmc->max_blk_count = 65535;
 	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
@@ -1069,6 +1095,11 @@ static int mxcmci_probe(struct platform_device *pdev)
 	} else {
 		host->devtype = pdev->id_entry->driver_data;
 	}
+
+	/* adjust max_segs after devtype detection */
+	if (!is_mpc512x_mmc(host))
+		mmc->max_segs = 64;
+
 	host->mmc = mmc;
 	host->pdata = pdata;
 	spin_lock_init(&host->lock);
-- 
1.7.5.4


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

* Re: [PATCH v3 0/5] mmc: mxcmmc: add mpc512x support
  2013-04-08 21:28 [PATCH v3 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin
                   ` (4 preceding siblings ...)
  2013-04-08 21:28 ` [PATCH v3 5/5] mmc: mxcmmc: enable DMA support on mpc512x Anatolij Gustschin
@ 2013-04-12 19:14 ` Chris Ball
  5 siblings, 0 replies; 7+ messages in thread
From: Chris Ball @ 2013-04-12 19:14 UTC (permalink / raw)
  To: Anatolij Gustschin
  Cc: linux-mmc, devicetree-discuss, Sascha Hauer, Markus Pargmann

Hi,

On Mon, Apr 08 2013, Anatolij Gustschin wrote:
> The SDHC controller on mpc512x is compatible with i.MX31 SDHC
> controller, the existing MMC host driver can be used on
> mpc512x with some modifications, the patch series extends
> the existing driver. It is based on the following v3 mxcmmc DT
> support patch:
>
>    https://patchwork.kernel.org/patch/2368631
>
> Changes in v3 series are mentioned in each patch
>
> Anatolij Gustschin (5):
>   mmc: mxcmmc: fix race conditions for host->req and host->data access
>   mmc: mxcmmc: add mpc512x SDHC support
>   mmc: mxcmmc: use slot-gpio API for write-protect detection
>   mmc: mxcmmc: constify mxcmci_devtype
>   mmc: mxcmmc: enable DMA support on mpc512x
>
>  arch/powerpc/boot/dts/mpc5121.dtsi |    2 +
>  drivers/mmc/host/Kconfig           |   10 +-
>  drivers/mmc/host/mxcmmc.c          |  209 ++++++++++++++++++++++++++----------
>  3 files changed, 159 insertions(+), 62 deletions(-)

Thanks, all pushed to mmc-next for 3.10.

- Chris.
-- 
Chris Ball   <cjb@laptop.org>   <http://printf.net/>
One Laptop Per Child

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

end of thread, other threads:[~2013-04-12 19:14 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-08 21:28 [PATCH v3 0/5] mmc: mxcmmc: add mpc512x support Anatolij Gustschin
     [not found] ` <1365456489-13152-1-git-send-email-agust-ynQEQJNshbs@public.gmane.org>
2013-04-08 21:28   ` [PATCH v3 1/5] mmc: mxcmmc: fix race conditions for host->req and host->data access Anatolij Gustschin
2013-04-08 21:28 ` [PATCH v3 2/5] mmc: mxcmmc: add mpc512x SDHC support Anatolij Gustschin
2013-04-08 21:28 ` [PATCH v3 3/5] mmc: mxcmmc: use slot-gpio API for write-protect detection Anatolij Gustschin
2013-04-08 21:28 ` [PATCH v3 4/5] mmc: mxcmmc: constify mxcmci_devtype Anatolij Gustschin
2013-04-08 21:28 ` [PATCH v3 5/5] mmc: mxcmmc: enable DMA support on mpc512x Anatolij Gustschin
2013-04-12 19:14 ` [PATCH v3 0/5] mmc: mxcmmc: add mpc512x support Chris Ball

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).