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