2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright (C) 2012, 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: sflash.c 345824 2012-07-19 06:29:12Z $
33 #define SFL_MSG(args) printf args
38 /* Private global state */
39 static struct sflash sflash
;
41 /* Issue a serial flash command */
43 sflash_cmd(osl_t
*osh
, chipcregs_t
*cc
, uint opcode
)
45 W_REG(osh
, &cc
->flashcontrol
, SFLASH_START
| opcode
);
46 while (R_REG(osh
, &cc
->flashcontrol
) & SFLASH_BUSY
);
49 static bool firsttime
= TRUE
;
51 /* Initialize serial flash access */
53 sflash_init(si_t
*sih
, chipcregs_t
*cc
)
56 const char *name
= "";
63 bzero(&sflash
, sizeof(sflash
));
65 sflash
.type
= sih
->cccaps
& CC_CAP_FLASH_MASK
;
67 switch (sflash
.type
) {
69 /* Probe for ST chips */
70 name
= "ST compatible";
71 sflash_cmd(osh
, cc
, SFLASH_ST_DP
);
72 W_REG(osh
, &cc
->flashaddress
, 0);
73 sflash_cmd(osh
, cc
, SFLASH_ST_RES
);
74 id
= R_REG(osh
, &cc
->flashdata
);
75 sflash
.blocksize
= 64 * 1024;
78 /* ST M25P20 2 Mbit Serial Flash */
82 /* ST M25P40 4 Mbit Serial Flash */
86 sflash_cmd(osh
, cc
, SFLASH_MXIC_RDID
);
87 id
= R_REG(osh
, &cc
->flashdata
);
88 if (id
== SFLASH_MXIC_MFID
) {
89 /* MXIC MX25L8006E 8 Mbit Serial Flash */
90 sflash
.blocksize
= 4 * 1024;
91 sflash
.numblocks
= 16 * 16;
93 /* ST M25P80 8 Mbit Serial Flash */
94 sflash
.numblocks
= 16;
98 /* ST M25P16 16 Mbit Serial Flash */
99 sflash
.numblocks
= 32;
102 /* ST M25P32 32 Mbit Serial Flash */
103 sflash
.numblocks
= 64;
106 /* ST M25P64 64 Mbit Serial Flash */
107 sflash
.numblocks
= 128;
110 /* ST M25FL128 128 Mbit Serial Flash */
111 sflash
.numblocks
= 256;
114 /* All of the following flashes are SST with
115 * 4KB subsectors. Others should be added but
116 * We'll have to revamp the way we identify them
117 * since RES is not eough to disambiguate them.
120 sflash
.blocksize
= 4 * 1024;
121 W_REG(osh
, &cc
->flashaddress
, 1);
122 sflash_cmd(osh
, cc
, SFLASH_ST_RES
);
123 id2
= R_REG(osh
, &cc
->flashdata
);
126 /* SST25WF512 512 Kbit Serial Flash */
127 sflash
.numblocks
= 16;
130 /* SST25VF512 512 Kbit Serial Flash */
131 sflash
.numblocks
= 16;
134 /* SST25WF010 1 Mbit Serial Flash */
135 sflash
.numblocks
= 32;
138 /* SST25VF010 1 Mbit Serial Flash */
139 sflash
.numblocks
= 32;
142 /* SST25WF020 2 Mbit Serial Flash */
143 sflash
.numblocks
= 64;
146 /* SST25VF020 2 Mbit Serial Flash */
147 sflash
.numblocks
= 64;
150 /* SST25WF040 4 Mbit Serial Flash */
151 sflash
.numblocks
= 128;
154 /* SST25VF040 4 Mbit Serial Flash */
155 sflash
.numblocks
= 128;
158 /* SST25VF040B 4 Mbit Serial Flash */
159 sflash
.numblocks
= 128;
162 /* SST25WF080 8 Mbit Serial Flash */
163 sflash
.numblocks
= 256;
166 /* SST25VF080B 8 Mbit Serial Flash */
167 sflash
.numblocks
= 256;
170 /* SST25VF016 16 Mbit Serial Flash */
171 sflash
.numblocks
= 512;
174 /* SST25VF032 32 Mbit Serial Flash */
175 sflash
.numblocks
= 1024;
178 /* SST25VF064 64 Mbit Serial Flash */
179 sflash
.numblocks
= 2048;
187 /* Probe for Atmel chips */
189 sflash_cmd(osh
, cc
, SFLASH_AT_STATUS
);
190 id
= R_REG(osh
, &cc
->flashdata
) & 0x3c;
193 /* Atmel AT45DB011 1Mbit Serial Flash */
194 sflash
.blocksize
= 256;
195 sflash
.numblocks
= 512;
198 /* Atmel AT45DB021 2Mbit Serial Flash */
199 sflash
.blocksize
= 256;
200 sflash
.numblocks
= 1024;
203 /* Atmel AT45DB041 4Mbit Serial Flash */
204 sflash
.blocksize
= 256;
205 sflash
.numblocks
= 2048;
208 /* Atmel AT45DB081 8Mbit Serial Flash */
209 sflash
.blocksize
= 256;
210 sflash
.numblocks
= 4096;
213 /* Atmel AT45DB161 16Mbit Serial Flash */
214 sflash
.blocksize
= 512;
215 sflash
.numblocks
= 4096;
218 /* Atmel AT45DB321 32Mbit Serial Flash */
219 sflash
.blocksize
= 512;
220 sflash
.numblocks
= 8192;
223 /* Atmel AT45DB642 64Mbit Serial Flash */
224 sflash
.blocksize
= 1024;
225 sflash
.numblocks
= 8192;
231 sflash
.size
= sflash
.blocksize
* sflash
.numblocks
;
232 sflash
.phybase
= SI_FLASH2
;
235 printf("Found an %s serial flash with %d %dKB blocks; total size %dMB\n",
236 name
, sflash
.numblocks
, sflash
.blocksize
/ 1024,
237 sflash
.size
/ (1024 * 1024));
240 return sflash
.size
? &sflash
: NULL
;
243 /* Read len bytes starting at offset into buf. Returns number of bytes read. */
245 sflash_read(si_t
*sih
, chipcregs_t
*cc
, uint offset
, uint len
, uchar
*buf
)
255 if ((offset
+ len
) > sflash
.size
)
258 if ((len
>= 4) && (offset
& 3))
259 cnt
= 4 - (offset
& 3);
260 else if ((len
>= 4) && ((uintptr
)buf
& 3))
261 cnt
= 4 - ((uintptr
)buf
& 3);
265 if (sih
->ccrev
== 12)
266 from
= (uint8
*)OSL_UNCACHED((void *)SI_FLASH2
+ offset
);
268 from
= (uint8
*)OSL_CACHED((void *)SI_FLASH2
+ offset
);
272 for (i
= 0; i
< cnt
; i
++) {
273 /* Cannot use R_REG because in bigendian that will
274 * xor the address and we don't want that here.
284 *(uint32
*)to
= *(uint32
*)from
;
293 /* Poll for command completion. Returns zero when complete. */
295 sflash_poll(si_t
*sih
, chipcregs_t
*cc
, uint offset
)
303 if (offset
>= sflash
.size
)
306 switch (sflash
.type
) {
308 /* Check for ST Write In Progress bit */
309 sflash_cmd(osh
, cc
, SFLASH_ST_RDSR
);
310 return R_REG(osh
, &cc
->flashdata
) & SFLASH_ST_WIP
;
312 /* Check for Atmel Ready bit */
313 sflash_cmd(osh
, cc
, SFLASH_AT_STATUS
);
314 return !(R_REG(osh
, &cc
->flashdata
) & SFLASH_AT_READY
);
320 /* Write len bytes starting at offset into buf. Returns number of bytes
321 * written. Caller should poll for completion.
327 #define GET_BYTE(ptr) (*(uint8 *)((uint32)(ptr) ^ 7))
328 #else /* !74K, bcm33xx */
329 #define GET_BYTE(ptr) (*(uint8 *)((uint32)(ptr) ^ 3))
330 #endif /* BCMHND74K */
331 #else /* !IL_BIGENDIAN */
332 #define GET_BYTE(ptr) (*(ptr))
333 #endif /* IL_BIGENDIAN */
336 sflash_write(si_t
*sih
, chipcregs_t
*cc
, uint offset
, uint length
, const uchar
*buffer
)
339 uint off
= offset
, len
= length
;
340 const uint8
*buf
= buffer
;
342 int ret
= 0, ntry
= 0;
344 uint32 page
, byte
, mask
;
355 if ((off
+ len
) > sfl
->size
)
360 is4712b0
= (CHIPID(sih
->chip
) == BCM4712_CHIP_ID
) && (CHIPREV(sih
->chiprev
) == 3);
362 retry
: sflash_cmd(osh
, cc
, SFLASH_ST_WREN
);
369 W_REG(osh
, &cc
->flashaddress
, off
);
370 data
= GET_BYTE(buf
);
372 W_REG(osh
, &cc
->flashdata
, data
);
373 /* Set chip select */
374 OR_REG(osh
, &cc
->gpioout
, mask
);
375 /* Issue a page program with the first byte */
376 sflash_cmd(osh
, cc
, SFLASH_ST_PP
);
381 if ((off
& 255) == 0) {
382 /* Page boundary, drop cs and return */
383 AND_REG(osh
, &cc
->gpioout
, ~mask
);
385 if (!sflash_poll(sih
, cc
, off
)) {
386 /* Flash rejected command */
387 if (ntry
<= ST_RETRIES
)
394 /* Write single byte */
395 data
= GET_BYTE(buf
);
397 sflash_cmd(osh
, cc
, data
);
403 /* All done, drop cs */
404 AND_REG(osh
, &cc
->gpioout
, ~mask
);
406 if (!sflash_poll(sih
, cc
, off
)) {
407 /* Flash rejected command */
408 if (ntry
<= ST_RETRIES
)
413 } else if (sih
->ccrev
>= 20) {
414 W_REG(osh
, &cc
->flashaddress
, off
);
415 data
= GET_BYTE(buf
);
417 W_REG(osh
, &cc
->flashdata
, data
);
418 /* Issue a page program with CSA bit set */
419 sflash_cmd(osh
, cc
, SFLASH_ST_CSA
| SFLASH_ST_PP
);
424 if ((off
& 255) == 0) {
425 /* Page boundary, poll droping cs and return */
426 W_REG(NULL
, &cc
->flashcontrol
, 0);
428 if (sflash_poll(sih
, cc
, off
) == 0) {
429 /* Flash rejected command */
430 SFL_MSG(("sflash: pp rejected, ntry: %d,"
431 " off: %d/%d, len: %d/%d, ret:"
432 "%d\n", ntry
, off
, offset
, len
,
434 if (ntry
<= ST_RETRIES
)
441 /* Write single byte */
442 data
= GET_BYTE(buf
);
444 sflash_cmd(osh
, cc
, SFLASH_ST_CSA
| data
);
450 /* All done, drop cs & poll */
451 W_REG(NULL
, &cc
->flashcontrol
, 0);
453 if (sflash_poll(sih
, cc
, off
) == 0) {
454 /* Flash rejected command */
455 SFL_MSG(("sflash: pp rejected, ntry: %d, off: %d/%d,"
456 " len: %d/%d, ret: %d\n",
457 ntry
, off
, offset
, len
, length
, ret
));
458 if (ntry
<= ST_RETRIES
)
465 W_REG(osh
, &cc
->flashaddress
, off
);
466 data
= GET_BYTE(buf
);
468 W_REG(osh
, &cc
->flashdata
, data
);
470 sflash_cmd(osh
, cc
, SFLASH_ST_PP
);
474 mask
= sfl
->blocksize
- 1;
475 page
= (off
& ~mask
) << 1;
477 /* Read main memory page into buffer 1 */
478 if (byte
|| (len
< sfl
->blocksize
)) {
479 W_REG(osh
, &cc
->flashaddress
, page
);
480 sflash_cmd(osh
, cc
, SFLASH_AT_BUF1_LOAD
);
481 /* 250 us for AT45DB321B */
482 SPINWAIT(sflash_poll(sih
, cc
, off
), 1000);
483 ASSERT(!sflash_poll(sih
, cc
, off
));
485 /* Write into buffer 1 */
486 for (ret
= 0; (ret
< (int)len
) && (byte
< sfl
->blocksize
); ret
++) {
487 W_REG(osh
, &cc
->flashaddress
, byte
++);
488 W_REG(osh
, &cc
->flashdata
, *buf
++);
489 sflash_cmd(osh
, cc
, SFLASH_AT_BUF1_WRITE
);
491 /* Write buffer 1 into main memory page */
492 W_REG(osh
, &cc
->flashaddress
, page
);
493 sflash_cmd(osh
, cc
, SFLASH_AT_BUF1_PROGRAM
);
500 /* Erase a region. Returns number of bytes scheduled for erasure.
501 * Caller should poll for completion.
504 sflash_erase(si_t
*sih
, chipcregs_t
*cc
, uint offset
)
514 if (offset
>= sfl
->size
)
519 sflash_cmd(osh
, cc
, SFLASH_ST_WREN
);
520 W_REG(osh
, &cc
->flashaddress
, offset
);
521 /* Newer flashes have "sub-sectors" which can be erased independently
522 * with a new command: ST_SSE. The ST_SE command erases 64KB just as
525 sflash_cmd(osh
, cc
, (sfl
->blocksize
< (64 * 1024)) ? SFLASH_ST_SSE
: SFLASH_ST_SE
);
526 return sfl
->blocksize
;
528 W_REG(osh
, &cc
->flashaddress
, offset
<< 1);
529 sflash_cmd(osh
, cc
, SFLASH_AT_PAGE_ERASE
);
530 return sfl
->blocksize
;
537 * writes the appropriate range of flash, a NULL buf simply erases
538 * the region of flash
541 sflash_commit(si_t
*sih
, chipcregs_t
*cc
, uint offset
, uint len
, const uchar
*buf
)
544 uchar
*block
= NULL
, *cur_ptr
, *blk_ptr
;
545 uint blocksize
= 0, mask
, cur_offset
, cur_length
, cur_retlen
, remainder
;
546 uint blk_offset
, blk_len
, copied
;
554 /* Check address range */
559 if ((offset
+ len
) > sfl
->size
)
562 blocksize
= sfl
->blocksize
;
563 mask
= blocksize
- 1;
565 /* Allocate a block of mem */
566 if (!(block
= MALLOC(osh
, blocksize
)))
571 cur_offset
= offset
& ~mask
;
572 cur_length
= blocksize
;
575 remainder
= blocksize
- (offset
& mask
);
579 cur_retlen
= remainder
;
581 /* buf == NULL means erase only */
583 /* Copy existing data into holding block if necessary */
584 if ((offset
& mask
) || (len
< blocksize
)) {
585 blk_offset
= cur_offset
;
586 blk_len
= cur_length
;
589 /* Copy entire block */
591 copied
= sflash_read(sih
, cc
, blk_offset
, blk_len
, blk_ptr
);
592 blk_offset
+= copied
;
598 /* Copy input data into holding block */
599 memcpy(cur_ptr
+ (offset
& mask
), buf
, cur_retlen
);
603 if ((ret
= sflash_erase(sih
, cc
, (uint
) cur_offset
)) < 0)
605 while (sflash_poll(sih
, cc
, (uint
) cur_offset
));
607 /* buf == NULL means erase only */
609 offset
+= cur_retlen
;
614 /* Write holding block */
615 while (cur_length
> 0) {
616 if ((bytes
= sflash_write(sih
, cc
,
619 (uchar
*) cur_ptr
)) < 0) {
623 while (sflash_poll(sih
, cc
, (uint
) cur_offset
));
629 offset
+= cur_retlen
;
637 MFREE(osh
, block
, blocksize
);