1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * Flash device driver File: dev_flash.c 5 * 6 * This driver supports various types of flash 7 * parts. You can also put the environment storage in 8 * the flash - the top sector is reserved for that purpose. 9 * 10 * Author: Mitch Lichtenberg 11 * 12 ********************************************************************* 13 * 14 * Copyright 2000,2001,2002,2003 15 * Broadcom Corporation. All rights reserved. 16 * 17 * This software is furnished under license and may be used and 18 * copied only in accordance with the following terms and 19 * conditions. Subject to these conditions, you may download, 20 * copy, install, use, modify and distribute modified or unmodified 21 * copies of this software in source and/or binary form. No title 22 * or ownership is transferred hereby. 23 * 24 * 1) Any source code used, modified or distributed must reproduce 25 * and retain this copyright notice and list of conditions 26 * as they appear in the source file. 27 * 28 * 2) No right is granted to use any trade name, trademark, or 29 * logo of Broadcom Corporation. The "Broadcom Corporation" 30 * name may not be used to endorse or promote products derived 31 * from this software without the prior written permission of 32 * Broadcom Corporation. 33 * 34 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 35 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 36 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 37 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 38 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 39 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 40 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 41 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 42 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 44 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 45 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 46 * THE POSSIBILITY OF SUCH DAMAGE. 47 ********************************************************************* */ 48 49 50#include "cfe.h" 51 52#include "dev_flash.h" 53 54/* ********************************************************************* 55 * Macros 56 ********************************************************************* */ 57 58#define FLASHCMD(sc,x,y) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+ \ 59 ((x)<<(sc)->flashdrv_widemode))) = (y) 60#define FLASHSTATUS(sc,x) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+ \ 61 ((x)<<(sc)->flashdrv_widemode))) 62 63#define WRITEFLASH_K1(sc,x,y) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+(x))) = (y) 64#define READFLASH_K1(sc,x) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+(x))) 65 66#define WRITEFLASH_K1W(sc,x,y) *((volatile unsigned short *)(sc->flashdrv_cmdaddr+(x))) = (y) 67#define READFLASH_K1W(sc,x) *((volatile unsigned short *)(sc->flashdrv_cmdaddr+(x))) 68 69 70#define GETCFIBYTE(softc,offset) READFLASH_K1(softc,((offset) << (softc->flashdrv_widemode))) 71 72/* ********************************************************************* 73 * Forward declarations 74 ********************************************************************* */ 75 76 77static void flashdrv_probe(cfe_driver_t *drv, 78 unsigned long probe_a, unsigned long probe_b, 79 void *probe_ptr); 80 81 82static int flashdrv_open(cfe_devctx_t *ctx); 83static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 84static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 85static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 86static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 87static int flashdrv_close(cfe_devctx_t *ctx); 88 89/* ********************************************************************* 90 * Device dispatch 91 ********************************************************************* */ 92 93const static cfe_devdisp_t flashdrv_dispatch = { 94 flashdrv_open, 95 flashdrv_read, 96 flashdrv_inpstat, 97 flashdrv_write, 98 flashdrv_ioctl, 99 flashdrv_close, 100 NULL, 101 NULL 102}; 103 104const cfe_driver_t flashdrv = { 105 "CFI flash", 106 "flash", 107 CFE_DEV_FLASH, 108 &flashdrv_dispatch, 109 flashdrv_probe 110}; 111 112 113/* ********************************************************************* 114 * Structures 115 ********************************************************************* */ 116 117typedef struct flash_cfidata_s { 118 unsigned int cfidata_cmdset; /* ID of primary command set */ 119 unsigned int cfidata_devif; /* device interface byte */ 120 unsigned int cfidata_size; /* probed device size */ 121} flash_cfidata_t; 122 123typedef struct flashops_s flashops_t; 124 125typedef struct flashdrv_s { 126 flash_probe_t flashdrv_probe; /* data from probe */ 127 int flashdrv_devsize; /* size reported by driver */ 128 unsigned char *flashdrv_cmdaddr; /* virtual address (K1) */ 129 int flashdrv_widemode; /* 1=wide flash in byte mode, 0=narrow flash */ 130 int flashdrv_initialized; /* true if we've probed already */ 131 flash_info_t flashdrv_info; 132 int flashdrv_nvram_ok; /* true if we can use as NVRAM */ 133 int flashdrv_unlocked; /* true if we can r/w past devsize */ 134 nvram_info_t flashdrv_nvraminfo; 135 flashops_t *flashdrv_ops; 136 flash_cfidata_t flashdrv_cfidata; 137} flashdrv_t; 138 139struct flashops_s { 140 int (*erasesector)(flashdrv_t *f,int offset); 141 int (*writeblk)(flashdrv_t *f,int offset,hsaddr_t buf,int len); 142}; 143 144/* ********************************************************************* 145 * Macros 146 ********************************************************************* */ 147 148#define FLASHOP_ERASE_SECTOR(softc,sect) (*((softc)->flashdrv_ops->erasesector))((softc),(sect)) 149#define FLASHOP_WRITE_BLOCK(softc,off,buf,len) (*((softc)->flashdrv_ops->writeblk))((softc),(off),(buf),(len)) 150 151/* ********************************************************************* 152 * forward declarations 153 ********************************************************************* */ 154 155 156static int flash_sector_query(flashdrv_t *softc,flash_sector_t *sector); 157 158static int amd_flash_write_block(flashdrv_t *softc,int offset,hsaddr_t buf,int len); 159static int amd_flash_erase_sector(flashdrv_t *softc,int offset); 160 161static int intel_flash_write_block(flashdrv_t *softc,int offset,hsaddr_t buf,int len); 162static int intel_flash_erase_sector(flashdrv_t *softc,int offset); 163 164static flashops_t amd_flashops = { 165 amd_flash_erase_sector, 166 amd_flash_write_block, 167}; 168 169static flashops_t intel_flashops = { 170 intel_flash_erase_sector, 171 intel_flash_write_block, 172}; 173 174#define FLASHOPS_DEFAULT amd_flashops 175 176 177 178/* ********************************************************************* 179 * Externs 180 ********************************************************************* */ 181 182extern void *flash_write_all_ptr; 183extern int flash_write_all_len; 184 185extern void _cfe_flushcache(int); 186 187 188#if 0 189/* ********************************************************************* 190 * jedec_flash_maufacturer(softc) 191 * 192 * Return the manufacturer ID for this flash part. 193 * 194 * Input parameters: 195 * softc - flash context 196 * 197 * Return value: 198 * nothing 199 ********************************************************************* */ 200 201static unsigned int jedec_flash_manufacturer(flashdrv_t *softc) 202{ 203 unsigned int res; 204 205 /* Do an "unlock write" sequence */ 206 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); 207 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2); 208 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL); 209 210 res = FLASHSTATUS(softc,FLASH_JEDEC_OFFSET_MFR) & 0xFF; 211 212 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_RESET); 213 214 return res; 215} 216 217/* ********************************************************************* 218 * jedec_flash_type(softc) 219 * 220 * Return the manufacturer's type for the flash 221 * 222 * Input parameters: 223 * softc - flash context 224 * 225 * Return value: 226 * nothing 227 ********************************************************************* */ 228static unsigned int jedec_flash_type(flashdrv_t *softc) 229{ 230 unsigned int res; 231 232 /* Do an "unlock write" sequence */ 233 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); 234 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2); 235 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL); 236 237 res = FLASHSTATUS(softc,FLASH_JEDEC_OFFSET_DEV) & 0xFF; 238 239 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_RESET); 240 241 return res; 242} 243 244#endif 245 246/* ********************************************************************* 247 * amd_flash_write_byte(softc,offset,val) 248 * 249 * Write a single byte to the flash. The sector that the flash 250 * byte is in should have been previously erased, or else this 251 * routine may hang. 252 * 253 * Input parameters: 254 * softc - flash context 255 * offset - distance in bytes into the flash 256 * val - byte to write 257 * 258 * Return value: 259 * 0 if ok 260 * else if flash could not be written 261 ********************************************************************* */ 262static inline int amd_flash_write_byte(flashdrv_t *softc,int offset, unsigned char val) 263{ 264 unsigned int value; 265 266 /* Do an "unlock write" sequence */ 267 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); 268 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2); 269 270 /* Send a program command */ 271 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_PROGRAM); 272 273 /* Write a byte */ 274 WRITEFLASH_K1(softc,offset,val); 275 276 for (;;) { 277 value = READFLASH_K1(softc,offset) & 0xFF; 278 279 if ((value & 0x80) == (val & 0x80)) { 280 return 0; 281 } 282 if ((value & 0x20) != 0x20) { 283 continue; 284 } 285 286 if ((READFLASH_K1(softc,offset) & 0x80) == (val & 0x80)) { 287 return 0; 288 } 289 else { 290 return -1; 291 } 292 } 293} 294 295 296/* ********************************************************************* 297 * amd_flash_write_block(softc,offset,val) 298 * 299 * Write a single byte to the flash. The sector that the flash 300 * byte is in should have been previously erased, or else this 301 * routine may hang. 302 * 303 * Input parameters: 304 * softc - flash context 305 * offset - distance in bytes into the flash 306 * buf - buffer of bytes to write 307 * len - number of bytes to write 308 * 309 * Return value: 310 * number of bytes written 311 ********************************************************************* */ 312static int amd_flash_write_block(flashdrv_t *softc,int offset,hsaddr_t buf,int len) 313{ 314 hsaddr_t ptr; 315 uint8_t b; 316 317 ptr = buf; 318 319 while (len) { 320 b = hs_read8(ptr); 321 if (amd_flash_write_byte(softc,offset,b) < 0) break; 322 len--; 323 ptr++; 324 offset++; 325 326 } 327 328 return (ptr - buf); 329} 330 331 332/* ********************************************************************* 333 * amd_flash_erase_sector(softc,offset) 334 * 335 * Erase a single sector in the flash device 336 * 337 * Input parameters: 338 * softc - device context 339 * offset - offset in flash of sector to erase 340 * 341 * Return value: 342 * 0 if ok, else error code 343 ********************************************************************* */ 344 345static int amd_flash_erase_sector(flashdrv_t *softc,int offset) 346{ 347 /* Do an "unlock write" sequence */ 348 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); /* cycles 1-2 */ 349 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2); 350 351 /* send the erase command */ 352 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_ERASE_3); /* cycle 3 */ 353 354 /* Do an "unlock write" sequence */ 355 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); /* cycles 4-5 */ 356 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2); 357 358 /* 359 * Send the "erase sector" qualifier - don't use FLASHCMD 360 * because it changes the offset. 361 */ 362 WRITEFLASH_K1(softc,offset,AMD_FLASH_ERASE_SEC_6); 363 364 while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) { 365 /* NULL LOOP */ 366 } 367 368 return 0; 369} 370 371 372 373/* ********************************************************************* 374 * intel_flash_write_byte(softc,offset,val) 375 * 376 * Write a single byte to the flash. The sector that the flash 377 * byte is in should have been previously erased, or else this 378 * routine may hang. 379 * 380 * Input parameters: 381 * softc - flash context 382 * offset - distance in bytes into the flash 383 * val - byte to write 384 * 385 * Return value: 386 * 0 if ok 387 * else if flash could not be written 388 ********************************************************************* */ 389static inline int intel_flash_write_byte(flashdrv_t *softc, 390 int offset, unsigned char val) 391{ 392 unsigned int value; 393 394 /* Send a program command */ 395 WRITEFLASH_K1(softc,offset,INTEL_FLASH_PROGRAM); 396 397 /* Write a byte */ 398 WRITEFLASH_K1(softc,offset,val); 399 400 401 while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) { 402 /* NULL LOOP */ 403 } 404 405 value = READFLASH_K1(softc,offset) & 0xFF; 406 407 if (value & (0x01|0x08|0x10)) return -1; 408 return 0; 409} 410 411/* ********************************************************************* 412 * intel_flash_write_word(softc,offset,val) 413 * 414 * Write a single word to the flash. The sector that the flash 415 * byte is in should have been previously erased, or else this 416 * routine may hang. 417 * 418 * Input parameters: 419 * softc - flash context 420 * offset - distance in bytes into the flash 421 * val - word to write 422 * 423 * Return value: 424 * 0 if ok 425 * else if flash could not be written 426 ********************************************************************* */ 427static inline int intel_flash_write_word(flashdrv_t *softc, 428 int offset, unsigned short val) 429{ 430 unsigned int value; 431 432 433 /* Send a program command */ 434 WRITEFLASH_K1W(softc,offset,INTEL_FLASH_PROGRAM); 435 436 /* Write a byte */ 437 WRITEFLASH_K1W(softc,offset,val); 438 439 440 while ((READFLASH_K1W(softc,offset) & 0x80) != 0x80) { 441 /* NULL LOOP */ 442 } 443 444 value = READFLASH_K1W(softc,offset) & 0xFF; 445 446 if (value & (0x01|0x08|0x10)) return -1; 447 return 0; 448} 449 450/* ********************************************************************* 451 * intel_flash_write_block(softc,offset,val) 452 * 453 * Write a single byte to the flash. The sector that the flash 454 * byte is in should have been previously erased, or else this 455 * routine may hang. 456 * 457 * Input parameters: 458 * softc - flash context 459 * offset - distance in bytes into the flash 460 * buf - buffer of bytes to write 461 * len - number of bytes to write 462 * 463 * Return value: 464 * number of bytes written 465 ********************************************************************* */ 466static int intel_flash_write_block(flashdrv_t *softc,int offset,hsaddr_t buf,int len) 467{ 468 hsaddr_t ptr; 469 uint8_t b; 470 uint16_t w; 471 472 ptr = buf; 473 474 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_16BIT) { 475 offset &= ~1; /* offset must be even */ 476 while (len > 0) { 477 w = hs_read16(ptr); 478 if (intel_flash_write_word(softc,offset,w) < 0) break; 479 len -= 2; 480 ptr += 2; 481 offset += 2; 482 } 483 WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE); 484 return (ptr - buf); 485 } 486 else { 487 while (len) { 488 b = hs_read8(ptr); 489 if (intel_flash_write_byte(softc,offset,b) < 0) break; 490 len--; 491 ptr++; 492 offset++; 493 } 494 WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE); 495 return (ptr - buf); 496 } 497 498} 499 500 501/* ********************************************************************* 502 * intel_flash_erase_sector(softc,offset) 503 * 504 * Erase a single sector on the flash device 505 * 506 * Input parameters: 507 * softc - device context 508 * offset - offset in flash of sector to erase 509 * 510 * Return value: 511 * 0 if ok, else error code 512 ********************************************************************* */ 513static int intel_flash_erase_sector(flashdrv_t *softc,int offset) 514{ 515 WRITEFLASH_K1(softc,offset,INTEL_FLASH_ERASE_BLOCK); 516 WRITEFLASH_K1(softc,offset,INTEL_FLASH_ERASE_CONFIRM); 517 518 while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) { 519 /* NULL LOOP */ 520 } 521 WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE); 522 523 return 0; 524} 525 526 527 528 529 530/* ********************************************************************* 531 * FLASH_ERASE_RANGE(softc,range) 532 * 533 * Erase a range of sectors 534 * 535 * Input parameters: 536 * softc - our flash 537 * range - range structure 538 * 539 * Return value: 540 * 0 if ok 541 * else error 542 ********************************************************************* */ 543 544static int flash_erase_range(flashdrv_t *softc,flash_range_t *range) 545{ 546 flash_sector_t sector; 547 int res; 548 549 if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) { 550 return CFE_ERR_UNSUPPORTED; 551 } 552 553 554 if (range->range_base+range->range_length > softc->flashdrv_devsize) { 555 return CFE_ERR_INV_PARAM; 556 } 557 558 res = 0; 559 560 sector.flash_sector_idx = 0; 561 562 for (;;) { 563 res = flash_sector_query(softc,§or); 564 if (res != 0) break; 565 if (sector.flash_sector_status == FLASH_SECTOR_INVALID) { 566 break; 567 } 568 569 if ((sector.flash_sector_offset >= range->range_base) && 570 (sector.flash_sector_offset < 571 (range->range_base+range->range_length-1))) { 572 573 if (softc->flashdrv_nvram_ok && 574 (sector.flash_sector_offset >= softc->flashdrv_nvraminfo.nvram_offset)) { 575 break; 576 } 577 res = FLASHOP_ERASE_SECTOR(softc,sector.flash_sector_offset); 578 if (res != 0) break; 579 } 580 sector.flash_sector_idx++; 581 } 582 583 return res; 584 585} 586 587/* ********************************************************************* 588 * FLASH_ERASE_ALL(softc) 589 * 590 * Erase the entire flash device, except the NVRAM area, 591 * sector-by-sector. 592 * 593 * Input parameters: 594 * softc - our flash 595 * 596 * Return value: 597 * 0 if ok 598 * else error code 599 ********************************************************************* */ 600 601static int flash_erase_all(flashdrv_t *softc) 602{ 603 flash_range_t range; 604 605 range.range_base = 0; 606 range.range_length = softc->flashdrv_devsize; 607 608 return flash_erase_range(softc,&range); 609} 610 611/* ********************************************************************* 612 * FLASH_CFI_GETSECTORS(softc) 613 * 614 * Query the CFI information and store the sector info in our 615 * private probe structure. 616 * 617 * Input parameters: 618 * softc - our flash info 619 * 620 * Return value: 621 * 0 if ok 622 * else error code 623 ********************************************************************* */ 624 625static int flash_cfi_getsectors(flashdrv_t *softc) 626{ 627 int idx; 628 int regcnt; 629 int nblks; 630 int blksiz; 631 632 regcnt = GETCFIBYTE(softc,FLASH_CFI_REGION_COUNT); 633 634 softc->flashdrv_probe.flash_nsectors = regcnt; 635 636 for (idx = 0; idx < regcnt; idx++) { 637 nblks = ((int)GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+0+idx*4) + 638 (int)(GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+1+idx*4)<<8)) + 1; 639 blksiz = ((int)GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+2+idx*4) + 640 (int)(GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+3+idx*4)<<8)) * 256; 641 softc->flashdrv_probe.flash_sectors[idx] = 642 FLASH_SECTOR_RANGE(nblks,blksiz); 643 } 644 645 646 return 0; 647} 648 649/* ********************************************************************* 650 * FLASH_SECTOR_QUERY(softc,sector) 651 * 652 * Query the sector information about a particular sector. You can 653 * call this iteratively to find out about all of the sectors. 654 * 655 * Input parameters: 656 * softc - our flash info 657 * sector - structure to receive sector information 658 * 659 * Return value: 660 * 0 if ok 661 * else error code 662 ********************************************************************* */ 663 664static int flash_sector_query(flashdrv_t *softc,flash_sector_t *sector) 665{ 666 int idx; 667 int nblks; 668 int blksiz; 669 unsigned int offset; 670 int curblk; 671 672 if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) { 673 return CFE_ERR_UNSUPPORTED; 674 } 675 676 if (softc->flashdrv_probe.flash_nsectors == 0) { 677 return CFE_ERR_UNSUPPORTED; 678 } 679 680 offset = 0; 681 curblk = 0; 682 for (idx = 0; idx < softc->flashdrv_probe.flash_nsectors; idx++) { 683 nblks = FLASH_SECTOR_NBLKS(softc->flashdrv_probe.flash_sectors[idx]); 684 blksiz = FLASH_SECTOR_SIZE(softc->flashdrv_probe.flash_sectors[idx]); 685 if (sector->flash_sector_idx < curblk+nblks) { 686 sector->flash_sector_status = FLASH_SECTOR_OK; 687 sector->flash_sector_offset = 688 offset + (sector->flash_sector_idx-curblk)*blksiz; 689 sector->flash_sector_size = blksiz; 690 break; 691 } 692 693 offset += (nblks)*blksiz; 694 curblk += nblks; 695 } 696 697 698 if (idx == softc->flashdrv_probe.flash_nsectors) { 699 sector->flash_sector_status = FLASH_SECTOR_INVALID; 700 } 701 702 return 0; 703} 704 705 706/* ********************************************************************* 707 * FLASH_SET_CMDSET(softc,cmdset) 708 * 709 * Set the command-set that we'll honor for this flash. 710 * 711 * Input parameters: 712 * softc - our flash 713 * cmdset - FLASH_CFI_CMDSET_xxx 714 * 715 * Return value: 716 * nothing 717 ********************************************************************* */ 718 719static void flash_set_cmdset(flashdrv_t *softc,int cmdset) 720{ 721 switch (cmdset) { 722 case FLASH_CFI_CMDSET_INTEL_ECS: 723 case FLASH_CFI_CMDSET_INTEL_STD: 724 softc->flashdrv_ops = &intel_flashops; 725 /* XXX: Intel flashes don't have the "a-1" line. Yay. */ 726 softc->flashdrv_widemode = 0; 727 break; 728 case FLASH_CFI_CMDSET_AMD_STD: 729 case FLASH_CFI_CMDSET_AMD_ECS: 730 softc->flashdrv_ops = &amd_flashops; 731 break; 732 default: 733 /* we don't understand the command set - treat it like ROM */ 734 softc->flashdrv_info.flash_type = FLASH_TYPE_ROM; 735 } 736} 737 738 739/* ********************************************************************* 740 * FLASH_CFI_PROBE(softc) 741 * 742 * Try to do a CFI query on this device. If we find the m 743 * magic signature, extract some useful information from the 744 * query structure. 745 * 746 * Input parameters: 747 * softc - out flash 748 * 749 * Return value: 750 * 0 if successful, <0 if error 751 ********************************************************************* */ 752static int flash_cfi_probe(flashdrv_t *softc) 753{ 754 FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_MODE); 755 756 if (!((GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+0) == 'Q') && 757 (GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+1) == 'R') && 758 (GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+2) == 'Y'))) { 759 760 FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT); 761 return CFE_ERR_UNSUPPORTED; 762 } 763 764 /* 765 * Gather info from flash 766 */ 767 768 softc->flashdrv_cfidata.cfidata_cmdset = 769 ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_COMMAND_SET))) + 770 (((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_COMMAND_SET+1))) << 8); 771 772 softc->flashdrv_cfidata.cfidata_devif = 773 ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_INTERFACE))) + 774 (((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_INTERFACE+1))) << 8); 775 776 softc->flashdrv_cfidata.cfidata_size = 777 1 << ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_SIZE))); 778 779 flash_cfi_getsectors(softc); 780 781 /* 782 * Don't need to be in query mode anymore. 783 */ 784 785 FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT); 786 787 softc->flashdrv_info.flash_type = FLASH_TYPE_FLASH; 788 789 flash_set_cmdset(softc,softc->flashdrv_cfidata.cfidata_cmdset); 790 791 return 0; 792 793} 794 795/* ********************************************************************* 796 * FLASH_GETWIDTH(softc,info) 797 * 798 * Try to determine the width of the flash. This is needed for 799 * management purposes, since some 16-bit flash parts in 8-bit mode 800 * have an "A-1" (address line -1) wire to select bytes within 801 * a 16-bit word. When this is present, the flash commands 802 * will have different offsets. 803 * 804 * Input parameters: 805 * softc - our flash 806 * info - flash info structure 807 * 808 * Return value: 809 * nothing 810 ********************************************************************* */ 811 812static void flash_getwidth(flashdrv_t *softc,flash_info_t *info) 813{ 814 softc->flashdrv_widemode = 0; /* first try narrow */ 815 816 if (flash_cfi_probe(softc) == 0) { 817 return; 818 } 819 820 softc->flashdrv_widemode = 1; /* then wide */ 821 822 if (flash_cfi_probe(softc) == 0) { 823 return; 824 } 825 826 /* Just return, assume not wide if no CFI interface */ 827 softc->flashdrv_widemode = 0; 828 829 softc->flashdrv_info.flash_type = FLASH_TYPE_ROM; /* no CFI: treat as ROM */ 830} 831 832/* ********************************************************************* 833 * flash_getinfo(softc) 834 * 835 * Try to determine if the specified region is flash, ROM, SRAM, 836 * or something else. 837 * 838 * Input parameters: 839 * softc - our context 840 * 841 * Return value: 842 * nothing 843 ********************************************************************* */ 844 845static void flash_getinfo(flashdrv_t *softc) 846{ 847 uint8_t save0,save1; 848 volatile uint8_t *ptr; 849 flash_info_t *info = &(softc->flashdrv_info); 850 851 /* 852 * Set up some defaults based on the probe data 853 */ 854 855 softc->flashdrv_widemode = 0; 856 info->flash_base = softc->flashdrv_probe.flash_phys; 857 info->flash_size = softc->flashdrv_probe.flash_size; 858 softc->flashdrv_devsize = softc->flashdrv_probe.flash_size; 859 info->flash_type = FLASH_TYPE_UNKNOWN; 860 info->flash_flags = 0; 861 862 /* 863 * If we've been told not to try probing, just assume 864 * we're a flash part. 865 */ 866 867 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_MANUAL) { 868 info->flash_type = FLASH_TYPE_FLASH; 869 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_WIDE) { 870 softc->flashdrv_widemode = TRUE; 871 } 872 if (softc->flashdrv_probe.flash_cmdset) { 873 flash_set_cmdset(softc,softc->flashdrv_probe.flash_cmdset); 874 } 875 return; 876 } 877 878 /* 879 * Attempt to read/write byte zero. If it is changable, 880 * this is SRAM (or maybe a ROM emulator with the write line hooked up) 881 */ 882 883 ptr = (volatile uint8_t *) UNCADDR(softc->flashdrv_probe.flash_phys); 884 save0 = *ptr; /* save old value */ 885 save1 = *(ptr+1); /* save old value */ 886 *(ptr) = 0x55; 887 if ((*ptr) == 0x55) { 888 *(ptr) = 0xAA; 889 if ((*ptr) == 0xAA) { 890 info->flash_type = FLASH_TYPE_SRAM; 891 } 892 } 893 894 if (*ptr == save0) info->flash_type = FLASH_TYPE_ROM; 895 else (*ptr) = save0; /* restore old value */ 896 897 /* 898 * If we thought it was ROM, try doing a CFI query 899 * to see if it was flash. This check is kind of kludgey 900 * but should work. 901 */ 902 903 if (info->flash_type == FLASH_TYPE_ROM) { 904 flash_getwidth(softc,info); 905 if (info->flash_type == FLASH_TYPE_FLASH) { 906 } 907 } 908} 909 910/* ********************************************************************* 911 * flashdrv_setup_nvram(softc) 912 * 913 * If we're going to be using a sector of the flash for NVRAM, 914 * go find that sector and set it up. 915 * 916 * Input parameters: 917 * softc - our flash 918 * 919 * Return value: 920 * nothing. flashdrv_nvram_ok might change though. 921 ********************************************************************* */ 922 923static void flashdrv_setup_nvram(flashdrv_t *softc) 924{ 925 flash_sector_t sector; 926 int res; 927 928 softc->flashdrv_nvram_ok = FALSE; 929 930 if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) { 931 return; 932 } 933 934 sector.flash_sector_idx = 0; 935 for (;;) { 936 res = flash_sector_query(softc,§or); 937 if (res == CFE_ERR_UNSUPPORTED) break; 938 if (res == 0) { 939 if (sector.flash_sector_status != FLASH_SECTOR_INVALID) { 940 sector.flash_sector_idx++; 941 continue; 942 } 943 } 944 break; 945 } 946 947 /* The sector offset will still contain the value at the end 948 of the last successful call. That's the last sector, so 949 we can now use this to fill in the NVRAM info structure */ 950 951 if (res != CFE_ERR_UNSUPPORTED) { 952 softc->flashdrv_nvraminfo.nvram_offset = sector.flash_sector_offset; 953 softc->flashdrv_nvraminfo.nvram_size = sector.flash_sector_size; 954 softc->flashdrv_nvraminfo.nvram_eraseflg = TRUE; /* needs erase */ 955 softc->flashdrv_nvram_ok = TRUE; 956 /* 957 * Set the flash's size as reported in the flash_info structure 958 * to be the size without the NVRAM sector at the end. 959 */ 960 softc->flashdrv_info.flash_size = sector.flash_sector_offset; 961 softc->flashdrv_devsize = sector.flash_sector_offset; 962 } 963 964} 965 966 967/* ********************************************************************* 968 * flashdrv_probe(drv,probe_a,probe_b,probe_ptr) 969 * 970 * Device probe routine. Attach the flash device to 971 * CFE's device table. 972 * 973 * Input parameters: 974 * drv - driver descriptor 975 * probe_a - physical address of flash 976 * probe_b - size of flash (bytes) 977 * probe_ptr - unused 978 * 979 * Return value: 980 * nothing 981 ********************************************************************* */ 982 983static void flashdrv_probe(cfe_driver_t *drv, 984 unsigned long probe_a, unsigned long probe_b, 985 void *probe_ptr) 986{ 987 flashdrv_t *softc; 988 flash_probe_t *probe; 989 char descr[80]; 990 991 probe = (flash_probe_t *) probe_ptr; 992 993 /* 994 * probe_a is the flash base address 995 * probe_b is the size of the flash 996 * probe_ptr is unused. 997 */ 998 999 softc = (flashdrv_t *) KMALLOC(sizeof(flashdrv_t),0); 1000 if (softc) { 1001 memset(softc,0,sizeof(flashdrv_t)); 1002 1003 if (probe) { 1004 /* Passed probe structure, do fancy stuff */ 1005 memcpy(&(softc->flashdrv_probe),probe,sizeof(flash_probe_t)); 1006 if (softc->flashdrv_probe.flash_prog_phys == 0) { 1007 softc->flashdrv_probe.flash_prog_phys = 1008 softc->flashdrv_probe.flash_phys; 1009 } 1010 } 1011 else { 1012 /* Didn't pass probe structure, do the compatible thing */ 1013 softc->flashdrv_probe.flash_phys = probe_a; 1014 softc->flashdrv_probe.flash_prog_phys = probe_a; 1015 softc->flashdrv_probe.flash_size = probe_b; 1016 softc->flashdrv_probe.flash_flags = FLASH_FLG_NVRAM; 1017 } 1018 1019 softc->flashdrv_cmdaddr = (char *) UNCADDR(softc->flashdrv_probe.flash_prog_phys); 1020 softc->flashdrv_initialized = 0; 1021 softc->flashdrv_ops = &FLASHOPS_DEFAULT; 1022 xsprintf(descr,"%s at %08X size %uKB",drv->drv_description, 1023 softc->flashdrv_probe.flash_phys, 1024 softc->flashdrv_probe.flash_size/1024); 1025 cfe_attach(drv,softc,NULL,descr); 1026 } 1027 1028} 1029 1030 1031/* ********************************************************************* 1032 * flashdrv_open(ctx) 1033 * 1034 * Called when the flash device is opened. 1035 * 1036 * Input parameters: 1037 * ctx - device context 1038 * 1039 * Return value: 1040 * 0 if ok else error code 1041 ********************************************************************* */ 1042 1043static int flashdrv_open(cfe_devctx_t *ctx) 1044{ 1045 flashdrv_t *softc = ctx->dev_softc; 1046 1047 /* 1048 * do initialization 1049 */ 1050 1051 if (!softc->flashdrv_initialized) { 1052 1053 /* 1054 * Assume it's not an NVRAM-capable flash 1055 */ 1056 1057 softc->flashdrv_nvram_ok = FALSE; 1058 1059 /* 1060 * Probe flash for geometry 1061 */ 1062 flash_getinfo(softc); 1063 1064 /* 1065 * Find the last sector if in NVRAM mode 1066 */ 1067 1068 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_NVRAM) { 1069 flashdrv_setup_nvram(softc); 1070 } 1071 1072 softc->flashdrv_initialized = TRUE; 1073 } 1074 1075 return 0; 1076} 1077 1078 1079/* ********************************************************************* 1080 * flashdrv_read(ctx,buffer) 1081 * 1082 * Read data from the flash device. The flash device is 1083 * considered to be like a disk (you need to specify the offset). 1084 * 1085 * Input parameters: 1086 * ctx - device context 1087 * buffer - buffer descriptor 1088 * 1089 * Return value: 1090 * 0 if ok, else error code 1091 ********************************************************************* */ 1092 1093static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 1094{ 1095 flashdrv_t *softc = ctx->dev_softc; 1096 hsaddr_t bptr; 1097 unsigned char *flashbase; 1098 int offset; 1099 int blen; 1100 1101 /* 1102 * For now, read the flash from K1 (always). Eventually 1103 * we need to flush the cache after a write. 1104 */ 1105 1106 flashbase = (unsigned char *) UNCADDR(softc->flashdrv_probe.flash_phys); 1107 1108 bptr = buffer->buf_ptr; 1109 blen = buffer->buf_length; 1110 offset = (int) buffer->buf_offset; 1111 1112 if (!(softc->flashdrv_unlocked)) { 1113 if ((offset + blen) > softc->flashdrv_devsize) { 1114 blen = softc->flashdrv_devsize - offset; 1115 } 1116 } 1117 1118#ifdef _FLASH_BROKEN_BYTEREAD_ 1119 /* 1120 * BCM1250 users: don't worry about this. This hack is for 1121 * something else and should not be used with the BCM1250. 1122 */ 1123 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_16BIT) { 1124 uint16_t *src; 1125 int len = blen; 1126 int idx = 0; 1127 union { 1128 uint16_t x; 1129 char b[2]; 1130 } u; 1131 1132 src = (uint16_t *) flashbase; 1133 while (len > 0) { 1134 u.x = src[(idx+offset)>>1]; 1135 hs_write8(bptr,u.b[(idx+offset)&1]); 1136 bptr++; 1137 len--; 1138 idx++; 1139 } 1140 } 1141 else { 1142 hs_memcpy_to_hs(bptr,flashbase + offset, blen); 1143 } 1144#else 1145 hs_memcpy_to_hs(bptr,flashbase + offset, blen); 1146#endif 1147 1148 buffer->buf_retlen = blen; 1149 1150 return 0; 1151} 1152 1153/* ********************************************************************* 1154 * flashdrv_inpstat(ctx,inpstat) 1155 * 1156 * Return "input status". For flash devices, we always return true. 1157 * 1158 * Input parameters: 1159 * ctx - device context 1160 * inpstat - input status structure 1161 * 1162 * Return value: 1163 * 0 if ok, else error code 1164 ********************************************************************* */ 1165 1166static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) 1167{ 1168 /* flashdrv_t *softc = ctx->dev_softc; */ 1169 1170 inpstat->inp_status = 1; 1171 return 0; 1172} 1173 1174 1175/* ********************************************************************* 1176 * flash_writeall(softc,buffer) 1177 * 1178 * Write the entire flash and reboot. This is a special case 1179 * used for when the flash currently being used for CFE's 1180 * execution is updated. A small assembly routine is relocated 1181 * to DRAM to do the update (so that the programming routine is 1182 * not erased while we're running it), and then the update 1183 * is done. When completed, CFE is restarted. 1184 * 1185 * (we could get really sleazy here and touch the routine first 1186 * so it will stay in the cache, thereby eliminating the need 1187 * to relocate it, but that's dangerous) 1188 * 1189 * Input parameters: 1190 * softc - our context 1191 * buffer - buffer descriptor 1192 * 1193 * Return value: 1194 * does not return 1195 ********************************************************************* */ 1196 1197static int flash_writeall(flashdrv_t *softc,iocb_buffer_t *buffer) 1198{ 1199 void *rptr; 1200 void (*routine)(hsaddr_t data,unsigned int flashbase, 1201 unsigned int size,unsigned int secsize); 1202 1203 rptr = KMALLOC(flash_write_all_len,0); 1204 1205 if (!rptr) return CFE_ERR_NOMEM; 1206 1207 memcpy(rptr,flash_write_all_ptr,flash_write_all_len); 1208 1209 _cfe_flushcache(0); 1210 1211 routine = rptr; 1212 1213 (*routine)(buffer->buf_ptr, 1214 softc->flashdrv_probe.flash_phys, 1215 buffer->buf_length, 1216 65536); 1217 1218 return -1; 1219} 1220 1221 1222/* ********************************************************************* 1223 * flashdrv_write(ctx,buffer) 1224 * 1225 * Write data to the flash device. The flash device is 1226 * considered to be like a disk (you need to specify the offset). 1227 * 1228 * Input parameters: 1229 * ctx - device context 1230 * buffer - buffer descriptor 1231 * 1232 * Return value: 1233 * 0 if ok, else error code 1234 ********************************************************************* */ 1235 1236static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 1237{ 1238 flashdrv_t *softc = ctx->dev_softc; 1239 hsaddr_t bptr; 1240 int offset; 1241 int blen; 1242 int res; 1243 1244 bptr = buffer->buf_ptr; 1245 blen = buffer->buf_length; 1246 offset = (int) buffer->buf_offset; 1247 1248 if (!(softc->flashdrv_unlocked)) { 1249 if ((offset + blen) > softc->flashdrv_devsize) { 1250 blen = softc->flashdrv_devsize - offset; 1251 } 1252 } 1253 1254 res = FLASHOP_WRITE_BLOCK(softc,offset,bptr,blen); 1255 1256 buffer->buf_retlen = res; 1257 1258 /* XXX flush the cache here? */ 1259 1260 return (res == blen) ? 0 : CFE_ERR_IOERR; 1261} 1262 1263/* ********************************************************************* 1264 * flashdrv_ioctl(ctx,buffer) 1265 * 1266 * Handle special IOCTL functions for the flash. Flash devices 1267 * support NVRAM information, sector and chip erase, and a 1268 * special IOCTL for updating the running copy of CFE. 1269 * 1270 * Input parameters: 1271 * ctx - device context 1272 * buffer - descriptor for IOCTL parameters 1273 * 1274 * Return value: 1275 * 0 if ok else error 1276 ********************************************************************* */ 1277static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 1278{ 1279 flashdrv_t *softc = ctx->dev_softc; 1280 nvram_info_t info; 1281 int offset; 1282 int ret; 1283 flash_sector_t fsect; 1284 flash_range_t frange; 1285 1286 /* 1287 * If using flash to store environment, only the last sector 1288 * is used for environment stuff. 1289 */ 1290 1291 switch ((int)buffer->buf_ioctlcmd) { 1292 case IOCTL_NVRAM_ERASE: 1293 if (softc->flashdrv_nvram_ok == FALSE) return CFE_ERR_UNSUPPORTED; 1294 FLASHOP_ERASE_SECTOR(softc,softc->flashdrv_nvraminfo.nvram_offset); 1295 return 0; 1296 1297 case IOCTL_NVRAM_GETINFO: 1298 if (buffer->buf_length != sizeof(nvram_info_t)) return CFE_ERR_INV_PARAM; 1299 if (softc->flashdrv_nvram_ok == FALSE) return CFE_ERR_UNSUPPORTED; 1300 info.nvram_offset = softc->flashdrv_nvraminfo.nvram_offset; 1301 info.nvram_size = softc->flashdrv_nvraminfo.nvram_size; 1302 info.nvram_eraseflg = softc->flashdrv_nvraminfo.nvram_eraseflg; 1303 hs_memcpy_to_hs(buffer->buf_ptr,&info,sizeof(nvram_info_t)); 1304 buffer->buf_retlen = sizeof(nvram_info_t); 1305 return 0; 1306 1307 case IOCTL_FLASH_ERASE_SECTOR: 1308 offset = (int) buffer->buf_offset; 1309 if (!(softc->flashdrv_unlocked)) { 1310 if (offset >= softc->flashdrv_devsize) return -1; 1311 } 1312 FLASHOP_ERASE_SECTOR(softc,offset); 1313 return 0; 1314 1315 case IOCTL_FLASH_ERASE_ALL: 1316 offset = (int) buffer->buf_offset; 1317 if (offset != 0) return -1; 1318 flash_erase_all(softc); 1319 return 0; 1320 1321 case IOCTL_FLASH_WRITE_ALL: 1322 flash_writeall(softc,buffer); 1323 return -1; /* should not return */ 1324 1325 case IOCTL_FLASH_GETINFO: 1326 hs_memcpy_to_hs(buffer->buf_ptr,&(softc->flashdrv_info),sizeof(flash_info_t)); 1327 return 0; 1328 1329 case IOCTL_FLASH_GETSECTORS: 1330 hs_memcpy_from_hs(&fsect,buffer->buf_ptr,sizeof(flash_sector_t)); 1331 ret = flash_sector_query(softc,&fsect); 1332 hs_memcpy_to_hs(buffer->buf_ptr,&fsect,sizeof(flash_sector_t)); 1333 return ret; 1334 1335 case IOCTL_FLASH_ERASE_RANGE: 1336 hs_memcpy_from_hs(&frange,buffer->buf_ptr,sizeof(flash_range_t)); 1337 ret = flash_erase_range(softc,&frange); 1338 hs_memcpy_to_hs(buffer->buf_ptr,&frange,sizeof(flash_range_t)); 1339 return ret; 1340 1341 case IOCTL_NVRAM_UNLOCK: 1342 softc->flashdrv_unlocked = TRUE; 1343 break; 1344 1345 default: 1346 return -1; 1347 } 1348 1349 return -1; 1350} 1351 1352 1353/* ********************************************************************* 1354 * flashdrv_close(ctx) 1355 * 1356 * Close the flash device. 1357 * 1358 * Input parameters: 1359 * ctx - device context 1360 * 1361 * Return value: 1362 * 0 1363 ********************************************************************* */ 1364static int flashdrv_close(cfe_devctx_t *ctx) 1365{ 1366 /* flashdrv_t *softc = ctx->dev_softc; */ 1367 1368 /* XXX Invalidate the cache */ 1369 1370 return 0; 1371} 1372 1373 1374