blob: fc0e1fc336f0c24e4a17c84953cd25a0c90db19e [file] [log] [blame]
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +09001/*
2 * SH QSPI (Quad SPI) driver
3 *
4 * Copyright (C) 2013 Renesas Electronics Corporation
5 * Copyright (C) 2013 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
6 *
7 * SPDX-License-Identifier: GPL-2.0
8 */
9
10#include <common.h>
Simon Glass24b852a2015-11-08 23:47:45 -070011#include <console.h>
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +090012#include <malloc.h>
13#include <spi.h>
Nobuhiro Iwamatsu22e75d62014-01-08 10:16:25 +090014#include <asm/arch/rmobile.h>
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +090015#include <asm/io.h>
16
17/* SH QSPI register bit masks <REG>_<BIT> */
18#define SPCR_MSTR 0x08
19#define SPCR_SPE 0x40
20#define SPSR_SPRFF 0x80
21#define SPSR_SPTEF 0x20
22#define SPPCR_IO3FV 0x04
23#define SPPCR_IO2FV 0x02
24#define SPPCR_IO1FV 0x01
Jagan Tekiccaa9482015-10-23 01:38:47 +053025#define SPBDCR_RXBC0 BIT(0)
26#define SPCMD_SCKDEN BIT(15)
27#define SPCMD_SLNDEN BIT(14)
28#define SPCMD_SPNDEN BIT(13)
29#define SPCMD_SSLKP BIT(7)
30#define SPCMD_BRDV0 BIT(2)
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +090031#define SPCMD_INIT1 SPCMD_SCKDEN | SPCMD_SLNDEN | \
32 SPCMD_SPNDEN | SPCMD_SSLKP | \
33 SPCMD_BRDV0
34#define SPCMD_INIT2 SPCMD_SPNDEN | SPCMD_SSLKP | \
35 SPCMD_BRDV0
Jagan Tekiccaa9482015-10-23 01:38:47 +053036#define SPBFCR_TXRST BIT(7)
37#define SPBFCR_RXRST BIT(6)
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +090038
39/* SH QSPI register set */
40struct sh_qspi_regs {
Marek Vasut0e6fa202018-04-10 16:47:38 +020041 u8 spcr;
42 u8 sslp;
43 u8 sppcr;
44 u8 spsr;
45 u32 spdr;
46 u8 spscr;
47 u8 spssr;
48 u8 spbr;
49 u8 spdcr;
50 u8 spckd;
51 u8 sslnd;
52 u8 spnd;
53 u8 dummy0;
54 u16 spcmd0;
55 u16 spcmd1;
56 u16 spcmd2;
57 u16 spcmd3;
58 u8 spbfcr;
59 u8 dummy1;
60 u16 spbdcr;
61 u32 spbmul0;
62 u32 spbmul1;
63 u32 spbmul2;
64 u32 spbmul3;
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +090065};
66
67struct sh_qspi_slave {
68 struct spi_slave slave;
69 struct sh_qspi_regs *regs;
70};
71
72static inline struct sh_qspi_slave *to_sh_qspi(struct spi_slave *slave)
73{
74 return container_of(slave, struct sh_qspi_slave, slave);
75}
76
77static void sh_qspi_init(struct sh_qspi_slave *ss)
78{
79 /* QSPI initialize */
80 /* Set master mode only */
81 writeb(SPCR_MSTR, &ss->regs->spcr);
82
83 /* Set SSL signal level */
84 writeb(0x00, &ss->regs->sslp);
85
86 /* Set MOSI signal value when transfer is in idle state */
87 writeb(SPPCR_IO3FV|SPPCR_IO2FV, &ss->regs->sppcr);
88
89 /* Set bit rate. See 58.3.8 Quad Serial Peripheral Interface */
90 writeb(0x01, &ss->regs->spbr);
91
92 /* Disable Dummy Data Transmission */
93 writeb(0x00, &ss->regs->spdcr);
94
95 /* Set clock delay value */
96 writeb(0x00, &ss->regs->spckd);
97
98 /* Set SSL negation delay value */
99 writeb(0x00, &ss->regs->sslnd);
100
101 /* Set next-access delay value */
102 writeb(0x00, &ss->regs->spnd);
103
104 /* Set equence command */
105 writew(SPCMD_INIT2, &ss->regs->spcmd0);
106
107 /* Reset transfer and receive Buffer */
108 setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
109
110 /* Clear transfer and receive Buffer control bit */
111 clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
112
113 /* Set equence control method. Use equence0 only */
114 writeb(0x00, &ss->regs->spscr);
115
116 /* Enable SPI function */
117 setbits_8(&ss->regs->spcr, SPCR_SPE);
118}
119
120int spi_cs_is_valid(unsigned int bus, unsigned int cs)
121{
122 return 1;
123}
124
125void spi_cs_activate(struct spi_slave *slave)
126{
127 struct sh_qspi_slave *ss = to_sh_qspi(slave);
128
129 /* Set master mode only */
130 writeb(SPCR_MSTR, &ss->regs->spcr);
131
132 /* Set command */
133 writew(SPCMD_INIT1, &ss->regs->spcmd0);
134
135 /* Reset transfer and receive Buffer */
136 setbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
137
138 /* Clear transfer and receive Buffer control bit */
139 clrbits_8(&ss->regs->spbfcr, SPBFCR_TXRST|SPBFCR_RXRST);
140
141 /* Set equence control method. Use equence0 only */
142 writeb(0x00, &ss->regs->spscr);
143
144 /* Enable SPI function */
145 setbits_8(&ss->regs->spcr, SPCR_SPE);
146}
147
148void spi_cs_deactivate(struct spi_slave *slave)
149{
150 struct sh_qspi_slave *ss = to_sh_qspi(slave);
151
152 /* Disable SPI Function */
153 clrbits_8(&ss->regs->spcr, SPCR_SPE);
154}
155
156void spi_init(void)
157{
158 /* nothing to do */
159}
160
161struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
162 unsigned int max_hz, unsigned int mode)
163{
164 struct sh_qspi_slave *ss;
165
166 if (!spi_cs_is_valid(bus, cs))
167 return NULL;
168
169 ss = spi_alloc_slave(struct sh_qspi_slave, bus, cs);
170 if (!ss) {
171 printf("SPI_error: Fail to allocate sh_qspi_slave\n");
172 return NULL;
173 }
174
Nobuhiro Iwamatsu22e75d62014-01-08 10:16:25 +0900175 ss->regs = (struct sh_qspi_regs *)SH_QSPI_BASE;
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +0900176
177 /* Init SH QSPI */
178 sh_qspi_init(ss);
179
180 return &ss->slave;
181}
182
183void spi_free_slave(struct spi_slave *slave)
184{
185 struct sh_qspi_slave *spi = to_sh_qspi(slave);
186
187 free(spi);
188}
189
190int spi_claim_bus(struct spi_slave *slave)
191{
192 return 0;
193}
194
195void spi_release_bus(struct spi_slave *slave)
196{
197}
198
199int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
200 void *din, unsigned long flags)
201{
202 struct sh_qspi_slave *ss = to_sh_qspi(slave);
Marek Vasut0e6fa202018-04-10 16:47:38 +0200203 u32 nbyte;
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +0900204 int ret = 0;
Marek Vasut0e6fa202018-04-10 16:47:38 +0200205 u8 dtdata = 0, drdata;
206 u8 *tdata = &dtdata, *rdata = &drdata;
207 u32 *spbmul0 = &ss->regs->spbmul0;
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +0900208
209 if (dout == NULL && din == NULL) {
210 if (flags & SPI_XFER_END)
211 spi_cs_deactivate(slave);
212 return 0;
213 }
214
215 if (bitlen % 8) {
216 printf("%s: bitlen is not 8bit alined %d", __func__, bitlen);
217 return 1;
218 }
219
220 nbyte = bitlen / 8;
221
222 if (flags & SPI_XFER_BEGIN) {
223 spi_cs_activate(slave);
224
225 /* Set 1048576 byte */
226 writel(0x100000, spbmul0);
227 }
228
229 if (flags & SPI_XFER_END)
230 writel(nbyte, spbmul0);
231
232 if (dout != NULL)
Marek Vasut0e6fa202018-04-10 16:47:38 +0200233 tdata = (u8 *)dout;
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +0900234
235 if (din != NULL)
236 rdata = din;
237
238 while (nbyte > 0) {
239 while (!(readb(&ss->regs->spsr) & SPSR_SPTEF)) {
240 if (ctrlc()) {
241 puts("abort\n");
242 return 1;
243 }
244 udelay(10);
245 }
246
Marek Vasut0e6fa202018-04-10 16:47:38 +0200247 writeb(*tdata, (u8 *)(&ss->regs->spdr));
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +0900248
249 while ((readw(&ss->regs->spbdcr) != SPBDCR_RXBC0)) {
250 if (ctrlc()) {
251 puts("abort\n");
252 return 1;
253 }
254 udelay(1);
255 }
256
257 while (!(readb(&ss->regs->spsr) & SPSR_SPRFF)) {
258 if (ctrlc()) {
259 puts("abort\n");
260 return 1;
261 }
262 udelay(10);
263 }
264
Marek Vasut0e6fa202018-04-10 16:47:38 +0200265 *rdata = readb((u8 *)(&ss->regs->spdr));
Nobuhiro Iwamatsu16f47c92013-12-18 15:31:55 +0900266
267 if (dout != NULL)
268 tdata++;
269 if (din != NULL)
270 rdata++;
271
272 nbyte--;
273 }
274
275 if (flags & SPI_XFER_END)
276 spi_cs_deactivate(slave);
277
278 return ret;
279}