flash/nor: add support for Nuvoton NPCX series flash
[fw/openocd] / contrib / loaders / flash / npcx / npcx_flash.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /*
4  * Copyright (C) 2020 by Nuvoton Technology Corporation
5  * Mulin Chao <mlchao@nuvoton.com>
6  * Wealian Liao <WHLIAO@nuvoton.com>
7  */
8
9 #include <stdint.h>
10 #include <string.h>
11 #include "npcx_flash.h"
12
13 /*----------------------------------------------------------------------------
14  *                             NPCX flash driver
15  *----------------------------------------------------------------------------*/
16 static void flash_execute_cmd(uint8_t code, uint8_t cts)
17 {
18         /* Set UMA code */
19         NPCX_UMA_CODE = code;
20         /* Execute UMA flash transaction by CTS setting */
21         NPCX_UMA_CTS = cts;
22         /* Wait for transaction completed */
23         while (NPCX_IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE))
24                 ;
25 }
26
27 static void flash_cs_level(uint8_t level)
28 {
29         /* Program chip select pin to high/low level */
30         if (level)
31                 NPCX_SET_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1);
32         else
33                 NPCX_CLEAR_BIT(NPCX_UMA_ECTS, NPCX_UMA_ECTS_SW_CS1);
34 }
35
36 static void flash_set_address(uint32_t dest_addr)
37 {
38         uint8_t *addr = (uint8_t *)&dest_addr;
39
40         /* Set target flash address */
41         NPCX_UMA_AB2 = addr[2];
42         NPCX_UMA_AB1 = addr[1];
43         NPCX_UMA_AB0 = addr[0];
44 }
45
46 void delay(uint32_t i)
47 {
48         while (i--)
49                 ;
50 }
51
52 static int flash_wait_ready(uint32_t timeout)
53 {
54         /* Chip Select down. -- Burst mode */
55         flash_cs_level(0);
56
57         /* Command for Read status register */
58         flash_execute_cmd(NPCX_CMD_READ_STATUS_REG, NPCX_MASK_CMD_ONLY);
59         while (timeout > 0) {
60                 /* Read status register */
61                 NPCX_UMA_CTS = NPCX_MASK_RD_1BYTE;
62                 while (NPCX_IS_BIT_SET(NPCX_UMA_CTS, NPCX_UMA_CTS_EXEC_DONE))
63                         ;
64
65                 if (!(NPCX_UMA_DB0 & NPCX_SPI_FLASH_SR1_BUSY))
66                         break;
67
68                 if (--timeout > 0)
69                         delay(100);
70
71         }; /* Wait for Busy clear */
72
73         /* Chip Select high. */
74         flash_cs_level(1);
75
76         if (timeout == 0)
77                 return NPCX_FLASH_STATUS_FAILED_TIMEOUT;
78
79         return NPCX_FLASH_STATUS_OK;
80 }
81
82 static int flash_write_enable(void)
83 {
84         /* Write enable command */
85         flash_execute_cmd(NPCX_CMD_WRITE_EN, NPCX_MASK_CMD_ONLY);
86
87         /* Wait for flash is not busy */
88         int status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT);
89         if (status != NPCX_FLASH_STATUS_OK)
90                 return status;
91
92         if (NPCX_UMA_DB0 & NPCX_SPI_FLASH_SR1_WEL)
93                 return NPCX_FLASH_STATUS_OK;
94         else
95                 return NPCX_FLASH_STATUS_FAILED;
96 }
97
98 static void flash_burst_write(uint32_t dest_addr, uint16_t bytes,
99                 const uint8_t *data)
100 {
101         /* Chip Select down -- Burst mode */
102         flash_cs_level(0);
103
104         /* Set write address */
105         flash_set_address(dest_addr);
106         /* Start programming */
107         flash_execute_cmd(NPCX_CMD_FLASH_PROGRAM, NPCX_MASK_CMD_WR_ADR);
108         for (uint32_t i = 0; i < bytes; i++) {
109                 flash_execute_cmd(*data, NPCX_MASK_CMD_WR_ONLY);
110                 data++;
111         }
112
113         /* Chip Select up */
114         flash_cs_level(1);
115 }
116
117 /* The data to write cannot cross 256 Bytes boundary */
118 static int flash_program_write(uint32_t addr, uint32_t size,
119                 const uint8_t *data)
120 {
121         int status = flash_write_enable();
122         if (status != NPCX_FLASH_STATUS_OK)
123                 return status;
124
125         flash_burst_write(addr, size, data);
126         return flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT);
127 }
128
129 int flash_physical_write(uint32_t offset, uint32_t size, const uint8_t *data)
130 {
131         int status;
132         uint32_t trunk_start = (offset + 0xff) & ~0xff;
133
134         /* write head */
135         uint32_t dest_addr = offset;
136         uint32_t write_len = ((trunk_start - offset) > size) ? size : (trunk_start - offset);
137
138         if (write_len) {
139                 status = flash_program_write(dest_addr, write_len, data);
140                 if (status != NPCX_FLASH_STATUS_OK)
141                         return status;
142                 data += write_len;
143         }
144
145         dest_addr = trunk_start;
146         size -= write_len;
147
148         /* write remaining data*/
149         while (size > 0) {
150                 write_len = (size > NPCX_FLASH_WRITE_SIZE) ?
151                                         NPCX_FLASH_WRITE_SIZE : size;
152
153                 status = flash_program_write(dest_addr, write_len, data);
154                 if (status != NPCX_FLASH_STATUS_OK)
155                         return status;
156
157                 data      += write_len;
158                 dest_addr += write_len;
159                 size      -= write_len;
160         }
161
162         return NPCX_FLASH_STATUS_OK;
163 }
164
165 int flash_physical_erase(uint32_t offset, uint32_t size)
166 {
167         /* Alignment has been checked in upper layer */
168         for (; size > 0; size -= NPCX_FLASH_ERASE_SIZE,
169                 offset += NPCX_FLASH_ERASE_SIZE) {
170                 /* Enable write */
171                 int status = flash_write_enable();
172                 if (status != NPCX_FLASH_STATUS_OK)
173                         return status;
174
175                 /* Set erase address */
176                 flash_set_address(offset);
177                 /* Start erase */
178                 flash_execute_cmd(NPCX_CMD_SECTOR_ERASE, NPCX_MASK_CMD_ADR);
179                 /* Wait erase completed */
180                 status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT);
181                 if (status != NPCX_FLASH_STATUS_OK)
182                         return status;
183         }
184
185         return NPCX_FLASH_STATUS_OK;
186 }
187
188 int flash_physical_erase_all(void)
189 {
190         /* Enable write */
191         int status = flash_write_enable();
192         if (status != NPCX_FLASH_STATUS_OK)
193                 return status;
194
195         /* Start erase */
196         flash_execute_cmd(NPCX_CMD_CHIP_ERASE, NPCX_MASK_CMD_ONLY);
197
198         /* Wait erase completed */
199         status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT);
200         if (status != NPCX_FLASH_STATUS_OK)
201                 return status;
202
203         return NPCX_FLASH_STATUS_OK;
204 }
205
206 int flash_physical_clear_stsreg(void)
207 {
208         /* Enable write */
209         int status = flash_write_enable();
210         if (status != NPCX_FLASH_STATUS_OK)
211                 return status;
212
213         NPCX_UMA_DB0 = 0x0;
214         NPCX_UMA_DB1 = 0x0;
215
216         /* Write status register 1/2 */
217         flash_execute_cmd(NPCX_CMD_WRITE_STATUS_REG, NPCX_MASK_CMD_WR_2BYTE);
218
219         /* Wait writing completed */
220         status = flash_wait_ready(NPCX_FLASH_ABORT_TIMEOUT);
221         if (status != NPCX_FLASH_STATUS_OK)
222                 return status;
223
224         /* Read status register 1/2 for checking */
225         flash_execute_cmd(NPCX_CMD_READ_STATUS_REG, NPCX_MASK_CMD_RD_1BYTE);
226         if (NPCX_UMA_DB0 != 0x00)
227                 return NPCX_FLASH_STATUS_FAILED;
228         flash_execute_cmd(NPCX_CMD_READ_STATUS_REG2, NPCX_MASK_CMD_RD_1BYTE);
229         if (NPCX_UMA_DB0 != 0x00)
230                 return NPCX_FLASH_STATUS_FAILED;
231
232         return NPCX_FLASH_STATUS_OK;
233 }
234
235 int flash_get_id(uint32_t *id)
236 {
237         flash_execute_cmd(NPCX_CMD_READ_ID, NPCX_MASK_CMD_RD_3BYTE);
238         *id = NPCX_UMA_DB0 << 16 | NPCX_UMA_DB1 << 8 | NPCX_UMA_DB2;
239
240         return NPCX_FLASH_STATUS_OK;
241 }
242
243 /*----------------------------------------------------------------------------
244  *                             flash loader function
245  *----------------------------------------------------------------------------*/
246 uint32_t flashloader_init(struct npcx_flash_params *params)
247 {
248         /* Initialize params buffers */
249         memset(params, 0, sizeof(struct npcx_flash_params));
250
251         return NPCX_FLASH_STATUS_OK;
252 }
253
254 /*----------------------------------------------------------------------------
255  *                                      Functions
256  *----------------------------------------------------------------------------*/
257 /* flashloader parameter structure */
258 __attribute__ ((section(".buffers.g_cfg")))
259 volatile struct npcx_flash_params g_cfg;
260 /* data buffer */
261 __attribute__ ((section(".buffers.g_buf")))
262 uint8_t g_buf[NPCX_FLASH_LOADER_BUFFER_SIZE];
263
264 int main(void)
265 {
266         uint32_t id;
267
268         /* set buffer */
269         flashloader_init((struct npcx_flash_params *)&g_cfg);
270
271         /* Avoid F_CS0 toggles while programming the internal flash. */
272         NPCX_SET_BIT(NPCX_DEVALT(0), NPCX_DEVALT0_NO_F_SPI);
273
274         /* clear flash status registers */
275         int status = flash_physical_clear_stsreg();
276         if (status != NPCX_FLASH_STATUS_OK) {
277                 while (1)
278                         g_cfg.sync = status;
279         }
280
281         while (1) {
282                 /* wait command*/
283                 while (g_cfg.sync == NPCX_FLASH_LOADER_WAIT)
284                         ;
285
286                 /* command handler */
287                 switch (g_cfg.cmd) {
288                 case NPCX_FLASH_CMD_GET_FLASH_ID:
289                         status = flash_get_id(&id);
290                         if (status == NPCX_FLASH_STATUS_OK) {
291                                 g_buf[0] = id & 0xff;
292                                 g_buf[1] = (id >> 8) & 0xff;
293                                 g_buf[2] = (id >> 16) & 0xff;
294                                 g_buf[3] = 0x00;
295                         }
296                         break;
297                 case NPCX_FLASH_CMD_ERASE_SECTORS:
298                         status = flash_physical_erase(g_cfg.addr, g_cfg.len);
299                         break;
300                 case NPCX_FLASH_CMD_ERASE_ALL:
301                         status = flash_physical_erase_all();
302                         break;
303                 case NPCX_FLASH_CMD_PROGRAM:
304                         status = flash_physical_write(g_cfg.addr,
305                                                         g_cfg.len,
306                                                         g_buf);
307                         break;
308                 default:
309                         status = NPCX_FLASH_STATUS_FAILED_UNKNOWN_COMMAND;
310                         break;
311                 }
312
313                 /* clear & set result for next command */
314                 if (status != NPCX_FLASH_STATUS_OK) {
315                         g_cfg.sync = status;
316                         while (1)
317                                 ;
318                 } else {
319                         g_cfg.sync = NPCX_FLASH_LOADER_WAIT;
320                 }
321         }
322
323         return 0;
324 }
325
326 __attribute__ ((section(".stack")))
327 __attribute__ ((used))
328 static uint32_t stack[NPCX_FLASH_LOADER_STACK_SIZE / 4];
329 extern uint32_t _estack;
330 extern uint32_t _bss;
331 extern uint32_t _ebss;
332
333 __attribute__ ((section(".entry")))
334 void entry(void)
335 {
336         /* set sp from end of stack */
337         __asm(" ldr sp, =_estack - 4");
338
339         main();
340
341         __asm(" bkpt #0x00");
342 }