cache_uniphier.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * Copyright (C) 2012-2015 Masahiro Yamada <yamada.masahiro@socionext.com>
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. #include <common.h>
  7. #include <linux/io.h>
  8. #include <asm/armv7.h>
  9. #include <mach/ssc-regs.h>
  10. #ifdef CONFIG_UNIPHIER_L2CACHE_ON
  11. static void uniphier_cache_maint_all(u32 operation)
  12. {
  13. /* try until the command is successfully set */
  14. do {
  15. writel(SSCOQM_S_ALL | SSCOQM_CE | operation, SSCOQM);
  16. } while (readl(SSCOPPQSEF) & (SSCOPPQSEF_FE | SSCOPPQSEF_OE));
  17. /* wait until the operation is completed */
  18. while (readl(SSCOLPQS) != SSCOLPQS_EF)
  19. ;
  20. /* clear the complete notification flag */
  21. writel(SSCOLPQS_EF, SSCOLPQS);
  22. writel(SSCOPE_CM_SYNC, SSCOPE); /* drain internal buffers */
  23. readl(SSCOPE); /* need a read back to confirm */
  24. }
  25. void v7_outer_cache_flush_all(void)
  26. {
  27. uniphier_cache_maint_all(SSCOQM_CM_WB_INV);
  28. }
  29. void v7_outer_cache_inval_all(void)
  30. {
  31. uniphier_cache_maint_all(SSCOQM_CM_INV);
  32. }
  33. static void __uniphier_cache_maint_range(u32 start, u32 size, u32 operation)
  34. {
  35. /* try until the command is successfully set */
  36. do {
  37. writel(SSCOQM_S_ADDRESS | SSCOQM_CE | operation, SSCOQM);
  38. writel(start, SSCOQAD);
  39. writel(size, SSCOQSZ);
  40. } while (readl(SSCOPPQSEF) & (SSCOPPQSEF_FE | SSCOPPQSEF_OE));
  41. /* wait until the operation is completed */
  42. while (readl(SSCOLPQS) != SSCOLPQS_EF)
  43. ;
  44. /* clear the complete notification flag */
  45. writel(SSCOLPQS_EF, SSCOLPQS);
  46. }
  47. static void uniphier_cache_maint_range(u32 start, u32 end, u32 operation)
  48. {
  49. u32 size;
  50. /*
  51. * If start address is not aligned to cache-line,
  52. * do cache operation for the first cache-line
  53. */
  54. start = start & ~(SSC_LINE_SIZE - 1);
  55. if (start == 0 && end >= (u32)(-SSC_LINE_SIZE)) {
  56. /* this means cache operation for all range */
  57. uniphier_cache_maint_all(operation);
  58. return;
  59. }
  60. /*
  61. * If end address is not aligned to cache-line,
  62. * do cache operation for the last cache-line
  63. */
  64. size = (end - start + SSC_LINE_SIZE - 1) & ~(SSC_LINE_SIZE - 1);
  65. while (size) {
  66. u32 chunk_size = size > SSC_RANGE_OP_MAX_SIZE ?
  67. SSC_RANGE_OP_MAX_SIZE : size;
  68. __uniphier_cache_maint_range(start, chunk_size, operation);
  69. start += chunk_size;
  70. size -= chunk_size;
  71. }
  72. writel(SSCOPE_CM_SYNC, SSCOPE); /* drain internal buffers */
  73. readl(SSCOPE); /* need a read back to confirm */
  74. }
  75. void v7_outer_cache_flush_range(u32 start, u32 end)
  76. {
  77. uniphier_cache_maint_range(start, end, SSCOQM_CM_WB_INV);
  78. }
  79. void v7_outer_cache_inval_range(u32 start, u32 end)
  80. {
  81. uniphier_cache_maint_range(start, end, SSCOQM_CM_INV);
  82. }
  83. void v7_outer_cache_enable(void)
  84. {
  85. u32 tmp;
  86. tmp = readl(SSCC);
  87. tmp |= SSCC_ON;
  88. writel(tmp, SSCC);
  89. }
  90. #endif
  91. void v7_outer_cache_disable(void)
  92. {
  93. u32 tmp;
  94. tmp = readl(SSCC);
  95. tmp &= ~SSCC_ON;
  96. writel(tmp, SSCC);
  97. }
  98. void enable_caches(void)
  99. {
  100. dcache_enable();
  101. }