blob: f03d453307f389ba41f8300a5cd36bd10f2fc528 [file] [log] [blame]
Daisuke Nojiria6712f32015-01-23 10:06:19 -08001/*
Corneliu Dobanb0484322015-02-18 17:25:20 -08002 * Copyright (C) 2015 Broadcom Corporation
Daisuke Nojiria6712f32015-01-23 10:06:19 -08003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
Daisuke Nojiria6712f32015-01-23 10:06:19 -080012 */
13
Corneliu Dobanb0484322015-02-18 17:25:20 -080014#include <arch/io.h>
15#include <timer.h>
16#include <delay.h>
17#include <stdlib.h>
Daisuke Nojiria6712f32015-01-23 10:06:19 -080018#include <spi-generic.h>
Corneliu Dobanb0484322015-02-18 17:25:20 -080019#include <spi_flash.h>
20#include <soc/addressmap.h>
21
22#define IPROC_QSPI_CLK 100000000
23
24/* SPI mode flags */
25#define SPI_CPHA 0x01 /* clock phase */
26#define SPI_CPOL 0x02 /* clock polarity */
27#define SPI_MODE_0 (0|0) /* original MicroWire */
28#define SPI_MODE_1 (0|SPI_CPHA)
29#define SPI_MODE_2 (SPI_CPOL|0)
30#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
31
32#define QSPI_MAX_HZ 50000000
33#define QSPI_MODE SPI_MODE_3
34
35#define QSPI_WAIT_TIMEOUT 200U /* msec */
36
37/* Controller attributes */
38#define SPBR_MIN 8U
39#define SPBR_MAX 255U
40#define NUM_TXRAM 32
41#define NUM_RXRAM 32
42#define NUM_CDRAM 16
43
44/*
45 * Register fields
46 */
47#define MSPI_SPCR0_MSB_BITS_8 0x00000020
48
49/* BSPI registers */
50#define BSPI_MAST_N_BOOT_CTRL_REG 0x008
51#define BSPI_BUSY_STATUS_REG 0x00c
52
53/* MSPI registers */
54#define MSPI_SPCR0_LSB_REG 0x200
55#define MSPI_SPCR0_MSB_REG 0x204
56#define MSPI_SPCR1_LSB_REG 0x208
57#define MSPI_SPCR1_MSB_REG 0x20c
58#define MSPI_NEWQP_REG 0x210
59#define MSPI_ENDQP_REG 0x214
60#define MSPI_SPCR2_REG 0x218
61#define MSPI_STATUS_REG 0x220
62#define MSPI_CPTQP_REG 0x224
63#define MSPI_TXRAM_REG 0x240
64#define MSPI_RXRAM_REG 0x2c0
65#define MSPI_CDRAM_REG 0x340
66#define MSPI_WRITE_LOCK_REG 0x380
67#define MSPI_DISABLE_FLUSH_GEN_REG 0x384
68
69/*
70 * Register access macros
71 */
72#define REG_RD(x) read32(x)
73#define REG_WR(x, y) write32((x), (y))
74#define REG_CLR(x, y) REG_WR((x), REG_RD(x) & ~(y))
75#define REG_SET(x, y) REG_WR((x), REG_RD(x) | (y))
76
77/* QSPI private data */
78struct qspi_priv {
Corneliu Dobanb0484322015-02-18 17:25:20 -080079 /* Specified SPI parameters */
80 unsigned int max_hz;
81 unsigned int spi_mode;
82
83 int mspi_enabled;
84 int mspi_16bit;
85
86 int bus_claimed;
87
88 /* Registers */
89 void *reg;
90};
91
92static struct qspi_priv qspi_slave;
93
Furquan Shaikh36b81af2016-12-01 01:02:44 -080094static struct qspi_priv *to_qspi_slave(const struct spi_slave *slave)
95{
96 return &qspi_slave;
97}
Daisuke Nojiria6712f32015-01-23 10:06:19 -080098
Corneliu Dobanb0484322015-02-18 17:25:20 -080099static int mspi_enable(struct qspi_priv *priv)
100{
101 struct stopwatch sw;
102
103 /* Switch to MSPI if not yet */
104 if ((REG_RD(priv->reg + BSPI_MAST_N_BOOT_CTRL_REG) & 1) == 0) {
105 stopwatch_init_msecs_expire(&sw, QSPI_WAIT_TIMEOUT);
106 while (!stopwatch_expired(&sw)) {
107 if ((REG_RD(priv->reg + BSPI_BUSY_STATUS_REG) & 1)
108 == 0) {
109 REG_WR(priv->reg + BSPI_MAST_N_BOOT_CTRL_REG,
110 1);
111 udelay(1);
112 break;
113 }
114 udelay(1);
115 }
116 if (REG_RD(priv->reg + BSPI_MAST_N_BOOT_CTRL_REG) != 1)
117 return -1;
118 }
119 priv->mspi_enabled = 1;
120 return 0;
Daisuke Nojiria6712f32015-01-23 10:06:19 -0800121}
122
Furquan Shaikh94f86992016-12-01 07:12:32 -0800123static int spi_ctrlr_claim_bus(const struct spi_slave *slave)
Daisuke Nojiria6712f32015-01-23 10:06:19 -0800124{
Corneliu Dobanb0484322015-02-18 17:25:20 -0800125 struct qspi_priv *priv = to_qspi_slave(slave);
126
127 if (priv->bus_claimed)
128 return -1;
129
130 if (!priv->mspi_enabled)
131 if (mspi_enable(priv))
132 return -1;
133
134 /* MSPI: Enable write lock */
135 REG_WR(priv->reg + MSPI_WRITE_LOCK_REG, 1);
136
137 priv->bus_claimed = 1;
138
Daisuke Nojiria6712f32015-01-23 10:06:19 -0800139 return 0;
140}
141
Furquan Shaikh94f86992016-12-01 07:12:32 -0800142static void spi_ctrlr_release_bus(const struct spi_slave *slave)
Daisuke Nojiria6712f32015-01-23 10:06:19 -0800143{
Corneliu Dobanb0484322015-02-18 17:25:20 -0800144 struct qspi_priv *priv = to_qspi_slave(slave);
145
146 /* MSPI: Disable write lock */
147 REG_WR(priv->reg + MSPI_WRITE_LOCK_REG, 0);
148
149 priv->bus_claimed = 0;
Daisuke Nojiria6712f32015-01-23 10:06:19 -0800150}
151
Corneliu Dobanb0484322015-02-18 17:25:20 -0800152#define RXRAM_16B(p, i) (REG_RD((p)->reg + MSPI_RXRAM_REG + ((i) << 2)) & 0xff)
153#define RXRAM_8B(p, i) (REG_RD((p)->reg + MSPI_RXRAM_REG + \
154 ((((i) << 1) + 1) << 2)) & 0xff)
155
Furquan Shaikh94f86992016-12-01 07:12:32 -0800156static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
157 size_t bytesout, void *din, size_t bytesin)
Daisuke Nojiria6712f32015-01-23 10:06:19 -0800158{
Corneliu Dobanb0484322015-02-18 17:25:20 -0800159 struct qspi_priv *priv = to_qspi_slave(slave);
160 const u8 *tx = (const u8 *)dout;
161 u8 *rx = (u8 *)din;
162 unsigned int bytes = bytesout + bytesin;
163 unsigned int rx_idx = 0;
164 unsigned int tx_idx = 0;
165 unsigned int in = 0;
166 unsigned int chunk;
167 unsigned int queues;
168 unsigned int i;
169 struct stopwatch sw;
170
171 if (!priv->bus_claimed)
172 return -1;
173
174 if (bytes & 1) {
175 /* Use 8-bit queue for odd-bytes transfer */
176 if (priv->mspi_16bit) {
177 REG_SET(priv->reg + MSPI_SPCR0_MSB_REG,
178 MSPI_SPCR0_MSB_BITS_8);
179 priv->mspi_16bit = 0;
180 }
181 } else {
182 /* Use 16-bit queue for even-bytes transfer */
183 if (!priv->mspi_16bit) {
184 REG_CLR(priv->reg + MSPI_SPCR0_MSB_REG,
185 MSPI_SPCR0_MSB_BITS_8);
186 priv->mspi_16bit = 1;
187 }
188 }
189
190 while (bytes) {
191 /* Separate code for 16bit and 8bit transfers for performance */
192 if (priv->mspi_16bit) {
193 /* Determine how many bytes to process this time */
194 chunk = min(bytes, NUM_CDRAM * 2);
195 queues = (chunk - 1) / 2 + 1;
196 bytes -= chunk;
197
198 /* Fill CDRAMs */
199 for (i = 0; i < queues; i++)
200 REG_WR(priv->reg + MSPI_CDRAM_REG + (i << 2),
201 0xc2);
202
203 /* Fill TXRAMs */
204 for (i = 0; i < chunk; i++) {
205 REG_WR(priv->reg + MSPI_TXRAM_REG + (i << 2),
206 (tx && (tx_idx < bytesout)) ?
207 tx[tx_idx] : 0xff);
208 tx_idx++;
209 }
210 } else {
211 /* Determine how many bytes to process this time */
212 chunk = min(bytes, NUM_CDRAM);
213 queues = chunk;
214 bytes -= chunk;
215
216 /* Fill CDRAMs and TXRAMS */
217 for (i = 0; i < chunk; i++) {
218 REG_WR(priv->reg + MSPI_CDRAM_REG + (i << 2),
219 0x82);
220 REG_WR(priv->reg + MSPI_TXRAM_REG + (i << 3),
221 (tx && (tx_idx < bytesout)) ?
222 tx[tx_idx] : 0xff);
223 tx_idx++;
224 }
225 }
226
227 /* Setup queue pointers */
228 REG_WR(priv->reg + MSPI_NEWQP_REG, 0);
229 REG_WR(priv->reg + MSPI_ENDQP_REG, queues - 1);
230
231 /* Deassert CS */
232 if (bytes == 0)
233 REG_CLR(priv->reg + MSPI_CDRAM_REG +
234 ((queues - 1) << 2), 0x0);
235
236 /* Kick off */
237 REG_WR(priv->reg + MSPI_STATUS_REG, 0);
238 REG_WR(priv->reg + MSPI_SPCR2_REG, 0xc0); /* cont | spe */
239
240 /* Wait for completion */
241 stopwatch_init_msecs_expire(&sw, QSPI_WAIT_TIMEOUT);
242 while (!stopwatch_expired(&sw)) {
243 if (REG_RD(priv->reg + MSPI_STATUS_REG) & 1)
244 break;
245 }
246 if ((REG_RD(priv->reg + MSPI_STATUS_REG) & 1) == 0) {
247 /* Make sure no operation is in progress */
248 REG_WR(priv->reg + MSPI_SPCR2_REG, 0);
249 udelay(1);
250 return -1;
251 }
252
253 /* Read data */
254 if (rx) {
255 if (priv->mspi_16bit) {
256 for (i = 0; i < chunk; i++) {
257 if (rx_idx >= bytesout) {
258 rx[in] = RXRAM_16B(priv, i);
259 in++;
260 }
261 rx_idx++;
262 }
263 } else {
264 for (i = 0; i < chunk; i++) {
265 if (rx_idx >= bytesout) {
266 rx[in] = RXRAM_8B(priv, i);
267 in++;
268 }
269 rx_idx++;
270 }
271 }
272 }
273 }
274
Daisuke Nojiria6712f32015-01-23 10:06:19 -0800275 return 0;
276}
Corneliu Dobanb0484322015-02-18 17:25:20 -0800277
Furquan Shaikh94f86992016-12-01 07:12:32 -0800278static const struct spi_ctrlr spi_ctrlr = {
279 .claim_bus = spi_ctrlr_claim_bus,
280 .release_bus = spi_ctrlr_release_bus,
281 .xfer = spi_ctrlr_xfer,
Furquan Shaikhc2973d12016-11-29 22:07:42 -0800282 .xfer_vector = spi_xfer_two_vectors,
Furquan Shaikh94f86992016-12-01 07:12:32 -0800283};
284
285int spi_setup_slave(unsigned int bus, unsigned int cs, struct spi_slave *slave)
286{
287 struct qspi_priv *priv = &qspi_slave;
288 unsigned int spbr;
289
290 slave->bus = bus;
291 slave->cs = cs;
292 slave->ctrlr = &spi_ctrlr;
293
294 priv->max_hz = QSPI_MAX_HZ;
295 priv->spi_mode = QSPI_MODE;
296 priv->reg = (void *)(IPROC_QSPI_BASE);
297 priv->mspi_enabled = 0;
298 priv->bus_claimed = 0;
299
300 /* MSPI: Basic hardware initialization */
301 REG_WR(priv->reg + MSPI_SPCR1_LSB_REG, 0);
302 REG_WR(priv->reg + MSPI_SPCR1_MSB_REG, 0);
303 REG_WR(priv->reg + MSPI_NEWQP_REG, 0);
304 REG_WR(priv->reg + MSPI_ENDQP_REG, 0);
305 REG_WR(priv->reg + MSPI_SPCR2_REG, 0);
306
307 /* MSPI: SCK configuration */
308 spbr = (IPROC_QSPI_CLK - 1) / (2 * priv->max_hz) + 1;
309 REG_WR(priv->reg + MSPI_SPCR0_LSB_REG,
310 MAX(MIN(spbr, SPBR_MAX), SPBR_MIN));
311
312 /* MSPI: Mode configuration (8 bits by default) */
313 priv->mspi_16bit = 0;
314 REG_WR(priv->reg + MSPI_SPCR0_MSB_REG,
315 0x80 | /* Master */
316 (8 << 2) | /* 8 bits per word */
317 (priv->spi_mode & 3)); /* mode: CPOL / CPHA */
318
319 return 0;
320}
321
Corneliu Dobanb0484322015-02-18 17:25:20 -0800322unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len)
323{
324 return min(65535, buf_len);
325}