blob: c56d82d998ad06b4e54e8129256f1f561fd8604b [file] [log] [blame]
Stefan Mavrodiev5d716042018-02-06 15:14:33 +02001/*
2 * (C) Copyright 2017 Whitebox Systems / Northend Systems B.V.
3 * S.J.R. van Schaik <stephan@whiteboxsystems.nl>
4 * M.B.W. Wajer <merlijn@whiteboxsystems.nl>
5 *
6 * (C) Copyright 2017 Olimex Ltd..
7 * Stefan Mavrodiev <stefan@olimex.com>
8 *
9 * Based on linux spi driver. Original copyright follows:
10 * linux/drivers/spi/spi-sun4i.c
11 *
12 * Copyright (C) 2012 - 2014 Allwinner Tech
13 * Pan Nan <pannan@allwinnertech.com>
14 *
15 * Copyright (C) 2014 Maxime Ripard
16 * Maxime Ripard <maxime.ripard@free-electrons.com>
17 *
18 * SPDX-License-Identifier: GPL-2.0+
19 */
20
21#include <common.h>
Jagan Teki97b3d5a2019-02-27 20:02:10 +053022#include <clk.h>
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020023#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060024#include <log.h>
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020025#include <spi.h>
26#include <errno.h>
27#include <fdt_support.h>
Jagan Tekif69b4252019-02-27 20:02:11 +053028#include <reset.h>
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020029#include <wait_bit.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060030#include <asm/global_data.h>
Simon Glass9bc15642020-02-03 07:36:16 -070031#include <dm/device_compat.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060032#include <linux/bitops.h>
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020033
34#include <asm/bitops.h>
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020035#include <asm/io.h>
36
Jagan Teki66220da2019-02-27 20:02:05 +053037#include <linux/iopoll.h>
38
Jagan Teki3f53a582019-02-27 20:02:12 +053039DECLARE_GLOBAL_DATA_PTR;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020040
Jagan Teki3f53a582019-02-27 20:02:12 +053041/* sun4i spi registers */
42#define SUN4I_RXDATA_REG 0x00
43#define SUN4I_TXDATA_REG 0x04
44#define SUN4I_CTL_REG 0x08
45#define SUN4I_CLK_CTL_REG 0x1c
46#define SUN4I_BURST_CNT_REG 0x20
47#define SUN4I_XMIT_CNT_REG 0x24
48#define SUN4I_FIFO_STA_REG 0x28
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020049
Jagan Tekif69b4252019-02-27 20:02:11 +053050/* sun6i spi registers */
51#define SUN6I_GBL_CTL_REG 0x04
52#define SUN6I_TFR_CTL_REG 0x08
53#define SUN6I_FIFO_CTL_REG 0x18
54#define SUN6I_FIFO_STA_REG 0x1c
55#define SUN6I_CLK_CTL_REG 0x24
56#define SUN6I_BURST_CNT_REG 0x30
57#define SUN6I_XMIT_CNT_REG 0x34
58#define SUN6I_BURST_CTL_REG 0x38
59#define SUN6I_TXDATA_REG 0x200
60#define SUN6I_RXDATA_REG 0x300
61
Jagan Teki3f53a582019-02-27 20:02:12 +053062/* sun spi bits */
63#define SUN4I_CTL_ENABLE BIT(0)
64#define SUN4I_CTL_MASTER BIT(1)
65#define SUN4I_CLK_CTL_CDR2_MASK 0xff
66#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK)
67#define SUN4I_CLK_CTL_CDR1_MASK 0xf
68#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
69#define SUN4I_CLK_CTL_DRS BIT(12)
70#define SUN4I_MAX_XFER_SIZE 0xffffff
71#define SUN4I_BURST_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE)
72#define SUN4I_XMIT_CNT(cnt) ((cnt) & SUN4I_MAX_XFER_SIZE)
73#define SUN4I_FIFO_STA_RF_CNT_BITS 0
74
Andre Przywara4d3521ce2022-04-26 23:58:53 +010075#ifdef CONFIG_MACH_SUNIV
76/* the AHB clock, which we programmed to be 1/3 of PLL_PERIPH@600MHz */
77#define SUNXI_INPUT_CLOCK 200000000 /* 200 MHz */
78#define SUN4I_SPI_MAX_RATE (SUNXI_INPUT_CLOCK / 2)
79#else
Andre Przywara27835682022-05-03 02:06:37 +010080/* the SPI mod clock, defaulting to be 1/1 of the HOSC@24MHz */
81#define SUNXI_INPUT_CLOCK 24000000 /* 24 MHz */
82#define SUN4I_SPI_MAX_RATE SUNXI_INPUT_CLOCK
Andre Przywara4d3521ce2022-04-26 23:58:53 +010083#endif
Jagan Teki3f53a582019-02-27 20:02:12 +053084#define SUN4I_SPI_MIN_RATE 3000
85#define SUN4I_SPI_DEFAULT_RATE 1000000
Icenowy Zhenga244be62022-06-28 14:49:24 +080086#define SUN4I_SPI_TIMEOUT_MS 1000
Stefan Mavrodiev5d716042018-02-06 15:14:33 +020087
Jagan Teki3f53a582019-02-27 20:02:12 +053088#define SPI_REG(priv, reg) ((priv)->base + \
Jagan Tekic25058c2019-02-27 20:02:08 +053089 (priv)->variant->regs[reg])
90#define SPI_BIT(priv, bit) ((priv)->variant->bits[bit])
91#define SPI_CS(priv, cs) (((cs) << SPI_BIT(priv, SPI_TCR_CS_SEL)) & \
92 SPI_BIT(priv, SPI_TCR_CS_MASK))
93
94/* sun spi register set */
95enum sun4i_spi_regs {
96 SPI_GCR,
97 SPI_TCR,
98 SPI_FCR,
99 SPI_FSR,
100 SPI_CCR,
101 SPI_BC,
102 SPI_TC,
103 SPI_BCTL,
104 SPI_TXD,
105 SPI_RXD,
106};
107
108/* sun spi register bits */
109enum sun4i_spi_bits {
110 SPI_GCR_TP,
Jagan Tekif69b4252019-02-27 20:02:11 +0530111 SPI_GCR_SRST,
Jagan Tekic25058c2019-02-27 20:02:08 +0530112 SPI_TCR_CPHA,
113 SPI_TCR_CPOL,
114 SPI_TCR_CS_ACTIVE_LOW,
115 SPI_TCR_CS_SEL,
116 SPI_TCR_CS_MASK,
117 SPI_TCR_XCH,
118 SPI_TCR_CS_MANUAL,
119 SPI_TCR_CS_LEVEL,
120 SPI_FCR_TF_RST,
121 SPI_FCR_RF_RST,
122 SPI_FSR_RF_CNT_MASK,
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200123};
124
Jagan Tekic25058c2019-02-27 20:02:08 +0530125struct sun4i_spi_variant {
126 const unsigned long *regs;
127 const u32 *bits;
Jagan Tekic12eb6a2019-02-27 20:02:09 +0530128 u32 fifo_depth;
Jagan Tekif69b4252019-02-27 20:02:11 +0530129 bool has_soft_reset;
130 bool has_burst_ctl;
Jagan Tekic25058c2019-02-27 20:02:08 +0530131};
132
Simon Glassb75b15b2020-12-03 16:55:23 -0700133struct sun4i_spi_plat {
Jagan Tekic25058c2019-02-27 20:02:08 +0530134 struct sun4i_spi_variant *variant;
Jagan Teki3f53a582019-02-27 20:02:12 +0530135 u32 base;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200136 u32 max_hz;
137};
138
139struct sun4i_spi_priv {
Jagan Tekic25058c2019-02-27 20:02:08 +0530140 struct sun4i_spi_variant *variant;
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530141 struct clk clk_ahb, clk_mod;
Jagan Tekif69b4252019-02-27 20:02:11 +0530142 struct reset_ctl reset;
Jagan Teki3f53a582019-02-27 20:02:12 +0530143 u32 base;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200144 u32 freq;
145 u32 mode;
146
147 const u8 *tx_buf;
148 u8 *rx_buf;
149};
150
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200151static inline void sun4i_spi_drain_fifo(struct sun4i_spi_priv *priv, int len)
152{
153 u8 byte;
154
155 while (len--) {
Jagan Tekic25058c2019-02-27 20:02:08 +0530156 byte = readb(SPI_REG(priv, SPI_RXD));
Stefan Mavrodiev165db622018-12-05 14:27:57 +0200157 if (priv->rx_buf)
158 *priv->rx_buf++ = byte;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200159 }
160}
161
162static inline void sun4i_spi_fill_fifo(struct sun4i_spi_priv *priv, int len)
163{
164 u8 byte;
165
166 while (len--) {
167 byte = priv->tx_buf ? *priv->tx_buf++ : 0;
Jagan Tekic25058c2019-02-27 20:02:08 +0530168 writeb(byte, SPI_REG(priv, SPI_TXD));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200169 }
170}
171
172static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable)
173{
174 struct sun4i_spi_priv *priv = dev_get_priv(bus);
175 u32 reg;
176
Jagan Tekic25058c2019-02-27 20:02:08 +0530177 reg = readl(SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200178
Jagan Tekic25058c2019-02-27 20:02:08 +0530179 reg &= ~SPI_BIT(priv, SPI_TCR_CS_MASK);
180 reg |= SPI_CS(priv, cs);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200181
182 if (enable)
Jagan Tekic25058c2019-02-27 20:02:08 +0530183 reg &= ~SPI_BIT(priv, SPI_TCR_CS_LEVEL);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200184 else
Jagan Tekic25058c2019-02-27 20:02:08 +0530185 reg |= SPI_BIT(priv, SPI_TCR_CS_LEVEL);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200186
Jagan Tekic25058c2019-02-27 20:02:08 +0530187 writel(reg, SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200188}
189
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530190static inline int sun4i_spi_set_clock(struct udevice *dev, bool enable)
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200191{
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530192 struct sun4i_spi_priv *priv = dev_get_priv(dev);
193 int ret;
194
195 if (!enable) {
196 clk_disable(&priv->clk_ahb);
197 clk_disable(&priv->clk_mod);
Jagan Tekif69b4252019-02-27 20:02:11 +0530198 if (reset_valid(&priv->reset))
199 reset_assert(&priv->reset);
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530200 return 0;
201 }
202
203 ret = clk_enable(&priv->clk_ahb);
204 if (ret) {
205 dev_err(dev, "failed to enable ahb clock (ret=%d)\n", ret);
206 return ret;
207 }
208
209 ret = clk_enable(&priv->clk_mod);
210 if (ret) {
211 dev_err(dev, "failed to enable mod clock (ret=%d)\n", ret);
212 goto err_ahb;
213 }
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200214
Jagan Tekif69b4252019-02-27 20:02:11 +0530215 if (reset_valid(&priv->reset)) {
216 ret = reset_deassert(&priv->reset);
217 if (ret) {
218 dev_err(dev, "failed to deassert reset\n");
219 goto err_mod;
220 }
221 }
222
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530223 return 0;
224
Jagan Tekif69b4252019-02-27 20:02:11 +0530225err_mod:
226 clk_disable(&priv->clk_mod);
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530227err_ahb:
228 clk_disable(&priv->clk_ahb);
229 return ret;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200230}
231
Andre Przywara62a24e12022-05-03 00:07:16 +0100232static void sun4i_spi_set_speed_mode(struct udevice *dev)
233{
234 struct sun4i_spi_priv *priv = dev_get_priv(dev);
235 unsigned int div;
236 u32 reg;
237
238 /*
239 * Setup clock divider.
240 *
241 * We have two choices there. Either we can use the clock
242 * divide rate 1, which is calculated thanks to this formula:
243 * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
244 * Or we can use CDR2, which is calculated with the formula:
245 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
246 * Whether we use the former or the latter is set through the
247 * DRS bit.
248 *
249 * First try CDR2, and if we can't reach the expected
250 * frequency, fall back to CDR1.
251 */
252
Andre Przywara27835682022-05-03 02:06:37 +0100253 div = DIV_ROUND_UP(SUNXI_INPUT_CLOCK, priv->freq);
Andre Przywara62a24e12022-05-03 00:07:16 +0100254 reg = readl(SPI_REG(priv, SPI_CCR));
255
Andre Przywara27835682022-05-03 02:06:37 +0100256 if ((div / 2) <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
257 div /= 2;
Andre Przywara62a24e12022-05-03 00:07:16 +0100258 if (div > 0)
259 div--;
260
261 reg &= ~(SUN4I_CLK_CTL_CDR2_MASK | SUN4I_CLK_CTL_DRS);
262 reg |= SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
263 } else {
Andre Przywara27835682022-05-03 02:06:37 +0100264 div = fls(div - 1);
Andre Przywara4d3521ce2022-04-26 23:58:53 +0100265 /* The F1C100s encodes the divider as 2^(n+1) */
266 if (IS_ENABLED(CONFIG_MACH_SUNIV))
267 div--;
Andre Przywara62a24e12022-05-03 00:07:16 +0100268 reg &= ~((SUN4I_CLK_CTL_CDR1_MASK << 8) | SUN4I_CLK_CTL_DRS);
269 reg |= SUN4I_CLK_CTL_CDR1(div);
270 }
271
272 writel(reg, SPI_REG(priv, SPI_CCR));
273
274 reg = readl(SPI_REG(priv, SPI_TCR));
275 reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA));
276
277 if (priv->mode & SPI_CPOL)
278 reg |= SPI_BIT(priv, SPI_TCR_CPOL);
279
280 if (priv->mode & SPI_CPHA)
281 reg |= SPI_BIT(priv, SPI_TCR_CPHA);
282
283 writel(reg, SPI_REG(priv, SPI_TCR));
284}
285
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200286static int sun4i_spi_claim_bus(struct udevice *dev)
287{
288 struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530289 int ret;
290
291 ret = sun4i_spi_set_clock(dev->parent, true);
292 if (ret)
293 return ret;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200294
Jagan Tekic25058c2019-02-27 20:02:08 +0530295 setbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE |
296 SUN4I_CTL_MASTER | SPI_BIT(priv, SPI_GCR_TP));
297
Jagan Tekif69b4252019-02-27 20:02:11 +0530298 if (priv->variant->has_soft_reset)
299 setbits_le32(SPI_REG(priv, SPI_GCR),
300 SPI_BIT(priv, SPI_GCR_SRST));
301
Jagan Tekic25058c2019-02-27 20:02:08 +0530302 setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) |
303 SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW));
Jagan Tekif9b70122019-02-27 20:02:07 +0530304
Andre Przywara62a24e12022-05-03 00:07:16 +0100305 sun4i_spi_set_speed_mode(dev->parent);
306
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200307 return 0;
308}
309
310static int sun4i_spi_release_bus(struct udevice *dev)
311{
312 struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200313
Jagan Tekic25058c2019-02-27 20:02:08 +0530314 clrbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200315
Jagan Teki97b3d5a2019-02-27 20:02:10 +0530316 sun4i_spi_set_clock(dev->parent, false);
317
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200318 return 0;
319}
320
321static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
322 const void *dout, void *din, unsigned long flags)
323{
324 struct udevice *bus = dev->parent;
325 struct sun4i_spi_priv *priv = dev_get_priv(bus);
Simon Glassb75b15b2020-12-03 16:55:23 -0700326 struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200327
328 u32 len = bitlen / 8;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200329 u8 nbytes;
330 int ret;
331
332 priv->tx_buf = dout;
333 priv->rx_buf = din;
334
335 if (bitlen % 8) {
336 debug("%s: non byte-aligned SPI transfer.\n", __func__);
337 return -ENAVAIL;
338 }
339
340 if (flags & SPI_XFER_BEGIN)
341 sun4i_spi_set_cs(bus, slave_plat->cs, true);
342
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200343 /* Reset FIFOs */
Jagan Tekic25058c2019-02-27 20:02:08 +0530344 setbits_le32(SPI_REG(priv, SPI_FCR), SPI_BIT(priv, SPI_FCR_RF_RST) |
345 SPI_BIT(priv, SPI_FCR_TF_RST));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200346
347 while (len) {
348 /* Setup the transfer now... */
Jagan Tekic12eb6a2019-02-27 20:02:09 +0530349 nbytes = min(len, (priv->variant->fifo_depth - 1));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200350
351 /* Setup the counters */
Jagan Tekic25058c2019-02-27 20:02:08 +0530352 writel(SUN4I_BURST_CNT(nbytes), SPI_REG(priv, SPI_BC));
353 writel(SUN4I_XMIT_CNT(nbytes), SPI_REG(priv, SPI_TC));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200354
Jagan Tekif69b4252019-02-27 20:02:11 +0530355 if (priv->variant->has_burst_ctl)
356 writel(SUN4I_BURST_CNT(nbytes),
357 SPI_REG(priv, SPI_BCTL));
358
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200359 /* Fill the TX FIFO */
360 sun4i_spi_fill_fifo(priv, nbytes);
361
362 /* Start the transfer */
Jagan Tekic25058c2019-02-27 20:02:08 +0530363 setbits_le32(SPI_REG(priv, SPI_TCR),
364 SPI_BIT(priv, SPI_TCR_XCH));
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200365
Icenowy Zhenga244be62022-06-28 14:49:24 +0800366 /* Wait for the transfer to be done */
367 ret = wait_for_bit_le32((const void *)SPI_REG(priv, SPI_TCR),
368 SPI_BIT(priv, SPI_TCR_XCH),
369 false, SUN4I_SPI_TIMEOUT_MS, false);
Jagan Teki66220da2019-02-27 20:02:05 +0530370 if (ret < 0) {
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200371 printf("ERROR: sun4i_spi: Timeout transferring data\n");
372 sun4i_spi_set_cs(bus, slave_plat->cs, false);
373 return ret;
374 }
375
376 /* Drain the RX FIFO */
377 sun4i_spi_drain_fifo(priv, nbytes);
378
379 len -= nbytes;
380 }
381
382 if (flags & SPI_XFER_END)
383 sun4i_spi_set_cs(bus, slave_plat->cs, false);
384
385 return 0;
386}
387
388static int sun4i_spi_set_speed(struct udevice *dev, uint speed)
389{
Simon Glassb75b15b2020-12-03 16:55:23 -0700390 struct sun4i_spi_plat *plat = dev_get_plat(dev);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200391 struct sun4i_spi_priv *priv = dev_get_priv(dev);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200392
393 if (speed > plat->max_hz)
394 speed = plat->max_hz;
395
396 if (speed < SUN4I_SPI_MIN_RATE)
397 speed = SUN4I_SPI_MIN_RATE;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200398
399 priv->freq = speed;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200400
401 return 0;
402}
403
404static int sun4i_spi_set_mode(struct udevice *dev, uint mode)
405{
406 struct sun4i_spi_priv *priv = dev_get_priv(dev);
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200407
408 priv->mode = mode;
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200409
410 return 0;
411}
412
413static const struct dm_spi_ops sun4i_spi_ops = {
414 .claim_bus = sun4i_spi_claim_bus,
415 .release_bus = sun4i_spi_release_bus,
416 .xfer = sun4i_spi_xfer,
417 .set_speed = sun4i_spi_set_speed,
418 .set_mode = sun4i_spi_set_mode,
419};
420
Jagan Teki3f53a582019-02-27 20:02:12 +0530421static int sun4i_spi_probe(struct udevice *bus)
422{
Simon Glassb75b15b2020-12-03 16:55:23 -0700423 struct sun4i_spi_plat *plat = dev_get_plat(bus);
Jagan Teki3f53a582019-02-27 20:02:12 +0530424 struct sun4i_spi_priv *priv = dev_get_priv(bus);
425 int ret;
426
427 ret = clk_get_by_name(bus, "ahb", &priv->clk_ahb);
428 if (ret) {
Sean Anderson64474dd2020-09-15 10:45:11 -0400429 dev_err(bus, "failed to get ahb clock\n");
Jagan Teki3f53a582019-02-27 20:02:12 +0530430 return ret;
431 }
432
433 ret = clk_get_by_name(bus, "mod", &priv->clk_mod);
434 if (ret) {
Sean Anderson64474dd2020-09-15 10:45:11 -0400435 dev_err(bus, "failed to get mod clock\n");
Jagan Teki3f53a582019-02-27 20:02:12 +0530436 return ret;
437 }
438
439 ret = reset_get_by_index(bus, 0, &priv->reset);
440 if (ret && ret != -ENOENT) {
Sean Anderson64474dd2020-09-15 10:45:11 -0400441 dev_err(bus, "failed to get reset\n");
Jagan Teki3f53a582019-02-27 20:02:12 +0530442 return ret;
443 }
444
Jagan Teki3f53a582019-02-27 20:02:12 +0530445 priv->variant = plat->variant;
446 priv->base = plat->base;
447 priv->freq = plat->max_hz;
448
449 return 0;
450}
451
Simon Glassaad29ae2020-12-03 16:55:21 -0700452static int sun4i_spi_of_to_plat(struct udevice *bus)
Jagan Teki3f53a582019-02-27 20:02:12 +0530453{
Simon Glassb75b15b2020-12-03 16:55:23 -0700454 struct sun4i_spi_plat *plat = dev_get_plat(bus);
Jagan Teki3f53a582019-02-27 20:02:12 +0530455 int node = dev_of_offset(bus);
456
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +0900457 plat->base = dev_read_addr(bus);
Jagan Teki3f53a582019-02-27 20:02:12 +0530458 plat->variant = (struct sun4i_spi_variant *)dev_get_driver_data(bus);
459 plat->max_hz = fdtdec_get_int(gd->fdt_blob, node,
460 "spi-max-frequency",
461 SUN4I_SPI_DEFAULT_RATE);
462
463 if (plat->max_hz > SUN4I_SPI_MAX_RATE)
464 plat->max_hz = SUN4I_SPI_MAX_RATE;
465
466 return 0;
467}
468
Jagan Tekic25058c2019-02-27 20:02:08 +0530469static const unsigned long sun4i_spi_regs[] = {
470 [SPI_GCR] = SUN4I_CTL_REG,
471 [SPI_TCR] = SUN4I_CTL_REG,
472 [SPI_FCR] = SUN4I_CTL_REG,
473 [SPI_FSR] = SUN4I_FIFO_STA_REG,
474 [SPI_CCR] = SUN4I_CLK_CTL_REG,
475 [SPI_BC] = SUN4I_BURST_CNT_REG,
476 [SPI_TC] = SUN4I_XMIT_CNT_REG,
477 [SPI_TXD] = SUN4I_TXDATA_REG,
478 [SPI_RXD] = SUN4I_RXDATA_REG,
479};
480
481static const u32 sun4i_spi_bits[] = {
482 [SPI_GCR_TP] = BIT(18),
483 [SPI_TCR_CPHA] = BIT(2),
484 [SPI_TCR_CPOL] = BIT(3),
485 [SPI_TCR_CS_ACTIVE_LOW] = BIT(4),
486 [SPI_TCR_XCH] = BIT(10),
487 [SPI_TCR_CS_SEL] = 12,
488 [SPI_TCR_CS_MASK] = 0x3000,
489 [SPI_TCR_CS_MANUAL] = BIT(16),
490 [SPI_TCR_CS_LEVEL] = BIT(17),
491 [SPI_FCR_TF_RST] = BIT(8),
492 [SPI_FCR_RF_RST] = BIT(9),
493 [SPI_FSR_RF_CNT_MASK] = GENMASK(6, 0),
494};
495
Jagan Tekif69b4252019-02-27 20:02:11 +0530496static const unsigned long sun6i_spi_regs[] = {
497 [SPI_GCR] = SUN6I_GBL_CTL_REG,
498 [SPI_TCR] = SUN6I_TFR_CTL_REG,
499 [SPI_FCR] = SUN6I_FIFO_CTL_REG,
500 [SPI_FSR] = SUN6I_FIFO_STA_REG,
501 [SPI_CCR] = SUN6I_CLK_CTL_REG,
502 [SPI_BC] = SUN6I_BURST_CNT_REG,
503 [SPI_TC] = SUN6I_XMIT_CNT_REG,
504 [SPI_BCTL] = SUN6I_BURST_CTL_REG,
505 [SPI_TXD] = SUN6I_TXDATA_REG,
506 [SPI_RXD] = SUN6I_RXDATA_REG,
507};
508
509static const u32 sun6i_spi_bits[] = {
510 [SPI_GCR_TP] = BIT(7),
511 [SPI_GCR_SRST] = BIT(31),
512 [SPI_TCR_CPHA] = BIT(0),
513 [SPI_TCR_CPOL] = BIT(1),
514 [SPI_TCR_CS_ACTIVE_LOW] = BIT(2),
515 [SPI_TCR_CS_SEL] = 4,
516 [SPI_TCR_CS_MASK] = 0x30,
517 [SPI_TCR_CS_MANUAL] = BIT(6),
518 [SPI_TCR_CS_LEVEL] = BIT(7),
519 [SPI_TCR_XCH] = BIT(31),
520 [SPI_FCR_RF_RST] = BIT(15),
521 [SPI_FCR_TF_RST] = BIT(31),
522 [SPI_FSR_RF_CNT_MASK] = GENMASK(7, 0),
523};
524
Jagan Tekic25058c2019-02-27 20:02:08 +0530525static const struct sun4i_spi_variant sun4i_a10_spi_variant = {
526 .regs = sun4i_spi_regs,
527 .bits = sun4i_spi_bits,
Jagan Tekic12eb6a2019-02-27 20:02:09 +0530528 .fifo_depth = 64,
Jagan Tekif69b4252019-02-27 20:02:11 +0530529};
530
531static const struct sun4i_spi_variant sun6i_a31_spi_variant = {
532 .regs = sun6i_spi_regs,
533 .bits = sun6i_spi_bits,
534 .fifo_depth = 128,
535 .has_soft_reset = true,
536 .has_burst_ctl = true,
537};
538
539static const struct sun4i_spi_variant sun8i_h3_spi_variant = {
540 .regs = sun6i_spi_regs,
541 .bits = sun6i_spi_bits,
542 .fifo_depth = 64,
543 .has_soft_reset = true,
544 .has_burst_ctl = true,
Jagan Tekic25058c2019-02-27 20:02:08 +0530545};
546
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200547static const struct udevice_id sun4i_spi_ids[] = {
Jagan Tekic25058c2019-02-27 20:02:08 +0530548 {
549 .compatible = "allwinner,sun4i-a10-spi",
550 .data = (ulong)&sun4i_a10_spi_variant,
551 },
Jagan Tekif69b4252019-02-27 20:02:11 +0530552 {
553 .compatible = "allwinner,sun6i-a31-spi",
554 .data = (ulong)&sun6i_a31_spi_variant,
555 },
556 {
557 .compatible = "allwinner,sun8i-h3-spi",
558 .data = (ulong)&sun8i_h3_spi_variant,
559 },
Jagan Teki3f53a582019-02-27 20:02:12 +0530560 { /* sentinel */ }
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200561};
562
563U_BOOT_DRIVER(sun4i_spi) = {
564 .name = "sun4i_spi",
565 .id = UCLASS_SPI,
566 .of_match = sun4i_spi_ids,
567 .ops = &sun4i_spi_ops,
Simon Glassaad29ae2020-12-03 16:55:21 -0700568 .of_to_plat = sun4i_spi_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700569 .plat_auto = sizeof(struct sun4i_spi_plat),
Simon Glass8a2b47f2020-12-03 16:55:17 -0700570 .priv_auto = sizeof(struct sun4i_spi_priv),
Stefan Mavrodiev5d716042018-02-06 15:14:33 +0200571 .probe = sun4i_spi_probe,
572};