]>
Commit | Line | Data |
---|---|---|
2abbe075 WD |
1 | /* LowLevel function for ATMEL DataFlash support |
2 | * Author : Hamid Ikdoumi (Atmel) | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License as | |
6 | * published by the Free Software Foundation; either version 2 of | |
7 | * the License, or (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program; if not, write to the Free Software | |
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
17 | * MA 02111-1307 USA | |
18 | * | |
19 | */ | |
20 | #include <common.h> | |
21 | #include <config.h> | |
22 | #ifdef CONFIG_HAS_DATAFLASH | |
23 | #include <asm/hardware.h> | |
24 | #include <dataflash.h> | |
25 | ||
26 | AT91S_DATAFLASH_INFO dataflash_info[CFG_MAX_DATAFLASH_BANKS]; | |
27 | static AT91S_DataFlash DataFlashInst; | |
28 | ||
29 | int cs[][CFG_MAX_DATAFLASH_BANKS] = { | |
30 | {CFG_DATAFLASH_LOGIC_ADDR_CS0, 0}, /* Logical adress, CS */ | |
31 | {CFG_DATAFLASH_LOGIC_ADDR_CS3, 3} | |
32 | }; | |
33 | ||
5779d8d9 WD |
34 | /*define the area offsets*/ |
35 | dataflash_protect_t area_list[NB_DATAFLASH_AREA] = { | |
36 | {0, 0x7fff, FLAG_PROTECT_SET}, /* ROM code */ | |
37 | {0x8000, 0x1ffff, FLAG_PROTECT_SET}, /* u-boot code */ | |
38 | {0x20000, 0x27fff, FLAG_PROTECT_CLEAR}, /* u-boot environment */ | |
39 | {0x28000, 0x1fffff, FLAG_PROTECT_CLEAR}, /* data area size to tune */ | |
40 | }; | |
41 | ||
2abbe075 WD |
42 | extern void AT91F_SpiInit (void); |
43 | extern int AT91F_DataflashProbe (int i, AT91PS_DataflashDesc pDesc); | |
44 | extern int AT91F_DataFlashRead (AT91PS_DataFlash pDataFlash, | |
45 | unsigned long addr, | |
46 | unsigned long size, char *buffer); | |
5779d8d9 WD |
47 | extern int AT91F_DataFlashWrite( AT91PS_DataFlash pDataFlash, |
48 | unsigned char *src, | |
49 | int dest, | |
50 | int size ); | |
2abbe075 WD |
51 | |
52 | int AT91F_DataflashInit (void) | |
53 | { | |
54 | int i, j; | |
55 | int dfcode; | |
56 | ||
57 | AT91F_SpiInit (); | |
58 | ||
59 | for (i = 0; i < CFG_MAX_DATAFLASH_BANKS; i++) { | |
5779d8d9 | 60 | dataflash_info[i].Desc.state = IDLE; |
2abbe075 WD |
61 | dataflash_info[i].id = 0; |
62 | dataflash_info[i].Device.pages_number = 0; | |
63 | dfcode = AT91F_DataflashProbe (cs[i][1], &dataflash_info[i].Desc); | |
64 | ||
65 | switch (dfcode) { | |
66 | case AT45DB161: | |
67 | dataflash_info[i].Device.pages_number = 4096; | |
68 | dataflash_info[i].Device.pages_size = 528; | |
69 | dataflash_info[i].Device.page_offset = 10; | |
70 | dataflash_info[i].Device.byte_mask = 0x300; | |
71 | dataflash_info[i].Device.cs = cs[i][1]; | |
72 | dataflash_info[i].Desc.DataFlash_state = IDLE; | |
73 | dataflash_info[i].logical_address = cs[i][0]; | |
74 | dataflash_info[i].id = dfcode; | |
75 | break; | |
76 | ||
77 | case AT45DB321: | |
78 | dataflash_info[i].Device.pages_number = 8192; | |
79 | dataflash_info[i].Device.pages_size = 528; | |
80 | dataflash_info[i].Device.page_offset = 10; | |
81 | dataflash_info[i].Device.byte_mask = 0x300; | |
82 | dataflash_info[i].Device.cs = cs[i][1]; | |
83 | dataflash_info[i].Desc.DataFlash_state = IDLE; | |
84 | dataflash_info[i].logical_address = cs[i][0]; | |
85 | dataflash_info[i].id = dfcode; | |
86 | break; | |
87 | ||
88 | case AT45DB642: | |
89 | dataflash_info[i].Device.pages_number = 8192; | |
90 | dataflash_info[i].Device.pages_size = 1056; | |
91 | dataflash_info[i].Device.page_offset = 11; | |
92 | dataflash_info[i].Device.byte_mask = 0x700; | |
93 | dataflash_info[i].Device.cs = cs[i][1]; | |
94 | dataflash_info[i].Desc.DataFlash_state = IDLE; | |
95 | dataflash_info[i].logical_address = cs[i][0]; | |
96 | dataflash_info[i].id = dfcode; | |
97 | break; | |
5779d8d9 WD |
98 | case AT45DB128: |
99 | dataflash_info[i].Device.pages_number = 16384; | |
100 | dataflash_info[i].Device.pages_size = 1056; | |
101 | dataflash_info[i].Device.page_offset = 11; | |
102 | dataflash_info[i].Device.byte_mask = 0x700; | |
103 | dataflash_info[i].Device.cs = cs[i][1]; | |
104 | dataflash_info[i].Desc.DataFlash_state = IDLE; | |
105 | dataflash_info[i].logical_address = cs[i][0]; | |
106 | dataflash_info[i].id = dfcode; | |
107 | break; | |
2abbe075 WD |
108 | |
109 | default: | |
110 | break; | |
111 | } | |
5779d8d9 WD |
112 | /* set the last area end to the dataflash size*/ |
113 | area_list[NB_DATAFLASH_AREA -1].end = | |
114 | (dataflash_info[i].Device.pages_number * | |
115 | dataflash_info[i].Device.pages_size)-1; | |
116 | ||
117 | /* set the area addresses */ | |
118 | for(j = 0; j<NB_DATAFLASH_AREA; j++) { | |
119 | dataflash_info[i].Device.area_list[j].start = area_list[j].start + dataflash_info[i].logical_address; | |
120 | dataflash_info[i].Device.area_list[j].end = area_list[j].end + dataflash_info[i].logical_address; | |
121 | dataflash_info[i].Device.area_list[j].protected = area_list[j].protected; | |
122 | } | |
2abbe075 WD |
123 | } |
124 | return (1); | |
125 | } | |
126 | ||
127 | ||
2abbe075 WD |
128 | void dataflash_print_info (void) |
129 | { | |
5779d8d9 | 130 | int i, j; |
2abbe075 WD |
131 | |
132 | for (i = 0; i < CFG_MAX_DATAFLASH_BANKS; i++) { | |
133 | if (dataflash_info[i].id != 0) { | |
134 | printf ("DataFlash:"); | |
135 | switch (dataflash_info[i].id) { | |
136 | case AT45DB161: | |
137 | printf ("AT45DB161\n"); | |
138 | break; | |
139 | ||
140 | case AT45DB321: | |
141 | printf ("AT45DB321\n"); | |
142 | break; | |
143 | ||
144 | case AT45DB642: | |
145 | printf ("AT45DB642\n"); | |
146 | break; | |
5779d8d9 WD |
147 | case AT45DB128: |
148 | printf ("AT45DB128\n"); | |
149 | break; | |
2abbe075 WD |
150 | } |
151 | ||
152 | printf ("Nb pages: %6d\n" | |
153 | "Page Size: %6d\n" | |
154 | "Size=%8d bytes\n" | |
155 | "Logical address: 0x%08X\n", | |
156 | (unsigned int) dataflash_info[i].Device.pages_number, | |
157 | (unsigned int) dataflash_info[i].Device.pages_size, | |
158 | (unsigned int) dataflash_info[i].Device.pages_number * | |
159 | dataflash_info[i].Device.pages_size, | |
160 | (unsigned int) dataflash_info[i].logical_address); | |
5779d8d9 | 161 | for (j=0; j< NB_DATAFLASH_AREA; j++) { |
c935d3bd | 162 | printf ("Area %i:\t%08lX to %08lX %s\n", j, |
5779d8d9 WD |
163 | dataflash_info[i].Device.area_list[j].start, |
164 | dataflash_info[i].Device.area_list[j].end, | |
165 | (dataflash_info[i].Device.area_list[j].protected == | |
166 | FLAG_PROTECT_SET) ? "(RO)" : ""); | |
167 | } | |
2abbe075 WD |
168 | } |
169 | } | |
170 | } | |
171 | ||
172 | ||
173 | /*------------------------------------------------------------------------------*/ | |
174 | /* Function Name : AT91F_DataflashSelect */ | |
175 | /* Object : Select the correct device */ | |
176 | /*------------------------------------------------------------------------------*/ | |
d52fb7e3 | 177 | AT91PS_DataFlash AT91F_DataflashSelect (AT91PS_DataFlash pFlash, unsigned long *addr) |
2abbe075 WD |
178 | { |
179 | char addr_valid = 0; | |
180 | int i; | |
181 | ||
182 | for (i = 0; i < CFG_MAX_DATAFLASH_BANKS; i++) | |
183 | if ((*addr & 0xFF000000) == dataflash_info[i].logical_address) { | |
184 | addr_valid = 1; | |
185 | break; | |
186 | } | |
187 | if (!addr_valid) { | |
188 | pFlash = (AT91PS_DataFlash) 0; | |
189 | return pFlash; | |
190 | } | |
191 | pFlash->pDataFlashDesc = &(dataflash_info[i].Desc); | |
192 | pFlash->pDevice = &(dataflash_info[i].Device); | |
193 | *addr -= dataflash_info[i].logical_address; | |
194 | return (pFlash); | |
195 | } | |
196 | ||
197 | /*------------------------------------------------------------------------------*/ | |
198 | /* Function Name : addr_dataflash */ | |
199 | /* Object : Test if address is valid */ | |
200 | /*------------------------------------------------------------------------------*/ | |
201 | int addr_dataflash (unsigned long addr) | |
202 | { | |
203 | int addr_valid = 0; | |
204 | int i; | |
205 | ||
206 | for (i = 0; i < CFG_MAX_DATAFLASH_BANKS; i++) { | |
207 | if ((((int) addr) & 0xFF000000) == | |
208 | dataflash_info[i].logical_address) { | |
209 | addr_valid = 1; | |
210 | break; | |
211 | } | |
212 | } | |
213 | ||
214 | return addr_valid; | |
215 | } | |
5779d8d9 WD |
216 | /*-----------------------------------------------------------------------------*/ |
217 | /* Function Name : size_dataflash */ | |
218 | /* Object : Test if address is valid regarding the size */ | |
219 | /*-----------------------------------------------------------------------------*/ | |
220 | int size_dataflash (AT91PS_DataFlash pdataFlash, unsigned long addr, unsigned long size) | |
221 | { | |
222 | /* is outside the dataflash */ | |
223 | if (((int)addr & 0x0FFFFFFF) > (pdataFlash->pDevice->pages_size * | |
224 | pdataFlash->pDevice->pages_number)) return 0; | |
225 | /* is too large for the dataflash */ | |
226 | if (size > ((pdataFlash->pDevice->pages_size * | |
227 | pdataFlash->pDevice->pages_number) - ((int)addr & 0x0FFFFFFF))) return 0; | |
228 | ||
229 | return 1; | |
230 | } | |
231 | /*-----------------------------------------------------------------------------*/ | |
232 | /* Function Name : prot_dataflash */ | |
233 | /* Object : Test if destination area is protected */ | |
234 | /*-----------------------------------------------------------------------------*/ | |
235 | int prot_dataflash (AT91PS_DataFlash pdataFlash, unsigned long addr) | |
236 | { | |
237 | int area; | |
238 | /* find area */ | |
239 | for (area=0; area < NB_DATAFLASH_AREA; area++) { | |
240 | if ((addr >= pdataFlash->pDevice->area_list[area].start) && | |
241 | (addr < pdataFlash->pDevice->area_list[area].end)) | |
242 | break; | |
243 | } | |
244 | if (area == NB_DATAFLASH_AREA) return -1; | |
245 | /*test protection value*/ | |
246 | if (pdataFlash->pDevice->area_list[area].protected == FLAG_PROTECT_SET) return 0; | |
247 | ||
248 | return 1; | |
249 | } | |
250 | /*-----------------------------------------------------------------------------*/ | |
251 | /* Function Name : dataflash_real_protect */ | |
252 | /* Object : protect/unprotect area */ | |
253 | /*-----------------------------------------------------------------------------*/ | |
254 | int dataflash_real_protect (int flag, unsigned long start_addr, unsigned long end_addr) | |
255 | { | |
256 | int i,j, area1, area2, addr_valid = 0; | |
257 | /* find dataflash */ | |
258 | for (i = 0; i < CFG_MAX_DATAFLASH_BANKS; i++) { | |
259 | if ((((int) start_addr) & 0xF0000000) == | |
260 | dataflash_info[i].logical_address) { | |
261 | addr_valid = 1; | |
262 | break; | |
263 | } | |
264 | } | |
265 | if (!addr_valid) { | |
266 | return -1; | |
267 | } | |
268 | /* find start area */ | |
269 | for (area1=0; area1 < NB_DATAFLASH_AREA; area1++) { | |
270 | if (start_addr == dataflash_info[i].Device.area_list[area1].start) break; | |
271 | } | |
272 | if (area1 == NB_DATAFLASH_AREA) return -1; | |
273 | /* find end area */ | |
274 | for (area2=0; area2 < NB_DATAFLASH_AREA; area2++) { | |
275 | if (end_addr == dataflash_info[i].Device.area_list[area2].end) break; | |
276 | } | |
277 | if (area2 == NB_DATAFLASH_AREA) return -1; | |
278 | ||
279 | /*set protection value*/ | |
280 | for(j = area1; j < area2+1 ; j++) | |
281 | if (flag == 0) dataflash_info[i].Device.area_list[j].protected = FLAG_PROTECT_CLEAR; | |
282 | else dataflash_info[i].Device.area_list[j].protected = FLAG_PROTECT_SET; | |
283 | ||
284 | return (area2-area1+1); | |
285 | } | |
2abbe075 WD |
286 | |
287 | /*------------------------------------------------------------------------------*/ | |
288 | /* Function Name : read_dataflash */ | |
289 | /* Object : dataflash memory read */ | |
290 | /*------------------------------------------------------------------------------*/ | |
291 | int read_dataflash (unsigned long addr, unsigned long size, char *result) | |
292 | { | |
d52fb7e3 | 293 | unsigned long AddrToRead = addr; |
2abbe075 WD |
294 | AT91PS_DataFlash pFlash = &DataFlashInst; |
295 | ||
296 | pFlash = AT91F_DataflashSelect (pFlash, &AddrToRead); | |
5779d8d9 | 297 | |
2abbe075 | 298 | if (pFlash == 0) |
5779d8d9 WD |
299 | return ERR_UNKNOWN_FLASH_TYPE; |
300 | ||
301 | if (size_dataflash(pFlash,addr,size) == 0) | |
302 | return ERR_INVAL; | |
2abbe075 WD |
303 | |
304 | return (AT91F_DataFlashRead (pFlash, AddrToRead, size, result)); | |
305 | } | |
306 | ||
307 | ||
308 | /*-----------------------------------------------------------------------------*/ | |
309 | /* Function Name : write_dataflash */ | |
310 | /* Object : write a block in dataflash */ | |
311 | /*-----------------------------------------------------------------------------*/ | |
312 | int write_dataflash (unsigned long addr_dest, unsigned long addr_src, | |
313 | unsigned long size) | |
314 | { | |
d52fb7e3 | 315 | unsigned long AddrToWrite = addr_dest; |
2abbe075 WD |
316 | AT91PS_DataFlash pFlash = &DataFlashInst; |
317 | ||
318 | pFlash = AT91F_DataflashSelect (pFlash, &AddrToWrite); | |
5779d8d9 WD |
319 | |
320 | if (pFlash == 0) | |
321 | return ERR_UNKNOWN_FLASH_TYPE; | |
322 | ||
323 | if (size_dataflash(pFlash,addr_dest,size) == 0) | |
324 | return ERR_INVAL; | |
325 | ||
326 | if (prot_dataflash(pFlash,addr_dest) == 0) | |
327 | return ERR_PROTECTED; | |
328 | ||
2abbe075 WD |
329 | if (AddrToWrite == -1) |
330 | return -1; | |
331 | ||
d52fb7e3 | 332 | return AT91F_DataFlashWrite (pFlash, (uchar *)addr_src, AddrToWrite, size); |
2abbe075 WD |
333 | } |
334 | ||
335 | ||
336 | void dataflash_perror (int err) | |
337 | { | |
338 | switch (err) { | |
339 | case ERR_OK: | |
340 | break; | |
341 | case ERR_TIMOUT: | |
342 | printf ("Timeout writing to DataFlash\n"); | |
343 | break; | |
344 | case ERR_PROTECTED: | |
345 | printf ("Can't write to protected DataFlash sectors\n"); | |
346 | break; | |
347 | case ERR_INVAL: | |
348 | printf ("Outside available DataFlash\n"); | |
349 | break; | |
350 | case ERR_UNKNOWN_FLASH_TYPE: | |
351 | printf ("Unknown Type of DataFlash\n"); | |
352 | break; | |
353 | case ERR_PROG_ERROR: | |
354 | printf ("General DataFlash Programming Error\n"); | |
355 | break; | |
356 | default: | |
357 | printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err); | |
358 | break; | |
359 | } | |
360 | } | |
361 | ||
362 | #endif |