1 /* SPDX-License-Identifier: GPL-2.0-or-later */
7 #include "../../../../src/flash/nor/spi.h"
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
17 #define FESPI_REG_DCSSCK 0x28
18 #define FESPI_REG_DSCKCS 0x2a
19 #define FESPI_REG_DINTERCS 0x2c
20 #define FESPI_REG_DINTERXFR 0x2e
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
28 #define FESPI_REG_FCTRL 0x60
29 #define FESPI_REG_FFMT 0x64
31 #define FESPI_REG_IE 0x70
32 #define FESPI_REG_IP 0x74
36 #define FESPI_SCK_POL 0x1
37 #define FESPI_SCK_PHA 0x2
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)
45 #define FESPI_TXWM(x) ((x) & 0xffff)
47 #define FESPI_RXWM(x) ((x) & 0xffff)
49 #define FESPI_IP_TXWM 0x1
50 #define FESPI_IP_RXWM 0x2
52 #define FESPI_FCTRL_EN 0x1
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)
65 #define FESPI_CSMODE_AUTO 0
66 #define FESPI_CSMODE_HOLD 2
67 #define FESPI_CSMODE_OFF 3
69 #define FESPI_DIR_RX 0
70 #define FESPI_DIR_TX 1
72 #define FESPI_PROTO_S 0
73 #define FESPI_PROTO_D 1
74 #define FESPI_PROTO_Q 2
76 #define FESPI_ENDIAN_MSB 0
77 #define FESPI_ENDIAN_LSB 1
79 /* Timeouts we use, in number of status checks. */
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. */
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
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
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);
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
115 int flash_fespi(volatile uint32_t *ctrl_base, uint32_t page_size,
116 const uint8_t *buffer, unsigned offset, uint32_t count,
121 result = fespi_txwm_wait(ctrl_base);
122 if (result != ERROR_OK)
123 return result | ERROR_STACK(0x1);
125 /* Disable Hardware accesses*/
126 fespi_disable_hw_mode(ctrl_base);
129 result = fespi_wip(ctrl_base);
130 if (result != ERROR_OK) {
131 result |= ERROR_STACK(0x2);
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);
138 /* central part, aligned words */
141 /* clip block at page boundary */
142 if (page_offset + count > page_size)
143 cur_count = page_size - page_offset;
147 result = fespi_write_buffer(ctrl_base, buffer, offset, cur_count, flash_info);
148 if (result != ERROR_OK) {
149 result |= ERROR_STACK(0x3);
160 /* Switch to HW mode before return to prompt */
161 fespi_enable_hw_mode(ctrl_base);
166 static uint32_t fespi_read_reg(volatile uint32_t *ctrl_base, unsigned address)
168 return ctrl_base[address / 4];
171 static void fespi_write_reg(volatile uint32_t *ctrl_base, unsigned address, uint32_t value)
173 ctrl_base[address / 4] = value;
176 static void fespi_disable_hw_mode(volatile uint32_t *ctrl_base)
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);
182 static void fespi_enable_hw_mode(volatile uint32_t *ctrl_base)
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);
188 /* Can set bits 7:4 in result. */
189 static int fespi_txwm_wait(volatile uint32_t *ctrl_base)
191 unsigned timeout = TIMEOUT;
194 uint32_t ip = fespi_read_reg(ctrl_base, FESPI_REG_IP);
195 if (ip & FESPI_IP_TXWM)
199 return ERROR_FESPI_TXWM_WAIT;
202 static void fespi_set_dir(volatile uint32_t *ctrl_base, bool dir)
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));
209 /* Can set bits 11:8 in result. */
210 static int fespi_tx(volatile uint32_t *ctrl_base, uint8_t in)
212 unsigned timeout = 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);
221 return ERROR_FESPI_TX;
224 /* Can set bits 15:12 in result. */
225 static int fespi_rx(volatile uint32_t *ctrl_base, uint8_t *out)
227 unsigned timeout = TIMEOUT;
230 uint32_t value = fespi_read_reg(ctrl_base, FESPI_REG_RXFIFO);
231 if (!(value >> 31)) {
238 return ERROR_FESPI_RX;
241 /* Can set bits 19:16 in result. */
242 static int fespi_wip(volatile uint32_t *ctrl_base)
244 fespi_set_dir(ctrl_base, FESPI_DIR_RX);
246 fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
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);
255 unsigned timeout = TIMEOUT;
257 result = fespi_tx(ctrl_base, 0);
258 if (result != ERROR_OK)
259 return result | ERROR_STACK(0x30000);
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);
271 return ERROR_FESPI_WIP;
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,
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);
286 fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
288 result = fespi_tx(ctrl_base, flash_info & 0xff);
289 if (result != ERROR_OK)
290 return result | ERROR_STACK(0x300000);
292 if (flash_info & 0x100) {
293 result = fespi_tx(ctrl_base, offset >> 24);
294 if (result != ERROR_OK)
295 return result | ERROR_STACK(0x400000);
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);
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);
313 result = fespi_txwm_wait(ctrl_base);
314 if (result != ERROR_OK)
315 return result | ERROR_STACK(0x800000);
317 fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
319 result = fespi_wip(ctrl_base);
320 if (result != ERROR_OK)
321 return result | ERROR_STACK(0x900000);