5323f92bfdca796a22d96c7eb8c732b08168fa77
[fw/openocd] / 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 }