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: 68*483a0cf8SMarian Balakowicz return; 69a562e1bdSwdenk } 70a562e1bdSwdenk 71a562e1bdSwdenk 72a562e1bdSwdenk unsigned long flash_init (void) 73a562e1bdSwdenk { 74a562e1bdSwdenk int i, j; 75a562e1bdSwdenk ulong size = 0; 76a562e1bdSwdenk 77a562e1bdSwdenk for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { 78a562e1bdSwdenk ulong flashbase = 0; 79a562e1bdSwdenk 80a562e1bdSwdenk flash_info[i].flash_id = 81a562e1bdSwdenk (AMD_MANUFACT & FLASH_VENDMASK) | 82a562e1bdSwdenk (AMD_ID_PL160CB & FLASH_TYPEMASK); 83a562e1bdSwdenk flash_info[i].size = FLASH_BANK_SIZE; 84a562e1bdSwdenk flash_info[i].sector_count = CFG_MAX_FLASH_SECT; 85a562e1bdSwdenk memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT); 86a562e1bdSwdenk if (i == 0) 87a562e1bdSwdenk flashbase = PHYS_FLASH_1; 88a562e1bdSwdenk else 89a562e1bdSwdenk panic ("configured to many flash banks!\n"); 90a562e1bdSwdenk 91a562e1bdSwdenk for (j = 0; j < flash_info[i].sector_count; j++) { 92a562e1bdSwdenk if (j == 0) { 93a562e1bdSwdenk /* 1st is 16 KiB */ 94a562e1bdSwdenk flash_info[i].start[j] = flashbase; 95a562e1bdSwdenk } 96a562e1bdSwdenk if ((j >= 1) && (j <= 2)) { 97a562e1bdSwdenk /* 2nd and 3rd are 8 KiB */ 98a562e1bdSwdenk flash_info[i].start[j] = 99a562e1bdSwdenk flashbase + 0x4000 + 0x2000 * (j - 1); 100a562e1bdSwdenk } 101a562e1bdSwdenk if (j == 3) { 102a562e1bdSwdenk /* 4th is 224 KiB */ 103a562e1bdSwdenk flash_info[i].start[j] = flashbase + 0x8000; 104a562e1bdSwdenk } 105a562e1bdSwdenk if ((j >= 4) && (j <= 10)) { 106a562e1bdSwdenk /* rest is 256 KiB */ 107a562e1bdSwdenk flash_info[i].start[j] = 108a562e1bdSwdenk flashbase + 0x40000 + 0x40000 * (j - 109a562e1bdSwdenk 4); 110a562e1bdSwdenk } 111a562e1bdSwdenk } 112a562e1bdSwdenk size += flash_info[i].size; 113a562e1bdSwdenk } 114a562e1bdSwdenk 115a562e1bdSwdenk flash_protect (FLAG_PROTECT_SET, 116a562e1bdSwdenk CFG_FLASH_BASE, 117a562e1bdSwdenk CFG_FLASH_BASE + 0x3ffff, &flash_info[0]); 118a562e1bdSwdenk 119a562e1bdSwdenk return size; 120a562e1bdSwdenk } 121a562e1bdSwdenk 122a562e1bdSwdenk 123a562e1bdSwdenk #define CMD_READ_ARRAY 0x00F0 124a562e1bdSwdenk #define CMD_UNLOCK1 0x00AA 125a562e1bdSwdenk #define CMD_UNLOCK2 0x0055 126a562e1bdSwdenk #define CMD_ERASE_SETUP 0x0080 127a562e1bdSwdenk #define CMD_ERASE_CONFIRM 0x0030 128a562e1bdSwdenk #define CMD_PROGRAM 0x00A0 129a562e1bdSwdenk #define CMD_UNLOCK_BYPASS 0x0020 130a562e1bdSwdenk 131a562e1bdSwdenk #define MEM_FLASH_ADDR1 (*(volatile u16 *)(CFG_FLASH_BASE + (0x00000555<<1))) 132a562e1bdSwdenk #define MEM_FLASH_ADDR2 (*(volatile u16 *)(CFG_FLASH_BASE + (0x000002AA<<1))) 133a562e1bdSwdenk 134a562e1bdSwdenk #define BIT_ERASE_DONE 0x0080 135a562e1bdSwdenk #define BIT_RDY_MASK 0x0080 136a562e1bdSwdenk #define BIT_PROGRAM_ERROR 0x0020 137a562e1bdSwdenk #define BIT_TIMEOUT 0x80000000 /* our flag */ 138a562e1bdSwdenk 139a562e1bdSwdenk #define READY 1 140a562e1bdSwdenk #define ERR 2 141a562e1bdSwdenk #define TMO 4 142a562e1bdSwdenk 143a562e1bdSwdenk 144a562e1bdSwdenk int flash_erase (flash_info_t * info, int s_first, int s_last) 145a562e1bdSwdenk { 146a562e1bdSwdenk ulong result; 147a562e1bdSwdenk int iflag, cflag, prot, sect; 148a562e1bdSwdenk int rc = ERR_OK; 149a562e1bdSwdenk int chip1; 150a562e1bdSwdenk 151a562e1bdSwdenk /* first look for protection bits */ 152a562e1bdSwdenk 153a562e1bdSwdenk if (info->flash_id == FLASH_UNKNOWN) 154a562e1bdSwdenk return ERR_UNKNOWN_FLASH_TYPE; 155a562e1bdSwdenk 156a562e1bdSwdenk if ((s_first < 0) || (s_first > s_last)) { 157a562e1bdSwdenk return ERR_INVAL; 158a562e1bdSwdenk } 159a562e1bdSwdenk 160a562e1bdSwdenk if ((info->flash_id & FLASH_VENDMASK) != 161a562e1bdSwdenk (AMD_MANUFACT & FLASH_VENDMASK)) { 162a562e1bdSwdenk return ERR_UNKNOWN_FLASH_VENDOR; 163a562e1bdSwdenk } 164a562e1bdSwdenk 165a562e1bdSwdenk prot = 0; 166a562e1bdSwdenk for (sect = s_first; sect <= s_last; ++sect) { 167a562e1bdSwdenk if (info->protect[sect]) { 168a562e1bdSwdenk prot++; 169a562e1bdSwdenk } 170a562e1bdSwdenk } 171a562e1bdSwdenk if (prot) 172a562e1bdSwdenk return ERR_PROTECTED; 173a562e1bdSwdenk 174a562e1bdSwdenk /* 175a562e1bdSwdenk * Disable interrupts which might cause a timeout 176a562e1bdSwdenk * here. Remember that our exception vectors are 177a562e1bdSwdenk * at address 0 in the flash, and we don't want a 178a562e1bdSwdenk * (ticker) exception to happen while the flash 179a562e1bdSwdenk * chip is in programming mode. 180a562e1bdSwdenk */ 181a562e1bdSwdenk 182a562e1bdSwdenk cflag = icache_status (); 183a562e1bdSwdenk icache_disable (); 184a562e1bdSwdenk iflag = disable_interrupts (); 185a562e1bdSwdenk 186a562e1bdSwdenk printf ("\n"); 187a562e1bdSwdenk 188a562e1bdSwdenk /* Start erase on unprotected sectors */ 189a562e1bdSwdenk for (sect = s_first; sect <= s_last && !ctrlc (); sect++) { 190a562e1bdSwdenk printf ("Erasing sector %2d ... ", sect); 191a562e1bdSwdenk 192a562e1bdSwdenk /* arm simple, non interrupt dependent timer */ 193a562e1bdSwdenk set_timer (0); 194a562e1bdSwdenk 195a562e1bdSwdenk if (info->protect[sect] == 0) { /* not protected */ 196a562e1bdSwdenk volatile u16 *addr = 197a562e1bdSwdenk (volatile u16 *) (info->start[sect]); 198a562e1bdSwdenk 199a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_UNLOCK1; 200a562e1bdSwdenk MEM_FLASH_ADDR2 = CMD_UNLOCK2; 201a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_ERASE_SETUP; 202a562e1bdSwdenk 203a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_UNLOCK1; 204a562e1bdSwdenk MEM_FLASH_ADDR2 = CMD_UNLOCK2; 205a562e1bdSwdenk *addr = CMD_ERASE_CONFIRM; 206a562e1bdSwdenk 207a562e1bdSwdenk /* wait until flash is ready */ 208a562e1bdSwdenk chip1 = 0; 209a562e1bdSwdenk 210a562e1bdSwdenk do { 211a562e1bdSwdenk result = *addr; 212a562e1bdSwdenk 213a562e1bdSwdenk /* check timeout */ 214a562e1bdSwdenk if (get_timer (0) > CFG_FLASH_ERASE_TOUT) { 215a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_READ_ARRAY; 216a562e1bdSwdenk chip1 = TMO; 217a562e1bdSwdenk break; 218a562e1bdSwdenk } 219a562e1bdSwdenk 220a562e1bdSwdenk if (!chip1 221a562e1bdSwdenk && (result & 0xFFFF) & BIT_ERASE_DONE) 222a562e1bdSwdenk chip1 = READY; 223a562e1bdSwdenk 224a562e1bdSwdenk } while (!chip1); 225a562e1bdSwdenk 226a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_READ_ARRAY; 227a562e1bdSwdenk 228a562e1bdSwdenk if (chip1 == ERR) { 229a562e1bdSwdenk rc = ERR_PROG_ERROR; 230a562e1bdSwdenk goto outahere; 231a562e1bdSwdenk } 232a562e1bdSwdenk if (chip1 == TMO) { 233a562e1bdSwdenk rc = ERR_TIMOUT; 234a562e1bdSwdenk goto outahere; 235a562e1bdSwdenk } 236a562e1bdSwdenk 237a562e1bdSwdenk printf ("ok.\n"); 238a562e1bdSwdenk } else { /* it was protected */ 239a562e1bdSwdenk 240a562e1bdSwdenk printf ("protected!\n"); 241a562e1bdSwdenk } 242a562e1bdSwdenk } 243a562e1bdSwdenk 244a562e1bdSwdenk if (ctrlc ()) 245a562e1bdSwdenk printf ("User Interrupt!\n"); 246a562e1bdSwdenk 247a562e1bdSwdenk outahere: 248a562e1bdSwdenk /* allow flash to settle - wait 10 ms */ 249a562e1bdSwdenk udelay (10000); 250a562e1bdSwdenk 251a562e1bdSwdenk if (iflag) 252a562e1bdSwdenk enable_interrupts (); 253a562e1bdSwdenk 254a562e1bdSwdenk if (cflag) 255a562e1bdSwdenk icache_enable (); 256a562e1bdSwdenk 257a562e1bdSwdenk return rc; 258a562e1bdSwdenk } 259a562e1bdSwdenk 2608de7ed3aSWolfgang Denk static int write_word (flash_info_t * info, ulong dest, ulong data) 261a562e1bdSwdenk { 262a562e1bdSwdenk volatile u16 *addr = (volatile u16 *) dest; 263a562e1bdSwdenk ulong result; 264a562e1bdSwdenk int rc = ERR_OK; 265a562e1bdSwdenk int cflag, iflag; 266a562e1bdSwdenk int chip1; 267a562e1bdSwdenk 268a562e1bdSwdenk /* 269a562e1bdSwdenk * Check if Flash is (sufficiently) erased 270a562e1bdSwdenk */ 271a562e1bdSwdenk result = *addr; 272a562e1bdSwdenk if ((result & data) != data) 273a562e1bdSwdenk return ERR_NOT_ERASED; 274a562e1bdSwdenk 275a562e1bdSwdenk 276a562e1bdSwdenk /* 277a562e1bdSwdenk * Disable interrupts which might cause a timeout 278a562e1bdSwdenk * here. Remember that our exception vectors are 279a562e1bdSwdenk * at address 0 in the flash, and we don't want a 280a562e1bdSwdenk * (ticker) exception to happen while the flash 281a562e1bdSwdenk * chip is in programming mode. 282a562e1bdSwdenk */ 283a562e1bdSwdenk 284a562e1bdSwdenk cflag = icache_status (); 285a562e1bdSwdenk icache_disable (); 286a562e1bdSwdenk iflag = disable_interrupts (); 287a562e1bdSwdenk 288a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_UNLOCK1; 289a562e1bdSwdenk MEM_FLASH_ADDR2 = CMD_UNLOCK2; 290a562e1bdSwdenk MEM_FLASH_ADDR1 = CMD_PROGRAM; 291a562e1bdSwdenk *addr = data; 292a562e1bdSwdenk 293a562e1bdSwdenk /* arm simple, non interrupt dependent timer */ 294a562e1bdSwdenk set_timer (0); 295a562e1bdSwdenk 296a562e1bdSwdenk /* wait until flash is ready */ 297a562e1bdSwdenk chip1 = 0; 298a562e1bdSwdenk do { 299a562e1bdSwdenk result = *addr; 300a562e1bdSwdenk 301a562e1bdSwdenk /* check timeout */ 302a562e1bdSwdenk if (get_timer (0) > CFG_FLASH_ERASE_TOUT) { 303a562e1bdSwdenk chip1 = ERR | TMO; 304a562e1bdSwdenk break; 305a562e1bdSwdenk } 306a562e1bdSwdenk if (!chip1 && ((result & 0x80) == (data & 0x80))) 307a562e1bdSwdenk chip1 = READY; 308a562e1bdSwdenk 309a562e1bdSwdenk } while (!chip1); 310a562e1bdSwdenk 311a562e1bdSwdenk *addr = CMD_READ_ARRAY; 312a562e1bdSwdenk 313a562e1bdSwdenk if (chip1 == ERR || *addr != data) 314a562e1bdSwdenk rc = ERR_PROG_ERROR; 315a562e1bdSwdenk 316a562e1bdSwdenk if (iflag) 317a562e1bdSwdenk enable_interrupts (); 318a562e1bdSwdenk 319a562e1bdSwdenk if (cflag) 320a562e1bdSwdenk icache_enable (); 321a562e1bdSwdenk 322a562e1bdSwdenk return rc; 323a562e1bdSwdenk } 324a562e1bdSwdenk 325a562e1bdSwdenk 326a562e1bdSwdenk int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) 327a562e1bdSwdenk { 328a562e1bdSwdenk ulong wp, data; 329a562e1bdSwdenk int rc; 330a562e1bdSwdenk 331a562e1bdSwdenk if (addr & 1) { 332a562e1bdSwdenk printf ("unaligned destination not supported\n"); 333a562e1bdSwdenk return ERR_ALIGN; 334a562e1bdSwdenk } 335a562e1bdSwdenk 336a562e1bdSwdenk #if 0 337a562e1bdSwdenk if (cnt & 1) { 338a562e1bdSwdenk printf ("odd transfer sizes not supported\n"); 339a562e1bdSwdenk return ERR_ALIGN; 340a562e1bdSwdenk } 341a562e1bdSwdenk #endif 342a562e1bdSwdenk 343a562e1bdSwdenk wp = addr; 344a562e1bdSwdenk 345a562e1bdSwdenk if (addr & 1) { 346a562e1bdSwdenk data = (*((volatile u8 *) addr) << 8) | *((volatile u8 *) 347a562e1bdSwdenk src); 348a562e1bdSwdenk if ((rc = write_word (info, wp - 1, data)) != 0) { 349a562e1bdSwdenk return (rc); 350a562e1bdSwdenk } 351a562e1bdSwdenk src += 1; 352a562e1bdSwdenk wp += 1; 353a562e1bdSwdenk cnt -= 1; 354a562e1bdSwdenk } 355a562e1bdSwdenk 356a562e1bdSwdenk while (cnt >= 2) { 357a562e1bdSwdenk data = *((volatile u16 *) src); 358a562e1bdSwdenk if ((rc = write_word (info, wp, data)) != 0) { 359a562e1bdSwdenk return (rc); 360a562e1bdSwdenk } 361a562e1bdSwdenk src += 2; 362a562e1bdSwdenk wp += 2; 363a562e1bdSwdenk cnt -= 2; 364a562e1bdSwdenk } 365a562e1bdSwdenk 366a562e1bdSwdenk if (cnt == 1) { 367a562e1bdSwdenk data = (*((volatile u8 *) src) << 8) | 368a562e1bdSwdenk *((volatile u8 *) (wp + 1)); 369a562e1bdSwdenk if ((rc = write_word (info, wp, data)) != 0) { 370a562e1bdSwdenk return (rc); 371a562e1bdSwdenk } 372a562e1bdSwdenk src += 1; 373a562e1bdSwdenk wp += 1; 374a562e1bdSwdenk cnt -= 1; 375a562e1bdSwdenk } 376a562e1bdSwdenk 377a562e1bdSwdenk return ERR_OK; 378a562e1bdSwdenk } 379