summaryrefslogtreecommitdiffstats
path: root/src/target/firmware/flash
diff options
context:
space:
mode:
authorIngo Albrecht <prom@berlin.ccc.de>2010-04-11 07:26:42 +0200
committerIngo Albrecht <prom@berlin.ccc.de>2010-07-20 14:41:19 +0200
commit3936c397a7918fa8625355b5af39a371da6adc3a (patch)
treee3bbd8b7e44aad22531098f856516ed360da126b /src/target/firmware/flash
parentd602dcaafb8d1d2018ca9a6ee2f7472480a4f972 (diff)
loader: flash locking commands, various flash rework
Diffstat (limited to 'src/target/firmware/flash')
-rw-r--r--src/target/firmware/flash/cfi_flash.c544
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;
}