]>
Commit | Line | Data |
---|---|---|
0eb5717a HCE |
1 | /* |
2 | * Copyright (C) 2008 Atmel Corporation | |
3 | * | |
4 | * See file CREDITS for list of people who contributed to this project. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the Free | |
8 | * Software Foundation; either version 2 of the License, or (at your option) | |
9 | * any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along with | |
17 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
18 | * Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
20 | #include <common.h> | |
21 | ||
22 | #ifdef CONFIG_FAVR32_EZKIT_EXT_FLASH | |
23 | #include <asm/cacheflush.h> | |
24 | #include <asm/io.h> | |
25 | #include <asm/sections.h> | |
26 | ||
27 | DECLARE_GLOBAL_DATA_PTR; | |
28 | ||
29 | flash_info_t flash_info[1]; | |
30 | ||
31 | static void flash_identify(uint16_t *flash, flash_info_t *info) | |
32 | { | |
33 | unsigned long flags; | |
34 | ||
35 | flags = disable_interrupts(); | |
36 | ||
37 | dcache_flush_unlocked(); | |
38 | ||
39 | writew(0xaa, flash + 0x555); | |
40 | writew(0x55, flash + 0xaaa); | |
41 | writew(0x90, flash + 0x555); | |
42 | info->flash_id = readl(flash); | |
43 | writew(0xff, flash); | |
44 | ||
45 | readw(flash); | |
46 | ||
47 | if (flags) | |
48 | enable_interrupts(); | |
49 | } | |
50 | ||
51 | unsigned long flash_init(void) | |
52 | { | |
53 | unsigned long addr; | |
54 | unsigned int i; | |
55 | ||
6d0f6bcf | 56 | flash_info[0].size = CONFIG_SYS_FLASH_SIZE; |
0eb5717a HCE |
57 | flash_info[0].sector_count = 135; |
58 | ||
6d0f6bcf | 59 | flash_identify(uncached((void *)CONFIG_SYS_FLASH_BASE), &flash_info[0]); |
0eb5717a HCE |
60 | |
61 | for (i = 0, addr = 0; i < 8; i++, addr += 0x2000) | |
62 | flash_info[0].start[i] = addr; | |
63 | for (; i < flash_info[0].sector_count; i++, addr += 0x10000) | |
64 | flash_info[0].start[i] = addr; | |
65 | ||
6d0f6bcf | 66 | return CONFIG_SYS_FLASH_SIZE; |
0eb5717a HCE |
67 | } |
68 | ||
69 | void flash_print_info(flash_info_t *info) | |
70 | { | |
25da0b84 | 71 | printf("Flash: Vendor ID: 0x%02lx, Product ID: 0x%02lx\n", |
0eb5717a HCE |
72 | info->flash_id >> 16, info->flash_id & 0xffff); |
73 | printf("Size: %ld MB in %d sectors\n", | |
74 | info->size >> 10, info->sector_count); | |
75 | } | |
76 | ||
77 | int flash_erase(flash_info_t *info, int s_first, int s_last) | |
78 | { | |
79 | unsigned long flags; | |
80 | unsigned long start_time; | |
81 | uint16_t *fb, *sb; | |
82 | unsigned int i; | |
83 | int ret; | |
84 | uint16_t status; | |
85 | ||
86 | if ((s_first < 0) || (s_first > s_last) | |
87 | || (s_last >= info->sector_count)) { | |
88 | puts("Error: first and/or last sector out of range\n"); | |
89 | return ERR_INVAL; | |
90 | } | |
91 | ||
92 | for (i = s_first; i < s_last; i++) | |
93 | if (info->protect[i]) { | |
94 | printf("Error: sector %d is protected\n", i); | |
95 | return ERR_PROTECTED; | |
96 | } | |
97 | ||
98 | fb = (uint16_t *)uncached(info->start[0]); | |
99 | ||
100 | dcache_flush_unlocked(); | |
101 | ||
102 | for (i = s_first; (i <= s_last) && !ctrlc(); i++) { | |
103 | printf("Erasing sector %3d...", i); | |
104 | ||
105 | sb = (uint16_t *)uncached(info->start[i]); | |
106 | ||
107 | flags = disable_interrupts(); | |
108 | ||
109 | start_time = get_timer(0); | |
110 | ||
111 | /* Unlock sector */ | |
112 | writew(0xaa, fb + 0x555); | |
113 | writew(0x70, sb); | |
114 | ||
115 | /* Erase sector */ | |
116 | writew(0xaa, fb + 0x555); | |
117 | writew(0x55, fb + 0xaaa); | |
118 | writew(0x80, fb + 0x555); | |
119 | writew(0xaa, fb + 0x555); | |
120 | writew(0x55, fb + 0xaaa); | |
121 | writew(0x30, sb); | |
122 | ||
123 | /* Wait for completion */ | |
124 | ret = ERR_OK; | |
125 | do { | |
126 | /* TODO: Timeout */ | |
127 | status = readw(sb); | |
128 | } while ((status != 0xffff) && !(status & 0x28)); | |
129 | ||
130 | writew(0xf0, fb); | |
131 | ||
132 | /* | |
133 | * Make sure the command actually makes it to the bus | |
134 | * before we re-enable interrupts. | |
135 | */ | |
136 | readw(fb); | |
137 | ||
138 | if (flags) | |
139 | enable_interrupts(); | |
140 | ||
141 | if (status != 0xffff) { | |
142 | printf("Flash erase error at address 0x%p: 0x%02x\n", | |
143 | sb, status); | |
144 | ret = ERR_PROG_ERROR; | |
145 | break; | |
146 | } | |
147 | } | |
148 | ||
149 | if (ctrlc()) | |
150 | printf("User interrupt!\n"); | |
151 | ||
152 | return ERR_OK; | |
153 | } | |
154 | ||
155 | int write_buff(flash_info_t *info, uchar *src, | |
156 | ulong addr, ulong count) | |
157 | { | |
158 | unsigned long flags; | |
159 | uint16_t *base, *p, *s, *end; | |
160 | uint16_t word, status, status1; | |
161 | int ret = ERR_OK; | |
162 | ||
163 | if (addr < info->start[0] | |
164 | || (addr + count) > (info->start[0] + info->size) | |
165 | || (addr + count) < addr) { | |
166 | puts("Error: invalid address range\n"); | |
167 | return ERR_INVAL; | |
168 | } | |
169 | ||
170 | if (addr & 1 || count & 1 || (unsigned int)src & 1) { | |
171 | puts("Error: misaligned source, destination or count\n"); | |
172 | return ERR_ALIGN; | |
173 | } | |
174 | ||
175 | base = (uint16_t *)uncached(info->start[0]); | |
176 | end = (uint16_t *)uncached(addr + count); | |
177 | ||
178 | flags = disable_interrupts(); | |
179 | ||
180 | dcache_flush_unlocked(); | |
181 | sync_write_buffer(); | |
182 | ||
183 | for (p = (uint16_t *)uncached(addr), s = (uint16_t *)src; | |
184 | p < end && !ctrlc(); p++, s++) { | |
185 | word = *s; | |
186 | ||
187 | writew(0xaa, base + 0x555); | |
188 | writew(0x55, base + 0xaaa); | |
189 | writew(0xa0, base + 0x555); | |
190 | writew(word, p); | |
191 | ||
192 | sync_write_buffer(); | |
193 | ||
194 | /* Wait for completion */ | |
195 | status1 = readw(p); | |
196 | do { | |
197 | /* TODO: Timeout */ | |
198 | status = status1; | |
199 | status1 = readw(p); | |
200 | } while (((status ^ status1) & 0x40) /* toggled */ | |
201 | && !(status1 & 0x28)); /* error bits */ | |
202 | ||
203 | /* | |
204 | * We'll need to check once again for toggle bit | |
205 | * because the toggle bit may stop toggling as I/O5 | |
206 | * changes to "1" (ref at49bv642.pdf p9) | |
207 | */ | |
208 | status1 = readw(p); | |
209 | status = readw(p); | |
210 | if ((status ^ status1) & 0x40) { | |
211 | printf("Flash write error at address 0x%p: " | |
212 | "0x%02x != 0x%02x\n", | |
213 | p, status,word); | |
214 | ret = ERR_PROG_ERROR; | |
215 | writew(0xf0, base); | |
216 | readw(base); | |
217 | break; | |
218 | } | |
219 | ||
220 | writew(0xf0, base); | |
221 | readw(base); | |
222 | } | |
223 | ||
224 | if (flags) | |
225 | enable_interrupts(); | |
226 | ||
227 | return ret; | |
228 | } | |
229 | ||
230 | #endif /* CONFIG_FAVR32_EZKIT_EXT_FLASH */ |