Merge branch 'evk1100-prep' into next
[oweals/u-boot.git] / board / earthlcd / favr-32-ezkit / flash.c
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/arch/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
56         flash_info[0].size = CONFIG_SYS_FLASH_SIZE;
57         flash_info[0].sector_count = 135;
58
59         flash_identify(uncached((void *)CONFIG_SYS_FLASH_BASE), &flash_info[0]);
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
66         return CONFIG_SYS_FLASH_SIZE;
67 }
68
69 void flash_print_info(flash_info_t *info)
70 {
71         printf("Flash: Vendor ID: 0x%02lx, Product ID: 0x%02lx\n",
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 */