flush.S 10 KB

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