blob: 50e87c1db4f29beceb626a21f6b4a0b2e7ed32bd [file] [log] [blame]
Yann Gautier1e5e85a2018-07-03 18:32:12 +02001/*
2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7/* Define a simple and generic interface to access eMMC and SD-card devices. */
8
Yann Gautier1e5e85a2018-07-03 18:32:12 +02009#include <assert.h>
Yann Gautier1e5e85a2018-07-03 18:32:12 +020010#include <errno.h>
Yann Gautier1e5e85a2018-07-03 18:32:12 +020011#include <stdbool.h>
12#include <string.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +000013
14#include <arch_helpers.h>
15#include <common/debug.h>
16#include <drivers/delay_timer.h>
17#include <drivers/mmc.h>
18#include <lib/utils.h>
Yann Gautier1e5e85a2018-07-03 18:32:12 +020019
20#define MMC_DEFAULT_MAX_RETRIES 5
21#define SEND_OP_COND_MAX_RETRIES 100
22
23#define MULT_BY_512K_SHIFT 19
24
25static const struct mmc_ops *ops;
26static unsigned int mmc_ocr_value;
27static struct mmc_csd_emmc mmc_csd;
Haojian Zhuangdf7271c2018-08-02 14:50:12 +080028static unsigned char mmc_ext_csd[512] __aligned(16);
Yann Gautier1e5e85a2018-07-03 18:32:12 +020029static unsigned int mmc_flags;
30static struct mmc_device_info *mmc_dev_info;
31static unsigned int rca;
32
33static const unsigned char tran_speed_base[16] = {
34 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80
35};
36
37static const unsigned char sd_tran_speed_base[16] = {
38 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
39};
40
41static bool is_cmd23_enabled(void)
42{
43 return ((mmc_flags & MMC_FLAG_CMD23) != 0U);
44}
45
46static int mmc_send_cmd(unsigned int idx, unsigned int arg,
47 unsigned int r_type, unsigned int *r_data)
48{
49 struct mmc_cmd cmd;
50 int ret;
51
52 zeromem(&cmd, sizeof(struct mmc_cmd));
53
54 cmd.cmd_idx = idx;
55 cmd.cmd_arg = arg;
56 cmd.resp_type = r_type;
57
58 ret = ops->send_cmd(&cmd);
59
60 if ((ret == 0) && (r_data != NULL)) {
61 int i;
62
63 for (i = 0; i < 4; i++) {
64 *r_data = cmd.resp_data[i];
65 r_data++;
66 }
67 }
68
69 if (ret != 0) {
70 VERBOSE("Send command %u error: %d\n", idx, ret);
71 }
72
73 return ret;
74}
75
76static int mmc_device_state(void)
77{
78 int retries = MMC_DEFAULT_MAX_RETRIES;
79 unsigned int resp_data[4];
80
81 do {
82 int ret;
83
84 if (retries == 0) {
85 ERROR("CMD13 failed after %d retries\n",
86 MMC_DEFAULT_MAX_RETRIES);
87 return -EIO;
88 }
89
90 ret = mmc_send_cmd(MMC_CMD(13), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +020091 MMC_RESPONSE_R1, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +020092 if (ret != 0) {
93 return ret;
94 }
95
96 if ((resp_data[0] & STATUS_SWITCH_ERROR) != 0U) {
97 return -EIO;
98 }
99
100 retries--;
101 } while ((resp_data[0] & STATUS_READY_FOR_DATA) == 0U);
102
103 return MMC_GET_STATE(resp_data[0]);
104}
105
106static int mmc_set_ext_csd(unsigned int ext_cmd, unsigned int value)
107{
108 int ret;
109
110 ret = mmc_send_cmd(MMC_CMD(6),
111 EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) |
112 EXTCSD_VALUE(value) | EXTCSD_CMD_SET_NORMAL,
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100113 MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200114 if (ret != 0) {
115 return ret;
116 }
117
118 do {
119 ret = mmc_device_state();
120 if (ret < 0) {
121 return ret;
122 }
123 } while (ret == MMC_STATE_PRG);
124
125 return 0;
126}
127
128static int mmc_sd_switch(unsigned int bus_width)
129{
130 int ret;
131 int retries = MMC_DEFAULT_MAX_RETRIES;
132 unsigned int scr[2] = { 0 };
133 unsigned int bus_width_arg = 0;
134
135 ret = ops->prepare(0, (uintptr_t)&scr, sizeof(scr));
136 if (ret != 0) {
137 return ret;
138 }
139
140 /* CMD55: Application Specific Command */
141 ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200142 MMC_RESPONSE_R5, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200143 if (ret != 0) {
144 return ret;
145 }
146
147 /* ACMD51: SEND_SCR */
148 do {
Yann Gautierf2e8b162018-09-28 16:48:37 +0200149 ret = mmc_send_cmd(MMC_ACMD(51), 0, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200150 if ((ret != 0) && (retries == 0)) {
151 ERROR("ACMD51 failed after %d retries (ret=%d)\n",
152 MMC_DEFAULT_MAX_RETRIES, ret);
153 return ret;
154 }
155
156 retries--;
157 } while (ret != 0);
158
159 ret = ops->read(0, (uintptr_t)&scr, sizeof(scr));
160 if (ret != 0) {
161 return ret;
162 }
163
164 if (((scr[0] & SD_SCR_BUS_WIDTH_4) != 0U) &&
165 (bus_width == MMC_BUS_WIDTH_4)) {
166 bus_width_arg = 2;
167 }
168
169 /* CMD55: Application Specific Command */
170 ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200171 MMC_RESPONSE_R5, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200172 if (ret != 0) {
173 return ret;
174 }
175
176 /* ACMD6: SET_BUS_WIDTH */
Yann Gautierf2e8b162018-09-28 16:48:37 +0200177 ret = mmc_send_cmd(MMC_ACMD(6), bus_width_arg, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200178 if (ret != 0) {
179 return ret;
180 }
181
182 do {
183 ret = mmc_device_state();
184 if (ret < 0) {
185 return ret;
186 }
187 } while (ret == MMC_STATE_PRG);
188
189 return 0;
190}
191
192static int mmc_set_ios(unsigned int clk, unsigned int bus_width)
193{
194 int ret;
195 unsigned int width = bus_width;
196
197 if (mmc_dev_info->mmc_dev_type != MMC_IS_EMMC) {
198 if (width == MMC_BUS_WIDTH_8) {
199 WARN("Wrong bus config for SD-card, force to 4\n");
200 width = MMC_BUS_WIDTH_4;
201 }
202 ret = mmc_sd_switch(width);
203 if (ret != 0) {
204 return ret;
205 }
206 } else if (mmc_csd.spec_vers == 4U) {
207 ret = mmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH,
208 (unsigned int)width);
209 if (ret != 0) {
210 return ret;
211 }
212 } else {
213 VERBOSE("Wrong MMC type or spec version\n");
214 }
215
216 return ops->set_ios(clk, width);
217}
218
219static int mmc_fill_device_info(void)
220{
221 unsigned long long c_size;
222 unsigned int speed_idx;
223 unsigned int nb_blocks;
224 unsigned int freq_unit;
Antonio Nino Diaz5d95e0a2018-08-10 13:04:02 +0100225 int ret = 0;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200226 struct mmc_csd_sd_v2 *csd_sd_v2;
227
228 switch (mmc_dev_info->mmc_dev_type) {
229 case MMC_IS_EMMC:
230 mmc_dev_info->block_size = MMC_BLOCK_SIZE;
231
232 ret = ops->prepare(0, (uintptr_t)&mmc_ext_csd,
233 sizeof(mmc_ext_csd));
234 if (ret != 0) {
235 return ret;
236 }
237
238 /* MMC CMD8: SEND_EXT_CSD */
Yann Gautierf2e8b162018-09-28 16:48:37 +0200239 ret = mmc_send_cmd(MMC_CMD(8), 0, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200240 if (ret != 0) {
241 return ret;
242 }
243
244 ret = ops->read(0, (uintptr_t)&mmc_ext_csd,
245 sizeof(mmc_ext_csd));
246 if (ret != 0) {
247 return ret;
248 }
249
Haojian Zhuang05274cb2018-11-21 09:19:49 +0800250 do {
251 ret = mmc_device_state();
252 if (ret < 0) {
253 return ret;
254 }
255 } while (ret != MMC_STATE_TRAN);
256
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200257 nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) |
258 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) |
259 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) |
260 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 3] << 24);
261
262 mmc_dev_info->device_size = (unsigned long long)nb_blocks *
263 mmc_dev_info->block_size;
264
265 break;
266
267 case MMC_IS_SD:
268 /*
269 * Use the same mmc_csd struct, as required fields here
270 * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC.
271 */
272 mmc_dev_info->block_size = BIT_32(mmc_csd.read_bl_len);
273
274 c_size = ((unsigned long long)mmc_csd.c_size_high << 2U) |
275 (unsigned long long)mmc_csd.c_size_low;
276 assert(c_size != 0xFFFU);
277
278 mmc_dev_info->device_size = (c_size + 1U) *
279 BIT_64(mmc_csd.c_size_mult + 2U) *
280 mmc_dev_info->block_size;
281
282 break;
283
284 case MMC_IS_SD_HC:
285 assert(mmc_csd.csd_structure == 1U);
286
287 mmc_dev_info->block_size = MMC_BLOCK_SIZE;
288
289 /* Need to use mmc_csd_sd_v2 struct */
290 csd_sd_v2 = (struct mmc_csd_sd_v2 *)&mmc_csd;
291 c_size = ((unsigned long long)csd_sd_v2->c_size_high << 16) |
292 (unsigned long long)csd_sd_v2->c_size_low;
293
294 mmc_dev_info->device_size = (c_size + 1U) << MULT_BY_512K_SHIFT;
295
296 break;
297
298 default:
299 ret = -EINVAL;
300 break;
301 }
302
303 if (ret != 0) {
304 return ret;
305 }
306
307 speed_idx = (mmc_csd.tran_speed & CSD_TRAN_SPEED_MULT_MASK) >>
308 CSD_TRAN_SPEED_MULT_SHIFT;
309
310 assert(speed_idx > 0U);
311
312 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
313 mmc_dev_info->max_bus_freq = tran_speed_base[speed_idx];
314 } else {
315 mmc_dev_info->max_bus_freq = sd_tran_speed_base[speed_idx];
316 }
317
318 freq_unit = mmc_csd.tran_speed & CSD_TRAN_SPEED_UNIT_MASK;
319 while (freq_unit != 0U) {
320 mmc_dev_info->max_bus_freq *= 10U;
321 --freq_unit;
322 }
323
324 mmc_dev_info->max_bus_freq *= 10000U;
325
326 return 0;
327}
328
329static int sd_send_op_cond(void)
330{
Yann Gautierde6959e2018-08-02 13:46:17 +0200331 int n;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200332 unsigned int resp_data[4];
333
Yann Gautierde6959e2018-08-02 13:46:17 +0200334 for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200335 int ret;
336
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200337 /* CMD55: Application Specific Command */
Yann Gautierf2e8b162018-09-28 16:48:37 +0200338 ret = mmc_send_cmd(MMC_CMD(55), 0, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200339 if (ret != 0) {
340 return ret;
341 }
342
343 /* ACMD41: SD_SEND_OP_COND */
Bryan O'Donoghuee62f4192018-08-15 15:59:07 +0100344 ret = mmc_send_cmd(MMC_ACMD(41), OCR_HCS, MMC_RESPONSE_R3,
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200345 &resp_data[0]);
346 if (ret != 0) {
347 return ret;
348 }
349
Yann Gautierde6959e2018-08-02 13:46:17 +0200350 if ((resp_data[0] & OCR_POWERUP) != 0U) {
351 mmc_ocr_value = resp_data[0];
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200352
Yann Gautierde6959e2018-08-02 13:46:17 +0200353 if ((mmc_ocr_value & OCR_HCS) != 0U) {
354 mmc_dev_info->mmc_dev_type = MMC_IS_SD_HC;
355 } else {
356 mmc_dev_info->mmc_dev_type = MMC_IS_SD;
357 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200358
Yann Gautierde6959e2018-08-02 13:46:17 +0200359 return 0;
360 }
361
362 mdelay(1);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200363 }
364
Yann Gautierde6959e2018-08-02 13:46:17 +0200365 ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
366
367 return -EIO;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200368}
369
Yann Gautierde6959e2018-08-02 13:46:17 +0200370static int mmc_reset_to_idle(void)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200371{
372 int ret;
Yann Gautierde6959e2018-08-02 13:46:17 +0200373
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200374 /* CMD0: reset to IDLE */
375 ret = mmc_send_cmd(MMC_CMD(0), 0, 0, NULL);
376 if (ret != 0) {
377 return ret;
378 }
379
Yann Gautierde6959e2018-08-02 13:46:17 +0200380 mdelay(2);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200381
Yann Gautierde6959e2018-08-02 13:46:17 +0200382 return 0;
383}
384
385static int mmc_send_op_cond(void)
386{
387 int ret, n;
388 unsigned int resp_data[4];
389
Yann Gautier4c7888a2018-11-29 15:43:37 +0100390 ret = mmc_reset_to_idle();
391 if (ret != 0) {
392 return ret;
393 };
Yann Gautierde6959e2018-08-02 13:46:17 +0200394
395 for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200396 ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE |
397 OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7,
Bryan O'Donoghuee62f4192018-08-15 15:59:07 +0100398 MMC_RESPONSE_R3, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200399 if (ret != 0) {
400 return ret;
401 }
402
Yann Gautierde6959e2018-08-02 13:46:17 +0200403 if ((resp_data[0] & OCR_POWERUP) != 0U) {
404 mmc_ocr_value = resp_data[0];
405 return 0;
406 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200407
Yann Gautierde6959e2018-08-02 13:46:17 +0200408 mdelay(1);
409 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200410
Yann Gautierde6959e2018-08-02 13:46:17 +0200411 ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
412
413 return -EIO;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200414}
415
416static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
417{
418 int ret;
419 unsigned int resp_data[4];
420
421 ops->init();
422
Yann Gautier4c7888a2018-11-29 15:43:37 +0100423 ret = mmc_reset_to_idle();
424 if (ret != 0) {
425 return ret;
426 };
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200427
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800428 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200429 ret = mmc_send_op_cond();
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800430 } else {
431 /* CMD8: Send Interface Condition Command */
432 ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200433 MMC_RESPONSE_R5, &resp_data[0]);
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800434
435 if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) {
436 ret = sd_send_op_cond();
437 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200438 }
439 if (ret != 0) {
440 return ret;
441 }
442
443 /* CMD2: Card Identification */
Shawn Guoab3b62b2018-09-28 14:21:01 +0800444 ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R2, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200445 if (ret != 0) {
446 return ret;
447 }
448
449 /* CMD3: Set Relative Address */
450 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
451 rca = MMC_FIX_RCA;
452 ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200453 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200454 if (ret != 0) {
455 return ret;
456 }
457 } else {
458 ret = mmc_send_cmd(MMC_CMD(3), 0,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200459 MMC_RESPONSE_R6, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200460 if (ret != 0) {
461 return ret;
462 }
463
464 rca = (resp_data[0] & 0xFFFF0000U) >> 16;
465 }
466
467 /* CMD9: CSD Register */
468 ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET,
Shawn Guoab3b62b2018-09-28 14:21:01 +0800469 MMC_RESPONSE_R2, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200470 if (ret != 0) {
471 return ret;
472 }
473
474 memcpy(&mmc_csd, &resp_data, sizeof(resp_data));
475
476 /* CMD7: Select Card */
477 ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200478 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200479 if (ret != 0) {
480 return ret;
481 }
482
483 do {
484 ret = mmc_device_state();
485 if (ret < 0) {
486 return ret;
487 }
488 } while (ret != MMC_STATE_TRAN);
489
Haojian Zhuangd618b272018-08-04 18:04:30 +0800490 ret = mmc_set_ios(clk, bus_width);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200491 if (ret != 0) {
492 return ret;
493 }
494
Haojian Zhuangd618b272018-08-04 18:04:30 +0800495 return mmc_fill_device_info();
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200496}
497
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800498size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200499{
500 int ret;
501 unsigned int cmd_idx, cmd_arg;
502
503 assert((ops != NULL) &&
504 (ops->read != NULL) &&
505 (size != 0U) &&
506 ((size & MMC_BLOCK_MASK) == 0U));
507
508 ret = ops->prepare(lba, buf, size);
509 if (ret != 0) {
510 return 0;
511 }
512
513 if (is_cmd23_enabled()) {
514 /* Set block count */
515 ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200516 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200517 if (ret != 0) {
518 return 0;
519 }
520
521 cmd_idx = MMC_CMD(18);
522 } else {
523 if (size > MMC_BLOCK_SIZE) {
524 cmd_idx = MMC_CMD(18);
525 } else {
526 cmd_idx = MMC_CMD(17);
527 }
528 }
529
530 if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) &&
531 (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) {
532 cmd_arg = lba * MMC_BLOCK_SIZE;
533 } else {
534 cmd_arg = lba;
535 }
536
Yann Gautierf2e8b162018-09-28 16:48:37 +0200537 ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200538 if (ret != 0) {
539 return 0;
540 }
541
542 ret = ops->read(lba, buf, size);
543 if (ret != 0) {
544 return 0;
545 }
546
547 /* Wait buffer empty */
548 do {
549 ret = mmc_device_state();
550 if (ret < 0) {
551 return 0;
552 }
553 } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA));
554
555 if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100556 ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200557 if (ret != 0) {
558 return 0;
559 }
560 }
561
562 return size;
563}
564
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800565size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200566{
567 int ret;
568 unsigned int cmd_idx, cmd_arg;
569
570 assert((ops != NULL) &&
571 (ops->write != NULL) &&
572 (size != 0U) &&
573 ((buf & MMC_BLOCK_MASK) == 0U) &&
574 ((size & MMC_BLOCK_MASK) == 0U));
575
576 ret = ops->prepare(lba, buf, size);
577 if (ret != 0) {
578 return 0;
579 }
580
581 if (is_cmd23_enabled()) {
582 /* Set block count */
583 ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200584 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200585 if (ret != 0) {
586 return 0;
587 }
588
589 cmd_idx = MMC_CMD(25);
590 } else {
591 if (size > MMC_BLOCK_SIZE) {
592 cmd_idx = MMC_CMD(25);
593 } else {
594 cmd_idx = MMC_CMD(24);
595 }
596 }
597
598 if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) {
599 cmd_arg = lba * MMC_BLOCK_SIZE;
600 } else {
601 cmd_arg = lba;
602 }
603
Yann Gautierf2e8b162018-09-28 16:48:37 +0200604 ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200605 if (ret != 0) {
606 return 0;
607 }
608
609 ret = ops->write(lba, buf, size);
610 if (ret != 0) {
611 return 0;
612 }
613
614 /* Wait buffer empty */
615 do {
616 ret = mmc_device_state();
617 if (ret < 0) {
618 return 0;
619 }
620 } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV));
621
622 if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100623 ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200624 if (ret != 0) {
625 return 0;
626 }
627 }
628
629 return size;
630}
631
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800632size_t mmc_erase_blocks(int lba, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200633{
634 int ret;
635
636 assert(ops != NULL);
637 assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U));
638
Yann Gautierf2e8b162018-09-28 16:48:37 +0200639 ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200640 if (ret != 0) {
641 return 0;
642 }
643
644 ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200645 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200646 if (ret != 0) {
647 return 0;
648 }
649
Yann Gautierf2e8b162018-09-28 16:48:37 +0200650 ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200651 if (ret != 0) {
652 return 0;
653 }
654
655 do {
656 ret = mmc_device_state();
657 if (ret < 0) {
658 return 0;
659 }
660 } while (ret != MMC_STATE_TRAN);
661
662 return size;
663}
664
665static inline void mmc_rpmb_enable(void)
666{
667 mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
668 PART_CFG_BOOT_PARTITION1_ENABLE |
669 PART_CFG_PARTITION1_ACCESS);
670}
671
672static inline void mmc_rpmb_disable(void)
673{
674 mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
675 PART_CFG_BOOT_PARTITION1_ENABLE);
676}
677
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800678size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200679{
680 size_t size_read;
681
682 mmc_rpmb_enable();
683 size_read = mmc_read_blocks(lba, buf, size);
684 mmc_rpmb_disable();
685
686 return size_read;
687}
688
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800689size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200690{
691 size_t size_written;
692
693 mmc_rpmb_enable();
694 size_written = mmc_write_blocks(lba, buf, size);
695 mmc_rpmb_disable();
696
697 return size_written;
698}
699
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800700size_t mmc_rpmb_erase_blocks(int lba, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200701{
702 size_t size_erased;
703
704 mmc_rpmb_enable();
705 size_erased = mmc_erase_blocks(lba, size);
706 mmc_rpmb_disable();
707
708 return size_erased;
709}
710
711int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk,
712 unsigned int width, unsigned int flags,
713 struct mmc_device_info *device_info)
714{
715 assert((ops_ptr != NULL) &&
716 (ops_ptr->init != NULL) &&
717 (ops_ptr->send_cmd != NULL) &&
718 (ops_ptr->set_ios != NULL) &&
719 (ops_ptr->prepare != NULL) &&
720 (ops_ptr->read != NULL) &&
721 (ops_ptr->write != NULL) &&
722 (device_info != NULL) &&
723 (clk != 0) &&
724 ((width == MMC_BUS_WIDTH_1) ||
725 (width == MMC_BUS_WIDTH_4) ||
726 (width == MMC_BUS_WIDTH_8) ||
727 (width == MMC_BUS_WIDTH_DDR_4) ||
728 (width == MMC_BUS_WIDTH_DDR_8)));
729
730 ops = ops_ptr;
731 mmc_flags = flags;
732 mmc_dev_info = device_info;
733
734 return mmc_enumerate(clk, width);
735}