cache-xsc3l2.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * arch/arm/mm/cache-xsc3l2.c - XScale3 L2 cache controller support
  4. *
  5. * Copyright (C) 2007 ARM Limited
  6. */
  7. #include <linux/init.h>
  8. #include <linux/highmem.h>
  9. #include <asm/cp15.h>
  10. #include <asm/cputype.h>
  11. #include <asm/cacheflush.h>
  12. #define CR_L2 (1 << 26)
  13. #define CACHE_LINE_SIZE 32
  14. #define CACHE_LINE_SHIFT 5
  15. #define CACHE_WAY_PER_SET 8
  16. #define CACHE_WAY_SIZE(l2ctype) (8192 << (((l2ctype) >> 8) & 0xf))
  17. #define CACHE_SET_SIZE(l2ctype) (CACHE_WAY_SIZE(l2ctype) >> CACHE_LINE_SHIFT)
  18. static inline int xsc3_l2_present(void)
  19. {
  20. unsigned long l2ctype;
  21. __asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2ctype));
  22. return !!(l2ctype & 0xf8);
  23. }
  24. static inline void xsc3_l2_clean_mva(unsigned long addr)
  25. {
  26. __asm__("mcr p15, 1, %0, c7, c11, 1" : : "r" (addr));
  27. }
  28. static inline void xsc3_l2_inv_mva(unsigned long addr)
  29. {
  30. __asm__("mcr p15, 1, %0, c7, c7, 1" : : "r" (addr));
  31. }
  32. static inline void xsc3_l2_inv_all(void)
  33. {
  34. unsigned long l2ctype, set_way;
  35. int set, way;
  36. __asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2ctype));
  37. for (set = 0; set < CACHE_SET_SIZE(l2ctype); set++) {
  38. for (way = 0; way < CACHE_WAY_PER_SET; way++) {
  39. set_way = (way << 29) | (set << 5);
  40. __asm__("mcr p15, 1, %0, c7, c11, 2" : : "r"(set_way));
  41. }
  42. }
  43. dsb();
  44. }
  45. static inline void l2_unmap_va(unsigned long va)
  46. {
  47. #ifdef CONFIG_HIGHMEM
  48. if (va != -1)
  49. kunmap_atomic((void *)va);
  50. #endif
  51. }
  52. static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va)
  53. {
  54. #ifdef CONFIG_HIGHMEM
  55. unsigned long va = prev_va & PAGE_MASK;
  56. unsigned long pa_offset = pa << (32 - PAGE_SHIFT);
  57. if (unlikely(pa_offset < (prev_va << (32 - PAGE_SHIFT)))) {
  58. /*
  59. * Switching to a new page. Because cache ops are
  60. * using virtual addresses only, we must put a mapping
  61. * in place for it.
  62. */
  63. l2_unmap_va(prev_va);
  64. va = (unsigned long)kmap_atomic_pfn(pa >> PAGE_SHIFT);
  65. }
  66. return va + (pa_offset >> (32 - PAGE_SHIFT));
  67. #else
  68. return __phys_to_virt(pa);
  69. #endif
  70. }
  71. static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
  72. {
  73. unsigned long vaddr;
  74. if (start == 0 && end == -1ul) {
  75. xsc3_l2_inv_all();
  76. return;
  77. }
  78. vaddr = -1; /* to force the first mapping */
  79. /*
  80. * Clean and invalidate partial first cache line.
  81. */
  82. if (start & (CACHE_LINE_SIZE - 1)) {
  83. vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr);
  84. xsc3_l2_clean_mva(vaddr);
  85. xsc3_l2_inv_mva(vaddr);
  86. start = (start | (CACHE_LINE_SIZE - 1)) + 1;
  87. }
  88. /*
  89. * Invalidate all full cache lines between 'start' and 'end'.
  90. */
  91. while (start < (end & ~(CACHE_LINE_SIZE - 1))) {
  92. vaddr = l2_map_va(start, vaddr);
  93. xsc3_l2_inv_mva(vaddr);
  94. start += CACHE_LINE_SIZE;
  95. }
  96. /*
  97. * Clean and invalidate partial last cache line.
  98. */
  99. if (start < end) {
  100. vaddr = l2_map_va(start, vaddr);
  101. xsc3_l2_clean_mva(vaddr);
  102. xsc3_l2_inv_mva(vaddr);
  103. }
  104. l2_unmap_va(vaddr);
  105. dsb();
  106. }
  107. static void xsc3_l2_clean_range(unsigned long start, unsigned long end)
  108. {
  109. unsigned long vaddr;
  110. vaddr = -1; /* to force the first mapping */
  111. start &= ~(CACHE_LINE_SIZE - 1);
  112. while (start < end) {
  113. vaddr = l2_map_va(start, vaddr);
  114. xsc3_l2_clean_mva(vaddr);
  115. start += CACHE_LINE_SIZE;
  116. }
  117. l2_unmap_va(vaddr);
  118. dsb();
  119. }
  120. /*
  121. * optimize L2 flush all operation by set/way format
  122. */
  123. static inline void xsc3_l2_flush_all(void)
  124. {
  125. unsigned long l2ctype, set_way;
  126. int set, way;
  127. __asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2ctype));
  128. for (set = 0; set < CACHE_SET_SIZE(l2ctype); set++) {
  129. for (way = 0; way < CACHE_WAY_PER_SET; way++) {
  130. set_way = (way << 29) | (set << 5);
  131. __asm__("mcr p15, 1, %0, c7, c15, 2" : : "r"(set_way));
  132. }
  133. }
  134. dsb();
  135. }
  136. static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
  137. {
  138. unsigned long vaddr;
  139. if (start == 0 && end == -1ul) {
  140. xsc3_l2_flush_all();
  141. return;
  142. }
  143. vaddr = -1; /* to force the first mapping */
  144. start &= ~(CACHE_LINE_SIZE - 1);
  145. while (start < end) {
  146. vaddr = l2_map_va(start, vaddr);
  147. xsc3_l2_clean_mva(vaddr);
  148. xsc3_l2_inv_mva(vaddr);
  149. start += CACHE_LINE_SIZE;
  150. }
  151. l2_unmap_va(vaddr);
  152. dsb();
  153. }
  154. static int __init xsc3_l2_init(void)
  155. {
  156. if (!cpu_is_xsc3() || !xsc3_l2_present())
  157. return 0;
  158. if (get_cr() & CR_L2) {
  159. pr_info("XScale3 L2 cache enabled.\n");
  160. xsc3_l2_inv_all();
  161. outer_cache.inv_range = xsc3_l2_inv_range;
  162. outer_cache.clean_range = xsc3_l2_clean_range;
  163. outer_cache.flush_range = xsc3_l2_flush_range;
  164. }
  165. return 0;
  166. }
  167. core_initcall(xsc3_l2_init);