⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uboot_flash.c

📁 uclinux下 intel mx 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 + -