contrib: add GPL license tag on files that miss it
[fw/openocd] / contrib / loaders / flash / bluenrg-x / bluenrg-x_write.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /* To be built with arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m0 -O3 bluenrgx.c */
4 /* Then postprocess output of command "arm-none-eabi-objdump -d bluenrgx.o" to make a C array of bytes */
5
6 #include <stdint.h>
7 #include "../../../../src/flash/nor/bluenrg-x.h"
8
9 /* Status Values ----------------------------------------------------------*/
10 #define SUCCESS             0
11 #define ERR_UNALIGNED       1
12 #define ERR_INVALID_ADDRESS 2
13 #define ERR_INVALID_TYPE    3
14 #define ERR_WRITE_PROTECTED 4
15 #define ERR_WRITE_FAILED    5
16 #define ERR_ERASE_REQUIRED  6
17 #define ERR_VERIFY_FAILED   7
18
19 #define MFB_MASS_ERASE 0x01
20 #define MFB_PAGE_ERASE 0x02
21
22 #define DO_ERASE  0x0100
23 #define DO_VERIFY 0x0200
24
25 #define MFB_BOTTOM                (0x10040000)
26 #define MFB_SIZE_B(regs_base)     ((16 * (((*(volatile uint32_t *)(regs_base + FLASH_SIZE_REG)) + 1) >> 12)) * 1024)
27 #define MFB_SIZE_W                (MFB_SIZE_B/4)
28 #define MFB_TOP                   (MFB_BOTTOM+MFB_SIZE_B-1)
29 #define MFB_PAGE_SIZE_B           (2048)
30 #define MFB_PAGE_SIZE_W           (MFB_PAGE_SIZE_B/4)
31
32 #define AREA_ERROR 0x01
33 #define AREA_MFB   0x04
34
35 typedef struct {
36         volatile uint8_t *wp;
37         uint8_t *rp;
38 } work_area_t;
39
40 /* Flash Commands --------------------------------------------------------*/
41 static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t address, uint8_t **data,
42                                                                  uint32_t writeLength, uint32_t flash_regs_base)
43 {
44         uint32_t index, flash_word[4];
45         uint8_t i;
46
47         *((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQMASK)) = 0;
48         for (index = 0; index < writeLength; index += (FLASH_WORD_LEN*4)) {
49                 for (i = 0; i < 4; i++)
50                         flash_word[i] = (*(uint32_t *) (*data + i*4));
51
52                 /* Clear the IRQ flags */
53                 *((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQRAW)) = 0x0000003F;
54                 /* Load the flash address to write */
55                 *((volatile uint32_t *)(flash_regs_base + FLASH_REG_ADDRESS)) = (uint16_t)((address + index - MFB_BOTTOM) >> 2);
56                 /* Prepare and load the data to flash */
57                 *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA0)) = flash_word[0];
58                 *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA1)) = flash_word[1];
59                 *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA2)) = flash_word[2];
60                 *((volatile uint32_t *)(flash_regs_base + FLASH_REG_DATA3)) = flash_word[3];
61                 /* Flash write command */
62                 *((volatile uint32_t *)(flash_regs_base + FLASH_REG_COMMAND)) = FLASH_CMD_BURSTWRITE;
63                 /* Wait the end of the flash write command */
64                 while ((*((volatile uint32_t *)(flash_regs_base + FLASH_REG_IRQRAW)) & FLASH_INT_CMDDONE) == 0)
65                         ;
66                 *data += (FLASH_WORD_LEN * 4);
67         }
68
69         return SUCCESS;
70 }
71
72 __attribute__((naked)) __attribute__((noreturn)) void write(uint8_t *work_area_p,
73                                                             uint8_t *fifo_end,
74                                                             uint8_t *target_address,
75                                                             uint32_t count,
76                                                             uint32_t flash_regs_base)
77 {
78         uint32_t retval;
79         volatile work_area_t *work_area = (work_area_t *) work_area_p;
80         uint8_t *fifo_start = (uint8_t *) work_area->rp;
81
82         while (count) {
83                 volatile int32_t fifo_linear_size;
84
85                 /* Wait for some data in the FIFO */
86                 while (work_area->rp == work_area->wp)
87                         ;
88                 if (work_area->wp == 0) {
89                         /* Aborted by other party */
90                         break;
91                 }
92                 if (work_area->rp > work_area->wp) {
93                         fifo_linear_size = fifo_end-work_area->rp;
94                 } else {
95                         fifo_linear_size = (work_area->wp - work_area->rp);
96                         if (fifo_linear_size < 0)
97                                 fifo_linear_size = 0;
98                 }
99                 if (fifo_linear_size < 16) {
100                         /* We should never get here */
101                         continue;
102                 }
103
104                 retval = flashWrite((uint32_t) target_address, (uint8_t **) &work_area->rp, fifo_linear_size, flash_regs_base);
105                 if (retval != SUCCESS) {
106                         work_area->rp = (uint8_t *)retval;
107                         break;
108                 }
109                 target_address += fifo_linear_size;
110                 if (work_area->rp >= fifo_end)
111                         work_area->rp = fifo_start;
112                 count -= fifo_linear_size;
113         }
114         __asm("bkpt 0");
115 }