sunxi: improve throughput in the sunxi_mmc driver
[platform/kernel/u-boot.git] / drivers / mmc / sunxi_mmc.c
1 /*
2  * (C) Copyright 2007-2011
3  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
4  * Aaron <leafy.myeh@allwinnertech.com>
5  *
6  * MMC driver for allwinner sunxi platform.
7  *
8  * SPDX-License-Identifier:     GPL-2.0+
9  */
10
11 #include <common.h>
12 #include <dm.h>
13 #include <errno.h>
14 #include <malloc.h>
15 #include <mmc.h>
16 #include <asm/io.h>
17 #include <asm/arch/clock.h>
18 #include <asm/arch/cpu.h>
19 #include <asm/arch/gpio.h>
20 #include <asm/arch/mmc.h>
21 #include <asm-generic/gpio.h>
22
23 struct sunxi_mmc_plat {
24         struct mmc_config cfg;
25         struct mmc mmc;
26 };
27
28 struct sunxi_mmc_priv {
29         unsigned mmc_no;
30         uint32_t *mclkreg;
31         unsigned fatal_err;
32         struct gpio_desc cd_gpio;       /* Change Detect GPIO */
33         int cd_inverted;                /* Inverted Card Detect */
34         struct sunxi_mmc *reg;
35         struct mmc_config cfg;
36 };
37
38 #if !CONFIG_IS_ENABLED(DM_MMC)
39 /* support 4 mmc hosts */
40 struct sunxi_mmc_priv mmc_host[4];
41
42 static int sunxi_mmc_getcd_gpio(int sdc_no)
43 {
44         switch (sdc_no) {
45         case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN);
46         case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN);
47         case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN);
48         case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN);
49         }
50         return -EINVAL;
51 }
52
53 static int mmc_resource_init(int sdc_no)
54 {
55         struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
56         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
57         int cd_pin, ret = 0;
58
59         debug("init mmc %d resource\n", sdc_no);
60
61         switch (sdc_no) {
62         case 0:
63                 priv->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
64                 priv->mclkreg = &ccm->sd0_clk_cfg;
65                 break;
66         case 1:
67                 priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
68                 priv->mclkreg = &ccm->sd1_clk_cfg;
69                 break;
70         case 2:
71                 priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
72                 priv->mclkreg = &ccm->sd2_clk_cfg;
73                 break;
74         case 3:
75                 priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
76                 priv->mclkreg = &ccm->sd3_clk_cfg;
77                 break;
78         default:
79                 printf("Wrong mmc number %d\n", sdc_no);
80                 return -1;
81         }
82         priv->mmc_no = sdc_no;
83
84         cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
85         if (cd_pin >= 0) {
86                 ret = gpio_request(cd_pin, "mmc_cd");
87                 if (!ret) {
88                         sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
89                         ret = gpio_direction_input(cd_pin);
90                 }
91         }
92
93         return ret;
94 }
95 #endif
96
97 static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
98 {
99         unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
100         bool new_mode = false;
101         u32 val = 0;
102
103         if (IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE) && (priv->mmc_no == 2))
104                 new_mode = true;
105
106         /*
107          * The MMC clock has an extra /2 post-divider when operating in the new
108          * mode.
109          */
110         if (new_mode)
111                 hz = hz * 2;
112
113         if (hz <= 24000000) {
114                 pll = CCM_MMC_CTRL_OSCM24;
115                 pll_hz = 24000000;
116         } else {
117 #ifdef CONFIG_MACH_SUN9I
118                 pll = CCM_MMC_CTRL_PLL_PERIPH0;
119                 pll_hz = clock_get_pll4_periph0();
120 #else
121                 pll = CCM_MMC_CTRL_PLL6;
122                 pll_hz = clock_get_pll6();
123 #endif
124         }
125
126         div = pll_hz / hz;
127         if (pll_hz % hz)
128                 div++;
129
130         n = 0;
131         while (div > 16) {
132                 n++;
133                 div = (div + 1) / 2;
134         }
135
136         if (n > 3) {
137                 printf("mmc %u error cannot set clock to %u\n", priv->mmc_no,
138                        hz);
139                 return -1;
140         }
141
142         /* determine delays */
143         if (hz <= 400000) {
144                 oclk_dly = 0;
145                 sclk_dly = 0;
146         } else if (hz <= 25000000) {
147                 oclk_dly = 0;
148                 sclk_dly = 5;
149 #ifdef CONFIG_MACH_SUN9I
150         } else if (hz <= 52000000) {
151                 oclk_dly = 5;
152                 sclk_dly = 4;
153         } else {
154                 /* hz > 52000000 */
155                 oclk_dly = 2;
156                 sclk_dly = 4;
157 #else
158         } else if (hz <= 52000000) {
159                 oclk_dly = 3;
160                 sclk_dly = 4;
161         } else {
162                 /* hz > 52000000 */
163                 oclk_dly = 1;
164                 sclk_dly = 4;
165 #endif
166         }
167
168         if (new_mode) {
169 #ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE
170                 val = CCM_MMC_CTRL_MODE_SEL_NEW;
171                 setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW);
172 #endif
173         } else {
174                 val = CCM_MMC_CTRL_OCLK_DLY(oclk_dly) |
175                         CCM_MMC_CTRL_SCLK_DLY(sclk_dly);
176         }
177
178         writel(CCM_MMC_CTRL_ENABLE| pll | CCM_MMC_CTRL_N(n) |
179                CCM_MMC_CTRL_M(div) | val, priv->mclkreg);
180
181         debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n",
182               priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div);
183
184         return 0;
185 }
186
187 static int mmc_update_clk(struct sunxi_mmc_priv *priv)
188 {
189         unsigned int cmd;
190         unsigned timeout_msecs = 2000;
191         unsigned long start = get_timer(0);
192
193         cmd = SUNXI_MMC_CMD_START |
194               SUNXI_MMC_CMD_UPCLK_ONLY |
195               SUNXI_MMC_CMD_WAIT_PRE_OVER;
196
197         writel(cmd, &priv->reg->cmd);
198         while (readl(&priv->reg->cmd) & SUNXI_MMC_CMD_START) {
199                 if (get_timer(start) > timeout_msecs)
200                         return -1;
201         }
202
203         /* clock update sets various irq status bits, clear these */
204         writel(readl(&priv->reg->rint), &priv->reg->rint);
205
206         return 0;
207 }
208
209 static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc)
210 {
211         unsigned rval = readl(&priv->reg->clkcr);
212
213         /* Disable Clock */
214         rval &= ~SUNXI_MMC_CLK_ENABLE;
215         writel(rval, &priv->reg->clkcr);
216         if (mmc_update_clk(priv))
217                 return -1;
218
219         /* Set mod_clk to new rate */
220         if (mmc_set_mod_clk(priv, mmc->clock))
221                 return -1;
222
223         /* Clear internal divider */
224         rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
225         writel(rval, &priv->reg->clkcr);
226
227         /* Re-enable Clock */
228         rval |= SUNXI_MMC_CLK_ENABLE;
229         writel(rval, &priv->reg->clkcr);
230         if (mmc_update_clk(priv))
231                 return -1;
232
233         return 0;
234 }
235
236 static int sunxi_mmc_set_ios_common(struct sunxi_mmc_priv *priv,
237                                     struct mmc *mmc)
238 {
239         debug("set ios: bus_width: %x, clock: %d\n",
240               mmc->bus_width, mmc->clock);
241
242         /* Change clock first */
243         if (mmc->clock && mmc_config_clock(priv, mmc) != 0) {
244                 priv->fatal_err = 1;
245                 return -EINVAL;
246         }
247
248         /* Change bus width */
249         if (mmc->bus_width == 8)
250                 writel(0x2, &priv->reg->width);
251         else if (mmc->bus_width == 4)
252                 writel(0x1, &priv->reg->width);
253         else
254                 writel(0x0, &priv->reg->width);
255
256         return 0;
257 }
258
259 #if !CONFIG_IS_ENABLED(DM_MMC)
260 static int sunxi_mmc_core_init(struct mmc *mmc)
261 {
262         struct sunxi_mmc_priv *priv = mmc->priv;
263
264         /* Reset controller */
265         writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
266         udelay(1000);
267
268         return 0;
269 }
270 #endif
271
272 static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
273                                  struct mmc_data *data)
274 {
275         const int reading = !!(data->flags & MMC_DATA_READ);
276         const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY :
277                                               SUNXI_MMC_STATUS_FIFO_FULL;
278         unsigned i;
279         unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
280         unsigned byte_cnt = data->blocksize * data->blocks;
281         unsigned timeout_msecs = byte_cnt >> 8;
282         unsigned long  start;
283
284         if (timeout_msecs < 2000)
285                 timeout_msecs = 2000;
286
287         /* Always read / write data through the CPU */
288         setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
289
290         start = get_timer(0);
291
292         for (i = 0; i < (byte_cnt >> 2); i++) {
293                 while (readl(&priv->reg->status) & status_bit) {
294                         if (get_timer(start) > timeout_msecs)
295                                 return -1;
296                 }
297
298                 if (reading)
299                         buff[i] = readl(&priv->reg->fifo);
300                 else
301                         writel(buff[i], &priv->reg->fifo);
302         }
303
304         return 0;
305 }
306
307 static int mmc_rint_wait(struct sunxi_mmc_priv *priv, struct mmc *mmc,
308                          uint timeout_msecs, uint done_bit, const char *what)
309 {
310         unsigned int status;
311         unsigned long start = get_timer(0);
312
313         do {
314                 status = readl(&priv->reg->rint);
315                 if ((get_timer(start) > timeout_msecs) ||
316                     (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) {
317                         debug("%s timeout %x\n", what,
318                               status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT);
319                         return -ETIMEDOUT;
320                 }
321         } while (!(status & done_bit));
322
323         return 0;
324 }
325
326 static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv,
327                                      struct mmc *mmc, struct mmc_cmd *cmd,
328                                      struct mmc_data *data)
329 {
330         unsigned int cmdval = SUNXI_MMC_CMD_START;
331         unsigned int timeout_msecs;
332         int error = 0;
333         unsigned int status = 0;
334         unsigned int bytecnt = 0;
335
336         if (priv->fatal_err)
337                 return -1;
338         if (cmd->resp_type & MMC_RSP_BUSY)
339                 debug("mmc cmd %d check rsp busy\n", cmd->cmdidx);
340         if (cmd->cmdidx == 12)
341                 return 0;
342
343         if (!cmd->cmdidx)
344                 cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ;
345         if (cmd->resp_type & MMC_RSP_PRESENT)
346                 cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE;
347         if (cmd->resp_type & MMC_RSP_136)
348                 cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE;
349         if (cmd->resp_type & MMC_RSP_CRC)
350                 cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC;
351
352         if (data) {
353                 if ((u32)(long)data->dest & 0x3) {
354                         error = -1;
355                         goto out;
356                 }
357
358                 cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER;
359                 if (data->flags & MMC_DATA_WRITE)
360                         cmdval |= SUNXI_MMC_CMD_WRITE;
361                 if (data->blocks > 1)
362                         cmdval |= SUNXI_MMC_CMD_AUTO_STOP;
363                 writel(data->blocksize, &priv->reg->blksz);
364                 writel(data->blocks * data->blocksize, &priv->reg->bytecnt);
365         }
366
367         debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", priv->mmc_no,
368               cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg);
369         writel(cmd->cmdarg, &priv->reg->arg);
370
371         if (!data)
372                 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
373
374         /*
375          * transfer data and check status
376          * STATREG[2] : FIFO empty
377          * STATREG[3] : FIFO full
378          */
379         if (data) {
380                 int ret = 0;
381
382                 bytecnt = data->blocksize * data->blocks;
383                 debug("trans data %d bytes\n", bytecnt);
384                 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
385                 ret = mmc_trans_data_by_cpu(priv, mmc, data);
386                 if (ret) {
387                         error = readl(&priv->reg->rint) &
388                                 SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
389                         error = -ETIMEDOUT;
390                         goto out;
391                 }
392         }
393
394         error = mmc_rint_wait(priv, mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE,
395                               "cmd");
396         if (error)
397                 goto out;
398
399         if (data) {
400                 timeout_msecs = 120;
401                 debug("cacl timeout %x msec\n", timeout_msecs);
402                 error = mmc_rint_wait(priv, mmc, timeout_msecs,
403                                       data->blocks > 1 ?
404                                       SUNXI_MMC_RINT_AUTO_COMMAND_DONE :
405                                       SUNXI_MMC_RINT_DATA_OVER,
406                                       "data");
407                 if (error)
408                         goto out;
409         }
410
411         if (cmd->resp_type & MMC_RSP_BUSY) {
412                 unsigned long start = get_timer(0);
413                 timeout_msecs = 2000;
414
415                 do {
416                         status = readl(&priv->reg->status);
417                         if (get_timer(start) > timeout_msecs) {
418                                 debug("busy timeout\n");
419                                 error = -ETIMEDOUT;
420                                 goto out;
421                         }
422                 } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY);
423         }
424
425         if (cmd->resp_type & MMC_RSP_136) {
426                 cmd->response[0] = readl(&priv->reg->resp3);
427                 cmd->response[1] = readl(&priv->reg->resp2);
428                 cmd->response[2] = readl(&priv->reg->resp1);
429                 cmd->response[3] = readl(&priv->reg->resp0);
430                 debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n",
431                       cmd->response[3], cmd->response[2],
432                       cmd->response[1], cmd->response[0]);
433         } else {
434                 cmd->response[0] = readl(&priv->reg->resp0);
435                 debug("mmc resp 0x%08x\n", cmd->response[0]);
436         }
437 out:
438         if (error < 0) {
439                 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
440                 mmc_update_clk(priv);
441         }
442         writel(0xffffffff, &priv->reg->rint);
443         writel(readl(&priv->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET,
444                &priv->reg->gctrl);
445
446         return error;
447 }
448
449 #if !CONFIG_IS_ENABLED(DM_MMC)
450 static int sunxi_mmc_set_ios_legacy(struct mmc *mmc)
451 {
452         struct sunxi_mmc_priv *priv = mmc->priv;
453
454         return sunxi_mmc_set_ios_common(priv, mmc);
455 }
456
457 static int sunxi_mmc_send_cmd_legacy(struct mmc *mmc, struct mmc_cmd *cmd,
458                                      struct mmc_data *data)
459 {
460         struct sunxi_mmc_priv *priv = mmc->priv;
461
462         return sunxi_mmc_send_cmd_common(priv, mmc, cmd, data);
463 }
464
465 static int sunxi_mmc_getcd_legacy(struct mmc *mmc)
466 {
467         struct sunxi_mmc_priv *priv = mmc->priv;
468         int cd_pin;
469
470         cd_pin = sunxi_mmc_getcd_gpio(priv->mmc_no);
471         if (cd_pin < 0)
472                 return 1;
473
474         return !gpio_get_value(cd_pin);
475 }
476
477 static const struct mmc_ops sunxi_mmc_ops = {
478         .send_cmd       = sunxi_mmc_send_cmd_legacy,
479         .set_ios        = sunxi_mmc_set_ios_legacy,
480         .init           = sunxi_mmc_core_init,
481         .getcd          = sunxi_mmc_getcd_legacy,
482 };
483
484 struct mmc *sunxi_mmc_init(int sdc_no)
485 {
486         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
487         struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
488         struct mmc_config *cfg = &priv->cfg;
489         int ret;
490
491         memset(priv, '\0', sizeof(struct sunxi_mmc_priv));
492
493         cfg->name = "SUNXI SD/MMC";
494         cfg->ops  = &sunxi_mmc_ops;
495
496         cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
497         cfg->host_caps = MMC_MODE_4BIT;
498 #if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I)
499         if (sdc_no == 2)
500                 cfg->host_caps = MMC_MODE_8BIT;
501 #endif
502         cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
503         cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
504
505         cfg->f_min = 400000;
506         cfg->f_max = 52000000;
507
508         if (mmc_resource_init(sdc_no) != 0)
509                 return NULL;
510
511         /* config ahb clock */
512         debug("init mmc %d clock and io\n", sdc_no);
513         setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
514
515 #ifdef CONFIG_SUNXI_GEN_SUN6I
516         /* unassert reset */
517         setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no));
518 #endif
519 #if defined(CONFIG_MACH_SUN9I)
520         /* sun9i has a mmc-common module, also set the gate and reset there */
521         writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET,
522                SUNXI_MMC_COMMON_BASE + 4 * sdc_no);
523 #endif
524         ret = mmc_set_mod_clk(priv, 24000000);
525         if (ret)
526                 return NULL;
527
528         return mmc_create(cfg, priv);
529 }
530 #else
531
532 static int sunxi_mmc_set_ios(struct udevice *dev)
533 {
534         struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
535         struct sunxi_mmc_priv *priv = dev_get_priv(dev);
536
537         return sunxi_mmc_set_ios_common(priv, &plat->mmc);
538 }
539
540 static int sunxi_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
541                               struct mmc_data *data)
542 {
543         struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
544         struct sunxi_mmc_priv *priv = dev_get_priv(dev);
545
546         return sunxi_mmc_send_cmd_common(priv, &plat->mmc, cmd, data);
547 }
548
549 static int sunxi_mmc_getcd(struct udevice *dev)
550 {
551         struct sunxi_mmc_priv *priv = dev_get_priv(dev);
552
553         if (dm_gpio_is_valid(&priv->cd_gpio)) {
554                 int cd_state = dm_gpio_get_value(&priv->cd_gpio);
555
556                 return cd_state ^ priv->cd_inverted;
557         }
558         return 1;
559 }
560
561 static const struct dm_mmc_ops sunxi_mmc_ops = {
562         .send_cmd       = sunxi_mmc_send_cmd,
563         .set_ios        = sunxi_mmc_set_ios,
564         .get_cd         = sunxi_mmc_getcd,
565 };
566
567 static int sunxi_mmc_probe(struct udevice *dev)
568 {
569         struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
570         struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
571         struct sunxi_mmc_priv *priv = dev_get_priv(dev);
572         struct mmc_config *cfg = &plat->cfg;
573         struct ofnode_phandle_args args;
574         u32 *gate_reg;
575         int bus_width, ret;
576
577         cfg->name = dev->name;
578         bus_width = dev_read_u32_default(dev, "bus-width", 1);
579
580         cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
581         cfg->host_caps = 0;
582         if (bus_width == 8)
583                 cfg->host_caps |= MMC_MODE_8BIT;
584         if (bus_width >= 4)
585                 cfg->host_caps |= MMC_MODE_4BIT;
586         cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
587         cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
588
589         cfg->f_min = 400000;
590         cfg->f_max = 52000000;
591
592         priv->reg = (void *)dev_read_addr(dev);
593
594         /* We don't have a sunxi clock driver so find the clock address here */
595         ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
596                                           1, &args);
597         if (ret)
598                 return ret;
599         priv->mclkreg = (u32 *)ofnode_get_addr(args.node);
600
601         ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
602                                           0, &args);
603         if (ret)
604                 return ret;
605         gate_reg = (u32 *)ofnode_get_addr(args.node);
606         setbits_le32(gate_reg, 1 << args.args[0]);
607         priv->mmc_no = args.args[0] - 8;
608
609         ret = mmc_set_mod_clk(priv, 24000000);
610         if (ret)
611                 return ret;
612
613         /* This GPIO is optional */
614         if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
615                                   GPIOD_IS_IN)) {
616                 int cd_pin = gpio_get_number(&priv->cd_gpio);
617
618                 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
619         }
620
621         /* Check if card detect is inverted */
622         priv->cd_inverted = dev_read_bool(dev, "cd-inverted");
623
624         upriv->mmc = &plat->mmc;
625
626         /* Reset controller */
627         writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
628         udelay(1000);
629
630         return 0;
631 }
632
633 static int sunxi_mmc_bind(struct udevice *dev)
634 {
635         struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
636
637         return mmc_bind(dev, &plat->mmc, &plat->cfg);
638 }
639
640 static const struct udevice_id sunxi_mmc_ids[] = {
641         { .compatible = "allwinner,sun5i-a13-mmc" },
642         { }
643 };
644
645 U_BOOT_DRIVER(sunxi_mmc_drv) = {
646         .name           = "sunxi_mmc",
647         .id             = UCLASS_MMC,
648         .of_match       = sunxi_mmc_ids,
649         .bind           = sunxi_mmc_bind,
650         .probe          = sunxi_mmc_probe,
651         .ops            = &sunxi_mmc_ops,
652         .platdata_auto_alloc_size = sizeof(struct sunxi_mmc_plat),
653         .priv_auto_alloc_size = sizeof(struct sunxi_mmc_priv),
654 };
655 #endif