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