aboutsummaryrefslogtreecommitdiff
path: root/contrib/loaders/flash/bluenrg-x/bluenrg-x_write.c
blob: 3dd17b2fcfadd98ab05e491a56dc179e51472c53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* To be built with arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m0 -O3 bluenrgx.c */
/* Then postprocess output of command "arm-none-eabi-objdump -d bluenrgx.o" to make a C array of bytes */

#include <stdint.h>

/* Status Values ----------------------------------------------------------*/
#define SUCCESS             0
#define ERR_UNALIGNED       1
#define ERR_INVALID_ADDRESS 2
#define ERR_INVALID_TYPE    3
#define ERR_WRITE_PROTECTED 4
#define ERR_WRITE_FAILED    5
#define ERR_ERASE_REQUIRED  6
#define ERR_VERIFY_FAILED   7

/* Flash Controller defines ---------------------------------------------------*/
#define FLASH_REG_COMMAND ((volatile uint32_t *)0x40100000)
#define FLASH_REG_CONFIG  ((volatile uint32_t *)0x40100004)
#define FLASH_REG_IRQSTAT ((volatile uint32_t *)0x40100008)
#define FLASH_REG_IRQMASK ((volatile uint32_t *)0x4010000C)
#define FLASH_REG_IRQRAW  ((volatile uint32_t *)0x40100010)
#define FLASH_REG_ADDRESS ((volatile uint32_t *)0x40100018)
#define FLASH_REG_UNLOCKM ((volatile uint32_t *)0x4010001C)
#define FLASH_REG_UNLOCKL ((volatile uint32_t *)0x40100020)
#define FLASH_REG_DATA0    ((volatile uint32_t *)0x40100040)
#define FLASH_REG_DATA1    ((volatile uint32_t *)0x40100044)
#define FLASH_REG_DATA2    ((volatile uint32_t *)0x40100048)
#define FLASH_REG_DATA3    ((volatile uint32_t *)0x4010004C)
#define FLASH_SIZE_REG 0x40100014

#define MFB_MASS_ERASE 0x01
#define MFB_PAGE_ERASE 0x02

#define DO_ERASE  0x0100
#define DO_VERIFY 0x0200
#define FLASH_CMD_ERASE_PAGE 0x11
#define FLASH_CMD_MASSERASE  0x22
#define FLASH_CMD_WRITE      0x33
#define FLASH_CMD_BURSTWRITE 0xCC
#define FLASH_INT_CMDDONE    0x01
#define MFB_BOTTOM          (0x10040000)
#define MFB_SIZE_B          ((16 * (((*(uint32_t *) FLASH_SIZE_REG) + 1) >> 12)) * 1024)
#define MFB_SIZE_W          (MFB_SIZE_B/4)
#define MFB_TOP             (MFB_BOTTOM+MFB_SIZE_B-1)
#define MFB_PAGE_SIZE_B     (2048)
#define MFB_PAGE_SIZE_W     (MFB_PAGE_SIZE_B/4)

#define AREA_ERROR 0x01
#define AREA_MFB   0x04

#define FLASH_WORD_LEN       4

typedef struct {
	volatile uint8_t *wp;
	uint8_t *rp;
} work_area_t;

/* Flash Commands --------------------------------------------------------*/
static inline __attribute__((always_inline)) uint32_t flashWrite(uint32_t address, uint8_t **data,
								 uint32_t writeLength)
{
	uint32_t index, flash_word[4];
	uint8_t i;

	*FLASH_REG_IRQMASK = 0;
	for (index = 0; index < writeLength; index += (FLASH_WORD_LEN*4)) {
		for (i = 0; i < 4; i++)
			flash_word[i] = (*(uint32_t *) (*data + i*4));

		/* Clear the IRQ flags */
		*FLASH_REG_IRQRAW = 0x0000003F;
		/* Load the flash address to write */
		*FLASH_REG_ADDRESS = (uint16_t)((address + index) >> 2);
		/* Prepare and load the data to flash */
		*FLASH_REG_DATA0 = flash_word[0];
		*FLASH_REG_DATA1 = flash_word[1];
		*FLASH_REG_DATA2 = flash_word[2];
		*FLASH_REG_DATA3 = flash_word[3];
		/* Flash write command */
		*FLASH_REG_COMMAND = FLASH_CMD_BURSTWRITE;
		/* Wait the end of the flash write command */
		while ((*FLASH_REG_IRQRAW & FLASH_INT_CMDDONE) == 0)
			;
		*data += (FLASH_WORD_LEN * 4);
	}

	return SUCCESS;
}

__attribute__((naked)) __attribute__((noreturn)) void write(uint8_t *work_area_p,
							    uint8_t *fifo_end,
							    uint8_t *target_address,
							    uint32_t count)
{
	uint32_t retval;
	volatile work_area_t *work_area = (work_area_t *) work_area_p;
	uint8_t *fifo_start = (uint8_t *) work_area->rp;

	while (count) {
		volatile int32_t fifo_linear_size;

		/* Wait for some data in the FIFO */
		while (work_area->rp == work_area->wp)
			;
		if (work_area->wp == 0) {
			/* Aborted by other party */
			break;
		}
		if (work_area->rp > work_area->wp) {
			fifo_linear_size = fifo_end-work_area->rp;
		} else {
			fifo_linear_size = (work_area->wp - work_area->rp);
			if (fifo_linear_size < 0)
				fifo_linear_size = 0;
		}
		if (fifo_linear_size < 16) {
			/* We should never get here */
			continue;
		}

		retval = flashWrite((uint32_t) target_address, (uint8_t **) &work_area->rp, fifo_linear_size);
		if (retval != SUCCESS) {
			work_area->rp = (uint8_t *)retval;
			break;
		}
		target_address += fifo_linear_size;
		if (work_area->rp >= fifo_end)
			work_area->rp = fifo_start;
		count -= fifo_linear_size;
	}
	__asm("bkpt 0");
}