at91_efc.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. * Copyright (C) 2006 by egnite Software GmbH. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. */
  33. /*!
  34. * \file arch/arm/dev/at91_efc.c
  35. * \brief SAM7 embedded flash controller support.
  36. *
  37. * \verbatim
  38. *
  39. * $Log$
  40. * Revision 1.4 2009/01/17 11:26:37 haraldkipp
  41. * Getting rid of two remaining BSD types in favor of stdint.
  42. * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
  43. *
  44. * Revision 1.3 2008/08/11 06:59:04 haraldkipp
  45. * BSD types replaced by stdint types (feature request #1282721).
  46. *
  47. * Revision 1.2 2006/10/08 16:48:07 haraldkipp
  48. * Documentation fixed
  49. *
  50. * Revision 1.1 2006/07/26 11:20:57 haraldkipp
  51. * Added non-volatile configuration memory support for SAM7X, using upper
  52. * 16k region of on-chip flash.
  53. *
  54. *
  55. * \endverbatim
  56. */
  57. #include <cfg/memory.h>
  58. #include <sys/atom.h>
  59. #include <dev/nvmem.h>
  60. #include <stdint.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <arch/arm/atmel/at91_efc.h>
  64. /*!
  65. * \addtogroup xgAt91Efc
  66. */
  67. /*@{*/
  68. /*! \brief Base address of the flash memory chip.
  69. */
  70. #ifndef EFC_CHIP_BASE
  71. #define EFC_CHIP_BASE 0x00100000
  72. #endif
  73. /*! \brief Size handled by each controller.
  74. */
  75. #ifndef EFC_CHIP_SIZE
  76. #define EFC_CHIP_SIZE 0x00040000
  77. #endif
  78. /*! \brief Address offset of the configuration sector.
  79. *
  80. * Although this is a configurable item, we try to determine
  81. * a default value for some of the most widely used CPUs.
  82. *
  83. * \todo Provide pre-defined flash layouts for all CPUs in
  84. * one of the architecture specific header files.
  85. */
  86. #ifndef FLASH_CONF_SECTOR
  87. #if defined(MCU_AT91SAM7S512) || defined(MCU_AT91SAM7SE512) || \
  88. defined(MCU_AT91SAM7X512) || defined(MCU_AT91SAM9XE512)
  89. #define FLASH_CONF_SECTOR 0x0007FF00
  90. #else
  91. #define FLASH_CONF_SECTOR 0x0003FF00
  92. #endif
  93. #endif
  94. /*! \brief Size of the configuration area.
  95. *
  96. * During write operations a buffer with this size is allocated
  97. * from heap and may cause memory problems with large sectors.
  98. * Thus, this value may be less than the size of the configuration
  99. * sector, in which case the rest of the sector is unused.
  100. *
  101. * Currently only 1 sector can be used for system configurations.
  102. */
  103. #ifndef FLASH_CONF_SIZE
  104. #define FLASH_CONF_SIZE 256
  105. #endif
  106. #ifndef EFC_WRITE_WAIT
  107. #define EFC_WRITE_WAIT 60000
  108. #endif
  109. #ifndef EFC_ERASE_WAIT
  110. #define EFC_ERASE_WAIT 60000
  111. #endif
  112. #ifndef EFC_CHIP_ERASE_WAIT
  113. #define EFC_CHIP_ERASE_WAIT 600000
  114. #endif
  115. typedef uint32_t flashdat_t;
  116. typedef unsigned long flashadr_t;
  117. typedef volatile flashdat_t *flashptr_t;
  118. /*!
  119. * \brief Execute flash controller command.
  120. *
  121. * This routine must not be located in internal flash memory.
  122. *
  123. */
  124. RAMFUNC int At91EfcCmdEx(int fci, unsigned int cmd, uint32_t tmo)
  125. {
  126. int rc = 0;
  127. unsigned int fsr;
  128. /* Make sure that the previous command has finished. */
  129. while ((inr(fci ? MC_FSR_EFC1: MC_FSR_EFC0) & MC_FRDY) == 0) {
  130. if (tmo && --tmo < 1) {
  131. return -1;
  132. }
  133. }
  134. /* IRQ handlers are located in flash. Disable them. */
  135. NutEnterCritical();
  136. /* Write command. */
  137. outr(fci ? MC_FCR_EFC1 : MC_FCR_EFC0, MC_KEY | cmd);
  138. /* Wait for ready flag set. */
  139. while (((fsr = inr(fci ? MC_FSR_EFC1 : MC_FSR_EFC0)) & MC_FRDY) == 0) {
  140. if (tmo && --tmo < 1) {
  141. rc = -1;
  142. break;
  143. }
  144. }
  145. /* Flash command finished. Re-enable IRQ handlers. */
  146. NutExitCritical();
  147. /* Check result. */
  148. if (fsr & (MC_LOCKE | MC_PROGE)) {
  149. rc = -1;
  150. }
  151. return rc;
  152. }
  153. /*!
  154. * \brief Execute flash controller command.
  155. *
  156. * This routine must not be located in internal flash memory.
  157. *
  158. */
  159. RAMFUNC int At91EfcCmd(unsigned int cmd, uint32_t tmo)
  160. {
  161. return At91EfcCmdEx(0, cmd, tmo);
  162. }
  163. /*!
  164. * \brief Read data from flash memory.
  165. *
  166. * \param off Start location within the chip, starting at 0.
  167. * \param data Points to a buffer that receives the data.
  168. * \param len Number of bytes to read.
  169. *
  170. * \return Always 0.
  171. */
  172. int At91EfcSectorRead(unsigned int off, void *data, unsigned int len)
  173. {
  174. memcpy(data, (void *) (uptr_t) (EFC_CHIP_BASE + off), len);
  175. return 0;
  176. }
  177. /*!
  178. * \brief Write data into flash memory.
  179. *
  180. * The related sector will be automatically erased before writing.
  181. *
  182. * \param off Start location within the chip, starting at 0.
  183. * \param data Points to a buffer that contains the bytes to be written.
  184. * If this is a NULL pointer, then the sector will be reased.
  185. * \param len Number of bytes to write, 1 full sector max.
  186. *
  187. * \return 0 on success or -1 in case of an error.
  188. */
  189. int At91EfcSectorWrite(unsigned int off, const void *data, unsigned int len)
  190. {
  191. flashptr_t dp = (flashptr_t) (uptr_t) (EFC_CHIP_BASE + off);
  192. int rc;
  193. unsigned int i;
  194. if (data) {
  195. flashptr_t sp = (flashptr_t) data;
  196. /* Copy data to the flash write buffer. */
  197. for (i = 0; i < len; i += sizeof(flashdat_t)) {
  198. *dp++ = *sp++;
  199. }
  200. }
  201. else {
  202. /* All bits set to emulate sector erasing. */
  203. for (i = 0; i < len; i += sizeof(flashdat_t)) {
  204. *dp++ = (flashdat_t)(-1);
  205. }
  206. }
  207. if (off < EFC_CHIP_SIZE) {
  208. /* Clear NEBP in mode register for automatic erasure. */
  209. outr(MC_FMR, (i = inr(MC_FMR)) & ~MC_NEBP);
  210. /* Execute page write command. */
  211. rc = At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_WP, EFC_WRITE_WAIT);
  212. /* Restore mode register. */
  213. outr(MC_FMR, i);
  214. } else {
  215. /* Clear NEBP in mode register for automatic erasure. */
  216. outr(MC_FMR_EFC1, (i = inr(MC_FMR_EFC1)) & ~MC_NEBP);
  217. /* Execute page write command. */
  218. rc = At91EfcCmdEx(1, ((off - EFC_CHIP_SIZE) & MC_PAGEN_MASK) | MC_FCMD_WP, EFC_WRITE_WAIT);
  219. /* Restore mode register. */
  220. outr(MC_FMR_EFC1, i);
  221. }
  222. return rc;
  223. }
  224. /*!
  225. * \brief Erase sector at the specified offset.
  226. */
  227. int At91EfcSectorErase(unsigned int off)
  228. {
  229. return At91EfcSectorWrite(off, NULL, 256);
  230. }
  231. /*!
  232. * \brief Lock specified region.
  233. *
  234. * \param off Location within the region to be locked.
  235. *
  236. * \return 0 on success or -1 in case of an error.
  237. */
  238. int At91EfcRegionLock(unsigned int off)
  239. {
  240. if (off < EFC_CHIP_SIZE) {
  241. return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_SLB, EFC_WRITE_WAIT);
  242. }
  243. off -= EFC_CHIP_SIZE;
  244. return At91EfcCmdEx(1,(off & MC_PAGEN_MASK) | MC_FCMD_SLB, EFC_WRITE_WAIT);
  245. }
  246. /*!
  247. * \brief Unlock specified region.
  248. *
  249. * \param off Location within the region to be unlocked.
  250. *
  251. * \return 0 on success or -1 in case of an error.
  252. */
  253. int At91EfcRegionUnlock(unsigned int off)
  254. {
  255. if (off < EFC_CHIP_SIZE) {
  256. return At91EfcCmd((off & MC_PAGEN_MASK) | MC_FCMD_CLB, EFC_WRITE_WAIT);
  257. }
  258. off -= EFC_CHIP_SIZE;
  259. return At91EfcCmdEx(1,(off & MC_PAGEN_MASK) | MC_FCMD_CLB, EFC_WRITE_WAIT);
  260. }
  261. /*!
  262. * \brief Load configuration parameters from embedded flash memory.
  263. *
  264. * Applications should call NutNvMemLoad().
  265. *
  266. * \param pos Start location within configuration sector.
  267. * \param data Points to a buffer that receives the contents.
  268. * \param len Number of bytes to read.
  269. *
  270. * \return Always 0.
  271. */
  272. int At91EfcParamRead(unsigned int pos, void *data, unsigned int len)
  273. {
  274. return At91EfcSectorRead(FLASH_CONF_SECTOR + pos, data, len);
  275. }
  276. /*!
  277. * \brief Store configuration parameters in embedded flash memory.
  278. *
  279. * Applications should call NutNvMemSave().
  280. *
  281. * The region that contains the configuration sector will be automatically
  282. * locked.
  283. *
  284. * \param pos Start location within configuration sector.
  285. * \param data Points to a buffer that contains the bytes to store.
  286. * \param len Number of bytes to store.
  287. *
  288. * \return 0 on success or -1 in case of an error.
  289. */
  290. int At91EfcParamWrite(unsigned int pos, const void *data, unsigned int len)
  291. {
  292. int rc = -1;
  293. uint8_t *buff;
  294. /* Load the complete configuration area. */
  295. if ((buff = malloc(FLASH_CONF_SIZE)) != NULL) {
  296. rc = At91EfcSectorRead(FLASH_CONF_SECTOR, buff, FLASH_CONF_SIZE);
  297. /* Compare old with new contents. */
  298. if (memcmp(buff + pos, data, len)) {
  299. /* New contents differs. Copy it into the sector buffer. */
  300. memcpy(buff + pos, data, len);
  301. /* Write back new data. Maintain region lock. */
  302. if (At91EfcRegionUnlock(FLASH_CONF_SECTOR) == 0) {
  303. rc = At91EfcSectorWrite(FLASH_CONF_SECTOR, buff, FLASH_CONF_SIZE);
  304. At91EfcRegionLock(FLASH_CONF_SECTOR);
  305. }
  306. }
  307. free(buff);
  308. }
  309. return rc;
  310. }
  311. /*@}*/