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