From 201692e05200ea854f248427f78eba32438d79c8 Mon Sep 17 00:00:00 2001 From: Jagannadha Sutradharudu Teki Date: Tue, 28 Aug 2012 14:58:39 +0530 Subject: [PATCH] Xilinx: ARM: spi: zynq: Runtime detection of dual qspi flash This patch adds support to check the dual qspi flash at runtime based on qspi MIO configurations done by FSBL. User needs to correctly configure the MIO's based on the number of flashes memories present on the board. Signed-off-by: Jagannadha Sutradharudu Teki --- drivers/spi/zynq_qspi.c | 71 ++++++++++++++++++++++++++++++++---- drivers/spi/zynq_qspi.h | 4 +- drivers/spi/zynq_qspi_wrap.c | 13 ++++++- include/spi.h | 2 + 4 files changed, 80 insertions(+), 10 deletions(-) diff --git a/drivers/spi/zynq_qspi.c b/drivers/spi/zynq_qspi.c index 3a002fd9785..dd9d04fc486 100755 --- a/drivers/spi/zynq_qspi.c +++ b/drivers/spi/zynq_qspi.c @@ -308,6 +308,7 @@ static struct xqspips_inst_format __devinitdata flash_inst[] = { /** * xqspips_init_hw - Initialize the hardware * @regs_base: Base address of QSPI controller + * @is_dual: Indicates whether dual memories are used * * The default settings of the QSPI controller's configurable parameters on * reset are @@ -325,7 +326,7 @@ static struct xqspips_inst_format __devinitdata flash_inst[] = { * - Set the little endian mode of TX FIFO and * - Enable the QSPI controller **/ -void xqspips_init_hw(void __iomem *regs_base) +void xqspips_init_hw(void __iomem *regs_base, unsigned int is_dual) { u32 config_reg; @@ -347,9 +348,10 @@ void xqspips_init_hw(void __iomem *regs_base) config_reg |= 0x8000FCC1; xqspips_write(regs_base + XQSPIPSS_CONFIG_OFFSET, config_reg); -#ifdef CONFIG_XILINX_PSS_QSPI_USE_DUAL_FLASH - xqspips_write(regs_base + XQSPIPSS_LINEAR_CFG_OFFSET, 0x6400016B); -#endif + if (is_dual == 1) + /* Enable two memories on seperate buses */ + xqspips_write(regs_base + XQSPIPSS_LINEAR_CFG_OFFSET, + 0x6400016B); xqspips_write(regs_base + XQSPIPSS_ENABLE_OFFSET, XQSPIPSS_ENABLE_ENABLE_MASK); @@ -806,11 +808,11 @@ static int xqspips_start_transfer(struct spi_device *qspi, xqspi->curr_inst = &flash_inst[index]; xqspi->inst_response = 1; -#ifdef CONFIG_XILINX_PSS_QSPI_USE_DUAL_FLASH /* In case of dual memories, convert 25 bit address to 24 bit * address before transmitting to the 2 memories */ - if ((instruction == XQSPIPSS_FLASH_OPCODE_PP) || + if ((xqspi->is_dual == 1) && + ((instruction == XQSPIPSS_FLASH_OPCODE_PP) || (instruction == XQSPIPSS_FLASH_OPCODE_SE) || (instruction == XQSPIPSS_FLASH_OPCODE_BE_32K) || (instruction == XQSPIPSS_FLASH_OPCODE_BE_4K) || @@ -818,7 +820,7 @@ static int xqspips_start_transfer(struct spi_device *qspi, (instruction == XQSPIPSS_FLASH_OPCODE_NORM_READ) || (instruction == XQSPIPSS_FLASH_OPCODE_FAST_READ) || (instruction == XQSPIPSS_FLASH_OPCODE_DUAL_READ) || - (instruction == XQSPIPSS_FLASH_OPCODE_QUAD_READ)) { + (instruction == XQSPIPSS_FLASH_OPCODE_QUAD_READ))) { u8 *ptr = (u8*) (xqspi->txbuf); data = ((u32) ptr[1] << 24) | ((u32) ptr[2] << 16) | @@ -830,7 +832,6 @@ static int xqspips_start_transfer(struct spi_device *qspi, xqspi->bytes_to_transfer -= 1; xqspi->bytes_to_receive -= 1; } -#endif /* Get the instruction */ data = 0; @@ -1366,3 +1367,57 @@ MODULE_DESCRIPTION("Xilinx PSS QSPI driver"); MODULE_LICENSE("GPL"); #endif + +/** + * xqspips_check_is_dual_flash - checking for dual or single qspi + * + * This function will check the type of the flash whether it supports + * single or dual qspi based on the MIO configuration done by FSBL. + * + * User needs to correctly configure the MIO's based on the + * number of qspi flashes present on the board. + * + * function will return -1, if there is no MIO configuration for + * qspi flash. + * + * @regs_base: base address of SLCR + */ + +int xqspips_check_is_dual_flash(void __iomem *regs_base) +{ + int is_dual = -1, lower_mio = 0, upper_mio = 0, val; + u16 mask = 3, type = 2; + u32 mio_base, mio_pin_index; + +#ifdef CONFIG_EP107 +#ifdef CONFIG_XILINX_PSS_QSPI_USE_DUAL_FLASH + is_dual = 1; +#else + is_dual = 0; +#endif + return is_dual; +#endif + + mio_base = regs_base + 0x700; + + /* checking single QSPI MIO's */ + for (mio_pin_index = 2; mio_pin_index < 7; mio_pin_index++) { + val = xqspips_read(mio_base + 4 * mio_pin_index); + if ((val & mask) == type) + lower_mio++; + } + + /* checking dual QSPI MIO's */ + for (mio_pin_index = 8; mio_pin_index < 14; mio_pin_index++) { + val = xqspips_read(mio_base + 4 * mio_pin_index); + if ((val & mask) == type) + upper_mio++; + } + + if ((lower_mio == 5) && (upper_mio == 6)) + is_dual = 1; + else if (lower_mio == 5) + is_dual = 0; + + return is_dual; +} diff --git a/drivers/spi/zynq_qspi.h b/drivers/spi/zynq_qspi.h index 45e805b07e5..c33cb138a00 100644 --- a/drivers/spi/zynq_qspi.h +++ b/drivers/spi/zynq_qspi.h @@ -23,6 +23,7 @@ struct xqspips { struct xqspips_inst_format *curr_inst; u8 inst_response; bool is_inst; + bool is_dual; }; struct spi_device { @@ -45,11 +46,12 @@ struct spi_transfer { }; /**************************************************************************/ -extern void xqspips_init_hw(void *regs_base); +extern void xqspips_init_hw(void *regs_base, unsigned int is_dual); extern int xqspips_setup_transfer(struct spi_device *qspi, struct spi_transfer *transfer); extern int xqspips_transfer(struct spi_device *qspi, struct spi_transfer *transfer); +extern int xqspips_check_is_dual_flash(void *regs_base); /**************************************************************************/ diff --git a/drivers/spi/zynq_qspi_wrap.c b/drivers/spi/zynq_qspi_wrap.c index b6452429319..a2259727c3e 100644 --- a/drivers/spi/zynq_qspi_wrap.c +++ b/drivers/spi/zynq_qspi_wrap.c @@ -55,6 +55,7 @@ void spi_init() struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { + int is_dual; struct zynq_spi_slave *pspi; #ifdef DEBUG @@ -62,7 +63,15 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, bus, cs, max_hz, mode); #endif - xqspips_init_hw((void *)XPSS_QSPI_BASEADDR); + is_dual = xqspips_check_is_dual_flash((void *)XPSS_SYS_CTRL_BASEADDR); + + if (is_dual == -1) { + printf("SPI error: No QSPI device detected based" + " on MIO settings\n"); + return NULL; + } + + xqspips_init_hw((void *)XPSS_QSPI_BASEADDR, is_dual); pspi = malloc(sizeof(struct zynq_spi_slave)); if (!pspi) { @@ -70,11 +79,13 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, } pspi->slave.bus = bus; pspi->slave.cs = cs; + pspi->slave.is_dual = is_dual; pspi->qspi.master.input_clk_hz = 100000000; pspi->qspi.master.speed_hz = pspi->qspi.master.input_clk_hz / 2; pspi->qspi.max_speed_hz = pspi->qspi.master.speed_hz; pspi->qspi.master.dev_busy = 0; pspi->qspi.master.regs = (void*)XPSS_QSPI_BASEADDR; + pspi->qspi.master.is_dual = is_dual; pspi->qspi.mode = mode; pspi->qspi.chip_select = 0; pspi->qspi.bits_per_word = 32; diff --git a/include/spi.h b/include/spi.h index 60e85db9a46..f48374204a0 100644 --- a/include/spi.h +++ b/include/spi.h @@ -49,10 +49,12 @@ * * bus: ID of the bus that the slave is attached to. * cs: ID of the chip select connected to the slave. + * is_dual: Indicates whether dual memories are used */ struct spi_slave { unsigned int bus; unsigned int cs; + unsigned int is_dual; }; /*----------------------------------------------------------------------- -- 2.47.3