xref: /openbmc/u-boot/drivers/spi/bcmstb_spi.c (revision 1612ff0d)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2018  Cisco Systems, Inc.
4  *
5  * Author: Thomas Fitzsimmons <fitzsim@fitzsim.org>
6  */
7 
8 #include <asm/io.h>
9 #include <command.h>
10 #include <config.h>
11 #include <dm.h>
12 #include <errno.h>
13 #include <fdtdec.h>
14 #include <linux/bitops.h>
15 #include <linux/delay.h>
16 #include <log.h>
17 #include <malloc.h>
18 #include <spi.h>
19 #include <time.h>
20 
21 DECLARE_GLOBAL_DATA_PTR;
22 
23 #define SPBR_MIN		8
24 #define BITS_PER_WORD		8
25 
26 #define NUM_TXRAM		32
27 #define NUM_RXRAM		32
28 #define NUM_CDRAM		16
29 
30 /* hif_mspi register structure. */
31 struct bcmstb_hif_mspi_regs {
32 	u32 spcr0_lsb;		/* 0x000 */
33 	u32 spcr0_msb;		/* 0x004 */
34 	u32 spcr1_lsb;		/* 0x008 */
35 	u32 spcr1_msb;		/* 0x00c */
36 	u32 newqp;		/* 0x010 */
37 	u32 endqp;		/* 0x014 */
38 	u32 spcr2;		/* 0x018 */
39 	u32 reserved0;		/* 0x01c */
40 	u32 mspi_status;	/* 0x020 */
41 	u32 cptqp;		/* 0x024 */
42 	u32 spcr3;		/* 0x028 */
43 	u32 revision;		/* 0x02c */
44 	u32 reserved1[4];	/* 0x030 */
45 	u32 txram[NUM_TXRAM];	/* 0x040 */
46 	u32 rxram[NUM_RXRAM];	/* 0x0c0 */
47 	u32 cdram[NUM_CDRAM];	/* 0x140 */
48 	u32 write_lock;		/* 0x180 */
49 };
50 
51 /* hif_mspi masks. */
52 #define HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK	0x00000080
53 #define HIF_MSPI_SPCR2_SPE_MASK			0x00000040
54 #define HIF_MSPI_SPCR2_SPIFIE_MASK		0x00000020
55 #define HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK	0x00000001
56 
57 /* bspi offsets. */
58 #define BSPI_MAST_N_BOOT_CTRL			0x008
59 
60 /* bspi_raf is not used in this driver. */
61 
62 /* hif_spi_intr2 offsets and masks. */
63 #define HIF_SPI_INTR2_CPU_CLEAR			0x08
64 #define HIF_SPI_INTR2_CPU_MASK_SET		0x10
65 #define HIF_SPI_INTR2_CPU_MASK_CLEAR		0x14
66 #define HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK	0x00000020
67 
68 /* SPI transfer timeout in milliseconds. */
69 #define HIF_MSPI_WAIT				10
70 
71 enum bcmstb_base_type {
72 	HIF_MSPI,
73 	BSPI,
74 	HIF_SPI_INTR2,
75 	CS_REG,
76 	BASE_LAST,
77 };
78 
79 struct bcmstb_spi_platdata {
80 	void *base[4];
81 };
82 
83 struct bcmstb_spi_priv {
84 	struct bcmstb_hif_mspi_regs *regs;
85 	void *bspi;
86 	void *hif_spi_intr2;
87 	void *cs_reg;
88 	int default_cs;
89 	int curr_cs;
90 	uint tx_slot;
91 	uint rx_slot;
92 	u8 saved_cmd[NUM_CDRAM];
93 	uint saved_cmd_len;
94 	void *saved_din_addr;
95 };
96 
bcmstb_spi_ofdata_to_platdata(struct udevice * bus)97 static int bcmstb_spi_ofdata_to_platdata(struct udevice *bus)
98 {
99 	struct bcmstb_spi_platdata *plat = dev_get_platdata(bus);
100 	const void *fdt = gd->fdt_blob;
101 	int node = dev_of_offset(bus);
102 	int ret = 0;
103 	int i = 0;
104 	struct fdt_resource resource = { 0 };
105 	char *names[BASE_LAST] = { "hif_mspi", "bspi", "hif_spi_intr2",
106 				   "cs_reg" };
107 	const phys_addr_t defaults[BASE_LAST] = { BCMSTB_HIF_MSPI_BASE,
108 						  BCMSTB_BSPI_BASE,
109 						  BCMSTB_HIF_SPI_INTR2,
110 						  BCMSTB_CS_REG };
111 
112 	for (i = 0; i < BASE_LAST; i++) {
113 		plat->base[i] = (void *)defaults[i];
114 
115 		ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
116 					     names[i], &resource);
117 		if (ret) {
118 			printf("%s: Assuming BCMSTB SPI %s address 0x0x%p\n",
119 			       __func__, names[i], (void *)defaults[i]);
120 		} else {
121 			plat->base[i] = (void *)resource.start;
122 			debug("BCMSTB SPI %s address: 0x0x%p\n",
123 			      names[i], (void *)plat->base[i]);
124 		}
125 	}
126 
127 	return 0;
128 }
129 
bcmstb_spi_hw_set_parms(struct bcmstb_spi_priv * priv)130 static void bcmstb_spi_hw_set_parms(struct bcmstb_spi_priv *priv)
131 {
132 	writel(SPBR_MIN, &priv->regs->spcr0_lsb);
133 	writel(BITS_PER_WORD << 2 | SPI_MODE_3, &priv->regs->spcr0_msb);
134 }
135 
bcmstb_spi_enable_interrupt(void * base,u32 mask)136 static void bcmstb_spi_enable_interrupt(void *base, u32 mask)
137 {
138 	void *reg = base + HIF_SPI_INTR2_CPU_MASK_CLEAR;
139 
140 	writel(readl(reg) | mask, reg);
141 	readl(reg);
142 }
143 
bcmstb_spi_disable_interrupt(void * base,u32 mask)144 static void bcmstb_spi_disable_interrupt(void *base, u32 mask)
145 {
146 	void *reg = base + HIF_SPI_INTR2_CPU_MASK_SET;
147 
148 	writel(readl(reg) | mask, reg);
149 	readl(reg);
150 }
151 
bcmstb_spi_clear_interrupt(void * base,u32 mask)152 static void bcmstb_spi_clear_interrupt(void *base, u32 mask)
153 {
154 	void *reg = base + HIF_SPI_INTR2_CPU_CLEAR;
155 
156 	writel(readl(reg) | mask, reg);
157 	readl(reg);
158 }
159 
bcmstb_spi_probe(struct udevice * bus)160 static int bcmstb_spi_probe(struct udevice *bus)
161 {
162 	struct bcmstb_spi_platdata *plat = dev_get_platdata(bus);
163 	struct bcmstb_spi_priv *priv = dev_get_priv(bus);
164 
165 	priv->regs = plat->base[HIF_MSPI];
166 	priv->bspi = plat->base[BSPI];
167 	priv->hif_spi_intr2 = plat->base[HIF_SPI_INTR2];
168 	priv->cs_reg = plat->base[CS_REG];
169 	priv->default_cs = 0;
170 	priv->curr_cs = -1;
171 	priv->tx_slot = 0;
172 	priv->rx_slot = 0;
173 	memset(priv->saved_cmd, 0, NUM_CDRAM);
174 	priv->saved_cmd_len = 0;
175 	priv->saved_din_addr = NULL;
176 
177 	debug("spi_xfer: tx regs: 0x%p\n", &priv->regs->txram[0]);
178 	debug("spi_xfer: rx regs: 0x%p\n", &priv->regs->rxram[0]);
179 
180 	/* Disable BSPI. */
181 	writel(1, priv->bspi + BSPI_MAST_N_BOOT_CTRL);
182 	readl(priv->bspi + BSPI_MAST_N_BOOT_CTRL);
183 
184 	/* Set up interrupts. */
185 	bcmstb_spi_disable_interrupt(priv->hif_spi_intr2, 0xffffffff);
186 	bcmstb_spi_clear_interrupt(priv->hif_spi_intr2, 0xffffffff);
187 	bcmstb_spi_enable_interrupt(priv->hif_spi_intr2,
188 				    HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK);
189 
190 	/* Set up control registers. */
191 	writel(0, &priv->regs->spcr1_lsb);
192 	writel(0, &priv->regs->spcr1_msb);
193 	writel(0, &priv->regs->newqp);
194 	writel(0, &priv->regs->endqp);
195 	writel(HIF_MSPI_SPCR2_SPIFIE_MASK, &priv->regs->spcr2);
196 	writel(0, &priv->regs->spcr3);
197 
198 	bcmstb_spi_hw_set_parms(priv);
199 
200 	return 0;
201 }
202 
bcmstb_spi_submit(struct bcmstb_spi_priv * priv,bool done)203 static void bcmstb_spi_submit(struct bcmstb_spi_priv *priv, bool done)
204 {
205 	debug("WR NEWQP: %d\n", 0);
206 	writel(0, &priv->regs->newqp);
207 
208 	debug("WR ENDQP: %d\n", priv->tx_slot - 1);
209 	writel(priv->tx_slot - 1, &priv->regs->endqp);
210 
211 	if (done) {
212 		debug("WR CDRAM[%d]: %02x\n", priv->tx_slot - 1,
213 		      readl(&priv->regs->cdram[priv->tx_slot - 1]) & ~0x80);
214 		writel(readl(&priv->regs->cdram[priv->tx_slot - 1]) & ~0x80,
215 		       &priv->regs->cdram[priv->tx_slot - 1]);
216 	}
217 
218 	/* Force chip select first time. */
219 	if (priv->curr_cs != priv->default_cs) {
220 		debug("spi_xfer: switching chip select to %d\n",
221 		      priv->default_cs);
222 		writel((readl(priv->cs_reg) & ~0xff) | (1 << priv->default_cs),
223 		       priv->cs_reg);
224 		readl(priv->cs_reg);
225 		udelay(10);
226 		priv->curr_cs = priv->default_cs;
227 	}
228 
229 	debug("WR WRITE_LOCK: %02x\n", 1);
230 	writel((readl(&priv->regs->write_lock) &
231 		~HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK) | 1,
232 	       &priv->regs->write_lock);
233 	readl(&priv->regs->write_lock);
234 
235 	debug("WR SPCR2: %02x\n",
236 	      HIF_MSPI_SPCR2_SPIFIE_MASK |
237 	      HIF_MSPI_SPCR2_SPE_MASK |
238 	      HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK);
239 	writel(HIF_MSPI_SPCR2_SPIFIE_MASK |
240 	       HIF_MSPI_SPCR2_SPE_MASK |
241 	       HIF_MSPI_SPCR2_CONT_AFTER_CMD_MASK,
242 	       &priv->regs->spcr2);
243 }
244 
bcmstb_spi_wait(struct bcmstb_spi_priv * priv)245 static int bcmstb_spi_wait(struct bcmstb_spi_priv *priv)
246 {
247 	u32 start_time = get_timer(0);
248 	u32 status = readl(&priv->regs->mspi_status);
249 
250 	while (!(status & 1)) {
251 		if (get_timer(start_time) > HIF_MSPI_WAIT)
252 			return -ETIMEDOUT;
253 		status = readl(&priv->regs->mspi_status);
254 	}
255 
256 	writel(readl(&priv->regs->mspi_status) & ~1, &priv->regs->mspi_status);
257 	bcmstb_spi_clear_interrupt(priv->hif_spi_intr2,
258 				   HIF_SPI_INTR2_CPU_SET_MSPI_DONE_MASK);
259 
260 	return 0;
261 }
262 
bcmstb_spi_xfer(struct udevice * dev,unsigned int bitlen,const void * dout,void * din,unsigned long flags)263 static int bcmstb_spi_xfer(struct udevice *dev, unsigned int bitlen,
264 			   const void *dout, void *din, unsigned long flags)
265 {
266 	uint len = bitlen / 8;
267 	uint tx_len = len;
268 	uint rx_len = len;
269 	const u8 *out_bytes = (u8 *)dout;
270 	u8 *in_bytes = (u8 *)din;
271 	struct udevice *bus = dev_get_parent(dev);
272 	struct bcmstb_spi_priv *priv = dev_get_priv(bus);
273 	struct bcmstb_hif_mspi_regs *regs = priv->regs;
274 
275 	debug("spi_xfer: %d, t: 0x%p, r: 0x%p, f: %lx\n",
276 	      len, dout, din, flags);
277 	debug("spi_xfer: chip select: %x\n", readl(priv->cs_reg) & 0xff);
278 	debug("spi_xfer: tx addr: 0x%p\n", &regs->txram[0]);
279 	debug("spi_xfer: rx addr: 0x%p\n", &regs->rxram[0]);
280 	debug("spi_xfer: cd addr: 0x%p\n", &regs->cdram[0]);
281 
282 	if (flags & SPI_XFER_END) {
283 		debug("spi_xfer: clearing saved din address: 0x%p\n",
284 		      priv->saved_din_addr);
285 		priv->saved_din_addr = NULL;
286 		priv->saved_cmd_len = 0;
287 		memset(priv->saved_cmd, 0, NUM_CDRAM);
288 	}
289 
290 	if (bitlen == 0)
291 		return 0;
292 
293 	if (bitlen % 8) {
294 		printf("%s: Non-byte-aligned transfer\n", __func__);
295 		return -EOPNOTSUPP;
296 	}
297 
298 	if (flags & ~(SPI_XFER_BEGIN | SPI_XFER_END)) {
299 		printf("%s: Unsupported flags: %lx\n", __func__, flags);
300 		return -EOPNOTSUPP;
301 	}
302 
303 	if (flags & SPI_XFER_BEGIN) {
304 		priv->tx_slot = 0;
305 		priv->rx_slot = 0;
306 
307 		if (out_bytes && len > NUM_CDRAM) {
308 			printf("%s: Unable to save transfer\n", __func__);
309 			return -EOPNOTSUPP;
310 		}
311 
312 		if (out_bytes && !(flags & SPI_XFER_END)) {
313 			/*
314 			 * This is the start of a transmit operation
315 			 * that will need repeating if the calling
316 			 * code polls for the result.  Save it for
317 			 * subsequent transmission.
318 			 */
319 			debug("spi_xfer: saving command: %x, %d\n",
320 			      out_bytes[0], len);
321 			priv->saved_cmd_len = len;
322 			memcpy(priv->saved_cmd, out_bytes, priv->saved_cmd_len);
323 		}
324 	}
325 
326 	if (!(flags & (SPI_XFER_BEGIN | SPI_XFER_END))) {
327 		if (priv->saved_din_addr == din) {
328 			/*
329 			 * The caller is polling for status.  Repeat
330 			 * the last transmission.
331 			 */
332 			int ret = 0;
333 
334 			debug("spi_xfer: Making recursive call\n");
335 			ret = bcmstb_spi_xfer(dev, priv->saved_cmd_len * 8,
336 					      priv->saved_cmd, NULL,
337 					      SPI_XFER_BEGIN);
338 			if (ret) {
339 				printf("%s: Recursive call failed\n", __func__);
340 				return ret;
341 			}
342 		} else {
343 			debug("spi_xfer: saving din address: 0x%p\n", din);
344 			priv->saved_din_addr = din;
345 		}
346 	}
347 
348 	while (rx_len > 0) {
349 		priv->rx_slot = priv->tx_slot;
350 
351 		while (priv->tx_slot < NUM_CDRAM && tx_len > 0) {
352 			bcmstb_spi_hw_set_parms(priv);
353 			debug("WR TXRAM[%d]: %02x\n", priv->tx_slot,
354 			      out_bytes ? out_bytes[len - tx_len] : 0xff);
355 			writel(out_bytes ? out_bytes[len - tx_len] : 0xff,
356 			       &regs->txram[priv->tx_slot << 1]);
357 			debug("WR CDRAM[%d]: %02x\n", priv->tx_slot, 0x8e);
358 			writel(0x8e, &regs->cdram[priv->tx_slot]);
359 			priv->tx_slot++;
360 			tx_len--;
361 			if (!in_bytes)
362 				rx_len--;
363 		}
364 
365 		debug("spi_xfer: early return clauses: %d, %d, %d\n",
366 		      len <= NUM_CDRAM,
367 		      !in_bytes,
368 		      (flags & (SPI_XFER_BEGIN |
369 				SPI_XFER_END)) == SPI_XFER_BEGIN);
370 		if (len <= NUM_CDRAM &&
371 		    !in_bytes &&
372 		    (flags & (SPI_XFER_BEGIN | SPI_XFER_END)) == SPI_XFER_BEGIN)
373 			return 0;
374 
375 		bcmstb_spi_submit(priv, tx_len == 0);
376 
377 		if (bcmstb_spi_wait(priv) == -ETIMEDOUT) {
378 			printf("%s: Timed out\n", __func__);
379 			return -ETIMEDOUT;
380 		}
381 
382 		priv->tx_slot %= NUM_CDRAM;
383 
384 		if (in_bytes) {
385 			while (priv->rx_slot < NUM_CDRAM && rx_len > 0) {
386 				in_bytes[len - rx_len] =
387 					readl(&regs->rxram[(priv->rx_slot << 1)
388 							   + 1])
389 					& 0xff;
390 				debug("RD RXRAM[%d]: %02x\n",
391 				      priv->rx_slot, in_bytes[len - rx_len]);
392 				priv->rx_slot++;
393 				rx_len--;
394 			}
395 		}
396 	}
397 
398 	if (flags & SPI_XFER_END) {
399 		debug("WR WRITE_LOCK: %02x\n", 0);
400 		writel((readl(&priv->regs->write_lock) &
401 			~HIF_MSPI_WRITE_LOCK_WRITE_LOCK_MASK) | 0,
402 		       &priv->regs->write_lock);
403 		readl(&priv->regs->write_lock);
404 	}
405 
406 	return 0;
407 }
408 
bcmstb_spi_set_speed(struct udevice * dev,uint speed)409 static int bcmstb_spi_set_speed(struct udevice *dev, uint speed)
410 {
411 	return 0;
412 }
413 
bcmstb_spi_set_mode(struct udevice * dev,uint mode)414 static int bcmstb_spi_set_mode(struct udevice *dev, uint mode)
415 {
416 	return 0;
417 }
418 
419 static const struct dm_spi_ops bcmstb_spi_ops = {
420 	.xfer		= bcmstb_spi_xfer,
421 	.set_speed	= bcmstb_spi_set_speed,
422 	.set_mode	= bcmstb_spi_set_mode,
423 };
424 
425 static const struct udevice_id bcmstb_spi_id[] = {
426 	{ .compatible = "brcm,spi-brcmstb" },
427 	{ }
428 };
429 
430 U_BOOT_DRIVER(bcmstb_spi) = {
431 	.name				= "bcmstb_spi",
432 	.id				= UCLASS_SPI,
433 	.of_match			= bcmstb_spi_id,
434 	.ops				= &bcmstb_spi_ops,
435 	.ofdata_to_platdata		= bcmstb_spi_ofdata_to_platdata,
436 	.probe				= bcmstb_spi_probe,
437 	.platdata_auto_alloc_size	= sizeof(struct bcmstb_spi_platdata),
438 	.priv_auto_alloc_size		= sizeof(struct bcmstb_spi_priv),
439 };
440