📄 flash.c
字号:
/*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <ppcboot.h>
#include <cogent/flash.h>
flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */
/*-----------------------------------------------------------------------
* Functions
*/
static int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt);
static int write_word (flash_info_t *info, ulong dest, ulong data);
static int flash_protect (int flag, ulong from, ulong to, flash_info_t *info);
/*-----------------------------------------------------------------------
* Protection Flags:
*/
#define FLAG_PROTECT_SET 0x01
#define FLAG_PROTECT_CLEAR 0x02
/*-----------------------------------------------------------------------
*/
#if defined(CONFIG_CMA302)
/*
* probe for the existence of flash at address "addr"
* 0 = yes, 1 = bad Manufacturer's Id, 2 = bad Device Id
*/
static int
c302f_probe_word(c302f_addr_t addr)
{
/* reset the flash */
*addr = C302F_BNK_CMD_RST;
/* check the manufacturer id */
*addr = C302F_BNK_CMD_RD_ID;
if (*C302F_BNK_ADDR_MAN(addr) != C302F_BNK_RD_ID_MAN)
return 1;
/* check the device id */
*addr = C302F_BNK_CMD_RD_ID;
if (*C302F_BNK_ADDR_DEV(addr) != C302F_BNK_RD_ID_DEV)
return 2;
#ifdef FLASH_DEBUG
printf("\nMaster Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFGM(addr));
printf("Block 0 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG0(addr));
printf("Block 1 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG1(addr));
printf("Block 2 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG2(addr));
printf("Block 3 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG3(addr));
printf("Block 4 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG4(addr));
printf("Block 5 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG5(addr));
printf("Block 6 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG6(addr));
printf("Block 7 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG7(addr));
printf("Block 8 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG8(addr));
printf("Block 9 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG9(addr));
printf("Block 10 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG10(addr));
printf("Block 11 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG11(addr));
printf("Block 12 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG12(addr));
printf("Block 13 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG13(addr));
printf("Block 14 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG14(addr));
printf("Block 15 Lock Config = 0x%08lx\n", *C302F_BNK_ADDR_CFG15(addr));
#endif
/* reset the flash again */
*addr = C302F_BNK_CMD_RST;
return 0;
}
/*
* probe for Cogent CMA302 flash module at address "base" and store
* info for any found into flash_info entry "fip". Must find at least
* one bank.
*/
static void
c302f_probe(flash_info_t *fip, c302f_addr_t base)
{
c302f_addr_t addr, eaddr;
int nbanks;
fip->size = 0L;
fip->sector_count = 0;
addr = base;
eaddr = C302F_BNK_ADDR_BASE(addr, C302F_MAX_BANKS);
nbanks = 0;
while (addr < eaddr) {
c302f_addr_t addrw, eaddrw, addrb;
int i, osc, nsc;
addrw = addr;
eaddrw = C302F_BNK_ADDR_NEXT_WORD(addrw);
while (addrw < eaddrw)
if (c302f_probe_word(addrw++) != 0)
goto out;
/* bank exists - append info for this bank to *fip */
fip->flash_id = FLASH_MAN_INTEL|FLASH_28F008S5;
fip->size += C302F_BNK_SIZE;
osc = fip->sector_count;
fip->sector_count += C302F_BNK_NBLOCKS;
if ((nsc = fip->sector_count) >= CFG_MAX_FLASH_SECT)
panic("Too many sectors in flash at address 0x%08lx\n",
(unsigned long)base);
addrb = addr;
for (i = osc; i < nsc; i++) {
fip->start[i] = (ulong)addrb;
fip->protect[i] = 0;
addrb = C302F_BNK_ADDR_NEXT_BLK(addrb);
}
addr = C302F_BNK_ADDR_NEXT_BNK(addr);
nbanks++;
}
out:
if (nbanks == 0)
panic("ERROR: no flash found at address 0x%08lx\n",
(unsigned long)base);
}
static void
c302f_reset(flash_info_t *info, int sect)
{
c302f_addr_t addrw, eaddrw;
addrw = (c302f_addr_t)info->start[sect];
eaddrw = C302F_BNK_ADDR_NEXT_WORD(addrw);
while (addrw < eaddrw) {
#ifdef FLASH_DEBUG
printf(" writing reset cmd to addr 0x%08lx\n",
(unsigned long)addrw);
#endif
*addrw = C302F_BNK_CMD_RST;
addrw++;
}
}
static void
c302f_erase_init(flash_info_t *info, int sect)
{
c302f_addr_t addrw, saddrw, eaddrw;
int flag;
#ifdef FLASH_DEBUG
printf("0x%08lx C302F_BNK_CMD_PROG\n", C302F_BNK_CMD_PROG);
printf("0x%08lx C302F_BNK_CMD_ERASE1\n", C302F_BNK_CMD_ERASE1);
printf("0x%08lx C302F_BNK_CMD_ERASE2\n", C302F_BNK_CMD_ERASE2);
printf("0x%08lx C302F_BNK_CMD_CLR_STAT\n", C302F_BNK_CMD_CLR_STAT);
printf("0x%08lx C302F_BNK_CMD_RST\n", C302F_BNK_CMD_RST);
printf("0x%08lx C302F_BNK_STAT_RDY\n", C302F_BNK_STAT_RDY);
printf("0x%08lx C302F_BNK_STAT_ERR\n", C302F_BNK_STAT_ERR);
#endif
saddrw = (c302f_addr_t)info->start[sect];
eaddrw = C302F_BNK_ADDR_NEXT_WORD(saddrw);
#ifdef FLASH_DEBUG
printf("erasing sector %d, start addr = 0x%08lx "
"(bank next word addr = 0x%08lx)\n", sect,
(unsigned long)saddrw, (unsigned long)eaddrw);
#endif
/* Disable intrs which might cause a timeout here */
flag = disable_interrupts();
for (addrw = saddrw; addrw < eaddrw; addrw++) {
#ifdef FLASH_DEBUG
printf(" writing erase cmd to addr 0x%08lx\n",
(unsigned long)addrw);
#endif
*addrw = C302F_BNK_CMD_ERASE1;
*addrw = C302F_BNK_CMD_ERASE2;
}
/* re-enable interrupts if necessary */
if (flag)
enable_interrupts();
}
static int
c302f_erase_poll(flash_info_t *info, int sect)
{
c302f_addr_t addrw, saddrw, eaddrw;
int sectdone, haderr;
saddrw = (c302f_addr_t)info->start[sect];
eaddrw = C302F_BNK_ADDR_NEXT_WORD(saddrw);
sectdone = 1;
haderr = 0;
for (addrw = saddrw; addrw < eaddrw; addrw++) {
c302f_word_t stat = *addrw;
#ifdef FLASH_DEBUG
printf(" checking status at addr "
"0x%08lx [0x%08lx]\n",
(unsigned long)addrw, stat);
#endif
if ((stat & C302F_BNK_STAT_RDY) != C302F_BNK_STAT_RDY)
sectdone = 0;
else if ((stat & C302F_BNK_STAT_ERR) != 0) {
printf(" failed on sector %d "
"(stat = 0x%08lx) at "
"address 0x%08lx\n",
sect, stat,
(unsigned long)addrw);
*addrw = C302F_BNK_CMD_CLR_STAT;
haderr = 1;
}
}
if (haderr)
return (-1);
else
return (sectdone);
}
static int
c302f_write_word(c302f_addr_t addr, c302f_word_t value)
{
c302f_word_t stat;
ulong start;
int flag, retval;
/* Disable interrupts which might cause a timeout here */
flag = disable_interrupts();
*addr = C302F_BNK_CMD_PROG;
*addr = value;
/* re-enable interrupts if necessary */
if (flag)
enable_interrupts();
retval = 0;
/* data polling for D7 */
start = get_timer (0);
do {
if (get_timer(start) > CFG_FLASH_WRITE_TOUT) {
retval = 1;
goto done;
}
stat = *addr;
} while ((stat & C302F_BNK_STAT_RDY) != C302F_BNK_STAT_RDY);
if ((stat & C302F_BNK_STAT_ERR) != 0) {
printf("flash program failed (stat = 0x%08lx) "
"at address 0x%08lx\n", (ulong)stat, (ulong)addr);
*addr = C302F_BNK_CMD_CLR_STAT;
retval = 3;
}
done:
/* reset to read mode */
*addr = C302F_BNK_CMD_RST;
return (retval);
}
#endif /* CONFIG_CMA302 */
unsigned long
flash_init(void)
{
unsigned long total;
int i;
flash_info_t *fip;
/* Init: no FLASHes known */
for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) {
flash_info[i].flash_id = FLASH_UNKNOWN;
}
fip = &flash_info[0];
total = 0L;
#if defined(CONFIG_CMA302)
c302f_probe(fip, (c302f_addr_t)CFG_FLASH_BASE);
total += fip->size;
fip++;
#endif
#if (CMA_MB_CAPS & CMA_MB_CAP_FLASH)
/* not yet ...
cmbf_probe(fip, (cmbf_addr_t)CMA_MB_FLASH_BASE);
total += fip->size;
fip++;
*/
#endif
/*
* protect monitor and environment sectors
*/
#if CFG_MONITOR_BASE == CFG_FLASH_BASE
(void)flash_protect(FLAG_PROTECT_SET,
CFG_MONITOR_BASE,
CFG_MONITOR_BASE+CFG_MONITOR_LEN-1,
&flash_info[0]);
#endif
#if defined(CFG_FLASH_ENV_ADDR)
(void)flash_protect(FLAG_PROTECT_SET,
CFG_FLASH_ENV_ADDR,
#if defined(CFG_FLASH_ENV_BUF)
CFG_FLASH_ENV_ADDR + CFG_FLASH_ENV_BUF - 1,
#else
CFG_FLASH_ENV_ADDR + CFG_FLASH_ENV_SIZE - 1,
#endif
&flash_info[0]);
#endif
return total;
}
/*-----------------------------------------------------------------------
* Check or set protection status for monitor sectors
*
* The monitor always occupies the _first_ part of the _first_ Flash bank.
*/
static int
flash_protect(int flag, ulong from, ulong to, flash_info_t *info)
{
ulong b_end = info->start[0] + info->size - 1; /* bank end address */
int rc = 0;
int first = -1;
int last = -1;
int i;
if (to < info->start[0]) {
return (0);
}
for (i=0; i<info->sector_count; ++i) {
ulong end; /* last address in current sect */
short s_end;
s_end = info->sector_count - 1;
end = (i == s_end) ? b_end : info->start[i + 1] - 1;
if (from > end) {
continue;
}
if (to < info->start[i]) {
continue;
}
if (from == info->start[i]) {
first = i;
if (last < 0) {
last = s_end;
}
}
if (to == end) {
last = i;
if (first < 0) {
first = 0;
}
}
}
for (i=first; i<=last; ++i) {
if (flag & FLAG_PROTECT_CLEAR) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -