Home | History | Annotate | Download | only in emmc
      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