amd29LvMtd.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:17k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* amd29LvMtd.c - TrueFFS MTD for AMD AM29LV devices */
  2.  
  3. /* Copyright 2000 Wind River, Inc. */
  4. /*
  5. modification history
  6. --------------------
  7. 01h,27oct01,mil  Removed inline eieio and replaced with CACHE_PIPE_FLUSH().
  8. 01g,11oct01,mil  Merged from post T2.1 release into T2.2.
  9. 01f,22aug01,mil  Decoupled this MTD from BSP by using tffsFlashBaseAdrs from
  10.                  sysTffs.c.
  11. 01e,21aug01,mil  Created in mcpn765 for TFFS until merged back to
  12.                  target/src/drv/tffs/amdmtd.c.
  13. 01d,06aug00,srr  Modified amd29lv323CT support for 16 MB.
  14. 01c,31jul00,cak  Renamed from mv2400mtd to amd29lvmtd.
  15.                  Added support for the amd29lv323. 
  16. 01b,09may00,add  Fixed erase bug (last 4 sectors are odd sizes)
  17. 01a,21apr00,add  Created.
  18. */
  19. /*
  20. DESCRIPTION
  21. This module implements an TrueFFS MTD for the AMD AM29LV160D and
  22. AM29LV323 flash devices.
  23.  
  24. */
  25. /* includes */
  26. #include <vxWorks.h>
  27. #include <taskLib.h>
  28. #include <logLib.h>
  29. #include <stdio.h>
  30. #include <cacheLib.h>
  31. #include "tffs/flflash.h"
  32. #include "tffs/backgrnd.h"
  33. IMPORT int sysClkRateGet();
  34. /* defines */
  35. #define AMD29LV_MTD_SECTOR_SIZE         (0x40000)
  36. #define AMD29LV_160_CHIP_SIZE           (0x800000) /*  8MB */
  37. #define AMD29LV_160_LAST_SECTOR_NUM     (AMD29LV_160_CHIP_SIZE / AMD29LV_MTD_SECTOR_SIZE - 1)
  38. #define AMD29LV_323_CHIP_SIZE           (0x1000000) /* 16MB */
  39. #define AMD29LV_323_LAST_SECTOR_SIZE    (0x8000)
  40. #define AMD29LV_323_LAST_SECTOR_NUM     (AMD29LV_323_CHIP_SIZE / AMD29LV_MTD_SECTOR_SIZE - 1)
  41. #define AMD29LV_MTD_CHIP_CNT            (1)
  42. #define AMD29LV_MTD_INTERLEAVE          (1)
  43. #define DEBUG_READ     0x00000001
  44. #define DEBUG_WRITE    0x00000002
  45. #define DEBUG_PROGRAM  0x00000004
  46. #define DEBUG_ERASE    0x00000008
  47. #define DEBUG_ID       0x00000010
  48. #define DEBUG_MAP      0x00000020
  49. #define DEBUG_PROG32   0x00000040
  50. #define DEBUG_ALWAYS   0xffffffff
  51. #define DEBUG
  52. #ifdef  DEBUG
  53.     LOCAL UINT32 debug;
  54.     #define DEBUG_PRINT(mask, string) 
  55.                 if ((debug & mask) || (mask == DEBUG_ALWAYS)) 
  56.                 printf string
  57. #else
  58.     #define DEBUG_PRINT(mask, string)
  59. #endif
  60. /* local routines */
  61. LOCAL FLStatus amd29lvSectorRangeErase(FLFlash* pVol, int, int);
  62. LOCAL FLStatus amd29lvProgram(FLFlash*, CardAddress, const void FAR1*, int,
  63.                              FLBoolean);
  64. LOCAL void FAR0* amd29lvMap(FLFlash*, CardAddress, int);
  65. LOCAL void flashReset(FLFlash*, BOOL);
  66. LOCAL void flashIdGet(FLFlash*, UINT16*, UINT16*);
  67. LOCAL void flashUnlock(FLFlash*, BOOL);
  68. LOCAL STATUS flashProgram32Bits(FLFlash*, volatile UINT32*, UINT32, BOOL);
  69. LOCAL void flashRegWrite32Bits(FLFlash*, UINT32, UINT32, BOOL);
  70. LOCAL UINT16 flashRegRead16Bits(FLFlash*, UINT32, BOOL);
  71. LOCAL STATUS flashHalfSectorErase(FLFlash*, int, BOOL);
  72. /******************************************************************************
  73. *
  74. * amd29lvMTDIdentify - MTD identify routine (see TrueFFS Programmer's Guide)
  75. *
  76. * RETURNS: FLStatus
  77. *
  78. */
  79. FLStatus amd29lvMTDIdentify
  80.     (
  81.     FLFlash* pVol
  82.     )
  83.     {
  84.     UINT16 manCode;
  85.     UINT16 devCode;
  86.     flashIdGet(pVol, &manCode, &devCode);
  87.     if (manCode != 0x0001)
  88.         {
  89.         DEBUG_PRINT(DEBUG_ALWAYS,
  90.                     ("amd29lvMTDIdentify Manufacturer unknown: 0x%02xn",
  91.                     manCode));
  92.         return(flUnknownMedia);
  93.         }
  94.     if (devCode == 0x22C4) /* amd29LV160BT */
  95. {
  96. pVol->type = 0x01C4;
  97. pVol->erasableBlockSize = AMD29LV_MTD_SECTOR_SIZE;
  98. pVol->chipSize = AMD29LV_160_CHIP_SIZE;
  99. pVol->noOfChips = AMD29LV_MTD_CHIP_CNT;
  100. pVol->interleaving = AMD29LV_MTD_INTERLEAVE;
  101. pVol->write = amd29lvProgram;
  102. pVol->erase = amd29lvSectorRangeErase;
  103. pVol->map = amd29lvMap;
  104. }
  105.     else if (devCode == 0x2250) /* amd29LV323CT */
  106. {
  107. pVol->type = 0x0150;
  108. pVol->erasableBlockSize = AMD29LV_MTD_SECTOR_SIZE;
  109. pVol->chipSize = AMD29LV_323_CHIP_SIZE;
  110. pVol->noOfChips = AMD29LV_MTD_CHIP_CNT;
  111. pVol->interleaving = AMD29LV_MTD_INTERLEAVE;
  112. pVol->write = amd29lvProgram;
  113. pVol->erase = amd29lvSectorRangeErase;
  114. pVol->map = amd29lvMap;
  115. }
  116.     else
  117.         {
  118.         DEBUG_PRINT(DEBUG_ALWAYS,
  119.                     ("amd29lvMTDIdentify Device unknown: 0x%02xn",
  120.                     devCode));
  121.         return(flUnknownMedia);
  122.         }    
  123.     DEBUG_PRINT(DEBUG_ID, ("amd29lvMTDIdentify succeeds!n"));
  124.     return(flOK);
  125.     }
  126. /******************************************************************************
  127. *
  128. * amd29lvProgram - MTD write routine (see TrueFFS Programmer's Guide)
  129. *
  130. * RETURNS: FLStatus
  131. *
  132. */
  133. LOCAL FLStatus amd29lvProgram
  134.     (
  135.     FLFlash*          pVol,
  136.     CardAddress       address,
  137.     const void FAR1*  buffer,
  138.     int               length,
  139.     FLBoolean         overwrite
  140.     )
  141.     {
  142.     volatile UINT32* pFlash;
  143.     UINT32* pBuffer;
  144.     STATUS rc = OK;
  145.     BOOL upper;
  146.     int i;
  147.     BOOL doFree = FALSE;
  148.     DEBUG_PRINT(DEBUG_PROGRAM,
  149.                 ("Program: 0x%08x, 0x%08x, %dn", (unsigned int) address,
  150.                  length, overwrite));
  151.     if (flWriteProtected(vol.socket))
  152.         {
  153.         return(flWriteProtect);
  154.         }
  155.     /* Check alignment */
  156.     if (((address & 0x03) != 0) || (((UINT32) buffer) &  0x03))
  157.         {
  158.         DEBUG_PRINT(DEBUG_ALWAYS, ("amd29lvProgram: Alignment errorn"));
  159.         return(flBadParameter);
  160.         }
  161.     if (overwrite && length == 2)
  162.         {
  163.         int sector;
  164.         int offset;
  165.         pFlash = (volatile UINT32*) pVol->map(pVol, address, length);
  166.         pBuffer = (UINT32*) malloc(AMD29LV_MTD_SECTOR_SIZE);
  167.         if (pBuffer == 0)
  168.             {
  169.             DEBUG_PRINT(DEBUG_ALWAYS, ("amd29lvProgram: No memoryn"));
  170.             return(flBadParameter);
  171.             }
  172.         /* Determine sector and offset */
  173.         sector = address / AMD29LV_MTD_SECTOR_SIZE;
  174.         offset = address % AMD29LV_MTD_SECTOR_SIZE;
  175.         DEBUG_PRINT(DEBUG_PROGRAM,("Overwrite sector: 0x%08x, offset: 0x%08xn",
  176.                     sector,offset));
  177.         /* Get a pointer to the flash sector */
  178.         pFlash = (volatile UINT32*) pVol->map(pVol,
  179.                                               sector * AMD29LV_MTD_SECTOR_SIZE,
  180.                                               AMD29LV_MTD_SECTOR_SIZE);
  181.         /* Copy the sector from flash to memory */
  182.         memcpy(pBuffer, (void*) pFlash, AMD29LV_MTD_SECTOR_SIZE);
  183.         /* Overwrite the sector in memory */
  184.        memcpy(((UINT8*) pBuffer) + offset, buffer, length);
  185.         /* Erase sector */
  186.         rc = amd29lvSectorRangeErase(pVol, sector, 1);
  187.         if (rc != flOK)
  188.             {
  189.             free(pBuffer);
  190.             return(rc);
  191.             }
  192.         length = AMD29LV_MTD_SECTOR_SIZE;
  193.         doFree = TRUE;
  194.         }
  195.     else
  196.         {
  197.         if ((length & 0x03) != 0)
  198.             {
  199.             DEBUG_PRINT(DEBUG_ALWAYS, ("amd29lvProgram: length: %dn", length));
  200.             return(flBadParameter);
  201.             }
  202.         pBuffer = (UINT32*) buffer;
  203.         pFlash = (volatile UINT32*) pVol->map(pVol, address, length);
  204.         }
  205.     /* Program 'length' bytes (4 bytes each iterations) */
  206.     upper = ((((UINT32) pFlash) & 0x04) != 0);
  207.     for (i = 0; i < (length / 4); i++, pFlash++, upper = !upper)
  208.         {
  209.         /* Don't bother programming if buffer data == format value */
  210.         if (pBuffer[i] == 0xffffffff)
  211.             continue;
  212.         /* Program 32 bits */
  213.         rc = flashProgram32Bits(pVol, pFlash, pBuffer[i], upper);
  214.         if (rc != OK)
  215.             break;
  216.         }
  217.     if (doFree)
  218.         {
  219.         free(pBuffer);
  220.         }
  221.     return((rc == OK) ? flOK : flTimedOut);
  222.     }
  223. /******************************************************************************
  224. *
  225. * amd29lvSectorRangeErase - MTD erase routine (see TrueFFS Programmer's Guide)
  226. *
  227. * RETURNS: FLStatus
  228. *
  229. */
  230. LOCAL FLStatus amd29lvSectorRangeErase
  231.     (
  232.     FLFlash* pVol,
  233.     int sectorNum,
  234.     int sectorCount
  235.     )
  236.     {
  237.     int i;
  238.     STATUS rc;
  239.     /* Check for valid range */
  240.     if (pVol->type == 0x1C4) /* amd29LV160BT */
  241. {
  242. if (sectorNum + sectorCount >  AMD29LV_160_LAST_SECTOR_NUM + 1)
  243.     {
  244.     DEBUG_PRINT(DEBUG_ALWAYS, ("Invalid sector range: %d - %dn",
  245.                 sectorNum, sectorCount));
  246.     }
  247. /* Last sector is really 4 seperately erasable sectors */
  248. if (sectorNum + sectorCount == AMD29LV_160_LAST_SECTOR_NUM + 1)
  249.     {
  250.     sectorCount += 3;
  251.     }
  252. }
  253.     else  /* amd29LV323CT */
  254. {
  255. if (sectorNum + sectorCount >  AMD29LV_323_LAST_SECTOR_NUM + 1)
  256.     {
  257.     DEBUG_PRINT(DEBUG_ALWAYS, ("Invalid sector range: %d - %dn",
  258.                 sectorNum, sectorCount));
  259.     }
  260. /* Last sector is really 8 seperately erasable sectors */
  261. if (sectorNum + sectorCount == AMD29LV_323_LAST_SECTOR_NUM + 1)
  262.     {
  263.     sectorCount += 7;
  264.     }
  265. }
  266.     for (i = 0; i < sectorCount; i++)
  267.         {
  268.         /* Erase lower half */
  269.         rc = flashHalfSectorErase(pVol, sectorNum + i, FALSE);
  270.         if (rc != OK)
  271.             return(flTimedOut);
  272.         /* Erase upper half */
  273.         rc = flashHalfSectorErase(pVol, sectorNum + i, TRUE);
  274.         if (rc != OK)
  275.             return(flTimedOut);
  276.         }
  277.     return(flOK);
  278.     }
  279. /******************************************************************************
  280. *
  281. * amd29lvMap - MTD map routine (see TrueFFS Programmer's Guide)
  282. *
  283. * RETURNS: FLStatus
  284. *
  285. */
  286. LOCAL void FAR0* amd29lvMap
  287.     (
  288.     FLFlash* pVol,
  289.     CardAddress address,
  290.     int length
  291.     )
  292.     {
  293.     UINT32 flashBaseAddr = (pVol->socket->window.baseAddress << 12);
  294.     void FAR0* pFlash = (void FAR0*) (flashBaseAddr + address);
  295.     DEBUG_PRINT(DEBUG_MAP, ("Mapping 0x%08x bytes at 0x%08x to %pn", length,
  296.                 (unsigned int) address, pFlash));
  297.     return(pFlash);
  298.     }
  299. /******************************************************************************
  300. *
  301. * flashProgram32Bits - Program 32 bits at 4 byte aligned address.
  302. *
  303. * RETURNS: OK or ERROR
  304. *
  305. */
  306. LOCAL STATUS flashProgram32Bits
  307.     (
  308.     FLFlash* pVol,
  309.     volatile UINT32* pData,
  310.     UINT32 data,
  311.     BOOL upper
  312.     )
  313.     {
  314.     BOOL programmed = FALSE;
  315.     int timeout;
  316.     flashUnlock(pVol, upper);
  317.     flashRegWrite32Bits(pVol, 0x555, 0x00a000a0, upper);
  318.     DEBUG_PRINT(DEBUG_PROG32, ("Programming 0x%08x to %p, upper = %dn",
  319.                 data, pData, upper));
  320.     *pData = data;
  321.     CACHE_PIPE_FLUSH();
  322.     for (timeout = flMsecCounter + 3000; flMsecCounter < timeout;)
  323.         {
  324.         if (*pData == data)
  325.             {
  326.             programmed = TRUE;
  327.             break;
  328.             }
  329.         taskDelay(0);
  330.         }
  331.     if (!programmed)
  332.         {
  333.         DEBUG_PRINT(DEBUG_ALWAYS, ("Timeoutn"));
  334.         return(ERROR);
  335.         }
  336.     return(OK);
  337.     }
  338. /******************************************************************************
  339. *
  340. * flashHalfSectorErase - Erase lower or upper half of sector.
  341. *
  342. * RETURNS: OK or ERROR
  343. *
  344. */
  345. LOCAL STATUS flashHalfSectorErase
  346.     (
  347.     FLFlash* pVol,
  348.     int sectorNum,
  349.     BOOL upper
  350.     )
  351.     {
  352.     BOOL erased = FALSE;
  353.     int timeout = sysClkRateGet() * 5;
  354.     UINT32 offset;
  355.     UINT32 size;
  356.     volatile UINT32* pFlash;
  357.     UINT32 sectorAddr;
  358.     if (pVol->type == 0x1C4) /* amd29LV160BT */
  359. {
  360. /* Sectors 31 - 34 are funky sizes */
  361. switch (sectorNum)
  362.     {
  363.     case 31:
  364.         offset = 0x7c0000;
  365.         size   = 0x20000;
  366.         sectorAddr = 0xf8000;
  367.         break;
  368.     case 32:
  369.         offset = 0x7e0000;
  370.         size   = 0x8000;
  371.         sectorAddr = 0xfc000;
  372.         break;
  373.     case 33:
  374.         offset = 0x7e8000;
  375.         size   = 0x8000;
  376.         sectorAddr = 0xfd000;
  377.         break;
  378.     case 34:
  379.         offset = 0x7f0000;
  380.         size   = 0x10000;
  381.         sectorAddr = 0xfe000;
  382.         break;
  383.     default:
  384.         offset = sectorNum * AMD29LV_MTD_SECTOR_SIZE;
  385.         size = AMD29LV_MTD_SECTOR_SIZE;
  386.         sectorAddr = (sectorNum << 15);
  387.     }
  388. }
  389.     else  /* amd29LV323CT */
  390. {
  391. /* Sectors 63 - 70 are 1/8th size of other sectors */
  392. if (sectorNum < AMD29LV_323_LAST_SECTOR_NUM)
  393.     {
  394.     offset     = sectorNum * AMD29LV_MTD_SECTOR_SIZE;
  395.     size       = AMD29LV_MTD_SECTOR_SIZE;
  396.     sectorAddr = (sectorNum << 15);
  397.     }
  398. else
  399.     {
  400.     offset  = AMD29LV_323_LAST_SECTOR_NUM * AMD29LV_MTD_SECTOR_SIZE;
  401.     offset += (sectorNum - AMD29LV_323_LAST_SECTOR_NUM) *
  402.               AMD29LV_323_LAST_SECTOR_SIZE;
  403.     size    = AMD29LV_323_LAST_SECTOR_SIZE;
  404.     sectorAddr  = (AMD29LV_323_LAST_SECTOR_NUM << 15);
  405.     sectorAddr += ((sectorNum - AMD29LV_323_LAST_SECTOR_NUM) << 12);
  406.     }
  407. }
  408.     DEBUG_PRINT(DEBUG_ERASE, ("Erasing sector %d, 0x%02x, upper = %dn",
  409.                 sectorNum, sectorAddr, upper));
  410.     /* Erase the sector half */
  411.     flashUnlock(pVol, upper);
  412.     flashRegWrite32Bits(pVol, 0x555, 0x00800080, upper);
  413.     flashUnlock(&vol, upper);
  414.     flashRegWrite32Bits(pVol, sectorAddr, 0x00300030, upper);
  415.     pFlash = (volatile UINT32*) pVol->map(pVol, offset, size);
  416.     if (upper)
  417.         pFlash++;
  418.     /* Sector's  upper/lower half erased?  If not, return ERROR */
  419.     for (timeout = flMsecCounter + 5000; flMsecCounter < timeout;)
  420.         {
  421.         if (*pFlash == 0xffffffff)
  422.             {
  423.             erased = TRUE;
  424.             break;
  425.             }
  426.         }
  427.     if (!erased)
  428.         {
  429.         DEBUG_PRINT(DEBUG_ALWAYS, ("Sector erase timeout, %pn", pFlash));
  430.         return(ERROR);
  431.         }
  432.     return(OK);
  433.     }
  434. /******************************************************************************
  435. *
  436. * flashRegWrite32Bits - Write 32 bits to 4 byte aligned address.
  437. *
  438. * RETURNS: N/A
  439. *
  440. */
  441. LOCAL void flashRegWrite32Bits
  442.     (
  443.     FLFlash* pVol,
  444.     UINT32 addr,
  445.     UINT32 data,
  446.     BOOL   upper
  447.     )
  448.     {
  449.     UINT32 flashBaseAddr = (pVol->socket->window.baseAddress << 12);
  450.     /* Adjust addr for amd29LV323 */
  451.     addr = flashBaseAddr + 8 * addr;
  452.     if (upper)
  453.         addr += 4;
  454.     DEBUG_PRINT(DEBUG_WRITE, ("Writing 0x%08x to 0x%08xn", data, addr));
  455.     /* Write */
  456.     *((volatile UINT32*) addr) = data;
  457.     CACHE_PIPE_FLUSH();
  458.     }
  459. /******************************************************************************
  460. *
  461. * flashRegRead16Bits - Read 16 bits from 2 byte aligned address.
  462. *
  463. * RETURNS: data at specified address
  464. *
  465. */
  466. LOCAL UINT16 flashRegRead16Bits
  467.     (
  468.     FLFlash* pVol,
  469.     UINT32 addr,
  470.     BOOL   upper
  471.     )
  472.     {
  473.     UINT16 data;
  474.     UINT32 flashBaseAddr = (pVol->socket->window.baseAddress << 12);
  475.     addr = flashBaseAddr + 8 * addr;
  476.     if (upper)
  477.         addr += 4;
  478.     data = *((volatile UINT16*) addr);
  479.     DEBUG_PRINT(DEBUG_READ, ("Read 0x%08x from 0x%08xn", data, addr));
  480.     CACHE_PIPE_FLUSH();
  481.     return(data);
  482.     }
  483. /******************************************************************************
  484. *
  485. * flashIdGet - Get flash man. and device codes.
  486. *
  487. * RETURNS: N/A
  488. *
  489. */
  490. LOCAL void flashIdGet
  491.     (
  492.     FLFlash* pVol,
  493.     UINT16* manCode,
  494.     UINT16* devCode
  495.     )
  496.     {
  497.     flashUnlock(pVol, FALSE);
  498.     flashRegWrite32Bits(pVol, 0x555, 0x00900090, FALSE);
  499.     *manCode = flashRegRead16Bits(pVol, 0x00, FALSE);
  500.     *devCode = flashRegRead16Bits(pVol, 0x01, FALSE);
  501.     flashReset(pVol, FALSE);
  502.     }
  503. /******************************************************************************
  504. *
  505. * flashUnlock - Write unlock sequence to upper or lower flash section.
  506. *
  507. * RETURNS: N/A
  508. *
  509. */
  510. LOCAL void flashUnlock
  511.     (
  512.     FLFlash* pVol,
  513.     BOOL upper
  514.     )
  515.     {
  516.     flashRegWrite32Bits(pVol, 0x555, 0x00aa00aa, upper);
  517.     flashRegWrite32Bits(pVol, 0x2aa, 0x00550055, upper);
  518.     }
  519. /******************************************************************************
  520. *
  521. * flashReset - Write reset sequence to upper or lower flash section.
  522. *
  523. * RETURNS: N/A
  524. *
  525. */
  526. LOCAL void flashReset
  527.     (
  528.     FLFlash* pVol,
  529.     BOOL upper
  530.     )
  531.     {
  532.     flashRegWrite32Bits(pVol, 0, 0x00f000f0, upper);
  533.     }
  534. #define FLASH_TEST
  535. #undef FLASH_TEST
  536. #ifdef FLASH_TEST
  537. #include "tffs/flsocket.h"
  538. LOCAL FLFlash testVol;
  539. LOCAL FLSocket testSocket;
  540. /* Make sure this functions are NOT static (LOCAL) in sysTffs.c */
  541. IMPORT void simmSetWindow (FLSocket vol);
  542. IMPORT void simmSetMappingContext (FLSocket vol, unsigned page);
  543. IMPORT FLBoolean simmWriteProtected (FLSocket vol);
  544. /* Initialize */
  545. LOCAL void FAR0 *flashMap(FLFlash vol, CardAddress address, int length)
  546. {
  547.   return flMap(vol.socket,address);
  548. }
  549. void fsinit()
  550.     {
  551.     FLStatus rc;
  552.     testSocket.window.baseAddress = tffsFlashBaseAdrs >> 12;
  553.     testSocket.window.currentPage = UNDEFINED_MAPPING;
  554.     testSocket.setWindow = simmSetWindow;
  555.     testSocket.setMappingContext = simmSetMappingContext;
  556.     testSocket.setMappingContext = simmSetMappingContext;
  557.     testSocket.writeProtected = simmWriteProtected;
  558.     testVol.socket = &testSocket;
  559.     testVol.map = flashMap;
  560.     rc = amd29lvMTDIdentify(&testVol);
  561.     if (rc != flOK)
  562.         {
  563.         printf("identify failsn");
  564.         }
  565.     }
  566. /* Show */
  567. void fsshow()
  568.     {
  569.     printf("Type 0x%04xn", testVol.type);
  570.     printf("Eraseable block size 0x%08lxn", testVol.erasableBlockSize);
  571.     }
  572. /* Erase */
  573. STATUS fse
  574.     (
  575.     UINT8 sectorNum,
  576.     UINT8 numSectors
  577.     )
  578.     {
  579.     FLStatus rc;
  580.     if (sectorNum <= 3)
  581.         {
  582.         printf("Sector contains bootrom!n");
  583.         return(ERROR);
  584.         }
  585.     rc = testVol.erase(&testVol, sectorNum, numSectors);
  586.     return(rc);
  587.     }
  588. /* Program */
  589. STATUS fprog
  590.     (
  591.     UINT32 offset,
  592.     UINT32 bufSize,
  593.     UINT8  pattern
  594.     )
  595.     {
  596.     FLStatus rc;
  597.     UINT32* pBuf;
  598.     UINT32 sectorNum = offset / AMD29LV_MTD_SECTOR_SIZE;
  599.     if (sectorNum <= 3)
  600.         {
  601.         printf("Sector contains bootrom!n");
  602.         return(ERROR);
  603.         }
  604.     if (bufSize == 0)
  605.         bufSize = 4;
  606.     if ((bufSize & 0x03) != 0)
  607.         bufSize += 4 - (bufSize & 0x03);
  608.     pBuf = memalign(4, bufSize);
  609.     if (pBuf == 0)
  610.         return(ERROR);
  611.     memset(pBuf, pattern, bufSize);
  612.     rc = testVol.write(&testVol, offset, pBuf, bufSize, FALSE);
  613.     free(pBuf);
  614.     return(rc == flOK ? OK : ERROR);
  615.     }
  616. #endif