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 
00052 #include <stdlib.h>
00053 #include <string.h>
00054 #include <sys/atom.h>
00055 #include <dev/nvmem.h>
00056 
00057 #include <arch/arm/at91_efc.h>
00058 
00063 
00066 #ifndef FLASH_CHIP_BASE
00067 #define FLASH_CHIP_BASE  0x00100000
00068 #endif
00069 
00072 #ifndef FLASH_CONF_SECTOR
00073 #define FLASH_CONF_SECTOR  0x0003FF00
00074 #endif
00075 
00085 #ifndef FLASH_CONF_SIZE
00086 #define FLASH_CONF_SIZE         256
00087 #endif
00088 
00089 #ifndef FLASH_WRITE_WAIT
00090 #define FLASH_WRITE_WAIT        60000
00091 #endif
00092 
00093 #ifndef FLASH_ERASE_WAIT
00094 #define FLASH_ERASE_WAIT        60000
00095 #endif
00096 
00097 #ifndef FLASH_CHIP_ERASE_WAIT
00098 #define FLASH_CHIP_ERASE_WAIT   600000
00099 #endif
00100 
00101 
00102 typedef u_long flashdat_t;
00103 typedef unsigned long flashadr_t;
00104 typedef volatile flashdat_t *flashptr_t;
00105 
00112 RAMFUNC int At91EfcCmd(u_int cmd, u_long tmo)
00113 {
00114     int rc = 0;
00115     u_int fsr;
00116 
00117     /* Make sure that the previous command has finished. */
00118     while ((inr(MC_FSR) & MC_FRDY) == 0) {
00119         if (tmo && --tmo < 1) {
00120             return -1;
00121         }
00122     }
00123 
00124     /* IRQ handlers are located in flash. Disable them. */
00125     NutEnterCritical();
00126 
00127     /* Write command. */
00128     outr(MC_FCR, MC_KEY | cmd);
00129 
00130     /* Wait for ready flag set. */
00131     while (((fsr = inr(MC_FSR)) & MC_FRDY) == 0) {
00132         if (tmo && --tmo < 1) {
00133             rc = -1;
00134             break;
00135         }
00136     }
00137 
00138     /* Flash command finished. Re-enable IRQ handlers. */
00139     NutExitCritical();
00140 
00141     /* Check result. */
00142     if (fsr & (MC_LOCKE | MC_PROGE)) {
00143         rc = -1;
00144     }
00145     return rc;
00146 }
00147 
00157 int At91EfcSectorRead(u_int off, void *data, u_int len)
00158 {
00159     memcpy(data, (void *) (uptr_t) (FLASH_CHIP_BASE + off), len);
00160 
00161     return 0;
00162 }
00163 
00176 int At91EfcSectorWrite(u_int off, CONST void *data, u_int len)
00177 {
00178     flashptr_t dp = (flashptr_t) (uptr_t) (FLASH_CHIP_BASE + off);
00179     int rc;
00180     u_int i;
00181 
00182     if (data) {
00183         flashptr_t sp = (flashptr_t) data;
00184 
00185         /* Copy data to the flash write buffer. */
00186         for (i = 0; i < len; i += sizeof(flashdat_t)) {
00187             *dp++ = *sp++;
00188         }
00189     }
00190     else {
00191         /* All bits set to emulate sector erasing. */
00192         for (i = 0; i < len; i += sizeof(flashdat_t)) {
00193             *dp++ = (flashdat_t)(-1);
00194         }
00195     }
00196 
00197     /* Clear NEBP in mode register for automatic erasure. */
00198     outr(MC_FMR, (i = inr(MC_FMR)) & ~MC_NEBP);
00199     /* Execute page write command. */
00200     rc = At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_WP, FLASH_WRITE_WAIT);
00201     /* Restore mode register. */
00202     outr(MC_FMR, i);
00203 
00204     return rc;
00205 }
00206 
00210 int At91EfcSectorErase(u_int off)
00211 {
00212     return At91EfcSectorWrite(off, NULL, 256);
00213 }
00214 
00222 int At91EfcRegionLock(u_int off)
00223 {
00224     return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_SLB, FLASH_WRITE_WAIT);
00225 }
00226 
00234 int At91EfcRegionUnlock(u_int off)
00235 {
00236     return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_CLB, FLASH_WRITE_WAIT);
00237 }
00238 
00250 int At91EfcParamRead(u_int pos, void *data, u_int len)
00251 {
00252     return At91EfcSectorRead(FLASH_CONF_SECTOR + pos, data, len);
00253 }
00254 
00269 int At91EfcParamWrite(u_int pos, CONST void *data, u_int len)
00270 {
00271     int rc = -1;
00272     u_char *buff;
00273 
00274     /* Load the complete configuration area. */
00275     if ((buff = malloc(FLASH_CONF_SIZE)) != NULL) {
00276 
00277         rc = At91EfcSectorRead(FLASH_CONF_SECTOR, buff, FLASH_CONF_SIZE);
00278         /* Compare old with new contents. */
00279         if (memcmp(buff + pos, data, len)) {
00280             /* New contents differs. Copy it into the sector buffer. */
00281             memcpy(buff + pos, data, len);
00282             /* Write back new data. Maintain region lock. */
00283             if (At91EfcRegionUnlock(FLASH_CONF_SECTOR) == 0) {
00284                 rc = At91EfcSectorWrite(FLASH_CONF_SECTOR, buff, FLASH_CONF_SIZE);
00285                 At91EfcRegionLock(FLASH_CONF_SECTOR);
00286             }
00287         }
00288         free(buff);
00289     }
00290     return rc;
00291 }
00292 

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