flush.S 10 KB

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