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