📄 flash.c
字号:
/***************************************** Copyright (c) 2003-2004 Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//* This file is part of the EM86XX boot loader *//* * flash.c * * by Ho Lee 02/05/2003 */#include "config.h"#include "uart.h"#include "hardware.h"#include "io.h"#include "em86xxapi.h"#include "flash.h"#define FLASH_VERBOSE 0#define FLASH_ERR_CNT (1<<8) /* Error limit before reporting */#define FLASH_WAIT_DIV 1 /* 1 for the board without IORDY lifted, it'll try the full cycle, or more than 1 for others */#define FLASH_USE_DQX /* Use DQx toggling bit to detect programming status */#ifdef CONFIG_ENABLE_FULLFUNCTIONstatic const char *finfo_msg = "Flash %d : base addr = %08x, size = %08x\n";#endifstatic unsigned flash_wait_div = FLASH_WAIT_DIV;/* * FlexROM / Parallel flash is connected to Peripheral Bus CS#2 * 8/24 nonmultiplexed mode */int flash_init(void){#if 0 // Peripheral Bus interface // use timing 0 __raw_writel(DEFAULT_PB_TIMING0, REG_BASE_HOST + PB_timing0); __raw_writel(DEFAULT_PB_USE_TIMING0, REG_BASE_HOST + PB_use_timing0);#endif return 0;}#ifdef CONFIG_ENABLE_FLASH/* * flash-cfi.c * * flash driver from scratch * based on CFI (Common Flash Memory Interface) Specification 2.0 * supports multiple flashes * supports command set 2 (AMD standard) * * first revision by Ho Lee 10/31/2002 * code cleanup by Ho Lee 11/08/2002 * code cleanup by Ho Lee 12/01/2003 */#include "config.h"#include "uart.h"#include "util.h"#include "io.h"#include "flash.h"//// for matching endian between CPU and CFI interface// CFI and HOST use same endian//#define cpu_to_cfi8(x) (x)#define cfi8_to_cpu(x) (x)#define cpu_to_cfi16(x) (x)#define cfi16_to_cpu(x) (x)#define cpu_to_cfi32(x) (x)#define cfi32_to_cpu(x) (x)//// CFI Query Identification//// Vendor command set & control interface ID code assignment // CFI Publication 100#define CFI_PRIMARY_ID_NULL 0 // none is specified#define CFI_PRIMARY_ID_INTEL_EXT 1 // Intel/Sharp Extended command set#define CFI_PRIMARY_ID_AMD_STD 2 // AMD/Fujitsu Standard command set#define CFI_PRIMARY_ID_INTEL_STD 3 // Intel Standard command set#define CFI_PRIMARY_ID_AMD_EXT 4 // AMD/Fujitsu Extended command set#define CFI_PRIMARY_ID_MITSUBISHI_STD 256 // Mitsubishi Standard command set#define CFI_PRIMARY_ID_MITSUBISHI_EXT 257 // Mitsubishi Extended command set#define CFI_PRIMARY_ID_SST 258 // Page Write command set#define CFI_PRIMARY_ID_RESERVED 65535// Device interface code assignment// CFI Publication 100#define CFI_INTERFACE_X8 0 // x8-only asynchronous interface#define CFI_INTERFACE_X16 1 // x16-only asynchronous inteface#define CFI_INTERFACE_X8_16 2 // x8 and x16 via BYTE# with asynchronous interface#define CFI_INTERFACE_X32 3 // x32-only asynchronous interface#define CFI_INTERFACE_X16_32 5 // x16 and x32 via WORD# with asynchronous interface#define CFI_INTERFACE_RESERVED 65535#define CFI_MAX_ERASE_REGIONS 8// Query ID structurestruct cfi_query_id { unsigned char query[3]; // 0x10 - 0x12 : query-unique ACSII string "QRY" unsigned short primary_id; // 0x13 - 0x14 : primary vendor command set and control interface ID code unsigned short primary_table_addr; // 0x15 - 0x16 : address for primary algorithm extended query table unsigned short alternate_id; // 0x17 - 0x18 : alternate vendor command set and control interface ID code unsigned short alternate_table_addr; // 0x19 - 0x1a : address for alternate algorithm extended query table unsigned char vcc_min; // 0x1b : Vcc logic supply minimum voltage unsigned char vcc_max; // 0x1c : Vcc logic supply maximum voltage unsigned char vpp_min; // 0x1d : Vpp logic supply minimum voltage unsigned char vpp_max; // 0x1e : Vpp logic supply maximum voltage unsigned char timeout_single_write; // 0x1f : typical timeout per single byte/word write unsigned char timeout_buffer_write; // 0x20 : typical timeout for minimum-size buffer write unsigned char timeout_block_erase; // 0x21 : typical timeout for individual block erase unsigned char timeout_chip_erase; // 0x22 : typical timeout for full chip erase unsigned char max_timeout_single_write; // 0x23 : maximum timeout per single byte/word write unsigned char max_timeout_buffer_write; // 0x24 : maximum timeout for minimum-size buffer write unsigned char max_timeout_block_erase; // 0x25 : maximum timeout for individual block erase unsigned char max_timeout_chip_erase; // 0x26 : maximum timeout for full chip erase unsigned char device_size; // 0x27 : device size = 2^n in number of bytes unsigned short interface_desc; // 0x28 - 0x29 : flash device interface description unsigned short max_multibyte_write; // 0x2a - 0x2b : maximum number of bytes in multi-byte write = 2^n unsigned char num_erase_regions; // 0x2c : number of erase block regions within device unsigned int erase_region_info[CFI_MAX_ERASE_REGIONS]; // erase block region information // bits 31-16 : // bits 15-0 : } __attribute__((packed));struct cfi_eraseregions { unsigned int start; unsigned int size; unsigned int blocks;};enum { FLSTATE_READY, FLSTATE_ERASING, FLSTATE_WRITING,};// CFI information block used by this drivertypedef struct { int exist; int chip_state; unsigned int base, size; struct cfi_query_id ident; struct cfi_eraseregions erase_regions[CFI_MAX_ERASE_REGIONS]; unsigned long addr_unlock1, addr_unlock2;} cfi_info_t;//// global variables//static int g_flash_inited = 0;static int g_flash_chips = 0;static cfi_info_t g_cfi[FLASH_MAX_CHIPSET];//// function prototypes//// data structure managementstatic cfi_info_t *get_free_cfi(void);static cfi_info_t *find_cfi(unsigned long addr);// CFI basic I/Ostatic __inline__ unsigned char cfi_readb(unsigned long addr) { return __raw_readb(addr); }static __inline__ unsigned short cfi_readw(unsigned long addr) { return __raw_readw(addr); }static __inline__ unsigned long cfi_readl(unsigned long addr) { return __raw_readl(addr); }static __inline__ void cfi_writeb(unsigned int val, unsigned long addr) { __raw_writeb(val, addr); mb(); }static __inline__ void cfi_writew(unsigned int val, unsigned long addr) { __raw_writew(val, addr); mb(); }static __inline__ void cfi_writel(unsigned int val, unsigned long addr) { __raw_writel(val, addr); mb(); }static __inline__ unsigned int cfi_read(unsigned long addr);static __inline__ void cfi_write(unsigned val, unsigned long addr);// CFI advanced I/Ostatic __inline__ unsigned int cfi_build_cmd_addr(unsigned long addr);static __inline__ unsigned int cfi_build_cmd(unsigned int cmd);static __inline__ void cfi_send_gen_cmd(unsigned int cmd, unsigned int cmd_addr, unsigned int base);// probing & setupstatic int cfi_probe_chip(cfi_info_t *pcfi);static int cfi_query_present(unsigned int base);static int cfi_chip_setup(cfi_info_t *pcfi);static void cfi_cmdset_0002(cfi_info_t *pcfi);// init & basicint flash_found(void);int flash_probe(unsigned int base, int force, int verbose);// eraseint flash_erase_all(void);int flash_erase_oneblock(unsigned long addr);int flash_erase_region(unsigned long addr, unsigned int len);// writeint flash_write_onebyte(unsigned long addr, unsigned int data);int flash_write_oneword(unsigned long addr, unsigned int data);static int flash_write_data_internal(unsigned long addr, unsigned short *data, int nwords, cfi_info_t *pcfi);int flash_write_data(unsigned long addr, unsigned char *data, int len);// miscellaneousstatic char *cfi_get_idname(unsigned int vendor);void flash_list(void *vpcfi);int flash_calcblock(unsigned long addr, unsigned int *pstart, unsigned int *plen);//// data structure management// cfi_info_t *get_free_cfi(void){ int i; for (i = 0; i < FLASH_MAX_CHIPSET; ++i) if (!g_cfi[i].exist) return &g_cfi[i]; return NULL;}cfi_info_t *find_cfi(unsigned long addr){ int i; for (i = 0; i < FLASH_MAX_CHIPSET; ++i) if (g_cfi[i].exist) if (addr >= g_cfi[i].base && addr < g_cfi[i].base + g_cfi[i].size) return &g_cfi[i]; return NULL;}//// CFI basic I/O//__inline__ unsigned int cfi_read(unsigned long addr){ unsigned int data; switch (CFIDEV_BUSWIDTH) { case 1 : data = cfi_readb(addr); break; case 2 : data = cfi_readw(addr); break; case 4 : data = cfi_readl(addr); break; default : return 0; }#if FLASH_VERBOSE uart_printf("FLASH Read addr = %08lx, data = %*x\n", addr, CFIDEV_BUSWIDTH * 2, data);#endif return data;}__inline__ void cfi_write(unsigned val, unsigned long addr){#if FLASH_VERBOSE // uart_printf("FLASH Write addr = %08lx, data = %*x\n", addr, CFIDEV_BUSWIDTH * 2, val);uart_printf("FLASH Write addr = %x, data = %x\n", addr, val);#endif switch (CFIDEV_BUSWIDTH) { case 1 : cfi_writeb(val, addr); break; case 2 : cfi_writew(val, addr); break; case 4 : cfi_writel(val, addr); break; default : return; }}// // CFI advanced I/O//// bus width address => byte address__inline__ unsigned int cfi_build_cmd_addr(unsigned long addr){ return addr * CFIDEV_DEVTYPE * CFIDEV_INTERLEAVE;}__inline__ unsigned int cfi_build_cmd(unsigned int cmd){ unsigned int val = 0; switch (CFIDEV_BUSWIDTH) { case 1 : val = cmd; break; case 2 : if (CFIDEV_INTERLEAVE == 1) val = cpu_to_cfi16(cmd); else if (CFIDEV_INTERLEAVE == 2) val = cpu_to_cfi16((cmd << 8) | cmd); break; case 4 : if (CFIDEV_INTERLEAVE == 1) val = cpu_to_cfi32(cmd); else if (CFIDEV_INTERLEAVE == 2) val = cpu_to_cfi32((cmd << 16) | cmd); else if (CFIDEV_INTERLEAVE == 4) { val = (cmd << 16) | cmd; val = cpu_to_cfi32((val << 8) | val); } break; default : break; } return val;}__inline__ void cfi_send_gen_cmd(unsigned int cmd, unsigned int cmd_addr, unsigned int base){ cfi_write(cfi_build_cmd(cmd), base + cfi_build_cmd_addr(cmd_addr));}__inline__ void cfi_send_cmd(unsigned int cmd, unsigned int cmd_addr, unsigned int base){ cfi_write(cfi_build_cmd(cmd), base + cmd_addr);}//// probing & setup// int cfi_probe_chip(cfi_info_t *pcfi){ int ret; unsigned long addr_probe1, addr_probe2; unsigned int data_probe1, data_probe2; if (pcfi->exist) --g_flash_chips; pcfi->exist = 0; addr_probe1 = pcfi->base + cfi_build_cmd_addr(0); addr_probe2 = pcfi->base + cfi_build_cmd_addr(0x55); data_probe1 = cfi_read(addr_probe1); data_probe2 = cfi_read(addr_probe2); // Reset cfi_send_gen_cmd(0xf0, 0, pcfi->base); // Enter CFI Query mode cfi_send_gen_cmd(0x98, 0x55, pcfi->base); if ((ret = cfi_query_present(pcfi->base)) != 0) { cfi_write(data_probe1, addr_probe1); cfi_write(data_probe2, addr_probe2); return ret; } pcfi->exist = 1; ++g_flash_chips; if ((ret = cfi_chip_setup(pcfi)) != 0) return ret; // Reset cfi_send_gen_cmd(0xf0, 0, pcfi->base); // internal settings cfi_cmdset_0002(pcfi); return FLASH_OK;}int cfi_query_present(unsigned int base){ return (cfi_read(base + cfi_build_cmd_addr(0x10)) == cfi_build_cmd('Q') && cfi_read(base + cfi_build_cmd_addr(0x11)) == cfi_build_cmd('R') && cfi_read(base + cfi_build_cmd_addr(0x12)) == cfi_build_cmd('Y')) ? FLASH_OK : FLASH_NOTEXIST;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -