blob: 4160003c8f6150dfbe69bcbef89b2d16d1a3320c [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
Yann Gautier4c7888a2018-11-29 15:43:37 +0100389 ret = mmc_reset_to_idle();
390 if (ret != 0) {
391 return ret;
392 };
Yann Gautierde6959e2018-08-02 13:46:17 +0200393
394 for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200395 ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE |
396 OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7,
Bryan O'Donoghuee62f4192018-08-15 15:59:07 +0100397 MMC_RESPONSE_R3, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200398 if (ret != 0) {
399 return ret;
400 }
401
Yann Gautierde6959e2018-08-02 13:46:17 +0200402 if ((resp_data[0] & OCR_POWERUP) != 0U) {
403 mmc_ocr_value = resp_data[0];
404 return 0;
405 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200406
Yann Gautierde6959e2018-08-02 13:46:17 +0200407 mdelay(1);
408 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200409
Yann Gautierde6959e2018-08-02 13:46:17 +0200410 ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
411
412 return -EIO;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200413}
414
415static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
416{
417 int ret;
418 unsigned int resp_data[4];
419
420 ops->init();
421
Yann Gautier4c7888a2018-11-29 15:43:37 +0100422 ret = mmc_reset_to_idle();
423 if (ret != 0) {
424 return ret;
425 };
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200426
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800427 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200428 ret = mmc_send_op_cond();
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800429 } else {
430 /* CMD8: Send Interface Condition Command */
431 ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200432 MMC_RESPONSE_R5, &resp_data[0]);
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800433
434 if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) {
435 ret = sd_send_op_cond();
436 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200437 }
438 if (ret != 0) {
439 return ret;
440 }
441
442 /* CMD2: Card Identification */
Shawn Guoab3b62b2018-09-28 14:21:01 +0800443 ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R2, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200444 if (ret != 0) {
445 return ret;
446 }
447
448 /* CMD3: Set Relative Address */
449 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
450 rca = MMC_FIX_RCA;
451 ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200452 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200453 if (ret != 0) {
454 return ret;
455 }
456 } else {
457 ret = mmc_send_cmd(MMC_CMD(3), 0,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200458 MMC_RESPONSE_R6, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200459 if (ret != 0) {
460 return ret;
461 }
462
463 rca = (resp_data[0] & 0xFFFF0000U) >> 16;
464 }
465
466 /* CMD9: CSD Register */
467 ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET,
Shawn Guoab3b62b2018-09-28 14:21:01 +0800468 MMC_RESPONSE_R2, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200469 if (ret != 0) {
470 return ret;
471 }
472
473 memcpy(&mmc_csd, &resp_data, sizeof(resp_data));
474
475 /* CMD7: Select Card */
476 ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200477 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200478 if (ret != 0) {
479 return ret;
480 }
481
482 do {
483 ret = mmc_device_state();
484 if (ret < 0) {
485 return ret;
486 }
487 } while (ret != MMC_STATE_TRAN);
488
Haojian Zhuangd618b272018-08-04 18:04:30 +0800489 ret = mmc_set_ios(clk, bus_width);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200490 if (ret != 0) {
491 return ret;
492 }
493
Haojian Zhuangd618b272018-08-04 18:04:30 +0800494 return mmc_fill_device_info();
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200495}
496
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800497size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200498{
499 int ret;
500 unsigned int cmd_idx, cmd_arg;
501
502 assert((ops != NULL) &&
503 (ops->read != NULL) &&
504 (size != 0U) &&
505 ((size & MMC_BLOCK_MASK) == 0U));
506
507 ret = ops->prepare(lba, buf, size);
508 if (ret != 0) {
509 return 0;
510 }
511
512 if (is_cmd23_enabled()) {
513 /* Set block count */
514 ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200515 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200516 if (ret != 0) {
517 return 0;
518 }
519
520 cmd_idx = MMC_CMD(18);
521 } else {
522 if (size > MMC_BLOCK_SIZE) {
523 cmd_idx = MMC_CMD(18);
524 } else {
525 cmd_idx = MMC_CMD(17);
526 }
527 }
528
529 if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) &&
530 (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) {
531 cmd_arg = lba * MMC_BLOCK_SIZE;
532 } else {
533 cmd_arg = lba;
534 }
535
Yann Gautierf2e8b162018-09-28 16:48:37 +0200536 ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200537 if (ret != 0) {
538 return 0;
539 }
540
541 ret = ops->read(lba, buf, size);
542 if (ret != 0) {
543 return 0;
544 }
545
546 /* Wait buffer empty */
547 do {
548 ret = mmc_device_state();
549 if (ret < 0) {
550 return 0;
551 }
552 } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA));
553
554 if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100555 ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200556 if (ret != 0) {
557 return 0;
558 }
559 }
560
561 return size;
562}
563
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800564size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200565{
566 int ret;
567 unsigned int cmd_idx, cmd_arg;
568
569 assert((ops != NULL) &&
570 (ops->write != NULL) &&
571 (size != 0U) &&
572 ((buf & MMC_BLOCK_MASK) == 0U) &&
573 ((size & MMC_BLOCK_MASK) == 0U));
574
575 ret = ops->prepare(lba, buf, size);
576 if (ret != 0) {
577 return 0;
578 }
579
580 if (is_cmd23_enabled()) {
581 /* Set block count */
582 ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200583 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200584 if (ret != 0) {
585 return 0;
586 }
587
588 cmd_idx = MMC_CMD(25);
589 } else {
590 if (size > MMC_BLOCK_SIZE) {
591 cmd_idx = MMC_CMD(25);
592 } else {
593 cmd_idx = MMC_CMD(24);
594 }
595 }
596
597 if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) {
598 cmd_arg = lba * MMC_BLOCK_SIZE;
599 } else {
600 cmd_arg = lba;
601 }
602
Yann Gautierf2e8b162018-09-28 16:48:37 +0200603 ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200604 if (ret != 0) {
605 return 0;
606 }
607
608 ret = ops->write(lba, buf, size);
609 if (ret != 0) {
610 return 0;
611 }
612
613 /* Wait buffer empty */
614 do {
615 ret = mmc_device_state();
616 if (ret < 0) {
617 return 0;
618 }
619 } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV));
620
621 if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100622 ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200623 if (ret != 0) {
624 return 0;
625 }
626 }
627
628 return size;
629}
630
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800631size_t mmc_erase_blocks(int lba, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200632{
633 int ret;
634
635 assert(ops != NULL);
636 assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U));
637
Yann Gautierf2e8b162018-09-28 16:48:37 +0200638 ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200639 if (ret != 0) {
640 return 0;
641 }
642
643 ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200644 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200645 if (ret != 0) {
646 return 0;
647 }
648
Yann Gautierf2e8b162018-09-28 16:48:37 +0200649 ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200650 if (ret != 0) {
651 return 0;
652 }
653
654 do {
655 ret = mmc_device_state();
656 if (ret < 0) {
657 return 0;
658 }
659 } while (ret != MMC_STATE_TRAN);
660
661 return size;
662}
663
664static inline void mmc_rpmb_enable(void)
665{
666 mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
667 PART_CFG_BOOT_PARTITION1_ENABLE |
668 PART_CFG_PARTITION1_ACCESS);
669}
670
671static inline void mmc_rpmb_disable(void)
672{
673 mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG,
674 PART_CFG_BOOT_PARTITION1_ENABLE);
675}
676
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800677size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200678{
679 size_t size_read;
680
681 mmc_rpmb_enable();
682 size_read = mmc_read_blocks(lba, buf, size);
683 mmc_rpmb_disable();
684
685 return size_read;
686}
687
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800688size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200689{
690 size_t size_written;
691
692 mmc_rpmb_enable();
693 size_written = mmc_write_blocks(lba, buf, size);
694 mmc_rpmb_disable();
695
696 return size_written;
697}
698
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800699size_t mmc_rpmb_erase_blocks(int lba, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200700{
701 size_t size_erased;
702
703 mmc_rpmb_enable();
704 size_erased = mmc_erase_blocks(lba, size);
705 mmc_rpmb_disable();
706
707 return size_erased;
708}
709
710int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk,
711 unsigned int width, unsigned int flags,
712 struct mmc_device_info *device_info)
713{
714 assert((ops_ptr != NULL) &&
715 (ops_ptr->init != NULL) &&
716 (ops_ptr->send_cmd != NULL) &&
717 (ops_ptr->set_ios != NULL) &&
718 (ops_ptr->prepare != NULL) &&
719 (ops_ptr->read != NULL) &&
720 (ops_ptr->write != NULL) &&
721 (device_info != NULL) &&
722 (clk != 0) &&
723 ((width == MMC_BUS_WIDTH_1) ||
724 (width == MMC_BUS_WIDTH_4) ||
725 (width == MMC_BUS_WIDTH_8) ||
726 (width == MMC_BUS_WIDTH_DDR_4) ||
727 (width == MMC_BUS_WIDTH_DDR_8)));
728
729 ops = ops_ptr;
730 mmc_flags = flags;
731 mmc_dev_info = device_info;
732
733 return mmc_enumerate(clk, width);
734}