emmc: support CMD23
authorHaojian Zhuang <[email protected]>
Tue, 2 Aug 2016 12:51:27 +0000 (20:51 +0800)
committerHaojian Zhuang <[email protected]>
Fri, 12 Aug 2016 03:41:00 +0000 (11:41 +0800)
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 <[email protected]>
drivers/emmc/emmc.c
include/drivers/emmc.h

index 5fe28efc031b3a15353230b644f5b6d8c1c51248..3fae2a15b8b5713265d2414cc2f2ffeca0b47cfd 100644 (file)
 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);
 }
index 61d449590f6f33f7f638e1728778cde8c660a8dc..5f78dcefa82d964bdabf513848fbcc0865eca164 100644 (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
 #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__ */