GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / dev / dev_flash.c
blob5b2aba4e4e48b2aed3cfc96440bce944c0d71df4
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * Flash device driver File: dev_flash.c
5 *
6 * This driver supports various types of flash
7 * parts. You can also put the environment storage in
8 * the flash - the top sector is reserved for that purpose.
9 *
10 * Author: Mitch Lichtenberg (mpl@broadcom.com)
12 *********************************************************************
14 * Copyright 2000,2001,2002,2003
15 * Broadcom Corporation. All rights reserved.
17 * This software is furnished under license and may be used and
18 * copied only in accordance with the following terms and
19 * conditions. Subject to these conditions, you may download,
20 * copy, install, use, modify and distribute modified or unmodified
21 * copies of this software in source and/or binary form. No title
22 * or ownership is transferred hereby.
24 * 1) Any source code used, modified or distributed must reproduce
25 * and retain this copyright notice and list of conditions
26 * as they appear in the source file.
28 * 2) No right is granted to use any trade name, trademark, or
29 * logo of Broadcom Corporation. The "Broadcom Corporation"
30 * name may not be used to endorse or promote products derived
31 * from this software without the prior written permission of
32 * Broadcom Corporation.
34 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
35 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
36 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
37 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
38 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
39 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
40 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
42 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
44 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
45 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
46 * THE POSSIBILITY OF SUCH DAMAGE.
47 ********************************************************************* */
50 #include "lib_types.h"
51 #include "lib_malloc.h"
52 #include "lib_printf.h"
53 #include "lib_string.h"
54 #include "addrspace.h"
55 #include "cfe_iocb.h"
56 #include "cfe_device.h"
57 #include "cfe_ioctl.h"
58 #include "cfe_error.h"
60 #include "dev_flash.h"
62 /* *********************************************************************
63 * Macros
64 ********************************************************************* */
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)))
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)))
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)))
78 #define GETCFIBYTE(softc,offset) READFLASH_K1(softc,((offset) << (softc->flashdrv_widemode)))
80 /* *********************************************************************
81 * Forward declarations
82 ********************************************************************* */
85 static void flashdrv_probe(cfe_driver_t *drv,
86 unsigned long probe_a, unsigned long probe_b,
87 void *probe_ptr);
90 static int flashdrv_open(cfe_devctx_t *ctx);
91 static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
92 static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
93 static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
94 static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
95 static int flashdrv_close(cfe_devctx_t *ctx);
97 /* *********************************************************************
98 * Device dispatch
99 ********************************************************************* */
101 const 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
112 const cfe_driver_t flashdrv = {
113 "CFI flash",
114 "flash",
115 CFE_DEV_FLASH,
116 &flashdrv_dispatch,
117 flashdrv_probe
121 /* *********************************************************************
122 * Structures
123 ********************************************************************* */
125 typedef 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;
131 typedef struct flashops_s flashops_t;
133 typedef 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;
147 struct flashops_s {
148 int (*erasesector)(flashdrv_t *f,int offset);
149 int (*writeblk)(flashdrv_t *f,int offset,void *buf,int len);
152 /* *********************************************************************
153 * Macros
154 ********************************************************************* */
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))
159 /* *********************************************************************
160 * forward declarations
161 ********************************************************************* */
164 static int flash_sector_query(flashdrv_t *softc,flash_sector_t *sector);
166 static int amd_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len);
167 static int amd_flash_erase_sector(flashdrv_t *softc,int offset);
169 static int intel_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len);
170 static int intel_flash_erase_sector(flashdrv_t *softc,int offset);
172 static flashops_t amd_flashops = {
173 amd_flash_erase_sector,
174 amd_flash_write_block,
177 static flashops_t intel_flashops = {
178 intel_flash_erase_sector,
179 intel_flash_write_block,
182 #define FLASHOPS_DEFAULT amd_flashops
186 /* *********************************************************************
187 * Externs
188 ********************************************************************* */
190 extern void *flash_write_all_ptr;
191 extern int flash_write_all_len;
193 extern void _cfe_flushcache(int);
197 /* *********************************************************************
198 * amd_flash_write_byte(softc,offset,val)
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.
204 * Input parameters:
205 * softc - flash context
206 * offset - distance in bytes into the flash
207 * val - byte to write
209 * Return value:
210 * 0 if ok
211 * else if flash could not be written
212 ********************************************************************* */
213 static inline int amd_flash_write_byte(flashdrv_t *softc,int offset, unsigned char val)
215 unsigned int value;
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);
221 /* Send a program command */
222 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_PROGRAM);
224 /* Write a byte */
225 WRITEFLASH_K1(softc,offset,val);
227 for (;;) {
228 value = READFLASH_K1(softc,offset) & 0xFF;
230 if ((value & 0x80) == (val & 0x80)) {
231 return 0;
233 if ((value & 0x20) != 0x20) {
234 continue;
237 if ((READFLASH_K1(softc,offset) & 0x80) == (val & 0x80)) {
238 return 0;
240 else {
241 return -1;
247 /* *********************************************************************
248 * amd_flash_write_block(softc,offset,val)
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.
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
260 * Return value:
261 * number of bytes written
262 ********************************************************************* */
263 static int amd_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len)
265 unsigned char *ptr;
267 ptr = buf;
269 while (len) {
270 if (amd_flash_write_byte(softc,offset,*ptr) < 0) break;
271 len--;
272 ptr++;
273 offset++;
277 return (ptr - (unsigned char *)buf);
281 /* *********************************************************************
282 * amd_flash_erase_sector(softc,offset)
284 * Erase a single sector in the flash device
286 * Input parameters:
287 * softc - device context
288 * offset - offset in flash of sector to erase
290 * Return value:
291 * 0 if ok, else error code
292 ********************************************************************* */
294 static int amd_flash_erase_sector(flashdrv_t *softc,int offset)
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);
300 /* send the erase command */
301 FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_ERASE_3); /* cycle 3 */
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);
308 * Send the "erase sector" qualifier - don't use FLASHCMD
309 * because it changes the offset.
311 WRITEFLASH_K1(softc,offset,AMD_FLASH_ERASE_SEC_6);
313 while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) {
314 /* NULL LOOP */
317 return 0;
322 /* *********************************************************************
323 * intel_flash_write_byte(softc,offset,val)
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.
329 * Input parameters:
330 * softc - flash context
331 * offset - distance in bytes into the flash
332 * val - byte to write
334 * Return value:
335 * 0 if ok
336 * else if flash could not be written
337 ********************************************************************* */
338 static inline int intel_flash_write_byte(flashdrv_t *softc,
339 int offset, unsigned char val)
341 unsigned int value;
343 /* Send a program command */
344 WRITEFLASH_K1(softc,offset,INTEL_FLASH_PROGRAM);
346 /* Write a byte */
347 WRITEFLASH_K1(softc,offset,val);
350 while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) {
351 /* NULL LOOP */
354 value = READFLASH_K1(softc,offset) & 0xFF;
356 if (value & (0x01|0x08|0x10)) return -1;
357 return 0;
360 /* *********************************************************************
361 * intel_flash_write_word(softc,offset,val)
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.
367 * Input parameters:
368 * softc - flash context
369 * offset - distance in bytes into the flash
370 * val - word to write
372 * Return value:
373 * 0 if ok
374 * else if flash could not be written
375 ********************************************************************* */
376 static inline int intel_flash_write_word(flashdrv_t *softc,
377 int offset, unsigned short val)
379 unsigned int value;
382 /* Send a program command */
383 WRITEFLASH_K1W(softc,offset,INTEL_FLASH_PROGRAM);
385 /* Write a byte */
386 WRITEFLASH_K1W(softc,offset,val);
389 while ((READFLASH_K1W(softc,offset) & 0x80) != 0x80) {
390 /* NULL LOOP */
393 value = READFLASH_K1W(softc,offset) & 0xFF;
395 if (value & (0x01|0x08|0x10)) return -1;
396 return 0;
399 /* *********************************************************************
400 * intel_flash_write_block(softc,offset,val)
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.
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
412 * Return value:
413 * number of bytes written
414 ********************************************************************* */
415 static int intel_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len)
417 unsigned char *ptr;
418 unsigned short *ptrw;
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;
429 WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE);
430 return ((unsigned char *) ptrw - (unsigned char *)buf);
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++;
440 WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE);
441 return (ptr - (unsigned char *)buf);
447 /* *********************************************************************
448 * intel_flash_erase_sector(softc,offset)
450 * Erase a single sector on the flash device
452 * Input parameters:
453 * softc - device context
454 * offset - offset in flash of sector to erase
456 * Return value:
457 * 0 if ok, else error code
458 ********************************************************************* */
459 static int intel_flash_erase_sector(flashdrv_t *softc,int offset)
461 WRITEFLASH_K1(softc,offset,INTEL_FLASH_ERASE_BLOCK);
462 WRITEFLASH_K1(softc,offset,INTEL_FLASH_ERASE_CONFIRM);
464 while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) {
465 /* NULL LOOP */
467 WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE);
469 return 0;
476 /* *********************************************************************
477 * FLASH_ERASE_RANGE(softc,range)
479 * Erase a range of sectors
481 * Input parameters:
482 * softc - our flash
483 * range - range structure
485 * Return value:
486 * 0 if ok
487 * else error
488 ********************************************************************* */
490 static int flash_erase_range(flashdrv_t *softc,flash_range_t *range)
492 flash_sector_t sector;
493 int res;
495 if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) {
496 return CFE_ERR_UNSUPPORTED;
500 if (range->range_base+range->range_length > softc->flashdrv_devsize) {
501 return CFE_ERR_INV_PARAM;
504 res = 0;
506 sector.flash_sector_idx = 0;
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;
515 if ((sector.flash_sector_offset >= range->range_base) &&
516 (sector.flash_sector_offset <
517 (range->range_base+range->range_length-1))) {
519 if (softc->flashdrv_nvram_ok &&
520 (sector.flash_sector_offset >= softc->flashdrv_nvraminfo.nvram_offset)) {
521 break;
523 res = FLASHOP_ERASE_SECTOR(softc,sector.flash_sector_offset);
524 if (res != 0) break;
526 sector.flash_sector_idx++;
529 return res;
533 /* *********************************************************************
534 * FLASH_ERASE_ALL(softc)
536 * Erase the entire flash device, except the NVRAM area,
537 * sector-by-sector.
539 * Input parameters:
540 * softc - our flash
542 * Return value:
543 * 0 if ok
544 * else error code
545 ********************************************************************* */
547 static int flash_erase_all(flashdrv_t *softc)
549 flash_range_t range;
551 range.range_base = 0;
552 range.range_length = softc->flashdrv_devsize;
554 return flash_erase_range(softc,&range);
557 /* *********************************************************************
558 * FLASH_CFI_GETSECTORS(softc)
560 * Query the CFI information and store the sector info in our
561 * private probe structure.
563 * Input parameters:
564 * softc - our flash info
566 * Return value:
567 * 0 if ok
568 * else error code
569 ********************************************************************* */
571 static int flash_cfi_getsectors(flashdrv_t *softc)
573 int idx;
574 int regcnt;
575 int nblks;
576 int blksiz;
578 regcnt = GETCFIBYTE(softc,FLASH_CFI_REGION_COUNT);
580 softc->flashdrv_probe.flash_nsectors = regcnt;
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);
592 return 0;
595 /* *********************************************************************
596 * FLASH_SECTOR_QUERY(softc,sector)
598 * Query the sector information about a particular sector. You can
599 * call this iteratively to find out about all of the sectors.
601 * Input parameters:
602 * softc - our flash info
603 * sector - structure to receive sector information
605 * Return value:
606 * 0 if ok
607 * else error code
608 ********************************************************************* */
610 static int flash_sector_query(flashdrv_t *softc,flash_sector_t *sector)
612 int idx;
613 int nblks;
614 int blksiz;
615 unsigned int offset;
616 int curblk;
618 if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) {
619 return CFE_ERR_UNSUPPORTED;
622 if (softc->flashdrv_probe.flash_nsectors == 0) {
623 return CFE_ERR_UNSUPPORTED;
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;
639 offset += (nblks)*blksiz;
640 curblk += nblks;
644 if (idx == softc->flashdrv_probe.flash_nsectors) {
645 sector->flash_sector_status = FLASH_SECTOR_INVALID;
648 return 0;
652 /* *********************************************************************
653 * FLASH_SET_CMDSET(softc,cmdset)
655 * Set the command-set that we'll honor for this flash.
657 * Input parameters:
658 * softc - our flash
659 * cmdset - FLASH_CFI_CMDSET_xxx
661 * Return value:
662 * nothing
663 ********************************************************************* */
665 static void flash_set_cmdset(flashdrv_t *softc,int cmdset)
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;
684 /* *********************************************************************
685 * FLASH_CFI_PROBE(softc)
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.
691 * Input parameters:
692 * softc - out flash
694 * Return value:
695 * 0 if successful, <0 if error
696 ********************************************************************* */
697 static int flash_cfi_probe(flashdrv_t *softc)
699 FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_MODE);
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'))) {
705 FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT);
706 return CFE_ERR_UNSUPPORTED;
710 * Gather info from flash
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);
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);
721 softc->flashdrv_cfidata.cfidata_size =
722 1 << ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_SIZE)));
724 flash_cfi_getsectors(softc);
727 * Don't need to be in query mode anymore.
730 FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT);
732 softc->flashdrv_info.flash_type = FLASH_TYPE_FLASH;
734 flash_set_cmdset(softc,softc->flashdrv_cfidata.cfidata_cmdset);
736 return 0;
740 /* *********************************************************************
741 * FLASH_GETWIDTH(softc,info)
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.
749 * Input parameters:
750 * softc - our flash
751 * info - flash info structure
753 * Return value:
754 * nothing
755 ********************************************************************* */
757 static void flash_getwidth(flashdrv_t *softc,flash_info_t *info)
759 softc->flashdrv_widemode = 0; /* first try narrow */
761 if (flash_cfi_probe(softc) == 0) {
762 return;
765 softc->flashdrv_widemode = 1; /* then wide */
767 if (flash_cfi_probe(softc) == 0) {
768 return;
771 /* Just return, assume not wide if no CFI interface */
772 softc->flashdrv_widemode = 0;
774 softc->flashdrv_info.flash_type = FLASH_TYPE_ROM; /* no CFI: treat as ROM */
777 /* *********************************************************************
778 * flash_getinfo(softc)
780 * Try to determine if the specified region is flash, ROM, SRAM,
781 * or something else.
783 * Input parameters:
784 * softc - our context
786 * Return value:
787 * nothing
788 ********************************************************************* */
790 static void flash_getinfo(flashdrv_t *softc)
792 uint8_t save0,save1;
793 volatile uint8_t *ptr;
794 flash_info_t *info = &(softc->flashdrv_info);
797 * Set up some defaults based on the probe data
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;
808 * If we've been told not to try probing, just assume
809 * we're a flash part.
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;
817 if (softc->flashdrv_probe.flash_cmdset) {
818 flash_set_cmdset(softc,softc->flashdrv_probe.flash_cmdset);
820 return;
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)
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;
839 if (*ptr == save0) info->flash_type = FLASH_TYPE_ROM;
840 else (*ptr) = save0; /* restore old value */
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.
848 if (info->flash_type == FLASH_TYPE_ROM) {
849 flash_getwidth(softc,info);
850 if (info->flash_type == FLASH_TYPE_FLASH) {
855 /* *********************************************************************
856 * flashdrv_setup_nvram(softc)
858 * If we're going to be using a sector of the flash for NVRAM,
859 * go find that sector and set it up.
861 * Input parameters:
862 * softc - our flash
864 * Return value:
865 * nothing. flashdrv_nvram_ok might change though.
866 ********************************************************************* */
868 static void flashdrv_setup_nvram(flashdrv_t *softc)
870 flash_sector_t sector;
871 int res;
873 softc->flashdrv_nvram_ok = FALSE;
875 if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) {
876 return;
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;
889 break;
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 */
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;
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.
905 softc->flashdrv_info.flash_size = sector.flash_sector_offset;
906 softc->flashdrv_devsize = sector.flash_sector_offset;
912 /* *********************************************************************
913 * flashdrv_probe(drv,probe_a,probe_b,probe_ptr)
915 * Device probe routine. Attach the flash device to
916 * CFE's device table.
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
924 * Return value:
925 * nothing
926 ********************************************************************* */
928 static void flashdrv_probe(cfe_driver_t *drv,
929 unsigned long probe_a, unsigned long probe_b,
930 void *probe_ptr)
932 flashdrv_t *softc;
933 flash_probe_t *probe;
934 char descr[80];
936 probe = (flash_probe_t *) probe_ptr;
939 * probe_a is the flash base address
940 * probe_b is the size of the flash
941 * probe_ptr is unused.
944 softc = (flashdrv_t *) KMALLOC(sizeof(flashdrv_t),0);
945 if (softc) {
946 memset(softc,0,sizeof(flashdrv_t));
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;
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;
964 softc->flashdrv_cmdaddr = (unsigned 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);
976 /* *********************************************************************
977 * flashdrv_open(ctx)
979 * Called when the flash device is opened.
981 * Input parameters:
982 * ctx - device context
984 * Return value:
985 * 0 if ok else error code
986 ********************************************************************* */
988 static int flashdrv_open(cfe_devctx_t *ctx)
990 flashdrv_t *softc = ctx->dev_softc;
993 * do initialization
996 if (!softc->flashdrv_initialized) {
999 * Assume it's not an NVRAM-capable flash
1002 softc->flashdrv_nvram_ok = FALSE;
1005 * Probe flash for geometry
1007 flash_getinfo(softc);
1010 * Find the last sector if in NVRAM mode
1013 if (softc->flashdrv_probe.flash_flags & FLASH_FLG_NVRAM) {
1014 flashdrv_setup_nvram(softc);
1017 softc->flashdrv_initialized = TRUE;
1020 return 0;
1024 /* *********************************************************************
1025 * flashdrv_read(ctx,buffer)
1027 * Read data from the flash device. The flash device is
1028 * considered to be like a disk (you need to specify the offset).
1030 * Input parameters:
1031 * ctx - device context
1032 * buffer - buffer descriptor
1034 * Return value:
1035 * 0 if ok, else error code
1036 ********************************************************************* */
1038 static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
1040 flashdrv_t *softc = ctx->dev_softc;
1041 unsigned char *bptr;
1042 unsigned char *flashbase;
1043 int offset;
1044 int blen;
1047 * For now, read the flash from K1 (always). Eventually
1048 * we need to flush the cache after a write.
1051 flashbase = (unsigned char *) UNCADDR(softc->flashdrv_probe.flash_phys);
1053 bptr = buffer->buf_ptr;
1054 blen = buffer->buf_length;
1055 offset = (int) buffer->buf_offset;
1057 if (!(softc->flashdrv_unlocked)) {
1058 if ((offset + blen) > softc->flashdrv_devsize) {
1059 blen = softc->flashdrv_devsize - offset;
1063 #ifdef _FLASH_BROKEN_BYTEREAD_
1065 * BCM1250 users: don't worry about this. This hack is for
1066 * something else and should not be used with the BCM1250.
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;
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++;
1085 else {
1086 memcpy(bptr,flashbase + offset, blen);
1088 #else
1089 memcpy(bptr,flashbase + offset, blen);
1090 #endif
1092 buffer->buf_retlen = blen;
1094 return 0;
1097 /* *********************************************************************
1098 * flashdrv_inpstat(ctx,inpstat)
1100 * Return "input status". For flash devices, we always return true.
1102 * Input parameters:
1103 * ctx - device context
1104 * inpstat - input status structure
1106 * Return value:
1107 * 0 if ok, else error code
1108 ********************************************************************* */
1110 static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
1112 /* flashdrv_t *softc = ctx->dev_softc; */
1114 inpstat->inp_status = 1;
1115 return 0;
1119 /* *********************************************************************
1120 * flash_writeall(softc,buffer)
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.
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)
1133 * Input parameters:
1134 * softc - our context
1135 * buffer - buffer descriptor
1137 * Return value:
1138 * does not return
1139 ********************************************************************* */
1141 static int flash_writeall(flashdrv_t *softc,iocb_buffer_t *buffer)
1143 void *rptr;
1144 void (*routine)(unsigned char *data,unsigned int flashbase,
1145 unsigned int size,unsigned int secsize);
1147 rptr = KMALLOC(flash_write_all_len,0);
1149 if (!rptr) return CFE_ERR_NOMEM;
1151 memcpy(rptr,flash_write_all_ptr,flash_write_all_len);
1153 _cfe_flushcache(0);
1155 routine = rptr;
1157 (*routine)(buffer->buf_ptr,
1158 softc->flashdrv_probe.flash_phys,
1159 buffer->buf_length,
1160 65536);
1162 return -1;
1166 /* *********************************************************************
1167 * flashdrv_write(ctx,buffer)
1169 * Write data to the flash device. The flash device is
1170 * considered to be like a disk (you need to specify the offset).
1172 * Input parameters:
1173 * ctx - device context
1174 * buffer - buffer descriptor
1176 * Return value:
1177 * 0 if ok, else error code
1178 ********************************************************************* */
1180 static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
1182 flashdrv_t *softc = ctx->dev_softc;
1183 unsigned char *bptr;
1184 int offset;
1185 int blen;
1186 int res;
1188 bptr = buffer->buf_ptr;
1189 blen = buffer->buf_length;
1190 offset = (int) buffer->buf_offset;
1192 if (!(softc->flashdrv_unlocked)) {
1193 if ((offset + blen) > softc->flashdrv_devsize) {
1194 blen = softc->flashdrv_devsize - offset;
1198 res = FLASHOP_WRITE_BLOCK(softc,offset,bptr,blen);
1200 buffer->buf_retlen = res;
1203 return (res == blen) ? 0 : CFE_ERR_IOERR;
1206 /* *********************************************************************
1207 * flashdrv_ioctl(ctx,buffer)
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.
1213 * Input parameters:
1214 * ctx - device context
1215 * buffer - descriptor for IOCTL parameters
1217 * Return value:
1218 * 0 if ok else error
1219 ********************************************************************* */
1220 static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
1222 flashdrv_t *softc = ctx->dev_softc;
1223 nvram_info_t *info;
1224 int offset;
1227 * If using flash to store environment, only the last sector
1228 * is used for environment stuff.
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;
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;
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;
1252 FLASHOP_ERASE_SECTOR(softc,offset);
1253 return 0;
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;
1261 case IOCTL_FLASH_WRITE_ALL:
1262 flash_writeall(softc,buffer);
1263 return -1; /* should not return */
1265 case IOCTL_FLASH_GETINFO:
1266 memcpy(buffer->buf_ptr,&(softc->flashdrv_info),sizeof(flash_info_t));
1267 return 0;
1269 case IOCTL_FLASH_GETSECTORS:
1270 return flash_sector_query(softc,(flash_sector_t *) buffer->buf_ptr);
1273 case IOCTL_FLASH_ERASE_RANGE:
1274 return flash_erase_range(softc,(flash_range_t *) buffer->buf_ptr);
1276 case IOCTL_NVRAM_UNLOCK:
1277 softc->flashdrv_unlocked = TRUE;
1278 break;
1280 default:
1281 return -1;
1284 return -1;
1288 /* *********************************************************************
1289 * flashdrv_close(ctx)
1291 * Close the flash device.
1293 * Input parameters:
1294 * ctx - device context
1296 * Return value:
1298 ********************************************************************* */
1299 static int flashdrv_close(cfe_devctx_t *ctx)
1301 /* flashdrv_t *softc = ctx->dev_softc; */
1304 return 0;