cache.S 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. * Blackfin cache control code
  3. *
  4. * Copyright 2004-2008 Analog Devices Inc.
  5. *
  6. * Enter bugs at http://blackfin.uclinux.org/
  7. *
  8. * Licensed under the GPL-2 or later.
  9. */
  10. #include <linux/linkage.h>
  11. #include <asm/blackfin.h>
  12. #include <asm/cache.h>
  13. #include <asm/page.h>
  14. .text
  15. /* Since all L1 caches work the same way, we use the same method for flushing
  16. * them. Only the actual flush instruction differs. We write this in asm as
  17. * GCC can be hard to coax into writing nice hardware loops.
  18. *
  19. * Also, we assume the following register setup:
  20. * R0 = start address
  21. * R1 = end address
  22. */
  23. .macro do_flush flushins:req optflushins optnopins label
  24. R2 = -L1_CACHE_BYTES;
  25. /* start = (start & -L1_CACHE_BYTES) */
  26. R0 = R0 & R2;
  27. /* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */
  28. R1 += -1;
  29. R1 = R1 & R2;
  30. R1 += L1_CACHE_BYTES;
  31. /* count = (end - start) >> L1_CACHE_SHIFT */
  32. R2 = R1 - R0;
  33. R2 >>= L1_CACHE_SHIFT;
  34. P1 = R2;
  35. .ifnb \label
  36. \label :
  37. .endif
  38. P0 = R0;
  39. LSETUP (1f, 2f) LC1 = P1;
  40. 1:
  41. .ifnb \optflushins
  42. \optflushins [P0];
  43. .endif
  44. #if ANOMALY_05000443
  45. .ifb \optnopins
  46. 2:
  47. .endif
  48. \flushins [P0++];
  49. .ifnb \optnopins
  50. 2: \optnopins;
  51. .endif
  52. #else
  53. 2: \flushins [P0++];
  54. #endif
  55. RTS;
  56. .endm
  57. /* Invalidate all instruction cache lines assocoiated with this memory area */
  58. ENTRY(_blackfin_icache_flush_range)
  59. /*
  60. * Walkaround to avoid loading wrong instruction after invalidating icache
  61. * and following sequence is met.
  62. *
  63. * 1) One instruction address is cached in the instruction cache.
  64. * 2) This instruction in SDRAM is changed.
  65. * 3) IFLASH[P0] is executed only once in blackfin_icache_flush_range().
  66. * 4) This instruction is executed again, but the old one is loaded.
  67. */
  68. P0 = R0;
  69. IFLUSH[P0];
  70. do_flush IFLUSH, , nop
  71. ENDPROC(_blackfin_icache_flush_range)
  72. /* Flush all cache lines assocoiated with this area of memory. */
  73. ENTRY(_blackfin_icache_dcache_flush_range)
  74. /*
  75. * Walkaround to avoid loading wrong instruction after invalidating icache
  76. * and following sequence is met.
  77. *
  78. * 1) One instruction address is cached in the instruction cache.
  79. * 2) This instruction in SDRAM is changed.
  80. * 3) IFLASH[P0] is executed only once in blackfin_icache_flush_range().
  81. * 4) This instruction is executed again, but the old one is loaded.
  82. */
  83. P0 = R0;
  84. IFLUSH[P0];
  85. do_flush FLUSH, IFLUSH
  86. ENDPROC(_blackfin_icache_dcache_flush_range)
  87. /* Throw away all D-cached data in specified region without any obligation to
  88. * write them back. Since the Blackfin ISA does not have an "invalidate"
  89. * instruction, we use flush/invalidate. Perhaps as a speed optimization we
  90. * could bang on the DTEST MMRs ...
  91. */
  92. ENTRY(_blackfin_dcache_invalidate_range)
  93. do_flush FLUSHINV
  94. ENDPROC(_blackfin_dcache_invalidate_range)
  95. /* Flush all data cache lines assocoiated with this memory area */
  96. ENTRY(_blackfin_dcache_flush_range)
  97. do_flush FLUSH, , , .Ldfr
  98. ENDPROC(_blackfin_dcache_flush_range)
  99. /* Our headers convert the page structure to an address, so just need to flush
  100. * its contents like normal. We know the start address is page aligned (which
  101. * greater than our cache alignment), as is the end address. So just jump into
  102. * the middle of the dcache flush function.
  103. */
  104. ENTRY(_blackfin_dflush_page)
  105. P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT);
  106. jump .Ldfr;
  107. ENDPROC(_blackfin_dflush_page)