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

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)