blob: 9f426661c49d98f38b2c0e4501c35f990135df05 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Ian Campbellb4e9f2f2014-05-05 14:42:31 +01002/*
3 * (C) Copyright 2007-2011
4 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
5 * Aaron <leafy.myeh@allwinnertech.com>
6 *
7 * MMC driver for allwinner sunxi platform.
Ian Campbellb4e9f2f2014-05-05 14:42:31 +01008 */
9
10#include <common.h>
Simon Glass7484ae72017-07-04 13:31:27 -060011#include <dm.h>
Hans de Goedeb1e107a2015-04-22 17:03:17 +020012#include <errno.h>
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010013#include <malloc.h>
14#include <mmc.h>
Andre Przywara29b533c2019-01-29 15:54:13 +000015#include <clk.h>
16#include <reset.h>
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010017#include <asm/io.h>
18#include <asm/arch/clock.h>
19#include <asm/arch/cpu.h>
Hans de Goede7412ef82014-10-02 20:29:26 +020020#include <asm/arch/gpio.h>
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010021#include <asm/arch/mmc.h>
Hans de Goede7412ef82014-10-02 20:29:26 +020022#include <asm-generic/gpio.h>
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010023
Jagan Teki2002b752019-01-09 16:58:39 +053024#ifdef CONFIG_DM_MMC
25struct sunxi_mmc_variant {
Jagan Teki2002b752019-01-09 16:58:39 +053026 u16 mclk_offset;
27};
28#endif
29
Simon Glass7484ae72017-07-04 13:31:27 -060030struct sunxi_mmc_plat {
31 struct mmc_config cfg;
32 struct mmc mmc;
33};
34
Simon Glass3f19fbf2017-07-04 13:31:23 -060035struct sunxi_mmc_priv {
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010036 unsigned mmc_no;
37 uint32_t *mclkreg;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010038 unsigned fatal_err;
Simon Glass7484ae72017-07-04 13:31:27 -060039 struct gpio_desc cd_gpio; /* Change Detect GPIO */
Heinrich Schuchardt8dc0a992018-02-01 23:39:19 +010040 int cd_inverted; /* Inverted Card Detect */
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010041 struct sunxi_mmc *reg;
42 struct mmc_config cfg;
Jagan Teki2002b752019-01-09 16:58:39 +053043#ifdef CONFIG_DM_MMC
44 const struct sunxi_mmc_variant *variant;
45#endif
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010046};
47
Simon Glass7484ae72017-07-04 13:31:27 -060048#if !CONFIG_IS_ENABLED(DM_MMC)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010049/* support 4 mmc hosts */
Simon Glass3f19fbf2017-07-04 13:31:23 -060050struct sunxi_mmc_priv mmc_host[4];
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010051
Hans de Goede3d1095f2014-10-31 16:55:02 +010052static int sunxi_mmc_getcd_gpio(int sdc_no)
53{
54 switch (sdc_no) {
55 case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN);
56 case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN);
57 case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN);
58 case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN);
59 }
Hans de Goedeb1e107a2015-04-22 17:03:17 +020060 return -EINVAL;
Hans de Goede3d1095f2014-10-31 16:55:02 +010061}
62
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010063static int mmc_resource_init(int sdc_no)
64{
Simon Glass8e659a22017-07-04 13:31:24 -060065 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010066 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede3d1095f2014-10-31 16:55:02 +010067 int cd_pin, ret = 0;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010068
69 debug("init mmc %d resource\n", sdc_no);
70
71 switch (sdc_no) {
72 case 0:
Simon Glass8e659a22017-07-04 13:31:24 -060073 priv->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
74 priv->mclkreg = &ccm->sd0_clk_cfg;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010075 break;
76 case 1:
Simon Glass8e659a22017-07-04 13:31:24 -060077 priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
78 priv->mclkreg = &ccm->sd1_clk_cfg;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010079 break;
80 case 2:
Simon Glass8e659a22017-07-04 13:31:24 -060081 priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
82 priv->mclkreg = &ccm->sd2_clk_cfg;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010083 break;
Icenowy Zhenga838a152018-07-21 16:20:29 +080084#ifdef SUNXI_MMC3_BASE
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010085 case 3:
Simon Glass8e659a22017-07-04 13:31:24 -060086 priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
87 priv->mclkreg = &ccm->sd3_clk_cfg;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010088 break;
Icenowy Zhenga838a152018-07-21 16:20:29 +080089#endif
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010090 default:
91 printf("Wrong mmc number %d\n", sdc_no);
92 return -1;
93 }
Simon Glass8e659a22017-07-04 13:31:24 -060094 priv->mmc_no = sdc_no;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010095
Hans de Goede3d1095f2014-10-31 16:55:02 +010096 cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
Hans de Goedeb1e107a2015-04-22 17:03:17 +020097 if (cd_pin >= 0) {
Hans de Goede3d1095f2014-10-31 16:55:02 +010098 ret = gpio_request(cd_pin, "mmc_cd");
Hans de Goedee6525302015-05-30 16:39:10 +020099 if (!ret) {
100 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
Axel Lin06da3462014-12-20 11:41:25 +0800101 ret = gpio_direction_input(cd_pin);
Hans de Goedee6525302015-05-30 16:39:10 +0200102 }
Axel Lin06da3462014-12-20 11:41:25 +0800103 }
Hans de Goede3d1095f2014-10-31 16:55:02 +0100104
105 return ret;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100106}
Simon Glass7484ae72017-07-04 13:31:27 -0600107#endif
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100108
Simon Glass8e659a22017-07-04 13:31:24 -0600109static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
Hans de Goede06bfab02014-12-07 20:55:10 +0100110{
111 unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
Vasily Khoruzhicka4e8dd92018-11-09 20:41:46 -0800112 bool new_mode = true;
Vasily Khoruzhick57789d62018-11-05 20:24:28 -0800113 bool calibrate = false;
Maxime Ripard95e34702017-08-23 12:03:41 +0200114 u32 val = 0;
115
Vasily Khoruzhicka4e8dd92018-11-09 20:41:46 -0800116 if (!IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE))
117 new_mode = false;
118
119 /* A83T support new mode only on eMMC */
120 if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T) && priv->mmc_no != 2)
121 new_mode = false;
Maxime Ripard95e34702017-08-23 12:03:41 +0200122
Vasily Khoruzhick57789d62018-11-05 20:24:28 -0800123#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6)
124 calibrate = true;
125#endif
126
Hans de Goede06bfab02014-12-07 20:55:10 +0100127 if (hz <= 24000000) {
128 pll = CCM_MMC_CTRL_OSCM24;
129 pll_hz = 24000000;
130 } else {
Hans de Goedef1865db2015-01-14 19:05:03 +0100131#ifdef CONFIG_MACH_SUN9I
132 pll = CCM_MMC_CTRL_PLL_PERIPH0;
133 pll_hz = clock_get_pll4_periph0();
Icenowy Zhenga838a152018-07-21 16:20:29 +0800134#elif defined(CONFIG_MACH_SUN50I_H6)
135 pll = CCM_MMC_CTRL_PLL6X2;
136 pll_hz = clock_get_pll6() * 2;
Hans de Goedef1865db2015-01-14 19:05:03 +0100137#else
Hans de Goede06bfab02014-12-07 20:55:10 +0100138 pll = CCM_MMC_CTRL_PLL6;
139 pll_hz = clock_get_pll6();
Hans de Goedef1865db2015-01-14 19:05:03 +0100140#endif
Hans de Goede06bfab02014-12-07 20:55:10 +0100141 }
142
143 div = pll_hz / hz;
144 if (pll_hz % hz)
145 div++;
146
147 n = 0;
148 while (div > 16) {
149 n++;
150 div = (div + 1) / 2;
151 }
152
153 if (n > 3) {
Simon Glass8e659a22017-07-04 13:31:24 -0600154 printf("mmc %u error cannot set clock to %u\n", priv->mmc_no,
155 hz);
Hans de Goede06bfab02014-12-07 20:55:10 +0100156 return -1;
157 }
158
159 /* determine delays */
160 if (hz <= 400000) {
161 oclk_dly = 0;
Hans de Goede5192ba22015-09-23 16:13:10 +0200162 sclk_dly = 0;
Hans de Goede06bfab02014-12-07 20:55:10 +0100163 } else if (hz <= 25000000) {
164 oclk_dly = 0;
165 sclk_dly = 5;
Hans de Goede5192ba22015-09-23 16:13:10 +0200166#ifdef CONFIG_MACH_SUN9I
Stefan Mavrodiev180194b2018-03-27 16:57:23 +0300167 } else if (hz <= 52000000) {
Hans de Goede5192ba22015-09-23 16:13:10 +0200168 oclk_dly = 5;
169 sclk_dly = 4;
Hans de Goede06bfab02014-12-07 20:55:10 +0100170 } else {
Stefan Mavrodiev180194b2018-03-27 16:57:23 +0300171 /* hz > 52000000 */
Hans de Goede06bfab02014-12-07 20:55:10 +0100172 oclk_dly = 2;
173 sclk_dly = 4;
Hans de Goede5192ba22015-09-23 16:13:10 +0200174#else
Stefan Mavrodiev180194b2018-03-27 16:57:23 +0300175 } else if (hz <= 52000000) {
Hans de Goede5192ba22015-09-23 16:13:10 +0200176 oclk_dly = 3;
177 sclk_dly = 4;
178 } else {
Stefan Mavrodiev180194b2018-03-27 16:57:23 +0300179 /* hz > 52000000 */
Hans de Goede5192ba22015-09-23 16:13:10 +0200180 oclk_dly = 1;
181 sclk_dly = 4;
182#endif
Maxime Ripard95e34702017-08-23 12:03:41 +0200183 }
184
185 if (new_mode) {
186#ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE
Vasily Khoruzhickb198e2c2018-11-09 20:41:44 -0800187#ifdef CONFIG_MMC_SUNXI_HAS_MODE_SWITCH
Maxime Ripard95e34702017-08-23 12:03:41 +0200188 val = CCM_MMC_CTRL_MODE_SEL_NEW;
Vasily Khoruzhickb198e2c2018-11-09 20:41:44 -0800189#endif
Chen-Yu Tsaie76f0062017-08-31 21:57:48 +0800190 setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW);
Maxime Ripard95e34702017-08-23 12:03:41 +0200191#endif
Vasily Khoruzhick57789d62018-11-05 20:24:28 -0800192 } else if (!calibrate) {
193 /*
194 * Use hardcoded delay values if controller doesn't support
195 * calibration
196 */
Maxime Ripard95e34702017-08-23 12:03:41 +0200197 val = CCM_MMC_CTRL_OCLK_DLY(oclk_dly) |
198 CCM_MMC_CTRL_SCLK_DLY(sclk_dly);
Hans de Goede06bfab02014-12-07 20:55:10 +0100199 }
200
Maxime Ripard95e34702017-08-23 12:03:41 +0200201 writel(CCM_MMC_CTRL_ENABLE| pll | CCM_MMC_CTRL_N(n) |
202 CCM_MMC_CTRL_M(div) | val, priv->mclkreg);
Hans de Goede06bfab02014-12-07 20:55:10 +0100203
204 debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n",
Simon Glass8e659a22017-07-04 13:31:24 -0600205 priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div);
Hans de Goede06bfab02014-12-07 20:55:10 +0100206
207 return 0;
208}
209
Simon Glass87ff0f72017-07-04 13:31:25 -0600210static int mmc_update_clk(struct sunxi_mmc_priv *priv)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100211{
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100212 unsigned int cmd;
213 unsigned timeout_msecs = 2000;
Philipp Tomsich1721b002018-03-21 12:18:58 +0100214 unsigned long start = get_timer(0);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100215
216 cmd = SUNXI_MMC_CMD_START |
217 SUNXI_MMC_CMD_UPCLK_ONLY |
218 SUNXI_MMC_CMD_WAIT_PRE_OVER;
Philipp Tomsich1721b002018-03-21 12:18:58 +0100219
Simon Glass8e659a22017-07-04 13:31:24 -0600220 writel(cmd, &priv->reg->cmd);
221 while (readl(&priv->reg->cmd) & SUNXI_MMC_CMD_START) {
Philipp Tomsich1721b002018-03-21 12:18:58 +0100222 if (get_timer(start) > timeout_msecs)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100223 return -1;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100224 }
225
226 /* clock update sets various irq status bits, clear these */
Simon Glass8e659a22017-07-04 13:31:24 -0600227 writel(readl(&priv->reg->rint), &priv->reg->rint);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100228
229 return 0;
230}
231
Simon Glass87ff0f72017-07-04 13:31:25 -0600232static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100233{
Simon Glass8e659a22017-07-04 13:31:24 -0600234 unsigned rval = readl(&priv->reg->clkcr);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100235
236 /* Disable Clock */
237 rval &= ~SUNXI_MMC_CLK_ENABLE;
Simon Glass8e659a22017-07-04 13:31:24 -0600238 writel(rval, &priv->reg->clkcr);
Simon Glass87ff0f72017-07-04 13:31:25 -0600239 if (mmc_update_clk(priv))
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100240 return -1;
241
Hans de Goede06bfab02014-12-07 20:55:10 +0100242 /* Set mod_clk to new rate */
Simon Glass8e659a22017-07-04 13:31:24 -0600243 if (mmc_set_mod_clk(priv, mmc->clock))
Hans de Goede06bfab02014-12-07 20:55:10 +0100244 return -1;
245
246 /* Clear internal divider */
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100247 rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
Simon Glass8e659a22017-07-04 13:31:24 -0600248 writel(rval, &priv->reg->clkcr);
Hans de Goede06bfab02014-12-07 20:55:10 +0100249
Vasily Khoruzhick57789d62018-11-05 20:24:28 -0800250#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6)
251 /* A64 supports calibration of delays on MMC controller and we
252 * have to set delay of zero before starting calibration.
253 * Allwinner BSP driver sets a delay only in the case of
254 * using HS400 which is not supported by mainline U-Boot or
255 * Linux at the moment
256 */
257 writel(SUNXI_MMC_CAL_DL_SW_EN, &priv->reg->samp_dl);
258#endif
259
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100260 /* Re-enable Clock */
261 rval |= SUNXI_MMC_CLK_ENABLE;
Simon Glass8e659a22017-07-04 13:31:24 -0600262 writel(rval, &priv->reg->clkcr);
Simon Glass87ff0f72017-07-04 13:31:25 -0600263 if (mmc_update_clk(priv))
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100264 return -1;
265
266 return 0;
267}
268
Simon Glass87ff0f72017-07-04 13:31:25 -0600269static int sunxi_mmc_set_ios_common(struct sunxi_mmc_priv *priv,
270 struct mmc *mmc)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100271{
Hans de Goede06bfab02014-12-07 20:55:10 +0100272 debug("set ios: bus_width: %x, clock: %d\n",
273 mmc->bus_width, mmc->clock);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100274
275 /* Change clock first */
Simon Glass87ff0f72017-07-04 13:31:25 -0600276 if (mmc->clock && mmc_config_clock(priv, mmc) != 0) {
Simon Glass8e659a22017-07-04 13:31:24 -0600277 priv->fatal_err = 1;
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900278 return -EINVAL;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100279 }
280
281 /* Change bus width */
282 if (mmc->bus_width == 8)
Simon Glass8e659a22017-07-04 13:31:24 -0600283 writel(0x2, &priv->reg->width);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100284 else if (mmc->bus_width == 4)
Simon Glass8e659a22017-07-04 13:31:24 -0600285 writel(0x1, &priv->reg->width);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100286 else
Simon Glass8e659a22017-07-04 13:31:24 -0600287 writel(0x0, &priv->reg->width);
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900288
289 return 0;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100290}
291
Simon Glass7484ae72017-07-04 13:31:27 -0600292#if !CONFIG_IS_ENABLED(DM_MMC)
Siarhei Siamashka253d77d2015-02-01 00:42:14 +0200293static int sunxi_mmc_core_init(struct mmc *mmc)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100294{
Simon Glass8e659a22017-07-04 13:31:24 -0600295 struct sunxi_mmc_priv *priv = mmc->priv;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100296
297 /* Reset controller */
Simon Glass8e659a22017-07-04 13:31:24 -0600298 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
Hans de Goede411dc872014-06-09 11:36:55 +0200299 udelay(1000);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100300
301 return 0;
302}
Simon Glass7484ae72017-07-04 13:31:27 -0600303#endif
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100304
Simon Glass87ff0f72017-07-04 13:31:25 -0600305static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
306 struct mmc_data *data)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100307{
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100308 const int reading = !!(data->flags & MMC_DATA_READ);
309 const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY :
310 SUNXI_MMC_STATUS_FIFO_FULL;
311 unsigned i;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100312 unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
Yousong Zhoub0170092015-08-29 21:26:11 +0800313 unsigned byte_cnt = data->blocksize * data->blocks;
Philipp Tomsich1721b002018-03-21 12:18:58 +0100314 unsigned timeout_msecs = byte_cnt >> 8;
315 unsigned long start;
316
317 if (timeout_msecs < 2000)
318 timeout_msecs = 2000;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100319
Hans de Goede411dc872014-06-09 11:36:55 +0200320 /* Always read / write data through the CPU */
Simon Glass8e659a22017-07-04 13:31:24 -0600321 setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
Hans de Goede411dc872014-06-09 11:36:55 +0200322
Philipp Tomsich1721b002018-03-21 12:18:58 +0100323 start = get_timer(0);
324
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100325 for (i = 0; i < (byte_cnt >> 2); i++) {
Simon Glass8e659a22017-07-04 13:31:24 -0600326 while (readl(&priv->reg->status) & status_bit) {
Philipp Tomsich1721b002018-03-21 12:18:58 +0100327 if (get_timer(start) > timeout_msecs)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100328 return -1;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100329 }
330
331 if (reading)
Simon Glass8e659a22017-07-04 13:31:24 -0600332 buff[i] = readl(&priv->reg->fifo);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100333 else
Simon Glass8e659a22017-07-04 13:31:24 -0600334 writel(buff[i], &priv->reg->fifo);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100335 }
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100336
337 return 0;
338}
339
Simon Glass87ff0f72017-07-04 13:31:25 -0600340static int mmc_rint_wait(struct sunxi_mmc_priv *priv, struct mmc *mmc,
341 uint timeout_msecs, uint done_bit, const char *what)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100342{
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100343 unsigned int status;
Philipp Tomsich1721b002018-03-21 12:18:58 +0100344 unsigned long start = get_timer(0);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100345
346 do {
Simon Glass8e659a22017-07-04 13:31:24 -0600347 status = readl(&priv->reg->rint);
Philipp Tomsich1721b002018-03-21 12:18:58 +0100348 if ((get_timer(start) > timeout_msecs) ||
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100349 (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) {
350 debug("%s timeout %x\n", what,
351 status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900352 return -ETIMEDOUT;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100353 }
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100354 } while (!(status & done_bit));
355
356 return 0;
357}
358
Simon Glass87ff0f72017-07-04 13:31:25 -0600359static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv,
360 struct mmc *mmc, struct mmc_cmd *cmd,
361 struct mmc_data *data)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100362{
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100363 unsigned int cmdval = SUNXI_MMC_CMD_START;
364 unsigned int timeout_msecs;
365 int error = 0;
366 unsigned int status = 0;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100367 unsigned int bytecnt = 0;
368
Simon Glass8e659a22017-07-04 13:31:24 -0600369 if (priv->fatal_err)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100370 return -1;
371 if (cmd->resp_type & MMC_RSP_BUSY)
372 debug("mmc cmd %d check rsp busy\n", cmd->cmdidx);
373 if (cmd->cmdidx == 12)
374 return 0;
375
376 if (!cmd->cmdidx)
377 cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ;
378 if (cmd->resp_type & MMC_RSP_PRESENT)
379 cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE;
380 if (cmd->resp_type & MMC_RSP_136)
381 cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE;
382 if (cmd->resp_type & MMC_RSP_CRC)
383 cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC;
384
385 if (data) {
Alexander Grafee1d8252016-03-29 17:29:09 +0200386 if ((u32)(long)data->dest & 0x3) {
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100387 error = -1;
388 goto out;
389 }
390
391 cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER;
392 if (data->flags & MMC_DATA_WRITE)
393 cmdval |= SUNXI_MMC_CMD_WRITE;
394 if (data->blocks > 1)
395 cmdval |= SUNXI_MMC_CMD_AUTO_STOP;
Simon Glass8e659a22017-07-04 13:31:24 -0600396 writel(data->blocksize, &priv->reg->blksz);
397 writel(data->blocks * data->blocksize, &priv->reg->bytecnt);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100398 }
399
Simon Glass8e659a22017-07-04 13:31:24 -0600400 debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", priv->mmc_no,
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100401 cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg);
Simon Glass8e659a22017-07-04 13:31:24 -0600402 writel(cmd->cmdarg, &priv->reg->arg);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100403
404 if (!data)
Simon Glass8e659a22017-07-04 13:31:24 -0600405 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100406
407 /*
408 * transfer data and check status
409 * STATREG[2] : FIFO empty
410 * STATREG[3] : FIFO full
411 */
412 if (data) {
413 int ret = 0;
414
415 bytecnt = data->blocksize * data->blocks;
416 debug("trans data %d bytes\n", bytecnt);
Simon Glass8e659a22017-07-04 13:31:24 -0600417 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
Simon Glass87ff0f72017-07-04 13:31:25 -0600418 ret = mmc_trans_data_by_cpu(priv, mmc, data);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100419 if (ret) {
Simon Glass8e659a22017-07-04 13:31:24 -0600420 error = readl(&priv->reg->rint) &
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100421 SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
Jaehoon Chung7825d202016-07-19 16:33:36 +0900422 error = -ETIMEDOUT;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100423 goto out;
424 }
425 }
426
Simon Glass87ff0f72017-07-04 13:31:25 -0600427 error = mmc_rint_wait(priv, mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE,
428 "cmd");
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100429 if (error)
430 goto out;
431
432 if (data) {
Hans de Goede411dc872014-06-09 11:36:55 +0200433 timeout_msecs = 120;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100434 debug("cacl timeout %x msec\n", timeout_msecs);
Simon Glass87ff0f72017-07-04 13:31:25 -0600435 error = mmc_rint_wait(priv, mmc, timeout_msecs,
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100436 data->blocks > 1 ?
437 SUNXI_MMC_RINT_AUTO_COMMAND_DONE :
438 SUNXI_MMC_RINT_DATA_OVER,
439 "data");
440 if (error)
441 goto out;
442 }
443
444 if (cmd->resp_type & MMC_RSP_BUSY) {
Philipp Tomsich1721b002018-03-21 12:18:58 +0100445 unsigned long start = get_timer(0);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100446 timeout_msecs = 2000;
Philipp Tomsich1721b002018-03-21 12:18:58 +0100447
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100448 do {
Simon Glass8e659a22017-07-04 13:31:24 -0600449 status = readl(&priv->reg->status);
Philipp Tomsich1721b002018-03-21 12:18:58 +0100450 if (get_timer(start) > timeout_msecs) {
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100451 debug("busy timeout\n");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900452 error = -ETIMEDOUT;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100453 goto out;
454 }
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100455 } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY);
456 }
457
458 if (cmd->resp_type & MMC_RSP_136) {
Simon Glass8e659a22017-07-04 13:31:24 -0600459 cmd->response[0] = readl(&priv->reg->resp3);
460 cmd->response[1] = readl(&priv->reg->resp2);
461 cmd->response[2] = readl(&priv->reg->resp1);
462 cmd->response[3] = readl(&priv->reg->resp0);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100463 debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n",
464 cmd->response[3], cmd->response[2],
465 cmd->response[1], cmd->response[0]);
466 } else {
Simon Glass8e659a22017-07-04 13:31:24 -0600467 cmd->response[0] = readl(&priv->reg->resp0);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100468 debug("mmc resp 0x%08x\n", cmd->response[0]);
469 }
470out:
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100471 if (error < 0) {
Simon Glass8e659a22017-07-04 13:31:24 -0600472 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
Simon Glass87ff0f72017-07-04 13:31:25 -0600473 mmc_update_clk(priv);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100474 }
Simon Glass8e659a22017-07-04 13:31:24 -0600475 writel(0xffffffff, &priv->reg->rint);
476 writel(readl(&priv->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET,
477 &priv->reg->gctrl);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100478
479 return error;
480}
481
Simon Glass7484ae72017-07-04 13:31:27 -0600482#if !CONFIG_IS_ENABLED(DM_MMC)
Simon Glass87ff0f72017-07-04 13:31:25 -0600483static int sunxi_mmc_set_ios_legacy(struct mmc *mmc)
484{
485 struct sunxi_mmc_priv *priv = mmc->priv;
486
487 return sunxi_mmc_set_ios_common(priv, mmc);
488}
489
490static int sunxi_mmc_send_cmd_legacy(struct mmc *mmc, struct mmc_cmd *cmd,
491 struct mmc_data *data)
492{
493 struct sunxi_mmc_priv *priv = mmc->priv;
494
495 return sunxi_mmc_send_cmd_common(priv, mmc, cmd, data);
496}
497
498static int sunxi_mmc_getcd_legacy(struct mmc *mmc)
Hans de Goede7412ef82014-10-02 20:29:26 +0200499{
Simon Glass8e659a22017-07-04 13:31:24 -0600500 struct sunxi_mmc_priv *priv = mmc->priv;
Hans de Goede3d1095f2014-10-31 16:55:02 +0100501 int cd_pin;
Hans de Goede7412ef82014-10-02 20:29:26 +0200502
Simon Glass8e659a22017-07-04 13:31:24 -0600503 cd_pin = sunxi_mmc_getcd_gpio(priv->mmc_no);
Hans de Goedeb1e107a2015-04-22 17:03:17 +0200504 if (cd_pin < 0)
Hans de Goede7412ef82014-10-02 20:29:26 +0200505 return 1;
506
Axel Lin06da3462014-12-20 11:41:25 +0800507 return !gpio_get_value(cd_pin);
Hans de Goede7412ef82014-10-02 20:29:26 +0200508}
509
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100510static const struct mmc_ops sunxi_mmc_ops = {
Simon Glass87ff0f72017-07-04 13:31:25 -0600511 .send_cmd = sunxi_mmc_send_cmd_legacy,
512 .set_ios = sunxi_mmc_set_ios_legacy,
Siarhei Siamashka253d77d2015-02-01 00:42:14 +0200513 .init = sunxi_mmc_core_init,
Simon Glass87ff0f72017-07-04 13:31:25 -0600514 .getcd = sunxi_mmc_getcd_legacy,
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100515};
516
Hans de Goede63deaa82014-10-02 21:13:54 +0200517struct mmc *sunxi_mmc_init(int sdc_no)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100518{
Simon Glass3a654152017-07-04 13:31:26 -0600519 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Simon Glass87ff0f72017-07-04 13:31:25 -0600520 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
521 struct mmc_config *cfg = &priv->cfg;
Simon Glass3a654152017-07-04 13:31:26 -0600522 int ret;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100523
Simon Glass87ff0f72017-07-04 13:31:25 -0600524 memset(priv, '\0', sizeof(struct sunxi_mmc_priv));
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100525
526 cfg->name = "SUNXI SD/MMC";
527 cfg->ops = &sunxi_mmc_ops;
528
529 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
530 cfg->host_caps = MMC_MODE_4BIT;
Icenowy Zhenga838a152018-07-21 16:20:29 +0800531#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) || defined(CONFIG_MACH_SUN50I_H6)
Siarhei Siamashka26c50fb2016-03-29 17:29:10 +0200532 if (sdc_no == 2)
533 cfg->host_caps = MMC_MODE_8BIT;
534#endif
Rob Herring5fd3edd2015-03-23 17:56:59 -0500535 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100536 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
537
538 cfg->f_min = 400000;
539 cfg->f_max = 52000000;
540
Hans de Goede3d1095f2014-10-31 16:55:02 +0100541 if (mmc_resource_init(sdc_no) != 0)
542 return NULL;
543
Simon Glass3a654152017-07-04 13:31:26 -0600544 /* config ahb clock */
545 debug("init mmc %d clock and io\n", sdc_no);
Icenowy Zhenga838a152018-07-21 16:20:29 +0800546#if !defined(CONFIG_MACH_SUN50I_H6)
Simon Glass3a654152017-07-04 13:31:26 -0600547 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
548
549#ifdef CONFIG_SUNXI_GEN_SUN6I
550 /* unassert reset */
551 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no));
552#endif
553#if defined(CONFIG_MACH_SUN9I)
554 /* sun9i has a mmc-common module, also set the gate and reset there */
555 writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET,
556 SUNXI_MMC_COMMON_BASE + 4 * sdc_no);
557#endif
Icenowy Zhenga838a152018-07-21 16:20:29 +0800558#else /* CONFIG_MACH_SUN50I_H6 */
559 setbits_le32(&ccm->sd_gate_reset, 1 << sdc_no);
560 /* unassert reset */
561 setbits_le32(&ccm->sd_gate_reset, 1 << (RESET_SHIFT + sdc_no));
562#endif
Simon Glass3a654152017-07-04 13:31:26 -0600563 ret = mmc_set_mod_clk(priv, 24000000);
564 if (ret)
565 return NULL;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100566
Maxime Ripard0cc228e2017-08-23 13:41:33 +0200567 return mmc_create(cfg, priv);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100568}
Simon Glass7484ae72017-07-04 13:31:27 -0600569#else
570
571static int sunxi_mmc_set_ios(struct udevice *dev)
572{
573 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
574 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
575
576 return sunxi_mmc_set_ios_common(priv, &plat->mmc);
577}
578
579static int sunxi_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
580 struct mmc_data *data)
581{
582 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
583 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
584
585 return sunxi_mmc_send_cmd_common(priv, &plat->mmc, cmd, data);
586}
587
588static int sunxi_mmc_getcd(struct udevice *dev)
589{
590 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
591
Heinrich Schuchardt8dc0a992018-02-01 23:39:19 +0100592 if (dm_gpio_is_valid(&priv->cd_gpio)) {
593 int cd_state = dm_gpio_get_value(&priv->cd_gpio);
Simon Glass7484ae72017-07-04 13:31:27 -0600594
Heinrich Schuchardt8dc0a992018-02-01 23:39:19 +0100595 return cd_state ^ priv->cd_inverted;
596 }
Simon Glass7484ae72017-07-04 13:31:27 -0600597 return 1;
598}
599
600static const struct dm_mmc_ops sunxi_mmc_ops = {
601 .send_cmd = sunxi_mmc_send_cmd,
602 .set_ios = sunxi_mmc_set_ios,
603 .get_cd = sunxi_mmc_getcd,
604};
605
606static int sunxi_mmc_probe(struct udevice *dev)
607{
608 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
609 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
610 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
Andre Przywara29b533c2019-01-29 15:54:13 +0000611 struct reset_ctl_bulk reset_bulk;
612 struct clk gate_clk;
Simon Glass7484ae72017-07-04 13:31:27 -0600613 struct mmc_config *cfg = &plat->cfg;
614 struct ofnode_phandle_args args;
Andre Przywara29b533c2019-01-29 15:54:13 +0000615 u32 *ccu_reg;
Simon Glass7484ae72017-07-04 13:31:27 -0600616 int bus_width, ret;
617
618 cfg->name = dev->name;
619 bus_width = dev_read_u32_default(dev, "bus-width", 1);
620
621 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
622 cfg->host_caps = 0;
623 if (bus_width == 8)
624 cfg->host_caps |= MMC_MODE_8BIT;
625 if (bus_width >= 4)
626 cfg->host_caps |= MMC_MODE_4BIT;
627 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
628 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
629
630 cfg->f_min = 400000;
631 cfg->f_max = 52000000;
632
633 priv->reg = (void *)dev_read_addr(dev);
Jagan Teki2002b752019-01-09 16:58:39 +0530634 priv->variant =
635 (const struct sunxi_mmc_variant *)dev_get_driver_data(dev);
Simon Glass7484ae72017-07-04 13:31:27 -0600636
637 /* We don't have a sunxi clock driver so find the clock address here */
638 ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
639 1, &args);
640 if (ret)
641 return ret;
Jagan Teki2002b752019-01-09 16:58:39 +0530642 ccu_reg = (u32 *)ofnode_get_addr(args.node);
Simon Glass7484ae72017-07-04 13:31:27 -0600643
Jagan Teki2002b752019-01-09 16:58:39 +0530644 priv->mmc_no = ((uintptr_t)priv->reg - SUNXI_MMC0_BASE) / 0x1000;
645 priv->mclkreg = (void *)ccu_reg +
646 (priv->variant->mclk_offset + (priv->mmc_no * 4));
Andre Przywara29b533c2019-01-29 15:54:13 +0000647
648 ret = clk_get_by_name(dev, "ahb", &gate_clk);
649 if (!ret)
650 clk_enable(&gate_clk);
651
652 ret = reset_get_bulk(dev, &reset_bulk);
653 if (!ret)
654 reset_deassert_bulk(&reset_bulk);
Simon Glass7484ae72017-07-04 13:31:27 -0600655
656 ret = mmc_set_mod_clk(priv, 24000000);
657 if (ret)
658 return ret;
659
660 /* This GPIO is optional */
Andre Przywara99f3a912019-01-19 01:30:53 +0000661 if (!dev_read_bool(dev, "non-removable") &&
662 !gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
Simon Glass7484ae72017-07-04 13:31:27 -0600663 GPIOD_IS_IN)) {
664 int cd_pin = gpio_get_number(&priv->cd_gpio);
665
666 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
667 }
668
Heinrich Schuchardt8dc0a992018-02-01 23:39:19 +0100669 /* Check if card detect is inverted */
670 priv->cd_inverted = dev_read_bool(dev, "cd-inverted");
671
Simon Glass7484ae72017-07-04 13:31:27 -0600672 upriv->mmc = &plat->mmc;
673
674 /* Reset controller */
675 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
676 udelay(1000);
677
678 return 0;
679}
680
681static int sunxi_mmc_bind(struct udevice *dev)
682{
683 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
684
685 return mmc_bind(dev, &plat->mmc, &plat->cfg);
686}
687
Jagan Teki2002b752019-01-09 16:58:39 +0530688static const struct sunxi_mmc_variant sun4i_a10_variant = {
Jagan Teki2002b752019-01-09 16:58:39 +0530689 .mclk_offset = 0x88,
690};
691
Jagan Teki64e2a742019-01-21 16:01:12 +0530692static const struct sunxi_mmc_variant sun9i_a80_variant = {
693 .mclk_offset = 0x410,
694};
695
Jagan Teki611f1672019-01-29 15:54:12 +0000696static const struct sunxi_mmc_variant sun50i_h6_variant = {
697 .mclk_offset = 0x830,
698};
699
Simon Glass7484ae72017-07-04 13:31:27 -0600700static const struct udevice_id sunxi_mmc_ids[] = {
Jagan Teki2002b752019-01-09 16:58:39 +0530701 {
702 .compatible = "allwinner,sun4i-a10-mmc",
703 .data = (ulong)&sun4i_a10_variant,
704 },
705 {
706 .compatible = "allwinner,sun5i-a13-mmc",
707 .data = (ulong)&sun4i_a10_variant,
708 },
709 {
710 .compatible = "allwinner,sun7i-a20-mmc",
711 .data = (ulong)&sun4i_a10_variant,
712 },
Jagan Teki79eaa5d2019-01-29 15:54:11 +0000713 {
714 .compatible = "allwinner,sun8i-a83t-emmc",
715 .data = (ulong)&sun4i_a10_variant,
716 },
717 {
Jagan Teki64e2a742019-01-21 16:01:12 +0530718 .compatible = "allwinner,sun9i-a80-mmc",
719 .data = (ulong)&sun9i_a80_variant,
720 },
721 {
Jagan Teki79eaa5d2019-01-29 15:54:11 +0000722 .compatible = "allwinner,sun50i-a64-mmc",
723 .data = (ulong)&sun4i_a10_variant,
724 },
725 {
726 .compatible = "allwinner,sun50i-a64-emmc",
727 .data = (ulong)&sun4i_a10_variant,
728 },
Jagan Teki611f1672019-01-29 15:54:12 +0000729 {
730 .compatible = "allwinner,sun50i-h6-mmc",
731 .data = (ulong)&sun50i_h6_variant,
732 },
733 {
734 .compatible = "allwinner,sun50i-h6-emmc",
735 .data = (ulong)&sun50i_h6_variant,
736 },
Jagan Teki2002b752019-01-09 16:58:39 +0530737 { /* sentinel */ }
Simon Glass7484ae72017-07-04 13:31:27 -0600738};
739
740U_BOOT_DRIVER(sunxi_mmc_drv) = {
741 .name = "sunxi_mmc",
742 .id = UCLASS_MMC,
743 .of_match = sunxi_mmc_ids,
744 .bind = sunxi_mmc_bind,
745 .probe = sunxi_mmc_probe,
746 .ops = &sunxi_mmc_ops,
747 .platdata_auto_alloc_size = sizeof(struct sunxi_mmc_plat),
748 .priv_auto_alloc_size = sizeof(struct sunxi_mmc_priv),
749};
750#endif