GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / arch / mips / board / lausanne / src / dev_lausanne_flash.c
blobc7fc04472a89648ad86d6d1dc532f04e9ad0c380
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)
12 *********************************************************************
14 * Copyright 2000,2001,2002,2003
15 * Broadcom Corporation. All rights reserved.
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.
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.
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.
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 ********************************************************************* */
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"
60 #include "sb1250_defs.h"
61 #include "sb1250_regs.h"
62 #include "sb1250_genbus.h"
64 #include "dev_flash.h"
65 #include "lausanne.h"
67 /* *********************************************************************
68 * Macros
69 ********************************************************************* */
71 #define FLASHCMD(sc,x,y) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+ \
72 ((x)<<(sc)->flashdrv_widemode))) = (y)
73 #define FLASHSTATUS(sc,x) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+ \
74 ((x)<<(sc)->flashdrv_widemode)))
76 #define WRITEFLASH_K1(sc,x,y) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+(x))) = (y)
77 #define READFLASH_K1(sc,x) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+(x)))
79 #define WRITEFLASH_K1W(sc,x,y) *((volatile unsigned short *)(sc->flashdrv_cmdaddr+(x))) = (y)
80 #define READFLASH_K1W(sc,x) *((volatile unsigned short *)(sc->flashdrv_cmdaddr+(x)))
82 #define WRITEFLASH_K1W_B(sc,x,y) *((volatile uint64_t *)(sc->flashdrv_cmdaddr+(x))) = (y)
83 #define READFLASH_K1W_B(sc,x) *((volatile uint64_t *)(sc->flashdrv_cmdaddr+(x)))
85 #define GETCFIBYTE(softc,offset) READFLASH_K1(softc,((offset) << (softc->flashdrv_widemode)))
87 /* *********************************************************************
88 * Forward declarations
89 ********************************************************************* */
92 static void flashdrv_probe(cfe_driver_t *drv,
93 unsigned long probe_a, unsigned long probe_b,
94 void *probe_ptr);
97 static int flashdrv_open(cfe_devctx_t *ctx);
98 static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
99 static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
100 static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
101 static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
102 static int flashdrv_close(cfe_devctx_t *ctx);
104 /* *********************************************************************
105 * Device dispatch
106 ********************************************************************* */
108 const static cfe_devdisp_t flashdrv_dispatch = {
109 flashdrv_open,
110 flashdrv_read,
111 flashdrv_inpstat,
112 flashdrv_write,
113 flashdrv_ioctl,
114 flashdrv_close,
115 NULL,
116 NULL
119 const cfe_driver_t lausanne_flashdrv = {
120 "CFI flash",
121 "flash",
122 CFE_DEV_FLASH,
123 &flashdrv_dispatch,
124 flashdrv_probe
128 /* *********************************************************************
129 * Structures
130 ********************************************************************* */
132 typedef struct flash_cfidata_s {
133 unsigned int cfidata_cmdset; /* ID of primary command set */
134 unsigned int cfidata_devif; /* device interface byte */
135 unsigned int cfidata_size; /* probed device size */
136 } flash_cfidata_t;
138 typedef struct flashops_s flashops_t;
140 typedef struct flashdrv_s {
141 flash_probe_t flashdrv_probe; /* data from probe */
142 int flashdrv_devsize; /* size reported by driver */
143 unsigned char *flashdrv_cmdaddr; /* virtual address (K1) */
144 int flashdrv_widemode; /* 1=wide flash in byte mode, 0=narrow flash */
145 int flashdrv_initialized; /* true if we've probed already */
146 flash_info_t flashdrv_info;
147 int flashdrv_nvram_ok; /* true if we can use as NVRAM */
148 int flashdrv_unlocked; /* true if we can r/w past devsize */
149 nvram_info_t flashdrv_nvraminfo;
150 flashops_t *flashdrv_ops;
151 flash_cfidata_t flashdrv_cfidata;
152 } flashdrv_t;
154 struct flashops_s {
155 int (*erasesector)(flashdrv_t *f,int offset);
156 int (*writeblk)(flashdrv_t *f,int offset,void *buf,int len);
159 /* *********************************************************************
160 * Macros
161 ********************************************************************* */
163 #define FLASHOP_ERASE_SECTOR(softc,sect) (*((softc)->flashdrv_ops->erasesector))((softc),(sect))
164 #define FLASHOP_WRITE_BLOCK(softc,off,buf,len) (*((softc)->flashdrv_ops->writeblk))((softc),(off),(buf),(len))
166 /* *********************************************************************
167 * forward declarations
168 ********************************************************************* */
170 static int flash_sector_query(flashdrv_t *softc,flash_sector_t *sector);
172 static int amd_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len);
173 static int amd_flash_erase_sector(flashdrv_t *softc,int offset);
175 static int intel_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len);
176 static int intel_flash_erase_sector(flashdrv_t *softc,int offset);
177 static int intel_flash_data_width_mode(flashdrv_t *softc,int flash_16bit);
178 static int burst_mode(flashdrv_t *softc, int burst_on);
180 static flashops_t amd_flashops = {
181 amd_flash_erase_sector,
182 amd_flash_write_block,
185 static flashops_t intel_flashops = {
186 intel_flash_erase_sector,
187 intel_flash_write_block,
190 #define FLASHOPS_DEFAULT intel_flashops
194 /* *********************************************************************
195 * Externs
196 ********************************************************************* */
198 extern void *flash_write_all_ptr;
199 extern int flash_write_all_len;
201 extern void _cfe_flushcache(int);
205 /* *********************************************************************
206 * amd_flash_write_byte(softc,offset,val)
208 * Write a single byte to the flash. The sector that the flash
209 * byte is in should have been previously erased, or else this
210 * routine may hang.
212 * Input parameters:
213 * softc - flash context
214 * offset - distance in bytes into the flash
215 * val - byte to write
217 * Return value:
218 * 0 if ok
219 * else if flash could not be written
220 ********************************************************************* */
221 static inline int amd_flash_write_byte(flashdrv_t *softc,int offset, unsigned char val)
223 unsigned int value;
225 /* Do an "unlock write" sequence */
226 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1);
227 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2);
229 /* Send a program command */
230 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_PROGRAM);
232 /* Write a byte */
233 WRITEFLASH_K1(softc,offset,val);
235 for (;;) {
236 value = READFLASH_K1(softc,offset) & 0xFF;
238 if ((value & 0x80) == (val & 0x80)) {
239 return 0;
241 if ((value & 0x20) != 0x20) {
242 continue;
245 if ((READFLASH_K1(softc,offset) & 0x80) == (val & 0x80)) {
246 return 0;
248 else {
249 return -1;
255 /* *********************************************************************
256 * amd_flash_write_block(softc,offset,val)
258 * Write a single byte to the flash. The sector that the flash
259 * byte is in should have been previously erased, or else this
260 * routine may hang.
262 * Input parameters:
263 * softc - flash context
264 * offset - distance in bytes into the flash
265 * buf - buffer of bytes to write
266 * len - number of bytes to write
268 * Return value:
269 * number of bytes written
270 ********************************************************************* */
271 static int amd_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len)
273 unsigned char *ptr;
275 ptr = buf;
277 while (len) {
278 if (amd_flash_write_byte(softc,offset,*ptr) < 0) break;
279 len--;
280 ptr++;
281 offset++;
285 return (ptr - (unsigned char *)buf);
289 /* *********************************************************************
290 * amd_flash_erase_sector(softc,offset)
292 * Erase a single sector in the flash device
294 * Input parameters:
295 * softc - device context
296 * offset - offset in flash of sector to erase
298 * Return value:
299 * 0 if ok, else error code
300 ********************************************************************* */
302 static int amd_flash_erase_sector(flashdrv_t *softc,int offset)
304 /* Do an "unlock write" sequence */
305 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); /* cycles 1-2 */
306 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2);
308 /* send the erase command */
309 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_ERASE_3); /* cycle 3 */
311 /* Do an "unlock write" sequence */
312 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); /* cycles 4-5 */
313 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2);
316 * Send the "erase sector" qualifier - don't use FLASHCMD
317 * because it changes the offset.
319 WRITEFLASH_K1(softc,offset,AMD_FLASH_ERASE_SEC_6);
321 while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) {
322 /* NULL LOOP */
325 return 0;
330 /* *********************************************************************
331 * intel_flash_write_byte(softc,offset,val)
333 * Write a single byte to the flash. The sector that the flash
334 * byte is in should have been previously erased, or else this
335 * routine may hang.
337 * Input parameters:
338 * softc - flash context
339 * offset - distance in bytes into the flash
340 * val - byte to write
342 * Return value:
343 * 0 if ok
344 * else if flash could not be written
345 ********************************************************************* */
346 static inline int intel_flash_write_byte(flashdrv_t *softc,
347 int offset, unsigned char val)
349 unsigned int value;
351 /* Send a program command */
352 WRITEFLASH_K1(softc,offset,INTEL_FLASH_PROGRAM);
354 /* Write a byte */
355 WRITEFLASH_K1(softc,offset,val);
358 while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) {
359 /* NULL LOOP */
362 value = READFLASH_K1(softc,offset) & 0xFF;
364 if (value & (0x01|0x08|0x10)) return -1;
365 return 0;
369 static inline int intel_flash_write_byte_burst(flashdrv_t *softc,
370 int offset, uint64_t val)
372 unsigned int value;
374 /* Send a program command */
375 WRITEFLASH_K1(softc,offset,INTEL_FLASH_PROGRAM);
377 /* Write a byte */
378 WRITEFLASH_K1(softc,offset,val);
381 while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) {
382 /* NULL LOOP */
385 value = READFLASH_K1(softc,offset) & 0xFF;
387 if (value & (0x01|0x08|0x10)) return -1;
388 return 0;
391 /* *********************************************************************
392 * intel_flash_write_word(softc,offset,val)
394 * Write a single word to the flash. The sector that the flash
395 * byte is in should have been previously erased, or else this
396 * routine may hang.
398 * Input parameters:
399 * softc - flash context
400 * offset - distance in bytes into the flash
401 * val - word to write
403 * Return value:
404 * 0 if ok
405 * else if flash could not be written
406 ********************************************************************* */
407 static inline int intel_flash_write_word(flashdrv_t *softc,
408 int offset, unsigned short val)
410 unsigned int value;
412 /* Send a program command */
413 WRITEFLASH_K1W(softc,offset,INTEL_FLASH_16BIT_PROGRAM);
415 /* Write a byte */
416 WRITEFLASH_K1W(softc,offset,val);
419 while ((READFLASH_K1W(softc,offset) & 0x8000) != 0x8000) {
420 /* NULL LOOP */
423 value = READFLASH_K1W(softc,offset) & 0xFFFF;
425 if (value & (0x0100|0x0800|0x1000)){
426 return -1;
428 return 0;
431 static int intel_flash_write_word_burst(flashdrv_t *softc,
432 int offset, uint64_t val)
434 unsigned int value;
436 /* Send a program command */
437 WRITEFLASH_K1W(softc,offset,0xE800);
439 while ((READFLASH_K1W(softc,offset) & 0x8000) != 0x8000) {
440 /* NULL LOOP */
443 WRITEFLASH_K1W(softc,offset,0x0300);
445 /* Write a byte */
446 WRITEFLASH_K1W_B(softc,offset,val);
448 WRITEFLASH_K1W(softc,offset,0xD000);
450 while ((READFLASH_K1W(softc,offset) & 0x8000) != 0x8000) {
451 /* NULL LOOP */
454 value = READFLASH_K1W(softc,offset) & 0xFFFF;
456 if (value & (0x0100|0x0800|0x1000)){
457 return -1;
460 return 0;
463 /* *********************************************************************
464 * intel_flash_write_block(softc,offset,val)
466 * Write a single byte to the flash. The sector that the flash
467 * byte is in should have been previously erased, or else this
468 * routine may hang.
470 * Input parameters:
471 * softc - flash context
472 * offset - distance in bytes into the flash
473 * buf - buffer of bytes to write
474 * len - number of bytes to write
476 * Return value:
477 * number of bytes written
478 ********************************************************************* */
479 static int intel_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len)
481 unsigned char *ptr;
482 unsigned short *ptrw;
483 uint64_t *ptr64;
485 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_16BIT) {
487 if( SBREADCSR(A_IO_EXT_REG(8)) & 0x20) {
488 xprintf("BURST 16 BIT\n");
489 ptr64 = (uint64_t *)buf;
490 offset &= ~1;
492 while (len > 0) {
493 if (intel_flash_write_word_burst(softc,offset,*ptr64) < 0) break;
494 len-=8;
495 ptr64++;
496 offset+=8;
498 WRITEFLASH_K1W(softc,offset,INTEL_FLASH_16BIT_READ_MODE);
499 return ((unsigned char *)ptr64 - (unsigned char *)buf);
502 ptrw = buf;
503 offset &= ~1; /* offset must be even */
504 while (len > 0) {
505 if (intel_flash_write_word(softc,offset,*ptrw) < 0) break;
506 len-=2;
507 ptrw++;
508 offset+=2;
510 WRITEFLASH_K1W(softc,offset,INTEL_FLASH_16BIT_READ_MODE);
511 return ((unsigned char *) ptrw - (unsigned char *)buf);
513 else {
515 if( SBREADCSR(A_IO_EXT_REG(8)) & 0x20) {
516 xprintf("BURST 8 BIT\n");
517 ptr64 = buf;
518 offset += ~1;
519 while (len > 0) {
520 if (intel_flash_write_byte_burst(softc,offset,*ptr64) < 0) break;
521 len-=4;
522 ptr64++;
523 offset+=4;
525 WRITEFLASH_K1W(softc,offset,INTEL_FLASH_16BIT_READ_MODE);
526 return ((unsigned char *)ptr64 - (unsigned char *)buf);
529 ptr = buf;
530 while (len) {
531 if (intel_flash_write_byte(softc,offset,*ptr) < 0) break;
532 len--;
533 ptr++;
534 offset++;
536 WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE);
537 return (ptr - (unsigned char *)buf);
541 /* *********************************************************************
542 * intel_flash_data_width_mode(softc)
544 * Switch the intel flash to 8 or16-bit mode via the GPIO. Also make
545 * data width size on Generic Bus to 2 bytes and multiplex mode.
547 * Input parameters:
548 * softc - device context
550 * Return value:
551 * 0 if ok, else error code
552 ********************************************************************* */
553 static int intel_flash_data_width_mode(flashdrv_t *softc,int flash_16bit)
555 uint64_t gpio_direction;
556 uint64_t io_ext_cfg;
558 if (flash_16bit) {
559 /*refer to lausanne.h. 16-mode switch at pin 15 on GPIO*/
560 gpio_direction = SBREADCSR(A_GPIO_DIRECTION);
561 gpio_direction |= 0x8000;
562 SBWRITECSR(A_GPIO_DIRECTION,gpio_direction);
564 // xprintf("GPIO DIRECTION:%16llX\n",SBREADCSR(A_GPIO_DIRECTION));
566 SBWRITECSR(A_GPIO_PIN_SET,0x8000);
568 /*Make data width of GENBUS CS 1 2 bytes wide*/
569 io_ext_cfg = SBREADCSR(A_IO_EXT_REG(8));
570 io_ext_cfg |= 0x4; /* 0x4=2-byte 0x0=1-byte*/
571 io_ext_cfg &= ~0x80; /*make sure we're mux'ed!!*/
572 SBWRITECSR(A_IO_EXT_REG(8),io_ext_cfg);
574 xprintf("FLASH 16-BIT MODE\n");
575 xprintf("GPIO READ:%16llX\n",SBREADCSR(A_GPIO_READ));
576 xprintf("GENCS 1:%16llX\n",SBREADCSR(A_IO_EXT_REG(8)) );
578 softc->flashdrv_probe.flash_flags |= FLASH_FLG_16BIT;
580 else {/*8 bit flash*/
581 gpio_direction = SBREADCSR(A_GPIO_DIRECTION);
582 gpio_direction &= ~0x8000;
583 SBWRITECSR(A_GPIO_DIRECTION,gpio_direction);
585 // xprintf("GPIO DIRECTION:%16llX\n",SBREADCSR(A_GPIO_DIRECTION));
587 SBWRITECSR(A_GPIO_PIN_CLR,0x8000);
589 /*GENBUS CS 1*/
590 io_ext_cfg = SBREADCSR(A_IO_EXT_REG(8));
591 io_ext_cfg &= ~0xC;
592 io_ext_cfg |= 0x80; /* nonmux and 1 byte wide*/
593 SBWRITECSR(A_IO_EXT_REG(8),io_ext_cfg);
595 xprintf("FLASH 8-BIT MODE\n");
596 xprintf("GPIO READ:%16llX\n",SBREADCSR(A_GPIO_READ));
597 xprintf("GENCS 1:%16llX\n",SBREADCSR(A_IO_EXT_REG(8)) );
599 softc->flashdrv_probe.flash_flags &= ~FLASH_FLG_16BIT;
601 return 0;
604 /* Switch burst mode off/on. Check if we're in 8/16 bit mode to make sure it's always
605 mux in 16-bit mode. Lausanne board has 8/16 bit mode toggle at gpio 15
607 static int burst_mode(flashdrv_t *softc,int burst_on)
609 uint64_t io_ext_cfg;
611 if (burst_on) {
612 /*GENBUS CS 1*/
613 io_ext_cfg = SBREADCSR(A_IO_EXT_REG(8));
614 io_ext_cfg |= 0x20;
615 SBWRITECSR(A_IO_EXT_REG(8),io_ext_cfg);
617 xprintf("BURST ON GENCS 1:%16llX\n",SBREADCSR(A_IO_EXT_REG(8)));
619 else { /*burst off*/
620 io_ext_cfg = SBREADCSR(A_IO_EXT_REG(8));
621 io_ext_cfg &= ~0x20;
622 SBWRITECSR(A_IO_EXT_REG(8),io_ext_cfg);
624 xprintf("BURST OFF GENCS 1:%16llX\n",SBREADCSR(A_IO_EXT_REG(8)));
627 return 0;
631 /* *********************************************************************
632 * intel_flash_erase_sector(softc,offset)
634 * Erase a single sector on the flash device
636 * Input parameters:
637 * softc - device context
638 * offset - offset in flash of sector to erase
640 * Return value:
641 * 0 if ok, else error code
642 ********************************************************************* */
643 static int intel_flash_erase_sector(flashdrv_t *softc,int offset)
646 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_16BIT) {
647 WRITEFLASH_K1W(softc,offset,INTEL_FLASH_16BIT_ERASE_BLOCK);
648 WRITEFLASH_K1W(softc,offset,INTEL_FLASH_16BIT_ERASE_CONFIRM);
650 while ((READFLASH_K1W(softc,offset) & 0x8000) != 0x8000) {
651 /* NULL LOOP */
653 WRITEFLASH_K1W(softc,offset,INTEL_FLASH_16BIT_READ_MODE);
655 else {
656 WRITEFLASH_K1(softc,offset,INTEL_FLASH_ERASE_BLOCK);
657 WRITEFLASH_K1(softc,offset,INTEL_FLASH_ERASE_CONFIRM);
659 while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) {
660 /* NULL LOOP */
662 WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE);
665 return 0;
672 /* *********************************************************************
673 * FLASH_ERASE_RANGE(softc,range)
675 * Erase a range of sectors
677 * Input parameters:
678 * softc - our flash
679 * range - range structure
681 * Return value:
682 * 0 if ok
683 * else error
684 ********************************************************************* */
686 static int flash_erase_range(flashdrv_t *softc,flash_range_t *range)
688 flash_sector_t sector;
689 int res;
691 if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) {
692 return CFE_ERR_UNSUPPORTED;
696 if (range->range_base+range->range_length > softc->flashdrv_devsize) {
697 return CFE_ERR_INV_PARAM;
700 res = 0;
702 sector.flash_sector_idx = 0;
704 for (;;) {
705 res = flash_sector_query(softc,&sector);
706 if (res != 0) break;
707 if (sector.flash_sector_status == FLASH_SECTOR_INVALID) {
708 break;
711 if ((sector.flash_sector_offset >= range->range_base) &&
712 (sector.flash_sector_offset <
713 (range->range_base+range->range_length-1))) {
715 if (softc->flashdrv_nvram_ok &&
716 (sector.flash_sector_offset >= softc->flashdrv_nvraminfo.nvram_offset)) {
717 break;
719 res = FLASHOP_ERASE_SECTOR(softc,sector.flash_sector_offset);
720 if (res != 0) break;
722 sector.flash_sector_idx++;
725 return res;
729 /* *********************************************************************
730 * FLASH_ERASE_ALL(softc)
732 * Erase the entire flash device, except the NVRAM area,
733 * sector-by-sector.
735 * Input parameters:
736 * softc - our flash
738 * Return value:
739 * 0 if ok
740 * else error code
741 ********************************************************************* */
743 static int flash_erase_all(flashdrv_t *softc)
745 flash_range_t range;
747 range.range_base = 0;
748 range.range_length = softc->flashdrv_devsize;
750 return flash_erase_range(softc,&range);
753 /* *********************************************************************
754 * FLASH_CFI_GETSECTORS(softc)
756 * Query the CFI information and store the sector info in our
757 * private probe structure.
759 * Input parameters:
760 * softc - our flash info
762 * Return value:
763 * 0 if ok
764 * else error code
765 ********************************************************************* */
767 static int flash_cfi_getsectors(flashdrv_t *softc)
769 int idx;
770 int regcnt;
771 int nblks;
772 int blksiz;
774 regcnt = GETCFIBYTE(softc,FLASH_CFI_REGION_COUNT);
776 softc->flashdrv_probe.flash_nsectors = regcnt;
778 for (idx = 0; idx < regcnt; idx++) {
779 nblks = ((int)GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+0+idx*4) +
780 (int)(GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+1+idx*4)<<8)) + 1;
781 blksiz = ((int)GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+2+idx*4) +
782 (int)(GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+3+idx*4)<<8)) * 256;
783 softc->flashdrv_probe.flash_sectors[idx] =
784 FLASH_SECTOR_RANGE(nblks,blksiz);
788 return 0;
791 /* *********************************************************************
792 * FLASH_SECTOR_QUERY(softc,sector)
794 * Query the sector information about a particular sector. You can
795 * call this iteratively to find out about all of the sectors.
797 * Input parameters:
798 * softc - our flash info
799 * sector - structure to receive sector information
801 * Return value:
802 * 0 if ok
803 * else error code
804 ********************************************************************* */
806 static int flash_sector_query(flashdrv_t *softc,flash_sector_t *sector)
808 int idx;
809 int nblks;
810 int blksiz;
811 unsigned int offset;
812 int curblk;
814 if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) {
815 return CFE_ERR_UNSUPPORTED;
818 if (softc->flashdrv_probe.flash_nsectors == 0) {
819 return CFE_ERR_UNSUPPORTED;
822 offset = 0;
823 curblk = 0;
824 for (idx = 0; idx < softc->flashdrv_probe.flash_nsectors; idx++) {
825 nblks = FLASH_SECTOR_NBLKS(softc->flashdrv_probe.flash_sectors[idx]);
826 blksiz = FLASH_SECTOR_SIZE(softc->flashdrv_probe.flash_sectors[idx]);
827 if (sector->flash_sector_idx < curblk+nblks) {
828 sector->flash_sector_status = FLASH_SECTOR_OK;
829 sector->flash_sector_offset =
830 offset + (sector->flash_sector_idx-curblk)*blksiz;
831 sector->flash_sector_size = blksiz;
832 break;
835 offset += (nblks)*blksiz;
836 curblk += nblks;
840 if (idx == softc->flashdrv_probe.flash_nsectors) {
841 sector->flash_sector_status = FLASH_SECTOR_INVALID;
844 return 0;
848 /* *********************************************************************
849 * FLASH_SET_CMDSET(softc,cmdset)
851 * Set the command-set that we'll honor for this flash.
853 * Input parameters:
854 * softc - our flash
855 * cmdset - FLASH_CFI_CMDSET_xxx
857 * Return value:
858 * nothing
859 ********************************************************************* */
861 static void flash_set_cmdset(flashdrv_t *softc,int cmdset)
863 switch (cmdset) {
864 case FLASH_CFI_CMDSET_INTEL_ECS:
865 case FLASH_CFI_CMDSET_INTEL_STD:
866 softc->flashdrv_ops = &intel_flashops;
867 softc->flashdrv_widemode = 0;
868 break;
869 case FLASH_CFI_CMDSET_AMD_STD:
870 case FLASH_CFI_CMDSET_AMD_ECS:
871 softc->flashdrv_ops = &amd_flashops;
872 break;
873 default:
874 /* we don't understand the command set - treat it like ROM */
875 softc->flashdrv_info.flash_type = FLASH_TYPE_ROM;
880 /* *********************************************************************
881 * FLASH_CFI_PROBE(softc)
883 * Try to do a CFI query on this device. If we find the m
884 * magic signature, extract some useful information from the
885 * query structure.
887 * Input parameters:
888 * softc - out flash
890 * Return value:
891 * 0 if successful, <0 if error
892 ********************************************************************* */
893 static int flash_cfi_probe(flashdrv_t *softc)
895 FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_MODE);
897 if (!((GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+0) == 'Q') &&
898 (GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+1) == 'R') &&
899 (GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+2) == 'Y'))) {
901 FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT);
902 return CFE_ERR_UNSUPPORTED;
906 * Gather info from flash
909 softc->flashdrv_cfidata.cfidata_cmdset =
910 ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_COMMAND_SET))) +
911 (((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_COMMAND_SET+1))) << 8);
913 softc->flashdrv_cfidata.cfidata_devif =
914 ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_INTERFACE))) +
915 (((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_INTERFACE+1))) << 8);
917 softc->flashdrv_cfidata.cfidata_size =
918 1 << ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_SIZE)));
920 flash_cfi_getsectors(softc);
923 * Don't need to be in query mode anymore.
926 FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT);
928 softc->flashdrv_info.flash_type = FLASH_TYPE_FLASH;
930 flash_set_cmdset(softc,softc->flashdrv_cfidata.cfidata_cmdset);
932 return 0;
936 /* *********************************************************************
937 * FLASH_GETWIDTH(softc,info)
939 * Try to determine the width of the flash. This is needed for
940 * management purposes, since some 16-bit flash parts in 8-bit mode
941 * have an "A-1" (address line -1) wire to select bytes within
942 * a 16-bit word. When this is present, the flash commands
943 * will have different offsets.
945 * Input parameters:
946 * softc - our flash
947 * info - flash info structure
949 * Return value:
950 * nothing
951 ********************************************************************* */
953 static void flash_getwidth(flashdrv_t *softc,flash_info_t *info)
955 softc->flashdrv_widemode = 0; /* first try narrow */
957 if (flash_cfi_probe(softc) == 0) {
958 return;
961 softc->flashdrv_widemode = 1; /* then wide */
963 if (flash_cfi_probe(softc) == 0) {
964 return;
967 /* Just return, assume not wide if no CFI interface */
968 softc->flashdrv_widemode = 0;
970 softc->flashdrv_info.flash_type = FLASH_TYPE_ROM; /* no CFI: treat as ROM */
973 /* *********************************************************************
974 * flash_getinfo(softc)
976 * Try to determine if the specified region is flash, ROM, SRAM,
977 * or something else.
979 * Input parameters:
980 * softc - our context
982 * Return value:
983 * nothing
984 ********************************************************************* */
986 static void flash_getinfo(flashdrv_t *softc)
988 uint8_t save0,save1;
989 volatile uint8_t *ptr;
990 flash_info_t *info = &(softc->flashdrv_info);
993 * Set up some defaults based on the probe data
996 softc->flashdrv_widemode = 0;
997 info->flash_base = softc->flashdrv_probe.flash_phys;
998 info->flash_size = softc->flashdrv_probe.flash_size;
999 softc->flashdrv_devsize = softc->flashdrv_probe.flash_size;
1000 info->flash_type = FLASH_TYPE_UNKNOWN;
1001 info->flash_flags = 0;
1004 * If we've been told not to try probing, just assume
1005 * we're a flash part.
1008 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_MANUAL) {
1009 info->flash_type = FLASH_TYPE_FLASH;
1010 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_WIDE) {
1011 softc->flashdrv_widemode = TRUE;
1013 if (softc->flashdrv_probe.flash_cmdset) {
1014 flash_set_cmdset(softc,softc->flashdrv_probe.flash_cmdset);
1016 return;
1020 * Attempt to read/write byte zero. If it is changable,
1021 * this is SRAM (or maybe a ROM emulator with the write line hooked up)
1024 ptr = (volatile uint8_t *) UNCADDR(softc->flashdrv_probe.flash_phys);
1025 save0 = *ptr; /* save old value */
1026 save1 = *(ptr+1); /* save old value */
1027 *(ptr) = 0x55;
1028 if ((*ptr) == 0x55) {
1029 *(ptr) = 0xAA;
1030 if ((*ptr) == 0xAA) {
1031 info->flash_type = FLASH_TYPE_SRAM;
1035 if (*ptr == save0) info->flash_type = FLASH_TYPE_ROM;
1036 else (*ptr) = save0; /* restore old value */
1039 * If we thought it was ROM, try doing a CFI query
1040 * to see if it was flash. This check is kind of kludgey
1041 * but should work.
1044 if (info->flash_type == FLASH_TYPE_ROM) {
1045 flash_getwidth(softc,info);
1046 if (info->flash_type == FLASH_TYPE_FLASH) {
1051 /* *********************************************************************
1052 * flashdrv_setup_nvram(softc)
1054 * If we're going to be using a sector of the flash for NVRAM,
1055 * go find that sector and set it up.
1057 * Input parameters:
1058 * softc - our flash
1060 * Return value:
1061 * nothing. flashdrv_nvram_ok might change though.
1062 ********************************************************************* */
1064 static void flashdrv_setup_nvram(flashdrv_t *softc)
1066 flash_sector_t sector;
1067 int res;
1069 softc->flashdrv_nvram_ok = FALSE;
1071 if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) {
1072 return;
1075 sector.flash_sector_idx = 0;
1076 for (;;) {
1077 res = flash_sector_query(softc,&sector);
1078 if (res == CFE_ERR_UNSUPPORTED) break;
1079 if (res == 0) {
1080 if (sector.flash_sector_status != FLASH_SECTOR_INVALID) {
1081 sector.flash_sector_idx++;
1082 continue;
1085 break;
1088 /* The sector offset will still contain the value at the end
1089 of the last successful call. That's the last sector, so
1090 we can now use this to fill in the NVRAM info structure */
1092 if (res != CFE_ERR_UNSUPPORTED) {
1093 softc->flashdrv_nvraminfo.nvram_offset = sector.flash_sector_offset;
1094 softc->flashdrv_nvraminfo.nvram_size = sector.flash_sector_size;
1095 softc->flashdrv_nvraminfo.nvram_eraseflg = TRUE; /* needs erase */
1096 softc->flashdrv_nvram_ok = TRUE;
1098 * Set the flash's size as reported in the flash_info structure
1099 * to be the size without the NVRAM sector at the end.
1101 softc->flashdrv_info.flash_size = sector.flash_sector_offset;
1102 softc->flashdrv_devsize = sector.flash_sector_offset;
1108 /* *********************************************************************
1109 * flashdrv_probe(drv,probe_a,probe_b,probe_ptr)
1111 * Device probe routine. Attach the flash device to
1112 * CFE's device table.
1114 * Input parameters:
1115 * drv - driver descriptor
1116 * probe_a - physical address of flash
1117 * probe_b - size of flash (bytes)
1118 * probe_ptr - unused
1120 * Return value:
1121 * nothing
1122 ********************************************************************* */
1124 static void flashdrv_probe(cfe_driver_t *drv,
1125 unsigned long probe_a, unsigned long probe_b,
1126 void *probe_ptr)
1128 flashdrv_t *softc;
1129 flash_probe_t *probe;
1130 char descr[80];
1132 probe = (flash_probe_t *) probe_ptr;
1135 * probe_a is the flash base address
1136 * probe_b is the size of the flash
1137 * probe_ptr is unused.
1140 softc = (flashdrv_t *) KMALLOC(sizeof(flashdrv_t),0);
1141 if (softc) {
1142 memset(softc,0,sizeof(flashdrv_t));
1144 if (probe) {
1145 /* Passed probe structure, do fancy stuff */
1146 memcpy(&(softc->flashdrv_probe),probe,sizeof(flash_probe_t));
1147 if (softc->flashdrv_probe.flash_prog_phys == 0) {
1148 softc->flashdrv_probe.flash_prog_phys =
1149 softc->flashdrv_probe.flash_phys;
1152 else {
1153 /* Didn't pass probe structure, do the compatible thing */
1154 softc->flashdrv_probe.flash_phys = probe_a;
1155 softc->flashdrv_probe.flash_prog_phys = probe_a;
1156 softc->flashdrv_probe.flash_size = probe_b;
1158 softc->flashdrv_probe.flash_flags = FLASH_FLG_NVRAM;
1161 softc->flashdrv_cmdaddr = (char *) UNCADDR(softc->flashdrv_probe.flash_prog_phys);
1162 softc->flashdrv_initialized = 0;
1163 softc->flashdrv_ops = &FLASHOPS_DEFAULT;
1164 xsprintf(descr,"%s at %08X size %uKB",drv->drv_description,
1165 softc->flashdrv_probe.flash_phys,
1166 softc->flashdrv_probe.flash_size/1024);
1167 cfe_attach(drv,softc,NULL,descr);
1173 /* *********************************************************************
1174 * flashdrv_open(ctx)
1176 * Called when the flash device is opened.
1178 * Input parameters:
1179 * ctx - device context
1181 * Return value:
1182 * 0 if ok else error code
1183 ********************************************************************* */
1185 static int flashdrv_open(cfe_devctx_t *ctx)
1187 flashdrv_t *softc = ctx->dev_softc;
1190 * do initialization
1193 if (!softc->flashdrv_initialized) {
1196 * Assume it's not an NVRAM-capable flash
1199 softc->flashdrv_nvram_ok = FALSE;
1202 * Probe flash for geometry
1204 flash_getinfo(softc);
1207 * Find the last sector if in NVRAM mode
1210 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_NVRAM) {
1211 flashdrv_setup_nvram(softc);
1214 softc->flashdrv_initialized = TRUE;
1217 return 0;
1221 /* *********************************************************************
1222 * flashdrv_read(ctx,buffer)
1224 * Read data from the flash device. The flash device is
1225 * considered to be like a disk (you need to specify the offset).
1227 * Input parameters:
1228 * ctx - device context
1229 * buffer - buffer descriptor
1231 * Return value:
1232 * 0 if ok, else error code
1233 ********************************************************************* */
1235 static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
1237 flashdrv_t *softc = ctx->dev_softc;
1238 unsigned char *bptr;
1239 unsigned char *flashbase;
1240 int offset;
1241 int blen;
1244 * For now, read the flash from K1 (always). Eventually
1245 * we need to flush the cache after a write.
1248 flashbase = (unsigned char *) UNCADDR(softc->flashdrv_probe.flash_phys);
1250 bptr = buffer->buf_ptr;
1251 blen = buffer->buf_length;
1252 offset = (int) buffer->buf_offset;
1254 xprintf("FLASHDRV READ blen:%d offset:%d\n",blen,offset);
1256 if (!(softc->flashdrv_unlocked)) {
1257 if ((offset + blen) > softc->flashdrv_devsize) {
1258 blen = softc->flashdrv_devsize - offset;
1262 #ifdef _FLASH_BROKEN_BYTEREAD_
1264 * BCM1250 users: don't worry about this. This hack is for
1265 * something else and should not be used with the BCM1250.
1267 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_16BIT) {
1268 uint16_t *src;
1269 int len = blen;
1270 int idx = 0;
1271 union {
1272 uint16_t x;
1273 char b[2];
1274 } u;
1276 src = (uint16_t *) flashbase;
1277 while (len > 0) {
1278 u.x = src[(idx+offset)>>1];
1279 *bptr++ = u.b[(idx+offset)&1];
1280 len--;
1281 idx++;
1284 else {
1285 memcpy(bptr,flashbase + offset, blen);
1287 #else
1288 memcpy(bptr,flashbase + offset, blen);
1289 #endif
1291 buffer->buf_retlen = blen;
1293 return 0;
1296 /* *********************************************************************
1297 * flashdrv_inpstat(ctx,inpstat)
1299 * Return "input status". For flash devices, we always return true.
1301 * Input parameters:
1302 * ctx - device context
1303 * inpstat - input status structure
1305 * Return value:
1306 * 0 if ok, else error code
1307 ********************************************************************* */
1309 static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
1311 /* flashdrv_t *softc = ctx->dev_softc; */
1313 inpstat->inp_status = 1;
1314 return 0;
1318 /* *********************************************************************
1319 * flash_writeall(softc,buffer)
1321 * Write the entire flash and reboot. This is a special case
1322 * used for when the flash currently being used for CFE's
1323 * execution is updated. A small assembly routine is relocated
1324 * to DRAM to do the update (so that the programming routine is
1325 * not erased while we're running it), and then the update
1326 * is done. When completed, CFE is restarted.
1328 * (we could get really sleazy here and touch the routine first
1329 * so it will stay in the cache, thereby eliminating the need
1330 * to relocate it, but that's dangerous)
1332 * Input parameters:
1333 * softc - our context
1334 * buffer - buffer descriptor
1336 * Return value:
1337 * does not return
1338 ********************************************************************* */
1340 static int flash_writeall(flashdrv_t *softc,iocb_buffer_t *buffer)
1342 void *rptr;
1343 void (*routine)(unsigned char *data,unsigned int flashbase,
1344 unsigned int size,unsigned int secsize);
1346 rptr = KMALLOC(flash_write_all_len,0);
1348 if (!rptr) return CFE_ERR_NOMEM;
1350 memcpy(rptr,flash_write_all_ptr,flash_write_all_len);
1352 _cfe_flushcache(0);
1354 routine = rptr;
1356 (*routine)(buffer->buf_ptr,
1357 softc->flashdrv_probe.flash_phys,
1358 buffer->buf_length,
1359 65536);
1361 return -1;
1365 /* *********************************************************************
1366 * flashdrv_write(ctx,buffer)
1368 * Write data to the flash device. The flash device is
1369 * considered to be like a disk (you need to specify the offset).
1371 * Input parameters:
1372 * ctx - device context
1373 * buffer - buffer descriptor
1375 * Return value:
1376 * 0 if ok, else error code
1377 ********************************************************************* */
1379 static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
1381 flashdrv_t *softc = ctx->dev_softc;
1382 unsigned char *bptr;
1383 int offset;
1384 int blen;
1385 int res;
1387 bptr = buffer->buf_ptr;
1388 blen = buffer->buf_length;
1389 offset = (int) buffer->buf_offset;
1391 if (!(softc->flashdrv_unlocked)) {
1392 if ((offset + blen) > softc->flashdrv_devsize) {
1393 blen = softc->flashdrv_devsize - offset;
1397 res = FLASHOP_WRITE_BLOCK(softc,offset,bptr,blen);
1399 buffer->buf_retlen = res;
1402 return (res >= blen) ? 0 : CFE_ERR_IOERR;
1405 /* *********************************************************************
1406 * flashdrv_ioctl(ctx,buffer)
1408 * Handle special IOCTL functions for the flash. Flash devices
1409 * support NVRAM information, sector and chip erase, and a
1410 * special IOCTL for updating the running copy of CFE.
1412 * Input parameters:
1413 * ctx - device context
1414 * buffer - descriptor for IOCTL parameters
1416 * Return value:
1417 * 0 if ok else error
1418 ********************************************************************* */
1419 static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
1421 flashdrv_t *softc = ctx->dev_softc;
1422 nvram_info_t *info;
1423 int offset;
1424 int * mode;
1427 * If using flash to store environment, only the last sector
1428 * is used for environment stuff.
1431 switch ((int)buffer->buf_ioctlcmd) {
1432 case IOCTL_NVRAM_ERASE:
1433 if (softc->flashdrv_nvram_ok == FALSE) return CFE_ERR_UNSUPPORTED;
1434 FLASHOP_ERASE_SECTOR(softc,softc->flashdrv_nvraminfo.nvram_offset);
1435 return 0;
1437 case IOCTL_NVRAM_GETINFO:
1438 info = (nvram_info_t *) buffer->buf_ptr;
1439 if (buffer->buf_length != sizeof(nvram_info_t)) return CFE_ERR_INV_PARAM;
1440 if (softc->flashdrv_nvram_ok == FALSE) return CFE_ERR_UNSUPPORTED;
1441 info->nvram_offset = softc->flashdrv_nvraminfo.nvram_offset;
1442 info->nvram_size = softc->flashdrv_nvraminfo.nvram_size;
1443 info->nvram_eraseflg = softc->flashdrv_nvraminfo.nvram_eraseflg;
1444 buffer->buf_retlen = sizeof(nvram_info_t);
1445 return 0;
1447 case IOCTL_FLASH_ERASE_SECTOR:
1448 offset = (int) buffer->buf_offset;
1449 if (!(softc->flashdrv_unlocked)) {
1450 if (offset >= softc->flashdrv_devsize) return -1;
1452 FLASHOP_ERASE_SECTOR(softc,offset);
1453 return 0;
1455 case IOCTL_FLASH_ERASE_ALL:
1456 offset = (int) buffer->buf_offset;
1457 if (offset != 0) return -1;
1458 flash_erase_all(softc);
1459 return 0;
1461 case IOCTL_FLASH_WRITE_ALL:
1462 flash_writeall(softc,buffer);
1463 return -1; /* should not return */
1465 case IOCTL_FLASH_GETINFO:
1466 memcpy(buffer->buf_ptr,&(softc->flashdrv_info),sizeof(flash_info_t));
1467 return 0;
1469 case IOCTL_FLASH_GETSECTORS:
1470 return flash_sector_query(softc,(flash_sector_t *) buffer->buf_ptr);
1473 case IOCTL_FLASH_ERASE_RANGE:
1474 return flash_erase_range(softc,(flash_range_t *) buffer->buf_ptr);
1476 case IOCTL_NVRAM_UNLOCK:
1477 softc->flashdrv_unlocked = TRUE;
1478 break;
1480 case IOCTL_FLASH_DATA_WIDTH_MODE:
1481 mode = (int *) buffer->buf_ptr;
1482 return intel_flash_data_width_mode(softc,*mode);
1483 break;
1485 case IOCTL_FLASH_BURST_MODE:
1486 mode = (int *) buffer->buf_ptr;
1487 return burst_mode(softc,*mode);
1488 break;
1490 default:
1491 return -1;
1494 return -1;
1498 /* *********************************************************************
1499 * flashdrv_close(ctx)
1501 * Close the flash device.
1503 * Input parameters:
1504 * ctx - device context
1506 * Return value:
1508 ********************************************************************* */
1509 static int flashdrv_close(cfe_devctx_t *ctx)
1511 /* flashdrv_t *softc = ctx->dev_softc; */
1514 return 0;