From 268da813c7f963c8318778de99be382d6b51055d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 27 Apr 2016 15:07:03 +0200 Subject: [PATCH 1/5] ARM: socfpga: Disable USB OC protection on SoCrates This is mandatory, otherwise the USB does not work. Signed-off-by: Marek Vasut Cc: Stefan Roese Cc: Dinh Nguyen --- arch/arm/dts/socfpga_cyclone5_socrates.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/dts/socfpga_cyclone5_socrates.dts b/arch/arm/dts/socfpga_cyclone5_socrates.dts index d2ab3b3669..bdd93248fb 100644 --- a/arch/arm/dts/socfpga_cyclone5_socrates.dts +++ b/arch/arm/dts/socfpga_cyclone5_socrates.dts @@ -83,5 +83,6 @@ }; &usb1 { + disable-over-current; status = "okay"; }; From 8b1a07493f0ad56fafaccce640a0403500e57a78 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 28 Apr 2016 07:17:16 +0200 Subject: [PATCH 2/5] arm: socfpga: socrates: Add 'time' command The time command is very helpful for performance and regressions tests. So lets enable it on SoCrates. Signed-off-by: Stefan Roese Cc: Marek Vasut --- configs/socfpga_socrates_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/socfpga_socrates_defconfig b/configs/socfpga_socrates_defconfig index b64ea158ab..a17e9d0fd9 100644 --- a/configs/socfpga_socrates_defconfig +++ b/configs/socfpga_socrates_defconfig @@ -27,6 +27,7 @@ CONFIG_CMD_DHCP=y CONFIG_CMD_MII=y CONFIG_CMD_PING=y CONFIG_CMD_CACHE=y +CONFIG_CMD_TIME=y CONFIG_CMD_EXT4=y CONFIG_CMD_EXT4_WRITE=y CONFIG_CMD_FAT=y From 26da6353e17111d7f0882866950cf26a679b8d5f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 27 Apr 2016 23:18:55 +0200 Subject: [PATCH 3/5] mtd: cqspi: Simplify indirect write code The indirect write code is buggy pile of nastiness which fails horribly when the system runs fast enough to saturate the controller. The failure results in some pages (256B) not being written to the flash. This can be observed on systems which run with Dcache enabled and L2 cache enabled, like the Altera SoCFPGA. This patch replaces the whole unmaintainable indirect write implementation with the one from upcoming Linux CQSPI driver, which went through multiple rounds of thorough review and testing. While this makes the patch look terrifying and violates all best-practices of software development, all the patch does is it plucks out duplicate ad-hoc code distributed across the driver and replaces it with more compact code doing exactly the same thing. Signed-off-by: Marek Vasut Cc: Anatolij Gustschin Cc: Chin Liang See Cc: Dinh Nguyen Cc: Jagan Teki Cc: Pavel Machek Cc: Stefan Roese Cc: Vignesh R --- drivers/spi/cadence_qspi_apb.c | 124 ++++++++------------------------- 1 file changed, 29 insertions(+), 95 deletions(-) diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index 7786dd65f5..5e84144940 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "cadence_qspi.h" #define CQSPI_REG_POLL_US (1) /* 1us */ @@ -214,32 +215,6 @@ static void cadence_qspi_apb_read_fifo_data(void *dest, return; } -static void cadence_qspi_apb_write_fifo_data(const void *dest_ahb_addr, - const void *src, unsigned int bytes) -{ - unsigned int temp = 0; - int i; - int remaining = bytes; - unsigned int *dest_ptr = (unsigned int *)dest_ahb_addr; - unsigned int *src_ptr = (unsigned int *)src; - - while (remaining >= CQSPI_FIFO_WIDTH) { - for (i = CQSPI_FIFO_WIDTH/sizeof(src_ptr) - 1; i >= 0; i--) - writel(*(src_ptr+i), dest_ptr+i); - src_ptr += CQSPI_FIFO_WIDTH/sizeof(src_ptr); - remaining -= CQSPI_FIFO_WIDTH; - } - if (remaining) { - /* dangling bytes */ - i = remaining/sizeof(dest_ptr); - memcpy(&temp, src_ptr+i, remaining % sizeof(dest_ptr)); - writel(temp, dest_ptr+i); - for (--i; i >= 0; i--) - writel(*(src_ptr+i), dest_ptr+i); - } - 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) @@ -276,44 +251,6 @@ static int qspi_read_sram_fifo_poll(const void *reg_base, void *dest_addr, 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; @@ -810,48 +747,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; + 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); - /* 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; + 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; + } - udelay(1); + txbuf += write_bytes; + remaining -= write_bytes; } - if (reg != 0) { - printf("QSPI: timeout for indirect write\n"); - 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); - } - - 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; } @@ -864,7 +798,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) From 5a824c493a31d06f04a6736fab8f67bf78145003 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 27 Apr 2016 23:38:05 +0200 Subject: [PATCH 4/5] mtd: cqspi: Simplify indirect read code The indirect read code is a pile of nastiness. This patch replaces the whole unmaintainable indirect read implementation with the one from upcoming Linux CQSPI driver, which went through multiple rounds of thorough review and testing. All the patch does is it plucks out duplicate ad-hoc code distributed across the driver and replaces it with more compact code doing exactly the same thing. There is no speed change of the read operation. Signed-off-by: Marek Vasut Cc: Anatolij Gustschin Cc: Chin Liang See Cc: Dinh Nguyen Cc: Jagan Teki Cc: Pavel Machek Cc: Stefan Roese Cc: Vignesh R --- drivers/spi/cadence_qspi_apb.c | 130 +++++++++++++++------------------ 1 file changed, 58 insertions(+), 72 deletions(-) diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index 5e84144940..a71531d309 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -193,64 +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 >= sizeof(dest_ptr)) { - *dest_ptr = readl(src_ptr); - remaining -= sizeof(src_ptr); - dest_ptr++; - } - if (remaining) { - /* dangling bytes */ - temp = readl(src_ptr); - memcpy(dest_ptr, &temp, remaining); - } - - 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; -} - void cadence_qspi_apb_controller_enable(void *reg_base) { unsigned int reg; @@ -679,40 +621,84 @@ int cadence_qspi_apb_indirect_read_setup(struct cadence_spi_platdata *plat, return 0; } -int cadence_qspi_apb_indirect_read_execute(struct cadence_spi_platdata *plat, - unsigned int rxlen, u8 *rxbuf) +static u32 cadence_qspi_get_rd_sram_level(struct cadence_spi_platdata *plat) { - unsigned int reg; + u32 reg = readl(plat->regbase + CQSPI_REG_SDRAMLEVEL); + reg >>= CQSPI_REG_SDRAMLEVEL_RD_LSB; + return reg & CQSPI_REG_SDRAMLEVEL_RD_MASK; +} - writel(rxlen, plat->regbase + CQSPI_REG_INDIRECTRDBYTES); +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 n_rx, u8 *rxbuf) +{ + unsigned int remaining = n_rx; + unsigned int bytes_to_read = 0; + int ret; + + 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; + } - /* 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); + 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 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) */ From 5289c5fa5371dada10e9cbdcdbf3fb010905ea2d Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Fri, 6 May 2016 17:16:31 +0200 Subject: [PATCH 5/5] socfpga: fix broken build if CONFIG_ETH_DESIGNWARE disabled Building without ethernet driver doesn't work. Fix it. Signed-off-by: Anatolij Gustschin Cc: Marek Vasut --- arch/arm/mach-socfpga/misc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-socfpga/misc.c b/arch/arm/mach-socfpga/misc.c index dd05e14c05..5cbd8a4325 100644 --- a/arch/arm/mach-socfpga/misc.c +++ b/arch/arm/mach-socfpga/misc.c @@ -172,7 +172,7 @@ static int socfpga_eth_reset(void) #else static int socfpga_eth_reset(void) { - return 0 + return 0; }; #endif