1 /* 2 * (C) Copyright 2000-2003 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * Copyright (C) 2004-2007 Freescale Semiconductor, Inc. 6 * TsiChung Liew (Tsi-Chung.Liew@freescale.com) 7 * 8 * See file CREDITS for list of people who contributed to this 9 * project. 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License as 13 * published by the Free Software Foundation; either version 2 of 14 * the License, or (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 24 * MA 02111-1307 USA 25 */ 26 27 #include <common.h> 28 29 #include <asm/immap.h> 30 31 #ifndef CONFIG_SYS_FLASH_CFI 32 typedef unsigned short FLASH_PORT_WIDTH; 33 typedef volatile unsigned short FLASH_PORT_WIDTHV; 34 35 #define FPW FLASH_PORT_WIDTH 36 #define FPWV FLASH_PORT_WIDTHV 37 38 #define FLASH_CYCLE1 0x5555 39 #define FLASH_CYCLE2 0x2aaa 40 41 #define SYNC __asm__("nop") 42 43 /*----------------------------------------------------------------------- 44 * Functions 45 */ 46 47 ulong flash_get_size(FPWV * addr, flash_info_t * info); 48 int flash_get_offsets(ulong base, flash_info_t * info); 49 int write_word(flash_info_t * info, FPWV * dest, u16 data); 50 void inline spin_wheel(void); 51 52 flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; 53 54 ulong flash_init(void) 55 { 56 ulong size = 0; 57 ulong fbase = 0; 58 59 fbase = (ulong) CONFIG_SYS_FLASH_BASE; 60 flash_get_size((FPWV *) fbase, &flash_info[0]); 61 flash_get_offsets((ulong) fbase, &flash_info[0]); 62 fbase += flash_info[0].size; 63 size += flash_info[0].size; 64 65 /* Protect monitor and environment sectors */ 66 flash_protect(FLAG_PROTECT_SET, 67 CONFIG_SYS_MONITOR_BASE, 68 CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1, &flash_info[0]); 69 70 return size; 71 } 72 73 int flash_get_offsets(ulong base, flash_info_t * info) 74 { 75 int j, k; 76 77 if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_SST) { 78 79 info->start[0] = base; 80 for (k = 0, j = 0; j < CONFIG_SYS_SST_SECT; j++, k++) { 81 info->start[k + 1] = info->start[k] + CONFIG_SYS_SST_SECTSZ; 82 info->protect[k] = 0; 83 } 84 } 85 86 return ERR_OK; 87 } 88 89 void flash_print_info(flash_info_t * info) 90 { 91 int i; 92 93 switch (info->flash_id & FLASH_VENDMASK) { 94 case FLASH_MAN_SST: 95 printf("SST "); 96 break; 97 default: 98 printf("Unknown Vendor "); 99 break; 100 } 101 102 switch (info->flash_id & FLASH_TYPEMASK) { 103 case FLASH_SST6401B: 104 printf("SST39VF6401B\n"); 105 break; 106 default: 107 printf("Unknown Chip Type\n"); 108 return; 109 } 110 111 if (info->size > 0x100000) { 112 int remainder; 113 114 printf(" Size: %ld", info->size >> 20); 115 116 remainder = (info->size % 0x100000); 117 if (remainder) { 118 remainder >>= 10; 119 remainder = (int)((float) 120 (((float)remainder / (float)1024) * 121 10000)); 122 printf(".%d ", remainder); 123 } 124 125 printf("MB in %d Sectors\n", info->sector_count); 126 } else 127 printf(" Size: %ld KB in %d Sectors\n", 128 info->size >> 10, info->sector_count); 129 130 printf(" Sector Start Addresses:"); 131 for (i = 0; i < info->sector_count; ++i) { 132 if ((i % 5) == 0) 133 printf("\n "); 134 printf(" %08lX%s", 135 info->start[i], info->protect[i] ? " (RO)" : " "); 136 } 137 printf("\n"); 138 } 139 140 /* 141 * The following code cannot be run from FLASH! 142 */ 143 ulong flash_get_size(FPWV * addr, flash_info_t * info) 144 { 145 u16 value; 146 147 addr[FLASH_CYCLE1] = (FPWV) 0x00AA00AA; /* for Atmel, Intel ignores this */ 148 addr[FLASH_CYCLE2] = (FPWV) 0x00550055; /* for Atmel, Intel ignores this */ 149 addr[FLASH_CYCLE1] = (FPWV) 0x00900090; /* selects Intel or Atmel */ 150 151 switch (addr[0] & 0xffff) { 152 case (u8) SST_MANUFACT: 153 info->flash_id = FLASH_MAN_SST; 154 value = addr[1]; 155 break; 156 default: 157 printf("Unknown Flash\n"); 158 info->flash_id = FLASH_UNKNOWN; 159 info->sector_count = 0; 160 info->size = 0; 161 162 *addr = (FPW) 0x00F000F0; 163 return (0); /* no or unknown flash */ 164 } 165 166 switch (value) { 167 case (u16) SST_ID_xF6401B: 168 info->flash_id += FLASH_SST6401B; 169 break; 170 default: 171 info->flash_id = FLASH_UNKNOWN; 172 break; 173 } 174 175 info->sector_count = 0; 176 info->size = 0; 177 info->sector_count = CONFIG_SYS_SST_SECT; 178 info->size = CONFIG_SYS_SST_SECT * CONFIG_SYS_SST_SECTSZ; 179 180 /* reset ID mode */ 181 *addr = (FPWV) 0x00F000F0; 182 183 if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) { 184 printf("** ERROR: sector count %d > max (%d) **\n", 185 info->sector_count, CONFIG_SYS_MAX_FLASH_SECT); 186 info->sector_count = CONFIG_SYS_MAX_FLASH_SECT; 187 } 188 189 return (info->size); 190 } 191 192 int flash_erase(flash_info_t * info, int s_first, int s_last) 193 { 194 FPWV *addr; 195 int flag, prot, sect, count; 196 ulong type, start, last; 197 int rcode = 0, flashtype = 0; 198 199 if ((s_first < 0) || (s_first > s_last)) { 200 if (info->flash_id == FLASH_UNKNOWN) 201 printf("- missing\n"); 202 else 203 printf("- no sectors to erase\n"); 204 return 1; 205 } 206 207 type = (info->flash_id & FLASH_VENDMASK); 208 209 switch (type) { 210 case FLASH_MAN_SST: 211 flashtype = 1; 212 break; 213 default: 214 type = (info->flash_id & FLASH_VENDMASK); 215 printf("Can't erase unknown flash type %08lx - aborted\n", 216 info->flash_id); 217 return 1; 218 } 219 220 prot = 0; 221 for (sect = s_first; sect <= s_last; ++sect) { 222 if (info->protect[sect]) { 223 prot++; 224 } 225 } 226 227 if (prot) 228 printf("- Warning: %d protected sectors will not be erased!\n", 229 prot); 230 else 231 printf("\n"); 232 233 flag = disable_interrupts(); 234 235 start = get_timer(0); 236 last = start; 237 238 if ((s_last - s_first) == (CONFIG_SYS_SST_SECT - 1)) { 239 if (prot == 0) { 240 addr = (FPWV *) info->start[0]; 241 242 addr[FLASH_CYCLE1] = 0x00AA; /* unlock */ 243 addr[FLASH_CYCLE2] = 0x0055; /* unlock */ 244 addr[FLASH_CYCLE1] = 0x0080; /* erase mode */ 245 addr[FLASH_CYCLE1] = 0x00AA; /* unlock */ 246 addr[FLASH_CYCLE2] = 0x0055; /* unlock */ 247 *addr = 0x0030; /* erase chip */ 248 249 count = 0; 250 start = get_timer(0); 251 252 while ((*addr & 0x0080) != 0x0080) { 253 if (count++ > 0x10000) { 254 spin_wheel(); 255 count = 0; 256 } 257 258 if (get_timer(start) > CONFIG_SYS_FLASH_ERASE_TOUT) { 259 printf("Timeout\n"); 260 *addr = 0x00F0; /* reset to read mode */ 261 262 return 1; 263 } 264 } 265 266 *addr = 0x00F0; /* reset to read mode */ 267 268 printf("\b. done\n"); 269 270 if (flag) 271 enable_interrupts(); 272 273 return 0; 274 } else if (prot == CONFIG_SYS_SST_SECT) { 275 return 1; 276 } 277 } 278 279 /* Start erase on unprotected sectors */ 280 for (sect = s_first; sect <= s_last; sect++) { 281 if (info->protect[sect] == 0) { /* not protected */ 282 283 addr = (FPWV *) (info->start[sect]); 284 285 printf("."); 286 287 /* arm simple, non interrupt dependent timer */ 288 start = get_timer(0); 289 290 switch (flashtype) { 291 case 1: 292 { 293 FPWV *base; /* first address in bank */ 294 295 flag = disable_interrupts(); 296 297 base = (FPWV *) (CONFIG_SYS_FLASH_BASE); /* First sector */ 298 299 base[FLASH_CYCLE1] = 0x00AA; /* unlock */ 300 base[FLASH_CYCLE2] = 0x0055; /* unlock */ 301 base[FLASH_CYCLE1] = 0x0080; /* erase mode */ 302 base[FLASH_CYCLE1] = 0x00AA; /* unlock */ 303 base[FLASH_CYCLE2] = 0x0055; /* unlock */ 304 *addr = 0x0050; /* erase sector */ 305 306 if (flag) 307 enable_interrupts(); 308 309 while ((*addr & 0x0080) != 0x0080) { 310 if (get_timer(start) > 311 CONFIG_SYS_FLASH_ERASE_TOUT) { 312 printf("Timeout\n"); 313 *addr = 0x00F0; /* reset to read mode */ 314 315 rcode = 1; 316 break; 317 } 318 } 319 320 *addr = 0x00F0; /* reset to read mode */ 321 break; 322 } 323 } /* switch (flashtype) */ 324 } 325 } 326 printf(" done\n"); 327 328 if (flag) 329 enable_interrupts(); 330 331 return rcode; 332 } 333 334 int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt) 335 { 336 ulong wp, count; 337 u16 data; 338 int rc, port_width; 339 340 if (info->flash_id == FLASH_UNKNOWN) 341 return 4; 342 343 /* get lower word aligned address */ 344 wp = addr; 345 port_width = sizeof(FPW); 346 347 /* handle unaligned start bytes */ 348 if (wp & 1) { 349 data = *((FPWV *) wp); 350 data = (data << 8) | *src; 351 352 if ((rc = write_word(info, (FPWV *) wp, data)) != 0) 353 return (rc); 354 355 wp++; 356 cnt -= 1; 357 src++; 358 } 359 360 while (cnt >= 2) { 361 /* 362 * handle word aligned part 363 */ 364 count = 0; 365 data = *((FPWV *) src); 366 367 if ((rc = write_word(info, (FPWV *) wp, data)) != 0) 368 return (rc); 369 370 wp += 2; 371 src += 2; 372 cnt -= 2; 373 374 if (count++ > 0x800) { 375 spin_wheel(); 376 count = 0; 377 } 378 } 379 /* handle word aligned part */ 380 if (cnt) { 381 /* handle word aligned part */ 382 count = 0; 383 data = *((FPWV *) wp); 384 385 data = (data & 0x00FF) | (*src << 8); 386 387 if ((rc = write_word(info, (FPWV *) wp, data)) != 0) 388 return (rc); 389 390 wp++; 391 src++; 392 cnt -= 1; 393 if (count++ > 0x800) { 394 spin_wheel(); 395 count = 0; 396 } 397 } 398 399 if (cnt == 0) 400 return ERR_OK; 401 402 return ERR_OK; 403 } 404 405 /*----------------------------------------------------------------------- 406 * Write a word to Flash 407 * A word is 16 bits, whichever the bus width of the flash bank 408 * (not an individual chip) is. 409 * 410 * returns: 411 * 0 - OK 412 * 1 - write timeout 413 * 2 - Flash not erased 414 */ 415 int write_word(flash_info_t * info, FPWV * dest, u16 data) 416 { 417 ulong start; 418 int flag; 419 int res = 0; /* result, assume success */ 420 FPWV *base; /* first address in flash bank */ 421 422 /* Check if Flash is (sufficiently) erased */ 423 if ((*dest & (u8) data) != (u8) data) { 424 return (2); 425 } 426 427 base = (FPWV *) (CONFIG_SYS_FLASH_BASE); 428 429 /* Disable interrupts which might cause a timeout here */ 430 flag = disable_interrupts(); 431 432 base[FLASH_CYCLE1] = (u8) 0x00AA00AA; /* unlock */ 433 base[FLASH_CYCLE2] = (u8) 0x00550055; /* unlock */ 434 base[FLASH_CYCLE1] = (u8) 0x00A000A0; /* selects program mode */ 435 436 *dest = data; /* start programming the data */ 437 438 /* re-enable interrupts if necessary */ 439 if (flag) 440 enable_interrupts(); 441 442 start = get_timer(0); 443 444 /* data polling for D7 */ 445 while (res == 0 446 && (*dest & (u8) 0x00800080) != (data & (u8) 0x00800080)) { 447 if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) { 448 *dest = (u8) 0x00F000F0; /* reset bank */ 449 res = 1; 450 } 451 } 452 453 *dest++ = (u8) 0x00F000F0; /* reset bank */ 454 455 return (res); 456 } 457 458 void inline spin_wheel(void) 459 { 460 static int p = 0; 461 static char w[] = "\\/-"; 462 463 printf("\010%c", w[p]); 464 (++p == 3) ? (p = 0) : 0; 465 } 466 467 #endif 468