aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/sunxi/patches-4.9/090-sunxi-mmc-from-4-13.patch
diff options
context:
space:
mode:
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.patch288
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);