openocd: fix SPDX tag format for files .c
[openocd.git] / 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 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)