blob: 1e20701d0d35484e6565152d9eb76fb7e2f3303b [file] [log] [blame]
Quentin Schulz3add62d2018-08-31 16:28:29 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2012
Patrick Delaunaya6b185e2022-05-20 18:38:10 +02004 * Armando Visconti, STMicroelectronics, armando.visconti@st.com.
Quentin Schulz3add62d2018-08-31 16:28:29 +02005 *
6 * (C) Copyright 2018
7 * Quentin Schulz, Bootlin, quentin.schulz@bootlin.com
8 *
9 * Driver for ARM PL022 SPI Controller.
10 */
11
Quentin Schulz3add62d2018-08-31 16:28:29 +020012#include <clk.h>
Quentin Schulz3add62d2018-08-31 16:28:29 +020013#include <dm.h>
Lukas Funkeaff5c1f2023-04-28 14:38:50 +020014#include <dm/device_compat.h>
Stefan Herbrechtsmeier2ed5d782023-04-28 14:38:49 +020015#include <fdtdec.h>
Quentin Schulz3add62d2018-08-31 16:28:29 +020016#include <linux/io.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060017#include <asm/global_data.h>
Lukas Funkeaff5c1f2023-04-28 14:38:50 +020018#include <asm/gpio.h>
Quentin Schulz3add62d2018-08-31 16:28:29 +020019#include <spi.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060020#include <linux/printk.h>
Quentin Schulz3add62d2018-08-31 16:28:29 +020021
22#define SSP_CR0 0x000
23#define SSP_CR1 0x004
24#define SSP_DR 0x008
25#define SSP_SR 0x00C
26#define SSP_CPSR 0x010
27#define SSP_IMSC 0x014
28#define SSP_RIS 0x018
29#define SSP_MIS 0x01C
30#define SSP_ICR 0x020
31#define SSP_DMACR 0x024
32#define SSP_CSR 0x030 /* vendor extension */
33#define SSP_ITCR 0x080
34#define SSP_ITIP 0x084
35#define SSP_ITOP 0x088
36#define SSP_TDR 0x08C
37
38#define SSP_PID0 0xFE0
39#define SSP_PID1 0xFE4
40#define SSP_PID2 0xFE8
41#define SSP_PID3 0xFEC
42
43#define SSP_CID0 0xFF0
44#define SSP_CID1 0xFF4
45#define SSP_CID2 0xFF8
46#define SSP_CID3 0xFFC
47
48/* SSP Control Register 0 - SSP_CR0 */
49#define SSP_CR0_SPO (0x1 << 6)
50#define SSP_CR0_SPH (0x1 << 7)
51#define SSP_CR0_BIT_MODE(x) ((x) - 1)
52#define SSP_SCR_MIN (0x00)
53#define SSP_SCR_MAX (0xFF)
54#define SSP_SCR_SHFT 8
55#define DFLT_CLKRATE 2
56
57/* SSP Control Register 1 - SSP_CR1 */
58#define SSP_CR1_MASK_SSE (0x1 << 1)
59
60#define SSP_CPSR_MIN (0x02)
61#define SSP_CPSR_MAX (0xFE)
62#define DFLT_PRESCALE (0x40)
63
64/* SSP Status Register - SSP_SR */
65#define SSP_SR_MASK_TFE (0x1 << 0) /* Transmit FIFO empty */
66#define SSP_SR_MASK_TNF (0x1 << 1) /* Transmit FIFO not full */
67#define SSP_SR_MASK_RNE (0x1 << 2) /* Receive FIFO not empty */
68#define SSP_SR_MASK_RFF (0x1 << 3) /* Receive FIFO full */
69#define SSP_SR_MASK_BSY (0x1 << 4) /* Busy Flag */
70
Stefan Herbrechtsmeier2ed5d782023-04-28 14:38:49 +020071struct pl022_spi_pdata {
72 fdt_addr_t addr;
73 fdt_size_t size;
74 unsigned int freq;
Lukas Funkeaff5c1f2023-04-28 14:38:50 +020075#if CONFIG_IS_ENABLED(DM_GPIO)
76 struct gpio_desc cs_gpio;
77#endif
Stefan Herbrechtsmeier2ed5d782023-04-28 14:38:49 +020078};
79
Quentin Schulz3add62d2018-08-31 16:28:29 +020080struct pl022_spi_slave {
81 void *base;
Quentin Schulz3add62d2018-08-31 16:28:29 +020082 unsigned int freq;
Quentin Schulz3add62d2018-08-31 16:28:29 +020083};
84
85/*
86 * ARM PL022 exists in different 'flavors'.
87 * This drivers currently support the standard variant (0x00041022), that has a
88 * 16bit wide and 8 locations deep TX/RX FIFO.
89 */
90static int pl022_is_supported(struct pl022_spi_slave *ps)
91{
92 /* PL022 version is 0x00041022 */
93 if ((readw(ps->base + SSP_PID0) == 0x22) &&
94 (readw(ps->base + SSP_PID1) == 0x10) &&
95 ((readw(ps->base + SSP_PID2) & 0xf) == 0x04) &&
96 (readw(ps->base + SSP_PID3) == 0x00))
97 return 1;
98
99 return 0;
100}
Quentin Schulz3add62d2018-08-31 16:28:29 +0200101
102static int pl022_spi_probe(struct udevice *bus)
103{
Simon Glassfa20e932020-12-03 16:55:20 -0700104 struct pl022_spi_pdata *plat = dev_get_plat(bus);
Quentin Schulz3add62d2018-08-31 16:28:29 +0200105 struct pl022_spi_slave *ps = dev_get_priv(bus);
106
107 ps->base = ioremap(plat->addr, plat->size);
Quentin Schulz3add62d2018-08-31 16:28:29 +0200108 ps->freq = plat->freq;
Quentin Schulz3add62d2018-08-31 16:28:29 +0200109
110 /* Check the PL022 version */
111 if (!pl022_is_supported(ps))
112 return -ENOTSUPP;
113
114 /* 8 bits per word, high polarity and default clock rate */
115 writew(SSP_CR0_BIT_MODE(8), ps->base + SSP_CR0);
116 writew(DFLT_PRESCALE, ps->base + SSP_CPSR);
117
118 return 0;
119}
120
Stefan Herbrechtsmeier003b07d2023-04-28 14:38:48 +0200121static void pl022_spi_flush(struct pl022_spi_slave *ps)
Quentin Schulz3add62d2018-08-31 16:28:29 +0200122{
123 do {
124 while (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE)
125 readw(ps->base + SSP_DR);
126 } while (readw(ps->base + SSP_SR) & SSP_SR_MASK_BSY);
127}
128
129static int pl022_spi_claim_bus(struct udevice *dev)
130{
131 struct udevice *bus = dev->parent;
132 struct pl022_spi_slave *ps = dev_get_priv(bus);
133 u16 reg;
134
135 /* Enable the SPI hardware */
136 reg = readw(ps->base + SSP_CR1);
137 reg |= SSP_CR1_MASK_SSE;
138 writew(reg, ps->base + SSP_CR1);
139
Stefan Herbrechtsmeier003b07d2023-04-28 14:38:48 +0200140 pl022_spi_flush(ps);
Quentin Schulz3add62d2018-08-31 16:28:29 +0200141
142 return 0;
143}
144
145static int pl022_spi_release_bus(struct udevice *dev)
146{
147 struct udevice *bus = dev->parent;
148 struct pl022_spi_slave *ps = dev_get_priv(bus);
149 u16 reg;
150
Stefan Herbrechtsmeier003b07d2023-04-28 14:38:48 +0200151 pl022_spi_flush(ps);
Quentin Schulz3add62d2018-08-31 16:28:29 +0200152
153 /* Disable the SPI hardware */
154 reg = readw(ps->base + SSP_CR1);
155 reg &= ~SSP_CR1_MASK_SSE;
156 writew(reg, ps->base + SSP_CR1);
157
158 return 0;
159}
160
Lukas Funkeaff5c1f2023-04-28 14:38:50 +0200161static void pl022_spi_set_cs(struct udevice *dev, bool on)
162{
163#if CONFIG_IS_ENABLED(DM_GPIO)
164 struct udevice *bus = dev->parent;
165 struct pl022_spi_pdata *plat = dev_get_plat(bus);
166
167 if (dm_gpio_is_valid(&plat->cs_gpio))
168 dm_gpio_set_value(&plat->cs_gpio, on ? 1 : 0);
169#endif
170}
171
Quentin Schulz3add62d2018-08-31 16:28:29 +0200172static int pl022_spi_xfer(struct udevice *dev, unsigned int bitlen,
173 const void *dout, void *din, unsigned long flags)
174{
175 struct udevice *bus = dev->parent;
176 struct pl022_spi_slave *ps = dev_get_priv(bus);
177 u32 len_tx = 0, len_rx = 0, len;
178 u32 ret = 0;
179 const u8 *txp = dout;
180 u8 *rxp = din, value;
181
182 if (bitlen == 0)
183 /* Finish any previously submitted transfers */
Lukas Funkeaff5c1f2023-04-28 14:38:50 +0200184 goto done;
Quentin Schulz3add62d2018-08-31 16:28:29 +0200185
186 /*
187 * TODO: The controller can do non-multiple-of-8 bit
188 * transfers, but this driver currently doesn't support it.
189 *
190 * It's also not clear how such transfers are supposed to be
191 * represented as a stream of bytes...this is a limitation of
192 * the current SPI interface.
193 */
194 if (bitlen % 8) {
195 /* Errors always terminate an ongoing transfer */
196 flags |= SPI_XFER_END;
Lukas Funkeaff5c1f2023-04-28 14:38:50 +0200197 ret = -1;
198 goto done;
Quentin Schulz3add62d2018-08-31 16:28:29 +0200199 }
200
Lukas Funkeaff5c1f2023-04-28 14:38:50 +0200201 if (flags & SPI_XFER_BEGIN)
202 pl022_spi_set_cs(dev, true);
203
Quentin Schulz3add62d2018-08-31 16:28:29 +0200204 len = bitlen / 8;
205
206 while (len_tx < len) {
207 if (readw(ps->base + SSP_SR) & SSP_SR_MASK_TNF) {
208 value = txp ? *txp++ : 0;
209 writew(value, ps->base + SSP_DR);
210 len_tx++;
211 }
212
213 if (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE) {
214 value = readw(ps->base + SSP_DR);
215 if (rxp)
216 *rxp++ = value;
217 len_rx++;
218 }
219 }
220
221 while (len_rx < len_tx) {
222 if (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE) {
223 value = readw(ps->base + SSP_DR);
224 if (rxp)
225 *rxp++ = value;
226 len_rx++;
227 }
228 }
229
Lukas Funkeaff5c1f2023-04-28 14:38:50 +0200230done:
231 if (flags & SPI_XFER_END)
232 pl022_spi_set_cs(dev, false);
233
Quentin Schulz3add62d2018-08-31 16:28:29 +0200234 return ret;
235}
236
237static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr)
238{
239 return rate / (cpsdvsr * (1 + scr));
240}
241
242static int pl022_spi_set_speed(struct udevice *bus, uint speed)
243{
244 struct pl022_spi_slave *ps = dev_get_priv(bus);
245 u16 scr = SSP_SCR_MIN, cr0 = 0, cpsr = SSP_CPSR_MIN, best_scr = scr,
246 best_cpsr = cpsr;
247 u32 min, max, best_freq = 0, tmp;
Quentin Schulz3add62d2018-08-31 16:28:29 +0200248 u32 rate = ps->freq;
Quentin Schulz3add62d2018-08-31 16:28:29 +0200249 bool found = false;
250
251 max = spi_rate(rate, SSP_CPSR_MIN, SSP_SCR_MIN);
252 min = spi_rate(rate, SSP_CPSR_MAX, SSP_SCR_MAX);
253
254 if (speed > max || speed < min) {
255 pr_err("Tried to set speed to %dHz but min=%d and max=%d\n",
256 speed, min, max);
257 return -EINVAL;
258 }
259
260 while (cpsr <= SSP_CPSR_MAX && !found) {
261 while (scr <= SSP_SCR_MAX) {
262 tmp = spi_rate(rate, cpsr, scr);
263
264 if (abs(speed - tmp) < abs(speed - best_freq)) {
265 best_freq = tmp;
266 best_cpsr = cpsr;
267 best_scr = scr;
268
269 if (tmp == speed) {
270 found = true;
271 break;
272 }
273 }
274
275 scr++;
276 }
277 cpsr += 2;
278 scr = SSP_SCR_MIN;
279 }
280
281 writew(best_cpsr, ps->base + SSP_CPSR);
282 cr0 = readw(ps->base + SSP_CR0);
283 writew(cr0 | (best_scr << SSP_SCR_SHFT), ps->base + SSP_CR0);
284
285 return 0;
286}
287
288static int pl022_spi_set_mode(struct udevice *bus, uint mode)
289{
290 struct pl022_spi_slave *ps = dev_get_priv(bus);
291 u16 reg;
292
293 reg = readw(ps->base + SSP_CR0);
294 reg &= ~(SSP_CR0_SPH | SSP_CR0_SPO);
295 if (mode & SPI_CPHA)
296 reg |= SSP_CR0_SPH;
297 if (mode & SPI_CPOL)
298 reg |= SSP_CR0_SPO;
299 writew(reg, ps->base + SSP_CR0);
300
301 return 0;
302}
303
304static int pl022_cs_info(struct udevice *bus, uint cs,
305 struct spi_cs_info *info)
306{
307 return 0;
308}
309
310static const struct dm_spi_ops pl022_spi_ops = {
311 .claim_bus = pl022_spi_claim_bus,
312 .release_bus = pl022_spi_release_bus,
313 .xfer = pl022_spi_xfer,
314 .set_speed = pl022_spi_set_speed,
315 .set_mode = pl022_spi_set_mode,
316 .cs_info = pl022_cs_info,
317};
318
Simon Glass92882652021-08-07 07:24:04 -0600319#if CONFIG_IS_ENABLED(OF_REAL)
Simon Glassaad29ae2020-12-03 16:55:21 -0700320static int pl022_spi_of_to_plat(struct udevice *bus)
Jagan Tekicd9e9982018-11-14 15:28:05 +0530321{
Simon Glass95588622020-12-22 19:30:28 -0700322 struct pl022_spi_pdata *plat = dev_get_plat(bus);
Jagan Tekicd9e9982018-11-14 15:28:05 +0530323 const void *fdt = gd->fdt_blob;
324 int node = dev_of_offset(bus);
325 struct clk clkdev;
326 int ret;
327
328 plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size);
329
330 ret = clk_get_by_index(bus, 0, &clkdev);
331 if (ret)
332 return ret;
333
334 plat->freq = clk_get_rate(&clkdev);
335
Lukas Funkeaff5c1f2023-04-28 14:38:50 +0200336#if CONFIG_IS_ENABLED(DM_GPIO)
337 ret = gpio_request_by_name(bus, "cs-gpios", 0, &plat->cs_gpio,
338 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
339 if (ret < 0 && ret != -ENOENT)
340 return ret;
341#endif
342
Jagan Tekicd9e9982018-11-14 15:28:05 +0530343 return 0;
344}
345
Quentin Schulz3add62d2018-08-31 16:28:29 +0200346static const struct udevice_id pl022_spi_ids[] = {
Lukas Funke76ad2982023-04-28 14:38:47 +0200347 { .compatible = "arm,pl022" },
Quentin Schulz3add62d2018-08-31 16:28:29 +0200348 { }
349};
350#endif
351
352U_BOOT_DRIVER(pl022_spi) = {
353 .name = "pl022_spi",
354 .id = UCLASS_SPI,
Simon Glass92882652021-08-07 07:24:04 -0600355#if CONFIG_IS_ENABLED(OF_REAL)
Quentin Schulz3add62d2018-08-31 16:28:29 +0200356 .of_match = pl022_spi_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -0700357 .of_to_plat = pl022_spi_of_to_plat,
Quentin Schulz3add62d2018-08-31 16:28:29 +0200358#endif
Jagan Tekicd9e9982018-11-14 15:28:05 +0530359 .ops = &pl022_spi_ops,
Simon Glass71fa5b42020-12-03 16:55:18 -0700360 .plat_auto = sizeof(struct pl022_spi_pdata),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700361 .priv_auto = sizeof(struct pl022_spi_slave),
Quentin Schulz3add62d2018-08-31 16:28:29 +0200362 .probe = pl022_spi_probe,
363};