blob: 0c443a732d5354944233505686c959279979893a [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Ian Campbelle24ea552014-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 Campbelle24ea552014-05-05 14:42:31 +01008 */
9
10#include <common.h>
Simon Glassdd279182017-07-04 13:31:27 -060011#include <dm.h>
Hans de Goede90641f82015-04-22 17:03:17 +020012#include <errno.h>
Ian Campbelle24ea552014-05-05 14:42:31 +010013#include <malloc.h>
14#include <mmc.h>
15#include <asm/io.h>
16#include <asm/arch/clock.h>
17#include <asm/arch/cpu.h>
Hans de Goedecd821132014-10-02 20:29:26 +020018#include <asm/arch/gpio.h>
Ian Campbelle24ea552014-05-05 14:42:31 +010019#include <asm/arch/mmc.h>
Hans de Goedecd821132014-10-02 20:29:26 +020020#include <asm-generic/gpio.h>
Ian Campbelle24ea552014-05-05 14:42:31 +010021
Jagan Tekie8f37f42019-01-09 16:58:39 +053022#ifdef CONFIG_DM_MMC
23struct sunxi_mmc_variant {
24 u16 gate_offset;
25 u16 mclk_offset;
26};
27#endif
28
Simon Glassdd279182017-07-04 13:31:27 -060029struct sunxi_mmc_plat {
30 struct mmc_config cfg;
31 struct mmc mmc;
32};
33
Simon Glasse3c794e2017-07-04 13:31:23 -060034struct sunxi_mmc_priv {
Ian Campbelle24ea552014-05-05 14:42:31 +010035 unsigned mmc_no;
36 uint32_t *mclkreg;
Ian Campbelle24ea552014-05-05 14:42:31 +010037 unsigned fatal_err;
Simon Glassdd279182017-07-04 13:31:27 -060038 struct gpio_desc cd_gpio; /* Change Detect GPIO */
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +010039 int cd_inverted; /* Inverted Card Detect */
Ian Campbelle24ea552014-05-05 14:42:31 +010040 struct sunxi_mmc *reg;
41 struct mmc_config cfg;
Jagan Tekie8f37f42019-01-09 16:58:39 +053042#ifdef CONFIG_DM_MMC
43 const struct sunxi_mmc_variant *variant;
44#endif
Ian Campbelle24ea552014-05-05 14:42:31 +010045};
46
Simon Glassdd279182017-07-04 13:31:27 -060047#if !CONFIG_IS_ENABLED(DM_MMC)
Ian Campbelle24ea552014-05-05 14:42:31 +010048/* support 4 mmc hosts */
Simon Glasse3c794e2017-07-04 13:31:23 -060049struct sunxi_mmc_priv mmc_host[4];
Ian Campbelle24ea552014-05-05 14:42:31 +010050
Hans de Goede967325f2014-10-31 16:55:02 +010051static int sunxi_mmc_getcd_gpio(int sdc_no)
52{
53 switch (sdc_no) {
54 case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN);
55 case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN);
56 case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN);
57 case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN);
58 }
Hans de Goede90641f82015-04-22 17:03:17 +020059 return -EINVAL;
Hans de Goede967325f2014-10-31 16:55:02 +010060}
61
Ian Campbelle24ea552014-05-05 14:42:31 +010062static int mmc_resource_init(int sdc_no)
63{
Simon Glass3f5af122017-07-04 13:31:24 -060064 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
Ian Campbelle24ea552014-05-05 14:42:31 +010065 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede967325f2014-10-31 16:55:02 +010066 int cd_pin, ret = 0;
Ian Campbelle24ea552014-05-05 14:42:31 +010067
68 debug("init mmc %d resource\n", sdc_no);
69
70 switch (sdc_no) {
71 case 0:
Simon Glass3f5af122017-07-04 13:31:24 -060072 priv->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
73 priv->mclkreg = &ccm->sd0_clk_cfg;
Ian Campbelle24ea552014-05-05 14:42:31 +010074 break;
75 case 1:
Simon Glass3f5af122017-07-04 13:31:24 -060076 priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
77 priv->mclkreg = &ccm->sd1_clk_cfg;
Ian Campbelle24ea552014-05-05 14:42:31 +010078 break;
79 case 2:
Simon Glass3f5af122017-07-04 13:31:24 -060080 priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
81 priv->mclkreg = &ccm->sd2_clk_cfg;
Ian Campbelle24ea552014-05-05 14:42:31 +010082 break;
Icenowy Zheng42956f12018-07-21 16:20:29 +080083#ifdef SUNXI_MMC3_BASE
Ian Campbelle24ea552014-05-05 14:42:31 +010084 case 3:
Simon Glass3f5af122017-07-04 13:31:24 -060085 priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
86 priv->mclkreg = &ccm->sd3_clk_cfg;
Ian Campbelle24ea552014-05-05 14:42:31 +010087 break;
Icenowy Zheng42956f12018-07-21 16:20:29 +080088#endif
Ian Campbelle24ea552014-05-05 14:42:31 +010089 default:
90 printf("Wrong mmc number %d\n", sdc_no);
91 return -1;
92 }
Simon Glass3f5af122017-07-04 13:31:24 -060093 priv->mmc_no = sdc_no;
Ian Campbelle24ea552014-05-05 14:42:31 +010094
Hans de Goede967325f2014-10-31 16:55:02 +010095 cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
Hans de Goede90641f82015-04-22 17:03:17 +020096 if (cd_pin >= 0) {
Hans de Goede967325f2014-10-31 16:55:02 +010097 ret = gpio_request(cd_pin, "mmc_cd");
Hans de Goede1c09fa32015-05-30 16:39:10 +020098 if (!ret) {
99 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
Axel Linb0c4ae12014-12-20 11:41:25 +0800100 ret = gpio_direction_input(cd_pin);
Hans de Goede1c09fa32015-05-30 16:39:10 +0200101 }
Axel Linb0c4ae12014-12-20 11:41:25 +0800102 }
Hans de Goede967325f2014-10-31 16:55:02 +0100103
104 return ret;
Ian Campbelle24ea552014-05-05 14:42:31 +0100105}
Simon Glassdd279182017-07-04 13:31:27 -0600106#endif
Ian Campbelle24ea552014-05-05 14:42:31 +0100107
Simon Glass3f5af122017-07-04 13:31:24 -0600108static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
Hans de Goedefc3a8322014-12-07 20:55:10 +0100109{
110 unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
Vasily Khoruzhick0e21a2f2018-11-09 20:41:46 -0800111 bool new_mode = true;
Vasily Khoruzhick20940ef2018-11-05 20:24:28 -0800112 bool calibrate = false;
Maxime Ripardde9b1772017-08-23 12:03:41 +0200113 u32 val = 0;
114
Vasily Khoruzhick0e21a2f2018-11-09 20:41:46 -0800115 if (!IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE))
116 new_mode = false;
117
118 /* A83T support new mode only on eMMC */
119 if (IS_ENABLED(CONFIG_MACH_SUN8I_A83T) && priv->mmc_no != 2)
120 new_mode = false;
Maxime Ripardde9b1772017-08-23 12:03:41 +0200121
Vasily Khoruzhick20940ef2018-11-05 20:24:28 -0800122#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6)
123 calibrate = true;
124#endif
125
Hans de Goedefc3a8322014-12-07 20:55:10 +0100126 if (hz <= 24000000) {
127 pll = CCM_MMC_CTRL_OSCM24;
128 pll_hz = 24000000;
129 } else {
Hans de Goededaf22632015-01-14 19:05:03 +0100130#ifdef CONFIG_MACH_SUN9I
131 pll = CCM_MMC_CTRL_PLL_PERIPH0;
132 pll_hz = clock_get_pll4_periph0();
Icenowy Zheng42956f12018-07-21 16:20:29 +0800133#elif defined(CONFIG_MACH_SUN50I_H6)
134 pll = CCM_MMC_CTRL_PLL6X2;
135 pll_hz = clock_get_pll6() * 2;
Hans de Goededaf22632015-01-14 19:05:03 +0100136#else
Hans de Goedefc3a8322014-12-07 20:55:10 +0100137 pll = CCM_MMC_CTRL_PLL6;
138 pll_hz = clock_get_pll6();
Hans de Goededaf22632015-01-14 19:05:03 +0100139#endif
Hans de Goedefc3a8322014-12-07 20:55:10 +0100140 }
141
142 div = pll_hz / hz;
143 if (pll_hz % hz)
144 div++;
145
146 n = 0;
147 while (div > 16) {
148 n++;
149 div = (div + 1) / 2;
150 }
151
152 if (n > 3) {
Simon Glass3f5af122017-07-04 13:31:24 -0600153 printf("mmc %u error cannot set clock to %u\n", priv->mmc_no,
154 hz);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100155 return -1;
156 }
157
158 /* determine delays */
159 if (hz <= 400000) {
160 oclk_dly = 0;
Hans de Goedebe909742015-09-23 16:13:10 +0200161 sclk_dly = 0;
Hans de Goedefc3a8322014-12-07 20:55:10 +0100162 } else if (hz <= 25000000) {
163 oclk_dly = 0;
164 sclk_dly = 5;
Hans de Goedebe909742015-09-23 16:13:10 +0200165#ifdef CONFIG_MACH_SUN9I
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300166 } else if (hz <= 52000000) {
Hans de Goedebe909742015-09-23 16:13:10 +0200167 oclk_dly = 5;
168 sclk_dly = 4;
Hans de Goedefc3a8322014-12-07 20:55:10 +0100169 } else {
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300170 /* hz > 52000000 */
Hans de Goedefc3a8322014-12-07 20:55:10 +0100171 oclk_dly = 2;
172 sclk_dly = 4;
Hans de Goedebe909742015-09-23 16:13:10 +0200173#else
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300174 } else if (hz <= 52000000) {
Hans de Goedebe909742015-09-23 16:13:10 +0200175 oclk_dly = 3;
176 sclk_dly = 4;
177 } else {
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300178 /* hz > 52000000 */
Hans de Goedebe909742015-09-23 16:13:10 +0200179 oclk_dly = 1;
180 sclk_dly = 4;
181#endif
Hans de Goedefc3a8322014-12-07 20:55:10 +0100182 }
183
Maxime Ripardde9b1772017-08-23 12:03:41 +0200184 if (new_mode) {
185#ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE
Vasily Khoruzhick2a8882e2018-11-09 20:41:44 -0800186#ifdef CONFIG_MMC_SUNXI_HAS_MODE_SWITCH
Maxime Ripardde9b1772017-08-23 12:03:41 +0200187 val = CCM_MMC_CTRL_MODE_SEL_NEW;
Vasily Khoruzhick2a8882e2018-11-09 20:41:44 -0800188#endif
Chen-Yu Tsai8a647fc2017-08-31 21:57:48 +0800189 setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW);
Maxime Ripardde9b1772017-08-23 12:03:41 +0200190#endif
Vasily Khoruzhick20940ef2018-11-05 20:24:28 -0800191 } else if (!calibrate) {
192 /*
193 * Use hardcoded delay values if controller doesn't support
194 * calibration
195 */
Maxime Ripardde9b1772017-08-23 12:03:41 +0200196 val = CCM_MMC_CTRL_OCLK_DLY(oclk_dly) |
197 CCM_MMC_CTRL_SCLK_DLY(sclk_dly);
198 }
199
200 writel(CCM_MMC_CTRL_ENABLE| pll | CCM_MMC_CTRL_N(n) |
201 CCM_MMC_CTRL_M(div) | val, priv->mclkreg);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100202
203 debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n",
Simon Glass3f5af122017-07-04 13:31:24 -0600204 priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100205
206 return 0;
207}
208
Simon Glass034e2262017-07-04 13:31:25 -0600209static int mmc_update_clk(struct sunxi_mmc_priv *priv)
Ian Campbelle24ea552014-05-05 14:42:31 +0100210{
Ian Campbelle24ea552014-05-05 14:42:31 +0100211 unsigned int cmd;
212 unsigned timeout_msecs = 2000;
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100213 unsigned long start = get_timer(0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100214
215 cmd = SUNXI_MMC_CMD_START |
216 SUNXI_MMC_CMD_UPCLK_ONLY |
217 SUNXI_MMC_CMD_WAIT_PRE_OVER;
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100218
Simon Glass3f5af122017-07-04 13:31:24 -0600219 writel(cmd, &priv->reg->cmd);
220 while (readl(&priv->reg->cmd) & SUNXI_MMC_CMD_START) {
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100221 if (get_timer(start) > timeout_msecs)
Ian Campbelle24ea552014-05-05 14:42:31 +0100222 return -1;
Ian Campbelle24ea552014-05-05 14:42:31 +0100223 }
224
225 /* clock update sets various irq status bits, clear these */
Simon Glass3f5af122017-07-04 13:31:24 -0600226 writel(readl(&priv->reg->rint), &priv->reg->rint);
Ian Campbelle24ea552014-05-05 14:42:31 +0100227
228 return 0;
229}
230
Simon Glass034e2262017-07-04 13:31:25 -0600231static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc)
Ian Campbelle24ea552014-05-05 14:42:31 +0100232{
Simon Glass3f5af122017-07-04 13:31:24 -0600233 unsigned rval = readl(&priv->reg->clkcr);
Ian Campbelle24ea552014-05-05 14:42:31 +0100234
235 /* Disable Clock */
236 rval &= ~SUNXI_MMC_CLK_ENABLE;
Simon Glass3f5af122017-07-04 13:31:24 -0600237 writel(rval, &priv->reg->clkcr);
Simon Glass034e2262017-07-04 13:31:25 -0600238 if (mmc_update_clk(priv))
Ian Campbelle24ea552014-05-05 14:42:31 +0100239 return -1;
240
Hans de Goedefc3a8322014-12-07 20:55:10 +0100241 /* Set mod_clk to new rate */
Simon Glass3f5af122017-07-04 13:31:24 -0600242 if (mmc_set_mod_clk(priv, mmc->clock))
Ian Campbelle24ea552014-05-05 14:42:31 +0100243 return -1;
Hans de Goedefc3a8322014-12-07 20:55:10 +0100244
245 /* Clear internal divider */
246 rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
Simon Glass3f5af122017-07-04 13:31:24 -0600247 writel(rval, &priv->reg->clkcr);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100248
Vasily Khoruzhick20940ef2018-11-05 20:24:28 -0800249#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6)
250 /* A64 supports calibration of delays on MMC controller and we
251 * have to set delay of zero before starting calibration.
252 * Allwinner BSP driver sets a delay only in the case of
253 * using HS400 which is not supported by mainline U-Boot or
254 * Linux at the moment
255 */
256 writel(SUNXI_MMC_CAL_DL_SW_EN, &priv->reg->samp_dl);
257#endif
258
Ian Campbelle24ea552014-05-05 14:42:31 +0100259 /* Re-enable Clock */
260 rval |= SUNXI_MMC_CLK_ENABLE;
Simon Glass3f5af122017-07-04 13:31:24 -0600261 writel(rval, &priv->reg->clkcr);
Simon Glass034e2262017-07-04 13:31:25 -0600262 if (mmc_update_clk(priv))
Ian Campbelle24ea552014-05-05 14:42:31 +0100263 return -1;
264
265 return 0;
266}
267
Simon Glass034e2262017-07-04 13:31:25 -0600268static int sunxi_mmc_set_ios_common(struct sunxi_mmc_priv *priv,
269 struct mmc *mmc)
Ian Campbelle24ea552014-05-05 14:42:31 +0100270{
Hans de Goedefc3a8322014-12-07 20:55:10 +0100271 debug("set ios: bus_width: %x, clock: %d\n",
272 mmc->bus_width, mmc->clock);
Ian Campbelle24ea552014-05-05 14:42:31 +0100273
274 /* Change clock first */
Simon Glass034e2262017-07-04 13:31:25 -0600275 if (mmc->clock && mmc_config_clock(priv, mmc) != 0) {
Simon Glass3f5af122017-07-04 13:31:24 -0600276 priv->fatal_err = 1;
Jaehoon Chung07b0b9c2016-12-30 15:30:16 +0900277 return -EINVAL;
Ian Campbelle24ea552014-05-05 14:42:31 +0100278 }
279
280 /* Change bus width */
281 if (mmc->bus_width == 8)
Simon Glass3f5af122017-07-04 13:31:24 -0600282 writel(0x2, &priv->reg->width);
Ian Campbelle24ea552014-05-05 14:42:31 +0100283 else if (mmc->bus_width == 4)
Simon Glass3f5af122017-07-04 13:31:24 -0600284 writel(0x1, &priv->reg->width);
Ian Campbelle24ea552014-05-05 14:42:31 +0100285 else
Simon Glass3f5af122017-07-04 13:31:24 -0600286 writel(0x0, &priv->reg->width);
Jaehoon Chung07b0b9c2016-12-30 15:30:16 +0900287
288 return 0;
Ian Campbelle24ea552014-05-05 14:42:31 +0100289}
290
Simon Glassdd279182017-07-04 13:31:27 -0600291#if !CONFIG_IS_ENABLED(DM_MMC)
Siarhei Siamashka5abdb152015-02-01 00:42:14 +0200292static int sunxi_mmc_core_init(struct mmc *mmc)
Ian Campbelle24ea552014-05-05 14:42:31 +0100293{
Simon Glass3f5af122017-07-04 13:31:24 -0600294 struct sunxi_mmc_priv *priv = mmc->priv;
Ian Campbelle24ea552014-05-05 14:42:31 +0100295
296 /* Reset controller */
Simon Glass3f5af122017-07-04 13:31:24 -0600297 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200298 udelay(1000);
Ian Campbelle24ea552014-05-05 14:42:31 +0100299
300 return 0;
301}
Simon Glassdd279182017-07-04 13:31:27 -0600302#endif
Ian Campbelle24ea552014-05-05 14:42:31 +0100303
Simon Glass034e2262017-07-04 13:31:25 -0600304static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
305 struct mmc_data *data)
Ian Campbelle24ea552014-05-05 14:42:31 +0100306{
Ian Campbelle24ea552014-05-05 14:42:31 +0100307 const int reading = !!(data->flags & MMC_DATA_READ);
308 const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY :
309 SUNXI_MMC_STATUS_FIFO_FULL;
310 unsigned i;
Ian Campbelle24ea552014-05-05 14:42:31 +0100311 unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
Yousong Zhou28f69b92015-08-29 21:26:11 +0800312 unsigned byte_cnt = data->blocksize * data->blocks;
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100313 unsigned timeout_msecs = byte_cnt >> 8;
314 unsigned long start;
315
316 if (timeout_msecs < 2000)
317 timeout_msecs = 2000;
Ian Campbelle24ea552014-05-05 14:42:31 +0100318
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200319 /* Always read / write data through the CPU */
Simon Glass3f5af122017-07-04 13:31:24 -0600320 setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200321
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100322 start = get_timer(0);
323
Ian Campbelle24ea552014-05-05 14:42:31 +0100324 for (i = 0; i < (byte_cnt >> 2); i++) {
Simon Glass3f5af122017-07-04 13:31:24 -0600325 while (readl(&priv->reg->status) & status_bit) {
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100326 if (get_timer(start) > timeout_msecs)
Ian Campbelle24ea552014-05-05 14:42:31 +0100327 return -1;
Ian Campbelle24ea552014-05-05 14:42:31 +0100328 }
329
330 if (reading)
Simon Glass3f5af122017-07-04 13:31:24 -0600331 buff[i] = readl(&priv->reg->fifo);
Ian Campbelle24ea552014-05-05 14:42:31 +0100332 else
Simon Glass3f5af122017-07-04 13:31:24 -0600333 writel(buff[i], &priv->reg->fifo);
Ian Campbelle24ea552014-05-05 14:42:31 +0100334 }
335
336 return 0;
337}
338
Simon Glass034e2262017-07-04 13:31:25 -0600339static int mmc_rint_wait(struct sunxi_mmc_priv *priv, struct mmc *mmc,
340 uint timeout_msecs, uint done_bit, const char *what)
Ian Campbelle24ea552014-05-05 14:42:31 +0100341{
Ian Campbelle24ea552014-05-05 14:42:31 +0100342 unsigned int status;
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100343 unsigned long start = get_timer(0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100344
345 do {
Simon Glass3f5af122017-07-04 13:31:24 -0600346 status = readl(&priv->reg->rint);
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100347 if ((get_timer(start) > timeout_msecs) ||
Ian Campbelle24ea552014-05-05 14:42:31 +0100348 (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) {
349 debug("%s timeout %x\n", what,
350 status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT);
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900351 return -ETIMEDOUT;
Ian Campbelle24ea552014-05-05 14:42:31 +0100352 }
Ian Campbelle24ea552014-05-05 14:42:31 +0100353 } while (!(status & done_bit));
354
355 return 0;
356}
357
Simon Glass034e2262017-07-04 13:31:25 -0600358static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv,
359 struct mmc *mmc, struct mmc_cmd *cmd,
360 struct mmc_data *data)
Ian Campbelle24ea552014-05-05 14:42:31 +0100361{
Ian Campbelle24ea552014-05-05 14:42:31 +0100362 unsigned int cmdval = SUNXI_MMC_CMD_START;
363 unsigned int timeout_msecs;
364 int error = 0;
365 unsigned int status = 0;
Ian Campbelle24ea552014-05-05 14:42:31 +0100366 unsigned int bytecnt = 0;
367
Simon Glass3f5af122017-07-04 13:31:24 -0600368 if (priv->fatal_err)
Ian Campbelle24ea552014-05-05 14:42:31 +0100369 return -1;
370 if (cmd->resp_type & MMC_RSP_BUSY)
371 debug("mmc cmd %d check rsp busy\n", cmd->cmdidx);
372 if (cmd->cmdidx == 12)
373 return 0;
374
375 if (!cmd->cmdidx)
376 cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ;
377 if (cmd->resp_type & MMC_RSP_PRESENT)
378 cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE;
379 if (cmd->resp_type & MMC_RSP_136)
380 cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE;
381 if (cmd->resp_type & MMC_RSP_CRC)
382 cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC;
383
384 if (data) {
Alexander Graf0ea5a042016-03-29 17:29:09 +0200385 if ((u32)(long)data->dest & 0x3) {
Ian Campbelle24ea552014-05-05 14:42:31 +0100386 error = -1;
387 goto out;
388 }
389
390 cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER;
391 if (data->flags & MMC_DATA_WRITE)
392 cmdval |= SUNXI_MMC_CMD_WRITE;
393 if (data->blocks > 1)
394 cmdval |= SUNXI_MMC_CMD_AUTO_STOP;
Simon Glass3f5af122017-07-04 13:31:24 -0600395 writel(data->blocksize, &priv->reg->blksz);
396 writel(data->blocks * data->blocksize, &priv->reg->bytecnt);
Ian Campbelle24ea552014-05-05 14:42:31 +0100397 }
398
Simon Glass3f5af122017-07-04 13:31:24 -0600399 debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", priv->mmc_no,
Ian Campbelle24ea552014-05-05 14:42:31 +0100400 cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg);
Simon Glass3f5af122017-07-04 13:31:24 -0600401 writel(cmd->cmdarg, &priv->reg->arg);
Ian Campbelle24ea552014-05-05 14:42:31 +0100402
403 if (!data)
Simon Glass3f5af122017-07-04 13:31:24 -0600404 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
Ian Campbelle24ea552014-05-05 14:42:31 +0100405
406 /*
407 * transfer data and check status
408 * STATREG[2] : FIFO empty
409 * STATREG[3] : FIFO full
410 */
411 if (data) {
412 int ret = 0;
413
414 bytecnt = data->blocksize * data->blocks;
415 debug("trans data %d bytes\n", bytecnt);
Simon Glass3f5af122017-07-04 13:31:24 -0600416 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
Simon Glass034e2262017-07-04 13:31:25 -0600417 ret = mmc_trans_data_by_cpu(priv, mmc, data);
Ian Campbelle24ea552014-05-05 14:42:31 +0100418 if (ret) {
Simon Glass3f5af122017-07-04 13:31:24 -0600419 error = readl(&priv->reg->rint) &
Ian Campbelle24ea552014-05-05 14:42:31 +0100420 SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900421 error = -ETIMEDOUT;
Ian Campbelle24ea552014-05-05 14:42:31 +0100422 goto out;
423 }
424 }
425
Simon Glass034e2262017-07-04 13:31:25 -0600426 error = mmc_rint_wait(priv, mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE,
427 "cmd");
Ian Campbelle24ea552014-05-05 14:42:31 +0100428 if (error)
429 goto out;
430
431 if (data) {
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200432 timeout_msecs = 120;
Ian Campbelle24ea552014-05-05 14:42:31 +0100433 debug("cacl timeout %x msec\n", timeout_msecs);
Simon Glass034e2262017-07-04 13:31:25 -0600434 error = mmc_rint_wait(priv, mmc, timeout_msecs,
Ian Campbelle24ea552014-05-05 14:42:31 +0100435 data->blocks > 1 ?
436 SUNXI_MMC_RINT_AUTO_COMMAND_DONE :
437 SUNXI_MMC_RINT_DATA_OVER,
438 "data");
439 if (error)
440 goto out;
441 }
442
443 if (cmd->resp_type & MMC_RSP_BUSY) {
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100444 unsigned long start = get_timer(0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100445 timeout_msecs = 2000;
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100446
Ian Campbelle24ea552014-05-05 14:42:31 +0100447 do {
Simon Glass3f5af122017-07-04 13:31:24 -0600448 status = readl(&priv->reg->status);
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100449 if (get_timer(start) > timeout_msecs) {
Ian Campbelle24ea552014-05-05 14:42:31 +0100450 debug("busy timeout\n");
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900451 error = -ETIMEDOUT;
Ian Campbelle24ea552014-05-05 14:42:31 +0100452 goto out;
453 }
Ian Campbelle24ea552014-05-05 14:42:31 +0100454 } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY);
455 }
456
457 if (cmd->resp_type & MMC_RSP_136) {
Simon Glass3f5af122017-07-04 13:31:24 -0600458 cmd->response[0] = readl(&priv->reg->resp3);
459 cmd->response[1] = readl(&priv->reg->resp2);
460 cmd->response[2] = readl(&priv->reg->resp1);
461 cmd->response[3] = readl(&priv->reg->resp0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100462 debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n",
463 cmd->response[3], cmd->response[2],
464 cmd->response[1], cmd->response[0]);
465 } else {
Simon Glass3f5af122017-07-04 13:31:24 -0600466 cmd->response[0] = readl(&priv->reg->resp0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100467 debug("mmc resp 0x%08x\n", cmd->response[0]);
468 }
469out:
Ian Campbelle24ea552014-05-05 14:42:31 +0100470 if (error < 0) {
Simon Glass3f5af122017-07-04 13:31:24 -0600471 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
Simon Glass034e2262017-07-04 13:31:25 -0600472 mmc_update_clk(priv);
Ian Campbelle24ea552014-05-05 14:42:31 +0100473 }
Simon Glass3f5af122017-07-04 13:31:24 -0600474 writel(0xffffffff, &priv->reg->rint);
475 writel(readl(&priv->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET,
476 &priv->reg->gctrl);
Ian Campbelle24ea552014-05-05 14:42:31 +0100477
478 return error;
479}
480
Simon Glassdd279182017-07-04 13:31:27 -0600481#if !CONFIG_IS_ENABLED(DM_MMC)
Simon Glass034e2262017-07-04 13:31:25 -0600482static int sunxi_mmc_set_ios_legacy(struct mmc *mmc)
483{
484 struct sunxi_mmc_priv *priv = mmc->priv;
485
486 return sunxi_mmc_set_ios_common(priv, mmc);
487}
488
489static int sunxi_mmc_send_cmd_legacy(struct mmc *mmc, struct mmc_cmd *cmd,
490 struct mmc_data *data)
491{
492 struct sunxi_mmc_priv *priv = mmc->priv;
493
494 return sunxi_mmc_send_cmd_common(priv, mmc, cmd, data);
495}
496
497static int sunxi_mmc_getcd_legacy(struct mmc *mmc)
Hans de Goedecd821132014-10-02 20:29:26 +0200498{
Simon Glass3f5af122017-07-04 13:31:24 -0600499 struct sunxi_mmc_priv *priv = mmc->priv;
Hans de Goede967325f2014-10-31 16:55:02 +0100500 int cd_pin;
Hans de Goedecd821132014-10-02 20:29:26 +0200501
Simon Glass3f5af122017-07-04 13:31:24 -0600502 cd_pin = sunxi_mmc_getcd_gpio(priv->mmc_no);
Hans de Goede90641f82015-04-22 17:03:17 +0200503 if (cd_pin < 0)
Hans de Goedecd821132014-10-02 20:29:26 +0200504 return 1;
505
Axel Linb0c4ae12014-12-20 11:41:25 +0800506 return !gpio_get_value(cd_pin);
Hans de Goedecd821132014-10-02 20:29:26 +0200507}
508
Ian Campbelle24ea552014-05-05 14:42:31 +0100509static const struct mmc_ops sunxi_mmc_ops = {
Simon Glass034e2262017-07-04 13:31:25 -0600510 .send_cmd = sunxi_mmc_send_cmd_legacy,
511 .set_ios = sunxi_mmc_set_ios_legacy,
Siarhei Siamashka5abdb152015-02-01 00:42:14 +0200512 .init = sunxi_mmc_core_init,
Simon Glass034e2262017-07-04 13:31:25 -0600513 .getcd = sunxi_mmc_getcd_legacy,
Ian Campbelle24ea552014-05-05 14:42:31 +0100514};
515
Hans de Goedee79c7c82014-10-02 21:13:54 +0200516struct mmc *sunxi_mmc_init(int sdc_no)
Ian Campbelle24ea552014-05-05 14:42:31 +0100517{
Simon Glassec73d962017-07-04 13:31:26 -0600518 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Simon Glass034e2262017-07-04 13:31:25 -0600519 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
520 struct mmc_config *cfg = &priv->cfg;
Simon Glassec73d962017-07-04 13:31:26 -0600521 int ret;
Ian Campbelle24ea552014-05-05 14:42:31 +0100522
Simon Glass034e2262017-07-04 13:31:25 -0600523 memset(priv, '\0', sizeof(struct sunxi_mmc_priv));
Ian Campbelle24ea552014-05-05 14:42:31 +0100524
525 cfg->name = "SUNXI SD/MMC";
526 cfg->ops = &sunxi_mmc_ops;
527
528 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
529 cfg->host_caps = MMC_MODE_4BIT;
Icenowy Zheng42956f12018-07-21 16:20:29 +0800530#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) || defined(CONFIG_MACH_SUN50I_H6)
Siarhei Siamashkad96ebc42016-03-29 17:29:10 +0200531 if (sdc_no == 2)
532 cfg->host_caps = MMC_MODE_8BIT;
533#endif
Rob Herring5a203972015-03-23 17:56:59 -0500534 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
Ian Campbelle24ea552014-05-05 14:42:31 +0100535 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
536
537 cfg->f_min = 400000;
538 cfg->f_max = 52000000;
539
Hans de Goede967325f2014-10-31 16:55:02 +0100540 if (mmc_resource_init(sdc_no) != 0)
541 return NULL;
542
Simon Glassec73d962017-07-04 13:31:26 -0600543 /* config ahb clock */
544 debug("init mmc %d clock and io\n", sdc_no);
Icenowy Zheng42956f12018-07-21 16:20:29 +0800545#if !defined(CONFIG_MACH_SUN50I_H6)
Simon Glassec73d962017-07-04 13:31:26 -0600546 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
547
548#ifdef CONFIG_SUNXI_GEN_SUN6I
549 /* unassert reset */
550 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no));
551#endif
552#if defined(CONFIG_MACH_SUN9I)
553 /* sun9i has a mmc-common module, also set the gate and reset there */
554 writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET,
555 SUNXI_MMC_COMMON_BASE + 4 * sdc_no);
556#endif
Icenowy Zheng42956f12018-07-21 16:20:29 +0800557#else /* CONFIG_MACH_SUN50I_H6 */
558 setbits_le32(&ccm->sd_gate_reset, 1 << sdc_no);
559 /* unassert reset */
560 setbits_le32(&ccm->sd_gate_reset, 1 << (RESET_SHIFT + sdc_no));
561#endif
Simon Glassec73d962017-07-04 13:31:26 -0600562 ret = mmc_set_mod_clk(priv, 24000000);
563 if (ret)
564 return NULL;
Ian Campbelle24ea552014-05-05 14:42:31 +0100565
Maxime Ripardead36972017-08-23 13:41:33 +0200566 return mmc_create(cfg, priv);
Ian Campbelle24ea552014-05-05 14:42:31 +0100567}
Simon Glassdd279182017-07-04 13:31:27 -0600568#else
569
570static int sunxi_mmc_set_ios(struct udevice *dev)
571{
572 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
573 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
574
575 return sunxi_mmc_set_ios_common(priv, &plat->mmc);
576}
577
578static int sunxi_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
579 struct mmc_data *data)
580{
581 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
582 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
583
584 return sunxi_mmc_send_cmd_common(priv, &plat->mmc, cmd, data);
585}
586
587static int sunxi_mmc_getcd(struct udevice *dev)
588{
589 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
590
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +0100591 if (dm_gpio_is_valid(&priv->cd_gpio)) {
592 int cd_state = dm_gpio_get_value(&priv->cd_gpio);
Simon Glassdd279182017-07-04 13:31:27 -0600593
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +0100594 return cd_state ^ priv->cd_inverted;
595 }
Simon Glassdd279182017-07-04 13:31:27 -0600596 return 1;
597}
598
599static const struct dm_mmc_ops sunxi_mmc_ops = {
600 .send_cmd = sunxi_mmc_send_cmd,
601 .set_ios = sunxi_mmc_set_ios,
602 .get_cd = sunxi_mmc_getcd,
603};
604
605static int sunxi_mmc_probe(struct udevice *dev)
606{
607 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
608 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
609 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
610 struct mmc_config *cfg = &plat->cfg;
611 struct ofnode_phandle_args args;
Jagan Tekie8f37f42019-01-09 16:58:39 +0530612 u32 *gate_reg, *ccu_reg;
Simon Glassdd279182017-07-04 13:31:27 -0600613 int bus_width, ret;
614
615 cfg->name = dev->name;
616 bus_width = dev_read_u32_default(dev, "bus-width", 1);
617
618 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
619 cfg->host_caps = 0;
620 if (bus_width == 8)
621 cfg->host_caps |= MMC_MODE_8BIT;
622 if (bus_width >= 4)
623 cfg->host_caps |= MMC_MODE_4BIT;
624 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
625 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
626
627 cfg->f_min = 400000;
628 cfg->f_max = 52000000;
629
630 priv->reg = (void *)dev_read_addr(dev);
Jagan Tekie8f37f42019-01-09 16:58:39 +0530631 priv->variant =
632 (const struct sunxi_mmc_variant *)dev_get_driver_data(dev);
Simon Glassdd279182017-07-04 13:31:27 -0600633
634 /* We don't have a sunxi clock driver so find the clock address here */
635 ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
636 1, &args);
637 if (ret)
638 return ret;
Jagan Tekie8f37f42019-01-09 16:58:39 +0530639 ccu_reg = (u32 *)ofnode_get_addr(args.node);
Simon Glassdd279182017-07-04 13:31:27 -0600640
Jagan Tekie8f37f42019-01-09 16:58:39 +0530641 priv->mmc_no = ((uintptr_t)priv->reg - SUNXI_MMC0_BASE) / 0x1000;
642 priv->mclkreg = (void *)ccu_reg +
643 (priv->variant->mclk_offset + (priv->mmc_no * 4));
644 gate_reg = (void *)ccu_reg + priv->variant->gate_offset;
645 setbits_le32(gate_reg, BIT(AHB_GATE_OFFSET_MMC(priv->mmc_no)));
Simon Glassdd279182017-07-04 13:31:27 -0600646
647 ret = mmc_set_mod_clk(priv, 24000000);
648 if (ret)
649 return ret;
650
651 /* This GPIO is optional */
652 if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
653 GPIOD_IS_IN)) {
654 int cd_pin = gpio_get_number(&priv->cd_gpio);
655
656 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
657 }
658
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +0100659 /* Check if card detect is inverted */
660 priv->cd_inverted = dev_read_bool(dev, "cd-inverted");
661
Simon Glassdd279182017-07-04 13:31:27 -0600662 upriv->mmc = &plat->mmc;
663
664 /* Reset controller */
665 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
666 udelay(1000);
667
668 return 0;
669}
670
671static int sunxi_mmc_bind(struct udevice *dev)
672{
673 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
674
675 return mmc_bind(dev, &plat->mmc, &plat->cfg);
676}
677
Jagan Tekie8f37f42019-01-09 16:58:39 +0530678static const struct sunxi_mmc_variant sun4i_a10_variant = {
679 .gate_offset = 0x60,
680 .mclk_offset = 0x88,
681};
682
Jagan Teki3c8c7da2019-01-21 16:01:12 +0530683static const struct sunxi_mmc_variant sun9i_a80_variant = {
684 .mclk_offset = 0x410,
685};
686
Jagan Teki9e233382019-01-29 15:54:12 +0000687static const struct sunxi_mmc_variant sun50i_h6_variant = {
688 .mclk_offset = 0x830,
689};
690
Simon Glassdd279182017-07-04 13:31:27 -0600691static const struct udevice_id sunxi_mmc_ids[] = {
Jagan Tekie8f37f42019-01-09 16:58:39 +0530692 {
693 .compatible = "allwinner,sun4i-a10-mmc",
694 .data = (ulong)&sun4i_a10_variant,
695 },
696 {
697 .compatible = "allwinner,sun5i-a13-mmc",
698 .data = (ulong)&sun4i_a10_variant,
699 },
700 {
701 .compatible = "allwinner,sun7i-a20-mmc",
702 .data = (ulong)&sun4i_a10_variant,
703 },
Jagan Tekia1925a62019-01-29 15:54:11 +0000704 {
705 .compatible = "allwinner,sun8i-a83t-emmc",
706 .data = (ulong)&sun4i_a10_variant,
707 },
708 {
Jagan Teki3c8c7da2019-01-21 16:01:12 +0530709 .compatible = "allwinner,sun9i-a80-mmc",
710 .data = (ulong)&sun9i_a80_variant,
711 },
712 {
Jagan Tekia1925a62019-01-29 15:54:11 +0000713 .compatible = "allwinner,sun50i-a64-mmc",
714 .data = (ulong)&sun4i_a10_variant,
715 },
716 {
717 .compatible = "allwinner,sun50i-a64-emmc",
718 .data = (ulong)&sun4i_a10_variant,
719 },
Jagan Teki9e233382019-01-29 15:54:12 +0000720 {
721 .compatible = "allwinner,sun50i-h6-mmc",
722 .data = (ulong)&sun50i_h6_variant,
723 },
724 {
725 .compatible = "allwinner,sun50i-h6-emmc",
726 .data = (ulong)&sun50i_h6_variant,
727 },
Jagan Tekie8f37f42019-01-09 16:58:39 +0530728 { /* sentinel */ }
Simon Glassdd279182017-07-04 13:31:27 -0600729};
730
731U_BOOT_DRIVER(sunxi_mmc_drv) = {
732 .name = "sunxi_mmc",
733 .id = UCLASS_MMC,
734 .of_match = sunxi_mmc_ids,
735 .bind = sunxi_mmc_bind,
736 .probe = sunxi_mmc_probe,
737 .ops = &sunxi_mmc_ops,
738 .platdata_auto_alloc_size = sizeof(struct sunxi_mmc_plat),
739 .priv_auto_alloc_size = sizeof(struct sunxi_mmc_priv),
740};
741#endif