X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fspi%2Fcadence_qspi_apb.c;h=e285d3c1e761047cd9562dc0520c5fc6350c5a5f;hb=cbe7706ab8aab06c18edaa9b120371f9c8012728;hp=00a115f3fba74e8f1937b2936886d4417cb5fd63;hpb=7a7ffedabd29adde9cb6ebe6066256c4cf8b77af;p=u-boot diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index 00a115f3fb..e285d3c1e7 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -27,7 +27,9 @@ #include #include -#include +#include +#include +#include #include "cadence_qspi.h" #define CQSPI_REG_POLL_US (1) /* 1us */ @@ -36,12 +38,6 @@ #define CQSPI_FIFO_WIDTH (4) -/* Controller sram size in word */ -#define CQSPI_REG_SRAM_SIZE_WORD (128) -#define CQSPI_REG_SRAM_RESV_WORDS (2) -#define CQSPI_REG_SRAM_PARTITION_WR (1) -#define CQSPI_REG_SRAM_PARTITION_RD \ - (CQSPI_REG_SRAM_SIZE_WORD - CQSPI_REG_SRAM_RESV_WORDS) #define CQSPI_REG_SRAM_THRESHOLD_WORDS (50) /* Transfer mode */ @@ -50,7 +46,6 @@ #define CQSPI_INST_TYPE_QUAD (2) #define CQSPI_STIG_DATA_LEN_MAX (8) -#define CQSPI_INDIRECTTRIGGER_ADDR_MASK (0xFFFFF) #define CQSPI_DUMMY_CLKS_PER_BYTE (8) #define CQSPI_DUMMY_BYTES_MAX (4) @@ -64,10 +59,10 @@ #define CQSPI_REG_CONFIG 0x00 #define CQSPI_REG_CONFIG_CLK_POL_LSB 1 #define CQSPI_REG_CONFIG_CLK_PHA_LSB 2 -#define CQSPI_REG_CONFIG_ENABLE_MASK (1 << 0) -#define CQSPI_REG_CONFIG_DIRECT_MASK (1 << 7) -#define CQSPI_REG_CONFIG_DECODE_MASK (1 << 9) -#define CQSPI_REG_CONFIG_XIP_IMM_MASK (1 << 18) +#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0) +#define CQSPI_REG_CONFIG_DIRECT_MASK BIT(7) +#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9) +#define CQSPI_REG_CONFIG_XIP_IMM_MASK BIT(18) #define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10 #define CQSPI_REG_CONFIG_BAUD_LSB 19 #define CQSPI_REG_CONFIG_IDLE_LSB 31 @@ -128,18 +123,18 @@ #define CQSPI_REG_IRQMASK 0x44 #define CQSPI_REG_INDIRECTRD 0x60 -#define CQSPI_REG_INDIRECTRD_START_MASK (1 << 0) -#define CQSPI_REG_INDIRECTRD_CANCEL_MASK (1 << 1) -#define CQSPI_REG_INDIRECTRD_INPROGRESS_MASK (1 << 2) -#define CQSPI_REG_INDIRECTRD_DONE_MASK (1 << 5) +#define CQSPI_REG_INDIRECTRD_START_MASK BIT(0) +#define CQSPI_REG_INDIRECTRD_CANCEL_MASK BIT(1) +#define CQSPI_REG_INDIRECTRD_INPROGRESS_MASK BIT(2) +#define CQSPI_REG_INDIRECTRD_DONE_MASK BIT(5) #define CQSPI_REG_INDIRECTRDWATERMARK 0x64 #define CQSPI_REG_INDIRECTRDSTARTADDR 0x68 #define CQSPI_REG_INDIRECTRDBYTES 0x6C #define CQSPI_REG_CMDCTRL 0x90 -#define CQSPI_REG_CMDCTRL_EXECUTE_MASK (1 << 0) -#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK (1 << 1) +#define CQSPI_REG_CMDCTRL_EXECUTE_MASK BIT(0) +#define CQSPI_REG_CMDCTRL_INPROGRESS_MASK BIT(1) #define CQSPI_REG_CMDCTRL_DUMMY_LSB 7 #define CQSPI_REG_CMDCTRL_WR_BYTES_LSB 12 #define CQSPI_REG_CMDCTRL_WR_EN_LSB 15 @@ -155,10 +150,10 @@ #define CQSPI_REG_CMDCTRL_OPCODE_MASK 0xFF #define CQSPI_REG_INDIRECTWR 0x70 -#define CQSPI_REG_INDIRECTWR_START_MASK (1 << 0) -#define CQSPI_REG_INDIRECTWR_CANCEL_MASK (1 << 1) -#define CQSPI_REG_INDIRECTWR_INPROGRESS_MASK (1 << 2) -#define CQSPI_REG_INDIRECTWR_DONE_MASK (1 << 5) +#define CQSPI_REG_INDIRECTWR_START_MASK BIT(0) +#define CQSPI_REG_INDIRECTWR_CANCEL_MASK BIT(1) +#define CQSPI_REG_INDIRECTWR_INPROGRESS_MASK BIT(2) +#define CQSPI_REG_INDIRECTWR_DONE_MASK BIT(5) #define CQSPI_REG_INDIRECTWRWATERMARK 0x74 #define CQSPI_REG_INDIRECTWRSTARTADDR 0x78 @@ -198,128 +193,6 @@ static unsigned int cadence_qspi_apb_cmd2addr(const unsigned char *addr_buf, return addr; } -static void cadence_qspi_apb_read_fifo_data(void *dest, - const void *src_ahb_addr, unsigned int bytes) -{ - unsigned int temp; - int remaining = bytes; - unsigned int *dest_ptr = (unsigned int *)dest; - unsigned int *src_ptr = (unsigned int *)src_ahb_addr; - - while (remaining > 0) { - if (remaining >= CQSPI_FIFO_WIDTH) { - *dest_ptr = readl(src_ptr); - remaining -= CQSPI_FIFO_WIDTH; - } else { - /* dangling bytes */ - temp = readl(src_ptr); - memcpy(dest_ptr, &temp, remaining); - break; - } - dest_ptr++; - } - - return; -} - -static void cadence_qspi_apb_write_fifo_data(const void *dest_ahb_addr, - const void *src, unsigned int bytes) -{ - unsigned int temp; - int remaining = bytes; - unsigned int *dest_ptr = (unsigned int *)dest_ahb_addr; - unsigned int *src_ptr = (unsigned int *)src; - - while (remaining > 0) { - if (remaining >= CQSPI_FIFO_WIDTH) { - writel(*src_ptr, dest_ptr); - remaining -= sizeof(unsigned int); - } else { - /* dangling bytes */ - memcpy(&temp, src_ptr, remaining); - writel(temp, dest_ptr); - break; - } - src_ptr++; - } - - return; -} - -/* Read from SRAM FIFO with polling SRAM fill level. */ -static int qspi_read_sram_fifo_poll(const void *reg_base, void *dest_addr, - const void *src_addr, unsigned int num_bytes) -{ - unsigned int remaining = num_bytes; - unsigned int retry; - unsigned int sram_level = 0; - unsigned char *dest = (unsigned char *)dest_addr; - - while (remaining > 0) { - retry = CQSPI_REG_RETRY; - while (retry--) { - sram_level = CQSPI_GET_RD_SRAM_LEVEL(reg_base); - if (sram_level) - break; - udelay(1); - } - - if (!retry) { - printf("QSPI: No receive data after polling for %d times\n", - CQSPI_REG_RETRY); - return -1; - } - - sram_level *= CQSPI_FIFO_WIDTH; - sram_level = sram_level > remaining ? remaining : sram_level; - - /* Read data from FIFO. */ - cadence_qspi_apb_read_fifo_data(dest, src_addr, sram_level); - dest += sram_level; - remaining -= sram_level; - udelay(1); - } - return 0; -} - -/* Write to SRAM FIFO with polling SRAM fill level. */ -static int qpsi_write_sram_fifo_push(struct cadence_spi_platdata *plat, - const void *src_addr, unsigned int num_bytes) -{ - const void *reg_base = plat->regbase; - void *dest_addr = plat->ahbbase; - unsigned int retry = CQSPI_REG_RETRY; - unsigned int sram_level; - unsigned int wr_bytes; - unsigned char *src = (unsigned char *)src_addr; - int remaining = num_bytes; - unsigned int page_size = plat->page_size; - unsigned int sram_threshold_words = CQSPI_REG_SRAM_THRESHOLD_WORDS; - - while (remaining > 0) { - retry = CQSPI_REG_RETRY; - while (retry--) { - sram_level = CQSPI_GET_WR_SRAM_LEVEL(reg_base); - if (sram_level <= sram_threshold_words) - break; - } - if (!retry) { - printf("QSPI: SRAM fill level (0x%08x) not hit lower expected level (0x%08x)", - sram_level, sram_threshold_words); - return -1; - } - /* Write a page or remaining bytes. */ - wr_bytes = (remaining > page_size) ? - page_size : remaining; - - cadence_qspi_apb_write_fifo_data(dest_addr, src, wr_bytes); - src += wr_bytes; - remaining -= wr_bytes; - } - - return 0; -} - void cadence_qspi_apb_controller_enable(void *reg_base) { unsigned int reg; @@ -420,8 +293,11 @@ void cadence_qspi_apb_config_baudrate_div(void *reg_base, debug("%s: ref_clk %dHz sclk %dHz Div 0x%x\n", __func__, ref_clk_hz, sclk_hz, div); - div = (div & CQSPI_REG_CONFIG_BAUD_MASK) << CQSPI_REG_CONFIG_BAUD_LSB; - reg |= div; + /* ensure the baud rate doesn't exceed the max value */ + if (div > CQSPI_REG_CONFIG_BAUD_MASK) + div = CQSPI_REG_CONFIG_BAUD_MASK; + + reg |= (div << CQSPI_REG_CONFIG_BAUD_LSB); writel(reg, reg_base + CQSPI_REG_CONFIG); cadence_qspi_apb_controller_enable(reg_base); @@ -538,6 +414,9 @@ void cadence_qspi_apb_controller_init(struct cadence_spi_platdata *plat) /* Configure the remap address register, no remap */ writel(0, plat->regbase + CQSPI_REG_REMAP); + /* Indirect mode configurations */ + writel((plat->sram_size/2), plat->regbase + CQSPI_REG_SRAMPARTITION); + /* Disable all interrupts */ writel(0, plat->regbase + CQSPI_REG_IRQMASK); @@ -673,7 +552,7 @@ int cadence_qspi_apb_command_write(void *reg_base, unsigned int cmdlen, /* Opcode + Address (3/4 bytes) + dummy bytes (0-4 bytes) */ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat, - unsigned int cmdlen, const u8 *cmdbuf) + unsigned int cmdlen, unsigned int rx_width, const u8 *cmdbuf) { unsigned int reg; unsigned int rd_reg; @@ -697,20 +576,15 @@ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat, addr_bytes = cmdlen - 1; /* Setup the indirect trigger address */ - writel(((u32)plat->ahbbase & CQSPI_INDIRECTTRIGGER_ADDR_MASK), + writel((u32)plat->ahbbase, plat->regbase + CQSPI_REG_INDIRECTTRIGGER); - /* Configure SRAM partition for read. */ - writel(CQSPI_REG_SRAM_PARTITION_RD, plat->regbase + - CQSPI_REG_SRAMPARTITION); - /* Configure the opcode */ rd_reg = cmdbuf[0] << CQSPI_REG_RD_INSTR_OPCODE_LSB; -#if (CONFIG_SPI_FLASH_QUAD == 1) - /* Instruction and address at DQ0, data at DQ0-3. */ - rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB; -#endif + if (rx_width & SPI_RX_QUAD) + /* Instruction and address at DQ0, data at DQ0-3. */ + rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB; /* Get address */ addr_value = cadence_qspi_apb_cmd2addr(&cmdbuf[1], addr_bytes); @@ -749,40 +623,84 @@ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat, return 0; } +static u32 cadence_qspi_get_rd_sram_level(struct cadence_spi_platdata *plat) +{ + u32 reg = readl(plat->regbase + CQSPI_REG_SDRAMLEVEL); + reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB; + return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK; +} + +static int cadence_qspi_wait_for_data(struct cadence_spi_platdata *plat) +{ + unsigned int timeout = 10000; + u32 reg; + + while (timeout--) { + reg = cadence_qspi_get_rd_sram_level(plat); + if (reg) + return reg; + udelay(1); + } + + return -ETIMEDOUT; +} + int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, - unsigned int rxlen, u8 *rxbuf) + unsigned int n_rx, u8 *rxbuf) { - unsigned int reg; + unsigned int remaining = n_rx; + unsigned int bytes_to_read = 0; + int ret; - writel(rxlen, plat->regbase + CQSPI_REG_INDIRECTRDBYTES); + writel(n_rx, plat->regbase + CQSPI_REG_INDIRECTRDBYTES); /* Start the indirect read transfer */ writel(CQSPI_REG_INDIRECTRD_START_MASK, plat->regbase + CQSPI_REG_INDIRECTRD); - if (qspi_read_sram_fifo_poll(plat->regbase, (void *)rxbuf, - (const void *)plat->ahbbase, rxlen)) - goto failrd; + while (remaining > 0) { + ret = cadence_qspi_wait_for_data(plat); + if (ret < 0) { + printf("Indirect write timed out (%i)\n", ret); + goto failrd; + } + + bytes_to_read = ret; + + while (bytes_to_read != 0) { + bytes_to_read *= CQSPI_FIFO_WIDTH; + bytes_to_read = bytes_to_read > remaining ? + remaining : bytes_to_read; + /* Handle non-4-byte aligned access to avoid data abort. */ + if (((uintptr_t)rxbuf % 4) || (bytes_to_read % 4)) + readsb(plat->ahbbase, rxbuf, bytes_to_read); + else + readsl(plat->ahbbase, rxbuf, bytes_to_read >> 2); + rxbuf += bytes_to_read; + remaining -= bytes_to_read; + bytes_to_read = cadence_qspi_get_rd_sram_level(plat); + } + } - /* Check flash indirect controller */ - reg = readl(plat->regbase + CQSPI_REG_INDIRECTRD); - if (!(reg & CQSPI_REG_INDIRECTRD_DONE_MASK)) { - reg = readl(plat->regbase + CQSPI_REG_INDIRECTRD); - printf("QSPI: indirect completion status error with reg 0x%08x\n", - reg); + /* Check indirect done status */ + ret = wait_for_bit("QSPI", plat->regbase + CQSPI_REG_INDIRECTRD, + CQSPI_REG_INDIRECTRD_DONE_MASK, 1, 10, 0); + if (ret) { + printf("Indirect read completion error (%i)\n", ret); goto failrd; } /* Clear indirect completion status */ writel(CQSPI_REG_INDIRECTRD_DONE_MASK, plat->regbase + CQSPI_REG_INDIRECTRD); + return 0; failrd: /* Cancel the indirect read */ writel(CQSPI_REG_INDIRECTRD_CANCEL_MASK, plat->regbase + CQSPI_REG_INDIRECTRD); - return -1; + return ret; } /* Opcode + Address (3/4 bytes) */ @@ -798,12 +716,9 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat, return -EINVAL; } /* Setup the indirect trigger address */ - writel(((u32)plat->ahbbase & CQSPI_INDIRECTTRIGGER_ADDR_MASK), + writel((u32)plat->ahbbase, plat->regbase + CQSPI_REG_INDIRECTTRIGGER); - writel(CQSPI_REG_SRAM_PARTITION_WR, - plat->regbase + CQSPI_REG_SRAMPARTITION); - /* Configure the opcode */ reg = cmdbuf[0] << CQSPI_REG_WR_INSTR_OPCODE_LSB; writel(reg, plat->regbase + CQSPI_REG_WR_INSTR); @@ -820,48 +735,45 @@ int cadence_qspi_apb_indirect_write_setup(struct cadence_spi_platdata *plat, } int cadence_qspi_apb_indirect_write_execute(struct cadence_spi_platdata *plat, - unsigned int txlen, const u8 *txbuf) + unsigned int n_tx, const u8 *txbuf) { - unsigned int reg = 0; - unsigned int retry; + unsigned int page_size = plat->page_size; + unsigned int remaining = n_tx; + unsigned int write_bytes; + int ret; /* Configure the indirect read transfer bytes */ - writel(txlen, plat->regbase + CQSPI_REG_INDIRECTWRBYTES); + writel(n_tx, plat->regbase + CQSPI_REG_INDIRECTWRBYTES); /* Start the indirect write transfer */ writel(CQSPI_REG_INDIRECTWR_START_MASK, plat->regbase + CQSPI_REG_INDIRECTWR); - if (qpsi_write_sram_fifo_push(plat, (const void *)txbuf, txlen)) - goto failwr; - - /* Wait until last write is completed (FIFO empty) */ - retry = CQSPI_REG_RETRY; - while (retry--) { - reg = CQSPI_GET_WR_SRAM_LEVEL(plat->regbase); - if (reg == 0) - break; - - udelay(1); - } - - if (reg != 0) { - printf("QSPI: timeout for indirect write\n"); - goto failwr; - } + while (remaining > 0) { + write_bytes = remaining > page_size ? page_size : remaining; + /* Handle non-4-byte aligned access to avoid data abort. */ + if (((uintptr_t)txbuf % 4) || (write_bytes % 4)) + writesb(plat->ahbbase, txbuf, write_bytes); + else + writesl(plat->ahbbase, txbuf, write_bytes >> 2); + + ret = wait_for_bit("QSPI", plat->regbase + CQSPI_REG_SDRAMLEVEL, + CQSPI_REG_SDRAMLEVEL_WR_MASK << + CQSPI_REG_SDRAMLEVEL_WR_LSB, 0, 10, 0); + if (ret) { + printf("Indirect write timed out (%i)\n", ret); + goto failwr; + } - /* Check flash indirect controller status */ - retry = CQSPI_REG_RETRY; - while (retry--) { - reg = readl(plat->regbase + CQSPI_REG_INDIRECTWR); - if (reg & CQSPI_REG_INDIRECTWR_DONE_MASK) - break; - udelay(1); + txbuf += write_bytes; + remaining -= write_bytes; } - if (!(reg & CQSPI_REG_INDIRECTWR_DONE_MASK)) { - printf("QSPI: indirect completion status error with reg 0x%08x\n", - reg); + /* Check indirect done status */ + ret = wait_for_bit("QSPI", plat->regbase + CQSPI_REG_INDIRECTWR, + CQSPI_REG_INDIRECTWR_DONE_MASK, 1, 10, 0); + if (ret) { + printf("Indirect write completion error (%i)\n", ret); goto failwr; } @@ -874,7 +786,7 @@ failwr: /* Cancel the indirect write */ writel(CQSPI_REG_INDIRECTWR_CANCEL_MASK, plat->regbase + CQSPI_REG_INDIRECTWR); - return -1; + return ret; } void cadence_qspi_apb_enter_xip(void *reg_base, char xip_dummy)