flash_amd.c

来自「Hermit-at-1.1.3,一款bootloader」· C语言 代码 · 共 271 行

C
271
字号
/* * Copyright (c) 2001 Atmark Techno, Inc.  All Rights Reserved. * * Commands to program the Fujitsu MBM29DL324BD flash chips on the * Armadillo board.  These are 32 Mbit "bottom boot" * (boot and param blocks at low end of address space) flash chips. */#include <target/buffer.h>#include <target/io.h>#include <target/herrno.h>#include <target/scan.h>#include <target/flash.h>#include <target/str.h>#include "../flash_memcpy.h"static flash_cfi cfi_info;#define FLASH_TIMEOUT 400000000#define flash_read(addr)         read16(addr)#define flash_write(addr, b)     write16((addr), (b))#if defined(SUZAKU)#if !defined(BIG_ENDIAN)#define BIG_ENDIAN#endif#endif#if defined(BIG_ENDIAN)#define flash_read_cmd(base, offset) \	cpu_to_le16(read16((base) + ((offset) << 1)))#define flash_write_cmd(addr, b) \	write16((addr), cpu_to_le16((b)))#else /* LITTLE_ENDIAN */#define flash_read_cmd(base, offset) \	read16((base) + ((offset) << 1))#define flash_write_cmd(addr, b) \	write16((addr), (b))#endifstatic void flash_print_chip_error_string(unsigned char status){	hprint("TimeOut");}/* * Come up with an error string representing the flash error; we can * have distinct errors for the two chips.  Get the status from * errdata, since this is used for error output. */static void flash_print_error_string(void){	hprint("lowbank:");	flash_print_chip_error_string(errdata.word);	hprint(" highbank:");	flash_print_chip_error_string(errdata.word >> 16);}/* * Loop until both write state machines complete. */static unsigned short flash_status_wait(addr_t addr, unsigned short value){	unsigned short status;	long timeout = FLASH_TIMEOUT;	while (((status = (flash_read(addr))) != value) && timeout > 0) {		timeout--;	}	return status;}/* * Loop until the Write State machine is ready, then do a full error * check.  Clear status and leave the flash in Read Array mode; return * 0 for no error, -1 for error. */static int flash_status_full_check(addr_t addr, unsigned short value1, unsigned short value2){	unsigned short status1, status2;	status1 = flash_status_wait(addr, value1);	status2 = flash_status_wait(addr + 2, value2);	if (status1 != value1 || status2 != value2) {		errdata.word = status1 | status2 << 16;		errfunc = &flash_print_error_string;	}	return (status1 != value1 || status2 != value2) ? -1 : 0;}/* * Program the contents of the download buffer to flash at the given * address.  Size is also specified; we shouldn't have to track usage * of the download buffer, since the host side can easily do that. * * We write words without checking status between each; we only go * through the full status check procedure once, when the full buffer * has been written. * * Alignment problems are errors here; we don't automatically correct * them because in the context of this command they signify bugs, and * we want to be extra careful when writing flash. */int flash_amd_program(const u32 from, const u32 to, const u32 size){	int status;	unsigned int loop;	unsigned short *ptr;	unsigned long base;	unsigned long addr;	if(from & UNALIGNED_MASK) return -H_EALIGN;	if(to & UNALIGNED_MASK) return -H_EALIGN;		base = (to & FLASH_BASE_MASK);		loop = (size >> BYTE_TO_WORD_SHIFT);	ptr = (unsigned short*)from;	addr = to;		for(status = 0; loop--; addr += (sizeof(short) * 2)) {		flash_write_cmd(base + (0x555 << 1), 0xAA);		flash_write_cmd(base + (0x2AA << 1), 0x55);		flash_write_cmd(base + (0x555 << 1), 0xA0);		flash_write(addr, *ptr);		flash_status_wait(addr, *ptr);		flash_write_cmd(base + (0x555 << 1), 0xAA);		flash_write_cmd(base + (0x2AA << 1), 0x55);		flash_write_cmd(base + (0x555 << 1), 0xA0);		flash_write(addr + 2, *(ptr + 1));		flash_status_wait(addr + 2, *(ptr + 1));		status |= flash_status_full_check(addr, *ptr, *(ptr + 1));		ptr += 2;	}	return status;}/* * Erase a flash block.  Single argument is the first address in the * block (actually, it can be anywhere in the block, but the host-side * hermit downloader gives the first address). */int flash_amd_erase(const u32 erase_addr){	unsigned long base;	unsigned long addr;	addr = (erase_addr & ~UNALIGNED_MASK);	/* word align */		base = (erase_addr & FLASH_BASE_MASK);		flash_write_cmd(base + (0x555 << 1), 0xAA);	flash_write_cmd(base + (0x2AA << 1), 0x55);	flash_write_cmd(base + (0x555 << 1), 0x80);	flash_write_cmd(base + (0x555 << 1), 0xAA);	flash_write_cmd(base + (0x2AA << 1), 0x55);	flash_write_cmd(addr, 0x30);	return flash_status_full_check(addr, 0xFFFF, 0xFFFF);}inline u8 flash_amd_read_byte(const u32 from){	return *(volatile u8 *)from;}u32 flash_amd_copy_to_dram(const u32 from, const u32 to, const u32 size){	flash_memcpy((u16 *)to, (u16 *)from,(u16 *)(to + size));	return size;}u32 flash_amd_get_id(const u32 base_addr){	u32 base;	u32 id;	base = (base_addr & FLASH_BASE_MASK);	flash_write_cmd(base, 0xF0);	flash_write_cmd(base + (0x555 << 1), 0xAA);	flash_write_cmd(base + (0x2AA << 1), 0x55);	flash_write_cmd(base + (0x555 << 1), 0x90);	id = *(u32 *)(base);	flash_write_cmd(base, 0xF0);	return id;}int flash_amd_get_size(const u32 base_addr){        return cfi_info.dev_size;}static intflash_amd_read_cfi(const u32 base_addr){	int i;	u32 base;	u8 *buf = (u8 *)&cfi_info;	base = (base_addr & FLASH_BASE_MASK);	flash_write_cmd(base, 0xf0);	flash_write_cmd(base + (0x555 << 1), 0x98);	for (i=0; i<0x1c; i++)		*(buf++) = flash_read_cmd(base, 0x10 + i) & 0xff;	flash_write_cmd(base, 0xf0);	if (strncmp(cfi_info.qry, "QRY", 3))		return -1;	return 0;}int flash_amd_initialize(const u32 base_addr){	int ret;	ret = flash_amd_read_cfi(base_addr);	return ret;}intflash_amd_create_eraseblock_table(const u32 base_addr, flash_eb *eb){	int i, addr = 0x2c;	u32 base;	base = (base_addr & FLASH_BASE_MASK);	flash_write_cmd(base, 0xf0);	flash_write_cmd(base + (0x555 << 1), 0x98);	eb->nr_eraseblock = flash_read_cmd(base, addr++) & 0xff;	if (eb->nr_eraseblock > MAX_NR_ERASEBLOCK) {		flash_write_cmd(base, 0xf0);		return -1;	}	for (i=0; i<eb->nr_eraseblock; i++) {		eb->eraseblock[i].num = 			(flash_read_cmd(base, addr++) & 0xff);		eb->eraseblock[i].num |=			(flash_read_cmd(base, addr++) & 0xff) << 8;		eb->eraseblock[i].size =			(flash_read_cmd(base, addr++) & 0xff);		eb->eraseblock[i].size |=			(flash_read_cmd(base, addr++) & 0xff) << 8;	}	flash_write_cmd(base, 0xf0);	eb->base_addr = base_addr;#if defined(FLASH_AMD_DEBUG)	for (i=0; i<eb->nr_eraseblock; i++) {		hprintf("eraseblock[%d]: %d x %d\n", i,			eb->eraseblock[i].num + 1, 			eb->eraseblock[i].size * 256);	}#endif	return 0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?