blob: 156c2b4eb5ae7c126a0e81f3b471b7a39a7f8009 [file] [log] [blame]
Haojian Zhuang06249dc2016-03-18 22:14:16 +08001/*
2 * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
3 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Haojian Zhuang06249dc2016-03-18 22:14:16 +08005 */
6
7#include <arch.h>
8#include <arch_helpers.h>
9#include <assert.h>
10#include <debug.h>
11#include <delay_timer.h>
12#include <dw_mmc.h>
13#include <emmc.h>
14#include <errno.h>
15#include <mmio.h>
16#include <string.h>
17
18#define DWMMC_CTRL (0x00)
19#define CTRL_IDMAC_EN (1 << 25)
20#define CTRL_DMA_EN (1 << 5)
21#define CTRL_INT_EN (1 << 4)
22#define CTRL_DMA_RESET (1 << 2)
23#define CTRL_FIFO_RESET (1 << 1)
24#define CTRL_RESET (1 << 0)
25#define CTRL_RESET_ALL (CTRL_DMA_RESET | CTRL_FIFO_RESET | \
26 CTRL_RESET)
27
28#define DWMMC_PWREN (0x04)
29#define DWMMC_CLKDIV (0x08)
30#define DWMMC_CLKSRC (0x0c)
31#define DWMMC_CLKENA (0x10)
32#define DWMMC_TMOUT (0x14)
33#define DWMMC_CTYPE (0x18)
34#define CTYPE_8BIT (1 << 16)
35#define CTYPE_4BIT (1)
36#define CTYPE_1BIT (0)
37
38#define DWMMC_BLKSIZ (0x1c)
39#define DWMMC_BYTCNT (0x20)
40#define DWMMC_INTMASK (0x24)
41#define INT_EBE (1 << 15)
42#define INT_SBE (1 << 13)
43#define INT_HLE (1 << 12)
44#define INT_FRUN (1 << 11)
45#define INT_DRT (1 << 9)
46#define INT_RTO (1 << 8)
47#define INT_DCRC (1 << 7)
48#define INT_RCRC (1 << 6)
49#define INT_RXDR (1 << 5)
50#define INT_TXDR (1 << 4)
51#define INT_DTO (1 << 3)
52#define INT_CMD_DONE (1 << 2)
53#define INT_RE (1 << 1)
54
55#define DWMMC_CMDARG (0x28)
56#define DWMMC_CMD (0x2c)
57#define CMD_START (1 << 31)
58#define CMD_USE_HOLD_REG (1 << 29) /* 0 if SDR50/100 */
59#define CMD_UPDATE_CLK_ONLY (1 << 21)
60#define CMD_SEND_INIT (1 << 15)
61#define CMD_STOP_ABORT_CMD (1 << 14)
62#define CMD_WAIT_PRVDATA_COMPLETE (1 << 13)
63#define CMD_WRITE (1 << 10)
64#define CMD_DATA_TRANS_EXPECT (1 << 9)
65#define CMD_CHECK_RESP_CRC (1 << 8)
66#define CMD_RESP_LEN (1 << 7)
67#define CMD_RESP_EXPECT (1 << 6)
68#define CMD(x) (x & 0x3f)
69
70#define DWMMC_RESP0 (0x30)
71#define DWMMC_RESP1 (0x34)
72#define DWMMC_RESP2 (0x38)
73#define DWMMC_RESP3 (0x3c)
74#define DWMMC_RINTSTS (0x44)
75#define DWMMC_STATUS (0x48)
76#define STATUS_DATA_BUSY (1 << 9)
77
78#define DWMMC_FIFOTH (0x4c)
79#define FIFOTH_TWMARK(x) (x & 0xfff)
80#define FIFOTH_RWMARK(x) ((x & 0x1ff) << 16)
81#define FIFOTH_DMA_BURST_SIZE(x) ((x & 0x7) << 28)
82
83#define DWMMC_DEBNCE (0x64)
84#define DWMMC_BMOD (0x80)
85#define BMOD_ENABLE (1 << 7)
86#define BMOD_FB (1 << 1)
87#define BMOD_SWRESET (1 << 0)
88
89#define DWMMC_DBADDR (0x88)
90#define DWMMC_IDSTS (0x8c)
91#define DWMMC_IDINTEN (0x90)
92#define DWMMC_CARDTHRCTL (0x100)
93#define CARDTHRCTL_RD_THR(x) ((x & 0xfff) << 16)
94#define CARDTHRCTL_RD_THR_EN (1 << 0)
95
96#define IDMAC_DES0_DIC (1 << 1)
97#define IDMAC_DES0_LD (1 << 2)
98#define IDMAC_DES0_FS (1 << 3)
99#define IDMAC_DES0_CH (1 << 4)
100#define IDMAC_DES0_ER (1 << 5)
101#define IDMAC_DES0_CES (1 << 30)
102#define IDMAC_DES0_OWN (1 << 31)
103#define IDMAC_DES1_BS1(x) ((x) & 0x1fff)
104#define IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13)
105
106#define DWMMC_DMA_MAX_BUFFER_SIZE (512 * 8)
107
108#define DWMMC_8BIT_MODE (1 << 6)
109
110#define TIMEOUT 100000
111
112struct dw_idmac_desc {
113 unsigned int des0;
114 unsigned int des1;
115 unsigned int des2;
116 unsigned int des3;
117};
118
119static void dw_init(void);
120static int dw_send_cmd(emmc_cmd_t *cmd);
121static int dw_set_ios(int clk, int width);
122static int dw_prepare(int lba, uintptr_t buf, size_t size);
123static int dw_read(int lba, uintptr_t buf, size_t size);
124static int dw_write(int lba, uintptr_t buf, size_t size);
125
126static const emmc_ops_t dw_mmc_ops = {
127 .init = dw_init,
128 .send_cmd = dw_send_cmd,
129 .set_ios = dw_set_ios,
130 .prepare = dw_prepare,
131 .read = dw_read,
132 .write = dw_write,
133};
134
135static dw_mmc_params_t dw_params;
136
137static void dw_update_clk(void)
138{
139 unsigned int data;
140
141 mmio_write_32(dw_params.reg_base + DWMMC_CMD,
142 CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY |
143 CMD_START);
144 while (1) {
145 data = mmio_read_32(dw_params.reg_base + DWMMC_CMD);
146 if ((data & CMD_START) == 0)
147 break;
148 data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS);
Haojian Zhuang5f386c02018-01-11 13:49:56 +0800149 assert((data & INT_HLE) == 0);
Haojian Zhuang06249dc2016-03-18 22:14:16 +0800150 }
151}
152
153static void dw_set_clk(int clk)
154{
155 unsigned int data;
156 int div;
157
158 assert(clk > 0);
159
160 for (div = 1; div < 256; div++) {
161 if ((dw_params.clk_rate / (2 * div)) <= clk) {
162 break;
163 }
164 }
165 assert(div < 256);
166
167 /* wait until controller is idle */
168 do {
169 data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS);
170 } while (data & STATUS_DATA_BUSY);
171
172 /* disable clock before change clock rate */
173 mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0);
174 dw_update_clk();
175
176 mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div);
177 dw_update_clk();
178
179 /* enable clock */
180 mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1);
181 mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0);
182 dw_update_clk();
183}
184
185static void dw_init(void)
186{
187 unsigned int data;
188 uintptr_t base;
189
190 assert((dw_params.reg_base & EMMC_BLOCK_MASK) == 0);
191
192 base = dw_params.reg_base;
193 mmio_write_32(base + DWMMC_PWREN, 1);
194 mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL);
195 do {
196 data = mmio_read_32(base + DWMMC_CTRL);
197 } while (data);
198
199 /* enable DMA in CTRL */
200 data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN;
201 mmio_write_32(base + DWMMC_CTRL, data);
202 mmio_write_32(base + DWMMC_RINTSTS, ~0);
203 mmio_write_32(base + DWMMC_INTMASK, 0);
204 mmio_write_32(base + DWMMC_TMOUT, ~0);
205 mmio_write_32(base + DWMMC_IDINTEN, ~0);
206 mmio_write_32(base + DWMMC_BLKSIZ, EMMC_BLOCK_SIZE);
207 mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024);
208 mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff);
209 mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET);
210 do {
211 data = mmio_read_32(base + DWMMC_BMOD);
212 } while (data & BMOD_SWRESET);
213 /* enable DMA in BMOD */
214 data |= BMOD_ENABLE | BMOD_FB;
215 mmio_write_32(base + DWMMC_BMOD, data);
216
217 udelay(100);
218 dw_set_clk(EMMC_BOOT_CLK_RATE);
219 udelay(100);
220}
221
222static int dw_send_cmd(emmc_cmd_t *cmd)
223{
224 unsigned int op, data, err_mask;
225 uintptr_t base;
226 int timeout;
227
228 assert(cmd);
229
230 base = dw_params.reg_base;
231
232 switch (cmd->cmd_idx) {
233 case EMMC_CMD0:
234 op = CMD_SEND_INIT;
235 break;
236 case EMMC_CMD12:
237 op = CMD_STOP_ABORT_CMD;
238 break;
239 case EMMC_CMD13:
240 op = CMD_WAIT_PRVDATA_COMPLETE;
241 break;
242 case EMMC_CMD8:
243 case EMMC_CMD17:
244 case EMMC_CMD18:
245 op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE;
246 break;
247 case EMMC_CMD24:
248 case EMMC_CMD25:
249 op = CMD_WRITE | CMD_DATA_TRANS_EXPECT |
250 CMD_WAIT_PRVDATA_COMPLETE;
251 break;
252 default:
253 op = 0;
254 break;
255 }
256 op |= CMD_USE_HOLD_REG | CMD_START;
257 switch (cmd->resp_type) {
258 case 0:
259 break;
260 case EMMC_RESPONSE_R2:
261 op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC |
262 CMD_RESP_LEN;
263 break;
264 case EMMC_RESPONSE_R3:
265 op |= CMD_RESP_EXPECT;
266 break;
267 default:
268 op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC;
269 break;
270 }
271 timeout = TIMEOUT;
272 do {
273 data = mmio_read_32(base + DWMMC_STATUS);
274 if (--timeout <= 0)
275 panic();
276 } while (data & STATUS_DATA_BUSY);
277
278 mmio_write_32(base + DWMMC_RINTSTS, ~0);
279 mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg);
280 mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx);
281
282 err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE |
283 INT_DCRC | INT_DRT | INT_SBE;
284 timeout = TIMEOUT;
285 do {
286 udelay(500);
287 data = mmio_read_32(base + DWMMC_RINTSTS);
288
289 if (data & err_mask)
290 return -EIO;
291 if (data & INT_DTO)
292 break;
293 if (--timeout == 0) {
294 ERROR("%s, RINTSTS:0x%x\n", __func__, data);
295 panic();
296 }
297 } while (!(data & INT_CMD_DONE));
298
299 if (op & CMD_RESP_EXPECT) {
300 cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0);
301 if (op & CMD_RESP_LEN) {
302 cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1);
303 cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2);
304 cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3);
305 }
306 }
307 return 0;
308}
309
310static int dw_set_ios(int clk, int width)
311{
312 switch (width) {
313 case EMMC_BUS_WIDTH_1:
314 mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT);
315 break;
316 case EMMC_BUS_WIDTH_4:
317 mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT);
318 break;
319 case EMMC_BUS_WIDTH_8:
320 mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT);
321 break;
322 default:
323 assert(0);
Jonathan Wright39b42212018-03-13 15:24:29 +0000324 break;
Haojian Zhuang06249dc2016-03-18 22:14:16 +0800325 }
326 dw_set_clk(clk);
327 return 0;
328}
329
330static int dw_prepare(int lba, uintptr_t buf, size_t size)
331{
332 struct dw_idmac_desc *desc;
333 int desc_cnt, i, last;
334 uintptr_t base;
335
336 assert(((buf & EMMC_BLOCK_MASK) == 0) &&
337 ((size % EMMC_BLOCK_SIZE) == 0) &&
338 (dw_params.desc_size > 0) &&
339 ((dw_params.reg_base & EMMC_BLOCK_MASK) == 0) &&
340 ((dw_params.desc_base & EMMC_BLOCK_MASK) == 0) &&
341 ((dw_params.desc_size & EMMC_BLOCK_MASK) == 0));
342
343 desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) /
344 DWMMC_DMA_MAX_BUFFER_SIZE;
345 assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size);
346
347 base = dw_params.reg_base;
348 desc = (struct dw_idmac_desc *)dw_params.desc_base;
349 mmio_write_32(base + DWMMC_BYTCNT, size);
350 mmio_write_32(base + DWMMC_RINTSTS, ~0);
351 for (i = 0; i < desc_cnt; i++) {
352 desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC;
353 desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE);
354 desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i;
355 desc[i].des3 = dw_params.desc_base +
356 (sizeof(struct dw_idmac_desc)) * (i + 1);
357 }
358 /* first descriptor */
359 desc->des0 |= IDMAC_DES0_FS;
360 /* last descriptor */
361 last = desc_cnt - 1;
362 (desc + last)->des0 |= IDMAC_DES0_LD;
363 (desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH);
364 (desc + last)->des1 = IDMAC_DES1_BS1(size - (last *
365 DWMMC_DMA_MAX_BUFFER_SIZE));
366 /* set next descriptor address as 0 */
367 (desc + last)->des3 = 0;
368
369 mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base);
370 clean_dcache_range(dw_params.desc_base,
371 desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE);
372
373 return 0;
374}
375
376static int dw_read(int lba, uintptr_t buf, size_t size)
377{
378 return 0;
379}
380
381static int dw_write(int lba, uintptr_t buf, size_t size)
382{
383 return 0;
384}
385
386void dw_mmc_init(dw_mmc_params_t *params)
387{
388 assert((params != 0) &&
389 ((params->reg_base & EMMC_BLOCK_MASK) == 0) &&
390 ((params->desc_base & EMMC_BLOCK_MASK) == 0) &&
391 ((params->desc_size & EMMC_BLOCK_MASK) == 0) &&
392 (params->desc_size > 0) &&
393 (params->clk_rate > 0) &&
394 ((params->bus_width == EMMC_BUS_WIDTH_1) ||
395 (params->bus_width == EMMC_BUS_WIDTH_4) ||
396 (params->bus_width == EMMC_BUS_WIDTH_8)));
397
398 memcpy(&dw_params, params, sizeof(dw_mmc_params_t));
399 emmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width,
400 params->flags);
401}