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.
25 #include <flash/cfi_flash.h>
27 /* XXX: strings must always be in ram */
33 /* global definitions */
34 #define CFI_FLASH_MAX_ERASE_REGIONS 4
36 /* structure of erase region descriptor */
40 } __attribute__ ((packed
));
42 /* structure of cfi query response */
53 uint8_t word_write_timeout_typ
;
54 uint8_t buf_write_timeout_typ
;
55 uint8_t block_erase_timeout_typ
;
56 uint8_t chip_erase_timeout_typ
;
57 uint8_t word_write_timeout_max
;
58 uint8_t buf_write_timeout_max
;
59 uint8_t block_erase_timeout_max
;
60 uint8_t chip_erase_timeout_max
;
62 uint16_t interface_desc
;
63 uint16_t max_buf_write_size
;
64 uint8_t num_erase_regions
;
65 struct cfi_region erase_regions
[CFI_FLASH_MAX_ERASE_REGIONS
];
66 } __attribute__ ((packed
));
70 CFI_ALGO_INTEL_3
= 0x03
73 /* various command bytes */
76 CFI_CMD_RESET_TO_READ_MODE
= 0xF0,
77 CFI_CMD_READ_ID
= 0x90,
79 CFI_CMD_READ_STATUS
= 0x70,
80 CFI_CMD_CLEAR_STATUS
= 0x50,
82 CFI_CMD_BLOCK_ERASE
= 0x20,
83 CFI_CMD_ERASE_CONFIRM
= 0xD0,
84 CFI_CMD_PROTECT
= 0x60,
85 CFI_CMD_UNLOCK1
= 0xAA,
86 CFI_CMD_UNLOCK2
= 0x55,
89 /* protection commands */
92 CFI_PROT_UNLOCK
= 0xD0,
93 CFI_PROT_LOCKDOWN
= 0x2F
96 /* offsets from base */
98 CFI_OFFSET_MANUFACTURER_ID
= 0x00,
99 CFI_OFFSET_DEVICE_ID
= 0x01,
100 CFI_OFFSET_EXT_DEVICE_ID1
= 0x0E,
101 CFI_OFFSET_EXT_DEVICE_ID2
= 0x0F,
102 CFI_OFFSET_INTEL_PROTECTION
= 0x81,
103 CFI_OFFSET_CFI_RESP
= 0x10
106 /* offsets from block base */
107 enum flash_block_offset
{
108 CFI_OFFSET_BLOCK_LOCKSTATE
= 0x02
113 CFI_STATUS_READY
= 0x80,
114 CFI_STATUS_ERASE_SUSPENDED
= 0x40,
115 CFI_STATUS_ERASE_ERROR
= 0x20,
116 CFI_STATUS_PROGRAM_ERROR
= 0x10,
117 CFI_STATUS_VPP_LOW
= 0x08,
118 CFI_STATUS_PROGRAM_SUSPENDED
= 0x04,
119 CFI_STATUS_LOCKED_ERROR
= 0x02,
120 CFI_STATUS_RESERVED
= 0x01
123 #define CFI_CMD_ADDR1 0xAAA
124 #define CFI_CMD_ADDR2 0x555
127 static inline void flash_write_cmd(const void *base_addr
, uint16_t cmd
)
129 writew(cmd
, base_addr
);
133 static inline uint16_t flash_read16(const void *base_addr
, uint32_t offset
)
135 return readw(base_addr
+ (offset
<< 1));
139 static char flash_protected(uint32_t block_offset
)
141 #ifdef CONFIG_FLASH_WRITE
142 # ifdef CONFIG_FLASH_WRITE_LOADER
145 return block_offset
<= 0xFFFF;
153 flash_lock_t
flash_block_getlock(flash_t
* flash
, uint32_t block_offset
)
155 const void *base_addr
= flash
->f_base
;
158 flash_write_cmd(base_addr
, CFI_CMD_READ_ID
);
160 flash_read16(base_addr
,
161 (block_offset
>> 1) + CFI_OFFSET_BLOCK_LOCKSTATE
);
162 flash_write_cmd(base_addr
, CFI_CMD_RESET
);
164 if (lockstate
& 0x2) {
165 return FLASH_LOCKED_DOWN
;
166 } else if (lockstate
& 0x01) {
169 return FLASH_UNLOCKED
;
174 int flash_block_unlock(flash_t
* flash
, uint32_t block_offset
)
176 const void *base_addr
= flash
->f_base
;
178 if (block_offset
>= flash
->f_size
) {
182 if (flash_protected(block_offset
)) {
186 printf("Unlocking block at 0x%08lx, meaning %p\n",
187 block_offset
, base_addr
+ block_offset
);
189 flash_write_cmd(base_addr
, CFI_CMD_PROTECT
);
190 flash_write_cmd(base_addr
+ block_offset
, CFI_PROT_UNLOCK
);
191 flash_write_cmd(base_addr
, CFI_CMD_RESET
);
197 int flash_block_lock(flash_t
* flash
, uint32_t block_offset
)
199 const void *base_addr
= flash
->f_base
;
201 if (block_offset
>= flash
->f_size
) {
205 printf("Locking block at 0x%08lx\n", block_offset
);
207 flash_write_cmd(base_addr
, CFI_CMD_PROTECT
);
208 flash_write_cmd(base_addr
+ block_offset
, CFI_PROT_LOCK
);
209 flash_write_cmd(base_addr
, CFI_CMD_RESET
);
215 int flash_block_lockdown(flash_t
* flash
, uint32_t block_offset
)
217 const void *base_addr
= flash
->f_base
;
219 if (block_offset
>= flash
->f_size
) {
223 printf("Locking down block at 0x%08lx\n", block_offset
);
225 flash_write_cmd(base_addr
, CFI_CMD_PROTECT
);
226 flash_write_cmd(base_addr
+ block_offset
, CFI_PROT_LOCKDOWN
);
227 flash_write_cmd(base_addr
, CFI_CMD_RESET
);
233 int flash_block_erase(flash_t
* flash
, uint32_t block_offset
)
235 const void *base_addr
= flash
->f_base
;
237 if (block_offset
>= flash
->f_size
) {
241 if (flash_protected(block_offset
)) {
245 printf("Erasing block 0x%08lx...", block_offset
);
247 void *block_addr
= ((uint8_t *) base_addr
) + block_offset
;
249 flash_write_cmd(base_addr
, CFI_CMD_CLEAR_STATUS
);
251 flash_write_cmd(block_addr
, CFI_CMD_BLOCK_ERASE
);
252 flash_write_cmd(block_addr
, CFI_CMD_ERASE_CONFIRM
);
254 flash_write_cmd(base_addr
, CFI_CMD_READ_STATUS
);
257 status
= flash_read16(base_addr
, 0);
258 } while (!(status
& CFI_STATUS_READY
));
261 if (status
& CFI_STATUS_ERASE_ERROR
) {
263 if (status
& CFI_STATUS_VPP_LOW
) {
264 puts("vpp insufficient\n");
266 } else if (status
& CFI_STATUS_LOCKED_ERROR
) {
267 puts("block is lock-protected\n");
270 puts("unknown fault\n");
277 flash_write_cmd(base_addr
, CFI_CMD_RESET
);
284 int flash_program(flash_t
* flash
, uint32_t dst
, void *src
, uint32_t nbytes
)
286 const void *base_addr
= flash
->f_base
;
290 /* check destination bounds */
291 if (dst
>= flash
->f_size
) {
294 if (dst
+ nbytes
> flash
->f_size
) {
298 /* check alignments */
299 if (((uint32_t) src
) % 2) {
309 /* check permissions */
310 if (flash_protected(dst
)) {
315 printf("Programming %lu bytes to 0x%08lx from 0x%p...", nbytes
, dst
, src
);
317 /* clear status register */
318 flash_write_cmd(base_addr
, CFI_CMD_CLEAR_STATUS
);
320 /* write the words */
322 for (i
= 0; i
< nbytes
; i
+= 2) {
323 uint16_t *src_addr
= (uint16_t *) (src
+ i
);
324 uint16_t *dst_addr
= (uint16_t *) (base_addr
+ dst
+ i
);
326 uint16_t data
= *src_addr
;
328 flash_write_cmd(dst_addr
, CFI_CMD_WRITE
);
329 flash_write_cmd(dst_addr
, data
);
331 flash_write_cmd(base_addr
, CFI_CMD_READ_STATUS
);
334 status
= flash_read16(base_addr
, 0);
335 } while (!(status
& CFI_STATUS_READY
));
337 if (status
& CFI_STATUS_PROGRAM_ERROR
) {
339 if (status
& CFI_STATUS_VPP_LOW
) {
340 puts("vpp insufficient");
342 } else if (status
& CFI_STATUS_LOCKED_ERROR
) {
343 puts("block is lock-protected");
346 puts("unknown fault");
353 flash_write_cmd(base_addr
, CFI_CMD_RESET
);
355 /* verify the result */
356 puts("verifying...");
357 for (i
= 0; i
< nbytes
; i
+= 2) {
358 uint16_t *src_addr
= (uint16_t *) (src
+ i
);
359 uint16_t *dst_addr
= (uint16_t *) (base_addr
+ dst
+ i
);
360 if (*src_addr
!= *dst_addr
) {
361 puts("error: verification failed");
372 flash_write_cmd(base_addr
, CFI_CMD_RESET
);
375 printf(" at offset 0x%lx\n", i
);
380 /* retrieve manufacturer and extended device id from id space */
382 int flash_get_id(void *base_addr
,
383 uint16_t * manufacturer_id
, uint16_t * device_id
)
385 flash_write_cmd(base_addr
, CFI_CMD_RESET_TO_READ_MODE
);
387 flash_write_cmd(base_addr
+ CFI_CMD_ADDR1
, CFI_CMD_UNLOCK1
);
388 flash_write_cmd(base_addr
+ CFI_CMD_ADDR2
, CFI_CMD_UNLOCK2
);
389 flash_write_cmd(base_addr
+ CFI_CMD_ADDR1
, CFI_CMD_READ_ID
);
392 *manufacturer_id
= flash_read16(base_addr
, CFI_OFFSET_MANUFACTURER_ID
);
395 device_id
[0] = flash_read16(base_addr
, CFI_OFFSET_DEVICE_ID
);
396 device_id
[1] = flash_read16(base_addr
, CFI_OFFSET_EXT_DEVICE_ID1
);
397 device_id
[2] = flash_read16(base_addr
, CFI_OFFSET_EXT_DEVICE_ID2
);
400 flash_write_cmd(base_addr
, CFI_CMD_RESET_TO_READ_MODE
);
405 /* Internal: retrieve cfi query response data */
407 static int get_query(void *base_addr
, struct cfi_query
*query
)
412 flash_write_cmd(base_addr
, CFI_CMD_CFI
);
414 for (i
= 0; i
< sizeof(struct cfi_query
); i
++) {
416 flash_read16(base_addr
, CFI_OFFSET_CFI_RESP
+ i
);
417 *(((volatile unsigned char *)query
) + i
) = byte
;
420 if (query
->qry
[0] != 'Q' || query
->qry
[1] != 'R' || query
->qry
[2] != 'Y') {
424 flash_write_cmd(base_addr
, CFI_CMD_RESET
);
431 /* Internal: retrieve intel protection data */
433 static int get_intel_protection(void *base_addr
,
434 uint16_t * lockp
, uint8_t protp
[8])
446 /* enter read id mode */
447 flash_write_cmd(base_addr
, CFI_CMD_READ_ID
);
450 *lockp
= flash_read16(base_addr
, CFI_OFFSET_INTEL_PROTECTION
);
453 for (i
= 0; i
< 8; i
++) {
454 protp
[i
] = flash_read16(base_addr
, CFI_OFFSET_INTEL_PROTECTION
+ 1 + i
);
457 /* leave read id mode */
458 flash_write_cmd(base_addr
, CFI_CMD_RESET
);
463 static void dump_intel_protection(uint16_t lock
, uint8_t data
[8])
466 (" protection lock 0x%4.4x data 0x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
467 lock
, data
[0], data
[1], data
[2], data
[3], data
[4], data
[5], data
[6], data
[7]);
470 static void dump_query_algorithms(struct cfi_query
*qry
)
472 printf(" primary algorithm 0x%4.4x\n", qry
->p_id
);
473 printf(" primary extended query 0x%4.4x\n", qry
->p_adr
);
474 printf(" alternate algorithm 0x%4.4x\n", qry
->a_id
);
475 printf(" alternate extended query 0x%4.4x\n", qry
->a_adr
);
478 static void dump_query_timing(struct cfi_query
*qry
)
480 uint32_t block_erase_typ
= 1 << qry
->block_erase_timeout_typ
;
481 uint32_t block_erase_max
=
482 (1 << qry
->block_erase_timeout_max
) * block_erase_typ
;
483 uint32_t word_program_typ
= 1 << qry
->word_write_timeout_typ
;
484 uint32_t word_program_max
=
485 (1 << qry
->word_write_timeout_max
) * word_program_typ
;
486 printf(" block erase typ %u ms\n", block_erase_typ
);
487 printf(" block erase max %u ms\n", block_erase_max
);
488 printf(" word program typ %u us\n", word_program_typ
);
489 printf(" word program max %u us\n", word_program_max
);
492 void flash_dump_info(flash_t
* flash
)
495 printf("flash at 0x%p of %d bytes with %d regions\n",
496 flash
->f_base
, flash
->f_size
, flash
->f_nregions
);
499 if (get_id(flash
->f_base
, &m_id
, &d_id
)) {
500 puts(" failed to get id\n");
502 printf(" manufacturer 0x%4.4x device 0x%4.4x\n", m_id
, d_id
);
507 if (get_intel_protection(flash
->f_base
, &plock
, pdata
)) {
508 puts(" failed to get protection data\n");
510 dump_intel_protection(plock
, pdata
);
513 struct cfi_query qry
;
514 if (get_query(flash
->f_base
, &qry
)) {
515 puts(" failed to get cfi query response\n");
517 dump_query_algorithms(&qry
);
518 dump_query_timing(&qry
);
521 for (i
= 0; i
< flash
->f_nregions
; i
++) {
522 flash_region_t
*fr
= &flash
->f_regions
[i
];
523 printf(" region %d: %d blocks of %d bytes at 0x%p\n",
524 i
, fr
->fr_bnum
, fr
->fr_bsize
, fr
->fr_base
);
531 int flash_init(flash_t
* flash
, void *base_addr
)
535 uint16_t m_id
, d_id
[3];
537 struct cfi_query qry
;
539 /* retrieve and check manufacturer and device id */
540 res
= flash_get_id(base_addr
, &m_id
, d_id
);
544 if (m_id
!= CFI_MANUF_INTEL
&& m_id
!= CFI_MANUF_ST
) {
548 /* retrieve and check query response */
549 res
= get_query(base_addr
, &qry
);
553 if (qry
.p_id
!= CFI_ALGO_INTEL_3
) {
554 /* we only support algo 3 */
557 if (qry
.num_erase_regions
> FLASH_MAX_REGIONS
) {
558 /* we have a hard limit on the number of regions */
562 /* fill in basic information */
563 flash
->f_base
= base_addr
;
564 flash
->f_size
= 1 << qry
.dev_size
;
566 /* determine number of erase regions */
567 flash
->f_nregions
= qry
.num_erase_regions
;
569 /* compute actual erase region info from cfi junk */
571 for (u
= 0; u
< flash
->f_nregions
; u
++) {
572 flash_region_t
*fr
= &flash
->f_regions
[u
];
574 fr
->fr_base
= (void *)base
;
575 fr
->fr_bnum
= qry
.erase_regions
[u
].b_count
+ 1;
576 fr
->fr_bsize
= qry
.erase_regions
[u
].b_size
* 256;
578 base
+= fr
->fr_bnum
* fr
->fr_bsize
;