/* * Write a word to Flash, returns: * 0 - OK * 1 - write timeout * 2 - Flash not erased */ static int write_word (flash_info_t *info, ulong dest, ulong data) { volatile ulong addr = info->start[0]; ulong start; int i; flash_to_xd(); /* Check if Flash is (sufficiently) erased */ if ((in32(dest) & data) != data) { flash_to_mem(); return (2); } /* write each byte out */ for (i = 0; i < 4; i++) { char *data_ch = (char *)&data; int flag = disable_interrupts(); out8(addr + 0x555, 0xAA); iobarrier_rw(); out8(addr + 0x2AA, 0x55); iobarrier_rw(); out8(addr + 0x555, 0xA0); iobarrier_rw(); out8(dest+i, data_ch[i]); iobarrier_rw(); /* re-enable interrupts if necessary */ if (flag) enable_interrupts(); /* data polling for D7 */ start = get_timer (0); while ((in8(dest+i) & 0x80) != (data_ch[i] & 0x80)) { if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) { flash_reset (addr); flash_to_mem(); return (1); } iobarrier_rw(); } } flash_reset (addr); flash_to_mem(); return (0); }
ulong flash_get_size(FPWV * addr, flash_info_t * info) { int i; /* Write auto select command: read Manufacturer ID */ /* Write auto select command sequence and test FLASH answer */ addr[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* for AMD, Intel ignores this */ addr[FLASH_CYCLE2] = (FPW) 0x00550055; /* for AMD, Intel ignores this */ addr[FLASH_CYCLE1] = (FPW) 0x00900090; /* selects Intel or AMD */ /* The manufacturer codes are only 1 byte, so just use 1 byte. */ /* This works for any bus width and any FLASH device width. */ udelay(100); switch (addr[FLASH_ID1] & 0x00ff) { case (uchar) AMD_MANUFACT: info->flash_id = FLASH_MAN_AMD; break; default: printf("unknown vendor=%x ", addr[FLASH_ID1] & 0xff); info->flash_id = FLASH_UNKNOWN; info->sector_count = 0; info->size = 0; break; } /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */ if (info->flash_id != FLASH_UNKNOWN) { switch ((FPW) addr[FLASH_ID2]) { case (FPW) AMD_ID_MIRROR: /* MIRROR BIT FLASH, read more ID bytes */ if ((FPW) addr[FLASH_ID3] == (FPW) AMD_ID_LV256U_2 && (FPW) addr[FLASH_ID4] == (FPW) AMD_ID_LV256U_3) { /* attention: only the first 16 MB will be used in u-boot */ info->flash_id += FLASH_AMLV256U; info->sector_count = 512; info->size = 0x02000000; for (i = 0; i < info->sector_count; i++) { info->start[i] = (ulong) addr + 0x10000 * i; } break; } /* fall thru to here ! */ default: printf("unknown AMD device=%x %x %x", (FPW) addr[FLASH_ID2], (FPW) addr[FLASH_ID3], (FPW) addr[FLASH_ID4]); info->flash_id = FLASH_UNKNOWN; info->sector_count = 0; info->size = 0x800000; break; } /* Put FLASH back in read mode */ flash_reset(info); } return (info->size); }
/* * Write a word to Flash, returns: * 0 - OK * 1 - write timeout * 2 - Flash not erased */ static int write_word (flash_info_t *info, ulong dest, ulong data) { volatile u32 addr = info->start[0]; ulong start; int flag, i; /* Check if Flash is (sufficiently) erased */ if ((in32(dest) & data) != data) { return (2); } /* Disable interrupts which might cause a timeout here */ flag = disable_interrupts(); /* first, perform an unlock bypass command to speed up flash writes */ out8(addr + 0x555, 0xAA); iobarrier_rw(); out8(addr + 0x2AA, 0x55); iobarrier_rw(); out8(addr + 0x555, 0x20); iobarrier_rw(); /* write each byte out */ for (i = 0; i < 4; i++) { char *data_ch = (char *)&data; out8(addr, 0xA0); iobarrier_rw(); out8(dest+i, data_ch[i]); iobarrier_rw(); udelay(10); /* XXX */ } /* we're done, now do an unlock bypass reset */ out8(addr, 0x90); iobarrier_rw(); out8(addr, 0x00); iobarrier_rw(); /* re-enable interrupts if necessary */ if (flag) enable_interrupts(); /* data polling for D7 */ start = get_timer (0); while ((in32(dest) & 0x80808080) != (data & 0x80808080)) { if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { return (1); } iobarrier_rw(); } flash_reset (addr); return (0); }
static int flash_eraseblk(unsigned long addr) { unsigned long a; uint16 st; a = (unsigned long)addr; if (a >= flashutl_desc->size) return 1; a = block(a, BLOCK_BASE); /* Ensure blocks are unlocked (for intel chips) */ if (flashutl_cmd->type == BSC) { scmd((unsigned char)INTEL_UNLOCK1, a); scmd((unsigned char)INTEL_UNLOCK2, a); } if (flashutl_cmd->pre_erase) cmd(flashutl_cmd->pre_erase, CMD_ADDR); if (flashutl_cmd->erase_block) cmd(flashutl_cmd->erase_block, a); if (flashutl_cmd->confirm) scmd(flashutl_cmd->confirm, a); if (flashutl_wsz == sizeof(uint8)) st = flash_poll(a, 0xff); else st = flash_poll(a, 0xffff); flash_reset(); if (st) { DPRINT(("Erase of block 0x%08lx-0x%08lx failed\n", a, block((unsigned long)addr, BLOCK_LIM))); return st; } DPRINT(("Erase of block 0x%08lx-0x%08lx done\n", a, block((unsigned long)addr, BLOCK_LIM))); return 0; }
int flash_page_program(uint8_t buf[], uint16_t row_addr) { int j; flash_reset(1); CLE_FLASH_HI(); *(volatile uint8_t*)(FLASH_ADDR) = (uint8_t)0x80; CLE_FLASH_LO(); ALE_FLASH_HI(); *(volatile uint8_t*)(FLASH_ADDR) = (uint8_t)0x00; *(volatile uint8_t*)(FLASH_ADDR) = (uint8_t)0x00; *(volatile uint8_t*)(FLASH_ADDR) = (uint8_t)(0xFF & row_addr); *(volatile uint8_t*)(FLASH_ADDR) = (uint8_t)((0xFF & row_addr) >> 8); ALE_FLASH_LO(); for(int i = 0; i < 2112; i++) { *(volatile uint8_t*)(FLASH_ADDR) = buf[i]; } CLE_FLASH_HI(); *(volatile uint8_t*)(FLASH_ADDR) = 0x10; CLE_FLASH_LO(); j = flash_wait_rb(0x7FFF); return j; }
void main(void) { byte test; byte manuf_id; word device_id; byte far *str; word test2,i; dword sec_size=0; long count=0; printf("Beginning test.....\n\n"); /* First, poke around the memory map to see what kind of flash is installed in the socket...assume a DL800B */ /* The purpose of init_flash is to perform any system memory mapping required, and to set up pointers to those region(s). init_flash() also selects the proper sector organization table defined in flash.c Note: init_flash() will need to be provided by users of the flash.c routines */ if(!init_flash(AM29DL800B)) { exit(1); } /* Verify the manufacturer code is indeed 0x01 for AMD */ manuf_id = flash_get_manuf_code(0); switch(manuf_id) { case AMDPART: printf("AMD Flash found in socket...\n"); break; default: printf("Non AMD part found in socket...exiting.\n"); exit(1); break; } /* Poll the device id so that the proper sector layout table is used for the device in the socket */ printf("Polling part for Device ID..."); /* Retrieve the device ID for this AMD flash part. All device id's are stored in flash.h */ device_id = flash_get_device_id(0); switch(device_id) { case ID_AM29DL800T: printf("found an Am29DL800T\n"); if(!init_flash(AM29DL800T)) exit(1); break; case ID_AM29DL800B: printf("found an Am29DL800B\n"); if(!init_flash(AM29DL800B)) exit(1); break; case ID_AM29LV800T: printf("found an Am29LV800T\n"); if(!init_flash(AM29LV800T)) exit(1); break; case ID_AM29LV800B: printf("found an Am29LV800B\n"); if(!init_flash(AM29LV800B)) exit(1); break; case ID_AM29LV160B: printf( "found an Am29LV160B\n"); if(!init_flash(AM29LV160B)) exit(1); break; case ID_AM29LV400B: printf( "found an Am29LV400B\n"); if(!init_flash(AM29LV400B)) exit(1); break; default: printf("error reading Device ID...exiting.\n"); exit(1); break; } randomize(); /* flash_get_status uses DQ7, DQ5, and DQ2 polling to get the status of the flash. All status codes are defined in flash.h Also note that for the DL parts, status is bank dependent */ printf("Checking current flash status...flash is "); test = flash_get_status(0); switch(test) { case STATUS_READY: printf("[Ready]\n");break; case STATUS_BUSY: printf("[Busy]\n");break; case STATUS_ERSUSP: printf("[Erase Suspended]\n");break; case STATUS_TIMEOUT: printf("[Timed Out]\n");break; default: printf("Error!\n"); exit(1);break; } printf("Performing API tests...\n\n"); /* flash_sector_erase_int() is the function which erases a single sector. It is different from flash_sector_erase() in that it 'interrupts' execution of the program until the erase is completed. For erasing a sector without pausing use flash_sector_erase(). */ flash_reset(); /* Quick safe check */ printf("Erasing sector 8..."); flash_sector_erase_int(8); printf("done.\n"); printf("Verifying erase..."); flash_get_sector_size(8, &sec_size); /* Get # of byte */ /* A simple test which reads every word from the flash, and checks to see if every word contains the data 0xFFFF, which indicates an erased word. */ for (count=0 ; count < (sec_size/2); count++) { if(count%2048 == 0) printf("."); /*print out some dots to show the program hasn't frozen */ if (flash_read_word(8,count) != 0xFFFF) { printf("erase not completed sucessfully!\n"); exit(1); } } printf("erase successful.\n"); /* flash_write_word() takes word data and programs it to the flash at the indicated offset. Note that this data must be *word aligned*, or else programming errors can result. It is also good to check the word for 0xFFFF data before programming. */ printf("Writing a single word [0xABCD]\n"); flash_write_word(8,0,0xABCD); /* flash_read_word() returns a single word of data at the specified sector/offset . Must also be word aligned */ printf("After write(0xABCD): %4x\n", flash_read_word(8,0)); str = (byte far *) calloc(0x7FFF, sizeof(byte)); /* Randomize the string with random ASCII characters */ for(i=0; i<0x7FFF; i++) { str[i] = (byte) (41 + (rand() % 26)); } printf("Erasing sector 9..."); flash_sector_erase_int(9); printf("done.\n"); /* flash_write_string() is a function to program bulk data from a C buffer. It is a bit faster than looping techniques using flash_write_word() because function overhead is eliminated. */ printf("Writing 32 kbyte string..."); flash_write_string(9,0,str,0x7FFE); printf("done.\n\n"); printf("Testing erase suspend\n"); printf("Beginning erase...\n"); /* This is an example of flash_sector_erase(). Note that the program will simply issue the command, and execution will continue while the flash is erasing. */ flash_sector_erase(10); /* flash_erase_suspend will suspend an erase in progress. The application can then do any reading of data from that sector, or another sector. */ printf("Suspending erase..."); flash_erase_suspend(10); printf("done.\n"); /* The current flash status should now be STATUS_ERSUSP */ printf("Checking current flash status...flash is "); test = flash_get_status(10); switch(test) { case STATUS_READY: printf("[Ready]\n");break; case STATUS_BUSY: printf("[Busy]\n");break; case STATUS_ERSUSP: printf("[Erase Suspended]\n");break; case STATUS_TIMEOUT: printf("[Timed Out]\n");break; default: printf("Error!\n"); exit(1);break; } /* Now we can resume the erase previously suspended */ printf("Resuming erase after status check.."); flash_erase_resume(10); printf("done.\n"); /* Now for a test of unlock bypass mode */ /* Unlock bypass allows for faster programming of flash data in that the number of required bus cycles is cut in half. The most benefit can be realized when programming large amounts of data using flash_write_string_ub() */ printf("Entering unlock bypass mode...\n"); flash_sector_erase_int(11); flash_ub(11); /* Enter unlock bypass mode */ printf("Programming a string in unlock bypass mode.."); flash_write_string_ub(11,0,str,0x7FFE); printf("done.\n"); printf("Exiting unlock bypass mode..\n"); flash_reset_ub(); flash_reset(); /* Last thing is a quick loop through all the sectors to check for sector protection. */ printf("\nVerifying sector protection...\n"); flash_get_numsectors(&test2); printf("This device contains %3i sectors: \n", test2); for(i=0; i < test2; i++) { test = flash_sector_protect_verify(i); flash_get_sector_size(i, &size); printf("Verify sector #%2i, size [%-5li]: ", i, size); if (test == 0x01) printf("sector is protected[%2i].\n", test); else printf("sector is not protected[%2i].\n", test); flash_reset(); } printf("Test drive done!\n"); free(str); exit(0); }
int flash_erase(flash_info_t * info, int s_first, int s_last) { FPWV *addr; int flag, prot, sect; int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL; ulong start, now, last; int rcode = 0; if ((s_first < 0) || (s_first > s_last)) { if (info->flash_id == FLASH_UNKNOWN) { printf("- missing\n"); } else { printf("- no sectors to erase\n"); } return 1; } switch (info->flash_id & FLASH_TYPEMASK) { case FLASH_AMLV256U: break; case FLASH_UNKNOWN: default: printf("Can't erase unknown flash type %08lx - aborted\n", info->flash_id); return 1; } prot = 0; for (sect = s_first; sect <= s_last; ++sect) { if (info->protect[sect]) { prot++; } } if (prot) { printf("- Warning: %d protected sectors will not be erased!\n", prot); } else { printf("\n"); } last = get_timer(0); /* Start erase on unprotected sectors */ for (sect = s_first; sect <= s_last && rcode == 0; sect++) { if (info->protect[sect] != 0) { /* protected, skip it */ continue; } /* Disable interrupts which might cause a timeout here */ flag = disable_interrupts(); addr = (FPWV *) (info->start[sect]); if (intel) { *addr = (FPW) 0x00500050; /* clear status register */ *addr = (FPW) 0x00200020; /* erase setup */ *addr = (FPW) 0x00D000D0; /* erase confirm */ } else { /* must be AMD style if not Intel */ FPWV *base; /* first address in bank */ base = (FPWV *) (info->start[0]); base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */ base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */ base[FLASH_CYCLE1] = (FPW) 0x00800080; /* erase mode */ base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */ base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */ *addr = (FPW) 0x00300030; /* erase sector */ } /* re-enable interrupts if necessary */ if (flag) { enable_interrupts(); } start = get_timer(0); /* wait at least 50us for AMD, 80us for Intel. */ /* Let's wait 1 ms. */ udelay(1000); while ((*addr & (FPW) 0x00800080) != (FPW) 0x00800080) { if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) { printf("Timeout\n"); if (intel) { /* suspend erase */ *addr = (FPW) 0x00B000B0; } flash_reset(info); /* reset to read mode */ rcode = 1; /* failed */ break; } /* show that we're waiting */ if ((get_timer(last)) > CFG_HZ) { /* every second */ putc('.'); last = get_timer(0); } } /* show that we're waiting */ if ((get_timer(last)) > CFG_HZ) { /* every second */ putc('.'); last = get_timer(0); } flash_reset(info); /* reset to read mode */ } printf(" done\n"); return (rcode); }
/* Read the flash ID and set the globals */ int sysFlashInit(char *flash_str) { osl_t *osh; uint32 fltype = PFLASH; uint16 flash_vendid = 0; uint16 flash_devid = 0; int idx; struct sflash *sflash; /* * Check for serial flash. */ sih = si_kattach(SI_OSH); ASSERT(sih); osh = si_osh(sih); cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX); ASSERT(cc); flashutl_base = (void *)OSL_UNCACHED((uintptr)SI_FLASH2); /* Select SFLASH ? */ fltype = R_REG(osh, &cc->capabilities) & CC_CAP_FLASH_MASK; if (fltype == SFLASH_ST || fltype == SFLASH_AT) { if (sih->ccrev == 12) flashutl_base = (void *)OSL_UNCACHED((uintptr)SI_FLASH2); else flashutl_base = (void *)OSL_CACHED((uintptr)SI_FLASH2); sflash = sflash_init(sih, cc); flashutl_cmd = &sflash_cmd_t; flashutl_desc = &sflash_desc; flashutl_desc->size = sflash->size; if (flash_str) sprintf(flash_str, "SFLASH %d kB", sflash->size/1024); return (0); } flashutl_wsz = (R_REG(osh, &cc->flash_config) & CC_CFG_DS) ? sizeof(uint16) : sizeof(uint8); ASSERT(flashutl_wsz == sizeof(uint8) || flashutl_wsz == sizeof(uint16)); /* * Parallel flash support * Some flashes have different unlock addresses, try each it turn */ for (idx = 0; fltype == PFLASH && idx < ARRAYSIZE(flash_cmds); idx ++) { flashutl_cmd = &flash_cmds[idx]; if (flashutl_cmd->type == OLD) continue; if (flashutl_cmd->read_id) { cmd(flashutl_cmd->read_id, CMD_ADDR); /* Delay for turn around time */ OSL_DELAY(1); } #ifdef MIPSEB #ifdef BCMHND74K flash_vendid = flash_readword(FLASH_ADDR(0)^6); flash_devid = flash_readword(FLASH_ADDR(2)^6); #else /* !74K, bcm33xx */ flash_vendid = flash_readword(FLASH_ADDR(2)); flash_devid = flash_readword(FLASH_ADDR(0)); #endif /* BCMHND74K */ #else flash_vendid = flash_readword(FLASH_ADDR(0)); flash_devid = flash_readword(FLASH_ADDR(2)); #endif /* MIPSEB */ /* Funky AMD, uses 3 byte device ID so use first byte (4th addr) to * identify it is a 3-byte ID and use the next two bytes (5th & 6th addr) * to form a word for unique identification of format xxyy, where * xx = 5th addr and yy = 6th addr */ if ((flash_vendid == 1) && ((flash_devid == 0x227e && flashutl_wsz == sizeof(uint16)) || (flash_devid == 0x7e && flashutl_wsz == sizeof(uint8)))) { /* Get real devid */ uint16 flash_devid_5th; #ifdef MIPSEB #ifdef BCMHND74K flash_devid_5th = flash_readword(FLASH_ADDR(0x1c)^6) << 8; flash_devid = (flash_readword(FLASH_ADDR(0x1e)^6) & 0xff) | flash_devid_5th; #else /* !74K, bcm33xx */ flash_devid_5th = flash_readword(FLASH_ADDR(0x1e)) << 8; flash_devid = (flash_readword(FLASH_ADDR(0x1c)) & 0xff) | flash_devid_5th; #endif /* BCMHND74K */ #else flash_devid_5th = flash_readword(FLASH_ADDR(0x1c)) << 8; flash_devid = (flash_readword(FLASH_ADDR(0x1e)) & 0xff) | flash_devid_5th; #endif /* MIPSEB */ } flashutl_desc = flashes; while (flashutl_desc->mfgid != 0 && !(flashutl_desc->mfgid == flash_vendid && flashutl_desc->devid == flash_devid)) { flashutl_desc++; } if (flashutl_desc->mfgid != 0) break; } if (flashutl_desc->mfgid == 0) { flashutl_desc = NULL; flashutl_cmd = NULL; } else { flashutl_cmd = flash_cmds; while (flashutl_cmd->type != 0 && flashutl_cmd->type != flashutl_desc->type) flashutl_cmd++; if (flashutl_cmd->type == 0) flashutl_cmd = NULL; } if (flashutl_cmd != NULL) { flash_reset(); } if (flashutl_desc == NULL) { if (flash_str) sprintf(flash_str, "UNKNOWN 0x%x 0x%x", flash_vendid, flash_devid); DPRINT(("Flash type UNKNOWN\n")); return 1; } if (flash_str) strcpy(flash_str, flashutl_desc->desc); DPRINT(("Flash type \"%s\"\n", flashutl_desc->desc)); return 0; }
static int flash_write(unsigned long off, uint8 *src, uint nbytes) { uint8 *dest; uint16 st, data; uint i, len; ASSERT(flashutl_desc != NULL); if (off >= flashutl_desc->size) return 1; ASSERT(!(off & (flashutl_wsz - 1))); dest = (uint8*)FLASH_ADDR(off); st = 0; while (nbytes) { if ((flashutl_desc->type == SCS) && flashutl_cmd->write_buf && ((off & (WBUFSIZE - 1)) == 0)) { /* issue write command */ if (flashutl_cmd->write_buf) cmd(flashutl_cmd->write_buf, off); if ((st = flash_poll(off, DONE))) continue; len = MIN(nbytes, WBUFSIZE); #ifndef MIPSEB /* write (length - 1) */ cmd(len / sizeof(uint16) - 1, off); /* write data */ for (i = 0; i < len; i += sizeof(uint16), dest += sizeof(uint16), src += sizeof(uint16)) *(uint16 *)dest = *(uint16 *)src; #else /* * BCM4710 endianness is word consistent but * byte/short scrambled. This write buffer * mechanism appears to be sensitive to the * order of the addresses hence we need to * unscramble them. We may also need to pad * the source with two bytes of 0xffff in case * an odd number of shorts are presented. */ /* write (padded length - 1) */ cmd((ROUNDUP(len, sizeof(uint32)) / sizeof(uint16)) - 1, off); /* write data (plus pad if necessary) */ for (i = 0; i < ROUNDUP(len, sizeof(uint32)); i += sizeof(uint32), dest += sizeof(uint32), src += sizeof(uint32)) { *((uint16 *)dest + 1) = ((i + sizeof(uint16)) < len) ? *((uint16 *)src + 1) : 0xffff; *(uint16 *)dest = *(uint16 *)src; } #endif /* MIPSEB */ /* write confirm */ if (flashutl_cmd->confirm) cmd(flashutl_cmd->confirm, off); if ((st = flash_poll(off, DONE))) break; } else { /* issue write command */ if (flashutl_cmd->write_word) cmd(flashutl_cmd->write_word, CMD_ADDR); /* write data */ data = flash_readword((unsigned long)src); flash_writeword((unsigned long)dest, data); /* poll for done */ if ((st = flash_poll(off, data))) break; len = MIN(nbytes, flashutl_wsz); dest += len; src += len; } nbytes -= len; off += len; } flash_reset(); return st; }
/* * The following code cannot be run from FLASH! */ static ulong flash_get_size (u32 addr, flash_info_t *info) { volatile uchar value; #if 0 int i; #endif /* Write auto select command: read Manufacturer ID */ out8(addr + 0x0555, 0xAA); iobarrier_rw(); udelay(10); out8(addr + 0x02AA, 0x55); iobarrier_rw(); udelay(10); out8(addr + 0x0555, 0x90); iobarrier_rw(); udelay(10); value = in8(addr); iobarrier_rw(); udelay(10); switch (value | (value << 16)) { case AMD_MANUFACT: info->flash_id = FLASH_MAN_AMD; break; case FUJ_MANUFACT: info->flash_id = FLASH_MAN_FUJ; break; default: info->flash_id = FLASH_UNKNOWN; flash_reset (addr); return 0; } value = in8(addr + 1); /* device ID */ iobarrier_rw(); switch (value) { case AMD_ID_LV033C: info->flash_id += FLASH_AM033C; info->size = hwc_flash_size(); if (info->size > CFG_MAX_FLASH_SIZE) { printf("U-Boot supports only %d MB\n", CFG_MAX_FLASH_SIZE); info->size = CFG_MAX_FLASH_SIZE; } info->sector_count = info->size / 0x10000; break; /* => 4 MB */ default: info->flash_id = FLASH_UNKNOWN; flash_reset (addr); return (0); /* => no or unknown flash */ } if (!flash_get_offsets (addr, info)) { flash_reset (addr); return 0; } #if 0 /* check for protected sectors */ for (i = 0; i < info->sector_count; i++) { /* read sector protection at sector address, (A7 .. A0) = 0x02 */ /* D0 = 1 if protected */ value = in8(info->start[i] + 2); iobarrier_rw(); info->protect[i] = (value & 1) != 0; } #endif /* * Reset bank to read mode */ flash_reset (addr); return (info->size); }
int flash_erase(flash_info_t *info, int s_first, int s_last) { FPWV *addr; int prot, sect; int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL; ulong start, now, last; int rcode = 0; int poll,kk,s_kk = 8; u32 s_sector_size = 0x00001000 ; FPWV *base; /* first address in bank */ if ((s_first < 0) || (s_first > s_last)) { if (info->flash_id == FLASH_UNKNOWN) { printf("- missing\n"); } else { printf("- no sectors to erase\n"); } return 1; } switch (info->flash_id & FLASH_TYPEMASK) { case FLASH_INTEL800B: case FLASH_INTEL160B: case FLASH_INTEL320B: case FLASH_INTEL640B: case FLASH_28F800C3B: case FLASH_28F160C3B: case FLASH_28F320C3B: case FLASH_28F640C3B: case FLASH_AM640U: case FLASH_MXLV320BT: case FLASH_MXLV160B: case FLASH_MXLV160T: case AMD_ID_LV320B: case EN_ID_29LV640H: case MX_ID_29LV640DB: case MX_ID_29LV128DB: #if defined (RT3052_MP2) && defined (ON_BOARD_32M_FLASH_COMPONENT) case FLASH_S29GL256N: #endif break; case FLASH_UNKNOWN: default: printf("Can't erase unknown flash type %08lx - aborted\n", info->flash_id); return 1; } prot = 0; for (sect=s_first; sect<=s_last; ++sect) { if (info->protect[sect]) { //kaiker,debug //info->protect[sect]=0; printf("\n protect sect[%d]\n",sect); prot++; } } if (prot) { printf("- Warning: %d protected sectors will not be erased!\n", prot); } else { printf("\n"); } last = get_timer(0); /* Start erase on unprotected sectors */ if(flash_use_SSI_standard) { s_kk = 16; s_sector_size = 0x00000800; printf("\n SSI Manufacture so its small sector \n"); } for (sect = s_first; sect<=s_last && rcode == 0; sect++) { if (info->protect[sect] != 0) /* protected, skip it */ { printf("\n sect[%d] is protected,skip \n",sect); continue; } printf("\n erase sector = %d \n",sect); /* Disable interrupts which might cause a timeout here */ //flag = disable_interrupts(); addr = (FPWV *)(info->start[sect]); //add by kaiker if( sect == 0 || flash_use_SSI_standard == 1) { base = (FPWV *)(info->start[0]); if(flash_use_SSI_standard) { printf("\n Erase to sector address[%08X]\n",addr); } else { printf("\n Erase Sector 0 with 8K SIZE,The sector 0 is Total 64K\n"); } for(kk =0 ; kk < s_kk ;kk++) { /* must be AMD style if not Intel */ base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */ base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */ base[FLASH_CYCLE1] = (FPW)0x00800080; /* erase mode */ base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */ base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */ *addr = (FPW)0x00300030; /* erase sector */ start = get_timer(0); /* wait at least 50us for AMD, 80us for Intel. * Let's wait 1 ms. */ udelay(1000); poll = 0; while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) { if ((now = get_timer(start)) > (ulong)CFG_FLASH_ERASE_TOUT) { printf("Timeout\n"); flash_reset(info); /* reset to read mode */ rcode = 1; /* failed */ break; } poll++; /* show that we're waiting */ if ((get_timer(last)) > CFG_HZ) {/* every second */ putc('*'); last = get_timer(0); } } // printf("sect = %d,s_last = %d,erase poll = %d\n",sect,s_last,poll); /* show that we're waiting */ if ((get_timer(last)) > CFG_HZ) { /* every second */ putc('.'); last = get_timer(0); } flash_reset(info); /* reset to read mode */ // printf("\n Pre addr = %08X \n",addr); addr = addr + s_sector_size; } if(!flash_use_SSI_standard) { printf("\n Exit Sector 0 erase !! \n"); } continue; sect = 7; } if (intel) { *addr = (FPW)0x00500050; /* clear status register */ *addr = (FPW)0x00200020; /* erase setup */ *addr = (FPW)0x00D000D0; /* erase confirm */ } else { /* must be AMD style if not Intel */ // FPWV *base; /* first address in bank */ base = (FPWV *)(info->start[0]); base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */ base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */ base[FLASH_CYCLE1] = (FPW)0x00800080; /* erase mode */ base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */ base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */ *addr = (FPW)0x00300030; /* erase sector */ } /* re-enable interrupts if necessary */ /* if (flag) enable_interrupts(); */ start = get_timer(0); #if 1 /* wait at least 50us for AMD, 80us for Intel. * Let's wait 1 ms. */ udelay(1000); poll = 0; while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) { if ((now = get_timer(start)) > (ulong)CFG_FLASH_ERASE_TOUT) { printf("Timeout\n"); if (intel) { /* suspend erase */ *addr = (FPW)0x00B000B0; } flash_reset(info); /* reset to read mode */ rcode = 1; /* failed */ break; } poll++; /* show that we're waiting */ if ((get_timer(last)) > CFG_HZ) {/* every second */ putc('*'); last = get_timer(0); } } printf("sect = %d,s_last = %d,erase poll = %d\n",sect,s_last,poll); #else #endif /* show that we're waiting */ if ((get_timer(last)) > CFG_HZ) { /* every second */ putc('.'); last = get_timer(0); } flash_reset(info); /* reset to read mode */ } printf(" done\n"); return rcode; }
/*----------------------------------------------------------------------- */ int erase_all_chip(flash_info_t *info, int s_first, int s_last) { int rcode = 0; FPWV *addr; int sect = 0; int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL; ulong start, now, last; int poll; if ((s_first < 0) || (s_first > s_last)) { if (info->flash_id == FLASH_UNKNOWN) { printf("- missing\n"); } else { printf("- no sectors to erase\n"); } return 1; } switch (info->flash_id & FLASH_TYPEMASK) { case FLASH_INTEL800B: case FLASH_INTEL160B: case FLASH_INTEL320B: case FLASH_INTEL640B: case FLASH_28F800C3B: case FLASH_28F160C3B: case FLASH_28F320C3B: case FLASH_28F640C3B: case FLASH_AM640U: case FLASH_MXLV320BT: case FLASH_MXLV160B: case FLASH_MXLV160T: case AMD_ID_LV320B: case EN_ID_29LV640H: break; case FLASH_UNKNOWN: default: printf("Can't erase unknown flash type %08lx - aborted\n", info->flash_id); return 1; } last = get_timer(0); /* Start erase on unprotected sectors */ printf("\n Erase All \n"); // for (sect = s_first; sect<=s_last && rcode == 0; sect++) { /* Disable interrupts which might cause a timeout here */ //flag = disable_interrupts(); addr = (FPWV *)(info->start[sect]); { /* must be AMD style if not Intel */ FPWV *base; /* first address in bank */ base = (FPWV *)(info->start[0]); base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */ base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */ base[FLASH_CYCLE1] = (FPW)0x00800080; /* erase mode */ base[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* unlock */ base[FLASH_CYCLE2] = (FPW)0x00550055; /* unlock */ base[FLASH_CYCLE1] = (FPW)0x10101010; /* erase all */ } /* re-enable interrupts if necessary */ /* if (flag) enable_interrupts(); */ start = get_timer(0); /* wait at least 50us for AMD, 80us for Intel. * Let's wait 1 ms. */ udelay(1000); poll = 0; while ((*addr & (FPW)0x00800080) != (FPW)0x00800080) { if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) { printf("Timeout\n"); if (intel) { /* suspend erase */ *addr = (FPW)0x00B000B0; } flash_reset(info); /* reset to read mode */ rcode = 1; /* failed */ break; } poll++; /* show that we're waiting */ if ((get_timer(last)) > CFG_HZ) {/* every second */ putc('*'); last = get_timer(0); } } printf(" Erase all OK!! \n"); for (sect=s_first; sect<=s_last; ++sect) { if (info->protect[sect]) { //kaiker,debug info->protect[sect]=0; } printf("protect off all !\n"); } flash_reset(info); /* reset to read mode */ } printf(" done\n"); return rcode; }
ulong flash_get_size(FPWV *addr, flash_info_t *info) { /* Write auto select command: read Manufacturer ID */ /* Write auto select command sequence and test FLASH answer */ addr[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */ addr[FLASH_CYCLE2] = (FPW)0x00550055; /* for AMD, Intel ignores this */ addr[FLASH_CYCLE1] = (FPW)0x00900090; /* selects Intel or AMD */ /* The manufacturer codes are only 1 byte, so just use 1 byte. * This works for any bus width and any FLASH device width. */ #if 1 if(addr[0] != (FPW)SST_MANUFACT) { FLASH_CYCLE1 = 0x0555; FLASH_CYCLE2 = 0x02aa; addr[FLASH_CYCLE1] = (FPW)0x00AA00AA; /* for AMD, Intel ignores this */ addr[FLASH_CYCLE2] = (FPW)0x00550055; /* for AMD, Intel ignores this */ addr[FLASH_CYCLE1] = (FPW)0x00900090; /* selects Intel or AMD */ } else { printf("\n The Flash follow SSI standard \n"); flash_use_SSI_standard = 1; } #endif // printf("\n The Flash ID =%08X \n",addr[1]); switch (addr[0] & 0xff) { case (uchar)AMD_MANUFACT: info->flash_id = FLASH_MAN_AMD; // printf("\nFLASH_MAN_AMD\n"); break; case (uchar)INTEL_MANUFACT: info->flash_id = FLASH_MAN_INTEL; // printf("\nFLASH_MAN_INTEL\n"); break; case (uchar)MX_MANUFACT: info->flash_id = FLASH_MAN_MX; // printf("\n vender : MX_MANUFACT \n"); break; case (uchar)AMD_MANUFACT_EON: info->flash_id = FLASH_MAN_AMD; // printf("\n vender : AMD_MANUFACT_EON \n"); break; default: info->flash_id = FLASH_MAN_AMD; // printf("\n vender : AMD_MANUFACT_EON \n"); break; /* info->flash_id = FLASH_UNKNOWN; info->sector_count = 0; info->size = 0; printf("\n FLASH_UNKNOWN \n"); */ break; } /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */ if (info->flash_id != FLASH_UNKNOWN) switch (addr[1]) { case (FPW)AMD_ID_LV640U: /* 29LV640 and 29LV641 have same ID */ info->flash_id += FLASH_AM640U; info->sector_count = 128; info->size = 0x00800000 * (sizeof(FPW)/2); break; /* => 8 or 16 MB */ case (FPW)INTEL_ID_28F800C3B: info->flash_id += FLASH_28F800C3B; info->sector_count = 23; info->size = 0x00100000 * (sizeof(FPW)/2); break; /* => 1 or 2 MB */ case (FPW)INTEL_ID_28F800B3B: info->flash_id += FLASH_INTEL800B; info->sector_count = 23; info->size = 0x00100000 * (sizeof(FPW)/2); break; /* => 1 or 2 MB */ case (FPW)INTEL_ID_28F160C3B: info->flash_id += FLASH_28F160C3B; info->sector_count = 39; info->size = 0x00200000 * (sizeof(FPW)/2); break; /* => 2 or 4 MB */ case (FPW)INTEL_ID_28F160B3B: info->flash_id += FLASH_INTEL160B; info->sector_count = 39; info->size = 0x00200000 * (sizeof(FPW)/2); break; /* => 2 or 4 MB */ case (FPW)INTEL_ID_28F320C3B: info->flash_id += FLASH_28F320C3B; info->sector_count = 71; info->size = 0x00400000 * (sizeof(FPW)/2); break; /* => 4 or 8 MB */ case (FPW)INTEL_ID_28F320B3B: info->flash_id += FLASH_INTEL320B; info->sector_count = 71; info->size = 0x00400000 * (sizeof(FPW)/2); break; /* => 4 or 8 MB */ case (FPW)INTEL_ID_28F640C3B: info->flash_id += FLASH_28F640C3B; info->sector_count = 135; info->size = 0x00800000 * (sizeof(FPW)/2); break; /* => 8 or 16 MB */ case (FPW)INTEL_ID_28F640B3B: info->flash_id += FLASH_INTEL640B; info->sector_count = 135; info->size = 0x00800000 * (sizeof(FPW)/2); break; /* => 8 or 16 MB */ case (FPW)AMD_ID_LV320B: info->flash_id += AMD_ID_LV320B; info->sector_count = 71; info->size = 0x00400000 * (sizeof(FPW)/2); // printf("\n AMD_ID_LV320B, Size = %08x bytes\n",info->size); break; /* => 4 or 8 MB */ case (FPW)MX_ID_LV320BT: info->flash_id += MX_ID_LV320BT; info->sector_count = 71; info->size = 0x00400000 * (sizeof(FPW)/2); // printf("\n MX_ID_LV320BT, Size = %08x bytes\n",info->size); break; /* => 4 or 8 MB */ case (FPW)MX_ID_LV160B: case (FPW)MX_ID_LV160T: info->flash_id += addr[1]; info->sector_count = 35; info->size = 0x00200000 * (sizeof(FPW)/2); // printf("\n MX_ID_LV160B, Size = %08x bytes\n",info->size); break; case (FPW)MX_ID_29LV640DB: info->flash_id += MX_ID_29LV640DB; info->sector_count = 135; info->size = 0x00800000 * (sizeof(FPW)/2); break; case (FPW)MX_ID_29LV128DB: info->flash_id += MX_ID_29LV128DB; info->sector_count = 263; info->size = 0x01000000 * (sizeof(FPW)/2); break; #if defined (RT3052_MP2) && defined (ON_BOARD_32M_FLASH_COMPONENT) case (FPW)FLASH_S29GL256N: /* winfred: * To support 32MB*1 (Spansion S29GL256N) flash on * RT3052 MP2, we separate it into 2 16MB bank: * bank 0: 0xBF000000 ~ 0xBFFFFFFF * bank 1: 0xBB000000 ~ 0xBBFFFFFF * So, we need to modify the flash info. * (We currently use first bank only, which makes * the sector_count to be 256 instead of 512. * Besides, sectorsize is 0x10000(wrong) instead of * 0x20000, and size is 0x1000000(wront) instead of * 0x2000000.) */ info->flash_id += FLASH_S29GL256N; info->sector_count = 256; info->size = 0x01000000 * (sizeof(FPW)/2); break; #endif default: info->flash_id += EN_ID_29LV640H; info->sector_count = 128; info->size = 0x00800000 * (sizeof(FPW)/2); // printf("\n EN_ID_29LV640H, Size = %08x bytes\n",info->size); break; #if 0 info->flash_id = FLASH_UNKNOWN; info->sector_count = 0; info->size = 0; return (0); /* => no or unknown flash */ #endif break; } flash_get_offsets((ulong)addr, info); /* Put FLASH back in read mode */ flash_reset(info); return (info->size); }
void init_jasmine(void) { UINT32 i, bank; extern UINT32 Image$$ER_ZI$$ZI$$Base; extern UINT32 Image$$ER_ZI$$ZI$$Length; // PLL initialization SETREG(CLKSelCon, USE_BYPASS_CLK); SETREG(PllCon, PLL_PD); // power down delay(600); // at least 500ns SETREG(PllCon, PLL_CLK_CONFIG | PLL_PD); // change settings delay(600); // at least 1us SETREG(PllCon, PLL_CLK_CONFIG); // power up while ((GETREG(PllCon) & PLL_LD) == 0); // wait lock SETREG(CLKSelCon, USE_PLL_CLK); // reset hardware modules SETREG(PMU_ResetCon, RESET_SDRAM | RESET_BM | RESET_SATA | RESET_FLASH); // GPIO bits // There are 7 GPIO bits from 0 to 6. // 0: This bit is connected to J2 (Factory Mode jumper). The ROM firmware configures it as input mode. // While main firmware is running, it can be freely used for arbitrary purpose. Beware that a "1" output while // the Factory Mode jumper is set to Normal position (tied to ground) can lead to circuit damage. // A "0" output while the jumper is tied to Vcc will also lead to circuit damage. // 1: This bit is connected to J3 (Boot ROM). The controller hardware checks its status upon reset. // After the reset is done, you can remove the jumper and use the pin as output. // 2 through 5: The IO pins for these bits are shared between MAX3232C (UART chip) and J4. // In order to use J4, you have to turn on the switches of SW4 and turn off the switches 1 through 4 in SW2. // In order to use UART, you have to turn off the switches of SW4 and turn on the switches 1 through 4 in SW2. // 6: This bit is connected to D4 (LED) via SW2. #if OPTION_UART_DEBUG SETREG(GPIO_MOD, 0); SETREG(GPIO_DIR, BIT3 | BIT4 | BIT6); // output pins: 3(UART_TXD), 4(UART_RTS), 6(LED) #else SETREG(GPIO_MOD, 7); SETREG(GPIO_DIR, BIT2 | BIT3 | BIT4 | BIT5 | BIT6); #endif SETREG(GPIO_REG, 0); // initial state of LED is "off" // ZI region is zero-filled by hardware. mem_set_sram((UINT32) &Image$$ER_ZI$$ZI$$Base, 0x00000000, (UINT32) &Image$$ER_ZI$$ZI$$Length); SETREG(PHY_DEBUG, 0x40000139); while((GETREG(PHY_DEBUG) & BIT30) == 1); SETREG(SDRAM_INIT, SDRAM_PARAM_MAIN_FW_INIT); SETREG(SDRAM_REFRESH, SDRAM_PARAM_MAIN_FW_REFRESH); SETREG(SDRAM_TIMING, SDRAM_PARAM_MAIN_FW_TIMING); SETREG(SDRAM_MRS, SDRAM_PARAM_MAIN_FW_MRS); SETREG(SDRAM_CTRL, SDRAM_INITIALIZE); // initialization of SDRAM begins now while (GETREG(SDRAM_STATUS) & 0x00000010); // wait until the initialization completes (200us) for (i = 0; i < DRAM_SIZE / MU_MAX_BYTES; i++) { mem_set_dram(DRAM_BASE + i * MU_MAX_BYTES, 0x00000000, MU_MAX_BYTES); } #if OPTION_UART_DEBUG uart_init(); uart_print("Welcome to OpenSSD"); #endif SETREG(SDRAM_ECC_MON, 0xFFFFFFFF); // configure SDRAM interrupt SETREG(SDRAM_INTCTRL, SDRAM_INT_ENABLE); // clear interrupt flags in DRAM controller SETREG(SDRAM_INTSTATUS, 0xFFFFFFFF); // configure ICU SETREG(APB_ICU_CON, INTR_SATA); // SATA = FIQ, other = IRQ SETREG(APB_INT_MSK, INTR_SATA | INTR_FLASH | INTR_SDRAM | INTR_TIMER_1 | INTR_TIMER_2 | INTR_TIMER_3); // clear interrupt flags in ICU SETREG(APB_INT_STS, 0xFFFFFFFF); flash_reset(); SETREG(FCONF_PAUSE, 0); SETREG(INTR_MASK, 0); for (bank = 0; bank < NUM_BANKS; bank++) { flash_clear_irq(); SETREG(FCP_CMD, FC_COL_ROW_READ_OUT); SETREG(FCP_OPTION, 0x06); // FO_E SETREG(FCP_DMA_ADDR, g_temp_mem); SETREG(FCP_DMA_CNT, BYTES_PER_SECTOR); SETREG(FCP_COL, 0); SETREG(FCP_ROW_L(bank), STAMP_PAGE_OFFSET); SETREG(FCP_ROW_H(bank), STAMP_PAGE_OFFSET); flash_issue_cmd(bank, RETURN_WHEN_DONE); if ( (BSP_INTR(bank) & 0xFE)== 0 ) break; } #if OPTION_FTL_TEST == FALSE sata_reset(); #endif ftl_open(); #if OPTION_FTL_TEST == TRUE extern void ftl_test(); ftl_test(); led(1); while (1); #endif }
/*----------------------------------------------------------------------- */ ulong flash_get_size( ulong baseaddr, flash_info_t *info ) { short i; unsigned long flashtest_h, flashtest_l; /* Write auto select command sequence and test FLASH answer */ V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00AA00AA; V_ULONG(baseaddr + ((ulong)0x02AA << 3)) = 0x00550055; V_ULONG(baseaddr + ((ulong)0x0555 << 3)) = 0x00900090; V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00AA00AA; V_ULONG(baseaddr + 4 + ((ulong)0x02AA << 3)) = 0x00550055; V_ULONG(baseaddr + 4 + ((ulong)0x0555 << 3)) = 0x00900090; flashtest_h = V_ULONG(baseaddr); /* manufacturer ID */ flashtest_l = V_ULONG(baseaddr + 4); if ((int)flashtest_h == AMD_MANUFACT) { info->flash_id = FLASH_MAN_AMD; } else { info->flash_id = FLASH_UNKNOWN; info->sector_count = 0; info->size = 0; return (0); /* no or unknown flash */ } flashtest_h = V_ULONG(baseaddr + 8); /* device ID */ flashtest_l = V_ULONG(baseaddr + 12); if (flashtest_h != flashtest_l) { info->flash_id = FLASH_UNKNOWN; return(0); } switch((int)flashtest_h) { case AMD_ID_DL323B: info->flash_id += FLASH_AMDL323B; info->sector_count = 71; info->size = 0x01000000; /* 4 * 4 MB = 16 MB */ break; case AMD_ID_LV640U: /* AMDLV640 and AMDLV641 have same ID */ info->flash_id += FLASH_AMLV640U; info->sector_count = 128; info->size = 0x02000000; /* 4 * 8 MB = 32 MB */ break; default: info->flash_id = FLASH_UNKNOWN; return(0); /* no or unknown flash */ } if(flashtest_h == AMD_ID_LV640U) { /* set up sector start adress table (uniform sector type) */ for (i = 0; i < info->sector_count; i++) info->start[i] = baseaddr + (i * 0x00040000); } else { /* set up sector start adress table (bottom sector type) */ for (i = 0; i < 8; i++) { info->start[i] = baseaddr + (i * 0x00008000); } for (i = 8; i < info->sector_count; i++) { info->start[i] = baseaddr + (i * 0x00040000) - 0x001C0000; } } /* check for protected sectors */ for (i = 0; i < info->sector_count; i++) { /* read sector protection at sector address, (A7 .. A0) = 0x02 */ if ((V_ULONG( info->start[i] + 16 ) & 0x00010001) || (V_ULONG( info->start[i] + 20 ) & 0x00010001)) { info->protect[i] = 1; /* D0 = 1 if protected */ } else { info->protect[i] = 0; } } flash_reset(); return(info->size); }
/* * The following code cannot be run from FLASH! */ static ulong flash_get_size (ulong addr, flash_info_t *info) { short i; uchar value; uchar *x = (uchar *)addr; flash_to_xd(); /* Write auto select command: read Manufacturer ID */ x[0x0555] = 0xAA; __asm volatile ("sync\n eieio"); x[0x02AA] = 0x55; __asm volatile ("sync\n eieio"); x[0x0555] = 0x90; __asm volatile ("sync\n eieio"); value = x[0]; __asm volatile ("sync\n eieio"); DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (ulong)addr, value); switch (value | (value << 16)) { case AMD_MANUFACT: info->flash_id = FLASH_MAN_AMD; break; case FUJ_MANUFACT: info->flash_id = FLASH_MAN_FUJ; break; case STM_MANUFACT: info->flash_id = FLASH_MAN_STM; break; default: info->flash_id = FLASH_UNKNOWN; info->sector_count = 0; info->size = 0; flash_reset (addr); return 0; } value = x[1]; __asm volatile ("sync\n eieio"); DEBUGF("Device ID @ 0x%08lx: 0x%08x\n", addr+1, value); switch (value) { case AMD_ID_F040B: DEBUGF("Am29F040B\n"); info->flash_id += FLASH_AM040; info->sector_count = 8; info->size = 0x00080000; break; /* => 512 kB */ case AMD_ID_LV040B: DEBUGF("Am29LV040B\n"); info->flash_id += FLASH_AM040; info->sector_count = 8; info->size = 0x00080000; break; /* => 512 kB */ case AMD_ID_LV400T: DEBUGF("Am29LV400T\n"); info->flash_id += FLASH_AM400T; info->sector_count = 11; info->size = 0x00100000; break; /* => 1 MB */ case AMD_ID_LV400B: DEBUGF("Am29LV400B\n"); info->flash_id += FLASH_AM400B; info->sector_count = 11; info->size = 0x00100000; break; /* => 1 MB */ case AMD_ID_LV800T: DEBUGF("Am29LV800T\n"); info->flash_id += FLASH_AM800T; info->sector_count = 19; info->size = 0x00200000; break; /* => 2 MB */ case AMD_ID_LV800B: DEBUGF("Am29LV400B\n"); info->flash_id += FLASH_AM800B; info->sector_count = 19; info->size = 0x00200000; break; /* => 2 MB */ case AMD_ID_LV160T: DEBUGF("Am29LV160T\n"); info->flash_id += FLASH_AM160T; info->sector_count = 35; info->size = 0x00400000; break; /* => 4 MB */ case AMD_ID_LV160B: DEBUGF("Am29LV160B\n"); info->flash_id += FLASH_AM160B; info->sector_count = 35; info->size = 0x00400000; break; /* => 4 MB */ case AMD_ID_LV320T: DEBUGF("Am29LV320T\n"); info->flash_id += FLASH_AM320T; info->sector_count = 67; info->size = 0x00800000; break; /* => 8 MB */ #if 0 /* Has the same ID as AMD_ID_LV320T, to be fixed */ case AMD_ID_LV320B: DEBUGF("Am29LV320B\n"); info->flash_id += FLASH_AM320B; info->sector_count = 67; info->size = 0x00800000; break; /* => 8 MB */ #endif case AMD_ID_LV033C: DEBUGF("Am29LV033C\n"); info->flash_id += FLASH_AM033C; info->sector_count = 64; info->size = 0x01000000; break; /* => 16Mb */ case STM_ID_F040B: DEBUGF("M29F040B\n"); info->flash_id += FLASH_AM040; info->sector_count = 8; info->size = 0x00080000; break; /* => 512 kB */ default: info->flash_id = FLASH_UNKNOWN; flash_reset (addr); flash_to_mem(); return (0); /* => no or unknown flash */ } if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) { printf ("** ERROR: sector count %d > max (%d) **\n", info->sector_count, CONFIG_SYS_MAX_FLASH_SECT); info->sector_count = CONFIG_SYS_MAX_FLASH_SECT; } if (! flash_get_offsets (addr, info)) { flash_reset (addr); flash_to_mem(); return 0; } /* check for protected sectors */ for (i = 0; i < info->sector_count; i++) { /* read sector protection at sector address, (A7 .. A0) = 0x02 */ /* D0 = 1 if protected */ value = in8(info->start[i] + 2); iobarrier_rw(); info->protect[i] = (value & 1) != 0; } /* * Reset bank to read mode */ flash_reset (addr); flash_to_mem(); return (info->size); }
int flash_erase (flash_info_t *info, int s_first, int s_last) { volatile ulong addr = info->start[0]; int flag, prot, sect, l_sect; ulong start, now, last; flash_to_xd(); if (s_first < 0 || s_first > s_last) { if (info->flash_id == FLASH_UNKNOWN) { printf ("- missing\n"); } else { printf ("- no sectors to erase\n"); } flash_to_mem(); return 1; } if (info->flash_id == FLASH_UNKNOWN) { printf ("Can't erase unknown flash type %08lx - aborted\n", info->flash_id); flash_to_mem(); return 1; } prot = 0; for (sect=s_first; sect<=s_last; ++sect) { if (info->protect[sect]) { prot++; } } if (prot) { printf ("- Warning: %d protected sectors will not be erased!\n", prot); } else { printf ("\n"); } l_sect = -1; /* Disable interrupts which might cause a timeout here */ flag = disable_interrupts(); out8(addr + 0x555, 0xAA); iobarrier_rw(); out8(addr + 0x2AA, 0x55); iobarrier_rw(); out8(addr + 0x555, 0x80); iobarrier_rw(); out8(addr + 0x555, 0xAA); iobarrier_rw(); out8(addr + 0x2AA, 0x55); iobarrier_rw(); /* Start erase on unprotected sectors */ for (sect = s_first; sect<=s_last; sect++) { if (info->protect[sect] == 0) { /* not protected */ addr = info->start[sect]; out8(addr, 0x30); iobarrier_rw(); l_sect = sect; } } /* re-enable interrupts if necessary */ if (flag) enable_interrupts(); /* wait at least 80us - let's wait 1 ms */ udelay (1000); /* * We wait for the last triggered sector */ if (l_sect < 0) goto DONE; start = get_timer (0); last = start; addr = info->start[l_sect]; DEBUGF ("Start erase timeout: %d\n", CONFIG_SYS_FLASH_ERASE_TOUT); while ((in8(addr) & 0x80) != 0x80) { if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) { printf ("Timeout\n"); flash_reset (info->start[0]); flash_to_mem(); return 1; } /* show that we're waiting */ if ((now - last) > 1000) { /* every second */ putc ('.'); last = now; } iobarrier_rw(); } DONE: /* reset to read mode */ flash_reset (info->start[0]); flash_to_mem(); printf (" done\n"); return 0; }
/*----------------------------------------------------------------------- */ ulong flash_get_size (ulong baseaddr, flash_info_t * info) { int i; unsigned long msr; DWORD flashtest; DWORD cmd_select[3] = { 0x00AA00AA00AA00AALL, 0x0055005500550055LL, 0x0090009000900090LL }; /* Enable FPU */ msr = get_msr (); set_msr (msr | MSR_FP); /* Write auto-select command sequence */ write_via_fpu ((DWORD*)(baseaddr + (0x0555 << 3)), &cmd_select[0] ); write_via_fpu ((DWORD*)(baseaddr + (0x02AA << 3)), &cmd_select[1] ); write_via_fpu ((DWORD*)(baseaddr + (0x0555 << 3)), &cmd_select[2] ); /* Restore FPU */ set_msr (msr); /* Read manufacturer ID */ flashtest = *(volatile DWORD*)baseaddr; switch ((int)flashtest) { case AMD_MANUFACT: info->flash_id = FLASH_MAN_AMD; break; case FUJ_MANUFACT: info->flash_id = FLASH_MAN_FUJ; break; default: /* No, faulty or unknown flash */ info->flash_id = FLASH_UNKNOWN; info->sector_count = 0; info->size = 0; return (0); } /* Read device ID */ flashtest = *(volatile DWORD*)(baseaddr + 8); switch ((long)flashtest) { case AMD_ID_LV800T: info->flash_id += FLASH_AM800T; info->sector_count = 19; info->size = 0x00400000; break; case AMD_ID_LV800B: info->flash_id += FLASH_AM800B; info->sector_count = 19; info->size = 0x00400000; break; case AMD_ID_LV160T: info->flash_id += FLASH_AM160T; info->sector_count = 35; info->size = 0x00800000; break; case AMD_ID_LV160B: info->flash_id += FLASH_AM160B; info->sector_count = 35; info->size = 0x00800000; break; case AMD_ID_DL322T: info->flash_id += FLASH_AMDL322T; info->sector_count = 71; info->size = 0x01000000; break; case AMD_ID_DL322B: info->flash_id += FLASH_AMDL322B; info->sector_count = 71; info->size = 0x01000000; break; case AMD_ID_DL323T: info->flash_id += FLASH_AMDL323T; info->sector_count = 71; info->size = 0x01000000; break; case AMD_ID_DL323B: info->flash_id += FLASH_AMDL323B; info->sector_count = 71; info->size = 0x01000000; break; case AMD_ID_LV640U: info->flash_id += FLASH_AM640U; info->sector_count = 128; info->size = 0x02000000; break; default: /* Unknown flash type */ info->flash_id = FLASH_UNKNOWN; return (0); } if ((long)flashtest == AMD_ID_LV640U) { /* set up sector start adress table (uniform sector type) */ for (i = 0; i < info->sector_count; i++) info->start[i] = baseaddr + (i * 0x00040000); } else if (info->flash_id & FLASH_BTYPE) { /* set up sector start adress table (bottom sector type) */ info->start[0] = baseaddr + 0x00000000; info->start[1] = baseaddr + 0x00010000; info->start[2] = baseaddr + 0x00018000; info->start[3] = baseaddr + 0x00020000; for (i = 4; i < info->sector_count; i++) { info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000; } } else { /* set up sector start adress table (top sector type) */ i = info->sector_count - 1; info->start[i--] = baseaddr + info->size - 0x00010000; info->start[i--] = baseaddr + info->size - 0x00018000; info->start[i--] = baseaddr + info->size - 0x00020000; for (; i >= 0; i--) { info->start[i] = baseaddr + i * 0x00040000; } } /* check for protected sectors */ for (i = 0; i < info->sector_count; i++) { /* read sector protection at sector address, (A7 .. A0) = 0x02 */ if (*(volatile DWORD*)(info->start[i] + 16) & 0x0001000100010001LL) { info->protect[i] = 1; /* D0 = 1 if protected */ } else { info->protect[i] = 0; } } flash_reset (); return (info->size); }
/*----------------------------------------------------------------------- */ ulong flash_get_size (ulong baseaddr, flash_info_t * info) { short i; unsigned long flashtest_h, flashtest_l; /* Write auto select command sequence and test FLASH answer */ V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00AA00AA; V_ULONG (baseaddr + ((ulong) 0x02AA << 3)) = 0x00550055; V_ULONG (baseaddr + ((ulong) 0x0555 << 3)) = 0x00900090; V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00AA00AA; V_ULONG (baseaddr + 4 + ((ulong) 0x02AA << 3)) = 0x00550055; V_ULONG (baseaddr + 4 + ((ulong) 0x0555 << 3)) = 0x00900090; flashtest_h = V_ULONG (baseaddr); /* manufacturer ID */ flashtest_l = V_ULONG (baseaddr + 4); switch ((int) flashtest_h) { case AMD_MANUFACT: info->flash_id = FLASH_MAN_AMD; break; case FUJ_MANUFACT: info->flash_id = FLASH_MAN_FUJ; break; default: info->flash_id = FLASH_UNKNOWN; info->sector_count = 0; info->size = 0; return (0); /* no or unknown flash */ } flashtest_h = V_ULONG (baseaddr + 8); /* device ID */ flashtest_l = V_ULONG (baseaddr + 12); if (flashtest_h != flashtest_l) { info->flash_id = FLASH_UNKNOWN; } else { switch (flashtest_h) { case AMD_ID_LV800T: info->flash_id += FLASH_AM800T; info->sector_count = 19; info->size = 0x00400000; break; /* 4 * 1 MB = 4 MB */ case AMD_ID_LV800B: info->flash_id += FLASH_AM800B; info->sector_count = 19; info->size = 0x00400000; break; /* 4 * 1 MB = 4 MB */ case AMD_ID_LV160T: info->flash_id += FLASH_AM160T; info->sector_count = 35; info->size = 0x00800000; break; /* 4 * 2 MB = 8 MB */ case AMD_ID_LV160B: info->flash_id += FLASH_AM160B; info->sector_count = 35; info->size = 0x00800000; break; /* 4 * 2 MB = 8 MB */ case AMD_ID_DL322T: info->flash_id += FLASH_AMDL322T; info->sector_count = 71; info->size = 0x01000000; break; /* 4 * 4 MB = 16 MB */ case AMD_ID_DL322B: info->flash_id += FLASH_AMDL322B; info->sector_count = 71; info->size = 0x01000000; break; /* 4 * 4 MB = 16 MB */ case AMD_ID_DL323T: info->flash_id += FLASH_AMDL323T; info->sector_count = 71; info->size = 0x01000000; break; /* 4 * 4 MB = 16 MB */ case AMD_ID_DL323B: info->flash_id += FLASH_AMDL323B; info->sector_count = 71; info->size = 0x01000000; break; /* 4 * 4 MB = 16 MB */ case AMD_ID_LV640U: info->flash_id += FLASH_AM640U; info->sector_count = 128; info->size = 0x02000000; break; /* 4 * 8 MB = 32 MB */ default: info->flash_id = FLASH_UNKNOWN; return (0); /* no or unknown flash */ } } if (flashtest_h == AMD_ID_LV640U) { /* set up sector start adress table (uniform sector type) */ for (i = 0; i < info->sector_count; i++) info->start[i] = baseaddr + (i * 0x00040000); } else if (info->flash_id & FLASH_BTYPE) { /* set up sector start adress table (bottom sector type) */ info->start[0] = baseaddr + 0x00000000; info->start[1] = baseaddr + 0x00010000; info->start[2] = baseaddr + 0x00018000; info->start[3] = baseaddr + 0x00020000; for (i = 4; i < info->sector_count; i++) { info->start[i] = baseaddr + (i * 0x00040000) - 0x000C0000; } } else { /* set up sector start adress table (top sector type) */ i = info->sector_count - 1; info->start[i--] = baseaddr + info->size - 0x00010000; info->start[i--] = baseaddr + info->size - 0x00018000; info->start[i--] = baseaddr + info->size - 0x00020000; for (; i >= 0; i--) { info->start[i] = baseaddr + i * 0x00040000; } } /* check for protected sectors */ for (i = 0; i < info->sector_count; i++) { /* read sector protection at sector address, (A7 .. A0) = 0x02 */ if ((V_ULONG (info->start[i] + 16) & 0x00010001) || (V_ULONG (info->start[i] + 20) & 0x00010001)) { info->protect[i] = 1; /* D0 = 1 if protected */ } else { info->protect[i] = 0; } } flash_reset (); return (info->size); }
/* Read the flash ID and set the globals */ int sysFlashInit(char *flash_str) { uint32 fltype = PFLASH; uint16 flash_vendid = 0; uint16 flash_devid = 0; uint16* flash = (uint16*)0xbfc00000; int idx; struct sflash *sflash; void *sbh; /* * Check for serial flash. */ sbh = sb_kattach(); ASSERT(sbh); cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0); if (cc) { flash = (uint16*)0xbc000000; fltype = R_REG(&cc->capabilities) & CAP_FLASH_MASK; /* Select SFLASH ? */ if (fltype == SFLASH_ST || fltype == SFLASH_AT) { sflash = sflash_init(cc); flashutl_cmd = &sflash_cmd_t; flashutl_desc = &sflash_desc; flashutl_desc->size = sflash->size; if (flash_str) sprintf(flash_str, "SFLASH %d kB", sflash->size/1024); return(0); } } flashutl_base = (uint8*)flash; /* * Parallel flash support * Some flashes have different unlock addresses, try each it turn */ idx = sizeof(flash_cmds)/sizeof(flash_cmds_t) - 2; flashutl_cmd = &flash_cmds[idx--]; while((fltype == PFLASH) && flashutl_cmd->type) { if (flashutl_cmd->read_id) cmd(flashutl_cmd->read_id, CMD_ADDR); #ifdef MIPSEB flash_vendid = *(flash + 1); flash_devid = *flash; #else flash_vendid = *flash; flash_devid = *(flash + 1); #endif /* Funky AMD */ if ((flash_vendid == 1) && (flash_devid == 0x227e)) { /* Get real devid */ #ifdef MIPSEB flash_devid = *(flash+0xe); #else flash_devid = *(flash+0xf); #endif } flashutl_desc = flashes; while (flashutl_desc->mfgid != 0 && !(flashutl_desc->mfgid == flash_vendid && flashutl_desc->devid == flash_devid)) { flashutl_desc++; } if (flashutl_desc->mfgid != 0) break; flashutl_cmd = &flash_cmds[idx--]; } if (flashutl_desc->mfgid == 0) { flashutl_desc = NULL; flashutl_cmd = NULL; } else { flashutl_cmd = flash_cmds; while (flashutl_cmd->type != 0 && flashutl_cmd->type != flashutl_desc->type) flashutl_cmd++; if (flashutl_cmd->type == 0) flashutl_cmd = NULL; } if (flashutl_cmd != NULL) { flash_reset(); } if (flashutl_desc == NULL) { if (flash_str) sprintf(flash_str, "UNKNOWN 0x%x 0x%x", flash_vendid, flash_devid); DPRINT(("Flash type UNKNOWN\n")); return 1; } if (flash_str) strcpy(flash_str, flashutl_desc->desc); DPRINT(("Flash type \"%s\"\n", flashutl_desc->desc)); return 0; }