blob: 02bf770e559e40c01b869217904317c7b14e2129 [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
9#include <arch_helpers.h>
10#include <assert.h>
11#include <debug.h>
Yann Gautierde6959e2018-08-02 13:46:17 +020012#include <delay_timer.h>
Yann Gautier1e5e85a2018-07-03 18:32:12 +020013#include <errno.h>
14#include <mmc.h>
15#include <stdbool.h>
16#include <string.h>
17#include <utils.h>
18
19#define MMC_DEFAULT_MAX_RETRIES 5
20#define SEND_OP_COND_MAX_RETRIES 100
21
22#define MULT_BY_512K_SHIFT 19
23
24static const struct mmc_ops *ops;
25static unsigned int mmc_ocr_value;
26static struct mmc_csd_emmc mmc_csd;
Haojian Zhuangdf7271c2018-08-02 14:50:12 +080027static unsigned char mmc_ext_csd[512] __aligned(16);
Yann Gautier1e5e85a2018-07-03 18:32:12 +020028static unsigned int mmc_flags;
29static struct mmc_device_info *mmc_dev_info;
30static unsigned int rca;
31
32static const unsigned char tran_speed_base[16] = {
33 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80
34};
35
36static const unsigned char sd_tran_speed_base[16] = {
37 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
38};
39
40static bool is_cmd23_enabled(void)
41{
42 return ((mmc_flags & MMC_FLAG_CMD23) != 0U);
43}
44
45static int mmc_send_cmd(unsigned int idx, unsigned int arg,
46 unsigned int r_type, unsigned int *r_data)
47{
48 struct mmc_cmd cmd;
49 int ret;
50
51 zeromem(&cmd, sizeof(struct mmc_cmd));
52
53 cmd.cmd_idx = idx;
54 cmd.cmd_arg = arg;
55 cmd.resp_type = r_type;
56
57 ret = ops->send_cmd(&cmd);
58
59 if ((ret == 0) && (r_data != NULL)) {
60 int i;
61
62 for (i = 0; i < 4; i++) {
63 *r_data = cmd.resp_data[i];
64 r_data++;
65 }
66 }
67
68 if (ret != 0) {
69 VERBOSE("Send command %u error: %d\n", idx, ret);
70 }
71
72 return ret;
73}
74
75static int mmc_device_state(void)
76{
77 int retries = MMC_DEFAULT_MAX_RETRIES;
78 unsigned int resp_data[4];
79
80 do {
81 int ret;
82
83 if (retries == 0) {
84 ERROR("CMD13 failed after %d retries\n",
85 MMC_DEFAULT_MAX_RETRIES);
86 return -EIO;
87 }
88
89 ret = mmc_send_cmd(MMC_CMD(13), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +020090 MMC_RESPONSE_R1, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +020091 if (ret != 0) {
92 return ret;
93 }
94
95 if ((resp_data[0] & STATUS_SWITCH_ERROR) != 0U) {
96 return -EIO;
97 }
98
99 retries--;
100 } while ((resp_data[0] & STATUS_READY_FOR_DATA) == 0U);
101
102 return MMC_GET_STATE(resp_data[0]);
103}
104
105static int mmc_set_ext_csd(unsigned int ext_cmd, unsigned int value)
106{
107 int ret;
108
109 ret = mmc_send_cmd(MMC_CMD(6),
110 EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) |
111 EXTCSD_VALUE(value) | EXTCSD_CMD_SET_NORMAL,
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100112 MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200113 if (ret != 0) {
114 return ret;
115 }
116
117 do {
118 ret = mmc_device_state();
119 if (ret < 0) {
120 return ret;
121 }
122 } while (ret == MMC_STATE_PRG);
123
124 return 0;
125}
126
127static int mmc_sd_switch(unsigned int bus_width)
128{
129 int ret;
130 int retries = MMC_DEFAULT_MAX_RETRIES;
131 unsigned int scr[2] = { 0 };
132 unsigned int bus_width_arg = 0;
133
134 ret = ops->prepare(0, (uintptr_t)&scr, sizeof(scr));
135 if (ret != 0) {
136 return ret;
137 }
138
139 /* CMD55: Application Specific Command */
140 ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200141 MMC_RESPONSE_R5, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200142 if (ret != 0) {
143 return ret;
144 }
145
146 /* ACMD51: SEND_SCR */
147 do {
Yann Gautierf2e8b162018-09-28 16:48:37 +0200148 ret = mmc_send_cmd(MMC_ACMD(51), 0, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200149 if ((ret != 0) && (retries == 0)) {
150 ERROR("ACMD51 failed after %d retries (ret=%d)\n",
151 MMC_DEFAULT_MAX_RETRIES, ret);
152 return ret;
153 }
154
155 retries--;
156 } while (ret != 0);
157
158 ret = ops->read(0, (uintptr_t)&scr, sizeof(scr));
159 if (ret != 0) {
160 return ret;
161 }
162
163 if (((scr[0] & SD_SCR_BUS_WIDTH_4) != 0U) &&
164 (bus_width == MMC_BUS_WIDTH_4)) {
165 bus_width_arg = 2;
166 }
167
168 /* CMD55: Application Specific Command */
169 ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200170 MMC_RESPONSE_R5, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200171 if (ret != 0) {
172 return ret;
173 }
174
175 /* ACMD6: SET_BUS_WIDTH */
Yann Gautierf2e8b162018-09-28 16:48:37 +0200176 ret = mmc_send_cmd(MMC_ACMD(6), bus_width_arg, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200177 if (ret != 0) {
178 return ret;
179 }
180
181 do {
182 ret = mmc_device_state();
183 if (ret < 0) {
184 return ret;
185 }
186 } while (ret == MMC_STATE_PRG);
187
188 return 0;
189}
190
191static int mmc_set_ios(unsigned int clk, unsigned int bus_width)
192{
193 int ret;
194 unsigned int width = bus_width;
195
196 if (mmc_dev_info->mmc_dev_type != MMC_IS_EMMC) {
197 if (width == MMC_BUS_WIDTH_8) {
198 WARN("Wrong bus config for SD-card, force to 4\n");
199 width = MMC_BUS_WIDTH_4;
200 }
201 ret = mmc_sd_switch(width);
202 if (ret != 0) {
203 return ret;
204 }
205 } else if (mmc_csd.spec_vers == 4U) {
206 ret = mmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH,
207 (unsigned int)width);
208 if (ret != 0) {
209 return ret;
210 }
211 } else {
212 VERBOSE("Wrong MMC type or spec version\n");
213 }
214
215 return ops->set_ios(clk, width);
216}
217
218static int mmc_fill_device_info(void)
219{
220 unsigned long long c_size;
221 unsigned int speed_idx;
222 unsigned int nb_blocks;
223 unsigned int freq_unit;
Antonio Nino Diaz5d95e0a2018-08-10 13:04:02 +0100224 int ret = 0;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200225 struct mmc_csd_sd_v2 *csd_sd_v2;
226
227 switch (mmc_dev_info->mmc_dev_type) {
228 case MMC_IS_EMMC:
229 mmc_dev_info->block_size = MMC_BLOCK_SIZE;
230
231 ret = ops->prepare(0, (uintptr_t)&mmc_ext_csd,
232 sizeof(mmc_ext_csd));
233 if (ret != 0) {
234 return ret;
235 }
236
237 /* MMC CMD8: SEND_EXT_CSD */
Yann Gautierf2e8b162018-09-28 16:48:37 +0200238 ret = mmc_send_cmd(MMC_CMD(8), 0, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200239 if (ret != 0) {
240 return ret;
241 }
242
243 ret = ops->read(0, (uintptr_t)&mmc_ext_csd,
244 sizeof(mmc_ext_csd));
245 if (ret != 0) {
246 return ret;
247 }
248
Haojian Zhuang05274cb2018-11-21 09:19:49 +0800249 do {
250 ret = mmc_device_state();
251 if (ret < 0) {
252 return ret;
253 }
254 } while (ret != MMC_STATE_TRAN);
255
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200256 nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) |
257 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) |
258 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) |
259 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 3] << 24);
260
261 mmc_dev_info->device_size = (unsigned long long)nb_blocks *
262 mmc_dev_info->block_size;
263
264 break;
265
266 case MMC_IS_SD:
267 /*
268 * Use the same mmc_csd struct, as required fields here
269 * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC.
270 */
271 mmc_dev_info->block_size = BIT_32(mmc_csd.read_bl_len);
272
273 c_size = ((unsigned long long)mmc_csd.c_size_high << 2U) |
274 (unsigned long long)mmc_csd.c_size_low;
275 assert(c_size != 0xFFFU);
276
277 mmc_dev_info->device_size = (c_size + 1U) *
278 BIT_64(mmc_csd.c_size_mult + 2U) *
279 mmc_dev_info->block_size;
280
281 break;
282
283 case MMC_IS_SD_HC:
284 assert(mmc_csd.csd_structure == 1U);
285
286 mmc_dev_info->block_size = MMC_BLOCK_SIZE;
287
288 /* Need to use mmc_csd_sd_v2 struct */
289 csd_sd_v2 = (struct mmc_csd_sd_v2 *)&mmc_csd;
290 c_size = ((unsigned long long)csd_sd_v2->c_size_high << 16) |
291 (unsigned long long)csd_sd_v2->c_size_low;
292
293 mmc_dev_info->device_size = (c_size + 1U) << MULT_BY_512K_SHIFT;
294
295 break;
296
297 default:
298 ret = -EINVAL;
299 break;
300 }
301
302 if (ret != 0) {
303 return ret;
304 }
305
306 speed_idx = (mmc_csd.tran_speed & CSD_TRAN_SPEED_MULT_MASK) >>
307 CSD_TRAN_SPEED_MULT_SHIFT;
308
309 assert(speed_idx > 0U);
310
311 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
312 mmc_dev_info->max_bus_freq = tran_speed_base[speed_idx];
313 } else {
314 mmc_dev_info->max_bus_freq = sd_tran_speed_base[speed_idx];
315 }
316
317 freq_unit = mmc_csd.tran_speed & CSD_TRAN_SPEED_UNIT_MASK;
318 while (freq_unit != 0U) {
319 mmc_dev_info->max_bus_freq *= 10U;
320 --freq_unit;
321 }
322
323 mmc_dev_info->max_bus_freq *= 10000U;
324
325 return 0;
326}
327
328static int sd_send_op_cond(void)
329{
Yann Gautierde6959e2018-08-02 13:46:17 +0200330 int n;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200331 unsigned int resp_data[4];
332
Yann Gautierde6959e2018-08-02 13:46:17 +0200333 for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200334 int ret;
335
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200336 /* CMD55: Application Specific Command */
Yann Gautierf2e8b162018-09-28 16:48:37 +0200337 ret = mmc_send_cmd(MMC_CMD(55), 0, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200338 if (ret != 0) {
339 return ret;
340 }
341
342 /* ACMD41: SD_SEND_OP_COND */
Bryan O'Donoghuee62f4192018-08-15 15:59:07 +0100343 ret = mmc_send_cmd(MMC_ACMD(41), OCR_HCS, MMC_RESPONSE_R3,
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200344 &resp_data[0]);
345 if (ret != 0) {
346 return ret;
347 }
348
Yann Gautierde6959e2018-08-02 13:46:17 +0200349 if ((resp_data[0] & OCR_POWERUP) != 0U) {
350 mmc_ocr_value = resp_data[0];
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200351
Yann Gautierde6959e2018-08-02 13:46:17 +0200352 if ((mmc_ocr_value & OCR_HCS) != 0U) {
353 mmc_dev_info->mmc_dev_type = MMC_IS_SD_HC;
354 } else {
355 mmc_dev_info->mmc_dev_type = MMC_IS_SD;
356 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200357
Yann Gautierde6959e2018-08-02 13:46:17 +0200358 return 0;
359 }
360
361 mdelay(1);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200362 }
363
Yann Gautierde6959e2018-08-02 13:46:17 +0200364 ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
365
366 return -EIO;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200367}
368
Yann Gautierde6959e2018-08-02 13:46:17 +0200369static int mmc_reset_to_idle(void)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200370{
371 int ret;
Yann Gautierde6959e2018-08-02 13:46:17 +0200372
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200373 /* CMD0: reset to IDLE */
374 ret = mmc_send_cmd(MMC_CMD(0), 0, 0, NULL);
375 if (ret != 0) {
376 return ret;
377 }
378
Yann Gautierde6959e2018-08-02 13:46:17 +0200379 mdelay(2);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200380
Yann Gautierde6959e2018-08-02 13:46:17 +0200381 return 0;
382}
383
384static int mmc_send_op_cond(void)
385{
386 int ret, n;
387 unsigned int resp_data[4];
388
389 mmc_reset_to_idle();
390
391 for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200392 ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE |
393 OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7,
Bryan O'Donoghuee62f4192018-08-15 15:59:07 +0100394 MMC_RESPONSE_R3, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200395 if (ret != 0) {
396 return ret;
397 }
398
Yann Gautierde6959e2018-08-02 13:46:17 +0200399 if ((resp_data[0] & OCR_POWERUP) != 0U) {
400 mmc_ocr_value = resp_data[0];
401 return 0;
402 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200403
Yann Gautierde6959e2018-08-02 13:46:17 +0200404 mdelay(1);
405 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200406
Yann Gautierde6959e2018-08-02 13:46:17 +0200407 ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
408
409 return -EIO;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200410}
411
412static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
413{
414 int ret;
415 unsigned int resp_data[4];
416
417 ops->init();
418
Yann Gautierde6959e2018-08-02 13:46:17 +0200419 mmc_reset_to_idle();
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200420
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800421 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200422 ret = mmc_send_op_cond();
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800423 } else {
424 /* CMD8: Send Interface Condition Command */
425 ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200426 MMC_RESPONSE_R5, &resp_data[0]);
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800427
428 if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) {
429 ret = sd_send_op_cond();
430 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200431 }
432 if (ret != 0) {
433 return ret;
434 }
435
436 /* CMD2: Card Identification */
Shawn Guoab3b62b2018-09-28 14:21:01 +0800437 ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R2, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200438 if (ret != 0) {
439 return ret;
440 }
441
442 /* CMD3: Set Relative Address */
443 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
444 rca = MMC_FIX_RCA;
445 ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200446 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200447 if (ret != 0) {
448 return ret;
449 }
450 } else {
451 ret = mmc_send_cmd(MMC_CMD(3), 0,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200452 MMC_RESPONSE_R6, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200453 if (ret != 0) {
454 return ret;
455 }
456
457 rca = (resp_data[0] & 0xFFFF0000U) >> 16;
458 }
459
460 /* CMD9: CSD Register */
461 ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET,
Shawn Guoab3b62b2018-09-28 14:21:01 +0800462 MMC_RESPONSE_R2, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200463 if (ret != 0) {
464 return ret;
465 }
466
467 memcpy(&mmc_csd, &resp_data, sizeof(resp_data));
468
469 /* CMD7: Select Card */
470 ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200471 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200472 if (ret != 0) {
473 return ret;
474 }
475
476 do {
477 ret = mmc_device_state();
478 if (ret < 0) {
479 return ret;
480 }
481 } while (ret != MMC_STATE_TRAN);
482
Haojian Zhuangd618b272018-08-04 18:04:30 +0800483 ret = mmc_set_ios(clk, bus_width);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200484 if (ret != 0) {
485 return ret;
486 }
487
Haojian Zhuangd618b272018-08-04 18:04:30 +0800488 return mmc_fill_device_info();
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200489}
490
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800491size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200492{
493 int ret;
494 unsigned int cmd_idx, cmd_arg;
495
496 assert((ops != NULL) &&
497 (ops->read != NULL) &&
498 (size != 0U) &&
499 ((size & MMC_BLOCK_MASK) == 0U));
500
501 ret = ops->prepare(lba, buf, size);
502 if (ret != 0) {
503 return 0;
504 }
505
506 if (is_cmd23_enabled()) {
507 /* Set block count */
508 ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200509 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200510 if (ret != 0) {
511 return 0;
512 }
513
514 cmd_idx = MMC_CMD(18);
515 } else {
516 if (size > MMC_BLOCK_SIZE) {
517 cmd_idx = MMC_CMD(18);
518 } else {
519 cmd_idx = MMC_CMD(17);
520 }
521 }
522
523 if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) &&
524 (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) {
525 cmd_arg = lba * MMC_BLOCK_SIZE;
526 } else {
527 cmd_arg = lba;
528 }
529
Yann Gautierf2e8b162018-09-28 16:48:37 +0200530 ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200531 if (ret != 0) {
532 return 0;
533 }
534
535 ret = ops->read(lba, buf, size);
536 if (ret != 0) {
537 return 0;
538 }
539
540 /* Wait buffer empty */
541 do {
542 ret = mmc_device_state();
543 if (ret < 0) {
544 return 0;
545 }
546 } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA));
547
548 if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100549 ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200550 if (ret != 0) {
551 return 0;
552 }
553 }
554
555 return size;
556}
557
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800558size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200559{
560 int ret;
561 unsigned int cmd_idx, cmd_arg;
562
563 assert((ops != NULL) &&
564 (ops->write != NULL) &&
565 (size != 0U) &&
566 ((buf & MMC_BLOCK_MASK) == 0U) &&
567 ((size & MMC_BLOCK_MASK) == 0U));
568
569 ret = ops->prepare(lba, buf, size);
570 if (ret != 0) {
571 return 0;
572 }
573
574 if (is_cmd23_enabled()) {
575 /* Set block count */
576 ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200577 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200578 if (ret != 0) {
579 return 0;
580 }
581
582 cmd_idx = MMC_CMD(25);
583 } else {
584 if (size > MMC_BLOCK_SIZE) {
585 cmd_idx = MMC_CMD(25);
586 } else {
587 cmd_idx = MMC_CMD(24);
588 }
589 }
590
591 if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) {
592 cmd_arg = lba * MMC_BLOCK_SIZE;
593 } else {
594 cmd_arg = lba;
595 }
596
Yann Gautierf2e8b162018-09-28 16:48:37 +0200597 ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200598 if (ret != 0) {
599 return 0;
600 }
601
602 ret = ops->write(lba, buf, size);
603 if (ret != 0) {
604 return 0;
605 }
606
607 /* Wait buffer empty */
608 do {
609 ret = mmc_device_state();
610 if (ret < 0) {
611 return 0;
612 }
613 } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV));
614
615 if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100616 ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200617 if (ret != 0) {
618 return 0;
619 }
620 }
621
622 return size;
623}
624
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800625size_t mmc_erase_blocks(int lba, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200626{
627 int ret;
628
629 assert(ops != NULL);
630 assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U));
631
Yann Gautierf2e8b162018-09-28 16:48:37 +0200632 ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200633 if (ret != 0) {
634 return 0;
635 }
636
637 ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200638 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200639 if (ret != 0) {
640 return 0;
641 }
642
Yann Gautierf2e8b162018-09-28 16:48:37 +0200643 ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200644 if (ret != 0) {
645 return 0;
646 }
647
648 do {
649 ret = mmc_device_state();
650 if (ret < 0) {
651 return 0;
652 }
653 } while (ret != MMC_STATE_TRAN);
654
655 return size;
656}
657
658static inline void mmc_rpmb_enable(void)
659{
660 mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
661 PART_CFG_BOOT_PARTITION1_ENABLE |
662 PART_CFG_PARTITION1_ACCESS);
663}
664
665static inline void mmc_rpmb_disable(void)
666{
667 mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
668 PART_CFG_BOOT_PARTITION1_ENABLE);
669}
670
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800671size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200672{
673 size_t size_read;
674
675 mmc_rpmb_enable();
676 size_read = mmc_read_blocks(lba, buf, size);
677 mmc_rpmb_disable();
678
679 return size_read;
680}
681
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800682size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200683{
684 size_t size_written;
685
686 mmc_rpmb_enable();
687 size_written = mmc_write_blocks(lba, buf, size);
688 mmc_rpmb_disable();
689
690 return size_written;
691}
692
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800693size_t mmc_rpmb_erase_blocks(int lba, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200694{
695 size_t size_erased;
696
697 mmc_rpmb_enable();
698 size_erased = mmc_erase_blocks(lba, size);
699 mmc_rpmb_disable();
700
701 return size_erased;
702}
703
704int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk,
705 unsigned int width, unsigned int flags,
706 struct mmc_device_info *device_info)
707{
708 assert((ops_ptr != NULL) &&
709 (ops_ptr->init != NULL) &&
710 (ops_ptr->send_cmd != NULL) &&
711 (ops_ptr->set_ios != NULL) &&
712 (ops_ptr->prepare != NULL) &&
713 (ops_ptr->read != NULL) &&
714 (ops_ptr->write != NULL) &&
715 (device_info != NULL) &&
716 (clk != 0) &&
717 ((width == MMC_BUS_WIDTH_1) ||
718 (width == MMC_BUS_WIDTH_4) ||
719 (width == MMC_BUS_WIDTH_8) ||
720 (width == MMC_BUS_WIDTH_DDR_4) ||
721 (width == MMC_BUS_WIDTH_DDR_8)));
722
723 ops = ops_ptr;
724 mmc_flags = flags;
725 mmc_dev_info = device_info;
726
727 return mmc_enumerate(clk, width);
728}