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