blob: f4c245c5ebaeff1b977f6b3e75dd33e694505d2f [file] [log] [blame]
Ian Campbelle24ea552014-05-05 14:42:31 +01001/*
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>
Simon Glassdd279182017-07-04 13:31:27 -060012#include <dm.h>
Hans de Goede90641f82015-04-22 17:03:17 +020013#include <errno.h>
Ian Campbelle24ea552014-05-05 14:42:31 +010014#include <malloc.h>
15#include <mmc.h>
16#include <asm/io.h>
17#include <asm/arch/clock.h>
18#include <asm/arch/cpu.h>
Hans de Goedecd821132014-10-02 20:29:26 +020019#include <asm/arch/gpio.h>
Ian Campbelle24ea552014-05-05 14:42:31 +010020#include <asm/arch/mmc.h>
Hans de Goedecd821132014-10-02 20:29:26 +020021#include <asm-generic/gpio.h>
Ian Campbelle24ea552014-05-05 14:42:31 +010022
Simon Glassdd279182017-07-04 13:31:27 -060023struct sunxi_mmc_plat {
24 struct mmc_config cfg;
25 struct mmc mmc;
26};
27
Simon Glasse3c794e2017-07-04 13:31:23 -060028struct sunxi_mmc_priv {
Ian Campbelle24ea552014-05-05 14:42:31 +010029 unsigned mmc_no;
30 uint32_t *mclkreg;
Ian Campbelle24ea552014-05-05 14:42:31 +010031 unsigned fatal_err;
Simon Glassdd279182017-07-04 13:31:27 -060032 struct gpio_desc cd_gpio; /* Change Detect GPIO */
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +010033 int cd_inverted; /* Inverted Card Detect */
Ian Campbelle24ea552014-05-05 14:42:31 +010034 struct sunxi_mmc *reg;
35 struct mmc_config cfg;
36};
37
Simon Glassdd279182017-07-04 13:31:27 -060038#if !CONFIG_IS_ENABLED(DM_MMC)
Ian Campbelle24ea552014-05-05 14:42:31 +010039/* support 4 mmc hosts */
Simon Glasse3c794e2017-07-04 13:31:23 -060040struct sunxi_mmc_priv mmc_host[4];
Ian Campbelle24ea552014-05-05 14:42:31 +010041
Hans de Goede967325f2014-10-31 16:55:02 +010042static 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 }
Hans de Goede90641f82015-04-22 17:03:17 +020050 return -EINVAL;
Hans de Goede967325f2014-10-31 16:55:02 +010051}
52
Ian Campbelle24ea552014-05-05 14:42:31 +010053static int mmc_resource_init(int sdc_no)
54{
Simon Glass3f5af122017-07-04 13:31:24 -060055 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
Ian Campbelle24ea552014-05-05 14:42:31 +010056 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede967325f2014-10-31 16:55:02 +010057 int cd_pin, ret = 0;
Ian Campbelle24ea552014-05-05 14:42:31 +010058
59 debug("init mmc %d resource\n", sdc_no);
60
61 switch (sdc_no) {
62 case 0:
Simon Glass3f5af122017-07-04 13:31:24 -060063 priv->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
64 priv->mclkreg = &ccm->sd0_clk_cfg;
Ian Campbelle24ea552014-05-05 14:42:31 +010065 break;
66 case 1:
Simon Glass3f5af122017-07-04 13:31:24 -060067 priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
68 priv->mclkreg = &ccm->sd1_clk_cfg;
Ian Campbelle24ea552014-05-05 14:42:31 +010069 break;
70 case 2:
Simon Glass3f5af122017-07-04 13:31:24 -060071 priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
72 priv->mclkreg = &ccm->sd2_clk_cfg;
Ian Campbelle24ea552014-05-05 14:42:31 +010073 break;
74 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;
78 default:
79 printf("Wrong mmc number %d\n", sdc_no);
80 return -1;
81 }
Simon Glass3f5af122017-07-04 13:31:24 -060082 priv->mmc_no = sdc_no;
Ian Campbelle24ea552014-05-05 14:42:31 +010083
Hans de Goede967325f2014-10-31 16:55:02 +010084 cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
Hans de Goede90641f82015-04-22 17:03:17 +020085 if (cd_pin >= 0) {
Hans de Goede967325f2014-10-31 16:55:02 +010086 ret = gpio_request(cd_pin, "mmc_cd");
Hans de Goede1c09fa32015-05-30 16:39:10 +020087 if (!ret) {
88 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
Axel Linb0c4ae12014-12-20 11:41:25 +080089 ret = gpio_direction_input(cd_pin);
Hans de Goede1c09fa32015-05-30 16:39:10 +020090 }
Axel Linb0c4ae12014-12-20 11:41:25 +080091 }
Hans de Goede967325f2014-10-31 16:55:02 +010092
93 return ret;
Ian Campbelle24ea552014-05-05 14:42:31 +010094}
Simon Glassdd279182017-07-04 13:31:27 -060095#endif
Ian Campbelle24ea552014-05-05 14:42:31 +010096
Simon Glass3f5af122017-07-04 13:31:24 -060097static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
Hans de Goedefc3a8322014-12-07 20:55:10 +010098{
99 unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
Maxime Ripardde9b1772017-08-23 12:03:41 +0200100 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;
Hans de Goedefc3a8322014-12-07 20:55:10 +0100112
113 if (hz <= 24000000) {
114 pll = CCM_MMC_CTRL_OSCM24;
115 pll_hz = 24000000;
116 } else {
Hans de Goededaf22632015-01-14 19:05:03 +0100117#ifdef CONFIG_MACH_SUN9I
118 pll = CCM_MMC_CTRL_PLL_PERIPH0;
119 pll_hz = clock_get_pll4_periph0();
120#else
Hans de Goedefc3a8322014-12-07 20:55:10 +0100121 pll = CCM_MMC_CTRL_PLL6;
122 pll_hz = clock_get_pll6();
Hans de Goededaf22632015-01-14 19:05:03 +0100123#endif
Hans de Goedefc3a8322014-12-07 20:55:10 +0100124 }
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) {
Simon Glass3f5af122017-07-04 13:31:24 -0600137 printf("mmc %u error cannot set clock to %u\n", priv->mmc_no,
138 hz);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100139 return -1;
140 }
141
142 /* determine delays */
143 if (hz <= 400000) {
144 oclk_dly = 0;
Hans de Goedebe909742015-09-23 16:13:10 +0200145 sclk_dly = 0;
Hans de Goedefc3a8322014-12-07 20:55:10 +0100146 } else if (hz <= 25000000) {
147 oclk_dly = 0;
148 sclk_dly = 5;
Hans de Goedebe909742015-09-23 16:13:10 +0200149#ifdef CONFIG_MACH_SUN9I
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300150 } else if (hz <= 52000000) {
Hans de Goedebe909742015-09-23 16:13:10 +0200151 oclk_dly = 5;
152 sclk_dly = 4;
Hans de Goedefc3a8322014-12-07 20:55:10 +0100153 } else {
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300154 /* hz > 52000000 */
Hans de Goedefc3a8322014-12-07 20:55:10 +0100155 oclk_dly = 2;
156 sclk_dly = 4;
Hans de Goedebe909742015-09-23 16:13:10 +0200157#else
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300158 } else if (hz <= 52000000) {
Hans de Goedebe909742015-09-23 16:13:10 +0200159 oclk_dly = 3;
160 sclk_dly = 4;
161 } else {
Stefan Mavrodiev4744d812018-03-27 16:57:23 +0300162 /* hz > 52000000 */
Hans de Goedebe909742015-09-23 16:13:10 +0200163 oclk_dly = 1;
164 sclk_dly = 4;
165#endif
Hans de Goedefc3a8322014-12-07 20:55:10 +0100166 }
167
Maxime Ripardde9b1772017-08-23 12:03:41 +0200168 if (new_mode) {
169#ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE
170 val = CCM_MMC_CTRL_MODE_SEL_NEW;
Chen-Yu Tsai8a647fc2017-08-31 21:57:48 +0800171 setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW);
Maxime Ripardde9b1772017-08-23 12:03:41 +0200172#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);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100180
181 debug("mmc %u set mod-clk req %u parent %u n %u m %u rate %u\n",
Simon Glass3f5af122017-07-04 13:31:24 -0600182 priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100183
184 return 0;
185}
186
Simon Glass034e2262017-07-04 13:31:25 -0600187static int mmc_update_clk(struct sunxi_mmc_priv *priv)
Ian Campbelle24ea552014-05-05 14:42:31 +0100188{
Ian Campbelle24ea552014-05-05 14:42:31 +0100189 unsigned int cmd;
190 unsigned timeout_msecs = 2000;
191
192 cmd = SUNXI_MMC_CMD_START |
193 SUNXI_MMC_CMD_UPCLK_ONLY |
194 SUNXI_MMC_CMD_WAIT_PRE_OVER;
Simon Glass3f5af122017-07-04 13:31:24 -0600195 writel(cmd, &priv->reg->cmd);
196 while (readl(&priv->reg->cmd) & SUNXI_MMC_CMD_START) {
Ian Campbelle24ea552014-05-05 14:42:31 +0100197 if (!timeout_msecs--)
198 return -1;
199 udelay(1000);
200 }
201
202 /* clock update sets various irq status bits, clear these */
Simon Glass3f5af122017-07-04 13:31:24 -0600203 writel(readl(&priv->reg->rint), &priv->reg->rint);
Ian Campbelle24ea552014-05-05 14:42:31 +0100204
205 return 0;
206}
207
Simon Glass034e2262017-07-04 13:31:25 -0600208static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc)
Ian Campbelle24ea552014-05-05 14:42:31 +0100209{
Simon Glass3f5af122017-07-04 13:31:24 -0600210 unsigned rval = readl(&priv->reg->clkcr);
Ian Campbelle24ea552014-05-05 14:42:31 +0100211
212 /* Disable Clock */
213 rval &= ~SUNXI_MMC_CLK_ENABLE;
Simon Glass3f5af122017-07-04 13:31:24 -0600214 writel(rval, &priv->reg->clkcr);
Simon Glass034e2262017-07-04 13:31:25 -0600215 if (mmc_update_clk(priv))
Ian Campbelle24ea552014-05-05 14:42:31 +0100216 return -1;
217
Hans de Goedefc3a8322014-12-07 20:55:10 +0100218 /* Set mod_clk to new rate */
Simon Glass3f5af122017-07-04 13:31:24 -0600219 if (mmc_set_mod_clk(priv, mmc->clock))
Ian Campbelle24ea552014-05-05 14:42:31 +0100220 return -1;
Hans de Goedefc3a8322014-12-07 20:55:10 +0100221
222 /* Clear internal divider */
223 rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
Simon Glass3f5af122017-07-04 13:31:24 -0600224 writel(rval, &priv->reg->clkcr);
Hans de Goedefc3a8322014-12-07 20:55:10 +0100225
Ian Campbelle24ea552014-05-05 14:42:31 +0100226 /* Re-enable 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
232 return 0;
233}
234
Simon Glass034e2262017-07-04 13:31:25 -0600235static int sunxi_mmc_set_ios_common(struct sunxi_mmc_priv *priv,
236 struct mmc *mmc)
Ian Campbelle24ea552014-05-05 14:42:31 +0100237{
Hans de Goedefc3a8322014-12-07 20:55:10 +0100238 debug("set ios: bus_width: %x, clock: %d\n",
239 mmc->bus_width, mmc->clock);
Ian Campbelle24ea552014-05-05 14:42:31 +0100240
241 /* Change clock first */
Simon Glass034e2262017-07-04 13:31:25 -0600242 if (mmc->clock && mmc_config_clock(priv, mmc) != 0) {
Simon Glass3f5af122017-07-04 13:31:24 -0600243 priv->fatal_err = 1;
Jaehoon Chung07b0b9c2016-12-30 15:30:16 +0900244 return -EINVAL;
Ian Campbelle24ea552014-05-05 14:42:31 +0100245 }
246
247 /* Change bus width */
248 if (mmc->bus_width == 8)
Simon Glass3f5af122017-07-04 13:31:24 -0600249 writel(0x2, &priv->reg->width);
Ian Campbelle24ea552014-05-05 14:42:31 +0100250 else if (mmc->bus_width == 4)
Simon Glass3f5af122017-07-04 13:31:24 -0600251 writel(0x1, &priv->reg->width);
Ian Campbelle24ea552014-05-05 14:42:31 +0100252 else
Simon Glass3f5af122017-07-04 13:31:24 -0600253 writel(0x0, &priv->reg->width);
Jaehoon Chung07b0b9c2016-12-30 15:30:16 +0900254
255 return 0;
Ian Campbelle24ea552014-05-05 14:42:31 +0100256}
257
Simon Glassdd279182017-07-04 13:31:27 -0600258#if !CONFIG_IS_ENABLED(DM_MMC)
Siarhei Siamashka5abdb152015-02-01 00:42:14 +0200259static int sunxi_mmc_core_init(struct mmc *mmc)
Ian Campbelle24ea552014-05-05 14:42:31 +0100260{
Simon Glass3f5af122017-07-04 13:31:24 -0600261 struct sunxi_mmc_priv *priv = mmc->priv;
Ian Campbelle24ea552014-05-05 14:42:31 +0100262
263 /* Reset controller */
Simon Glass3f5af122017-07-04 13:31:24 -0600264 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200265 udelay(1000);
Ian Campbelle24ea552014-05-05 14:42:31 +0100266
267 return 0;
268}
Simon Glassdd279182017-07-04 13:31:27 -0600269#endif
Ian Campbelle24ea552014-05-05 14:42:31 +0100270
Simon Glass034e2262017-07-04 13:31:25 -0600271static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
272 struct mmc_data *data)
Ian Campbelle24ea552014-05-05 14:42:31 +0100273{
Ian Campbelle24ea552014-05-05 14:42:31 +0100274 const int reading = !!(data->flags & MMC_DATA_READ);
275 const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY :
276 SUNXI_MMC_STATUS_FIFO_FULL;
277 unsigned i;
Ian Campbelle24ea552014-05-05 14:42:31 +0100278 unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
Yousong Zhou28f69b92015-08-29 21:26:11 +0800279 unsigned byte_cnt = data->blocksize * data->blocks;
Tobias Doerffel26c0c152016-07-08 12:40:14 +0200280 unsigned timeout_usecs = (byte_cnt >> 8) * 1000;
281 if (timeout_usecs < 2000000)
282 timeout_usecs = 2000000;
Ian Campbelle24ea552014-05-05 14:42:31 +0100283
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200284 /* Always read / write data through the CPU */
Simon Glass3f5af122017-07-04 13:31:24 -0600285 setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200286
Ian Campbelle24ea552014-05-05 14:42:31 +0100287 for (i = 0; i < (byte_cnt >> 2); i++) {
Simon Glass3f5af122017-07-04 13:31:24 -0600288 while (readl(&priv->reg->status) & status_bit) {
Tobias Doerffel26c0c152016-07-08 12:40:14 +0200289 if (!timeout_usecs--)
Ian Campbelle24ea552014-05-05 14:42:31 +0100290 return -1;
Tobias Doerffel26c0c152016-07-08 12:40:14 +0200291 udelay(1);
Ian Campbelle24ea552014-05-05 14:42:31 +0100292 }
293
294 if (reading)
Simon Glass3f5af122017-07-04 13:31:24 -0600295 buff[i] = readl(&priv->reg->fifo);
Ian Campbelle24ea552014-05-05 14:42:31 +0100296 else
Simon Glass3f5af122017-07-04 13:31:24 -0600297 writel(buff[i], &priv->reg->fifo);
Ian Campbelle24ea552014-05-05 14:42:31 +0100298 }
299
300 return 0;
301}
302
Simon Glass034e2262017-07-04 13:31:25 -0600303static int mmc_rint_wait(struct sunxi_mmc_priv *priv, struct mmc *mmc,
304 uint timeout_msecs, uint done_bit, const char *what)
Ian Campbelle24ea552014-05-05 14:42:31 +0100305{
Ian Campbelle24ea552014-05-05 14:42:31 +0100306 unsigned int status;
307
308 do {
Simon Glass3f5af122017-07-04 13:31:24 -0600309 status = readl(&priv->reg->rint);
Ian Campbelle24ea552014-05-05 14:42:31 +0100310 if (!timeout_msecs-- ||
311 (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) {
312 debug("%s timeout %x\n", what,
313 status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT);
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900314 return -ETIMEDOUT;
Ian Campbelle24ea552014-05-05 14:42:31 +0100315 }
316 udelay(1000);
317 } while (!(status & done_bit));
318
319 return 0;
320}
321
Simon Glass034e2262017-07-04 13:31:25 -0600322static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv,
323 struct mmc *mmc, struct mmc_cmd *cmd,
324 struct mmc_data *data)
Ian Campbelle24ea552014-05-05 14:42:31 +0100325{
Ian Campbelle24ea552014-05-05 14:42:31 +0100326 unsigned int cmdval = SUNXI_MMC_CMD_START;
327 unsigned int timeout_msecs;
328 int error = 0;
329 unsigned int status = 0;
Ian Campbelle24ea552014-05-05 14:42:31 +0100330 unsigned int bytecnt = 0;
331
Simon Glass3f5af122017-07-04 13:31:24 -0600332 if (priv->fatal_err)
Ian Campbelle24ea552014-05-05 14:42:31 +0100333 return -1;
334 if (cmd->resp_type & MMC_RSP_BUSY)
335 debug("mmc cmd %d check rsp busy\n", cmd->cmdidx);
336 if (cmd->cmdidx == 12)
337 return 0;
338
339 if (!cmd->cmdidx)
340 cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ;
341 if (cmd->resp_type & MMC_RSP_PRESENT)
342 cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE;
343 if (cmd->resp_type & MMC_RSP_136)
344 cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE;
345 if (cmd->resp_type & MMC_RSP_CRC)
346 cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC;
347
348 if (data) {
Alexander Graf0ea5a042016-03-29 17:29:09 +0200349 if ((u32)(long)data->dest & 0x3) {
Ian Campbelle24ea552014-05-05 14:42:31 +0100350 error = -1;
351 goto out;
352 }
353
354 cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER;
355 if (data->flags & MMC_DATA_WRITE)
356 cmdval |= SUNXI_MMC_CMD_WRITE;
357 if (data->blocks > 1)
358 cmdval |= SUNXI_MMC_CMD_AUTO_STOP;
Simon Glass3f5af122017-07-04 13:31:24 -0600359 writel(data->blocksize, &priv->reg->blksz);
360 writel(data->blocks * data->blocksize, &priv->reg->bytecnt);
Ian Campbelle24ea552014-05-05 14:42:31 +0100361 }
362
Simon Glass3f5af122017-07-04 13:31:24 -0600363 debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", priv->mmc_no,
Ian Campbelle24ea552014-05-05 14:42:31 +0100364 cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg);
Simon Glass3f5af122017-07-04 13:31:24 -0600365 writel(cmd->cmdarg, &priv->reg->arg);
Ian Campbelle24ea552014-05-05 14:42:31 +0100366
367 if (!data)
Simon Glass3f5af122017-07-04 13:31:24 -0600368 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
Ian Campbelle24ea552014-05-05 14:42:31 +0100369
370 /*
371 * transfer data and check status
372 * STATREG[2] : FIFO empty
373 * STATREG[3] : FIFO full
374 */
375 if (data) {
376 int ret = 0;
377
378 bytecnt = data->blocksize * data->blocks;
379 debug("trans data %d bytes\n", bytecnt);
Simon Glass3f5af122017-07-04 13:31:24 -0600380 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
Simon Glass034e2262017-07-04 13:31:25 -0600381 ret = mmc_trans_data_by_cpu(priv, mmc, data);
Ian Campbelle24ea552014-05-05 14:42:31 +0100382 if (ret) {
Simon Glass3f5af122017-07-04 13:31:24 -0600383 error = readl(&priv->reg->rint) &
Ian Campbelle24ea552014-05-05 14:42:31 +0100384 SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900385 error = -ETIMEDOUT;
Ian Campbelle24ea552014-05-05 14:42:31 +0100386 goto out;
387 }
388 }
389
Simon Glass034e2262017-07-04 13:31:25 -0600390 error = mmc_rint_wait(priv, mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE,
391 "cmd");
Ian Campbelle24ea552014-05-05 14:42:31 +0100392 if (error)
393 goto out;
394
395 if (data) {
Hans de Goedeb6ae6762014-06-09 11:36:55 +0200396 timeout_msecs = 120;
Ian Campbelle24ea552014-05-05 14:42:31 +0100397 debug("cacl timeout %x msec\n", timeout_msecs);
Simon Glass034e2262017-07-04 13:31:25 -0600398 error = mmc_rint_wait(priv, mmc, timeout_msecs,
Ian Campbelle24ea552014-05-05 14:42:31 +0100399 data->blocks > 1 ?
400 SUNXI_MMC_RINT_AUTO_COMMAND_DONE :
401 SUNXI_MMC_RINT_DATA_OVER,
402 "data");
403 if (error)
404 goto out;
405 }
406
407 if (cmd->resp_type & MMC_RSP_BUSY) {
408 timeout_msecs = 2000;
409 do {
Simon Glass3f5af122017-07-04 13:31:24 -0600410 status = readl(&priv->reg->status);
Ian Campbelle24ea552014-05-05 14:42:31 +0100411 if (!timeout_msecs--) {
412 debug("busy timeout\n");
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900413 error = -ETIMEDOUT;
Ian Campbelle24ea552014-05-05 14:42:31 +0100414 goto out;
415 }
416 udelay(1000);
417 } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY);
418 }
419
420 if (cmd->resp_type & MMC_RSP_136) {
Simon Glass3f5af122017-07-04 13:31:24 -0600421 cmd->response[0] = readl(&priv->reg->resp3);
422 cmd->response[1] = readl(&priv->reg->resp2);
423 cmd->response[2] = readl(&priv->reg->resp1);
424 cmd->response[3] = readl(&priv->reg->resp0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100425 debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n",
426 cmd->response[3], cmd->response[2],
427 cmd->response[1], cmd->response[0]);
428 } else {
Simon Glass3f5af122017-07-04 13:31:24 -0600429 cmd->response[0] = readl(&priv->reg->resp0);
Ian Campbelle24ea552014-05-05 14:42:31 +0100430 debug("mmc resp 0x%08x\n", cmd->response[0]);
431 }
432out:
Ian Campbelle24ea552014-05-05 14:42:31 +0100433 if (error < 0) {
Simon Glass3f5af122017-07-04 13:31:24 -0600434 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
Simon Glass034e2262017-07-04 13:31:25 -0600435 mmc_update_clk(priv);
Ian Campbelle24ea552014-05-05 14:42:31 +0100436 }
Simon Glass3f5af122017-07-04 13:31:24 -0600437 writel(0xffffffff, &priv->reg->rint);
438 writel(readl(&priv->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET,
439 &priv->reg->gctrl);
Ian Campbelle24ea552014-05-05 14:42:31 +0100440
441 return error;
442}
443
Simon Glassdd279182017-07-04 13:31:27 -0600444#if !CONFIG_IS_ENABLED(DM_MMC)
Simon Glass034e2262017-07-04 13:31:25 -0600445static int sunxi_mmc_set_ios_legacy(struct mmc *mmc)
446{
447 struct sunxi_mmc_priv *priv = mmc->priv;
448
449 return sunxi_mmc_set_ios_common(priv, mmc);
450}
451
452static int sunxi_mmc_send_cmd_legacy(struct mmc *mmc, struct mmc_cmd *cmd,
453 struct mmc_data *data)
454{
455 struct sunxi_mmc_priv *priv = mmc->priv;
456
457 return sunxi_mmc_send_cmd_common(priv, mmc, cmd, data);
458}
459
460static int sunxi_mmc_getcd_legacy(struct mmc *mmc)
Hans de Goedecd821132014-10-02 20:29:26 +0200461{
Simon Glass3f5af122017-07-04 13:31:24 -0600462 struct sunxi_mmc_priv *priv = mmc->priv;
Hans de Goede967325f2014-10-31 16:55:02 +0100463 int cd_pin;
Hans de Goedecd821132014-10-02 20:29:26 +0200464
Simon Glass3f5af122017-07-04 13:31:24 -0600465 cd_pin = sunxi_mmc_getcd_gpio(priv->mmc_no);
Hans de Goede90641f82015-04-22 17:03:17 +0200466 if (cd_pin < 0)
Hans de Goedecd821132014-10-02 20:29:26 +0200467 return 1;
468
Axel Linb0c4ae12014-12-20 11:41:25 +0800469 return !gpio_get_value(cd_pin);
Hans de Goedecd821132014-10-02 20:29:26 +0200470}
471
Ian Campbelle24ea552014-05-05 14:42:31 +0100472static const struct mmc_ops sunxi_mmc_ops = {
Simon Glass034e2262017-07-04 13:31:25 -0600473 .send_cmd = sunxi_mmc_send_cmd_legacy,
474 .set_ios = sunxi_mmc_set_ios_legacy,
Siarhei Siamashka5abdb152015-02-01 00:42:14 +0200475 .init = sunxi_mmc_core_init,
Simon Glass034e2262017-07-04 13:31:25 -0600476 .getcd = sunxi_mmc_getcd_legacy,
Ian Campbelle24ea552014-05-05 14:42:31 +0100477};
478
Hans de Goedee79c7c82014-10-02 21:13:54 +0200479struct mmc *sunxi_mmc_init(int sdc_no)
Ian Campbelle24ea552014-05-05 14:42:31 +0100480{
Simon Glassec73d962017-07-04 13:31:26 -0600481 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Simon Glass034e2262017-07-04 13:31:25 -0600482 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
483 struct mmc_config *cfg = &priv->cfg;
Simon Glassec73d962017-07-04 13:31:26 -0600484 int ret;
Ian Campbelle24ea552014-05-05 14:42:31 +0100485
Simon Glass034e2262017-07-04 13:31:25 -0600486 memset(priv, '\0', sizeof(struct sunxi_mmc_priv));
Ian Campbelle24ea552014-05-05 14:42:31 +0100487
488 cfg->name = "SUNXI SD/MMC";
489 cfg->ops = &sunxi_mmc_ops;
490
491 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
492 cfg->host_caps = MMC_MODE_4BIT;
Maxime Ripardfb013182016-11-04 16:18:09 +0100493#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I)
Siarhei Siamashkad96ebc42016-03-29 17:29:10 +0200494 if (sdc_no == 2)
495 cfg->host_caps = MMC_MODE_8BIT;
496#endif
Rob Herring5a203972015-03-23 17:56:59 -0500497 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
Ian Campbelle24ea552014-05-05 14:42:31 +0100498 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
499
500 cfg->f_min = 400000;
501 cfg->f_max = 52000000;
502
Hans de Goede967325f2014-10-31 16:55:02 +0100503 if (mmc_resource_init(sdc_no) != 0)
504 return NULL;
505
Simon Glassec73d962017-07-04 13:31:26 -0600506 /* config ahb clock */
507 debug("init mmc %d clock and io\n", sdc_no);
508 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
509
510#ifdef CONFIG_SUNXI_GEN_SUN6I
511 /* unassert reset */
512 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no));
513#endif
514#if defined(CONFIG_MACH_SUN9I)
515 /* sun9i has a mmc-common module, also set the gate and reset there */
516 writel(SUNXI_MMC_COMMON_CLK_GATE | SUNXI_MMC_COMMON_RESET,
517 SUNXI_MMC_COMMON_BASE + 4 * sdc_no);
518#endif
519 ret = mmc_set_mod_clk(priv, 24000000);
520 if (ret)
521 return NULL;
Ian Campbelle24ea552014-05-05 14:42:31 +0100522
Maxime Ripardead36972017-08-23 13:41:33 +0200523 return mmc_create(cfg, priv);
Ian Campbelle24ea552014-05-05 14:42:31 +0100524}
Simon Glassdd279182017-07-04 13:31:27 -0600525#else
526
527static int sunxi_mmc_set_ios(struct udevice *dev)
528{
529 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
530 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
531
532 return sunxi_mmc_set_ios_common(priv, &plat->mmc);
533}
534
535static int sunxi_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
536 struct mmc_data *data)
537{
538 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
539 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
540
541 return sunxi_mmc_send_cmd_common(priv, &plat->mmc, cmd, data);
542}
543
544static int sunxi_mmc_getcd(struct udevice *dev)
545{
546 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
547
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +0100548 if (dm_gpio_is_valid(&priv->cd_gpio)) {
549 int cd_state = dm_gpio_get_value(&priv->cd_gpio);
Simon Glassdd279182017-07-04 13:31:27 -0600550
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +0100551 return cd_state ^ priv->cd_inverted;
552 }
Simon Glassdd279182017-07-04 13:31:27 -0600553 return 1;
554}
555
556static const struct dm_mmc_ops sunxi_mmc_ops = {
557 .send_cmd = sunxi_mmc_send_cmd,
558 .set_ios = sunxi_mmc_set_ios,
559 .get_cd = sunxi_mmc_getcd,
560};
561
562static int sunxi_mmc_probe(struct udevice *dev)
563{
564 struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
565 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
566 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
567 struct mmc_config *cfg = &plat->cfg;
568 struct ofnode_phandle_args args;
569 u32 *gate_reg;
570 int bus_width, ret;
571
572 cfg->name = dev->name;
573 bus_width = dev_read_u32_default(dev, "bus-width", 1);
574
575 cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
576 cfg->host_caps = 0;
577 if (bus_width == 8)
578 cfg->host_caps |= MMC_MODE_8BIT;
579 if (bus_width >= 4)
580 cfg->host_caps |= MMC_MODE_4BIT;
581 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
582 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
583
584 cfg->f_min = 400000;
585 cfg->f_max = 52000000;
586
587 priv->reg = (void *)dev_read_addr(dev);
588
589 /* We don't have a sunxi clock driver so find the clock address here */
590 ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
591 1, &args);
592 if (ret)
593 return ret;
594 priv->mclkreg = (u32 *)ofnode_get_addr(args.node);
595
596 ret = dev_read_phandle_with_args(dev, "clocks", "#clock-cells", 0,
597 0, &args);
598 if (ret)
599 return ret;
600 gate_reg = (u32 *)ofnode_get_addr(args.node);
601 setbits_le32(gate_reg, 1 << args.args[0]);
602 priv->mmc_no = args.args[0] - 8;
603
604 ret = mmc_set_mod_clk(priv, 24000000);
605 if (ret)
606 return ret;
607
608 /* This GPIO is optional */
609 if (!gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
610 GPIOD_IS_IN)) {
611 int cd_pin = gpio_get_number(&priv->cd_gpio);
612
613 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
614 }
615
Heinrich Schuchardt8be4e612018-02-01 23:39:19 +0100616 /* Check if card detect is inverted */
617 priv->cd_inverted = dev_read_bool(dev, "cd-inverted");
618
Simon Glassdd279182017-07-04 13:31:27 -0600619 upriv->mmc = &plat->mmc;
620
621 /* Reset controller */
622 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
623 udelay(1000);
624
625 return 0;
626}
627
628static int sunxi_mmc_bind(struct udevice *dev)
629{
630 struct sunxi_mmc_plat *plat = dev_get_platdata(dev);
631
632 return mmc_bind(dev, &plat->mmc, &plat->cfg);
633}
634
635static const struct udevice_id sunxi_mmc_ids[] = {
636 { .compatible = "allwinner,sun5i-a13-mmc" },
637 { }
638};
639
640U_BOOT_DRIVER(sunxi_mmc_drv) = {
641 .name = "sunxi_mmc",
642 .id = UCLASS_MMC,
643 .of_match = sunxi_mmc_ids,
644 .bind = sunxi_mmc_bind,
645 .probe = sunxi_mmc_probe,
646 .ops = &sunxi_mmc_ops,
647 .platdata_auto_alloc_size = sizeof(struct sunxi_mmc_plat),
648 .priv_auto_alloc_size = sizeof(struct sunxi_mmc_priv),
649};
650#endif