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 
00059 #include <sys/atom.h>
00060 #include <dev/nvmem.h>
00061 
00062 #include <stdint.h>
00063 #include <stdlib.h>
00064 #include <string.h>
00065 
00066 #include <arch/arm/at91_efc.h>
00067 
00072 
00075 #ifndef FLASH_CHIP_BASE
00076 #define FLASH_CHIP_BASE  0x00100000
00077 #endif
00078 
00081 #ifndef FLASH_CONF_SECTOR
00082 #define FLASH_CONF_SECTOR  0x0003FF00
00083 #endif
00084 
00094 #ifndef FLASH_CONF_SIZE
00095 #define FLASH_CONF_SIZE         256
00096 #endif
00097 
00098 #ifndef FLASH_WRITE_WAIT
00099 #define FLASH_WRITE_WAIT        60000
00100 #endif
00101 
00102 #ifndef FLASH_ERASE_WAIT
00103 #define FLASH_ERASE_WAIT        60000
00104 #endif
00105 
00106 #ifndef FLASH_CHIP_ERASE_WAIT
00107 #define FLASH_CHIP_ERASE_WAIT   600000
00108 #endif
00109 
00110 
00111 typedef uint32_t flashdat_t;
00112 typedef unsigned long flashadr_t;
00113 typedef volatile flashdat_t *flashptr_t;
00114 
00121 RAMFUNC int At91EfcCmd(unsigned int cmd, uint32_t tmo)
00122 {
00123     int rc = 0;
00124     unsigned int fsr;
00125 
00126     /* Make sure that the previous command has finished. */
00127     while ((inr(MC_FSR) & MC_FRDY) == 0) {
00128         if (tmo && --tmo < 1) {
00129             return -1;
00130         }
00131     }
00132 
00133     /* IRQ handlers are located in flash. Disable them. */
00134     NutEnterCritical();
00135 
00136     /* Write command. */
00137     outr(MC_FCR, MC_KEY | cmd);
00138 
00139     /* Wait for ready flag set. */
00140     while (((fsr = inr(MC_FSR)) & MC_FRDY) == 0) {
00141         if (tmo && --tmo < 1) {
00142             rc = -1;
00143             break;
00144         }
00145     }
00146 
00147     /* Flash command finished. Re-enable IRQ handlers. */
00148     NutExitCritical();
00149 
00150     /* Check result. */
00151     if (fsr & (MC_LOCKE | MC_PROGE)) {
00152         rc = -1;
00153     }
00154     return rc;
00155 }
00156 
00166 int At91EfcSectorRead(unsigned int off, void *data, unsigned int len)
00167 {
00168     memcpy(data, (void *) (uptr_t) (FLASH_CHIP_BASE + off), len);
00169 
00170     return 0;
00171 }
00172 
00185 int At91EfcSectorWrite(unsigned int off, CONST void *data, unsigned int len)
00186 {
00187     flashptr_t dp = (flashptr_t) (uptr_t) (FLASH_CHIP_BASE + off);
00188     int rc;
00189     unsigned int i;
00190 
00191     if (data) {
00192         flashptr_t sp = (flashptr_t) data;
00193 
00194         /* Copy data to the flash write buffer. */
00195         for (i = 0; i < len; i += sizeof(flashdat_t)) {
00196             *dp++ = *sp++;
00197         }
00198     }
00199     else {
00200         /* All bits set to emulate sector erasing. */
00201         for (i = 0; i < len; i += sizeof(flashdat_t)) {
00202             *dp++ = (flashdat_t)(-1);
00203         }
00204     }
00205 
00206     /* Clear NEBP in mode register for automatic erasure. */
00207     outr(MC_FMR, (i = inr(MC_FMR)) & ~MC_NEBP);
00208     /* Execute page write command. */
00209     rc = At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_WP, FLASH_WRITE_WAIT);
00210     /* Restore mode register. */
00211     outr(MC_FMR, i);
00212 
00213     return rc;
00214 }
00215 
00219 int At91EfcSectorErase(unsigned int off)
00220 {
00221     return At91EfcSectorWrite(off, NULL, 256);
00222 }
00223 
00231 int At91EfcRegionLock(unsigned int off)
00232 {
00233     return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_SLB, FLASH_WRITE_WAIT);
00234 }
00235 
00243 int At91EfcRegionUnlock(unsigned int off)
00244 {
00245     return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_CLB, FLASH_WRITE_WAIT);
00246 }
00247 
00259 int At91EfcParamRead(unsigned int pos, void *data, unsigned int len)
00260 {
00261     return At91EfcSectorRead(FLASH_CONF_SECTOR + pos, data, len);
00262 }
00263 
00278 int At91EfcParamWrite(unsigned int pos, CONST void *data, unsigned int len)
00279 {
00280     int rc = -1;
00281     uint8_t *buff;
00282 
00283     /* Load the complete configuration area. */
00284     if ((buff = malloc(FLASH_CONF_SIZE)) != NULL) {
00285 
00286         rc = At91EfcSectorRead(FLASH_CONF_SECTOR, buff, FLASH_CONF_SIZE);
00287         /* Compare old with new contents. */
00288         if (memcmp(buff + pos, data, len)) {
00289             /* New contents differs. Copy it into the sector buffer. */
00290             memcpy(buff + pos, data, len);
00291             /* Write back new data. Maintain region lock. */
00292             if (At91EfcRegionUnlock(FLASH_CONF_SECTOR) == 0) {
00293                 rc = At91EfcSectorWrite(FLASH_CONF_SECTOR, buff, FLASH_CONF_SIZE);
00294                 At91EfcRegionLock(FLASH_CONF_SECTOR);
00295             }
00296         }
00297         free(buff);
00298     }
00299     return rc;
00300 }
00301 

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