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,&sector);
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,&sector);
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(&sector,&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