2 * flashutl.c - Flash Read/write/Erase routines
4 * Copyright 2004, Broadcom Corporation
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
18 #define DECLARE_FLASHES
29 #define ERR2 0x30 /* Mask for err UNUSED */
30 #define DONE 0x80 /* Mask for done */
31 #define WBUFSIZE 32 /* Write Buffer size */
32 #define FLASH_TRIES 4000000 /* retry count */
33 #define CMD_ADDR ((unsigned long)0xFFFFFFFF)
35 /* 'which' param for block() */
36 #define BLOCK_BASE 0 /* Base of block */
37 #define BLOCK_LIM 1 /* Limit of block */
39 #define FLASH_ADDR(off) ((unsigned long)flashutl_base + (off))
42 static sb_t
*sbh
= NULL
;
43 static chipcregs_t
*cc
= NULL
;
46 uint8
*flashutl_base
= NULL
;
47 flash_desc_t
*flashutl_desc
= NULL
;
48 flash_cmds_t
*flashutl_cmd
= NULL
;
49 uint8 flashutl_wsz
= sizeof(uint16
);
51 static void scmd(uint16 cmd
, unsigned long off
);
52 static void cmd(uint16 cmd
, unsigned long off
);
53 static void flash_reset(void);
54 static int flash_poll(unsigned long off
, uint16 data
);
55 static unsigned long block(unsigned long addr
, int which
);
56 static int flash_eraseblk(unsigned long off
);
57 static int flash_write(unsigned long off
, uint8
*src
, uint nbytes
);
58 static uint16 INLINE
flash_readword(unsigned long addr
);
59 static void INLINE
flash_writeword(unsigned long addr
, uint16 data
);
61 int sysFlashErase(uint off
, unsigned int numbytes
);
63 /* Read the flash ID and set the globals */
65 sysFlashInit(char *flash_str
)
68 uint32 fltype
= PFLASH
;
69 uint16 flash_vendid
= 0;
70 uint16 flash_devid
= 0;
72 struct sflash
*sflash
;
75 * Check for serial flash.
77 sbh
= sb_kattach(SB_OSH
);
82 flashutl_base
= (uint8
*)OSL_UNCACHED(SB_FLASH1
);
83 flashutl_wsz
= sizeof(uint16
);
84 cc
= (chipcregs_t
*)sb_setcore(sbh
, SB_CC
, 0);
86 flashutl_base
= (uint8
*)OSL_UNCACHED(SB_FLASH2
);
87 flashutl_wsz
= (R_REG(osh
, &cc
->flash_config
) & CC_CFG_DS
) ?
88 sizeof(uint16
) : sizeof(uint8
);
90 fltype
= R_REG(osh
, &cc
->capabilities
) & CC_CAP_FLASH_MASK
;
91 if (fltype
== SFLASH_ST
|| fltype
== SFLASH_AT
) {
92 sflash
= sflash_init(sbh
, cc
);
93 flashutl_cmd
= &sflash_cmd_t
;
94 flashutl_desc
= &sflash_desc
;
95 flashutl_desc
->size
= sflash
->size
;
97 sprintf(flash_str
, "SFLASH %d kB", sflash
->size
/1024);
102 ASSERT(flashutl_wsz
== sizeof(uint8
) || flashutl_wsz
== sizeof(uint16
));
105 * Parallel flash support
106 * Some flashes have different unlock addresses, try each it turn
109 fltype
== PFLASH
&& idx
< ARRAYSIZE(flash_cmds
);
111 flashutl_cmd
= &flash_cmds
[idx
];
112 if (flashutl_cmd
->type
== OLD
)
115 if (flashutl_cmd
->read_id
)
116 cmd(flashutl_cmd
->read_id
, CMD_ADDR
);
119 flash_vendid
= flash_readword(FLASH_ADDR(2));
120 flash_devid
= flash_readword(FLASH_ADDR(0));
122 flash_vendid
= flash_readword(FLASH_ADDR(0));
123 flash_devid
= flash_readword(FLASH_ADDR(2));
126 /* Funky AMD, uses 3 byte device ID so use first byte (4th addr) to
127 * identify it is a 3-byte ID and use the next two bytes (5th & 6th addr)
128 * to form a word for unique identification of format xxyy, where
129 * xx = 5th addr and yy = 6th addr
131 if ((flash_vendid
== 1) && (flash_devid
== 0x227e)) {
133 uint16 flash_devid_5th
;
135 flash_devid_5th
= flash_readword(FLASH_ADDR(0x1e)) << 8;
136 flash_devid
= (flash_readword(FLASH_ADDR(0x1c)) & 0xff) | flash_devid_5th
;
138 flash_devid_5th
= flash_readword(FLASH_ADDR(0x1c)) << 8;
139 flash_devid
= (flash_readword(FLASH_ADDR(0x1e)) & 0xff) | flash_devid_5th
;
143 flashutl_desc
= flashes
;
144 while (flashutl_desc
->mfgid
!= 0 &&
145 !(flashutl_desc
->mfgid
== flash_vendid
&&
146 flashutl_desc
->devid
== flash_devid
)) {
149 if (flashutl_desc
->mfgid
!= 0)
153 if (flashutl_desc
->mfgid
== 0) {
154 flashutl_desc
= NULL
;
157 flashutl_cmd
= flash_cmds
;
158 while (flashutl_cmd
->type
!= 0 && flashutl_cmd
->type
!= flashutl_desc
->type
)
160 if (flashutl_cmd
->type
== 0)
164 if (flashutl_cmd
!= NULL
) {
168 if (flashutl_desc
== NULL
) {
170 sprintf(flash_str
, "UNKNOWN 0x%x 0x%x", flash_vendid
, flash_devid
);
171 DPRINT(("Flash type UNKNOWN\n"));
176 strcpy(flash_str
, flashutl_desc
->desc
);
177 DPRINT(("Flash type \"%s\"\n", flashutl_desc
->desc
));
183 flash_eraseblk(unsigned long addr
)
188 a
= (unsigned long)addr
;
189 if (a
>= flashutl_desc
->size
)
192 a
= block(a
, BLOCK_BASE
);
194 /* Ensure blocks are unlocked (for intel chips) */
195 if (flashutl_cmd
->type
== BSC
) {
196 scmd((unsigned char)INTEL_UNLOCK1
, a
);
197 scmd((unsigned char)INTEL_UNLOCK2
, a
);
200 if (flashutl_cmd
->pre_erase
)
201 cmd(flashutl_cmd
->pre_erase
, CMD_ADDR
);
202 if (flashutl_cmd
->erase_block
)
203 cmd(flashutl_cmd
->erase_block
, a
);
204 if (flashutl_cmd
->confirm
)
205 scmd(flashutl_cmd
->confirm
, a
);
207 if (flashutl_wsz
== sizeof(uint8
))
208 st
= flash_poll(a
, 0xff);
210 st
= flash_poll(a
, 0xffff);
215 DPRINT(("Erase of block 0x%08lx-0x%08lx failed\n",
216 a
, block((unsigned long)addr
, BLOCK_LIM
)));
220 DPRINT(("Erase of block 0x%08lx-0x%08lx done\n", a
, block((unsigned long)addr
, BLOCK_LIM
)));
226 flash_write(unsigned long off
, uint8
*src
, uint nbytes
)
232 ASSERT(flashutl_desc
!= NULL
);
234 if (off
>= flashutl_desc
->size
)
237 ASSERT(!(off
& (flashutl_wsz
- 1)));
239 dest
= (uint8
*)FLASH_ADDR(off
);
243 if ((flashutl_desc
->type
== SCS
) &&
244 flashutl_cmd
->write_buf
&&
245 ((off
& (WBUFSIZE
- 1)) == 0)) {
246 /* issue write command */
247 if (flashutl_cmd
->write_buf
)
248 cmd(flashutl_cmd
->write_buf
, off
);
249 if ((st
= flash_poll(off
, DONE
)))
252 len
= MIN(nbytes
, WBUFSIZE
);
255 /* write (length - 1) */
256 cmd(len
/ sizeof(uint16
) - 1, off
);
259 for (i
= 0; i
< len
; i
+= sizeof(uint16
),
260 dest
+= sizeof(uint16
), src
+= sizeof(uint16
))
261 *(uint16
*)dest
= *(uint16
*)src
;
264 * BCM4710 endianness is word consistent but
265 * byte/short scrambled. This write buffer
266 * mechanism appears to be sensitive to the
267 * order of the addresses hence we need to
268 * unscramble them. We may also need to pad
269 * the source with two bytes of 0xffff in case
270 * an odd number of shorts are presented.
273 /* write (padded length - 1) */
274 cmd((ROUNDUP(len
, sizeof(uint32
)) / sizeof(uint16
)) - 1, off
);
276 /* write data (plus pad if necessary) */
277 for (i
= 0; i
< ROUNDUP(len
, sizeof(uint32
)); i
+= sizeof(uint32
),
278 dest
+= sizeof(uint32
), src
+= sizeof(uint32
)) {
279 *((uint16
*)dest
+ 1) = ((i
+ sizeof(uint16
)) < len
) ?
280 *((uint16
*)src
+ 1) : 0xffff;
281 *(uint16
*)dest
= *(uint16
*)src
;
286 if (flashutl_cmd
->confirm
)
287 cmd(flashutl_cmd
->confirm
, off
);
289 if ((st
= flash_poll(off
, DONE
)))
292 /* issue write command */
293 if (flashutl_cmd
->write_word
)
294 cmd(flashutl_cmd
->write_word
, CMD_ADDR
);
297 data
= flash_readword((unsigned long)src
);
298 flash_writeword((unsigned long)dest
, data
);
301 if ((st
= flash_poll(off
, data
)))
304 len
= MIN(nbytes
, flashutl_wsz
);
319 flash_readword(unsigned long addr
)
321 if (flashutl_wsz
== sizeof(uint8
))
322 return *(uint8
*)addr
;
324 return *(uint16
*)addr
;
328 flash_writeword(unsigned long addr
, uint16 data
)
330 if (flashutl_wsz
== sizeof(uint8
))
331 *(uint8
*)addr
= (uint8
)data
;
333 *(uint16
*)addr
= data
;
336 /* Writes a single command to the flash. */
338 scmd(uint16 cmd
, unsigned long off
)
340 /* cmd |= cmd << 8; */
342 flash_writeword(FLASH_ADDR(off
), cmd
);
345 /* Writes a command to flash, performing an unlock if needed. */
347 cmd(uint16 cmd
, unsigned long off
)
350 unlock_cmd_t
*ul
= NULL
;
352 ASSERT(flashutl_cmd
!= NULL
);
354 switch (flashutl_cmd
->type
) {
356 ul
= &unlock_cmd_amd
;
359 ul
= &unlock_cmd_sst
;
365 if (flashutl_cmd
->need_unlock
) {
367 for (i
= 0; i
< UNLOCK_CMD_WORDS
; i
++)
368 flash_writeword(FLASH_ADDR(ul
->addr
[i
]), ul
->cmd
[i
]);
371 /* cmd |= cmd << 8; */
373 if (off
== CMD_ADDR
) {
374 switch (flashutl_cmd
->type
) {
391 flash_writeword(FLASH_ADDR(off
), cmd
);
397 ASSERT(flashutl_desc
!= NULL
);
399 if (flashutl_cmd
->clear_csr
)
400 scmd(flashutl_cmd
->clear_csr
, 0);
401 if (flashutl_cmd
->read_array
)
402 scmd(flashutl_cmd
->read_array
, 0);
406 flash_poll(unsigned long off
, uint16 data
)
409 int cnt
= FLASH_TRIES
;
412 ASSERT(flashutl_desc
!= NULL
);
414 if (flashutl_desc
->type
== AMD
|| flashutl_desc
->type
== SST
) {
415 /* AMD style poll checkes the address being written */
416 addr
= FLASH_ADDR(off
);
417 while ((st
= flash_readword(addr
)) != data
&& cnt
!= 0)
420 DPRINT(("flash_poll: timeout, off %lx, read 0x%x, expected 0x%x\n",
425 /* INTEL style poll is at second word of the block being written */
426 addr
= FLASH_ADDR(block(off
, BLOCK_BASE
)+sizeof(uint16
));
427 while (((st
= flash_readword(addr
)) & DONE
) == 0 && cnt
!= 0)
430 DPRINT(("flash_poll: timeout, error status = 0x%x\n", st
));
439 block(unsigned long addr
, int which
)
441 unsigned long b
, l
, sb
;
445 ASSERT(flashutl_desc
!= NULL
);
446 ASSERT(addr
< (unsigned long)flashutl_desc
->size
);
448 b
= addr
/ flashutl_desc
->bsize
;
449 /* check for an address a full size block */
450 if (b
>= flashutl_desc
->ff
&& b
<= flashutl_desc
->lf
) {
451 if (which
== BLOCK_LIM
) b
++;
452 return (b
* flashutl_desc
->bsize
);
455 /* search for the sub-block */
456 if (flashutl_desc
->ff
== 0) {
457 /* sub blocks are at the end of the flash */
458 sb
= flashutl_desc
->bsize
* (flashutl_desc
->lf
+ 1);
460 /* sub blocks are at the start of the flash */
464 sblocks
= flashutl_desc
->subblocks
;
465 for (i
= 0; i
< flashutl_desc
->nsub
; i
++) {
467 l
= sb
+ sblocks
[i
+1];
468 if (addr
>= b
&& addr
< l
) {
469 if (which
== BLOCK_BASE
)
480 nvWrite(unsigned short *data
, unsigned int len
)
482 uint off
= flashutl_desc
->size
- NVRAM_SPACE
;
483 sysFlashWrite(off
, (uchar
*)data
, len
);
487 nvWriteChars(unsigned char *data
, unsigned int len
)
489 uint off
= flashutl_desc
->size
- NVRAM_SPACE
;
492 if (flashutl_cmd
->type
== SFLASH
)
493 err
= sflash_commit(sbh
, cc
, off
, len
, data
);
495 err
= flash_write(off
, data
, len
);
498 DPRINT(("nvWriteChars failed\n"));
500 DPRINT(("nvWriteChars succeeded\n"));
504 sysFlashErase(uint off
, unsigned int numbytes
)
506 unsigned long end
= off
+ numbytes
;
509 if (flashutl_cmd
->type
== SFLASH
) {
510 err
= sflash_commit(sbh
, cc
, off
, numbytes
, NULL
);
513 err
= flash_eraseblk(off
);
516 off
= block(off
, BLOCK_LIM
);
521 DPRINT(("Block erase at 0x%x failed\n", off
));
529 sysFlashWrite(uint off
, uchar
*src
, uint numbytes
)
533 DPRINT(("Writing 0x%x bytes to flash @0x%x ...\n", (unsigned int)numbytes
, off
));
535 if (flashutl_cmd
->type
== SFLASH
)
536 err
= sflash_commit(sbh
, cc
, off
, numbytes
, src
);
538 if (!sysFlashErase(off
, numbytes
))
540 err
= flash_write(off
, src
, numbytes
);
544 DPRINT(("Flash write failed\n"));
546 DPRINT(("Flash write succeeded\n"));
552 sysFlashRead(uint off
, uchar
*buf
, uint numbytes
)
554 uint read
, total_read
= 0;
556 if (flashutl_cmd
->type
== SFLASH
) {
558 read
= sflash_read(sbh
, cc
, off
, numbytes
, buf
);
565 ASSERT(!(off
& (flashutl_wsz
- 1)));
566 ASSERT(!(numbytes
& (flashutl_wsz
- 1)));
569 flash_writeword((unsigned long)buf
, flash_readword(FLASH_ADDR(off
)));
570 numbytes
-= flashutl_wsz
;
573 total_read
+= flashutl_wsz
;