1 /*
2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3 * Copyright 2025 NXP
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <assert.h>
9 #include <errno.h>
10 #include <string.h>
11
12 #include <arch.h>
13 #include <arch_helpers.h>
14 #include <common/debug.h>
15 #include <drivers/delay_timer.h>
16 #include <drivers/mmc.h>
17 #include <lib/mmio_poll.h>
18 #include <lib/xlat_tables/xlat_tables_v2.h>
19
20 #include <imx_usdhc.h>
21
22 /* These masks represent the commands which involve a data transfer. */
23 #define ADTC_MASK_SD (BIT_32(6U) | BIT_32(17U) | BIT_32(18U) |\
24 BIT_32(24U) | BIT_32(25U))
25 #define ADTC_MASK_ACMD (BIT_64(51U))
26
27 #define USDHC_TIMEOUT_US (1U * 1000U) /* 1 msec */
28 #define USDHC_TRANSFER_TIMEOUT (1U * 1000U * 1000U) /* 1 sec */
29
30 struct imx_usdhc_device_data {
31 uint32_t addr;
32 uint32_t blk_size;
33 uint32_t blks;
34 bool valid;
35 };
36
37 static void imx_usdhc_initialize(void);
38 static int imx_usdhc_send_cmd(struct mmc_cmd *cmd);
39 static int imx_usdhc_set_ios(unsigned int clk, unsigned int width);
40 static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size);
41 static int imx_usdhc_read(int lba, uintptr_t buf, size_t size);
42 static int imx_usdhc_write(int lba, uintptr_t buf, size_t size);
43
44 static const struct mmc_ops imx_usdhc_ops = {
45 .init = imx_usdhc_initialize,
46 .send_cmd = imx_usdhc_send_cmd,
47 .set_ios = imx_usdhc_set_ios,
48 .prepare = imx_usdhc_prepare,
49 .read = imx_usdhc_read,
50 .write = imx_usdhc_write,
51 };
52
53 static imx_usdhc_params_t imx_usdhc_params;
54 static struct imx_usdhc_device_data imx_usdhc_data;
55
imx_usdhc_is_buf_valid(void)56 static bool imx_usdhc_is_buf_valid(void)
57 {
58 return imx_usdhc_data.valid;
59 }
60
imx_usdhc_is_buf_multiblk(void)61 static bool imx_usdhc_is_buf_multiblk(void)
62 {
63 return imx_usdhc_data.blks > 1U;
64 }
65
imx_usdhc_inval_buf_data(void)66 static void imx_usdhc_inval_buf_data(void)
67 {
68 imx_usdhc_data.valid = false;
69 }
70
imx_usdhc_save_buf_data(uintptr_t buf,size_t size)71 static int imx_usdhc_save_buf_data(uintptr_t buf, size_t size)
72 {
73 uint32_t block_size;
74 uint64_t blks;
75
76 if (size <= MMC_BLOCK_SIZE) {
77 block_size = (uint32_t)size;
78 } else {
79 block_size = MMC_BLOCK_SIZE;
80 }
81
82 if (buf > UINT32_MAX) {
83 return -EOVERFLOW;
84 }
85
86 imx_usdhc_data.addr = (uint32_t)buf;
87 imx_usdhc_data.blk_size = block_size;
88 blks = size / block_size;
89 imx_usdhc_data.blks = (uint32_t)blks;
90
91 imx_usdhc_data.valid = true;
92
93 return 0;
94 }
95
imx_usdhc_write_buf_data(void)96 static void imx_usdhc_write_buf_data(void)
97 {
98 uintptr_t reg_base = imx_usdhc_params.reg_base;
99 uint32_t addr, blks, blk_size;
100
101 addr = imx_usdhc_data.addr;
102 blks = imx_usdhc_data.blks;
103 blk_size = imx_usdhc_data.blk_size;
104
105 mmio_write_32(reg_base + DSADDR, addr);
106 mmio_write_32(reg_base + BLKATT, BLKATT_BLKCNT(blks) |
107 BLKATT_BLKSIZE(blk_size));
108 }
109
110 #define IMX7_MMC_SRC_CLK_RATE (200 * 1000 * 1000)
imx_usdhc_set_clk(unsigned int clk)111 static int imx_usdhc_set_clk(unsigned int clk)
112 {
113 unsigned int sdhc_clk = IMX7_MMC_SRC_CLK_RATE;
114 uintptr_t reg_base = imx_usdhc_params.reg_base;
115 unsigned int pre_div = 1U, div = 1U;
116 uint32_t pstate;
117 int ret;
118
119 assert(clk > 0);
120
121 while (sdhc_clk / (16 * pre_div) > clk && pre_div < 256)
122 pre_div *= 2;
123
124 while (((sdhc_clk / (div * pre_div)) > clk) && (div < 16U)) {
125 div++;
126 }
127
128 pre_div >>= 1;
129 div -= 1;
130 clk = (pre_div << 8) | (div << 4);
131
132 ret = mmio_read_32_poll_timeout(reg_base + PSTATE, pstate,
133 (pstate & PSTATE_SDSTB) != 0U,
134 USDHC_TIMEOUT_US);
135 if (ret == -ETIMEDOUT) {
136 ERROR("Unstable SD clock\n");
137 return ret;
138 }
139
140 mmio_clrbits32(reg_base + VENDSPEC, VENDSPEC_CARD_CLKEN);
141 mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_CLOCK_MASK, clk);
142 udelay(10000);
143
144 mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_PER_CLKEN | VENDSPEC_CARD_CLKEN);
145
146 return 0;
147 }
148
imx_usdhc_initialize(void)149 static void imx_usdhc_initialize(void)
150 {
151 uintptr_t reg_base = imx_usdhc_params.reg_base;
152 uint32_t sysctrl;
153 int ret;
154
155 assert((imx_usdhc_params.reg_base & MMC_BLOCK_MASK) == 0);
156
157 /* reset the controller */
158 mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTA);
159
160 /* wait for reset done */
161 ret = mmio_read_32_poll_timeout(reg_base + SYSCTRL, sysctrl,
162 (sysctrl & SYSCTRL_RSTA) == 0U,
163 USDHC_TIMEOUT_US);
164 if (ret == -ETIMEDOUT) {
165 ERROR("Failed to reset the USDHC controller\n");
166 panic();
167 }
168
169 mmio_write_32(reg_base + MMCBOOT, 0);
170 mmio_write_32(reg_base + MIXCTRL, 0);
171 mmio_write_32(reg_base + CLKTUNECTRLSTS, 0);
172
173 mmio_write_32(reg_base + VENDSPEC, VENDSPEC_INIT);
174 mmio_write_32(reg_base + DLLCTRL, 0);
175 mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_IPG_CLKEN | VENDSPEC_PER_CLKEN);
176
177 /* Set the initial boot clock rate */
178 ret = imx_usdhc_set_clk(MMC_BOOT_CLK_RATE);
179 if (ret != 0) {
180 panic();
181 }
182
183 udelay(100);
184
185 /* Clear read/write ready status */
186 mmio_clrbits32(reg_base + INTSTATEN, INTSTATEN_BRR | INTSTATEN_BWR);
187
188 /* configure as little endian */
189 mmio_write_32(reg_base + PROTCTRL, PROTCTRL_LE);
190
191 /* Set timeout to the maximum value */
192 mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_TIMEOUT_MASK,
193 SYSCTRL_TIMEOUT(15));
194
195 /* set wartermark level as 16 for safe for MMC */
196 mmio_clrsetbits32(reg_base + WATERMARKLEV, WMKLV_MASK, 16 | (16 << 16));
197 }
198
is_data_transfer_to_card(const struct mmc_cmd * cmd)199 static bool is_data_transfer_to_card(const struct mmc_cmd *cmd)
200 {
201 unsigned int cmd_idx = cmd->cmd_idx;
202
203 return (cmd_idx == MMC_CMD(24)) || (cmd_idx == MMC_CMD(25));
204 }
205
is_data_transfer_cmd(const struct mmc_cmd * cmd)206 static bool is_data_transfer_cmd(const struct mmc_cmd *cmd)
207 {
208 uintptr_t reg_base = imx_usdhc_params.reg_base;
209 unsigned int cmd_idx = cmd->cmd_idx;
210 uint32_t xfer_type;
211
212 xfer_type = mmio_read_32(reg_base + XFERTYPE);
213
214 if (XFERTYPE_GET_CMD(xfer_type) == MMC_CMD(55)) {
215 return (ADTC_MASK_ACMD & BIT_64(cmd_idx)) != 0ULL;
216 }
217
218 if ((ADTC_MASK_SD & BIT_32(cmd->cmd_idx)) != 0U) {
219 return true;
220 }
221
222 return false;
223 }
224
get_xfr_type(const struct mmc_cmd * cmd,bool data,uint32_t * xfertype)225 static int get_xfr_type(const struct mmc_cmd *cmd, bool data, uint32_t *xfertype)
226 {
227 *xfertype = XFERTYPE_CMD(cmd->cmd_idx);
228
229 switch (cmd->resp_type) {
230 case MMC_RESPONSE_R2:
231 *xfertype |= XFERTYPE_RSPTYP_136;
232 *xfertype |= XFERTYPE_CCCEN;
233 break;
234 case MMC_RESPONSE_R4:
235 *xfertype |= XFERTYPE_RSPTYP_48;
236 break;
237 case MMC_RESPONSE_R6:
238 *xfertype |= XFERTYPE_RSPTYP_48;
239 *xfertype |= XFERTYPE_CICEN;
240 *xfertype |= XFERTYPE_CCCEN;
241 break;
242 case MMC_RESPONSE_R1B:
243 *xfertype |= XFERTYPE_RSPTYP_48_BUSY;
244 *xfertype |= XFERTYPE_CICEN;
245 *xfertype |= XFERTYPE_CCCEN;
246 break;
247 case MMC_RESPONSE_NONE:
248 break;
249 default:
250 ERROR("Invalid CMD response: %u\n", cmd->resp_type);
251 return -EINVAL;
252 }
253
254 if (data) {
255 *xfertype |= XFERTYPE_DPSEL;
256 }
257
258 return 0;
259 }
260
imx_usdhc_send_cmd(struct mmc_cmd * cmd)261 static int imx_usdhc_send_cmd(struct mmc_cmd *cmd)
262 {
263 uintptr_t reg_base = imx_usdhc_params.reg_base;
264 unsigned int flags = INTSTATEN_CC | INTSTATEN_CTOE;
265 uint32_t xfertype, pstate, intstat, sysctrl;
266 unsigned int mixctl = 0;
267 int err = 0, ret;
268 bool data;
269
270 assert(cmd);
271
272 data = is_data_transfer_cmd(cmd);
273
274 err = get_xfr_type(cmd, data, &xfertype);
275 if (err != 0) {
276 return err;
277 }
278
279 /* clear all irq status */
280 mmio_write_32(reg_base + INTSTAT, 0xffffffff);
281
282 /* Wait for the bus to be idle */
283 err = mmio_read_32_poll_timeout(reg_base + PSTATE, pstate,
284 (pstate & (PSTATE_CDIHB | PSTATE_CIHB)) == 0U,
285 USDHC_TIMEOUT_US);
286 if (err == -ETIMEDOUT) {
287 ERROR("Failed to wait an idle bus\n");
288 return err;
289 }
290
291 err = mmio_read_32_poll_timeout(reg_base + PSTATE, pstate,
292 (pstate & PSTATE_DLA) == 0U,
293 USDHC_TIMEOUT_US);
294 if (err == -ETIMEDOUT) {
295 ERROR("Active data line during the uSDHC init\n");
296 return err;
297 }
298
299 mmio_write_32(reg_base + INTSIGEN, 0);
300
301 if (data) {
302 mixctl |= MIXCTRL_DMAEN;
303 }
304
305 if (!is_data_transfer_to_card(cmd)) {
306 mixctl |= MIXCTRL_DTDSEL;
307 }
308
309 if ((cmd->cmd_idx != MMC_CMD(55)) && imx_usdhc_is_buf_valid()) {
310 if (imx_usdhc_is_buf_multiblk()) {
311 mixctl |= MIXCTRL_MSBSEL | MIXCTRL_BCEN;
312 }
313
314 imx_usdhc_write_buf_data();
315 imx_usdhc_inval_buf_data();
316 }
317
318 /* Send the command */
319 mmio_write_32(reg_base + CMDARG, cmd->cmd_arg);
320 mmio_clrsetbits32(reg_base + MIXCTRL, MIXCTRL_DATMASK, mixctl);
321 mmio_write_32(reg_base + XFERTYPE, xfertype);
322
323 /* Wait for the command done */
324 err = mmio_read_32_poll_timeout(reg_base + INTSTAT, intstat,
325 (intstat & flags) != 0U,
326 USDHC_TIMEOUT_US);
327 if ((err == -ETIMEDOUT) || ((intstat & (INTSTATEN_CTOE | CMD_ERR)) != 0U)) {
328 if ((intstat & (INTSTATEN_CTOE | CMD_ERR)) != 0U) {
329 err = -EIO;
330 }
331 ERROR("imx_usdhc mmc cmd %d state 0x%x errno=%d\n",
332 cmd->cmd_idx, intstat, err);
333 goto out;
334 }
335
336 /* Copy the response to the response buffer */
337 if (cmd->resp_type & MMC_RSP_136) {
338 unsigned int cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0;
339
340 cmdrsp3 = mmio_read_32(reg_base + CMDRSP3);
341 cmdrsp2 = mmio_read_32(reg_base + CMDRSP2);
342 cmdrsp1 = mmio_read_32(reg_base + CMDRSP1);
343 cmdrsp0 = mmio_read_32(reg_base + CMDRSP0);
344 cmd->resp_data[3] = (cmdrsp3 << 8) | (cmdrsp2 >> 24);
345 cmd->resp_data[2] = (cmdrsp2 << 8) | (cmdrsp1 >> 24);
346 cmd->resp_data[1] = (cmdrsp1 << 8) | (cmdrsp0 >> 24);
347 cmd->resp_data[0] = (cmdrsp0 << 8);
348 } else {
349 cmd->resp_data[0] = mmio_read_32(reg_base + CMDRSP0);
350 }
351
352 /* Wait until all of the blocks are transferred */
353 if (data) {
354 flags = DATA_COMPLETE;
355 err = mmio_read_32_poll_timeout(reg_base + INTSTAT, intstat,
356 (((intstat & (INTSTATEN_DTOE | DATA_ERR)) != 0U) ||
357 ((intstat & flags) == flags)),
358 USDHC_TRANSFER_TIMEOUT);
359 if ((intstat & (INTSTATEN_DTOE | DATA_ERR)) != 0U) {
360 err = -EIO;
361 ERROR("imx_usdhc mmc data state 0x%x\n", intstat);
362 goto out;
363 }
364
365 if (err == -ETIMEDOUT) {
366 ERROR("Timeout in block transfer\n");
367 goto out;
368 }
369 }
370
371 out:
372 /* Reset CMD and DATA on error */
373 if (err) {
374 mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTC);
375 ret = mmio_read_32_poll_timeout(reg_base + SYSCTRL, sysctrl,
376 (sysctrl & SYSCTRL_RSTC) == 0U,
377 USDHC_TIMEOUT_US);
378 if (ret == -ETIMEDOUT) {
379 ERROR("Failed to reset the CMD line\n");
380 }
381
382 if (data) {
383 mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTD);
384 ret = mmio_read_32_poll_timeout(reg_base + SYSCTRL, sysctrl,
385 (sysctrl & SYSCTRL_RSTD) == 0U,
386 USDHC_TIMEOUT_US);
387 if (ret == -ETIMEDOUT) {
388 ERROR("Failed to reset the data line\n");
389 }
390 }
391 }
392
393 /* clear all irq status */
394 mmio_write_32(reg_base + INTSTAT, 0xffffffff);
395
396 return err;
397 }
398
imx_usdhc_set_ios(unsigned int clk,unsigned int width)399 static int imx_usdhc_set_ios(unsigned int clk, unsigned int width)
400 {
401 uintptr_t reg_base = imx_usdhc_params.reg_base;
402 int ret;
403
404 ret = imx_usdhc_set_clk(clk);
405 if (ret != 0) {
406 return ret;
407 }
408
409 if (width == MMC_BUS_WIDTH_4)
410 mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK,
411 PROTCTRL_WIDTH_4);
412 else if (width == MMC_BUS_WIDTH_8)
413 mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK,
414 PROTCTRL_WIDTH_8);
415
416 return 0;
417 }
418
imx_usdhc_prepare(int lba,uintptr_t buf,size_t size)419 static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size)
420 {
421 flush_dcache_range(buf, size);
422 return imx_usdhc_save_buf_data(buf, size);
423 }
424
imx_usdhc_read(int lba,uintptr_t buf,size_t size)425 static int imx_usdhc_read(int lba, uintptr_t buf, size_t size)
426 {
427 inv_dcache_range(buf, size);
428 return 0;
429 }
430
imx_usdhc_write(int lba,uintptr_t buf,size_t size)431 static int imx_usdhc_write(int lba, uintptr_t buf, size_t size)
432 {
433 return 0;
434 }
435
imx_usdhc_init(imx_usdhc_params_t * params,struct mmc_device_info * mmc_dev_info)436 void imx_usdhc_init(imx_usdhc_params_t *params,
437 struct mmc_device_info *mmc_dev_info)
438 {
439 int ret __maybe_unused;
440
441 assert((params != 0) &&
442 ((params->reg_base & MMC_BLOCK_MASK) == 0) &&
443 ((params->bus_width == MMC_BUS_WIDTH_1) ||
444 (params->bus_width == MMC_BUS_WIDTH_4) ||
445 (params->bus_width == MMC_BUS_WIDTH_8)));
446
447 #if PLAT_XLAT_TABLES_DYNAMIC
448 ret = mmap_add_dynamic_region(params->reg_base, params->reg_base,
449 PAGE_SIZE,
450 MT_DEVICE | MT_RW | MT_SECURE);
451 if (ret != 0) {
452 ERROR("Failed to map the uSDHC registers\n");
453 panic();
454 }
455 #endif
456
457 memcpy(&imx_usdhc_params, params, sizeof(imx_usdhc_params_t));
458 mmc_init(&imx_usdhc_ops, params->clk_rate, params->bus_width,
459 params->flags, mmc_dev_info);
460 }
461