1a562e1bdSwdenk /* 2a562e1bdSwdenk * (C) Copyright 2000-2003 3a562e1bdSwdenk * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4a562e1bdSwdenk * 5a562e1bdSwdenk * See file CREDITS for list of people who contributed to this 6a562e1bdSwdenk * project. 7a562e1bdSwdenk * 8a562e1bdSwdenk * This program is free software; you can redistribute it and/or 9a562e1bdSwdenk * modify it under the terms of the GNU General Public License as 10a562e1bdSwdenk * published by the Free Software Foundation; either version 2 of 11a562e1bdSwdenk * the License, or (at your option) any later version. 12a562e1bdSwdenk * 13a562e1bdSwdenk * This program is distributed in the hope that it will be useful, 14a562e1bdSwdenk * but WITHOUT ANY WARRANTY; without even the implied warranty of 15a562e1bdSwdenk * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16a562e1bdSwdenk * GNU General Public License for more details. 17a562e1bdSwdenk * 18a562e1bdSwdenk * You should have received a copy of the GNU General Public License 19a562e1bdSwdenk * along with this program; if not, write to the Free Software 20a562e1bdSwdenk * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21a562e1bdSwdenk * MA 02111-1307 USA 22a562e1bdSwdenk */ 23a562e1bdSwdenk 24a562e1bdSwdenk #include <common.h> 25a562e1bdSwdenk 26a562e1bdSwdenk #define PHYS_FLASH_1 CFG_FLASH_BASE 27a562e1bdSwdenk #define FLASH_BANK_SIZE 0x200000 28a562e1bdSwdenk 29a562e1bdSwdenk flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; 30a562e1bdSwdenk 31a562e1bdSwdenk void flash_print_info (flash_info_t * info) 32a562e1bdSwdenk { 33a562e1bdSwdenk int i; 34a562e1bdSwdenk 35a562e1bdSwdenk switch (info->flash_id & FLASH_VENDMASK) { 36a562e1bdSwdenk case (AMD_MANUFACT & FLASH_VENDMASK): 37a562e1bdSwdenk printf ("AMD: "); 38a562e1bdSwdenk break; 39a562e1bdSwdenk default: 40a562e1bdSwdenk printf ("Unknown Vendor "); 41a562e1bdSwdenk break; 42a562e1bdSwdenk } 43a562e1bdSwdenk 44a562e1bdSwdenk switch (info->flash_id & FLASH_TYPEMASK) { 45a562e1bdSwdenk case (AMD_ID_PL160CB & FLASH_TYPEMASK): 46a562e1bdSwdenk printf ("AM29PL160CB (16Mbit)\n"); 47a562e1bdSwdenk break; 48a562e1bdSwdenk default: 49a562e1bdSwdenk printf ("Unknown Chip Type\n"); 50a562e1bdSwdenk goto Done; 51a562e1bdSwdenk break; 52a562e1bdSwdenk } 53a562e1bdSwdenk 54a562e1bdSwdenk printf (" Size: %ld MB in %d Sectors\n", 55a562e1bdSwdenk info->size >> 20, info->sector_count); 56a562e1bdSwdenk 57a562e1bdSwdenk printf (" Sector Start Addresses:"); 58a562e1bdSwdenk for (i = 0; i < info->sector_count; i++) { 59a562e1bdSwdenk if ((i % 5) == 0) { 60a562e1bdSwdenk printf ("\n "); 61a562e1bdSwdenk } 62a562e1bdSwdenk printf (" %08lX%s", info->start[i], 63a562e1bdSwdenk info->protect[i] ? " (RO)" : " "); 64a562e1bdSwdenk } 65a562e1bdSwdenk printf ("\n"); 66a562e1bdSwdenk 67a562e1bdSwdenk Done: 68a562e1bdSwdenk } 69a562e1bdSwdenk 70a562e1bdSwdenk 71a562e1bdSwdenk unsigned long flash_init (void) 72a562e1bdSwdenk { 73a562e1bdSwdenk int i, j; 74a562e1bdSwdenk ulong size = 0; 75a562e1bdSwdenk 76a562e1bdSwdenk for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { 77a562e1bdSwdenk ulong flashbase = 0; 78a562e1bdSwdenk 79a562e1bdSwdenk flash_info[i].flash_id = 80a562e1bdSwdenk (AMD_MANUFACT & FLASH_VENDMASK) | 81a562e1bdSwdenk (AMD_ID_PL160CB & FLASH_TYPEMASK); 82a562e1bdSwdenk flash_info[i].size = FLASH_BANK_SIZE; 83a562e1bdSwdenk flash_info[i].sector_count = CFG_MAX_FLASH_SECT; 84a562e1bdSwdenk memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); 85a562e1bdSwdenk if (i == 0) 86a562e1bdSwdenk flashbase = PHYS_FLASH_1; 87a562e1bdSwdenk else 88a562e1bdSwdenk panic ("configured to many flash banks!\n"); 89a562e1bdSwdenk 90a562e1bdSwdenk for (j = 0; j < flash_info[i].sector_count; j++) { 91a562e1bdSwdenk if (j == 0) { 92a562e1bdSwdenk /* 1st is 16 KiB */ 93a562e1bdSwdenk flash_info[i].start[j] = flashbase; 94a562e1bdSwdenk } 95a562e1bdSwdenk if ((j >= 1) && (j <= 2)) { 96a562e1bdSwdenk /* 2nd and 3rd are 8 KiB */ 97a562e1bdSwdenk flash_info[i].start[j] = 98a562e1bdSwdenk flashbase + 0x4000 + 0x2000 * (j - 1); 99a562e1bdSwdenk } 100a562e1bdSwdenk if (j == 3) { 101a562e1bdSwdenk /* 4th is 224 KiB */ 102a562e1bdSwdenk flash_info[i].start[j] = flashbase + 0x8000; 103a562e1bdSwdenk } 104a562e1bdSwdenk if ((j >= 4) && (j <= 10)) { 105a562e1bdSwdenk /* rest is 256 KiB */ 106a562e1bdSwdenk flash_info[i].start[j] = 107a562e1bdSwdenk flashbase + 0x40000 + 0x40000 * (j - 108a562e1bdSwdenk 4); 109a562e1bdSwdenk } 110a562e1bdSwdenk } 111a562e1bdSwdenk size += flash_info[i].size; 112a562e1bdSwdenk } 113a562e1bdSwdenk 114a562e1bdSwdenk flash_protect (FLAG_PROTECT_SET, 115a562e1bdSwdenk CFG_FLASH_BASE, 116a562e1bdSwdenk CFG_FLASH_BASE + 0x3ffff, &flash_info[0]); 117a562e1bdSwdenk 118a562e1bdSwdenk return size; 119a562e1bdSwdenk } 120a562e1bdSwdenk 121a562e1bdSwdenk 122a562e1bdSwdenk #define CMD_READ_ARRAY 0x00F0 123a562e1bdSwdenk #define CMD_UNLOCK1 0x00AA 124a562e1bdSwdenk #define CMD_UNLOCK2 0x0055 125a562e1bdSwdenk #define CMD_ERASE_SETUP 0x0080 126a562e1bdSwdenk #define CMD_ERASE_CONFIRM 0x0030 127a562e1bdSwdenk #define CMD_PROGRAM 0x00A0 128a562e1bdSwdenk #define CMD_UNLOCK_BYPASS 0x0020 129a562e1bdSwdenk 130a562e1bdSwdenk #define MEM_FLASH_ADDR1 (*(volatile u16 *)(CFG_FLASH_BASE + (0x00000555<<1))) 131a562e1bdSwdenk #define MEM_FLASH_ADDR2 (*(volatile u16 *)(CFG_FLASH_BASE + (0x000002AA<<1))) 132a562e1bdSwdenk 133a562e1bdSwdenk #define BIT_ERASE_DONE 0x0080 134a562e1bdSwdenk #define BIT_RDY_MASK 0x0080 135a562e1bdSwdenk #define BIT_PROGRAM_ERROR 0x0020 136a562e1bdSwdenk #define BIT_TIMEOUT 0x80000000 /* our flag */ 137a562e1bdSwdenk 138a562e1bdSwdenk #define READY 1 139a562e1bdSwdenk #define ERR 2 140a562e1bdSwdenk #define TMO 4 141a562e1bdSwdenk 142a562e1bdSwdenk 143a562e1bdSwdenk int flash_erase (flash_info_t * info, int s_first, int s_last) 144a562e1bdSwdenk { 145a562e1bdSwdenk ulong result; 146a562e1bdSwdenk int iflag, cflag, prot, sect; 147a562e1bdSwdenk int rc = ERR_OK; 148a562e1bdSwdenk int chip1; 149a562e1bdSwdenk 150a562e1bdSwdenk /* first look for protection bits */ 151a562e1bdSwdenk 152a562e1bdSwdenk if (info->flash_id == FLASH_UNKNOWN) 153a562e1bdSwdenk return ERR_UNKNOWN_FLASH_TYPE; 154a562e1bdSwdenk 155a562e1bdSwdenk if ((s_first < 0) || (s_first > s_last)) { 156a562e1bdSwdenk return ERR_INVAL; 157a562e1bdSwdenk } 158a562e1bdSwdenk 159a562e1bdSwdenk if ((info->flash_id & FLASH_VENDMASK) != 160a562e1bdSwdenk (AMD_MANUFACT & FLASH_VENDMASK)) { 161a562e1bdSwdenk return ERR_UNKNOWN_FLASH_VENDOR; 162a562e1bdSwdenk } 163a562e1bdSwdenk 164a562e1bdSwdenk prot = 0; 165a562e1bdSwdenk for (sect = s_first; sect <= s_last; ++sect) { 166a562e1bdSwdenk if (info->protect[sect]) { 167a562e1bdSwdenk prot++; 168a562e1bdSwdenk } 169a562e1bdSwdenk } 170a562e1bdSwdenk if (prot) 171a562e1bdSwdenk return ERR_PROTECTED; 172a562e1bdSwdenk 173a562e1bdSwdenk /* 174a562e1bdSwdenk * Disable interrupts which might cause a timeout 175a562e1bdSwdenk * here. Remember that our exception vectors are 176a562e1bdSwdenk * at address 0 in the flash, and we don't want a 177a562e1bdSwdenk * (ticker) exception to happen while the flash 178a562e1bdSwdenk * chip is in programming mode. 179a562e1bdSwdenk */ 180a562e1bdSwdenk 181a562e1bdSwdenk cflag = icache_status (); 182a562e1bdSwdenk icache_disable (); 183a562e1bdSwdenk iflag = disable_interrupts (); 184a562e1bdSwdenk 185a562e1bdSwdenk printf ("\n"); 186a562e1bdSwdenk 187a562e1bdSwdenk /* Start erase on unprotected sectors */ 188a562e1bdSwdenk for (sect = s_first; sect <= s_last && !ctrlc (); sect++) { 189a562e1bdSwdenk printf ("Erasing sector %2d ... ", sect); 190a562e1bdSwdenk 191a562e1bdSwdenk /* arm simple, non interrupt dependent timer */ 192a562e1bdSwdenk set_timer (0); 193a562e1bdSwdenk 194a562e1bdSwdenk if (info->protect[sect] == 0) { /* not protected */ 195a562e1bdSwdenk volatile u16 *addr = 196a562e1bdSwdenk (volatile u16 *) (info->start[sect]); 197a562e1bdSwdenk 198a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_UNLOCK1; 199a562e1bdSwdenk MEM_FLASH_ADDR2 = CMD_UNLOCK2; 200a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_ERASE_SETUP; 201a562e1bdSwdenk 202a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_UNLOCK1; 203a562e1bdSwdenk MEM_FLASH_ADDR2 = CMD_UNLOCK2; 204a562e1bdSwdenk *addr = CMD_ERASE_CONFIRM; 205a562e1bdSwdenk 206a562e1bdSwdenk /* wait until flash is ready */ 207a562e1bdSwdenk chip1 = 0; 208a562e1bdSwdenk 209a562e1bdSwdenk do { 210a562e1bdSwdenk result = *addr; 211a562e1bdSwdenk 212a562e1bdSwdenk /* check timeout */ 213a562e1bdSwdenk if (get_timer (0) > CFG_FLASH_ERASE_TOUT) { 214a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_READ_ARRAY; 215a562e1bdSwdenk chip1 = TMO; 216a562e1bdSwdenk break; 217a562e1bdSwdenk } 218a562e1bdSwdenk 219a562e1bdSwdenk if (!chip1 220a562e1bdSwdenk && (result & 0xFFFF) & BIT_ERASE_DONE) 221a562e1bdSwdenk chip1 = READY; 222a562e1bdSwdenk 223a562e1bdSwdenk } while (!chip1); 224a562e1bdSwdenk 225a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_READ_ARRAY; 226a562e1bdSwdenk 227a562e1bdSwdenk if (chip1 == ERR) { 228a562e1bdSwdenk rc = ERR_PROG_ERROR; 229a562e1bdSwdenk goto outahere; 230a562e1bdSwdenk } 231a562e1bdSwdenk if (chip1 == TMO) { 232a562e1bdSwdenk rc = ERR_TIMOUT; 233a562e1bdSwdenk goto outahere; 234a562e1bdSwdenk } 235a562e1bdSwdenk 236a562e1bdSwdenk printf ("ok.\n"); 237a562e1bdSwdenk } else { /* it was protected */ 238a562e1bdSwdenk 239a562e1bdSwdenk printf ("protected!\n"); 240a562e1bdSwdenk } 241a562e1bdSwdenk } 242a562e1bdSwdenk 243a562e1bdSwdenk if (ctrlc ()) 244a562e1bdSwdenk printf ("User Interrupt!\n"); 245a562e1bdSwdenk 246a562e1bdSwdenk outahere: 247a562e1bdSwdenk /* allow flash to settle - wait 10 ms */ 248a562e1bdSwdenk udelay (10000); 249a562e1bdSwdenk 250a562e1bdSwdenk if (iflag) 251a562e1bdSwdenk enable_interrupts (); 252a562e1bdSwdenk 253a562e1bdSwdenk if (cflag) 254a562e1bdSwdenk icache_enable (); 255a562e1bdSwdenk 256a562e1bdSwdenk return rc; 257a562e1bdSwdenk } 258a562e1bdSwdenk 259*8de7ed3aSWolfgang Denk static int write_word (flash_info_t * info, ulong dest, ulong data) 260a562e1bdSwdenk { 261a562e1bdSwdenk volatile u16 *addr = (volatile u16 *) dest; 262a562e1bdSwdenk ulong result; 263a562e1bdSwdenk int rc = ERR_OK; 264a562e1bdSwdenk int cflag, iflag; 265a562e1bdSwdenk int chip1; 266a562e1bdSwdenk 267a562e1bdSwdenk /* 268a562e1bdSwdenk * Check if Flash is (sufficiently) erased 269a562e1bdSwdenk */ 270a562e1bdSwdenk result = *addr; 271a562e1bdSwdenk if ((result & data) != data) 272a562e1bdSwdenk return ERR_NOT_ERASED; 273a562e1bdSwdenk 274a562e1bdSwdenk 275a562e1bdSwdenk /* 276a562e1bdSwdenk * Disable interrupts which might cause a timeout 277a562e1bdSwdenk * here. Remember that our exception vectors are 278a562e1bdSwdenk * at address 0 in the flash, and we don't want a 279a562e1bdSwdenk * (ticker) exception to happen while the flash 280a562e1bdSwdenk * chip is in programming mode. 281a562e1bdSwdenk */ 282a562e1bdSwdenk 283a562e1bdSwdenk cflag = icache_status (); 284a562e1bdSwdenk icache_disable (); 285a562e1bdSwdenk iflag = disable_interrupts (); 286a562e1bdSwdenk 287a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_UNLOCK1; 288a562e1bdSwdenk MEM_FLASH_ADDR2 = CMD_UNLOCK2; 289a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_PROGRAM; 290a562e1bdSwdenk *addr = data; 291a562e1bdSwdenk 292a562e1bdSwdenk /* arm simple, non interrupt dependent timer */ 293a562e1bdSwdenk set_timer (0); 294a562e1bdSwdenk 295a562e1bdSwdenk /* wait until flash is ready */ 296a562e1bdSwdenk chip1 = 0; 297a562e1bdSwdenk do { 298a562e1bdSwdenk result = *addr; 299a562e1bdSwdenk 300a562e1bdSwdenk /* check timeout */ 301a562e1bdSwdenk if (get_timer (0) > CFG_FLASH_ERASE_TOUT) { 302a562e1bdSwdenk chip1 = ERR | TMO; 303a562e1bdSwdenk break; 304a562e1bdSwdenk } 305a562e1bdSwdenk if (!chip1 && ((result & 0x80) == (data & 0x80))) 306a562e1bdSwdenk chip1 = READY; 307a562e1bdSwdenk 308a562e1bdSwdenk } while (!chip1); 309a562e1bdSwdenk 310a562e1bdSwdenk *addr = CMD_READ_ARRAY; 311a562e1bdSwdenk 312a562e1bdSwdenk if (chip1 == ERR || *addr != data) 313a562e1bdSwdenk rc = ERR_PROG_ERROR; 314a562e1bdSwdenk 315a562e1bdSwdenk if (iflag) 316a562e1bdSwdenk enable_interrupts (); 317a562e1bdSwdenk 318a562e1bdSwdenk if (cflag) 319a562e1bdSwdenk icache_enable (); 320a562e1bdSwdenk 321a562e1bdSwdenk return rc; 322a562e1bdSwdenk } 323a562e1bdSwdenk 324a562e1bdSwdenk 325a562e1bdSwdenk int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) 326a562e1bdSwdenk { 327a562e1bdSwdenk ulong wp, data; 328a562e1bdSwdenk int rc; 329a562e1bdSwdenk 330a562e1bdSwdenk if (addr & 1) { 331a562e1bdSwdenk printf ("unaligned destination not supported\n"); 332a562e1bdSwdenk return ERR_ALIGN; 333a562e1bdSwdenk } 334a562e1bdSwdenk 335a562e1bdSwdenk #if 0 336a562e1bdSwdenk if (cnt & 1) { 337a562e1bdSwdenk printf ("odd transfer sizes not supported\n"); 338a562e1bdSwdenk return ERR_ALIGN; 339a562e1bdSwdenk } 340a562e1bdSwdenk #endif 341a562e1bdSwdenk 342a562e1bdSwdenk wp = addr; 343a562e1bdSwdenk 344a562e1bdSwdenk if (addr & 1) { 345a562e1bdSwdenk data = (*((volatile u8 *) addr) << 8) | *((volatile u8 *) 346a562e1bdSwdenk src); 347a562e1bdSwdenk if ((rc = write_word (info, wp - 1, data)) != 0) { 348a562e1bdSwdenk return (rc); 349a562e1bdSwdenk } 350a562e1bdSwdenk src += 1; 351a562e1bdSwdenk wp += 1; 352a562e1bdSwdenk cnt -= 1; 353a562e1bdSwdenk } 354a562e1bdSwdenk 355a562e1bdSwdenk while (cnt >= 2) { 356a562e1bdSwdenk data = *((volatile u16 *) src); 357a562e1bdSwdenk if ((rc = write_word (info, wp, data)) != 0) { 358a562e1bdSwdenk return (rc); 359a562e1bdSwdenk } 360a562e1bdSwdenk src += 2; 361a562e1bdSwdenk wp += 2; 362a562e1bdSwdenk cnt -= 2; 363a562e1bdSwdenk } 364a562e1bdSwdenk 365a562e1bdSwdenk if (cnt == 1) { 366a562e1bdSwdenk data = (*((volatile u8 *) src) << 8) | 367a562e1bdSwdenk *((volatile u8 *) (wp + 1)); 368a562e1bdSwdenk if ((rc = write_word (info, wp, data)) != 0) { 369a562e1bdSwdenk return (rc); 370a562e1bdSwdenk } 371a562e1bdSwdenk src += 1; 372a562e1bdSwdenk wp += 1; 373a562e1bdSwdenk cnt -= 1; 374a562e1bdSwdenk } 375a562e1bdSwdenk 376a562e1bdSwdenk return ERR_OK; 377a562e1bdSwdenk } 378