diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/arm/gic/v3/gicv3_main.c | 5 | ||||
-rw-r--r-- | drivers/emmc/emmc.c | 75 | ||||
-rw-r--r-- | drivers/io/io_block.c | 64 |
3 files changed, 109 insertions, 35 deletions
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index 8cb80203..d13e2c9c 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -284,9 +284,10 @@ void gicv3_cpuif_disable(unsigned int proc_num) write_icc_igrpen0_el1(read_icc_igrpen0_el1() & ~IGRPEN1_EL1_ENABLE_G0_BIT); - /* Disable Group1 Secure interrupts */ + /* Disable Group1 Secure and Non-Secure interrupts */ write_icc_igrpen1_el3(read_icc_igrpen1_el3() & - ~IGRPEN1_EL3_ENABLE_G1S_BIT); + ~(IGRPEN1_EL3_ENABLE_G1NS_BIT | + IGRPEN1_EL3_ENABLE_G1S_BIT)); /* Synchronise accesses to group enable registers */ isb(); diff --git a/drivers/emmc/emmc.c b/drivers/emmc/emmc.c index 5fe28efc..3fae2a15 100644 --- a/drivers/emmc/emmc.c +++ b/drivers/emmc/emmc.c @@ -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); } diff --git a/drivers/io/io_block.c b/drivers/io/io_block.c index 198b723b..4ec59bc7 100644 --- a/drivers/io/io_block.c +++ b/drivers/io/io_block.c @@ -198,6 +198,7 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, io_block_ops_t *ops; size_t aligned_length, skip, count, left, padding, block_size; int lba; + int buffer_not_aligned; assert(entity->info != (uintptr_t)NULL); cur = (block_dev_state_t *)entity->info; @@ -208,6 +209,17 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, (length > 0) && (ops->read != 0)); + if ((buffer & (block_size - 1)) != 0) { + /* + * buffer isn't aligned with block size. + * Block device always relies on DMA operation. + * It's better to make the buffer as block size aligned. + */ + buffer_not_aligned = 1; + } else { + buffer_not_aligned = 0; + } + skip = cur->file_pos % block_size; aligned_length = ((skip + length) + (block_size - 1)) & ~(block_size - 1); @@ -216,8 +228,13 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, do { lba = (cur->file_pos + cur->base) / block_size; if (left >= buf->length) { - /* Since left is larger, it's impossible to padding. */ - if (skip) { + /* + * Since left is larger, it's impossible to padding. + * + * If buffer isn't aligned, we need to use aligned + * buffer instead. + */ + if (skip || buffer_not_aligned) { /* * The beginning address (file_pos) isn't * aligned with block size, we need to use @@ -231,10 +248,11 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, } assert(count == buf->length); cur->file_pos += count - skip; - if (skip) { + if (skip || buffer_not_aligned) { /* - * Since it's not aligned with block size, - * block buffer is used to store data. + * Since there's not aligned block size caused + * by skip or not aligned buffer, block buffer + * is used to store data. */ memcpy((void *)buffer, (void *)(buf->offset + skip), @@ -242,13 +260,16 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, } left = left - (count - skip); } else { - if (skip || padding) { + if (skip || padding || buffer_not_aligned) { /* * The beginning address (file_pos) isn't * aligned with block size, we have to read * full block by block buffer instead. * The size isn't aligned with block size. * Use block buffer to avoid overflow. + * + * If buffer isn't aligned, use block buffer + * to avoid DMA error. */ count = ops->read(lba, buf->offset, left); } else @@ -256,10 +277,10 @@ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, assert(count == left); left = left - (skip + padding); cur->file_pos += left; - if (skip || padding) { + if (skip || padding || buffer_not_aligned) { /* - * Since it's not aligned with block size, - * block buffer is used to store data. + * Since there's not aligned block size or + * buffer, block buffer is used to store data. */ memcpy((void *)buffer, (void *)(buf->offset + skip), @@ -283,6 +304,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, io_block_ops_t *ops; size_t aligned_length, skip, count, left, padding, block_size; int lba; + int buffer_not_aligned; assert(entity->info != (uintptr_t)NULL); cur = (block_dev_state_t *)entity->info; @@ -294,6 +316,17 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, (ops->read != 0) && (ops->write != 0)); + if ((buffer & (block_size - 1)) != 0) { + /* + * buffer isn't aligned with block size. + * Block device always relies on DMA operation. + * It's better to make the buffer as block size aligned. + */ + buffer_not_aligned = 1; + } else { + buffer_not_aligned = 0; + } + skip = cur->file_pos % block_size; aligned_length = ((skip + length) + (block_size - 1)) & ~(block_size - 1); @@ -303,12 +336,12 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, lba = (cur->file_pos + cur->base) / block_size; if (left >= buf->length) { /* Since left is larger, it's impossible to padding. */ - if (skip) { + if (skip || buffer_not_aligned) { /* * The beginning address (file_pos) isn't - * aligned with block size, we need to use - * block buffer to write block. Since block - * device is always relied on DMA operation. + * aligned with block size or buffer isn't + * aligned, we need to use block buffer to + * write block. */ count = ops->read(lba, buf->offset, buf->length); @@ -324,7 +357,7 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, cur->file_pos += count - skip; left = left - (count - skip); } else { - if (skip || padding) { + if (skip || padding || buffer_not_aligned) { /* * The beginning address (file_pos) isn't * aligned with block size, we need to avoid @@ -332,6 +365,9 @@ static int block_write(io_entity_t *entity, const uintptr_t buffer, * skipping the beginning is the only way. * The size isn't aligned with block size. * Use block buffer to avoid overflow. + * + * If buffer isn't aligned, use block buffer + * to avoid DMA error. */ count = ops->read(lba, buf->offset, left); assert(count == left); |