xref: /aosp_15_r20/external/coreboot/src/soc/sifive/fu540/spi.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <device/mmio.h>
4 #include <soc/spi.h>
5 #include <soc/clock.h>
6 #include <soc/addressmap.h>
7 
8 #include "spi_internal.h"
9 
10 static struct spi_ctrl *spictrls[] = {
11 	(struct spi_ctrl *)FU540_QSPI0,
12 	(struct spi_ctrl *)FU540_QSPI1,
13 	(struct spi_ctrl *)FU540_QSPI2
14 };
15 
16 /**
17  * Wait until SPI is ready for transmission and transmit byte.
18  */
spi_tx(volatile struct spi_ctrl * spictrl,uint8_t in)19 static void spi_tx(volatile struct spi_ctrl *spictrl, uint8_t in)
20 {
21 #if __riscv_atomic
22 	int32_t r;
23 	do {
24 		asm volatile (
25 			"amoor.w %0, %2, %1\n"
26 			: "=r" (r), "+A" (spictrl->txdata.raw_bits)
27 			: "r" (in)
28 		);
29 	} while (r < 0);
30 #else
31 	while ((int32_t)spictrl->txdata.raw_bits < 0)
32 		;
33 	spictrl->txdata.data = in;
34 #endif
35 }
36 
37 /**
38  * Wait until SPI receive queue has data and read byte.
39  */
spi_rx(volatile struct spi_ctrl * spictrl)40 static uint8_t spi_rx(volatile struct spi_ctrl *spictrl)
41 {
42 	int32_t out;
43 	while ((out = (int32_t)spictrl->rxdata.raw_bits) < 0)
44 		;
45 	return (uint8_t)out;
46 }
47 
spi_claim_bus_(const struct spi_slave * slave)48 static int spi_claim_bus_(const struct spi_slave *slave)
49 {
50 	struct spi_ctrl *spictrl = spictrls[slave->bus];
51 	spi_reg_csmode csmode;
52 	csmode.raw_bits = 0;
53 	csmode.mode = FU540_SPI_CSMODE_HOLD;
54 	write32(&spictrl->csmode.raw_bits, csmode.raw_bits);
55 	return 0;
56 }
57 
spi_release_bus_(const struct spi_slave * slave)58 static void spi_release_bus_(const struct spi_slave *slave)
59 {
60 	struct spi_ctrl *spictrl = spictrls[slave->bus];
61 	spi_reg_csmode csmode;
62 	csmode.raw_bits = 0;
63 	csmode.mode = FU540_SPI_CSMODE_OFF;
64 	write32(&spictrl->csmode.raw_bits, csmode.raw_bits);
65 }
66 
spi_xfer_(const struct spi_slave * slave,const void * dout,size_t bytesout,void * din,size_t bytesin)67 static int spi_xfer_(const struct spi_slave *slave,
68 		const void *dout, size_t bytesout,
69 		void *din, size_t bytesin)
70 {
71 	struct spi_ctrl *spictrl = spictrls[slave->bus];
72 	spi_reg_fmt fmt;
73 	fmt.raw_bits = read32(&spictrl->fmt.raw_bits);
74 	if (fmt.proto == FU540_SPI_PROTO_S) {
75 		/* working in full-duplex mode
76 		 * receiving data needs to be triggered by sending data */
77 		while (bytesout || bytesin) {
78 			uint8_t in, out = 0;
79 			if (bytesout) {
80 				out = *(uint8_t *)dout++;
81 				bytesout--;
82 			}
83 			spi_tx(spictrl, out);
84 			in = spi_rx(spictrl);
85 			if (bytesin) {
86 				*(uint8_t *)din++ = in;
87 				bytesin--;
88 			}
89 		}
90 	} else {
91 		/* Working in half duplex
92 		 * send and receive can be done separately */
93 		if (dout && din)
94 			return -1;
95 
96 		if (dout) {
97 			while (bytesout) {
98 				spi_tx(spictrl, *(uint8_t *)dout++);
99 				bytesout--;
100 			}
101 		}
102 
103 		if (din) {
104 			while (bytesin) {
105 				*(uint8_t *)din++ = spi_rx(spictrl);
106 				bytesin--;
107 			}
108 		}
109 	}
110 	return 0;
111 }
112 
spi_setup_(const struct spi_slave * slave)113 static int spi_setup_(const struct spi_slave *slave)
114 {
115 	spi_reg_sckmode sckmode;
116 	spi_reg_csmode csmode;
117 	spi_reg_fmt fmt;
118 
119 	if ((slave->bus > 2) || (slave->cs != 0))
120 		return -1;
121 
122 	struct spi_ctrl *spictrl = spictrls[slave->bus];
123 
124 	write32(&spictrl->sckdiv, spi_min_clk_divisor(clock_get_tlclk_khz(),
125 				10000));
126 
127 	sckmode.raw_bits = 0;
128 	sckmode.pha = FU540_SPI_PHA_LOW;
129 	sckmode.pol = FU540_SPI_POL_LEADING;
130 	write32(&spictrl->sckmode.raw_bits, sckmode.raw_bits);
131 
132 	write32(&spictrl->csdef, 0xffffffff);
133 
134 	csmode.raw_bits = 0;
135 	csmode.mode = FU540_SPI_CSMODE_AUTO;
136 	write32(&spictrl->csmode.raw_bits, csmode.raw_bits);
137 
138 	fmt.raw_bits = 0;
139 	fmt.proto = FU540_SPI_PROTO_S;
140 	fmt.endian = FU540_SPI_ENDIAN_BIG;
141 	fmt.dir = 0;
142 	fmt.len = 8;
143 	write32(&spictrl->fmt.raw_bits, fmt.raw_bits);
144 
145 	return 0;
146 }
147 
148 struct spi_ctrlr fu540_spi_ctrlr = {
149 	.xfer  = spi_xfer_,
150 	.setup = spi_setup_,
151 	.claim_bus = spi_claim_bus_,
152 	.release_bus = spi_release_bus_,
153 };
154 
155 const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
156 	{
157 		.bus_start = 0,
158 		.bus_end = 2,
159 		.ctrlr = &fu540_spi_ctrlr,
160 	}
161 };
162 
163 const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);
164 
fu540_spi_setup(unsigned int bus,unsigned int cs,struct spi_slave * slave,struct fu540_spi_config * config)165 int fu540_spi_setup(unsigned int bus, unsigned int cs,
166 		struct spi_slave *slave,
167 		struct fu540_spi_config *config)
168 {
169 	spi_reg_sckmode sckmode;
170 	spi_reg_csmode csmode;
171 	spi_reg_fmt fmt;
172 
173 	if ((bus > 2) || (cs != 0))
174 		return -1;
175 
176 	if ((config->pha > 1)
177 		|| (config->pol > 1)
178 		|| (config->protocol > 2)
179 		|| (config->endianness > 1)
180 		|| (config->bits_per_frame > 8))
181 		return -1;
182 
183 	slave->bus = bus;
184 	slave->cs = cs;
185 	slave->ctrlr = &fu540_spi_ctrlr;
186 
187 	struct spi_ctrl *spictrl = spictrls[slave->bus];
188 
189 	write32(&spictrl->sckdiv, spi_min_clk_divisor(clock_get_tlclk_khz(),
190 			config->freq / 1000));
191 
192 	sckmode.raw_bits = 0;
193 	sckmode.pha = config->pha;
194 	sckmode.pol = config->pol;
195 	write32(&spictrl->sckmode.raw_bits, sckmode.raw_bits);
196 
197 	write32(&spictrl->csdef, 0xffffffff);
198 
199 	csmode.raw_bits = 0;
200 	csmode.mode = FU540_SPI_CSMODE_AUTO;
201 	write32(&spictrl->csmode.raw_bits, csmode.raw_bits);
202 
203 	fmt.raw_bits = 0;
204 	fmt.proto = config->protocol;
205 	fmt.endian = config->endianness;
206 	fmt.dir = 0;
207 	fmt.len = config->bits_per_frame;
208 	write32(&spictrl->fmt.raw_bits, fmt.raw_bits);
209 
210 	return 0;
211 }
212 
fu540_spi_mmap(const struct spi_slave * slave,const struct fu540_spi_mmap_config * config)213 int fu540_spi_mmap(
214 		const struct spi_slave *slave,
215 		const struct fu540_spi_mmap_config *config)
216 {
217 	spi_reg_fctrl fctrl;
218 	spi_reg_ffmt ffmt;
219 
220 	if (slave->bus > 2)
221 		return -1;
222 
223 	if ((config->cmd_en > 1)
224 		|| (config->addr_len > 4)
225 		|| (config->pad_cnt > 15)
226 		|| (config->cmd_proto > 2)
227 		|| (config->addr_proto > 2)
228 		|| (config->data_proto > 2)
229 		|| (config->cmd_code > 255)
230 		|| (config->pad_code > 255))
231 		return -1;
232 
233 	struct spi_ctrl *spictrl = spictrls[slave->bus];
234 
235 	/* disable direct memory-mapped spi flash mode */
236 	fctrl.raw_bits = 0;
237 	fctrl.en = 0;
238 	write32(&spictrl->fctrl.raw_bits, fctrl.raw_bits);
239 
240 	/* reset spi flash chip */
241 	spi_tx(spictrl, 0x66);
242 	spi_tx(spictrl, 0x99);
243 
244 	/* Pass the information of the flash read operation to the spi
245 	 * controller */
246 	ffmt.raw_bits = 0;
247 	ffmt.cmd_en = config->cmd_en;
248 	ffmt.addr_len = config->addr_len;
249 	ffmt.pad_cnt = config->pad_cnt;
250 	ffmt.command_proto = config->cmd_proto;
251 	ffmt.addr_proto = config->addr_proto;
252 	ffmt.data_proto = config->data_proto;
253 	ffmt.command_code = config->cmd_code;
254 	ffmt.pad_code = config->pad_code;
255 	write32(&spictrl->ffmt.raw_bits, ffmt.raw_bits);
256 
257 	/* enable direct memory-mapped spi flash mode */
258 	fctrl.raw_bits = 0;
259 	fctrl.en = 1;
260 	write32(&spictrl->fctrl.raw_bits, fctrl.raw_bits);
261 
262 	return 0;
263 }
264