efi_loader: correct comments for efi_status_t
[oweals/u-boot.git] / drivers / spi / sh_qspi.c
index 77ede6bba3a5d9655a7bc46be8dca39d70d2834d..5ae203d8d4f87c734933e934b9871e120f28fa70 100644 (file)
@@ -1,15 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * SH QSPI (Quad SPI) driver
  *
  * Copyright (C) 2013 Renesas Electronics Corporation
  * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
- *
- * SPDX-License-Identifier:    GPL-2.0
  */
 
 #include <common.h>
+#include <console.h>
 #include <malloc.h>
 #include <spi.h>
+#include <wait_bit.h>
 #include <asm/arch/rmobile.h>
 #include <asm/io.h>
 
 #define SPPCR_IO3FV    0x04
 #define SPPCR_IO2FV    0x02
 #define SPPCR_IO1FV    0x01
-#define SPBDCR_RXBC0   (1 << 0)
-#define SPCMD_SCKDEN   (1 << 15)
-#define SPCMD_SLNDEN   (1 << 14)
-#define SPCMD_SPNDEN   (1 << 13)
-#define SPCMD_SSLKP    (1 << 7)
-#define SPCMD_BRDV0    (1 << 2)
+#define SPBDCR_RXBC0   BIT(0)
+#define SPCMD_SCKDEN   BIT(15)
+#define SPCMD_SLNDEN   BIT(14)
+#define SPCMD_SPNDEN   BIT(13)
+#define SPCMD_SSLKP    BIT(7)
+#define SPCMD_BRDV0    BIT(2)
 #define SPCMD_INIT1    SPCMD_SCKDEN | SPCMD_SLNDEN | \
                        SPCMD_SPNDEN | SPCMD_SSLKP | \
                        SPCMD_BRDV0
 #define SPCMD_INIT2    SPCMD_SPNDEN | SPCMD_SSLKP | \
                        SPCMD_BRDV0
-#define SPBFCR_TXRST   (1 << 7)
-#define SPBFCR_RXRST   (1 << 6)
+#define SPBFCR_TXRST   BIT(7)
+#define SPBFCR_RXRST   BIT(6)
+#define SPBFCR_TXTRG   0x30
+#define SPBFCR_RXTRG   0x07
 
 /* SH QSPI register set */
 struct sh_qspi_regs {
-       unsigned char spcr;
-       unsigned char sslp;
-       unsigned char sppcr;
-       unsigned char spsr;
-       unsigned long spdr;
-       unsigned char spscr;
-       unsigned char spssr;
-       unsigned char spbr;
-       unsigned char spdcr;
-       unsigned char spckd;
-       unsigned char sslnd;
-       unsigned char spnd;
-       unsigned char dummy0;
-       unsigned short spcmd0;
-       unsigned short spcmd1;
-       unsigned short spcmd2;
-       unsigned short spcmd3;
-       unsigned char spbfcr;
-       unsigned char dummy1;
-       unsigned short spbdcr;
-       unsigned long spbmul0;
-       unsigned long spbmul1;
-       unsigned long spbmul2;
-       unsigned long spbmul3;
+       u8      spcr;
+       u8      sslp;
+       u8      sppcr;
+       u8      spsr;
+       u32     spdr;
+       u8      spscr;
+       u8      spssr;
+       u8      spbr;
+       u8      spdcr;
+       u8      spckd;
+       u8      sslnd;
+       u8      spnd;
+       u8      dummy0;
+       u16     spcmd0;
+       u16     spcmd1;
+       u16     spcmd2;
+       u16     spcmd3;
+       u8      spbfcr;
+       u8      dummy1;
+       u16     spbdcr;
+       u32     spbmul0;
+       u32     spbmul1;
+       u32     spbmul2;
+       u32     spbmul3;
 };
 
 struct sh_qspi_slave {
+#ifndef CONFIG_DM_SPI
        struct spi_slave        slave;
+#endif
        struct sh_qspi_regs     *regs;
 };
 
-static inline struct sh_qspi_slave *to_sh_qspi(struct spi_slave *slave)
-{
-       return container_of(slave, struct sh_qspi_slave, slave);
-}
-
 static void sh_qspi_init(struct sh_qspi_slave *ss)
 {
        /* QSPI initialize */
@@ -116,15 +116,8 @@ static void sh_qspi_init(struct sh_qspi_slave *ss)
        setbits_8(&ss->regs->spcr, SPCR_SPE);
 }
 
