cache-uniphier.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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 <asm/armv7.h>
  11. #include "ssc-regs.h"
  12. #ifdef CONFIG_UNIPHIER_L2CACHE_ON
  13. static void uniphier_cache_sync(void)
  14. {
  15. /* drain internal buffers */
  16. writel(UNIPHIER_SSCOPE_CM_SYNC, UNIPHIER_SSCOPE);
  17. /* need a read back to confirm */
  18. readl(UNIPHIER_SSCOPE);
  19. }
  20. static void uniphier_cache_maint_all(u32 operation)
  21. {
  22. /* clear the complete notification flag */
  23. writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS);
  24. /* try until the command is successfully set */
  25. do {
  26. writel(UNIPHIER_SSCOQM_S_ALL | UNIPHIER_SSCOQM_CE | operation,
  27. UNIPHIER_SSCOQM);
  28. } while (readl(UNIPHIER_SSCOPPQSEF) &
  29. (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE));
  30. /* wait until the operation is completed */
  31. while (readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF)
  32. ;
  33. uniphier_cache_sync();
  34. }
  35. void v7_outer_cache_flush_all(void)
  36. {
  37. uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_FLUSH);
  38. }
  39. void v7_outer_cache_inval_all(void)
  40. {
  41. uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_INV);
  42. }
  43. static void __uniphier_cache_maint_range(u32 start, u32 size, u32 operation)
  44. {
  45. /* clear the complete notification flag */
  46. writel(UNIPHIER_SSCOLPQS_EF, UNIPHIER_SSCOLPQS);
  47. /* try until the command is successfully set */
  48. do {
  49. writel(UNIPHIER_SSCOQM_S_RANGE | UNIPHIER_SSCOQM_CE | operation,
  50. UNIPHIER_SSCOQM);
  51. writel(start, UNIPHIER_SSCOQAD);
  52. writel(size, UNIPHIER_SSCOQSZ);
  53. } while (readl(UNIPHIER_SSCOPPQSEF) &
  54. (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE));
  55. /* wait until the operation is completed */
  56. while (readl(UNIPHIER_SSCOLPQS) != UNIPHIER_SSCOLPQS_EF)
  57. ;
  58. }
  59. static void uniphier_cache_maint_range(u32 start, u32 end, u32 operation)
  60. {
  61. u32 size;
  62. /*
  63. * If start address is not aligned to cache-line,
  64. * do cache operation for the first cache-line
  65. */
  66. start = start & ~(UNIPHIER_SSC_LINE_SIZE - 1);
  67. size = end - start;
  68. if (unlikely(size >= (u32)(-UNIPHIER_SSC_LINE_SIZE))) {
  69. /* this means cache operation for all range */
  70. uniphier_cache_maint_all(operation);
  71. return;
  72. }
  73. /*
  74. * If end address is not aligned to cache-line,
  75. * do cache operation for the last cache-line
  76. */
  77. size = ALIGN(size, UNIPHIER_SSC_LINE_SIZE);
  78. while (size) {
  79. u32 chunk_size = size > UNIPHIER_SSC_RANGE_OP_MAX_SIZE ?
  80. UNIPHIER_SSC_RANGE_OP_MAX_SIZE : size;
  81. __uniphier_cache_maint_range(start, chunk_size, operation);
  82. start += chunk_size;
  83. size -= chunk_size;
  84. }
  85. uniphier_cache_sync();
  86. }
  87. void v7_outer_cache_flush_range(u32 start, u32 end)
  88. {
  89. uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_FLUSH);
  90. }
  91. void v7_outer_cache_inval_range(u32 start, u32 end)
  92. {
  93. if (start & (UNIPHIER_SSC_LINE_SIZE - 1)) {
  94. start &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
  95. __uniphier_cache_maint_range(start, UNIPHIER_SSC_LINE_SIZE,
  96. UNIPHIER_SSCOQM_CM_FLUSH);
  97. start += UNIPHIER_SSC_LINE_SIZE;
  98. }
  99. if (start >= end) {
  100. uniphier_cache_sync();
  101. return;
  102. }
  103. if (end & (UNIPHIER_SSC_LINE_SIZE - 1)) {
  104. end &= ~(UNIPHIER_SSC_LINE_SIZE - 1);
  105. __uniphier_cache_maint_range(end, UNIPHIER_SSC_LINE_SIZE,
  106. UNIPHIER_SSCOQM_CM_FLUSH);
  107. }
  108. if (start >= end) {
  109. uniphier_cache_sync();
  110. return;
  111. }
  112. uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_INV);
  113. }
  114. void v7_outer_cache_enable(void)
  115. {
  116. u32 tmp;
  117. writel(U32_MAX, UNIPHIER_SSCLPDAWCR); /* activate all ways */
  118. tmp = readl(UNIPHIER_SSCC);
  119. tmp |= UNIPHIER_SSCC_ON;
  120. writel(tmp, UNIPHIER_SSCC);
  121. }
  122. #endif
  123. void v7_outer_cache_disable(void)
  124. {
  125. u32 tmp;
  126. tmp = readl(UNIPHIER_SSCC);
  127. tmp &= ~UNIPHIER_SSCC_ON;
  128. writel(tmp, UNIPHIER_SSCC);
  129. }
  130. void enable_caches(void)
  131. {
  132. dcache_enable();
  133. }