2 * Copyright © 2013 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 #define IAP_LOCATION 0x1fff1ff1
24 typedef void (*iap_func)(uint32_t *in, uint32_t *out);
27 iap(uint32_t *in, uint32_t *out)
29 ao_arch_block_interrupts();
30 lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_FLASHREG);
31 ((iap_func) IAP_LOCATION)(in, out);
32 ao_arch_release_interrupts();
35 #define LPC_IAP_PREPARE_WRITE 50
36 #define LPC_IAP_COPY_RAM_TO_FLASH 51
37 #define LPC_IAP_ERASE_SECTOR 52
38 #define LPC_IAP_BLANK_CHECK 53
39 #define LPC_IAP_READ_PART_ID 54
40 #define LPC_IAP_READ_BOOT_CODE_VERSION 55
41 #define LPC_IAP_COMPARE 56
42 #define LPC_IAP_REINVOKE_ISP 57
43 #define LPC_IAP_READ_UID 58
44 #define LPC_IAP_ERASE_PAGE 59
45 #define LPC_IAP_EEPROM_WRITE 61
46 #define LPC_IAP_EEPROM_READ 62
48 #define LPC_IAP_CMD_SUCCESS 0
49 #define LPC_IAP_INVALID_COMMAND 1
50 #define LPC_IAP_SRC_ADDR_ERROR 2
51 #define LPC_IAP_DST_ADDR_ERROR 3
52 #define LPC_IAP_SRC_ADDR_NOT_MAPPED 4
53 #define LPC_IAP_DST_ADDR_NOT_MAPPED 5
54 #define LPC_IAP_COUNT_ERROR 6
55 #define LPC_IAP_INVALID_SECTOR 7
56 #define LPC_IAP_SECTOR_NOT_BLANK 8
57 #define LPC_IAP_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 9
58 #define LPC_IAP_COMPARE_ERROR 10
59 #define LPC_IAP_BUSY 11
60 #define LPC_IAP_PARAM_ERROR 12
61 #define LPC_IAP_ADDR_ERROR 13
62 #define LPC_IAP_ADDR_NOT_MAPPED 14
63 #define LPC_IAP_CMD_LOCKED 15
64 #define LPC_IAP_INVALID_CODE 16
65 #define LPC_IAP_INVALID_BAUD_RATE 17
66 #define LPC_IAP_INVALID_STOP_BIT 18
67 #define LPC_IAP_CODE_READ_PROTECTION_ENABLED 19
69 #define LPC_FLASH_BASE ((uint8_t *) 0x0)
70 #define LPC_FLASH_SECTOR 4096
71 #define LPC_FLASH_SECTOR_MASK (LPC_FLASH_SECTOR - 1)
72 #define LPC_FLASH_SECTOR_SHIFT 12
74 static uint32_t iap_in[5], iap_out[5];
79 ao_lpc_addr_to_sector(uint8_t *addr)
81 uint32_t off = (uint32_t) (addr - LPC_FLASH_BASE);
83 return off >> LPC_FLASH_SECTOR_SHIFT;
87 ao_lpc_addr_is_sector_aligned(uint8_t *addr)
89 uint32_t off = (uint32_t) (addr - LPC_FLASH_BASE);
90 return (off & LPC_FLASH_SECTOR_MASK) == 0;
94 ao_lpc_prepare_write(uint32_t start_sector, uint32_t end_sector)
96 iap_in[0] = LPC_IAP_PREPARE_WRITE;
97 iap_in[1] = start_sector;
98 iap_in[2] = end_sector;
104 ao_lpc_copy_ram_to_flash(uint8_t *dst, uint8_t *src, uint32_t len, uint32_t freq)
106 iap_in[0] = LPC_IAP_COPY_RAM_TO_FLASH;
107 iap_in[1] = (uint32_t) dst;
108 iap_in[2] = (uint32_t) src;
116 ao_lpc_erase_sector(uint32_t start_sector, uint32_t end_sector, uint32_t freq)
118 iap_in[0] = LPC_IAP_ERASE_SECTOR;
119 iap_in[1] = start_sector;
120 iap_in[2] = end_sector;
127 ao_lpc_read_part_id(void)
129 iap_in[0] = LPC_IAP_READ_PART_ID;
135 ao_flash_erase_page(uint8_t *page)
137 uint32_t ret = LPC_IAP_CMD_SUCCESS;
138 if (ao_lpc_addr_is_sector_aligned(page)) {
139 uint32_t sector = ao_lpc_addr_to_sector(page);
140 ret = ao_lpc_prepare_write(sector, sector);
141 if (ret == LPC_IAP_CMD_SUCCESS)
142 ret = ao_lpc_erase_sector(sector, sector, AO_LPC_SYSCLK / 1000);
148 ao_flash_page(uint8_t *page, uint8_t *src)
150 uint32_t sector = ao_lpc_addr_to_sector(page);
153 ret = ao_flash_erase_page(page);
154 if (ret != LPC_IAP_CMD_SUCCESS)
156 ret = ao_lpc_prepare_write(sector, sector);
157 if (ret != LPC_IAP_CMD_SUCCESS)
159 ret = ao_lpc_copy_ram_to_flash(page, src, 256, AO_LPC_SYSCLK / 1000);
172 ao_eeprom_write(ao_pos_t pos, void *v, uint16_t len)
174 iap_in[0] = LPC_IAP_EEPROM_WRITE;
175 iap_in[1] = (uint32_t) pos;
176 iap_in[2] = (uint32_t) v;
177 iap_in[3] = (uint32_t) len;
178 iap_in[4] = AO_LPC_SYSCLK / 1000;
180 return iap_out[0] == LPC_IAP_CMD_SUCCESS;
187 ao_eeprom_read(ao_pos_t pos, void *v, uint16_t len)
189 iap_in[0] = LPC_IAP_EEPROM_READ;
190 iap_in[1] = (uint32_t) pos;
191 iap_in[2] = (uint32_t) v;
192 iap_in[3] = (uint32_t) len;
193 iap_in[4] = AO_LPC_SYSCLK / 1000;
195 return iap_out[0] == LPC_IAP_CMD_SUCCESS;
201 /* Nothing to do here */