kernel: move console loglevel to generic
[oweals/openwrt.git] / target / linux / sunxi / patches-4.9 / 090-sunxi-mmc-from-4-13.patch
1 --- a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
2 +++ b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
3 @@ -13,6 +13,7 @@ Required properties:
4     * "allwinner,sun5i-a13-mmc"
5     * "allwinner,sun7i-a20-mmc"
6     * "allwinner,sun9i-a80-mmc"
7 +   * "allwinner,sun50i-a64-emmc"
8     * "allwinner,sun50i-a64-mmc"
9   - reg : mmc controller base registers
10   - clocks : a list with 4 phandle + clock specifier pairs
11 --- a/drivers/mmc/host/sunxi-mmc.c
12 +++ b/drivers/mmc/host/sunxi-mmc.c
13 @@ -5,6 +5,7 @@
14   * (C) Copyright 2013-2014 O2S GmbH <www.o2s.ch>
15   * (C) Copyright 2013-2014 David Lanzend�rfer <david.lanzendoerfer@o2s.ch>
16   * (C) Copyright 2013-2014 Hans de Goede <hdegoede@redhat.com>
17 + * (C) Copyright 2017 Sootech SA
18   *
19   * This program is free software; you can redistribute it and/or
20   * modify it under the terms of the GNU General Public License as
21 @@ -101,6 +102,7 @@
22         (SDXC_SOFT_RESET | SDXC_FIFO_RESET | SDXC_DMA_RESET)
23  
24  /* clock control bits */
25 +#define SDXC_MASK_DATA0                        BIT(31)
26  #define SDXC_CARD_CLOCK_ON             BIT(16)
27  #define SDXC_LOW_POWER_ON              BIT(17)
28  
29 @@ -253,6 +255,11 @@ struct sunxi_mmc_cfg {
30  
31         /* does the IP block support autocalibration? */
32         bool can_calibrate;
33 +
34 +       /* Does DATA0 needs to be masked while the clock is updated */
35 +       bool mask_data0;
36 +
37 +       bool needs_new_timings;
38  };
39  
40  struct sunxi_mmc_host {
41 @@ -482,7 +489,7 @@ static void sunxi_mmc_dump_errinfo(struc
42                                       cmd->opcode == SD_IO_RW_DIRECT))
43                 return;
44  
45 -       dev_err(mmc_dev(host->mmc),
46 +       dev_dbg(mmc_dev(host->mmc),
47                 "smc %d err, cmd %d,%s%s%s%s%s%s%s%s%s%s !!\n",
48                 host->mmc->index, cmd->opcode,
49                 data ? (data->flags & MMC_DATA_WRITE ? " WR" : " RD") : "",
50 @@ -654,11 +661,16 @@ static int sunxi_mmc_oclk_onoff(struct s
51         unsigned long expire = jiffies + msecs_to_jiffies(750);
52         u32 rval;
53  
54 +       dev_dbg(mmc_dev(host->mmc), "%sabling the clock\n",
55 +               oclk_en ? "en" : "dis");
56 +
57         rval = mmc_readl(host, REG_CLKCR);
58 -       rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON);
59 +       rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON | SDXC_MASK_DATA0);
60  
61         if (oclk_en)
62                 rval |= SDXC_CARD_CLOCK_ON;
63 +       if (host->cfg->mask_data0)
64 +               rval |= SDXC_MASK_DATA0;
65  
66         mmc_writel(host, REG_CLKCR, rval);
67  
68 @@ -678,46 +690,29 @@ static int sunxi_mmc_oclk_onoff(struct s
69                 return -EIO;
70         }
71  
72 +       if (host->cfg->mask_data0) {
73 +               rval = mmc_readl(host, REG_CLKCR);
74 +               mmc_writel(host, REG_CLKCR, rval & ~SDXC_MASK_DATA0);
75 +       }
76 +
77         return 0;
78  }
79  
80  static int sunxi_mmc_calibrate(struct sunxi_mmc_host *host, int reg_off)
81  {
82 -       u32 reg = readl(host->reg_base + reg_off);
83 -       u32 delay;
84 -       unsigned long timeout;
85 -
86         if (!host->cfg->can_calibrate)
87                 return 0;
88  
89 -       reg &= ~(SDXC_CAL_DL_MASK << SDXC_CAL_DL_SW_SHIFT);
90 -       reg &= ~SDXC_CAL_DL_SW_EN;
91 -
92 -       writel(reg | SDXC_CAL_START, host->reg_base + reg_off);
93 -
94 -       dev_dbg(mmc_dev(host->mmc), "calibration started\n");
95 -
96 -       timeout = jiffies + HZ * SDXC_CAL_TIMEOUT;
97 -
98 -       while (!((reg = readl(host->reg_base + reg_off)) & SDXC_CAL_DONE)) {
99 -               if (time_before(jiffies, timeout))
100 -                       cpu_relax();
101 -               else {
102 -                       reg &= ~SDXC_CAL_START;
103 -                       writel(reg, host->reg_base + reg_off);
104 -
105 -                       return -ETIMEDOUT;
106 -               }
107 -       }
108 -
109 -       delay = (reg >> SDXC_CAL_DL_SHIFT) & SDXC_CAL_DL_MASK;
110 -
111 -       reg &= ~SDXC_CAL_START;
112 -       reg |= (delay << SDXC_CAL_DL_SW_SHIFT) | SDXC_CAL_DL_SW_EN;
113 -
114 -       writel(reg, host->reg_base + reg_off);
115 -
116 -       dev_dbg(mmc_dev(host->mmc), "calibration ended, reg is 0x%x\n", reg);
117 +       /*
118 +        * FIXME:
119 +        * This is not clear how the calibration is supposed to work
120 +        * yet. The best rate have been obtained by simply setting the
121 +        * delay to 0, as Allwinner does in its BSP.
122 +        *
123 +        * The only mode that doesn't have such a delay is HS400, that
124 +        * is in itself a TODO.
125 +        */
126 +       writel(SDXC_CAL_DL_SW_EN, host->reg_base + reg_off);
127  
128         return 0;
129  }
130 @@ -745,6 +740,7 @@ static int sunxi_mmc_clk_set_phase(struc
131                         index = SDXC_CLK_50M_DDR;
132                 }
133         } else {
134 +               dev_dbg(mmc_dev(host->mmc), "Invalid clock... returning\n");
135                 return -EINVAL;
136         }
137  
138 @@ -757,10 +753,21 @@ static int sunxi_mmc_clk_set_phase(struc
139  static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
140                                   struct mmc_ios *ios)
141  {
142 +       struct mmc_host *mmc = host->mmc;
143         long rate;
144         u32 rval, clock = ios->clock;
145         int ret;
146  
147 +       ret = sunxi_mmc_oclk_onoff(host, 0);
148 +       if (ret)
149 +               return ret;
150 +
151 +       /* Our clock is gated now */
152 +       mmc->actual_clock = 0;
153 +
154 +       if (!ios->clock)
155 +               return 0;
156 +
157         /* 8 bit DDR requires a higher module clock */
158         if (ios->timing == MMC_TIMING_MMC_DDR52 &&
159             ios->bus_width == MMC_BUS_WIDTH_8)
160 @@ -768,25 +775,21 @@ static int sunxi_mmc_clk_set_rate(struct
161  
162         rate = clk_round_rate(host->clk_mmc, clock);
163         if (rate < 0) {
164 -               dev_err(mmc_dev(host->mmc), "error rounding clk to %d: %ld\n",
165 +               dev_err(mmc_dev(mmc), "error rounding clk to %d: %ld\n",
166                         clock, rate);
167                 return rate;
168         }
169 -       dev_dbg(mmc_dev(host->mmc), "setting clk to %d, rounded %ld\n",
170 +       dev_dbg(mmc_dev(mmc), "setting clk to %d, rounded %ld\n",
171                 clock, rate);
172  
173         /* setting clock rate */
174         ret = clk_set_rate(host->clk_mmc, rate);
175         if (ret) {
176 -               dev_err(mmc_dev(host->mmc), "error setting clk to %ld: %d\n",
177 +               dev_err(mmc_dev(mmc), "error setting clk to %ld: %d\n",
178                         rate, ret);
179                 return ret;
180         }
181  
182 -       ret = sunxi_mmc_oclk_onoff(host, 0);
183 -       if (ret)
184 -               return ret;
185 -
186         /* clear internal divider */
187         rval = mmc_readl(host, REG_CLKCR);
188         rval &= ~0xff;
189 @@ -798,6 +801,13 @@ static int sunxi_mmc_clk_set_rate(struct
190         }
191         mmc_writel(host, REG_CLKCR, rval);
192  
193 +       if (host->cfg->needs_new_timings) {
194 +               /* Don't touch the delay bits */
195 +               rval = mmc_readl(host, REG_SD_NTSR);
196 +               rval |= SDXC_2X_TIMING_MODE;
197 +               mmc_writel(host, REG_SD_NTSR, rval);
198 +       }
199 +
200         ret = sunxi_mmc_clk_set_phase(host, ios, rate);
201         if (ret)
202                 return ret;
203 @@ -806,9 +816,22 @@ static int sunxi_mmc_clk_set_rate(struct
204         if (ret)
205                 return ret;
206  
207 -       /* TODO: enable calibrate on sdc2 SDXC_REG_DS_DL_REG of A64 */
208 +       /*
209 +        * FIXME:
210 +        *
211 +        * In HS400 we'll also need to calibrate the data strobe
212 +        * signal. This should only happen on the MMC2 controller (at
213 +        * least on the A64).
214 +        */
215 +
216 +       ret = sunxi_mmc_oclk_onoff(host, 1);
217 +       if (ret)
218 +               return ret;
219  
220 -       return sunxi_mmc_oclk_onoff(host, 1);
221 +       /* And we just enabled our clock back */
222 +       mmc->actual_clock = rate;
223 +
224 +       return 0;
225  }
226  
227  static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
228 @@ -822,10 +845,13 @@ static void sunxi_mmc_set_ios(struct mmc
229                 break;
230  
231         case MMC_POWER_UP:
232 -               host->ferror = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
233 -                                                    ios->vdd);
234 -               if (host->ferror)
235 -                       return;
236 +               if (!IS_ERR(mmc->supply.vmmc)) {
237 +                       host->ferror = mmc_regulator_set_ocr(mmc,
238 +                                                            mmc->supply.vmmc,
239 +                                                            ios->vdd);
240 +                       if (host->ferror)
241 +                               return;
242 +               }
243  
244                 if (!IS_ERR(mmc->supply.vqmmc)) {
245                         host->ferror = regulator_enable(mmc->supply.vqmmc);
246 @@ -847,7 +873,9 @@ static void sunxi_mmc_set_ios(struct mmc
247         case MMC_POWER_OFF:
248                 dev_dbg(mmc_dev(mmc), "power off!\n");
249                 sunxi_mmc_reset_host(host);
250 -               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
251 +               if (!IS_ERR(mmc->supply.vmmc))
252 +                       mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
253 +
254                 if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled)
255                         regulator_disable(mmc->supply.vqmmc);
256                 host->vqmmc_enabled = false;
257 @@ -877,7 +905,7 @@ static void sunxi_mmc_set_ios(struct mmc
258         mmc_writel(host, REG_GCTRL, rval);
259  
260         /* set up clock */
261 -       if (ios->clock && ios->power_mode) {
262 +       if (ios->power_mode) {
263                 host->ferror = sunxi_mmc_clk_set_rate(host, ios);
264                 /* Android code had a usleep_range(50000, 55000); here */
265         }
266 @@ -1084,6 +1112,14 @@ static const struct sunxi_mmc_cfg sun50i
267         .idma_des_size_bits = 16,
268         .clk_delays = NULL,
269         .can_calibrate = true,
270 +       .mask_data0 = true,
271 +       .needs_new_timings = true,
272 +};
273 +
274 +static const struct sunxi_mmc_cfg sun50i_a64_emmc_cfg = {
275 +       .idma_des_size_bits = 13,
276 +       .clk_delays = NULL,
277 +       .can_calibrate = true,
278  };
279  
280  static const struct of_device_id sunxi_mmc_of_match[] = {
281 @@ -1092,6 +1128,7 @@ static const struct of_device_id sunxi_m
282         { .compatible = "allwinner,sun7i-a20-mmc", .data = &sun7i_a20_cfg },
283         { .compatible = "allwinner,sun9i-a80-mmc", .data = &sun9i_a80_cfg },
284         { .compatible = "allwinner,sun50i-a64-mmc", .data = &sun50i_a64_cfg },
285 +       { .compatible = "allwinner,sun50i-a64-emmc", .data = &sun50i_a64_emmc_cfg },
286         { /* sentinel */ }
287  };
288  MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);