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