blob: 1b6e96b076f6e766939c06e4227d962ed402df3a [file] [log] [blame]
Yann Gautier1e5e85a2018-07-03 18:32:12 +02001/*
Ahmad Fatoumee8f3422022-05-23 17:06:37 +02002 * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
Yann Gautier1e5e85a2018-07-03 18:32:12 +02003 *
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;
Yann Gautier0307b712019-06-12 15:55:37 +020028static struct sd_switch_status sd_switch_func_status;
Haojian Zhuangdf7271c2018-08-02 14:50:12 +080029static unsigned char mmc_ext_csd[512] __aligned(16);
Yann Gautier1e5e85a2018-07-03 18:32:12 +020030static unsigned int mmc_flags;
Yann Gautierd8b6b8e2021-03-22 14:02:54 +010031static struct mmc_device_info *mmc_dev_info;
Yann Gautier1e5e85a2018-07-03 18:32:12 +020032static unsigned int rca;
Tien Hock, Loh313e9002019-03-07 11:34:20 +080033static unsigned int scr[2]__aligned(16) = { 0 };
Yann Gautier1e5e85a2018-07-03 18:32:12 +020034
35static const unsigned char tran_speed_base[16] = {
36 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80
37};
38
39static const unsigned char sd_tran_speed_base[16] = {
40 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
41};
42
43static bool is_cmd23_enabled(void)
44{
45 return ((mmc_flags & MMC_FLAG_CMD23) != 0U);
46}
47
Yann Gautier0307b712019-06-12 15:55:37 +020048static bool is_sd_cmd6_enabled(void)
49{
50 return ((mmc_flags & MMC_FLAG_SD_CMD6) != 0U);
51}
52
Yann Gautier1e5e85a2018-07-03 18:32:12 +020053static int mmc_send_cmd(unsigned int idx, unsigned int arg,
54 unsigned int r_type, unsigned int *r_data)
55{
56 struct mmc_cmd cmd;
57 int ret;
58
59 zeromem(&cmd, sizeof(struct mmc_cmd));
60
61 cmd.cmd_idx = idx;
62 cmd.cmd_arg = arg;
63 cmd.resp_type = r_type;
64
65 ret = ops->send_cmd(&cmd);
66
67 if ((ret == 0) && (r_data != NULL)) {
68 int i;
69
70 for (i = 0; i < 4; i++) {
71 *r_data = cmd.resp_data[i];
72 r_data++;
73 }
74 }
75
76 if (ret != 0) {
77 VERBOSE("Send command %u error: %d\n", idx, ret);
78 }
79
80 return ret;
81}
82
83static int mmc_device_state(void)
84{
85 int retries = MMC_DEFAULT_MAX_RETRIES;
86 unsigned int resp_data[4];
87
88 do {
89 int ret;
90
91 if (retries == 0) {
92 ERROR("CMD13 failed after %d retries\n",
93 MMC_DEFAULT_MAX_RETRIES);
94 return -EIO;
95 }
96
97 ret = mmc_send_cmd(MMC_CMD(13), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +020098 MMC_RESPONSE_R1, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +020099 if (ret != 0) {
Tien Hock, Loh313e9002019-03-07 11:34:20 +0800100 retries--;
101 continue;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200102 }
103
104 if ((resp_data[0] & STATUS_SWITCH_ERROR) != 0U) {
105 return -EIO;
106 }
107
108 retries--;
109 } while ((resp_data[0] & STATUS_READY_FOR_DATA) == 0U);
110
111 return MMC_GET_STATE(resp_data[0]);
112}
113
Vyacheslav Yurkovb3d5f342021-03-30 08:16:20 +0200114static int mmc_send_part_switch_cmd(unsigned int part_config)
115{
116 int ret;
117 unsigned int part_time = 0;
118
119 ret = mmc_send_cmd(MMC_CMD(6),
120 EXTCSD_WRITE_BYTES |
121 EXTCSD_CMD(CMD_EXTCSD_PARTITION_CONFIG) |
122 EXTCSD_VALUE(part_config) |
123 EXTCSD_CMD_SET_NORMAL,
124 MMC_RESPONSE_R1B, NULL);
125 if (ret != 0) {
126 return ret;
127 }
128
129 /* Partition switch timing is in 10ms units */
130 part_time = mmc_ext_csd[CMD_EXTCSD_PART_SWITCH_TIME] * 10;
131
132 mdelay(part_time);
133
134 do {
135 ret = mmc_device_state();
136 if (ret < 0) {
137 return ret;
138 }
139 } while (ret == MMC_STATE_PRG);
140
141 return 0;
142}
143
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200144static int mmc_set_ext_csd(unsigned int ext_cmd, unsigned int value)
145{
146 int ret;
147
148 ret = mmc_send_cmd(MMC_CMD(6),
149 EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) |
150 EXTCSD_VALUE(value) | EXTCSD_CMD_SET_NORMAL,
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100151 MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200152 if (ret != 0) {
153 return ret;
154 }
155
156 do {
157 ret = mmc_device_state();
158 if (ret < 0) {
159 return ret;
160 }
161 } while (ret == MMC_STATE_PRG);
162
163 return 0;
164}
165
166static int mmc_sd_switch(unsigned int bus_width)
167{
168 int ret;
169 int retries = MMC_DEFAULT_MAX_RETRIES;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200170 unsigned int bus_width_arg = 0;
171
172 ret = ops->prepare(0, (uintptr_t)&scr, sizeof(scr));
173 if (ret != 0) {
174 return ret;
175 }
176
177 /* CMD55: Application Specific Command */
178 ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200179 MMC_RESPONSE_R5, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200180 if (ret != 0) {
181 return ret;
182 }
183
184 /* ACMD51: SEND_SCR */
185 do {
Yann Gautierf2e8b162018-09-28 16:48:37 +0200186 ret = mmc_send_cmd(MMC_ACMD(51), 0, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200187 if ((ret != 0) && (retries == 0)) {
188 ERROR("ACMD51 failed after %d retries (ret=%d)\n",
189 MMC_DEFAULT_MAX_RETRIES, ret);
190 return ret;
191 }
192
193 retries--;
194 } while (ret != 0);
195
196 ret = ops->read(0, (uintptr_t)&scr, sizeof(scr));
197 if (ret != 0) {
198 return ret;
199 }
200
201 if (((scr[0] & SD_SCR_BUS_WIDTH_4) != 0U) &&
202 (bus_width == MMC_BUS_WIDTH_4)) {
203 bus_width_arg = 2;
204 }
205
206 /* CMD55: Application Specific Command */
207 ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200208 MMC_RESPONSE_R5, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200209 if (ret != 0) {
210 return ret;
211 }
212
213 /* ACMD6: SET_BUS_WIDTH */
Yann Gautierf2e8b162018-09-28 16:48:37 +0200214 ret = mmc_send_cmd(MMC_ACMD(6), bus_width_arg, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200215 if (ret != 0) {
216 return ret;
217 }
218
219 do {
220 ret = mmc_device_state();
221 if (ret < 0) {
222 return ret;
223 }
224 } while (ret == MMC_STATE_PRG);
225
226 return 0;
227}
228
229static int mmc_set_ios(unsigned int clk, unsigned int bus_width)
230{
231 int ret;
232 unsigned int width = bus_width;
233
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100234 if (mmc_dev_info->mmc_dev_type != MMC_IS_EMMC) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200235 if (width == MMC_BUS_WIDTH_8) {
236 WARN("Wrong bus config for SD-card, force to 4\n");
237 width = MMC_BUS_WIDTH_4;
238 }
239 ret = mmc_sd_switch(width);
240 if (ret != 0) {
241 return ret;
242 }
243 } else if (mmc_csd.spec_vers == 4U) {
244 ret = mmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH,
245 (unsigned int)width);
246 if (ret != 0) {
247 return ret;
248 }
249 } else {
250 VERBOSE("Wrong MMC type or spec version\n");
251 }
252
253 return ops->set_ios(clk, width);
254}
255
256static int mmc_fill_device_info(void)
257{
258 unsigned long long c_size;
259 unsigned int speed_idx;
260 unsigned int nb_blocks;
261 unsigned int freq_unit;
Antonio Nino Diaz5d95e0a2018-08-10 13:04:02 +0100262 int ret = 0;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200263 struct mmc_csd_sd_v2 *csd_sd_v2;
264
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100265 switch (mmc_dev_info->mmc_dev_type) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200266 case MMC_IS_EMMC:
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100267 mmc_dev_info->block_size = MMC_BLOCK_SIZE;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200268
269 ret = ops->prepare(0, (uintptr_t)&mmc_ext_csd,
270 sizeof(mmc_ext_csd));
271 if (ret != 0) {
272 return ret;
273 }
274
275 /* MMC CMD8: SEND_EXT_CSD */
Yann Gautierf2e8b162018-09-28 16:48:37 +0200276 ret = mmc_send_cmd(MMC_CMD(8), 0, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200277 if (ret != 0) {
278 return ret;
279 }
280
281 ret = ops->read(0, (uintptr_t)&mmc_ext_csd,
282 sizeof(mmc_ext_csd));
283 if (ret != 0) {
284 return ret;
285 }
286
Haojian Zhuang05274cb2018-11-21 09:19:49 +0800287 do {
288 ret = mmc_device_state();
289 if (ret < 0) {
290 return ret;
291 }
292 } while (ret != MMC_STATE_TRAN);
293
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200294 nb_blocks = (mmc_ext_csd[CMD_EXTCSD_SEC_CNT] << 0) |
295 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 1] << 8) |
296 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 2] << 16) |
297 (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 3] << 24);
298
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100299 mmc_dev_info->device_size = (unsigned long long)nb_blocks *
300 mmc_dev_info->block_size;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200301
302 break;
303
304 case MMC_IS_SD:
305 /*
306 * Use the same mmc_csd struct, as required fields here
307 * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC.
308 */
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100309 mmc_dev_info->block_size = BIT_32(mmc_csd.read_bl_len);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200310
311 c_size = ((unsigned long long)mmc_csd.c_size_high << 2U) |
312 (unsigned long long)mmc_csd.c_size_low;
313 assert(c_size != 0xFFFU);
314
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100315 mmc_dev_info->device_size = (c_size + 1U) *
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200316 BIT_64(mmc_csd.c_size_mult + 2U) *
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100317 mmc_dev_info->block_size;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200318
319 break;
320
321 case MMC_IS_SD_HC:
322 assert(mmc_csd.csd_structure == 1U);
323
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100324 mmc_dev_info->block_size = MMC_BLOCK_SIZE;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200325
326 /* Need to use mmc_csd_sd_v2 struct */
327 csd_sd_v2 = (struct mmc_csd_sd_v2 *)&mmc_csd;
328 c_size = ((unsigned long long)csd_sd_v2->c_size_high << 16) |
329 (unsigned long long)csd_sd_v2->c_size_low;
330
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100331 mmc_dev_info->device_size = (c_size + 1U) << MULT_BY_512K_SHIFT;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200332
333 break;
334
335 default:
336 ret = -EINVAL;
337 break;
338 }
339
Yann Gautiere8eb33f2019-01-17 11:17:05 +0100340 if (ret < 0) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200341 return ret;
342 }
343
344 speed_idx = (mmc_csd.tran_speed & CSD_TRAN_SPEED_MULT_MASK) >>
345 CSD_TRAN_SPEED_MULT_SHIFT;
346
347 assert(speed_idx > 0U);
348
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100349 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
350 mmc_dev_info->max_bus_freq = tran_speed_base[speed_idx];
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200351 } else {
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100352 mmc_dev_info->max_bus_freq = sd_tran_speed_base[speed_idx];
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200353 }
354
355 freq_unit = mmc_csd.tran_speed & CSD_TRAN_SPEED_UNIT_MASK;
356 while (freq_unit != 0U) {
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100357 mmc_dev_info->max_bus_freq *= 10U;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200358 --freq_unit;
359 }
360
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100361 mmc_dev_info->max_bus_freq *= 10000U;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200362
363 return 0;
364}
365
Yann Gautier0307b712019-06-12 15:55:37 +0200366static int sd_switch(unsigned int mode, unsigned char group,
367 unsigned char func)
368{
369 unsigned int group_shift = (group - 1U) * 4U;
370 unsigned int group_mask = GENMASK(group_shift + 3U, group_shift);
371 unsigned int arg;
372 int ret;
373
374 ret = ops->prepare(0, (uintptr_t)&sd_switch_func_status,
375 sizeof(sd_switch_func_status));
376 if (ret != 0) {
377 return ret;
378 }
379
380 /* MMC CMD6: SWITCH_FUNC */
381 arg = mode | SD_SWITCH_ALL_GROUPS_MASK;
382 arg &= ~group_mask;
383 arg |= func << group_shift;
384 ret = mmc_send_cmd(MMC_CMD(6), arg, MMC_RESPONSE_R1, NULL);
385 if (ret != 0) {
386 return ret;
387 }
388
389 return ops->read(0, (uintptr_t)&sd_switch_func_status,
390 sizeof(sd_switch_func_status));
391}
392
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200393static int sd_send_op_cond(void)
394{
Yann Gautierde6959e2018-08-02 13:46:17 +0200395 int n;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200396 unsigned int resp_data[4];
397
Yann Gautierde6959e2018-08-02 13:46:17 +0200398 for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200399 int ret;
400
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200401 /* CMD55: Application Specific Command */
Yann Gautierf2e8b162018-09-28 16:48:37 +0200402 ret = mmc_send_cmd(MMC_CMD(55), 0, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200403 if (ret != 0) {
404 return ret;
405 }
406
407 /* ACMD41: SD_SEND_OP_COND */
Tien Hock, Loh313e9002019-03-07 11:34:20 +0800408 ret = mmc_send_cmd(MMC_ACMD(41), OCR_HCS |
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100409 mmc_dev_info->ocr_voltage, MMC_RESPONSE_R3,
Tien Hock, Loh313e9002019-03-07 11:34:20 +0800410 &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200411 if (ret != 0) {
412 return ret;
413 }
414
Yann Gautierde6959e2018-08-02 13:46:17 +0200415 if ((resp_data[0] & OCR_POWERUP) != 0U) {
416 mmc_ocr_value = resp_data[0];
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200417
Yann Gautierde6959e2018-08-02 13:46:17 +0200418 if ((mmc_ocr_value & OCR_HCS) != 0U) {
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100419 mmc_dev_info->mmc_dev_type = MMC_IS_SD_HC;
Yann Gautierde6959e2018-08-02 13:46:17 +0200420 } else {
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100421 mmc_dev_info->mmc_dev_type = MMC_IS_SD;
Yann Gautierde6959e2018-08-02 13:46:17 +0200422 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200423
Yann Gautierde6959e2018-08-02 13:46:17 +0200424 return 0;
425 }
426
Yann Gautier38d80352019-08-16 16:49:41 +0200427 mdelay(10);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200428 }
429
Yann Gautierde6959e2018-08-02 13:46:17 +0200430 ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
431
432 return -EIO;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200433}
434
Yann Gautierde6959e2018-08-02 13:46:17 +0200435static int mmc_reset_to_idle(void)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200436{
437 int ret;
Yann Gautierde6959e2018-08-02 13:46:17 +0200438
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200439 /* CMD0: reset to IDLE */
440 ret = mmc_send_cmd(MMC_CMD(0), 0, 0, NULL);
441 if (ret != 0) {
442 return ret;
443 }
444
Yann Gautierde6959e2018-08-02 13:46:17 +0200445 mdelay(2);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200446
Yann Gautierde6959e2018-08-02 13:46:17 +0200447 return 0;
448}
449
450static int mmc_send_op_cond(void)
451{
452 int ret, n;
453 unsigned int resp_data[4];
454
Yann Gautier4c7888a2018-11-29 15:43:37 +0100455 ret = mmc_reset_to_idle();
456 if (ret != 0) {
457 return ret;
Yann Gautiere77be522021-03-23 13:30:43 +0100458 }
Yann Gautierde6959e2018-08-02 13:46:17 +0200459
460 for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200461 ret = mmc_send_cmd(MMC_CMD(1), OCR_SECTOR_MODE |
462 OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7,
Bryan O'Donoghuee62f4192018-08-15 15:59:07 +0100463 MMC_RESPONSE_R3, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200464 if (ret != 0) {
465 return ret;
466 }
467
Yann Gautierde6959e2018-08-02 13:46:17 +0200468 if ((resp_data[0] & OCR_POWERUP) != 0U) {
469 mmc_ocr_value = resp_data[0];
470 return 0;
471 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200472
Joakim Bech8428a042018-12-18 10:09:02 +0100473 mdelay(10);
Yann Gautierde6959e2018-08-02 13:46:17 +0200474 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200475
Yann Gautierde6959e2018-08-02 13:46:17 +0200476 ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES);
477
478 return -EIO;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200479}
480
481static int mmc_enumerate(unsigned int clk, unsigned int bus_width)
482{
483 int ret;
484 unsigned int resp_data[4];
485
486 ops->init();
487
Yann Gautier4c7888a2018-11-29 15:43:37 +0100488 ret = mmc_reset_to_idle();
489 if (ret != 0) {
490 return ret;
Yann Gautiere77be522021-03-23 13:30:43 +0100491 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200492
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100493 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200494 ret = mmc_send_op_cond();
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800495 } else {
496 /* CMD8: Send Interface Condition Command */
497 ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200498 MMC_RESPONSE_R5, &resp_data[0]);
Haojian Zhuanged59cd52018-08-02 14:48:17 +0800499
500 if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) {
501 ret = sd_send_op_cond();
502 }
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200503 }
504 if (ret != 0) {
505 return ret;
506 }
507
508 /* CMD2: Card Identification */
Shawn Guoab3b62b2018-09-28 14:21:01 +0800509 ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R2, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200510 if (ret != 0) {
511 return ret;
512 }
513
514 /* CMD3: Set Relative Address */
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100515 if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200516 rca = MMC_FIX_RCA;
517 ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200518 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200519 if (ret != 0) {
520 return ret;
521 }
522 } else {
523 ret = mmc_send_cmd(MMC_CMD(3), 0,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200524 MMC_RESPONSE_R6, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200525 if (ret != 0) {
526 return ret;
527 }
528
529 rca = (resp_data[0] & 0xFFFF0000U) >> 16;
530 }
531
532 /* CMD9: CSD Register */
533 ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET,
Shawn Guoab3b62b2018-09-28 14:21:01 +0800534 MMC_RESPONSE_R2, &resp_data[0]);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200535 if (ret != 0) {
536 return ret;
537 }
538
539 memcpy(&mmc_csd, &resp_data, sizeof(resp_data));
540
541 /* CMD7: Select Card */
542 ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200543 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200544 if (ret != 0) {
545 return ret;
546 }
547
548 do {
549 ret = mmc_device_state();
550 if (ret < 0) {
551 return ret;
552 }
553 } while (ret != MMC_STATE_TRAN);
554
Haojian Zhuangd618b272018-08-04 18:04:30 +0800555 ret = mmc_set_ios(clk, bus_width);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200556 if (ret != 0) {
557 return ret;
558 }
559
Yann Gautier0307b712019-06-12 15:55:37 +0200560 ret = mmc_fill_device_info();
561 if (ret != 0) {
562 return ret;
563 }
564
565 if (is_sd_cmd6_enabled() &&
566 (mmc_dev_info->mmc_dev_type == MMC_IS_SD_HC)) {
567 /* Try to switch to High Speed Mode */
568 ret = sd_switch(SD_SWITCH_FUNC_CHECK, 1U, 1U);
569 if (ret != 0) {
570 return ret;
571 }
572
573 if ((sd_switch_func_status.support_g1 & BIT(9)) == 0U) {
574 /* High speed not supported, keep default speed */
575 return 0;
576 }
577
578 ret = sd_switch(SD_SWITCH_FUNC_SWITCH, 1U, 1U);
579 if (ret != 0) {
580 return ret;
581 }
582
583 if ((sd_switch_func_status.sel_g2_g1 & 0x1U) == 0U) {
584 /* Cannot switch to high speed, keep default speed */
585 return 0;
586 }
587
588 mmc_dev_info->max_bus_freq = 50000000U;
589 ret = ops->set_ios(clk, bus_width);
590 }
591
592 return ret;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200593}
594
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800595size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200596{
597 int ret;
598 unsigned int cmd_idx, cmd_arg;
599
600 assert((ops != NULL) &&
601 (ops->read != NULL) &&
602 (size != 0U) &&
603 ((size & MMC_BLOCK_MASK) == 0U));
604
605 ret = ops->prepare(lba, buf, size);
606 if (ret != 0) {
607 return 0;
608 }
609
610 if (is_cmd23_enabled()) {
611 /* Set block count */
612 ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200613 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200614 if (ret != 0) {
615 return 0;
616 }
617
618 cmd_idx = MMC_CMD(18);
619 } else {
620 if (size > MMC_BLOCK_SIZE) {
621 cmd_idx = MMC_CMD(18);
622 } else {
623 cmd_idx = MMC_CMD(17);
624 }
625 }
626
627 if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) &&
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100628 (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) {
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200629 cmd_arg = lba * MMC_BLOCK_SIZE;
630 } else {
631 cmd_arg = lba;
632 }
633
Yann Gautierf2e8b162018-09-28 16:48:37 +0200634 ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200635 if (ret != 0) {
636 return 0;
637 }
638
639 ret = ops->read(lba, buf, size);
640 if (ret != 0) {
641 return 0;
642 }
643
644 /* Wait buffer empty */
645 do {
646 ret = mmc_device_state();
647 if (ret < 0) {
648 return 0;
649 }
650 } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA));
651
652 if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100653 ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200654 if (ret != 0) {
655 return 0;
656 }
657 }
658
659 return size;
660}
661
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800662size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200663{
664 int ret;
665 unsigned int cmd_idx, cmd_arg;
666
667 assert((ops != NULL) &&
668 (ops->write != NULL) &&
669 (size != 0U) &&
670 ((buf & MMC_BLOCK_MASK) == 0U) &&
671 ((size & MMC_BLOCK_MASK) == 0U));
672
673 ret = ops->prepare(lba, buf, size);
674 if (ret != 0) {
675 return 0;
676 }
677
678 if (is_cmd23_enabled()) {
679 /* Set block count */
680 ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200681 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200682 if (ret != 0) {
683 return 0;
684 }
685
686 cmd_idx = MMC_CMD(25);
687 } else {
688 if (size > MMC_BLOCK_SIZE) {
689 cmd_idx = MMC_CMD(25);
690 } else {
691 cmd_idx = MMC_CMD(24);
692 }
693 }
694
695 if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) {
696 cmd_arg = lba * MMC_BLOCK_SIZE;
697 } else {
698 cmd_arg = lba;
699 }
700
Yann Gautierf2e8b162018-09-28 16:48:37 +0200701 ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200702 if (ret != 0) {
703 return 0;
704 }
705
706 ret = ops->write(lba, buf, size);
707 if (ret != 0) {
708 return 0;
709 }
710
711 /* Wait buffer empty */
712 do {
713 ret = mmc_device_state();
714 if (ret < 0) {
715 return 0;
716 }
717 } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV));
718
719 if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) {
Bryan O'Donoghuee6b56cc2018-08-15 16:25:30 +0100720 ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200721 if (ret != 0) {
722 return 0;
723 }
724 }
725
726 return size;
727}
728
Haojian Zhuangd87f0b72018-08-02 14:49:51 +0800729size_t mmc_erase_blocks(int lba, size_t size)
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200730{
731 int ret;
732
733 assert(ops != NULL);
734 assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U));
735
Yann Gautierf2e8b162018-09-28 16:48:37 +0200736 ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200737 if (ret != 0) {
738 return 0;
739 }
740
741 ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U,
Yann Gautierf2e8b162018-09-28 16:48:37 +0200742 MMC_RESPONSE_R1, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200743 if (ret != 0) {
744 return 0;
745 }
746
Yann Gautierf2e8b162018-09-28 16:48:37 +0200747 ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R1B, NULL);
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200748 if (ret != 0) {
749 return 0;
750 }
751
752 do {
753 ret = mmc_device_state();
754 if (ret < 0) {
755 return 0;
756 }
757 } while (ret != MMC_STATE_TRAN);
758
759 return size;
760}
761
Vyacheslav Yurkovb3d5f342021-03-30 08:16:20 +0200762static int mmc_part_switch(unsigned int part_type)
763{
764 uint8_t part_config = mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG];
765
766 part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
767 part_config |= part_type;
768
769 return mmc_send_part_switch_cmd(part_config);
770}
771
772static unsigned char mmc_current_boot_part(void)
773{
774 return PART_CFG_CURRENT_BOOT_PARTITION(mmc_ext_csd[CMD_EXTCSD_PARTITION_CONFIG]);
775}
776
Ahmad Fatoumee8f3422022-05-23 17:06:37 +0200777int mmc_part_switch_current_boot(void)
Vyacheslav Yurkovb3d5f342021-03-30 08:16:20 +0200778{
Vyacheslav Yurkovb3d5f342021-03-30 08:16:20 +0200779 unsigned char current_boot_part = mmc_current_boot_part();
Ahmad Fatoumee8f3422022-05-23 17:06:37 +0200780 int ret;
Vyacheslav Yurkovb3d5f342021-03-30 08:16:20 +0200781
782 if (current_boot_part != 1U &&
783 current_boot_part != 2U) {
784 ERROR("Got unexpected value for active boot partition, %u\n", current_boot_part);
Ahmad Fatoumee8f3422022-05-23 17:06:37 +0200785 return -EIO;
Vyacheslav Yurkovb3d5f342021-03-30 08:16:20 +0200786 }
787
788 ret = mmc_part_switch(current_boot_part);
789 if (ret < 0) {
790 ERROR("Failed to switch to boot partition, %d\n", ret);
Ahmad Fatoumee8f3422022-05-23 17:06:37 +0200791 }
792
793 return ret;
794}
795
796int mmc_part_switch_user(void)
797{
798 int ret;
799
Ahmad Fatoumb61eb752022-05-31 10:03:04 +0200800 ret = mmc_part_switch(PART_CFG_BOOT_PARTITION_NO_ACCESS);
Ahmad Fatoumee8f3422022-05-23 17:06:37 +0200801 if (ret < 0) {
802 ERROR("Failed to switch to user partition, %d\n", ret);
803 }
804
805 return ret;
806}
807
808size_t mmc_boot_part_read_blocks(int lba, uintptr_t buf, size_t size)
809{
810 size_t size_read;
811 int ret;
812
813 ret = mmc_part_switch_current_boot();
814 if (ret < 0) {
Vyacheslav Yurkovb3d5f342021-03-30 08:16:20 +0200815 return 0;
816 }
817
818 size_read = mmc_read_blocks(lba, buf, size);
819
Ahmad Fatoumee8f3422022-05-23 17:06:37 +0200820 ret = mmc_part_switch_user();
Vyacheslav Yurkovb3d5f342021-03-30 08:16:20 +0200821 if (ret < 0) {
Vyacheslav Yurkovb3d5f342021-03-30 08:16:20 +0200822 return 0;
823 }
824
825 return size_read;
826}
827
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200828int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk,
829 unsigned int width, unsigned int flags,
830 struct mmc_device_info *device_info)
831{
832 assert((ops_ptr != NULL) &&
833 (ops_ptr->init != NULL) &&
834 (ops_ptr->send_cmd != NULL) &&
835 (ops_ptr->set_ios != NULL) &&
836 (ops_ptr->prepare != NULL) &&
837 (ops_ptr->read != NULL) &&
838 (ops_ptr->write != NULL) &&
839 (device_info != NULL) &&
840 (clk != 0) &&
841 ((width == MMC_BUS_WIDTH_1) ||
842 (width == MMC_BUS_WIDTH_4) ||
843 (width == MMC_BUS_WIDTH_8) ||
844 (width == MMC_BUS_WIDTH_DDR_4) ||
845 (width == MMC_BUS_WIDTH_DDR_8)));
846
847 ops = ops_ptr;
848 mmc_flags = flags;
Yann Gautierd8b6b8e2021-03-22 14:02:54 +0100849 mmc_dev_info = device_info;
Yann Gautier1e5e85a2018-07-03 18:32:12 +0200850
851 return mmc_enumerate(clk, width);
852}