xref: /openbmc/u-boot/drivers/spi/sh_qspi.c (revision 22e75d6d)
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>
1116f47c9cSNobuhiro Iwamatsu #include <malloc.h>
1216f47c9cSNobuhiro Iwamatsu #include <spi.h>
13*22e75d6dSNobuhiro Iwamatsu #include <asm/arch/rmobile.h>
1416f47c9cSNobuhiro Iwamatsu #include <asm/io.h>
1516f47c9cSNobuhiro Iwamatsu 
1616f47c9cSNobuhiro Iwamatsu /* SH QSPI register bit masks <REG>_<BIT> */
1716f47c9cSNobuhiro Iwamatsu #define SPCR_MSTR	0x08
1816f47c9cSNobuhiro Iwamatsu #define SPCR_SPE	0x40
1916f47c9cSNobuhiro Iwamatsu #define SPSR_SPRFF	0x80
2016f47c9cSNobuhiro Iwamatsu #define SPSR_SPTEF	0x20
2116f47c9cSNobuhiro Iwamatsu #define SPPCR_IO3FV	0x04
2216f47c9cSNobuhiro Iwamatsu #define SPPCR_IO2FV	0x02
2316f47c9cSNobuhiro Iwamatsu #define SPPCR_IO1FV	0x01
2416f47c9cSNobuhiro Iwamatsu #define SPBDCR_RXBC0	(1 << 0)
2516f47c9cSNobuhiro Iwamatsu #define SPCMD_SCKDEN	(1 << 15)
2616f47c9cSNobuhiro Iwamatsu #define SPCMD_SLNDEN	(1 << 14)
2716f47c9cSNobuhiro Iwamatsu #define SPCMD_SPNDEN	(1 << 13)
2816f47c9cSNobuhiro Iwamatsu #define SPCMD_SSLKP	(1 << 7)
2916f47c9cSNobuhiro Iwamatsu #define SPCMD_BRDV0	(1 << 2)
3016f47c9cSNobuhiro Iwamatsu #define SPCMD_INIT1	SPCMD_SCKDEN | SPCMD_SLNDEN | \
3116f47c9cSNobuhiro Iwamatsu 			SPCMD_SPNDEN | SPCMD_SSLKP | \
3216f47c9cSNobuhiro Iwamatsu 			SPCMD_BRDV0
3316f47c9cSNobuhiro Iwamatsu #define SPCMD_INIT2	SPCMD_SPNDEN | SPCMD_SSLKP | \
3416f47c9cSNobuhiro Iwamatsu 			SPCMD_BRDV0
3516f47c9cSNobuhiro Iwamatsu #define SPBFCR_TXRST	(1 << 7)
3616f47c9cSNobuhiro Iwamatsu #define SPBFCR_RXRST	(1 << 6)
3716f47c9cSNobuhiro Iwamatsu 
3816f47c9cSNobuhiro Iwamatsu /* SH QSPI register set */
3916f47c9cSNobuhiro Iwamatsu struct sh_qspi_regs {
4016f47c9cSNobuhiro Iwamatsu 	unsigned char spcr;
4116f47c9cSNobuhiro Iwamatsu 	unsigned char sslp;
4216f47c9cSNobuhiro Iwamatsu 	unsigned char sppcr;
4316f47c9cSNobuhiro Iwamatsu 	unsigned char spsr;
4416f47c9cSNobuhiro Iwamatsu 	unsigned long spdr;
4516f47c9cSNobuhiro Iwamatsu 	unsigned char spscr;
4616f47c9cSNobuhiro Iwamatsu 	unsigned char spssr;
4716f47c9cSNobuhiro Iwamatsu 	unsigned char spbr;
4816f47c9cSNobuhiro Iwamatsu 	unsigned char spdcr;
4916f47c9cSNobuhiro Iwamatsu 	unsigned char spckd;
5016f47c9cSNobuhiro Iwamatsu 	unsigned char sslnd;
5116f47c9cSNobuhiro Iwamatsu 	unsigned char spnd;
5216f47c9cSNobuhiro Iwamatsu 	unsigned char dummy0;
5316f47c9cSNobuhiro Iwamatsu 	unsigned short spcmd0;
5416f47c9cSNobuhiro Iwamatsu 	unsigned short spcmd1;
5516f47c9cSNobuhiro Iwamatsu 	unsigned short spcmd2;
5616f47c9cSNobuhiro Iwamatsu 	unsigned short spcmd3;
5716f47c9cSNobuhiro Iwamatsu 	unsigned char spbfcr;
5816f47c9cSNobuhiro Iwamatsu 	unsigned char dummy1;
5916f47c9cSNobuhiro Iwamatsu 	unsigned short spbdcr;
6016f47c9cSNobuhiro Iwamatsu 	unsigned long spbmul0;
6116f47c9cSNobuhiro Iwamatsu 	unsigned long spbmul1;
6216f47c9cSNobuhiro Iwamatsu 	unsigned long spbmul2;
6316f47c9cSNobuhiro Iwamatsu 	unsigned long spbmul3;
6416f47c9cSNobuhiro Iwamatsu };
6516f47c9cSNobuhiro Iwamatsu 
6616f47c9cSNobuhiro Iwamatsu struct sh_qspi_slave {
6716f47c9cSNobuhiro Iwamatsu 	struct spi_slave	slave;
6816f47c9cSNobuhiro Iwamatsu 	struct sh_qspi_regs	*regs;
6916f47c9cSNobuhiro Iwamatsu };
7016f47c9cSNobuhiro Iwamatsu 
7116f47c9cSNobuhiro Iwamatsu static inline struct sh_qspi_slave *to_sh_qspi(struct spi_slave *slave)
7216f47c9cSNobuhiro Iwamatsu {
7316f47c9cSNobuhiro Iwamatsu 	return container_of(slave, struct sh_qspi_slave, slave);
7416f47c9cSNobuhiro Iwamatsu }
7516f47c9cSNobuhiro Iwamatsu 
7616f47c9cSNobuhiro Iwamatsu static void sh_qspi_init(struct sh_qspi_slave *ss)
7716f47c9cSNobuhiro Iwamatsu {
7816f47c9cSNobuhiro Iwamatsu 	/* QSPI initialize */
7916f47c9cSNobuhiro Iwamatsu 	/* Set master mode only */
8016f47c9cSNobuhiro Iwamatsu 	writeb(SPCR_MSTR, &ss->regs->spcr);
8116f47c9cSNobuhiro Iwamatsu 
8216f47c9cSNobuhiro Iwamatsu 	/* Set SSL signal level */
8316f47c9cSNobuhiro Iwamatsu 	writeb(0x00, &ss->regs->sslp);
8416f47c9cSNobuhiro Iwamatsu 
8516f47c9cSNobuhiro Iwamatsu 	/* Set MOSI signal value when transfer is in idle state */
8616f47c9cSNobuhiro Iwamatsu 	writeb(SPPCR_IO3FV|SPPCR_IO2FV, &ss->regs->sppcr);
8716f47c9cSNobuhiro Iwamatsu 
8816f47c9cSNobuhiro Iwamatsu 	/* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */
8916f47c9cSNobuhiro Iwamatsu 	writeb(0x01, &ss->regs->spbr);
9016f47c9cSNobuhiro Iwamatsu 
9116f47c9cSNobuhiro Iwamatsu 	/* Disable Dummy Data Transmission */
9216f47c9cSNobuhiro Iwamatsu 	writeb(0x00, &ss->regs->spdcr);
9316f47c9cSNobuhiro Iwamatsu 
9416f47c9cSNobuhiro Iwamatsu 	/* Set clock delay value */
9516f47c9cSNobuhiro Iwamatsu 	writeb(0x00, &ss->regs->spckd);
9616f47c9cSNobuhiro Iwamatsu 
9716f47c9cSNobuhiro Iwamatsu 	/* Set SSL negation delay value */
9816f47c9cSNobuhiro Iwamatsu 	writeb(0x00, &ss->regs->sslnd);
9916f47c9cSNobuhiro Iwamatsu 
10016f47c9cSNobuhiro Iwamatsu 	/* Set next-access delay value */
10116f47c9cSNobuhiro Iwamatsu 	writeb(0x00, &ss->regs->spnd);
10216f47c9cSNobuhiro Iwamatsu 
10316f47c9cSNobuhiro Iwamatsu 	/* Set equence command */
10416f47c9cSNobuhiro Iwamatsu 	writew(SPCMD_INIT2, &ss->regs->spcmd0);
10516f47c9cSNobuhiro Iwamatsu 
10616f47c9cSNobuhiro Iwamatsu 	/* Reset transfer and receive Buffer */
10716f47c9cSNobuhiro Iwamatsu 	setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
10816f47c9cSNobuhiro Iwamatsu 
10916f47c9cSNobuhiro Iwamatsu 	/* Clear transfer and receive Buffer control bit */
11016f47c9cSNobuhiro Iwamatsu 	clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
11116f47c9cSNobuhiro Iwamatsu 
11216f47c9cSNobuhiro Iwamatsu 	/* Set equence control method. Use equence0 only */
11316f47c9cSNobuhiro Iwamatsu 	writeb(0x00, &ss->regs->spscr);
11416f47c9cSNobuhiro Iwamatsu 
11516f47c9cSNobuhiro Iwamatsu 	/* Enable SPI function */
11616f47c9cSNobuhiro Iwamatsu 	setbits_8(&ss->regs->spcr, SPCR_SPE);
11716f47c9cSNobuhiro Iwamatsu }
11816f47c9cSNobuhiro Iwamatsu 
11916f47c9cSNobuhiro Iwamatsu int spi_cs_is_valid(unsigned int bus, unsigned int cs)
12016f47c9cSNobuhiro Iwamatsu {
12116f47c9cSNobuhiro Iwamatsu 	return 1;
12216f47c9cSNobuhiro Iwamatsu }
12316f47c9cSNobuhiro Iwamatsu 
12416f47c9cSNobuhiro Iwamatsu void spi_cs_activate(struct spi_slave *slave)
12516f47c9cSNobuhiro Iwamatsu {
12616f47c9cSNobuhiro Iwamatsu 	struct sh_qspi_slave *ss = to_sh_qspi(slave);
12716f47c9cSNobuhiro Iwamatsu 
12816f47c9cSNobuhiro Iwamatsu 	/* Set master mode only */
12916f47c9cSNobuhiro Iwamatsu 	writeb(SPCR_MSTR, &ss->regs->spcr);
13016f47c9cSNobuhiro Iwamatsu 
13116f47c9cSNobuhiro Iwamatsu 	/* Set command */
13216f47c9cSNobuhiro Iwamatsu 	writew(SPCMD_INIT1, &ss->regs->spcmd0);
13316f47c9cSNobuhiro Iwamatsu 
13416f47c9cSNobuhiro Iwamatsu 	/* Reset transfer and receive Buffer */
13516f47c9cSNobuhiro Iwamatsu 	setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
13616f47c9cSNobuhiro Iwamatsu 
13716f47c9cSNobuhiro Iwamatsu 	/* Clear transfer and receive Buffer control bit */
13816f47c9cSNobuhiro Iwamatsu 	clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
13916f47c9cSNobuhiro Iwamatsu 
14016f47c9cSNobuhiro Iwamatsu 	/* Set equence control method. Use equence0 only */
14116f47c9cSNobuhiro Iwamatsu 	writeb(0x00, &ss->regs->spscr);
14216f47c9cSNobuhiro Iwamatsu 
14316f47c9cSNobuhiro Iwamatsu 	/* Enable SPI function */
14416f47c9cSNobuhiro Iwamatsu 	setbits_8(&ss->regs->spcr, SPCR_SPE);
14516f47c9cSNobuhiro Iwamatsu }
14616f47c9cSNobuhiro Iwamatsu 
14716f47c9cSNobuhiro Iwamatsu void spi_cs_deactivate(struct spi_slave *slave)
14816f47c9cSNobuhiro Iwamatsu {
14916f47c9cSNobuhiro Iwamatsu 	struct sh_qspi_slave *ss = to_sh_qspi(slave);
15016f47c9cSNobuhiro Iwamatsu 
15116f47c9cSNobuhiro Iwamatsu 	/* Disable SPI Function */
15216f47c9cSNobuhiro Iwamatsu 	clrbits_8(&ss->regs->spcr, SPCR_SPE);
15316f47c9cSNobuhiro Iwamatsu }
15416f47c9cSNobuhiro Iwamatsu 
15516f47c9cSNobuhiro Iwamatsu void spi_init(void)
15616f47c9cSNobuhiro Iwamatsu {
15716f47c9cSNobuhiro Iwamatsu 	/* nothing to do */
15816f47c9cSNobuhiro Iwamatsu }
15916f47c9cSNobuhiro Iwamatsu 
16016f47c9cSNobuhiro Iwamatsu struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
16116f47c9cSNobuhiro Iwamatsu 		unsigned int max_hz, unsigned int mode)
16216f47c9cSNobuhiro Iwamatsu {
16316f47c9cSNobuhiro Iwamatsu 	struct sh_qspi_slave *ss;
16416f47c9cSNobuhiro Iwamatsu 
16516f47c9cSNobuhiro Iwamatsu 	if (!spi_cs_is_valid(bus, cs))
16616f47c9cSNobuhiro Iwamatsu 		return NULL;
16716f47c9cSNobuhiro Iwamatsu 
16816f47c9cSNobuhiro Iwamatsu 	ss = spi_alloc_slave(struct sh_qspi_slave, bus, cs);
16916f47c9cSNobuhiro Iwamatsu 	if (!ss) {
17016f47c9cSNobuhiro Iwamatsu 		printf("SPI_error: Fail to allocate sh_qspi_slave\n");
17116f47c9cSNobuhiro Iwamatsu 		return NULL;
17216f47c9cSNobuhiro Iwamatsu 	}
17316f47c9cSNobuhiro Iwamatsu 
174*22e75d6dSNobuhiro Iwamatsu 	ss->regs = (struct sh_qspi_regs *)SH_QSPI_BASE;
17516f47c9cSNobuhiro Iwamatsu 
17616f47c9cSNobuhiro Iwamatsu 	/* Init SH QSPI */
17716f47c9cSNobuhiro Iwamatsu 	sh_qspi_init(ss);
17816f47c9cSNobuhiro Iwamatsu 
17916f47c9cSNobuhiro Iwamatsu 	return &ss->slave;
18016f47c9cSNobuhiro Iwamatsu }
18116f47c9cSNobuhiro Iwamatsu 
18216f47c9cSNobuhiro Iwamatsu void spi_free_slave(struct spi_slave *slave)
18316f47c9cSNobuhiro Iwamatsu {
18416f47c9cSNobuhiro Iwamatsu 	struct sh_qspi_slave *spi = to_sh_qspi(slave);
18516f47c9cSNobuhiro Iwamatsu 
18616f47c9cSNobuhiro Iwamatsu 	free(spi);
18716f47c9cSNobuhiro Iwamatsu }
18816f47c9cSNobuhiro Iwamatsu 
18916f47c9cSNobuhiro Iwamatsu int spi_claim_bus(struct spi_slave *slave)
19016f47c9cSNobuhiro Iwamatsu {
19116f47c9cSNobuhiro Iwamatsu 	return 0;
19216f47c9cSNobuhiro Iwamatsu }
19316f47c9cSNobuhiro Iwamatsu 
19416f47c9cSNobuhiro Iwamatsu void spi_release_bus(struct spi_slave *slave)
19516f47c9cSNobuhiro Iwamatsu {
19616f47c9cSNobuhiro Iwamatsu }
19716f47c9cSNobuhiro Iwamatsu 
19816f47c9cSNobuhiro Iwamatsu int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
19916f47c9cSNobuhiro Iwamatsu 	     void *din, unsigned long flags)
20016f47c9cSNobuhiro Iwamatsu {
20116f47c9cSNobuhiro Iwamatsu 	struct sh_qspi_slave *ss = to_sh_qspi(slave);
20216f47c9cSNobuhiro Iwamatsu 	unsigned long nbyte;
20316f47c9cSNobuhiro Iwamatsu 	int ret = 0;
20416f47c9cSNobuhiro Iwamatsu 	unsigned char dtdata = 0, drdata;
20516f47c9cSNobuhiro Iwamatsu 	unsigned char *tdata = &dtdata, *rdata = &drdata;
20616f47c9cSNobuhiro Iwamatsu 	unsigned long *spbmul0 = &ss->regs->spbmul0;
20716f47c9cSNobuhiro Iwamatsu 
20816f47c9cSNobuhiro Iwamatsu 	if (dout == NULL && din == NULL) {
20916f47c9cSNobuhiro Iwamatsu 		if (flags & SPI_XFER_END)
21016f47c9cSNobuhiro Iwamatsu 			spi_cs_deactivate(slave);
21116f47c9cSNobuhiro Iwamatsu 		return 0;
21216f47c9cSNobuhiro Iwamatsu 	}
21316f47c9cSNobuhiro Iwamatsu 
21416f47c9cSNobuhiro Iwamatsu 	if (bitlen % 8) {
21516f47c9cSNobuhiro Iwamatsu 		printf("%s: bitlen is not 8bit alined %d", __func__, bitlen);
21616f47c9cSNobuhiro Iwamatsu 		return 1;
21716f47c9cSNobuhiro Iwamatsu 	}
21816f47c9cSNobuhiro Iwamatsu 
21916f47c9cSNobuhiro Iwamatsu 	nbyte = bitlen / 8;
22016f47c9cSNobuhiro Iwamatsu 
22116f47c9cSNobuhiro Iwamatsu 	if (flags & SPI_XFER_BEGIN) {
22216f47c9cSNobuhiro Iwamatsu 		spi_cs_activate(slave);
22316f47c9cSNobuhiro Iwamatsu 
22416f47c9cSNobuhiro Iwamatsu 		/* Set 1048576 byte */
22516f47c9cSNobuhiro Iwamatsu 		writel(0x100000, spbmul0);
22616f47c9cSNobuhiro Iwamatsu 	}
22716f47c9cSNobuhiro Iwamatsu 
22816f47c9cSNobuhiro Iwamatsu 	if (flags & SPI_XFER_END)
22916f47c9cSNobuhiro Iwamatsu 		writel(nbyte, spbmul0);
23016f47c9cSNobuhiro Iwamatsu 
23116f47c9cSNobuhiro Iwamatsu 	if (dout != NULL)
23216f47c9cSNobuhiro Iwamatsu 		tdata = (unsigned char *)dout;
23316f47c9cSNobuhiro Iwamatsu 
23416f47c9cSNobuhiro Iwamatsu 	if (din != NULL)
23516f47c9cSNobuhiro Iwamatsu 		rdata = din;
23616f47c9cSNobuhiro Iwamatsu 
23716f47c9cSNobuhiro Iwamatsu 	while (nbyte > 0) {
23816f47c9cSNobuhiro Iwamatsu 		while (!(readb(&ss->regs->spsr) & SPSR_SPTEF)) {
23916f47c9cSNobuhiro Iwamatsu 			if (ctrlc()) {
24016f47c9cSNobuhiro Iwamatsu 				puts("abort\n");
24116f47c9cSNobuhiro Iwamatsu 				return 1;
24216f47c9cSNobuhiro Iwamatsu 			}
24316f47c9cSNobuhiro Iwamatsu 			udelay(10);
24416f47c9cSNobuhiro Iwamatsu 		}
24516f47c9cSNobuhiro Iwamatsu 
24616f47c9cSNobuhiro Iwamatsu 		writeb(*tdata, (unsigned char *)(&ss->regs->spdr));
24716f47c9cSNobuhiro Iwamatsu 
24816f47c9cSNobuhiro Iwamatsu 		while ((readw(&ss->regs->spbdcr) != SPBDCR_RXBC0)) {
24916f47c9cSNobuhiro Iwamatsu 			if (ctrlc()) {
25016f47c9cSNobuhiro Iwamatsu 				puts("abort\n");
25116f47c9cSNobuhiro Iwamatsu 				return 1;
25216f47c9cSNobuhiro Iwamatsu 			}
25316f47c9cSNobuhiro Iwamatsu 			udelay(1);
25416f47c9cSNobuhiro Iwamatsu 		}
25516f47c9cSNobuhiro Iwamatsu 
25616f47c9cSNobuhiro Iwamatsu 		while (!(readb(&ss->regs->spsr) & SPSR_SPRFF)) {
25716f47c9cSNobuhiro Iwamatsu 			if (ctrlc()) {
25816f47c9cSNobuhiro Iwamatsu 				puts("abort\n");
25916f47c9cSNobuhiro Iwamatsu 				return 1;
26016f47c9cSNobuhiro Iwamatsu 			}
26116f47c9cSNobuhiro Iwamatsu 			udelay(10);
26216f47c9cSNobuhiro Iwamatsu 		}
26316f47c9cSNobuhiro Iwamatsu 
26416f47c9cSNobuhiro Iwamatsu 		*rdata = readb((unsigned char *)(&ss->regs->spdr));
26516f47c9cSNobuhiro Iwamatsu 
26616f47c9cSNobuhiro Iwamatsu 		if (dout != NULL)
26716f47c9cSNobuhiro Iwamatsu 			tdata++;
26816f47c9cSNobuhiro Iwamatsu 		if (din != NULL)
26916f47c9cSNobuhiro Iwamatsu 			rdata++;
27016f47c9cSNobuhiro Iwamatsu 
27116f47c9cSNobuhiro Iwamatsu 		nbyte--;
27216f47c9cSNobuhiro Iwamatsu 	}
27316f47c9cSNobuhiro Iwamatsu 
27416f47c9cSNobuhiro Iwamatsu 	if (flags & SPI_XFER_END)
27516f47c9cSNobuhiro Iwamatsu 		spi_cs_deactivate(slave);
27616f47c9cSNobuhiro Iwamatsu 
27716f47c9cSNobuhiro Iwamatsu 	return ret;
27816f47c9cSNobuhiro Iwamatsu }
279