blob: 03d5150b207ae8bef1e0b30c781397b09bbb9fd8 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
DrEagle3fe3b4f2014-07-25 21:07:30 +02002/*
3 * Marvell MMC/SD/SDIO driver
4 *
Gerald Kerma2591fbd2014-12-13 21:35:31 +01005 * (C) Copyright 2012-2014
DrEagle3fe3b4f2014-07-25 21:07:30 +02006 * Marvell Semiconductor <www.marvell.com>
7 * Written-by: Maen Suleiman, Gerald Kerma
DrEagle3fe3b4f2014-07-25 21:07:30 +02008 */
9
10#include <common.h>
Jaehoon Chung915ffa52016-07-19 16:33:36 +090011#include <errno.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060012#include <log.h>
DrEagle3fe3b4f2014-07-25 21:07:30 +020013#include <malloc.h>
14#include <part.h>
15#include <mmc.h>
16#include <asm/io.h>
17#include <asm/arch/cpu.h>
Stefan Roese3dc23f72014-10-22 12:13:06 +020018#include <asm/arch/soc.h>
DrEagle3fe3b4f2014-07-25 21:07:30 +020019#include <mvebu_mmc.h>
20
Mario Schuknechtbcd06982014-08-25 14:12:26 +020021DECLARE_GLOBAL_DATA_PTR;
22
DrEagle3fe3b4f2014-07-25 21:07:30 +020023#define DRIVER_NAME "MVEBU_MMC"
24
Mario Schuknechtbcd06982014-08-25 14:12:26 +020025#define MVEBU_TARGET_DRAM 0
26
Gerald Kerma28d27b72014-12-13 21:35:32 +010027#define TIMEOUT_DELAY 5*CONFIG_SYS_HZ /* wait 5 seconds */
28
DrEagle3fe3b4f2014-07-25 21:07:30 +020029static void mvebu_mmc_write(u32 offs, u32 val)
30{
31 writel(val, CONFIG_SYS_MMC_BASE + (offs));
32}
33
34static u32 mvebu_mmc_read(u32 offs)
35{
36 return readl(CONFIG_SYS_MMC_BASE + (offs));
37}
38
39static int mvebu_mmc_setup_data(struct mmc_data *data)
40{
41 u32 ctrl_reg;
42
43 debug("%s, data %s : blocks=%d blksz=%d\n", DRIVER_NAME,
44 (data->flags & MMC_DATA_READ) ? "read" : "write",
45 data->blocks, data->blocksize);
46
47 /* default to maximum timeout */
48 ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL);
49 ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX);
50 mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg);
51
52 if (data->flags & MMC_DATA_READ) {
53 mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->dest & 0xffff);
54 mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->dest >> 16);
55 } else {
56 mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->src & 0xffff);
57 mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->src >> 16);
58 }
59
60 mvebu_mmc_write(SDIO_BLK_COUNT, data->blocks);
61 mvebu_mmc_write(SDIO_BLK_SIZE, data->blocksize);
62
63 return 0;
64}
65
66static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
67 struct mmc_data *data)
68{
Gerald Kerma28d27b72014-12-13 21:35:32 +010069 ulong start;
DrEagle3fe3b4f2014-07-25 21:07:30 +020070 ushort waittype = 0;
71 ushort resptype = 0;
72 ushort xfertype = 0;
73 ushort resp_indx = 0;
74
Gerald Kermafc0f25f2014-12-13 21:35:33 +010075 debug("%s: cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n",
76 DRIVER_NAME, cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
DrEagle3fe3b4f2014-07-25 21:07:30 +020077
DrEagle3fe3b4f2014-07-25 21:07:30 +020078 debug("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME,
79 cmd->cmdidx, mvebu_mmc_read(SDIO_HW_STATE));
80
Gerald Kerma28d27b72014-12-13 21:35:32 +010081 /*
82 * Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE
83 * register is sometimes not set before a while when some
84 * "unusual" data block sizes are used (such as with the SWITCH
85 * command), even despite the fact that the XFER_DONE interrupt
86 * was raised. And if another data transfer starts before
87 * this bit comes to good sense (which eventually happens by
88 * itself) then the new transfer simply fails with a timeout.
89 */
90 if (!(mvebu_mmc_read(SDIO_HW_STATE) & CMD_FIFO_EMPTY)) {
91 ushort hw_state, count = 0;
92
93 start = get_timer(0);
94 do {
95 hw_state = mvebu_mmc_read(SDIO_HW_STATE);
96 if ((get_timer(0) - start) > TIMEOUT_DELAY) {
97 printf("%s : FIFO_EMPTY bit missing\n",
98 DRIVER_NAME);
99 break;
100 }
101 count++;
102 } while (!(hw_state & CMD_FIFO_EMPTY));
103 debug("%s *** wait for FIFO_EMPTY bit (hw=0x%04x, count=%d, jiffies=%ld)\n",
104 DRIVER_NAME, hw_state, count, (get_timer(0) - (start)));
DrEagle3fe3b4f2014-07-25 21:07:30 +0200105 }
106
Gerald Kerma02b27392014-12-13 21:35:35 +0100107 /* Clear status */
108 mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK);
109 mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
DrEagle3fe3b4f2014-07-25 21:07:30 +0200110
111 resptype = SDIO_CMD_INDEX(cmd->cmdidx);
112
113 /* Analyzing resptype/xfertype/waittype for the command */
114 if (cmd->resp_type & MMC_RSP_BUSY)
115 resptype |= SDIO_CMD_RSP_48BUSY;
116 else if (cmd->resp_type & MMC_RSP_136)
117 resptype |= SDIO_CMD_RSP_136;
118 else if (cmd->resp_type & MMC_RSP_PRESENT)
119 resptype |= SDIO_CMD_RSP_48;
120 else
121 resptype |= SDIO_CMD_RSP_NONE;
122
123 if (cmd->resp_type & MMC_RSP_CRC)
124 resptype |= SDIO_CMD_CHECK_CMDCRC;
125
126 if (cmd->resp_type & MMC_RSP_OPCODE)
127 resptype |= SDIO_CMD_INDX_CHECK;
128
129 if (cmd->resp_type & MMC_RSP_PRESENT) {
130 resptype |= SDIO_UNEXPECTED_RESP;
131 waittype |= SDIO_NOR_UNEXP_RSP;
132 }
133
134 if (data) {
Gerald Kerma02b27392014-12-13 21:35:35 +0100135 int err = mvebu_mmc_setup_data(data);
136
137 if (err) {
138 debug("%s: command DATA error :%x\n",
139 DRIVER_NAME, err);
140 return err;
141 }
142
DrEagle3fe3b4f2014-07-25 21:07:30 +0200143 resptype |= SDIO_CMD_DATA_PRESENT | SDIO_CMD_CHECK_DATACRC16;
144 xfertype |= SDIO_XFER_MODE_HW_WR_DATA_EN;
145 if (data->flags & MMC_DATA_READ) {
146 xfertype |= SDIO_XFER_MODE_TO_HOST;
147 waittype = SDIO_NOR_DMA_INI;
148 } else {
149 waittype |= SDIO_NOR_XFER_DONE;
150 }
151 } else {
152 waittype |= SDIO_NOR_CMD_DONE;
153 }
154
155 /* Setting cmd arguments */
156 mvebu_mmc_write(SDIO_ARG_LOW, cmd->cmdarg & 0xffff);
157 mvebu_mmc_write(SDIO_ARG_HI, cmd->cmdarg >> 16);
158
159 /* Setting Xfer mode */
160 mvebu_mmc_write(SDIO_XFER_MODE, xfertype);
161
DrEagle3fe3b4f2014-07-25 21:07:30 +0200162 /* Sending command */
163 mvebu_mmc_write(SDIO_CMD, resptype);
164
Gerald Kerma28d27b72014-12-13 21:35:32 +0100165 start = get_timer(0);
DrEagle3fe3b4f2014-07-25 21:07:30 +0200166
167 while (!((mvebu_mmc_read(SDIO_NOR_INTR_STATUS)) & waittype)) {
168 if (mvebu_mmc_read(SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) {
169 debug("%s: error! cmdidx : %d, err reg: %04x\n",
170 DRIVER_NAME, cmd->cmdidx,
171 mvebu_mmc_read(SDIO_ERR_INTR_STATUS));
172 if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) &
Gerald Kermafc0f25f2014-12-13 21:35:33 +0100173 (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) {
174 debug("%s: command READ timed out\n",
175 DRIVER_NAME);
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900176 return -ETIMEDOUT;
Gerald Kermafc0f25f2014-12-13 21:35:33 +0100177 }
178 debug("%s: command READ error\n", DRIVER_NAME);
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900179 return -ECOMM;
DrEagle3fe3b4f2014-07-25 21:07:30 +0200180 }
181
Gerald Kerma28d27b72014-12-13 21:35:32 +0100182 if ((get_timer(0) - start) > TIMEOUT_DELAY) {
183 debug("%s: command timed out\n", DRIVER_NAME);
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900184 return -ETIMEDOUT;
DrEagle3fe3b4f2014-07-25 21:07:30 +0200185 }
186 }
Gerald Kerma28d27b72014-12-13 21:35:32 +0100187
DrEagle3fe3b4f2014-07-25 21:07:30 +0200188 /* Handling response */
189 if (cmd->resp_type & MMC_RSP_136) {
190 uint response[8];
191
192 for (resp_indx = 0; resp_indx < 8; resp_indx++)
193 response[resp_indx]
194 = mvebu_mmc_read(SDIO_RSP(resp_indx));
195
196 cmd->response[0] = ((response[0] & 0x03ff) << 22) |
197 ((response[1] & 0xffff) << 6) |
198 ((response[2] & 0xfc00) >> 10);
199 cmd->response[1] = ((response[2] & 0x03ff) << 22) |
200 ((response[3] & 0xffff) << 6) |
201 ((response[4] & 0xfc00) >> 10);
202 cmd->response[2] = ((response[4] & 0x03ff) << 22) |
203 ((response[5] & 0xffff) << 6) |
204 ((response[6] & 0xfc00) >> 10);
205 cmd->response[3] = ((response[6] & 0x03ff) << 22) |
206 ((response[7] & 0x3fff) << 8);
207 } else if (cmd->resp_type & MMC_RSP_PRESENT) {
208 uint response[3];
209
210 for (resp_indx = 0; resp_indx < 3; resp_indx++)
211 response[resp_indx]
212 = mvebu_mmc_read(SDIO_RSP(resp_indx));
213
214 cmd->response[0] = ((response[2] & 0x003f) << (8 - 8)) |
215 ((response[1] & 0xffff) << (14 - 8)) |
216 ((response[0] & 0x03ff) << (30 - 8));
217 cmd->response[1] = ((response[0] & 0xfc00) >> 10);
218 cmd->response[2] = 0;
219 cmd->response[3] = 0;
Gerald Kerma02b27392014-12-13 21:35:35 +0100220 } else {
221 cmd->response[0] = 0;
222 cmd->response[1] = 0;
223 cmd->response[2] = 0;
224 cmd->response[3] = 0;
DrEagle3fe3b4f2014-07-25 21:07:30 +0200225 }
226
227 debug("%s: resp[0x%x] ", DRIVER_NAME, cmd->resp_type);
228 debug("[0x%x] ", cmd->response[0]);
229 debug("[0x%x] ", cmd->response[1]);
230 debug("[0x%x] ", cmd->response[2]);
231 debug("[0x%x] ", cmd->response[3]);
232 debug("\n");
233
Gerald Kerma02b27392014-12-13 21:35:35 +0100234 if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) &
235 (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT))
Jaehoon Chung915ffa52016-07-19 16:33:36 +0900236 return -ETIMEDOUT;
Gerald Kerma02b27392014-12-13 21:35:35 +0100237
DrEagle3fe3b4f2014-07-25 21:07:30 +0200238 return 0;
239}
240
241static void mvebu_mmc_power_up(void)
242{
243 debug("%s: power up\n", DRIVER_NAME);
244
245 /* disable interrupts */
246 mvebu_mmc_write(SDIO_NOR_INTR_EN, 0);
247 mvebu_mmc_write(SDIO_ERR_INTR_EN, 0);
248
249 /* SW reset */
250 mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW);
251
252 mvebu_mmc_write(SDIO_XFER_MODE, 0);
253
254 /* enable status */
255 mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK);
256 mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK);
257
258 /* enable interrupts status */
259 mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK);
260 mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
261}
262
263static void mvebu_mmc_set_clk(unsigned int clock)
264{
265 unsigned int m;
266
267 if (clock == 0) {
268 debug("%s: clock off\n", DRIVER_NAME);
269 mvebu_mmc_write(SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK);
270 mvebu_mmc_write(SDIO_CLK_DIV, MVEBU_MMC_BASE_DIV_MAX);
271 } else {
272 m = MVEBU_MMC_BASE_FAST_CLOCK/(2*clock) - 1;
273 if (m > MVEBU_MMC_BASE_DIV_MAX)
274 m = MVEBU_MMC_BASE_DIV_MAX;
275 mvebu_mmc_write(SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX);
Gerald Kermafc0f25f2014-12-13 21:35:33 +0100276 debug("%s: clock (%d) div : %d\n", DRIVER_NAME, clock, m);
DrEagle3fe3b4f2014-07-25 21:07:30 +0200277 }
DrEagle3fe3b4f2014-07-25 21:07:30 +0200278}
279
280static void mvebu_mmc_set_bus(unsigned int bus)
281{
282 u32 ctrl_reg = 0;
283
284 ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL);
285 ctrl_reg &= ~SDIO_HOST_CTRL_DATA_WIDTH_4_BITS;
286
287 switch (bus) {
288 case 4:
289 ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_4_BITS;
290 break;
291 case 1:
292 default:
293 ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_1_BIT;
294 }
295
296 /* default transfer mode */
297 ctrl_reg |= SDIO_HOST_CTRL_BIG_ENDIAN;
298 ctrl_reg &= ~SDIO_HOST_CTRL_LSB_FIRST;
299
300 /* default to maximum timeout */
301 ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX);
Mario Schuknechtbcd06982014-08-25 14:12:26 +0200302 ctrl_reg |= SDIO_HOST_CTRL_TMOUT_EN;
DrEagle3fe3b4f2014-07-25 21:07:30 +0200303
304 ctrl_reg |= SDIO_HOST_CTRL_PUSH_PULL_EN;
305
306 ctrl_reg |= SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY;
307
308 debug("%s: ctrl 0x%04x: %s %s %s\n", DRIVER_NAME, ctrl_reg,
309 (ctrl_reg & SDIO_HOST_CTRL_PUSH_PULL_EN) ?
310 "push-pull" : "open-drain",
311 (ctrl_reg & SDIO_HOST_CTRL_DATA_WIDTH_4_BITS) ?
312 "4bit-width" : "1bit-width",
313 (ctrl_reg & SDIO_HOST_CTRL_HI_SPEED_EN) ?
314 "high-speed" : "");
315
316 mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg);
DrEagle3fe3b4f2014-07-25 21:07:30 +0200317}
318
Jaehoon Chung07b0b9c2016-12-30 15:30:16 +0900319static int mvebu_mmc_set_ios(struct mmc *mmc)
DrEagle3fe3b4f2014-07-25 21:07:30 +0200320{
321 debug("%s: bus[%d] clock[%d]\n", DRIVER_NAME,
322 mmc->bus_width, mmc->clock);
323 mvebu_mmc_set_bus(mmc->bus_width);
324 mvebu_mmc_set_clk(mmc->clock);
Jaehoon Chung07b0b9c2016-12-30 15:30:16 +0900325
326 return 0;
DrEagle3fe3b4f2014-07-25 21:07:30 +0200327}
328
Mario Schuknechtbcd06982014-08-25 14:12:26 +0200329/*
330 * Set window register.
331 */
332static void mvebu_window_setup(void)
333{
334 int i;
335
336 for (i = 0; i < 4; i++) {
337 mvebu_mmc_write(WINDOW_CTRL(i), 0);
338 mvebu_mmc_write(WINDOW_BASE(i), 0);
339 }
340 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
341 u32 size, base, attrib;
342
343 /* Enable DRAM bank */
344 switch (i) {
345 case 0:
346 attrib = KWCPU_ATTR_DRAM_CS0;
347 break;
348 case 1:
349 attrib = KWCPU_ATTR_DRAM_CS1;
350 break;
351 case 2:
352 attrib = KWCPU_ATTR_DRAM_CS2;
353 break;
354 case 3:
355 attrib = KWCPU_ATTR_DRAM_CS3;
356 break;
357 default:
358 /* invalide bank, disable access */
359 attrib = 0;
360 break;
361 }
362
363 size = gd->bd->bi_dram[i].size;
364 base = gd->bd->bi_dram[i].start;
365 if (size && attrib) {
366 mvebu_mmc_write(WINDOW_CTRL(i),
367 MVCPU_WIN_CTRL_DATA(size,
368 MVEBU_TARGET_DRAM,
369 attrib,
370 MVCPU_WIN_ENABLE));
371 } else {
372 mvebu_mmc_write(WINDOW_CTRL(i), MVCPU_WIN_DISABLE);
373 }
374 mvebu_mmc_write(WINDOW_BASE(i), base);
375 }
376}
377
DrEagle3fe3b4f2014-07-25 21:07:30 +0200378static int mvebu_mmc_initialize(struct mmc *mmc)
379{
Gerald Kermafc0f25f2014-12-13 21:35:33 +0100380 debug("%s: mvebu_mmc_initialize\n", DRIVER_NAME);
DrEagle3fe3b4f2014-07-25 21:07:30 +0200381
382 /*
383 * Setting host parameters
384 * Initial Host Ctrl : Timeout : max , Normal Speed mode,
385 * 4-bit data mode, Big Endian, SD memory Card, Push_pull CMD Line
386 */
387 mvebu_mmc_write(SDIO_HOST_CTRL,
388 SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX) |
389 SDIO_HOST_CTRL_DATA_WIDTH_4_BITS |
390 SDIO_HOST_CTRL_BIG_ENDIAN |
391 SDIO_HOST_CTRL_PUSH_PULL_EN |
392 SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY);
393
394 mvebu_mmc_write(SDIO_CLK_CTRL, 0);
395
396 /* enable status */
397 mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK);
398 mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK);
399
400 /* disable interrupts */
401 mvebu_mmc_write(SDIO_NOR_INTR_EN, 0);
402 mvebu_mmc_write(SDIO_ERR_INTR_EN, 0);
403
Mario Schuknechtbcd06982014-08-25 14:12:26 +0200404 mvebu_window_setup();
405
DrEagle3fe3b4f2014-07-25 21:07:30 +0200406 /* SW reset */
407 mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW);
408
DrEagle3fe3b4f2014-07-25 21:07:30 +0200409 return 0;
410}
411
412static const struct mmc_ops mvebu_mmc_ops = {
413 .send_cmd = mvebu_mmc_send_cmd,
414 .set_ios = mvebu_mmc_set_ios,
415 .init = mvebu_mmc_initialize,
416};
417
418static struct mmc_config mvebu_mmc_cfg = {
419 .name = DRIVER_NAME,
420 .ops = &mvebu_mmc_ops,
421 .f_min = MVEBU_MMC_BASE_FAST_CLOCK / MVEBU_MMC_BASE_DIV_MAX,
422 .f_max = MVEBU_MMC_CLOCKRATE_MAX,
423 .voltages = MMC_VDD_32_33 | MMC_VDD_33_34,
Rob Herring5a203972015-03-23 17:56:59 -0500424 .host_caps = MMC_MODE_4BIT | MMC_MODE_HS |
Mario Schuknechtbcd06982014-08-25 14:12:26 +0200425 MMC_MODE_HS_52MHz,
DrEagle3fe3b4f2014-07-25 21:07:30 +0200426 .part_type = PART_TYPE_DOS,
427 .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
428};
429
Masahiro Yamadab75d8dc2020-06-26 15:13:33 +0900430int mvebu_mmc_init(struct bd_info *bis)
DrEagle3fe3b4f2014-07-25 21:07:30 +0200431{
432 struct mmc *mmc;
433
434 mvebu_mmc_power_up();
435
436 mmc = mmc_create(&mvebu_mmc_cfg, bis);
437 if (mmc == NULL)
438 return -1;
439
440 return 0;
441}