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:
parent
3d99b17f60
commit
445b1e704e
|
@ -40,6 +40,12 @@
|
||||||
static const emmc_ops_t *ops;
|
static const emmc_ops_t *ops;
|
||||||
static unsigned int emmc_ocr_value;
|
static unsigned int emmc_ocr_value;
|
||||||
static emmc_csd_t emmc_csd;
|
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)
|
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);
|
ret = ops->prepare(lba, buf, size);
|
||||||
assert(ret == 0);
|
assert(ret == 0);
|
||||||
|
|
||||||
memset(&cmd, 0, sizeof(emmc_cmd_t));
|
if (is_cmd23_enabled()) {
|
||||||
if (size > EMMC_BLOCK_SIZE)
|
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;
|
cmd.cmd_idx = EMMC_CMD18;
|
||||||
else
|
} else {
|
||||||
cmd.cmd_idx = EMMC_CMD17;
|
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)
|
if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE)
|
||||||
cmd.cmd_arg = lba * EMMC_BLOCK_SIZE;
|
cmd.cmd_arg = lba * EMMC_BLOCK_SIZE;
|
||||||
else
|
else
|
||||||
|
@ -193,11 +211,13 @@ size_t emmc_read_blocks(int lba, uintptr_t buf, size_t size)
|
||||||
/* wait buffer empty */
|
/* wait buffer empty */
|
||||||
emmc_device_state();
|
emmc_device_state();
|
||||||
|
|
||||||
if (size > EMMC_BLOCK_SIZE) {
|
if (is_cmd23_enabled() == 0) {
|
||||||
memset(&cmd, 0, sizeof(emmc_cmd_t));
|
if (size > EMMC_BLOCK_SIZE) {
|
||||||
cmd.cmd_idx = EMMC_CMD12;
|
memset(&cmd, 0, sizeof(emmc_cmd_t));
|
||||||
ret = ops->send_cmd(&cmd);
|
cmd.cmd_idx = EMMC_CMD12;
|
||||||
assert(ret == 0);
|
ret = ops->send_cmd(&cmd);
|
||||||
|
assert(ret == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Ignore improbable errors in release builds */
|
/* Ignore improbable errors in release builds */
|
||||||
(void)ret;
|
(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);
|
ret = ops->prepare(lba, buf, size);
|
||||||
assert(ret == 0);
|
assert(ret == 0);
|
||||||
|
|
||||||
memset(&cmd, 0, sizeof(emmc_cmd_t));
|
if (is_cmd23_enabled()) {
|
||||||
if (size > EMMC_BLOCK_SIZE)
|
/* 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;
|
cmd.cmd_idx = EMMC_CMD25;
|
||||||
else
|
} else {
|
||||||
cmd.cmd_idx = EMMC_CMD24;
|
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)
|
if ((emmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE)
|
||||||
cmd.cmd_arg = lba * EMMC_BLOCK_SIZE;
|
cmd.cmd_arg = lba * EMMC_BLOCK_SIZE;
|
||||||
else
|
else
|
||||||
|
@ -237,11 +270,13 @@ size_t emmc_write_blocks(int lba, const uintptr_t buf, size_t size)
|
||||||
/* wait buffer empty */
|
/* wait buffer empty */
|
||||||
emmc_device_state();
|
emmc_device_state();
|
||||||
|
|
||||||
if (size > EMMC_BLOCK_SIZE) {
|
if (is_cmd23_enabled() == 0) {
|
||||||
memset(&cmd, 0, sizeof(emmc_cmd_t));
|
if (size > EMMC_BLOCK_SIZE) {
|
||||||
cmd.cmd_idx = EMMC_CMD12;
|
memset(&cmd, 0, sizeof(emmc_cmd_t));
|
||||||
ret = ops->send_cmd(&cmd);
|
cmd.cmd_idx = EMMC_CMD12;
|
||||||
assert(ret == 0);
|
ret = ops->send_cmd(&cmd);
|
||||||
|
assert(ret == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* Ignore improbable errors in release builds */
|
/* Ignore improbable errors in release builds */
|
||||||
(void)ret;
|
(void)ret;
|
||||||
|
@ -328,7 +363,8 @@ size_t emmc_rpmb_erase_blocks(int lba, size_t size)
|
||||||
return size_erased;
|
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) &&
|
assert((ops_ptr != 0) &&
|
||||||
(ops_ptr->init != 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_4) ||
|
||||||
(width == EMMC_BUS_WIDTH_8)));
|
(width == EMMC_BUS_WIDTH_8)));
|
||||||
ops = ops_ptr;
|
ops = ops_ptr;
|
||||||
|
emmc_flags = flags;
|
||||||
|
|
||||||
emmc_enumerate(clk, width);
|
emmc_enumerate(clk, width);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#define EMMC_CMD13 13
|
#define EMMC_CMD13 13
|
||||||
#define EMMC_CMD17 17
|
#define EMMC_CMD17 17
|
||||||
#define EMMC_CMD18 18
|
#define EMMC_CMD18 18
|
||||||
|
#define EMMC_CMD23 23
|
||||||
#define EMMC_CMD24 24
|
#define EMMC_CMD24 24
|
||||||
#define EMMC_CMD25 25
|
#define EMMC_CMD25 25
|
||||||
#define EMMC_CMD35 35
|
#define EMMC_CMD35 35
|
||||||
|
@ -111,6 +112,8 @@
|
||||||
#define EMMC_STATE_BTST 9
|
#define EMMC_STATE_BTST 9
|
||||||
#define EMMC_STATE_SLP 10
|
#define EMMC_STATE_SLP 10
|
||||||
|
|
||||||
|
#define EMMC_FLAG_CMD23 (1 << 0)
|
||||||
|
|
||||||
typedef struct emmc_cmd {
|
typedef struct emmc_cmd {
|
||||||
unsigned int cmd_idx;
|
unsigned int cmd_idx;
|
||||||
unsigned int cmd_arg;
|
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_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_write_blocks(int lba, const uintptr_t buf, size_t size);
|
||||||
size_t emmc_rpmb_erase_blocks(int lba, 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__ */
|
#endif /* __EMMC_H__ */
|
||||||
|
|
Loading…
Reference in New Issue