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