arc_cache.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /* ------------------------------------------
  2. * Copyright (c) 2016, Synopsys, Inc. All rights reserved.
  3. * Redistribution and use in source and binary forms, with or without modification,
  4. * are permitted provided that the following conditions are met:
  5. * 1) Redistributions of source code must retain the above copyright notice, this
  6. * list of conditions and the following disclaimer.
  7. * 2) Redistributions in binary form must reproduce the above copyright notice,
  8. * this list of conditions and the following disclaimer in the documentation and/or
  9. * other materials provided with the distribution.
  10. * 3) Neither the name of the Synopsys, Inc., nor the names of its contributors may
  11. * be used to endorse or promote products derived from this software without
  12. * specific prior written permission.
  13. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  14. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  17. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  18. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  19. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  20. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  21. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  22. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. *
  24. * \version 2016.05
  25. * \date 2014-07-15
  26. * \author Wayne Ren(Wei.Ren@synopsys.com)
  27. --------------------------------------------- */
  28. /**
  29. * \file
  30. * \ingroup ARC_HAL_MISC_CACHE
  31. * \brief implementation of cache related functions
  32. */
  33. #include "inc/arc/arc_cache.h"
  34. #define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
  35. struct cache_config {
  36. uint8_t ver; /* version */
  37. uint8_t assoc; /* Cache Associativity */
  38. uint16_t line; /* cache line/block size */
  39. uint32_t capacity; /* capacity */
  40. };
  41. static struct cache_config icache_config, dcache_config;
  42. /**
  43. * \brief invalidate multi instruction cache lines
  44. *
  45. * \param[in] start_addr start address in instruction cache
  46. * \param[in] size the bytes to be invalidated
  47. * \return 0, succeeded, -1, failed
  48. */
  49. int32_t icache_invalidate_mlines(uint32_t start_addr, uint32_t size)
  50. {
  51. if (!icache_available()) return -1;
  52. if ((size == 0) || (size > icache_config.capacity)) {
  53. return -1;
  54. }
  55. uint32_t end_addr;
  56. uint32_t line_size;
  57. uint32_t status;
  58. line_size = (uint32_t)(icache_config.line);
  59. end_addr = start_addr + size - 1;
  60. start_addr &= (uint32_t)(~(line_size - 1));
  61. status = cpu_lock_save();
  62. do {
  63. _arc_aux_write(AUX_IC_IVIL, start_addr);
  64. Asm("nop_s");
  65. Asm("nop_s");
  66. Asm("nop_s");
  67. start_addr += line_size;
  68. } while (start_addr <= end_addr);
  69. cpu_unlock_restore(status);
  70. return 0;
  71. }
  72. /**
  73. * \brief lock multi lines in instruction cache
  74. *
  75. * \param[in] start_addr start address in instruction cache
  76. * \param[in] size the bytes to be locked
  77. * \return 0, succeeded, -1, failed (cache already locked or other reasons)
  78. */
  79. int32_t icache_lock_mlines(uint32_t start_addr, uint32_t size)
  80. {
  81. if (!icache_available()) return -1;
  82. if ((size == 0) || (size > icache_config.capacity)) {
  83. return -1;
  84. }
  85. uint32_t end_addr;
  86. uint32_t line_size;
  87. uint32_t status;
  88. int32_t ercd = 0;
  89. line_size = (uint32_t)(icache_config.line);
  90. end_addr = start_addr + size - 1;
  91. start_addr &= (uint32_t)(~(line_size - 1));
  92. status = cpu_lock_save();
  93. do {
  94. _arc_aux_write(AUX_IC_LIL, start_addr);
  95. if(_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_OP_SUCCEEDED) {
  96. start_addr += line_size;
  97. } else {
  98. ercd = -1; /* the operation failed */
  99. break;
  100. }
  101. } while (start_addr <= end_addr);
  102. cpu_unlock_restore(status);
  103. return ercd;
  104. }
  105. /**
  106. * \brief directly write icache internal ram
  107. *
  108. * \param[in] cache_addr, icache internal address(way+index+offset)
  109. * \param[in] tag cache tag to write (tag+lock bit+valid bit)
  110. * \param[in] data cache data to write
  111. * \return 0, succeeded, -1, failed
  112. */
  113. int32_t icache_direct_write(uint32_t cache_addr, uint32_t tag, uint32_t data)
  114. {
  115. if (!icache_available()) return -1;
  116. if (_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_INDIRECT_ACCESS) {
  117. return -1;
  118. }
  119. _arc_aux_write(AUX_IC_RAM_ADDR, cache_addr);
  120. _arc_aux_write(AUX_IC_TAG, tag );
  121. _arc_aux_write(AUX_IC_DATA, data);
  122. return 0;
  123. }
  124. /**
  125. * \brief directly read icache internal ram
  126. *
  127. * \param[in] cache_addr, icache internal address(way+index+offset)
  128. * \param[out] tag cache tag to read (tag+index+lock bit+valid bit)
  129. * \param[out] data cache data to read
  130. * \return 0, succeeded, -1, failed
  131. */
  132. int32_t icache_direct_read(uint32_t cache_addr, uint32_t *tag, uint32_t *data)
  133. {
  134. if (!icache_available()) return -1;
  135. if (_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_INDIRECT_ACCESS) {
  136. return -1;
  137. }
  138. _arc_aux_write(AUX_IC_RAM_ADDR, cache_addr);
  139. *tag = _arc_aux_read(AUX_IC_TAG);
  140. *data = _arc_aux_read(AUX_IC_DATA);
  141. return 0;
  142. }
  143. /**
  144. * \brief indirectly read icache internal ram
  145. *
  146. * \param[in] mem_addr, memory address
  147. * \param[out] tag cache tag to read
  148. * \param[out] data cache data to read
  149. * \return 0, succeeded, -1, failed
  150. */
  151. int32_t icache_indirect_read(uint32_t mem_addr, uint32_t *tag, uint32_t *data)
  152. {
  153. if (!icache_available()) return -1;
  154. if (!(_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_INDIRECT_ACCESS)) {
  155. return -1;
  156. }
  157. _arc_aux_write(AUX_IC_RAM_ADDR, mem_addr);
  158. if(_arc_aux_read(AUX_IC_CTRL) & IC_CTRL_OP_SUCCEEDED) {
  159. *tag = _arc_aux_read(AUX_IC_TAG);
  160. *data = _arc_aux_read(AUX_IC_DATA);
  161. } else {
  162. return -1; /* the specified memory is not in icache */
  163. }
  164. return 0;
  165. }
  166. /**
  167. * \brief invalidate multi data cache lines
  168. *
  169. * \param[in] start_addr start address in data cache
  170. * \param[in] size the bytes to be invalidated
  171. * \return 0, succeeded, -1, failed
  172. */
  173. int32_t dcache_invalidate_mlines(uint32_t start_addr, uint32_t size)
  174. {
  175. if (!dcache_available()) return -1;
  176. uint32_t end_addr;
  177. uint32_t line_size;
  178. uint32_t status;
  179. if ((size == 0) || (size > dcache_config.capacity)) {
  180. return -1;
  181. }
  182. line_size = (uint32_t)(dcache_config.line);
  183. end_addr = start_addr + size - 1;
  184. start_addr &= (uint32_t)(~(line_size - 1));
  185. status = cpu_lock_save();
  186. do {
  187. _arc_aux_write(AUX_DC_IVDL, start_addr);
  188. Asm("nop_s");
  189. Asm("nop_s");
  190. Asm("nop_s");
  191. /* wait for flush completion */
  192. while (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS);
  193. start_addr += line_size;
  194. } while (start_addr <= end_addr);
  195. cpu_unlock_restore(status);
  196. return 0;
  197. }
  198. /**
  199. * \brief flush multi lines in data cache
  200. *
  201. * \param[in] start_addr start address
  202. * \param[in] size the bytes to be flushed
  203. * \return 0, succeeded, -1, failed
  204. */
  205. int32_t dcache_flush_mlines(uint32_t start_addr, uint32_t size)
  206. {
  207. if (!dcache_available()) return -1;
  208. if ((size == 0) || (size > dcache_config.capacity)) {
  209. return -1;
  210. }
  211. uint32_t end_addr;
  212. uint32_t line_size;
  213. uint32_t status;
  214. line_size = (uint32_t)(dcache_config.line);
  215. end_addr = start_addr + size - 1;
  216. start_addr &= (uint32_t)(~(line_size - 1));
  217. status = cpu_lock_save();
  218. do {
  219. _arc_aux_write(AUX_DC_FLDL, start_addr);
  220. Asm("nop_s");
  221. Asm("nop_s");
  222. Asm("nop_s");
  223. /* wait for flush completion */
  224. while (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_FLUSH_STATUS);
  225. start_addr += line_size;
  226. } while (start_addr <= end_addr);
  227. cpu_unlock_restore(status);
  228. return 0;
  229. }
  230. /**
  231. * \brief lock multi lines in data cache
  232. *
  233. * \param[in] start_addr start address in data cache
  234. * \param[in] size the bytes to be locked
  235. * \return 0, succeeded, -1, failed
  236. */
  237. int32_t dcache_lock_mlines(uint32_t start_addr, uint32_t size)
  238. {
  239. if (!dcache_available()) return -1;
  240. if ((size == 0) || (size > dcache_config.capacity)) {
  241. return -1;
  242. }
  243. uint32_t end_addr;
  244. uint32_t line_size;
  245. uint32_t status;
  246. int32_t ercd = 0;
  247. line_size = (uint32_t)(dcache_config.line);
  248. end_addr = start_addr + size - 1;
  249. start_addr &= (uint32_t)(~(line_size - 1));
  250. status = cpu_lock_save();
  251. do {
  252. _arc_aux_write(AUX_DC_LDL, start_addr);
  253. Asm("nop_s");
  254. if(_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_OP_SUCCEEDED) {
  255. start_addr += line_size;
  256. } else {
  257. ercd = -1; /* the operation failed */
  258. break;
  259. }
  260. } while (start_addr <= end_addr);
  261. cpu_unlock_restore(status);
  262. return ercd;
  263. }
  264. /**
  265. * \brief directly write dcache internal ram
  266. *
  267. * \param[in] cache_addr, dcache internal address(way+index+offset)
  268. * \param[in] tag cache tag to write
  269. * \param[in] data cache data to write
  270. * \return 0, succeeded, -1, failed
  271. */
  272. int32_t dcache_direct_write(uint32_t cache_addr, uint32_t tag, uint32_t data)
  273. {
  274. if (!dcache_available()) return -1;
  275. if (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_INDIRECT_ACCESS) {
  276. return -1;
  277. }
  278. _arc_aux_write(AUX_DC_RAM_ADDR, cache_addr);
  279. _arc_aux_write(AUX_DC_TAG, tag);
  280. _arc_aux_write(AUX_DC_DATA, data);
  281. return 0;
  282. }
  283. /**
  284. * \brief directly read dcache internal ram
  285. *
  286. * \param[in] cache_addr, dcache internal address(way+index+offset)
  287. * \param[out] tag cache tag to read
  288. * \param[out] data cache data to read
  289. * \return 0, succeeded, -1, failed
  290. */
  291. int32_t dcache_direct_read(uint32_t cache_addr, uint32_t *tag, uint32_t *data)
  292. {
  293. if (!dcache_available()) return -1;
  294. if (_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_INDIRECT_ACCESS) {
  295. return -1;
  296. }
  297. _arc_aux_write(AUX_DC_RAM_ADDR, cache_addr);
  298. *tag = _arc_aux_read(AUX_DC_TAG);
  299. *data = _arc_aux_read(AUX_DC_DATA);
  300. return 0;
  301. }
  302. /**
  303. * \brief indirectly read dcache internal ram
  304. *
  305. * \param[in] mem_addr, memory address(tag+index+offset)
  306. * \param[out] tag cache tag to read
  307. * \param[out] data cache data to read
  308. * \return 0, succeeded, -1, failed
  309. */
  310. int32_t dcache_indirect_read(uint32_t mem_addr, uint32_t *tag, uint32_t *data)
  311. {
  312. if (!dcache_available()) return -1;
  313. if (!(_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_INDIRECT_ACCESS)) {
  314. return -1;
  315. }
  316. _arc_aux_write(AUX_DC_RAM_ADDR, mem_addr);
  317. if(_arc_aux_read(AUX_DC_CTRL) & DC_CTRL_OP_SUCCEEDED) {
  318. *tag = _arc_aux_read(AUX_DC_TAG);
  319. *data = _arc_aux_read(AUX_DC_DATA);
  320. } else {
  321. return -1; /* the specified memory is not in dcache */
  322. }
  323. return 0;
  324. }
  325. /**
  326. * \brief initialize cache
  327. * 1. invalidate icache and dcache
  328. * 2. Only support ARCv2 cache
  329. */
  330. void arc_cache_init(void)
  331. {
  332. uint32_t build_cfg;
  333. build_cfg = _arc_aux_read(AUX_BCR_D_CACHE);
  334. dcache_config.ver = build_cfg & 0xff;
  335. if (dcache_config.ver >= 0x04) { /* ARCv2 */
  336. dcache_enable(DC_CTRL_DISABLE_FLUSH_LOCKED |
  337. DC_CTRL_INDIRECT_ACCESS | DC_CTRL_INVALID_FLUSH);
  338. dcache_invalidate();
  339. dcache_config.assoc = 1 << ((build_cfg >> 8) & 0xf);
  340. dcache_config.capacity = 512 << ((build_cfg >> 12) & 0xf);
  341. dcache_config.line = 16 << ((build_cfg >> 16) & 0xf);
  342. }
  343. build_cfg = _arc_aux_read(AUX_BCR_I_CACHE);
  344. icache_config.ver = build_cfg & 0xff;
  345. if (icache_config.ver >= 0x04) { /* ARCv2 */
  346. icache_config.assoc = 1 << ((build_cfg >> 8) & 0xf);
  347. icache_config.capacity = 512 << ((build_cfg >> 12) & 0xf);
  348. icache_config.line = 8 << ((build_cfg >> 16) & 0xf);
  349. icache_enable(IC_CTRL_IC_ENABLE);
  350. icache_invalidate();
  351. }
  352. }