flush.S 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. /* Copyright (C) 2003-2007 Analog Devices Inc.
  2. *
  3. * This file is subject to the terms and conditions of the GNU General Public
  4. * License.
  5. */
  6. #define ASSEMBLY
  7. #include <asm/linkage.h>
  8. #include <asm/cplb.h>
  9. #include <config.h>
  10. #include <asm/blackfin.h>
  11. .text
  12. /* This is an external function being called by the user
  13. * application through __flush_cache_all. Currently this function
  14. * serves the purpose of flushing all the pending writes in
  15. * in the instruction cache.
  16. */
  17. ENTRY(_flush_instruction_cache)
  18. [--SP] = ( R7:6, P5:4 );
  19. LINK 12;
  20. SP += -12;
  21. P5.H = (ICPLB_ADDR0 >> 16);
  22. P5.L = (ICPLB_ADDR0 & 0xFFFF);
  23. P4.H = (ICPLB_DATA0 >> 16);
  24. P4.L = (ICPLB_DATA0 & 0xFFFF);
  25. R7 = CPLB_VALID | CPLB_L1_CHBL;
  26. R6 = 16;
  27. inext: R0 = [P5++];
  28. R1 = [P4++];
  29. [--SP] = RETS;
  30. CALL _icplb_flush; /* R0 = page, R1 = data*/
  31. RETS = [SP++];
  32. iskip: R6 += -1;
  33. CC = R6;
  34. IF CC JUMP inext;
  35. SSYNC;
  36. SP += 12;
  37. UNLINK;
  38. ( R7:6, P5:4 ) = [SP++];
  39. RTS;
  40. /* This is an internal function to flush all pending
  41. * writes in the cache associated with a particular ICPLB.
  42. *
  43. * R0 - page's start address
  44. * R1 - CPLB's data field.
  45. */
  46. .align 2
  47. ENTRY(_icplb_flush)
  48. [--SP] = ( R7:0, P5:0 );
  49. [--SP] = LC0;
  50. [--SP] = LT0;
  51. [--SP] = LB0;
  52. [--SP] = LC1;
  53. [--SP] = LT1;
  54. [--SP] = LB1;
  55. /* If it's a 1K or 4K page, then it's quickest to
  56. * just systematically flush all the addresses in
  57. * the page, regardless of whether they're in the
  58. * cache, or dirty. If it's a 1M or 4M page, there
  59. * are too many addresses, and we have to search the
  60. * cache for lines corresponding to the page.
  61. */
  62. CC = BITTST(R1, 17); /* 1MB or 4MB */
  63. IF !CC JUMP iflush_whole_page;
  64. /* We're only interested in the page's size, so extract
  65. * this from the CPLB (bits 17:16), and scale to give an
  66. * offset into the page_size and page_prefix tables.
  67. */
  68. R1 <<= 14;
  69. R1 >>= 30;
  70. R1 <<= 2;
  71. /* We can also determine the sub-bank used, because this is
  72. * taken from bits 13:12 of the address.
  73. */
  74. R3 = ((12<<8)|2); /* Extraction pattern */
  75. nop; /*Anamoly 05000209*/
  76. R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits*/
  77. R3.H = R4.L << 0 ; /* Save in extraction pattern for later deposit.*/
  78. /* So:
  79. * R0 = Page start
  80. * R1 = Page length (actually, offset into size/prefix tables)
  81. * R3 = sub-bank deposit values
  82. *
  83. * The cache has 2 Ways, and 64 sets, so we iterate through
  84. * the sets, accessing the tag for each Way, for our Bank and
  85. * sub-bank, looking for dirty, valid tags that match our
  86. * address prefix.
  87. */
  88. P5.L = (ITEST_COMMAND & 0xFFFF);
  89. P5.H = (ITEST_COMMAND >> 16);
  90. P4.L = (ITEST_DATA0 & 0xFFFF);
  91. P4.H = (ITEST_DATA0 >> 16);
  92. P0.L = page_prefix_table;
  93. P0.H = page_prefix_table;
  94. P1 = R1;
  95. R5 = 0; /* Set counter*/
  96. P0 = P1 + P0;
  97. R4 = [P0]; /* This is the address prefix*/
  98. /* We're reading (bit 1==0) the tag (bit 2==0), and we
  99. * don't care about which double-word, since we're only
  100. * fetching tags, so we only have to set Set, Bank,
  101. * Sub-bank and Way.
  102. */
  103. P2 = 4;
  104. LSETUP (ifs1, ife1) LC1 = P2;
  105. ifs1: P0 = 32; /* iterate over all sets*/
  106. LSETUP (ifs0, ife0) LC0 = P0;
  107. ifs0: R6 = R5 << 5; /* Combine set*/
  108. R6.H = R3.H << 0 ; /* and sub-bank*/
  109. [P5] = R6; /* Issue Command*/
  110. SSYNC; /* CSYNC will not work here :(*/
  111. R7 = [P4]; /* and read Tag.*/
  112. CC = BITTST(R7, 0); /* Check if valid*/
  113. IF !CC JUMP ifskip; /* and skip if not.*/
  114. /* Compare against the page address. First, plant bits 13:12
  115. * into the tag, since those aren't part of the returned data.
  116. */
  117. R7 = DEPOSIT(R7, R3); /* set 13:12*/
  118. R1 = R7 & R4; /* Mask off lower bits*/
  119. CC = R1 == R0; /* Compare against page start.*/
  120. IF !CC JUMP ifskip; /* Skip it if it doesn't match.*/
  121. /* Tag address matches against page, so this is an entry
  122. * we must flush.
  123. */
  124. R7 >>= 10; /* Mask off the non-address bits*/
  125. R7 <<= 10;
  126. P3 = R7;
  127. IFLUSH [P3]; /* And flush the entry*/
  128. ifskip:
  129. ife0: R5 += 1; /* Advance to next Set*/
  130. ife1: NOP;
  131. ifinished:
  132. SSYNC; /* Ensure the data gets out to mem.*/
  133. /*Finished. Restore context.*/
  134. LB1 = [SP++];
  135. LT1 = [SP++];
  136. LC1 = [SP++];
  137. LB0 = [SP++];
  138. LT0 = [SP++];
  139. LC0 = [SP++];
  140. ( R7:0, P5:0 ) = [SP++];
  141. RTS;
  142. iflush_whole_page:
  143. /* It's a 1K or 4K page, so quicker to just flush the
  144. * entire page.
  145. */
  146. P1 = 32; /* For 1K pages*/
  147. P2 = P1 << 2; /* For 4K pages*/
  148. P0 = R0; /* Start of page*/
  149. CC = BITTST(R1, 16); /* Whether 1K or 4K*/
  150. IF CC P1 = P2;
  151. P1 += -1; /* Unroll one iteration*/
  152. SSYNC;
  153. IFLUSH [P0++]; /* because CSYNC can't end loops.*/
  154. LSETUP (isall, ieall) LC0 = P1;
  155. isall:IFLUSH [P0++];
  156. ieall: NOP;
  157. SSYNC;
  158. JUMP ifinished;
  159. /* This is an external function being called by the user
  160. * application through __flush_cache_all. Currently this function
  161. * serves the purpose of flushing all the pending writes in
  162. * in the data cache.
  163. */
  164. ENTRY(_flush_data_cache)
  165. [--SP] = ( R7:6, P5:4 );
  166. LINK 12;
  167. SP += -12;
  168. P5.H = (DCPLB_ADDR0 >> 16);
  169. P5.L = (DCPLB_ADDR0 & 0xFFFF);
  170. P4.H = (DCPLB_DATA0 >> 16);
  171. P4.L = (DCPLB_DATA0 & 0xFFFF);
  172. R7 = CPLB_VALID | CPLB_L1_CHBL | CPLB_DIRTY (Z);
  173. R6 = 16;
  174. next: R0 = [P5++];
  175. R1 = [P4++];
  176. CC = BITTST(R1, 14); /* Is it write-through?*/
  177. IF CC JUMP skip; /* If so, ignore it.*/
  178. R2 = R1 & R7; /* Is it a dirty, cached page?*/
  179. CC = R2;
  180. IF !CC JUMP skip; /* If not, ignore it.*/
  181. [--SP] = RETS;
  182. CALL _dcplb_flush; /* R0 = page, R1 = data*/
  183. RETS = [SP++];
  184. skip: R6 += -1;
  185. CC = R6;
  186. IF CC JUMP next;
  187. SSYNC;
  188. SP += 12;
  189. UNLINK;
  190. ( R7:6, P5:4 ) = [SP++];
  191. RTS;
  192. /* This is an internal function to flush all pending
  193. * writes in the cache associated with a particular DCPLB.
  194. *
  195. * R0 - page's start address
  196. * R1 - CPLB's data field.
  197. */
  198. .align 2
  199. ENTRY(_dcplb_flush)
  200. [--SP] = ( R7:0, P5:0 );
  201. [--SP] = LC0;
  202. [--SP] = LT0;
  203. [--SP] = LB0;
  204. [--SP] = LC1;
  205. [--SP] = LT1;
  206. [--SP] = LB1;
  207. /* If it's a 1K or 4K page, then it's quickest to
  208. * just systematically flush all the addresses in
  209. * the page, regardless of whether they're in the
  210. * cache, or dirty. If it's a 1M or 4M page, there
  211. * are too many addresses, and we have to search the
  212. * cache for lines corresponding to the page.
  213. */
  214. CC = BITTST(R1, 17); /* 1MB or 4MB */
  215. IF !CC JUMP dflush_whole_page;
  216. /* We're only interested in the page's size, so extract
  217. * this from the CPLB (bits 17:16), and scale to give an
  218. * offset into the page_size and page_prefix tables.
  219. */
  220. R1 <<= 14;
  221. R1 >>= 30;
  222. R1 <<= 2;
  223. /* The page could be mapped into Bank A or Bank B, depending
  224. * on (a) whether both banks are configured as cache, and
  225. * (b) on whether address bit A[x] is set. x is determined
  226. * by DCBS in DMEM_CONTROL
  227. */
  228. R2 = 0; /* Default to Bank A (Bank B would be 1)*/
  229. P0.L = (DMEM_CONTROL & 0xFFFF);
  230. P0.H = (DMEM_CONTROL >> 16);
  231. R3 = [P0]; /* If Bank B is not enabled as cache*/
  232. CC = BITTST(R3, 2); /* then Bank A is our only option.*/
  233. IF CC JUMP bank_chosen;
  234. R4 = 1<<14; /* If DCBS==0, use A[14].*/
  235. R5 = R4 << 7; /* If DCBS==1, use A[23];*/
  236. CC = BITTST(R3, 4);
  237. IF CC R4 = R5; /* R4 now has either bit 14 or bit 23 set.*/
  238. R5 = R0 & R4; /* Use it to test the Page address*/
  239. CC = R5; /* and if that bit is set, we use Bank B,*/
  240. R2 = CC; /* else we use Bank A.*/
  241. R2 <<= 23; /* The Bank selection's at posn 23.*/
  242. bank_chosen:
  243. /* We can also determine the sub-bank used, because this is
  244. * taken from bits 13:12 of the address.
  245. */
  246. R3 = ((12<<8)|2); /* Extraction pattern */
  247. nop; /*Anamoly 05000209*/
  248. R4 = EXTRACT(R0, R3.L) (Z); /* Extract bits*/
  249. /* Save in extraction pattern for later deposit.*/
  250. R3.H = R4.L << 0;
  251. /* So:
  252. * R0 = Page start
  253. * R1 = Page length (actually, offset into size/prefix tables)
  254. * R2 = Bank select mask
  255. * R3 = sub-bank deposit values
  256. *
  257. * The cache has 2 Ways, and 64 sets, so we iterate through
  258. * the sets, accessing the tag for each Way, for our Bank and
  259. * sub-bank, looking for dirty, valid tags that match our
  260. * address prefix.
  261. */
  262. P5.L = (DTEST_COMMAND & 0xFFFF);
  263. P5.H = (DTEST_COMMAND >> 16);
  264. P4.L = (DTEST_DATA0 & 0xFFFF);
  265. P4.H = (DTEST_DATA0 >> 16);
  266. P0.L = page_prefix_table;
  267. P0.H = page_prefix_table;
  268. P1 = R1;
  269. R5 = 0; /* Set counter*/
  270. P0 = P1 + P0;
  271. R4 = [P0]; /* This is the address prefix*/
  272. /* We're reading (bit 1==0) the tag (bit 2==0), and we
  273. * don't care about which double-word, since we're only
  274. * fetching tags, so we only have to set Set, Bank,
  275. * Sub-bank and Way.
  276. */
  277. P2 = 2;
  278. LSETUP (fs1, fe1) LC1 = P2;
  279. fs1: P0 = 64; /* iterate over all sets*/
  280. LSETUP (fs0, fe0) LC0 = P0;
  281. fs0: R6 = R5 << 5; /* Combine set*/
  282. R6.H = R3.H << 0 ; /* and sub-bank*/
  283. R6 = R6 | R2; /* and Bank. Leave Way==0 at first.*/
  284. BITSET(R6,14);
  285. [P5] = R6; /* Issue Command*/
  286. SSYNC;
  287. R7 = [P4]; /* and read Tag.*/
  288. CC = BITTST(R7, 0); /* Check if valid*/
  289. IF !CC JUMP fskip; /* and skip if not.*/
  290. CC = BITTST(R7, 1); /* Check if dirty*/
  291. IF !CC JUMP fskip; /* and skip if not.*/
  292. /* Compare against the page address. First, plant bits 13:12
  293. * into the tag, since those aren't part of the returned data.
  294. */
  295. R7 = DEPOSIT(R7, R3); /* set 13:12*/
  296. R1 = R7 & R4; /* Mask off lower bits*/
  297. CC = R1 == R0; /* Compare against page start.*/
  298. IF !CC JUMP fskip; /* Skip it if it doesn't match.*/
  299. /* Tag address matches against page, so this is an entry
  300. * we must flush.
  301. */
  302. R7 >>= 10; /* Mask off the non-address bits*/
  303. R7 <<= 10;
  304. P3 = R7;
  305. SSYNC;
  306. FLUSHINV [P3]; /* And flush the entry*/
  307. fskip:
  308. fe0: R5 += 1; /* Advance to next Set*/
  309. fe1: BITSET(R2, 26); /* Go to next Way.*/
  310. dfinished:
  311. SSYNC; /* Ensure the data gets out to mem.*/
  312. /*Finished. Restore context.*/
  313. LB1 = [SP++];
  314. LT1 = [SP++];
  315. LC1 = [SP++];
  316. LB0 = [SP++];
  317. LT0 = [SP++];
  318. LC0 = [SP++];
  319. ( R7:0, P5:0 ) = [SP++];
  320. RTS;
  321. dflush_whole_page:
  322. /* It's a 1K or 4K page, so quicker to just flush the
  323. * entire page.
  324. */
  325. P1 = 32; /* For 1K pages*/
  326. P2 = P1 << 2; /* For 4K pages*/
  327. P0 = R0; /* Start of page*/
  328. CC = BITTST(R1, 16); /* Whether 1K or 4K*/
  329. IF CC P1 = P2;
  330. P1 += -1; /* Unroll one iteration*/
  331. SSYNC;
  332. FLUSHINV [P0++]; /* because CSYNC can't end loops.*/
  333. LSETUP (eall, eall) LC0 = P1;
  334. eall: FLUSHINV [P0++];
  335. SSYNC;
  336. JUMP dfinished;
  337. .align 4;
  338. page_prefix_table:
  339. .byte4 0xFFFFFC00; /* 1K */
  340. .byte4 0xFFFFF000; /* 4K */
  341. .byte4 0xFFF00000; /* 1M */
  342. .byte4 0xFFC00000; /* 4M */
  343. .page_prefix_table.end: