summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2021-06-16 10:54:37 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-06-16 10:54:37 +0200
commit0e062b8296a22afff4157f56c5b6b64e7fac5aac (patch)
tree7cfca330bec0f26799b8a5142c9a880b215ae9b6 /drivers
parentbdc5a5d220edf8c8a2685f9f3f066798f521f9e8 (diff)
parent0868df7d44538298fcf9a037916d7a4ae9bc3b48 (diff)
downloadbarebox-0e062b8296a22afff4157f56c5b6b64e7fac5aac.tar.gz
barebox-0e062b8296a22afff4157f56c5b6b64e7fac5aac.tar.xz
Merge branch 'for-next/mmc'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mci/Kconfig7
-rw-r--r--drivers/mci/Makefile1
-rw-r--r--drivers/mci/arasan-sdhci.c208
-rw-r--r--drivers/mci/atmel-sdhci-common.c75
-rw-r--r--drivers/mci/dove-sdhci.c84
-rw-r--r--drivers/mci/dw_mmc.c53
-rw-r--r--drivers/mci/imx-esdhc-common.c109
-rw-r--r--drivers/mci/imx-esdhc-pbl.c22
-rw-r--r--drivers/mci/imx-esdhc.c20
-rw-r--r--drivers/mci/imx-esdhc.h8
-rw-r--r--drivers/mci/mci-bcm2835.c2
-rw-r--r--drivers/mci/mci-core.c4
-rw-r--r--drivers/mci/rockchip-dwcmshc-sdhci.c377
-rw-r--r--drivers/mci/sdhci.c399
-rw-r--r--drivers/mci/sdhci.h168
15 files changed, 1097 insertions, 440 deletions
diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index 7d4e72138d..e1fcd41271 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -79,6 +79,13 @@ config MCI_MXS
Enable this entry to add support to read and write SD cards on a
i.MX23/i.MX28 based system.
+config MCI_ROCKCHIP_DWCMSHC
+ bool "MCI sdhc support for Rockchip SoCs"
+ select MCI_SDHCI
+ help
+ Enable this entry to add support for a Rockchip derivation of the
+ DWCMSHC controller found on some Rockchip SoCs like the RK3568.
+
config MCI_S3C
bool "S3C"
depends on ARCH_S3C24xx
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index 60dc100c37..b113b1c732 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_MCI_MXS) += mxs.o
obj-$(CONFIG_MCI_OMAP_HSMMC) += omap_hsmmc.o
obj-$(CONFIG_MCI_PXA) += pxamci.o
obj-$(CONFIG_MCI_S3C) += s3c.o
+obj-$(CONFIG_MCI_ROCKCHIP_DWCMSHC) += rockchip-dwcmshc-sdhci.o
obj-$(CONFIG_MCI_TEGRA) += tegra-sdmmc.o
obj-$(CONFIG_MCI_SPI) += mci_spi.o
obj-$(CONFIG_MCI_DW) += dw_mmc.o
diff --git a/drivers/mci/arasan-sdhci.c b/drivers/mci/arasan-sdhci.c
index 520bf30ff9..d45f9184cd 100644
--- a/drivers/mci/arasan-sdhci.c
+++ b/drivers/mci/arasan-sdhci.c
@@ -12,20 +12,20 @@
#define SDHCI_ARASAN_HCAP_CLK_FREQ_MASK 0xFF00
#define SDHCI_ARASAN_HCAP_CLK_FREQ_SHIFT 8
#define SDHCI_INT_ADMAE BIT(29)
-#define SDHCI_ARASAN_INT_DATA_MASK SDHCI_INT_XFER_COMPLETE | \
+#define SDHCI_ARASAN_INT_DATA_MASK (SDHCI_INT_XFER_COMPLETE | \
SDHCI_INT_DMA | \
SDHCI_INT_SPACE_AVAIL | \
SDHCI_INT_DATA_AVAIL | \
SDHCI_INT_DATA_TIMEOUT | \
SDHCI_INT_DATA_CRC | \
SDHCI_INT_DATA_END_BIT | \
- SDHCI_INT_ADMAE
+ SDHCI_INT_ADMAE)
-#define SDHCI_ARASAN_INT_CMD_MASK SDHCI_INT_CMD_COMPLETE | \
+#define SDHCI_ARASAN_INT_CMD_MASK (SDHCI_INT_CMD_COMPLETE | \
SDHCI_INT_TIMEOUT | \
SDHCI_INT_CRC | \
SDHCI_INT_END_BIT | \
- SDHCI_INT_INDEX
+ SDHCI_INT_INDEX)
#define SDHCI_ARASAN_BUS_WIDTH 4
#define TIMEOUT_VAL 0xE
@@ -33,14 +33,12 @@
struct arasan_sdhci_host {
struct mci_host mci;
struct sdhci sdhci;
- void __iomem *ioaddr;
unsigned int quirks; /* Arasan deviations from spec */
/* Controller does not have CD wired and will not function normally without */
#define SDHCI_ARASAN_QUIRK_FORCE_CDTEST BIT(0)
#define SDHCI_ARASAN_QUIRK_NO_1_8_V BIT(1)
};
-
static inline
struct arasan_sdhci_host *to_arasan_sdhci_host(struct mci_host *mci)
{
@@ -53,60 +51,24 @@ struct arasan_sdhci_host *sdhci_to_arasan(struct sdhci *sdhci)
return container_of(sdhci, struct arasan_sdhci_host, sdhci);
}
-static void arasan_sdhci_writel(struct sdhci *sdhci, int reg, u32 val)
-{
- struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
- writel(val, p->ioaddr + reg);
-}
-
-static void arasan_sdhci_writew(struct sdhci *sdhci, int reg, u16 val)
-{
- struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
- writew(val, p->ioaddr + reg);
-}
-
-static void arasan_sdhci_writeb(struct sdhci *sdhci, int reg, u8 val)
-{
- struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
- writeb(val, p->ioaddr + reg);
-}
-
-static u32 arasan_sdhci_readl(struct sdhci *sdhci, int reg)
-{
- struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
- return readl(p->ioaddr + reg);
-}
-
-static u16 arasan_sdhci_readw(struct sdhci *sdhci, int reg)
-{
- struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
- return readw(p->ioaddr + reg);
-}
-
-static u8 arasan_sdhci_readb(struct sdhci *sdhci, int reg)
-{
- struct arasan_sdhci_host *p = sdhci_to_arasan(sdhci);
-
- return readb(p->ioaddr + reg);
-}
-
static int arasan_sdhci_card_present(struct mci_host *mci)
{
struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci);
+ u32 val;
+
+ val = sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE);
- return !!(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_CARD_DETECT);
+ return !!(val & SDHCI_CARD_DETECT);
}
static int arasan_sdhci_card_write_protected(struct mci_host *mci)
{
struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci);
+ u32 val;
- return !(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_WRITE_PROTECT);
+ val = sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE);
+
+ return !(val & SDHCI_WRITE_PROTECT);
}
static int arasan_sdhci_reset(struct arasan_sdhci_host *host, u8 mask)
@@ -115,7 +77,7 @@ static int arasan_sdhci_reset(struct arasan_sdhci_host *host, u8 mask)
/* wait for reset completion */
if (wait_on_timeout(100 * MSECOND,
- !(sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & mask))){
+ !(sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & mask))) {
dev_err(host->mci.hw_dev, "SDHCI reset timeout\n");
return -ETIMEDOUT;
}
@@ -124,7 +86,7 @@ static int arasan_sdhci_reset(struct arasan_sdhci_host *host, u8 mask)
u8 ctrl;
ctrl = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL);
- ctrl |= SDHCI_CARD_DETECT_TEST_LEVEL | SDHCI_CARD_DETECT_SIGNAL_SELECTION;
+ ctrl |= SDHCI_CTRL_CDTEST_INS | SDHCI_CTRL_CDTEST_INS;
sdhci_write8(&host->sdhci, ctrl, SDHCI_HOST_CONTROL);
}
@@ -141,82 +103,32 @@ static int arasan_sdhci_init(struct mci_host *mci, struct device_d *dev)
return ret;
sdhci_write8(&host->sdhci, SDHCI_POWER_CONTROL,
- SDHCI_BUS_VOLTAGE_330 | SDHCI_BUS_POWER_EN);
+ SDHCI_BUS_VOLTAGE_330 | SDHCI_BUS_POWER_EN);
udelay(400);
sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE,
- SDHCI_ARASAN_INT_DATA_MASK |
- SDHCI_ARASAN_INT_CMD_MASK);
- sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, 0x00);
+ SDHCI_ARASAN_INT_DATA_MASK | SDHCI_ARASAN_INT_CMD_MASK);
+ sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, 0);
return 0;
}
-#define SDHCI_MAX_DIV_SPEC_300 2046
-
-static u16 arasan_sdhci_get_clock_divider(struct arasan_sdhci_host *host,
- unsigned int reqclk)
-{
- u16 div;
-
- for (div = 1; div < SDHCI_MAX_DIV_SPEC_300; div += 2)
- if ((host->mci.f_max / div) <= reqclk)
- break;
- div /= 2;
-
- return div;
-}
-
-#define SDHCI_FREQ_SEL_10_BIT(x) (((x) & 0x300) >> 2)
-
static void arasan_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
{
struct arasan_sdhci_host *host = to_arasan_sdhci_host(mci);
u16 val;
- /* stop clock */
- sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0);
-
- if (ios->clock) {
- u64 start;
-
- /* set & start clock */
- val = arasan_sdhci_get_clock_divider(host, ios->clock);
- /* Bit 6 & 7 are upperbits of 10bit divider */
- val = SDHCI_FREQ_SEL(val) | SDHCI_FREQ_SEL_10_BIT(val);
- val |= SDHCI_INTCLOCK_EN;
- sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val);
-
- start = get_time_ns();
- while (!(sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL) &
- SDHCI_INTCLOCK_STABLE)) {
- if (is_timeout(start, 20 * MSECOND)) {
- dev_err(host->mci.hw_dev,
- "SDHCI clock stable timeout\n");
- return;
- }
- }
- /* enable bus clock */
- sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL,
- val | SDHCI_SDCLOCK_EN);
- }
+ if (ios->clock)
+ sdhci_set_clock(&host->sdhci, ios->clock, host->sdhci.max_clk);
- val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
- ~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
+ sdhci_set_bus_width(&host->sdhci, ios->bus_width);
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_8:
- val |= SDHCI_DATA_WIDTH_8BIT;
- break;
- case MMC_BUS_WIDTH_4:
- val |= SDHCI_DATA_WIDTH_4BIT;
- break;
- }
+ val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL);
if (ios->clock > 26000000)
- val |= SDHCI_HIGHSPEED_EN;
+ val |= SDHCI_CTRL_HISPD;
else
- val &= ~SDHCI_HIGHSPEED_EN;
+ val &= ~SDHCI_CTRL_HISPD;
sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
}
@@ -225,18 +137,21 @@ static int arasan_sdhci_wait_for_done(struct arasan_sdhci_host *host, u32 mask)
{
u64 start = get_time_ns();
u16 stat;
+ u16 error;
do {
stat = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS);
if (stat & SDHCI_INT_ERROR) {
+ error = sdhci_read16(&host->sdhci,
+ SDHCI_INT_ERROR_STATUS);
dev_err(host->mci.hw_dev, "SDHCI_INT_ERROR: 0x%08x\n",
- sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS));
+ error);
return -EPERM;
}
if (is_timeout(start, 1000 * MSECOND)) {
dev_err(host->mci.hw_dev,
- "SDHCI timeout while waiting for done\n");
+ "SDHCI timeout while waiting for done\n");
return -ETIMEDOUT;
}
} while ((stat & mask) != mask);
@@ -247,7 +162,7 @@ static int arasan_sdhci_wait_for_done(struct arasan_sdhci_host *host, u32 mask)
static void print_error(struct arasan_sdhci_host *host, int cmdidx)
{
dev_err(host->mci.hw_dev,
- "error while transfering data for command %d\n", cmdidx);
+ "error while transferring data for command %d\n", cmdidx);
dev_err(host->mci.hw_dev, "state = 0x%08x , interrupt = 0x%08x\n",
sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE),
sdhci_read32(&host->sdhci, SDHCI_INT_NORMAL_STATUS));
@@ -266,27 +181,31 @@ static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
mask |= SDHCI_CMD_INHIBIT_DATA;
ret = wait_on_timeout(10 * MSECOND,
- !(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & mask));
-
+ !(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & mask));
if (ret) {
dev_err(host->mci.hw_dev,
- "SDHCI timeout while waiting for idle\n");
+ "SDHCI timeout while waiting for idle\n");
return ret;
}
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
mask = SDHCI_INT_CMD_COMPLETE;
- if (data)
+ if (data && data->flags == MMC_DATA_READ)
mask |= SDHCI_INT_DATA_AVAIL;
+ if (cmd->resp_type & MMC_RSP_BUSY)
+ mask |= SDHCI_INT_XFER_COMPLETE;
- sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data, false, &command, &xfer);
+ sdhci_set_cmd_xfer_mode(&host->sdhci,
+ cmd, data, false, &command, &xfer);
sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, TIMEOUT_VAL);
- sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer);
- sdhci_write16(&host->sdhci, SDHCI_BLOCK_SIZE, SDHCI_DMA_BOUNDARY_512K |
- SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize));
- sdhci_write16(&host->sdhci, SDHCI_BLOCK_COUNT, data->blocks);
+ if (data) {
+ sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer);
+ sdhci_write16(&host->sdhci, SDHCI_BLOCK_SIZE,
+ SDHCI_DMA_BOUNDARY_512K | SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize));
+ sdhci_write16(&host->sdhci, SDHCI_BLOCK_COUNT, data->blocks);
+ }
sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
@@ -300,7 +219,7 @@ static int arasan_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, mask);
if (data)
- ret = sdhci_transfer_data(&host->sdhci, data);
+ ret = sdhci_transfer_data_pio(&host->sdhci, data);
error:
if (ret) {
@@ -310,33 +229,8 @@ error:
}
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
- return ret;
-}
-
-
-static void arasan_sdhci_set_mci_caps(struct arasan_sdhci_host *host)
-{
- u16 caps = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES_1);
-
- if ((caps & SDHCI_HOSTCAP_VOLTAGE_180) &&
- !(host->quirks & SDHCI_ARASAN_QUIRK_NO_1_8_V))
- host->mci.voltages |= MMC_VDD_165_195;
- if (caps & SDHCI_HOSTCAP_VOLTAGE_300)
- host->mci.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
- if (caps & SDHCI_HOSTCAP_VOLTAGE_330)
- host->mci.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
- if (caps & SDHCI_HOSTCAP_HIGHSPEED)
- host->mci.host_caps |= (MMC_CAP_MMC_HIGHSPEED_52MHZ |
- MMC_CAP_MMC_HIGHSPEED |
- MMC_CAP_SD_HIGHSPEED);
-
- /* parse board supported bus width capabilities */
- mci_of_parse(&host->mci);
-
- /* limit bus widths to controller capabilities */
- if (!(caps & SDHCI_HOSTCAP_8BIT))
- host->mci.host_caps &= ~MMC_CAP_8_BIT_DATA;
+ return ret;
}
static int arasan_sdhci_probe(struct device_d *dev)
@@ -355,7 +249,6 @@ static int arasan_sdhci_probe(struct device_d *dev)
iores = dev_request_mem_resource(dev, 0);
if (IS_ERR(iores))
return PTR_ERR(iores);
- arasan_sdhci->ioaddr = IOMEM(iores->start);
clk_ahb = clk_get(dev, "clk_ahb");
if (IS_ERR(clk_ahb)) {
@@ -387,12 +280,8 @@ static int arasan_sdhci_probe(struct device_d *dev)
if (of_property_read_bool(np, "no-1-8-v"))
arasan_sdhci->quirks |= SDHCI_ARASAN_QUIRK_NO_1_8_V;
- arasan_sdhci->sdhci.read32 = arasan_sdhci_readl;
- arasan_sdhci->sdhci.read16 = arasan_sdhci_readw;
- arasan_sdhci->sdhci.read8 = arasan_sdhci_readb;
- arasan_sdhci->sdhci.write32 = arasan_sdhci_writel;
- arasan_sdhci->sdhci.write16 = arasan_sdhci_writew;
- arasan_sdhci->sdhci.write8 = arasan_sdhci_writeb;
+ arasan_sdhci->sdhci.base = IOMEM(iores->start);
+ arasan_sdhci->sdhci.mci = mci;
mci->send_cmd = arasan_sdhci_send_cmd;
mci->set_ios = arasan_sdhci_set_ios;
mci->init = arasan_sdhci_init;
@@ -403,7 +292,10 @@ static int arasan_sdhci_probe(struct device_d *dev)
mci->f_max = clk_get_rate(clk_xin);
mci->f_min = 50000000 / 256;
- arasan_sdhci_set_mci_caps(arasan_sdhci);
+ /* parse board supported bus width capabilities */
+ mci_of_parse(&arasan_sdhci->mci);
+
+ sdhci_setup_host(&arasan_sdhci->sdhci);
dev->priv = arasan_sdhci;
diff --git a/drivers/mci/atmel-sdhci-common.c b/drivers/mci/atmel-sdhci-common.c
index a83610c3d0..eff2a993db 100644
--- a/drivers/mci/atmel-sdhci-common.c
+++ b/drivers/mci/atmel-sdhci-common.c
@@ -11,6 +11,7 @@
#include <common.h>
#include <mci.h>
+#include <linux/bitfield.h>
#include <mach/early_udelay.h>
@@ -24,8 +25,6 @@
#include "atmel-sdhci.h"
-#define AT91_SDHCI_CA1R 0x44 /* Capabilities 1 Register */
-
#define AT91_SDHCI_MC1R 0x204
#define AT91_SDHCI_MC1_FCD BIT(7)
#define AT91_SDHCI_CALCR 0x240
@@ -42,13 +41,13 @@ void at91_sdhci_host_capability(struct at91_sdhci *host,
{
u16 caps;
- caps = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES_1);
+ caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
- if (caps & SDHCI_HOSTCAP_VOLTAGE_330)
+ if (caps & SDHCI_CAN_VDD_330)
*voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
- if (caps & SDHCI_HOSTCAP_VOLTAGE_300)
+ if (caps & SDHCI_CAN_VDD_300)
*voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
- if (caps & SDHCI_HOSTCAP_VOLTAGE_180)
+ if (caps & SDHCI_CAN_VDD_180)
*voltages |= MMC_VDD_165_195;
}
@@ -167,7 +166,7 @@ int at91_sdhci_send_command(struct at91_sdhci *host, struct mci_cmd *cmd,
sdhci_write32(sdhci, SDHCI_INT_STATUS, mask);
if (data)
- sdhci_transfer_data(sdhci, data);
+ sdhci_transfer_data_pio(sdhci, data);
udelay(1000);
@@ -237,9 +236,9 @@ static int at91_sdhci_set_clock(struct at91_sdhci *host, unsigned clock)
if (clock == 0)
return 0;
- caps = sdhci_read32(sdhci, AT91_SDHCI_CA1R);
+ caps = sdhci_read32(sdhci, SDHCI_CAPABILITIES_1);
- caps_clk_mult = (caps & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT;
+ caps_clk_mult = FIELD_GET(SDHCI_CLOCK_MUL_MASK, caps);
if (caps_clk_mult) {
for (clk_div = 1; clk_div <= 1024; clk_div++) {
@@ -264,26 +263,26 @@ static int at91_sdhci_set_clock(struct at91_sdhci *host, unsigned clock)
clk |= SDHCI_FREQ_SEL(clk_div);
clk |= ((clk_div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
<< SDHCI_DIVIDER_HI_SHIFT;
- clk |= SDHCI_INTCLOCK_EN;
+ clk |= SDHCI_CLOCK_INT_EN;
sdhci_write16(sdhci, SDHCI_CLOCK_CONTROL, clk);
ret = sdhci_read32_poll_timeout(sdhci, SDHCI_CLOCK_CONTROL, clk,
- clk & SDHCI_INTCLOCK_STABLE,
+ clk & SDHCI_CLOCK_INT_STABLE,
20 * USEC_PER_MSEC);
if (ret) {
dev_warn(host->dev, "Timeout waiting for clock stable\n");
return ret;
}
- clk |= SDHCI_SDCLOCK_EN;
+ clk |= SDHCI_CLOCK_CARD_EN;
sdhci_write16(sdhci, SDHCI_CLOCK_CONTROL, clk);
reg = sdhci_read8(sdhci, SDHCI_HOST_CONTROL);
if (clock > 26000000)
- reg |= SDHCI_HIGHSPEED_EN;
+ reg |= SDHCI_CTRL_HISPD;
else
- reg &= ~SDHCI_HIGHSPEED_EN;
+ reg &= ~SDHCI_CTRL_HISPD;
sdhci_write8(sdhci, SDHCI_HOST_CONTROL, reg);
@@ -299,15 +298,15 @@ static int at91_sdhci_set_bus_width(struct at91_sdhci *host, unsigned bus_width)
switch(bus_width) {
case MMC_BUS_WIDTH_8:
- reg |= SDHCI_DATA_WIDTH_8BIT;
+ reg |= SDHCI_CTRL_8BITBUS;
break;
case MMC_BUS_WIDTH_4:
- reg &= ~SDHCI_DATA_WIDTH_8BIT;
- reg |= SDHCI_DATA_WIDTH_4BIT;
+ reg &= ~SDHCI_CTRL_8BITBUS;
+ reg |= SDHCI_CTRL_8BITBUS;
break;
default:
- reg &= ~SDHCI_DATA_WIDTH_8BIT;
- reg &= ~SDHCI_DATA_WIDTH_4BIT;
+ reg &= ~SDHCI_CTRL_8BITBUS;
+ reg &= ~SDHCI_CTRL_8BITBUS;
}
sdhci_write8(sdhci, SDHCI_HOST_CONTROL, reg);
@@ -379,43 +378,7 @@ int at91_sdhci_init(struct at91_sdhci *host, u32 maxclk,
return 0;
}
-static u32 at91_sdhci_read32(struct sdhci *sdhci, int reg)
-{
- return readl(to_priv(sdhci)->base + reg);
-}
-
-static void at91_sdhci_write32(struct sdhci *sdhci, int reg, u32 value)
-{
- writel(value, to_priv(sdhci)->base + reg);
-}
-
-static u16 at91_sdhci_read16(struct sdhci *sdhci, int reg)
-{
- return readw(to_priv(sdhci)->base + reg);
-}
-
-static void at91_sdhci_write16(struct sdhci *sdhci, int reg, u16 value)
-{
- writew(value, to_priv(sdhci)->base + reg);
-}
-
-static u8 at91_sdhci_read8(struct sdhci *sdhci, int reg)
-{
- return readb(to_priv(sdhci)->base + reg);
-}
-
-static void at91_sdhci_write8(struct sdhci *sdhci, int reg, u8 value)
-{
- writeb(value, to_priv(sdhci)->base + reg);
-}
-
void at91_sdhci_mmio_init(struct at91_sdhci *host, void __iomem *base)
{
- host->base = base;
- host->sdhci.read8 = at91_sdhci_read8;
- host->sdhci.read16 = at91_sdhci_read16;
- host->sdhci.read32 = at91_sdhci_read32;
- host->sdhci.write8 = at91_sdhci_write8;
- host->sdhci.write16 = at91_sdhci_write16;
- host->sdhci.write32 = at91_sdhci_write32;
+ host->sdhci.base = base;
}
diff --git a/drivers/mci/dove-sdhci.c b/drivers/mci/dove-sdhci.c
index c734a6e0dd..e6ac769bde 100644
--- a/drivers/mci/dove-sdhci.c
+++ b/drivers/mci/dove-sdhci.c
@@ -20,55 +20,12 @@
struct dove_sdhci {
struct mci_host mci;
- void __iomem *base;
struct sdhci sdhci;
};
#define priv_from_mci_host(h) \
container_of(h, struct dove_sdhci, mci);
-static void dove_sdhci_writel(struct sdhci *sdhci, int reg, u32 val)
-{
- struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
- writel(val, p->base + reg);
-}
-
-static void dove_sdhci_writew(struct sdhci *sdhci, int reg, u16 val)
-{
- struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
- writew(val, p->base + reg);
-}
-
-static void dove_sdhci_writeb(struct sdhci *sdhci, int reg, u8 val)
-{
- struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
- writeb(val, p->base + reg);
-}
-
-static u32 dove_sdhci_readl(struct sdhci *sdhci, int reg)
-{
- struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
- return readl(p->base + reg);
-}
-
-static u16 dove_sdhci_readw(struct sdhci *sdhci, int reg)
-{
- struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
- return readw(p->base + reg);
-}
-
-static u8 dove_sdhci_readb(struct sdhci *sdhci, int reg)
-{
- struct dove_sdhci *p = container_of(sdhci, struct dove_sdhci, sdhci);
-
- return readb(p->base + reg);
-}
-
static int dove_sdhci_wait_for_done(struct dove_sdhci *host, u16 mask)
{
u16 status;
@@ -197,7 +154,7 @@ static u16 dove_sdhci_get_clock_divider(struct dove_sdhci *host, u32 reqclk)
{
u16 div;
- for (div = 1; div < SDHCI_SPEC_200_MAX_CLK_DIVIDER; div *= 2)
+ for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2)
if ((host->mci.f_max / div) <= reqclk)
break;
div /= 2;
@@ -224,33 +181,33 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
/* set bus width */
val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL) &
- ~(SDHCI_DATA_WIDTH_4BIT | SDHCI_DATA_WIDTH_8BIT);
+ ~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_8BITBUS);
switch (ios->bus_width) {
case MMC_BUS_WIDTH_8:
- val |= SDHCI_DATA_WIDTH_8BIT;
+ val |= SDHCI_CTRL_8BITBUS;
break;
case MMC_BUS_WIDTH_4:
- val |= SDHCI_DATA_WIDTH_4BIT;
+ val |= SDHCI_CTRL_8BITBUS;
break;
}
if (ios->clock > 26000000)
- val |= SDHCI_HIGHSPEED_EN;
+ val |= SDHCI_CTRL_HISPD;
else
- val &= ~SDHCI_HIGHSPEED_EN;
+ val &= ~SDHCI_CTRL_HISPD;
sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
/* set bus clock */
sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0);
val = dove_sdhci_get_clock_divider(host, ios->clock);
- val = SDHCI_INTCLOCK_EN | SDHCI_FREQ_SEL(val);
+ val = SDHCI_CLOCK_INT_EN | SDHCI_FREQ_SEL(val);
sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val);
/* wait for internal clock stable */
start = get_time_ns();
while (!(sdhci_read16(&host->sdhci, SDHCI_CLOCK_CONTROL) &
- SDHCI_INTCLOCK_STABLE)) {
+ SDHCI_CLOCK_INT_STABLE)) {
if (is_timeout(start, 20 * MSECOND)) {
dev_err(host->mci.hw_dev, "SDHCI clock stable timeout\n");
return;
@@ -258,7 +215,7 @@ static void dove_sdhci_mci_set_ios(struct mci_host *mci, struct mci_ios *ios)
}
/* enable bus clock */
- sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val | SDHCI_SDCLOCK_EN);
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, val | SDHCI_CLOCK_CARD_EN);
}
static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev)
@@ -290,19 +247,18 @@ static int dove_sdhci_mci_init(struct mci_host *mci, struct device_d *dev)
static void dove_sdhci_set_mci_caps(struct dove_sdhci *host)
{
- u16 caps[2];
+ u32 caps;
- caps[0] = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES);
- caps[1] = sdhci_read16(&host->sdhci, SDHCI_CAPABILITIES_1);
+ caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
- if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_180)
+ if (caps & SDHCI_CAN_VDD_180)
host->mci.voltages |= MMC_VDD_165_195;
- if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_300)
+ if (caps & SDHCI_CAN_VDD_300)
host->mci.voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
- if (caps[1] & SDHCI_HOSTCAP_VOLTAGE_330)
+ if (caps & SDHCI_CAN_VDD_330)
host->mci.voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
- if (caps[1] & SDHCI_HOSTCAP_HIGHSPEED)
+ if (caps & SDHCI_CAN_DO_HISPD)
host->mci.host_caps |= (MMC_CAP_MMC_HIGHSPEED_52MHZ |
MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_SD_HIGHSPEED);
@@ -311,7 +267,7 @@ static void dove_sdhci_set_mci_caps(struct dove_sdhci *host)
mci_of_parse(&host->mci);
/* limit bus widths to controller capabilities */
- if ((caps[1] & SDHCI_HOSTCAP_8BIT) == 0)
+ if ((caps & SDHCI_CAN_DO_8BIT) == 0)
host->mci.host_caps &= ~MMC_CAP_8_BIT_DATA;
}
@@ -321,7 +277,7 @@ static int dove_sdhci_probe(struct device_d *dev)
int ret;
host = xzalloc(sizeof(*host));
- host->base = dev_request_mem_region(dev, 0);
+ host->sdhci.base = dev_request_mem_region(dev, 0);
host->mci.max_req_size = 0x8000;
host->mci.hw_dev = dev;
host->mci.send_cmd = dove_sdhci_mci_send_cmd;
@@ -329,12 +285,6 @@ static int dove_sdhci_probe(struct device_d *dev)
host->mci.init = dove_sdhci_mci_init;
host->mci.f_max = 50000000;
host->mci.f_min = host->mci.f_max / 256;
- host->sdhci.read32 = dove_sdhci_readl;
- host->sdhci.read16 = dove_sdhci_readw;
- host->sdhci.read8 = dove_sdhci_readb;
- host->sdhci.write32 = dove_sdhci_writel;
- host->sdhci.write16 = dove_sdhci_writew;
- host->sdhci.write8 = dove_sdhci_writeb;
dove_sdhci_set_mci_caps(host);
diff --git a/drivers/mci/dw_mmc.c b/drivers/mci/dw_mmc.c
index 7979568841..930b538adc 100644
--- a/drivers/mci/dw_mmc.c
+++ b/drivers/mci/dw_mmc.c
@@ -25,6 +25,7 @@
struct dwmci_host {
struct mci_host mci;
+ struct device_d *dev;
struct clk *clk_biu, *clk_ciu;
void *ioaddr;
unsigned int fifo_size_bytes;
@@ -34,6 +35,7 @@ struct dwmci_host {
int ciu_div;
u32 fifoth_val;
u32 pwren_value;
+ dma_addr_t idmac_dma;
};
struct dwmci_idmac {
@@ -110,12 +112,12 @@ static int dwmci_prepare_data_pio(struct dwmci_host *host,
}
static int dwmci_prepare_data_dma(struct dwmci_host *host,
- struct mci_data *data)
+ struct mci_data *data, dma_addr_t dma)
{
unsigned long ctrl;
unsigned int i = 0, flags, cnt, blk_cnt;
- unsigned start_addr;
struct dwmci_idmac *desc = host->idmac;
+ dma_addr_t desc_dma = host->idmac_dma;
blk_cnt = data->blocks;
@@ -124,12 +126,7 @@ static int dwmci_prepare_data_dma(struct dwmci_host *host,
dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET);
- dwmci_writel(host, DWMCI_DBADDR, (uint32_t)desc);
-
- if (data->flags & MMC_DATA_READ)
- start_addr = (uint32_t)data->dest;
- else
- start_addr = (uint32_t)data->src;
+ dwmci_writel(host, DWMCI_DBADDR, desc_dma);
do {
flags = DWMCI_IDMAC_OWN | DWMCI_IDMAC_CH;
@@ -142,10 +139,12 @@ static int dwmci_prepare_data_dma(struct dwmci_host *host,
cnt = data->blocksize * 8;
}
+ desc_dma += sizeof(*desc);
+
desc->flags = flags;
desc->cnt = cnt;
- desc->addr = start_addr + (i * PAGE_SIZE);
- desc->next_addr = (uint32_t)(desc + 1);
+ desc->addr = dma + (i * PAGE_SIZE);
+ desc->next_addr = desc_dma;
dev_dbg(host->mci.hw_dev, "desc@ 0x%p 0x%08x 0x%08x 0x%08x 0x%08x\n",
desc, flags, cnt, desc->addr, desc->next_addr);
@@ -172,12 +171,12 @@ static int dwmci_prepare_data_dma(struct dwmci_host *host,
}
static int dwmci_prepare_data(struct dwmci_host *host,
- struct mci_data *data)
+ struct mci_data *data, dma_addr_t dma)
{
if (dwmci_use_pio(host))
return dwmci_prepare_data_pio(host, data);
else
- return dwmci_prepare_data_dma(host, data);
+ return dwmci_prepare_data_dma(host, data, dma);
}
static int dwmci_set_transfer_mode(struct dwmci_host *host,
@@ -272,6 +271,7 @@ dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
uint64_t start;
int ret;
unsigned int num_bytes = 0;
+ dma_addr_t dma = 0;
start = get_time_ns();
while (1) {
@@ -287,16 +287,20 @@ dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_ALL);
if (data) {
+
num_bytes = data->blocks * data->blocksize;
if (data->flags & MMC_DATA_WRITE)
- dma_sync_single_for_device((unsigned long)data->src,
- num_bytes, DMA_TO_DEVICE);
+ dma = dma_map_single(host->dev, (void *)data->src, num_bytes,
+ DMA_TO_DEVICE);
else
- dma_sync_single_for_device((unsigned long)data->dest,
- num_bytes, DMA_FROM_DEVICE);
+ dma = dma_map_single(host->dev, data->dest, num_bytes,
+ DMA_FROM_DEVICE);
- ret = dwmci_prepare_data(host, data);
+ if (dma_mapping_error(host->dev, dma))
+ return -EFAULT;
+
+ ret = dwmci_prepare_data(host, data, dma);
if (ret)
return ret;
}
@@ -400,11 +404,11 @@ dwmci_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
dwmci_writel(host, DWMCI_CTRL, ctrl);
if (data->flags & MMC_DATA_WRITE)
- dma_sync_single_for_cpu((unsigned long)data->src,
- num_bytes, DMA_TO_DEVICE);
+ dma_unmap_single(host->dev, dma, num_bytes,
+ DMA_TO_DEVICE);
else
- dma_sync_single_for_cpu((unsigned long)data->dest,
- num_bytes, DMA_FROM_DEVICE);
+ dma_unmap_single(host->dev, dma, num_bytes,
+ DMA_FROM_DEVICE);
}
}
@@ -550,6 +554,9 @@ static int dw_mmc_probe(struct device_d *dev)
host = xzalloc(sizeof(*host));
+ dma_set_mask(dev, DMA_BIT_MASK(32));
+ host->dev = dev;
+
host->clk_biu = clk_get(dev, "biu");
if (IS_ERR(host->clk_biu))
return PTR_ERR(host->clk_biu);
@@ -567,7 +574,9 @@ static int dw_mmc_probe(struct device_d *dev)
host->ioaddr = IOMEM(iores->start);
host->idmac = dma_alloc_coherent(sizeof(*host->idmac) * DW_MMC_NUM_IDMACS,
- DMA_ADDRESS_BROKEN);
+ &host->idmac_dma);
+ if (!host->idmac)
+ return -ENOMEM;
host->mci.send_cmd = dwmci_cmd;
host->mci.set_ios = dwmci_set_ios;
diff --git a/drivers/mci/imx-esdhc-common.c b/drivers/mci/imx-esdhc-common.c
index 7ee0674b99..77d7e4d478 100644
--- a/drivers/mci/imx-esdhc-common.c
+++ b/drivers/mci/imx-esdhc-common.c
@@ -10,48 +10,41 @@
#define PRSSTAT_DAT0 0x01000000
-struct fsl_esdhc_dma_transfer {
- dma_addr_t dma;
- unsigned int size;
- enum dma_data_direction dir;
-};
-
-static u32 esdhc_op_read32_le(struct sdhci *sdhci, int reg)
+static u32 esdhc_op_read32_be(struct sdhci *sdhci, int reg)
{
struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
- return readl(host->regs + reg);
+ return in_be32(host->sdhci.base + reg);
}
-static u32 esdhc_op_read32_be(struct sdhci *sdhci, int reg)
+static void esdhc_op_write32_be(struct sdhci *sdhci, int reg, u32 val)
{
struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
- return in_be32(host->regs + reg);
+ out_be32(host->sdhci.base + reg, val);
}
-static void esdhc_op_write32_le(struct sdhci *sdhci, int reg, u32 val)
+static u16 esdhc_op_read16_be(struct sdhci *sdhci, int reg)
{
struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
- writel(val, host->regs + reg);
+ return in_be16(host->sdhci.base + reg);
}
-static void esdhc_op_write32_be(struct sdhci *sdhci, int reg, u32 val)
+static void esdhc_op_write16_be(struct sdhci *sdhci, int reg, u16 val)
{
struct fsl_esdhc_host *host = sdhci_to_esdhc(sdhci);
- out_be32(host->regs + reg, val);
+ out_be16(host->sdhci.base + reg, val);
}
void esdhc_populate_sdhci(struct fsl_esdhc_host *host)
{
if (host->socdata->flags & ESDHC_FLAG_BIGENDIAN) {
+ host->sdhci.read16 = esdhc_op_read16_be;
+ host->sdhci.write16 = esdhc_op_write16_be;
host->sdhci.read32 = esdhc_op_read32_be;
host->sdhci.write32 = esdhc_op_write32_be;
- } else {
- host->sdhci.read32 = esdhc_op_read32_le;
- host->sdhci.write32 = esdhc_op_write32_le;
}
}
@@ -59,71 +52,33 @@ static bool esdhc_use_pio_mode(void)
{
return IN_PBL || IS_ENABLED(CONFIG_MCI_IMX_ESDHC_PIO);
}
+
static int esdhc_setup_data(struct fsl_esdhc_host *host, struct mci_data *data,
- struct fsl_esdhc_dma_transfer *tr)
+ dma_addr_t *dma)
{
u32 wml_value;
- void *ptr;
-
- if (!esdhc_use_pio_mode()) {
- wml_value = data->blocksize/4;
-
- if (data->flags & MMC_DATA_READ) {
- if (wml_value > 0x10)
- wml_value = 0x10;
-
- esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value);
- } else {
- if (wml_value > 0x80)
- wml_value = 0x80;
-
- esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_WR_WML_MASK,
- wml_value << 16);
- }
-
- tr->size = data->blocks * data->blocksize;
- if (data->flags & MMC_DATA_WRITE) {
- ptr = (void *)data->src;
- tr->dir = DMA_TO_DEVICE;
- } else {
- ptr = data->dest;
- tr->dir = DMA_FROM_DEVICE;
- }
+ wml_value = data->blocksize / 4;
- tr->dma = dma_map_single(host->dev, ptr, tr->size, tr->dir);
- if (dma_mapping_error(host->dev, tr->dma))
- return -EFAULT;
+ if (data->flags & MMC_DATA_READ) {
+ if (wml_value > 0x10)
+ wml_value = 0x10;
+ esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_RD_WML_MASK, wml_value);
+ } else {
+ if (wml_value > 0x80)
+ wml_value = 0x80;
- sdhci_write32(&host->sdhci, SDHCI_DMA_ADDRESS, tr->dma);
+ esdhc_clrsetbits32(host, IMX_SDHCI_WML, WML_WR_WML_MASK,
+ wml_value << 16);
}
- sdhci_write32(&host->sdhci, SDHCI_BLOCK_SIZE__BLOCK_COUNT, data->blocks << 16 | data->blocksize);
-
- return 0;
-}
-
-static int esdhc_do_data(struct fsl_esdhc_host *host, struct mci_data *data,
- struct fsl_esdhc_dma_transfer *tr)
-{
- u32 irqstat;
+ host->sdhci.sdma_boundary = 0;
if (esdhc_use_pio_mode())
- return sdhci_transfer_data(&host->sdhci, data);
-
- do {
- irqstat = sdhci_read32(&host->sdhci, SDHCI_INT_STATUS);
-
- if (irqstat & DATA_ERR)
- return -EIO;
-
- if (irqstat & SDHCI_INT_DATA_TIMEOUT)
- return -ETIMEDOUT;
- } while (!(irqstat & SDHCI_INT_XFER_COMPLETE) &&
- (sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_DATA_LINE_ACTIVE));
-
- dma_unmap_single(host->dev, tr->dma, tr->size, tr->dir);
+ sdhci_setup_data_pio(&host->sdhci, data);
+ else
+ sdhci_setup_data_dma(&host->sdhci, data, dma);
return 0;
}
@@ -175,7 +130,7 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
{
u32 xfertyp, mixctrl, command;
u32 irqstat;
- struct fsl_esdhc_dma_transfer tr = { 0 };
+ dma_addr_t dma = SDHCI_NO_DMA;
int ret;
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, -1);
@@ -185,13 +140,13 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
/* Set up for a data transfer if we have one */
if (data) {
- ret = esdhc_setup_data(host, data, &tr);
+ ret = esdhc_setup_data(host, data, &dma);
if (ret)
return ret;
}
sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data,
- !esdhc_use_pio_mode(), &command, &xfertyp);
+ dma != SDHCI_NO_DMA, &command, &xfertyp);
if ((host->socdata->flags & ESDHC_FLAG_MULTIBLK_NO_INT) &&
(cmd->cmdidx == MMC_CMD_STOP_TRANSMISSION))
@@ -248,7 +203,11 @@ int __esdhc_send_cmd(struct fsl_esdhc_host *host, struct mci_cmd *cmd,
/* Wait until all of the blocks are transferred */
if (data) {
- ret = esdhc_do_data(host, data, &tr);
+ if (esdhc_use_pio_mode())
+ ret = sdhci_transfer_data_pio(&host->sdhci, data);
+ else
+ ret = sdhci_transfer_data_dma(&host->sdhci, data, dma);
+
if (ret)
return ret;
}
diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c
index c3a8b377e2..d7136f5492 100644
--- a/drivers/mci/imx-esdhc-pbl.c
+++ b/drivers/mci/imx-esdhc-pbl.c
@@ -200,14 +200,14 @@ static int imx8m_esdhc_init(struct fsl_esdhc_host *host,
{
switch (instance) {
case 0:
- host->regs = IOMEM(MX8M_USDHC1_BASE_ADDR);
+ host->sdhci.base = IOMEM(MX8M_USDHC1_BASE_ADDR);
break;
case 1:
- host->regs = IOMEM(MX8M_USDHC2_BASE_ADDR);
+ host->sdhci.base = IOMEM(MX8M_USDHC2_BASE_ADDR);
break;
case 2:
/* Only exists on i.MX8MM, not on i.MX8MQ */
- host->regs = IOMEM(MX8MM_USDHC3_BASE_ADDR);
+ host->sdhci.base = IOMEM(MX8MM_USDHC3_BASE_ADDR);
break;
default:
return -EINVAL;
@@ -237,16 +237,16 @@ int imx6_esdhc_start_image(int instance)
switch (instance) {
case 0:
- host.regs = IOMEM(MX6_USDHC1_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX6_USDHC1_BASE_ADDR);
break;
case 1:
- host.regs = IOMEM(MX6_USDHC2_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX6_USDHC2_BASE_ADDR);
break;
case 2:
- host.regs = IOMEM(MX6_USDHC3_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX6_USDHC3_BASE_ADDR);
break;
case 3:
- host.regs = IOMEM(MX6_USDHC4_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX6_USDHC4_BASE_ADDR);
break;
default:
return -EINVAL;
@@ -276,13 +276,13 @@ int imx7_esdhc_start_image(int instance)
switch (instance) {
case 0:
- host.regs = IOMEM(MX7_USDHC1_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX7_USDHC1_BASE_ADDR);
break;
case 1:
- host.regs = IOMEM(MX7_USDHC2_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX7_USDHC2_BASE_ADDR);
break;
case 2:
- host.regs = IOMEM(MX7_USDHC3_BASE_ADDR);
+ host.sdhci.base = IOMEM(MX7_USDHC3_BASE_ADDR);
break;
default:
return -EINVAL;
@@ -375,7 +375,7 @@ int ls1046a_esdhc_start_image(unsigned long r0, unsigned long r1, unsigned long
.flags = ESDHC_FLAG_BIGENDIAN,
};
struct fsl_esdhc_host host = {
- .regs = IOMEM(0x01560000),
+ .sdhci.base = IOMEM(0x01560000),
.socdata = &data,
};
unsigned long sdram = 0x80000000;
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index 93f3c57d4e..5a664ce4c3 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -230,7 +230,6 @@ static int fsl_esdhc_probe(struct device_d *dev)
struct resource *iores;
struct fsl_esdhc_host *host;
struct mci_host *mci;
- u32 caps;
int ret;
unsigned long rate;
struct esdhc_platform_data *pdata = dev->platform_data;
@@ -265,33 +264,26 @@ static int fsl_esdhc_probe(struct device_d *dev)
ret = PTR_ERR(iores);
goto err_clk_disable;
}
- host->regs = IOMEM(iores->start);
+ host->sdhci.base = IOMEM(iores->start);
esdhc_populate_sdhci(host);
- caps = sdhci_read32(&host->sdhci, SDHCI_CAPABILITIES);
-
- if (caps & ESDHC_HOSTCAPBLT_VS18)
- mci->voltages |= MMC_VDD_165_195;
- if (caps & ESDHC_HOSTCAPBLT_VS30)
- mci->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
- if (caps & ESDHC_HOSTCAPBLT_VS33)
- mci->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
-
if (pdata) {
mci->host_caps = pdata->caps;
if (pdata->devname)
mci->devname = pdata->devname;
}
- if (caps & ESDHC_HOSTCAPBLT_HSS)
- mci->host_caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
-
host->mci.send_cmd = esdhc_send_cmd;
host->mci.set_ios = esdhc_set_ios;
host->mci.init = esdhc_init;
host->mci.card_present = esdhc_card_present;
host->mci.hw_dev = dev;
+ host->sdhci.mci = &host->mci;
+
+ ret = sdhci_setup_host(&host->sdhci);
+ if (ret)
+ goto err_clk_disable;
rate = clk_get_rate(host->clk);
host->mci.f_min = rate >> 12;
diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h
index 8abe1207d7..f1685eac06 100644
--- a/drivers/mci/imx-esdhc.h
+++ b/drivers/mci/imx-esdhc.h
@@ -37,13 +37,6 @@
#define BLKATTR_SIZE(x) (x & 0x1fff)
#define MAX_BLK_CNT 0x7fff /* so malloc will have enough room with 32M */
-#define ESDHC_HOSTCAPBLT_VS18 0x04000000
-#define ESDHC_HOSTCAPBLT_VS30 0x02000000
-#define ESDHC_HOSTCAPBLT_VS33 0x01000000
-#define ESDHC_HOSTCAPBLT_SRS 0x00800000
-#define ESDHC_HOSTCAPBLT_DMAS 0x00400000
-#define ESDHC_HOSTCAPBLT_HSS 0x00200000
-
#define PIO_TIMEOUT 100000
#define IMX_SDHCI_WML 0x44
@@ -108,7 +101,6 @@ struct fsl_esdhc_host {
struct mci_host mci;
struct clk *clk;
struct device_d *dev;
- void __iomem *regs;
const struct esdhc_soc_data *socdata;
struct sdhci sdhci;
};
diff --git a/drivers/mci/mci-bcm2835.c b/drivers/mci/mci-bcm2835.c
index 91027857be..0450f899c6 100644
--- a/drivers/mci/mci-bcm2835.c
+++ b/drivers/mci/mci-bcm2835.c
@@ -172,7 +172,7 @@ static int bcm2835_mci_request(struct mci_host *mci, struct mci_cmd *cmd,
}
if (!ret && data)
- ret = sdhci_transfer_data(&host->sdhci, data);
+ ret = sdhci_transfer_data_pio(&host->sdhci, data);
sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, 0xFFFFFFFF);
if (ret) {
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index a160b98894..a094f3cbf5 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1358,7 +1358,8 @@ static int __maybe_unused mci_sd_write(struct block_device *blk,
mci_blk_part_switch(part);
- if (host->card_write_protected && host->card_write_protected(host)) {
+ if (!host->disable_wp &&
+ host->card_write_protected && host->card_write_protected(host)) {
dev_err(&mci->dev, "card write protected\n");
return -EPERM;
}
@@ -2016,6 +2017,7 @@ void mci_of_parse_node(struct mci_host *host,
host->non_removable = of_property_read_bool(np, "non-removable");
host->no_sd = of_property_read_bool(np, "no-sd");
+ host->disable_wp = of_property_read_bool(np, "disable-wp");
}
void mci_of_parse(struct mci_host *host)
diff --git a/drivers/mci/rockchip-dwcmshc-sdhci.c b/drivers/mci/rockchip-dwcmshc-sdhci.c
new file mode 100644
index 0000000000..164f662552
--- /dev/null
+++ b/drivers/mci/rockchip-dwcmshc-sdhci.c
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <clock.h>
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <linux/clk.h>
+#include <mci.h>
+#include <dma.h>
+#include <linux/iopoll.h>
+
+#include "sdhci.h"
+
+/* DWCMSHC specific Mode Select value */
+#define DWCMSHC_CTRL_HS400 0x7
+
+#define DWCMSHC_VER_ID 0x500
+#define DWCMSHC_VER_TYPE 0x504
+#define DWCMSHC_HOST_CTRL3 0x508
+#define DWCMSHC_EMMC_CONTROL 0x52c
+#define DWCMSHC_EMMC_ATCTRL 0x540
+
+/* Rockchip specific Registers */
+#define DWCMSHC_EMMC_DLL_CTRL 0x800
+#define DWCMSHC_EMMC_DLL_RXCLK 0x804
+#define DWCMSHC_EMMC_DLL_TXCLK 0x808
+#define DWCMSHC_EMMC_DLL_STRBIN 0x80c
+#define DWCMSHC_EMMC_DLL_STATUS0 0x840
+#define DWCMSHC_EMMC_DLL_START BIT(0)
+#define DWCMSHC_EMMC_DLL_RXCLK_SRCSEL 29
+#define DWCMSHC_EMMC_DLL_START_POINT 16
+#define DWCMSHC_EMMC_DLL_INC 8
+#define DWCMSHC_EMMC_DLL_DLYENA BIT(27)
+#define DLL_TXCLK_TAPNUM_DEFAULT 0x8
+#define DLL_STRBIN_TAPNUM_DEFAULT 0x8
+#define DLL_TXCLK_TAPNUM_FROM_SW BIT(24)
+#define DLL_STRBIN_TAPNUM_FROM_SW BIT(24)
+#define DWCMSHC_EMMC_DLL_LOCKED BIT(8)
+#define DWCMSHC_EMMC_DLL_TIMEOUT BIT(9)
+#define DLL_RXCLK_NO_INVERTER 1
+#define DLL_RXCLK_INVERTER 0
+#define DWCMSHC_ENHANCED_STROBE BIT(8)
+#define DLL_LOCK_WO_TMOUT(x) \
+ ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \
+ (((x) & DWCMSHC_EMMC_DLL_TIMEOUT) == 0))
+
+#define SDHCI_DWCMSHC_INT_DATA_MASK SDHCI_INT_XFER_COMPLETE | \
+ SDHCI_INT_DMA | \
+ SDHCI_INT_SPACE_AVAIL | \
+ SDHCI_INT_DATA_AVAIL | \
+ SDHCI_INT_DATA_TIMEOUT | \
+ SDHCI_INT_DATA_CRC | \
+ SDHCI_INT_DATA_END_BIT
+
+#define SDHCI_DWCMSHC_INT_CMD_MASK SDHCI_INT_CMD_COMPLETE | \
+ SDHCI_INT_TIMEOUT | \
+ SDHCI_INT_CRC | \
+ SDHCI_INT_END_BIT | \
+ SDHCI_INT_INDEX
+
+enum {
+ CLK_CORE,
+ CLK_BUS,
+ CLK_AXI,
+ CLK_BLOCK,
+ CLK_TIMER,
+ CLK_MAX,
+};
+
+struct rk_sdhci_host {
+ struct mci_host mci;
+ struct sdhci sdhci;
+ struct clk_bulk_data clks[CLK_MAX];
+};
+
+
+static inline
+struct rk_sdhci_host *to_rk_sdhci_host(struct mci_host *mci)
+{
+ return container_of(mci, struct rk_sdhci_host, mci);
+}
+
+static int rk_sdhci_card_present(struct mci_host *mci)
+{
+ struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+
+ return !!(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & SDHCI_CARD_DETECT);
+}
+
+static int rk_sdhci_reset(struct rk_sdhci_host *host, u8 mask)
+{
+ sdhci_write8(&host->sdhci, SDHCI_SOFTWARE_RESET, mask);
+
+ /* wait for reset completion */
+ if (wait_on_timeout(100 * MSECOND,
+ !(sdhci_read8(&host->sdhci, SDHCI_SOFTWARE_RESET) & mask))){
+ dev_err(host->mci.hw_dev, "SDHCI reset timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int rk_sdhci_init(struct mci_host *mci, struct device_d *dev)
+{
+ struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+ int ret;
+
+ ret = rk_sdhci_reset(host, SDHCI_RESET_ALL);
+ if (ret)
+ return ret;
+
+ sdhci_write8(&host->sdhci, SDHCI_POWER_CONTROL,
+ SDHCI_BUS_VOLTAGE_330 | SDHCI_BUS_POWER_EN);
+ udelay(400);
+
+ sdhci_write32(&host->sdhci, SDHCI_INT_ENABLE,
+ SDHCI_DWCMSHC_INT_DATA_MASK |
+ SDHCI_DWCMSHC_INT_CMD_MASK);
+ sdhci_write32(&host->sdhci, SDHCI_SIGNAL_ENABLE, 0x00);
+
+ /* Disable cmd conflict check */
+ sdhci_write32(&host->sdhci, DWCMSHC_HOST_CTRL3, 0x0);
+ /* Reset previous settings */
+ sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_TXCLK, 0);
+ sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_STRBIN, 0);
+
+ return 0;
+}
+
+static void rk_sdhci_set_clock(struct rk_sdhci_host *host, unsigned int clock)
+{
+ u32 txclk_tapnum = DLL_TXCLK_TAPNUM_DEFAULT, extra;
+ int err;
+
+ host->mci.clock = 0;
+
+ /* DO NOT TOUCH THIS SETTING */
+ extra = DWCMSHC_EMMC_DLL_DLYENA |
+ DLL_RXCLK_NO_INVERTER << DWCMSHC_EMMC_DLL_RXCLK_SRCSEL;
+ sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_RXCLK, extra);
+
+ if (clock == 0)
+ return;
+
+ /* Rockchip platform only support 375KHz for identify mode */
+ if (clock <= 400000)
+ clock = 375000;
+
+ clk_set_rate(host->clks[CLK_CORE].clk, clock);
+
+ sdhci_set_clock(&host->sdhci, clock, clk_get_rate(host->clks[CLK_CORE].clk));
+
+ if (clock <= 400000)
+ return;
+
+ /* Reset DLL */
+ sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_CTRL, BIT(1));
+ udelay(1);
+ sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_CTRL, 0x0);
+
+ /* Init DLL settings */
+ extra = 0x5 << DWCMSHC_EMMC_DLL_START_POINT |
+ 0x2 << DWCMSHC_EMMC_DLL_INC |
+ DWCMSHC_EMMC_DLL_START;
+ sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_CTRL, extra);
+ err = readl_poll_timeout(host->sdhci.base + DWCMSHC_EMMC_DLL_STATUS0,
+ extra, DLL_LOCK_WO_TMOUT(extra),
+ 500 * USEC_PER_MSEC);
+ if (err) {
+ dev_err(host->mci.hw_dev, "DLL lock timeout!\n");
+ return;
+ }
+
+ /* Disable cmd conflict check */
+ extra = sdhci_read32(&host->sdhci, DWCMSHC_HOST_CTRL3);
+ extra &= ~BIT(0);
+ sdhci_write32(&host->sdhci, DWCMSHC_HOST_CTRL3, extra);
+
+ extra = 0x1 << 16 | /* tune clock stop en */
+ 0x2 << 17 | /* pre-change delay */
+ 0x3 << 19; /* post-change delay */
+ sdhci_write32(&host->sdhci, DWCMSHC_EMMC_ATCTRL, extra);
+
+ extra = DWCMSHC_EMMC_DLL_DLYENA |
+ DLL_TXCLK_TAPNUM_FROM_SW |
+ txclk_tapnum;
+ sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_TXCLK, extra);
+
+ extra = DWCMSHC_EMMC_DLL_DLYENA |
+ DLL_STRBIN_TAPNUM_DEFAULT |
+ DLL_STRBIN_TAPNUM_FROM_SW;
+ sdhci_write32(&host->sdhci, DWCMSHC_EMMC_DLL_STRBIN, extra);
+}
+
+static void rk_sdhci_set_ios(struct mci_host *mci, struct mci_ios *ios)
+{
+ struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+ u16 val;
+
+ /* stop clock */
+ sdhci_write16(&host->sdhci, SDHCI_CLOCK_CONTROL, 0);
+
+ if (ios->clock)
+ rk_sdhci_set_clock(host, ios->clock);
+
+ sdhci_set_bus_width(&host->sdhci, ios->bus_width);
+
+ val = sdhci_read8(&host->sdhci, SDHCI_HOST_CONTROL);
+
+ if (ios->clock > 26000000)
+ val |= SDHCI_CTRL_HISPD;
+ else
+ val &= ~SDHCI_CTRL_HISPD;
+
+ sdhci_write8(&host->sdhci, SDHCI_HOST_CONTROL, val);
+}
+
+static int rk_sdhci_wait_for_done(struct rk_sdhci_host *host, u32 mask)
+{
+ u64 start = get_time_ns();
+ u16 stat;
+
+ do {
+ stat = sdhci_read16(&host->sdhci, SDHCI_INT_NORMAL_STATUS);
+ if (stat & SDHCI_INT_ERROR) {
+ dev_err(host->mci.hw_dev, "SDHCI_INT_ERROR: 0x%08x\n",
+ sdhci_read16(&host->sdhci, SDHCI_INT_ERROR_STATUS));
+ return -EPERM;
+ }
+
+ if (is_timeout(start, 1000 * MSECOND)) {
+ dev_err(host->mci.hw_dev,
+ "SDHCI timeout while waiting for done\n");
+ return -ETIMEDOUT;
+ }
+ } while ((stat & mask) != mask);
+
+ return 0;
+}
+
+static void print_error(struct rk_sdhci_host *host, int cmdidx)
+{
+ dev_err(host->mci.hw_dev,
+ "error while transfering data for command %d\n", cmdidx);
+ dev_err(host->mci.hw_dev, "state = 0x%08x , interrupt = 0x%08x\n",
+ sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE),
+ sdhci_read32(&host->sdhci, SDHCI_INT_NORMAL_STATUS));
+}
+
+static int rk_sdhci_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
+ struct mci_data *data)
+{
+ struct rk_sdhci_host *host = to_rk_sdhci_host(mci);
+ u32 mask, command, xfer;
+ int ret;
+ dma_addr_t dma;
+
+ /* Wait for idle before next command */
+ mask = SDHCI_CMD_INHIBIT_CMD;
+ if (cmd->cmdidx != MMC_CMD_STOP_TRANSMISSION)
+ mask |= SDHCI_CMD_INHIBIT_DATA;
+
+ ret = wait_on_timeout(10 * MSECOND,
+ !(sdhci_read32(&host->sdhci, SDHCI_PRESENT_STATE) & mask));
+
+ if (ret) {
+ dev_err(host->mci.hw_dev,
+ "SDHCI timeout while waiting for idle\n");
+ return ret;
+ }
+
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+
+ sdhci_write8(&host->sdhci, SDHCI_TIMEOUT_CONTROL, 0xe);
+
+ sdhci_setup_data_dma(&host->sdhci, data, &dma);
+
+ sdhci_set_cmd_xfer_mode(&host->sdhci, cmd, data,
+ dma == SDHCI_NO_DMA ? false : true,
+ &command, &xfer);
+
+ sdhci_write16(&host->sdhci, SDHCI_TRANSFER_MODE, xfer);
+
+ sdhci_write32(&host->sdhci, SDHCI_ARGUMENT, cmd->cmdarg);
+ sdhci_write16(&host->sdhci, SDHCI_COMMAND, command);
+
+ ret = rk_sdhci_wait_for_done(host, SDHCI_INT_CMD_COMPLETE);
+ if (ret == -EPERM)
+ goto error;
+ else if (ret)
+ return ret;
+
+ sdhci_read_response(&host->sdhci, cmd);
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, SDHCI_INT_CMD_COMPLETE);
+
+ ret = sdhci_transfer_data_dma(&host->sdhci, data, dma);
+
+error:
+ if (ret) {
+ print_error(host, cmd->cmdidx);
+ rk_sdhci_reset(host, BIT(1)); /* SDHCI_RESET_CMD */
+ rk_sdhci_reset(host, BIT(2)); /* SDHCI_RESET_DATA */
+ }
+
+ sdhci_write32(&host->sdhci, SDHCI_INT_STATUS, ~0);
+ return ret;
+}
+
+static int rk_sdhci_probe(struct device_d *dev)
+{
+ struct rk_sdhci_host *host;
+ struct resource *iores;
+ struct mci_host *mci;
+ int ret;
+
+ host = xzalloc(sizeof(*host));
+
+ mci = &host->mci;
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return PTR_ERR(iores);
+
+ host->sdhci.base = IOMEM(iores->start);
+ host->sdhci.mci = mci;
+ mci->send_cmd = rk_sdhci_send_cmd;
+ mci->set_ios = rk_sdhci_set_ios;
+ mci->init = rk_sdhci_init;
+ mci->card_present = rk_sdhci_card_present;
+ mci->hw_dev = dev;
+
+ host->clks[CLK_CORE].id = "core";
+ host->clks[CLK_BUS].id = "bus";
+ host->clks[CLK_AXI].id = "axi";
+ host->clks[CLK_BLOCK].id = "block";
+ host->clks[CLK_TIMER].id = "timer";
+
+ ret = clk_bulk_get(host->mci.hw_dev, CLK_MAX, host->clks);
+ if (ret) {
+ dev_err(host->mci.hw_dev, "failed to get clocks: %s\n",
+ strerror(-ret));
+ return ret;
+ }
+
+ ret = clk_bulk_enable(CLK_MAX, host->clks);
+ if (ret) {
+ dev_err(host->mci.hw_dev, "failed to enable clocks: %s\n",
+ strerror(-ret));
+ return ret;
+ }
+
+ host->sdhci.max_clk = clk_get_rate(host->clks[CLK_CORE].clk);
+
+ mci_of_parse(&host->mci);
+
+ sdhci_setup_host(&host->sdhci);
+
+ dev->priv = host;
+
+ return mci_register(&host->mci);
+}
+
+static __maybe_unused struct of_device_id rk_sdhci_compatible[] = {
+ {
+ .compatible = "rockchip,rk3568-dwcmshc"
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d rk_sdhci_driver = {
+ .name = "rk3568-dwcmshc-sdhci",
+ .probe = rk_sdhci_probe,
+ .of_compatible = DRV_OF_COMPAT(rk_sdhci_compatible),
+};
+device_platform_driver(rk_sdhci_driver);
diff --git a/drivers/mci/sdhci.c b/drivers/mci/sdhci.c
index dba26b2665..aca4a5a6f9 100644
--- a/drivers/mci/sdhci.c
+++ b/drivers/mci/sdhci.c
@@ -4,6 +4,8 @@
#include <driver.h>
#include <mci.h>
#include <io.h>
+#include <dma.h>
+#include <linux/bitfield.h>
#include "sdhci.h"
@@ -88,6 +90,27 @@ static void sdhci_tx_pio(struct sdhci *sdhci, struct mci_data *data,
sdhci_write32(sdhci, SDHCI_BUFFER, buf[i]);
}
+void sdhci_set_bus_width(struct sdhci *host, int width)
+{
+ u8 ctrl;
+
+ BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+ ctrl = sdhci_read8(host, SDHCI_HOST_CONTROL);
+ if (width == MMC_BUS_WIDTH_8) {
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ ctrl |= SDHCI_CTRL_8BITBUS;
+ } else {
+ if (host->mci->host_caps & MMC_CAP_8_BIT_DATA)
+ ctrl &= ~SDHCI_CTRL_8BITBUS;
+ if (width == MMC_BUS_WIDTH_4)
+ ctrl |= SDHCI_CTRL_4BITBUS;
+ else
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ }
+ sdhci_write8(host, SDHCI_HOST_CONTROL, ctrl);
+}
+
#ifdef __PBL__
/*
* Stubs to make timeout logic below work in PBL
@@ -101,12 +124,112 @@ static void sdhci_tx_pio(struct sdhci *sdhci, struct mci_data *data,
#endif
-int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data)
+void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data)
+{
+ if (!data)
+ return;
+
+ sdhci_write16(sdhci, SDHCI_BLOCK_SIZE, sdhci->sdma_boundary |
+ SDHCI_TRANSFER_BLOCK_SIZE(data->blocksize));
+ sdhci_write16(sdhci, SDHCI_BLOCK_COUNT, data->blocks);
+}
+
+void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data,
+ dma_addr_t *dma)
+{
+ struct device_d *dev = sdhci->mci->hw_dev;
+ int nbytes;
+
+ if (!data)
+ return;
+
+ sdhci_setup_data_pio(sdhci, data);
+
+ if (!dma)
+ return;
+
+ nbytes = data->blocks * data->blocksize;
+
+ if (data->flags & MMC_DATA_READ)
+ *dma = dma_map_single(dev, (void *)data->src, nbytes,
+ DMA_FROM_DEVICE);
+ else
+ *dma = dma_map_single(dev, data->dest, nbytes,
+ DMA_TO_DEVICE);
+
+ if (dma_mapping_error(dev, *dma)) {
+ *dma = SDHCI_NO_DMA;
+ return;
+ }
+
+ sdhci_write32(sdhci, SDHCI_DMA_ADDRESS, *dma);
+}
+
+int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
+ dma_addr_t dma)
+{
+ struct device_d *dev = sdhci->mci->hw_dev;
+ int nbytes;
+ u32 irqstat;
+ int ret;
+
+ if (!data)
+ return 0;
+
+ nbytes = data->blocks * data->blocksize;
+
+ do {
+ irqstat = sdhci_read32(sdhci, SDHCI_INT_STATUS);
+
+ if (irqstat & SDHCI_INT_DATA_END_BIT) {
+ ret = -EIO;
+ goto out;
+ }
+
+ if (irqstat & SDHCI_INT_DATA_CRC) {
+ ret = -EBADMSG;
+ goto out;
+ }
+
+ if (irqstat & SDHCI_INT_DATA_TIMEOUT) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ if (irqstat & SDHCI_INT_DMA) {
+ u32 addr = sdhci_read32(sdhci, SDHCI_DMA_ADDRESS);
+
+ /*
+ * DMA engine has stopped on buffer boundary. Acknowledge
+ * the interrupt and kick the DMA engine again.
+ */
+ sdhci_write32(sdhci, SDHCI_INT_STATUS, SDHCI_INT_DMA);
+ sdhci_write32(sdhci, SDHCI_DMA_ADDRESS, addr);
+ }
+
+ if (irqstat & SDHCI_INT_XFER_COMPLETE)
+ break;
+ } while (1);
+
+ ret = 0;
+out:
+ if (data->flags & MMC_DATA_READ)
+ dma_unmap_single(dev, dma, nbytes, DMA_FROM_DEVICE);
+ else
+ dma_unmap_single(dev, dma, nbytes, DMA_TO_DEVICE);
+
+ return 0;
+}
+
+int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data)
{
unsigned int block = 0;
u32 stat, prs;
uint64_t start = get_time_ns();
+ if (!data)
+ return 0;
+
do {
stat = sdhci_read32(sdhci, SDHCI_INT_STATUS);
if (stat & SDHCI_INT_ERROR)
@@ -139,6 +262,19 @@ int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data)
return 0;
}
+int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma)
+{
+ struct device_d *dev = sdhci->mci->hw_dev;
+
+ if (!data)
+ return 0;
+
+ if (dma_mapping_error(dev, dma))
+ return sdhci_transfer_data_pio(sdhci, data);
+ else
+ return sdhci_transfer_data_dma(sdhci, data, dma);
+}
+
int sdhci_reset(struct sdhci *sdhci, u8 mask)
{
u8 val;
@@ -149,3 +285,264 @@ int sdhci_reset(struct sdhci *sdhci, u8 mask)
val, !(val & mask),
100 * USEC_PER_MSEC);
}
+
+static u16 sdhci_get_preset_value(struct sdhci *host)
+{
+ u16 preset = 0;
+
+ BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+ switch (host->timing) {
+ case MMC_TIMING_UHS_SDR12:
+ preset = sdhci_read16(host, SDHCI_PRESET_FOR_SDR12);
+ break;
+ case MMC_TIMING_UHS_SDR25:
+ preset = sdhci_read16(host, SDHCI_PRESET_FOR_SDR25);
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ preset = sdhci_read16(host, SDHCI_PRESET_FOR_SDR50);
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ case MMC_TIMING_MMC_HS200:
+ preset = sdhci_read16(host, SDHCI_PRESET_FOR_SDR104);
+ break;
+ case MMC_TIMING_UHS_DDR50:
+ case MMC_TIMING_MMC_DDR52:
+ preset = sdhci_read16(host, SDHCI_PRESET_FOR_DDR50);
+ break;
+ case MMC_TIMING_MMC_HS400:
+ preset = sdhci_read16(host, SDHCI_PRESET_FOR_HS400);
+ break;
+ default:
+ dev_warn(host->mci->hw_dev, "Invalid UHS-I mode selected\n");
+ preset = sdhci_read16(host, SDHCI_PRESET_FOR_SDR12);
+ break;
+ }
+ return preset;
+}
+
+u16 sdhci_calc_clk(struct sdhci *host, unsigned int clock,
+ unsigned int *actual_clock, unsigned int input_clock)
+{
+ int div = 0; /* Initialized for compiler warning */
+ int real_div = div, clk_mul = 1;
+ u16 clk = 0;
+ bool switch_base_clk = false;
+
+ BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+ if (host->version >= SDHCI_SPEC_300) {
+ if (host->preset_enabled) {
+ u16 pre_val;
+
+ clk = sdhci_read16(host, SDHCI_CLOCK_CONTROL);
+ pre_val = sdhci_get_preset_value(host);
+ div = FIELD_GET(SDHCI_PRESET_SDCLK_FREQ_MASK, pre_val);
+ if (host->clk_mul &&
+ (pre_val & SDHCI_PRESET_CLKGEN_SEL)) {
+ clk = SDHCI_PROG_CLOCK_MODE;
+ real_div = div + 1;
+ clk_mul = host->clk_mul;
+ } else {
+ real_div = max_t(int, 1, div << 1);
+ }
+ goto clock_set;
+ }
+
+ /*
+ * Check if the Host Controller supports Programmable Clock
+ * Mode.
+ */
+ if (host->clk_mul) {
+ for (div = 1; div <= 1024; div++) {
+ if ((input_clock * host->clk_mul / div)
+ <= clock)
+ break;
+ }
+ if ((input_clock * host->clk_mul / div) <= clock) {
+ /*
+ * Set Programmable Clock Mode in the Clock
+ * Control register.
+ */
+ clk = SDHCI_PROG_CLOCK_MODE;
+ real_div = div;
+ clk_mul = host->clk_mul;
+ div--;
+ } else {
+ /*
+ * Divisor can be too small to reach clock
+ * speed requirement. Then use the base clock.
+ */
+ switch_base_clk = true;
+ }
+ }
+
+ if (!host->clk_mul || switch_base_clk) {
+ /* Version 3.00 divisors must be a multiple of 2. */
+ if (input_clock <= clock)
+ div = 1;
+ else {
+ for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
+ div += 2) {
+ if ((input_clock / div) <= clock)
+ break;
+ }
+ }
+ real_div = div;
+ div >>= 1;
+ if ((host->quirks2 & SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN)
+ && !div && input_clock <= 25000000)
+ div = 1;
+ }
+ } else {
+ /* Version 2.00 divisors must be a power of 2. */
+ for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
+ if ((input_clock / div) <= clock)
+ break;
+ }
+ real_div = div;
+ div >>= 1;
+ }
+
+clock_set:
+ if (real_div)
+ *actual_clock = (input_clock * clk_mul) / real_div;
+ clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+ clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
+ << SDHCI_DIVIDER_HI_SHIFT;
+
+ return clk;
+}
+
+void sdhci_enable_clk(struct sdhci *host, u16 clk)
+{
+ u64 start;
+
+ BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+ clk |= SDHCI_CLOCK_INT_EN;
+ sdhci_write16(host, SDHCI_CLOCK_CONTROL, clk);
+
+ start = get_time_ns();
+ while (!(sdhci_read16(host, SDHCI_CLOCK_CONTROL) &
+ SDHCI_CLOCK_INT_STABLE)) {
+ if (is_timeout(start, 150 * MSECOND)) {
+ dev_err(host->mci->hw_dev,
+ "SDHCI clock stable timeout\n");
+ return;
+ }
+ }
+
+ clk |= SDHCI_CLOCK_CARD_EN;
+ sdhci_write16(host, SDHCI_CLOCK_CONTROL, clk);
+}
+
+void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_clock)
+{
+ u16 clk;
+
+ BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+ host->mci->clock = 0;
+
+ sdhci_write16(host, SDHCI_CLOCK_CONTROL, 0);
+
+ if (clock == 0)
+ return;
+
+ clk = sdhci_calc_clk(host, clock, &host->mci->clock, input_clock);
+ sdhci_enable_clk(host, clk);
+}
+
+void __sdhci_read_caps(struct sdhci *host, const u16 *ver,
+ const u32 *caps, const u32 *caps1)
+{
+ u16 v;
+ u64 dt_caps_mask = 0;
+ u64 dt_caps = 0;
+ struct device_node *np = host->mci->hw_dev->device_node;
+
+ BUG_ON(!host->mci); /* Call sdhci_setup_host() before using this */
+
+ if (host->read_caps)
+ return;
+
+ host->read_caps = true;
+
+ sdhci_reset(host, SDHCI_RESET_ALL);
+
+ of_property_read_u64(np, "sdhci-caps-mask", &dt_caps_mask);
+ of_property_read_u64(np, "sdhci-caps", &dt_caps);
+
+ v = ver ? *ver : sdhci_read16(host, SDHCI_HOST_VERSION);
+ host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
+
+ if (host->quirks & SDHCI_QUIRK_MISSING_CAPS)
+ return;
+
+ if (caps) {
+ host->caps = *caps;
+ } else {
+ host->caps = sdhci_read32(host, SDHCI_CAPABILITIES);
+ host->caps &= ~lower_32_bits(dt_caps_mask);
+ host->caps |= lower_32_bits(dt_caps);
+ }
+
+ if (host->version < SDHCI_SPEC_300)
+ return;
+
+ if (caps1) {
+ host->caps1 = *caps1;
+ } else {
+ host->caps1 = sdhci_read32(host, SDHCI_CAPABILITIES_1);
+ host->caps1 &= ~upper_32_bits(dt_caps_mask);
+ host->caps1 |= upper_32_bits(dt_caps);
+ }
+}
+
+int sdhci_setup_host(struct sdhci *host)
+{
+ struct mci_host *mci = host->mci;
+
+ BUG_ON(!mci);
+
+ sdhci_read_caps(host);
+
+ if (!host->max_clk) {
+ if (host->version >= SDHCI_SPEC_300)
+ host->max_clk = FIELD_GET(SDHCI_CLOCK_V3_BASE_MASK, host->caps);
+ else
+ host->max_clk = FIELD_GET(SDHCI_CLOCK_BASE_MASK, host->caps);
+
+ host->max_clk *= 1000000;
+ }
+
+ /*
+ * In case of Host Controller v3.00, find out whether clock
+ * multiplier is supported.
+ */
+ host->clk_mul = FIELD_GET(SDHCI_CLOCK_MUL_MASK, host->caps1);
+
+ /*
+ * In case the value in Clock Multiplier is 0, then programmable
+ * clock mode is not supported, otherwise the actual clock
+ * multiplier is one more than the value of Clock Multiplier
+ * in the Capabilities Register.
+ */
+ if (host->clk_mul)
+ host->clk_mul += 1;
+
+ if (host->caps & SDHCI_CAN_VDD_180)
+ mci->voltages |= MMC_VDD_165_195;
+ if (host->caps & SDHCI_CAN_VDD_300)
+ mci->voltages |= MMC_VDD_29_30 | MMC_VDD_30_31;
+ if (host->caps & SDHCI_CAN_VDD_330)
+ mci->voltages |= MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ if (host->caps & SDHCI_CAN_DO_HISPD)
+ mci->host_caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
+
+ host->sdma_boundary = SDHCI_DMA_BOUNDARY_512K;
+
+ return 0;
+}
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index 7b3f64486f..351940a511 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -2,6 +2,7 @@
#define __MCI_SDHCI_H
#include <pbl.h>
+#include <dma.h>
#include <linux/iopoll.h>
#define SDHCI_DMA_ADDRESS 0x00
@@ -54,11 +55,18 @@
#define SDHCI_PRESENT_STATE1 0x26
#define SDHCI_HOST_CONTROL__POWER_CONTROL__BLOCK_GAP_CONTROL 0x28
#define SDHCI_HOST_CONTROL 0x28
-#define SDHCI_CARD_DETECT_SIGNAL_SELECTION BIT(7)
-#define SDHCI_CARD_DETECT_TEST_LEVEL BIT(6)
-#define SDHCI_DATA_WIDTH_8BIT BIT(5)
-#define SDHCI_HIGHSPEED_EN BIT(2)
-#define SDHCI_DATA_WIDTH_4BIT BIT(1)
+#define SDHCI_CTRL_LED BIT(0)
+#define SDHCI_CTRL_4BITBUS BIT(1)
+#define SDHCI_CTRL_HISPD BIT(2)
+#define SDHCI_CTRL_DMA_MASK 0x18
+#define SDHCI_CTRL_SDMA 0x00
+#define SDHCI_CTRL_ADMA1 0x08
+#define SDHCI_CTRL_ADMA32 0x10
+#define SDHCI_CTRL_ADMA64 0x18
+#define SDHCI_CTRL_ADMA3 0x18
+#define SDHCI_CTRL_8BITBUS BIT(5)
+#define SDHCI_CTRL_CDTEST_INS BIT(6)
+#define SDHCI_CTRL_CDTEST_EN BIT(7)
#define SDHCI_POWER_CONTROL 0x29
#define SDHCI_POWER_ON 0x01
#define SDHCI_POWER_180 0x0A
@@ -68,15 +76,19 @@
#define SDHCI_BUS_VOLTAGE(v) ((v) << 1)
#define SDHCI_BUS_POWER_EN BIT(0)
#define SDHCI_CLOCK_CONTROL__TIMEOUT_CONTROL__SOFTWARE_RESET 0x2c
-#define SDHCI_CLOCK_CONTROL 0x2c
+#define SDHCI_CLOCK_CONTROL 0x2C
+#define SDHCI_DIVIDER_SHIFT 8
#define SDHCI_DIVIDER_HI_SHIFT 6
+#define SDHCI_DIV_MASK 0xFF
#define SDHCI_DIV_HI_MASK 0x300
#define SDHCI_DIV_MASK_LEN 8
-#define SDHCI_FREQ_SEL(x) (((x) & 0xff) << 8)
+#define SDHCI_FREQ_SEL(x) (((x) & 0xff) << 8)
+#define SDHCI_DIV_HI_MASK 0x300
#define SDHCI_PROG_CLOCK_MODE BIT(5)
-#define SDHCI_SDCLOCK_EN BIT(2)
-#define SDHCI_INTCLOCK_STABLE BIT(1)
-#define SDHCI_INTCLOCK_EN BIT(0)
+#define SDHCI_CLOCK_CARD_EN BIT(2)
+#define SDHCI_CLOCK_PLL_EN BIT(3)
+#define SDHCI_CLOCK_INT_STABLE BIT(1)
+#define SDHCI_CLOCK_INT_EN BIT(0)
#define SDHCI_TIMEOUT_CONTROL 0x2e
#define SDHCI_SOFTWARE_RESET 0x2f
#define SDHCI_RESET_ALL BIT(0)
@@ -105,19 +117,66 @@
#define SDHCI_SIGNAL_ENABLE 0x38
#define SDHCI_ACMD12_ERR__HOST_CONTROL2 0x3C
#define SDHCI_CAPABILITIES 0x40
-#define SDHCI_CAPABILITIES_1 0x42
-#define SDHCI_HOSTCAP_VOLTAGE_180 BIT(10)
-#define SDHCI_HOSTCAP_VOLTAGE_300 BIT(9)
-#define SDHCI_HOSTCAP_VOLTAGE_330 BIT(8)
-#define SDHCI_HOSTCAP_HIGHSPEED BIT(5)
-#define SDHCI_HOSTCAP_8BIT BIT(2)
-
-#define SDHCI_CLOCK_MUL_MASK 0x00FF0000
+#define SDHCI_TIMEOUT_CLK_MASK GENMASK(5, 0)
+#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
+#define SDHCI_CLOCK_BASE_MASK GENMASK(13, 8)
+#define SDHCI_CLOCK_V3_BASE_MASK GENMASK(15, 8)
+#define SDHCI_MAX_BLOCK_MASK 0x00030000
+#define SDHCI_MAX_BLOCK_SHIFT 16
+#define SDHCI_CAN_DO_8BIT 0x00040000
+#define SDHCI_CAN_DO_ADMA2 0x00080000
+#define SDHCI_CAN_DO_ADMA1 0x00100000
+#define SDHCI_CAN_DO_HISPD 0x00200000
+#define SDHCI_CAN_DO_SDMA 0x00400000
+#define SDHCI_CAN_DO_SUSPEND 0x00800000
+#define SDHCI_CAN_VDD_330 0x01000000
+#define SDHCI_CAN_VDD_300 0x02000000
+#define SDHCI_CAN_VDD_180 0x04000000
+#define SDHCI_CAN_64BIT_V4 0x08000000
+#define SDHCI_CAN_64BIT 0x10000000
+
+#define SDHCI_CAPABILITIES_1 0x44
+#define SDHCI_SUPPORT_SDR50 0x00000001
+#define SDHCI_SUPPORT_SDR104 0x00000002
+#define SDHCI_SUPPORT_DDR50 0x00000004
+#define SDHCI_DRIVER_TYPE_A 0x00000010
+#define SDHCI_DRIVER_TYPE_C 0x00000020
+#define SDHCI_DRIVER_TYPE_D 0x00000040
+#define SDHCI_RETUNING_TIMER_COUNT_MASK GENMASK(11, 8)
+#define SDHCI_USE_SDR50_TUNING 0x00002000
+#define SDHCI_RETUNING_MODE_MASK GENMASK(15, 14)
+#define SDHCI_CLOCK_MUL_MASK GENMASK(23, 16)
+#define SDHCI_CAN_DO_ADMA3 0x08000000
+#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */
+
+#define SDHCI_PRESET_FOR_SDR12 0x66
+#define SDHCI_PRESET_FOR_SDR25 0x68
+#define SDHCI_PRESET_FOR_SDR50 0x6A
+#define SDHCI_PRESET_FOR_SDR104 0x6C
+#define SDHCI_PRESET_FOR_DDR50 0x6E
+#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
+#define SDHCI_PRESET_CLKGEN_SEL BIT(10)
+#define SDHCI_PRESET_SDCLK_FREQ_MASK GENMASK(9, 0)
+
+#define SDHCI_HOST_VERSION 0xFE
+#define SDHCI_VENDOR_VER_MASK 0xFF00
+#define SDHCI_VENDOR_VER_SHIFT 8
+#define SDHCI_SPEC_VER_MASK 0x00FF
+#define SDHCI_SPEC_VER_SHIFT 0
+#define SDHCI_SPEC_100 0
+#define SDHCI_SPEC_200 1
+#define SDHCI_SPEC_300 2
+#define SDHCI_SPEC_400 3
+#define SDHCI_SPEC_410 4
+#define SDHCI_SPEC_420 5
+
#define SDHCI_CLOCK_MUL_SHIFT 16
-#define SDHCI_SPEC_200_MAX_CLK_DIVIDER 256
#define SDHCI_MMC_BOOT 0xC4
+#define SDHCI_MAX_DIV_SPEC_200 256
+#define SDHCI_MAX_DIV_SPEC_300 2046
+
struct sdhci {
u32 (*read32)(struct sdhci *host, int reg);
u16 (*read16)(struct sdhci *host, int reg);
@@ -125,44 +184,101 @@ struct sdhci {
void (*write32)(struct sdhci *host, int reg, u32 val);
void (*write16)(struct sdhci *host, int reg, u16 val);
void (*write8)(struct sdhci *host, int reg, u8 val);
+
+ void __iomem *base;
+
+ int max_clk; /* Max possible freq (Hz) */
+ int clk_mul; /* Clock Muliplier value */
+
+ unsigned int version; /* SDHCI spec. version */
+
+ enum mci_timing timing;
+ bool preset_enabled; /* Preset is enabled */
+
+ unsigned int quirks;
+#define SDHCI_QUIRK_MISSING_CAPS BIT(27)
+ unsigned int quirks2;
+#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN BIT(15)
+ u32 caps; /* CAPABILITY_0 */
+ u32 caps1; /* CAPABILITY_1 */
+ bool read_caps; /* Capability flags have been read */
+ u32 sdma_boundary;
+
+ struct mci_host *mci;
};
static inline u32 sdhci_read32(struct sdhci *host, int reg)
{
- return host->read32(host, reg);
+ if (host->read32)
+ return host->read32(host, reg);
+ else
+ return readl(host->base + reg);
}
static inline u32 sdhci_read16(struct sdhci *host, int reg)
{
- return host->read16(host, reg);
+ if (host->read16)
+ return host->read16(host, reg);
+ else
+ return readw(host->base + reg);
}
static inline u32 sdhci_read8(struct sdhci *host, int reg)
{
- return host->read8(host, reg);
+ if (host->read8)
+ return host->read8(host, reg);
+ else
+ return readb(host->base + reg);
}
static inline void sdhci_write32(struct sdhci *host, int reg, u32 val)
{
- host->write32(host, reg, val);
+ if (host->write32)
+ host->write32(host, reg, val);
+ else
+ writel(val, host->base + reg);
}
static inline void sdhci_write16(struct sdhci *host, int reg, u32 val)
{
- host->write16(host, reg, val);
+ if (host->write16)
+ host->write16(host, reg, val);
+ else
+ writew(val, host->base + reg);
}
static inline void sdhci_write8(struct sdhci *host, int reg, u32 val)
{
- host->write8(host, reg, val);
+ if (host->write8)
+ host->write8(host, reg, val);
+ else
+ writeb(val, host->base + reg);
}
+#define SDHCI_NO_DMA DMA_ERROR_CODE
void sdhci_read_response(struct sdhci *host, struct mci_cmd *cmd);
void sdhci_set_cmd_xfer_mode(struct sdhci *host, struct mci_cmd *cmd,
struct mci_data *data, bool dma, u32 *command,
u32 *xfer);
-int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data);
+void sdhci_setup_data_pio(struct sdhci *sdhci, struct mci_data *data);
+void sdhci_setup_data_dma(struct sdhci *sdhci, struct mci_data *data, dma_addr_t *dma);
+int sdhci_transfer_data(struct sdhci *sdhci, struct mci_data *data, dma_addr_t dma);
+int sdhci_transfer_data_pio(struct sdhci *sdhci, struct mci_data *data);
+int sdhci_transfer_data_dma(struct sdhci *sdhci, struct mci_data *data,
+ dma_addr_t dma);
int sdhci_reset(struct sdhci *sdhci, u8 mask);
+u16 sdhci_calc_clk(struct sdhci *host, unsigned int clock,
+ unsigned int *actual_clock, unsigned int input_clock);
+void sdhci_set_clock(struct sdhci *host, unsigned int clock, unsigned int input_clock);
+void sdhci_enable_clk(struct sdhci *host, u16 clk);
+int sdhci_setup_host(struct sdhci *host);
+void __sdhci_read_caps(struct sdhci *host, const u16 *ver,
+ const u32 *caps, const u32 *caps1);
+static inline void sdhci_read_caps(struct sdhci *host)
+{
+ __sdhci_read_caps(host, NULL, NULL, NULL);
+}
+void sdhci_set_bus_width(struct sdhci *host, int width);
#define sdhci_read8_poll_timeout(sdhci, reg, val, cond, timeout_us) \
read_poll_timeout(sdhci_read8, val, cond, timeout_us, sdhci, reg)