]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mmc/sunxi_mmc.c
ARM: sunxi-mmc: Add mmc support for sun6i / A31
[karo-tx-uboot.git] / drivers / mmc / sunxi_mmc.c
1 /*
2  * (C) Copyright 2007-2011
3  * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
4  * Aaron <leafy.myeh@allwinnertech.com>
5  *
6  * MMC driver for allwinner sunxi platform.
7  *
8  * SPDX-License-Identifier:     GPL-2.0+
9  */
10
11 #include <common.h>
12 #include <malloc.h>
13 #include <mmc.h>
14 #include <asm/io.h>
15 #include <asm/arch/clock.h>
16 #include <asm/arch/cpu.h>
17 #include <asm/arch/mmc.h>
18
19 struct sunxi_mmc_host {
20         unsigned mmc_no;
21         uint32_t *mclkreg;
22         unsigned fatal_err;
23         unsigned mod_clk;
24         struct sunxi_mmc *reg;
25         struct mmc_config cfg;
26 };
27
28 /* support 4 mmc hosts */
29 struct sunxi_mmc_host mmc_host[4];
30
31 static int mmc_resource_init(int sdc_no)
32 {
33         struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no];
34         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
35
36         debug("init mmc %d resource\n", sdc_no);
37
38         switch (sdc_no) {
39         case 0:
40                 mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC0_BASE;
41                 mmchost->mclkreg = &ccm->sd0_clk_cfg;
42                 break;
43         case 1:
44                 mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC1_BASE;
45                 mmchost->mclkreg = &ccm->sd1_clk_cfg;
46                 break;
47         case 2:
48                 mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC2_BASE;
49                 mmchost->mclkreg = &ccm->sd2_clk_cfg;
50                 break;
51         case 3:
52                 mmchost->reg = (struct sunxi_mmc *)SUNXI_MMC3_BASE;
53                 mmchost->mclkreg = &ccm->sd3_clk_cfg;
54                 break;
55         default:
56                 printf("Wrong mmc number %d\n", sdc_no);
57                 return -1;
58         }
59         mmchost->mmc_no = sdc_no;
60
61         return 0;
62 }
63
64 static int mmc_clk_io_on(int sdc_no)
65 {
66         unsigned int pll_clk;
67         unsigned int divider;
68         struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no];
69         struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
70
71         debug("init mmc %d clock and io\n", sdc_no);
72
73         /* config ahb clock */
74         setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
75
76 #if defined(CONFIG_SUN6I)
77         /* unassert reset */
78         setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no));
79 #endif
80
81         /* config mod clock */
82         pll_clk = clock_get_pll6();
83         /* should be close to 100 MHz but no more, so round up */
84         divider = ((pll_clk + 99999999) / 100000000) - 1;
85         writel(CCM_MMC_CTRL_ENABLE | CCM_MMC_CTRL_PLL6 | divider,
86                mmchost->mclkreg);
87         mmchost->mod_clk = pll_clk / (divider + 1);
88
89         return 0;
90 }
91
92 static int mmc_update_clk(struct mmc *mmc)
93 {
94         struct sunxi_mmc_host *mmchost = mmc->priv;
95         unsigned int cmd;
96         unsigned timeout_msecs = 2000;
97
98         cmd = SUNXI_MMC_CMD_START |
99               SUNXI_MMC_CMD_UPCLK_ONLY |
100               SUNXI_MMC_CMD_WAIT_PRE_OVER;
101         writel(cmd, &mmchost->reg->cmd);
102         while (readl(&mmchost->reg->cmd) & SUNXI_MMC_CMD_START) {
103                 if (!timeout_msecs--)
104                         return -1;
105                 udelay(1000);
106         }
107
108         /* clock update sets various irq status bits, clear these */
109         writel(readl(&mmchost->reg->rint), &mmchost->reg->rint);
110
111         return 0;
112 }
113
114 static int mmc_config_clock(struct mmc *mmc, unsigned div)
115 {
116         struct sunxi_mmc_host *mmchost = mmc->priv;
117         unsigned rval = readl(&mmchost->reg->clkcr);
118
119         /* Disable Clock */
120         rval &= ~SUNXI_MMC_CLK_ENABLE;
121         writel(rval, &mmchost->reg->clkcr);
122         if (mmc_update_clk(mmc))
123                 return -1;
124
125         /* Change Divider Factor */
126         rval &= ~SUNXI_MMC_CLK_DIVIDER_MASK;
127         rval |= div;
128         writel(rval, &mmchost->reg->clkcr);
129         if (mmc_update_clk(mmc))
130                 return -1;
131         /* Re-enable Clock */
132         rval |= SUNXI_MMC_CLK_ENABLE;
133         writel(rval, &mmchost->reg->clkcr);
134
135         if (mmc_update_clk(mmc))
136                 return -1;
137
138         return 0;
139 }
140
141 static void mmc_set_ios(struct mmc *mmc)
142 {
143         struct sunxi_mmc_host *mmchost = mmc->priv;
144         unsigned int clkdiv = 0;
145
146         debug("set ios: bus_width: %x, clock: %d, mod_clk: %d\n",
147               mmc->bus_width, mmc->clock, mmchost->mod_clk);
148
149         /* Change clock first */
150         clkdiv = (mmchost->mod_clk + (mmc->clock >> 1)) / mmc->clock / 2;
151         if (mmc->clock) {
152                 if (mmc_config_clock(mmc, clkdiv)) {
153                         mmchost->fatal_err = 1;
154                         return;
155                 }
156         }
157
158         /* Change bus width */
159         if (mmc->bus_width == 8)
160                 writel(0x2, &mmchost->reg->width);
161         else if (mmc->bus_width == 4)
162                 writel(0x1, &mmchost->reg->width);
163         else
164                 writel(0x0, &mmchost->reg->width);
165 }
166
167 static int mmc_core_init(struct mmc *mmc)
168 {
169         struct sunxi_mmc_host *mmchost = mmc->priv;
170
171         /* Reset controller */
172         writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl);
173         udelay(1000);
174
175         return 0;
176 }
177
178 static int mmc_trans_data_by_cpu(struct mmc *mmc, struct mmc_data *data)
179 {
180         struct sunxi_mmc_host *mmchost = mmc->priv;
181         const int reading = !!(data->flags & MMC_DATA_READ);
182         const uint32_t status_bit = reading ? SUNXI_MMC_STATUS_FIFO_EMPTY :
183                                               SUNXI_MMC_STATUS_FIFO_FULL;
184         unsigned i;
185         unsigned byte_cnt = data->blocksize * data->blocks;
186         unsigned timeout_msecs = 2000;
187         unsigned *buff = (unsigned int *)(reading ? data->dest : data->src);
188
189         /* Always read / write data through the CPU */
190         setbits_le32(&mmchost->reg->gctrl, SUNXI_MMC_GCTRL_ACCESS_BY_AHB);
191
192         for (i = 0; i < (byte_cnt >> 2); i++) {
193                 while (readl(&mmchost->reg->status) & status_bit) {
194                         if (!timeout_msecs--)
195                                 return -1;
196                         udelay(1000);
197                 }
198
199                 if (reading)
200                         buff[i] = readl(&mmchost->reg->fifo);
201                 else
202                         writel(buff[i], &mmchost->reg->fifo);
203         }
204
205         return 0;
206 }
207
208 static int mmc_rint_wait(struct mmc *mmc, unsigned int timeout_msecs,
209                          unsigned int done_bit, const char *what)
210 {
211         struct sunxi_mmc_host *mmchost = mmc->priv;
212         unsigned int status;
213
214         do {
215                 status = readl(&mmchost->reg->rint);
216                 if (!timeout_msecs-- ||
217                     (status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT)) {
218                         debug("%s timeout %x\n", what,
219                               status & SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT);
220                         return TIMEOUT;
221                 }
222                 udelay(1000);
223         } while (!(status & done_bit));
224
225         return 0;
226 }
227
228 static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
229                         struct mmc_data *data)
230 {
231         struct sunxi_mmc_host *mmchost = mmc->priv;
232         unsigned int cmdval = SUNXI_MMC_CMD_START;
233         unsigned int timeout_msecs;
234         int error = 0;
235         unsigned int status = 0;
236         unsigned int bytecnt = 0;
237
238         if (mmchost->fatal_err)
239                 return -1;
240         if (cmd->resp_type & MMC_RSP_BUSY)
241                 debug("mmc cmd %d check rsp busy\n", cmd->cmdidx);
242         if (cmd->cmdidx == 12)
243                 return 0;
244
245         if (!cmd->cmdidx)
246                 cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ;
247         if (cmd->resp_type & MMC_RSP_PRESENT)
248                 cmdval |= SUNXI_MMC_CMD_RESP_EXPIRE;
249         if (cmd->resp_type & MMC_RSP_136)
250                 cmdval |= SUNXI_MMC_CMD_LONG_RESPONSE;
251         if (cmd->resp_type & MMC_RSP_CRC)
252                 cmdval |= SUNXI_MMC_CMD_CHK_RESPONSE_CRC;
253
254         if (data) {
255                 if ((u32) data->dest & 0x3) {
256                         error = -1;
257                         goto out;
258                 }
259
260                 cmdval |= SUNXI_MMC_CMD_DATA_EXPIRE|SUNXI_MMC_CMD_WAIT_PRE_OVER;
261                 if (data->flags & MMC_DATA_WRITE)
262                         cmdval |= SUNXI_MMC_CMD_WRITE;
263                 if (data->blocks > 1)
264                         cmdval |= SUNXI_MMC_CMD_AUTO_STOP;
265                 writel(data->blocksize, &mmchost->reg->blksz);
266                 writel(data->blocks * data->blocksize, &mmchost->reg->bytecnt);
267         }
268
269         debug("mmc %d, cmd %d(0x%08x), arg 0x%08x\n", mmchost->mmc_no,
270               cmd->cmdidx, cmdval | cmd->cmdidx, cmd->cmdarg);
271         writel(cmd->cmdarg, &mmchost->reg->arg);
272
273         if (!data)
274                 writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd);
275
276         /*
277          * transfer data and check status
278          * STATREG[2] : FIFO empty
279          * STATREG[3] : FIFO full
280          */
281         if (data) {
282                 int ret = 0;
283
284                 bytecnt = data->blocksize * data->blocks;
285                 debug("trans data %d bytes\n", bytecnt);
286                 writel(cmdval | cmd->cmdidx, &mmchost->reg->cmd);
287                 ret = mmc_trans_data_by_cpu(mmc, data);
288                 if (ret) {
289                         error = readl(&mmchost->reg->rint) & \
290                                 SUNXI_MMC_RINT_INTERRUPT_ERROR_BIT;
291                         error = TIMEOUT;
292                         goto out;
293                 }
294         }
295
296         error = mmc_rint_wait(mmc, 0xfffff, SUNXI_MMC_RINT_COMMAND_DONE, "cmd");
297         if (error)
298                 goto out;
299
300         if (data) {
301                 timeout_msecs = 120;
302                 debug("cacl timeout %x msec\n", timeout_msecs);
303                 error = mmc_rint_wait(mmc, timeout_msecs,
304                                       data->blocks > 1 ?
305                                       SUNXI_MMC_RINT_AUTO_COMMAND_DONE :
306                                       SUNXI_MMC_RINT_DATA_OVER,
307                                       "data");
308                 if (error)
309                         goto out;
310         }
311
312         if (cmd->resp_type & MMC_RSP_BUSY) {
313                 timeout_msecs = 2000;
314                 do {
315                         status = readl(&mmchost->reg->status);
316                         if (!timeout_msecs--) {
317                                 debug("busy timeout\n");
318                                 error = TIMEOUT;
319                                 goto out;
320                         }
321                         udelay(1000);
322                 } while (status & SUNXI_MMC_STATUS_CARD_DATA_BUSY);
323         }
324
325         if (cmd->resp_type & MMC_RSP_136) {
326                 cmd->response[0] = readl(&mmchost->reg->resp3);
327                 cmd->response[1] = readl(&mmchost->reg->resp2);
328                 cmd->response[2] = readl(&mmchost->reg->resp1);
329                 cmd->response[3] = readl(&mmchost->reg->resp0);
330                 debug("mmc resp 0x%08x 0x%08x 0x%08x 0x%08x\n",
331                       cmd->response[3], cmd->response[2],
332                       cmd->response[1], cmd->response[0]);
333         } else {
334                 cmd->response[0] = readl(&mmchost->reg->resp0);
335                 debug("mmc resp 0x%08x\n", cmd->response[0]);
336         }
337 out:
338         if (error < 0) {
339                 writel(SUNXI_MMC_GCTRL_RESET, &mmchost->reg->gctrl);
340                 mmc_update_clk(mmc);
341         }
342         writel(0xffffffff, &mmchost->reg->rint);
343         writel(readl(&mmchost->reg->gctrl) | SUNXI_MMC_GCTRL_FIFO_RESET,
344                &mmchost->reg->gctrl);
345
346         return error;
347 }
348
349 static const struct mmc_ops sunxi_mmc_ops = {
350         .send_cmd       = mmc_send_cmd,
351         .set_ios        = mmc_set_ios,
352         .init           = mmc_core_init,
353 };
354
355 int sunxi_mmc_init(int sdc_no)
356 {
357         struct mmc_config *cfg = &mmc_host[sdc_no].cfg;
358
359         memset(&mmc_host[sdc_no], 0, sizeof(struct sunxi_mmc_host));
360
361         cfg->name = "SUNXI SD/MMC";
362         cfg->ops  = &sunxi_mmc_ops;
363
364         cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
365         cfg->host_caps = MMC_MODE_4BIT;
366         cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
367 #if defined(CONFIG_SUN6I) || defined(CONFIG_SUN7I) || defined(CONFIG_SUN8I)
368         cfg->host_caps |= MMC_MODE_HC;
369 #endif
370         cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
371
372         cfg->f_min = 400000;
373         cfg->f_max = 52000000;
374
375         mmc_resource_init(sdc_no);
376         mmc_clk_io_on(sdc_no);
377
378         if (mmc_create(cfg, &mmc_host[sdc_no]) == NULL)
379                 return -1;
380
381         return 0;
382 }