5 #include "../../../../src/flash/nor/spi.h"
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
15 #define FESPI_REG_DCSSCK 0x28
16 #define FESPI_REG_DSCKCS 0x2a
17 #define FESPI_REG_DINTERCS 0x2c
18 #define FESPI_REG_DINTERXFR 0x2e
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
26 #define FESPI_REG_FCTRL 0x60
27 #define FESPI_REG_FFMT 0x64
29 #define FESPI_REG_IE 0x70
30 #define FESPI_REG_IP 0x74
34 #define FESPI_SCK_POL 0x1
35 #define FESPI_SCK_PHA 0x2
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)
43 #define FESPI_TXWM(x) ((x) & 0xffff)
45 #define FESPI_RXWM(x) ((x) & 0xffff)
47 #define FESPI_IP_TXWM 0x1
48 #define FESPI_IP_RXWM 0x2
50 #define FESPI_FCTRL_EN 0x1
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)
63 #define FESPI_CSMODE_AUTO 0
64 #define FESPI_CSMODE_HOLD 2
65 #define FESPI_CSMODE_OFF 3
67 #define FESPI_DIR_RX 0
68 #define FESPI_DIR_TX 1
70 #define FESPI_PROTO_S 0
71 #define FESPI_PROTO_D 1
72 #define FESPI_PROTO_Q 2
74 #define FESPI_ENDIAN_MSB 0
75 #define FESPI_ENDIAN_LSB 1
77 /* Timeouts we use, in number of status checks. */
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. */
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
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
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);
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
113 int flash_fespi(volatile uint32_t *ctrl_base, uint32_t page_size,
114 const uint8_t *buffer, unsigned offset, uint32_t count,
119 result = fespi_txwm_wait(ctrl_base);
120 if (result != ERROR_OK)
121 return result | ERROR_STACK(0x1);
123 /* Disable Hardware accesses*/
124 fespi_disable_hw_mode(ctrl_base);
127 result = fespi_wip(ctrl_base);
128 if (result != ERROR_OK) {
129 result |= ERROR_STACK(0x2);
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);
136 /* central part, aligned words */
139 /* clip block at page boundary */
140 if (page_offset + count > page_size)
141 cur_count = page_size - page_offset;
145 result = fespi_write_buffer(ctrl_base, buffer, offset, cur_count, flash_info);
146 if (result != ERROR_OK) {
147 result |= ERROR_STACK(0x3);
158 /* Switch to HW mode before return to prompt */
159 fespi_enable_hw_mode(ctrl_base);
164 static uint32_t fespi_read_reg(volatile uint32_t *ctrl_base, unsigned address)
166 return ctrl_base[address / 4];
169 static void fespi_write_reg(volatile uint32_t *ctrl_base, unsigned address, uint32_t value)
171 ctrl_base[address / 4] = value;
174 static void fespi_disable_hw_mode(volatile uint32_t *ctrl_base)
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);
180 static void fespi_enable_hw_mode(volatile uint32_t *ctrl_base)
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);
186 /* Can set bits 7:4 in result. */
187 static int fespi_txwm_wait(volatile uint32_t *ctrl_base)
189 unsigned timeout = TIMEOUT;
192 uint32_t ip = fespi_read_reg(ctrl_base, FESPI_REG_IP);
193 if (ip & FESPI_IP_TXWM)
197 return ERROR_FESPI_TXWM_WAIT;
200 static void fespi_set_dir(volatile uint32_t *ctrl_base, bool dir)
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));
207 /* Can set bits 11:8 in result. */
208 static int fespi_tx(volatile uint32_t *ctrl_base, uint8_t in)
210 unsigned timeout = 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);
219 return ERROR_FESPI_TX;
222 /* Can set bits 15:12 in result. */
223 static int fespi_rx(volatile uint32_t *ctrl_base, uint8_t *out)
225 unsigned timeout = TIMEOUT;
228 uint32_t value = fespi_read_reg(ctrl_base, FESPI_REG_RXFIFO);
229 if (!(value >> 31)) {
236 return ERROR_FESPI_RX;
239 /* Can set bits 19:16 in result. */
240 static int fespi_wip(volatile uint32_t *ctrl_base)
242 fespi_set_dir(ctrl_base, FESPI_DIR_RX);
244 fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
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);
253 unsigned timeout = TIMEOUT;
255 result = fespi_tx(ctrl_base, 0);
256 if (result != ERROR_OK)
257 return result | ERROR_STACK(0x30000);
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);
269 return ERROR_FESPI_WIP;
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,
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);
284 fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD);
286 result = fespi_tx(ctrl_base, flash_info & 0xff);
287 if (result != ERROR_OK)
288 return result | ERROR_STACK(0x300000);
290 if (flash_info & 0x100) {
291 result = fespi_tx(ctrl_base, offset >> 24);
292 if (result != ERROR_OK)
293 return result | ERROR_STACK(0x400000);
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);
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);
311 result = fespi_txwm_wait(ctrl_base);
312 if (result != ERROR_OK)
313 return result | ERROR_STACK(0x800000);
315 fespi_write_reg(ctrl_base, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO);
317 result = fespi_wip(ctrl_base);
318 if (result != ERROR_OK)
319 return result | ERROR_STACK(0x900000);