116f47c9cSNobuhiro Iwamatsu /* 216f47c9cSNobuhiro Iwamatsu * SH QSPI (Quad SPI) driver 316f47c9cSNobuhiro Iwamatsu * 416f47c9cSNobuhiro Iwamatsu * Copyright (C) 2013 Renesas Electronics Corporation 516f47c9cSNobuhiro Iwamatsu * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com> 616f47c9cSNobuhiro Iwamatsu * 716f47c9cSNobuhiro Iwamatsu * SPDX-License-Identifier: GPL-2.0 816f47c9cSNobuhiro Iwamatsu */ 916f47c9cSNobuhiro Iwamatsu 1016f47c9cSNobuhiro Iwamatsu #include <common.h> 1124b852a7SSimon Glass #include <console.h> 1216f47c9cSNobuhiro Iwamatsu #include <malloc.h> 1316f47c9cSNobuhiro Iwamatsu #include <spi.h> 14*9573db65SMarek Vasut #include <wait_bit.h> 1522e75d6dSNobuhiro Iwamatsu #include <asm/arch/rmobile.h> 1616f47c9cSNobuhiro Iwamatsu #include <asm/io.h> 1716f47c9cSNobuhiro Iwamatsu 1816f47c9cSNobuhiro Iwamatsu /* SH QSPI register bit masks <REG>_<BIT> */ 1916f47c9cSNobuhiro Iwamatsu #define SPCR_MSTR 0x08 2016f47c9cSNobuhiro Iwamatsu #define SPCR_SPE 0x40 2116f47c9cSNobuhiro Iwamatsu #define SPSR_SPRFF 0x80 2216f47c9cSNobuhiro Iwamatsu #define SPSR_SPTEF 0x20 2316f47c9cSNobuhiro Iwamatsu #define SPPCR_IO3FV 0x04 2416f47c9cSNobuhiro Iwamatsu #define SPPCR_IO2FV 0x02 2516f47c9cSNobuhiro Iwamatsu #define SPPCR_IO1FV 0x01 26ccaa9485SJagan Teki #define SPBDCR_RXBC0 BIT(0) 27ccaa9485SJagan Teki #define SPCMD_SCKDEN BIT(15) 28ccaa9485SJagan Teki #define SPCMD_SLNDEN BIT(14) 29ccaa9485SJagan Teki #define SPCMD_SPNDEN BIT(13) 30ccaa9485SJagan Teki #define SPCMD_SSLKP BIT(7) 31ccaa9485SJagan Teki #define SPCMD_BRDV0 BIT(2) 3216f47c9cSNobuhiro Iwamatsu #define SPCMD_INIT1 SPCMD_SCKDEN | SPCMD_SLNDEN | \ 3316f47c9cSNobuhiro Iwamatsu SPCMD_SPNDEN | SPCMD_SSLKP | \ 3416f47c9cSNobuhiro Iwamatsu SPCMD_BRDV0 3516f47c9cSNobuhiro Iwamatsu #define SPCMD_INIT2 SPCMD_SPNDEN | SPCMD_SSLKP | \ 3616f47c9cSNobuhiro Iwamatsu SPCMD_BRDV0 37ccaa9485SJagan Teki #define SPBFCR_TXRST BIT(7) 38ccaa9485SJagan Teki #define SPBFCR_RXRST BIT(6) 3916f47c9cSNobuhiro Iwamatsu 4016f47c9cSNobuhiro Iwamatsu /* SH QSPI register set */ 4116f47c9cSNobuhiro Iwamatsu struct sh_qspi_regs { 420e6fa20bSMarek Vasut u8 spcr; 430e6fa20bSMarek Vasut u8 sslp; 440e6fa20bSMarek Vasut u8 sppcr; 450e6fa20bSMarek Vasut u8 spsr; 460e6fa20bSMarek Vasut u32 spdr; 470e6fa20bSMarek Vasut u8 spscr; 480e6fa20bSMarek Vasut u8 spssr; 490e6fa20bSMarek Vasut u8 spbr; 500e6fa20bSMarek Vasut u8 spdcr; 510e6fa20bSMarek Vasut u8 spckd; 520e6fa20bSMarek Vasut u8 sslnd; 530e6fa20bSMarek Vasut u8 spnd; 540e6fa20bSMarek Vasut u8 dummy0; 550e6fa20bSMarek Vasut u16 spcmd0; 560e6fa20bSMarek Vasut u16 spcmd1; 570e6fa20bSMarek Vasut u16 spcmd2; 580e6fa20bSMarek Vasut u16 spcmd3; 590e6fa20bSMarek Vasut u8 spbfcr; 600e6fa20bSMarek Vasut u8 dummy1; 610e6fa20bSMarek Vasut u16 spbdcr; 620e6fa20bSMarek Vasut u32 spbmul0; 630e6fa20bSMarek Vasut u32 spbmul1; 640e6fa20bSMarek Vasut u32 spbmul2; 650e6fa20bSMarek Vasut u32 spbmul3; 6616f47c9cSNobuhiro Iwamatsu }; 6716f47c9cSNobuhiro Iwamatsu 6816f47c9cSNobuhiro Iwamatsu struct sh_qspi_slave { 6916f47c9cSNobuhiro Iwamatsu struct spi_slave slave; 7016f47c9cSNobuhiro Iwamatsu struct sh_qspi_regs *regs; 7116f47c9cSNobuhiro Iwamatsu }; 7216f47c9cSNobuhiro Iwamatsu 7316f47c9cSNobuhiro Iwamatsu static inline struct sh_qspi_slave *to_sh_qspi(struct spi_slave *slave) 7416f47c9cSNobuhiro Iwamatsu { 7516f47c9cSNobuhiro Iwamatsu return container_of(slave, struct sh_qspi_slave, slave); 7616f47c9cSNobuhiro Iwamatsu } 7716f47c9cSNobuhiro Iwamatsu 7816f47c9cSNobuhiro Iwamatsu static void sh_qspi_init(struct sh_qspi_slave *ss) 7916f47c9cSNobuhiro Iwamatsu { 8016f47c9cSNobuhiro Iwamatsu /* QSPI initialize */ 8116f47c9cSNobuhiro Iwamatsu /* Set master mode only */ 8216f47c9cSNobuhiro Iwamatsu writeb(SPCR_MSTR, &ss->regs->spcr); 8316f47c9cSNobuhiro Iwamatsu 8416f47c9cSNobuhiro Iwamatsu /* Set SSL signal level */ 8516f47c9cSNobuhiro Iwamatsu writeb(0x00, &ss->regs->sslp); 8616f47c9cSNobuhiro Iwamatsu 8716f47c9cSNobuhiro Iwamatsu /* Set MOSI signal value when transfer is in idle state */ 8816f47c9cSNobuhiro Iwamatsu writeb(SPPCR_IO3FV|SPPCR_IO2FV, &ss->regs->sppcr); 8916f47c9cSNobuhiro Iwamatsu 9016f47c9cSNobuhiro Iwamatsu /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */ 9116f47c9cSNobuhiro Iwamatsu writeb(0x01, &ss->regs->spbr); 9216f47c9cSNobuhiro Iwamatsu 9316f47c9cSNobuhiro Iwamatsu /* Disable Dummy Data Transmission */ 9416f47c9cSNobuhiro Iwamatsu writeb(0x00, &ss->regs->spdcr); 9516f47c9cSNobuhiro Iwamatsu 9616f47c9cSNobuhiro Iwamatsu /* Set clock delay value */ 9716f47c9cSNobuhiro Iwamatsu writeb(0x00, &ss->regs->spckd); 9816f47c9cSNobuhiro Iwamatsu 9916f47c9cSNobuhiro Iwamatsu /* Set SSL negation delay value */ 10016f47c9cSNobuhiro Iwamatsu writeb(0x00, &ss->regs->sslnd); 10116f47c9cSNobuhiro Iwamatsu 10216f47c9cSNobuhiro Iwamatsu /* Set next-access delay value */ 10316f47c9cSNobuhiro Iwamatsu writeb(0x00, &ss->regs->spnd); 10416f47c9cSNobuhiro Iwamatsu 10516f47c9cSNobuhiro Iwamatsu /* Set equence command */ 10616f47c9cSNobuhiro Iwamatsu writew(SPCMD_INIT2, &ss->regs->spcmd0); 10716f47c9cSNobuhiro Iwamatsu 10816f47c9cSNobuhiro Iwamatsu /* Reset transfer and receive Buffer */ 10916f47c9cSNobuhiro Iwamatsu setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); 11016f47c9cSNobuhiro Iwamatsu 11116f47c9cSNobuhiro Iwamatsu /* Clear transfer and receive Buffer control bit */ 11216f47c9cSNobuhiro Iwamatsu clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); 11316f47c9cSNobuhiro Iwamatsu 11416f47c9cSNobuhiro Iwamatsu /* Set equence control method. Use equence0 only */ 11516f47c9cSNobuhiro Iwamatsu writeb(0x00, &ss->regs->spscr); 11616f47c9cSNobuhiro Iwamatsu 11716f47c9cSNobuhiro Iwamatsu /* Enable SPI function */ 11816f47c9cSNobuhiro Iwamatsu setbits_8(&ss->regs->spcr, SPCR_SPE); 11916f47c9cSNobuhiro Iwamatsu } 12016f47c9cSNobuhiro Iwamatsu 12116f47c9cSNobuhiro Iwamatsu int spi_cs_is_valid(unsigned int bus, unsigned int cs) 12216f47c9cSNobuhiro Iwamatsu { 12316f47c9cSNobuhiro Iwamatsu return 1; 12416f47c9cSNobuhiro Iwamatsu } 12516f47c9cSNobuhiro Iwamatsu 12616f47c9cSNobuhiro Iwamatsu void spi_cs_activate(struct spi_slave *slave) 12716f47c9cSNobuhiro Iwamatsu { 12816f47c9cSNobuhiro Iwamatsu struct sh_qspi_slave *ss = to_sh_qspi(slave); 12916f47c9cSNobuhiro Iwamatsu 13016f47c9cSNobuhiro Iwamatsu /* Set master mode only */ 13116f47c9cSNobuhiro Iwamatsu writeb(SPCR_MSTR, &ss->regs->spcr); 13216f47c9cSNobuhiro Iwamatsu 13316f47c9cSNobuhiro Iwamatsu /* Set command */ 13416f47c9cSNobuhiro Iwamatsu writew(SPCMD_INIT1, &ss->regs->spcmd0); 13516f47c9cSNobuhiro Iwamatsu 13616f47c9cSNobuhiro Iwamatsu /* Reset transfer and receive Buffer */ 13716f47c9cSNobuhiro Iwamatsu setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); 13816f47c9cSNobuhiro Iwamatsu 13916f47c9cSNobuhiro Iwamatsu /* Clear transfer and receive Buffer control bit */ 14016f47c9cSNobuhiro Iwamatsu clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST); 14116f47c9cSNobuhiro Iwamatsu 14216f47c9cSNobuhiro Iwamatsu /* Set equence control method. Use equence0 only */ 14316f47c9cSNobuhiro Iwamatsu writeb(0x00, &ss->regs->spscr); 14416f47c9cSNobuhiro Iwamatsu 14516f47c9cSNobuhiro Iwamatsu /* Enable SPI function */ 14616f47c9cSNobuhiro Iwamatsu setbits_8(&ss->regs->spcr, SPCR_SPE); 14716f47c9cSNobuhiro Iwamatsu } 14816f47c9cSNobuhiro Iwamatsu 14916f47c9cSNobuhiro Iwamatsu void spi_cs_deactivate(struct spi_slave *slave) 15016f47c9cSNobuhiro Iwamatsu { 15116f47c9cSNobuhiro Iwamatsu struct sh_qspi_slave *ss = to_sh_qspi(slave); 15216f47c9cSNobuhiro Iwamatsu 15316f47c9cSNobuhiro Iwamatsu /* Disable SPI Function */ 15416f47c9cSNobuhiro Iwamatsu clrbits_8(&ss->regs->spcr, SPCR_SPE); 15516f47c9cSNobuhiro Iwamatsu } 15616f47c9cSNobuhiro Iwamatsu 15716f47c9cSNobuhiro Iwamatsu void spi_init(void) 15816f47c9cSNobuhiro Iwamatsu { 15916f47c9cSNobuhiro Iwamatsu /* nothing to do */ 16016f47c9cSNobuhiro Iwamatsu } 16116f47c9cSNobuhiro Iwamatsu 16216f47c9cSNobuhiro Iwamatsu struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, 16316f47c9cSNobuhiro Iwamatsu unsigned int max_hz, unsigned int mode) 16416f47c9cSNobuhiro Iwamatsu { 16516f47c9cSNobuhiro Iwamatsu struct sh_qspi_slave *ss; 16616f47c9cSNobuhiro Iwamatsu 16716f47c9cSNobuhiro Iwamatsu if (!spi_cs_is_valid(bus, cs)) 16816f47c9cSNobuhiro Iwamatsu return NULL; 16916f47c9cSNobuhiro Iwamatsu 17016f47c9cSNobuhiro Iwamatsu ss = spi_alloc_slave(struct sh_qspi_slave, bus, cs); 17116f47c9cSNobuhiro Iwamatsu if (!ss) { 17216f47c9cSNobuhiro Iwamatsu printf("SPI_error: Fail to allocate sh_qspi_slave\n"); 17316f47c9cSNobuhiro Iwamatsu return NULL; 17416f47c9cSNobuhiro Iwamatsu } 17516f47c9cSNobuhiro Iwamatsu 17622e75d6dSNobuhiro Iwamatsu ss->regs = (struct sh_qspi_regs *)SH_QSPI_BASE; 17716f47c9cSNobuhiro Iwamatsu 17816f47c9cSNobuhiro Iwamatsu /* Init SH QSPI */ 17916f47c9cSNobuhiro Iwamatsu sh_qspi_init(ss); 18016f47c9cSNobuhiro Iwamatsu 18116f47c9cSNobuhiro Iwamatsu return &ss->slave; 18216f47c9cSNobuhiro Iwamatsu } 18316f47c9cSNobuhiro Iwamatsu 18416f47c9cSNobuhiro Iwamatsu void spi_free_slave(struct spi_slave *slave) 18516f47c9cSNobuhiro Iwamatsu { 18616f47c9cSNobuhiro Iwamatsu struct sh_qspi_slave *spi = to_sh_qspi(slave); 18716f47c9cSNobuhiro Iwamatsu 18816f47c9cSNobuhiro Iwamatsu free(spi); 18916f47c9cSNobuhiro Iwamatsu } 19016f47c9cSNobuhiro Iwamatsu 19116f47c9cSNobuhiro Iwamatsu int spi_claim_bus(struct spi_slave *slave) 19216f47c9cSNobuhiro Iwamatsu { 19316f47c9cSNobuhiro Iwamatsu return 0; 19416f47c9cSNobuhiro Iwamatsu } 19516f47c9cSNobuhiro Iwamatsu 19616f47c9cSNobuhiro Iwamatsu void spi_release_bus(struct spi_slave *slave) 19716f47c9cSNobuhiro Iwamatsu { 19816f47c9cSNobuhiro Iwamatsu } 19916f47c9cSNobuhiro Iwamatsu 20016f47c9cSNobuhiro Iwamatsu int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, 20116f47c9cSNobuhiro Iwamatsu void *din, unsigned long flags) 20216f47c9cSNobuhiro Iwamatsu { 20316f47c9cSNobuhiro Iwamatsu struct sh_qspi_slave *ss = to_sh_qspi(slave); 2040e6fa20bSMarek Vasut u32 nbyte; 20516f47c9cSNobuhiro Iwamatsu int ret = 0; 2060e6fa20bSMarek Vasut u8 dtdata = 0, drdata; 2070e6fa20bSMarek Vasut u8 *tdata = &dtdata, *rdata = &drdata; 2080e6fa20bSMarek Vasut u32 *spbmul0 = &ss->regs->spbmul0; 20916f47c9cSNobuhiro Iwamatsu 21016f47c9cSNobuhiro Iwamatsu if (dout == NULL && din == NULL) { 21116f47c9cSNobuhiro Iwamatsu if (flags & SPI_XFER_END) 21216f47c9cSNobuhiro Iwamatsu spi_cs_deactivate(slave); 21316f47c9cSNobuhiro Iwamatsu return 0; 21416f47c9cSNobuhiro Iwamatsu } 21516f47c9cSNobuhiro Iwamatsu 21616f47c9cSNobuhiro Iwamatsu if (bitlen % 8) { 21716f47c9cSNobuhiro Iwamatsu printf("%s: bitlen is not 8bit alined %d", __func__, bitlen); 21816f47c9cSNobuhiro Iwamatsu return 1; 21916f47c9cSNobuhiro Iwamatsu } 22016f47c9cSNobuhiro Iwamatsu 22116f47c9cSNobuhiro Iwamatsu nbyte = bitlen / 8; 22216f47c9cSNobuhiro Iwamatsu 22316f47c9cSNobuhiro Iwamatsu if (flags & SPI_XFER_BEGIN) { 22416f47c9cSNobuhiro Iwamatsu spi_cs_activate(slave); 22516f47c9cSNobuhiro Iwamatsu 22616f47c9cSNobuhiro Iwamatsu /* Set 1048576 byte */ 22716f47c9cSNobuhiro Iwamatsu writel(0x100000, spbmul0); 22816f47c9cSNobuhiro Iwamatsu } 22916f47c9cSNobuhiro Iwamatsu 23016f47c9cSNobuhiro Iwamatsu if (flags & SPI_XFER_END) 23116f47c9cSNobuhiro Iwamatsu writel(nbyte, spbmul0); 23216f47c9cSNobuhiro Iwamatsu 23316f47c9cSNobuhiro Iwamatsu if (dout != NULL) 2340e6fa20bSMarek Vasut tdata = (u8 *)dout; 23516f47c9cSNobuhiro Iwamatsu 23616f47c9cSNobuhiro Iwamatsu if (din != NULL) 23716f47c9cSNobuhiro Iwamatsu rdata = din; 23816f47c9cSNobuhiro Iwamatsu 23916f47c9cSNobuhiro Iwamatsu while (nbyte > 0) { 240*9573db65SMarek Vasut ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPTEF, 241*9573db65SMarek Vasut true, 1000, true); 242*9573db65SMarek Vasut if (ret) 243*9573db65SMarek Vasut return ret; 24416f47c9cSNobuhiro Iwamatsu 2450e6fa20bSMarek Vasut writeb(*tdata, (u8 *)(&ss->regs->spdr)); 24616f47c9cSNobuhiro Iwamatsu 247*9573db65SMarek Vasut ret = wait_for_bit_8(&ss->regs->spsr, SPSR_SPRFF, 248*9573db65SMarek Vasut true, 1000, true); 249*9573db65SMarek Vasut if (ret) 250*9573db65SMarek Vasut return ret; 25116f47c9cSNobuhiro Iwamatsu 2520e6fa20bSMarek Vasut *rdata = readb((u8 *)(&ss->regs->spdr)); 25316f47c9cSNobuhiro Iwamatsu 25416f47c9cSNobuhiro Iwamatsu if (dout != NULL) 25516f47c9cSNobuhiro Iwamatsu tdata++; 25616f47c9cSNobuhiro Iwamatsu if (din != NULL) 25716f47c9cSNobuhiro Iwamatsu rdata++; 25816f47c9cSNobuhiro Iwamatsu 25916f47c9cSNobuhiro Iwamatsu nbyte--; 26016f47c9cSNobuhiro Iwamatsu } 26116f47c9cSNobuhiro Iwamatsu 26216f47c9cSNobuhiro Iwamatsu if (flags & SPI_XFER_END) 26316f47c9cSNobuhiro Iwamatsu spi_cs_deactivate(slave); 26416f47c9cSNobuhiro Iwamatsu 26516f47c9cSNobuhiro Iwamatsu return ret; 26616f47c9cSNobuhiro Iwamatsu } 267