fsl_lmem_cache.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /*
  2. * The Clear BSD License
  3. * Copyright (c) 2015, Freescale Semiconductor, Inc.
  4. * Copyright 2016-2017 NXP
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without modification,
  8. * are permitted (subject to the limitations in the disclaimer below) provided
  9. * that the following conditions are met:
  10. *
  11. * o Redistributions of source code must retain the above copyright notice, this list
  12. * of conditions and the following disclaimer.
  13. *
  14. * o Redistributions in binary form must reproduce the above copyright notice, this
  15. * list of conditions and the following disclaimer in the documentation and/or
  16. * other materials provided with the distribution.
  17. *
  18. * o Neither the name of the copyright holder nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  24. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  25. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  27. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  28. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  30. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include "fsl_lmem_cache.h"
  35. /*******************************************************************************
  36. * Definitions
  37. ******************************************************************************/
  38. /* Component ID definition, used by tools. */
  39. #ifndef FSL_COMPONENT_ID
  40. #define FSL_COMPONENT_ID "platform.drivers.lmem"
  41. #endif
  42. #define LMEM_CACHEMODE_WIDTH (2U)
  43. #define LMEM_CACHEMODE_MASK_UNIT (0x3U)
  44. /*******************************************************************************
  45. * Code
  46. ******************************************************************************/
  47. void LMEM_EnableCodeCache(LMEM_Type *base, bool enable)
  48. {
  49. if (enable)
  50. {
  51. /* First, invalidate the entire cache. */
  52. LMEM_CodeCacheInvalidateAll(base);
  53. /* Now enable the cache. */
  54. base->PCCCR |= LMEM_PCCCR_ENCACHE_MASK;
  55. }
  56. else
  57. {
  58. /* First, push any modified contents. */
  59. LMEM_CodeCachePushAll(base);
  60. /* Now disable the cache. */
  61. base->PCCCR &= ~LMEM_PCCCR_ENCACHE_MASK;
  62. }
  63. }
  64. void LMEM_CodeCacheInvalidateAll(LMEM_Type *base)
  65. {
  66. /* Enables the processor code bus to invalidate all lines in both ways.
  67. and Initiate the processor code bus code cache command. */
  68. base->PCCCR |= LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK | LMEM_PCCCR_GO_MASK;
  69. /* Wait until the cache command completes. */
  70. while (base->PCCCR & LMEM_PCCCR_GO_MASK)
  71. {
  72. }
  73. /* As a precaution clear the bits to avoid inadvertently re-running this command. */
  74. base->PCCCR &= ~(LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK);
  75. }
  76. void LMEM_CodeCachePushAll(LMEM_Type *base)
  77. {
  78. /* Enable the processor code bus to push all modified lines. */
  79. base->PCCCR |= LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK | LMEM_PCCCR_GO_MASK;
  80. /* Wait until the cache command completes. */
  81. while (base->PCCCR & LMEM_PCCCR_GO_MASK)
  82. {
  83. }
  84. /* As a precaution clear the bits to avoid inadvertently re-running this command. */
  85. base->PCCCR &= ~(LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK);
  86. }
  87. void LMEM_CodeCacheClearAll(LMEM_Type *base)
  88. {
  89. /* Push and invalidate all. */
  90. base->PCCCR |= LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK | LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK |
  91. LMEM_PCCCR_GO_MASK;
  92. /* Wait until the cache command completes. */
  93. while (base->PCCCR & LMEM_PCCCR_GO_MASK)
  94. {
  95. }
  96. /* As a precaution clear the bits to avoid inadvertently re-running this command. */
  97. base->PCCCR &= ~(LMEM_PCCCR_PUSHW0_MASK | LMEM_PCCCR_PUSHW1_MASK | LMEM_PCCCR_INVW0_MASK | LMEM_PCCCR_INVW1_MASK);
  98. }
  99. /*FUNCTION**********************************************************************
  100. *
  101. * Function Name : LMEM_CodeCacheInvalidateLine
  102. * Description : This function invalidates a specific line in the Processor Code bus cache.
  103. *
  104. * This function invalidates a specific line in the cache. The function invalidates a
  105. * line in cache based on the physical address passed in by the user.
  106. * Invalidate - Unconditionally clear valid and modify bits of a cache entry
  107. *
  108. *END**************************************************************************/
  109. void LMEM_CodeCacheInvalidateLine(LMEM_Type *base, uint32_t address)
  110. {
  111. uint32_t pccReg = 0;
  112. /* Set the invalidate by line command and use the physical address. */
  113. pccReg =
  114. (base->PCCLCR & ~LMEM_PCCLCR_LCMD_MASK) | LMEM_PCCLCR_LCMD(kLMEM_CacheLineInvalidate) | LMEM_PCCLCR_LADSEL_MASK;
  115. base->PCCLCR = pccReg;
  116. /* Set the address and initiate the command. */
  117. base->PCCSAR = (address & LMEM_PCCSAR_PHYADDR_MASK) | LMEM_PCCSAR_LGO_MASK;
  118. /* Wait until the cache command completes. */
  119. while (base->PCCSAR & LMEM_PCCSAR_LGO_MASK)
  120. {
  121. }
  122. /* No need to clear this command since future line commands will overwrite
  123. the line command field. */
  124. }
  125. void LMEM_CodeCacheInvalidateMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
  126. {
  127. uint32_t endAddr = address + length;
  128. /* Align address to cache line size. */
  129. address = address & ~(LMEM_CACHE_LINE_SIZE - 1U);
  130. /* If the length exceeds 4KB, invalidate all. */
  131. if (length >= LMEM_CACHE_SIZE_ONEWAY)
  132. {
  133. LMEM_CodeCacheInvalidateAll(base);
  134. }
  135. else
  136. { /* Proceed with multi-line invalidate. */
  137. while (address < endAddr)
  138. {
  139. LMEM_CodeCacheInvalidateLine(base, address);
  140. address = address + LMEM_CACHE_LINE_SIZE;
  141. }
  142. }
  143. }
  144. void LMEM_CodeCachePushLine(LMEM_Type *base, uint32_t address)
  145. {
  146. uint32_t pccReg = 0;
  147. /* Set the push by line command. */
  148. pccReg = (base->PCCLCR & ~LMEM_PCCLCR_LCMD_MASK) | LMEM_PCCLCR_LCMD(kLMEM_CacheLinePush) | LMEM_PCCLCR_LADSEL_MASK;
  149. base->PCCLCR = pccReg;
  150. /* Set the address and initiate the command. */
  151. base->PCCSAR = (address & LMEM_PCCSAR_PHYADDR_MASK) | LMEM_PCCSAR_LGO_MASK;
  152. /* Wait until the cache command completes. */
  153. while (base->PCCSAR & LMEM_PCCSAR_LGO_MASK)
  154. {
  155. }
  156. /* No need to clear this command since future line commands will overwrite
  157. the line command field. */
  158. }
  159. void LMEM_CodeCachePushMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
  160. {
  161. uint32_t endAddr = address + length;
  162. /* Align address to cache line size. */
  163. address = address & ~(LMEM_CACHE_LINE_SIZE - 1U);
  164. /* If the length exceeds 4KB, push all. */
  165. if (length >= LMEM_CACHE_SIZE_ONEWAY)
  166. {
  167. LMEM_CodeCachePushAll(base);
  168. }
  169. else
  170. { /* Proceed with multi-line push. */
  171. while (address < endAddr)
  172. {
  173. LMEM_CodeCachePushLine(base, address);
  174. address = address + LMEM_CACHE_LINE_SIZE;
  175. }
  176. }
  177. }
  178. void LMEM_CodeCacheClearLine(LMEM_Type *base, uint32_t address)
  179. {
  180. uint32_t pccReg = 0;
  181. /* Set the push by line command. */
  182. pccReg = (base->PCCLCR & ~LMEM_PCCLCR_LCMD_MASK) | LMEM_PCCLCR_LCMD(kLMEM_CacheLineClear) | LMEM_PCCLCR_LADSEL_MASK;
  183. base->PCCLCR = pccReg;
  184. /* Set the address and initiate the command. */
  185. base->PCCSAR = (address & LMEM_PCCSAR_PHYADDR_MASK) | LMEM_PCCSAR_LGO_MASK;
  186. /* Wait until the cache command completes. */
  187. while (base->PCCSAR & LMEM_PCCSAR_LGO_MASK)
  188. {
  189. }
  190. /* No need to clear this command since future line commands will overwrite
  191. the line command field. */
  192. }
  193. void LMEM_CodeCacheClearMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
  194. {
  195. uint32_t endAddr = address + length;
  196. /* Align address to cache line size. */
  197. address = address & ~(LMEM_CACHE_LINE_SIZE - 1U);
  198. /* If the length exceeds 4KB, clear all. */
  199. if (length >= LMEM_CACHE_SIZE_ONEWAY)
  200. {
  201. LMEM_CodeCacheClearAll(base);
  202. }
  203. else /* Proceed with multi-line clear. */
  204. {
  205. while (address < endAddr)
  206. {
  207. LMEM_CodeCacheClearLine(base, address);
  208. address = address + LMEM_CACHE_LINE_SIZE;
  209. }
  210. }
  211. }
  212. #if (!defined(FSL_FEATURE_LMEM_SUPPORT_ICACHE_DEMOTE_REMOVE)) || !FSL_FEATURE_LMEM_SUPPORT_ICACHE_DEMOTE_REMOVE
  213. status_t LMEM_CodeCacheDemoteRegion(LMEM_Type *base, lmem_cache_region_t region, lmem_cache_mode_t cacheMode)
  214. {
  215. uint32_t mode = base->PCCRMR;
  216. uint32_t shift = LMEM_CACHEMODE_WIDTH * (uint32_t)region; /* Region shift. */
  217. uint32_t mask = LMEM_CACHEMODE_MASK_UNIT << shift; /* Region mask. */
  218. /* If the current cache mode is higher than the requested mode, return error. */
  219. if ((uint32_t)cacheMode >= ((mode & mask) >> shift))
  220. {
  221. return kStatus_Fail;
  222. }
  223. else
  224. { /* Proceed to demote the region. */
  225. LMEM_CodeCacheClearAll(base);
  226. base->PCCRMR = (mode & ~mask) | cacheMode << shift;
  227. return kStatus_Success;
  228. }
  229. }
  230. #endif /* FSL_FEATURE_LMEM_SUPPORT_ICACHE_DEMOTE_REMOVE */
  231. #if FSL_FEATURE_LMEM_HAS_SYSTEMBUS_CACHE
  232. void LMEM_EnableSystemCache(LMEM_Type *base, bool enable)
  233. {
  234. if (enable)
  235. {
  236. /* First, invalidate the entire cache. */
  237. LMEM_SystemCacheInvalidateAll(base);
  238. /* Now enable the cache. */
  239. base->PSCCR |= LMEM_PSCCR_ENCACHE_MASK ;
  240. }
  241. else
  242. {
  243. /* First, push any modified contents. */
  244. LMEM_SystemCachePushAll(base);
  245. /* Now disable the cache. */
  246. base->PSCCR &= ~LMEM_PSCCR_ENCACHE_MASK;
  247. }
  248. }
  249. void LMEM_SystemCacheInvalidateAll(LMEM_Type *base)
  250. {
  251. /* Enables the processor system bus to invalidate all lines in both ways.
  252. and Initiate the processor system bus cache command. */
  253. base->PSCCR |= LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK | LMEM_PSCCR_GO_MASK;
  254. /* Wait until the cache command completes */
  255. while (base->PSCCR & LMEM_PSCCR_GO_MASK)
  256. {
  257. }
  258. /* As a precaution clear the bits to avoid inadvertently re-running this command. */
  259. base->PSCCR &= ~(LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK);
  260. }
  261. void LMEM_SystemCachePushAll(LMEM_Type *base)
  262. {
  263. /* Enable the processor system bus to push all modified lines. */
  264. base->PSCCR |= LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK | LMEM_PSCCR_GO_MASK;
  265. /* Wait until the cache command completes. */
  266. while (base->PSCCR & LMEM_PSCCR_GO_MASK)
  267. {
  268. }
  269. /* As a precaution clear the bits to avoid inadvertently re-running this command. */
  270. base->PSCCR &= ~(LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK);
  271. }
  272. void LMEM_SystemCacheClearAll(LMEM_Type *base)
  273. {
  274. /* Push and invalidate all. */
  275. base->PSCCR |= LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK | LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK |
  276. LMEM_PSCCR_GO_MASK;
  277. /* Wait until the cache command completes. */
  278. while (base->PSCCR & LMEM_PSCCR_GO_MASK)
  279. {
  280. }
  281. /* As a precaution clear the bits to avoid inadvertently re-running this command. */
  282. base->PSCCR &= ~(LMEM_PSCCR_PUSHW0_MASK | LMEM_PSCCR_PUSHW1_MASK | LMEM_PSCCR_INVW0_MASK | LMEM_PSCCR_INVW1_MASK);
  283. }
  284. void LMEM_SystemCacheInvalidateLine(LMEM_Type *base, uint32_t address)
  285. {
  286. uint32_t pscReg = 0;
  287. /* Set the invalidate by line command and use the physical address. */
  288. pscReg =
  289. (base->PSCLCR & ~LMEM_PSCLCR_LCMD_MASK) | LMEM_PSCLCR_LCMD(kLMEM_CacheLineInvalidate) | LMEM_PSCLCR_LADSEL_MASK;
  290. base->PSCLCR = pscReg;
  291. /* Set the address and initiate the command. */
  292. base->PSCSAR = (address & LMEM_PSCSAR_PHYADDR_MASK) | LMEM_PSCSAR_LGO_MASK;
  293. /* Wait until the cache command completes. */
  294. while (base->PSCSAR & LMEM_PSCSAR_LGO_MASK)
  295. {
  296. }
  297. /* No need to clear this command since future line commands will overwrite
  298. the line command field. */
  299. }
  300. void LMEM_SystemCacheInvalidateMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
  301. {
  302. uint32_t endAddr = address + length;
  303. address = address & ~(LMEM_CACHE_LINE_SIZE - 1U); /* Align address to cache line size */
  304. /* If the length exceeds 4KB, invalidate all. */
  305. if (length >= LMEM_CACHE_SIZE_ONEWAY)
  306. {
  307. LMEM_SystemCacheInvalidateAll(base);
  308. }
  309. else /* Proceed with multi-line invalidate. */
  310. {
  311. while (address < endAddr)
  312. {
  313. LMEM_SystemCacheInvalidateLine(base, address);
  314. address = address + LMEM_CACHE_LINE_SIZE;
  315. }
  316. }
  317. }
  318. void LMEM_SystemCachePushLine(LMEM_Type *base, uint32_t address)
  319. {
  320. uint32_t pscReg = 0;
  321. /* Set the push by line command. */
  322. pscReg = (base->PSCLCR & ~LMEM_PSCLCR_LCMD_MASK) | LMEM_PSCLCR_LCMD(kLMEM_CacheLinePush) | LMEM_PSCLCR_LADSEL_MASK;
  323. base->PSCLCR = pscReg;
  324. /* Set the address and initiate the command. */
  325. base->PSCSAR = (address & LMEM_PSCSAR_PHYADDR_MASK) | LMEM_PSCSAR_LGO_MASK;
  326. /* Wait until the cache command completes. */
  327. while (base->PSCSAR & LMEM_PSCSAR_LGO_MASK)
  328. {
  329. }
  330. /* No need to clear this command since future line commands will overwrite
  331. the line command field. */
  332. }
  333. void LMEM_SystemCachePushMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
  334. {
  335. uint32_t endAddr = address + length;
  336. address = address & ~(LMEM_CACHE_LINE_SIZE - 1U); /* Align address to cache line size. */
  337. /* If the length exceeds 4KB, push all. */
  338. if (length >= LMEM_CACHE_SIZE_ONEWAY)
  339. {
  340. LMEM_SystemCachePushAll(base);
  341. }
  342. else
  343. { /* Proceed with multi-line push. */
  344. while (address < endAddr)
  345. {
  346. LMEM_SystemCachePushLine(base, address);
  347. address = address + LMEM_CACHE_LINE_SIZE;
  348. }
  349. }
  350. }
  351. void LMEM_SystemCacheClearLine(LMEM_Type *base, uint32_t address)
  352. {
  353. uint32_t pscReg = 0;
  354. /* Set the push by line command. */
  355. pscReg = (base->PSCLCR & ~LMEM_PSCLCR_LCMD_MASK) | LMEM_PSCLCR_LCMD(kLMEM_CacheLineClear) | LMEM_PSCLCR_LADSEL_MASK;
  356. base->PSCLCR = pscReg;
  357. /* Set the address and initiate the command. */
  358. base->PSCSAR = (address & LMEM_PSCSAR_PHYADDR_MASK) | LMEM_PSCSAR_LGO_MASK;
  359. /* Wait until the cache command completes. */
  360. while (base->PSCSAR & LMEM_PSCSAR_LGO_MASK)
  361. {
  362. }
  363. /* No need to clear this command since future line commands will overwrite
  364. the line command field. */
  365. }
  366. void LMEM_SystemCacheClearMultiLines(LMEM_Type *base, uint32_t address, uint32_t length)
  367. {
  368. uint32_t endAddr = address + length;
  369. address = address & ~(LMEM_CACHE_LINE_SIZE - 1U); /* Align address to cache line size. */
  370. /* If the length exceeds 4KB, clear all. */
  371. if (length >= LMEM_CACHE_SIZE_ONEWAY)
  372. {
  373. LMEM_SystemCacheClearAll(base);
  374. }
  375. else /* Proceed with multi-line clear. */
  376. {
  377. while (address < endAddr)
  378. {
  379. LMEM_SystemCacheClearLine(base, address);
  380. address = address + LMEM_CACHE_LINE_SIZE;
  381. }
  382. }
  383. }
  384. status_t LMEM_SystemCacheDemoteRegion(LMEM_Type *base, lmem_cache_region_t region, lmem_cache_mode_t cacheMode)
  385. {
  386. uint32_t mode = base->PSCRMR;
  387. uint32_t shift = LMEM_CACHEMODE_WIDTH * (uint32_t)region; /* Region shift. */
  388. uint32_t mask = LMEM_CACHEMODE_MASK_UNIT << shift; /* Region mask. */
  389. /* If the current cache mode is higher than the requested mode, return error. */
  390. if ((uint32_t)cacheMode >= ((mode & mask) >> shift))
  391. {
  392. return kStatus_Fail;
  393. }
  394. else
  395. { /* Proceed to demote the region. */
  396. LMEM_SystemCacheClearAll(base);
  397. base->PSCRMR = (mode & ~mask) | (cacheMode << shift);
  398. return kStatus_Success;
  399. }
  400. }
  401. #endif /* FSL_FEATURE_LMEM_HAS_SYSTEMBUS_CACHE */