1/* 2 * Broadcom SiliconBackplane chipcommon serial flash interface 3 * 4 * Copyright (C) 2015, 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. 17 * 18 * $Id: sflash.c 345826 2012-07-19 06:34:55Z $ 19 */ 20 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> 31 32#ifdef BCMDBG 33#define SFL_MSG(args) printf args 34#else 35#define SFL_MSG(args) 36#endif /* BCMDBG */ 37 38/* Private global state */ 39static struct sflash sflash; 40 41/* Issue a serial flash command */ 42static INLINE void 43sflash_cmd(osl_t *osh, chipcregs_t *cc, uint opcode) 44{ 45 W_REG(osh, &cc->flashcontrol, SFLASH_START | opcode); 46 while (R_REG(osh, &cc->flashcontrol) & SFLASH_BUSY); 47} 48 49static bool firsttime = TRUE; 50 51/* Initialize serial flash access */ 52struct sflash * 53sflash_init(si_t *sih, chipcregs_t *cc) 54{ 55 uint32 id, id2; 56 const char *name = ""; 57 osl_t *osh; 58 59 ASSERT(sih); 60 61 osh = si_osh(sih); 62 63 bzero(&sflash, sizeof(sflash)); 64 65 sflash.type = sih->cccaps & CC_CAP_FLASH_MASK; 66 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; 95 } 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. 118 */ 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; 181 } 182 break; 183 } 184 break; 185 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; 227 } 228 break; 229 } 230 231 sflash.size = sflash.blocksize * sflash.numblocks; 232 sflash.phybase = SI_FLASH2; 233 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)); 238 239 firsttime = FALSE; 240 return sflash.size ? &sflash : NULL; 241} 242 243/* Read len bytes starting at offset into buf. Returns number of bytes read. */ 244int 245sflash_read(si_t *sih, chipcregs_t *cc, uint offset, uint len, uchar *buf) 246{ 247 uint8 *from, *to; 248 int cnt, i; 249 250 ASSERT(sih); 251 252 if (!len) 253 return 0; 254 255 if ((offset + len) > sflash.size) 256 return -22; 257 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; 264 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; 270 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. 275 */ 276 *to = *from; 277 from ++; 278 to ++; 279 } 280 return cnt; 281 } 282 283 while (cnt >= 4) { 284 *(uint32 *)to = *(uint32 *)from; 285 from += 4; 286 to += 4; 287 cnt -= 4; 288 } 289 290 return (len - cnt); 291} 292 293/* Poll for command completion. Returns zero when complete. */ 294int 295sflash_poll(si_t *sih, chipcregs_t *cc, uint offset) 296{ 297 osl_t *osh; 298 299 ASSERT(sih); 300 301 osh = si_osh(sih); 302 303 if (offset >= sflash.size) 304 return -22; 305 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); 315 } 316 317 return 0; 318} 319 320/* Write len bytes starting at offset into buf. Returns number of bytes 321 * written. Caller should poll for completion. 322 */ 323#define ST_RETRIES 3 324 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 */ 334 335int 336sflash_write(si_t *sih, chipcregs_t *cc, uint offset, uint length, const uchar *buffer) 337{ 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; 346 347 ASSERT(sih); 348 349 osh = si_osh(sih); 350 351 if (!len) 352 return 0; 353 354 sfl = &sflash; 355 if ((off + len) > sfl->size) 356 return -22; 357 358 switch (sfl->type) { 359 case SFLASH_ST: 360 is4712b0 = (CHIPID(sih->chip) == BCM4712_CHIP_ID) && (CHIPREV(sih->chiprev) == 3); 361 /* Enable writes */ 362retry: 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; 391 } 392 return ret; 393 } else { 394 /* Write single byte */ 395 data = GET_BYTE(buf); 396 buf++; 397 sflash_cmd(osh, cc, data); 398 } 399 ret++; 400 off++; 401 len--; 402 } 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; 412 } 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; 438 } 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); 445 } 446 ret++; 447 off++; 448 len--; 449 } 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; 462 } 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); 471 } 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)); 484 } 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); 490 } 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; 495 } 496 497 return ret; 498} 499 500/* Erase a region. Returns number of bytes scheduled for erasure. 501 * Caller should poll for completion. 502 */ 503int 504sflash_erase(si_t *sih, chipcregs_t *cc, uint offset) 505{ 506 struct sflash *sfl; 507 osl_t *osh; 508 509 ASSERT(sih); 510 511 osh = si_osh(sih); 512 513 sfl = &sflash; 514 if (offset >= sfl->size) 515 return -22; 516 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. 524 */ 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; 531 } 532 533 return 0; 534} 535 536/* 537 * writes the appropriate range of flash, a NULL buf simply erases 538 * the region of flash 539 */ 540int 541sflash_commit(si_t *sih, chipcregs_t *cc, uint offset, uint len, const uchar *buf) 542{ 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; 549 550 ASSERT(sih); 551 552 osh = si_osh(sih); 553 554 /* Check address range */ 555 if (len <= 0) 556 return 0; 557 558 sfl = &sflash; 559 if ((offset + len) > sfl->size) 560 return -1; 561 562 blocksize = sfl->blocksize; 563 mask = blocksize - 1; 564 565 /* Allocate a block of mem */ 566 if (!(block = MALLOC(osh, blocksize))) 567 return -1; 568 569 while (len) { 570 /* Align offset */ 571 cur_offset = offset & ~mask; 572 cur_length = blocksize; 573 cur_ptr = block; 574 575 remainder = blocksize - (offset & mask); 576 if (len < remainder) 577 cur_retlen = len; 578 else 579 cur_retlen = remainder; 580 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; 588 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; 595 } 596 } 597 598 /* Copy input data into holding block */ 599 memcpy(cur_ptr + (offset & mask), buf, cur_retlen); 600 } 601 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)); 606 607 /* buf == NULL means erase only */ 608 if (!buf) { 609 offset += cur_retlen; 610 len -= cur_retlen; 611 continue; 612 } 613 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; 622 } 623 while (sflash_poll(sih, cc, (uint) cur_offset)); 624 cur_offset += bytes; 625 cur_length -= bytes; 626 cur_ptr += bytes; 627 } 628 629 offset += cur_retlen; 630 len -= cur_retlen; 631 buf += cur_retlen; 632 } 633 634 ret = len; 635done: 636 if (block) 637 MFREE(osh, block, blocksize); 638 return ret; 639} 640