2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright 2004, 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.
21 /* Private global state */
22 static struct sflash sflash
;
24 /* Issue a serial flash command */
26 sflash_cmd(chipcregs_t
*cc
, uint opcode
)
28 W_REG(&cc
->flashcontrol
, SFLASH_START
| opcode
);
29 while (R_REG(&cc
->flashcontrol
) & SFLASH_BUSY
);
32 /* Initialize serial flash access */
34 sflash_init(chipcregs_t
*cc
)
38 bzero(&sflash
, sizeof(sflash
));
40 sflash
.type
= R_REG(&cc
->capabilities
) & CAP_FLASH_MASK
;
42 switch (sflash
.type
) {
44 /* Probe for ST chips */
45 sflash_cmd(cc
, SFLASH_ST_DP
);
46 sflash_cmd(cc
, SFLASH_ST_RES
);
47 id
= R_REG(&cc
->flashdata
);
50 /* ST M25P20 2 Mbit Serial Flash */
51 sflash
.blocksize
= 64 * 1024;
55 /* ST M25P40 4 Mbit Serial Flash */
56 sflash
.blocksize
= 64 * 1024;
60 /* ST M25P80 8 Mbit Serial Flash */
61 sflash
.blocksize
= 64 * 1024;
62 sflash
.numblocks
= 16;
65 /* ST M25P16 16 Mbit Serial Flash */
66 sflash
.blocksize
= 64 * 1024;
67 sflash
.numblocks
= 32;
70 W_REG(&cc
->flashaddress
, 1);
71 sflash_cmd(cc
, SFLASH_ST_RES
);
72 id2
= R_REG(&cc
->flashdata
);
74 /* SST M25VF80 4 Mbit Serial Flash */
75 sflash
.blocksize
= 64 * 1024;
83 /* Probe for Atmel chips */
84 sflash_cmd(cc
, SFLASH_AT_STATUS
);
85 id
= R_REG(&cc
->flashdata
) & 0x3c;
88 /* Atmel AT45DB161 16Mbit Serial Flash */
89 sflash
.blocksize
= 512;
90 sflash
.numblocks
= 4096;
93 /* Atmel AT45DB321 32Mbit Serial Flash */
94 sflash
.blocksize
= 512;
95 sflash
.numblocks
= 8192;
98 /* Atmel AT45DB642 64Mbit Serial Flash */
99 sflash
.blocksize
= 1024;
100 sflash
.numblocks
= 8192;
106 sflash
.size
= sflash
.blocksize
* sflash
.numblocks
;
107 return sflash
.size
? &sflash
: NULL
;
110 /* Read len bytes starting at offset into buf. Returns number of bytes read. */
112 sflash_read(chipcregs_t
*cc
, uint offset
, uint len
, uchar
*buf
)
120 if ((offset
+ len
) > sflash
.size
)
123 if ((len
>= 4) && (offset
& 3))
124 cnt
= 4 - (offset
& 3);
125 else if ((len
>= 4) && ((uint32
)buf
& 3))
126 cnt
= 4 - ((uint32
)buf
& 3);
130 from
= (uint32
*)(CC_FLASH_BASE
+ offset
);
134 bcopy(from
, to
, cnt
);
146 /* Poll for command completion. Returns zero when complete. */
148 sflash_poll(chipcregs_t
*cc
, uint offset
)
150 if (offset
>= sflash
.size
)
153 switch (sflash
.type
) {
155 /* Check for ST Write In Progress bit */
156 sflash_cmd(cc
, SFLASH_ST_RDSR
);
157 return R_REG(&cc
->flashdata
) & SFLASH_ST_WIP
;
159 /* Check for Atmel Ready bit */
160 sflash_cmd(cc
, SFLASH_AT_STATUS
);
161 return !(R_REG(&cc
->flashdata
) & SFLASH_AT_READY
);
167 /* Write len bytes starting at offset into buf. Returns number of bytes
168 * written. Caller should poll for completion.
171 sflash_write(chipcregs_t
*cc
, uint offset
, uint len
, const uchar
*buf
)
175 uint32 page
, byte
, mask
;
180 if ((offset
+ len
) > sflash
.size
)
188 sflash_cmd(cc
, SFLASH_ST_WREN
);
189 W_REG(&cc
->flashaddress
, offset
);
190 W_REG(&cc
->flashdata
, *buf
);
192 sflash_cmd(cc
, SFLASH_ST_PP
);
195 mask
= sfl
->blocksize
- 1;
196 page
= (offset
& ~mask
) << 1;
197 byte
= offset
& mask
;
198 /* Read main memory page into buffer 1 */
199 if (byte
|| len
< sfl
->blocksize
) {
200 W_REG(&cc
->flashaddress
, page
);
201 sflash_cmd(cc
, SFLASH_AT_BUF1_LOAD
);
202 /* 250 us for AT45DB321B */
203 SPINWAIT(sflash_poll(cc
, offset
), 1000);
204 ASSERT(!sflash_poll(cc
, offset
));
206 /* Write into buffer 1 */
207 for (ret
= 0; ret
< len
&& byte
< sfl
->blocksize
; ret
++) {
208 W_REG(&cc
->flashaddress
, byte
++);
209 W_REG(&cc
->flashdata
, *buf
++);
210 sflash_cmd(cc
, SFLASH_AT_BUF1_WRITE
);
212 /* Write buffer 1 into main memory page */
213 W_REG(&cc
->flashaddress
, page
);
214 sflash_cmd(cc
, SFLASH_AT_BUF1_PROGRAM
);
221 /* Erase a region. Returns number of bytes scheduled for erasure.
222 * Caller should poll for completion.
225 sflash_erase(chipcregs_t
*cc
, uint offset
)
229 if (offset
>= sflash
.size
)
235 sflash_cmd(cc
, SFLASH_ST_WREN
);
236 W_REG(&cc
->flashaddress
, offset
);
237 sflash_cmd(cc
, SFLASH_ST_SE
);
238 return sfl
->blocksize
;
240 W_REG(&cc
->flashaddress
, offset
<< 1);
241 sflash_cmd(cc
, SFLASH_AT_PAGE_ERASE
);
242 return sfl
->blocksize
;
249 * writes the appropriate range of flash, a NULL buf simply erases
250 * the region of flash
253 sflash_commit(chipcregs_t
*cc
, uint offset
, uint len
, const uchar
*buf
)
256 uchar
*block
= NULL
, *cur_ptr
, *blk_ptr
;
257 uint blocksize
= 0, mask
, cur_offset
, cur_length
, cur_retlen
, remainder
;
258 uint blk_offset
, blk_len
, copied
;
261 /* Check address range */
266 if ((offset
+ len
) > sfl
->size
)
269 blocksize
= sfl
->blocksize
;
270 mask
= blocksize
- 1;
272 /* Allocate a block of mem */
273 if (!(block
= MALLOC(blocksize
)))
278 cur_offset
= offset
& ~mask
;
279 cur_length
= blocksize
;
282 remainder
= blocksize
- (offset
& mask
);
286 cur_retlen
= remainder
;
288 /* buf == NULL means erase only */
290 /* Copy existing data into holding block if necessary */
291 if ((offset
& mask
) || (len
< blocksize
)) {
292 blk_offset
= cur_offset
;
293 blk_len
= cur_length
;
296 /* Copy entire block */
298 copied
= sflash_read(cc
, blk_offset
, blk_len
, blk_ptr
);
299 blk_offset
+= copied
;
305 /* Copy input data into holding block */
306 memcpy(cur_ptr
+ (offset
& mask
), buf
, cur_retlen
);
310 if ((ret
= sflash_erase(cc
, (uint
) cur_offset
)) < 0)
312 while (sflash_poll(cc
, (uint
) cur_offset
));
314 /* buf == NULL means erase only */
316 offset
+= cur_retlen
;
321 /* Write holding block */
322 while (cur_length
> 0) {
323 if ((bytes
= sflash_write(cc
,
326 (uchar
*) cur_ptr
)) < 0) {
330 while (sflash_poll(cc
, (uint
) cur_offset
));
336 offset
+= cur_retlen
;
343 MFREE(block
, blocksize
);
This page took 0.071445 seconds and 5 git commands to generate.