📄 uboot_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
*/
/* #define DEBUG */
#include "uboot_common.h"
env_t *uboot_env_ptr;
env_t *uboot_flash_addr = (env_t *)CFG_ENV_ADDR;
uboot_flash_info_t uboot_flash_info[CFG_MAX_FLASH_BANKS];
/*-----------------------------------------------------------------------
* Set protection status for monitor sectors
*
* The monitor is always located in the _first_ Flash bank.
* If necessary you have to map the second bank at lower addresses.
*/
void
uboot_flash_protect (int flag, ulong from, ulong to, uboot_flash_info_t *info)
{
ulong b_end = info->start[0] + info->size - 1; /* bank end address */
short s_end = info->sector_count - 1; /* index of last sector */
int i;
/* Do nothing if input data is bad. */
if (info->sector_count == 0 || info->size == 0 || to < from) {
return;
}
/* There is nothing to do if we have no data about the flash
* or the protect range and flash range don't overlap.
*/
if (info->flash_id == FLASH_UNKNOWN ||
to < info->start[0] || from > b_end) {
return;
}
for (i=0; i<info->sector_count; ++i) {
ulong end; /* last address in current sect */
end = (i == s_end) ? b_end : info->start[i + 1] - 1;
/* Update protection if any part of the sector
* is in the specified range.
*/
if (from <= end && to >= info->start[i]) {
if (flag & FLAG_PROTECT_CLEAR) {
info->protect[i] = 0;
}
else if (flag & FLAG_PROTECT_SET) {
info->protect[i] = 1;
}
}
}
}
/*-----------------------------------------------------------------------
*/
uboot_flash_info_t *
uboot_addr2info (ulong addr)
{
uboot_flash_info_t *info;
int i;
for (i=0, info=&uboot_flash_info[0]; i<CFG_MAX_FLASH_BANKS; ++i, ++info)
{
if (info->flash_id != FLASH_UNKNOWN &&
addr >= info->start[0] &&
/* WARNING - The '- 1' is needed if the flash
* is at the end of the address space, since
* info->start[0] + info->size wraps back to 0.
* Please don't change this unless you understand this.
*/
addr <= info->start[0] + info->size - 1)
{
return (info);
}
}
return (NULL);
}
/*-----------------------------------------------------------------------
* Copy memory to flash.
* Make sure all target addresses are within Flash bounds,
* and no protected sectors are hit.
* Returns:
* ERR_OK 0 - OK
* ERR_TIMOUT 1 - write timeout
* ERR_NOT_ERASED 2 - Flash not erased
* ERR_PROTECTED 4 - target range includes protected sectors
* ERR_INVAL 8 - target address not in Flash memory
* ERR_ALIGN 16 - target address not aligned on boundary
* (only some targets require alignment)
*/
int
uboot_flash_write (uchar *src, ulong addr, ulong cnt)
{
int i;
ulong end = addr + cnt - 1;
uboot_flash_info_t *info_first = uboot_addr2info (addr);
uboot_flash_info_t *info_last = uboot_addr2info (end );
uboot_flash_info_t *info;
if (cnt == 0) {
return (ERR_OK);
}
if (!info_first || !info_last) {
return (ERR_INVAL);
}
for (info = info_first; info <= info_last; ++info) {
ulong b_end = info->start[0] + info->size; /* bank end addr */
short s_end = info->sector_count - 1;
for (i=0; i<info->sector_count; ++i) {
ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
if ((end >= info->start[i]) && (addr < e_addr) &&
(info->protect[i] != 0) ) {
return (ERR_PROTECTED);
}
}
}
/* finally write data to flash */
for (info = info_first; info <= info_last && cnt > 0; ++info)
{
ulong len;
len = info->start[0] + info->size - addr;
if (len > cnt)
len = cnt;
if ((i = uboot_write_buff(info, src, addr, len)) != 0)
{
return (i);
}
cnt -= len;
addr += len;
src += len;
}
return (ERR_OK);
}
/*-----------------------------------------------------------------------
*/
void uboot_flash_perror (int err)
{
switch (err) {
case ERR_OK:
break;
case ERR_TIMOUT:
printk ("Timeout writing to Flash\n");
break;
case ERR_NOT_ERASED:
printk ("Flash not Erased\n");
break;
case ERR_PROTECTED:
printk ("Can't write to protected Flash sectors\n");
break;
case ERR_INVAL:
printk ("Outside available Flash\n");
break;
case ERR_ALIGN:
printk ("Start and/or end address not on sector boundary\n");
break;
case ERR_UNKNOWN_FLASH_VENDOR:
printk ("Unknown Vendor of Flash\n");
break;
case ERR_UNKNOWN_FLASH_TYPE:
printk ("Unknown Type of Flash\n");
break;
case ERR_PROG_ERROR:
printk ("General Flash Programming Error\n");
break;
default:
printk ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err);
break;
}
}
static int
uboot_flash_fill_sect_ranges (ulong addr_first, ulong addr_last,
int *s_first, int *s_last,
int *s_count )
{
uboot_flash_info_t *info;
ulong bank;
int rcode = 0;
*s_count = 0;
for (bank=0; bank < CFG_MAX_FLASH_BANKS; ++bank) {
s_first[bank] = -1; /* first sector to erase */
s_last [bank] = -1; /* last sector to erase */
}
for (bank=0,info=&uboot_flash_info[0];
(bank < CFG_MAX_FLASH_BANKS) && (addr_first <= addr_last);
++bank, ++info)
{
ulong b_end;
int sect;
short s_end;
if (info->flash_id == FLASH_UNKNOWN)
{
continue;
}
b_end = info->start[0] + info->size - 1; /* bank end addr */
s_end = info->sector_count - 1; /* last sector */
// printk("addr_first :%x, addr_last:%x\n", addr_first, addr_last);
for (sect=0; sect < info->sector_count; ++sect)
{
ulong end; /* last address in current sect */
end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
// printk("sect:%d, info->start[sect]:%x, end:%x\n", sect, info->start[sect], end);
if (addr_first > end)
continue;
if (addr_last < info->start[sect])
continue;
if (addr_first == info->start[sect])
{
s_first[bank] = sect;
}
if (addr_last <= end)
{ /* mhfan */
s_last[bank] = sect;
break;
}
}
// printk("first:%d, last %d\n", s_first[bank], s_last[bank]);
if (s_first[bank] >= 0)
{
if (s_last[bank] < 0)
{
if (addr_last > b_end)
{
s_last[bank] = s_end;
}
else
{
rcode = 1;
break;
}
}
if (s_last[bank] < s_first[bank])
{
rcode = 1;
break;
}
sect = s_last[bank];
addr_first = (sect == s_end) ? b_end + 1: info->start[sect + 1];
(*s_count) += s_last[bank] - s_first[bank] + 1;
}
else if (s_last[bank] >= 0) {
rcode = 1;
break;
}
}
return rcode;
}
int uboot_flash_sect_erase (ulong addr_first, ulong addr_last)
{
uboot_flash_info_t *info;
ulong bank;
int s_first[CFG_MAX_FLASH_BANKS], s_last[CFG_MAX_FLASH_BANKS];
int erased = 0;
int planned;
int rcode = 0;
rcode = uboot_flash_fill_sect_ranges (addr_first, addr_last,
s_first, s_last, &planned );
if (planned && (rcode == 0)) {
for (bank=0,info=&uboot_flash_info[0];
(bank < CFG_MAX_FLASH_BANKS) && (rcode == 0);
++bank, ++info) {
if (s_first[bank]>=0) {
erased += s_last[bank] - s_first[bank] + 1;
rcode = uboot_flash_erase (info, s_first[bank], s_last[bank]);
}
}
//printk ("Erased %d sectors\n", erased);
} else if (rcode == 0) {
printk ("Error: start and/or end address"
" not on sector boundary\n");
rcode = 1;
}
return rcode;
}
int uboot_flash_sect_protect (int p, ulong addr_first, ulong addr_last)
{
uboot_flash_info_t *info;
ulong bank;
int s_first[CFG_MAX_FLASH_BANKS], s_last[CFG_MAX_FLASH_BANKS];
int protected, i;
int planned;
int rcode;
rcode = uboot_flash_fill_sect_ranges( addr_first, addr_last, s_first, s_last, &planned );
protected = 0;
if (planned && (rcode == 0)) {
for (bank=0,info=&uboot_flash_info[0]; bank < CFG_MAX_FLASH_BANKS; ++bank, ++info) {
if (info->flash_id == FLASH_UNKNOWN) {
continue;
}
if (s_first[bank]>=0 && s_first[bank]<=s_last[bank]) {
protected += s_last[bank] - s_first[bank] + 1;
for (i=s_first[bank]; i<=s_last[bank]; ++i) {
info->protect[i] = p;
}
}
}
//printk ("%sProtected %d sectors\n",p ? "" : "Un-", protected);
} else if (rcode == 0) {
rcode = 1;
}
return rcode;
}
int uboot_saveenv(int flash_offset)
{
int len, rc;
ulong end_addr;
ulong flash_sect_addr;
uboot_flash_info_t *info = &uboot_flash_info[0];
uchar *env_buffer = (char *)uboot_env_ptr;
int rcode = 0;
flash_sect_addr = (ulong)uboot_flash_addr+flash_offset;
if (flash_offset<0x10000)
{
if (info->size == 0x400000)
len= CFG_BOOT_SECT_SIZE;
else if(info->size == 0x200000)
{
if(flash_offset ==0x0000)
{
len = CFG_BOOT_SECT_SIZE*2;
}
else if (flash_offset ==0x4000||flash_offset ==0x6000)
{
len = CFG_BOOT_SECT_SIZE;
}
else
{
len = CFG_BOOT_SECT_SIZE*4;
}
}
}
else if ( (flash_offset>=0x10000) && (flash_offset<info->size) )
len = CFG_MAIN_SECT_SIZE;
end_addr = flash_sect_addr + len - 1;
// printk("disable sect_protect!\n");
if (uboot_flash_sect_protect (0, flash_sect_addr, end_addr))
return 1;
// printk("flash sect_erase!\n");
if (uboot_flash_sect_erase (flash_sect_addr, end_addr))
return 1;
// puts ("Writing to Flash... ");
//while(1);
// printk("write to flash!\n");
rc = uboot_flash_write(env_buffer, flash_sect_addr, len);
if (rc != 0)
{
uboot_flash_perror (rc);
rcode = 1;
}
else
{
//puts ("done\n");
//printk("write flash environment done!\n");
}
// printk("flash_sect_addr = %x, len = %x !\n", flash_sect_addr, len);
/* try to re-protect */
(void) uboot_flash_sect_protect (1, flash_sect_addr, end_addr);
return rcode;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -