cache-xsc3l2.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * arch/arm/mm/cache-xsc3l2.c - XScale3 L2 cache controller support
  3. *
  4. * Copyright (C) 2007 ARM Limited
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. #include <linux/init.h>
  20. #include <asm/system.h>
  21. #include <asm/cputype.h>
  22. #include <asm/cacheflush.h>
  23. #include <asm/kmap_types.h>
  24. #include <asm/fixmap.h>
  25. #include <asm/pgtable.h>
  26. #include <asm/tlbflush.h>
  27. #include "mm.h"
  28. #define CR_L2 (1 << 26)
  29. #define CACHE_LINE_SIZE 32
  30. #define CACHE_LINE_SHIFT 5
  31. #define CACHE_WAY_PER_SET 8
  32. #define CACHE_WAY_SIZE(l2ctype) (8192 << (((l2ctype) >> 8) & 0xf))
  33. #define CACHE_SET_SIZE(l2ctype) (CACHE_WAY_SIZE(l2ctype) >> CACHE_LINE_SHIFT)
  34. static inline int xsc3_l2_present(void)
  35. {
  36. unsigned long l2ctype;
  37. __asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2ctype));
  38. return !!(l2ctype & 0xf8);
  39. }
  40. static inline void xsc3_l2_clean_mva(unsigned long addr)
  41. {
  42. __asm__("mcr p15, 1, %0, c7, c11, 1" : : "r" (addr));
  43. }
  44. static inline void xsc3_l2_inv_mva(unsigned long addr)
  45. {
  46. __asm__("mcr p15, 1, %0, c7, c7, 1" : : "r" (addr));
  47. }
  48. static inline void xsc3_l2_inv_all(void)
  49. {
  50. unsigned long l2ctype, set_way;
  51. int set, way;
  52. __asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2ctype));
  53. for (set = 0; set < CACHE_SET_SIZE(l2ctype); set++) {
  54. for (way = 0; way < CACHE_WAY_PER_SET; way++) {
  55. set_way = (way << 29) | (set << 5);
  56. __asm__("mcr p15, 1, %0, c7, c11, 2" : : "r"(set_way));
  57. }
  58. }
  59. dsb();
  60. }
  61. #ifdef CONFIG_HIGHMEM
  62. #define l2_map_save_flags(x) raw_local_save_flags(x)
  63. #define l2_map_restore_flags(x) raw_local_irq_restore(x)
  64. #else
  65. #define l2_map_save_flags(x) ((x) = 0)
  66. #define l2_map_restore_flags(x) ((void)(x))
  67. #endif
  68. static inline unsigned long l2_map_va(unsigned long pa, unsigned long prev_va,
  69. unsigned long flags)
  70. {
  71. #ifdef CONFIG_HIGHMEM
  72. unsigned long va = prev_va & PAGE_MASK;
  73. unsigned long pa_offset = pa << (32 - PAGE_SHIFT);
  74. if (unlikely(pa_offset < (prev_va << (32 - PAGE_SHIFT)))) {
  75. /*
  76. * Switching to a new page. Because cache ops are
  77. * using virtual addresses only, we must put a mapping
  78. * in place for it. We also enable interrupts for a
  79. * short while and disable them again to protect this
  80. * mapping.
  81. */
  82. unsigned long idx;
  83. raw_local_irq_restore(flags);
  84. idx = KM_L2_CACHE + KM_TYPE_NR * smp_processor_id();
  85. va = __fix_to_virt(FIX_KMAP_BEGIN + idx);
  86. raw_local_irq_restore(flags | PSR_I_BIT);
  87. set_pte_ext(TOP_PTE(va), pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL), 0);
  88. local_flush_tlb_kernel_page(va);
  89. }
  90. return va + (pa_offset >> (32 - PAGE_SHIFT));
  91. #else
  92. return __phys_to_virt(pa);
  93. #endif
  94. }
  95. static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
  96. {
  97. unsigned long vaddr, flags;
  98. if (start == 0 && end == -1ul) {
  99. xsc3_l2_inv_all();
  100. return;
  101. }
  102. vaddr = -1; /* to force the first mapping */
  103. l2_map_save_flags(flags);
  104. /*
  105. * Clean and invalidate partial first cache line.
  106. */
  107. if (start & (CACHE_LINE_SIZE - 1)) {
  108. vaddr = l2_map_va(start & ~(CACHE_LINE_SIZE - 1), vaddr, flags);
  109. xsc3_l2_clean_mva(vaddr);
  110. xsc3_l2_inv_mva(vaddr);
  111. start = (start | (CACHE_LINE_SIZE - 1)) + 1;
  112. }
  113. /*
  114. * Invalidate all full cache lines between 'start' and 'end'.
  115. */
  116. while (start < (end & ~(CACHE_LINE_SIZE - 1))) {
  117. vaddr = l2_map_va(start, vaddr, flags);
  118. xsc3_l2_inv_mva(vaddr);
  119. start += CACHE_LINE_SIZE;
  120. }
  121. /*
  122. * Clean and invalidate partial last cache line.
  123. */
  124. if (start < end) {
  125. vaddr = l2_map_va(start, vaddr, flags);
  126. xsc3_l2_clean_mva(vaddr);
  127. xsc3_l2_inv_mva(vaddr);
  128. }
  129. l2_map_restore_flags(flags);
  130. dsb();
  131. }
  132. static void xsc3_l2_clean_range(unsigned long start, unsigned long end)
  133. {
  134. unsigned long vaddr, flags;
  135. vaddr = -1; /* to force the first mapping */
  136. l2_map_save_flags(flags);
  137. start &= ~(CACHE_LINE_SIZE - 1);
  138. while (start < end) {
  139. vaddr = l2_map_va(start, vaddr, flags);
  140. xsc3_l2_clean_mva(vaddr);
  141. start += CACHE_LINE_SIZE;
  142. }
  143. l2_map_restore_flags(flags);
  144. dsb();
  145. }
  146. /*
  147. * optimize L2 flush all operation by set/way format
  148. */
  149. static inline void xsc3_l2_flush_all(void)
  150. {
  151. unsigned long l2ctype, set_way;
  152. int set, way;
  153. __asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2ctype));
  154. for (set = 0; set < CACHE_SET_SIZE(l2ctype); set++) {
  155. for (way = 0; way < CACHE_WAY_PER_SET; way++) {
  156. set_way = (way << 29) | (set << 5);
  157. __asm__("mcr p15, 1, %0, c7, c15, 2" : : "r"(set_way));
  158. }
  159. }
  160. dsb();
  161. }
  162. static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
  163. {
  164. unsigned long vaddr, flags;
  165. if (start == 0 && end == -1ul) {
  166. xsc3_l2_flush_all();
  167. return;
  168. }
  169. vaddr = -1; /* to force the first mapping */
  170. l2_map_save_flags(flags);
  171. start &= ~(CACHE_LINE_SIZE - 1);
  172. while (start < end) {
  173. vaddr = l2_map_va(start, vaddr, flags);
  174. xsc3_l2_clean_mva(vaddr);
  175. xsc3_l2_inv_mva(vaddr);
  176. start += CACHE_LINE_SIZE;
  177. }
  178. l2_map_restore_flags(flags);
  179. dsb();
  180. }
  181. static int __init xsc3_l2_init(void)
  182. {
  183. if (!cpu_is_xsc3() || !xsc3_l2_present())
  184. return 0;
  185. if (!(get_cr() & CR_L2)) {
  186. pr_info("XScale3 L2 cache enabled.\n");
  187. adjust_cr(CR_L2, CR_L2);
  188. xsc3_l2_inv_all();
  189. }
  190. outer_cache.inv_range = xsc3_l2_inv_range;
  191. outer_cache.clean_range = xsc3_l2_clean_range;
  192. outer_cache.flush_range = xsc3_l2_flush_range;
  193. return 0;
  194. }
  195. core_initcall(xsc3_l2_init);