spi: zynqmp_gqspi: Fix issue of reading more than 32bits length
[platform/kernel/u-boot.git] / drivers / spi / apple_spi.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2021 Mark Kettenis <kettenis@openbsd.org>
4  * Copyright The Asahi Linux Contributors
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <clk.h>
10 #include <spi.h>
11 #include <asm/io.h>
12 #include <linux/bitfield.h>
13 #include <linux/delay.h>
14
15 #define APPLE_SPI_CTRL                  0x000
16 #define APPLE_SPI_CTRL_RUN              BIT(0)
17 #define APPLE_SPI_CTRL_TX_RESET         BIT(2)
18 #define APPLE_SPI_CTRL_RX_RESET         BIT(3)
19
20 #define APPLE_SPI_CFG                   0x004
21 #define APPLE_SPI_CFG_CPHA              BIT(1)
22 #define APPLE_SPI_CFG_CPOL              BIT(2)
23 #define APPLE_SPI_CFG_MODE              GENMASK(6, 5)
24 #define APPLE_SPI_CFG_MODE_POLLED       0
25 #define APPLE_SPI_CFG_MODE_IRQ          1
26 #define APPLE_SPI_CFG_MODE_DMA          2
27 #define APPLE_SPI_CFG_IE_RXCOMPLETE     BIT(7)
28 #define APPLE_SPI_CFG_IE_TXRXTHRESH     BIT(8)
29 #define APPLE_SPI_CFG_LSB_FIRST         BIT(13)
30 #define APPLE_SPI_CFG_WORD_SIZE         GENMASK(16, 15)
31 #define APPLE_SPI_CFG_WORD_SIZE_8B      0
32 #define APPLE_SPI_CFG_WORD_SIZE_16B     1
33 #define APPLE_SPI_CFG_WORD_SIZE_32B     2
34 #define APPLE_SPI_CFG_FIFO_THRESH       GENMASK(18, 17)
35 #define APPLE_SPI_CFG_FIFO_THRESH_8B    0
36 #define APPLE_SPI_CFG_FIFO_THRESH_4B    1
37 #define APPLE_SPI_CFG_FIFO_THRESH_1B    2
38 #define APPLE_SPI_CFG_IE_TXCOMPLETE     BIT(21)
39
40 #define APPLE_SPI_STATUS                0x008
41 #define APPLE_SPI_STATUS_RXCOMPLETE     BIT(0)
42 #define APPLE_SPI_STATUS_TXRXTHRESH     BIT(1)
43 #define APPLE_SPI_STATUS_TXCOMPLETE     BIT(2)
44
45 #define APPLE_SPI_PIN                   0x00c
46 #define APPLE_SPI_PIN_KEEP_MOSI         BIT(0)
47 #define APPLE_SPI_PIN_CS                BIT(1)
48
49 #define APPLE_SPI_TXDATA                0x010
50 #define APPLE_SPI_RXDATA                0x020
51 #define APPLE_SPI_CLKDIV                0x030
52 #define APPLE_SPI_CLKDIV_MIN            0x002
53 #define APPLE_SPI_CLKDIV_MAX            0x7ff
54 #define APPLE_SPI_RXCNT                 0x034
55 #define APPLE_SPI_WORD_DELAY            0x038
56 #define APPLE_SPI_TXCNT                 0x04c
57
58 #define APPLE_SPI_FIFOSTAT              0x10c
59 #define APPLE_SPI_FIFOSTAT_TXFULL       BIT(4)
60 #define APPLE_SPI_FIFOSTAT_LEVEL_TX     GENMASK(15, 8)
61 #define APPLE_SPI_FIFOSTAT_RXEMPTY      BIT(20)
62 #define APPLE_SPI_FIFOSTAT_LEVEL_RX     GENMASK(31, 24)
63
64 #define APPLE_SPI_IE_XFER               0x130
65 #define APPLE_SPI_IF_XFER               0x134
66 #define APPLE_SPI_XFER_RXCOMPLETE       BIT(0)
67 #define APPLE_SPI_XFER_TXCOMPLETE       BIT(1)
68
69 #define APPLE_SPI_IE_FIFO               0x138
70 #define APPLE_SPI_IF_FIFO               0x13c
71 #define APPLE_SPI_FIFO_RXTHRESH         BIT(4)
72 #define APPLE_SPI_FIFO_TXTHRESH         BIT(5)
73 #define APPLE_SPI_FIFO_RXFULL           BIT(8)
74 #define APPLE_SPI_FIFO_TXEMPTY          BIT(9)
75 #define APPLE_SPI_FIFO_RXUNDERRUN       BIT(16)
76 #define APPLE_SPI_FIFO_TXOVERFLOW       BIT(17)
77
78 #define APPLE_SPI_SHIFTCFG              0x150
79 #define APPLE_SPI_SHIFTCFG_CLK_ENABLE   BIT(0)
80 #define APPLE_SPI_SHIFTCFG_CS_ENABLE    BIT(1)
81 #define APPLE_SPI_SHIFTCFG_AND_CLK_DATA BIT(8)
82 #define APPLE_SPI_SHIFTCFG_CS_AS_DATA   BIT(9)
83 #define APPLE_SPI_SHIFTCFG_TX_ENABLE    BIT(10)
84 #define APPLE_SPI_SHIFTCFG_RX_ENABLE    BIT(11)
85 #define APPLE_SPI_SHIFTCFG_BITS         GENMASK(21, 16)
86 #define APPLE_SPI_SHIFTCFG_OVERRIDE_CS  BIT(24)
87
88 #define APPLE_SPI_PINCFG                0x154
89 #define APPLE_SPI_PINCFG_KEEP_CLK       BIT(0)
90 #define APPLE_SPI_PINCFG_KEEP_CS        BIT(1)
91 #define APPLE_SPI_PINCFG_KEEP_MOSI      BIT(2)
92 #define APPLE_SPI_PINCFG_CLK_IDLE_VAL   BIT(8)
93 #define APPLE_SPI_PINCFG_CS_IDLE_VAL    BIT(9)
94 #define APPLE_SPI_PINCFG_MOSI_IDLE_VAL  BIT(10)
95
96 #define APPLE_SPI_DELAY_PRE             0x160
97 #define APPLE_SPI_DELAY_POST            0x168
98 #define APPLE_SPI_DELAY_ENABLE          BIT(0)
99 #define APPLE_SPI_DELAY_NO_INTERBYTE    BIT(1)
100 #define APPLE_SPI_DELAY_SET_SCK         BIT(4)
101 #define APPLE_SPI_DELAY_SET_MOSI        BIT(6)
102 #define APPLE_SPI_DELAY_SCK_VAL         BIT(8)
103 #define APPLE_SPI_DELAY_MOSI_VAL        BIT(12)
104
105 #define APPLE_SPI_FIFO_DEPTH            16
106
107 #define APPLE_SPI_TIMEOUT_MS            200
108
109 struct apple_spi_priv {
110         void *base;
111         u32 clkfreq;            /* Input clock frequency */
112 };
113
114 static void apple_spi_set_cs(struct apple_spi_priv *priv, int on)
115 {
116         writel(on ? 0 : APPLE_SPI_PIN_CS, priv->base + APPLE_SPI_PIN);
117 }
118
119 /* Fill Tx FIFO. */
120 static void apple_spi_tx(struct apple_spi_priv *priv, uint *len,
121                          const void **dout)
122 {
123         const u8 *out = *dout;
124         u32 data, fifostat;
125         uint count;
126
127         fifostat = readl(priv->base + APPLE_SPI_FIFOSTAT);
128         count = APPLE_SPI_FIFO_DEPTH -
129                 FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_TX, fifostat);
130         while (*len > 0 && count > 0) {
131                 data = out ? *out++ : 0;
132                 writel(data, priv->base + APPLE_SPI_TXDATA);
133                 (*len)--;
134                 count--;
135         }
136
137         *dout = out;
138 }
139
140 /* Empty Rx FIFO. */
141 static void apple_spi_rx(struct apple_spi_priv *priv, uint *len,
142                          void **din)
143 {
144         u8 *in = *din;
145         u32 data, fifostat;
146         uint count;
147
148         fifostat = readl(priv->base + APPLE_SPI_FIFOSTAT);
149         count = FIELD_GET(APPLE_SPI_FIFOSTAT_LEVEL_RX, fifostat);
150         while (*len > 0 && count > 0) {
151                 data = readl(priv->base + APPLE_SPI_RXDATA);
152                 if (in)
153                         *in++ = data;
154                 (*len)--;
155                 count--;
156         }
157
158         *din = in;
159 }
160
161 static int apple_spi_xfer(struct udevice *dev, unsigned int bitlen,
162                           const void *dout, void *din, unsigned long flags)
163 {
164         struct apple_spi_priv *priv = dev_get_priv(dev->parent);
165         unsigned long start = get_timer(0);
166         uint txlen, rxlen;
167         int ret = 0;
168
169         if ((bitlen % 8) != 0)
170                 return -EINVAL;
171         txlen = rxlen = bitlen / 8;
172
173         if (flags & SPI_XFER_BEGIN)
174                 apple_spi_set_cs(priv, 1);
175
176         if (txlen > 0) {
177                 /* Reset FIFOs */
178                 writel(APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET,
179                        priv->base + APPLE_SPI_CTRL);
180
181                 /* Set the transfer length */
182                 writel(txlen, priv->base + APPLE_SPI_TXCNT);
183                 writel(rxlen, priv->base + APPLE_SPI_RXCNT);
184
185                 /* Prime transmit FIFO */
186                 apple_spi_tx(priv, &txlen, &dout);
187
188                 /* Start transfer */
189                 writel(APPLE_SPI_CTRL_RUN, priv->base + APPLE_SPI_CTRL);
190
191                 while ((txlen > 0 || rxlen > 0)) {
192                         apple_spi_rx(priv, &rxlen, &din);
193                         apple_spi_tx(priv, &txlen, &dout);
194
195                         if (get_timer(start) > APPLE_SPI_TIMEOUT_MS) {
196                                 ret = -ETIMEDOUT;
197                                 break;
198                         }
199                 }
200
201                 /* Stop transfer. */
202                 writel(0, priv->base + APPLE_SPI_CTRL);
203         }
204
205         if (flags & SPI_XFER_END)
206                 apple_spi_set_cs(priv, 0);
207
208         return ret;
209 }
210
211 static int apple_spi_set_speed(struct udevice *dev, uint speed)
212 {
213         struct apple_spi_priv *priv = dev_get_priv(dev);
214         u32 div;
215
216         div = DIV_ROUND_UP(priv->clkfreq, speed);
217         if (div < APPLE_SPI_CLKDIV_MIN)
218                 div = APPLE_SPI_CLKDIV_MIN;
219         if (div > APPLE_SPI_CLKDIV_MAX)
220                 div = APPLE_SPI_CLKDIV_MAX;
221
222         writel(div, priv->base + APPLE_SPI_CLKDIV);
223
224         return 0;
225 }
226
227 static int apple_spi_set_mode(struct udevice *bus, uint mode)
228 {
229         return 0;
230 }
231
232 struct dm_spi_ops apple_spi_ops = {
233         .xfer = apple_spi_xfer,
234         .set_speed = apple_spi_set_speed,
235         .set_mode = apple_spi_set_mode,
236 };
237
238 static int apple_spi_probe(struct udevice *dev)
239 {
240         struct apple_spi_priv *priv = dev_get_priv(dev);
241         struct clk clkdev;
242         int ret;
243
244         priv->base = dev_read_addr_ptr(dev);
245         if (!priv->base)
246                 return -EINVAL;
247
248         ret = clk_get_by_index(dev, 0, &clkdev);
249         if (ret)
250                 return ret;
251         priv->clkfreq = clk_get_rate(&clkdev);
252
253         /* Set CS high (inactive) and disable override and auto-CS */
254         writel(APPLE_SPI_PIN_CS, priv->base + APPLE_SPI_PIN);
255         writel(readl(priv->base + APPLE_SPI_SHIFTCFG) & ~APPLE_SPI_SHIFTCFG_OVERRIDE_CS,
256                priv->base + APPLE_SPI_SHIFTCFG);
257         writel((readl(priv->base + APPLE_SPI_PINCFG) & ~APPLE_SPI_PINCFG_CS_IDLE_VAL) |
258                APPLE_SPI_PINCFG_KEEP_CS, priv->base + APPLE_SPI_PINCFG);
259
260         /* Reset FIFOs */
261         writel(APPLE_SPI_CTRL_RX_RESET | APPLE_SPI_CTRL_TX_RESET,
262                priv->base + APPLE_SPI_CTRL);
263
264         /* Configure defaults */
265         writel(FIELD_PREP(APPLE_SPI_CFG_MODE, APPLE_SPI_CFG_MODE_IRQ) |
266                FIELD_PREP(APPLE_SPI_CFG_WORD_SIZE, APPLE_SPI_CFG_WORD_SIZE_8B) |
267                FIELD_PREP(APPLE_SPI_CFG_FIFO_THRESH, APPLE_SPI_CFG_FIFO_THRESH_8B),
268                priv->base + APPLE_SPI_CFG);
269
270         return 0;
271 }
272
273 static const struct udevice_id apple_spi_of_match[] = {
274         { .compatible = "apple,spi" },
275         { /* sentinel */ }
276 };
277
278 U_BOOT_DRIVER(apple_spi) = {
279         .name = "apple_spi",
280         .id = UCLASS_SPI,
281         .of_match = apple_spi_of_match,
282         .probe = apple_spi_probe,
283         .priv_auto = sizeof(struct apple_spi_priv),
284         .ops = &apple_spi_ops,
285 };