Nut/OS  4.10.3
API Reference
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 <cfg/memory.h>
00060 
00061 #include <sys/atom.h>
00062 #include <dev/nvmem.h>
00063 
00064 #include <stdint.h>
00065 #include <stdlib.h>
00066 #include <string.h>
00067 
00068 #include <arch/arm/atmel/at91_efc.h>
00069 
00074 
00077 #ifndef EFC_CHIP_BASE
00078 #define EFC_CHIP_BASE  0x00100000
00079 #endif
00080 
00083 #ifndef EFC_CHIP_SIZE
00084 #define EFC_CHIP_SIZE  0x00040000
00085 #endif
00086 
00095 #ifndef FLASH_CONF_SECTOR
00096 #if defined(MCU_AT91SAM7S512) || defined(MCU_AT91SAM7SE512) || \
00097     defined(MCU_AT91SAM7X512) || defined(MCU_AT91SAM9XE512)
00098 #define FLASH_CONF_SECTOR  0x0007FF00
00099 #else
00100 #define FLASH_CONF_SECTOR  0x0003FF00
00101 #endif
00102 #endif
00103 
00113 #ifndef FLASH_CONF_SIZE
00114 #define FLASH_CONF_SIZE         256
00115 #endif
00116 
00117 #ifndef EFC_WRITE_WAIT
00118 #define EFC_WRITE_WAIT        60000
00119 #endif
00120 
00121 #ifndef EFC_ERASE_WAIT
00122 #define EFC_ERASE_WAIT        60000
00123 #endif
00124 
00125 #ifndef EFC_CHIP_ERASE_WAIT
00126 #define EFC_CHIP_ERASE_WAIT   600000
00127 #endif
00128 
00129 
00130 typedef uint32_t flashdat_t;
00131 typedef unsigned long flashadr_t;
00132 typedef volatile flashdat_t *flashptr_t;
00133 
00140 RAMFUNC int At91EfcCmdEx(int fci, unsigned int cmd, uint32_t tmo)
00141 {
00142     int rc = 0;
00143     unsigned int fsr;
00144 
00145     /* Make sure that the previous command has finished. */
00146     while ((inr(fci ? MC_FSR_EFC1: MC_FSR_EFC0) & MC_FRDY) == 0) {
00147         if (tmo && --tmo < 1) {
00148             return -1;
00149         }
00150     }
00151 
00152     /* IRQ handlers are located in flash. Disable them. */
00153     NutEnterCritical();
00154 
00155     /* Write command. */
00156     outr(fci ? MC_FCR_EFC1 : MC_FCR_EFC0, MC_KEY | cmd);
00157 
00158     /* Wait for ready flag set. */
00159     while (((fsr = inr(fci ? MC_FSR_EFC1 : MC_FSR_EFC0)) & MC_FRDY) == 0) {
00160         if (tmo && --tmo < 1) {
00161             rc = -1;
00162             break;
00163         }
00164     }
00165 
00166     /* Flash command finished. Re-enable IRQ handlers. */
00167     NutExitCritical();
00168 
00169     /* Check result. */
00170     if (fsr & (MC_LOCKE | MC_PROGE)) {
00171         rc = -1;
00172     }
00173     return rc;
00174 }
00175 
00182 RAMFUNC int At91EfcCmd(unsigned int cmd, uint32_t tmo)
00183 {
00184     return At91EfcCmdEx(0, cmd, tmo);
00185 }
00186 
00196 int At91EfcSectorRead(unsigned int off, void *data, unsigned int len)
00197 {
00198     memcpy(data, (void *) (uptr_t) (EFC_CHIP_BASE + off), len);
00199 
00200     return 0;
00201 }
00202 
00215 int At91EfcSectorWrite(unsigned int off, CONST void *data, unsigned int len)
00216 {
00217     flashptr_t dp = (flashptr_t) (uptr_t) (EFC_CHIP_BASE + off);
00218     int rc;
00219     unsigned int i;
00220 
00221     if (data) {
00222         flashptr_t sp = (flashptr_t) data;
00223 
00224         /* Copy data to the flash write buffer. */
00225         for (i = 0; i < len; i += sizeof(flashdat_t)) {
00226             *dp++ = *sp++;
00227         }
00228     }
00229     else {
00230         /* All bits set to emulate sector erasing. */
00231         for (i = 0; i < len; i += sizeof(flashdat_t)) {
00232             *dp++ = (flashdat_t)(-1);
00233         }
00234     }
00235 
00236     if (off < EFC_CHIP_SIZE) {
00237         /* Clear NEBP in mode register for automatic erasure. */
00238         outr(MC_FMR, (i = inr(MC_FMR)) & ~MC_NEBP);
00239         /* Execute page write command. */
00240         rc = At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_WP, EFC_WRITE_WAIT);
00241         /* Restore mode register. */
00242         outr(MC_FMR, i);
00243     } else {
00244         /* Clear NEBP in mode register for automatic erasure. */
00245         outr(MC_FMR_EFC1, (i = inr(MC_FMR_EFC1)) & ~MC_NEBP);
00246         /* Execute page write command. */
00247         rc = At91EfcCmdEx(1, ((off - EFC_CHIP_SIZE) & MC_PAGEN_MASK) | MC_FCMD_WP, EFC_WRITE_WAIT);
00248         /* Restore mode register. */
00249         outr(MC_FMR_EFC1, i);
00250     }
00251     return rc;
00252 }
00253 
00257 int At91EfcSectorErase(unsigned int off)
00258 {
00259     return At91EfcSectorWrite(off, NULL, 256);
00260 }
00261 
00269 int At91EfcRegionLock(unsigned int off)
00270 {
00271     if (off < EFC_CHIP_SIZE) {
00272         return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_SLB, EFC_WRITE_WAIT);
00273     }
00274     off -= EFC_CHIP_SIZE;
00275     return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_SLB, EFC_WRITE_WAIT);
00276 }
00277 
00285 int At91EfcRegionUnlock(unsigned int off)
00286 {
00287     if (off < EFC_CHIP_SIZE) {
00288         return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_CLB, EFC_WRITE_WAIT);
00289     }
00290     off -= EFC_CHIP_SIZE;
00291     return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_CLB, EFC_WRITE_WAIT);
00292 }
00293 
00305 int At91EfcParamRead(unsigned int pos, void *data, unsigned int len)
00306 {
00307     return At91EfcSectorRead(FLASH_CONF_SECTOR + pos, data, len);
00308 }
00309 
00324 int At91EfcParamWrite(unsigned int pos, CONST void *data, unsigned int len)
00325 {
00326     int rc = -1;
00327     uint8_t *buff;
00328 
00329     /* Load the complete configuration area. */
00330     if ((buff = malloc(FLASH_CONF_SIZE)) != NULL) {
00331 
00332         rc = At91EfcSectorRead(FLASH_CONF_SECTOR, buff, FLASH_CONF_SIZE);
00333         /* Compare old with new contents. */
00334         if (memcmp(buff + pos, data, len)) {
00335             /* New contents differs. Copy it into the sector buffer. */
00336             memcpy(buff + pos, data, len);
00337             /* Write back new data. Maintain region lock. */
00338             if (At91EfcRegionUnlock(FLASH_CONF_SECTOR) == 0) {
00339                 rc = At91EfcSectorWrite(FLASH_CONF_SECTOR, buff, FLASH_CONF_SIZE);
00340                 At91EfcRegionLock(FLASH_CONF_SECTOR);
00341             }
00342         }
00343         free(buff);
00344     }
00345     return rc;
00346 }
00347