
ti_qspi uses memory map mode for faster read. Enabling DMA will increase read speed by 3x @48MHz on DRA74 EVM.
Signed-off-by: Vignesh R vigneshr@ti.com --- drivers/spi/ti_qspi.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+)
diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c index 3356c0f072e5..0c533e295962 100644 --- a/drivers/spi/ti_qspi.c +++ b/drivers/spi/ti_qspi.c @@ -13,6 +13,8 @@ #include <spi.h> #include <asm/gpio.h> #include <asm/omap_gpio.h> +#include <asm/omap_common.h> +#include <asm/ti-common/ti-edma3.h>
/* ti qpsi register bit masks */ #define QSPI_TIMEOUT 2000000 @@ -347,3 +349,94 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
return 0; } +#ifdef CONFIG_TI_EDMA3 +void spi_flash_copy_mmap(void *data, void *offset, size_t len) +{ + struct edma3_slot_config slot; + struct edma3_channel_config edma_channel; + int b_cnt_value = 1; + int rem_bytes = 0; + int a_cnt_value = len; + unsigned int addr = (unsigned int) (data); + unsigned int max_acnt = 0x7FFFU; + unsigned int edma_slot_num = 1; + + if (len > max_acnt) { + b_cnt_value = (len / max_acnt); + rem_bytes = (len % max_acnt); + a_cnt_value = max_acnt; + } + + /* Invalidate the area, so no writeback into the RAM races with DMA */ + invalidate_dcache_range(addr, addr + roundup(len, ARCH_DMA_MINALIGN)); + + /* enable edma3 clocks */ + enable_edma3_clocks(); + /* Compute QSPI address and size */ + slot.opt = 0; + slot.src = ((unsigned int) offset); + slot.acnt = a_cnt_value; + slot.bcnt = b_cnt_value; + slot.ccnt = 1; + slot.src_bidx = a_cnt_value; + slot.dst_bidx = a_cnt_value; + slot.src_cidx = 0; + slot.dst_cidx = 0; + slot.link = EDMA3_PARSET_NULL_LINK; + slot.bcntrld = 0; + slot.opt = EDMA3_SLOPT_TRANS_COMP_INT_ENB | + EDMA3_SLOPT_COMP_CODE(0) | + EDMA3_SLOPT_STATIC | EDMA3_SLOPT_AB_SYNC; + + edma3_slot_configure(EDMA3_BASE, edma_slot_num, &slot); + edma_channel.slot = edma_slot_num; + edma_channel.chnum = 0; + edma_channel.complete_code = 0; + /* set event trigger to dst update */ + edma_channel.trigger_slot_word = EDMA3_TWORD(dst); + + qedma3_start(EDMA3_BASE, &edma_channel); + edma3_set_dest_addr(EDMA3_BASE, edma_channel.slot, addr); + + while (edma3_check_for_transfer(EDMA3_BASE, &edma_channel)) + ; + qedma3_stop(EDMA3_BASE, &edma_channel); + + if (rem_bytes != 0) { + /* Compute QSPI address and size */ + slot.opt = 0; + slot.src = + (b_cnt_value * max_acnt) + ((unsigned int) offset); + slot.acnt = rem_bytes; + slot.bcnt = 1; + slot.ccnt = 1; + slot.src_bidx = rem_bytes; + slot.dst_bidx = rem_bytes; + slot.src_cidx = 0; + slot.dst_cidx = 0; + slot.link = EDMA3_PARSET_NULL_LINK; + slot.bcntrld = 0; + slot.opt = EDMA3_SLOPT_TRANS_COMP_INT_ENB | + EDMA3_SLOPT_COMP_CODE(0) | + EDMA3_SLOPT_STATIC | EDMA3_SLOPT_AB_SYNC; + edma3_slot_configure(EDMA3_BASE, edma_slot_num, &slot); + edma_channel.slot = edma_slot_num; + edma_channel.chnum = 0; + edma_channel.complete_code = 0; + /* set event trigger to dst update */ + edma_channel.trigger_slot_word = EDMA3_TWORD(dst); + + qedma3_start(EDMA3_BASE, &edma_channel); + edma3_set_dest_addr(EDMA3_BASE, edma_channel.slot, addr + + (max_acnt * b_cnt_value)); + + while (edma3_check_for_transfer(EDMA3_BASE, &edma_channel)) + ; + qedma3_stop(EDMA3_BASE, &edma_channel); + } + *((unsigned int *)offset) += len; + + /* disable edma3 clocks */ + disable_edma3_clocks(); +} +#endif