Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/xilinx/zy7_qspi.c
39483 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2018 Thomas Skibo <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/cdefs.h>
30
/*
31
* This is a driver for the Quad-SPI Flash Controller in the Xilinx
32
* Zynq-7000 SoC.
33
*/
34
35
#include <sys/param.h>
36
#include <sys/systm.h>
37
#include <sys/conf.h>
38
#include <sys/kernel.h>
39
#include <sys/module.h>
40
#include <sys/sysctl.h>
41
#include <sys/lock.h>
42
#include <sys/mutex.h>
43
#include <sys/resource.h>
44
#include <sys/rman.h>
45
#include <sys/stdarg.h>
46
#include <sys/uio.h>
47
48
#include <machine/bus.h>
49
#include <machine/resource.h>
50
51
#include <dev/fdt/fdt_common.h>
52
#include <dev/ofw/ofw_bus.h>
53
#include <dev/ofw/ofw_bus_subr.h>
54
55
#include <dev/spibus/spi.h>
56
#include <dev/spibus/spibusvar.h>
57
58
#include <dev/flash/mx25lreg.h>
59
60
#include "spibus_if.h"
61
62
static struct ofw_compat_data compat_data[] = {
63
{"xlnx,zy7_qspi", 1},
64
{"xlnx,zynq-qspi-1.0", 1},
65
{NULL, 0}
66
};
67
68
struct zy7_qspi_softc {
69
device_t dev;
70
device_t child;
71
struct mtx sc_mtx;
72
struct resource *mem_res;
73
struct resource *irq_res;
74
void *intrhandle;
75
76
uint32_t cfg_reg_shadow;
77
uint32_t lqspi_cfg_shadow;
78
uint32_t spi_clock;
79
uint32_t ref_clock;
80
unsigned int spi_clk_real_freq;
81
unsigned int rx_overflows;
82
unsigned int tx_underflows;
83
unsigned int interrupts;
84
unsigned int stray_ints;
85
struct spi_command *cmd;
86
int tx_bytes; /* tx_cmd_sz + tx_data_sz */
87
int tx_bytes_sent;
88
int rx_bytes; /* rx_cmd_sz + rx_data_sz */
89
int rx_bytes_rcvd;
90
int busy;
91
int is_dual;
92
int is_stacked;
93
int is_dio;
94
};
95
96
#define ZY7_QSPI_DEFAULT_SPI_CLOCK 50000000
97
98
#define QSPI_SC_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
99
#define QSPI_SC_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
100
#define QSPI_SC_LOCK_INIT(sc) \
101
mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), NULL, MTX_DEF)
102
#define QSPI_SC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx)
103
#define QSPI_SC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED)
104
105
#define RD4(sc, off) (bus_read_4((sc)->mem_res, (off)))
106
#define WR4(sc, off, val) (bus_write_4((sc)->mem_res, (off), (val)))
107
108
/*
109
* QSPI device registers.
110
* Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
111
* (v1.12.2) July 1, 2018. Xilinx doc UG585.
112
*/
113
#define ZY7_QSPI_CONFIG_REG 0x0000
114
#define ZY7_QSPI_CONFIG_IFMODE (1U << 31)
115
#define ZY7_QSPI_CONFIG_ENDIAN (1 << 26)
116
#define ZY7_QSPI_CONFIG_HOLDB_DR (1 << 19)
117
#define ZY7_QSPI_CONFIG_RSVD1 (1 << 17) /* must be 1 */
118
#define ZY7_QSPI_CONFIG_MANSTRT (1 << 16)
119
#define ZY7_QSPI_CONFIG_MANSTRTEN (1 << 15)
120
#define ZY7_QSPI_CONFIG_SSFORCE (1 << 14)
121
#define ZY7_QSPI_CONFIG_PCS (1 << 10)
122
#define ZY7_QSPI_CONFIG_REF_CLK (1 << 8)
123
#define ZY7_QSPI_CONFIG_FIFO_WIDTH_MASK (3 << 6)
124
#define ZY7_QSPI_CONFIG_FIFO_WIDTH32 (3 << 6)
125
#define ZY7_QSPI_CONFIG_BAUD_RATE_DIV_MASK (7 << 3)
126
#define ZY7_QSPI_CONFIG_BAUD_RATE_DIV_SHIFT 3
127
#define ZY7_QSPI_CONFIG_BAUD_RATE_DIV(x) ((x) << 3) /* divide by 2<<x */
128
#define ZY7_QSPI_CONFIG_CLK_PH (1 << 2) /* clock phase */
129
#define ZY7_QSPI_CONFIG_CLK_POL (1 << 1) /* clock polarity */
130
#define ZY7_QSPI_CONFIG_MODE_SEL (1 << 0) /* master enable */
131
132
#define ZY7_QSPI_INTR_STAT_REG 0x0004
133
#define ZY7_QSPI_INTR_EN_REG 0x0008
134
#define ZY7_QSPI_INTR_DIS_REG 0x000c
135
#define ZY7_QSPI_INTR_MASK_REG 0x0010
136
#define ZY7_QSPI_INTR_TX_FIFO_UNDERFLOW (1 << 6)
137
#define ZY7_QSPI_INTR_RX_FIFO_FULL (1 << 5)
138
#define ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY (1 << 4)
139
#define ZY7_QSPI_INTR_TX_FIFO_FULL (1 << 3)
140
#define ZY7_QSPI_INTR_TX_FIFO_NOT_FULL (1 << 2)
141
#define ZY7_QSPI_INTR_RX_OVERFLOW (1 << 0)
142
143
#define ZY7_QSPI_EN_REG 0x0014
144
#define ZY7_SPI_ENABLE 1
145
146
#define ZY7_QSPI_DELAY_REG 0x0018
147
#define ZY7_QSPI_DELAY_NSS_MASK (0xffU << 24)
148
#define ZY7_QSPI_DELAY_NSS_SHIFT 24
149
#define ZY7_QSPI_DELAY_NSS(x) ((x) << 24)
150
#define ZY7_QSPI_DELAY_BTWN_MASK (0xff << 16)
151
#define ZY7_QSPI_DELAY_BTWN_SHIFT 16
152
#define ZY7_QSPI_DELAY_BTWN(x) ((x) << 16)
153
#define ZY7_QSPI_DELAY_AFTER_MASK (0xff << 8)
154
#define ZY7_QSPI_DELAY_AFTER_SHIFT 8
155
#define ZY7_QSPI_DELAY_AFTER(x) ((x) << 8)
156
#define ZY7_QSPI_DELAY_INIT_MASK 0xff
157
#define ZY7_QSPI_DELAY_INIT_SHIFT 0
158
#define ZY7_QSPI_DELAY_INIT(x) (x)
159
160
#define ZY7_QSPI_TXD0_REG 0x001c
161
#define ZY7_QSPI_RX_DATA_REG 0x0020
162
163
#define ZY7_QSPI_SLV_IDLE_CT_REG 0x0024
164
#define ZY7_QSPI_SLV_IDLE_CT_MASK 0xff
165
166
#define ZY7_QSPI_TX_THRESH_REG 0x0028
167
#define ZY7_QSPI_RX_THRESH_REG 0x002c
168
169
#define ZY7_QSPI_GPIO_REG 0x0030
170
#define ZY7_QSPI_GPIO_WP_N 1
171
172
#define ZY7_QSPI_LPBK_DLY_ADJ_REG 0x0038
173
#define ZY7_QSPI_LPBK_DLY_ADJ_LPBK_SEL (1 << 8)
174
#define ZY7_QSPI_LPBK_DLY_ADJ_LPBK_PH (1 << 7)
175
#define ZY7_QSPI_LPBK_DLY_ADJ_USE_LPBK (1 << 5)
176
#define ZY7_QSPI_LPBK_DLY_ADJ_DLY1_MASK (3 << 3)
177
#define ZY7_QSPI_LPBK_DLY_ADJ_DLY1_SHIFT 3
178
#define ZY7_QSPI_LPBK_DLY_ADJ_DLY1(x) ((x) << 3)
179
#define ZY7_QSPI_LPBK_DLY_ADJ_DLY0_MASK 7
180
#define ZY7_QSPI_LPBK_DLY_ADJ_DLY0_SHIFT 0
181
#define ZY7_QSPI_LPBK_DLY_ADJ_DLY0(x) (x)
182
183
#define ZY7_QSPI_TXD1_REG 0x0080
184
#define ZY7_QSPI_TXD2_REG 0x0084
185
#define ZY7_QSPI_TXD3_REG 0x0088
186
187
#define ZY7_QSPI_LQSPI_CFG_REG 0x00a0
188
#define ZY7_QSPI_LQSPI_CFG_LINEAR (1U << 31)
189
#define ZY7_QSPI_LQSPI_CFG_TWO_MEM (1 << 30)
190
#define ZY7_QSPI_LQSPI_CFG_SEP_BUS (1 << 29)
191
#define ZY7_QSPI_LQSPI_CFG_U_PAGE (1 << 28)
192
#define ZY7_QSPI_LQSPI_CFG_MODE_EN (1 << 25)
193
#define ZY7_QSPI_LQSPI_CFG_MODE_ON (1 << 24)
194
#define ZY7_QSPI_LQSPI_CFG_MODE_BITS_MASK (0xff << 16)
195
#define ZY7_QSPI_LQSPI_CFG_MODE_BITS_SHIFT 16
196
#define ZY7_QSPI_LQSPI_CFG_MODE_BITS(x) ((x) << 16)
197
#define ZY7_QSPI_LQSPI_CFG_DUMMY_BYTES_MASK (7 << 8)
198
#define ZY7_QSPI_LQSPI_CFG_DUMMY_BYTES_SHIFT 8
199
#define ZY7_QSPI_LQSPI_CFG_DUMMY_BYTES(x) ((x) << 8)
200
#define ZY7_QSPI_LQSPI_CFG_INST_CODE_MASK 0xff
201
#define ZY7_QSPI_LQSPI_CFG_INST_CODE_SHIFT 0
202
#define ZY7_QSPI_LQSPI_CFG_INST_CODE(x) (x)
203
204
#define ZY7_QSPI_LQSPI_STS_REG 0x00a4
205
#define ZY7_QSPI_LQSPI_STS_D_FSM_ERR (1 << 2)
206
#define ZY7_QSPI_LQSPI_STS_WR_RECVD (1 << 1)
207
208
#define ZY7_QSPI_MOD_ID_REG 0x00fc
209
210
static int zy7_qspi_detach(device_t);
211
212
/* Fill hardware fifo with command and data bytes. */
213
static void
214
zy7_qspi_write_fifo(struct zy7_qspi_softc *sc, int nbytes)
215
{
216
int n, nvalid;
217
uint32_t data;
218
219
while (nbytes > 0) {
220
nvalid = MIN(4, nbytes);
221
data = 0xffffffff;
222
223
/*
224
* A hardware bug forces us to wait until the tx fifo is
225
* empty before writing partial words. We'll come back
226
* next tx interrupt.
227
*/
228
if (nvalid < 4 && (RD4(sc, ZY7_QSPI_INTR_STAT_REG) &
229
ZY7_QSPI_INTR_TX_FIFO_NOT_FULL) == 0)
230
return;
231
232
if (sc->tx_bytes_sent < sc->cmd->tx_cmd_sz) {
233
/* Writing command. */
234
n = MIN(nvalid, sc->cmd->tx_cmd_sz -
235
sc->tx_bytes_sent);
236
memcpy(&data, (uint8_t *)sc->cmd->tx_cmd +
237
sc->tx_bytes_sent, n);
238
239
if (nvalid > n) {
240
/* Writing start of data. */
241
memcpy((uint8_t *)&data + n,
242
sc->cmd->tx_data, nvalid - n);
243
}
244
} else
245
/* Writing data. */
246
memcpy(&data, (uint8_t *)sc->cmd->tx_data +
247
(sc->tx_bytes_sent - sc->cmd->tx_cmd_sz), nvalid);
248
249
switch (nvalid) {
250
case 1:
251
WR4(sc, ZY7_QSPI_TXD1_REG, data);
252
break;
253
case 2:
254
WR4(sc, ZY7_QSPI_TXD2_REG, data);
255
break;
256
case 3:
257
WR4(sc, ZY7_QSPI_TXD3_REG, data);
258
break;
259
case 4:
260
WR4(sc, ZY7_QSPI_TXD0_REG, data);
261
break;
262
}
263
264
sc->tx_bytes_sent += nvalid;
265
nbytes -= nvalid;
266
}
267
}
268
269
/* Read hardware fifo data into command response and data buffers. */
270
static void
271
zy7_qspi_read_fifo(struct zy7_qspi_softc *sc)
272
{
273
int n, nbytes;
274
uint32_t data;
275
276
do {
277
data = RD4(sc, ZY7_QSPI_RX_DATA_REG);
278
nbytes = MIN(4, sc->rx_bytes - sc->rx_bytes_rcvd);
279
280
/*
281
* Last word in non-word-multiple transfer is packed
282
* non-intuitively.
283
*/
284
if (nbytes < 4)
285
data >>= 8 * (4 - nbytes);
286
287
if (sc->rx_bytes_rcvd < sc->cmd->rx_cmd_sz) {
288
/* Reading command. */
289
n = MIN(nbytes, sc->cmd->rx_cmd_sz -
290
sc->rx_bytes_rcvd);
291
memcpy((uint8_t *)sc->cmd->rx_cmd + sc->rx_bytes_rcvd,
292
&data, n);
293
sc->rx_bytes_rcvd += n;
294
nbytes -= n;
295
data >>= 8 * n;
296
}
297
298
if (nbytes > 0) {
299
/* Reading data. */
300
memcpy((uint8_t *)sc->cmd->rx_data +
301
(sc->rx_bytes_rcvd - sc->cmd->rx_cmd_sz),
302
&data, nbytes);
303
sc->rx_bytes_rcvd += nbytes;
304
}
305
306
} while (sc->rx_bytes_rcvd < sc->rx_bytes &&
307
(RD4(sc, ZY7_QSPI_INTR_STAT_REG) &
308
ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY) != 0);
309
}
310
311
/* End a transfer early by draining rx fifo and disabling interrupts. */
312
static void
313
zy7_qspi_abort_transfer(struct zy7_qspi_softc *sc)
314
{
315
/* Drain receive fifo. */
316
while ((RD4(sc, ZY7_QSPI_INTR_STAT_REG) &
317
ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY) != 0)
318
(void)RD4(sc, ZY7_QSPI_RX_DATA_REG);
319
320
/* Shut down interrupts. */
321
WR4(sc, ZY7_QSPI_INTR_DIS_REG,
322
ZY7_QSPI_INTR_RX_OVERFLOW |
323
ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY |
324
ZY7_QSPI_INTR_TX_FIFO_NOT_FULL);
325
}
326
327
static void
328
zy7_qspi_intr(void *arg)
329
{
330
struct zy7_qspi_softc *sc = (struct zy7_qspi_softc *)arg;
331
uint32_t istatus;
332
333
QSPI_SC_LOCK(sc);
334
335
sc->interrupts++;
336
337
istatus = RD4(sc, ZY7_QSPI_INTR_STAT_REG);
338
339
/* Stray interrupts can happen if a transfer gets interrupted. */
340
if (!sc->busy) {
341
sc->stray_ints++;
342
QSPI_SC_UNLOCK(sc);
343
return;
344
}
345
346
if ((istatus & ZY7_QSPI_INTR_RX_OVERFLOW) != 0) {
347
device_printf(sc->dev, "rx fifo overflow!\n");
348
sc->rx_overflows++;
349
350
/* Clear status bit. */
351
WR4(sc, ZY7_QSPI_INTR_STAT_REG,
352
ZY7_QSPI_INTR_RX_OVERFLOW);
353
}
354
355
/* Empty receive fifo before any more transmit data is sent. */
356
if (sc->rx_bytes_rcvd < sc->rx_bytes &&
357
(istatus & ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY) != 0) {
358
zy7_qspi_read_fifo(sc);
359
if (sc->rx_bytes_rcvd == sc->rx_bytes)
360
/* Disable receive interrupts. */
361
WR4(sc, ZY7_QSPI_INTR_DIS_REG,
362
ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY |
363
ZY7_QSPI_INTR_RX_OVERFLOW);
364
}
365
366
/*
367
* Transmit underflows aren't really a bug because a hardware
368
* bug forces us to allow the tx fifo to go empty between full
369
* and partial fifo writes. Why bother counting?
370
*/
371
if ((istatus & ZY7_QSPI_INTR_TX_FIFO_UNDERFLOW) != 0) {
372
sc->tx_underflows++;
373
374
/* Clear status bit. */
375
WR4(sc, ZY7_QSPI_INTR_STAT_REG,
376
ZY7_QSPI_INTR_TX_FIFO_UNDERFLOW);
377
}
378
379
/* Fill transmit fifo. */
380
if (sc->tx_bytes_sent < sc->tx_bytes &&
381
(istatus & ZY7_QSPI_INTR_TX_FIFO_NOT_FULL) != 0) {
382
zy7_qspi_write_fifo(sc, MIN(240, sc->tx_bytes -
383
sc->tx_bytes_sent));
384
385
if (sc->tx_bytes_sent == sc->tx_bytes) {
386
/*
387
* Disable transmit FIFO interrupt, enable receive
388
* FIFO interrupt.
389
*/
390
WR4(sc, ZY7_QSPI_INTR_DIS_REG,
391
ZY7_QSPI_INTR_TX_FIFO_NOT_FULL);
392
WR4(sc, ZY7_QSPI_INTR_EN_REG,
393
ZY7_QSPI_INTR_RX_FIFO_NOT_EMPTY);
394
}
395
}
396
397
/* Finished with transfer? */
398
if (sc->tx_bytes_sent == sc->tx_bytes &&
399
sc->rx_bytes_rcvd == sc->rx_bytes) {
400
/* De-assert CS. */
401
sc->cfg_reg_shadow |= ZY7_QSPI_CONFIG_PCS;
402
WR4(sc, ZY7_QSPI_CONFIG_REG, sc->cfg_reg_shadow);
403
404
wakeup(sc->dev);
405
}
406
407
QSPI_SC_UNLOCK(sc);
408
}
409
410
/* Initialize hardware. */
411
static int
412
zy7_qspi_init_hw(struct zy7_qspi_softc *sc)
413
{
414
uint32_t baud_div;
415
416
/* Configure LQSPI Config register. Disable linear mode. */
417
sc->lqspi_cfg_shadow = RD4(sc, ZY7_QSPI_LQSPI_CFG_REG);
418
sc->lqspi_cfg_shadow &= ~(ZY7_QSPI_LQSPI_CFG_LINEAR |
419
ZY7_QSPI_LQSPI_CFG_TWO_MEM |
420
ZY7_QSPI_LQSPI_CFG_SEP_BUS);
421
if (sc->is_dual) {
422
sc->lqspi_cfg_shadow |= ZY7_QSPI_LQSPI_CFG_TWO_MEM;
423
if (sc->is_stacked) {
424
sc->lqspi_cfg_shadow &=
425
~ZY7_QSPI_LQSPI_CFG_INST_CODE_MASK;
426
sc->lqspi_cfg_shadow |=
427
ZY7_QSPI_LQSPI_CFG_INST_CODE(sc->is_dio ?
428
CMD_READ_DUAL_IO : CMD_READ_QUAD_OUTPUT);
429
} else
430
sc->lqspi_cfg_shadow |= ZY7_QSPI_LQSPI_CFG_SEP_BUS;
431
}
432
WR4(sc, ZY7_QSPI_LQSPI_CFG_REG, sc->lqspi_cfg_shadow);
433
434
/* Find best clock divider. */
435
baud_div = 0;
436
while ((sc->ref_clock >> (baud_div + 1)) > sc->spi_clock &&
437
baud_div < 8)
438
baud_div++;
439
if (baud_div >= 8) {
440
device_printf(sc->dev, "cannot configure clock divider: ref=%d"
441
" spi=%d.\n", sc->ref_clock, sc->spi_clock);
442
return (EINVAL);
443
}
444
sc->spi_clk_real_freq = sc->ref_clock >> (baud_div + 1);
445
446
/*
447
* If divider is 2 (the max speed), use internal loopback master
448
* clock for read data. (See section 12.3.1 in ref man.)
449
*/
450
if (baud_div == 0)
451
WR4(sc, ZY7_QSPI_LPBK_DLY_ADJ_REG,
452
ZY7_QSPI_LPBK_DLY_ADJ_USE_LPBK |
453
ZY7_QSPI_LPBK_DLY_ADJ_DLY1(0) |
454
ZY7_QSPI_LPBK_DLY_ADJ_DLY0(0));
455
else
456
WR4(sc, ZY7_QSPI_LPBK_DLY_ADJ_REG, 0);
457
458
/* Set up configuration register. */
459
sc->cfg_reg_shadow =
460
ZY7_QSPI_CONFIG_IFMODE |
461
ZY7_QSPI_CONFIG_HOLDB_DR |
462
ZY7_QSPI_CONFIG_RSVD1 |
463
ZY7_QSPI_CONFIG_SSFORCE |
464
ZY7_QSPI_CONFIG_PCS |
465
ZY7_QSPI_CONFIG_FIFO_WIDTH32 |
466
ZY7_QSPI_CONFIG_BAUD_RATE_DIV(baud_div) |
467
ZY7_QSPI_CONFIG_MODE_SEL;
468
WR4(sc, ZY7_QSPI_CONFIG_REG, sc->cfg_reg_shadow);
469
470
/*
471
* Set thresholds. We must use 1 for tx threshold because there
472
* is no fifo empty flag and we need one to implement a bug
473
* workaround.
474
*/
475
WR4(sc, ZY7_QSPI_TX_THRESH_REG, 1);
476
WR4(sc, ZY7_QSPI_RX_THRESH_REG, 1);
477
478
/* Clear and disable all interrupts. */
479
WR4(sc, ZY7_QSPI_INTR_STAT_REG, ~0);
480
WR4(sc, ZY7_QSPI_INTR_DIS_REG, ~0);
481
482
/* Enable SPI. */
483
WR4(sc, ZY7_QSPI_EN_REG, ZY7_SPI_ENABLE);
484
485
return (0);
486
}
487
488
static void
489
zy7_qspi_add_sysctls(device_t dev)
490
{
491
struct zy7_qspi_softc *sc = device_get_softc(dev);
492
struct sysctl_ctx_list *ctx;
493
struct sysctl_oid_list *child;
494
495
ctx = device_get_sysctl_ctx(dev);
496
child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
497
498
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "spi_clk_real_freq", CTLFLAG_RD,
499
&sc->spi_clk_real_freq, 0, "SPI clock real frequency");
500
501
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_overflows", CTLFLAG_RD,
502
&sc->rx_overflows, 0, "RX FIFO overflow events");
503
504
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_underflows", CTLFLAG_RD,
505
&sc->tx_underflows, 0, "TX FIFO underflow events");
506
507
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "interrupts", CTLFLAG_RD,
508
&sc->interrupts, 0, "interrupt calls");
509
510
SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "stray_ints", CTLFLAG_RD,
511
&sc->stray_ints, 0, "stray interrupts");
512
}
513
514
static int
515
zy7_qspi_probe(device_t dev)
516
{
517
518
if (!ofw_bus_status_okay(dev))
519
return (ENXIO);
520
521
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
522
return (ENXIO);
523
524
device_set_desc(dev, "Zynq Quad-SPI Flash Controller");
525
526
return (BUS_PROBE_DEFAULT);
527
}
528
529
static int
530
zy7_qspi_attach(device_t dev)
531
{
532
struct zy7_qspi_softc *sc;
533
int rid, err;
534
phandle_t node;
535
pcell_t cell;
536
537
sc = device_get_softc(dev);
538
sc->dev = dev;
539
540
QSPI_SC_LOCK_INIT(sc);
541
542
/* Get ref-clock, spi-clock, and other properties. */
543
node = ofw_bus_get_node(dev);
544
if (OF_getprop(node, "ref-clock", &cell, sizeof(cell)) > 0)
545
sc->ref_clock = fdt32_to_cpu(cell);
546
else {
547
device_printf(dev, "must have ref-clock property\n");
548
return (ENXIO);
549
}
550
if (OF_getprop(node, "spi-clock", &cell, sizeof(cell)) > 0)
551
sc->spi_clock = fdt32_to_cpu(cell);
552
else
553
sc->spi_clock = ZY7_QSPI_DEFAULT_SPI_CLOCK;
554
if (OF_getprop(node, "is-stacked", &cell, sizeof(cell)) > 0 &&
555
fdt32_to_cpu(cell) != 0) {
556
sc->is_dual = 1;
557
sc->is_stacked = 1;
558
} else if (OF_getprop(node, "is-dual", &cell, sizeof(cell)) > 0 &&
559
fdt32_to_cpu(cell) != 0)
560
sc->is_dual = 1;
561
if (OF_getprop(node, "is-dio", &cell, sizeof(cell)) > 0 &&
562
fdt32_to_cpu(cell) != 0)
563
sc->is_dio = 1;
564
565
/* Get memory resource. */
566
rid = 0;
567
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
568
RF_ACTIVE);
569
if (sc->mem_res == NULL) {
570
device_printf(dev, "could not allocate memory resources.\n");
571
zy7_qspi_detach(dev);
572
return (ENOMEM);
573
}
574
575
/* Allocate IRQ. */
576
rid = 0;
577
sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
578
RF_ACTIVE);
579
if (sc->irq_res == NULL) {
580
device_printf(dev, "could not allocate IRQ resource.\n");
581
zy7_qspi_detach(dev);
582
return (ENOMEM);
583
}
584
585
/* Activate the interrupt. */
586
err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
587
NULL, zy7_qspi_intr, sc, &sc->intrhandle);
588
if (err) {
589
device_printf(dev, "could not setup IRQ.\n");
590
zy7_qspi_detach(dev);
591
return (err);
592
}
593
594
/* Configure the device. */
595
err = zy7_qspi_init_hw(sc);
596
if (err) {
597
zy7_qspi_detach(dev);
598
return (err);
599
}
600
601
sc->child = device_add_child(dev, "spibus", DEVICE_UNIT_ANY);
602
603
zy7_qspi_add_sysctls(dev);
604
605
/* Attach spibus driver as a child later when interrupts work. */
606
bus_delayed_attach_children(dev);
607
608
return (0);
609
}
610
611
static int
612
zy7_qspi_detach(device_t dev)
613
{
614
struct zy7_qspi_softc *sc = device_get_softc(dev);
615
int error;
616
617
error = bus_generic_detach(dev);
618
if (error != 0)
619
return (error);
620
621
/* Disable hardware. */
622
if (sc->mem_res != NULL) {
623
/* Disable SPI. */
624
WR4(sc, ZY7_QSPI_EN_REG, 0);
625
626
/* Clear and disable all interrupts. */
627
WR4(sc, ZY7_QSPI_INTR_STAT_REG, ~0);
628
WR4(sc, ZY7_QSPI_INTR_DIS_REG, ~0);
629
}
630
631
/* Teardown and release interrupt. */
632
if (sc->irq_res != NULL) {
633
if (sc->intrhandle)
634
bus_teardown_intr(dev, sc->irq_res, sc->intrhandle);
635
bus_release_resource(dev, SYS_RES_IRQ,
636
rman_get_rid(sc->irq_res), sc->irq_res);
637
}
638
639
/* Release memory resource. */
640
if (sc->mem_res != NULL)
641
bus_release_resource(dev, SYS_RES_MEMORY,
642
rman_get_rid(sc->mem_res), sc->mem_res);
643
644
QSPI_SC_LOCK_DESTROY(sc);
645
646
return (0);
647
}
648
649
static phandle_t
650
zy7_qspi_get_node(device_t bus, device_t dev)
651
{
652
653
return (ofw_bus_get_node(bus));
654
}
655
656
static int
657
zy7_qspi_transfer(device_t dev, device_t child, struct spi_command *cmd)
658
{
659
struct zy7_qspi_softc *sc = device_get_softc(dev);
660
int err = 0;
661
662
KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
663
("TX/RX command sizes should be equal"));
664
KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
665
("TX/RX data sizes should be equal"));
666
667
if (sc->is_dual && cmd->tx_data_sz % 2 != 0) {
668
device_printf(dev, "driver does not support odd byte data "
669
"transfers in dual mode. (sz=%d)\n", cmd->tx_data_sz);
670
return (EINVAL);
671
}
672
673
QSPI_SC_LOCK(sc);
674
675
/* Wait for controller available. */
676
while (sc->busy != 0) {
677
err = mtx_sleep(dev, &sc->sc_mtx, 0, "zqspi0", 0);
678
if (err) {
679
QSPI_SC_UNLOCK(sc);
680
return (err);
681
}
682
}
683
684
/* Start transfer. */
685
sc->busy = 1;
686
sc->cmd = cmd;
687
sc->tx_bytes = sc->cmd->tx_cmd_sz + sc->cmd->tx_data_sz;
688
sc->tx_bytes_sent = 0;
689
sc->rx_bytes = sc->cmd->rx_cmd_sz + sc->cmd->rx_data_sz;
690
sc->rx_bytes_rcvd = 0;
691
692
/* Enable interrupts. zy7_qspi_intr() will handle transfer. */
693
WR4(sc, ZY7_QSPI_INTR_EN_REG,
694
ZY7_QSPI_INTR_TX_FIFO_NOT_FULL |
695
ZY7_QSPI_INTR_RX_OVERFLOW);
696
697
#ifdef SPI_XFER_U_PAGE /* XXX: future support for stacked memories. */
698
if (sc->is_stacked) {
699
if ((cmd->flags & SPI_XFER_U_PAGE) != 0)
700
sc->lqspi_cfg_shadow |= ZY7_QSPI_LQSPI_CFG_U_PAGE;
701
else
702
sc->lqspi_cfg_shadow &= ~ZY7_QSPI_LQSPI_CFG_U_PAGE;
703
WR4(sc, ZY7_QSPI_LQSPI_CFG_REG, sc->lqspi_cfg_shadow);
704
}
705
#endif
706
707
/* Assert CS. */
708
sc->cfg_reg_shadow &= ~ZY7_QSPI_CONFIG_PCS;
709
WR4(sc, ZY7_QSPI_CONFIG_REG, sc->cfg_reg_shadow);
710
711
/* Wait for completion. */
712
err = mtx_sleep(dev, &sc->sc_mtx, 0, "zqspi1", hz * 2);
713
if (err)
714
zy7_qspi_abort_transfer(sc);
715
716
/* Release controller. */
717
sc->busy = 0;
718
wakeup_one(dev);
719
720
QSPI_SC_UNLOCK(sc);
721
722
return (err);
723
}
724
725
static device_method_t zy7_qspi_methods[] = {
726
/* Device interface */
727
DEVMETHOD(device_probe, zy7_qspi_probe),
728
DEVMETHOD(device_attach, zy7_qspi_attach),
729
DEVMETHOD(device_detach, zy7_qspi_detach),
730
731
/* SPI interface */
732
DEVMETHOD(spibus_transfer, zy7_qspi_transfer),
733
734
/* ofw_bus interface */
735
DEVMETHOD(ofw_bus_get_node, zy7_qspi_get_node),
736
737
DEVMETHOD_END
738
};
739
740
static driver_t zy7_qspi_driver = {
741
"zy7_qspi",
742
zy7_qspi_methods,
743
sizeof(struct zy7_qspi_softc),
744
};
745
746
DRIVER_MODULE(zy7_qspi, simplebus, zy7_qspi_driver, 0, 0);
747
DRIVER_MODULE(ofw_spibus, zy7_qspi, ofw_spibus_driver, 0, 0);
748
SIMPLEBUS_PNP_INFO(compat_data);
749
MODULE_DEPEND(zy7_qspi, ofw_spibus, 1, 1, 1);
750
751