summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c5
-rw-r--r--drivers/emmc/emmc.c75
-rw-r--r--drivers/io/io_block.c64
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);