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