Broadcom SDK and wireless driver: another attempt to update to ver. 5.10.147.0
[tomato.git] / release / src-rt / shared / sflash.c
blob54236ffdbba68ecc703dbc75e8aa959cb8ccf9e3
1 /*
2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright (C) 2009, Broadcom Corporation
5 * All Rights Reserved.
6 *
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.44.2.7 2010/02/18 02:08:55 Exp $
15 #include <typedefs.h>
16 #include <osl.h>
17 #include <bcmutils.h>
18 #include <siutils.h>
19 #include <hndsoc.h>
20 #include <sbhndcpu.h>
21 #include <sbchipc.h>
22 #include <bcmdevs.h>
23 #include <sflash.h>
25 #define SFL_MSG(args)
27 bool sflash_uncached = FALSE;
29 /* Private global state */
30 static struct sflash sflash;
32 /* Issue a serial flash command */
33 static INLINE void
34 sflash_cmd(osl_t *osh, chipcregs_t *cc, uint opcode)
36 W_REG(osh, &cc->flashcontrol, SFLASH_START | opcode);
37 while (R_REG(osh, &cc->flashcontrol) & SFLASH_BUSY);
40 /* Initialize serial flash access */
41 struct sflash *
42 sflash_init(si_t *sih, chipcregs_t *cc)
44 uint32 id, id2;
45 char *name = "";
46 osl_t *osh;
47 static bool firsttime = TRUE;
49 ASSERT(sih);
51 osh = si_osh(sih);
53 bzero(&sflash, sizeof(sflash));
55 sflash.type = sih->cccaps & CC_CAP_FLASH_MASK;
57 switch (sflash.type) {
58 case SFLASH_ST:
59 /* Probe for ST chips */
60 name = "ST compatible";
61 sflash_cmd(osh, cc, SFLASH_ST_DP);
62 sflash_cmd(osh, cc, SFLASH_ST_RES);
63 id = R_REG(osh, &cc->flashdata);
64 switch (id) {
65 case 0x11:
66 /* ST M25P20 2 Mbit Serial Flash */
67 sflash.blocksize = 64 * 1024;
68 sflash.numblocks = 4;
69 break;
70 case 0x12:
71 /* ST M25P40 4 Mbit Serial Flash */
72 sflash.blocksize = 64 * 1024;
73 sflash.numblocks = 8;
74 break;
75 case 0x13:
76 /* ST M25P80 8 Mbit Serial Flash */
77 sflash.blocksize = 64 * 1024;
78 sflash.numblocks = 16;
79 break;
80 case 0x14:
81 /* ST M25P16 16 Mbit Serial Flash */
82 sflash.blocksize = 64 * 1024;
83 sflash.numblocks = 32;
84 break;
85 case 0x15:
86 /* ST M25P32 32 Mbit Serial Flash */
87 sflash.blocksize = 64 * 1024;
88 sflash.numblocks = 64;
89 break;
90 case 0x16:
91 /* ST M25P64 64 Mbit Serial Flash */
92 sflash.blocksize = 64 * 1024;
93 sflash.numblocks = 128;
94 break;
95 case 0x17:
96 /* ST M25FL128 128 Mbit Serial Flash */
97 sflash.blocksize = 64 * 1024;
98 sflash.numblocks = 256;
99 break;
100 case 0xbf:
101 W_REG(osh, &cc->flashaddress, 1);
102 sflash_cmd(osh, cc, SFLASH_ST_RES);
103 id2 = R_REG(osh, &cc->flashdata);
104 if (id2 == 0x44) {
105 /* SST M25VF80 4 Mbit Serial Flash */
106 name = "SST";
107 sflash.blocksize = 64 * 1024;
108 sflash.numblocks = 8;
110 break;
112 break;
114 case SFLASH_AT:
115 /* Probe for Atmel chips */
116 name = "Atmel";
117 sflash_cmd(osh, cc, SFLASH_AT_STATUS);
118 id = R_REG(osh, &cc->flashdata) & 0x3c;
119 switch (id) {
120 case 0xc:
121 /* Atmel AT45DB011 1Mbit Serial Flash */
122 sflash.blocksize = 256;
123 sflash.numblocks = 512;
124 break;
125 case 0x14:
126 /* Atmel AT45DB021 2Mbit Serial Flash */
127 sflash.blocksize = 256;
128 sflash.numblocks = 1024;
129 break;
130 case 0x1c:
131 /* Atmel AT45DB041 4Mbit Serial Flash */
132 sflash.blocksize = 256;
133 sflash.numblocks = 2048;
134 break;
135 case 0x24:
136 /* Atmel AT45DB081 8Mbit Serial Flash */
137 sflash.blocksize = 256;
138 sflash.numblocks = 4096;
139 break;
140 case 0x2c:
141 /* Atmel AT45DB161 16Mbit Serial Flash */
142 sflash.blocksize = 512;
143 sflash.numblocks = 4096;
144 break;
145 case 0x34:
146 /* Atmel AT45DB321 32Mbit Serial Flash */
147 sflash.blocksize = 512;
148 sflash.numblocks = 8192;
149 break;
150 case 0x3c:
151 /* Atmel AT45DB642 64Mbit Serial Flash */
152 sflash.blocksize = 1024;
153 sflash.numblocks = 8192;
154 break;
156 break;
159 sflash.size = sflash.blocksize * sflash.numblocks;
161 if (firsttime)
162 printf("Found a %dMB %s serial flash\n",
163 sflash.size / (1024 * 1024), name);
165 /* 4716A0 hack */
166 if (((sih->chip == BCM4716_CHIP_ID) || (sih->chip == BCM4748_CHIP_ID)) &&
167 (sih->chiprev == 0)) {
168 if (sflash.size > (4 * 1024 * 1024)) {
169 sflash.size = 4 * 1024 * 1024;
170 if (firsttime)
171 printf("Using only 4MB in BCM4716a0\n");
174 firsttime = FALSE;
175 return sflash.size ? &sflash : NULL;
178 /* Read len bytes starting at offset into buf. Returns number of bytes read. */
180 sflash_read(si_t *sih, chipcregs_t *cc, uint offset, uint len, uchar *buf)
182 uint8 *from, *to;
183 int cnt, i;
184 osl_t *osh;
186 ASSERT(sih);
188 if (!len)
189 return 0;
191 if ((offset + len) > sflash.size)
192 return -22;
194 if ((len >= 4) && (offset & 3))
195 cnt = 4 - (offset & 3);
196 else if ((len >= 4) && ((uintptr)buf & 3))
197 cnt = 4 - ((uintptr)buf & 3);
198 else
199 cnt = len;
201 osh = si_osh(sih);
203 if (sih->ccrev == 12)
204 from = (uint8 *)OSL_UNCACHED(SI_FLASH2 + offset);
205 else
206 /* Read sflash using uncached addresses if the override exists.
207 * Otherwise default to reading thru' cache.
209 from = (uint8 *)(sflash_uncached ? OSL_UNCACHED(SI_FLASH2 + offset) :
210 OSL_CACHED(SI_FLASH2 + offset));
211 to = (uint8 *)buf;
213 if (cnt < 4) {
214 for (i = 0; i < cnt; i ++) {
215 /* Cannot use R_REG because in bigendian that will
216 * xor the address and we don't want that here.
218 *to = *from;
219 from ++;
220 to ++;
222 return cnt;
225 while (cnt >= 4) {
226 *(uint32 *)to = *(uint32 *)from;
227 from += 4;
228 to += 4;
229 cnt -= 4;
232 return (len - cnt);
235 /* Poll for command completion. Returns zero when complete. */
237 sflash_poll(si_t *sih, chipcregs_t *cc, uint offset)
239 osl_t *osh;
241 ASSERT(sih);
243 osh = si_osh(sih);
245 if (offset >= sflash.size)
246 return -22;
248 switch (sflash.type) {
249 case SFLASH_ST:
250 /* Check for ST Write In Progress bit */
251 sflash_cmd(osh, cc, SFLASH_ST_RDSR);
252 return R_REG(osh, &cc->flashdata) & SFLASH_ST_WIP;
253 case SFLASH_AT:
254 /* Check for Atmel Ready bit */
255 sflash_cmd(osh, cc, SFLASH_AT_STATUS);
256 return !(R_REG(osh, &cc->flashdata) & SFLASH_AT_READY);
259 return 0;
262 /* Write len bytes starting at offset into buf. Returns number of bytes
263 * written. Caller should poll for completion.
265 #define ST_RETRIES 3
267 #ifdef IL_BIGENDIAN
268 #ifdef BCMHND74K
269 #define GET_BYTE(ptr) (*(uint8 *)((uint32)(ptr) ^ 7))
270 #else /* !74K, bcm33xx */
271 #define GET_BYTE(ptr) (*(uint8 *)((uint32)(ptr) ^ 3))
272 #endif /* BCMHND74K */
273 #else /* !IL_BIGENDIAN */
274 #define GET_BYTE(ptr) (*(ptr))
275 #endif /* IL_BIGENDIAN */
278 sflash_write(si_t *sih, chipcregs_t *cc, uint offset, uint length, const uchar *buffer)
280 struct sflash *sfl;
281 uint off = offset, len = length;
282 const uint8 *buf = buffer;
283 uint8 data;
284 int ret = 0, ntry = 0;
285 bool is4712b0;
286 uint32 page, byte, mask;
287 osl_t *osh;
289 ASSERT(sih);
291 osh = si_osh(sih);
293 if (!len)
294 return 0;
296 sfl = &sflash;
297 if ((off + len) > sfl->size)
298 return -22;
300 switch (sfl->type) {
301 case SFLASH_ST:
302 is4712b0 = (sih->chip == BCM4712_CHIP_ID) && (sih->chiprev == 3);
303 /* Enable writes */
304 retry: sflash_cmd(osh, cc, SFLASH_ST_WREN);
305 off = offset;
306 len = length;
307 buf = buffer;
308 ntry++;
309 if (is4712b0) {
310 mask = 1 << 14;
311 W_REG(osh, &cc->flashaddress, off);
312 data = GET_BYTE(buf);
313 buf++;
314 W_REG(osh, &cc->flashdata, data);
315 /* Set chip select */
316 OR_REG(osh, &cc->gpioout, mask);
317 /* Issue a page program with the first byte */
318 sflash_cmd(osh, cc, SFLASH_ST_PP);
319 ret = 1;
320 off++;
321 len--;
322 while (len > 0) {
323 if ((off & 255) == 0) {
324 /* Page boundary, drop cs and return */
325 AND_REG(osh, &cc->gpioout, ~mask);
326 OSL_DELAY(1);
327 if (!sflash_poll(sih, cc, off)) {
328 /* Flash rejected command */
329 if (ntry <= ST_RETRIES)
330 goto retry;
331 else
332 return -11;
334 return ret;
335 } else {
336 /* Write single byte */
337 data = GET_BYTE(buf);
338 buf++;
339 sflash_cmd(osh, cc, data);
341 ret++;
342 off++;
343 len--;
345 /* All done, drop cs */
346 AND_REG(osh, &cc->gpioout, ~mask);
347 OSL_DELAY(1);
348 if (!sflash_poll(sih, cc, off)) {
349 /* Flash rejected command */
350 if (ntry <= ST_RETRIES)
351 goto retry;
352 else
353 return -12;
355 } else if (sih->ccrev >= 20) {
356 W_REG(osh, &cc->flashaddress, off);
357 data = GET_BYTE(buf);
358 buf++;
359 W_REG(osh, &cc->flashdata, data);
360 /* Issue a page program with CSA bit set */
361 sflash_cmd(osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP);
362 ret = 1;
363 off++;
364 len--;
365 while (len > 0) {
366 if ((off & 255) == 0) {
367 /* Page boundary, poll droping cs and return */
368 W_REG(NULL, &cc->flashcontrol, 0);
369 OSL_DELAY(1);
370 if (sflash_poll(sih, cc, off) == 0) {
371 /* Flash rejected command */
372 SFL_MSG(("sflash: pp rejected, ntry: %d,"
373 " off: %d/%d, len: %d/%d, ret:"
374 "%d\n", ntry, off, offset, len,
375 length, ret));
376 if (ntry <= ST_RETRIES)
377 goto retry;
378 else
379 return -11;
381 return ret;
382 } else {
383 /* Write single byte */
384 data = GET_BYTE(buf);
385 buf++;
386 sflash_cmd(osh, cc, SFLASH_ST_CSA | data);
388 ret++;
389 off++;
390 len--;
392 /* All done, drop cs & poll */
393 W_REG(NULL, &cc->flashcontrol, 0);
394 OSL_DELAY(1);
395 if (sflash_poll(sih, cc, off) == 0) {
396 /* Flash rejected command */
397 SFL_MSG(("sflash: pp rejected, ntry: %d, off: %d/%d,"
398 " len: %d/%d, ret: %d\n",
399 ntry, off, offset, len, length, ret));
400 if (ntry <= ST_RETRIES)
401 goto retry;
402 else
403 return -12;
405 } else {
406 ret = 1;
407 W_REG(osh, &cc->flashaddress, off);
408 data = GET_BYTE(buf);
409 buf++;
410 W_REG(osh, &cc->flashdata, data);
411 /* Page program */
412 sflash_cmd(osh, cc, SFLASH_ST_PP);
414 break;
415 case SFLASH_AT:
416 mask = sfl->blocksize - 1;
417 page = (off & ~mask) << 1;
418 byte = off & mask;
419 /* Read main memory page into buffer 1 */
420 if (byte || (len < sfl->blocksize)) {
421 W_REG(osh, &cc->flashaddress, page);
422 sflash_cmd(osh, cc, SFLASH_AT_BUF1_LOAD);
423 /* 250 us for AT45DB321B */
424 SPINWAIT(sflash_poll(sih, cc, off), 1000);
425 ASSERT(!sflash_poll(sih, cc, off));
427 /* Write into buffer 1 */
428 for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
429 W_REG(osh, &cc->flashaddress, byte++);
430 W_REG(osh, &cc->flashdata, *buf++);
431 sflash_cmd(osh, cc, SFLASH_AT_BUF1_WRITE);
433 /* Write buffer 1 into main memory page */
434 W_REG(osh, &cc->flashaddress, page);
435 sflash_cmd(osh, cc, SFLASH_AT_BUF1_PROGRAM);
436 break;
439 return ret;
442 /* Erase a region. Returns number of bytes scheduled for erasure.
443 * Caller should poll for completion.
446 sflash_erase(si_t *sih, chipcregs_t *cc, uint offset)
448 struct sflash *sfl;
449 osl_t *osh;
451 ASSERT(sih);
453 osh = si_osh(sih);
455 sfl = &sflash;
456 if (offset >= sfl->size)
457 return -22;
459 switch (sfl->type) {
460 case SFLASH_ST:
461 sflash_cmd(osh, cc, SFLASH_ST_WREN);
462 W_REG(osh, &cc->flashaddress, offset);
463 sflash_cmd(osh, cc, SFLASH_ST_SE);
464 return sfl->blocksize;
465 case SFLASH_AT:
466 W_REG(osh, &cc->flashaddress, offset << 1);
467 sflash_cmd(osh, cc, SFLASH_AT_PAGE_ERASE);
468 return sfl->blocksize;
471 return 0;
475 * writes the appropriate range of flash, a NULL buf simply erases
476 * the region of flash
479 sflash_commit(si_t *sih, chipcregs_t *cc, uint offset, uint len, const uchar *buf)
481 struct sflash *sfl;
482 uchar *block = NULL, *cur_ptr, *blk_ptr;
483 uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
484 uint blk_offset, blk_len, copied;
485 int bytes, ret = 0;
486 osl_t *osh;
488 ASSERT(sih);
490 osh = si_osh(sih);
492 /* Check address range */
493 if (len <= 0)
494 return 0;
496 sfl = &sflash;
497 if ((offset + len) > sfl->size)
498 return -1;
500 blocksize = sfl->blocksize;
501 mask = blocksize - 1;
503 /* Allocate a block of mem */
504 if (!(block = MALLOC(osh, blocksize)))
505 return -1;
507 while (len) {
508 /* Align offset */
509 cur_offset = offset & ~mask;
510 cur_length = blocksize;
511 cur_ptr = block;
513 remainder = blocksize - (offset & mask);
514 if (len < remainder)
515 cur_retlen = len;
516 else
517 cur_retlen = remainder;
519 /* buf == NULL means erase only */
520 if (buf) {
521 /* Copy existing data into holding block if necessary */
522 if ((offset & mask) || (len < blocksize)) {
523 blk_offset = cur_offset;
524 blk_len = cur_length;
525 blk_ptr = cur_ptr;
527 /* Copy entire block */
528 while (blk_len) {
529 copied = sflash_read(sih, cc, blk_offset, blk_len, blk_ptr);
530 blk_offset += copied;
531 blk_len -= copied;
532 blk_ptr += copied;
536 /* Copy input data into holding block */
537 memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
540 /* Erase block */
541 if ((ret = sflash_erase(sih, cc, (uint) cur_offset)) < 0)
542 goto done;
543 while (sflash_poll(sih, cc, (uint) cur_offset));
545 /* buf == NULL means erase only */
546 if (!buf) {
547 offset += cur_retlen;
548 len -= cur_retlen;
549 continue;
552 /* Write holding block */
553 while (cur_length > 0) {
554 if ((bytes = sflash_write(sih, cc,
555 (uint) cur_offset,
556 (uint) cur_length,
557 (uchar *) cur_ptr)) < 0) {
558 ret = bytes;
559 goto done;
561 while (sflash_poll(sih, cc, (uint) cur_offset));
562 cur_offset += bytes;
563 cur_length -= bytes;
564 cur_ptr += bytes;
567 offset += cur_retlen;
568 len -= cur_retlen;
569 buf += cur_retlen;
572 ret = len;
573 done:
574 if (block)
575 MFREE(osh, block, blocksize);
576 return ret;