1 /* NOR Flash Driver for Intel 28F160C3 NOR flash */
3 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include <flash/cfi_flash.h>
31 /* XXX: memdump_range() */
32 #include <calypso/misc.h>
33 #include <calypso/uart.h>
34 #include <comm/sercomm.h>
36 /* XXX: strings must always be in ram */
42 /* global definitions */
43 #define CFI_FLASH_MAX_ERASE_REGIONS 4
45 /* structure of erase region descriptor */
49 } __attribute__ ((packed));
51 /* structure of cfi query response */
62 uint8_t word_write_timeout_typ;
63 uint8_t buf_write_timeout_typ;
64 uint8_t block_erase_timeout_typ;
65 uint8_t chip_erase_timeout_typ;
66 uint8_t word_write_timeout_max;
67 uint8_t buf_write_timeout_max;
68 uint8_t block_erase_timeout_max;
69 uint8_t chip_erase_timeout_max;
71 uint16_t interface_desc;
72 uint16_t max_buf_write_size;
73 uint8_t num_erase_regions;
74 struct cfi_region erase_regions[CFI_FLASH_MAX_ERASE_REGIONS];
75 } __attribute__ ((packed));
77 /* manufacturer ids */
79 CFI_MANUF_INTEL = 0x0089,
84 CFI_ALGO_INTEL_3 = 0x03
87 /* various command bytes */
90 CFI_CMD_READ_ID = 0x90,
92 CFI_CMD_READ_STATUS = 0x70,
93 CFI_CMD_CLEAR_STATUS = 0x50,
95 CFI_CMD_BLOCK_ERASE = 0x20,
96 CFI_CMD_ERASE_CONFIRM = 0xD0,
97 CFI_CMD_PROTECT = 0x60,
100 /* protection commands */
101 enum flash_prot_cmd {
102 CFI_PROT_LOCK = 0x01,
103 CFI_PROT_UNLOCK = 0xD0,
104 CFI_PROT_LOCKDOWN = 0x2F
107 /* offsets from base */
109 CFI_OFFSET_MANUFACTURER_ID = 0x00,
110 CFI_OFFSET_DEVICE_ID = 0x01,
111 CFI_OFFSET_INTEL_PROTECTION = 0x81,
112 CFI_OFFSET_CFI_RESP = 0x10
115 /* offsets from block base */
116 enum flash_block_offset {
117 CFI_OFFSET_BLOCK_LOCKSTATE = 0x02
122 CFI_STATUS_READY = 0x80,
123 CFI_STATUS_ERASE_SUSPENDED = 0x40,
124 CFI_STATUS_ERASE_ERROR = 0x20,
125 CFI_STATUS_PROGRAM_ERROR = 0x10,
126 CFI_STATUS_VPP_LOW = 0x08,
127 CFI_STATUS_PROGRAM_SUSPENDED = 0x04,
128 CFI_STATUS_LOCKED_ERROR = 0x02,
129 CFI_STATUS_RESERVED = 0x01
133 static inline void flash_write_cmd(const void *base_addr, uint16_t cmd)
135 writew(cmd, base_addr);
139 static inline uint16_t flash_read16(const void *base_addr, uint32_t offset)
141 return readw(base_addr + (offset << 1));
145 static char flash_protected(uint32_t block_offset)
147 #ifdef CONFIG_FLASH_WRITE
148 # ifdef CONFIG_FLASH_WRITE_LOADER
151 return block_offset <= 0xFFFF;
159 flash_lock_t flash_block_getlock(flash_t * flash, uint32_t block_offset)
161 const void *base_addr = flash->f_base;
164 flash_write_cmd(base_addr, CFI_CMD_READ_ID);
166 flash_read16(base_addr,
167 (block_offset >> 1) + CFI_OFFSET_BLOCK_LOCKSTATE);
168 flash_write_cmd(base_addr, CFI_CMD_RESET);
170 if (lockstate & 0x2) {
171 return FLASH_LOCKED_DOWN;
172 } else if (lockstate & 0x01) {
175 return FLASH_UNLOCKED;
180 int flash_block_unlock(flash_t * flash, uint32_t block_offset)
182 const void *base_addr = flash->f_base;
184 if (block_offset >= flash->f_size) {
188 if (flash_protected(block_offset)) {
192 printf("Unlocking block at 0x%08x, meaning %08x\n",
193 block_offset, base_addr + block_offset);
195 flash_write_cmd(base_addr, CFI_CMD_PROTECT);
196 flash_write_cmd(base_addr + block_offset, CFI_PROT_UNLOCK);
197 flash_write_cmd(base_addr, CFI_CMD_RESET);
203 int flash_block_lock(flash_t * flash, uint32_t block_offset)
205 const void *base_addr = flash->f_base;
207 if (block_offset >= flash->f_size) {
211 printf("Locking block at 0x%08x\n", block_offset);
213 flash_write_cmd(base_addr, CFI_CMD_PROTECT);
214 flash_write_cmd(base_addr + block_offset, CFI_PROT_LOCK);
215 flash_write_cmd(base_addr, CFI_CMD_RESET);
221 int flash_block_lockdown(flash_t * flash, uint32_t block_offset)
223 const void *base_addr = flash->f_base;
225 if (block_offset >= flash->f_size) {
229 printf("Locking down block at 0x%08x\n", block_offset);
231 flash_write_cmd(base_addr, CFI_CMD_PROTECT);
232 flash_write_cmd(base_addr + block_offset, CFI_PROT_LOCKDOWN);
233 flash_write_cmd(base_addr, CFI_CMD_RESET);
239 int flash_block_erase(flash_t * flash, uint32_t block_offset)
241 const void *base_addr = flash->f_base;
243 if (block_offset >= flash->f_size) {
247 if (flash_protected(block_offset)) {
251 printf("Erasing block 0x%08x...", block_offset);
253 void *block_addr = ((uint8_t *) base_addr) + block_offset;
255 flash_write_cmd(base_addr, CFI_CMD_CLEAR_STATUS);
257 flash_write_cmd(block_addr, CFI_CMD_BLOCK_ERASE);
258 flash_write_cmd(block_addr, CFI_CMD_ERASE_CONFIRM);
260 flash_write_cmd(base_addr, CFI_CMD_READ_STATUS);
263 status = flash_read16(base_addr, 0);
264 } while (!(status & CFI_STATUS_READY));
267 if (status & CFI_STATUS_ERASE_ERROR) {
269 if (status & CFI_STATUS_VPP_LOW) {
270 puts("vpp insufficient\n");
272 } else if (status & CFI_STATUS_LOCKED_ERROR) {
273 puts("block is lock-protected\n");
276 puts("unknown fault\n");
283 flash_write_cmd(base_addr, CFI_CMD_RESET);
290 int flash_program(flash_t * flash, uint32_t dst, void *src, uint32_t nbytes)
292 const void *base_addr = flash->f_base;
296 /* check destination bounds */
297 if (dst >= flash->f_size) {
300 if (dst + nbytes > flash->f_size) {
304 /* check alignments */
305 if (((uint32_t) src) % 2) {
315 /* check permissions */
316 if (flash_protected(dst)) {
321 printf("Programming %u bytes to 0x%08x from 0x%p...", nbytes, dst, src);
323 /* clear status register */
324 flash_write_cmd(base_addr, CFI_CMD_CLEAR_STATUS);
326 /* write the words */
328 for (i = 0; i < nbytes; i += 2) {
329 uint16_t *src_addr = (uint16_t *) (src + i);
330 uint16_t *dst_addr = (uint16_t *) (base_addr + dst + i);
332 uint16_t data = *src_addr;
334 flash_write_cmd(dst_addr, CFI_CMD_WRITE);
335 flash_write_cmd(dst_addr, data);
337 flash_write_cmd(base_addr, CFI_CMD_READ_STATUS);
340 status = flash_read16(base_addr, 0);
341 } while (!(status & CFI_STATUS_READY));
343 if (status & CFI_STATUS_PROGRAM_ERROR) {
345 if (status & CFI_STATUS_VPP_LOW) {
346 puts("vpp insufficient");
348 } else if (status & CFI_STATUS_LOCKED_ERROR) {
349 puts("block is lock-protected");
352 puts("unknown fault");
359 flash_write_cmd(base_addr, CFI_CMD_RESET);
361 /* verify the result */
362 puts("verifying...");
363 for (i = 0; i < nbytes; i += 2) {
364 uint16_t *src_addr = (uint16_t *) (src + i);
365 uint16_t *dst_addr = (uint16_t *) (base_addr + dst + i);
366 if (*src_addr != *dst_addr) {
367 puts("error: verification failed");
378 flash_write_cmd(base_addr, CFI_CMD_RESET);
381 printf(" at offset 0x%x\n", i);
386 /* Internal: retrieve manufacturer and device id from id space */
388 static int get_id(void *base_addr,
389 uint16_t * manufacturer_id, uint16_t * device_id)
391 flash_write_cmd(base_addr, CFI_CMD_READ_ID);
393 *manufacturer_id = flash_read16(base_addr, CFI_OFFSET_MANUFACTURER_ID);
394 *device_id = flash_read16(base_addr, CFI_OFFSET_DEVICE_ID);
396 flash_write_cmd(base_addr, CFI_CMD_RESET);
401 /* Internal: retrieve cfi query response data */
403 static int get_query(void *base_addr, struct cfi_query *query)
408 flash_write_cmd(base_addr, CFI_CMD_CFI);
410 for (i = 0; i < sizeof(struct cfi_query); i++) {
412 flash_read16(base_addr, CFI_OFFSET_CFI_RESP + i);
413 *(((volatile unsigned char *)query) + i) = byte;
416 if (query->qry[0] != 'Q' || query->qry[1] != 'R' || query->qry[2] != 'Y') {
420 flash_write_cmd(base_addr, CFI_CMD_RESET);
427 /* Internal: retrieve intel protection data */
429 static int get_intel_protection(void *base_addr,
430 uint16_t * lockp, uint8_t protp[8])
442 /* enter read id mode */
443 flash_write_cmd(base_addr, CFI_CMD_READ_ID);
446 *lockp = flash_read16(base_addr, CFI_OFFSET_INTEL_PROTECTION);
449 for (i = 0; i < 8; i++) {
450 protp[i] = flash_read16(base_addr, CFI_OFFSET_INTEL_PROTECTION + 1 + i);
453 /* leave read id mode */
454 flash_write_cmd(base_addr, CFI_CMD_RESET);
459 static void dump_intel_protection(uint16_t lock, uint8_t data[8])
462 (" protection lock 0x%4.4x data 0x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
463 lock, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
466 static void dump_query_algorithms(struct cfi_query *qry)
468 printf(" primary algorithm 0x%4.4x\n", qry->p_id);
469 printf(" primary extended query 0x%4.4x\n", qry->p_adr);
470 printf(" alternate algorithm 0x%4.4x\n", qry->a_id);
471 printf(" alternate extended query 0x%4.4x\n", qry->a_adr);
474 static void dump_query_timing(struct cfi_query *qry)
476 uint32_t block_erase_typ = 1 << qry->block_erase_timeout_typ;
477 uint32_t block_erase_max =
478 (1 << qry->block_erase_timeout_max) * block_erase_typ;
479 uint32_t word_program_typ = 1 << qry->word_write_timeout_typ;
480 uint32_t word_program_max =
481 (1 << qry->word_write_timeout_max) * word_program_typ;
482 printf(" block erase typ %u ms\n", block_erase_typ);
483 printf(" block erase max %u ms\n", block_erase_max);
484 printf(" word program typ %u us\n", word_program_typ);
485 printf(" word program max %u us\n", word_program_max);
488 void flash_dump_info(flash_t * flash)
491 printf("flash at 0x%p of %d bytes with %d regions\n",
492 flash->f_base, flash->f_size, flash->f_nregions);
495 if (get_id(flash->f_base, &m_id, &d_id)) {
496 puts(" failed to get id\n");
498 printf(" manufacturer 0x%4.4x device 0x%4.4x\n", m_id, d_id);
503 if (get_intel_protection(flash->f_base, &plock, pdata)) {
504 puts(" failed to get protection data\n");
506 dump_intel_protection(plock, pdata);
509 struct cfi_query qry;
510 if (get_query(flash->f_base, &qry)) {
511 puts(" failed to get cfi query response\n");
513 dump_query_algorithms(&qry);
514 dump_query_timing(&qry);
517 for (i = 0; i < flash->f_nregions; i++) {
518 flash_region_t *fr = &flash->f_regions[i];
519 printf(" region %d: %d blocks of %d bytes at 0x%p\n",
520 i, fr->fr_bnum, fr->fr_bsize, fr->fr_base);
527 int flash_init(flash_t * flash, void *base_addr)
533 struct cfi_query qry;
535 /* retrieve and check manufacturer and device id */
536 res = get_id(base_addr, &m_id, &d_id);
540 if (m_id != CFI_MANUF_INTEL) {
541 /* we only support intel devices */
545 /* retrieve and check query response */
546 res = get_query(base_addr, &qry);
550 if (qry.p_id != CFI_ALGO_INTEL_3) {
551 /* we only support algo 3 */
554 if (qry.num_erase_regions > FLASH_MAX_REGIONS) {
555 /* we have a hard limit on the number of regions */
559 /* fill in basic information */
560 flash->f_base = base_addr;
561 flash->f_size = 1 << qry.dev_size;
563 /* determine number of erase regions */
564 flash->f_nregions = qry.num_erase_regions;
566 /* compute actual erase region info from cfi junk */
568 for (u = 0; u < flash->f_nregions; u++) {
569 flash_region_t *fr = &flash->f_regions[u];
571 fr->fr_base = (void *)base;
572 fr->fr_bnum = qry.erase_regions[u].b_count + 1;
573 fr->fr_bsize = qry.erase_regions[u].b_size * 256;
575 base += fr->fr_bnum * fr->fr_bsize;