blob: 147eb9b4d5f9c3c49f92a414b85c7ee4442da5c3 [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
Simon Glassdd279182017-07-04 13:31:27 -060022struct sunxi_mmc_plat {
23 struct mmc_config cfg;
24 struct mmc mmc;
25};
26
Simon Glasse3c794e2017-07-04 13:31:23 -060027struct sunxi_mmc_priv {
Ian Campbelle24ea552014-05-05 14:42:31 +010028 unsigned mmc_no;
29 uint32_t *mclkreg;
Ian Campbelle24ea552014-05-05 14:42:31 +010030 unsigned fatal_err;
Simon Glassdd279182017-07-04 13:31:27 -060031 struct gpio_desc cd_gpio; /* Change Detect GPIO */
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +010032 int cd_inverted; /* Inverted Card Detect */
Ian Campbelle24ea552014-05-05 14:42:31 +010033 struct sunxi_mmc *reg;
34 struct mmc_config cfg;
35};
36
Simon Glassdd279182017-07-04 13:31:27 -060037#if !CONFIG_IS_ENABLED(DM_MMC)
Ian Campbelle24ea552014-05-05 14:42:31 +010038/* support 4 mmc hosts */
Simon Glasse3c794e2017-07-04 13:31:23 -060039struct sunxi_mmc_priv mmc_host[4];
Ian Campbelle24ea552014-05-05 14:42:31 +010040
Hans de Goede967325f2014-10-31 16:55:02 +010041static int sunxi_mmc_getcd_gpio(int sdc_no)
42{
43 switch (sdc_no) {
44 case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN);
45 case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN);
46 case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN);
47 case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN);
48 }
Hans de Goede90641f82015-04-22 17:03:17 +020049 return -EINVAL;
Hans de Goede967325f2014-10-31 16:55:02 +010050}
51
Ian Campbelle24ea552014-05-05 14:42:31 +010052static int mmc_resource_init(int sdc_no)
53{
Simon Glass3f5af122017-07-04 13:31:24 -060054 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
Ian Campbelle24ea552014-05-05 14:42:31 +010055 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede967325f2014-10-31 16:55:02 +010056 int cd_pin, ret = 0;
Ian Campbelle24ea552014-05-05 14:42:31 +010057
58 debug("init mmc %d resource\n", sdc_no);
59
60 switch (sdc_no) {
61 case 0:
Simon Glass3f5af122017-07-04 13:31:24 -060062 priv->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
63 priv->mclkreg = &ccm->sd0_clk_cfg;
Ian Campbelle24ea552014-05-05 14:42:31 +010064 break;
65 case 1:
Simon Glass3f5af122017-07-04 13:31:24 -060066 priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
67 priv->mclkreg = &ccm->sd1_clk_cfg;
Ian Campbelle24ea552014-05-05 14:42:31 +010068 break;
69 case 2:
Simon Glass3f5af122017-07-04 13:31:24 -060070 priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
71 priv->mclkreg = &ccm->sd2_clk_cfg;
Ian Campbelle24ea552014-05-05 14:42:31 +010072 break;
Icenowy Zheng42956f12018-07-21 16:20:29 +080073#ifdef SUNXI_MMC3_BASE
Ian Campbelle24ea552014-05-05 14:42:31 +010074 case 3:
Simon Glass3f5af122017-07-04 13:31:24 -060075 priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
76 priv->mclkreg = &ccm->sd3_clk_cfg;
Ian Campbelle24ea552014-05-05 14:42:31 +010077 break;
Icenowy Zheng42956f12018-07-21 16:20:29 +080078#endif
Ian Campbelle24ea552014-05-05 14:42:31 +010079 default:
80 printf("Wrong mmc number %d\n", sdc_no);
81 return -1;
82 }
Simon Glass3f5af122017-07-04 13:31:24 -060083 priv->mmc_no = sdc_no;
Ian Campbelle24ea552014-05-05 14:42:31 +010084
Hans de Goede967325f2014-10-31 16:55:02 +010085 cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
Hans de Goede90641f82015-04-22 17:03:17 +020086 if (cd_pin >= 0) {
Hans de Goede967325f2014-10-31 16:55:02 +010087 ret = gpio_request(cd_pin, "mmc_cd");
Hans de Goede1c09fa32015-05-30 16:39:10 +020088 if (!ret) {
89 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
Axel Linb0c4ae12014-12-20 11:41:25 +080090 ret = gpio_direction_input(cd_pin);
Hans de Goede1c09fa32015-05-30 16:39:10 +020091 }
Axel Linb0c4ae12014-12-20 11:41:25 +080092 }
Hans de Goede967325f2014-10-31 16:55:02 +010093
94 return ret;
Ian Campbelle24ea552014-05-05 14:42:31 +010095}
Simon Glassdd279182017-07-04 13:31:27 -060096#endif
Ian Campbelle24ea552014-05-05 14:42:31 +010097
Simon Glass3f5af122017-07-04 13:31:24 -060098static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
Hans de Goedefc3a8322014-12-07 20:55:10 +010099{
100 unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
Maxime Ripardde9b1772017-08-23 12:03:41 +0200101 bool new_mode = false;
Vasily Khoruzhick20940ef2018-11-05 20:24:28 -0800102 bool calibrate = false;
Maxime Ripardde9b1772017-08-23 12:03:41 +0200103 u32 val = 0;
104
105 if (IS_ENABLED(CONFIG_MMC_SUNXI_HAS_NEW_MODE) && (priv->mmc_no == 2))
106 new_mode = true;
107
Vasily Khoruzhick20940ef2018-11-05 20:24:28 -0800108#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6)
109 calibrate = true;
110#endif
111
Maxime Ripardde9b1772017-08-23 12:03:41 +0200112 /*
113 * The MMC clock has an extra /2 post-divider when operating in the new
114 * mode.
115 */
116 if (new_mode)
117 hz = hz * 2;
Hans de Goedefc3a8322014-12-07 20:55:10 +0100118
119 if (hz <= 24000000) {
120 pll = CCM_MMC_CTRL_OSCM24;
121 pll_hz = 24000000;
122 } else {
Hans de Goededaf22632015-01-14 19:05:03 +0100123#ifdef CONFIG_MACH_SUN9I
124 pll = CCM_MMC_CTRL_PLL_PERIPH0;
125 pll_hz = clock_get_pll4_periph0();
Icenowy Zheng42956f12018-07-21 16:20:29 +0800126#elif defined(CONFIG_MACH_SUN50I_H6)
127 pll = CCM_MMC_CTRL_PLL6X2;
128 pll_hz = clock_get_pll6() * 2;
Hans de Goededaf22632015-01-14 19:05:03 +0100129#else
Hans de Goedefc3a8322014-12-07 20:55:10 +0100130 pll = CCM_MMC_CTRL_PLL6;
131 pll_hz = clock_get_pll6();
Hans de Goededaf22632015-01-14 19:05:03 +0100132#endif
Hans de Goedefc3a8322014-12-07 20:55:10 +0100133 }
134
135 div = pll_hz / hz;
136 if (pll_hz % hz)
137 div++;
138
139 n = 0;
140 while (div > 16) {
141 n++;
142 div = (div + 1) / 2;
143 }
144
145 if (n > 3) {
Simon Glass3f5af122017-07-04 13:31:24 -0600146 printf("mmc %u error cannot set clock to %u\n", priv->mmc_no,
147 hz);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100148 return -1;
149 }
150
151 /* determine delays */
152 if (hz <= 400000) {
153 oclk_dly = 0;
Hans de Goedebe909742015-09-23 16:13:10 +0200154 sclk_dly = 0;
Hans de Goedefc3a8322014-12-07 20:55:10 +0100155 } else if (hz <= 25000000) {
156 oclk_dly = 0;
157 sclk_dly = 5;
Hans de Goedebe909742015-09-23 16:13:10 +0200158#ifdef CONFIG_MACH_SUN9I
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300159 } else if (hz <= 52000000) {
Hans de Goedebe909742015-09-23 16:13:10 +0200160 oclk_dly = 5;
161 sclk_dly = 4;
Hans de Goedefc3a8322014-12-07 20:55:10 +0100162 } else {
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300163 /* hz > 52000000 */
Hans de Goedefc3a8322014-12-07 20:55:10 +0100164 oclk_dly = 2;
165 sclk_dly = 4;
Hans de Goedebe909742015-09-23 16:13:10 +0200166#else
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300167 } else if (hz <= 52000000) {
Hans de Goedebe909742015-09-23 16:13:10 +0200168 oclk_dly = 3;
169 sclk_dly = 4;
170 } else {
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300171 /* hz > 52000000 */
Hans de Goedebe909742015-09-23 16:13:10 +0200172 oclk_dly = 1;
173 sclk_dly = 4;
174#endif
Hans de Goedefc3a8322014-12-07 20:55:10 +0100175 }
176
Maxime Ripardde9b1772017-08-23 12:03:41 +0200177 if (new_mode) {
178#ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE
179 val = CCM_MMC_CTRL_MODE_SEL_NEW;
Chen-Yu Tsai8a647fc2017-08-31 21:57:48 +0800180 setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW);
Maxime Ripardde9b1772017-08-23 12:03:41 +0200181#endif
Vasily Khoruzhick20940ef2018-11-05 20:24:28 -0800182 } else if (!calibrate) {
183 /*
184 * Use hardcoded delay values if controller doesn't support
185 * calibration
186 */
Maxime Ripardde9b1772017-08-23 12:03:41 +0200187 val = CCM_MMC_CTRL_OCLK_DLY(oclk_dly) |
188 CCM_MMC_CTRL_SCLK_DLY(sclk_dly);
189 }
190
191 writel(CCM_MMC_CTRL_ENABLE| pll | CCM_MMC_CTRL_N(n) |
192 CCM_MMC_CTRL_M(div) | val, priv->mclkreg);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100193
194 debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n",
Simon Glass3f5af122017-07-04 13:31:24 -0600195 priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100196
197 return 0;
198}
199
Simon Glass034e2262017-07-04 13:31:25 -0600200static int mmc_update_clk(struct sunxi_mmc_priv *priv)
Ian Campbelle24ea552014-05-05 14:42:31 +0100201{
Ian Campbelle24ea552014-05-05 14:42:31 +0100202 unsigned int cmd;
203 unsigned timeout_msecs = 2000;
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100204 unsigned long start = get_timer(0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100205
206 cmd = SUNXI_MMC_CMD_START |
207 SUNXI_MMC_CMD_UPCLK_ONLY |
208 SUNXI_MMC_CMD_WAIT_PRE_OVER;
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100209
Simon Glass3f5af122017-07-04 13:31:24 -0600210 writel(cmd, &priv->reg->cmd);
211 while (readl(&priv->reg->cmd) & SUNXI_MMC_CMD_START) {
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100212 if (get_timer(start) > timeout_msecs)
Ian Campbelle24ea552014-05-05 14:42:31 +0100213 return -1;
Ian Campbelle24ea552014-05-05 14:42:31 +0100214 }
215
216 /* clock update sets various irq status bits, clear these */
Simon Glass3f5af122017-07-04 13:31:24 -0600217 writel(readl(&priv->reg->rint), &priv->reg->rint);
Ian Campbelle24ea552014-05-05 14:42:31 +0100218
219 return 0;
220}
221
Simon Glass034e2262017-07-04 13:31:25 -0600222static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc)
Ian Campbelle24ea552014-05-05 14:42:31 +0100223{
Simon Glass3f5af122017-07-04 13:31:24 -0600224 unsigned rval = readl(&priv->reg->clkcr);
Ian Campbelle24ea552014-05-05 14:42:31 +0100225
226 /* Disable Clock */
227 rval &= ~SUNXI_MMC_CLK_ENABLE;
Simon Glass3f5af122017-07-04 13:31:24 -0600228 writel(rval, &priv->reg->clkcr);
Simon Glass034e2262017-07-04 13:31:25 -0600229 if (mmc_update_clk(priv))
Ian Campbelle24ea552014-05-05 14:42:31 +0100230 return -1;
231
Hans de Goedefc3a8322014-12-07 20:55:10 +0100232 /* Set mod_clk to new rate */
Simon Glass3f5af122017-07-04 13:31:24 -0600233 if (mmc_set_mod_clk(priv, mmc->clock))
Ian Campbelle24ea552014-05-05 14:42:31 +0100234 return -1;
Hans de Goedefc3a8322014-12-07 20:55:10 +0100235
236 /* Clear internal divider */
237 rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
Simon Glass3f5af122017-07-04 13:31:24 -0600238 writel(rval, &priv->reg->clkcr);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100239
Vasily Khoruzhick20940ef2018-11-05 20:24:28 -0800240#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN50I_H6)
241 /* A64 supports calibration of delays on MMC controller and we
242 * have to set delay of zero before starting calibration.
243 * Allwinner BSP driver sets a delay only in the case of
244 * using HS400 which is not supported by mainline U-Boot or
245 * Linux at the moment
246 */
247 writel(SUNXI_MMC_CAL_DL_SW_EN, &priv->reg->samp_dl);
248#endif
249
Ian Campbelle24ea552014-05-05 14:42:31 +0100250 /* Re-enable Clock */
251 rval |= SUNXI_MMC_CLK_ENABLE;
Simon Glass3f5af122017-07-04 13:31:24 -0600252 writel(rval, &priv->reg->clkcr);
Simon Glass034e2262017-07-04 13:31:25 -0600253 if (mmc_update_clk(priv))
Ian Campbelle24ea552014-05-05 14:42:31 +0100254 return -1;
255
256 return 0;
257}
258
Simon Glass034e2262017-07-04 13:31:25 -0600259static int sunxi_mmc_set_ios_common(struct sunxi_mmc_priv *priv,
260 struct mmc *mmc)
Ian Campbelle24ea552014-05-05 14:42:31 +0100261{
Hans de Goedefc3a8322014-12-07 20:55:10 +0100262 debug("set ios: bus_width: %x, clock: %d\n",
263 mmc->bus_width, mmc->clock);
Ian Campbelle24ea552014-05-05 14:42:31 +0100264
265 /* Change clock first */
Simon Glass034e2262017-07-04 13:31:25 -0600266 if (mmc->clock && mmc_config_clock(priv, mmc) != 0) {
Simon Glass3f5af122017-07-04 13:31:24 -0600267 priv->fatal_err = 1;
Jaehoon Chung07b0b9c2016-12-30 15:30:16 +0900268 return -EINVAL;
Ian Campbelle24ea552014-05-05 14:42:31 +0100269 }
270
271 /* Change bus width */
272 if (mmc->bus_width == 8)
Simon Glass3f5af122017-07-04 13:31:24 -0600273 writel(0x2, &priv->reg->width);
Ian Campbelle24ea552014-05-05 14:42:31 +0100274 else if (mmc->bus_width == 4)
Simon Glass3f5af122017-07-04 13:31:24 -0600275 writel(0x1, &priv->reg->width);
Ian Campbelle24ea552014-05-05 14:42:31 +0100276 else
Simon Glass3f5af122017-07-04 13:31:24 -0600277 writel(0x0, &priv->reg->width);
Jaehoon Chung07b0b9c2016-12-30 15:30:16 +0900278
279 return 0;
Ian Campbelle24ea552014-05-05 14:42:31 +0100280}
281
Simon Glassdd279182017-07-04 13:31:27 -0600282#if !CONFIG_IS_ENABLED(DM_MMC)
Siarhei Siamashka5abdb152015-02-01 00:42:14 +0200283static int sunxi_mmc_core_init(struct mmc *mmc)
Ian Campbelle24ea552014-05-05 14:42:31 +0100284{
Simon Glass3f5af122017-07-04 13:31:24 -0600285 struct sunxi_mmc_priv *priv = mmc->priv;
Ian Campbelle24ea552014-05-05 14:42:31 +0100286
287 /* Reset controller */
Simon Glass3f5af122017-07-04 13:31:24 -0600288 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200289 udelay(1000);
Ian Campbelle24ea552014-05-05 14:42:31 +0100290
291 return 0;
292}
Simon Glassdd279182017-07-04 13:31:27 -0600293#endif
Ian Campbelle24ea552014-05-05 14:42:31 +0100294
Simon Glass034e2262017-07-04 13:31:25 -0600295static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
296 struct mmc_data *data)
Ian Campbelle24ea552014-05-05 14:42:31 +0100297{
Ian Campbelle24ea552014-05-05 14:42:31 +0100298 const int reading = !!(data->flags & MMC_DATA_READ);
299 const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY :
300 SUNXI_MMC_STATUS_FIFO_FULL;
301 unsigned i;
Ian Campbelle24ea552014-05-05 14:42:31 +0100302 unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
Yousong Zhou28f69b92015-08-29 21:26:11 +0800303 unsigned byte_cnt = data->blocksize * data->blocks;
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100304 unsigned timeout_msecs = byte_cnt >> 8;
305 unsigned long start;
306
307 if (timeout_msecs < 2000)
308 timeout_msecs = 2000;
Ian Campbelle24ea552014-05-05 14:42:31 +0100309
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200310 /* Always read / write data through the CPU */
Simon Glass3f5af122017-07-04 13:31:24 -0600311 setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200312
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100313 start = get_timer(0);
314
Ian Campbelle24ea552014-05-05 14:42:31 +0100315 for (i = 0; i < (byte_cnt >> 2); i++) {
Simon Glass3f5af122017-07-04 13:31:24 -0600316 while (readl(&priv->reg->status) & status_bit) {
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100317 if (get_timer(start) > timeout_msecs)
Ian Campbelle24ea552014-05-05 14:42:31 +0100318 return -1;
Ian Campbelle24ea552014-05-05 14:42:31 +0100319 }
320
321 if (reading)
Simon Glass3f5af122017-07-04 13:31:24 -0600322 buff[i] = readl(&priv->reg->fifo);
Ian Campbelle24ea552014-05-05 14:42:31 +0100323 else
Simon Glass3f5af122017-07-04 13:31:24 -0600324 writel(buff[i], &priv->reg->fifo);
Ian Campbelle24ea552014-05-05 14:42:31 +0100325 }
326
327 return 0;
328}
329
Simon Glass034e2262017-07-04 13:31:25 -0600330static int mmc_rint_wait(struct sunxi_mmc_priv *priv, struct mmc *mmc,
331 uint timeout_msecs, uint done_bit, const char *what)
Ian Campbelle24ea552014-05-05 14:42:31 +0100332{
Ian Campbelle24ea552014-05-05 14:42:31 +0100333 unsigned int status;
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100334 unsigned long start = get_timer(0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100335
336 do {
Simon Glass3f5af122017-07-04 13:31:24 -0600337 status = readl(&priv->reg->rint);
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100338 if ((get_timer(start) > timeout_msecs) ||
Ian Campbelle24ea552014-05-05 14:42:31 +0100339 (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) {
340 debug("%s timeout %x\n", what,
341 status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT);
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900342 return -ETIMEDOUT;
Ian Campbelle24ea552014-05-05 14:42:31 +0100343 }
Ian Campbelle24ea552014-05-05 14:42:31 +0100344 } while (!(status & done_bit));
345
346 return 0;
347}
348
Simon Glass034e2262017-07-04 13:31:25 -0600349static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv,
350 struct mmc *mmc, struct mmc_cmd *cmd,
351 struct mmc_data *data)
Ian Campbelle24ea552014-05-05 14:42:31 +0100352{
Ian Campbelle24ea552014-05-05 14:42:31 +0100353 unsigned int cmdval = SUNXI_MMC_CMD_START;
354 unsigned int timeout_msecs;
355 int error = 0;
356 unsigned int status = 0;
Ian Campbelle24ea552014-05-05 14:42:31 +0100357 unsigned int bytecnt = 0;
358
Simon Glass3f5af122017-07-04 13:31:24 -0600359 if (priv->fatal_err)
Ian Campbelle24ea552014-05-05 14:42:31 +0100360 return -1;
361 if (cmd->resp_type & MMC_RSP_BUSY)
362 debug("mmc cmd %d check rsp busy\n", cmd->cmdidx);
363 if (cmd->cmdidx == 12)
364 return 0;
365
366 if (!cmd->cmdidx)
367 cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ;
368 if (cmd->resp_type & MMC_RSP_PRESENT)
369 cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE;
370 if (cmd->resp_type & MMC_RSP_136)
371 cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE;
372 if (cmd->resp_type & MMC_RSP_CRC)
373 cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC;
374
375 if (data) {
Alexander Graf0ea5a042016-03-29 17:29:09 +0200376 if ((u32)(long)data->dest & 0x3) {
Ian Campbelle24ea552014-05-05 14:42:31 +0100377 error = -1;
378 goto out;
379 }
380
381 cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER;
382 if (data->flags & MMC_DATA_WRITE)
383 cmdval |= SUNXI_MMC_CMD_WRITE;
384 if (data->blocks > 1)
385 cmdval |= SUNXI_MMC_CMD_AUTO_STOP;
Simon Glass3f5af122017-07-04 13:31:24 -0600386 writel(data->blocksize, &priv->reg->blksz);
387 writel(data->blocks * data->blocksize, &priv->reg->bytecnt);
Ian Campbelle24ea552014-05-05 14:42:31 +0100388 }
389
Simon Glass3f5af122017-07-04 13:31:24 -0600390 debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", priv->mmc_no,
Ian Campbelle24ea552014-05-05 14:42:31 +0100391 cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg);
Simon Glass3f5af122017-07-04 13:31:24 -0600392 writel(cmd->cmdarg, &priv->reg->arg);
Ian Campbelle24ea552014-05-05 14:42:31 +0100393
394 if (!data)
Simon Glass3f5af122017-07-04 13:31:24 -0600395 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
Ian Campbelle24ea552014-05-05 14:42:31 +0100396
397 /*
398 * transfer data and check status
399 * STATREG[2] : FIFO empty
400 * STATREG[3] : FIFO full
401 */
402 if (data) {
403 int ret = 0;
404
405 bytecnt = data->blocksize * data->blocks;
406 debug("trans data %d bytes\n", bytecnt);
Simon Glass3f5af122017-07-04 13:31:24 -0600407 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
Simon Glass034e2262017-07-04 13:31:25 -0600408 ret = mmc_trans_data_by_cpu(priv, mmc, data);
Ian Campbelle24ea552014-05-05 14:42:31 +0100409 if (ret) {
Simon Glass3f5af122017-07-04 13:31:24 -0600410 error = readl(&priv->reg->rint) &
Ian Campbelle24ea552014-05-05 14:42:31 +0100411 SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900412 error = -ETIMEDOUT;
Ian Campbelle24ea552014-05-05 14:42:31 +0100413 goto out;
414 }
415 }
416
Simon Glass034e2262017-07-04 13:31:25 -0600417 error = mmc_rint_wait(priv, mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE,
418 "cmd");
Ian Campbelle24ea552014-05-05 14:42:31 +0100419 if (error)
420 goto out;
421
422 if (data) {
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200423 timeout_msecs = 120;
Ian Campbelle24ea552014-05-05 14:42:31 +0100424 debug("cacl timeout %x msec\n", timeout_msecs);
Simon Glass034e2262017-07-04 13:31:25 -0600425 error = mmc_rint_wait(priv, mmc, timeout_msecs,
Ian Campbelle24ea552014-05-05 14:42:31 +0100426 data->blocks > 1 ?
427 SUNXI_MMC_RINT_AUTO_COMMAND_DONE :
428 SUNXI_MMC_RINT_DATA_OVER,
429 "data");
430 if (error)
431 goto out;
432 }
433
434 if (cmd->resp_type & MMC_RSP_BUSY) {
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100435 unsigned long start = get_timer(0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100436 timeout_msecs = 2000;
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100437
Ian Campbelle24ea552014-05-05 14:42:31 +0100438 do {
Simon Glass3f5af122017-07-04 13:31:24 -0600439 status = readl(&priv->reg->status);
Philipp Tomsich5ff8e542018-03-21 12:18:58 +0100440 if (get_timer(start) > timeout_msecs) {
Ian Campbelle24ea552014-05-05 14:42:31 +0100441 debug("busy timeout\n");
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900442 error = -ETIMEDOUT;
Ian Campbelle24ea552014-05-05 14:42:31 +0100443 goto out;
444 }
Ian Campbelle24ea552014-05-05 14:42:31 +0100445 } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY);
446 }
447
448 if (cmd->resp_type & MMC_RSP_136) {
Simon Glass3f5af122017-07-04 13:31:24 -0600449 cmd->response[0] = readl(&priv->reg->resp3);
450 cmd->response[1] = readl(&priv->reg->resp2);
451 cmd->response[2] = readl(&priv->reg->resp1);
452 cmd->response[3] = readl(&priv->reg->resp0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100453 debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n",
454 cmd->response[3], cmd->response[2],
455 cmd->response[1], cmd->response[0]);
456 } else {
Simon Glass3f5af122017-07-04 13:31:24 -0600457 cmd->response[0] = readl(&priv->reg->resp0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100458 debug("mmc resp 0x%08x\n", cmd->response[0]);
459 }
460out:
Ian Campbelle24ea552014-05-05 14:42:31 +0100461 if (error < 0) {
Simon Glass3f5af122017-07-04 13:31:24 -0600462 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
Simon Glass034e2262017-07-04 13:31:25 -0600463 mmc_update_clk(priv);
Ian Campbelle24ea552014-05-05 14:42:31 +0100464 }
Simon Glass3f5af122017-07-04 13:31:24 -0600465 writel(0xffffffff, &priv->reg->rint);
466 writel(readl(&priv->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET,
467 &priv->reg->gctrl);
Ian Campbelle24ea552014-05-05 14:42:31 +0100468
469 return error;
470}
471
Simon Glassdd279182017-07-04 13:31:27 -0600472#if !CONFIG_IS_ENABLED(DM_MMC)
Simon Glass034e2262017-07-04 13:31:25 -0600473static int sunxi_mmc_set_ios_legacy(struct mmc *mmc)
474{
475 struct sunxi_mmc_priv *priv = mmc->priv;
476
477 return sunxi_mmc_set_ios_common(priv, mmc);
478}
479
480static int sunxi_mmc_send_cmd_legacy(struct mmc *mmc, struct mmc_cmd *cmd,
481 struct mmc_data *data)
482{
483 struct sunxi_mmc_priv *priv = mmc->priv;
484
485 return sunxi_mmc_send_cmd_common(priv, mmc, cmd, data);
486}
487
488static int sunxi_mmc_getcd_legacy(struct mmc *mmc)
Hans de Goedecd821132014-10-02 20:29:26 +0200489{
Simon Glass3f5af122017-07-04 13:31:24 -0600490 struct sunxi_mmc_priv *priv = mmc->priv;
Hans de Goede967325f2014-10-31 16:55:02 +0100491 int cd_pin;
Hans de Goedecd821132014-10-02 20:29:26 +0200492
Simon Glass3f5af122017-07-04 13:31:24 -0600493 cd_pin = sunxi_mmc_getcd_gpio(priv->mmc_no);
Hans de Goede90641f82015-04-22 17:03:17 +0200494 if (cd_pin < 0)
Hans de Goedecd821132014-10-02 20:29:26 +0200495 return 1;
496
Axel Linb0c4ae12014-12-20 11:41:25 +0800497 return !gpio_get_value(cd_pin);
Hans de Goedecd821132014-10-02 20:29:26 +0200498}
499
Ian Campbelle24ea552014-05-05 14:42:31 +0100500static const struct mmc_ops sunxi_mmc_ops = {
Simon Glass034e2262017-07-04 13:31:25 -0600501 .send_cmd = sunxi_mmc_send_cmd_legacy,
502 .set_ios = sunxi_mmc_set_ios_legacy,
Siarhei Siamashka5abdb152015-02-01 00:42:14 +0200503 .init = sunxi_mmc_core_init,
Simon Glass034e2262017-07-04 13:31:25 -0600504 .getcd = sunxi_mmc_getcd_legacy,
Ian Campbelle24ea552014-05-05 14:42:31 +0100505};
506
Hans de Goedee79c7c82014-10-02 21:13:54 +0200507struct mmc *sunxi_mmc_init(int sdc_no)
Ian Campbelle24ea552014-05-05 14:42:31 +0100508{
Simon Glassec73d962017-07-04 13:31:26 -0600509 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Simon Glass034e2262017-07-04 13:31:25 -0600510 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
511 struct mmc_config *cfg = &priv->cfg;
Simon Glassec73d962017-07-04 13:31:26 -0600512 int ret;
Ian Campbelle24ea552014-05-05 14:42:31 +0100513
Simon Glass034e2262017-07-04 13:31:25 -0600514 memset(priv, '\0', sizeof(struct sunxi_mmc_priv));
Ian Campbelle24ea552014-05-05 14:42:31 +0100515
516 cfg->name = "SUNXI SD/MMC";
517 cfg->ops = &sunxi_mmc_ops;
518
519 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
520 cfg->host_caps = MMC_MODE_4BIT;
Icenowy Zheng42956f12018-07-21 16:20:29 +0800521#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I) || defined(CONFIG_MACH_SUN50I_H6)
Siarhei Siamashkad96ebc42016-03-29 17:29:10 +0200522 if (sdc_no == 2)
523 cfg->host_caps = MMC_MODE_8BIT;
524#endif
Rob Herring5a203972015-03-23 17:56:59 -0500525 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
Ian Campbelle24ea552014-05-05 14:42:31 +0100526 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
527
528 cfg->f_min = 400000;
529 cfg->f_max = 52000000;
530
Hans de Goede967325f2014-10-31 16:55:02 +0100531 if (mmc_resource_init(sdc_no) != 0)
532 return NULL;
533
Simon Glassec73d962017-07-04 13:31:26 -0600534 /* config ahb clock */
535 debug("init mmc %d clock and io\n", sdc_no);
Icenowy Zheng42956f12018-07-21 16:20:29 +0800536#if !defined(CONFIG_MACH_SUN50I_H6)
Simon Glassec73d962017-07-04 13:31:26 -0600537 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
538
539#ifdef CONFIG_SUNXI_GEN_SUN6I
540 /* unassert reset */
541 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no));
542#endif
543#if defined(CONFIG_MACH_SUN9I)
544 /* sun9i has a mmc-common module, also set the gate and reset there */
545 writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET,
546 SUNXI_MMC_COMMON_BASE + 4 * sdc_no);
547#endif
Icenowy Zheng42956f12018-07-21 16:20:29 +0800548#else /* CONFIG_MACH_SUN50I_H6 */
549 setbits_le32(&ccm->sd_gate_reset, 1 << sdc_no);
550 /* unassert reset */
551 setbits_le32(&ccm->sd_gate_reset, 1 << (RESET_SHIFT + sdc_no));
552#endif
Simon Glassec73d962017-07-04 13:31:26 -0600553 ret = mmc_set_mod_clk(priv, 24000000);
554 if (ret)
555 return NULL;
Ian Campbelle24ea552014-05-05 14:42:31 +0100556
Maxime Ripardead36972017-08-23 13:41:33 +0200557 return mmc_create(cfg, priv);
Ian Campbelle24ea552014-05-05 14:42:31 +0100558}
Simon Glassdd279182017-07-04 13:31:27 -0600559#else
560
561static int sunxi_mmc_set_ios(struct udevice *dev)
562{
563 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
564 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
565
566 return sunxi_mmc_set_ios_common(priv, &plat->mmc);
567}
568
569static int sunxi_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
570 struct mmc_data *data)
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_send_cmd_common(priv, &plat->mmc, cmd, data);
576}
577
578static int sunxi_mmc_getcd(struct udevice *dev)
579{
580 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
581
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +0100582 if (dm_gpio_is_valid(&priv->cd_gpio)) {
583 int cd_state = dm_gpio_get_value(&priv->cd_gpio);
Simon Glassdd279182017-07-04 13:31:27 -0600584
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +0100585 return cd_state ^ priv->cd_inverted;
586 }
Simon Glassdd279182017-07-04 13:31:27 -0600587 return 1;
588}
589
590static const struct dm_mmc_ops sunxi_mmc_ops = {
591 .send_cmd = sunxi_mmc_send_cmd,
592 .set_ios = sunxi_mmc_set_ios,
593 .get_cd = sunxi_mmc_getcd,
594};
595
596static int sunxi_mmc_probe(struct udevice *dev)
597{
598 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
599 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
600 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
601 struct mmc_config *cfg = &plat->cfg;
602 struct ofnode_phandle_args args;
603 u32 *gate_reg;
604 int bus_width, ret;
605
606 cfg->name = dev->name;
607 bus_width = dev_read_u32_default(dev, "bus-width", 1);
608
609 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
610 cfg->host_caps = 0;
611 if (bus_width == 8)
612 cfg->host_caps |= MMC_MODE_8BIT;
613 if (bus_width >= 4)
614 cfg->host_caps |= MMC_MODE_4BIT;
615 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
616 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
617
618 cfg->f_min = 400000;
619 cfg->f_max = 52000000;
620
621 priv->reg = (void *)dev_read_addr(dev);
622
623 /* We don't have a sunxi clock driver so find the clock address here */
624 ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
625 1, &args);
626 if (ret)
627 return ret;
628 priv->mclkreg = (u32 *)ofnode_get_addr(args.node);
629
630 ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
631 0, &args);
632 if (ret)
633 return ret;
634 gate_reg = (u32 *)ofnode_get_addr(args.node);
635 setbits_le32(gate_reg, 1 << args.args[0]);
636 priv->mmc_no = args.args[0] - 8;
637
638 ret = mmc_set_mod_clk(priv, 24000000);
639 if (ret)
640 return ret;
641
642 /* This GPIO is optional */
643 if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
644 GPIOD_IS_IN)) {
645 int cd_pin = gpio_get_number(&priv->cd_gpio);
646
647 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
648 }
649
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +0100650 /* Check if card detect is inverted */
651 priv->cd_inverted = dev_read_bool(dev, "cd-inverted");
652
Simon Glassdd279182017-07-04 13:31:27 -0600653 upriv->mmc = &plat->mmc;
654
655 /* Reset controller */
656 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
657 udelay(1000);
658
659 return 0;
660}
661
662static int sunxi_mmc_bind(struct udevice *dev)
663{
664 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
665
666 return mmc_bind(dev, &plat->mmc, &plat->cfg);
667}
668
669static const struct udevice_id sunxi_mmc_ids[] = {
Adam Sampson979b2392018-06-30 01:02:28 +0100670 { .compatible = "allwinner,sun4i-a10-mmc" },
Simon Glassdd279182017-07-04 13:31:27 -0600671 { .compatible = "allwinner,sun5i-a13-mmc" },
Adam Sampson979b2392018-06-30 01:02:28 +0100672 { .compatible = "allwinner,sun7i-a20-mmc" },
Simon Glassdd279182017-07-04 13:31:27 -0600673 { }
674};
675
676U_BOOT_DRIVER(sunxi_mmc_drv) = {
677 .name = "sunxi_mmc",
678 .id = UCLASS_MMC,
679 .of_match = sunxi_mmc_ids,
680 .bind = sunxi_mmc_bind,
681 .probe = sunxi_mmc_probe,
682 .ops = &sunxi_mmc_ops,
683 .platdata_auto_alloc_size = sizeof(struct sunxi_mmc_plat),
684 .priv_auto_alloc_size = sizeof(struct sunxi_mmc_priv),
685};
686#endif