cache-uniphier.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Copyright (C) 2012-2014 Panasonic Corporation
  3. * Copyright (C) 2015-2016 Socionext Inc.
  4. * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. */
  8. #include <common.h>
  9. #include <linux/io.h>
  10. #include <linux/kernel.h>
  11. #include <asm/armv7.h>
  12. #include <asm/processor.h>
  13. #include "ssc-regs.h"
  14. #define UNIPHIER_SSCOQAD_IS_NEEDED(op) \
  15. ((op & UNIPHIER_SSCOQM_S_MASK) == UNIPHIER_SSCOQM_S_RANGE)
  16. #ifdef CONFIG_UNIPHIER_L2CACHE_ON
  17. /* uniphier_cache_sync - perform a sync point for a particular cache level */
  18. static void uniphier_cache_sync(void)
  19. {
  20. /* drain internal buffers */
  21. writel(UNIPHIER_SSCOPE_CM_SYNC, UNIPHIER_SSCOPE);
  22. /* need a read back to confirm */
  23. readl(UNIPHIER_SSCOPE);
  24. }
  25. /**
  26. * uniphier_cache_maint_common - run a queue operation
  27. *
  28. * @start: start address of range operation (don't care for "all" operation)
  29. * @size: data size of range operation (don't care for "all" operation)
  30. * @operation: flags to specify the desired cache operation
  31. */
  32. static void uniphier_cache_maint_common(u32 start, u32 size, u32 operation)
  33. {
  34. /* clear the complete notification flag */
  35. writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS);
  36. do {
  37. /* set cache operation */
  38. writel(UNIPHIER_SSCOQM_CE | operation, UNIPHIER_SSCOQM);
  39. /* set address range if needed */
  40. if (likely(UNIPHIER_SSCOQAD_IS_NEEDED(operation))) {
  41. writel(start, UNIPHIER_SSCOQAD);
  42. writel(size, UNIPHIER_SSCOQSZ);
  43. }
  44. } while (unlikely(readl(UNIPHIER_SSCOPPQSEF) &
  45. (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE)));
  46. /* wait until the operation is completed */
  47. while (likely(readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF))
  48. cpu_relax();
  49. }
  50. static void uniphier_cache_maint_all(u32 operation)
  51. {
  52. uniphier_cache_maint_common(0, 0, UNIPHIER_SSCOQM_S_ALL | operation);
  53. uniphier_cache_sync();
  54. }
  55. static void uniphier_cache_maint_range(u32 start, u32 end, u32 operation)
  56. {
  57. u32 size;
  58. /*
  59. * If the start address is not aligned,
  60. * perform a cache operation for the first cache-line
  61. */
  62. start = start & ~(UNIPHIER_SSC_LINE_SIZE - 1);
  63. size = end - start;
  64. if (unlikely(size >= (u32)(-UNIPHIER_SSC_LINE_SIZE))) {
  65. /* this means cache operation for all range */
  66. uniphier_cache_maint_all(operation);
  67. return;
  68. }
  69. /*
  70. * If the end address is not aligned,
  71. * perform a cache operation for the last cache-line
  72. */
  73. size = ALIGN(size, UNIPHIER_SSC_LINE_SIZE);
  74. while (size) {
  75. u32 chunk_size = min_t(u32, size, UNIPHIER_SSC_RANGE_OP_MAX_SIZE);
  76. uniphier_cache_maint_common(start, chunk_size,
  77. UNIPHIER_SSCOQM_S_RANGE | operation);
  78. start += chunk_size;
  79. size -= chunk_size;
  80. }
  81. uniphier_cache_sync();
  82. }
  83. void v7_outer_cache_flush_all(void)
  84. {
  85. uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_FLUSH);
  86. }
  87. void v7_outer_cache_inval_all(void)
  88. {
  89. uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_INV);
  90. }
  91. void v7_outer_cache_flush_range(u32 start, u32 end)
  92. {
  93. uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_FLUSH);
  94. }
  95. void v7_outer_cache_inval_range(u32 start, u32 end)
  96. {
  97. if (start & (UNIPHIER_SSC_LINE_SIZE - 1)) {
  98. start &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
  99. uniphier_cache_maint_range(start, UNIPHIER_SSC_LINE_SIZE,
  100. UNIPHIER_SSCOQM_CM_FLUSH);
  101. start += UNIPHIER_SSC_LINE_SIZE;
  102. }
  103. if (start >= end) {
  104. uniphier_cache_sync();
  105. return;
  106. }
  107. if (end & (UNIPHIER_SSC_LINE_SIZE - 1)) {
  108. end &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
  109. uniphier_cache_maint_range(end, UNIPHIER_SSC_LINE_SIZE,
  110. UNIPHIER_SSCOQM_CM_FLUSH);
  111. }
  112. if (start >= end) {
  113. uniphier_cache_sync();
  114. return;
  115. }
  116. uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_INV);
  117. }
  118. void v7_outer_cache_enable(void)
  119. {
  120. u32 tmp;
  121. writel(U32_MAX, UNIPHIER_SSCLPDAWCR); /* activate all ways */
  122. tmp = readl(UNIPHIER_SSCC);
  123. tmp |= UNIPHIER_SSCC_ON;
  124. writel(tmp, UNIPHIER_SSCC);
  125. }
  126. #endif
  127. void v7_outer_cache_disable(void)
  128. {
  129. u32 tmp;
  130. tmp = readl(UNIPHIER_SSCC);
  131. tmp &= ~UNIPHIER_SSCC_ON;
  132. writel(tmp, UNIPHIER_SSCC);
  133. }
  134. void enable_caches(void)
  135. {
  136. dcache_enable();
  137. }