X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fspi%2Fsh_qspi.c;h=5ae203d8d4f87c734933e934b9871e120f28fa70;hb=10d3e90f46feace58f4141b696d91644e594e3ed;hp=d7f558a54126291799c7e2f89ac9e6104a0c5dee;hpb=9573db654d1999a1dfde6469782aa8d7cf3d589f;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/spi/sh_qspi.c b/drivers/spi/sh_qspi.c index d7f558a..5ae203d 100644 --- a/drivers/spi/sh_qspi.c +++ b/drivers/spi/sh_qspi.c @@ -1,10 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SH QSPI (Quad SPI) driver * * Copyright (C) 2013 Renesas Electronics Corporation * Copyright (C) 2013 Nobuhiro Iwamatsu - * - * SPDX-License-Identifier: GPL-2.0 */ #include @@ -36,6 +35,8 @@ SPCMD_BRDV0 #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 { @@ -66,15 +67,12 @@ struct sh_qspi_regs { }; 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 */ @@ -118,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); @@ -146,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) +{ + 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) { - /* nothing to do */ + 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, @@ -197,70 +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); - u32 nbyte; - int 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) - spi_cs_deactivate(slave); - return 0; - } + return sh_qspi_xfer_common(ss, bitlen, dout, din, flags); +} - if (bitlen % 8) { - printf("%s: bitlen is not 8bit alined %d", __func__, bitlen); - return 1; - } +#else - nbyte = bitlen / 8; +#include - if (flags & SPI_XFER_BEGIN) { - spi_cs_activate(slave); +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); - /* Set 1048576 byte */ - writel(0x100000, spbmul0); - } + return sh_qspi_xfer_common(ss, bitlen, dout, din, flags); +} - if (flags & SPI_XFER_END) - writel(nbyte, spbmul0); +static int sh_qspi_set_speed(struct udevice *dev, uint speed) +{ + /* This is a SPI NOR controller, do nothing. */ + return 0; +} - if (dout != NULL) - tdata = (u8 *)dout; +static int sh_qspi_set_mode(struct udevice *dev, uint mode) +{ + /* This is a SPI NOR controller, do nothing. */ + return 0; +} - if (din != NULL) - rdata = din; +static int sh_qspi_probe(struct udevice *dev) +{ + struct sh_qspi_slave *ss = dev_get_platdata(dev); - while (nbyte > 0) { - ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPTEF, - true, 1000, true); - if (ret) - return ret; + sh_qspi_init(ss); - writeb(*tdata, (u8 *)(&ss->regs->spdr)); + return 0; +} - ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPRFF, - true, 1000, true); - if (ret) - return ret; +static int sh_qspi_ofdata_to_platdata(struct udevice *dev) +{ + struct sh_qspi_slave *plat = dev_get_platdata(dev); - *rdata = readb((u8 *)(&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