emmc: support CMD23

Support CMD23. When CMD23 is used, CMD12 could be avoided.

Two scenarios:
1. CMD17 for single block, CMD18 + CMD12 for multiple blocks.
2. CMD23 + CMD18 for both single block and multiple blocks.

The emmc_init() should initialize whether CMD23 is supported
or not.

Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
This commit is contained in:
Haojian Zhuang 2016-08-02 20:51:27 +08:00
parent 3d99b17f60
commit 445b1e704e
2 changed files with 61 additions and 20 deletions

View File

@ -40,6 +40,12 @@
static const emmc_ops_t *ops;
static unsigned int emmc_ocr_value;
static emmc_csd_t emmc_csd;
static unsigned int emmc_flags;
static int is_cmd23_enabled(void)
{
return (!!(emmc_flags & EMMC_FLAG_CMD23));
}
static int emmc_device_state(void)
{
@ -174,11 +180,23 @@ size_t emmc_read_blocks(int lba, uintptr_t buf, size_t size)
ret = ops->prepare(lba, buf, size);
assert(ret == 0);
memset(&cmd, 0, sizeof(emmc_cmd_t));
if (size > EMMC_BLOCK_SIZE)
if (is_cmd23_enabled()) {
memset(&cmd, 0, sizeof(emmc_cmd_t));
/* set block count */
cmd.cmd_idx = EMMC_CMD23;
cmd.cmd_arg = size / EMMC_BLOCK_SIZE;
cmd.resp_type = EMMC_RESPONSE_R1;
ret = ops->send_cmd(&cmd);
assert(ret == 0);
memset(&cmd, 0, sizeof(emmc_cmd_t));
cmd.cmd_idx = EMMC_CMD18;
else
cmd.cmd_idx = EMMC_CMD17;
} else {
if (size > EMMC_BLOCK_SIZE)
cmd.cmd_idx = EMMC_CMD18;
else
cmd.cmd_idx = EMMC_CMD17;
}
if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE)
cmd.cmd_arg = lba * EMMC_BLOCK_SIZE;
else
@ -193,11 +211,13 @@ size_t emmc_read_blocks(int lba, uintptr_t buf, size_t size)
/* wait buffer empty */
emmc_device_state();
if (size > EMMC_BLOCK_SIZE) {
memset(&cmd, 0, sizeof(emmc_cmd_t));
cmd.cmd_idx = EMMC_CMD12;
ret = ops->send_cmd(&cmd);
assert(ret == 0);
if (is_cmd23_enabled() == 0) {
if (size > EMMC_BLOCK_SIZE) {
memset(&cmd, 0, sizeof(emmc_cmd_t));
cmd.cmd_idx = EMMC_CMD12;
ret = ops->send_cmd(&cmd);
assert(ret == 0);
}
}
/* Ignore improbable errors in release builds */
(void)ret;
@ -218,11 +238,24 @@ size_t emmc_write_blocks(int lba, const uintptr_t buf, size_t size)
ret = ops->prepare(lba, buf, size);
assert(ret == 0);
memset(&cmd, 0, sizeof(emmc_cmd_t));
if (size > EMMC_BLOCK_SIZE)
if (is_cmd23_enabled()) {
/* set block count */
memset(&cmd, 0, sizeof(emmc_cmd_t));
cmd.cmd_idx = EMMC_CMD23;
cmd.cmd_arg = size / EMMC_BLOCK_SIZE;
cmd.resp_type = EMMC_RESPONSE_R1;
ret = ops->send_cmd(&cmd);
assert(ret == 0);
memset(&cmd, 0, sizeof(emmc_cmd_t));
cmd.cmd_idx = EMMC_CMD25;
else
cmd.cmd_idx = EMMC_CMD24;
} else {
memset(&cmd, 0, sizeof(emmc_cmd_t));
if (size > EMMC_BLOCK_SIZE)
cmd.cmd_idx = EMMC_CMD25;
else
cmd.cmd_idx = EMMC_CMD24;
}
if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE)
cmd.cmd_arg = lba * EMMC_BLOCK_SIZE;
else
@ -237,11 +270,13 @@ size_t emmc_write_blocks(int lba, const uintptr_t buf, size_t size)
/* wait buffer empty */
emmc_device_state();
if (size > EMMC_BLOCK_SIZE) {
memset(&cmd, 0, sizeof(emmc_cmd_t));
cmd.cmd_idx = EMMC_CMD12;
ret = ops->send_cmd(&cmd);
assert(ret == 0);
if (is_cmd23_enabled() == 0) {
if (size > EMMC_BLOCK_SIZE) {
memset(&cmd, 0, sizeof(emmc_cmd_t));
cmd.cmd_idx = EMMC_CMD12;
ret = ops->send_cmd(&cmd);
assert(ret == 0);
}
}
/* Ignore improbable errors in release builds */
(void)ret;
@ -328,7 +363,8 @@ size_t emmc_rpmb_erase_blocks(int lba, size_t size)
return size_erased;
}
void emmc_init(const emmc_ops_t *ops_ptr, int clk, int width)
void emmc_init(const emmc_ops_t *ops_ptr, int clk, int width,
unsigned int flags)
{
assert((ops_ptr != 0) &&
(ops_ptr->init != 0) &&
@ -342,6 +378,7 @@ void emmc_init(const emmc_ops_t *ops_ptr, int clk, int width)
(width == EMMC_BUS_WIDTH_4) ||
(width == EMMC_BUS_WIDTH_8)));
ops = ops_ptr;
emmc_flags = flags;
emmc_enumerate(clk, width);
}

View File

@ -49,6 +49,7 @@
#define EMMC_CMD13 13
#define EMMC_CMD17 17
#define EMMC_CMD18 18
#define EMMC_CMD23 23
#define EMMC_CMD24 24
#define EMMC_CMD25 25
#define EMMC_CMD35 35
@ -111,6 +112,8 @@
#define EMMC_STATE_BTST 9
#define EMMC_STATE_SLP 10
#define EMMC_FLAG_CMD23 (1 << 0)
typedef struct emmc_cmd {
unsigned int cmd_idx;
unsigned int cmd_arg;
@ -177,6 +180,7 @@ size_t emmc_erase_blocks(int lba, size_t size);
size_t emmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size);
size_t emmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size);
size_t emmc_rpmb_erase_blocks(int lba, size_t size);
void emmc_init(const emmc_ops_t *ops, int clk, int bus_width);
void emmc_init(const emmc_ops_t *ops, int clk, int bus_width,
unsigned int flags);
#endif /* __EMMC_H__ */