1/* ********************************************************************* 2 * Broadcom Common Firmware Environment (CFE) 3 * 4 * "New" Flash device driver File: dev_newflash.c 5 * 6 * This driver supports various types of flash 7 * parts. 8 * 9 * Author: Mitch Lichtenberg (mpl@broadcom.com) 10 * 11 ********************************************************************* 12 * 13 * Copyright 2000,2001,2002,2003 14 * Broadcom Corporation. All rights reserved. 15 * 16 * This software is furnished under license and may be used and 17 * copied only in accordance with the following terms and 18 * conditions. Subject to these conditions, you may download, 19 * copy, install, use, modify and distribute modified or unmodified 20 * copies of this software in source and/or binary form. No title 21 * or ownership is transferred hereby. 22 * 23 * 1) Any source code used, modified or distributed must reproduce 24 * and retain this copyright notice and list of conditions 25 * as they appear in the source file. 26 * 27 * 2) No right is granted to use any trade name, trademark, or 28 * logo of Broadcom Corporation. The "Broadcom Corporation" 29 * name may not be used to endorse or promote products derived 30 * from this software without the prior written permission of 31 * Broadcom Corporation. 32 * 33 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR 34 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED 35 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 36 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 37 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 38 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, 39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 40 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 43 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 44 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 45 * THE POSSIBILITY OF SUCH DAMAGE. 46 ********************************************************************* */ 47 48 49#include "lib_types.h" 50#include "lib_malloc.h" 51#include "lib_printf.h" 52#include "lib_string.h" 53#include "addrspace.h" 54#include "cfe_iocb.h" 55#include "cfe_device.h" 56#include "cfe_ioctl.h" 57#include "cfe_error.h" 58 59#include "bsp_config.h" 60#include "dev_newflash.h" 61 62/* ********************************************************************* 63 * Macros 64 ********************************************************************* */ 65 66#define min(a,b) ((a) < (b) ? (a) : (b)) 67#define max(a,b) ((a) > (b) ? (a) : (b)) 68 69/* 70 * Get the address of the flash sector buffer from the 71 * config file. Addresses are PHYSICAL. 72 */ 73 74#ifndef CFG_FLASH_SECTOR_BUFFER_ADDR 75#define CFG_FLASH_SECTOR_BUFFER_ADDR (100*1024*1024-128*1024) 76#endif 77 78#ifndef CFG_FLASH_SECTOR_BUFFER_SIZE 79#define CFG_FLASH_SECTOR_BUFFER_SIZE (128*1024) 80#endif 81 82 83/*#define _NEWFLASH_DEBUG_ */ 84 85/* ********************************************************************* 86 * Forward declarations 87 ********************************************************************* */ 88 89 90static void flashdrv_probe(cfe_driver_t *drv, 91 unsigned long probe_a, unsigned long probe_b, 92 void *probe_ptr); 93 94 95static int flashdrv_open(cfe_devctx_t *ctx); 96static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 97static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat); 98static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 99static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer); 100static int flashdrv_close(cfe_devctx_t *ctx); 101 102/* ********************************************************************* 103 * Device dispatch 104 ********************************************************************* */ 105 106const static cfe_devdisp_t flashdrv_dispatch = { 107 flashdrv_open, 108 flashdrv_read, 109 flashdrv_inpstat, 110 flashdrv_write, 111 flashdrv_ioctl, 112 flashdrv_close, 113 NULL, 114 NULL 115}; 116 117const cfe_driver_t newflashdrv = { 118 "New CFI flash", 119 "flash", 120 CFE_DEV_FLASH, 121 &flashdrv_dispatch, 122 flashdrv_probe 123}; 124 125 126 127/* ********************************************************************* 128 * Externs 129 ********************************************************************* */ 130 131extern void *flashop_engine_ptr; 132extern int flashop_engine_len; 133 134extern void _cfe_flushcache(int); 135 136static int flash_sector_query(flashdev_t *softc,flash_sector_t *sector); 137 138/* ********************************************************************* 139 * Globals 140 ********************************************************************* */ 141 142/* 143 * This is a pointer to a DRAM version of our flash subroutines. 144 * We make a global here so that it doesn't get copied multiple 145 * times for each flash we instantiate. 146 */ 147 148static int (*flashop_engine_ram)(flashinstr_t *prog) = NULL; 149static uint8_t *flash_sector_buffer = NULL; 150 151/* ********************************************************************* 152 * FLASH_OP_BEGIN(softc) 153 * 154 * Reset the pointer to the flash operations so that we can 155 * begin filling in new instructions to execute 156 * 157 * Input parameters: 158 * softc - our softc. 159 * 160 * Return value: 161 * nothing 162 ********************************************************************* */ 163 164#define flash_op_begin(softc) softc->fd_iptr = 0; 165 166/* ********************************************************************* 167 * FLASH_OP_ADD(softc,op,dest,src,cnt) 168 * 169 * Add an instruction to the flashop table 170 * 171 * Input parameters: 172 * softc - our flash 173 * op,dest,src,cnt - data for the opcode 174 * 175 * Return value: 176 * nothing 177 ********************************************************************* */ 178 179static void flash_op_add(flashdev_t *softc,long base,long op,long dest,long src,long cnt) 180{ 181 flashinstr_t *fi = &(softc->fd_inst[softc->fd_iptr]); 182 183 fi->fi_op = op; 184 fi->fi_base = base; 185 fi->fi_dest = dest; 186 fi->fi_src = src; 187 fi->fi_cnt = cnt; 188 189 softc->fd_iptr++; 190} 191 192 193/* ********************************************************************* 194 * FLASH_OP_EXECUTE(softc) 195 * 196 * Execute the stored "flash operations" 197 * 198 * Input parameters: 199 * softc - our flash 200 * 201 * Return value: 202 * 0 if ok, else # of failures (less than zero) 203 ********************************************************************* */ 204 205static int flash_op_execute(flashdev_t *softc) 206{ 207 flash_op_add(softc,softc->fd_probe.flash_phys,FEOP_RETURN,0,0,0); 208 209#ifdef _NEWFLASH_DEBUG_ 210 if (1) { 211 int idx; 212 printf("---------------\nCalling engine @ %08X\n",flashop_engine_ram); 213 for (idx = 0; idx < softc->fd_iptr; idx++) { 214 printf("%2d %08X %08X %08X %08X\n", 215 softc->fd_inst[idx].fi_op, 216 softc->fd_inst[idx].fi_base, 217 softc->fd_inst[idx].fi_dest, 218 softc->fd_inst[idx].fi_src, 219 softc->fd_inst[idx].fi_cnt); 220 } 221 } 222#endif 223 224 /* 225 * If someone hooked the flashop engine, call the hook. 226 */ 227 if (softc->fd_probe.flash_engine_hook) { 228 return (*(softc->fd_probe.flash_engine_hook))(&(softc->fd_inst[0])); 229 } 230 231 /* 232 * Otherwise, call the standard one. 233 */ 234 if (!flashop_engine_ram) return CFE_ERR_UNSUPPORTED; 235 return (*flashop_engine_ram)(&(softc->fd_inst[0])); 236} 237 238 239/* ********************************************************************* 240 * FLASH_SETUP_ENGINE() 241 * 242 * Set up the "flash engine", copying the routine to DRAM 243 * and flushing the cache so we can call it. 244 * 245 * Input parameters: 246 * nothing 247 * 248 * Return value: 249 * nothing 250 ********************************************************************* */ 251 252static void flash_setup_engine(void) 253{ 254#if ((CFG_RAMAPP) || (CFG_EMBEDDED_PIC) || (CFG_CFLASH)) 255 /* CFE is relocated, no need to copy flash engine to heap */ 256 flashop_engine_ram = (void *) flashop_engine_ptr; 257#else 258 /* Copy flash engine to heap */ 259 uint32_t *dst,*src; 260 int idx; 261 262 if (flashop_engine_ram) return; /* already done */ 263 264 /* 265 * Allocate space for engine 266 */ 267 268 flashop_engine_ram = (void *) KMALLOC(flashop_engine_len,0); 269 if (!flashop_engine_ram) return; 270 271 /* 272 * Copy engine to RAM - do it 32-bits at a time to avoid 273 * a certain platform with broken byte reads (no, not the 1250) 274 */ 275 276 dst = (uint32_t *) flashop_engine_ram; 277 src = (uint32_t *) flashop_engine_ptr; 278 for (idx = 0; idx < flashop_engine_len/sizeof(uint32_t); idx++) { 279 *dst++ = *src++; 280 } 281 282 /* 283 * Flush the d-cache, invalidate the I-cache. 284 */ 285 286 _cfe_flushcache(1); 287 _cfe_flushcache(2); 288#endif 289} 290 291/* ********************************************************************* 292 * FLASH_ERASE_RANGE(softc,range) 293 * 294 * Erase a range of sectors 295 * 296 * Input parameters: 297 * softc - our flash 298 * range - range structure 299 * 300 * Return value: 301 * 0 if ok 302 * else error 303 ********************************************************************* */ 304 305static int flash_erase_range(flashdev_t *softc,flash_range_t *range) 306{ 307 flash_sector_t sector; 308 int res; 309 310 if (softc->fd_probe.flash_type != FLASH_TYPE_FLASH) { 311 return CFE_ERR_UNSUPPORTED; 312 } 313 314 if (range->range_base+range->range_length > softc->fd_probe.flash_size) { 315 return CFE_ERR_INV_PARAM; 316 } 317 318 res = 0; 319 320 sector.flash_sector_idx = 0; 321 322 for (;;) { 323 res = flash_sector_query(softc,§or); 324 if (res != 0) break; 325 if (sector.flash_sector_status == FLASH_SECTOR_INVALID) { 326 break; 327 } 328 329 if ((sector.flash_sector_offset >= range->range_base) && 330 (sector.flash_sector_offset < 331 (range->range_base+range->range_length-1))) { 332 333 flash_op_begin(softc); 334 flash_op_add(softc,softc->fd_probe.flash_phys, 335 softc->fd_erasefunc, 336 sector.flash_sector_offset, 337 0,0); 338 res = flash_op_execute(softc); 339 340 if (res != 0) break; 341 } 342 sector.flash_sector_idx++; 343 } 344 345 return res; 346 347} 348 349/* ********************************************************************* 350 * FLASH_ERASE_ALL(softc) 351 * 352 * Erase the entire flash device, except the NVRAM area, 353 * sector-by-sector. 354 * 355 * Input parameters: 356 * softc - our flash 357 * 358 * Return value: 359 * 0 if ok 360 * else error code 361 ********************************************************************* */ 362 363static int flash_erase_all(flashdev_t *softc) 364{ 365 flash_range_t range; 366 367 range.range_base = 0; 368 range.range_length = softc->fd_probe.flash_size * 369 softc->fd_probe.flash_nchips; 370 371 return flash_erase_range(softc,&range); 372} 373 374 375/* ********************************************************************* 376 * flash_range_intersection(sector,inrange,outrange) 377 * 378 * Compute the intersection between a flash range and a 379 * sector. 380 * 381 * Input parameters: 382 * sector - sector to examine 383 * range - range we are checking 384 * outrange - where to put resulting intersection range 385 * 386 * Return value: 387 * 1 - range is an entire sector 388 * 0 - range is a partial sector 389 * -1 - range has no intersection 390 ********************************************************************* */ 391 392static int flash_range_intersection(flash_sector_t *sector, 393 flash_range_t *inrange, 394 flash_range_t *outrange) 395{ 396 int start,end; 397 398 /* 399 * compute the start and end pointers 400 */ 401 402 start = (int) (max(sector->flash_sector_offset, 403 inrange->range_base)); 404 405 end = (int) (min((sector->flash_sector_offset+sector->flash_sector_size), 406 (inrange->range_base+inrange->range_length))); 407 408 /* 409 * if the end is in the right place wrt the start, 410 * there is an intersection. 411 */ 412 413 if (end > start) { 414 outrange->range_base = (unsigned int) start; 415 outrange->range_length = (unsigned int) (end-start); 416 417 if ((sector->flash_sector_offset == outrange->range_base) && 418 (sector->flash_sector_size == outrange->range_length)) { 419 return 1; /* instersection: entire sector */ 420 } 421 else { 422 return 0; /* intersection: partial sector */ 423 } 424 } 425 else { 426 outrange->range_base = (unsigned int) start; 427 outrange->range_length = 0; 428 return -1; /* intersection: none */ 429 } 430} 431 432 433/* ********************************************************************* 434 * FLASH_SECTOR_QUERY(softc,sector) 435 * 436 * Query the sector information about a particular sector. You can 437 * call this iteratively to find out about all of the sectors. 438 * 439 * Input parameters: 440 * softc - our flash info 441 * sector - structure to receive sector information 442 * 443 * Return value: 444 * 0 if ok 445 * else error code 446 ********************************************************************* */ 447 448static int flash_sector_query(flashdev_t *softc,flash_sector_t *sector) 449{ 450 int idx; 451 int nblks; 452 int blksiz; 453 unsigned int offset; 454 int whichchip; 455 int secidx; 456 int curblk; 457 458 if (softc->fd_probe.flash_type != FLASH_TYPE_FLASH) { 459 return CFE_ERR_UNSUPPORTED; 460 } 461 462 if (softc->fd_probe.flash_nsectors == 0) { 463 return CFE_ERR_UNSUPPORTED; 464 } 465 466 /* Figure out which chip */ 467 whichchip = sector->flash_sector_idx / softc->fd_ttlsect; 468 if (whichchip >= softc->fd_probe.flash_nchips) { 469 sector->flash_sector_status = FLASH_SECTOR_INVALID; 470 return 0; 471 } 472 473 /* Within that chip, get sector info */ 474 offset = softc->fd_probe.flash_size * whichchip; 475 secidx = sector->flash_sector_idx % softc->fd_ttlsect; 476 curblk = 0; 477 478 for (idx = 0; idx < softc->fd_probe.flash_nsectors; idx++) { 479 nblks = FLASH_SECTOR_NBLKS(softc->fd_probe.flash_sectors[idx]); 480 blksiz = FLASH_SECTOR_SIZE(softc->fd_probe.flash_sectors[idx]); 481 if (secidx < curblk+nblks) { 482 sector->flash_sector_status = FLASH_SECTOR_OK; 483 sector->flash_sector_offset = 484 offset + (secidx-curblk)*blksiz; 485 sector->flash_sector_size = blksiz; 486 break; 487 } 488 489 offset += (nblks)*blksiz; 490 curblk += nblks; 491 } 492 493 494 if (idx == softc->fd_probe.flash_nsectors) { 495 sector->flash_sector_status = FLASH_SECTOR_INVALID; 496 } 497 498 return 0; 499} 500 501 502/* ********************************************************************* 503 * FLASH_SET_CMDSET(softc,cmdset,bus16,dev16) 504 * 505 * Set the command-set that we'll honor for this flash. 506 * 507 * Input parameters: 508 * softc - our flash 509 * cmdset - FLASH_CFI_CMDSET_xxx 510 * bus16 - true if bus is 16 bits wide 511 * dev16 - true if device supports 16-bit operation 512 * 513 * So: bus16 && dev16 -> 16-bit commands 514 * !bus16 && dev16 -> 8-bit commands to 16-bit flash with BYTE# 515 * !bus16 && !dev16 -> 8-bit commands 516 * 517 * Return value: 518 * nothing 519 ********************************************************************* */ 520 521static void flash_set_cmdset(flashdev_t *softc,int cmdset,int bus16,int dev16) 522{ 523 switch (cmdset) { 524#if (FLASH_DRIVERS & FLASH_DRIVER_INTEL) 525 case FLASH_CFI_CMDSET_INTEL_ECS: 526 if (bus16) { 527 softc->fd_erasefunc = FEOP_INTELEXT_ERASE16; 528 softc->fd_pgmfunc = FEOP_INTELEXT_PGM16; 529 softc->fd_readfunc = FEOP_READ16; 530 } 531 else { 532 softc->fd_erasefunc = FEOP_INTELEXT_ERASE8; 533 softc->fd_pgmfunc = FEOP_INTELEXT_PGM8; 534 softc->fd_readfunc = FEOP_READ8; 535 } 536 break; 537 case FLASH_CFI_CMDSET_INTEL_STD: 538 if (bus16) { 539 softc->fd_erasefunc = FEOP_INTEL_ERASE16; 540 softc->fd_pgmfunc = FEOP_INTEL_PGM16; 541 softc->fd_readfunc = FEOP_READ16; 542 } 543 else { 544 softc->fd_erasefunc = FEOP_INTEL_ERASE8; 545 softc->fd_pgmfunc = FEOP_INTEL_PGM8; 546 softc->fd_readfunc = FEOP_READ8; 547 } 548 break; 549#endif 550#if (FLASH_DRIVERS & FLASH_DRIVER_AMD) 551 case FLASH_CFI_CMDSET_AMD_STD: 552 case FLASH_CFI_CMDSET_AMD_ECS: 553 if (!bus16 && !dev16) { /* 8-bit bus, 8-bit flash */ 554 softc->fd_erasefunc = FEOP_AMD_ERASE8; 555 softc->fd_pgmfunc = FEOP_AMD_PGM8; 556 softc->fd_readfunc = FEOP_READ8; 557 } 558 else if (bus16 && dev16) { /* 16-bit bus, 16-bit flash */ 559 softc->fd_erasefunc = FEOP_AMD_ERASE16; 560 softc->fd_pgmfunc = FEOP_AMD_PGM16; 561 softc->fd_readfunc = FEOP_READ16; 562 } 563 else { /* 8-bit bus, 16-bit flash w/BYTE# */ 564 softc->fd_erasefunc = FEOP_AMD_ERASE16B; 565 softc->fd_pgmfunc = FEOP_AMD_PGM16B; 566 softc->fd_readfunc = FEOP_READ8; 567 } 568 break; 569#endif 570#if (FLASH_DRIVERS & FLASH_DRIVER_SST) 571 case FLASH_CFI_CMDSET_SST: 572 if (bus16 && dev16) { /* 16-bit bus, 16-bit flash */ 573 softc->fd_erasefunc = FEOP_SST_ERASE16; 574 softc->fd_pgmfunc = FEOP_SST_PGM16; 575 softc->fd_readfunc = FEOP_READ16; 576 } 577 else { 578 /* we don't understand the command set - treat it like ROM */ 579 softc->fd_erasefunc = FEOP_RETURN; 580 softc->fd_pgmfunc = FEOP_RETURN; 581 softc->fd_readfunc = bus16 ? FEOP_READ16 : FEOP_READ8; 582 } 583 break; 584#endif 585 default: 586 /* we don't understand the command set - treat it like ROM */ 587 softc->fd_erasefunc = FEOP_RETURN; 588 softc->fd_pgmfunc = FEOP_RETURN; 589 softc->fd_readfunc = bus16 ? FEOP_READ16 : FEOP_READ8; 590 break; 591 } 592} 593 594#if (FLASH_DRIVERS & FLASH_DRIVER_CFI) 595/* ********************************************************************* 596 * FLASH_CFI_PROBE(softc) 597 * 598 * Try to do a CFI query on this device. If we find the m 599 * magic signature, extract some useful information from the 600 * query structure. 601 * 602 * Input parameters: 603 * softc - out flash 604 * 605 * Return value: 606 * 0 if successful, <0 if error 607 ********************************************************************* */ 608static int flash_cfi_probe(flashdev_t *softc) 609{ 610 uint8_t cfidata[FLASH_MAX_CFIDATA]; 611 unsigned int cmdset; 612 unsigned int devif; 613 int bus16 = 0; 614 int dev16 = 0; 615 int idx; 616 int found = 0; 617 int regcnt; 618 int nblks; 619 int blksiz; 620 int insane = 0; 621 uint8_t insaner = 0; 622 623 if (softc->fd_probe.flash_flags & FLASH_FLG_BUS16) { 624 bus16 = 1; 625 } 626 627 /* 628 * Do a CFI query (16-bit) 629 */ 630 631 idx = FEOP_CFIQUERY8; 632 if (softc->fd_probe.flash_flags & FLASH_FLG_DEV16) { 633 idx = (softc->fd_probe.flash_flags & FLASH_FLG_BUS16) ? 634 FEOP_CFIQUERY16 : FEOP_CFIQUERY16B; 635 } 636 637 flash_op_begin(softc); 638 flash_op_add(softc,softc->fd_probe.flash_phys, 639 idx,(long)cfidata,0,FLASH_MAX_CFIDATA); 640 flash_op_execute(softc); 641 642 /* 643 * Look for signature. 644 */ 645 646 647 if ((cfidata[FLASH_CFI_SIGNATURE+0] == 'Q') && 648 (cfidata[FLASH_CFI_SIGNATURE+1] == 'R') && 649 (cfidata[FLASH_CFI_SIGNATURE+2] == 'Y')) { 650 found = 1; 651 } 652 653 /* Now try the SST CFI query */ 654 if (!found && (idx==FEOP_CFIQUERY16)) { 655 idx = FEOP_SST_CFIQUERY16; 656 flash_op_begin(softc); 657 flash_op_add(softc,softc->fd_probe.flash_phys, 658 idx,(long)cfidata,0,FLASH_MAX_CFIDATA); 659 flash_op_execute(softc); 660 661 /* 662 * Look for signature. 663 */ 664 665 if ((cfidata[FLASH_CFI_SIGNATURE+0] == 'Q') && 666 (cfidata[FLASH_CFI_SIGNATURE+1] == 'R') && 667 (cfidata[FLASH_CFI_SIGNATURE+2] == 'Y')) { 668 found = 1; 669 } 670 } 671 672 /* 673 * No CFI, bail. First, set the command set to an invalid 674 * value so that we'll use default routines to read but not do programming 675 */ 676 677 if (!found) { 678 flash_set_cmdset(softc,-1,bus16,dev16); 679 return CFE_ERR_UNSUPPORTED; 680 } 681 682 softc->fd_probe.flash_type = FLASH_TYPE_FLASH; 683 684 /* 685 * Gather info from flash 686 */ 687 688 cmdset = ((unsigned int) (cfidata[FLASH_CFI_COMMAND_SET])) + 689 (((unsigned int) (cfidata[FLASH_CFI_COMMAND_SET+1])) << 8); 690 691 692 devif = ((unsigned int) (cfidata[FLASH_CFI_DEVICE_INTERFACE])) + 693 (((unsigned int) (cfidata[FLASH_CFI_DEVICE_INTERFACE+1])) << 8); 694 695 696 softc->fd_probe.flash_size = (1 << (unsigned int)(cfidata[FLASH_CFI_DEVICE_SIZE])); 697 698 /* 699 * It's a 16-bit device if it is either always 16 bits or can be. 700 * we'll use "bus16" to decide if the BYTE# pin was strapped 701 */ 702 703 dev16 = 0; 704 if ((devif == FLASH_CFI_DEVIF_X16) || (devif == FLASH_CFI_DEVIF_X8X16)) dev16 = 1; 705 706 regcnt = cfidata[FLASH_CFI_REGION_COUNT]; 707 708 softc->fd_probe.flash_nsectors = regcnt; 709 710 /* 711 * Hiss! Some AMD top-boot flash parts have broken CFI tables - they are backwards! 712 * Do some extra probing to find it. 713 */ 714 715 if (cmdset == FLASH_CFI_CMDSET_AMD_STD) { 716 idx = FEOP_AMD_DEVCODE8; 717 if (softc->fd_probe.flash_flags & FLASH_FLG_DEV16) { 718 idx = (softc->fd_probe.flash_flags & FLASH_FLG_BUS16) ? 719 FEOP_AMD_DEVCODE16 : FEOP_AMD_DEVCODE16B; 720 } 721 722 flash_op_begin(softc); 723 flash_op_add(softc,softc->fd_probe.flash_phys, 724 idx,(long)&insaner,0,0); 725 flash_op_execute(softc); 726#ifdef _NEWFLASH_DEBUG_ 727 xprintf("Insaner = 0x%x\n", insaner); 728#endif /* _NEWFLASH_DEBUG_ */ 729 if(((insaner & 0xFF) == 0xC4)||((insaner & 0xFF) == 0xF6)){ 730 insane = 1; 731#ifdef _NEWFLASH_DEBUG_ 732 xprintf("Warning: insane AMD part, backwards CFI table!\n"); 733#endif /* _NEWFLASH_DEBUG_ */ 734 } 735 } 736 737 738 for (idx = 0; idx < regcnt; idx++) { 739 nblks = ((int)cfidata[FLASH_CFI_REGION_TABLE+0+idx*4] + 740 (int)(cfidata[FLASH_CFI_REGION_TABLE+1+idx*4]<<8)) + 1; 741 blksiz = ((int)cfidata[FLASH_CFI_REGION_TABLE+2+idx*4] + 742 (int)(cfidata[FLASH_CFI_REGION_TABLE+3+idx*4]<<8)) * 256; 743 744 if (insane) { 745 /* Insane */ 746 softc->fd_probe.flash_sectors[((regcnt-1)-idx)] = 747 FLASH_SECTOR_RANGE(nblks,blksiz); 748 } 749 else { 750 /* Sane */ 751 softc->fd_probe.flash_sectors[idx] = 752 FLASH_SECTOR_RANGE(nblks,blksiz); 753 } 754 } 755 756 /* 757 * Set the command set we're going to use. 758 */ 759 760 flash_set_cmdset(softc,cmdset,bus16,dev16); 761 762 return 0; 763 764} 765 766 767 768/* ********************************************************************* 769 * FLASH_DO_PROBE(softc) 770 * 771 * Probe to see if we're ROM or RAM. If ROM, see if we're flash. 772 * If flash, do CFI query. 773 * 774 * Input parameters: 775 * softc - our structure 776 * 777 * Return value: 778 * FLASH_TYPE_xxx 779 ********************************************************************* */ 780static int flash_do_probe(flashdev_t *softc) 781{ 782 uint8_t test_byte0,test_byte1; 783 uint8_t save0,save1; 784 volatile uint8_t *ptr; 785 786 /* 787 * flash_do_probe is called before we open the device, so we 788 * need to allocate space for instructions so the flashop 789 * engine will work. 790 */ 791 792 softc->fd_inst = KMALLOC(FLASH_MAX_INST*sizeof(flashinstr_t),0); 793 if (!softc->fd_inst) return FLASH_TYPE_ROM; 794 795 /* 796 * Attempt to read/write byte zero. If it is changable, 797 * this is SRAM (or maybe a ROM emulator with the write line hooked up) 798 */ 799 800 ptr = (volatile uint8_t *) UNCADDR(softc->fd_probe.flash_phys); 801 save0 = *ptr; /* save old value */ 802 save1 = *(ptr+1); /* save old value */ 803 804 test_byte0 = (save0 != 0x88) ? 0x88 : 0x89; 805 test_byte1 = (save1 != 0x99) ? 0x99 : 0x91; 806 807 *(ptr) = test_byte0; 808 *(ptr+1) = test_byte1; 809 810 if ((*ptr == test_byte0) && (*(ptr+1) == test_byte1)) { 811 softc->fd_probe.flash_type = FLASH_TYPE_SRAM; 812 813 /*Only write back saved values if it's RAM*/ 814 *(ptr) = save0; 815 *(ptr+1) = save1; 816 817#ifdef _NEWFLASH_DEBUG_ 818 xprintf("Flash type SRAM\n"); 819#endif 820 821 } 822 else { 823 softc->fd_probe.flash_type = FLASH_TYPE_ROM; 824 825#ifdef _NEWFLASH_DEBUG_ 826 xprintf("Flash type ROM\n"); 827#endif 828 829 } 830 831 /* 832 * If we thought it was ROM, try doing a CFI query 833 * to see if it was flash. This check is kind of kludgey 834 * but should work. 835 */ 836 837 if (softc->fd_probe.flash_type == FLASH_TYPE_ROM) { 838 flash_cfi_probe(softc); 839 } 840 841 842 KFREE(softc->fd_inst); 843 softc->fd_inst = NULL; 844 845 return softc->fd_probe.flash_type; 846} 847 848#endif /* (FLASH_DRIVERS & FLASH_DRIVER_CFI) */ 849 850 851/* ********************************************************************* 852 * flash_do_parts(probe,parts) 853 * 854 * Partition the flash into the sizes specified. We use 855 * the sizes in the table to generate a table of {offset,size} 856 * pairs that eventually become partitions. 857 * 858 * The only thing magical about this is that size "0" means 859 * "fill to max" and that partitions beyond the "0" are aligned 860 * to the top of the flash. Therefore, if you had a 4MB 861 * flash and listed four partitions, 512K, 0, 512K, 512K, 862 * then there would be a 2.5M partition in the middle and two 863 * 512K partitions at the top. 864 * 865 * Input parameters: 866 * probe - flash probe data (user-supplied table) 867 * parts - our partition table (output) 868 * 869 * Return value: 870 * nothing 871 ********************************************************************* */ 872 873static void flash_do_parts(flashdev_t *softc) 874{ 875 int idx; 876 int middlepart = -1; 877 int lobound = 0; 878 newflash_probe_t *probe = &(softc->fd_probe); 879 flashpart_t *parts = &(softc->fd_parts[0]); 880 int hibound = probe->flash_size*probe->flash_nchips; 881 882 for (idx = 0; idx < probe->flash_nparts; idx++) { 883 if (probe->flash_parts[idx].fp_size == 0) { 884 middlepart = idx; 885 break; 886 } 887 parts[idx].fp_offset = lobound; 888 parts[idx].fp_size = probe->flash_parts[idx].fp_size; 889 lobound += probe->flash_parts[idx].fp_size; 890 } 891 892 if (idx != probe->flash_nparts) { 893 for (idx = probe->flash_nparts - 1; idx > middlepart; 894 idx--) { 895 parts[idx].fp_size = probe->flash_parts[idx].fp_size; 896 hibound -= probe->flash_parts[idx].fp_size; 897 parts[idx].fp_offset = hibound; 898 } 899 } 900 901 if (middlepart != -1) { 902 parts[middlepart].fp_offset = lobound; 903 parts[middlepart].fp_size = hibound - lobound; 904 } 905 906#ifdef _NEWFLASH_DEBUG_ 907 printf("Partition information:\n"); 908 for (idx = 0; idx < probe->flash_nparts;idx++) { 909 printf("#%02d %08X -> %08X (%d)\n",idx, 910 parts[idx].fp_offset,parts[idx].fp_offset+parts[idx].fp_size-1, 911 parts[idx].fp_size); 912 } 913#endif 914} 915 916 917/* ********************************************************************* 918 * flashdrv_allocbuf(dev) 919 * 920 * Allocate sector buffer for flash programming. Use a global 921 * buffer for all devices. 922 * 923 * Input parameters: 924 * dev - our device 925 * 926 * Return value: 927 * nothing 928 ********************************************************************* */ 929static void flashdrv_allocbuf(flashdev_t *softc) 930{ 931 if (!flash_sector_buffer) { 932#if CFG_FLASH_ALLOC_SECTOR_BUFFER 933 flash_sector_buffer = KMALLOC(CFG_FLASH_SECTOR_BUFFER_SIZE,0); 934 if (!flash_sector_buffer) { 935 printf("FLASH: Could not allocate sector buffer, using default\n"); 936 flash_sector_buffer = (uint8_t *) KERNADDR(CFG_FLASH_SECTOR_BUFFER_SIZE); 937 } 938#else 939 flash_sector_buffer = (uint8_t *) KERNADDR(CFG_FLASH_SECTOR_BUFFER_ADDR); 940#endif 941 } 942 943 softc->fd_sectorbuffer = flash_sector_buffer; 944} 945 946/* ********************************************************************* 947 * flashdrv_probe(drv,probe_a,probe_b,probe_ptr) 948 * 949 * Device probe routine. Attach the flash device to 950 * CFE's device table. 951 * 952 * Input parameters: 953 * drv - driver descriptor 954 * probe_a - physical address of flash 955 * probe_b - size of flash (bytes) 956 * probe_ptr - unused 957 * 958 * Return value: 959 * nothing 960 ********************************************************************* */ 961 962static void flashdrv_probe(cfe_driver_t *drv, 963 unsigned long probe_a, unsigned long probe_b, 964 void *probe_ptr) 965{ 966 flashdev_t *softc; 967 newflash_probe_t *probe; 968 int idx; 969 char descr[80]; 970 static int flashidx = 0; 971 char *x; 972 973 /* 974 * First thing to do is configure the flashop engine 975 * if not already done. Basically we copy a bit of 976 * position-independent code into the DRAM. 977 */ 978 979 flash_setup_engine(); 980 981 /* 982 * Now, on with the probing. 983 */ 984 985 probe = (newflash_probe_t *) probe_ptr; 986 987 /* 988 * probe_a is the flash base address 989 * probe_b is the size of the flash 990 * probe_ptr is unused. 991 */ 992 993 softc = (flashdev_t *) KMALLOC(sizeof(flashdev_t),0); 994 if (softc) { 995 memset(softc,0,sizeof(flashdev_t)); 996 997 flashdrv_allocbuf(softc); 998 999 if (probe) { 1000 /* 1001 * Passed probe structure, do fancy stuff 1002 */ 1003 memcpy(&(softc->fd_probe),probe,sizeof(newflash_probe_t)); 1004 if (softc->fd_probe.flash_nchips == 0) { 1005 softc->fd_probe.flash_nchips = 1; 1006 } 1007 } 1008 else { 1009 /* Didn't pass probe structure, do the compatible thing */ 1010 softc->fd_probe.flash_phys = probe_a; 1011 softc->fd_probe.flash_size = (probe_b & FLASH_SIZE_MASK); 1012 softc->fd_probe.flash_flags = (probe_b & FLASH_FLG_MASK); 1013 softc->fd_probe.flash_nchips = 1; 1014 } 1015 1016 if (softc->fd_probe.flash_flags & FLASH_FLG_MANUAL) { 1017 /* Manual probing, just set the command set. */ 1018 flash_set_cmdset(softc,softc->fd_probe.flash_cmdset, 1019 ((softc->fd_probe.flash_flags & FLASH_FLG_BUS16) ? 1 : 0), 1020 ((softc->fd_probe.flash_flags & FLASH_FLG_DEV16) ? 1 : 0)); 1021 } 1022 else { 1023 /* Do automatic probing */ 1024#if (FLASH_DRIVERS & FLASH_DRIVER_CFI) 1025 flash_do_probe(softc); 1026#else 1027 return; /* No automatic probing, bail! */ 1028#endif 1029 } 1030 1031 /* Remember total size of all devices */ 1032 softc->fd_ttlsize = softc->fd_probe.flash_nchips * softc->fd_probe.flash_size; 1033 1034 /* Set description */ 1035 x = descr; 1036 x += xsprintf(x,"%s at %08X size %uKB",drv->drv_description, 1037 softc->fd_probe.flash_phys, 1038 softc->fd_ttlsize/1024); 1039 if (softc->fd_probe.flash_nchips > 1) { 1040 xsprintf(x," (%d chips)",softc->fd_probe.flash_nchips); 1041 } 1042 1043 /* 1044 * If flash is not partitioned, just instantiate one 1045 * device. Otherwise, instantiate multiple flashes 1046 * to cover the entire device. 1047 */ 1048 1049 if (softc->fd_probe.flash_nparts == 0) { 1050 softc->fd_parts[0].fp_dev = softc; 1051 softc->fd_parts[0].fp_offset = 0; 1052 softc->fd_parts[0].fp_size = softc->fd_probe.flash_size; 1053 cfe_attach(drv,&(softc->fd_parts[0]),NULL,descr); 1054 } 1055 else { 1056 /* 1057 * Partition flash into chunks 1058 */ 1059 flash_do_parts(softc); 1060 1061 /* 1062 * Instantiate devices for each piece 1063 */ 1064 1065 for (idx = 0; idx < softc->fd_probe.flash_nparts; idx++) { 1066 char name[32]; 1067 char *nptr; 1068 1069 xsprintf(descr,"%s at %08X offset %08X size %uKB", 1070 drv->drv_description, 1071 softc->fd_probe.flash_phys, 1072 softc->fd_parts[idx].fp_offset, 1073 (softc->fd_parts[idx].fp_size+1023)/1024); 1074 1075 softc->fd_parts[idx].fp_dev = softc; 1076 if (softc->fd_probe.flash_parts[idx].fp_name == NULL) { 1077 sprintf(name,"%d",idx); 1078 nptr = name; 1079 } 1080 else { 1081 nptr = softc->fd_probe.flash_parts[idx].fp_name; 1082 } 1083 cfe_attach_idx(drv, 1084 flashidx, 1085 &(softc->fd_parts[idx]), 1086 nptr, 1087 descr); 1088 } 1089 } 1090 1091 flashidx++; 1092 1093 /* Count total sectors on the device */ 1094 1095 softc->fd_ttlsect = 0; 1096 for (idx = 0; idx < softc->fd_probe.flash_nsectors; idx++) { 1097 softc->fd_ttlsect += FLASH_SECTOR_NBLKS(softc->fd_probe.flash_sectors[idx]); 1098 } 1099 1100 } 1101 1102} 1103 1104 1105/* ********************************************************************* 1106 * flashdrv_open(ctx) 1107 * 1108 * Called when the flash device is opened. 1109 * 1110 * Input parameters: 1111 * ctx - device context 1112 * 1113 * Return value: 1114 * 0 if ok else error code 1115 ********************************************************************* */ 1116 1117static int flashdrv_open(cfe_devctx_t *ctx) 1118{ 1119 flashpart_t *part = ctx->dev_softc; 1120 flashdev_t *softc = part->fp_dev; 1121 int ttlsect = softc->fd_ttlsect; 1122 1123 /* 1124 * Calculate number of flashop instructions we'll need at most. 1125 * This will be two for each sector plus two more for the first 1126 * and last sectors, plus two extra 1127 */ 1128 1129 ttlsect = (ttlsect * 2 * softc->fd_probe.flash_nchips) + 6; 1130 1131 /* 1132 * Allocate memory for instructions. 1133 */ 1134 1135#ifdef _NEWFLASH_DEBUG_ 1136 printf("%s: allocating %d instructions\n",cfe_device_name(ctx),ttlsect); 1137#endif 1138 1139 softc->fd_inst = KMALLOC(ttlsect*sizeof(flashinstr_t),0); 1140 if (!softc->fd_inst) return CFE_ERR_NOMEM; 1141 1142 return 0; 1143} 1144 1145 1146/* ********************************************************************* 1147 * flashdrv_read(ctx,buffer) 1148 * 1149 * Read data from the flash device. The flash device is 1150 * considered to be like a disk (you need to specify the offset). 1151 * 1152 * Input parameters: 1153 * ctx - device context 1154 * buffer - buffer descriptor 1155 * 1156 * Return value: 1157 * 0 if ok, else error code 1158 ********************************************************************* */ 1159 1160static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 1161{ 1162 flashpart_t *part = ctx->dev_softc; 1163 flashdev_t *softc = part->fp_dev; 1164 int blen; 1165 int offset; 1166 1167 blen = buffer->buf_length; 1168 offset = (long)buffer->buf_offset; 1169 1170 if ((offset + blen) > part->fp_size) { 1171 blen = part->fp_size - offset; 1172 } 1173 1174 offset += part->fp_offset; 1175 1176 if (blen > 0) { 1177 flash_op_begin(softc); 1178 flash_op_add(softc,softc->fd_probe.flash_phys, 1179 softc->fd_readfunc,(long)buffer->buf_ptr,offset,blen); 1180 flash_op_execute(softc); 1181 } 1182 1183 buffer->buf_retlen = blen; 1184 1185 return 0; 1186} 1187 1188/* ********************************************************************* 1189 * flashdrv_inpstat(ctx,inpstat) 1190 * 1191 * Return "input status". For flash devices, we always return true. 1192 * 1193 * Input parameters: 1194 * ctx - device context 1195 * inpstat - input status structure 1196 * 1197 * Return value: 1198 * 0 if ok, else error code 1199 ********************************************************************* */ 1200 1201static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat) 1202{ 1203 inpstat->inp_status = 1; 1204 return 0; 1205} 1206 1207 1208/* ********************************************************************* 1209 * flashdrv_write(ctx,buffer) 1210 * 1211 * Write data to the flash device. The flash device is 1212 * considered to be like a disk (you need to specify the offset). 1213 * 1214 * Input parameters: 1215 * ctx - device context 1216 * buffer - buffer descriptor 1217 * 1218 * Return value: 1219 * 0 if ok, else error code 1220 ********************************************************************* */ 1221 1222static int flashdrv_write2(cfe_devctx_t *ctx,iocb_buffer_t *buffer,int reboot) 1223{ 1224 flashpart_t *part = ctx->dev_softc; 1225 flashdev_t *softc = part->fp_dev; 1226 int blen; 1227 int res; 1228 int offset; 1229 int whichchip; 1230 long chipbase; 1231 flash_range_t outrange; 1232 flash_range_t inrange; 1233 flash_sector_t sector; 1234 1235 blen = buffer->buf_length; 1236 offset = (long)buffer->buf_offset; 1237 1238 /* Compute range within physical flash */ 1239 1240 if ((offset + blen) > part->fp_size) { 1241 blen = part->fp_size - offset; 1242 } 1243 1244 offset += part->fp_offset; 1245 1246 /* Handle case of writing nothing */ 1247 1248 if (blen == 0) { 1249 buffer->buf_retlen = blen; 1250 return (buffer->buf_length == blen) ? 0 : CFE_ERR_IOERR; 1251 } 1252 1253 /* now, offset/blen forms the range we want to write to. */ 1254 1255 inrange.range_base = offset; 1256 inrange.range_length = blen; 1257 1258 sector.flash_sector_idx = 0; 1259 1260 flash_op_begin(softc); 1261 1262 for (;;) { 1263 res = flash_sector_query(softc,§or); 1264 if (res != 0) break; 1265 if (sector.flash_sector_status == FLASH_SECTOR_INVALID) { 1266 break; 1267 } 1268 1269 whichchip = sector.flash_sector_idx / softc->fd_ttlsect; 1270 chipbase = softc->fd_probe.flash_phys + 1271 (long) (whichchip * softc->fd_probe.flash_size); 1272 1273 res = flash_range_intersection(§or,&inrange,&outrange); 1274 1275 switch (res) { 1276 case 1: /* Erease/program entire sector */ 1277 flash_op_add(softc,chipbase, 1278 softc->fd_erasefunc, 1279 sector.flash_sector_offset, 1280 0,0); 1281 flash_op_add(softc,chipbase, 1282 softc->fd_pgmfunc, 1283 outrange.range_base, 1284 ((long)buffer->buf_ptr)+(outrange.range_base-inrange.range_base), 1285 outrange.range_length); 1286 break; 1287 1288 case 0: /* Erase/reprogram partial sector */ 1289 /* Save old sector */ 1290 flash_op_add(softc,chipbase, 1291 softc->fd_readfunc, 1292 (long)(softc->fd_sectorbuffer), 1293 sector.flash_sector_offset, 1294 sector.flash_sector_size); 1295 /* Copy in new stuff */ 1296 flash_op_add(softc,chipbase, 1297 FEOP_MEMCPY, 1298 ((long)(softc->fd_sectorbuffer))+(outrange.range_base-sector.flash_sector_offset), 1299 ((long)buffer->buf_ptr)+(outrange.range_base-inrange.range_base), 1300 outrange.range_length); 1301 /* Erase sector */ 1302 flash_op_add(softc,chipbase, 1303 softc->fd_erasefunc, 1304 sector.flash_sector_offset, 1305 0,0); 1306 /* Program sector */ 1307 flash_op_add(softc,chipbase, 1308 softc->fd_pgmfunc, 1309 sector.flash_sector_offset, 1310 (long)(softc->fd_sectorbuffer), 1311 sector.flash_sector_size); 1312 break; 1313 1314 case -1: /* No intersection */ 1315 break; 1316 } 1317 1318 sector.flash_sector_idx++; 1319 1320 } 1321 1322 if (reboot) { 1323 flash_op_add(softc,softc->fd_probe.flash_phys,FEOP_REBOOT,0,0,0); 1324 } 1325 1326 res = flash_op_execute(softc); 1327 1328 buffer->buf_retlen = blen; 1329 1330 return (res == 0) ? 0 : CFE_ERR_IOERR; 1331} 1332 1333static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 1334{ 1335 return flashdrv_write2(ctx,buffer,0); 1336} 1337 1338 1339/* ********************************************************************* 1340 * flashdrv_ioctl(ctx,buffer) 1341 * 1342 * Handle special IOCTL functions for the flash. Flash devices 1343 * support NVRAM information, sector and chip erase, and a 1344 * special IOCTL for updating the running copy of CFE. 1345 * 1346 * Input parameters: 1347 * ctx - device context 1348 * buffer - descriptor for IOCTL parameters 1349 * 1350 * Return value: 1351 * 0 if ok else error 1352 ********************************************************************* */ 1353static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer) 1354{ 1355 flashpart_t *part = ctx->dev_softc; 1356 flashdev_t *softc = part->fp_dev; 1357 nvram_info_t *nvinfo; 1358 flash_info_t *info; 1359 flash_range_t range; 1360 int offset; 1361 1362 switch ((int)buffer->buf_ioctlcmd) { 1363 case IOCTL_NVRAM_GETINFO: 1364 /* 1365 * We only support NVRAM on flashes that have been partitioned 1366 * into at least two partitions. Every partition supports 1367 * being an NVRAM in that case, but we'll only attach one 1368 * of them to the environment subsystem. 1369 */ 1370 if (softc->fd_probe.flash_nparts <= 1) { 1371 return CFE_ERR_UNSUPPORTED; 1372 } 1373 nvinfo = (nvram_info_t *) buffer->buf_ptr; 1374 if (buffer->buf_length != sizeof(nvram_info_t)) return CFE_ERR_INV_PARAM; 1375 1376 nvinfo->nvram_offset = 0; 1377 nvinfo->nvram_size = part->fp_size; 1378 nvinfo->nvram_eraseflg = 1; 1379 buffer->buf_retlen = sizeof(nvram_info_t); 1380 return 0; 1381 break; 1382 1383 case IOCTL_FLASH_ERASE_SECTOR: 1384 offset = (int) buffer->buf_offset; 1385 offset += part->fp_offset; 1386 if (offset >= softc->fd_probe.flash_size) return -1; 1387 1388 flash_op_begin(softc); 1389 flash_op_add(softc, 1390 softc->fd_probe.flash_phys, 1391 softc->fd_erasefunc, 1392 offset, 1393 0,0); 1394 flash_op_execute(softc); 1395 return 0; 1396 1397 case IOCTL_FLASH_ERASE_ALL: 1398 offset = (int) buffer->buf_offset; 1399 if (offset != 0) return -1; 1400 flash_erase_all(softc); 1401 return 0; 1402 1403 case IOCTL_FLASH_WRITE_ALL: 1404 /* Write file and reboot */ 1405 flashdrv_write2(ctx,buffer,1); 1406 return -1; /* should not return */ 1407 1408 case IOCTL_FLASH_GETINFO: 1409 info = (flash_info_t *) buffer->buf_ptr; 1410 info->flash_base = softc->fd_probe.flash_phys; 1411 info->flash_size = softc->fd_probe.flash_size; 1412 info->flash_type = softc->fd_probe.flash_type; 1413 info->flash_flags = FLASH_FLAG_NOERASE; 1414 if (flashop_engine_ram != (void *) flashop_engine_ptr) 1415 info->flash_flags |= FLASH_FLAG_INUSE; 1416 return 0; 1417 1418 case IOCTL_FLASH_GETSECTORS: 1419 return flash_sector_query(softc,(flash_sector_t *) buffer->buf_ptr); 1420 1421 case IOCTL_FLASH_ERASE_RANGE: 1422 memcpy(&range,buffer->buf_ptr,sizeof(flash_range_t)); 1423 range.range_base += part->fp_offset; 1424 if (range.range_length > part->fp_size) { 1425 range.range_length = part->fp_size; 1426 } 1427 return flash_erase_range(softc,&range); 1428 1429 default: 1430 /* Call hook if present. */ 1431 if (softc->fd_probe.flash_ioctl_hook) { 1432 return (*(softc->fd_probe.flash_ioctl_hook))(ctx,buffer); 1433 } 1434 return -1; 1435 } 1436 1437 return -1; 1438} 1439 1440 1441/* ********************************************************************* 1442 * flashdrv_close(ctx) 1443 * 1444 * Close the flash device. 1445 * 1446 * Input parameters: 1447 * ctx - device context 1448 * 1449 * Return value: 1450 * 0 1451 ********************************************************************* */ 1452static int flashdrv_close(cfe_devctx_t *ctx) 1453{ 1454 flashpart_t *part = ctx->dev_softc; 1455 flashdev_t *softc = part->fp_dev; 1456 1457 if (softc->fd_inst) { 1458 KFREE(softc->fd_inst); 1459 } 1460 1461 softc->fd_inst = NULL; 1462 1463 1464 return 0; 1465} 1466 1467 1468