📄 flashprg.c
字号:
/* openbios/miscLib/flashprg.c, redbios, redbios_iii_1.0 6/14/99 14:33:55 *//*-----------------------------------------------------------------------------+|| This source code has been made available to you by IBM on an AS-IS| basis. Anyone receiving this source is licensed under IBM| copyrights to use it in any way he or she deems fit, including| copying it, modifying it, compiling it, and redistributing it either| with or without modifications. No license under IBM patents or| patent applications is to be implied by the copyright license.|| Any user of this software should understand that IBM cannot provide| technical support for this software and will not be responsible for| any consequences resulting from the use of this software.|| Any person who transfers this source code or any derivative work| must include the IBM copyright notice, this paragraph, and the| preceding two paragraphs in the transferred software.|| COPYRIGHT I B M CORPORATION 1995| LICENSED MATERIAL - PROGRAM PROPERTY OF I B M+-----------------------------------------------------------------------------*//*-----------------------------------------------------------------------------+|| File Name: flash_prog.c|| Function: Programs flash memory, must run out of DRAM.|| Author: Maciej P. Tyrlik.|| Change Activity-|| Date Description of Change BY| --------- --------------------- ---| 14-Jun-94 Created MPT| 15-Jun-94 Finished MPT| 30-Sep-94 Changed to use ROM ID (removed PASS_TWO_128 & PASS_TWO_512) KDW| 05-Oct-94 Added more comments KDW| 08-Nov-94 Removed PASS_ONE MPT| 24-Apr-95 Include s1Lib.h for function prototypes JWB| 23-Jan-97 Ported to DDI board KDW| 27-Jun-97 Updated to support multiple sector erease and programming pag| 25-Feb-98 ported to redwood board pag| 04-Jun-98 fixed comments, added no_erase_mode flag. pag| 15-Jan-99 Ported to Redwood III (removed dram refresh) pag| 10-Jun-99 Replaced intemp and outtemp with macros pag| 14-Jun-99 copy code to RAM in order to simplify make file. pag| 03-Mar-00 Rewrite using Sector Map Table jfh| 03-Mar-00 Rewrite for 16 Meg Flash devices AMD 29LV160BB jfh| 25-Apr-00 Move FLASH_CODE_ADDRESS to eval.h (easier to see Mem Map) jfh| 07-Jan-02 Rewrite to enable random write accross all range YYD| by read before write| 24-Jun-02 Added interrupt lock and cache flush for flash_prog YYD+-----------------------------------------------------------------------------*/#include <stddef.h>#include <ppcLib.h>#include <s1Lib.h>#include <string.h>#include <s1ldLib.h>#include <eval.h>#include "flash.h"//#define DEBUG#undef DEBUG/* function pointers for copied code that does the actual work */static unsigned long (*get_flash_type_ptr)(void);static int (*write_flash_ptr)(unsigned short *, unsigned short, unsigned short);static int (*flash_prog_ptr)(unsigned long start, int offset, char *addr, size_t len, int no_erase_mode);static int (*flash_printf)(const char *format, ...);/* prototypes for copied code that does the actual work */static unsigned long zget_flash_type(void);static int zwrite_flash(unsigned short *, unsigned short, unsigned short);static int zflash_prog(unsigned long start, int offset, char *addr, size_t len, int no_erase_mode);void init_flash_code(void){ int len = zflash_code_size(); int i; unsigned long *sptr, *dptr;#ifdef DEBUG s1printf("Copying Flash code to RAM... \n");#endif /* copy the flash code to RAM one word at a time to support OCM */ sptr = (unsigned long *) zget_flash_type; dptr = (unsigned long *) BIOS_FLASH_CODE_ADDR;#ifdef DEBUG s1printf(" Source %x\n", sptr); s1printf(" Destination %x\n", dptr);#endif /* copy the code to FLASH code to the address where it will run */ for (i = 0; i < len/4; ++i) { *dptr++ = *sptr++; }#ifdef DEBUG s1printf("Copying completed\n");#endif /* update the function pointers to the newly copied locations. */ get_flash_type_ptr = (unsigned long (*)(void)) BIOS_FLASH_CODE_ADDR; write_flash_ptr = (int (*)(unsigned short *, unsigned short, unsigned short)) (BIOS_FLASH_CODE_ADDR + (int) zwrite_flash - (int) zget_flash_type); flash_prog_ptr = (int (*)(unsigned long, int, char *, size_t, int)) (BIOS_FLASH_CODE_ADDR + (int) zflash_prog - (int) zget_flash_type); flash_printf = s1printf;#ifdef DEBUG s1printf("Get Flash Type %x\n", get_flash_type_ptr); s1printf("Write Flash %x\n", write_flash_ptr); s1printf("Program Flash %x\n", flash_prog_ptr);#endif}unsigned long get_flash_type(){ return get_flash_type_ptr();}int flash_prog(unsigned long start, int offset, char *addr, size_t len, int no_erase_mode){ // YYD, added interrupt lock and cache invalidate int rtn; unsigned long msr; msr=ppcAndMsr(~(ppcMsrEE|ppcMsrCI)); rtn = flash_prog_ptr(start, offset, addr, len, no_erase_mode); invalidated_invlidatei((unsigned char *)(start + offset), len); (void)ppcMtmsr(msr); return rtn;}/* This function will allow for determining the manufacturing information *//* associated with the ROM being used. Code sequences were taken from the *//* AMD Flash Memory Products 1992/1993 Data Book/Handbook. */unsigned long zget_flash_type(){ unsigned int fl_base; unsigned short mfg_code, dev_code; volatile unsigned short *flashp; /*--------------------------------------------------------------------------+ | Read Autoselect bytes to determnine FLASH type. +--------------------------------------------------------------------------*/ for (fl_base = FLASH_START; fl_base < (unsigned)FLASH_START + FLASH_TOTAL_SIZE; fl_base = fl_base + FLASH_DEV_SIZE) { flashp = (unsigned short *)fl_base; flashp[0x000] = 0xF0; flashp[0x555] = 0xAA; flashp[0x2AA] = 0x55; flashp[0x555] = 0x90; mfg_code = flashp[0]; dev_code = flashp[1]; /*---------------------------------------------------------------------+ | Reset the FLASH (enable read access) +----------------------------------------------------------------------*/ flashp[0x000] = 0xF0; #ifdef DEBUG flash_printf("mfg_code = %8.8X dev_code = %8.8X\n",mfg_code, dev_code);#endif if ((mfg_code != MFG_STRING) || (dev_code != DEV_STRING)) { flash_printf("Device not recognized\n"); flash_printf("mfg_code = %8.8X dev_code = %8.8X\n",mfg_code, dev_code); return -1; // YYD } } return(dev_code);}/* writes one word to the flash at specified address */int zwrite_flash(unsigned short *addr, unsigned short data, unsigned short mask){ volatile unsigned short *flashp; unsigned short temp; int i; if (mask == 0xffff) { temp = data; } else { flashp = addr; temp = (flashp[0x000] & ~mask) | (data & mask); } /* Set-up sequence for writing data. */ flashp = (unsigned short *) ((unsigned long ) addr & 0x7fff0000); flashp[0x555] = 0xAA; flashp[0x2AA] = 0x55; flashp[0x555] = 0xA0; flashp = addr; flashp[0x000] = temp; while (1) { /* poll until the write is complete */ for (i = 0; i < 500 ; i++); if ((flashp[0x000] & 0x80) == (temp & 0x80)) { break; } if ((flashp[0x000] & 0x20) != 0) { if ((flashp[0x000] & 0x80) == (temp & 0x80)) { break; } else {#ifdef DEBUG flash_printf("Failed to write flash address 0x%08x\n", addr);#endif return -1; } } } return 0;}// YYD, this one has been rewrite to enable random write by read before writeint zflash_prog(unsigned long start, int offset, char *addr, size_t len, int no_erase_mode){ int sector; unsigned long nvptr, nvend, bufptr; /* Determine the size of the flash being used. */ if (get_flash_type_ptr() != DEV_STRING) // YYD {#ifdef DEBUG flash_printf("Unsupported FLASH device\n");#endif return -1; } /*--------------------------------------------------------------------------+ | Write requested information. +--------------------------------------------------------------------------*/ /* Set nvstart to the address where writing will begin. */ nvptr = (start + offset) & FLASH_ADDR_MASK; nvend = nvptr + len; bufptr = 0; if(nvptr < FLASH_START || nvptr >= (unsigned)FLASH_START + FLASH_TOTAL_SIZE || nvend >= (unsigned)FLASH_START + FLASH_TOTAL_SIZE) {#ifdef DEBUG flash_printf("Flash address out of range\n");#endif return -1; }#ifdef DEBUG flash_printf("FLASH: Flashing address 0x%08x 0x%08x\n", nvptr, nvend);#endif /*--------------------------------------------------------------------------+ | Locate the first modified sector +--------------------------------------------------------------------------*/ for (sector = 0; sector < NUM_SECTORS; sector++) { if (nvptr >= flash_map[sector].start_addr && nvptr < flash_map[sector+1].start_addr) { break; } } if(sector >= NUM_SECTORS) //YYD, failed to located the sector address {#ifdef DEBUG flash_printf("FLASH: Flash address out of range\n");#endif return -1; // should not happen since we have checked the address } while(nvptr < nvend) { int sect_len = flash_map[sector+1].start_addr - flash_map[sector].start_addr; unsigned short *flash_buffer = (unsigned short *)BIOS_FLASH_BUFFER_ADDR; unsigned short *sect_addr = (unsigned short *)flash_map[sector].start_addr; int k; if(sect_len > BIOS_FLASH_BUFFER_SIZE) {#ifdef DEBUG flash_printf("FLASH: device secter too large, please change BIOS_FLASH_BUFFER_SIZE\n");#endif return -1; } if (nvptr < flash_map[sector].start_addr || nvptr >= flash_map[sector+1].start_addr) { return -1; // some dirty mistake happened } // read the sector first for(k=0; k<sect_len/2; k++) { flash_buffer[k] = sect_addr[k]; }#ifdef DEBUG flash_printf("FLASH: copied sector %d (%d) bytes\n", sector, sect_len);#endif // copy the changed content then for(k=nvptr-(unsigned int)sect_addr; k<sect_len && nvptr<nvend; nvptr++, bufptr++, k++) { *((unsigned char *)flash_buffer + k) = addr[bufptr]; }#ifdef DEBUG flash_printf("FLASH: copied buffer 0x%08x (%d) bytes\n", nvptr-k, k);#endif // erase the sector now { /*--------------------------------------------------------------------------+ | Start the erase sector in each sector that needs to be erased. +--------------------------------------------------------------------------*/ volatile unsigned short *flashp = sect_addr; flashp[0x555] = 0xAA; flashp[0x2AA] = 0x55; flashp[0x555] = 0x80; flashp[0x555] = 0xAA; flashp[0x2AA] = 0x55; flashp[0x000] = 0x30; /*--------------------------------------------------------------------------+ | Poll for completion of the erase sector in each sector that we're erasing. +--------------------------------------------------------------------------*/ while (1) { /* poll until the erase is complete */ if ((flashp[0] & 0x80)!=0) { break; } if ((flashp[0] & 0x20)!=0) { if ((flashp[0] & 0x80)!=0) { break; } else {#ifdef DEBUG flash_printf("FLASH: erase sector %d failed\n", sector);#endif return -1; // flash erase failed !!! } } } } // at last, write the updated sector for(k=0; k<sect_len/2; k++) { if (write_flash_ptr(sect_addr+k, flash_buffer[k], 0xffff)) {#ifdef DEBUG flash_printf("FLASH: write 0x%08x failed\n", sect_addr+k);#endif return(-1); } } // then move to next sector sector ++; if(sector >= NUM_SECTORS && nvptr < nvend) {#ifdef DEBUG flash_printf("FLASH: sector number out of range\n");#endif return -1; // we should never be here } } return(0);}int zflash_code_size(void){ return (int) zflash_code_size - (int) zget_flash_type;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -