mmc: mxcmmc: add mpc512x SDHC support
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>
Signed-off-by: Chris Ball <cjb@laptop.org>
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index b82e37a..3f8d339 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 @@
.name = "imx31-mmc",
.driver_data = IMX31_MMC,
}, {
+ .name = "mpc512x-sdhc",
+ .driver_data = MPC512X_MMC,
+ }, {
/* sentinel */
}
};
@@ -185,6 +188,9 @@
.compatible = "fsl,imx31-mmc",
.data = &mxcmci_devtype[IMX31_MMC],
}, {
+ .compatible = "fsl,mpc5121-sdhc",
+ .data = &mxcmci_devtype[MPC512X_MMC],
+ }, {
/* sentinel */
}
};
@@ -195,6 +201,43 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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");