at91_efc.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00055 #include <sys/atom.h>
00056 #include <dev/nvmem.h>
00057 
00058 #include <stdint.h>
00059 #include <stdlib.h>
00060 #include <string.h>
00061 
00062 #include <arch/arm/at91_efc.h>
00063 
00068 
00071 #ifndef FLASH_CHIP_BASE
00072 #define FLASH_CHIP_BASE  0x00100000
00073 #endif
00074 
00077 #ifndef FLASH_CONF_SECTOR
00078 #define FLASH_CONF_SECTOR  0x0003FF00
00079 #endif
00080 
00090 #ifndef FLASH_CONF_SIZE
00091 #define FLASH_CONF_SIZE         256
00092 #endif
00093 
00094 #ifndef FLASH_WRITE_WAIT
00095 #define FLASH_WRITE_WAIT        60000
00096 #endif
00097 
00098 #ifndef FLASH_ERASE_WAIT
00099 #define FLASH_ERASE_WAIT        60000
00100 #endif
00101 
00102 #ifndef FLASH_CHIP_ERASE_WAIT
00103 #define FLASH_CHIP_ERASE_WAIT   600000
00104 #endif
00105 
00106 
00107 typedef uint32_t flashdat_t;
00108 typedef unsigned long flashadr_t;
00109 typedef volatile flashdat_t *flashptr_t;
00110 
00117 RAMFUNC int At91EfcCmd(u_int cmd, uint32_t tmo)
00118 {
00119     int rc = 0;
00120     u_int fsr;
00121 
00122     /* Make sure that the previous command has finished. */
00123     while ((inr(MC_FSR) & MC_FRDY) == 0) {
00124         if (tmo && --tmo < 1) {
00125             return -1;
00126         }
00127     }
00128 
00129     /* IRQ handlers are located in flash. Disable them. */
00130     NutEnterCritical();
00131 
00132     /* Write command. */
00133     outr(MC_FCR, MC_KEY | cmd);
00134 
00135     /* Wait for ready flag set. */
00136     while (((fsr = inr(MC_FSR)) & MC_FRDY) == 0) {
00137         if (tmo && --tmo < 1) {
00138             rc = -1;
00139             break;
00140         }
00141     }
00142 
00143     /* Flash command finished. Re-enable IRQ handlers. */
00144     NutExitCritical();
00145 
00146     /* Check result. */
00147     if (fsr & (MC_LOCKE | MC_PROGE)) {
00148         rc = -1;
00149     }
00150     return rc;
00151 }
00152 
00162 int At91EfcSectorRead(u_int off, void *data, u_int len)
00163 {
00164     memcpy(data, (void *) (uptr_t) (FLASH_CHIP_BASE + off), len);
00165 
00166     return 0;
00167 }
00168 
00181 int At91EfcSectorWrite(u_int off, CONST void *data, u_int len)
00182 {
00183     flashptr_t dp = (flashptr_t) (uptr_t) (FLASH_CHIP_BASE + off);
00184     int rc;
00185     u_int i;
00186 
00187     if (data) {
00188         flashptr_t sp = (flashptr_t) data;
00189 
00190         /* Copy data to the flash write buffer. */
00191         for (i = 0; i < len; i += sizeof(flashdat_t)) {
00192             *dp++ = *sp++;
00193         }
00194     }
00195     else {
00196         /* All bits set to emulate sector erasing. */
00197         for (i = 0; i < len; i += sizeof(flashdat_t)) {
00198             *dp++ = (flashdat_t)(-1);
00199         }
00200     }
00201 
00202     /* Clear NEBP in mode register for automatic erasure. */
00203     outr(MC_FMR, (i = inr(MC_FMR)) & ~MC_NEBP);
00204     /* Execute page write command. */
00205     rc = At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_WP, FLASH_WRITE_WAIT);
00206     /* Restore mode register. */
00207     outr(MC_FMR, i);
00208 
00209     return rc;
00210 }
00211 
00215 int At91EfcSectorErase(u_int off)
00216 {
00217     return At91EfcSectorWrite(off, NULL, 256);
00218 }
00219 
00227 int At91EfcRegionLock(u_int off)
00228 {
00229     return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_SLB, FLASH_WRITE_WAIT);
00230 }
00231 
00239 int At91EfcRegionUnlock(u_int off)
00240 {
00241     return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_CLB, FLASH_WRITE_WAIT);
00242 }
00243 
00255 int At91EfcParamRead(u_int pos, void *data, u_int len)
00256 {
00257     return At91EfcSectorRead(FLASH_CONF_SECTOR + pos, data, len);
00258 }
00259 
00274 int At91EfcParamWrite(u_int pos, CONST void *data, u_int len)
00275 {
00276     int rc = -1;
00277     uint8_t *buff;
00278 
00279     /* Load the complete configuration area. */
00280     if ((buff = malloc(FLASH_CONF_SIZE)) != NULL) {
00281 
00282         rc = At91EfcSectorRead(FLASH_CONF_SECTOR, buff, FLASH_CONF_SIZE);
00283         /* Compare old with new contents. */
00284         if (memcmp(buff + pos, data, len)) {
00285             /* New contents differs. Copy it into the sector buffer. */
00286             memcpy(buff + pos, data, len);
00287             /* Write back new data. Maintain region lock. */
00288             if (At91EfcRegionUnlock(FLASH_CONF_SECTOR) == 0) {
00289                 rc = At91EfcSectorWrite(FLASH_CONF_SECTOR, buff, FLASH_CONF_SIZE);
00290                 At91EfcRegionLock(FLASH_CONF_SECTOR);
00291             }
00292         }
00293         free(buff);
00294     }
00295     return rc;
00296 }
00297 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/