]> git.sur5r.net Git - u-boot/blob - board/atmel/atstk1000/flash.c
Merge with /home/tur/git/u-boot#motionpro
[u-boot] / board / atmel / atstk1000 / flash.c
1 /*
2  * Copyright (C) 2005-2006 Atmel Corporation
3  *
4  * See file CREDITS for list of people who contributed to this
5  * project.
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 #include <common.h>
23
24 #ifdef CONFIG_ATSTK1000_EXT_FLASH
25 #include <asm/cacheflush.h>
26 #include <asm/io.h>
27 #include <asm/sections.h>
28
29 DECLARE_GLOBAL_DATA_PTR;
30
31 flash_info_t flash_info[1];
32
33 static void __flashprog flash_identify(uint16_t *flash, flash_info_t *info)
34 {
35         unsigned long flags;
36
37         flags = disable_interrupts();
38
39         dcache_flush_unlocked();
40
41         writew(0xaa, flash + 0x555);
42         writew(0x55, flash + 0xaaa);
43         writew(0x90, flash + 0x555);
44         info->flash_id = readl(flash);
45         writew(0xff, flash);
46
47         readw(flash);
48
49         if (flags)
50                 enable_interrupts();
51 }
52
53 unsigned long flash_init(void)
54 {
55         unsigned long addr;
56         unsigned int i;
57
58         gd->bd->bi_flashstart = CFG_FLASH_BASE;
59         gd->bd->bi_flashsize = CFG_FLASH_SIZE;
60         gd->bd->bi_flashoffset = _edata - _text;
61
62         flash_info[0].size = CFG_FLASH_SIZE;
63         flash_info[0].sector_count = 135;
64
65         flash_identify(uncached((void *)CFG_FLASH_BASE), &flash_info[0]);
66
67         for (i = 0, addr = 0; i < 8; i++, addr += 0x2000)
68                 flash_info[0].start[i] = addr;
69         for (; i < flash_info[0].sector_count; i++, addr += 0x10000)
70                 flash_info[0].start[i] = addr;
71
72         return CFG_FLASH_SIZE;
73 }
74
75 void flash_print_info(flash_info_t *info)
76 {
77         printf("Flash: Vendor ID: 0x%02x, Product ID: 0x%02x\n",
78                info->flash_id >> 16, info->flash_id & 0xffff);
79         printf("Size: %ld MB in %d sectors\n",
80                info->size >> 10, info->sector_count);
81 }
82
83 int __flashprog flash_erase(flash_info_t *info, int s_first, int s_last)
84 {
85         unsigned long flags;
86         unsigned long start_time;
87         uint16_t *fb, *sb;
88         unsigned int i;
89         int ret;
90         uint16_t status;
91
92         if ((s_first < 0) || (s_first > s_last)
93             || (s_last >= info->sector_count)) {
94                 puts("Error: first and/or last sector out of range\n");
95                 return ERR_INVAL;
96         }
97
98         for (i = s_first; i < s_last; i++)
99                 if (info->protect[i]) {
100                         printf("Error: sector %d is protected\n", i);
101                         return ERR_PROTECTED;
102                 }
103
104         fb = (uint16_t *)uncached(info->start[0]);
105
106         dcache_flush_unlocked();
107
108         for (i = s_first; (i <= s_last) && !ctrlc(); i++) {
109                 printf("Erasing sector %3d...", i);
110
111                 sb = (uint16_t *)uncached(info->start[i]);
112
113                 flags = disable_interrupts();
114
115                 start_time = get_timer(0);
116
117                 /* Unlock sector */
118                 writew(0xaa, fb + 0x555);
119                 writew(0x70, sb);
120
121                 /* Erase sector */
122                 writew(0xaa, fb + 0x555);
123                 writew(0x55, fb + 0xaaa);
124                 writew(0x80, fb + 0x555);
125                 writew(0xaa, fb + 0x555);
126                 writew(0x55, fb + 0xaaa);
127                 writew(0x30, sb);
128
129                 /* Wait for completion */
130                 ret = ERR_OK;
131                 do {
132                         /* TODO: Timeout */
133                         status = readw(sb);
134                 } while ((status != 0xffff) && !(status & 0x28));
135
136                 writew(0xf0, fb);
137
138                 /*
139                  * Make sure the command actually makes it to the bus
140                  * before we re-enable interrupts.
141                  */
142                 readw(fb);
143
144                 if (flags)
145                         enable_interrupts();
146
147                 if (status != 0xffff) {
148                         printf("Flash erase error at address 0x%p: 0x%02x\n",
149                                sb, status);
150                         ret = ERR_PROG_ERROR;
151                         break;
152                 }
153         }
154
155         if (ctrlc())
156                 printf("User interrupt!\n");
157
158         return ERR_OK;
159 }
160
161 int __flashprog write_buff(flash_info_t *info, uchar *src,
162                            ulong addr, ulong count)
163 {
164         unsigned long flags;
165         uint16_t *base, *p, *s, *end;
166         uint16_t word, status;
167         int ret = ERR_OK;
168
169         if (addr < info->start[0]
170             || (addr + count) > (info->start[0] + info->size)
171             || (addr + count) < addr) {
172                 puts("Error: invalid address range\n");
173                 return ERR_INVAL;
174         }
175
176         if (addr & 1 || count & 1 || (unsigned int)src & 1) {
177                 puts("Error: misaligned source, destination or count\n");
178                 return ERR_ALIGN;
179         }
180
181         base = (uint16_t *)uncached(info->start[0]);
182         end = (uint16_t *)uncached(addr + count);
183
184         flags = disable_interrupts();
185
186         dcache_flush_unlocked();
187         sync_write_buffer();
188
189         for (p = (uint16_t *)uncached(addr), s = (uint16_t *)src;
190              p < end && !ctrlc(); p++, s++) {
191                 word = *s;
192
193                 writew(0xaa, base + 0x555);
194                 writew(0x55, base + 0xaaa);
195                 writew(0xa0, base + 0x555);
196                 writew(word, p);
197
198                 sync_write_buffer();
199
200                 /* Wait for completion */
201                 do {
202                         /* TODO: Timeout */
203                         status = readw(p);
204                 } while ((status != word) && !(status & 0x28));
205
206                 writew(0xf0, base);
207                 readw(base);
208
209                 if (status != word) {
210                         printf("Flash write error at address 0x%p: 0x%02x\n",
211                                p, status);
212                         ret = ERR_PROG_ERROR;
213                         break;
214                 }
215         }
216
217         if (flags)
218                 enable_interrupts();
219
220         return ret;
221 }
222
223 #endif /* CONFIG_ATSTK1000_EXT_FLASH */