GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / shared / sflash.c
blob4097b5665411274e37a3baab33ccf03ea718b6a1
1 /*
2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
5 *
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.
9 *
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 345824 2012-07-19 06:29:12Z $
21 #include <bcm_cfg.h>
22 #include <typedefs.h>
23 #include <osl.h>
24 #include <bcmutils.h>
25 #include <siutils.h>
26 #include <hndsoc.h>
27 #include <sbhndcpu.h>
28 #include <sbchipc.h>
29 #include <bcmdevs.h>
30 #include <sflash.h>
32 #ifdef BCMDBG
33 #define SFL_MSG(args) printf args
34 #else
35 #define SFL_MSG(args)
36 #endif /* BCMDBG */
38 /* Private global state */
39 static struct sflash sflash;
41 /* Issue a serial flash command */
42 static INLINE void
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 */
52 struct sflash *
53 sflash_init(si_t *sih, chipcregs_t *cc)
55 uint32 id, id2;
56 const char *name = "";
57 osl_t *osh;
59 ASSERT(sih);
61 osh = si_osh(sih);
63 bzero(&sflash, sizeof(sflash));
65 sflash.type = sih->cccaps & CC_CAP_FLASH_MASK;
67 switch (sflash.type) {
68 case SFLASH_ST:
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;
76 switch (id) {
77 case 0x11:
78 /* ST M25P20 2 Mbit Serial Flash */
79 sflash.numblocks = 4;
80 break;
81 case 0x12:
82 /* ST M25P40 4 Mbit Serial Flash */
83 sflash.numblocks = 8;
84 break;
85 case 0x13:
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;
92 } else {
93 /* ST M25P80 8 Mbit Serial Flash */
94 sflash.numblocks = 16;
96 break;
97 case 0x14:
98 /* ST M25P16 16 Mbit Serial Flash */
99 sflash.numblocks = 32;
100 break;
101 case 0x15:
102 /* ST M25P32 32 Mbit Serial Flash */
103 sflash.numblocks = 64;
104 break;
105 case 0x16:
106 /* ST M25P64 64 Mbit Serial Flash */
107 sflash.numblocks = 128;
108 break;
109 case 0x17:
110 /* ST M25FL128 128 Mbit Serial Flash */
111 sflash.numblocks = 256;
112 break;
113 case 0xbf:
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.
119 name = "SST";
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);
124 switch (id2) {
125 case 1:
126 /* SST25WF512 512 Kbit Serial Flash */
127 sflash.numblocks = 16;
128 break;
129 case 0x48:
130 /* SST25VF512 512 Kbit Serial Flash */
131 sflash.numblocks = 16;
132 break;
133 case 2:
134 /* SST25WF010 1 Mbit Serial Flash */
135 sflash.numblocks = 32;
136 break;
137 case 0x49:
138 /* SST25VF010 1 Mbit Serial Flash */
139 sflash.numblocks = 32;
140 break;
141 case 3:
142 /* SST25WF020 2 Mbit Serial Flash */
143 sflash.numblocks = 64;
144 break;
145 case 0x43:
146 /* SST25VF020 2 Mbit Serial Flash */
147 sflash.numblocks = 64;
148 break;
149 case 4:
150 /* SST25WF040 4 Mbit Serial Flash */
151 sflash.numblocks = 128;
152 break;
153 case 0x44:
154 /* SST25VF040 4 Mbit Serial Flash */
155 sflash.numblocks = 128;
156 break;
157 case 0x8d:
158 /* SST25VF040B 4 Mbit Serial Flash */
159 sflash.numblocks = 128;
160 break;
161 case 5:
162 /* SST25WF080 8 Mbit Serial Flash */
163 sflash.numblocks = 256;
164 break;
165 case 0x8e:
166 /* SST25VF080B 8 Mbit Serial Flash */
167 sflash.numblocks = 256;
168 break;
169 case 0x41:
170 /* SST25VF016 16 Mbit Serial Flash */
171 sflash.numblocks = 512;
172 break;
173 case 0x4a:
174 /* SST25VF032 32 Mbit Serial Flash */
175 sflash.numblocks = 1024;
176 break;
177 case 0x4b:
178 /* SST25VF064 64 Mbit Serial Flash */
179 sflash.numblocks = 2048;
180 break;
182 break;
184 break;
186 case SFLASH_AT:
187 /* Probe for Atmel chips */
188 name = "Atmel";
189 sflash_cmd(osh, cc, SFLASH_AT_STATUS);
190 id = R_REG(osh, &cc->flashdata) & 0x3c;
191 switch (id) {
192 case 0xc:
193 /* Atmel AT45DB011 1Mbit Serial Flash */
194 sflash.blocksize = 256;
195 sflash.numblocks = 512;
196 break;
197 case 0x14:
198 /* Atmel AT45DB021 2Mbit Serial Flash */
199 sflash.blocksize = 256;
200 sflash.numblocks = 1024;
201 break;
202 case 0x1c:
203 /* Atmel AT45DB041 4Mbit Serial Flash */
204 sflash.blocksize = 256;
205 sflash.numblocks = 2048;
206 break;
207 case 0x24:
208 /* Atmel AT45DB081 8Mbit Serial Flash */
209 sflash.blocksize = 256;
210 sflash.numblocks = 4096;
211 break;
212 case 0x2c:
213 /* Atmel AT45DB161 16Mbit Serial Flash */
214 sflash.blocksize = 512;
215 sflash.numblocks = 4096;
216 break;
217 case 0x34:
218 /* Atmel AT45DB321 32Mbit Serial Flash */
219 sflash.blocksize = 512;
220 sflash.numblocks = 8192;
221 break;
222 case 0x3c:
223 /* Atmel AT45DB642 64Mbit Serial Flash */
224 sflash.blocksize = 1024;
225 sflash.numblocks = 8192;
226 break;
228 break;
231 sflash.size = sflash.blocksize * sflash.numblocks;
232 sflash.phybase = SI_FLASH2;
234 if (firsttime)
235 printf("Found an %s serial flash with %d %dKB blocks; total size %dMB\n",
236 name, sflash.numblocks, sflash.blocksize / 1024,
237 sflash.size / (1024 * 1024));
239 firsttime = FALSE;
240 return sflash.size ? &sflash : NULL;
243 /* Read len bytes starting at offset into buf. Returns number of bytes read. */
245 sflash_read(si_t *sih, chipcregs_t *cc, uint offset, uint len, uchar *buf)
247 uint8 *from, *to;
248 int cnt, i;
250 ASSERT(sih);
252 if (!len)
253 return 0;
255 if ((offset + len) > sflash.size)
256 return -22;
258 if ((len >= 4) && (offset & 3))
259 cnt = 4 - (offset & 3);
260 else if ((len >= 4) && ((uintptr)buf & 3))
261 cnt = 4 - ((uintptr)buf & 3);
262 else
263 cnt = len;
265 if (sih->ccrev == 12)
266 from = (uint8 *)OSL_UNCACHED((void *)SI_FLASH2 + offset);
267 else
268 from = (uint8 *)OSL_CACHED((void *)SI_FLASH2 + offset);
269 to = (uint8 *)buf;
271 if (cnt < 4) {
272 for (i = 0; i < cnt; i ++) {
273 /* Cannot use R_REG because in bigendian that will
274 * xor the address and we don't want that here.
276 *to = *from;
277 from ++;
278 to ++;
280 return cnt;
283 while (cnt >= 4) {
284 *(uint32 *)to = *(uint32 *)from;
285 from += 4;
286 to += 4;
287 cnt -= 4;
290 return (len - cnt);
293 /* Poll for command completion. Returns zero when complete. */
295 sflash_poll(si_t *sih, chipcregs_t *cc, uint offset)
297 osl_t *osh;
299 ASSERT(sih);
301 osh = si_osh(sih);
303 if (offset >= sflash.size)
304 return -22;
306 switch (sflash.type) {
307 case SFLASH_ST:
308 /* Check for ST Write In Progress bit */
309 sflash_cmd(osh, cc, SFLASH_ST_RDSR);
310 return R_REG(osh, &cc->flashdata) & SFLASH_ST_WIP;
311 case SFLASH_AT:
312 /* Check for Atmel Ready bit */
313 sflash_cmd(osh, cc, SFLASH_AT_STATUS);
314 return !(R_REG(osh, &cc->flashdata) & SFLASH_AT_READY);
317 return 0;
320 /* Write len bytes starting at offset into buf. Returns number of bytes
321 * written. Caller should poll for completion.
323 #define ST_RETRIES 3
325 #ifdef IL_BIGENDIAN
326 #ifdef BCMHND74K
327 #define GET_BYTE(ptr) (*(uint8 *)((uint32)(ptr) ^ 7))
328 #else /* !74K, bcm33xx */
329 #define GET_BYTE(ptr) (*(uint8 *)((uint32)(ptr) ^ 3))
330 #endif /* BCMHND74K */
331 #else /* !IL_BIGENDIAN */
332 #define GET_BYTE(ptr) (*(ptr))
333 #endif /* IL_BIGENDIAN */
336 sflash_write(si_t *sih, chipcregs_t *cc, uint offset, uint length, const uchar *buffer)
338 struct sflash *sfl;
339 uint off = offset, len = length;
340 const uint8 *buf = buffer;
341 uint8 data;
342 int ret = 0, ntry = 0;
343 bool is4712b0;
344 uint32 page, byte, mask;
345 osl_t *osh;
347 ASSERT(sih);
349 osh = si_osh(sih);
351 if (!len)
352 return 0;
354 sfl = &sflash;
355 if ((off + len) > sfl->size)
356 return -22;
358 switch (sfl->type) {
359 case SFLASH_ST:
360 is4712b0 = (CHIPID(sih->chip) == BCM4712_CHIP_ID) && (CHIPREV(sih->chiprev) == 3);
361 /* Enable writes */
362 retry: sflash_cmd(osh, cc, SFLASH_ST_WREN);
363 off = offset;
364 len = length;
365 buf = buffer;
366 ntry++;
367 if (is4712b0) {
368 mask = 1 << 14;
369 W_REG(osh, &cc->flashaddress, off);
370 data = GET_BYTE(buf);
371 buf++;
372 W_REG(osh, &cc->flashdata, data);
373 /* Set chip select */
374 OR_REG(osh, &cc->gpioout, mask);
375 /* Issue a page program with the first byte */
376 sflash_cmd(osh, cc, SFLASH_ST_PP);
377 ret = 1;
378 off++;
379 len--;
380 while (len > 0) {
381 if ((off & 255) == 0) {
382 /* Page boundary, drop cs and return */
383 AND_REG(osh, &cc->gpioout, ~mask);
384 OSL_DELAY(1);
385 if (!sflash_poll(sih, cc, off)) {
386 /* Flash rejected command */
387 if (ntry <= ST_RETRIES)
388 goto retry;
389 else
390 return -11;
392 return ret;
393 } else {
394 /* Write single byte */
395 data = GET_BYTE(buf);
396 buf++;
397 sflash_cmd(osh, cc, data);
399 ret++;
400 off++;
401 len--;
403 /* All done, drop cs */
404 AND_REG(osh, &cc->gpioout, ~mask);
405 OSL_DELAY(1);
406 if (!sflash_poll(sih, cc, off)) {
407 /* Flash rejected command */
408 if (ntry <= ST_RETRIES)
409 goto retry;
410 else
411 return -12;
413 } else if (sih->ccrev >= 20) {
414 W_REG(osh, &cc->flashaddress, off);
415 data = GET_BYTE(buf);
416 buf++;
417 W_REG(osh, &cc->flashdata, data);
418 /* Issue a page program with CSA bit set */
419 sflash_cmd(osh, cc, SFLASH_ST_CSA | SFLASH_ST_PP);
420 ret = 1;
421 off++;
422 len--;
423 while (len > 0) {
424 if ((off & 255) == 0) {
425 /* Page boundary, poll droping cs and return */
426 W_REG(NULL, &cc->flashcontrol, 0);
427 OSL_DELAY(1);
428 if (sflash_poll(sih, cc, off) == 0) {
429 /* Flash rejected command */
430 SFL_MSG(("sflash: pp rejected, ntry: %d,"
431 " off: %d/%d, len: %d/%d, ret:"
432 "%d\n", ntry, off, offset, len,
433 length, ret));
434 if (ntry <= ST_RETRIES)
435 goto retry;
436 else
437 return -11;
439 return ret;
440 } else {
441 /* Write single byte */
442 data = GET_BYTE(buf);
443 buf++;
444 sflash_cmd(osh, cc, SFLASH_ST_CSA | data);
446 ret++;
447 off++;
448 len--;
450 /* All done, drop cs & poll */
451 W_REG(NULL, &cc->flashcontrol, 0);
452 OSL_DELAY(1);
453 if (sflash_poll(sih, cc, off) == 0) {
454 /* Flash rejected command */
455 SFL_MSG(("sflash: pp rejected, ntry: %d, off: %d/%d,"
456 " len: %d/%d, ret: %d\n",
457 ntry, off, offset, len, length, ret));
458 if (ntry <= ST_RETRIES)
459 goto retry;
460 else
461 return -12;
463 } else {
464 ret = 1;
465 W_REG(osh, &cc->flashaddress, off);
466 data = GET_BYTE(buf);
467 buf++;
468 W_REG(osh, &cc->flashdata, data);
469 /* Page program */
470 sflash_cmd(osh, cc, SFLASH_ST_PP);
472 break;
473 case SFLASH_AT:
474 mask = sfl->blocksize - 1;
475 page = (off & ~mask) << 1;
476 byte = off & mask;
477 /* Read main memory page into buffer 1 */
478 if (byte || (len < sfl->blocksize)) {
479 W_REG(osh, &cc->flashaddress, page);
480 sflash_cmd(osh, cc, SFLASH_AT_BUF1_LOAD);
481 /* 250 us for AT45DB321B */
482 SPINWAIT(sflash_poll(sih, cc, off), 1000);
483 ASSERT(!sflash_poll(sih, cc, off));
485 /* Write into buffer 1 */
486 for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
487 W_REG(osh, &cc->flashaddress, byte++);
488 W_REG(osh, &cc->flashdata, *buf++);
489 sflash_cmd(osh, cc, SFLASH_AT_BUF1_WRITE);
491 /* Write buffer 1 into main memory page */
492 W_REG(osh, &cc->flashaddress, page);
493 sflash_cmd(osh, cc, SFLASH_AT_BUF1_PROGRAM);
494 break;
497 return ret;
500 /* Erase a region. Returns number of bytes scheduled for erasure.
501 * Caller should poll for completion.
504 sflash_erase(si_t *sih, chipcregs_t *cc, uint offset)
506 struct sflash *sfl;
507 osl_t *osh;
509 ASSERT(sih);
511 osh = si_osh(sih);
513 sfl = &sflash;
514 if (offset >= sfl->size)
515 return -22;
517 switch (sfl->type) {
518 case SFLASH_ST:
519 sflash_cmd(osh, cc, SFLASH_ST_WREN);
520 W_REG(osh, &cc->flashaddress, offset);
521 /* Newer flashes have "sub-sectors" which can be erased independently
522 * with a new command: ST_SSE. The ST_SE command erases 64KB just as
523 * before.
525 sflash_cmd(osh, cc, (sfl->blocksize < (64 * 1024)) ? SFLASH_ST_SSE : SFLASH_ST_SE);
526 return sfl->blocksize;
527 case SFLASH_AT:
528 W_REG(osh, &cc->flashaddress, offset << 1);
529 sflash_cmd(osh, cc, SFLASH_AT_PAGE_ERASE);
530 return sfl->blocksize;
533 return 0;
537 * writes the appropriate range of flash, a NULL buf simply erases
538 * the region of flash
541 sflash_commit(si_t *sih, chipcregs_t *cc, uint offset, uint len, const uchar *buf)
543 struct sflash *sfl;
544 uchar *block = NULL, *cur_ptr, *blk_ptr;
545 uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
546 uint blk_offset, blk_len, copied;
547 int bytes, ret = 0;
548 osl_t *osh;
550 ASSERT(sih);
552 osh = si_osh(sih);
554 /* Check address range */
555 if (len <= 0)
556 return 0;
558 sfl = &sflash;
559 if ((offset + len) > sfl->size)
560 return -1;
562 blocksize = sfl->blocksize;
563 mask = blocksize - 1;
565 /* Allocate a block of mem */
566 if (!(block = MALLOC(osh, blocksize)))
567 return -1;
569 while (len) {
570 /* Align offset */
571 cur_offset = offset & ~mask;
572 cur_length = blocksize;
573 cur_ptr = block;
575 remainder = blocksize - (offset & mask);
576 if (len < remainder)
577 cur_retlen = len;
578 else
579 cur_retlen = remainder;
581 /* buf == NULL means erase only */
582 if (buf) {
583 /* Copy existing data into holding block if necessary */
584 if ((offset & mask) || (len < blocksize)) {
585 blk_offset = cur_offset;
586 blk_len = cur_length;
587 blk_ptr = cur_ptr;
589 /* Copy entire block */
590 while (blk_len) {
591 copied = sflash_read(sih, cc, blk_offset, blk_len, blk_ptr);
592 blk_offset += copied;
593 blk_len -= copied;
594 blk_ptr += copied;
598 /* Copy input data into holding block */
599 memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
602 /* Erase block */
603 if ((ret = sflash_erase(sih, cc, (uint) cur_offset)) < 0)
604 goto done;
605 while (sflash_poll(sih, cc, (uint) cur_offset));
607 /* buf == NULL means erase only */
608 if (!buf) {
609 offset += cur_retlen;
610 len -= cur_retlen;
611 continue;
614 /* Write holding block */
615 while (cur_length > 0) {
616 if ((bytes = sflash_write(sih, cc,
617 (uint) cur_offset,
618 (uint) cur_length,
619 (uchar *) cur_ptr)) < 0) {
620 ret = bytes;
621 goto done;
623 while (sflash_poll(sih, cc, (uint) cur_offset));
624 cur_offset += bytes;
625 cur_length -= bytes;
626 cur_ptr += bytes;
629 offset += cur_retlen;
630 len -= cur_retlen;
631 buf += cur_retlen;
634 ret = len;
635 done:
636 if (block)
637 MFREE(osh, block, blocksize);
638 return ret;