📄 flash_intel.c
字号:
/* * Copyright (c) 2000 Blue Mug, Inc. All Rights Reserved. * * Commands to program the Intel 28F320B3 flash chips on the Cirrus * Logic CDB89712 evaluation board. These are 32 Mbit "bottom boot" * (boot and param blocks at low end of address space) flash chips. * * The CDB89712 has two 8Mbyte flash banks, each using two flash chips. * The flash chips are 16 bits wide; one occupies the 16 high lines on * the data bus, the other the low lines. So when we write commands * to the flash, we have to duplicate each command across each half of * the data bus: * * *addr = 0x00FF00FF; * * This is seen as a word-wide write of 0x00FF by each 16-bit flash * chip. Such an arrangement should be familiar to embedded * developers who have worked with flash in 32-bit systems. * * Two of the boot blocks in each flash are write protected. We don't * provide any way of circumventing that protection here. From a * quick look at the CDB89712 schematics, it looks like the write * protect line is held at logic high, so the blocks are always * writeable on this board. * * Even in other configurations (e.g. WP line wired to a GPIO output) * I expect that I'll want to avoid automatic disabling of write * protect here, since the consequences of writing garbage into the * boot blocks can be grave. In the infrequent case in which you're * writing over the boot loader itself, it's not too onerous to have * to fire up the command line and do a little register prodding. */#include <target/buffer.h>#include <target/io.h>#include <target/herrno.h>#include <target/scan.h>#include "flash.h"/* download buffer for the flash programmer */#define DLBUFSIZE (8*1024)unsigned char dlbuf [DLBUFSIZE];word_t dlbufsize = DLBUFSIZE;/* timeout for auto-boot, in seconds */#define FL_WORD(addr) (*(volatile unsigned long*)(addr))/* command user interface (CUI) */#define CUI_READ_ARRAY 0x00FF00FF;#define CUI_READ_IDENTIFIER 0x00900090;#define CUI_READ_STATUS 0x00700070;#define CUI_CLEAR_STATUS 0x00500050;#define CUI_PROGRAM 0x00400040;#define CUI_BLOCK_ERASE 0x00200020;#define CUI_PROG_ERASE_SUSPEND 0x00B000B0;#define CUI_PROG_ERASE_RESUME 0x00D000D0;/* status register bits */#define SR7_WSMS (1<<7) /* Write State Machine Status */#define SR6_ESS (1<<6) /* Erase-Suspend Status */#define SR5_ES (1<<5) /* Erase Status */#define SR4_PS (1<<4) /* Program Status */#define SR3_VPPS (1<<3) /* V_PP (program voltage) Status */#define SR2_PSS (1<<2) /* Program Suspend Status */#define SR1_BLLK (1<<1) /* Block Lock Status *//* bit 0 is reserved */#define SR_MASK (SR7_WSMS|SR6_ESS|SR5_ES|SR4_PS|SR3_VPPS|SR2_PSS|SR1_BLLK)#define SR_ERASE_ERR (SR5_ES|SR4_PS|SR3_VPPS|SR1_BLLK)#define SR_BOTH_MASK (SM_MASK | (SM_MASK << 16))#define SR_BOTH_WSMS (SR7_WSMS | (SR7_WSMS << 16))#define SR_BOTH_ERASE_ERR (SR_ERASE_ERR | (SR_ERASE_ERR << 16))/* handy flash functions */static void flash_print_chip_error_string(unsigned char status);static void flash_print_error_string(void);static word_t flash_status_wait(addr_t addr);static int flash_status_full_check(addr_t addr);static void flash_print_chip_error_string(unsigned char status){ if (status & SR3_VPPS) hprint("VPPRange"); else if ((status & SR5_ES) && (status & SR4_PS)) hprint("CommandSequence"); else if (status & SR5_ES) hprint("BlockErase"); else if (status & SR1_BLLK) hprint("LockedBlock"); else hprint("NoError");}/* * 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 & SR_MASK); hprint(" highbank:"); flash_print_chip_error_string((errdata.word >> 16) & SR_MASK);}/* * Loop until both write state machines complete. */static word_t flash_status_wait(addr_t addr){ word_t status; do { status = FL_WORD(addr); } while ((status & SR_BOTH_WSMS) != SR_BOTH_WSMS); 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){ word_t status; status = flash_status_wait(addr) & SR_BOTH_ERASE_ERR; if (status) { errdata.word = status; errfunc = &flash_print_error_string; } FL_WORD(addr) = CUI_CLEAR_STATUS; FL_WORD(addr) = CUI_READ_ARRAY; return status ? -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. */static int flash_program_cmdfunc(int argc, char *argv[]){ addr_t addr; size_t size; word_t *ptr; if (argc != 3) return -H_EUSAGE; if (scan(*++argv, &addr)) return -H_EADDR; if (scan(*++argv, &size)) return -H_EADDR; if (addr & UNALIGNED_MASK) return -H_EALIGN; if (size & UNALIGNED_MASK) return -H_EALIGN; size >>= BYTE_TO_WORD_SHIFT; for (ptr = (word_t*)dlbuf; size--; addr += sizeof(word_t)) { FL_WORD(addr) = CUI_PROGRAM; FL_WORD(addr) = *ptr++; flash_status_wait(addr); } return flash_status_full_check(addr);}const command_t flash_program_command = { "program", "<addr> <size>", "program flash from download buffer", &flash_program_cmdfunc };/* * 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). */static int flash_erase_cmdfunc(int argc, char *argv[]){ addr_t addr; if (argc != 2) return -H_EUSAGE; if (scan(*++argv, &addr)) return -H_EADDR; addr &= ~(addr_t)UNALIGNED_MASK; /* word align */ FL_WORD(addr) = CUI_BLOCK_ERASE; FL_WORD(addr) = CUI_PROG_ERASE_RESUME; return flash_status_full_check(addr);}const command_t flash_erase_command = { "erase", "<addr>", "erase flash block", &flash_erase_cmdfunc };
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -