]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
Xilinx: ARM: spi: zynq: Runtime detection of dual qspi flash
authorJagannadha Sutradharudu Teki <jaganna@xilinx.com>
Tue, 28 Aug 2012 09:28:39 +0000 (14:58 +0530)
committerJohn Linn <john.linn@xilinx.com>
Wed, 29 Aug 2012 23:11:05 +0000 (16:11 -0700)
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 <jaganna@xilinx.com>
drivers/spi/zynq_qspi.c
drivers/spi/zynq_qspi.h
drivers/spi/zynq_qspi_wrap.c
include/spi.h

index 3a002fd9785cb03f882a3227c4cb86bd626997b7..dd9d04fc4862e6ee9297d25cac32635fa9b01a5c 100755 (executable)
@@ -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;
+}
index 45e805b07e58526b60eaa93d99c959bcb956681c..c33cb138a00c2a0b6c230af9333c0548089e0c24 100644 (file)
@@ -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);
 
 /**************************************************************************/
 
index b6452429319cf5917ec7b3b5cfe159b17fc34041..a2259727c3e936f706ab95d1d2181e1923025b47 100644 (file)
@@ -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;
index 60e85db9a46e052c97b638c58bb93114a378e3b7..f48374204a0d2f6c36f8e490b2ede746800a1491 100644 (file)
  *
  *   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;
 };
 
 /*-----------------------------------------------------------------------