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