📄 flash.c
字号:
/* * $Id: flash.c,v 1.3 2003/09/26 07:11:55 jfabo Exp $ * * Copyright (C) 2001, 2002 ETC s.r.o. * * 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. * * Written by Marcel Telka <marcel@telka.sk>, 2001, 2002. * */#include ".config.h"#include <stdint.h>#include <flash/cfi.h>#include <flash/intel.h>#include "board.h"#include "except.h"#include "flash.h"#include "format.h"#include "splash.h"#define FLASH(addr) (*(volatile uint32_t *)(MEM_VIRT_FLASH + ((addr) << 2)))#define MAXBUFSIZE 1024#define MAXBLOCKS 256static uint32_t flashoffset;static uint8_t flashbuf[MAXBUFSIZE];static size_t flashbufsize;static uint32_t flashbufptr;static int erasedblocks[MAXBLOCKS];static size_t blocksize;static voiderase( int block ){ if (!erasedblocks[block]) { EdbgOutputDebugString( "Erasing block #%d%s\n", block, block ? "" : " WARNING: Overwriting xboot!" ); if (FlashClearBlockLockBit( block )) Throw E_FL_BLOCKUNLOCK; if (FlashBlockErase( block )) Throw E_FL_BLOCKERASE; erasedblocks[block] = 1; }}static voidflash( void *dst, const void *src, size_t count ){ size_t offset = (size_t) dst - MEM_VIRT_FLASH; if ((offset % sizeof (size_t)) || (count % sizeof (size_t))) Throw E_FL_DATAALIGNMENT; /* TODO: check offset and offset + count to be in flashsize */ while (count) { size_t len; int block = offset / blocksize; size_t nbo = (block + 1) * blocksize; if ((len = (nbo - offset)) > count) len = count; erase( block ); count -= len; while (len) { size_t flen = (len > flashbufsize) ? flashbufsize : len; if (FlashWriteToBuffer( offset, src, flen / 4 )) Throw E_FL_WRITETOBUFFER; offset += flen; len -= flen; src = (void *) ((size_t) src + flen); } }}static voidWriteFlashBuf( void ){ uint32_t block = flashoffset / blocksize; erase( block ); if (FlashWriteToBuffer( flashoffset, (uint32_t *) &flashbuf, (flashbufptr + 3) / 4 )) Throw E_FL_WRITETOBUFFER; flashoffset += flashbufptr;}static voidWriteByte( uint8_t c ){ flashbuf[flashbufptr++] = c; if (flashbufptr == flashbufsize) { WriteFlashBuf(); flashbufptr = 0; }}static voidWriteDWord( uint32_t dw ){ WriteByte( (uint8_t) (dw & 0xFF) ); WriteByte( (uint8_t) ((dw >> 8) & 0xFF) ); WriteByte( (uint8_t) ((dw >> 16) & 0xFF) ); WriteByte( (uint8_t) ((dw >> 24) & 0xFF) );}static voidStartFlash( uint32_t offset, struct FlashInfo *fi ){ int i; if ((fi->wbufsize > MAXBUFSIZE) || (fi->eblocks > MAXBLOCKS)) Throw E_FL_OUTOFMEMORY; flashoffset = offset; flashbufsize = fi->wbufsize; flashbufptr = 0; blocksize = fi->eblocksize; for (i = 0; i < fi->eblocks; i++) erasedblocks[i] = 0;}static voidEndFlash( void ){ if (flashbufptr > 0) WriteFlashBuf(); FlashReadArray();}voidFlashXIP( struct imginfo *img ){ unsigned int *rec = (void *) img->target;#ifdef CONFIG_SPLASH_SCREEN unsigned int total_length = 0; unsigned char progress_percentage = 0;#endif switch (img->start & 0xFF000000) { case MEM_VIRT_FLASH: img->target = img->start; break; case MEM_PHYS_FLASH: img->target = img->start + MEM_VIRT_FLASH - MEM_PHYS_FLASH; break; default: Throw E_FL_UNKNOWNMEMORY; } for (;;) { unsigned int addr = *rec++; unsigned int len = *rec++; unsigned int sum = *rec++;#ifdef CONFIG_SPLASH_SCREEN unsigned int step = 0, current = 0;#endif if (!addr && !sum) { FlashReadArray();#ifdef CONFIG_SPLASH_SCREEN progress_bar(100, 0);#endif return; }#ifdef CONFIG_SPLASH_SCREEN#define LARGE_BLOCK 262144 step = (LARGE_BLOCK < len) ? LARGE_BLOCK : len; current = 0; while (current < len) { total_length += step; if (((total_length * 100 )/ img->len ) > progress_percentage ){ progress_percentage = (unsigned char)((total_length * 100 )/ img->len ); progress_bar(progress_percentage, 0); } flash( (void *) (addr - img->start + img->target + current), rec + current/4, step ); current +=step; step = (LARGE_BLOCK < (len - current)) ? LARGE_BLOCK : (len - current); } #else flash( (void *) (addr - img->start + img->target), rec, len );#endif rec += len / sizeof *rec; }}voidFlashImage( struct imginfo *img, unsigned int FlashOffset ){ struct FlashInfo fi; unsigned int *rec; if (!FlashReadInfo( &fi )) Throw E_FL_READINFO; EdbgOutputDebugString( "Flash size: %d (0x%X)\n", fi.size, fi.size ); EdbgOutputDebugString( "Write buffer size: %d\n", fi.wbufsize ); EdbgOutputDebugString( "Number of blocks: %d\n", fi.eblocks ); EdbgOutputDebugString( "Block size: %d (0x%X)\n", fi.eblocksize, fi.eblocksize ); EdbgOutputDebugString( "\n" ); StartFlash( FlashOffset, &fi ); if (img->copy) { FlashXIP( img ); return; } WriteByte( 'B' ); WriteByte( '0' ); WriteByte( '0' ); WriteByte( '0' ); WriteByte( 'F' ); WriteByte( 'F' ); WriteByte( '\n' ); WriteDWord( img->start ); WriteDWord( img->len ); rec = (void *) (img->target + img->len); for (;;) { unsigned int addr = *rec++; unsigned int len = *rec++; unsigned int sum = *rec++; unsigned int calcCRC = 0; unsigned int i; WriteDWord( addr ); WriteDWord( len ); WriteDWord( sum ); if (!addr && !sum) { EndFlash(); return; } for (i = 0; i < len; i++) { unsigned char d = *(unsigned char *) (addr++ - img->start + img->target); WriteByte( d ); calcCRC += d; } if (calcCRC != sum) Throw E_FL_CHECKSUM; }}static voidFlashCommand( uint8_t cmd, uint32_t addr ){ uint32_t command = cmd; FLASH( addr ) = (command << 16) | command;}/* 4.1 */voidFlashReadArray( void ){ FlashCommand( CFI_CMD_READ_ARRAY1, 0x00 );}/* 4.2 */#define DOUBLETEST(val) { if (((val) & 0xFFFF) != ((val) >> 16)) return 0; }#define COMBINEREAD(adr1, adr2) ((FLASH( adr1 ) & 0xFF00FF) | ((FLASH( adr2 ) & 0xFF00FF) << 8))intFlashReadInfo( struct FlashInfo *fi ){ uint32_t dw; FlashCommand( CFI_CMD_QUERY, CFI_CMD_QUERY_OFFSET ); /* * 4.2.1 - 4.2.3 */ /* (nothing to do) */ /* * 4.2.4 CFI Query Interface String */ /* check query-unique ascii string */ if (FLASH( CFI_QUERY_ID_OFFSET ) != 0x00510051) return 0; /* Q */ if (FLASH( CFI_QUERY_ID_OFFSET + 1 ) != 0x00520052) return 0; /* R */ if (FLASH( CFI_QUERY_ID_OFFSET + 2) != 0x00590059) return 0; /* Y */ /* check vendor specific algorithm */ if (COMBINEREAD( 0x13, 0x14 ) != 0x00010001) return 0; /* check extended query table primary algorithm address */ if (COMBINEREAD( 0x15, 0x16 ) != 0x00310031) return 0; /* check alternate vendor command set */ if (COMBINEREAD( 0x17, 0x18 ) != 0x00000000) return 0; /* check secondary algorithm extended query table address */ if (COMBINEREAD( 0x19, 0x1A ) != 0x00000000) return 0; /* * 4.2.5 System Interface Information */ /* check Vcc logic supply minimum program/erase voltage */ if (FLASH( 0x1B ) != 0x00270027) return 0; /* check Vcc logic supply maximum program/erase voltage */ if (FLASH( 0x1C ) != 0x00360036) return 0; /* check Vpp [programming] supply minimum program/erase voltage */ if (FLASH( 0x1D ) != 0x00000000) return 0; /* check Vpp [programming] supply maximum program/erase voltage */ if (FLASH( 0x1E ) != 0x00000000) return 0; /* TODO: addresses 0x1F - 0x26 */ /* * 4.2.6 Device Geometry Definition */ /* read device size */ DOUBLETEST( dw = FLASH( 0x27 ) ); /* device size is multiplied by two, because we have two ICs */ fi->size = (1 << (dw & 0xFFFF)) * 2; /* read max. number of bytes in write buffer */ DOUBLETEST( dw = COMBINEREAD( 0x2A, 0x2B ) ); /* write buffer size is multiplied by two, because we have two ICs */ fi->wbufsize = (1 << (dw & 0xFFFF)) * 2; /* check number of erase block regions */ if (FLASH( 0x2C ) != 0x00010001) return 0; /* read number of erase blocks */ DOUBLETEST( dw = COMBINEREAD( 0x2D, 0x2E ) ); fi->eblocks = (uint16_t) ((dw & 0xFFFF) + 1); /* read erase block size */ DOUBLETEST( dw = COMBINEREAD( 0x2F, 0x30 ) ); /* erase block size is multiplied by two, because we have two ICs */ fi->eblocksize = ((dw & 0xFFFF) << 8) * 2; /* * 4.2.7 Primary-Vendor Specific Extended Query Table * TODO */ return 1;}#undef COMBINEREAD#undef DOUBLETEST/* 4.3 */intFlashReadID( void ){ FlashCommand( 0x90, 0x00 ); /* check Manufacturer Code */ if (FLASH( 0x00 ) != 0x890089) return 0; /* check Device Code */ switch (FLASH( 0x01 )) { case 0x160016: return 0x16; case 0x170017: return 0x17; case 0x180018: return 0x18; } return 0;}/* 4.4 TODO */uint32_tFlashReadStatusRegister( void ){ FlashCommand( 0x70, 0x00 ); return FLASH( 0x00 );}/* 4.5 */voidFlashClearStatusRegister( void ){ FlashCommand( 0x50, 0x00 );}/* 4.6 */uint32_tFlashBlockErase( int block ){ FlashClearStatusRegister(); FlashCommand( 0x20, block << 16 ); /* Block Erase Command */ FlashCommand( 0xD0, block << 16 ); /* confirm */ while ((FlashReadStatusRegister() & 0x00800080) != 0x00800080) /* wait for SR.7 = 1 */ ; return FlashReadStatusRegister() & 0x007E007E; /* return masked SR */}/* 4.8 */uint32_tFlashWriteToBuffer( uint32_t dst, const uint32_t *src, uint32_t size ){ uint32_t i; dst >>= 2; FlashClearStatusRegister(); /* clear status register */ do { FlashCommand( 0xE8, dst ); /* Write to Buffer Command */ } while ((FLASH( dst ) & 0x00800080) != 0x00800080); /* repeat until XSR.7 = 1 */ FlashCommand( (uint8_t) (size - 1), dst ); /* set word count */ for (i = 0; i < size; i++) FLASH( dst++ ) = *src++; /* copy data to write buffer */ FlashCommand( 0xD0, 0x00 ); /* confirm */ while ((FlashReadStatusRegister() & 0x00800080) != 0x00800080) /* wait for SR.7 = 1 */ ; return FlashReadStatusRegister() & 0x007E007E; /* return masked SR */}/* 4.14 */uint32_tFlashClearBlockLockBit( int block ){ FlashClearStatusRegister(); FlashCommand( CFI_INTEL_CMD_LOCK_SETUP, block << 16 ); FlashCommand( CFI_INTEL_CMD_UNLOCK_BLOCK, block << 16 ); while ((FlashReadStatusRegister() & 0x00800080) != 0x00800080) /* wait for SR.7 = 1 */ ; return FlashReadStatusRegister() & 0x007E007E; /* return masked SR */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -