If mmc controler is accessed in bootloader, it's required to execute disable boot before resetting the controller & enabling the clock in kernel driver.
Signed-off-by: Haojian Zhuang haojian.zhuang@linaro.org --- .../devicetree/bindings/mmc/k3-dw-mshc.txt | 7 +++++ drivers/mmc/host/dw_mmc-k3.c | 33 ++++++++++++++++++++++ drivers/mmc/host/dw_mmc.h | 1 + 3 files changed, 41 insertions(+)
diff --git a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt index 3b35449..cf12cfa 100644 --- a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt +++ b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt @@ -14,6 +14,13 @@ Required Properties: * compatible: should be one of the following. - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extensions.
+Optional Properties: + +* "hisilicon,disable-boot" + - Disable boot before reseting mmc controller and enabling clocks. It's + required on Hisilicon Hi6220 SoC if the mmc controller is accessed in + bootloader. + Example:
/* for Hi3620 */ diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c index 83a9f49..3042a7c 100644 --- a/drivers/mmc/host/dw_mmc-k3.c +++ b/drivers/mmc/host/dw_mmc-k3.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/delay.h> #include <linux/mmc/host.h> #include <linux/mmc/dw_mmc.h> #include <linux/of_address.h> @@ -29,8 +30,40 @@ static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios) host->bus_hz = clk_get_rate(host->ciu_clk); }
+static void disable_boot(struct dw_mci *host) +{ + int timeout = 0; + unsigned int data; + + mci_writel(host, CTRL, SDMMC_CTRL_FIFO_RESET); + mci_writel(host, CMD, SDMMC_CMD_START | SDMMC_CMD_DISABLE_BOOT); + + while (1) { + data = mci_readl(host, CMD) & 0x80000000; + if (data == 0) + break; + if (timeout < 2000) { + timeout++; + mdelay(1); + } else { + dev_warn(host->dev, "failed to stop MMC\n"); + break; + } + } +} + +static int dw_mci_k3_parse_dt(struct dw_mci *host) +{ + struct device_node *np = host->dev->of_node; + if (of_find_property(np, "hisilicon,disable-boot", NULL)) { + disable_boot(host); + } + return 0; +} + static const struct dw_mci_drv_data k3_drv_data = { .set_ios = dw_mci_k3_set_ios, + .parse_dt = dw_mci_k3_parse_dt, };
static const struct of_device_id dw_mci_k3_match[] = { diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 01b99e8..8c5977b 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -115,6 +115,7 @@ #define SDMMC_CMD_START BIT(31) #define SDMMC_CMD_USE_HOLD_REG BIT(29) #define SDMMC_CMD_VOLT_SWITCH BIT(28) +#define SDMMC_CMD_DISABLE_BOOT BIT(26) #define SDMMC_CMD_CCS_EXP BIT(23) #define SDMMC_CMD_CEATA_RD BIT(22) #define SDMMC_CMD_UPD_CLK BIT(21)