openocd: fix SPDX tag format for files .c
[openocd.git] / contrib / loaders / flash / fespi / riscv_fespi.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 #include <stdbool.h>
4 #include <stdint.h>
5 #include <stdio.h>
6
7 #include "../../../../src/flash/nor/spi.h"
8
9 /* Register offsets */
10
11 #define FESPI_REG_SCKDIV 0x00
12 #define FESPI_REG_SCKMODE 0x04
13 #define FESPI_REG_CSID 0x10
14 #define FESPI_REG_CSDEF 0x14
15 #define FESPI_REG_CSMODE 0x18
16
17 #define FESPI_REG_DCSSCK 0x28
18 #define FESPI_REG_DSCKCS 0x2a
19 #define FESPI_REG_DINTERCS 0x2c
20 #define FESPI_REG_DINTERXFR 0x2e
21
22 #define FESPI_REG_FMT 0x40
23 #define FESPI_REG_TXFIFO 0x48
24 #define FESPI_REG_RXFIFO 0x4c
25 #define FESPI_REG_TXCTRL 0x50
26 #define FESPI_REG_RXCTRL 0x54
27
28 #define FESPI_REG_FCTRL 0x60
29 #define FESPI_REG_FFMT 0x64
30
31 #define FESPI_REG_IE 0x70
32 #define FESPI_REG_IP 0x74
33
34 /* Fields */
35
36 #define FESPI_SCK_POL 0x1
37 #define FESPI_SCK_PHA 0x2
38
39 #define FESPI_FMT_PROTO(x) ((x) & 0x3)
40 #define FESPI_FMT_ENDIAN(x) (((x) & 0x1) << 2)
41 #define FESPI_FMT_DIR(x) (((x) & 0x1) << 3)
42 #define FESPI_FMT_LEN(x) (((x) & 0xf) << 16)
43
44 /* TXCTRL register */
45 #define FESPI_TXWM(x) ((x) & 0xffff)
46 /* RXCTRL register */
47 #define FESPI_RXWM(x) ((x) & 0xffff)
48
49 #define FESPI_IP_TXWM 0x1
50 #define FESPI_IP_RXWM 0x2
51
52 #define FESPI_FCTRL_EN 0x1
53
54 #define FESPI_INSN_CMD_EN 0x1
55 #define FESPI_INSN_ADDR_LEN(x) (((x) & 0x7) << 1)
56 #define FESPI_INSN_PAD_CNT(x) (((x) & 0xf) << 4)
57 #define FESPI_INSN_CMD_PROTO(x) (((x) & 0x3) << 8)
58 #define FESPI_INSN_ADDR_PROTO(x) (((x) & 0x3) << 10)
59 #define FESPI_INSN_DATA_PROTO(x) (((x) & 0x3) << 12)
60 #define FESPI_INSN_CMD_CODE(x) (((x) & 0xff) << 16)
61 #define FESPI_INSN_PAD_CODE(x) (((x) & 0xff) << 24)
62
63 /* Values */
64
65 #define FESPI_CSMODE_AUTO 0
66 #define FESPI_CSMODE_HOLD 2
67 #define FESPI_CSMODE_OFF 3
68
69 #define FESPI_DIR_RX 0
70 #define FESPI_DIR_TX 1
71
72 #define FESPI_PROTO_S 0
73 #define FESPI_PROTO_D 1
74 #define FESPI_PROTO_Q 2
75
76 #define FESPI_ENDIAN_MSB 0
77 #define FESPI_ENDIAN_LSB 1
78
79 /* Timeouts we use, in number of status checks. */
80 #define TIMEOUT 1000
81
82 /* #define DEBUG to make the return error codes provide enough information to
83 * reconstruct the stack from where the error occurred. This is not enabled
84 * usually to reduce the program size. */
85 #ifdef DEBUG
86 #define ERROR_STACK(x) (x)
87 #define ERROR_FESPI_TXWM_WAIT 0x10
88 #define ERROR_FESPI_TX 0x100
89 #define ERROR_FESPI_RX 0x1000
90 #define ERROR_FESPI_WIP 0x50000
91 #else
92 #define ERROR_STACK(x) 0
93 #define ERROR_FESPI_TXWM_WAIT 1
94 #define ERROR_FESPI_TX 1
95 #define ERROR_FESPI_RX 1
96 #define ERROR_FESPI_WIP 1
97 #endif
98
99 #define ERROR_OK 0
100
101 static int fespi_txwm_wait(volatile uint32_t *ctrl_base);
102 static void fespi_disable_hw_mode(volatile uint32_t *ctrl_base);
103 static void fespi_enable_hw_mode(volatile uint32_t *ctrl_base);
104 static int fespi_wip(volatile uint32_t *ctrl_base);
105 static int fespi_write_buffer(volatile uint32_t *ctrl_base,
106 const uint8_t *buffer, unsigned offset, unsigned len,
107 uint32_t flash_info);
108
109 /* Can set bits 3:0 in result. */
110 /* flash_info contains:
111 * bits 7:0 -- pprog_cmd
112 * bit 8 -- 0 means send 3 bytes after pprog_cmd, 1 means send 4 bytes
113 * after pprog_cmd
114 */
115 int flash_fespi(volatile uint32_t *ctrl_base, uint32_t page_size,
116 const uint8_t *buffer, unsigned offset, uint32_t count,
117 uint32_t flash_info)
118 {
119 int result;
120
121 result = fespi_txwm_wait(ctrl_base);
122 if (result != ERROR_OK)
123 return result | ERROR_STACK(0x1);
124
125 /* Disable Hardware accesses*/
126 fespi_disable_hw_mode(ctrl_base);
127
128 /* poll WIP */
129 result = fespi_wip(ctrl_base);
130 if (result != ERROR_OK) {
131 result |= ERROR_STACK(0x2);
132 goto err;
133 }
134
135 /* Assume page_size is a power of two so we don't need the modulus code. */
136 uint32_t page_offset = offset & (page_size - 1);
137
138 /* central part, aligned words */
139 while (count > 0) {
140 uint32_t cur_count;
141 /* clip block at page boundary */
142 if (page_offset + count > page_size)
143 cur_count = page_size - page_offset;
144 else
145 cur_count = count;
146
147 result = fespi_write_buffer(ctrl_base, buffer, offset, cur_count, flash_info);
148 if (result != ERROR_OK) {
149 result |= ERROR_STACK(0x3);
150 goto err;
151 }
152
153 page_offset = 0;
154 buffer += cur_count;
155 offset += cur_count;
156 count -= cur_count;
157 }
158
159 err:
160 /* Switch to HW mode before return to prompt */
161 fespi_enable_hw_mode(ctrl_base);
162
163 return result;
164 }
165
166 static uint32_t fespi_read_reg(volatile uint32_t *ctrl_base, unsigned address)
167 {
168 return ctrl_base[address / 4];
169 }
170
171 static void fespi_write_reg(volatile uint32_t *ctrl_base, unsigned address, uint32_t value)
172 {
173 ctrl_base[address / 4] = value;
174 }
175
176 static void fespi_disable_hw_mode(volatile uint32_t *ctrl_base)
177 {
178 uint32_t fctrl = fespi_read_reg(ctrl_base, FESPI_REG_FCTRL);
179 fespi_write_reg(ctrl_base, FESPI_REG_FCTRL, fctrl & ~FESPI_FCTRL_EN);
180 }
181
182 static void fespi_enable_hw_mode(volatile uint32_t *ctrl_base)
183 {
184 uint32_t fctrl = fespi_read_reg(ctrl_base, FESPI_REG_FCTRL);
185 fespi_write_reg(ctrl_base, FESPI_REG_FCTRL, fctrl | FESPI_FCTRL_EN);
186 }
187
188 /* Can set bits 7:4 in result. */
189 static int fespi_txwm_wait(volatile uint32_t *ctrl_base)
190 {
191 unsigned timeout = TIMEOUT;
192
193 while (timeout--) {
194 uint32_t ip = fespi_read_reg(ctrl_base, FESPI_REG_IP);
195 if (ip & FESPI_IP_TXWM)
196 return ERROR_OK;
197 }
198
199 return ERROR_FESPI_TXWM_WAIT;
200 }
201
202 static void fespi_set_dir(volatile uint32_t *ctrl_base, bool dir)
203 {
204 uint32_t fmt = fespi_read_reg(ctrl_base, FESPI_REG_FMT);
205 fespi_write_reg(ctrl_base, FESPI_REG_FMT,
206 (fmt & ~(FESPI_FMT_DIR(0xFFFFFFFF))) | FESPI_FMT_DIR(dir));
207 }
208
209 /* Can set bits 11:8 in result. */
210 static int fespi_tx(volatile uint32_t *ctrl_base, uint8_t in)
211 {
212 unsigned timeout = TIMEOUT;
213
214 while (timeout--) {
215 uint32_t txfifo = fespi_read_reg(ctrl_base, FESPI_REG_TXFIFO);
216 if (!(txfifo >> 31)) {
217 fespi_write_reg(ctrl_base, FESPI_REG_TXFIFO, in);
218 return ERROR_OK;
219 }
220 }
221 return ERROR_FESPI_TX;
222 }
223
224 /* Can set bits 15:12 in result. */
225 static int fespi_rx(volatile uint32_t *ctrl_base, uint8_t *out)
226 {
227 unsigned timeout = TIMEOUT;
228
229 while (timeout--) {
230 uint32_t value = fespi_read_reg(ctrl_base, FESPI_REG_RXFIFO);
231 if (!(value >> 31)) {
232 if (out)
233 *out = value & 0xff;
234 return ERROR_OK;
235 }
236 }
237
238 return ERROR_FESPI_RX;
239 }
240
241 /* Can set bits 19:16 in result. */
242 static int fespi_wip(volatile uint32_t *ctrl_base)
243 {
244 fespi_set_dir(ctrl_base, FESPI_DIR_RX);
245
246 fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
247
248 int result = fespi_tx(ctrl_base, SPIFLASH_READ_STATUS);
249 if (result != ERROR_OK)
250 return result | ERROR_STACK(0x10000);
251 result = fespi_rx(ctrl_base, NULL);
252 if (result != ERROR_OK)
253 return result | ERROR_STACK(0x20000);
254
255 unsigned timeout = TIMEOUT;
256 while (timeout--) {
257 result = fespi_tx(ctrl_base, 0);
258 if (result != ERROR_OK)
259 return result | ERROR_STACK(0x30000);
260 uint8_t rx;
261 result = fespi_rx(ctrl_base, &rx);
262 if (result != ERROR_OK)
263 return result | ERROR_STACK(0x40000);
264 if ((rx & SPIFLASH_BSY_BIT) == 0) {
265 fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
266 fespi_set_dir(ctrl_base, FESPI_DIR_TX);
267 return ERROR_OK;
268 }
269 }
270
271 return ERROR_FESPI_WIP;
272 }
273
274 /* Can set bits 23:20 in result. */
275 static int fespi_write_buffer(volatile uint32_t *ctrl_base,
276 const uint8_t *buffer, unsigned offset, unsigned len,
277 uint32_t flash_info)
278 {
279 int result = fespi_tx(ctrl_base, SPIFLASH_WRITE_ENABLE);
280 if (result != ERROR_OK)
281 return result | ERROR_STACK(0x100000);
282 result = fespi_txwm_wait(ctrl_base);
283 if (result != ERROR_OK)
284 return result | ERROR_STACK(0x200000);
285
286 fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
287
288 result = fespi_tx(ctrl_base, flash_info & 0xff);
289 if (result != ERROR_OK)
290 return result | ERROR_STACK(0x300000);
291
292 if (flash_info & 0x100) {
293 result = fespi_tx(ctrl_base, offset >> 24);
294 if (result != ERROR_OK)
295 return result | ERROR_STACK(0x400000);
296 }
297 result = fespi_tx(ctrl_base, offset >> 16);
298 if (result != ERROR_OK)
299 return result | ERROR_STACK(0x400000);
300 result = fespi_tx(ctrl_base, offset >> 8);
301 if (result != ERROR_OK)
302 return result | ERROR_STACK(0x500000);
303 result = fespi_tx(ctrl_base, offset);
304 if (result != ERROR_OK)
305 return result | ERROR_STACK(0x600000);
306
307 for (unsigned i = 0; i < len; i++) {
308 result = fespi_tx(ctrl_base, buffer[i]);
309 if (result != ERROR_OK)
310 return result | ERROR_STACK(0x700000);
311 }
312
313 result = fespi_txwm_wait(ctrl_base);
314 if (result != ERROR_OK)
315 return result | ERROR_STACK(0x800000);
316
317 fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
318
319 result = fespi_wip(ctrl_base);
320 if (result != ERROR_OK)
321 return result | ERROR_STACK(0x900000);
322 return ERROR_OK;
323 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)