]>
Commit | Line | Data |
---|---|---|
3fe3b4fb D |
1 | /* |
2 | * Marvell MMC/SD/SDIO driver | |
3 | * | |
2591fbdb | 4 | * (C) Copyright 2012-2014 |
3fe3b4fb D |
5 | * 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> | |
12 | #include <malloc.h> | |
13 | #include <part.h> | |
14 | #include <mmc.h> | |
15 | #include <asm/io.h> | |
16 | #include <asm/arch/cpu.h> | |
3dc23f78 | 17 | #include <asm/arch/soc.h> |
3fe3b4fb D |
18 | #include <mvebu_mmc.h> |
19 | ||
bcd06989 MS |
20 | DECLARE_GLOBAL_DATA_PTR; |
21 | ||
3fe3b4fb D |
22 | #define DRIVER_NAME "MVEBU_MMC" |
23 | ||
bcd06989 MS |
24 | #define MVEBU_TARGET_DRAM 0 |
25 | ||
28d27b79 GK |
26 | #define TIMEOUT_DELAY 5*CONFIG_SYS_HZ /* wait 5 seconds */ |
27 | ||
3fe3b4fb D |
28 | static void mvebu_mmc_write(u32 offs, u32 val) |
29 | { | |
30 | writel(val, CONFIG_SYS_MMC_BASE + (offs)); | |
31 | } | |
32 | ||
33 | static u32 mvebu_mmc_read(u32 offs) | |
34 | { | |
35 | return readl(CONFIG_SYS_MMC_BASE + (offs)); | |
36 | } | |
37 | ||
38 | static int mvebu_mmc_setup_data(struct mmc_data *data) | |
39 | { | |
40 | u32 ctrl_reg; | |
41 | ||
42 | debug("%s, data %s : blocks=%d blksz=%d\n", DRIVER_NAME, | |
43 | (data->flags & MMC_DATA_READ) ? "read" : "write", | |
44 | data->blocks, data->blocksize); | |
45 | ||
46 | /* default to maximum timeout */ | |
47 | ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL); | |
48 | ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX); | |
49 | mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg); | |
50 | ||
51 | if (data->flags & MMC_DATA_READ) { | |
52 | mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->dest & 0xffff); | |
53 | mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->dest >> 16); | |
54 | } else { | |
55 | mvebu_mmc_write(SDIO_SYS_ADDR_LOW, (u32)data->src & 0xffff); | |
56 | mvebu_mmc_write(SDIO_SYS_ADDR_HI, (u32)data->src >> 16); | |
57 | } | |
58 | ||
59 | mvebu_mmc_write(SDIO_BLK_COUNT, data->blocks); | |
60 | mvebu_mmc_write(SDIO_BLK_SIZE, data->blocksize); | |
61 | ||
62 | return 0; | |
63 | } | |
64 | ||
65 | static int mvebu_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, | |
66 | struct mmc_data *data) | |
67 | { | |
28d27b79 | 68 | ulong start; |
3fe3b4fb D |
69 | ushort waittype = 0; |
70 | ushort resptype = 0; | |
71 | ushort xfertype = 0; | |
72 | ushort resp_indx = 0; | |
73 | ||
74 | debug("cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n", | |
75 | cmd->cmdidx, cmd->resp_type, cmd->cmdarg); | |
76 | ||
3fe3b4fb D |
77 | debug("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME, |
78 | cmd->cmdidx, mvebu_mmc_read(SDIO_HW_STATE)); | |
79 | ||
28d27b79 GK |
80 | /* |
81 | * Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE | |
82 | * register is sometimes not set before a while when some | |
83 | * "unusual" data block sizes are used (such as with the SWITCH | |
84 | * command), even despite the fact that the XFER_DONE interrupt | |
85 | * was raised. And if another data transfer starts before | |
86 | * this bit comes to good sense (which eventually happens by | |
87 | * itself) then the new transfer simply fails with a timeout. | |
88 | */ | |
89 | if (!(mvebu_mmc_read(SDIO_HW_STATE) & CMD_FIFO_EMPTY)) { | |
90 | ushort hw_state, count = 0; | |
91 | ||
92 | start = get_timer(0); | |
93 | do { | |
94 | hw_state = mvebu_mmc_read(SDIO_HW_STATE); | |
95 | if ((get_timer(0) - start) > TIMEOUT_DELAY) { | |
96 | printf("%s : FIFO_EMPTY bit missing\n", | |
97 | DRIVER_NAME); | |
98 | break; | |
99 | } | |
100 | count++; | |
101 | } while (!(hw_state & CMD_FIFO_EMPTY)); | |
102 | debug("%s *** wait for FIFO_EMPTY bit (hw=0x%04x, count=%d, jiffies=%ld)\n", | |
103 | DRIVER_NAME, hw_state, count, (get_timer(0) - (start))); | |
3fe3b4fb D |
104 | } |
105 | ||
106 | /* Set up for a data transfer if we have one */ | |
107 | if (data) { | |
108 | int err = mvebu_mmc_setup_data(data); | |
109 | ||
110 | if (err) | |
111 | return err; | |
112 | } | |
113 | ||
114 | resptype = SDIO_CMD_INDEX(cmd->cmdidx); | |
115 | ||
116 | /* Analyzing resptype/xfertype/waittype for the command */ | |
117 | if (cmd->resp_type & MMC_RSP_BUSY) | |
118 | resptype |= SDIO_CMD_RSP_48BUSY; | |
119 | else if (cmd->resp_type & MMC_RSP_136) | |
120 | resptype |= SDIO_CMD_RSP_136; | |
121 | else if (cmd->resp_type & MMC_RSP_PRESENT) | |
122 | resptype |= SDIO_CMD_RSP_48; | |
123 | else | |
124 | resptype |= SDIO_CMD_RSP_NONE; | |
125 | ||
126 | if (cmd->resp_type & MMC_RSP_CRC) | |
127 | resptype |= SDIO_CMD_CHECK_CMDCRC; | |
128 | ||
129 | if (cmd->resp_type & MMC_RSP_OPCODE) | |
130 | resptype |= SDIO_CMD_INDX_CHECK; | |
131 | ||
132 | if (cmd->resp_type & MMC_RSP_PRESENT) { | |
133 | resptype |= SDIO_UNEXPECTED_RESP; | |
134 | waittype |= SDIO_NOR_UNEXP_RSP; | |
135 | } | |
136 | ||
137 | if (data) { | |
138 | resptype |= SDIO_CMD_DATA_PRESENT | SDIO_CMD_CHECK_DATACRC16; | |
139 | xfertype |= SDIO_XFER_MODE_HW_WR_DATA_EN; | |
140 | if (data->flags & MMC_DATA_READ) { | |
141 | xfertype |= SDIO_XFER_MODE_TO_HOST; | |
142 | waittype = SDIO_NOR_DMA_INI; | |
143 | } else { | |
144 | waittype |= SDIO_NOR_XFER_DONE; | |
145 | } | |
146 | } else { | |
147 | waittype |= SDIO_NOR_CMD_DONE; | |
148 | } | |
149 | ||
150 | /* Setting cmd arguments */ | |
151 | mvebu_mmc_write(SDIO_ARG_LOW, cmd->cmdarg & 0xffff); | |
152 | mvebu_mmc_write(SDIO_ARG_HI, cmd->cmdarg >> 16); | |
153 | ||
154 | /* Setting Xfer mode */ | |
155 | mvebu_mmc_write(SDIO_XFER_MODE, xfertype); | |
156 | ||
157 | mvebu_mmc_write(SDIO_NOR_INTR_STATUS, ~SDIO_NOR_CARD_INT); | |
158 | mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); | |
159 | ||
160 | /* Sending command */ | |
161 | mvebu_mmc_write(SDIO_CMD, resptype); | |
162 | ||
163 | mvebu_mmc_write(SDIO_NOR_INTR_EN, SDIO_POLL_MASK); | |
164 | mvebu_mmc_write(SDIO_ERR_INTR_EN, SDIO_POLL_MASK); | |
165 | ||
28d27b79 | 166 | start = get_timer(0); |
3fe3b4fb D |
167 | |
168 | while (!((mvebu_mmc_read(SDIO_NOR_INTR_STATUS)) & waittype)) { | |
169 | if (mvebu_mmc_read(SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) { | |
170 | debug("%s: error! cmdidx : %d, err reg: %04x\n", | |
171 | DRIVER_NAME, cmd->cmdidx, | |
172 | mvebu_mmc_read(SDIO_ERR_INTR_STATUS)); | |
173 | if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) & | |
174 | (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) | |
175 | return TIMEOUT; | |
176 | return COMM_ERR; | |
177 | } | |
178 | ||
28d27b79 GK |
179 | if ((get_timer(0) - start) > TIMEOUT_DELAY) { |
180 | debug("%s: command timed out\n", DRIVER_NAME); | |
3fe3b4fb D |
181 | return TIMEOUT; |
182 | } | |
183 | } | |
28d27b79 | 184 | |
bcd06989 MS |
185 | if (mvebu_mmc_read(SDIO_ERR_INTR_STATUS) & |
186 | (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) | |
187 | return TIMEOUT; | |
3fe3b4fb D |
188 | |
189 | /* Handling response */ | |
190 | if (cmd->resp_type & MMC_RSP_136) { | |
191 | uint response[8]; | |
192 | ||
193 | for (resp_indx = 0; resp_indx < 8; resp_indx++) | |
194 | response[resp_indx] | |
195 | = mvebu_mmc_read(SDIO_RSP(resp_indx)); | |
196 | ||
197 | cmd->response[0] = ((response[0] & 0x03ff) << 22) | | |
198 | ((response[1] & 0xffff) << 6) | | |
199 | ((response[2] & 0xfc00) >> 10); | |
200 | cmd->response[1] = ((response[2] & 0x03ff) << 22) | | |
201 | ((response[3] & 0xffff) << 6) | | |
202 | ((response[4] & 0xfc00) >> 10); | |
203 | cmd->response[2] = ((response[4] & 0x03ff) << 22) | | |
204 | ((response[5] & 0xffff) << 6) | | |
205 | ((response[6] & 0xfc00) >> 10); | |
206 | cmd->response[3] = ((response[6] & 0x03ff) << 22) | | |
207 | ((response[7] & 0x3fff) << 8); | |
208 | } else if (cmd->resp_type & MMC_RSP_PRESENT) { | |
209 | uint response[3]; | |
210 | ||
211 | for (resp_indx = 0; resp_indx < 3; resp_indx++) | |
212 | response[resp_indx] | |
213 | = mvebu_mmc_read(SDIO_RSP(resp_indx)); | |
214 | ||
215 | cmd->response[0] = ((response[2] & 0x003f) << (8 - 8)) | | |
216 | ((response[1] & 0xffff) << (14 - 8)) | | |
217 | ((response[0] & 0x03ff) << (30 - 8)); | |
218 | cmd->response[1] = ((response[0] & 0xfc00) >> 10); | |
219 | cmd->response[2] = 0; | |
220 | cmd->response[3] = 0; | |
221 | } | |
222 | ||
223 | debug("%s: resp[0x%x] ", DRIVER_NAME, cmd->resp_type); | |
224 | debug("[0x%x] ", cmd->response[0]); | |
225 | debug("[0x%x] ", cmd->response[1]); | |
226 | debug("[0x%x] ", cmd->response[2]); | |
227 | debug("[0x%x] ", cmd->response[3]); | |
228 | debug("\n"); | |
229 | ||
230 | return 0; | |
231 | } | |
232 | ||
233 | static void mvebu_mmc_power_up(void) | |
234 | { | |
235 | debug("%s: power up\n", DRIVER_NAME); | |
236 | ||
237 | /* disable interrupts */ | |
238 | mvebu_mmc_write(SDIO_NOR_INTR_EN, 0); | |
239 | mvebu_mmc_write(SDIO_ERR_INTR_EN, 0); | |
240 | ||
241 | /* SW reset */ | |
242 | mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW); | |
243 | ||
244 | mvebu_mmc_write(SDIO_XFER_MODE, 0); | |
245 | ||
246 | /* enable status */ | |
247 | mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK); | |
248 | mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK); | |
249 | ||
250 | /* enable interrupts status */ | |
251 | mvebu_mmc_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK); | |
252 | mvebu_mmc_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK); | |
253 | } | |
254 | ||
255 | static void mvebu_mmc_set_clk(unsigned int clock) | |
256 | { | |
257 | unsigned int m; | |
258 | ||
259 | if (clock == 0) { | |
260 | debug("%s: clock off\n", DRIVER_NAME); | |
261 | mvebu_mmc_write(SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK); | |
262 | mvebu_mmc_write(SDIO_CLK_DIV, MVEBU_MMC_BASE_DIV_MAX); | |
263 | } else { | |
264 | m = MVEBU_MMC_BASE_FAST_CLOCK/(2*clock) - 1; | |
265 | if (m > MVEBU_MMC_BASE_DIV_MAX) | |
266 | m = MVEBU_MMC_BASE_DIV_MAX; | |
267 | mvebu_mmc_write(SDIO_CLK_DIV, m & MVEBU_MMC_BASE_DIV_MAX); | |
268 | } | |
269 | ||
270 | udelay(10*1000); | |
271 | } | |
272 | ||
273 | static void mvebu_mmc_set_bus(unsigned int bus) | |
274 | { | |
275 | u32 ctrl_reg = 0; | |
276 | ||
277 | ctrl_reg = mvebu_mmc_read(SDIO_HOST_CTRL); | |
278 | ctrl_reg &= ~SDIO_HOST_CTRL_DATA_WIDTH_4_BITS; | |
279 | ||
280 | switch (bus) { | |
281 | case 4: | |
282 | ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_4_BITS; | |
283 | break; | |
284 | case 1: | |
285 | default: | |
286 | ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_1_BIT; | |
287 | } | |
288 | ||
289 | /* default transfer mode */ | |
290 | ctrl_reg |= SDIO_HOST_CTRL_BIG_ENDIAN; | |
291 | ctrl_reg &= ~SDIO_HOST_CTRL_LSB_FIRST; | |
292 | ||
293 | /* default to maximum timeout */ | |
294 | ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX); | |
bcd06989 | 295 | ctrl_reg |= SDIO_HOST_CTRL_TMOUT_EN; |
3fe3b4fb D |
296 | |
297 | ctrl_reg |= SDIO_HOST_CTRL_PUSH_PULL_EN; | |
298 | ||
299 | ctrl_reg |= SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY; | |
300 | ||
301 | debug("%s: ctrl 0x%04x: %s %s %s\n", DRIVER_NAME, ctrl_reg, | |
302 | (ctrl_reg & SDIO_HOST_CTRL_PUSH_PULL_EN) ? | |
303 | "push-pull" : "open-drain", | |
304 | (ctrl_reg & SDIO_HOST_CTRL_DATA_WIDTH_4_BITS) ? | |
305 | "4bit-width" : "1bit-width", | |
306 | (ctrl_reg & SDIO_HOST_CTRL_HI_SPEED_EN) ? | |
307 | "high-speed" : ""); | |
308 | ||
309 | mvebu_mmc_write(SDIO_HOST_CTRL, ctrl_reg); | |
310 | udelay(10*1000); | |
311 | } | |
312 | ||
313 | static void mvebu_mmc_set_ios(struct mmc *mmc) | |
314 | { | |
315 | debug("%s: bus[%d] clock[%d]\n", DRIVER_NAME, | |
316 | mmc->bus_width, mmc->clock); | |
317 | mvebu_mmc_set_bus(mmc->bus_width); | |
318 | mvebu_mmc_set_clk(mmc->clock); | |
319 | } | |
320 | ||
bcd06989 MS |
321 | /* |
322 | * Set window register. | |
323 | */ | |
324 | static void mvebu_window_setup(void) | |
325 | { | |
326 | int i; | |
327 | ||
328 | for (i = 0; i < 4; i++) { | |
329 | mvebu_mmc_write(WINDOW_CTRL(i), 0); | |
330 | mvebu_mmc_write(WINDOW_BASE(i), 0); | |
331 | } | |
332 | for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { | |
333 | u32 size, base, attrib; | |
334 | ||
335 | /* Enable DRAM bank */ | |
336 | switch (i) { | |
337 | case 0: | |
338 | attrib = KWCPU_ATTR_DRAM_CS0; | |
339 | break; | |
340 | case 1: | |
341 | attrib = KWCPU_ATTR_DRAM_CS1; | |
342 | break; | |
343 | case 2: | |
344 | attrib = KWCPU_ATTR_DRAM_CS2; | |
345 | break; | |
346 | case 3: | |
347 | attrib = KWCPU_ATTR_DRAM_CS3; | |
348 | break; | |
349 | default: | |
350 | /* invalide bank, disable access */ | |
351 | attrib = 0; | |
352 | break; | |
353 | } | |
354 | ||
355 | size = gd->bd->bi_dram[i].size; | |
356 | base = gd->bd->bi_dram[i].start; | |
357 | if (size && attrib) { | |
358 | mvebu_mmc_write(WINDOW_CTRL(i), | |
359 | MVCPU_WIN_CTRL_DATA(size, | |
360 | MVEBU_TARGET_DRAM, | |
361 | attrib, | |
362 | MVCPU_WIN_ENABLE)); | |
363 | } else { | |
364 | mvebu_mmc_write(WINDOW_CTRL(i), MVCPU_WIN_DISABLE); | |
365 | } | |
366 | mvebu_mmc_write(WINDOW_BASE(i), base); | |
367 | } | |
368 | } | |
369 | ||
3fe3b4fb D |
370 | static int mvebu_mmc_initialize(struct mmc *mmc) |
371 | { | |
372 | debug("%s: mvebu_mmc_initialize", DRIVER_NAME); | |
373 | ||
374 | /* | |
375 | * Setting host parameters | |
376 | * Initial Host Ctrl : Timeout : max , Normal Speed mode, | |
377 | * 4-bit data mode, Big Endian, SD memory Card, Push_pull CMD Line | |
378 | */ | |
379 | mvebu_mmc_write(SDIO_HOST_CTRL, | |
380 | SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX) | | |
381 | SDIO_HOST_CTRL_DATA_WIDTH_4_BITS | | |
382 | SDIO_HOST_CTRL_BIG_ENDIAN | | |
383 | SDIO_HOST_CTRL_PUSH_PULL_EN | | |
384 | SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY); | |
385 | ||
386 | mvebu_mmc_write(SDIO_CLK_CTRL, 0); | |
387 | ||
388 | /* enable status */ | |
389 | mvebu_mmc_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK); | |
390 | mvebu_mmc_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK); | |
391 | ||
392 | /* disable interrupts */ | |
393 | mvebu_mmc_write(SDIO_NOR_INTR_EN, 0); | |
394 | mvebu_mmc_write(SDIO_ERR_INTR_EN, 0); | |
395 | ||
bcd06989 MS |
396 | mvebu_window_setup(); |
397 | ||
3fe3b4fb D |
398 | /* SW reset */ |
399 | mvebu_mmc_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW); | |
400 | ||
401 | udelay(10*1000); | |
402 | ||
403 | return 0; | |
404 | } | |
405 | ||
406 | static const struct mmc_ops mvebu_mmc_ops = { | |
407 | .send_cmd = mvebu_mmc_send_cmd, | |
408 | .set_ios = mvebu_mmc_set_ios, | |
409 | .init = mvebu_mmc_initialize, | |
410 | }; | |
411 | ||
412 | static struct mmc_config mvebu_mmc_cfg = { | |
413 | .name = DRIVER_NAME, | |
414 | .ops = &mvebu_mmc_ops, | |
415 | .f_min = MVEBU_MMC_BASE_FAST_CLOCK / MVEBU_MMC_BASE_DIV_MAX, | |
416 | .f_max = MVEBU_MMC_CLOCKRATE_MAX, | |
417 | .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, | |
bcd06989 MS |
418 | .host_caps = MMC_MODE_4BIT | MMC_MODE_HS | MMC_MODE_HC | |
419 | MMC_MODE_HS_52MHz, | |
3fe3b4fb D |
420 | .part_type = PART_TYPE_DOS, |
421 | .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, | |
422 | }; | |
423 | ||
424 | int mvebu_mmc_init(bd_t *bis) | |
425 | { | |
426 | struct mmc *mmc; | |
427 | ||
428 | mvebu_mmc_power_up(); | |
429 | ||
430 | mmc = mmc_create(&mvebu_mmc_cfg, bis); | |
431 | if (mmc == NULL) | |
432 | return -1; | |
433 | ||
434 | return 0; | |
435 | } |