-int spi_cs_is_valid(unsigned int bus, unsigned int cs)
-{
-       return 1;
-}
-
-void spi_cs_activate(struct spi_slave *slave)
+static void sh_qspi_cs_activate(struct sh_qspi_slave *ss)
 {
-       struct sh_qspi_slave *ss = to_sh_qspi(slave);
-
        /* Set master mode only */
        writeb(SPCR_MSTR, &ss->regs->spcr);
 
@@ -144,17 +137,114 @@ void spi_cs_activate(struct spi_slave *slave)
        setbits_8(&ss->regs->spcr, SPCR_SPE);
 }
 
-void spi_cs_deactivate(struct spi_slave *slave)
+static void sh_qspi_cs_deactivate(struct sh_qspi_slave *ss)
 {
-       struct sh_qspi_slave *ss = to_sh_qspi(slave);
-
        /* Disable SPI Function */
        clrbits_8(&ss->regs->spcr, SPCR_SPE);
 }
 
-void spi_init(void)
+static int sh_qspi_xfer_common(struct sh_qspi_slave *ss, unsigned int bitlen,
+                              const void *dout, void *din, unsigned long flags)
+{
+       u32 nbyte, chunk;
+       int i, ret = 0;
+       u8 dtdata = 0, drdata;
+       u8 *tdata = &dtdata, *rdata = &drdata;
+       u32 *spbmul0 = &ss->regs->spbmul0;
+
+       if (dout == NULL && din == NULL) {
+               if (flags & SPI_XFER_END)
+                       sh_qspi_cs_deactivate(ss);
+               return 0;
+       }
+
+       if (bitlen % 8) {
+               printf("%s: bitlen is not 8bit alined %d", __func__, bitlen);
+               return 1;
+       }
+
+       nbyte = bitlen / 8;
+
+       if (flags & SPI_XFER_BEGIN) {
+               sh_qspi_cs_activate(ss);
+
+               /* Set 1048576 byte */
+               writel(0x100000, spbmul0);
+       }
+
+       if (flags & SPI_XFER_END)
+               writel(nbyte, spbmul0);
+
+       if (dout != NULL)
+               tdata = (u8 *)dout;
+
+       if (din != NULL)
+               rdata = din;
+
+       while (nbyte > 0) {
+               /*
+                * Check if there is 32 Byte chunk and if there is, transfer
+                * it in one burst, otherwise transfer on byte-by-byte basis.
+                */
+               chunk = (nbyte >= 32) ? 32 : 1;
+
+               clrsetbits_8(&ss->regs->spbfcr, SPBFCR_TXTRG | SPBFCR_RXTRG,
+                            chunk == 32 ? SPBFCR_TXTRG | SPBFCR_RXTRG : 0);
+
+               ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPTEF,
+                                    true, 1000, true);
+               if (ret)
+                       return ret;
+
+               for (i = 0; i < chunk; i++) {
+                       writeb(*tdata, &ss->regs->spdr);
+                       if (dout != NULL)
+                               tdata++;
+               }
+
+               ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPRFF,
+                                    true, 1000, true);
+               if (ret)
+                       return ret;
+
+               for (i = 0; i < chunk; i++) {
+                       *rdata = readb(&ss->regs->spdr);
+                       if (din != NULL)
+                               rdata++;
+               }
+
+               nbyte -= chunk;
+       }
+
+       if (flags & SPI_XFER_END)
+               sh_qspi_cs_deactivate(ss);
+
+       return ret;
+}
+
+#ifndef CONFIG_DM_SPI
+static inline struct sh_qspi_slave *to_sh_qspi(struct spi_slave *slave)
 {
-       /* nothing to do */
+       return container_of(slave, struct sh_qspi_slave, slave);
+}
+
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+       return 1;
+}
+
+void spi_cs_activate(struct spi_slave *slave)
+{
+       struct sh_qspi_slave *ss = to_sh_qspi(slave);
+
+       sh_qspi_cs_activate(ss);
+}
+
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+       struct sh_qspi_slave *ss = to_sh_qspi(slave);
+
+       sh_qspi_cs_deactivate(ss);
 }
 
 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
