📄 intel16.c
字号:
/*
* intel16.c: Intel 16 bit flash driver
*
* Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
* Copyright (C) 1999 Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
*
* 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
*
*/
#ident "$Id: intel16.c,v 1.4 2002/01/03 16:07:17 erikm Exp $"
#ifdef HAVE_CONFIG_H
# include <blob/config.h>
#endif
#include <blob/errno.h>
#include <blob/flash.h>
#include <blob/util.h>
#include <blob/serial.h>
/* flash commands for a single 16 bit intel flash chip */
#define READ_ARRAY 0x000000FF
#define ERASE_SETUP 0x00000020
#define ERASE_CONFIRM 0x000000D0
#define PGM_SETUP 0x00000040
#define STATUS_READ 0x00000070
#define STATUS_CLEAR 0x00000050
#define STATUS_BUSY 0x00000080
#define STATUS_ERASE_ERR 0x00000020
#define STATUS_PGM_ERR 0x00000010
#define CONFIG_SETUP 0x00000060
#define LOCK_SECTOR 0x00000001
#define UNLOCK_SECTOR 0x000000D0
#define READ_CONFIG 0x00000090
#define LOCK_STATUS_LOCKED 0x00000001
#define LOCK_STATUS_LOCKEDDOWN 0x00000002
static int do_erase(u16 *addr)
{
u16 result;
*addr = STATUS_CLEAR;
barrier();
/* prepare for erase */
*addr = ERASE_SETUP;
barrier();
/* erase block */
*addr = ERASE_CONFIRM;
barrier();
/* status check */
do {
*addr = STATUS_READ;
barrier();
result = *addr;
barrier();
} while((~result & STATUS_BUSY) != 0);
/* put flash back into Read Array mode */
*addr = READ_ARRAY;
barrier();
if((result & STATUS_ERASE_ERR) != 0) {
#ifdef BLOB_DEBUG
SerialOutputString(__FUNCTION__ " failed, result=0x");
SerialOutputHex(result);
SerialOutputString(", addr=0x");
SerialOutputHex((u32) addr);
serial_write('\n');
#endif
return -EFLASHERASE;
}
return 0;
}
static int do_write(u16 *dst, const u16* src)
{
u16 result;
*dst = STATUS_CLEAR;
barrier();
/* setup flash for writing */
*dst = PGM_SETUP;
barrier();
/* write data */
*dst = *src;
barrier();
/* status check */
do {
*dst = STATUS_READ;
barrier();
result = *dst;
barrier();
} while((~result & STATUS_BUSY) != 0);
/* put flash back into Read Array mode */
*dst = READ_ARRAY;
barrier();
if(((result & STATUS_PGM_ERR) != 0) || (*dst != *src)) {
#ifdef BLOB_DEBUG
SerialOutputString(__FUNCTION__ " failed, result=0x");
SerialOutputHex(result);
SerialOutputString(", dst=0x");
SerialOutputHex((u32) dst);
SerialOutputString(", *dst=0x");
SerialOutputHex(*dst);
SerialOutputString(", *src=0x");
SerialOutputHex(*src);
serial_write('\n');
#endif
return -EFLASHPGM;
}
return 0;
}
/* erases a flash block at the given address */
/* we have to break this up in two erases at 16 bit aligned addresses
* (if necessary)
*/
static int flash_erase_intel16(u32 *addr)
{
int result;
u16 *addr16 = (u16*)addr;
/* erase first block */
result = do_erase(addr16);
if(result != 0)
return result;
addr16++;
/* if the second address is not erased, also erase it */
if(*addr16 != 0xffff)
result = do_erase(addr16);
if(result != 0)
return result;
return 0;
}
/* write a flash block at a given location */
/* this has to be broken up into two consectutive 16 bit writes */
static int flash_write_intel16(u32 *dst, const u32* src)
{
u16 *dst16 = (u16 *)dst;
u16 *src16 = (u16 *)src;
int result;
result = do_write(dst16, src16);
if(result != 0)
return result;
dst16++;
src16++;
result = do_write(dst16, src16);
if(result != 0)
return result;
return 0;
}
static int flash_lock_block_intel16(u32 *blockStart)
{
u16 *p = (u16 *) blockStart;
u16 result;
*p = STATUS_CLEAR;
barrier();
*p = CONFIG_SETUP;
barrier();
*p = LOCK_SECTOR;
barrier();
/* status check */
*p = STATUS_READ;
barrier();
result = *p;
barrier();
*p = READ_ARRAY;
barrier();
if ((result & STATUS_PGM_ERR) != 0) {
#ifdef BLOB_DEBUG
SerialOutputString(__FUNCTION__ " failed at 0x");
SerialOutputHex((u32) blockStart);
SerialOutputString(", status=0x");
SerialOutputHex((u32) result);
serial_write('\n');
#endif
return -EFLASHPGM;
}
return 0;
}
static int flash_unlock_block_intel16(u32 *blockStart)
{
u16 *p = (u16 *) blockStart;
u16 result;
*p = STATUS_CLEAR;
barrier();
*p = CONFIG_SETUP;
barrier();
*p = UNLOCK_SECTOR;
barrier();
/* status check */
*p = STATUS_READ;
barrier();
result = *p;
barrier();
*p = READ_ARRAY;
barrier();
if ((result & STATUS_PGM_ERR) != 0) {
#ifdef BLOB_DEBUG
SerialOutputString(__FUNCTION__ " failed at 0x");
SerialOutputHex((u32) blockStart);
SerialOutputString(", status=0x");
SerialOutputHex((u32) result);
serial_write('\n');
#endif
return -EFLASHPGM;
}
return 0;
}
static int flash_query_block_lock_intel16(u32 *blockStart)
{
u16 *p = (u16 *) blockStart;
u16 result;
*p = READ_CONFIG;
barrier();
result = *(p + 2);
barrier();
*blockStart = READ_ARRAY;
barrier();
#ifdef BLOB_DEBUG
SerialOutputString(__FUNCTION__ ": status of block starting at 0x");
SerialOutputHex((u32) blockStart);
SerialOutputString(": 0x");
SerialOutputHex((u32) result);
serial_write('\n');
#endif
return result & (LOCK_STATUS_LOCKED | LOCK_STATUS_LOCKEDDOWN);
}
/* flash driver structure */
flash_driver_t intel16_flash_driver = {
erase: flash_erase_intel16,
write: flash_write_intel16,
lock_block: flash_lock_block_intel16,
unlock_block: flash_unlock_block_intel16,
query_block_lock: flash_query_block_lock_intel16
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -