blob: 36e0fcac790dca5ff7f55049d92e849f46e9a138 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 2000
3 * Marius Groeger <mgroeger@sysgo.de>
4 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
5 *
6 * (C) Copyright 2000
7 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
8 *
9 * Flash Routines for STM29W320DB/STM29W800D flash chips
10 *
11 *--------------------------------------------------------------------
12 * See file CREDITS for list of people who contributed to this
13 * project.
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License as
17 * published by the Free Software Foundation; either version 2 of
18 * the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28 * MA 02111-1307 USA
29 */
30
31#include <common.h>
32#include <mpc8xx.h>
33
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020034flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips */
wdenkc6097192002-11-03 00:24:07 +000035
36/*-----------------------------------------------------------------------
37 * Functions
38 */
39
40static ulong flash_get_size (vu_char *addr, flash_info_t *info);
41static int write_byte (flash_info_t *info, ulong dest, uchar data);
42
43/*-----------------------------------------------------------------------
44 */
45
46unsigned long flash_init (void)
47{
48 unsigned long size;
49 int i;
50
51 /* Init: no FLASHes known */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020052 for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
wdenkc6097192002-11-03 00:24:07 +000053 flash_info[i].flash_id = FLASH_UNKNOWN;
54 }
55
56 /*
57 * We use the following trick here: since flash is cyclically
58 * mapped in the 0xFF800000-0xFFFFFFFF area, we detect the type
59 * and the size of flash using 0xFF800000 as the base address,
60 * and then call flash_get_size() again to fill flash_info.
61 */
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020062 size = flash_get_size((vu_char *)CONFIG_SYS_FLASH_PRELIMBASE, &flash_info[0]);
wdenkc6097192002-11-03 00:24:07 +000063 if (size)
64 {
65 flash_get_size((vu_char *)(-size), &flash_info[0]);
66 }
67
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020068#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_PRELIMBASE)
wdenkc6097192002-11-03 00:24:07 +000069 /* monitor protection ON by default */
70 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020071 CONFIG_SYS_MONITOR_BASE,
72 CONFIG_SYS_MONITOR_BASE+monitor_flash_len-1,
wdenkc6097192002-11-03 00:24:07 +000073 &flash_info[0]);
74#endif
75
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020076#if defined(CONFIG_ENV_IS_IN_FLASH) && defined(CONFIG_ENV_ADDR)
77# ifndef CONFIG_ENV_SIZE
78# define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE
wdenkc6097192002-11-03 00:24:07 +000079# endif
80 flash_protect(FLAG_PROTECT_SET,
Jean-Christophe PLAGNIOL-VILLARD7e1cda62008-09-10 22:48:06 +020081 CONFIG_ENV_ADDR,
82 CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1,
wdenkc6097192002-11-03 00:24:07 +000083 &flash_info[0]);
84#endif
85
86 return (size);
87}
88
89/*-----------------------------------------------------------------------
90 */
91void flash_print_info (flash_info_t *info)
92{
93 int i;
94
95 if (info->flash_id == FLASH_UNKNOWN) {
96 printf ("missing or unknown FLASH type\n");
97 return;
98 }
99
100 switch (info->flash_id & FLASH_VENDMASK) {
101 case FLASH_MAN_STM:
102 printf ("ST ");
103 break;
104 default:
105 printf ("Unknown Vendor ");
106 break;
107 }
108
109 switch (info->flash_id & FLASH_TYPEMASK) {
110 case FLASH_STM320DB:
111 printf ("M29W320DB (32 Mbit)\n");
112 break;
113 case FLASH_STM800DB:
114 printf ("M29W800DB (8 Mbit, bottom boot block)\n");
115 break;
116 case FLASH_STM800DT:
117 printf ("M29W800DT (8 Mbit, top boot block)\n");
118 break;
119 default:
120 printf ("Unknown Chip Type\n");
121 break;
122 }
123
124 printf (" Size: %ld KB in %d Sectors\n",
125 info->size >> 10, info->sector_count);
126
127 printf (" Sector Start Addresses:");
128 for (i=0; i<info->sector_count; ++i) {
129 if ((i % 5) == 0)
130 printf ("\n ");
131 printf (" %08lX%s",
132 info->start[i],
133 info->protect[i] ? " (RO)" : " "
134 );
135 }
136 printf ("\n");
137 return;
138}
139
140/*
141 * The following code cannot be run from FLASH!
142 */
143
144static ulong flash_get_size (vu_char *addr, flash_info_t *info)
145{
146 short i;
147 uchar vendor, devid;
148 ulong base = (ulong)addr;
149
150 /* Write auto select command: read Manufacturer ID */
151 addr[0x0AAA] = 0xAA;
152 addr[0x0555] = 0x55;
153 addr[0x0AAA] = 0x90;
154
155 udelay(1000);
156
157 vendor = addr[0];
158 devid = addr[2];
159
160 /* only support STM */
161 if ((vendor << 16) != FLASH_MAN_STM) {
162 return 0;
163 }
164
165 if (devid == FLASH_STM320DB) {
Wolfgang Denka1be4762008-05-20 16:00:29 +0200166 /* MPC8240 can address maximum 2Mb of flash, that is why the MSB
wdenkc6097192002-11-03 00:24:07 +0000167 * lead is grounded and we can access only 2 first Mb */
168 info->flash_id = vendor << 16 | devid;
169 info->sector_count = 32;
170 info->size = info->sector_count * 0x10000;
171 for (i = 0; i < info->sector_count; i++) {
172 info->start[i] = base + i * 0x10000;
173 }
174 }
175 else if (devid == FLASH_STM800DB) {
176 info->flash_id = vendor << 16 | devid;
177 info->sector_count = 19;
178 info->size = 0x100000;
179 info->start[0] = 0x0000;
180 info->start[1] = 0x4000;
181 info->start[2] = 0x6000;
182 info->start[3] = 0x8000;
183 for (i = 4; i < info->sector_count; i++) {
184 info->start[i] = base + (i-3) * 0x10000;
185 }
186 }
187 else if (devid == FLASH_STM800DT) {
188 info->flash_id = vendor << 16 | devid;
189 info->sector_count = 19;
190 info->size = 0x100000;
191 for (i = 0; i < info->sector_count-4; i++) {
192 info->start[i] = base + i * 0x10000;
193 }
194 info->start[i] = base + i * 0x10000;
195 info->start[i+1] = base + i * 0x10000 + 0x8000;
196 info->start[i+2] = base + i * 0x10000 + 0xa000;
197 info->start[i+3] = base + i * 0x10000 + 0xc000;
198 }
199 else {
200 return 0;
201 }
202
203 /* mark all sectors as unprotected */
204 for (i = 0; i < info->sector_count; i++) {
205 info->protect[i] = 0;
206 }
207
208 /* Issue the reset command */
209 if (info->flash_id != FLASH_UNKNOWN) {
210 addr[0] = 0xF0; /* reset bank */
211 }
212
213 return (info->size);
214}
215
216
217/*-----------------------------------------------------------------------
218 */
219
220int flash_erase (flash_info_t *info, int s_first, int s_last)
221{
222 vu_char *addr = (vu_char *)(info->start[0]);
223 int flag, prot, sect, l_sect;
224 ulong start, now, last;
225
226 if ((s_first < 0) || (s_first > s_last)) {
227 if (info->flash_id == FLASH_UNKNOWN) {
228 printf ("- missing\n");
229 } else {
230 printf ("- no sectors to erase\n");
231 }
232 return 1;
233 }
234
235 prot = 0;
236 for (sect = s_first; sect <= s_last; sect++) {
237 if (info->protect[sect]) {
238 prot++;
239 }
240 }
241
242 if (prot) {
243 printf ("- Warning: %d protected sectors will not be erased!\n",
244 prot);
245 } else {
246 printf ("\n");
247 }
248
249 l_sect = -1;
250
251 /* Disable interrupts which might cause a timeout here */
252 flag = disable_interrupts();
253
254 addr[0x0AAA] = 0xAA;
255 addr[0x0555] = 0x55;
256 addr[0x0AAA] = 0x80;
257 addr[0x0AAA] = 0xAA;
258 addr[0x0555] = 0x55;
259
260 /* wait at least 80us - let's wait 1 ms */
261 udelay (1000);
262
263 /* Start erase on unprotected sectors */
264 for (sect = s_first; sect<=s_last; sect++) {
265 if (info->protect[sect] == 0) { /* not protected */
266 addr = (vu_char *)(info->start[sect]);
267 addr[0] = 0x30;
268 l_sect = sect;
269 }
270 }
271
272 /* re-enable interrupts if necessary */
273 if (flag)
274 enable_interrupts();
275
276 /* wait at least 80us - let's wait 1 ms */
277 udelay (1000);
278
279 /*
280 * We wait for the last triggered sector
281 */
282 if (l_sect < 0)
283 goto DONE;
284
285 start = get_timer (0);
286 last = start;
287 addr = (vu_char *)(info->start[l_sect]);
288 while ((addr[0] & 0x80) != 0x80) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200289 if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
wdenkc6097192002-11-03 00:24:07 +0000290 printf ("Timeout\n");
291 return 1;
292 }
293 /* show that we're waiting */
294 if ((now - last) > 1000) { /* every second */
295 serial_putc ('.');
296 last = now;
297 }
298 }
299
300 DONE:
301 /* reset to read mode */
302 addr = (volatile unsigned char *)info->start[0];
303 addr[0] = 0xF0; /* reset bank */
304
305 printf (" done\n");
306 return 0;
307}
308
309/*-----------------------------------------------------------------------
310 * Copy memory to flash, returns:
311 * 0 - OK
312 * 1 - write timeout
313 * 2 - Flash not erased
314 */
315
316int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
317{
318 int rc;
319
320 while (cnt > 0) {
321 if ((rc = write_byte(info, addr, *src)) != 0) {
322 return (rc);
323 }
324 addr++;
325 src++;
326 cnt--;
327 }
328
329 return (0);
330}
331
332/*-----------------------------------------------------------------------
333 * Write a byte to Flash, returns:
334 * 0 - OK
335 * 1 - write timeout
336 * 2 - Flash not erased
337 */
338static int write_byte (flash_info_t *info, ulong dest, uchar data)
339{
340 vu_char *addr = (vu_char *)(info->start[0]);
341 ulong start;
342 int flag;
343
344 /* Check if Flash is (sufficiently) erased */
345 if ((*((vu_char *)dest) & data) != data) {
346 return (2);
347 }
348 /* Disable interrupts which might cause a timeout here */
349 flag = disable_interrupts();
350
351 addr[0x0AAA] = 0xAA;
352 addr[0x0555] = 0x55;
353 addr[0x0AAA] = 0xA0;
354
355 *((vu_char *)dest) = data;
356
357 /* re-enable interrupts if necessary */
358 if (flag)
359 enable_interrupts();
360
361 /* data polling for D7 */
362 start = get_timer (0);
363 while ((*((vu_char *)dest) & 0x80) != (data & 0x80)) {
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200364 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
wdenkc6097192002-11-03 00:24:07 +0000365 return (1);
366 }
367 }
368 return (0);
369}
370
371/*-----------------------------------------------------------------------
372 */