blob: b6cd7ddafadc0f34a40f0dc5764bb4519a6d73e6 [file] [log] [blame]
Stefan Mavrodiev7f25d812018-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 Teki8d71a192019-02-27 20:02:10 +053022#include <clk.h>
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020023#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060024#include <log.h>
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020025#include <spi.h>
26#include <errno.h>
27#include <fdt_support.h>
Jagan Teki853f4512019-02-27 20:02:11 +053028#include <reset.h>
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020029#include <wait_bit.h>
Simon Glass401d1c42020-10-30 21:38:53 -060030#include <asm/global_data.h>
Simon Glass336d4612020-02-03 07:36:16 -070031#include <dm/device_compat.h>
Simon Glasscd93d622020-05-10 11:40:13 -060032#include <linux/bitops.h>
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020033
34#include <asm/bitops.h>
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020035#include <asm/io.h>
36
Jagan Teki6cb6aa62019-02-27 20:02:05 +053037#include <linux/iopoll.h>
38
Jagan Teki903e7cf2019-02-27 20:02:12 +053039DECLARE_GLOBAL_DATA_PTR;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020040
Jagan Teki903e7cf2019-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 Mavrodiev7f25d812018-02-06 15:14:33 +020049
Jagan Teki853f4512019-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 Teki903e7cf2019-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
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +020074
Jagan Teki903e7cf2019-02-27 20:02:12 +053075#define SUN4I_SPI_MAX_RATE 24000000
76#define SUN4I_SPI_MIN_RATE 3000
77#define SUN4I_SPI_DEFAULT_RATE 1000000
78#define SUN4I_SPI_TIMEOUT_US 1000000
79
80#define SPI_REG(priv, reg) ((priv)->base + \
Jagan Teki8d9bf462019-02-27 20:02:08 +053081 (priv)->variant->regs[reg])
82#define SPI_BIT(priv, bit) ((priv)->variant->bits[bit])
83#define SPI_CS(priv, cs) (((cs) << SPI_BIT(priv, SPI_TCR_CS_SEL)) & \
84 SPI_BIT(priv, SPI_TCR_CS_MASK))
85
86/* sun spi register set */
87enum sun4i_spi_regs {
88 SPI_GCR,
89 SPI_TCR,
90 SPI_FCR,
91 SPI_FSR,
92 SPI_CCR,
93 SPI_BC,
94 SPI_TC,
95 SPI_BCTL,
96 SPI_TXD,
97 SPI_RXD,
98};
99
100/* sun spi register bits */
101enum sun4i_spi_bits {
102 SPI_GCR_TP,
Jagan Teki853f4512019-02-27 20:02:11 +0530103 SPI_GCR_SRST,
Jagan Teki8d9bf462019-02-27 20:02:08 +0530104 SPI_TCR_CPHA,
105 SPI_TCR_CPOL,
106 SPI_TCR_CS_ACTIVE_LOW,
107 SPI_TCR_CS_SEL,
108 SPI_TCR_CS_MASK,
109 SPI_TCR_XCH,
110 SPI_TCR_CS_MANUAL,
111 SPI_TCR_CS_LEVEL,
112 SPI_FCR_TF_RST,
113 SPI_FCR_RF_RST,
114 SPI_FSR_RF_CNT_MASK,
115};
116
117struct sun4i_spi_variant {
118 const unsigned long *regs;
119 const u32 *bits;
Jagan Teki178fbd22019-02-27 20:02:09 +0530120 u32 fifo_depth;
Jagan Teki853f4512019-02-27 20:02:11 +0530121 bool has_soft_reset;
122 bool has_burst_ctl;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200123};
124
Simon Glass8a8d24b2020-12-03 16:55:23 -0700125struct sun4i_spi_plat {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530126 struct sun4i_spi_variant *variant;
Jagan Teki903e7cf2019-02-27 20:02:12 +0530127 u32 base;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200128 u32 max_hz;
129};
130
131struct sun4i_spi_priv {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530132 struct sun4i_spi_variant *variant;
Jagan Teki8d71a192019-02-27 20:02:10 +0530133 struct clk clk_ahb, clk_mod;
Jagan Teki853f4512019-02-27 20:02:11 +0530134 struct reset_ctl reset;
Jagan Teki903e7cf2019-02-27 20:02:12 +0530135 u32 base;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200136 u32 freq;
137 u32 mode;
138
139 const u8 *tx_buf;
140 u8 *rx_buf;
141};
142
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200143static inline void sun4i_spi_drain_fifo(struct sun4i_spi_priv *priv, int len)
144{
145 u8 byte;
146
147 while (len--) {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530148 byte = readb(SPI_REG(priv, SPI_RXD));
Stefan Mavrodiev5c1a87d2018-12-05 14:27:57 +0200149 if (priv->rx_buf)
150 *priv->rx_buf++ = byte;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200151 }
152}
153
154static inline void sun4i_spi_fill_fifo(struct sun4i_spi_priv *priv, int len)
155{
156 u8 byte;
157
158 while (len--) {
159 byte = priv->tx_buf ? *priv->tx_buf++ : 0;
Jagan Teki8d9bf462019-02-27 20:02:08 +0530160 writeb(byte, SPI_REG(priv, SPI_TXD));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200161 }
162}
163
164static void sun4i_spi_set_cs(struct udevice *bus, u8 cs, bool enable)
165{
166 struct sun4i_spi_priv *priv = dev_get_priv(bus);
167 u32 reg;
168
Jagan Teki8d9bf462019-02-27 20:02:08 +0530169 reg = readl(SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200170
Jagan Teki8d9bf462019-02-27 20:02:08 +0530171 reg &= ~SPI_BIT(priv, SPI_TCR_CS_MASK);
172 reg |= SPI_CS(priv, cs);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200173
174 if (enable)
Jagan Teki8d9bf462019-02-27 20:02:08 +0530175 reg &= ~SPI_BIT(priv, SPI_TCR_CS_LEVEL);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200176 else
Jagan Teki8d9bf462019-02-27 20:02:08 +0530177 reg |= SPI_BIT(priv, SPI_TCR_CS_LEVEL);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200178
Jagan Teki8d9bf462019-02-27 20:02:08 +0530179 writel(reg, SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200180}
181
Jagan Teki8d71a192019-02-27 20:02:10 +0530182static inline int sun4i_spi_set_clock(struct udevice *dev, bool enable)
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200183{
Jagan Teki8d71a192019-02-27 20:02:10 +0530184 struct sun4i_spi_priv *priv = dev_get_priv(dev);
185 int ret;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200186
Jagan Teki8d71a192019-02-27 20:02:10 +0530187 if (!enable) {
188 clk_disable(&priv->clk_ahb);
189 clk_disable(&priv->clk_mod);
Jagan Teki853f4512019-02-27 20:02:11 +0530190 if (reset_valid(&priv->reset))
191 reset_assert(&priv->reset);
Jagan Teki8d71a192019-02-27 20:02:10 +0530192 return 0;
193 }
194
195 ret = clk_enable(&priv->clk_ahb);
196 if (ret) {
197 dev_err(dev, "failed to enable ahb clock (ret=%d)\n", ret);
198 return ret;
199 }
200
201 ret = clk_enable(&priv->clk_mod);
202 if (ret) {
203 dev_err(dev, "failed to enable mod clock (ret=%d)\n", ret);
204 goto err_ahb;
205 }
206
Jagan Teki853f4512019-02-27 20:02:11 +0530207 if (reset_valid(&priv->reset)) {
208 ret = reset_deassert(&priv->reset);
209 if (ret) {
210 dev_err(dev, "failed to deassert reset\n");
211 goto err_mod;
212 }
213 }
214
Jagan Teki8d71a192019-02-27 20:02:10 +0530215 return 0;
216
Jagan Teki853f4512019-02-27 20:02:11 +0530217err_mod:
218 clk_disable(&priv->clk_mod);
Jagan Teki8d71a192019-02-27 20:02:10 +0530219err_ahb:
220 clk_disable(&priv->clk_ahb);
221 return ret;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200222}
223
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200224static int sun4i_spi_claim_bus(struct udevice *dev)
225{
226 struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
Jagan Teki8d71a192019-02-27 20:02:10 +0530227 int ret;
228
229 ret = sun4i_spi_set_clock(dev->parent, true);
230 if (ret)
231 return ret;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200232
Jagan Teki8d9bf462019-02-27 20:02:08 +0530233 setbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE |
234 SUN4I_CTL_MASTER | SPI_BIT(priv, SPI_GCR_TP));
235
Jagan Teki853f4512019-02-27 20:02:11 +0530236 if (priv->variant->has_soft_reset)
237 setbits_le32(SPI_REG(priv, SPI_GCR),
238 SPI_BIT(priv, SPI_GCR_SRST));
239
Jagan Teki8d9bf462019-02-27 20:02:08 +0530240 setbits_le32(SPI_REG(priv, SPI_TCR), SPI_BIT(priv, SPI_TCR_CS_MANUAL) |
241 SPI_BIT(priv, SPI_TCR_CS_ACTIVE_LOW));
Jagan Teki8cbf09b2019-02-27 20:02:07 +0530242
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200243 return 0;
244}
245
246static int sun4i_spi_release_bus(struct udevice *dev)
247{
248 struct sun4i_spi_priv *priv = dev_get_priv(dev->parent);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200249
Jagan Teki8d9bf462019-02-27 20:02:08 +0530250 clrbits_le32(SPI_REG(priv, SPI_GCR), SUN4I_CTL_ENABLE);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200251
Jagan Teki8d71a192019-02-27 20:02:10 +0530252 sun4i_spi_set_clock(dev->parent, false);
253
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200254 return 0;
255}
256
257static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
258 const void *dout, void *din, unsigned long flags)
259{
260 struct udevice *bus = dev->parent;
261 struct sun4i_spi_priv *priv = dev_get_priv(bus);
Simon Glass8a8d24b2020-12-03 16:55:23 -0700262 struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200263
264 u32 len = bitlen / 8;
Jagan Teki8cbf09b2019-02-27 20:02:07 +0530265 u32 rx_fifocnt;
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200266 u8 nbytes;
267 int ret;
268
269 priv->tx_buf = dout;
270 priv->rx_buf = din;
271
272 if (bitlen % 8) {
273 debug("%s: non byte-aligned SPI transfer.\n", __func__);
274 return -ENAVAIL;
275 }
276
277 if (flags & SPI_XFER_BEGIN)
278 sun4i_spi_set_cs(bus, slave_plat->cs, true);
279
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200280 /* Reset FIFOs */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530281 setbits_le32(SPI_REG(priv, SPI_FCR), SPI_BIT(priv, SPI_FCR_RF_RST) |
282 SPI_BIT(priv, SPI_FCR_TF_RST));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200283
284 while (len) {
285 /* Setup the transfer now... */
Jagan Teki178fbd22019-02-27 20:02:09 +0530286 nbytes = min(len, (priv->variant->fifo_depth - 1));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200287
288 /* Setup the counters */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530289 writel(SUN4I_BURST_CNT(nbytes), SPI_REG(priv, SPI_BC));
290 writel(SUN4I_XMIT_CNT(nbytes), SPI_REG(priv, SPI_TC));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200291
Jagan Teki853f4512019-02-27 20:02:11 +0530292 if (priv->variant->has_burst_ctl)
293 writel(SUN4I_BURST_CNT(nbytes),
294 SPI_REG(priv, SPI_BCTL));
295
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200296 /* Fill the TX FIFO */
297 sun4i_spi_fill_fifo(priv, nbytes);
298
299 /* Start the transfer */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530300 setbits_le32(SPI_REG(priv, SPI_TCR),
301 SPI_BIT(priv, SPI_TCR_XCH));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200302
Jagan Teki6cb6aa62019-02-27 20:02:05 +0530303 /* Wait till RX FIFO to be empty */
Jagan Teki8d9bf462019-02-27 20:02:08 +0530304 ret = readl_poll_timeout(SPI_REG(priv, SPI_FSR),
305 rx_fifocnt,
306 (((rx_fifocnt &
307 SPI_BIT(priv, SPI_FSR_RF_CNT_MASK)) >>
Jagan Teki6cb6aa62019-02-27 20:02:05 +0530308 SUN4I_FIFO_STA_RF_CNT_BITS) >= nbytes),
309 SUN4I_SPI_TIMEOUT_US);
310 if (ret < 0) {
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200311 printf("ERROR: sun4i_spi: Timeout transferring data\n");
312 sun4i_spi_set_cs(bus, slave_plat->cs, false);
313 return ret;
314 }
315
316 /* Drain the RX FIFO */
317 sun4i_spi_drain_fifo(priv, nbytes);
318
319 len -= nbytes;
320 }
321
322 if (flags & SPI_XFER_END)
323 sun4i_spi_set_cs(bus, slave_plat->cs, false);
324
325 return 0;
326}
327
328static int sun4i_spi_set_speed(struct udevice *dev, uint speed)
329{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700330 struct sun4i_spi_plat *plat = dev_get_plat(dev);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200331 struct sun4i_spi_priv *priv = dev_get_priv(dev);
332 unsigned int div;
333 u32 reg;
334
335 if (speed > plat->max_hz)
336 speed = plat->max_hz;
337
338 if (speed < SUN4I_SPI_MIN_RATE)
339 speed = SUN4I_SPI_MIN_RATE;
340 /*
341 * Setup clock divider.
342 *
343 * We have two choices there. Either we can use the clock
344 * divide rate 1, which is calculated thanks to this formula:
345 * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
346 * Or we can use CDR2, which is calculated with the formula:
347 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
348 * Whether we use the former or the latter is set through the
349 * DRS bit.
350 *
351 * First try CDR2, and if we can't reach the expected
352 * frequency, fall back to CDR1.
353 */
354
355 div = SUN4I_SPI_MAX_RATE / (2 * speed);
Jagan Teki8d9bf462019-02-27 20:02:08 +0530356 reg = readl(SPI_REG(priv, SPI_CCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200357
358 if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
359 if (div > 0)
360 div--;
361
362 reg &= ~(SUN4I_CLK_CTL_CDR2_MASK | SUN4I_CLK_CTL_DRS);
363 reg |= SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
364 } else {
365 div = __ilog2(SUN4I_SPI_MAX_RATE) - __ilog2(speed);
366 reg &= ~((SUN4I_CLK_CTL_CDR1_MASK << 8) | SUN4I_CLK_CTL_DRS);
367 reg |= SUN4I_CLK_CTL_CDR1(div);
368 }
369
370 priv->freq = speed;
Jagan Teki8d9bf462019-02-27 20:02:08 +0530371 writel(reg, SPI_REG(priv, SPI_CCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200372
373 return 0;
374}
375
376static int sun4i_spi_set_mode(struct udevice *dev, uint mode)
377{
378 struct sun4i_spi_priv *priv = dev_get_priv(dev);
379 u32 reg;
380
Jagan Teki8d9bf462019-02-27 20:02:08 +0530381 reg = readl(SPI_REG(priv, SPI_TCR));
382 reg &= ~(SPI_BIT(priv, SPI_TCR_CPOL) | SPI_BIT(priv, SPI_TCR_CPHA));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200383
384 if (mode & SPI_CPOL)
Jagan Teki8d9bf462019-02-27 20:02:08 +0530385 reg |= SPI_BIT(priv, SPI_TCR_CPOL);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200386
387 if (mode & SPI_CPHA)
Jagan Teki8d9bf462019-02-27 20:02:08 +0530388 reg |= SPI_BIT(priv, SPI_TCR_CPHA);
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200389
390 priv->mode = mode;
Jagan Teki8d9bf462019-02-27 20:02:08 +0530391 writel(reg, SPI_REG(priv, SPI_TCR));
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200392
393 return 0;
394}
395
396static const struct dm_spi_ops sun4i_spi_ops = {
397 .claim_bus = sun4i_spi_claim_bus,
398 .release_bus = sun4i_spi_release_bus,
399 .xfer = sun4i_spi_xfer,
400 .set_speed = sun4i_spi_set_speed,
401 .set_mode = sun4i_spi_set_mode,
402};
403
Jagan Teki903e7cf2019-02-27 20:02:12 +0530404static int sun4i_spi_probe(struct udevice *bus)
405{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700406 struct sun4i_spi_plat *plat = dev_get_plat(bus);
Jagan Teki903e7cf2019-02-27 20:02:12 +0530407 struct sun4i_spi_priv *priv = dev_get_priv(bus);
408 int ret;
409
410 ret = clk_get_by_name(bus, "ahb", &priv->clk_ahb);
411 if (ret) {
Sean Anderson32bbe5b2020-09-15 10:45:11 -0400412 dev_err(bus, "failed to get ahb clock\n");
Jagan Teki903e7cf2019-02-27 20:02:12 +0530413 return ret;
414 }
415
416 ret = clk_get_by_name(bus, "mod", &priv->clk_mod);
417 if (ret) {
Sean Anderson32bbe5b2020-09-15 10:45:11 -0400418 dev_err(bus, "failed to get mod clock\n");
Jagan Teki903e7cf2019-02-27 20:02:12 +0530419 return ret;
420 }
421
422 ret = reset_get_by_index(bus, 0, &priv->reset);
423 if (ret && ret != -ENOENT) {
Sean Anderson32bbe5b2020-09-15 10:45:11 -0400424 dev_err(bus, "failed to get reset\n");
Jagan Teki903e7cf2019-02-27 20:02:12 +0530425 return ret;
426 }
427
Jagan Teki903e7cf2019-02-27 20:02:12 +0530428 priv->variant = plat->variant;
429 priv->base = plat->base;
430 priv->freq = plat->max_hz;
431
432 return 0;
433}
434
Simon Glassd1998a92020-12-03 16:55:21 -0700435static int sun4i_spi_of_to_plat(struct udevice *bus)
Jagan Teki903e7cf2019-02-27 20:02:12 +0530436{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700437 struct sun4i_spi_plat *plat = dev_get_plat(bus);
Jagan Teki903e7cf2019-02-27 20:02:12 +0530438 int node = dev_of_offset(bus);
439
Masahiro Yamada25484932020-07-17 14:36:48 +0900440 plat->base = dev_read_addr(bus);
Jagan Teki903e7cf2019-02-27 20:02:12 +0530441 plat->variant = (struct sun4i_spi_variant *)dev_get_driver_data(bus);
442 plat->max_hz = fdtdec_get_int(gd->fdt_blob, node,
443 "spi-max-frequency",
444 SUN4I_SPI_DEFAULT_RATE);
445
446 if (plat->max_hz > SUN4I_SPI_MAX_RATE)
447 plat->max_hz = SUN4I_SPI_MAX_RATE;
448
449 return 0;
450}
451
Jagan Teki8d9bf462019-02-27 20:02:08 +0530452static const unsigned long sun4i_spi_regs[] = {
453 [SPI_GCR] = SUN4I_CTL_REG,
454 [SPI_TCR] = SUN4I_CTL_REG,
455 [SPI_FCR] = SUN4I_CTL_REG,
456 [SPI_FSR] = SUN4I_FIFO_STA_REG,
457 [SPI_CCR] = SUN4I_CLK_CTL_REG,
458 [SPI_BC] = SUN4I_BURST_CNT_REG,
459 [SPI_TC] = SUN4I_XMIT_CNT_REG,
460 [SPI_TXD] = SUN4I_TXDATA_REG,
461 [SPI_RXD] = SUN4I_RXDATA_REG,
462};
463
464static const u32 sun4i_spi_bits[] = {
465 [SPI_GCR_TP] = BIT(18),
466 [SPI_TCR_CPHA] = BIT(2),
467 [SPI_TCR_CPOL] = BIT(3),
468 [SPI_TCR_CS_ACTIVE_LOW] = BIT(4),
469 [SPI_TCR_XCH] = BIT(10),
470 [SPI_TCR_CS_SEL] = 12,
471 [SPI_TCR_CS_MASK] = 0x3000,
472 [SPI_TCR_CS_MANUAL] = BIT(16),
473 [SPI_TCR_CS_LEVEL] = BIT(17),
474 [SPI_FCR_TF_RST] = BIT(8),
475 [SPI_FCR_RF_RST] = BIT(9),
476 [SPI_FSR_RF_CNT_MASK] = GENMASK(6, 0),
477};
478
Jagan Teki853f4512019-02-27 20:02:11 +0530479static const unsigned long sun6i_spi_regs[] = {
480 [SPI_GCR] = SUN6I_GBL_CTL_REG,
481 [SPI_TCR] = SUN6I_TFR_CTL_REG,
482 [SPI_FCR] = SUN6I_FIFO_CTL_REG,
483 [SPI_FSR] = SUN6I_FIFO_STA_REG,
484 [SPI_CCR] = SUN6I_CLK_CTL_REG,
485 [SPI_BC] = SUN6I_BURST_CNT_REG,
486 [SPI_TC] = SUN6I_XMIT_CNT_REG,
487 [SPI_BCTL] = SUN6I_BURST_CTL_REG,
488 [SPI_TXD] = SUN6I_TXDATA_REG,
489 [SPI_RXD] = SUN6I_RXDATA_REG,
490};
491
492static const u32 sun6i_spi_bits[] = {
493 [SPI_GCR_TP] = BIT(7),
494 [SPI_GCR_SRST] = BIT(31),
495 [SPI_TCR_CPHA] = BIT(0),
496 [SPI_TCR_CPOL] = BIT(1),
497 [SPI_TCR_CS_ACTIVE_LOW] = BIT(2),
498 [SPI_TCR_CS_SEL] = 4,
499 [SPI_TCR_CS_MASK] = 0x30,
500 [SPI_TCR_CS_MANUAL] = BIT(6),
501 [SPI_TCR_CS_LEVEL] = BIT(7),
502 [SPI_TCR_XCH] = BIT(31),
503 [SPI_FCR_RF_RST] = BIT(15),
504 [SPI_FCR_TF_RST] = BIT(31),
505 [SPI_FSR_RF_CNT_MASK] = GENMASK(7, 0),
506};
507
Jagan Teki8d9bf462019-02-27 20:02:08 +0530508static const struct sun4i_spi_variant sun4i_a10_spi_variant = {
509 .regs = sun4i_spi_regs,
510 .bits = sun4i_spi_bits,
Jagan Teki178fbd22019-02-27 20:02:09 +0530511 .fifo_depth = 64,
Jagan Teki8d9bf462019-02-27 20:02:08 +0530512};
513
Jagan Teki853f4512019-02-27 20:02:11 +0530514static const struct sun4i_spi_variant sun6i_a31_spi_variant = {
515 .regs = sun6i_spi_regs,
516 .bits = sun6i_spi_bits,
517 .fifo_depth = 128,
518 .has_soft_reset = true,
519 .has_burst_ctl = true,
520};
521
522static const struct sun4i_spi_variant sun8i_h3_spi_variant = {
523 .regs = sun6i_spi_regs,
524 .bits = sun6i_spi_bits,
525 .fifo_depth = 64,
526 .has_soft_reset = true,
527 .has_burst_ctl = true,
528};
529
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200530static const struct udevice_id sun4i_spi_ids[] = {
Jagan Teki8d9bf462019-02-27 20:02:08 +0530531 {
532 .compatible = "allwinner,sun4i-a10-spi",
533 .data = (ulong)&sun4i_a10_spi_variant,
534 },
Jagan Teki853f4512019-02-27 20:02:11 +0530535 {
536 .compatible = "allwinner,sun6i-a31-spi",
537 .data = (ulong)&sun6i_a31_spi_variant,
538 },
539 {
540 .compatible = "allwinner,sun8i-h3-spi",
541 .data = (ulong)&sun8i_h3_spi_variant,
542 },
Jagan Teki903e7cf2019-02-27 20:02:12 +0530543 { /* sentinel */ }
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200544};
545
546U_BOOT_DRIVER(sun4i_spi) = {
547 .name = "sun4i_spi",
548 .id = UCLASS_SPI,
549 .of_match = sun4i_spi_ids,
550 .ops = &sun4i_spi_ops,
Simon Glassd1998a92020-12-03 16:55:21 -0700551 .of_to_plat = sun4i_spi_of_to_plat,
Simon Glass8a8d24b2020-12-03 16:55:23 -0700552 .plat_auto = sizeof(struct sun4i_spi_plat),
Simon Glass41575d82020-12-03 16:55:17 -0700553 .priv_auto = sizeof(struct sun4i_spi_priv),
Stefan Mavrodiev7f25d812018-02-06 15:14:33 +0200554 .probe = sun4i_spi_probe,
555};