On 17 March 2015 at 09:52, Haojian Zhuang haojian.zhuang@linaro.org wrote:
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
I've been using this patch for a few days now in 4.0rc and it works wonders, so:
Tested-by: Koen Kooi <koen.kooi@linaro.org.
I'm not convinced yet-another-DT-property is the right way for mainline acceptence, but it works.
.../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)
1.9.1