diff options
author | Ingo Albrecht <prom@berlin.ccc.de> | 2010-04-11 07:26:42 +0200 |
---|---|---|
committer | Ingo Albrecht <prom@berlin.ccc.de> | 2010-07-20 14:41:19 +0200 |
commit | 3936c397a7918fa8625355b5af39a371da6adc3a (patch) | |
tree | e3bbd8b7e44aad22531098f856516ed360da126b /src/target/firmware/flash | |
parent | d602dcaafb8d1d2018ca9a6ee2f7472480a4f972 (diff) |
loader: flash locking commands, various flash rework
Diffstat (limited to 'src/target/firmware/flash')
-rw-r--r-- | src/target/firmware/flash/cfi_flash.c | 544 |
1 files changed, 315 insertions, 229 deletions
diff --git a/src/target/firmware/flash/cfi_flash.c b/src/target/firmware/flash/cfi_flash.c index a269142f..624d1433 100644 --- a/src/target/firmware/flash/cfi_flash.c +++ b/src/target/firmware/flash/cfi_flash.c @@ -23,50 +23,103 @@ #include <debug.h> #include <stdio.h> #include <stdint.h> +#include <errno.h> #include <memory.h> #include <cfi_flash.h> /* XXX: memdump_range() */ #include <calypso/misc.h> +#include <calypso/uart.h> +#include <comm/sercomm.h> + +/* global definitions */ +#define CFI_FLASH_MAX_ERASE_REGIONS 4 + +/* structure of erase region descriptor */ +struct cfi_region { + uint16_t b_count; + uint16_t b_size; +} __attribute__((packed)); + +/* structure of cfi query response */ +struct cfi_query { + uint8_t qry[3]; + uint16_t p_id; + uint16_t p_adr; + uint16_t a_id; + uint16_t a_adr; + uint8_t vcc_min; + uint8_t vcc_max; + uint8_t vpp_min; + uint8_t vpp_max; + uint8_t word_write_timeout_typ; + uint8_t buf_write_timeout_typ; + uint8_t block_erase_timeout_typ; + uint8_t chip_erase_timeout_typ; + uint8_t word_write_timeout_max; + uint8_t buf_write_timeout_max; + uint8_t block_erase_timeout_max; + uint8_t chip_erase_timeout_max; + uint8_t dev_size; + uint16_t interface_desc; + uint16_t max_buf_write_size; + uint8_t num_erase_regions; + struct cfi_region erase_regions[CFI_FLASH_MAX_ERASE_REGIONS]; +} __attribute__((packed)); + +/* manufacturer ids */ +enum cfi_manuf { + CFI_MANUF_INTEL = 0x0089, +}; + +/* algorithm ids */ +enum cfi_algo { + CFI_ALGO_INTEL_3 = 0x03 +}; -enum flash_cmd { - FLASH_CMD_RESET = 0xff, - FLASH_CMD_READ_ID = 0x90, - FLASH_CMD_CFI = 0x98, - FLASH_CMD_READ_STATUS = 0x70, - FLASH_CMD_CLEAR_STATUS = 0x50, - FLASH_CMD_WRITE = 0x40, - FLASH_CMD_BLOCK_ERASE = 0x20, - FLASH_CMD_ERASE_CONFIRM = 0xD0, - FLASH_CMD_PROTECT = 0x60, +/* various command bytes */ +enum cfi_flash_cmd { + CFI_CMD_RESET = 0xff, + CFI_CMD_READ_ID = 0x90, + CFI_CMD_CFI = 0x98, + CFI_CMD_READ_STATUS = 0x70, + CFI_CMD_CLEAR_STATUS = 0x50, + CFI_CMD_WRITE = 0x40, + CFI_CMD_BLOCK_ERASE = 0x20, + CFI_CMD_ERASE_CONFIRM = 0xD0, + CFI_CMD_PROTECT = 0x60, }; +/* protection commands */ enum flash_prot_cmd { - FLASH_PROT_LOCK = 0x01, - FLASH_PROT_UNLOCK = 0xD0, - FLASH_PROT_LOCKDOWN = 0x2F + CFI_PROT_LOCK = 0x01, + CFI_PROT_UNLOCK = 0xD0, + CFI_PROT_LOCKDOWN = 0x2F }; +/* offsets from base */ enum flash_offset { - FLASH_OFFSET_MANUFACTURER_ID = 0x00, - FLASH_OFFSET_DEVICE_ID = 0x01, - FLASH_OFFSET_INTEL_PROTECTION = 0x81, - FLASH_OFFSET_CFI_RESP = 0x10 + CFI_OFFSET_MANUFACTURER_ID = 0x00, + CFI_OFFSET_DEVICE_ID = 0x01, + CFI_OFFSET_INTEL_PROTECTION = 0x81, + CFI_OFFSET_CFI_RESP = 0x10 }; +/* offsets from block base */ enum flash_block_offset { - FLASH_OFFSET_BLOCK_LOCKSTATE = 0x02 + CFI_OFFSET_BLOCK_LOCKSTATE = 0x02 }; +/* status masks */ enum flash_status { - FLASH_STATUS_READY = 0x80, - FLASH_STATUS_ERASE_SUSPENDED = 0x40, - FLASH_STATUS_ERASE_ERROR = 0x20, - FLASH_STATUS_PROGRAM_ERROR = 0x10, - FLASH_STATUS_VPP_LOW = 0x08, - FLASH_STATUS_PROGRAM_SUSPENDED = 0x04, - FLASH_STATUS_LOCKED_ERROR = 0x02, - FLASH_STATUS_RESERVED = 0x01 + CFI_STATUS_READY = 0x80, + CFI_STATUS_ERASE_SUSPENDED = 0x40, + CFI_STATUS_ERASE_ERROR = 0x20, + CFI_STATUS_PROGRAM_ERROR = 0x10, + CFI_STATUS_VPP_LOW = 0x08, + CFI_STATUS_PROGRAM_SUSPENDED = 0x04, + CFI_STATUS_LOCKED_ERROR = 0x02, + CFI_STATUS_RESERVED = 0x01 }; static inline void flash_write_cmd(const void *base_addr, uint16_t cmd) @@ -83,105 +136,158 @@ static char flash_protected(uint32_t block_offset) { return block_offset < 64*1024; } -uint8_t flash_block_getlock(cfi_flash_t *flash, uint32_t block_offset) { + +flash_lock_t flash_block_getlock(flash_t *flash, uint32_t block_offset) { const void *base_addr = flash->f_base; + uint8_t lockstate; - flash_write_cmd(base_addr, FLASH_CMD_READ_ID); - lockstate = flash_read16(base_addr, block_offset + FLASH_OFFSET_BLOCK_LOCKSTATE); - flash_write_cmd(base_addr, FLASH_CMD_RESET); - return lockstate; + flash_write_cmd(base_addr, CFI_CMD_READ_ID); + lockstate = flash_read16(base_addr, (block_offset>>1) + CFI_OFFSET_BLOCK_LOCKSTATE); + flash_write_cmd(base_addr, CFI_CMD_RESET); + + if(lockstate & 0x2) { + return FLASH_LOCKED_DOWN; + } else if(lockstate & 0x01) { + return FLASH_LOCKED; + } else { + return FLASH_UNLOCKED; + } } -void flash_block_unlock(cfi_flash_t *flash, uint32_t block_offset) { +int flash_block_unlock(flash_t *flash, uint32_t block_offset) { const void *base_addr = flash->f_base; - printf("Unlocking block at 0x%08x\n", block_offset); + + if(block_offset >= flash->f_size) { + return -EINVAL; + } if(flash_protected(block_offset)) { - puts("error: block is soft-protected\n"); - return; + return -EPERM; } - flash_write_cmd(base_addr, FLASH_CMD_PROTECT); - flash_write_cmd(base_addr + block_offset, FLASH_PROT_UNLOCK); - flash_write_cmd(base_addr, FLASH_CMD_RESET); + printf("Unlocking block at 0x%08x, meaning %08x\n", block_offset, base_addr + block_offset); + + flash_write_cmd(base_addr, CFI_CMD_PROTECT); + flash_write_cmd(base_addr + block_offset, CFI_PROT_UNLOCK); + flash_write_cmd(base_addr, CFI_CMD_RESET); + + return 0; } -void flash_block_lock(cfi_flash_t *flash, uint32_t block_offset) { +int flash_block_lock(flash_t *flash, uint32_t block_offset) { const void *base_addr = flash->f_base; + + if(block_offset >= flash->f_size) { + return -EINVAL; + } + printf("Locking block at 0x%08x\n", block_offset); - flash_write_cmd(base_addr, FLASH_CMD_PROTECT); - flash_write_cmd(base_addr + block_offset, FLASH_PROT_LOCK); - flash_write_cmd(base_addr, FLASH_CMD_RESET); + + flash_write_cmd(base_addr, CFI_CMD_PROTECT); + flash_write_cmd(base_addr + block_offset, CFI_PROT_LOCK); + flash_write_cmd(base_addr, CFI_CMD_RESET); + + return 0; } -void flash_block_lockdown(cfi_flash_t *flash, uint32_t block_offset) { +int flash_block_lockdown(flash_t *flash, uint32_t block_offset) { const void *base_addr = flash->f_base; + + if(block_offset >= flash->f_size) { + return -EINVAL; + } + printf("Locking down block at 0x%08x\n", block_offset); - flash_write_cmd(base_addr, FLASH_CMD_PROTECT); - flash_write_cmd(base_addr + block_offset, FLASH_PROT_LOCKDOWN); - flash_write_cmd(base_addr, FLASH_CMD_RESET); + + flash_write_cmd(base_addr, CFI_CMD_PROTECT); + flash_write_cmd(base_addr + block_offset, CFI_PROT_LOCKDOWN); + flash_write_cmd(base_addr, CFI_CMD_RESET); + + return 0; } -void flash_block_erase(cfi_flash_t *flash, uint32_t block_offset) { +int flash_block_erase(flash_t *flash, uint32_t block_offset) { const void *base_addr = flash->f_base; - printf("Erasing block 0x%08x...", block_offset); + + if(block_offset >= flash->f_size) { + return -EINVAL; + } if(flash_protected(block_offset)) { - puts("error: block is soft-protected\n"); - return; + return -EPERM; } + printf("Erasing block 0x%08x...", block_offset); + void *block_addr = ((uint8_t*)base_addr) + block_offset; - flash_write_cmd(base_addr, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(base_addr, CFI_CMD_CLEAR_STATUS); - flash_write_cmd(block_addr, FLASH_CMD_BLOCK_ERASE); - flash_write_cmd(block_addr, FLASH_CMD_ERASE_CONFIRM); + flash_write_cmd(block_addr, CFI_CMD_BLOCK_ERASE); + flash_write_cmd(block_addr, CFI_CMD_ERASE_CONFIRM); - flash_write_cmd(base_addr, FLASH_CMD_READ_STATUS); + flash_write_cmd(base_addr, CFI_CMD_READ_STATUS); uint16_t status; do { status = flash_read16(base_addr, 0); - } while(!(status&FLASH_STATUS_READY)); + } while(!(status&CFI_STATUS_READY)); - if(status&FLASH_STATUS_ERASE_ERROR) { + int res = 0; + if(status&CFI_STATUS_ERASE_ERROR) { puts("error: "); - if(status&FLASH_STATUS_VPP_LOW) { + if(status&CFI_STATUS_VPP_LOW) { puts("vpp insufficient\n"); - } - if(status&FLASH_STATUS_LOCKED_ERROR) { + res = -EFAULT; + } else if(status&CFI_STATUS_LOCKED_ERROR) { puts("block is lock-protected\n"); + res = -EPERM; + } else { + puts("unknown fault\n"); + res = -EFAULT; } } else { puts("done\n"); } - flash_write_cmd(base_addr, FLASH_CMD_RESET); + flash_write_cmd(base_addr, CFI_CMD_RESET); + + return res; + } -void flash_program(cfi_flash_t *flash, uint32_t dst, void *src, uint32_t nbytes) { +int flash_program(flash_t *flash, uint32_t dst, void *src, uint32_t nbytes) { const void *base_addr = flash->f_base; + int res = 0; uint32_t i; - printf("Programming %u bytes to 0x%08x from 0x%p...", nbytes, dst, src); + /* check destination bounds */ + if(dst >= flash->f_size) { + return -EINVAL; + } + if(dst + nbytes > flash->f_size) { + return -EINVAL; + } + /* check destination alignment */ if(dst%2) { - puts("error: unaligned destination\n"); - return; + return -EINVAL; } - if(nbytes%2) { - puts("error: unaligned count\n"); - return; + return -EINVAL; } + /* check permissions */ if(flash_protected(dst)) { - puts("error: block is soft-protected\n"); - return; + return -EPERM; } - flash_write_cmd(base_addr, FLASH_CMD_CLEAR_STATUS); + /* say something */ + printf("Programming %u bytes to 0x%08x from 0x%p...", nbytes, dst, src); + + /* clear status register */ + flash_write_cmd(base_addr, CFI_CMD_CLEAR_STATUS); + /* write the words */ puts("writing..."); for(i = 0; i < nbytes; i += 2) { uint16_t *src_addr = (uint16_t*)(src + i); @@ -189,248 +295,228 @@ void flash_program(cfi_flash_t *flash, uint32_t dst, void *src, uint32_t nbytes) uint16_t data = *src_addr; - flash_write_cmd(dst_addr, FLASH_CMD_WRITE); + flash_write_cmd(dst_addr, CFI_CMD_WRITE); flash_write_cmd(dst_addr, data); - flash_write_cmd(base_addr, FLASH_CMD_READ_STATUS); + flash_write_cmd(base_addr, CFI_CMD_READ_STATUS); uint16_t status; do { status = flash_read16(base_addr, 0); - } while(!(status&FLASH_STATUS_READY)); + } while(!(status&CFI_STATUS_READY)); - if(status&FLASH_STATUS_PROGRAM_ERROR) { + if(status&CFI_STATUS_PROGRAM_ERROR) { puts("error: "); - if(status&FLASH_STATUS_VPP_LOW) { + if(status&CFI_STATUS_VPP_LOW) { puts("vpp insufficient"); - } - if(status&FLASH_STATUS_LOCKED_ERROR) { + res = -EFAULT; + } else if(status&CFI_STATUS_LOCKED_ERROR) { puts("block is lock-protected"); + res = -EPERM; + } else { + puts("unknown fault"); + res = -EFAULT; } goto err_reset; } } - flash_write_cmd(base_addr, FLASH_CMD_RESET); + flash_write_cmd(base_addr, CFI_CMD_RESET); + /* verify the result */ puts("verifying..."); for(i = 0; i < nbytes; i += 2) { uint16_t *src_addr = (uint16_t*)(src + i); uint16_t *dst_addr = (uint16_t*)(base_addr + dst + i); if(*src_addr != *dst_addr) { puts("error: verification failed"); + res = -EFAULT; goto err; } } puts("done\n"); - return; + return res; err_reset: - flash_write_cmd(base_addr, FLASH_CMD_RESET); + flash_write_cmd(base_addr, CFI_CMD_RESET); err: printf(" at offset 0x%x\n", i); -} - -typedef void (*flash_block_cb_t)(cfi_flash_t *flash, - uint32_t block_offset, - uint32_t block_size); -void flash_iterate_blocks(cfi_flash_t *flash, struct cfi_query *qry, - uint32_t start_offset, uint32_t end_offset, - flash_block_cb_t callback) -{ - int region, block; - - uint32_t block_start = 0; - for(region = 0; region < qry->num_erase_regions; region++) { - uint16_t actual_count = qry->erase_regions[region].b_count + 1; - uint32_t actual_size = qry->erase_regions[region].b_size * 256; - for(block = 0; block < actual_count; block++) { - uint32_t block_end = block_start + actual_size; - if(block_start >= start_offset && block_end-1 <= end_offset) { - callback(flash, block_start, actual_size); - } - block_start = block_end; - } - } + return res; } -static void get_id(void *base_addr, uint16_t *manufacturer_id, uint16_t *device_id) { - flash_write_cmd(base_addr, FLASH_CMD_READ_ID); +/* Internal: retrieve manufacturer and device id from id space */ +static int get_id(void *base_addr, uint16_t *manufacturer_id, uint16_t *device_id) { + flash_write_cmd(base_addr, CFI_CMD_READ_ID); - *manufacturer_id = flash_read16(base_addr, FLASH_OFFSET_MANUFACTURER_ID); - *device_id = flash_read16(base_addr, FLASH_OFFSET_DEVICE_ID); + *manufacturer_id = flash_read16(base_addr, CFI_OFFSET_MANUFACTURER_ID); + *device_id = flash_read16(base_addr, CFI_OFFSET_DEVICE_ID); - flash_write_cmd(base_addr, FLASH_CMD_RESET); + flash_write_cmd(base_addr, CFI_CMD_RESET); + + return 0; } -static void get_query(void *base_addr, struct cfi_query *query) { - unsigned int i; +/* Internal: retrieve cfi query response data */ +static int get_query(void *base_addr, struct cfi_query *query) { + int res = 0; + int i; - flash_write_cmd(base_addr, FLASH_CMD_CFI); + flash_write_cmd(base_addr, CFI_CMD_CFI); for(i = 0; i < sizeof(struct cfi_query); i++) { - uint16_t byte = flash_read16(base_addr, FLASH_OFFSET_CFI_RESP+i); + uint16_t byte = flash_read16(base_addr, CFI_OFFSET_CFI_RESP+i); *(((unsigned char*)query)+i) = byte; } if(query->qry[0] != 'Q' || query->qry[1] != 'R' || query->qry[2] != 'Y') { - puts("Error: CFI query signature not found\n"); + res = -ENOENT; } - flash_write_cmd(base_addr, FLASH_CMD_RESET); -} - -static void dump_query(void *base_addr, struct cfi_query *query) { - unsigned int i; - - flash_write_cmd(base_addr, FLASH_CMD_CFI); + flash_write_cmd(base_addr, CFI_CMD_RESET); - for(i = 0; i < sizeof(struct cfi_query); i++) { - uint8_t byte = *(((uint8_t*)query)+i); - printf("%04X: %02X\n", FLASH_OFFSET_CFI_RESP+i, byte); - } - - flash_write_cmd(base_addr, FLASH_CMD_RESET); + return res; } -static void dump_layout(void *base_addr, const struct cfi_query *qry) { - int region; +/* Internal: retrieve intel protection data */ +static int get_intel_protection(void *base_addr, uint16_t *lockp, uint8_t protp[8]) { + int i; - flash_write_cmd(base_addr, FLASH_CMD_READ_ID); - for(region = 0; region < qry->num_erase_regions; region++) { - uint16_t actual_count = qry->erase_regions[region].b_count + 1; - uint32_t actual_size = qry->erase_regions[region].b_size * 256; - printf("Region of 0x%04x times 0x%6x bytes\n", actual_count, - actual_size); + /* check args */ + if(!lockp) { + return -EINVAL; } - flash_write_cmd(base_addr, FLASH_CMD_RESET); -} - -static void dump_locks(void *base_addr, const struct cfi_query *qry) { - int region, block; - - uint32_t block_addr = 0; - flash_write_cmd(base_addr, FLASH_CMD_READ_ID); - for(region = 0; region < qry->num_erase_regions; region++) { - uint16_t actual_count = qry->erase_regions[region].b_count + 1; - uint32_t actual_size = qry->erase_regions[region].b_size * 256; - for(block = 0; block < actual_count; block++) { - uint8_t lock = flash_read16(base_addr, block_addr+2); - printf("Block 0x%08x lock 0x%02x\n", block_addr*2, lock); - block_addr += actual_size / 2; - } + if(!protp) { + return -EINVAL; } - flash_write_cmd(base_addr, FLASH_CMD_RESET); -} -static void dump_protection(void *base_addr) { - flash_write_cmd(base_addr, FLASH_CMD_READ_ID); + /* enter read id mode */ + flash_write_cmd(base_addr, CFI_CMD_READ_ID); - uint16_t lock = flash_read16(base_addr, FLASH_OFFSET_INTEL_PROTECTION); - printf("Protection Lock: 0x%04x\n", lock); + /* get lock */ + *lockp = flash_read16(base_addr, CFI_OFFSET_INTEL_PROTECTION); - puts("Protection Data: "); - int i; + /* get data */ for(i = 0; i < 8; i++) { - printf("%04x", flash_read16(base_addr, FLASH_OFFSET_INTEL_PROTECTION + 1 + i)); + protp[i] = flash_read16(base_addr, CFI_OFFSET_INTEL_PROTECTION + 1 + i); } - putchar('\n'); - flash_write_cmd(base_addr, FLASH_CMD_RESET); -} + /* leave read id mode */ + flash_write_cmd(base_addr, CFI_CMD_RESET); -static void dump_timing(void *base_addr, struct cfi_query *qry) { - uint32_t block_erase_typ = 1<<qry->block_erase_timeout_typ; - uint32_t block_erase_max = (1<<qry->block_erase_timeout_max) * block_erase_typ; - uint32_t word_program_typ = 1<<qry->word_write_timeout_typ; - uint32_t word_program_max = (1<<qry->word_write_timeout_max) * word_program_typ; - printf("Block Erase Typical: %u ms\n", block_erase_typ); - printf("Block Erase Maximum: %u ms\n", block_erase_max); - printf("Word Program Typical: %u us\n", word_program_typ); - printf("Word Program Maximum: %u us\n", word_program_max); + return 0; } -static void dump_algorithms(void *base_addr, struct cfi_query *qry) { - printf("Primary Algorithm ID: %04x\n", qry->p_id); - printf("Primary Extended Query: %04x\n", qry->p_adr); +#if 0 - printf("Alternate Algorithm ID: %04x\n", qry->a_id); - printf("Alternate Extended Query: %04x\n", qry->a_adr); +static void dump_intel_protection(uint16_t lock, uint8_t data[8]) { + printf(" protection lock 0x%4.4x data 0x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + lock, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]); } -void -lockdown_block_cb(cfi_flash_t *flash, - uint32_t block_offset, - uint32_t block_size) -{ - flash_block_lockdown(flash, block_offset); +static void dump_query_algorithms(struct cfi_query *qry) { + printf(" primary algorithm 0x%4.4x\n", qry->p_id); + printf(" primary extended query 0x%4.4x\n", qry->p_adr); + printf(" alternate algorithm 0x%4.4x\n", qry->a_id); + printf(" alternate extended query 0x%4.4x\n", qry->a_adr); } -void -print_block_cb(cfi_flash_t *flash, - uint32_t block_offset, - uint32_t block_size) -{ - printf("%08x size %08x\n", block_offset, block_size); +static void dump_query_timing(struct cfi_query *qry) { + uint32_t block_erase_typ = 1<<qry->block_erase_timeout_typ; + uint32_t block_erase_max = (1<<qry->block_erase_timeout_max) * block_erase_typ; + uint32_t word_program_typ = 1<<qry->word_write_timeout_typ; + uint32_t word_program_max = (1<<qry->word_write_timeout_max) * word_program_typ; + printf(" block erase typ %u ms\n", block_erase_typ); + printf(" block erase max %u ms\n", block_erase_max); + printf(" word program typ %u us\n", word_program_typ); + printf(" word program max %u us\n", word_program_max); } -void flash_dump_info(cfi_flash_t *flash) { - void *base_addr = flash->f_base; - struct cfi_query *qry = &flash->f_query; - - printf("Flash Manufacturer ID: %04x\n", flash->f_manuf_id); - printf("Flash Device ID: %04x\n", flash->f_dev_id); - - printf("Flash Size: 0x%08x bytes\n", flash->f_size); - - dump_algorithms(base_addr, qry); +void flash_dump_info(flash_t *flash) { + int i; + printf("flash at 0x%p of %d bytes with %d regions\n", flash->f_base, flash->f_size, flash->f_nregions); - dump_timing(base_addr, qry); + uint16_t m_id, d_id; + if(get_id(flash->f_base, &m_id, &d_id)) { + puts(" failed to get id\n"); + } else { + printf(" manufacturer 0x%4.4x device 0x%4.4x\n", m_id, d_id); + } - dump_protection(base_addr); + uint16_t plock; + uint8_t pdata[8]; + if(get_intel_protection(flash->f_base, &plock, pdata)) { + puts(" failed to get protection data\n"); + } else { + dump_intel_protection(plock, pdata); + } - dump_layout(base_addr, qry); + struct cfi_query qry; + if(get_query(flash->f_base, &qry)) { + puts(" failed to get cfi query response\n"); + } else { + dump_query_algorithms(&qry); + dump_query_timing(&qry); + } - dump_locks(base_addr, qry); + for(i = 0; i < flash->f_nregions; i++) { + flash_region_t *fr = &flash->f_regions[i]; + printf(" region %d: %d blocks of %d bytes at 0x%p\n", i, fr->fr_bnum, fr->fr_bsize, fr->fr_base); + } } -void flash_init(cfi_flash_t *flash, void *base_addr) { - printd("Initializing CFI flash at 0x%p\n", base_addr); +#endif - flash->f_base = base_addr; +int flash_init(flash_t *flash, void *base_addr) { + int res, i; + uint16_t m_id, d_id; + uint32_t base; + struct cfi_query qry; - get_id(base_addr, &flash->f_manuf_id, &flash->f_dev_id); + /* retrieve and check manufacturer and device id */ + res = get_id(base_addr, &m_id, &d_id); + if(res) { + return res; + } + if(m_id != CFI_MANUF_INTEL) { + /* we only support intel devices */ + return -ENOTSUP; + } - get_query(base_addr, &flash->f_query); + /* retrieve and check query response */ + res = get_query(base_addr, &qry); + if(res) { + return res; + } + if(qry.p_id != CFI_ALGO_INTEL_3) { + /* we only support algo 3 */ + return -ENOTSUP; + } + if(qry.num_erase_regions > FLASH_MAX_REGIONS) { + /* we have a hard limit on the number of regions */ + return -ENOTSUP; + } - flash->f_size = 1<<flash->f_query.dev_size; -} + /* fill in basic information */ + flash->f_base = base_addr; + flash->f_size = 1<<qry.dev_size; -void flash_test() { - /* block iterator test */ -#if 0 - flash_iterate_blocks(flash, qry, 0x0000, 0xFFFF, &lockdown_block_cb); -#endif + /* determine number of erase regions */ + flash->f_nregions = qry.num_erase_regions; - /* programming test */ -#if 0 - static uint8_t magic[] = {0xAA, 0xBB, 0xCC, 0xDD, 0xDE, 0xAD, 0xBE, 0xEF}; + /* compute actual erase region info from cfi junk */ + base = 0; + for(i = 0; i < flash->f_nregions; i++) { + flash_region_t *fr = &flash->f_regions[i]; - memdump_range(&magic, sizeof(magic)); + fr->fr_base = base; + fr->fr_bnum = qry.erase_regions[i].b_count + 1; + fr->fr_bsize = qry.erase_regions[i].b_size * 256; -#if 0 -#define ADDR 0x001E0000 - flash_block_unlock(flash, ADDR); - memdump_range(ADDR, 16); - flash_block_erase(flash, ADDR); - memdump_range(ADDR, 16); - flash_program(flash, ADDR, &magic, sizeof(magic)); - memdump_range(ADDR, 16); -#undef ADDR -#endif + base += fr->fr_bnum * fr->fr_bsize; + } -#endif + return 0; } |