spi: zynqmp_gqspi: Fix issue of reading more than 32bits length
[platform/kernel/u-boot.git] / drivers / spi / gxp_spi.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * GXP SPI driver
4  *
5  * (C) Copyright 2022 Hewlett Packard Enterprise Development LP.
6  * Author: Nick Hawkins <nick.hawkins@hpe.com>
7  * Author: Jean-Marie Verdun <verdun@hpe.com>
8  */
9
10 #include <spi.h>
11 #include <asm/io.h>
12 #include <dm.h>
13
14 #define GXP_SPI0_MAX_CHIPSELECT         2
15
16 #define MANUAL_MODE     0
17 #define AUTO_MODE               1
18 #define OFFSET_SPIMCFG  0x00
19 #define OFFSET_SPIMCTRL 0x04
20 #define OFFSET_SPICMD           0x05
21 #define OFFSET_SPIDCNT  0x06
22 #define OFFSET_SPIADDR  0x08
23 #define OFFSET_SPILDAT  0x40
24 #define GXP_SPILDAT_SIZE 64
25
26 #define SPIMCTRL_START  0x01
27 #define SPIMCTRL_BUSY           0x02
28
29 #define CMD_READ_ARRAY_FAST             0x0b
30
31 struct gxp_spi_priv {
32         struct spi_slave        slave;
33         void __iomem *base;
34         unsigned int mode;
35
36 };
37
38 static void spi_set_mode(struct gxp_spi_priv *priv, int mode)
39 {
40         unsigned char value;
41
42         value = readb(priv->base + OFFSET_SPIMCTRL);
43         if (mode == MANUAL_MODE) {
44                 writeb(0x55, priv->base + OFFSET_SPICMD);
45                 writeb(0xaa, priv->base + OFFSET_SPICMD);
46                 /* clear bit5 and bit4, auto_start and start_mask */
47                 value &= ~(0x03 << 4);
48         } else {
49                 value |= (0x03 << 4);
50         }
51         writeb(value, priv->base + OFFSET_SPIMCTRL);
52 }
53
54 static int gxp_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din,
55                         unsigned long flags)
56 {
57         struct gxp_spi_priv *priv = dev_get_priv(dev->parent);
58         struct spi_slave *slave = dev_get_parent_priv(dev);
59         struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev);
60
61         unsigned int len = bitlen / 8;
62         unsigned int value;
63         unsigned int addr = 0;
64         unsigned char uchar_out[len];
65         unsigned char *uchar_in = (unsigned char *)din;
66         int read_len;
67         int read_ptr;
68
69         if (dout && din) {
70                 /*
71                  * error: gxp spi engin cannot send data to dout and read data from din at the same
72                  * time
73                  */
74                 return -1;
75         }
76
77         memset(uchar_out, 0, sizeof(uchar_out));
78         if (dout)
79                 memcpy(uchar_out, dout, len);
80
81         if (flags & SPI_XFER_BEGIN) {
82                 /* the dout is cmd + addr, cmd=dout[0], add1~3=dout[1~3]. */
83                 /* cmd reg */
84                 writeb(uchar_out[0], priv->base + OFFSET_SPICMD);
85
86                 /* config reg */
87                 value = readl(priv->base + OFFSET_SPIMCFG);
88                 value &= ~(1 << 24);
89                 /* set chipselect */
90                 value |= (slave_plat->cs << 24);
91
92                 /* addr reg and addr size */
93                 if (len >= 4) {
94                         addr = uchar_out[1] << 16 | uchar_out[2] << 8 | uchar_out[3];
95                         writel(addr, priv->base + OFFSET_SPIADDR);
96                         value &= ~(0x07 << 16);
97                         /* set the address size to 3 byte */
98                         value |= (3 << 16);
99                 } else {
100                         writel(0, priv->base + OFFSET_SPIADDR);
101                         /* set the address size to 0 byte */
102                         value &= ~(0x07 << 16);
103                 }
104
105                 /* dummy */
106                 /* clear dummy_cnt to */
107                 value &= ~(0x1f << 19);
108                 if (uchar_out[0] == CMD_READ_ARRAY_FAST) {
109                         /* fast read needs 8 dummy clocks */
110                         value |= (8 << 19);
111                 }
112
113                 writel(value, priv->base + OFFSET_SPIMCFG);
114
115                 if (flags & SPI_XFER_END) {
116                         /* no data cmd just start it */
117                         /* set the data direction bit to 1 */
118                         value = readb(priv->base + OFFSET_SPIMCTRL);
119                         value |= (1 << 3);
120                         writeb(value, priv->base + OFFSET_SPIMCTRL);
121
122                         /* set the data byte count */
123                         writeb(0, priv->base + OFFSET_SPIDCNT);
124
125                         /* set the start bit */
126                         value = readb(priv->base + OFFSET_SPIMCTRL);
127                         value |= SPIMCTRL_START;
128                         writeb(value, priv->base + OFFSET_SPIMCTRL);
129
130                         /* wait busy bit is cleared */
131                         do {
132                                 value = readb(priv->base + OFFSET_SPIMCTRL);
133                         } while (value & SPIMCTRL_BUSY);
134                         return 0;
135                 }
136         }
137
138         if (!(flags & SPI_XFER_END) && (flags & SPI_XFER_BEGIN)) {
139                 /* first of spi_xfer calls */
140                 return 0;
141         }
142
143         /* if dout != null, write data to buf and start transaction */
144         if (dout) {
145                 if (len > slave->max_write_size) {
146                         printf("SF: write length is too big(>%d)\n", slave->max_write_size);
147                         return -1;
148                 }
149
150                 /* load the data bytes */
151                 memcpy((u8 *)priv->base + OFFSET_SPILDAT, dout, len);
152
153                 /* write: set the data direction bit to 1 */
154                 value = readb(priv->base + OFFSET_SPIMCTRL);
155                 value |= (1 << 3);
156                 writeb(value, priv->base + OFFSET_SPIMCTRL);
157
158                 /* set the data byte count */
159                 writeb(len, priv->base + OFFSET_SPIDCNT);
160
161                 /* set the start bit */
162                 value = readb(priv->base + OFFSET_SPIMCTRL);
163                 value |= SPIMCTRL_START;
164                 writeb(value, priv->base + OFFSET_SPIMCTRL);
165
166                 /* wait busy bit is cleared */
167                 do {
168                         value = readb(priv->base + OFFSET_SPIMCTRL);
169                 } while (value & SPIMCTRL_BUSY);
170
171                 return 0;
172         }
173
174         /* if din !=null, start and read data */
175         if (uchar_in) {
176                 read_ptr = 0;
177
178                 while (read_ptr < len) {
179                         read_len = len - read_ptr;
180                         if (read_len > GXP_SPILDAT_SIZE)
181                                 read_len = GXP_SPILDAT_SIZE;
182
183                         /* read: set the data direction bit to 0 */
184                         value = readb(priv->base + OFFSET_SPIMCTRL);
185                         value &= ~(1 << 3);
186                         writeb(value, priv->base + OFFSET_SPIMCTRL);
187
188                         /* set the data byte count */
189                         writeb(read_len, priv->base + OFFSET_SPIDCNT);
190
191                         /* set the start bit */
192                         value = readb(priv->base + OFFSET_SPIMCTRL);
193                         value |= SPIMCTRL_START;
194                         writeb(value, priv->base + OFFSET_SPIMCTRL);
195
196                         /* wait busy bit is cleared */
197                         do {
198                                 value = readb(priv->base + OFFSET_SPIMCTRL);
199                         } while (value & SPIMCTRL_BUSY);
200
201                         /* store the data bytes */
202                         memcpy(uchar_in + read_ptr, (u8 *)priv->base + OFFSET_SPILDAT, read_len);
203                         /* update read_ptr and addr reg */
204                         read_ptr += read_len;
205
206                         addr = readl(priv->base + OFFSET_SPIADDR);
207                         addr += read_len;
208                         writel(addr, priv->base + OFFSET_SPIADDR);
209                 }
210
211                 return 0;
212         }
213         return -2;
214 }
215
216 static int gxp_spi_set_speed(struct udevice *dev, unsigned int speed)
217 {
218         /* Accept any speed */
219         return 0;
220 }
221
222 static int gxp_spi_set_mode(struct udevice *dev, unsigned int mode)
223 {
224         struct gxp_spi_priv *priv = dev_get_priv(dev->parent);
225
226         priv->mode = mode;
227
228         return 0;
229 }
230
231 static int gxp_spi_claim_bus(struct udevice *dev)
232 {
233         struct gxp_spi_priv *priv = dev_get_priv(dev->parent);
234         unsigned char cmd;
235
236         spi_set_mode(priv, MANUAL_MODE);
237
238         /* exit 4 bytes addr mode, uboot spi_flash only supports 3 byets address mode */
239         cmd = 0xe9;
240         gxp_spi_xfer(dev, 1 * 8, &cmd, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
241         return 0;
242 }
243
244 static int gxp_spi_release_bus(struct udevice *dev)
245 {
246         struct gxp_spi_priv *priv = dev_get_priv(dev->parent);
247
248         spi_set_mode(priv, AUTO_MODE);
249
250         return 0;
251 }
252
253 int gxp_spi_cs_info(struct udevice *bus, unsigned int cs, struct spi_cs_info *info)
254 {
255         if (cs < GXP_SPI0_MAX_CHIPSELECT)
256                 return 0;
257         else
258                 return -ENODEV;
259 }
260
261 static int gxp_spi_probe(struct udevice *bus)
262 {
263         struct gxp_spi_priv *priv = dev_get_priv(bus);
264
265         priv->base = dev_read_addr_ptr(bus);
266         if (!priv->base)
267                 return -ENOENT;
268
269         return 0;
270 }
271
272 static int gxp_spi_child_pre_probe(struct udevice *dev)
273 {
274         struct spi_slave *slave = dev_get_parent_priv(dev);
275
276         slave->max_write_size = GXP_SPILDAT_SIZE;
277
278         return 0;
279 }
280
281 static const struct dm_spi_ops gxp_spi_ops = {
282         .claim_bus = gxp_spi_claim_bus,
283         .release_bus = gxp_spi_release_bus,
284         .xfer = gxp_spi_xfer,
285         .set_speed = gxp_spi_set_speed,
286         .set_mode = gxp_spi_set_mode,
287         .cs_info = gxp_spi_cs_info,
288 };
289
290 static const struct udevice_id gxp_spi_ids[] = {
291         { .compatible = "hpe,gxp-spi" },
292         { }
293 };
294
295 U_BOOT_DRIVER(gxp_spi) = {
296         .name   = "gxp_spi",
297         .id     = UCLASS_SPI,
298         .of_match = gxp_spi_ids,
299         .ops    = &gxp_spi_ops,
300         .priv_auto = sizeof(struct gxp_spi_priv),
301         .probe  = gxp_spi_probe,
302         .child_pre_probe = gxp_spi_child_pre_probe,
303 };
304