2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright 2005, 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.
12 * $Id: sflash.c,v 1.1.1.11 2005/03/07 07:31:12 kanki Exp $
24 /* Private global state */
25 static struct sflash sflash
;
27 /* Issue a serial flash command */
29 sflash_cmd(chipcregs_t
*cc
, uint opcode
)
31 W_REG(&cc
->flashcontrol
, SFLASH_START
| opcode
);
32 while (R_REG(&cc
->flashcontrol
) & SFLASH_BUSY
);
35 /* Initialize serial flash access */
37 sflash_init(chipcregs_t
*cc
)
41 bzero(&sflash
, sizeof(sflash
));
43 sflash
.type
= R_REG(&cc
->capabilities
) & CAP_FLASH_MASK
;
45 switch (sflash
.type
) {
47 /* Probe for ST chips */
48 sflash_cmd(cc
, SFLASH_ST_DP
);
49 sflash_cmd(cc
, SFLASH_ST_RES
);
50 id
= R_REG(&cc
->flashdata
);
53 /* ST M25P20 2 Mbit Serial Flash */
54 sflash
.blocksize
= 64 * 1024;
58 /* ST M25P40 4 Mbit Serial Flash */
59 sflash
.blocksize
= 64 * 1024;
63 /* ST M25P80 8 Mbit Serial Flash */
64 sflash
.blocksize
= 64 * 1024;
65 sflash
.numblocks
= 16;
68 /* ST M25P16 16 Mbit Serial Flash */
69 sflash
.blocksize
= 64 * 1024;
70 sflash
.numblocks
= 32;
73 /* ST M25P32 32 Mbit Serial Flash */
74 sflash
.blocksize
= 64 * 1024;
75 sflash
.numblocks
= 64;
78 W_REG(&cc
->flashaddress
, 1);
79 sflash_cmd(cc
, SFLASH_ST_RES
);
80 id2
= R_REG(&cc
->flashdata
);
82 /* SST M25VF80 4 Mbit Serial Flash */
83 sflash
.blocksize
= 64 * 1024;
91 /* Probe for Atmel chips */
92 sflash_cmd(cc
, SFLASH_AT_STATUS
);
93 id
= R_REG(&cc
->flashdata
) & 0x3c;
96 /* Atmel AT45DB011 1Mbit Serial Flash */
97 sflash
.blocksize
= 256;
98 sflash
.numblocks
= 512;
101 /* Atmel AT45DB021 2Mbit Serial Flash */
102 sflash
.blocksize
= 256;
103 sflash
.numblocks
= 1024;
106 /* Atmel AT45DB041 4Mbit Serial Flash */
107 sflash
.blocksize
= 256;
108 sflash
.numblocks
= 2048;
111 /* Atmel AT45DB081 8Mbit Serial Flash */
112 sflash
.blocksize
= 256;
113 sflash
.numblocks
= 4096;
116 /* Atmel AT45DB161 16Mbit Serial Flash */
117 sflash
.blocksize
= 512;
118 sflash
.numblocks
= 4096;
121 /* Atmel AT45DB321 32Mbit Serial Flash */
122 sflash
.blocksize
= 512;
123 sflash
.numblocks
= 8192;
126 /* Atmel AT45DB642 64Mbit Serial Flash */
127 sflash
.blocksize
= 1024;
128 sflash
.numblocks
= 8192;
134 sflash
.size
= sflash
.blocksize
* sflash
.numblocks
;
135 return sflash
.size
? &sflash
: NULL
;
138 /* Read len bytes starting at offset into buf. Returns number of bytes read. */
140 sflash_read(chipcregs_t
*cc
, uint offset
, uint len
, uchar
*buf
)
148 if ((offset
+ len
) > sflash
.size
)
151 if ((len
>= 4) && (offset
& 3))
152 cnt
= 4 - (offset
& 3);
153 else if ((len
>= 4) && ((uint32
)buf
& 3))
154 cnt
= 4 - ((uint32
)buf
& 3);
158 from
= (uint32
*)KSEG1ADDR(SB_FLASH2
+ offset
);
162 bcopy(from
, to
, cnt
);
174 /* Poll for command completion. Returns zero when complete. */
176 sflash_poll(chipcregs_t
*cc
, uint offset
)
178 if (offset
>= sflash
.size
)
181 switch (sflash
.type
) {
183 /* Check for ST Write In Progress bit */
184 sflash_cmd(cc
, SFLASH_ST_RDSR
);
185 return R_REG(&cc
->flashdata
) & SFLASH_ST_WIP
;
187 /* Check for Atmel Ready bit */
188 sflash_cmd(cc
, SFLASH_AT_STATUS
);
189 return !(R_REG(&cc
->flashdata
) & SFLASH_AT_READY
);
195 /* Write len bytes starting at offset into buf. Returns number of bytes
196 * written. Caller should poll for completion.
199 sflash_write(chipcregs_t
*cc
, uint offset
, uint len
, const uchar
*buf
)
204 uint32 page
, byte
, mask
;
209 if ((offset
+ len
) > sflash
.size
)
215 mask
= R_REG(&cc
->chipid
);
216 is4712b0
= (((mask
& CID_ID_MASK
) == BCM4712_DEVICE_ID
) &&
217 ((mask
& CID_REV_MASK
) == (3 << CID_REV_SHIFT
)));
219 sflash_cmd(cc
, SFLASH_ST_WREN
);
222 W_REG(&cc
->flashaddress
, offset
);
223 W_REG(&cc
->flashdata
, *buf
++);
224 /* Set chip select */
225 OR_REG(&cc
->gpioout
, mask
);
226 /* Issue a page program with the first byte */
227 sflash_cmd(cc
, SFLASH_ST_PP
);
232 if ((offset
& 255) == 0) {
233 /* Page boundary, drop cs and return */
234 AND_REG(&cc
->gpioout
, ~mask
);
235 if (!sflash_poll(cc
, offset
)) {
236 /* Flash rejected command */
241 /* Write single byte */
242 sflash_cmd(cc
, *buf
++);
248 /* All done, drop cs if needed */
249 if ((offset
& 255) != 1) {
251 AND_REG(&cc
->gpioout
, ~mask
);
252 if (!sflash_poll(cc
, offset
)) {
253 /* Flash rejected command */
259 W_REG(&cc
->flashaddress
, offset
);
260 W_REG(&cc
->flashdata
, *buf
);
262 sflash_cmd(cc
, SFLASH_ST_PP
);
266 mask
= sfl
->blocksize
- 1;
267 page
= (offset
& ~mask
) << 1;
268 byte
= offset
& mask
;
269 /* Read main memory page into buffer 1 */
270 if (byte
|| len
< sfl
->blocksize
) {
271 W_REG(&cc
->flashaddress
, page
);
272 sflash_cmd(cc
, SFLASH_AT_BUF1_LOAD
);
273 /* 250 us for AT45DB321B */
274 SPINWAIT(sflash_poll(cc
, offset
), 1000);
275 ASSERT(!sflash_poll(cc
, offset
));
277 /* Write into buffer 1 */
278 for (ret
= 0; ret
< len
&& byte
< sfl
->blocksize
; ret
++) {
279 W_REG(&cc
->flashaddress
, byte
++);
280 W_REG(&cc
->flashdata
, *buf
++);
281 sflash_cmd(cc
, SFLASH_AT_BUF1_WRITE
);
283 /* Write buffer 1 into main memory page */
284 W_REG(&cc
->flashaddress
, page
);
285 sflash_cmd(cc
, SFLASH_AT_BUF1_PROGRAM
);
292 /* Erase a region. Returns number of bytes scheduled for erasure.
293 * Caller should poll for completion.
296 sflash_erase(chipcregs_t
*cc
, uint offset
)
300 if (offset
>= sflash
.size
)
306 sflash_cmd(cc
, SFLASH_ST_WREN
);
307 W_REG(&cc
->flashaddress
, offset
);
308 sflash_cmd(cc
, SFLASH_ST_SE
);
309 return sfl
->blocksize
;
311 W_REG(&cc
->flashaddress
, offset
<< 1);
312 sflash_cmd(cc
, SFLASH_AT_PAGE_ERASE
);
313 return sfl
->blocksize
;
320 * writes the appropriate range of flash, a NULL buf simply erases
321 * the region of flash
324 sflash_commit(chipcregs_t
*cc
, uint offset
, uint len
, const uchar
*buf
)
327 uchar
*block
= NULL
, *cur_ptr
, *blk_ptr
;
328 uint blocksize
= 0, mask
, cur_offset
, cur_length
, cur_retlen
, remainder
;
329 uint blk_offset
, blk_len
, copied
;
333 /* Check address range */
338 if ((offset
+ len
) > sfl
->size
)
341 blocksize
= sfl
->blocksize
;
342 mask
= blocksize
- 1;
344 /* get kernel osl handler */
345 osh
= osl_attach(NULL
);
347 /* Allocate a block of mem */
348 if (!(block
= MALLOC(osh
, blocksize
)))
353 cur_offset
= offset
& ~mask
;
354 cur_length
= blocksize
;
357 remainder
= blocksize
- (offset
& mask
);
361 cur_retlen
= remainder
;
363 /* buf == NULL means erase only */
365 /* Copy existing data into holding block if necessary */
366 if ((offset
& mask
) || (len
< blocksize
)) {
367 blk_offset
= cur_offset
;
368 blk_len
= cur_length
;
371 /* Copy entire block */
373 copied
= sflash_read(cc
, blk_offset
, blk_len
, blk_ptr
);
374 blk_offset
+= copied
;
380 /* Copy input data into holding block */
381 memcpy(cur_ptr
+ (offset
& mask
), buf
, cur_retlen
);
385 if ((ret
= sflash_erase(cc
, (uint
) cur_offset
)) < 0)
387 while (sflash_poll(cc
, (uint
) cur_offset
));
389 /* buf == NULL means erase only */
391 offset
+= cur_retlen
;
396 /* Write holding block */
397 while (cur_length
> 0) {
398 if ((bytes
= sflash_write(cc
,
401 (uchar
*) cur_ptr
)) < 0) {
405 while (sflash_poll(cc
, (uint
) cur_offset
));
411 offset
+= cur_retlen
;
419 MFREE(osh
, block
, blocksize
);