blob: 3e722e3b6b77a00298995d956eaa1692c0860aae [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,
90 MMC_RESPONSE_R(1), &resp_data[0]);
91 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,
141 MMC_RESPONSE_R(1), NULL);
142 if (ret != 0) {
143 return ret;
144 }
145
146 /* ACMD51: SEND_SCR */
147 do {
148 ret = mmc_send_cmd(MMC_ACMD(51), 0, MMC_RESPONSE_R(1), NULL);
149 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,
170 MMC_RESPONSE_R(1), NULL);
171 if (ret != 0) {
172 return ret;
173 }
174
175 /* ACMD6: SET_BUS_WIDTH */
176 ret = mmc_send_cmd(MMC_ACMD(6), bus_width_arg, MMC_RESPONSE_R(1), NULL);
177 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 */
238 ret = mmc_send_cmd(MMC_CMD(8), 0, MMC_RESPONSE_R(1), NULL);
239 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
249 nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) |
250 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) |
251 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) |
252 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 3] << 24);
253
254 mmc_dev_info->device_size = (unsigned long long)nb_blocks *
255 mmc_dev_info->block_size;
256
257 break;
258
259 case MMC_IS_SD:
260 /*
261 * Use the same mmc_csd struct, as required fields here
262 * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC.
263 */
264 mmc_dev_info->block_size = BIT_32(mmc_csd.read_bl_len);
265
266 c_size = ((unsigned long long)mmc_csd.c_size_high << 2U) |
267 (unsigned long long)mmc_csd.c_size_low;
268 assert(c_size != 0xFFFU);
269
270 mmc_dev_info->device_size = (c_size + 1U) *
271 BIT_64(mmc_csd.c_size_mult + 2U) *
272 mmc_dev_info->block_size;
273
274 break;
275
276 case MMC_IS_SD_HC:
277 assert(mmc_csd.csd_structure == 1U);
278
279 mmc_dev_info->block_size = MMC_BLOCK_SIZE;
280
281 /* Need to use mmc_csd_sd_v2 struct */
282 csd_sd_v2 = (struct mmc_csd_sd_v2 *)&mmc_csd;
283 c_size = ((unsigned long long)csd_sd_v2->c_size_high << 16) |
284 (unsigned long long)csd_sd_v2->c_size_low;
285
286 mmc_dev_info->device_size = (c_size + 1U) << MULT_BY_512K_SHIFT;
287
288 break;
289
290 default:
291 ret = -EINVAL;
292 break;
293 }
294
295 if (ret != 0) {
296 return ret;
297 }
298
299 speed_idx = (mmc_csd.tran_speed & CSD_TRAN_SPEED_MULT_MASK) >>
300 CSD_TRAN_SPEED_MULT_SHIFT;
301
302 assert(speed_idx > 0U);
303
304 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
305 mmc_dev_info->max_bus_freq = tran_speed_base[speed_idx];
306 } else {
307 mmc_dev_info->max_bus_freq = sd_tran_speed_base[speed_idx];
308 }
309
310 freq_unit = mmc_csd.tran_speed & CSD_TRAN_SPEED_UNIT_MASK;
311 while (freq_unit != 0U) {
312 mmc_dev_info->max_bus_freq *= 10U;
313 --freq_unit;
314 }
315
316 mmc_dev_info->max_bus_freq *= 10000U;
317
318 return 0;
319}
320
321static int sd_send_op_cond(void)
322{
Yann Gautierde6959e2018-08-02 13:46:17 +0200323 int n;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200324 unsigned int resp_data[4];
325
Yann Gautierde6959e2018-08-02 13:46:17 +0200326 for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200327 int ret;
328
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200329 /* CMD55: Application Specific Command */
330 ret = mmc_send_cmd(MMC_CMD(55), 0, MMC_RESPONSE_R(1), NULL);
331 if (ret != 0) {
332 return ret;
333 }
334
335 /* ACMD41: SD_SEND_OP_COND */
Bryan O'Donoghuee62f4192018-08-15 15:59:07 +0100336 ret = mmc_send_cmd(MMC_ACMD(41), OCR_HCS, MMC_RESPONSE_R3,
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200337 &resp_data[0]);
338 if (ret != 0) {
339 return ret;
340 }
341
Yann Gautierde6959e2018-08-02 13:46:17 +0200342 if ((resp_data[0] & OCR_POWERUP) != 0U) {
343 mmc_ocr_value = resp_data[0];
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200344
Yann Gautierde6959e2018-08-02 13:46:17 +0200345 if ((mmc_ocr_value & OCR_HCS) != 0U) {
346 mmc_dev_info->mmc_dev_type = MMC_IS_SD_HC;
347 } else {
348 mmc_dev_info->mmc_dev_type = MMC_IS_SD;
349 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200350
Yann Gautierde6959e2018-08-02 13:46:17 +0200351 return 0;
352 }
353
354 mdelay(1);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200355 }
356
Yann Gautierde6959e2018-08-02 13:46:17 +0200357 ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
358
359 return -EIO;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200360}
361
Yann Gautierde6959e2018-08-02 13:46:17 +0200362static int mmc_reset_to_idle(void)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200363{
364 int ret;
Yann Gautierde6959e2018-08-02 13:46:17 +0200365
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200366 /* CMD0: reset to IDLE */
367 ret = mmc_send_cmd(MMC_CMD(0), 0, 0, NULL);
368 if (ret != 0) {
369 return ret;
370 }
371
Yann Gautierde6959e2018-08-02 13:46:17 +0200372 mdelay(2);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200373
Yann Gautierde6959e2018-08-02 13:46:17 +0200374 return 0;
375}
376
377static int mmc_send_op_cond(void)
378{
379 int ret, n;
380 unsigned int resp_data[4];
381
382 mmc_reset_to_idle();
383
384 for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200385 ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE |
386 OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7,
Bryan O'Donoghuee62f4192018-08-15 15:59:07 +0100387 MMC_RESPONSE_R3, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200388 if (ret != 0) {
389 return ret;
390 }
391
Yann Gautierde6959e2018-08-02 13:46:17 +0200392 if ((resp_data[0] & OCR_POWERUP) != 0U) {
393 mmc_ocr_value = resp_data[0];
394 return 0;
395 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200396
Yann Gautierde6959e2018-08-02 13:46:17 +0200397 mdelay(1);
398 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200399
Yann Gautierde6959e2018-08-02 13:46:17 +0200400 ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
401
402 return -EIO;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200403}
404
405static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
406{
407 int ret;
408 unsigned int resp_data[4];
409
410 ops->init();
411
Yann Gautierde6959e2018-08-02 13:46:17 +0200412 mmc_reset_to_idle();
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200413
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800414 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200415 ret = mmc_send_op_cond();
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800416 } else {
417 /* CMD8: Send Interface Condition Command */
418 ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN,
419 MMC_RESPONSE_R(7), &resp_data[0]);
420
421 if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) {
422 ret = sd_send_op_cond();
423 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200424 }
425 if (ret != 0) {
426 return ret;
427 }
428
429 /* CMD2: Card Identification */
Shawn Guoab3b62b2018-09-28 14:21:01 +0800430 ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R2, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200431 if (ret != 0) {
432 return ret;
433 }
434
435 /* CMD3: Set Relative Address */
436 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
437 rca = MMC_FIX_RCA;
438 ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET,
439 MMC_RESPONSE_R(1), NULL);
440 if (ret != 0) {
441 return ret;
442 }
443 } else {
444 ret = mmc_send_cmd(MMC_CMD(3), 0,
445 MMC_RESPONSE_R(6), &resp_data[0]);
446 if (ret != 0) {
447 return ret;
448 }
449
450 rca = (resp_data[0] & 0xFFFF0000U) >> 16;
451 }
452
453 /* CMD9: CSD Register */
454 ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET,
Shawn Guoab3b62b2018-09-28 14:21:01 +0800455 MMC_RESPONSE_R2, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200456 if (ret != 0) {
457 return ret;
458 }
459
460 memcpy(&mmc_csd, &resp_data, sizeof(resp_data));
461
462 /* CMD7: Select Card */
463 ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET,
464 MMC_RESPONSE_R(1), NULL);
465 if (ret != 0) {
466 return ret;
467 }
468
469 do {
470 ret = mmc_device_state();
471 if (ret < 0) {
472 return ret;
473 }
474 } while (ret != MMC_STATE_TRAN);
475
Haojian Zhuangd618b272018-08-04 18:04:30 +0800476 ret = mmc_set_ios(clk, bus_width);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200477 if (ret != 0) {
478 return ret;
479 }
480
Haojian Zhuangd618b272018-08-04 18:04:30 +0800481 return mmc_fill_device_info();
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200482}
483
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800484size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200485{
486 int ret;
487 unsigned int cmd_idx, cmd_arg;
488
489 assert((ops != NULL) &&
490 (ops->read != NULL) &&
491 (size != 0U) &&
492 ((size & MMC_BLOCK_MASK) == 0U));
493
494 ret = ops->prepare(lba, buf, size);
495 if (ret != 0) {
496 return 0;
497 }
498
499 if (is_cmd23_enabled()) {
500 /* Set block count */
501 ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
502 MMC_RESPONSE_R(1), NULL);
503 if (ret != 0) {
504 return 0;
505 }
506
507 cmd_idx = MMC_CMD(18);
508 } else {
509 if (size > MMC_BLOCK_SIZE) {
510 cmd_idx = MMC_CMD(18);
511 } else {
512 cmd_idx = MMC_CMD(17);
513 }
514 }
515
516 if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) &&
517 (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) {
518 cmd_arg = lba * MMC_BLOCK_SIZE;
519 } else {
520 cmd_arg = lba;
521 }
522
523 ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R(1), NULL);
524 if (ret != 0) {
525 return 0;
526 }
527
528 ret = ops->read(lba, buf, size);
529 if (ret != 0) {
530 return 0;
531 }
532
533 /* Wait buffer empty */
534 do {
535 ret = mmc_device_state();
536 if (ret < 0) {
537 return 0;
538 }
539 } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA));
540
541 if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100542 ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200543 if (ret != 0) {
544 return 0;
545 }
546 }
547
548 return size;
549}
550
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800551size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200552{
553 int ret;
554 unsigned int cmd_idx, cmd_arg;
555
556 assert((ops != NULL) &&
557 (ops->write != NULL) &&
558 (size != 0U) &&
559 ((buf & MMC_BLOCK_MASK) == 0U) &&
560 ((size & MMC_BLOCK_MASK) == 0U));
561
562 ret = ops->prepare(lba, buf, size);
563 if (ret != 0) {
564 return 0;
565 }
566
567 if (is_cmd23_enabled()) {
568 /* Set block count */
569 ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
570 MMC_RESPONSE_R(1), NULL);
571 if (ret != 0) {
572 return 0;
573 }
574
575 cmd_idx = MMC_CMD(25);
576 } else {
577 if (size > MMC_BLOCK_SIZE) {
578 cmd_idx = MMC_CMD(25);
579 } else {
580 cmd_idx = MMC_CMD(24);
581 }
582 }
583
584 if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) {
585 cmd_arg = lba * MMC_BLOCK_SIZE;
586 } else {
587 cmd_arg = lba;
588 }
589
590 ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R(1), NULL);
591 if (ret != 0) {
592 return 0;
593 }
594
595 ret = ops->write(lba, buf, size);
596 if (ret != 0) {
597 return 0;
598 }
599
600 /* Wait buffer empty */
601 do {
602 ret = mmc_device_state();
603 if (ret < 0) {
604 return 0;
605 }
606 } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV));
607
608 if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100609 ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200610 if (ret != 0) {
611 return 0;
612 }
613 }
614
615 return size;
616}
617
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800618size_t mmc_erase_blocks(int lba, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200619{
620 int ret;
621
622 assert(ops != NULL);
623 assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U));
624
625 ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R(1), NULL);
626 if (ret != 0) {
627 return 0;
628 }
629
630 ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U,
631 MMC_RESPONSE_R(1), NULL);
632 if (ret != 0) {
633 return 0;
634 }
635
636 ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R(0x1B), NULL);
637 if (ret != 0) {
638 return 0;
639 }
640
641 do {
642 ret = mmc_device_state();
643 if (ret < 0) {
644 return 0;
645 }
646 } while (ret != MMC_STATE_TRAN);
647
648 return size;
649}
650
651static inline void mmc_rpmb_enable(void)
652{
653 mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
654 PART_CFG_BOOT_PARTITION1_ENABLE |
655 PART_CFG_PARTITION1_ACCESS);
656}
657
658static inline void mmc_rpmb_disable(void)
659{
660 mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
661 PART_CFG_BOOT_PARTITION1_ENABLE);
662}
663
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800664size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200665{
666 size_t size_read;
667
668 mmc_rpmb_enable();
669 size_read = mmc_read_blocks(lba, buf, size);
670 mmc_rpmb_disable();
671
672 return size_read;
673}
674
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800675size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200676{
677 size_t size_written;
678
679 mmc_rpmb_enable();
680 size_written = mmc_write_blocks(lba, buf, size);
681 mmc_rpmb_disable();
682
683 return size_written;
684}
685
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800686size_t mmc_rpmb_erase_blocks(int lba, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200687{
688 size_t size_erased;
689
690 mmc_rpmb_enable();
691 size_erased = mmc_erase_blocks(lba, size);
692 mmc_rpmb_disable();
693
694 return size_erased;
695}
696
697int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk,
698 unsigned int width, unsigned int flags,
699 struct mmc_device_info *device_info)
700{
701 assert((ops_ptr != NULL) &&
702 (ops_ptr->init != NULL) &&
703 (ops_ptr->send_cmd != NULL) &&
704 (ops_ptr->set_ios != NULL) &&
705 (ops_ptr->prepare != NULL) &&
706 (ops_ptr->read != NULL) &&
707 (ops_ptr->write != NULL) &&
708 (device_info != NULL) &&
709 (clk != 0) &&
710 ((width == MMC_BUS_WIDTH_1) ||
711 (width == MMC_BUS_WIDTH_4) ||
712 (width == MMC_BUS_WIDTH_8) ||
713 (width == MMC_BUS_WIDTH_DDR_4) ||
714 (width == MMC_BUS_WIDTH_DDR_8)));
715
716 ops = ops_ptr;
717 mmc_flags = flags;
718 mmc_dev_info = device_info;
719
720 return mmc_enumerate(clk, width);
721}