blob: 5292f2d3cc10a2051c7573ce81fb0f2647d5d496 [file] [log] [blame]
Ian Campbellb4e9f2f2014-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 Glass7484ae72017-07-04 13:31:27 -060012#include <dm.h>
Hans de Goedeb1e107a2015-04-22 17:03:17 +020013#include <errno.h>
Ian Campbellb4e9f2f2014-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 Goede7412ef82014-10-02 20:29:26 +020019#include <asm/arch/gpio.h>
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010020#include <asm/arch/mmc.h>
Hans de Goede7412ef82014-10-02 20:29:26 +020021#include <asm-generic/gpio.h>
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010022
Simon Glass7484ae72017-07-04 13:31:27 -060023struct sunxi_mmc_plat {
24 struct mmc_config cfg;
25 struct mmc mmc;
26};
27
Simon Glass3f19fbf2017-07-04 13:31:23 -060028struct sunxi_mmc_priv {
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010029 unsigned mmc_no;
30 uint32_t *mclkreg;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010031 unsigned fatal_err;
Simon Glass7484ae72017-07-04 13:31:27 -060032 struct gpio_desc cd_gpio; /* Change Detect GPIO */
Heinrich Schuchardt8dc0a992018-02-01 23:39:19 +010033 int cd_inverted; /* Inverted Card Detect */
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010034 struct sunxi_mmc *reg;
35 struct mmc_config cfg;
36};
37
Simon Glass7484ae72017-07-04 13:31:27 -060038#if !CONFIG_IS_ENABLED(DM_MMC)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010039/* support 4 mmc hosts */
Simon Glass3f19fbf2017-07-04 13:31:23 -060040struct sunxi_mmc_priv mmc_host[4];
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010041
Hans de Goede3d1095f2014-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 Goedeb1e107a2015-04-22 17:03:17 +020050 return -EINVAL;
Hans de Goede3d1095f2014-10-31 16:55:02 +010051}
52
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010053static int mmc_resource_init(int sdc_no)
54{
Simon Glass8e659a22017-07-04 13:31:24 -060055 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010056 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Hans de Goede3d1095f2014-10-31 16:55:02 +010057 int cd_pin, ret = 0;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010058
59 debug("init mmc %d resource\n", sdc_no);
60
61 switch (sdc_no) {
62 case 0:
Simon Glass8e659a22017-07-04 13:31:24 -060063 priv->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
64 priv->mclkreg = &ccm->sd0_clk_cfg;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010065 break;
66 case 1:
Simon Glass8e659a22017-07-04 13:31:24 -060067 priv->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
68 priv->mclkreg = &ccm->sd1_clk_cfg;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010069 break;
70 case 2:
Simon Glass8e659a22017-07-04 13:31:24 -060071 priv->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
72 priv->mclkreg = &ccm->sd2_clk_cfg;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010073 break;
74 case 3:
Simon Glass8e659a22017-07-04 13:31:24 -060075 priv->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
76 priv->mclkreg = &ccm->sd3_clk_cfg;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010077 break;
78 default:
79 printf("Wrong mmc number %d\n", sdc_no);
80 return -1;
81 }
Simon Glass8e659a22017-07-04 13:31:24 -060082 priv->mmc_no = sdc_no;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010083
Hans de Goede3d1095f2014-10-31 16:55:02 +010084 cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
Hans de Goedeb1e107a2015-04-22 17:03:17 +020085 if (cd_pin >= 0) {
Hans de Goede3d1095f2014-10-31 16:55:02 +010086 ret = gpio_request(cd_pin, "mmc_cd");
Hans de Goedee6525302015-05-30 16:39:10 +020087 if (!ret) {
88 sunxi_gpio_set_pull(cd_pin, SUNXI_GPIO_PULL_UP);
Axel Lin06da3462014-12-20 11:41:25 +080089 ret = gpio_direction_input(cd_pin);
Hans de Goedee6525302015-05-30 16:39:10 +020090 }
Axel Lin06da3462014-12-20 11:41:25 +080091 }
Hans de Goede3d1095f2014-10-31 16:55:02 +010092
93 return ret;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010094}
Simon Glass7484ae72017-07-04 13:31:27 -060095#endif
Ian Campbellb4e9f2f2014-05-05 14:42:31 +010096
Simon Glass8e659a22017-07-04 13:31:24 -060097static int mmc_set_mod_clk(struct sunxi_mmc_priv *priv, unsigned int hz)
Hans de Goede06bfab02014-12-07 20:55:10 +010098{
99 unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
Maxime Ripard95e34702017-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 Goede06bfab02014-12-07 20:55:10 +0100112
113 if (hz <= 24000000) {
114 pll = CCM_MMC_CTRL_OSCM24;
115 pll_hz = 24000000;
116 } else {
Hans de Goedef1865db2015-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 Goede06bfab02014-12-07 20:55:10 +0100121 pll = CCM_MMC_CTRL_PLL6;
122 pll_hz = clock_get_pll6();
Hans de Goedef1865db2015-01-14 19:05:03 +0100123#endif
Hans de Goede06bfab02014-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 Glass8e659a22017-07-04 13:31:24 -0600137 printf("mmc %u error cannot set clock to %u\n", priv->mmc_no,
138 hz);
Hans de Goede06bfab02014-12-07 20:55:10 +0100139 return -1;
140 }
141
142 /* determine delays */
143 if (hz <= 400000) {
144 oclk_dly = 0;
Hans de Goede5192ba22015-09-23 16:13:10 +0200145 sclk_dly = 0;
Hans de Goede06bfab02014-12-07 20:55:10 +0100146 } else if (hz <= 25000000) {
147 oclk_dly = 0;
148 sclk_dly = 5;
Hans de Goede5192ba22015-09-23 16:13:10 +0200149#ifdef CONFIG_MACH_SUN9I
Stefan Mavrodiev180194b2018-03-27 16:57:23 +0300150 } else if (hz <= 52000000) {
Hans de Goede5192ba22015-09-23 16:13:10 +0200151 oclk_dly = 5;
152 sclk_dly = 4;
Hans de Goede06bfab02014-12-07 20:55:10 +0100153 } else {
Stefan Mavrodiev180194b2018-03-27 16:57:23 +0300154 /* hz > 52000000 */
Hans de Goede06bfab02014-12-07 20:55:10 +0100155 oclk_dly = 2;
156 sclk_dly = 4;
Hans de Goede5192ba22015-09-23 16:13:10 +0200157#else
Stefan Mavrodiev180194b2018-03-27 16:57:23 +0300158 } else if (hz <= 52000000) {
Hans de Goede5192ba22015-09-23 16:13:10 +0200159 oclk_dly = 3;
160 sclk_dly = 4;
161 } else {
Stefan Mavrodiev180194b2018-03-27 16:57:23 +0300162 /* hz > 52000000 */
Hans de Goede5192ba22015-09-23 16:13:10 +0200163 oclk_dly = 1;
164 sclk_dly = 4;
165#endif
Maxime Ripard95e34702017-08-23 12:03:41 +0200166 }
167
168 if (new_mode) {
169#ifdef CONFIG_MMC_SUNXI_HAS_NEW_MODE
170 val = CCM_MMC_CTRL_MODE_SEL_NEW;
Chen-Yu Tsaie76f0062017-08-31 21:57:48 +0800171 setbits_le32(&priv->reg->ntsr, SUNXI_MMC_NTSR_MODE_SEL_NEW);
Maxime Ripard95e34702017-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);
Hans de Goede06bfab02014-12-07 20:55:10 +0100176 }
177
Maxime Ripard95e34702017-08-23 12:03:41 +0200178 writel(CCM_MMC_CTRL_ENABLE| pll | CCM_MMC_CTRL_N(n) |
179 CCM_MMC_CTRL_M(div) | val, priv->mclkreg);
Hans de Goede06bfab02014-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 Glass8e659a22017-07-04 13:31:24 -0600182 priv->mmc_no, hz, pll_hz, 1u << n, div, pll_hz / (1u << n) / div);
Hans de Goede06bfab02014-12-07 20:55:10 +0100183
184 return 0;
185}
186
Simon Glass87ff0f72017-07-04 13:31:25 -0600187static int mmc_update_clk(struct sunxi_mmc_priv *priv)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100188{
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100189 unsigned int cmd;
190 unsigned timeout_msecs = 2000;
Philipp Tomsich1721b002018-03-21 12:18:58 +0100191 unsigned long start = get_timer(0);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100192
193 cmd = SUNXI_MMC_CMD_START |
194 SUNXI_MMC_CMD_UPCLK_ONLY |
195 SUNXI_MMC_CMD_WAIT_PRE_OVER;
Philipp Tomsich1721b002018-03-21 12:18:58 +0100196
Simon Glass8e659a22017-07-04 13:31:24 -0600197 writel(cmd, &priv->reg->cmd);
198 while (readl(&priv->reg->cmd) & SUNXI_MMC_CMD_START) {
Philipp Tomsich1721b002018-03-21 12:18:58 +0100199 if (get_timer(start) > timeout_msecs)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100200 return -1;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100201 }
202
203 /* clock update sets various irq status bits, clear these */
Simon Glass8e659a22017-07-04 13:31:24 -0600204 writel(readl(&priv->reg->rint), &priv->reg->rint);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100205
206 return 0;
207}
208
Simon Glass87ff0f72017-07-04 13:31:25 -0600209static int mmc_config_clock(struct sunxi_mmc_priv *priv, struct mmc *mmc)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100210{
Simon Glass8e659a22017-07-04 13:31:24 -0600211 unsigned rval = readl(&priv->reg->clkcr);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100212
213 /* Disable Clock */
214 rval &= ~SUNXI_MMC_CLK_ENABLE;
Simon Glass8e659a22017-07-04 13:31:24 -0600215 writel(rval, &priv->reg->clkcr);
Simon Glass87ff0f72017-07-04 13:31:25 -0600216 if (mmc_update_clk(priv))
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100217 return -1;
218
Hans de Goede06bfab02014-12-07 20:55:10 +0100219 /* Set mod_clk to new rate */
Simon Glass8e659a22017-07-04 13:31:24 -0600220 if (mmc_set_mod_clk(priv, mmc->clock))
Hans de Goede06bfab02014-12-07 20:55:10 +0100221 return -1;
222
223 /* Clear internal divider */
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100224 rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
Simon Glass8e659a22017-07-04 13:31:24 -0600225 writel(rval, &priv->reg->clkcr);
Hans de Goede06bfab02014-12-07 20:55:10 +0100226
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100227 /* Re-enable Clock */
228 rval |= SUNXI_MMC_CLK_ENABLE;
Simon Glass8e659a22017-07-04 13:31:24 -0600229 writel(rval, &priv->reg->clkcr);
Simon Glass87ff0f72017-07-04 13:31:25 -0600230 if (mmc_update_clk(priv))
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100231 return -1;
232
233 return 0;
234}
235
Simon Glass87ff0f72017-07-04 13:31:25 -0600236static int sunxi_mmc_set_ios_common(struct sunxi_mmc_priv *priv,
237 struct mmc *mmc)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100238{
Hans de Goede06bfab02014-12-07 20:55:10 +0100239 debug("set ios: bus_width: %x, clock: %d\n",
240 mmc->bus_width, mmc->clock);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100241
242 /* Change clock first */
Simon Glass87ff0f72017-07-04 13:31:25 -0600243 if (mmc->clock && mmc_config_clock(priv, mmc) != 0) {
Simon Glass8e659a22017-07-04 13:31:24 -0600244 priv->fatal_err = 1;
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900245 return -EINVAL;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100246 }
247
248 /* Change bus width */
249 if (mmc->bus_width == 8)
Simon Glass8e659a22017-07-04 13:31:24 -0600250 writel(0x2, &priv->reg->width);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100251 else if (mmc->bus_width == 4)
Simon Glass8e659a22017-07-04 13:31:24 -0600252 writel(0x1, &priv->reg->width);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100253 else
Simon Glass8e659a22017-07-04 13:31:24 -0600254 writel(0x0, &priv->reg->width);
Jaehoon Chungb6cd1d32016-12-30 15:30:16 +0900255
256 return 0;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100257}
258
Simon Glass7484ae72017-07-04 13:31:27 -0600259#if !CONFIG_IS_ENABLED(DM_MMC)
Siarhei Siamashka253d77d2015-02-01 00:42:14 +0200260static int sunxi_mmc_core_init(struct mmc *mmc)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100261{
Simon Glass8e659a22017-07-04 13:31:24 -0600262 struct sunxi_mmc_priv *priv = mmc->priv;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100263
264 /* Reset controller */
Simon Glass8e659a22017-07-04 13:31:24 -0600265 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
Hans de Goede411dc872014-06-09 11:36:55 +0200266 udelay(1000);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100267
268 return 0;
269}
Simon Glass7484ae72017-07-04 13:31:27 -0600270#endif
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100271
Simon Glass87ff0f72017-07-04 13:31:25 -0600272static int mmc_trans_data_by_cpu(struct sunxi_mmc_priv *priv, struct mmc *mmc,
273 struct mmc_data *data)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100274{
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100275 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;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100279 unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
Yousong Zhoub0170092015-08-29 21:26:11 +0800280 unsigned byte_cnt = data->blocksize * data->blocks;
Philipp Tomsich1721b002018-03-21 12:18:58 +0100281 unsigned timeout_msecs = byte_cnt >> 8;
282 unsigned long start;
283
284 if (timeout_msecs < 2000)
285 timeout_msecs = 2000;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100286
Hans de Goede411dc872014-06-09 11:36:55 +0200287 /* Always read / write data through the CPU */
Simon Glass8e659a22017-07-04 13:31:24 -0600288 setbits_le32(&priv->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
Hans de Goede411dc872014-06-09 11:36:55 +0200289
Philipp Tomsich1721b002018-03-21 12:18:58 +0100290 start = get_timer(0);
291
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100292 for (i = 0; i < (byte_cnt >> 2); i++) {
Simon Glass8e659a22017-07-04 13:31:24 -0600293 while (readl(&priv->reg->status) & status_bit) {
Philipp Tomsich1721b002018-03-21 12:18:58 +0100294 if (get_timer(start) > timeout_msecs)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100295 return -1;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100296 }
297
298 if (reading)
Simon Glass8e659a22017-07-04 13:31:24 -0600299 buff[i] = readl(&priv->reg->fifo);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100300 else
Simon Glass8e659a22017-07-04 13:31:24 -0600301 writel(buff[i], &priv->reg->fifo);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100302 }
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100303
304 return 0;
305}
306
Simon Glass87ff0f72017-07-04 13:31:25 -0600307static int mmc_rint_wait(struct sunxi_mmc_priv *priv, struct mmc *mmc,
308 uint timeout_msecs, uint done_bit, const char *what)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100309{
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100310 unsigned int status;
Philipp Tomsich1721b002018-03-21 12:18:58 +0100311 unsigned long start = get_timer(0);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100312
313 do {
Simon Glass8e659a22017-07-04 13:31:24 -0600314 status = readl(&priv->reg->rint);
Philipp Tomsich1721b002018-03-21 12:18:58 +0100315 if ((get_timer(start) > timeout_msecs) ||
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100316 (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) {
317 debug("%s timeout %x\n", what,
318 status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900319 return -ETIMEDOUT;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100320 }
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100321 } while (!(status & done_bit));
322
323 return 0;
324}
325
Simon Glass87ff0f72017-07-04 13:31:25 -0600326static int sunxi_mmc_send_cmd_common(struct sunxi_mmc_priv *priv,
327 struct mmc *mmc, struct mmc_cmd *cmd,
328 struct mmc_data *data)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100329{
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100330 unsigned int cmdval = SUNXI_MMC_CMD_START;
331 unsigned int timeout_msecs;
332 int error = 0;
333 unsigned int status = 0;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100334 unsigned int bytecnt = 0;
335
Simon Glass8e659a22017-07-04 13:31:24 -0600336 if (priv->fatal_err)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100337 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) {
Alexander Grafee1d8252016-03-29 17:29:09 +0200353 if ((u32)(long)data->dest & 0x3) {
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100354 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;
Simon Glass8e659a22017-07-04 13:31:24 -0600363 writel(data->blocksize, &priv->reg->blksz);
364 writel(data->blocks * data->blocksize, &priv->reg->bytecnt);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100365 }
366
Simon Glass8e659a22017-07-04 13:31:24 -0600367 debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", priv->mmc_no,
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100368 cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg);
Simon Glass8e659a22017-07-04 13:31:24 -0600369 writel(cmd->cmdarg, &priv->reg->arg);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100370
371 if (!data)
Simon Glass8e659a22017-07-04 13:31:24 -0600372 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100373
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);
Simon Glass8e659a22017-07-04 13:31:24 -0600384 writel(cmdval | cmd->cmdidx, &priv->reg->cmd);
Simon Glass87ff0f72017-07-04 13:31:25 -0600385 ret = mmc_trans_data_by_cpu(priv, mmc, data);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100386 if (ret) {
Simon Glass8e659a22017-07-04 13:31:24 -0600387 error = readl(&priv->reg->rint) &
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100388 SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
Jaehoon Chung7825d202016-07-19 16:33:36 +0900389 error = -ETIMEDOUT;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100390 goto out;
391 }
392 }
393
Simon Glass87ff0f72017-07-04 13:31:25 -0600394 error = mmc_rint_wait(priv, mmc, 1000, SUNXI_MMC_RINT_COMMAND_DONE,
395 "cmd");
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100396 if (error)
397 goto out;
398
399 if (data) {
Hans de Goede411dc872014-06-09 11:36:55 +0200400 timeout_msecs = 120;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100401 debug("cacl timeout %x msec\n", timeout_msecs);
Simon Glass87ff0f72017-07-04 13:31:25 -0600402 error = mmc_rint_wait(priv, mmc, timeout_msecs,
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100403 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) {
Philipp Tomsich1721b002018-03-21 12:18:58 +0100412 unsigned long start = get_timer(0);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100413 timeout_msecs = 2000;
Philipp Tomsich1721b002018-03-21 12:18:58 +0100414
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100415 do {
Simon Glass8e659a22017-07-04 13:31:24 -0600416 status = readl(&priv->reg->status);
Philipp Tomsich1721b002018-03-21 12:18:58 +0100417 if (get_timer(start) > timeout_msecs) {
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100418 debug("busy timeout\n");
Jaehoon Chung7825d202016-07-19 16:33:36 +0900419 error = -ETIMEDOUT;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100420 goto out;
421 }
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100422 } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY);
423 }
424
425 if (cmd->resp_type & MMC_RSP_136) {
Simon Glass8e659a22017-07-04 13:31:24 -0600426 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);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100430 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 {
Simon Glass8e659a22017-07-04 13:31:24 -0600434 cmd->response[0] = readl(&priv->reg->resp0);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100435 debug("mmc resp 0x%08x\n", cmd->response[0]);
436 }
437out:
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100438 if (error < 0) {
Simon Glass8e659a22017-07-04 13:31:24 -0600439 writel(SUNXI_MMC_GCTRL_RESET, &priv->reg->gctrl);
Simon Glass87ff0f72017-07-04 13:31:25 -0600440 mmc_update_clk(priv);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100441 }
Simon Glass8e659a22017-07-04 13:31:24 -0600442 writel(0xffffffff, &priv->reg->rint);
443 writel(readl(&priv->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET,
444 &priv->reg->gctrl);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100445
446 return error;
447}
448
Simon Glass7484ae72017-07-04 13:31:27 -0600449#if !CONFIG_IS_ENABLED(DM_MMC)
Simon Glass87ff0f72017-07-04 13:31:25 -0600450static 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
457static 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
465static int sunxi_mmc_getcd_legacy(struct mmc *mmc)
Hans de Goede7412ef82014-10-02 20:29:26 +0200466{
Simon Glass8e659a22017-07-04 13:31:24 -0600467 struct sunxi_mmc_priv *priv = mmc->priv;
Hans de Goede3d1095f2014-10-31 16:55:02 +0100468 int cd_pin;
Hans de Goede7412ef82014-10-02 20:29:26 +0200469
Simon Glass8e659a22017-07-04 13:31:24 -0600470 cd_pin = sunxi_mmc_getcd_gpio(priv->mmc_no);
Hans de Goedeb1e107a2015-04-22 17:03:17 +0200471 if (cd_pin < 0)
Hans de Goede7412ef82014-10-02 20:29:26 +0200472 return 1;
473
Axel Lin06da3462014-12-20 11:41:25 +0800474 return !gpio_get_value(cd_pin);
Hans de Goede7412ef82014-10-02 20:29:26 +0200475}
476
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100477static const struct mmc_ops sunxi_mmc_ops = {
Simon Glass87ff0f72017-07-04 13:31:25 -0600478 .send_cmd = sunxi_mmc_send_cmd_legacy,
479 .set_ios = sunxi_mmc_set_ios_legacy,
Siarhei Siamashka253d77d2015-02-01 00:42:14 +0200480 .init = sunxi_mmc_core_init,
Simon Glass87ff0f72017-07-04 13:31:25 -0600481 .getcd = sunxi_mmc_getcd_legacy,
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100482};
483
Hans de Goede63deaa82014-10-02 21:13:54 +0200484struct mmc *sunxi_mmc_init(int sdc_no)
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100485{
Simon Glass3a654152017-07-04 13:31:26 -0600486 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
Simon Glass87ff0f72017-07-04 13:31:25 -0600487 struct sunxi_mmc_priv *priv = &mmc_host[sdc_no];
488 struct mmc_config *cfg = &priv->cfg;
Simon Glass3a654152017-07-04 13:31:26 -0600489 int ret;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100490
Simon Glass87ff0f72017-07-04 13:31:25 -0600491 memset(priv, '\0', sizeof(struct sunxi_mmc_priv));
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100492
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;
Maxime Ripard584d7ae2016-11-04 16:18:09 +0100498#if defined(CONFIG_MACH_SUN50I) || defined(CONFIG_MACH_SUN8I)
Siarhei Siamashka26c50fb2016-03-29 17:29:10 +0200499 if (sdc_no == 2)
500 cfg->host_caps = MMC_MODE_8BIT;
501#endif
Rob Herring5fd3edd2015-03-23 17:56:59 -0500502 cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100503 cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
504
505 cfg->f_min = 400000;
506 cfg->f_max = 52000000;
507
Hans de Goede3d1095f2014-10-31 16:55:02 +0100508 if (mmc_resource_init(sdc_no) != 0)
509 return NULL;
510
Simon Glass3a654152017-07-04 13:31:26 -0600511 /* 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;
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100527
Maxime Ripard0cc228e2017-08-23 13:41:33 +0200528 return mmc_create(cfg, priv);
Ian Campbellb4e9f2f2014-05-05 14:42:31 +0100529}
Simon Glass7484ae72017-07-04 13:31:27 -0600530#else
531
532static 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
540static 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
549static int sunxi_mmc_getcd(struct udevice *dev)
550{
551 struct sunxi_mmc_priv *priv = dev_get_priv(dev);
552
Heinrich Schuchardt8dc0a992018-02-01 23:39:19 +0100553 if (dm_gpio_is_valid(&priv->cd_gpio)) {
554 int cd_state = dm_gpio_get_value(&priv->cd_gpio);
Simon Glass7484ae72017-07-04 13:31:27 -0600555
Heinrich Schuchardt8dc0a992018-02-01 23:39:19 +0100556 return cd_state ^ priv->cd_inverted;
557 }
Simon Glass7484ae72017-07-04 13:31:27 -0600558 return 1;
559}
560
561static 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
567static 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
Heinrich Schuchardt8dc0a992018-02-01 23:39:19 +0100621 /* Check if card detect is inverted */
622 priv->cd_inverted = dev_read_bool(dev, "cd-inverted");
623
Simon Glass7484ae72017-07-04 13:31:27 -0600624 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
633static 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
640static const struct udevice_id sunxi_mmc_ids[] = {
641 { .compatible = "allwinner,sun5i-a13-mmc" },
642 { }
643};
644
645U_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