diff options
Diffstat (limited to 'target/linux/sunxi/patches-4.9/090-sunxi-mmc-from-4-13.patch')
-rw-r--r-- | target/linux/sunxi/patches-4.9/090-sunxi-mmc-from-4-13.patch | 288 |
1 files changed, 0 insertions, 288 deletions
diff --git a/target/linux/sunxi/patches-4.9/090-sunxi-mmc-from-4-13.patch b/target/linux/sunxi/patches-4.9/090-sunxi-mmc-from-4-13.patch deleted file mode 100644 index e64581ff83..0000000000 --- a/target/linux/sunxi/patches-4.9/090-sunxi-mmc-from-4-13.patch +++ /dev/null @@ -1,288 +0,0 @@ ---- a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt -+++ b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt -@@ -13,6 +13,7 @@ Required properties: - * "allwinner,sun5i-a13-mmc" - * "allwinner,sun7i-a20-mmc" - * "allwinner,sun9i-a80-mmc" -+ * "allwinner,sun50i-a64-emmc" - * "allwinner,sun50i-a64-mmc" - - reg : mmc controller base registers - - clocks : a list with 4 phandle + clock specifier pairs ---- a/drivers/mmc/host/sunxi-mmc.c -+++ b/drivers/mmc/host/sunxi-mmc.c -@@ -5,6 +5,7 @@ - * (C) Copyright 2013-2014 O2S GmbH <www.o2s.ch> - * (C) Copyright 2013-2014 David Lanzend�rfer <david.lanzendoerfer@o2s.ch> - * (C) Copyright 2013-2014 Hans de Goede <hdegoede@redhat.com> -+ * (C) Copyright 2017 Sootech SA - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as -@@ -101,6 +102,7 @@ - (SDXC_SOFT_RESET | SDXC_FIFO_RESET | SDXC_DMA_RESET) - - /* clock control bits */ -+#define SDXC_MASK_DATA0 BIT(31) - #define SDXC_CARD_CLOCK_ON BIT(16) - #define SDXC_LOW_POWER_ON BIT(17) - -@@ -253,6 +255,11 @@ struct sunxi_mmc_cfg { - - /* does the IP block support autocalibration? */ - bool can_calibrate; -+ -+ /* Does DATA0 needs to be masked while the clock is updated */ -+ bool mask_data0; -+ -+ bool needs_new_timings; - }; - - struct sunxi_mmc_host { -@@ -482,7 +489,7 @@ static void sunxi_mmc_dump_errinfo(struc - cmd->opcode == SD_IO_RW_DIRECT)) - return; - -- dev_err(mmc_dev(host->mmc), -+ dev_dbg(mmc_dev(host->mmc), - "smc %d err, cmd %d,%s%s%s%s%s%s%s%s%s%s !!\n", - host->mmc->index, cmd->opcode, - data ? (data->flags & MMC_DATA_WRITE ? " WR" : " RD") : "", -@@ -654,11 +661,16 @@ static int sunxi_mmc_oclk_onoff(struct s - unsigned long expire = jiffies + msecs_to_jiffies(750); - u32 rval; - -+ dev_dbg(mmc_dev(host->mmc), "%sabling the clock\n", -+ oclk_en ? "en" : "dis"); -+ - rval = mmc_readl(host, REG_CLKCR); -- rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON); -+ rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON | SDXC_MASK_DATA0); - - if (oclk_en) - rval |= SDXC_CARD_CLOCK_ON; -+ if (host->cfg->mask_data0) -+ rval |= SDXC_MASK_DATA0; - - mmc_writel(host, REG_CLKCR, rval); - -@@ -678,46 +690,29 @@ static int sunxi_mmc_oclk_onoff(struct s - return -EIO; - } - -+ if (host->cfg->mask_data0) { -+ rval = mmc_readl(host, REG_CLKCR); -+ mmc_writel(host, REG_CLKCR, rval & ~SDXC_MASK_DATA0); -+ } -+ - return 0; - } - - static int sunxi_mmc_calibrate(struct sunxi_mmc_host *host, int reg_off) - { -- u32 reg = readl(host->reg_base + reg_off); -- u32 delay; -- unsigned long timeout; -- - if (!host->cfg->can_calibrate) - return 0; - -- reg &= ~(SDXC_CAL_DL_MASK << SDXC_CAL_DL_SW_SHIFT); -- reg &= ~SDXC_CAL_DL_SW_EN; -- -- writel(reg | SDXC_CAL_START, host->reg_base + reg_off); -- -- dev_dbg(mmc_dev(host->mmc), "calibration started\n"); -- -- timeout = jiffies + HZ * SDXC_CAL_TIMEOUT; -- -- while (!((reg = readl(host->reg_base + reg_off)) & SDXC_CAL_DONE)) { -- if (time_before(jiffies, timeout)) -- cpu_relax(); -- else { -- reg &= ~SDXC_CAL_START; -- writel(reg, host->reg_base + reg_off); -- -- return -ETIMEDOUT; -- } -- } -- -- delay = (reg >> SDXC_CAL_DL_SHIFT) & SDXC_CAL_DL_MASK; -- -- reg &= ~SDXC_CAL_START; -- reg |= (delay << SDXC_CAL_DL_SW_SHIFT) | SDXC_CAL_DL_SW_EN; -- -- writel(reg, host->reg_base + reg_off); -- -- dev_dbg(mmc_dev(host->mmc), "calibration ended, reg is 0x%x\n", reg); -+ /* -+ * FIXME: -+ * This is not clear how the calibration is supposed to work -+ * yet. The best rate have been obtained by simply setting the -+ * delay to 0, as Allwinner does in its BSP. -+ * -+ * The only mode that doesn't have such a delay is HS400, that -+ * is in itself a TODO. -+ */ -+ writel(SDXC_CAL_DL_SW_EN, host->reg_base + reg_off); - - return 0; - } -@@ -745,6 +740,7 @@ static int sunxi_mmc_clk_set_phase(struc - index = SDXC_CLK_50M_DDR; - } - } else { -+ dev_dbg(mmc_dev(host->mmc), "Invalid clock... returning\n"); - return -EINVAL; - } - -@@ -757,10 +753,21 @@ static int sunxi_mmc_clk_set_phase(struc - static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, - struct mmc_ios *ios) - { -+ struct mmc_host *mmc = host->mmc; - long rate; - u32 rval, clock = ios->clock; - int ret; - -+ ret = sunxi_mmc_oclk_onoff(host, 0); -+ if (ret) -+ return ret; -+ -+ /* Our clock is gated now */ -+ mmc->actual_clock = 0; -+ -+ if (!ios->clock) -+ return 0; -+ - /* 8 bit DDR requires a higher module clock */ - if (ios->timing == MMC_TIMING_MMC_DDR52 && - ios->bus_width == MMC_BUS_WIDTH_8) -@@ -768,25 +775,21 @@ static int sunxi_mmc_clk_set_rate(struct - - rate = clk_round_rate(host->clk_mmc, clock); - if (rate < 0) { -- dev_err(mmc_dev(host->mmc), "error rounding clk to %d: %ld\n", -+ dev_err(mmc_dev(mmc), "error rounding clk to %d: %ld\n", - clock, rate); - return rate; - } -- dev_dbg(mmc_dev(host->mmc), "setting clk to %d, rounded %ld\n", -+ dev_dbg(mmc_dev(mmc), "setting clk to %d, rounded %ld\n", - clock, rate); - - /* setting clock rate */ - ret = clk_set_rate(host->clk_mmc, rate); - if (ret) { -- dev_err(mmc_dev(host->mmc), "error setting clk to %ld: %d\n", -+ dev_err(mmc_dev(mmc), "error setting clk to %ld: %d\n", - rate, ret); - return ret; - } - -- ret = sunxi_mmc_oclk_onoff(host, 0); -- if (ret) -- return ret; -- - /* clear internal divider */ - rval = mmc_readl(host, REG_CLKCR); - rval &= ~0xff; -@@ -798,6 +801,13 @@ static int sunxi_mmc_clk_set_rate(struct - } - mmc_writel(host, REG_CLKCR, rval); - -+ if (host->cfg->needs_new_timings) { -+ /* Don't touch the delay bits */ -+ rval = mmc_readl(host, REG_SD_NTSR); -+ rval |= SDXC_2X_TIMING_MODE; -+ mmc_writel(host, REG_SD_NTSR, rval); -+ } -+ - ret = sunxi_mmc_clk_set_phase(host, ios, rate); - if (ret) - return ret; -@@ -806,9 +816,22 @@ static int sunxi_mmc_clk_set_rate(struct - if (ret) - return ret; - -- /* TODO: enable calibrate on sdc2 SDXC_REG_DS_DL_REG of A64 */ -+ /* -+ * FIXME: -+ * -+ * In HS400 we'll also need to calibrate the data strobe -+ * signal. This should only happen on the MMC2 controller (at -+ * least on the A64). -+ */ -+ -+ ret = sunxi_mmc_oclk_onoff(host, 1); -+ if (ret) -+ return ret; - -- return sunxi_mmc_oclk_onoff(host, 1); -+ /* And we just enabled our clock back */ -+ mmc->actual_clock = rate; -+ -+ return 0; - } - - static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -@@ -822,10 +845,13 @@ static void sunxi_mmc_set_ios(struct mmc - break; - - case MMC_POWER_UP: -- host->ferror = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, -- ios->vdd); -- if (host->ferror) -- return; -+ if (!IS_ERR(mmc->supply.vmmc)) { -+ host->ferror = mmc_regulator_set_ocr(mmc, -+ mmc->supply.vmmc, -+ ios->vdd); -+ if (host->ferror) -+ return; -+ } - - if (!IS_ERR(mmc->supply.vqmmc)) { - host->ferror = regulator_enable(mmc->supply.vqmmc); -@@ -847,7 +873,9 @@ static void sunxi_mmc_set_ios(struct mmc - case MMC_POWER_OFF: - dev_dbg(mmc_dev(mmc), "power off!\n"); - sunxi_mmc_reset_host(host); -- mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); -+ if (!IS_ERR(mmc->supply.vmmc)) -+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); -+ - if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) - regulator_disable(mmc->supply.vqmmc); - host->vqmmc_enabled = false; -@@ -877,7 +905,7 @@ static void sunxi_mmc_set_ios(struct mmc - mmc_writel(host, REG_GCTRL, rval); - - /* set up clock */ -- if (ios->clock && ios->power_mode) { -+ if (ios->power_mode) { - host->ferror = sunxi_mmc_clk_set_rate(host, ios); - /* Android code had a usleep_range(50000, 55000); here */ - } -@@ -1084,6 +1112,14 @@ static const struct sunxi_mmc_cfg sun50i - .idma_des_size_bits = 16, - .clk_delays = NULL, - .can_calibrate = true, -+ .mask_data0 = true, -+ .needs_new_timings = true, -+}; -+ -+static const struct sunxi_mmc_cfg sun50i_a64_emmc_cfg = { -+ .idma_des_size_bits = 13, -+ .clk_delays = NULL, -+ .can_calibrate = true, - }; - - static const struct of_device_id sunxi_mmc_of_match[] = { -@@ -1092,6 +1128,7 @@ static const struct of_device_id sunxi_m - { .compatible = "allwinner,sun7i-a20-mmc", .data = &sun7i_a20_cfg }, - { .compatible = "allwinner,sun9i-a80-mmc", .data = &sun9i_a80_cfg }, - { .compatible = "allwinner,sun50i-a64-mmc", .data = &sun50i_a64_cfg }, -+ { .compatible = "allwinner,sun50i-a64-emmc", .data = &sun50i_a64_emmc_cfg }, - { /* sentinel */ } - }; - MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match); |