2 * flashutl.c - Flash Read/write/Erase routines
4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved.
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id: flashutl.c 401759 2013-05-13 16:08:08Z $
25 #define DECLARE_FLASHES
36 #define ERR2 0x30 /* Mask for err UNUSED */
37 #define DONE 0x80 /* Mask for done */
38 #define WBUFSIZE 32 /* Write Buffer size */
39 #define FLASH_TRIES 700000 /* retry count */
40 #define CMD_ADDR ((unsigned long)0xFFFFFFFF)
42 /* 'which' param for block() */
43 #define BLOCK_BASE 0 /* Base of block */
44 #define BLOCK_LIM 1 /* Limit of block */
46 #define FLASH_ADDR(off) ((unsigned long)flashutl_base + (off))
49 static si_t
*sih
= NULL
;
50 static chipcregs_t
*cc
= NULL
;
53 uint8
*flashutl_base
= NULL
;
54 flash_desc_t
*flashutl_desc
= NULL
;
55 flash_cmds_t
*flashutl_cmd
= NULL
;
56 uint8 flashutl_wsz
= sizeof(uint16
);
58 static void scmd(uint16 cmd
, unsigned long off
);
59 static void cmd(uint16 cmd
, unsigned long off
);
60 static void flash_reset(void);
61 static int flash_poll(unsigned long off
, uint16 data
);
62 static unsigned long block(unsigned long addr
, int which
);
63 static int flash_eraseblk(unsigned long off
);
64 static int flash_write(unsigned long off
, uint8
*src
, uint nbytes
);
65 static uint16 INLINE
flash_readword(unsigned long addr
);
66 static void INLINE
flash_writeword(unsigned long addr
, uint16 data
);
68 int sysFlashErase(uint off
, unsigned int numbytes
);
70 /* Read the flash ID and set the globals */
72 sysFlashInit(char *flash_str
)
75 uint32 fltype
= PFLASH
;
76 uint16 flash_vendid
= 0;
77 uint16 flash_devid
= 0;
79 struct sflash
*sflash
;
82 * Check for serial flash.
84 sih
= si_kattach(SI_OSH
);
89 cc
= (chipcregs_t
*)si_setcoreidx(sih
, SI_CC_IDX
);
92 flashutl_base
= (void *)OSL_UNCACHED((uintptr
)SI_FLASH2
);
94 fltype
= R_REG(osh
, &cc
->capabilities
) & CC_CAP_FLASH_MASK
;
95 if (fltype
== SFLASH_ST
|| fltype
== SFLASH_AT
) {
97 flashutl_base
= (void *)OSL_UNCACHED((uintptr
)SI_FLASH2
);
99 flashutl_base
= (void *)OSL_CACHED((uintptr
)SI_FLASH2
);
100 sflash
= sflash_init(sih
, cc
);
101 flashutl_cmd
= &sflash_cmd_t
;
102 flashutl_desc
= &sflash_desc
;
103 flashutl_desc
->size
= sflash
->size
;
105 sprintf(flash_str
, "SFLASH %d kB", sflash
->size
/1024);
109 flashutl_wsz
= (R_REG(osh
, &cc
->flash_config
) & CC_CFG_DS
) ? sizeof(uint16
) : sizeof(uint8
);
110 ASSERT(flashutl_wsz
== sizeof(uint8
) || flashutl_wsz
== sizeof(uint16
));
113 * Parallel flash support
114 * Some flashes have different unlock addresses, try each it turn
117 fltype
== PFLASH
&& idx
< ARRAYSIZE(flash_cmds
);
119 flashutl_cmd
= &flash_cmds
[idx
];
120 if (flashutl_cmd
->type
== OLD
)
123 if (flashutl_cmd
->read_id
) {
124 cmd(flashutl_cmd
->read_id
, CMD_ADDR
);
125 /* Delay for turn around time */
131 flash_vendid
= flash_readword(FLASH_ADDR(0)^6);
132 flash_devid
= flash_readword(FLASH_ADDR(2)^6);
133 #else /* !74K, bcm33xx */
134 flash_vendid
= flash_readword(FLASH_ADDR(2));
135 flash_devid
= flash_readword(FLASH_ADDR(0));
136 #endif /* BCMHND74K */
138 flash_vendid
= flash_readword(FLASH_ADDR(0));
139 flash_devid
= flash_readword(FLASH_ADDR(2));
142 /* Funky AMD, uses 3 byte device ID so use first byte (4th addr) to
143 * identify it is a 3-byte ID and use the next two bytes (5th & 6th addr)
144 * to form a word for unique identification of format xxyy, where
145 * xx = 5th addr and yy = 6th addr
147 if ((flash_vendid
== 1) &&
148 ((flash_devid
== 0x227e && flashutl_wsz
== sizeof(uint16
)) ||
149 (flash_devid
== 0x7e && flashutl_wsz
== sizeof(uint8
)))) {
151 uint16 flash_devid_5th
;
154 flash_devid_5th
= flash_readword(FLASH_ADDR(0x1c)^6) << 8;
155 flash_devid
= (flash_readword(FLASH_ADDR(0x1e)^6) & 0xff) | flash_devid_5th
;
156 #else /* !74K, bcm33xx */
157 flash_devid_5th
= flash_readword(FLASH_ADDR(0x1e)) << 8;
158 flash_devid
= (flash_readword(FLASH_ADDR(0x1c)) & 0xff) | flash_devid_5th
;
159 #endif /* BCMHND74K */
161 flash_devid_5th
= flash_readword(FLASH_ADDR(0x1c)) << 8;
162 flash_devid
= (flash_readword(FLASH_ADDR(0x1e)) & 0xff) | flash_devid_5th
;
166 flashutl_desc
= flashes
;
167 while (flashutl_desc
->mfgid
!= 0 &&
168 !(flashutl_desc
->mfgid
== flash_vendid
&&
169 flashutl_desc
->devid
== flash_devid
)) {
172 if (flashutl_desc
->mfgid
!= 0)
176 if (flashutl_desc
->mfgid
== 0) {
177 flashutl_desc
= NULL
;
180 flashutl_cmd
= flash_cmds
;
181 while (flashutl_cmd
->type
!= 0 && flashutl_cmd
->type
!= flashutl_desc
->type
)
183 if (flashutl_cmd
->type
== 0)
187 if (flashutl_cmd
!= NULL
) {
191 if (flashutl_desc
== NULL
) {
193 sprintf(flash_str
, "UNKNOWN 0x%x 0x%x", flash_vendid
, flash_devid
);
194 DPRINT(("Flash type UNKNOWN\n"));
199 strcpy(flash_str
, flashutl_desc
->desc
);
200 DPRINT(("Flash type \"%s\"\n", flashutl_desc
->desc
));
206 flash_eraseblk(unsigned long addr
)
211 a
= (unsigned long)addr
;
212 if (a
>= flashutl_desc
->size
)
215 a
= block(a
, BLOCK_BASE
);
217 /* Ensure blocks are unlocked (for intel chips) */
218 if (flashutl_cmd
->type
== BSC
) {
219 scmd((unsigned char)INTEL_UNLOCK1
, a
);
220 scmd((unsigned char)INTEL_UNLOCK2
, a
);
223 if (flashutl_cmd
->pre_erase
)
224 cmd(flashutl_cmd
->pre_erase
, CMD_ADDR
);
225 if (flashutl_cmd
->erase_block
)
226 cmd(flashutl_cmd
->erase_block
, a
);
227 if (flashutl_cmd
->confirm
)
228 scmd(flashutl_cmd
->confirm
, a
);
230 if (flashutl_wsz
== sizeof(uint8
))
231 st
= flash_poll(a
, 0xff);
233 st
= flash_poll(a
, 0xffff);
238 DPRINT(("Erase of block 0x%08lx-0x%08lx failed\n",
239 a
, block((unsigned long)addr
, BLOCK_LIM
)));
243 DPRINT(("Erase of block 0x%08lx-0x%08lx done\n", a
, block((unsigned long)addr
, BLOCK_LIM
)));
249 flash_write(unsigned long off
, uint8
*src
, uint nbytes
)
255 ASSERT(flashutl_desc
!= NULL
);
257 if (off
>= flashutl_desc
->size
)
260 ASSERT(!(off
& (flashutl_wsz
- 1)));
262 dest
= (uint8
*)FLASH_ADDR(off
);
266 if ((flashutl_desc
->type
== SCS
) &&
267 flashutl_cmd
->write_buf
&&
268 ((off
& (WBUFSIZE
- 1)) == 0)) {
269 /* issue write command */
270 if (flashutl_cmd
->write_buf
)
271 cmd(flashutl_cmd
->write_buf
, off
);
272 if ((st
= flash_poll(off
, DONE
)))
275 len
= MIN(nbytes
, WBUFSIZE
);
278 /* write (length - 1) */
279 cmd(len
/ sizeof(uint16
) - 1, off
);
282 for (i
= 0; i
< len
; i
+= sizeof(uint16
),
283 dest
+= sizeof(uint16
), src
+= sizeof(uint16
))
284 *(uint16
*)dest
= *(uint16
*)src
;
287 * BCM4710 endianness is word consistent but
288 * byte/short scrambled. This write buffer
289 * mechanism appears to be sensitive to the
290 * order of the addresses hence we need to
291 * unscramble them. We may also need to pad
292 * the source with two bytes of 0xffff in case
293 * an odd number of shorts are presented.
296 /* write (padded length - 1) */
297 cmd((ROUNDUP(len
, sizeof(uint32
)) / sizeof(uint16
)) - 1, off
);
299 /* write data (plus pad if necessary) */
300 for (i
= 0; i
< ROUNDUP(len
, sizeof(uint32
)); i
+= sizeof(uint32
),
301 dest
+= sizeof(uint32
), src
+= sizeof(uint32
)) {
302 *((uint16
*)dest
+ 1) = ((i
+ sizeof(uint16
)) < len
) ?
303 *((uint16
*)src
+ 1) : 0xffff;
304 *(uint16
*)dest
= *(uint16
*)src
;
309 if (flashutl_cmd
->confirm
)
310 cmd(flashutl_cmd
->confirm
, off
);
312 if ((st
= flash_poll(off
, DONE
)))
315 /* issue write command */
316 if (flashutl_cmd
->write_word
)
317 cmd(flashutl_cmd
->write_word
, CMD_ADDR
);
320 data
= flash_readword((unsigned long)src
);
321 flash_writeword((unsigned long)dest
, data
);
324 if ((st
= flash_poll(off
, data
)))
327 len
= MIN(nbytes
, flashutl_wsz
);
342 flash_readword(unsigned long addr
)
344 if (flashutl_wsz
== sizeof(uint8
))
345 return *(uint8
*)addr
;
347 return *(uint16
*)addr
;
351 flash_writeword(unsigned long addr
, uint16 data
)
353 if (flashutl_wsz
== sizeof(uint8
))
354 *(uint8
*)addr
= (uint8
)data
;
356 *(uint16
*)addr
= data
;
359 /* Writes a single command to the flash. */
361 scmd(uint16 cmd
, unsigned long off
)
363 /* cmd |= cmd << 8; */
365 flash_writeword(FLASH_ADDR(off
), cmd
);
368 /* Writes a command to flash, performing an unlock if needed. */
370 cmd(uint16 cmd
, unsigned long off
)
373 unlock_cmd_t
*ul
= NULL
;
375 ASSERT(flashutl_cmd
!= NULL
);
377 switch (flashutl_cmd
->type
) {
379 ul
= &unlock_cmd_amd
;
382 ul
= &unlock_cmd_sst
;
388 if (flashutl_cmd
->need_unlock
) {
390 for (i
= 0; i
< UNLOCK_CMD_WORDS
; i
++)
391 flash_writeword(FLASH_ADDR(ul
->addr
[i
]), ul
->cmd
[i
]);
394 /* cmd |= cmd << 8; */
396 if (off
== CMD_ADDR
) {
397 switch (flashutl_cmd
->type
) {
413 #else /* !74K, bcm33xx */
415 #endif /* BCMHND74K */
418 flash_writeword(FLASH_ADDR(off
), cmd
);
424 ASSERT(flashutl_cmd
!= NULL
);
426 if (flashutl_cmd
->clear_csr
)
427 scmd(flashutl_cmd
->clear_csr
, 0);
428 if (flashutl_cmd
->read_array
)
429 scmd(flashutl_cmd
->read_array
, 0);
433 flash_poll(unsigned long off
, uint16 data
)
436 int cnt
= FLASH_TRIES
;
439 ASSERT(flashutl_desc
!= NULL
);
441 if (flashutl_desc
->type
== AMD
|| flashutl_desc
->type
== SST
) {
442 /* AMD style poll checkes the address being written */
443 addr
= FLASH_ADDR(off
);
444 while ((st
= flash_readword(addr
)) != data
&& cnt
!= 0) {
449 DPRINT(("%s: timeout, off %lx, read 0x%x, expected 0x%x\n",
450 __FUNCTION__
, off
, st
, data
));
454 /* INTEL style poll is at second word of the block being written */
455 addr
= FLASH_ADDR(block(off
, BLOCK_BASE
)+sizeof(uint16
));
456 while (((st
= flash_readword(addr
)) & DONE
) == 0 && cnt
!= 0) {
461 DPRINT(("%s: timeout, error status = 0x%x\n", __FUNCTION__
, st
));
470 block(unsigned long addr
, int which
)
472 unsigned long b
, l
, sb
;
476 ASSERT(flashutl_desc
!= NULL
);
478 ASSERT(addr
< (unsigned long)flashutl_desc
->size
);
480 b
= addr
/ flashutl_desc
->bsize
;
481 /* check for an address a full size block */
482 if (b
>= flashutl_desc
->ff
&& b
<= flashutl_desc
->lf
) {
483 if (which
== BLOCK_LIM
) b
++;
484 return (b
* flashutl_desc
->bsize
);
487 /* search for the sub-block */
488 if (flashutl_desc
->ff
== 0) {
489 /* sub blocks are at the end of the flash */
490 sb
= flashutl_desc
->bsize
* (flashutl_desc
->lf
+ 1);
492 /* sub blocks are at the start of the flash */
496 sblocks
= flashutl_desc
->subblocks
;
497 for (i
= 0; i
< flashutl_desc
->nsub
; i
++) {
499 l
= sb
+ sblocks
[i
+1];
500 if (addr
>= b
&& addr
< l
) {
501 if (which
== BLOCK_BASE
)
512 nvWrite(unsigned short *data
, unsigned int len
)
514 uint off
= flashutl_desc
->size
- NVRAM_SPACE
;
515 sysFlashWrite(off
, (uchar
*)data
, len
);
519 nvWriteChars(unsigned char *data
, unsigned int len
)
521 uint off
= flashutl_desc
->size
- NVRAM_SPACE
;
524 if (flashutl_cmd
->type
== SFLASH
)
525 err
= sflash_commit(sih
, cc
, off
, len
, data
);
527 err
= flash_write(off
, data
, len
);
530 DPRINT(("nvWriteChars failed\n"));
532 DPRINT(("nvWriteChars succeeded\n"));
536 sysFlashErase(uint off
, unsigned int numbytes
)
538 unsigned long end
= off
+ numbytes
;
541 if (flashutl_cmd
->type
== SFLASH
) {
542 err
= sflash_commit(sih
, cc
, off
, numbytes
, NULL
);
545 err
= flash_eraseblk(off
);
548 off
= block(off
, BLOCK_LIM
);
553 DPRINT(("Block erase at 0x%x failed\n", off
));
561 sysFlashWrite(uint off
, uchar
*src
, uint numbytes
)
565 DPRINT(("Writing 0x%x bytes to flash @0x%x ...\n", (unsigned int)numbytes
, off
));
567 if (flashutl_cmd
->type
== SFLASH
)
568 err
= sflash_commit(sih
, cc
, off
, numbytes
, src
);
570 if (!sysFlashErase(off
, numbytes
))
572 err
= flash_write(off
, src
, numbytes
);
576 DPRINT(("Flash write failed\n"));
578 DPRINT(("Flash write succeeded\n"));
584 sysFlashRead(uint off
, uchar
*buf
, uint numbytes
)
586 uint read
, total_read
= 0;
588 if (flashutl_cmd
->type
== SFLASH
) {
590 read
= sflash_read(sih
, cc
, off
, numbytes
, buf
);
597 ASSERT(!(off
& (flashutl_wsz
- 1)));
598 ASSERT(!(numbytes
& (flashutl_wsz
- 1)));
601 flash_writeword((unsigned long)buf
, flash_readword(FLASH_ADDR(off
)));
602 numbytes
-= flashutl_wsz
;
605 total_read
+= flashutl_wsz
;