blob: a2792ac4ecb76c4c7757ba4bc45e6b242a5b1619 [file] [log] [blame]
DrEaglead881742014-07-25 21:07:30 +02001/*
2 * Marvell MMC/SD/SDIO driver
3 *
Gerald Kermac5fb9f72014-12-13 21:35:31 +01004 * (C) Copyright 2012-2014
DrEaglead881742014-07-25 21:07:30 +02005 * Marvell Semiconductor <www.marvell.com>
6 * Written-by: Maen Suleiman, Gerald Kerma
7 *
8 * SPDX-License-Identifier: GPL-2.0+
9 */
10
11#include <common.h>
Jaehoon Chung7825d202016-07-19 16:33:36 +090012#include <errno.h>
DrEaglead881742014-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 Roesec2437842014-10-22 12:13:06 +020018#include <asm/arch/soc.h>
DrEaglead881742014-07-25 21:07:30 +020019#include <mvebu_mmc.h>
20
Mario Schuknecht6764f372014-08-25 14:12:26 +020021DECLARE_GLOBAL_DATA_PTR;
22
DrEaglead881742014-07-25 21:07:30 +020023#define DRIVER_NAME "MVEBU_MMC"
24
Mario Schuknecht6764f372014-08-25 14:12:26 +020025#define MVEBU_TARGET_DRAM 0
26
Gerald Kerma20d96912014-12-13 21:35:32 +010027#define TIMEOUT_DELAY 5*CONFIG_SYS_HZ /* wait 5 seconds */
28
DrEaglead881742014-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 Kerma20d96912014-12-13 21:35:32 +010069 ulong start;
DrEaglead881742014-07-25 21:07:30 +020070 ushort waittype = 0;
71 ushort resptype = 0;
72 ushort xfertype = 0;
73 ushort resp_indx = 0;
74
Gerald Kerma501791c2014-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);
DrEaglead881742014-07-25 21:07:30 +020077
DrEaglead881742014-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 Kerma20d96912014-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)));
DrEaglead881742014-07-25 21:07:30 +0200105 }
106
Gerald Kerma85a25fd2014-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);
DrEaglead881742014-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 Kerma85a25fd2014-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
DrEaglead881742014-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
DrEaglead881742014-07-25 21:07:30 +0200162 /* Sending command */
163 mvebu_mmc_write(SDIO_CMD, resptype);
164
Gerald Kerma20d96912014-12-13 21:35:32 +0100165 start = get_timer(0);
DrEaglead881742014-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 Kerma501791c2014-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 Chung7825d202016-07-19 16:33:36 +0900176 return -ETIMEDOUT;
Gerald Kerma501791c2014-12-13 21:35:33 +0100177 }
178 debug("%s: command READ error\n", DRIVER_NAME);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900179 return -ECOMM;
DrEaglead881742014-07-25 21:07:30 +0200180 }
181
Gerald Kerma20d96912014-12-13 21:35:32 +0100182 if ((get_timer(0) - start) > TIMEOUT_DELAY) {
183 debug("%s: command timed out\n", DRIVER_NAME);
Jaehoon Chung7825d202016-07-19 16:33:36 +0900184 return -ETIMEDOUT;
DrEaglead881742014-07-25 21:07:30 +0200185 }
186 }
Gerald Kerma20d96912014-12-13 21:35:32 +0100187
DrEaglead881742014-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 Kerma85a25fd2014-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;
DrEaglead881742014-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 Kerma85a25fd2014-12-13 21:35:35 +0100234 if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) &
235 (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT))
Jaehoon Chung7825d202016-07-19 16:33:36 +0900236 return -ETIMEDOUT;
Gerald Kerma85a25fd2014-12-13 21:35:35 +0100237
DrEaglead881742014-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 Kerma501791c2014-12-13 21:35:33 +0100276 debug("%s: clock (%d) div : %d\n", DRIVER_NAME, clock, m);
DrEaglead881742014-07-25 21:07:30 +0200277 }
DrEaglead881742014-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 Schuknecht6764f372014-08-25 14:12:26 +0200302 ctrl_reg |= SDIO_HOST_CTRL_TMOUT_EN;
DrEaglead881742014-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);
DrEaglead881742014-07-25 21:07:30 +0200317}
318
319static void mvebu_mmc_set_ios(struct mmc *mmc)
320{
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);
325}
326
Mario Schuknecht6764f372014-08-25 14:12:26 +0200327/*
328 * Set window register.
329 */
330static void mvebu_window_setup(void)
331{
332 int i;
333
334 for (i = 0; i < 4; i++) {
335 mvebu_mmc_write(WINDOW_CTRL(i), 0);
336 mvebu_mmc_write(WINDOW_BASE(i), 0);
337 }
338 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
339 u32 size, base, attrib;
340
341 /* Enable DRAM bank */
342 switch (i) {
343 case 0:
344 attrib = KWCPU_ATTR_DRAM_CS0;
345 break;
346 case 1:
347 attrib = KWCPU_ATTR_DRAM_CS1;
348 break;
349 case 2:
350 attrib = KWCPU_ATTR_DRAM_CS2;
351 break;
352 case 3:
353 attrib = KWCPU_ATTR_DRAM_CS3;
354 break;
355 default:
356 /* invalide bank, disable access */
357 attrib = 0;
358 break;
359 }
360
361 size = gd->bd->bi_dram[i].size;
362 base = gd->bd->bi_dram[i].start;
363 if (size && attrib) {
364 mvebu_mmc_write(WINDOW_CTRL(i),
365 MVCPU_WIN_CTRL_DATA(size,
366 MVEBU_TARGET_DRAM,
367 attrib,
368 MVCPU_WIN_ENABLE));
369 } else {
370 mvebu_mmc_write(WINDOW_CTRL(i), MVCPU_WIN_DISABLE);
371 }
372 mvebu_mmc_write(WINDOW_BASE(i), base);
373 }
374}
375
DrEaglead881742014-07-25 21:07:30 +0200376static int mvebu_mmc_initialize(struct mmc *mmc)
377{
Gerald Kerma501791c2014-12-13 21:35:33 +0100378 debug("%s: mvebu_mmc_initialize\n", DRIVER_NAME);
DrEaglead881742014-07-25 21:07:30 +0200379
380 /*
381 * Setting host parameters
382 * Initial Host Ctrl : Timeout : max , Normal Speed mode,
383 * 4-bit data mode, Big Endian, SD memory Card, Push_pull CMD Line
384 */
385 mvebu_mmc_write(SDIO_HOST_CTRL,
386 SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX) |
387 SDIO_HOST_CTRL_DATA_WIDTH_4_BITS |
388 SDIO_HOST_CTRL_BIG_ENDIAN |
389 SDIO_HOST_CTRL_PUSH_PULL_EN |
390 SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY);
391
392 mvebu_mmc_write(SDIO_CLK_CTRL, 0);
393
394 /* enable status */
395 mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK);
396 mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK);
397
398 /* disable interrupts */
399 mvebu_mmc_write(SDIO_NOR_INTR_EN, 0);
400 mvebu_mmc_write(SDIO_ERR_INTR_EN, 0);
401
Mario Schuknecht6764f372014-08-25 14:12:26 +0200402 mvebu_window_setup();
403
DrEaglead881742014-07-25 21:07:30 +0200404 /* SW reset */
405 mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW);
406
DrEaglead881742014-07-25 21:07:30 +0200407 return 0;
408}
409
410static const struct mmc_ops mvebu_mmc_ops = {
411 .send_cmd = mvebu_mmc_send_cmd,
412 .set_ios = mvebu_mmc_set_ios,
413 .init = mvebu_mmc_initialize,
414};
415
416static struct mmc_config mvebu_mmc_cfg = {
417 .name = DRIVER_NAME,
418 .ops = &mvebu_mmc_ops,
419 .f_min = MVEBU_MMC_BASE_FAST_CLOCK / MVEBU_MMC_BASE_DIV_MAX,
420 .f_max = MVEBU_MMC_CLOCKRATE_MAX,
421 .voltages = MMC_VDD_32_33 | MMC_VDD_33_34,
Rob Herring5fd3edd2015-03-23 17:56:59 -0500422 .host_caps = MMC_MODE_4BIT | MMC_MODE_HS |
Mario Schuknecht6764f372014-08-25 14:12:26 +0200423 MMC_MODE_HS_52MHz,
DrEaglead881742014-07-25 21:07:30 +0200424 .part_type = PART_TYPE_DOS,
425 .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
426};
427
428int mvebu_mmc_init(bd_t *bis)
429{
430 struct mmc *mmc;
431
432 mvebu_mmc_power_up();
433
434 mmc = mmc_create(&mvebu_mmc_cfg, bis);
435 if (mmc == NULL)
436 return -1;
437
438 return 0;
439}