1 /* 2 * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 * 6 * Defines a simple and generic interface to access eMMC device. 7 */ 8 9 #include <arch_helpers.h> 10 #include <assert.h> 11 #include <debug.h> 12 #include <emmc.h> 13 #include <errno.h> 14 #include <string.h> 15 #include <utils.h> 16 17 static const emmc_ops_t *ops; 18 static unsigned int emmc_ocr_value; 19 static emmc_csd_t emmc_csd; 20 static unsigned int emmc_flags; 21 22 static int is_cmd23_enabled(void) 23 { 24 return (!!(emmc_flags & EMMC_FLAG_CMD23)); 25 } 26 27 static int emmc_device_state(void) 28 { 29 emmc_cmd_t cmd; 30 int ret; 31 32 do { 33 zeromem(&cmd, sizeof(emmc_cmd_t)); 34 cmd.cmd_idx = EMMC_CMD13; 35 cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET; 36 cmd.resp_type = EMMC_RESPONSE_R1; 37 ret = ops->send_cmd(&cmd); 38 assert(ret == 0); 39 assert((cmd.resp_data[0] & STATUS_SWITCH_ERROR) == 0); 40 /* Ignore improbable errors in release builds */ 41 (void)ret; 42 } while ((cmd.resp_data[0] & STATUS_READY_FOR_DATA) == 0); 43 return EMMC_GET_STATE(cmd.resp_data[0]); 44 } 45 46 static void emmc_set_ext_csd(unsigned int ext_cmd, unsigned int value) 47 { 48 emmc_cmd_t cmd; 49 int ret, state; 50 51 zeromem(&cmd, sizeof(emmc_cmd_t)); 52 cmd.cmd_idx = EMMC_CMD6; 53 cmd.cmd_arg = EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) | 54 EXTCSD_VALUE(value) | 1; 55 ret = ops->send_cmd(&cmd); 56 assert(ret == 0); 57 58 /* wait to exit PRG state */ 59 do { 60 state = emmc_device_state(); 61 } while (state == EMMC_STATE_PRG); 62 /* Ignore improbable errors in release builds */ 63 (void)ret; 64 } 65 66 static void emmc_set_ios(int clk, int bus_width) 67 { 68 int ret; 69 70 /* set IO speed & IO bus width */ 71 if (emmc_csd.spec_vers == 4) 72 emmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH, bus_width); 73 ret = ops->set_ios(clk, bus_width); 74 assert(ret == 0); 75 /* Ignore improbable errors in release builds */ 76 (void)ret; 77 } 78 79 static int emmc_enumerate(int clk, int bus_width) 80 { 81 emmc_cmd_t cmd; 82 int ret, state; 83 84 ops->init(); 85 86 /* CMD0: reset to IDLE */ 87 zeromem(&cmd, sizeof(emmc_cmd_t)); 88 cmd.cmd_idx = EMMC_CMD0; 89 ret = ops->send_cmd(&cmd); 90 assert(ret == 0); 91 92 while (1) { 93 /* CMD1: get OCR register */ 94 zeromem(&cmd, sizeof(emmc_cmd_t)); 95 cmd.cmd_idx = EMMC_CMD1; 96 cmd.cmd_arg = OCR_SECTOR_MODE | OCR_VDD_MIN_2V7 | 97 OCR_VDD_MIN_1V7; 98 cmd.resp_type = EMMC_RESPONSE_R3; 99 ret = ops->send_cmd(&cmd); 100 assert(ret == 0); 101 emmc_ocr_value = cmd.resp_data[0]; 102 if (emmc_ocr_value & OCR_POWERUP) 103 break; 104 } 105 106 /* CMD2: Card Identification */ 107 zeromem(&cmd, sizeof(emmc_cmd_t)); 108 cmd.cmd_idx = EMMC_CMD2; 109 cmd.resp_type = EMMC_RESPONSE_R2; 110 ret = ops->send_cmd(&cmd); 111 assert(ret == 0); 112 113 /* CMD3: Set Relative Address */ 114 zeromem(&cmd, sizeof(emmc_cmd_t)); 115 cmd.cmd_idx = EMMC_CMD3; 116 cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET; 117 cmd.resp_type = EMMC_RESPONSE_R1; 118 ret = ops->send_cmd(&cmd); 119 assert(ret == 0); 120 121 /* CMD9: CSD Register */ 122 zeromem(&cmd, sizeof(emmc_cmd_t)); 123 cmd.cmd_idx = EMMC_CMD9; 124 cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET; 125 cmd.resp_type = EMMC_RESPONSE_R2; 126 ret = ops->send_cmd(&cmd); 127 assert(ret == 0); 128 memcpy(&emmc_csd, &cmd.resp_data, sizeof(cmd.resp_data)); 129 130 /* CMD7: Select Card */ 131 zeromem(&cmd, sizeof(emmc_cmd_t)); 132 cmd.cmd_idx = EMMC_CMD7; 133 cmd.cmd_arg = EMMC_FIX_RCA << RCA_SHIFT_OFFSET; 134 cmd.resp_type = EMMC_RESPONSE_R1; 135 ret = ops->send_cmd(&cmd); 136 assert(ret == 0); 137 /* wait to TRAN state */ 138 do { 139 state = emmc_device_state(); 140 } while (state != EMMC_STATE_TRAN); 141 142 emmc_set_ios(clk, bus_width); 143 return ret; 144 } 145 146 size_t emmc_read_blocks(int lba, uintptr_t buf, size_t size) 147 { 148 emmc_cmd_t cmd; 149 int ret; 150 151 assert((ops != 0) && 152 (ops->read != 0) && 153 ((buf & EMMC_BLOCK_MASK) == 0) && 154 ((size & EMMC_BLOCK_MASK) == 0)); 155 156 inv_dcache_range(buf, size); 157 ret = ops->prepare(lba, buf, size); 158 assert(ret == 0); 159 160 if (is_cmd23_enabled()) { 161 zeromem(&cmd, sizeof(emmc_cmd_t)); 162 /* set block count */ 163 cmd.cmd_idx = EMMC_CMD23; 164 cmd.cmd_arg = size / EMMC_BLOCK_SIZE; 165 cmd.resp_type = EMMC_RESPONSE_R1; 166 ret = ops->send_cmd(&cmd); 167 assert(ret == 0); 168 169 zeromem(&cmd, sizeof(emmc_cmd_t)); 170 cmd.cmd_idx = EMMC_CMD18; 171 } else { 172 if (size > EMMC_BLOCK_SIZE) 173 cmd.cmd_idx = EMMC_CMD18; 174 else 175 cmd.cmd_idx = EMMC_CMD17; 176 } 177 if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) 178 cmd.cmd_arg = lba * EMMC_BLOCK_SIZE; 179 else 180 cmd.cmd_arg = lba; 181 cmd.resp_type = EMMC_RESPONSE_R1; 182 ret = ops->send_cmd(&cmd); 183 assert(ret == 0); 184 185 ret = ops->read(lba, buf, size); 186 assert(ret == 0); 187 188 /* wait buffer empty */ 189 emmc_device_state(); 190 191 if (is_cmd23_enabled() == 0) { 192 if (size > EMMC_BLOCK_SIZE) { 193 zeromem(&cmd, sizeof(emmc_cmd_t)); 194 cmd.cmd_idx = EMMC_CMD12; 195 ret = ops->send_cmd(&cmd); 196 assert(ret == 0); 197 } 198 } 199 /* Ignore improbable errors in release builds */ 200 (void)ret; 201 return size; 202 } 203 204 size_t emmc_write_blocks(int lba, const uintptr_t buf, size_t size) 205 { 206 emmc_cmd_t cmd; 207 int ret; 208 209 assert((ops != 0) && 210 (ops->write != 0) && 211 ((buf & EMMC_BLOCK_MASK) == 0) && 212 ((size & EMMC_BLOCK_MASK) == 0)); 213 214 clean_dcache_range(buf, size); 215 ret = ops->prepare(lba, buf, size); 216 assert(ret == 0); 217 218 if (is_cmd23_enabled()) { 219 /* set block count */ 220 zeromem(&cmd, sizeof(emmc_cmd_t)); 221 cmd.cmd_idx = EMMC_CMD23; 222 cmd.cmd_arg = size / EMMC_BLOCK_SIZE; 223 cmd.resp_type = EMMC_RESPONSE_R1; 224 ret = ops->send_cmd(&cmd); 225 assert(ret == 0); 226 227 zeromem(&cmd, sizeof(emmc_cmd_t)); 228 cmd.cmd_idx = EMMC_CMD25; 229 } else { 230 zeromem(&cmd, sizeof(emmc_cmd_t)); 231 if (size > EMMC_BLOCK_SIZE) 232 cmd.cmd_idx = EMMC_CMD25; 233 else 234 cmd.cmd_idx = EMMC_CMD24; 235 } 236 if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) 237 cmd.cmd_arg = lba * EMMC_BLOCK_SIZE; 238 else 239 cmd.cmd_arg = lba; 240 cmd.resp_type = EMMC_RESPONSE_R1; 241 ret = ops->send_cmd(&cmd); 242 assert(ret == 0); 243 244 ret = ops->write(lba, buf, size); 245 assert(ret == 0); 246 247 /* wait buffer empty */ 248 emmc_device_state(); 249 250 if (is_cmd23_enabled() == 0) { 251 if (size > EMMC_BLOCK_SIZE) { 252 zeromem(&cmd, sizeof(emmc_cmd_t)); 253 cmd.cmd_idx = EMMC_CMD12; 254 ret = ops->send_cmd(&cmd); 255 assert(ret == 0); 256 } 257 } 258 /* Ignore improbable errors in release builds */ 259 (void)ret; 260 return size; 261 } 262 263 size_t emmc_erase_blocks(int lba, size_t size) 264 { 265 emmc_cmd_t cmd; 266 int ret, state; 267 268 assert(ops != 0); 269 assert((size != 0) && ((size % EMMC_BLOCK_SIZE) == 0)); 270 271 zeromem(&cmd, sizeof(emmc_cmd_t)); 272 cmd.cmd_idx = EMMC_CMD35; 273 cmd.cmd_arg = lba; 274 cmd.resp_type = EMMC_RESPONSE_R1; 275 ret = ops->send_cmd(&cmd); 276 assert(ret == 0); 277 278 zeromem(&cmd, sizeof(emmc_cmd_t)); 279 cmd.cmd_idx = EMMC_CMD36; 280 cmd.cmd_arg = lba + (size / EMMC_BLOCK_SIZE) - 1; 281 cmd.resp_type = EMMC_RESPONSE_R1; 282 ret = ops->send_cmd(&cmd); 283 assert(ret == 0); 284 285 zeromem(&cmd, sizeof(emmc_cmd_t)); 286 cmd.cmd_idx = EMMC_CMD38; 287 cmd.resp_type = EMMC_RESPONSE_R1B; 288 ret = ops->send_cmd(&cmd); 289 assert(ret == 0); 290 291 /* wait to TRAN state */ 292 do { 293 state = emmc_device_state(); 294 } while (state != EMMC_STATE_TRAN); 295 /* Ignore improbable errors in release builds */ 296 (void)ret; 297 return size; 298 } 299 300 static inline void emmc_rpmb_enable(void) 301 { 302 emmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG, 303 PART_CFG_BOOT_PARTITION1_ENABLE | 304 PART_CFG_PARTITION1_ACCESS); 305 } 306 307 static inline void emmc_rpmb_disable(void) 308 { 309 emmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG, 310 PART_CFG_BOOT_PARTITION1_ENABLE); 311 } 312 313 size_t emmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size) 314 { 315 size_t size_read; 316 317 emmc_rpmb_enable(); 318 size_read = emmc_read_blocks(lba, buf, size); 319 emmc_rpmb_disable(); 320 return size_read; 321 } 322 323 size_t emmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size) 324 { 325 size_t size_written; 326 327 emmc_rpmb_enable(); 328 size_written = emmc_write_blocks(lba, buf, size); 329 emmc_rpmb_disable(); 330 return size_written; 331 } 332 333 size_t emmc_rpmb_erase_blocks(int lba, size_t size) 334 { 335 size_t size_erased; 336 337 emmc_rpmb_enable(); 338 size_erased = emmc_erase_blocks(lba, size); 339 emmc_rpmb_disable(); 340 return size_erased; 341 } 342 343 void emmc_init(const emmc_ops_t *ops_ptr, int clk, int width, 344 unsigned int flags) 345 { 346 assert((ops_ptr != 0) && 347 (ops_ptr->init != 0) && 348 (ops_ptr->send_cmd != 0) && 349 (ops_ptr->set_ios != 0) && 350 (ops_ptr->prepare != 0) && 351 (ops_ptr->read != 0) && 352 (ops_ptr->write != 0) && 353 (clk != 0) && 354 ((width == EMMC_BUS_WIDTH_1) || 355 (width == EMMC_BUS_WIDTH_4) || 356 (width == EMMC_BUS_WIDTH_8))); 357 ops = ops_ptr; 358 emmc_flags = flags; 359 360 emmc_enumerate(clk, width); 361 } 362