2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright 2006, 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.13 2006/02/27 03:43:16 honor 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(NULL
, &cc
->flashcontrol
, SFLASH_START
| opcode
);
32 while (R_REG(NULL
, &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(NULL
, &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(NULL
, &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 /* ST M25P64 64 Mbit Serial Flash */
79 sflash
.blocksize
= 64 * 1024;
80 sflash
.numblocks
= 128;
83 W_REG(NULL
, &cc
->flashaddress
, 1);
84 sflash_cmd(cc
, SFLASH_ST_RES
);
85 id2
= R_REG(NULL
, &cc
->flashdata
);
87 /* SST M25VF80 4 Mbit Serial Flash */
88 sflash
.blocksize
= 64 * 1024;
96 /* Probe for Atmel chips */
97 sflash_cmd(cc
, SFLASH_AT_STATUS
);
98 id
= R_REG(NULL
, &cc
->flashdata
) & 0x3c;
101 /* Atmel AT45DB011 1Mbit Serial Flash */
102 sflash
.blocksize
= 256;
103 sflash
.numblocks
= 512;
106 /* Atmel AT45DB021 2Mbit Serial Flash */
107 sflash
.blocksize
= 256;
108 sflash
.numblocks
= 1024;
111 /* Atmel AT45DB041 4Mbit Serial Flash */
112 sflash
.blocksize
= 256;
113 sflash
.numblocks
= 2048;
116 /* Atmel AT45DB081 8Mbit Serial Flash */
117 sflash
.blocksize
= 256;
118 sflash
.numblocks
= 4096;
121 /* Atmel AT45DB161 16Mbit Serial Flash */
122 sflash
.blocksize
= 512;
123 sflash
.numblocks
= 4096;
126 /* Atmel AT45DB321 32Mbit Serial Flash */
127 sflash
.blocksize
= 512;
128 sflash
.numblocks
= 8192;
131 /* Atmel AT45DB642 64Mbit Serial Flash */
132 sflash
.blocksize
= 1024;
133 sflash
.numblocks
= 8192;
139 sflash
.size
= sflash
.blocksize
* sflash
.numblocks
;
140 return sflash
.size
? &sflash
: NULL
;
143 /* Read len bytes starting at offset into buf. Returns number of bytes read. */
145 sflash_read(chipcregs_t
*cc
, uint offset
, uint len
, uchar
*buf
)
153 if ((offset
+ len
) > sflash
.size
)
156 if ((len
>= 4) && (offset
& 3))
157 cnt
= 4 - (offset
& 3);
158 else if ((len
>= 4) && ((uint32
)buf
& 3))
159 cnt
= 4 - ((uint32
)buf
& 3);
163 from
= (uint32
*)KSEG1ADDR(SB_FLASH2
+ offset
);
167 bcopy(from
, to
, cnt
);
179 /* Poll for command completion. Returns zero when complete. */
181 sflash_poll(chipcregs_t
*cc
, uint offset
)
183 if (offset
>= sflash
.size
)
186 switch (sflash
.type
) {
188 /* Check for ST Write In Progress bit */
189 sflash_cmd(cc
, SFLASH_ST_RDSR
);
190 return R_REG(NULL
, &cc
->flashdata
) & SFLASH_ST_WIP
;
192 /* Check for Atmel Ready bit */
193 sflash_cmd(cc
, SFLASH_AT_STATUS
);
194 return !(R_REG(NULL
, &cc
->flashdata
) & SFLASH_AT_READY
);
200 /* Write len bytes starting at offset into buf. Returns number of bytes
201 * written. Caller should poll for completion.
204 sflash_write(chipcregs_t
*cc
, uint offset
, uint len
, const uchar
*buf
)
209 uint32 page
, byte
, mask
;
214 if ((offset
+ len
) > sflash
.size
)
220 mask
= R_REG(NULL
, &cc
->chipid
);
221 is4712b0
= (((mask
& CID_ID_MASK
) == BCM4712_CHIP_ID
) &&
222 ((mask
& CID_REV_MASK
) == (3 << CID_REV_SHIFT
)));
224 sflash_cmd(cc
, SFLASH_ST_WREN
);
227 W_REG(NULL
, &cc
->flashaddress
, offset
);
228 W_REG(NULL
, &cc
->flashdata
, *buf
++);
229 /* Set chip select */
230 OR_REG(NULL
, &cc
->gpioout
, mask
);
231 /* Issue a page program with the first byte */
232 sflash_cmd(cc
, SFLASH_ST_PP
);
237 if ((offset
& 255) == 0) {
238 /* Page boundary, drop cs and return */
239 AND_REG(NULL
, &cc
->gpioout
, ~mask
);
240 if (!sflash_poll(cc
, offset
)) {
241 /* Flash rejected command */
246 /* Write single byte */
247 sflash_cmd(cc
, *buf
++);
253 /* All done, drop cs if needed */
254 if ((offset
& 255) != 1) {
256 AND_REG(NULL
, &cc
->gpioout
, ~mask
);
257 if (!sflash_poll(cc
, offset
)) {
258 /* Flash rejected command */
264 W_REG(NULL
, &cc
->flashaddress
, offset
);
265 W_REG(NULL
, &cc
->flashdata
, *buf
);
267 sflash_cmd(cc
, SFLASH_ST_PP
);
271 mask
= sfl
->blocksize
- 1;
272 page
= (offset
& ~mask
) << 1;
273 byte
= offset
& mask
;
274 /* Read main memory page into buffer 1 */
275 if (byte
|| (len
< sfl
->blocksize
)) {
276 W_REG(NULL
, &cc
->flashaddress
, page
);
277 sflash_cmd(cc
, SFLASH_AT_BUF1_LOAD
);
278 /* 250 us for AT45DB321B */
279 SPINWAIT(sflash_poll(cc
, offset
), 1000);
280 ASSERT(!sflash_poll(cc
, offset
));
282 /* Write into buffer 1 */
283 for (ret
= 0; (ret
< (int)len
) && (byte
< sfl
->blocksize
); ret
++) {
284 W_REG(NULL
, &cc
->flashaddress
, byte
++);
285 W_REG(NULL
, &cc
->flashdata
, *buf
++);
286 sflash_cmd(cc
, SFLASH_AT_BUF1_WRITE
);
288 /* Write buffer 1 into main memory page */
289 W_REG(NULL
, &cc
->flashaddress
, page
);
290 sflash_cmd(cc
, SFLASH_AT_BUF1_PROGRAM
);
297 /* Erase a region. Returns number of bytes scheduled for erasure.
298 * Caller should poll for completion.
301 sflash_erase(chipcregs_t
*cc
, uint offset
)
305 if (offset
>= sflash
.size
)
311 sflash_cmd(cc
, SFLASH_ST_WREN
);
312 W_REG(NULL
, &cc
->flashaddress
, offset
);
313 sflash_cmd(cc
, SFLASH_ST_SE
);
314 return sfl
->blocksize
;
316 W_REG(NULL
, &cc
->flashaddress
, offset
<< 1);
317 sflash_cmd(cc
, SFLASH_AT_PAGE_ERASE
);
318 return sfl
->blocksize
;
325 * writes the appropriate range of flash, a NULL buf simply erases
326 * the region of flash
329 sflash_commit(chipcregs_t
*cc
, uint offset
, uint len
, const uchar
*buf
)
332 uchar
*block
= NULL
, *cur_ptr
, *blk_ptr
;
333 uint blocksize
= 0, mask
, cur_offset
, cur_length
, cur_retlen
, remainder
;
334 uint blk_offset
, blk_len
, copied
;
337 /* Check address range */
342 if ((offset
+ len
) > sfl
->size
)
345 blocksize
= sfl
->blocksize
;
346 mask
= blocksize
- 1;
348 /* Allocate a block of mem */
349 if (!(block
= MALLOC(NULL
, blocksize
)))
354 cur_offset
= offset
& ~mask
;
355 cur_length
= blocksize
;
358 remainder
= blocksize
- (offset
& mask
);
362 cur_retlen
= remainder
;
364 /* buf == NULL means erase only */
366 /* Copy existing data into holding block if necessary */
367 if ((offset
& mask
) || (len
< blocksize
)) {
368 blk_offset
= cur_offset
;
369 blk_len
= cur_length
;
372 /* Copy entire block */
374 copied
= sflash_read(cc
, blk_offset
, blk_len
, blk_ptr
);
375 blk_offset
+= copied
;
381 /* Copy input data into holding block */
382 memcpy(cur_ptr
+ (offset
& mask
), buf
, cur_retlen
);
386 if ((ret
= sflash_erase(cc
, (uint
) cur_offset
)) < 0)
388 while (sflash_poll(cc
, (uint
) cur_offset
));
390 /* buf == NULL means erase only */
392 offset
+= cur_retlen
;
397 /* Write holding block */
398 while (cur_length
> 0) {
399 if ((bytes
= sflash_write(cc
,
402 (uchar
*) cur_ptr
)) < 0) {
406 while (sflash_poll(cc
, (uint
) cur_offset
));
412 offset
+= cur_retlen
;
420 MFREE(NULL
, block
, blocksize
);
This page took 0.077639 seconds and 5 git commands to generate.