2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright (C) 2011, 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 300516 2011-12-04 17:39:44Z $
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
;
234 printf("Found an %s serial flash with %d %dKB blocks; total size %dMB\n",
235 name
, sflash
.numblocks
, sflash
.blocksize
/ 1024,
236 sflash
.size
/ (1024 * 1024));
239 return sflash
.size
? &sflash
: NULL
;
242 /* Read len bytes starting at offset into buf. Returns number of bytes read. */
244 sflash_read(si_t
*sih
, chipcregs_t
*cc
, uint offset
, uint len
, uchar
*buf
)
254 if ((offset
+ len
) > sflash
.size
)
257 if ((len
>= 4) && (offset
& 3))
258 cnt
= 4 - (offset
& 3);
259 else if ((len
>= 4) && ((uintptr
)buf
& 3))
260 cnt
= 4 - ((uintptr
)buf
& 3);
264 if (sih
->ccrev
== 12)
265 from
= (uint8
*)OSL_UNCACHED((void *)SI_FLASH2
+ offset
);
267 from
= (uint8
*)OSL_CACHED((void *)SI_FLASH2
+ offset
);
271 for (i
= 0; i
< cnt
; i
++) {
272 /* Cannot use R_REG because in bigendian that will
273 * xor the address and we don't want that here.
283 *(uint32
*)to
= *(uint32
*)from
;
292 /* Poll for command completion. Returns zero when complete. */
294 sflash_poll(si_t
*sih
, chipcregs_t
*cc
, uint offset
)
302 if (offset
>= sflash
.size
)
305 switch (sflash
.type
) {
307 /* Check for ST Write In Progress bit */
308 sflash_cmd(osh
, cc
, SFLASH_ST_RDSR
);
309 return R_REG(osh
, &cc
->flashdata
) & SFLASH_ST_WIP
;
311 /* Check for Atmel Ready bit */
312 sflash_cmd(osh
, cc
, SFLASH_AT_STATUS
);
313 return !(R_REG(osh
, &cc
->flashdata
) & SFLASH_AT_READY
);
319 /* Write len bytes starting at offset into buf. Returns number of bytes
320 * written. Caller should poll for completion.
326 #define GET_BYTE(ptr) (*(uint8 *)((uint32)(ptr) ^ 7))
327 #else /* !74K, bcm33xx */
328 #define GET_BYTE(ptr) (*(uint8 *)((uint32)(ptr) ^ 3))
329 #endif /* BCMHND74K */
330 #else /* !IL_BIGENDIAN */
331 #define GET_BYTE(ptr) (*(ptr))
332 #endif /* IL_BIGENDIAN */
335 sflash_write(si_t
*sih
, chipcregs_t
*cc
, uint offset
, uint length
, const uchar
*buffer
)
338 uint off
= offset
, len
= length
;
339 const uint8
*buf
= buffer
;
341 int ret
= 0, ntry
= 0;
343 uint32 page
, byte
, mask
;
354 if ((off
+ len
) > sfl
->size
)
359 is4712b0
= (CHIPID(sih
->chip
) == BCM4712_CHIP_ID
) && (CHIPREV(sih
->chiprev
) == 3);
361 retry
: sflash_cmd(osh
, cc
, SFLASH_ST_WREN
);
368 W_REG(osh
, &cc
->flashaddress
, off
);
369 data
= GET_BYTE(buf
);
371 W_REG(osh
, &cc
->flashdata
, data
);
372 /* Set chip select */
373 OR_REG(osh
, &cc
->gpioout
, mask
);
374 /* Issue a page program with the first byte */
375 sflash_cmd(osh
, cc
, SFLASH_ST_PP
);
380 if ((off
& 255) == 0) {
381 /* Page boundary, drop cs and return */
382 AND_REG(osh
, &cc
->gpioout
, ~mask
);
384 if (!sflash_poll(sih
, cc
, off
)) {
385 /* Flash rejected command */
386 if (ntry
<= ST_RETRIES
)
393 /* Write single byte */
394 data
= GET_BYTE(buf
);
396 sflash_cmd(osh
, cc
, data
);
402 /* All done, drop cs */
403 AND_REG(osh
, &cc
->gpioout
, ~mask
);
405 if (!sflash_poll(sih
, cc
, off
)) {
406 /* Flash rejected command */
407 if (ntry
<= ST_RETRIES
)
412 } else if (sih
->ccrev
>= 20) {
413 W_REG(osh
, &cc
->flashaddress
, off
);
414 data
= GET_BYTE(buf
);
416 W_REG(osh
, &cc
->flashdata
, data
);
417 /* Issue a page program with CSA bit set */
418 sflash_cmd(osh
, cc
, SFLASH_ST_CSA
| SFLASH_ST_PP
);
423 if ((off
& 255) == 0) {
424 /* Page boundary, poll droping cs and return */
425 W_REG(NULL
, &cc
->flashcontrol
, 0);
427 if (sflash_poll(sih
, cc
, off
) == 0) {
428 /* Flash rejected command */
429 SFL_MSG(("sflash: pp rejected, ntry: %d,"
430 " off: %d/%d, len: %d/%d, ret:"
431 "%d\n", ntry
, off
, offset
, len
,
433 if (ntry
<= ST_RETRIES
)
440 /* Write single byte */
441 data
= GET_BYTE(buf
);
443 sflash_cmd(osh
, cc
, SFLASH_ST_CSA
| data
);
449 /* All done, drop cs & poll */
450 W_REG(NULL
, &cc
->flashcontrol
, 0);
452 if (sflash_poll(sih
, cc
, off
) == 0) {
453 /* Flash rejected command */
454 SFL_MSG(("sflash: pp rejected, ntry: %d, off: %d/%d,"
455 " len: %d/%d, ret: %d\n",
456 ntry
, off
, offset
, len
, length
, ret
));
457 if (ntry
<= ST_RETRIES
)
464 W_REG(osh
, &cc
->flashaddress
, off
);
465 data
= GET_BYTE(buf
);
467 W_REG(osh
, &cc
->flashdata
, data
);
469 sflash_cmd(osh
, cc
, SFLASH_ST_PP
);
473 mask
= sfl
->blocksize
- 1;
474 page
= (off
& ~mask
) << 1;
476 /* Read main memory page into buffer 1 */
477 if (byte
|| (len
< sfl
->blocksize
)) {
478 W_REG(osh
, &cc
->flashaddress
, page
);
479 sflash_cmd(osh
, cc
, SFLASH_AT_BUF1_LOAD
);
480 /* 250 us for AT45DB321B */
481 SPINWAIT(sflash_poll(sih
, cc
, off
), 1000);
482 ASSERT(!sflash_poll(sih
, cc
, off
));
484 /* Write into buffer 1 */
485 for (ret
= 0; (ret
< (int)len
) && (byte
< sfl
->blocksize
); ret
++) {
486 W_REG(osh
, &cc
->flashaddress
, byte
++);
487 W_REG(osh
, &cc
->flashdata
, *buf
++);
488 sflash_cmd(osh
, cc
, SFLASH_AT_BUF1_WRITE
);
490 /* Write buffer 1 into main memory page */
491 W_REG(osh
, &cc
->flashaddress
, page
);
492 sflash_cmd(osh
, cc
, SFLASH_AT_BUF1_PROGRAM
);
499 /* Erase a region. Returns number of bytes scheduled for erasure.
500 * Caller should poll for completion.
503 sflash_erase(si_t
*sih
, chipcregs_t
*cc
, uint offset
)
513 if (offset
>= sfl
->size
)
518 sflash_cmd(osh
, cc
, SFLASH_ST_WREN
);
519 W_REG(osh
, &cc
->flashaddress
, offset
);
520 /* Newer flashes have "sub-sectors" which can be erased independently
521 * with a new command: ST_SSE. The ST_SE command erases 64KB just as
524 sflash_cmd(osh
, cc
, (sfl
->blocksize
< (64 * 1024)) ? SFLASH_ST_SSE
: SFLASH_ST_SE
);
525 return sfl
->blocksize
;
527 W_REG(osh
, &cc
->flashaddress
, offset
<< 1);
528 sflash_cmd(osh
, cc
, SFLASH_AT_PAGE_ERASE
);
529 return sfl
->blocksize
;
536 * writes the appropriate range of flash, a NULL buf simply erases
537 * the region of flash
540 sflash_commit(si_t
*sih
, chipcregs_t
*cc
, uint offset
, uint len
, const uchar
*buf
)
543 uchar
*block
= NULL
, *cur_ptr
, *blk_ptr
;
544 uint blocksize
= 0, mask
, cur_offset
, cur_length
, cur_retlen
, remainder
;
545 uint blk_offset
, blk_len
, copied
;
553 /* Check address range */
558 if ((offset
+ len
) > sfl
->size
)
561 blocksize
= sfl
->blocksize
;
562 mask
= blocksize
- 1;
564 /* Allocate a block of mem */
565 if (!(block
= MALLOC(osh
, blocksize
)))
570 cur_offset
= offset
& ~mask
;
571 cur_length
= blocksize
;
574 remainder
= blocksize
- (offset
& mask
);
578 cur_retlen
= remainder
;
580 /* buf == NULL means erase only */
582 /* Copy existing data into holding block if necessary */
583 if ((offset
& mask
) || (len
< blocksize
)) {
584 blk_offset
= cur_offset
;
585 blk_len
= cur_length
;
588 /* Copy entire block */
590 copied
= sflash_read(sih
, cc
, blk_offset
, blk_len
, blk_ptr
);
591 blk_offset
+= copied
;
597 /* Copy input data into holding block */
598 memcpy(cur_ptr
+ (offset
& mask
), buf
, cur_retlen
);
602 if ((ret
= sflash_erase(sih
, cc
, (uint
) cur_offset
)) < 0)
604 while (sflash_poll(sih
, cc
, (uint
) cur_offset
));
606 /* buf == NULL means erase only */
608 offset
+= cur_retlen
;
613 /* Write holding block */
614 while (cur_length
> 0) {
615 if ((bytes
= sflash_write(sih
, cc
,
618 (uchar
*) cur_ptr
)) < 0) {
622 while (sflash_poll(sih
, cc
, (uint
) cur_offset
));
628 offset
+= cur_retlen
;
636 MFREE(osh
, block
, blocksize
);