mmu.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*
  2. * Copyright (c) 2008-2012, Freescale Semiconductor, Inc.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without modification,
  6. * are permitted provided that the following conditions are met:
  7. *
  8. * o Redistributions of source code must retain the above copyright notice, this list
  9. * of conditions and the following disclaimer.
  10. *
  11. * o Redistributions in binary form must reproduce the above copyright notice, this
  12. * list of conditions and the following disclaimer in the documentation and/or
  13. * other materials provided with the distribution.
  14. *
  15. * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
  16. * contributors may be used to endorse or promote products derived from this
  17. * software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  23. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  24. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  25. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  26. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  28. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /*!
  31. * @file mmu.c
  32. * @brief System memory arangement.
  33. */
  34. #include "cortex_a.h"
  35. #include "mmu.h"
  36. #include "arm_cp_registers.h"
  37. ////////////////////////////////////////////////////////////////////////////////
  38. // Definitions
  39. ////////////////////////////////////////////////////////////////////////////////
  40. //! @brief Size in bytes of the first-level page table.
  41. #define MMU_L1_PAGE_TABLE_SIZE (16 * 1024)
  42. //! @brief First-level 1MB section descriptor entry.
  43. typedef union mmu_l1_section {
  44. uint32_t u;
  45. struct {
  46. uint32_t id:2; //!< ID
  47. uint32_t b:1; //!< Bufferable
  48. uint32_t c:1; //!< Cacheable
  49. uint32_t xn:1; //!< Execute-not
  50. uint32_t domain:4; //!< Domain
  51. uint32_t _impl_defined:1; //!< Implementation defined, should be zero.
  52. uint32_t ap1_0:2; //!< Access permissions AP[1:0]
  53. uint32_t tex:3; //!< TEX remap
  54. uint32_t ap2:1; //!< Access permissions AP[2]
  55. uint32_t s:1; //!< Shareable
  56. uint32_t ng:1; //!< Not-global
  57. uint32_t _zero:1; //!< Should be zero.
  58. uint32_t ns:1; //!< Non-secure
  59. uint32_t address:12; //!< Physical base address
  60. };
  61. } mmu_l1_section_t;
  62. enum {
  63. kMMU_L1_Section_ID = 2, //!< ID value for a 1MB section first-level entry.
  64. kMMU_L1_Section_Address_Shift = 20 //!< Bit offset of the physical base address field.
  65. };
  66. ////////////////////////////////////////////////////////////////////////////////
  67. // Externs
  68. ////////////////////////////////////////////////////////////////////////////////
  69. extern char __l1_page_table_start;
  70. ////////////////////////////////////////////////////////////////////////////////
  71. // Code
  72. ////////////////////////////////////////////////////////////////////////////////
  73. void mmu_enable()
  74. {
  75. // invalidate all tlb
  76. arm_unified_tlb_invalidate();
  77. // read SCTLR
  78. uint32_t sctlr;
  79. _ARM_MRC(15, 0, sctlr, 1, 0, 0);
  80. // set MMU enable bit
  81. sctlr |= BM_SCTLR_M;
  82. // write modified SCTLR
  83. _ARM_MCR(15, 0, sctlr, 1, 0, 0);
  84. }
  85. void mmu_disable()
  86. {
  87. // read current SCTLR
  88. uint32_t sctlr;
  89. _ARM_MRC(15, 0, sctlr, 1, 0, 0);
  90. // clear MMU enable bit
  91. sctlr &=~ BM_SCTLR_M;
  92. // write modified SCTLR
  93. _ARM_MCR(15, 0, sctlr, 1, 0, 0);
  94. }
  95. void mmu_init()
  96. {
  97. // Get the L1 page table base address.
  98. uint32_t * table = (uint32_t *)&__l1_page_table_start;
  99. uint32_t share_attr = kShareable;
  100. // write table address to TTBR0
  101. _ARM_MCR(15, 0, table, 2, 0, 0);
  102. // set Client mode for all Domains
  103. uint32_t dacr = 0x55555555;
  104. _ARM_MCR(15, 0, dacr, 3, 0, 0); // MCR p15, 0, <Rd>, c3, c0, 0 ; Write DACR
  105. // Clear the L1 table.
  106. bzero(table, MMU_L1_PAGE_TABLE_SIZE);
  107. // Create default mappings.
  108. mmu_map_l1_range(0x00000000, 0x00000000, 0x00900000, kStronglyOrdered, kShareable, kRWAccess); // ROM and peripherals
  109. mmu_map_l1_range(0x00900000, 0x00900000, 0x00100000, kStronglyOrdered, kShareable, kRWAccess); // OCRAM
  110. mmu_map_l1_range(0x00a00000, 0x00a00000, 0x0f600000, kStronglyOrdered, kShareable, kRWAccess); // More peripherals
  111. // Check whether SMP is enabled. If it is not, then we don't want to make SDRAM shareable.
  112. uint32_t actlr = 0x0;
  113. _ARM_MRC(15, 0, actlr, 1, 0, 1);
  114. if (actlr & BM_ACTLR_SMP)
  115. {
  116. share_attr = kShareable;
  117. }
  118. else
  119. {
  120. share_attr = kNonshareable;
  121. }
  122. #if defined(CHIP_MX6DQ) || defined(CHIP_MX6SDL)
  123. mmu_map_l1_range(0x10000000, 0x10000000, 0x80000000, kOuterInner_WB_WA, share_attr, kRWAccess); // 2GB DDR
  124. #elif defined(CHIP_MX6SL) || defined(CHIP_MX6UL)
  125. mmu_map_l1_range(0x80000000, 0x80000000, 0x40000000, kOuterInner_WB_WA, share_attr, kRWAccess); // 1GB DDR
  126. #else
  127. #error Unknown chip type!
  128. #endif
  129. }
  130. void mmu_map_l1_range(uint32_t pa, uint32_t va, uint32_t length, mmu_memory_type_t memoryType, mmu_shareability_t isShareable, mmu_access_t access)
  131. {
  132. register mmu_l1_section_t entry;
  133. entry.u = 0;
  134. // Set constant attributes.
  135. entry.id = kMMU_L1_Section_ID;
  136. entry.xn = 0; // Allow execution
  137. entry.domain = 0; // Domain 0
  138. entry.ng = 0; // Global
  139. entry.ns = 0; // Secure
  140. // Set attributes based on the selected memory type.
  141. switch (memoryType)
  142. {
  143. case kStronglyOrdered:
  144. entry.c = 0;
  145. entry.b = 0;
  146. entry.tex = 0;
  147. entry.s = 1; // Ignored
  148. break;
  149. case kDevice:
  150. if (isShareable)
  151. {
  152. entry.c = 0;
  153. entry.b = 1;
  154. entry.tex = 0;
  155. entry.s = 1; // Ignored
  156. }
  157. else
  158. {
  159. entry.c = 0;
  160. entry.b = 0;
  161. entry.tex = 2;
  162. entry.s = 0; // Ignored
  163. }
  164. break;
  165. case kOuterInner_WB_WA:
  166. entry.c = 1;
  167. entry.b = 1;
  168. entry.tex = 1;
  169. entry.s = isShareable;
  170. break;
  171. case kOuterInner_WT:
  172. entry.c = 1;
  173. entry.b = 0;
  174. entry.tex = 0;
  175. entry.s = isShareable;
  176. break;
  177. case kNoncacheable:
  178. entry.c = 0;
  179. entry.b = 0;
  180. entry.tex = 1;
  181. entry.s = isShareable;
  182. break;
  183. }
  184. // Set attributes from specified access mode.
  185. switch (access)
  186. {
  187. case kNoAccess:
  188. entry.ap2 = 0;
  189. entry.ap1_0 = 0;
  190. break;
  191. case kROAccess:
  192. entry.ap2 = 1;
  193. entry.ap1_0 = 3;
  194. break;
  195. case kRWAccess:
  196. entry.ap2 = 0;
  197. entry.ap1_0 = 3;
  198. break;
  199. }
  200. // Get the L1 page table base address.
  201. uint32_t * table = (uint32_t *)&__l1_page_table_start;
  202. // Convert addresses to 12-bit bases.
  203. uint32_t vbase = va >> kMMU_L1_Section_Address_Shift;
  204. uint32_t pbase = pa >> kMMU_L1_Section_Address_Shift;
  205. uint32_t entries = length >> kMMU_L1_Section_Address_Shift;
  206. // Fill in L1 page table entries.
  207. for (; entries > 0; ++pbase, ++vbase, --entries)
  208. {
  209. entry.address = pbase;
  210. table[vbase] = entry.u;
  211. }
  212. // Invalidate TLB
  213. arm_unified_tlb_invalidate();
  214. }
  215. bool mmu_virtual_to_physical(uint32_t virtualAddress, uint32_t * physicalAddress)
  216. {
  217. uint32_t pa = 0;
  218. // VA to PA translation with privileged read permission check
  219. _ARM_MCR(15, 0, virtualAddress & 0xfffffc00, 7, 8, 0);
  220. // Read PA register
  221. _ARM_MRC(15, 0, pa, 7, 4, 0);
  222. // First bit of returned value is Result of conversion (0 is successful translation)
  223. if (pa & 1)
  224. {
  225. // We can try write permission also
  226. // VA to PA translation with privileged write permission check
  227. _ARM_MCR(15, 0, virtualAddress & 0xfffffc00, 7, 8, 1);
  228. // Read PA register
  229. _ARM_MRC(15, 0, pa, 7, 4, 0);
  230. // First bit of returned value is Result of conversion (0 is successful translation)
  231. if (pa & 1)
  232. {
  233. return false;
  234. }
  235. }
  236. if (physicalAddress)
  237. {
  238. // complete address returning base + offset
  239. pa = (pa & 0xfffff000) | (virtualAddress & 0x00000fff);
  240. *physicalAddress = pa;
  241. }
  242. return true;
  243. }
  244. ////////////////////////////////////////////////////////////////////////////////
  245. // EOF
  246. ////////////////////////////////////////////////////////////////////////////////