static int flash_poll(unsigned long off, uint16 data) { unsigned long addr; int cnt = FLASH_TRIES; uint16 st; ASSERT(flashutl_desc != NULL); if (flashutl_desc->type == AMD || flashutl_desc->type == SST) { /* AMD style poll checkes the address being written */ addr = FLASH_ADDR(off); while ((st = flash_readword(addr)) != data && cnt != 0) cnt--; if (cnt == 0) { DPRINT(("flash_poll: timeout, off %lx, read 0x%x, expected 0x%x\n", off, st, data)); return -1; } } else { /* INTEL style poll is at second word of the block being written */ addr = FLASH_ADDR(block(off, BLOCK_BASE)+sizeof(uint16)); while (((st = flash_readword(addr)) & DONE) == 0 && cnt != 0) cnt--; if (cnt == 0) { DPRINT(("flash_poll: timeout, error status = 0x%x\n", st)); return -1; } } return 0; }
int nvm_save(void) { char *src, *dest, *bak; int magic = NVM_MAGIC; int sz_ram, pages; src = __section_begin(".nvm.ram"); sz_ram = (int)__section_end(".nvm.ram") - (int)__section_begin(".nvm.ram"); if(sz_ram == 0) return 0; sz_ram = align(sz_ram, 4); pages = align(sz_ram + 8, FLASH_PAGE_SZ) / FLASH_PAGE_SZ; dest = (char *)FLASH_ADDR(FLASH_PAGE_NR - pages); //rom 1 bak = (char *)FLASH_ADDR(FLASH_PAGE_NR - pages - pages); // rom 2 //ram -> rom 1 flash_Write(dest + 4, &sz_ram, 4); flash_Write(dest + 8, src, sz_ram); flash_Write(dest + 0, &magic, 4); //ram -> rom 2 flash_Erase(bak, pages); flash_Write(bak + 4, &sz_ram, 4); flash_Write(bak + 8, src, sz_ram); flash_Write(bak + 0, &magic, 4); //erase rom 1 flash_Erase(dest, pages); return 0; }
int nvm_init(void) { char *src, *dst, *bak; int sz_ram, magic, sz_nvm, pages; dst = __section_begin(".nvm.ram"); sz_ram = (int)__section_end(".nvm.ram") - (int)__section_begin(".nvm.ram"); if(sz_ram == 0) { //no nvm var is used nvm_flag_null = 0; return 0; } sz_ram = align(sz_ram, 4); pages = align(sz_ram + 8, FLASH_PAGE_SZ) / FLASH_PAGE_SZ; src = (char *)FLASH_ADDR(FLASH_PAGE_NR - pages); //rom 1 bak = (char *)FLASH_ADDR(FLASH_PAGE_NR - pages - pages); // rom 2 //rom 1 -> ram, always read & erase rom 1 in case of "rom1 not null!!!" flash_Read(&magic, src, 4); flash_Read(&sz_nvm, src + 4, 4); if(magic == NVM_MAGIC && sz_nvm == sz_ram) { flash_Read(dst, src + 8, sz_ram); //rom1 data is ok, rom1 -> rom 2 flash_Erase(bak, pages); flash_Write(bak + 4, &sz_nvm, 4); flash_Write(bak + 8, dst, sz_ram); flash_Write(bak + 0, &magic, 4); flash_Erase(src, pages); //erase rom 1 nvm_flag_null = 0; return 0; } //to avoid one more time erase op on an empty flash page if(sz_nvm != -1) { flash_Erase(src, pages); //erase rom 1 } //rom 2 -> ram src = bak; flash_Read(&magic, src, 4); flash_Read(&sz_nvm, src + 4, 4); if(magic == NVM_MAGIC && sz_nvm == sz_ram) { flash_Read(dst, src + 8, sz_ram); nvm_flag_null = 0; return 0; } //fail ... nvm_flag_null = 1; return -1; }
/* Writes a command to flash, performing an unlock if needed. */ static void cmd(uint16 cmd, unsigned long off) { int i; unlock_cmd_t *ul = NULL; ASSERT(flashutl_cmd != NULL); switch (flashutl_cmd->type) { case AMD: ul = &unlock_cmd_amd; break; case SST: ul = &unlock_cmd_sst; break; default: break; } if (flashutl_cmd->need_unlock) { ASSERT(ul); for (i = 0; i < UNLOCK_CMD_WORDS; i++) flash_writeword(FLASH_ADDR(ul->addr[i]), ul->cmd[i]); } /* cmd |= cmd << 8; */ if (off == CMD_ADDR) { switch (flashutl_cmd->type) { case AMD: off = AMD_CMD; break; case SST: off = SST_CMD; break; default: off = 0; break; } } #ifdef MIPSEB #ifdef BCMHND74K off ^= 6; #else /* !74K, bcm33xx */ off ^= 2; #endif /* BCMHND74K */ #endif /* MIPSEB */ flash_writeword(FLASH_ADDR(off), cmd); }
int sysFlashRead(uint off, uchar *buf, uint numbytes) { uint read, total_read = 0; if (flashutl_cmd->type == SFLASH) { while (numbytes) { read = sflash_read(sih, cc, off, numbytes, buf); numbytes -= read; buf += read; off += read; total_read += read; } } else { ASSERT(!(off & (flashutl_wsz - 1))); ASSERT(!(numbytes & (flashutl_wsz - 1))); while (numbytes) { flash_writeword((unsigned long)buf, flash_readword(FLASH_ADDR(off))); numbytes -= flashutl_wsz; buf += flashutl_wsz; off += flashutl_wsz; total_read += flashutl_wsz; } } return (total_read); }
/* Writes a single command to the flash. */ static void scmd(uint16 cmd, unsigned long off) { /* cmd |= cmd << 8; */ flash_writeword(FLASH_ADDR(off), cmd); }
/*clear nvm strorage to default state*/ int nvm_clear(void) { char *src, *dest, *bak; int sz_ram, pages; src = __section_begin(".nvm.ram"); sz_ram = (int)__section_end(".nvm.ram") - (int)__section_begin(".nvm.ram"); if(sz_ram == 0) return 0; sz_ram = align(sz_ram, 4); pages = align(sz_ram + 8, FLASH_PAGE_SZ) / FLASH_PAGE_SZ; dest = (char *)FLASH_ADDR(FLASH_PAGE_NR - pages); //rom 1 bak = (char *)FLASH_ADDR(FLASH_PAGE_NR - pages - pages); // rom 2 //erase rom 2 flash_Erase(bak, pages); //erase rom 1 flash_Erase(dest, pages); return 0; }
/* 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; }