@@ -195,84 +285,75 @@ void spi_release_bus(struct spi_slave *slave)
 {
 }
 
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
-            void *din, unsigned long flags)
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+            const void *dout, void *din, unsigned long flags)
 {
        struct sh_qspi_slave *ss = to_sh_qspi(slave);
-       unsigned long nbyte;
-       int ret = 0;
-       unsigned char dtdata = 0, drdata;
-       unsigned char *tdata = &dtdata, *rdata = &drdata;
-       unsigned long *spbmul0 = &ss->regs->spbmul0;
 
-       if (dout == NULL && din == NULL) {
-               if (flags & SPI_XFER_END)
-                       spi_cs_deactivate(slave);
-               return 0;
-       }
-
-       if (bitlen % 8) {
-               printf("%s: bitlen is not 8bit alined %d", __func__, bitlen);
-               return 1;
-       }
+       return sh_qspi_xfer_common(ss, bitlen, dout, din, flags);
+}
 
-       nbyte = bitlen / 8;
+#else
 
-       if (flags & SPI_XFER_BEGIN) {
-               spi_cs_activate(slave);
+#include <dm.h>
 
-               /* Set 1048576 byte */
-               writel(0x100000, spbmul0);
-       }
+static int sh_qspi_xfer(struct udevice *dev, unsigned int bitlen,
+                       const void *dout, void *din, unsigned long flags)
+{
+       struct udevice *bus = dev->parent;
+       struct sh_qspi_slave *ss = dev_get_platdata(bus);
 
-       if (flags & SPI_XFER_END)
-               writel(nbyte, spbmul0);
+       return sh_qspi_xfer_common(ss, bitlen, dout, din, flags);
+}
 
-       if (dout != NULL)
-               tdata = (unsigned char *)dout;
+static int sh_qspi_set_speed(struct udevice *dev, uint speed)
+{
+       /* This is a SPI NOR controller, do nothing. */
+       return 0;
+}
 
-       if (din != NULL)
-               rdata = din;
+static int sh_qspi_set_mode(struct udevice *dev, uint mode)
+{
+       /* This is a SPI NOR controller, do nothing. */
+       return 0;
+}
 
-       while (nbyte > 0) {
-               while (!(readb(&ss->regs->spsr) & SPSR_SPTEF)) {
-                       if (ctrlc()) {
-                               puts("abort\n");
-                               return 1;
-                       }
-                       udelay(10);
-               }
+static int sh_qspi_probe(struct udevice *dev)
+{
+       struct sh_qspi_slave *ss = dev_get_platdata(dev);
 
-               writeb(*tdata, (unsigned char *)(&ss->regs->spdr));
+       sh_qspi_init(ss);
 
-               while ((readw(&ss->regs->spbdcr) != SPBDCR_RXBC0)) {
-                       if (ctrlc()) {
-                               puts("abort\n");
-                               return 1;
-                       }
-                       udelay(1);
-               }
+       return 0;
+}
 
-               while (!(readb(&ss->regs->spsr) & SPSR_SPRFF)) {
-                       if (ctrlc()) {
-                               puts("abort\n");
-                               return 1;
-                       }
-                       udelay(10);
-               }
+static int sh_qspi_ofdata_to_platdata(struct udevice *dev)
+{
+       struct sh_qspi_slave *plat = dev_get_platdata(dev);
 
-               *rdata = readb((unsigned char *)(&ss->regs->spdr));
+       plat->regs = (struct sh_qspi_regs *)dev_read_addr(dev);
 
-               if (dout != NULL)
-                       tdata++;
-               if (din != NULL)
-                       rdata++;
+       return 0;
+}
 
-               nbyte--;
-       }
+static const struct dm_spi_ops sh_qspi_ops = {
+       .xfer           = sh_qspi_xfer,
+       .set_speed      = sh_qspi_set_speed,
+       .set_mode       = sh_qspi_set_mode,
+};
 
-       if (flags & SPI_XFER_END)
-               spi_cs_deactivate(slave);
+static const struct udevice_id sh_qspi_ids[] = {
+       { .compatible = "renesas,qspi" },
+       { }
+};
 
-       return ret;
-}
+U_BOOT_DRIVER(sh_qspi) = {
+       .name           = "sh_qspi",
+       .id             = UCLASS_SPI,
+       .of_match       = sh_qspi_ids,
+       .ops            = &sh_qspi_ops,
+       .ofdata_to_platdata = sh_qspi_ofdata_to_platdata,
+       .platdata_auto_alloc_size = sizeof(struct sh_qspi_slave),
+       .probe          = sh_qspi_probe,
+};
+#endif