bluenrg-x: added support for BlueNRG-LP device
[fw/openocd] / contrib / loaders / flash / bluenrg-x / bluenrg-x_write.c
1 /* To be built with arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m0 -O3 bluenrgx.c */
2 /* Then postprocess output of command "arm-none-eabi-objdump -d bluenrgx.o" to make a C array of bytes */
3
4 #include <stdint.h>
5
6 /* Status Values ----------------------------------------------------------*/
7 #define SUCCESS             0
8 #define ERR_UNALIGNED       1
9 #define ERR_INVALID_ADDRESS 2
10 #define ERR_INVALID_TYPE    3
11 #define ERR_WRITE_PROTECTED 4
12 #define ERR_WRITE_FAILED    5
13 #define ERR_ERASE_REQUIRED  6
14 #define ERR_VERIFY_FAILED   7
15
16 /* Flash Controller defines ---------------------------------------------------*/
17 #ifdef BLUENRG_LP
18 #define FLASH_REG_COMMAND ((volatile uint32_t *)0x40001000)
19 #define FLASH_REG_CONFIG  ((volatile uint32_t *)0x40001004)
20 #define FLASH_REG_IRQSTAT ((volatile uint32_t *)0x40001008)
21 #define FLASH_REG_IRQMASK ((volatile uint32_t *)0x4000100C)
22 #define FLASH_REG_IRQRAW  ((volatile uint32_t *)0x40001010)
23 #define FLASH_REG_ADDRESS ((volatile uint32_t *)0x40001018)
24 #define FLASH_REG_UNLOCKM ((volatile uint32_t *)0x4000101C)
25 #define FLASH_REG_UNLOCKL ((volatile uint32_t *)0x40001020)
26 #define FLASH_REG_DATA0   ((volatile uint32_t *)0x40001040)
27 #define FLASH_REG_DATA1   ((volatile uint32_t *)0x40001044)
28 #define FLASH_REG_DATA2   ((volatile uint32_t *)0x40001048)
29 #define FLASH_REG_DATA3   ((volatile uint32_t *)0x4000104C)
30 #define FLASH_SIZE_REG 0x40001014
31 #else
32 #define FLASH_REG_COMMAND ((volatile uint32_t *)0x40100000)
33 #define FLASH_REG_CONFIG  ((volatile uint32_t *)0x40100004)
34 #define FLASH_REG_IRQSTAT ((volatile uint32_t *)0x40100008)
35 #define FLASH_REG_IRQMASK ((volatile uint32_t *)0x4010000C)
36 #define FLASH_REG_IRQRAW  ((volatile uint32_t *)0x40100010)
37 #define FLASH_REG_ADDRESS ((volatile uint32_t *)0x40100018)
38 #define FLASH_REG_UNLOCKM ((volatile uint32_t *)0x4010001C)
39 #define FLASH_REG_UNLOCKL ((volatile uint32_t *)0x40100020)
40 #define FLASH_REG_DATA0   ((volatile uint32_t *)0x40100040)
41 #define FLASH_REG_DATA1   ((volatile uint32_t *)0x40100044)
42 #define FLASH_REG_DATA2   ((volatile uint32_t *)0x40100048)
43 #define FLASH_REG_DATA3   ((volatile uint32_t *)0x4010004C)
44 #define FLASH_SIZE_REG 0x40100014
45 #endif
46
47 #define MFB_MASS_ERASE 0x01
48 #define MFB_PAGE_ERASE 0x02
49
50 #define DO_ERASE  0x0100
51 #define DO_VERIFY 0x0200
52 #define FLASH_CMD_ERASE_PAGE 0x11
53 #define FLASH_CMD_MASSERASE  0x22
54 #define FLASH_CMD_WRITE      0x33
55 #define FLASH_CMD_BURSTWRITE 0xCC
56 #define FLASH_INT_CMDDONE    0x01
57 #define MFB_BOTTOM          (0x10040000)
58 #define MFB_SIZE_B          ((16 * (((*(uint32_t *) FLASH_SIZE_REG) + 1) >> 12)) * 1024)
59 #define MFB_SIZE_W          (MFB_SIZE_B/4)
60 #define MFB_TOP             (MFB_BOTTOM+MFB_SIZE_B-1)
61 #define MFB_PAGE_SIZE_B     (2048)
62 #define MFB_PAGE_SIZE_W     (MFB_PAGE_SIZE_B/4)
63
64 #define AREA_ERROR 0x01
65 #define AREA_MFB   0x04
66
67 #define FLASH_WORD_LEN       4
68
69 typedef struct {
70         volatile uint8_t *wp;
71         uint8_t *rp;
72 } work_area_t;
73
74 /* Flash Commands --------------------------------------------------------*/
75 static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t address, uint8_t **data,
76                                                                  uint32_t writeLength)
77 {
78         uint32_t index, flash_word[4];
79         uint8_t i;
80
81         *FLASH_REG_IRQMASK = 0;
82         for (index = 0; index < writeLength; index += (FLASH_WORD_LEN*4)) {
83                 for (i = 0; i < 4; i++)
84                         flash_word[i] = (*(uint32_t *) (*data + i*4));
85
86                 /* Clear the IRQ flags */
87                 *FLASH_REG_IRQRAW = 0x0000003F;
88                 /* Load the flash address to write */
89                 *FLASH_REG_ADDRESS = (uint16_t)((address + index - MFB_BOTTOM) >> 2);
90                 /* Prepare and load the data to flash */
91                 *FLASH_REG_DATA0 = flash_word[0];
92                 *FLASH_REG_DATA1 = flash_word[1];
93                 *FLASH_REG_DATA2 = flash_word[2];
94                 *FLASH_REG_DATA3 = flash_word[3];
95                 /* Flash write command */
96                 *FLASH_REG_COMMAND = FLASH_CMD_BURSTWRITE;
97                 /* Wait the end of the flash write command */
98                 while ((*FLASH_REG_IRQRAW & FLASH_INT_CMDDONE) == 0)
99                         ;
100                 *data += (FLASH_WORD_LEN * 4);
101         }
102
103         return SUCCESS;
104 }
105
106 __attribute__((naked)) __attribute__((noreturn)) void write(uint8_t *work_area_p,
107                                                             uint8_t *fifo_end,
108                                                             uint8_t *target_address,
109                                                             uint32_t count)
110 {
111         uint32_t retval;
112         volatile work_area_t *work_area = (work_area_t *) work_area_p;
113         uint8_t *fifo_start = (uint8_t *) work_area->rp;
114
115         while (count) {
116                 volatile int32_t fifo_linear_size;
117
118                 /* Wait for some data in the FIFO */
119                 while (work_area->rp == work_area->wp)
120                         ;
121                 if (work_area->wp == 0) {
122                         /* Aborted by other party */
123                         break;
124                 }
125                 if (work_area->rp > work_area->wp) {
126                         fifo_linear_size = fifo_end-work_area->rp;
127                 } else {
128                         fifo_linear_size = (work_area->wp - work_area->rp);
129                         if (fifo_linear_size < 0)
130                                 fifo_linear_size = 0;
131                 }
132                 if (fifo_linear_size < 16) {
133                         /* We should never get here */
134                         continue;
135                 }
136
137                 retval = flashWrite((uint32_t) target_address, (uint8_t **) &work_area->rp, fifo_linear_size);
138                 if (retval != SUCCESS) {
139                         work_area->rp = (uint8_t *)retval;
140                         break;
141                 }
142                 target_address += fifo_linear_size;
143                 if (work_area->rp >= fifo_end)
144                         work_area->rp = fifo_start;
145                 count -= fifo_linear_size;
146         }
147         __asm("bkpt 0");
148 }