]>
Commit | Line | Data |
---|---|---|
160131bf PP |
1 | /* |
2 | * (C) Copyright 2006 Embedded Artists AB <www.embeddedartists.com> | |
3 | * | |
4 | * Modified to remove all but the IAP-command related code by | |
5 | * Gary Jennejohn <garyj@denx.de> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License as | |
9 | * published by the Free Software Foundation; either version 2 of | |
10 | * the License, or (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
20 | * MA 02111-1307 USA | |
21 | */ | |
22 | ||
23 | #include <common.h> | |
24 | #include <asm/arch/hardware.h> | |
25 | ||
26 | /* IAP commands use 32 bytes at the top of CPU internal sram, we | |
27 | use 512 bytes below that */ | |
28 | #define COPY_BUFFER_LOCATION 0x40003de0 | |
29 | ||
30 | #define IAP_LOCATION 0x7ffffff1 | |
31 | #define IAP_CMD_PREPARE 50 | |
32 | #define IAP_CMD_COPY 51 | |
33 | #define IAP_CMD_ERASE 52 | |
34 | #define IAP_CMD_CHECK 53 | |
35 | #define IAP_CMD_ID 54 | |
36 | #define IAP_CMD_VERSION 55 | |
37 | #define IAP_CMD_COMPARE 56 | |
38 | ||
39 | #define IAP_RET_CMD_SUCCESS 0 | |
40 | ||
41 | static unsigned long command[5]; | |
42 | static unsigned long result[2]; | |
43 | ||
44 | extern void iap_entry(unsigned long * command, unsigned long * result); | |
45 | ||
46 | /*----------------------------------------------------------------------- | |
47 | * | |
48 | */ | |
49 | static int get_flash_sector(flash_info_t * info, ulong flash_addr) | |
50 | { | |
51 | int i; | |
52 | ||
53 | for(i = 1; i < (info->sector_count); i++) { | |
54 | if (flash_addr < (info->start[i])) | |
55 | break; | |
56 | } | |
57 | ||
58 | return (i-1); | |
59 | } | |
60 | ||
61 | /*----------------------------------------------------------------------- | |
62 | * This function assumes that flash_addr is aligned on 512 bytes boundary | |
63 | * in flash. This function also assumes that prepare have been called | |
64 | * for the sector in question. | |
65 | */ | |
66 | int lpc2292_copy_buffer_to_flash(flash_info_t * info, ulong flash_addr) | |
67 | { | |
68 | int first_sector; | |
69 | int last_sector; | |
70 | ||
71 | first_sector = get_flash_sector(info, flash_addr); | |
72 | last_sector = get_flash_sector(info, flash_addr + 512 - 1); | |
73 | ||
74 | /* prepare sectors for write */ | |
75 | command[0] = IAP_CMD_PREPARE; | |
76 | command[1] = first_sector; | |
77 | command[2] = last_sector; | |
78 | iap_entry(command, result); | |
79 | if (result[0] != IAP_RET_CMD_SUCCESS) { | |
80 | printf("IAP prepare failed\n"); | |
81 | return ERR_PROG_ERROR; | |
82 | } | |
83 | ||
84 | command[0] = IAP_CMD_COPY; | |
85 | command[1] = flash_addr; | |
86 | command[2] = COPY_BUFFER_LOCATION; | |
87 | command[3] = 512; | |
6d0f6bcf | 88 | command[4] = CONFIG_SYS_SYS_CLK_FREQ >> 10; |
160131bf PP |
89 | iap_entry(command, result); |
90 | if (result[0] != IAP_RET_CMD_SUCCESS) { | |
91 | printf("IAP copy failed\n"); | |
92 | return 1; | |
93 | } | |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
98 | /*----------------------------------------------------------------------- | |
99 | */ | |
100 | ||
101 | int lpc2292_flash_erase (flash_info_t * info, int s_first, int s_last) | |
102 | { | |
103 | int flag; | |
104 | int prot; | |
105 | int sect; | |
106 | ||
107 | prot = 0; | |
108 | for (sect = s_first; sect <= s_last; ++sect) { | |
109 | if (info->protect[sect]) { | |
110 | prot++; | |
111 | } | |
112 | } | |
113 | if (prot) | |
114 | return ERR_PROTECTED; | |
115 | ||
116 | ||
117 | flag = disable_interrupts(); | |
118 | ||
119 | printf ("Erasing %d sectors starting at sector %2d.\n" | |
120 | "This make take some time ... ", | |
121 | s_last - s_first + 1, s_first); | |
122 | ||
123 | command[0] = IAP_CMD_PREPARE; | |
124 | command[1] = s_first; | |
125 | command[2] = s_last; | |
126 | iap_entry(command, result); | |
127 | if (result[0] != IAP_RET_CMD_SUCCESS) { | |
128 | printf("IAP prepare failed\n"); | |
129 | return ERR_PROTECTED; | |
130 | } | |
131 | ||
132 | command[0] = IAP_CMD_ERASE; | |
133 | command[1] = s_first; | |
134 | command[2] = s_last; | |
6d0f6bcf | 135 | command[3] = CONFIG_SYS_SYS_CLK_FREQ >> 10; |
160131bf PP |
136 | iap_entry(command, result); |
137 | if (result[0] != IAP_RET_CMD_SUCCESS) { | |
138 | printf("IAP erase failed\n"); | |
139 | return ERR_PROTECTED; | |
140 | } | |
141 | ||
142 | if (flag) | |
143 | enable_interrupts(); | |
144 | ||
145 | return ERR_OK; | |
146 | } | |
147 | ||
148 | int lpc2292_write_buff (flash_info_t * info, uchar * src, ulong addr, | |
149 | ulong cnt) | |
150 | { | |
151 | int first_copy_size; | |
152 | int last_copy_size; | |
153 | int first_block; | |
154 | int last_block; | |
155 | int nbr_mid_blocks; | |
156 | uchar memmap_value; | |
157 | ulong i; | |
158 | uchar* src_org; | |
159 | uchar* dst_org; | |
160 | int ret = ERR_OK; | |
161 | ||
162 | src_org = src; | |
163 | dst_org = (uchar*)addr; | |
164 | ||
165 | first_block = addr / 512; | |
166 | last_block = (addr + cnt) / 512; | |
167 | nbr_mid_blocks = last_block - first_block - 1; | |
168 | ||
169 | first_copy_size = 512 - (addr % 512); | |
170 | last_copy_size = (addr + cnt) % 512; | |
171 | ||
172 | debug("\ncopy first block: (1) %lX -> %lX 0x200 bytes, " | |
173 | "(2) %lX -> %lX 0x%X bytes, (3) %lX -> %lX 0x200 bytes\n", | |
174 | (ulong)(first_block * 512), | |
175 | (ulong)COPY_BUFFER_LOCATION, | |
176 | (ulong)src, | |
177 | (ulong)(COPY_BUFFER_LOCATION + 512 - first_copy_size), | |
178 | first_copy_size, | |
179 | (ulong)COPY_BUFFER_LOCATION, | |
180 | (ulong)(first_block * 512)); | |
181 | ||
182 | /* copy first block */ | |
183 | memcpy((void*)COPY_BUFFER_LOCATION, | |
184 | (void*)(first_block * 512), 512); | |
185 | memcpy((void*)(COPY_BUFFER_LOCATION + 512 - first_copy_size), | |
186 | src, first_copy_size); | |
187 | lpc2292_copy_buffer_to_flash(info, first_block * 512); | |
188 | src += first_copy_size; | |
189 | addr += first_copy_size; | |
190 | ||
191 | /* copy middle blocks */ | |
192 | for (i = 0; i < nbr_mid_blocks; i++) { | |
193 | debug("copy middle block: %lX -> %lX 512 bytes, " | |
194 | "%lX -> %lX 512 bytes\n", | |
195 | (ulong)src, | |
196 | (ulong)COPY_BUFFER_LOCATION, | |
197 | (ulong)COPY_BUFFER_LOCATION, | |
198 | (ulong)addr); | |
199 | ||
200 | memcpy((void*)COPY_BUFFER_LOCATION, src, 512); | |
201 | lpc2292_copy_buffer_to_flash(info, addr); | |
202 | src += 512; | |
203 | addr += 512; | |
204 | } | |
205 | ||
206 | ||
207 | if (last_copy_size > 0) { | |
208 | debug("copy last block: (1) %lX -> %lX 0x200 bytes, " | |
209 | "(2) %lX -> %lX 0x%X bytes, (3) %lX -> %lX x200 bytes\n", | |
210 | (ulong)(last_block * 512), | |
211 | (ulong)COPY_BUFFER_LOCATION, | |
212 | (ulong)src, | |
213 | (ulong)(COPY_BUFFER_LOCATION), | |
214 | last_copy_size, | |
215 | (ulong)COPY_BUFFER_LOCATION, | |
216 | (ulong)addr); | |
217 | ||
218 | /* copy last block */ | |
219 | memcpy((void*)COPY_BUFFER_LOCATION, | |
220 | (void*)(last_block * 512), 512); | |
221 | memcpy((void*)COPY_BUFFER_LOCATION, | |
222 | src, last_copy_size); | |
223 | lpc2292_copy_buffer_to_flash(info, addr); | |
224 | } | |
225 | ||
226 | /* verify write */ | |
227 | memmap_value = GET8(MEMMAP); | |
228 | ||
229 | disable_interrupts(); | |
230 | ||
231 | PUT8(MEMMAP, 01); /* we must make sure that initial 64 | |
232 | bytes are taken from flash when we | |
233 | do the compare */ | |
234 | ||
235 | for (i = 0; i < cnt; i++) { | |
236 | if (*dst_org != *src_org){ | |
237 | printf("Write failed. Byte %lX differs\n", i); | |
238 | ret = ERR_PROG_ERROR; | |
239 | break; | |
240 | } | |
241 | dst_org++; | |
242 | src_org++; | |
243 | } | |
244 | ||
245 | PUT8(MEMMAP, memmap_value); | |
246 | enable_interrupts(); | |
247 | ||
248 | return ret; | |
249 | } |