cache.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /*
  2. * (C) Copyright 2003
  3. * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. */
  7. #include <common.h>
  8. #include <asm/cacheops.h>
  9. #include <asm/mipsregs.h>
  10. static inline unsigned long icache_line_size(void)
  11. {
  12. unsigned long conf1, il;
  13. if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO))
  14. return CONFIG_SYS_ICACHE_LINE_SIZE;
  15. conf1 = read_c0_config1();
  16. il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHF;
  17. if (!il)
  18. return 0;
  19. return 2 << il;
  20. }
  21. static inline unsigned long dcache_line_size(void)
  22. {
  23. unsigned long conf1, dl;
  24. if (!config_enabled(CONFIG_SYS_CACHE_SIZE_AUTO))
  25. return CONFIG_SYS_DCACHE_LINE_SIZE;
  26. conf1 = read_c0_config1();
  27. dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHF;
  28. if (!dl)
  29. return 0;
  30. return 2 << dl;
  31. }
  32. #define cache_loop(start, end, lsize, ops...) do { \
  33. const void *addr = (const void *)(start & ~(lsize - 1)); \
  34. const void *aend = (const void *)((end - 1) & ~(lsize - 1)); \
  35. const unsigned int cache_ops[] = { ops }; \
  36. unsigned int i; \
  37. \
  38. for (; addr <= aend; addr += lsize) { \
  39. for (i = 0; i < ARRAY_SIZE(cache_ops); i++) \
  40. mips_cache(cache_ops[i], addr); \
  41. } \
  42. } while (0)
  43. void flush_cache(ulong start_addr, ulong size)
  44. {
  45. unsigned long ilsize = icache_line_size();
  46. unsigned long dlsize = dcache_line_size();
  47. /* aend will be miscalculated when size is zero, so we return here */
  48. if (size == 0)
  49. return;
  50. if (ilsize == dlsize) {
  51. /* flush I-cache & D-cache simultaneously */
  52. cache_loop(start_addr, start_addr + size, ilsize,
  53. HIT_WRITEBACK_INV_D, HIT_INVALIDATE_I);
  54. return;
  55. }
  56. /* flush D-cache */
  57. cache_loop(start_addr, start_addr + size, dlsize, HIT_WRITEBACK_INV_D);
  58. /* flush I-cache */
  59. cache_loop(start_addr, start_addr + size, ilsize, HIT_INVALIDATE_I);
  60. }
  61. void flush_dcache_range(ulong start_addr, ulong stop)
  62. {
  63. unsigned long lsize = dcache_line_size();
  64. /* aend will be miscalculated when size is zero, so we return here */
  65. if (start_addr == stop)
  66. return;
  67. cache_loop(start_addr, stop, lsize, HIT_WRITEBACK_INV_D);
  68. }
  69. void invalidate_dcache_range(ulong start_addr, ulong stop)
  70. {
  71. unsigned long lsize = dcache_line_size();
  72. /* aend will be miscalculated when size is zero, so we return here */
  73. if (start_addr == stop)
  74. return;
  75. cache_loop(start_addr, stop, lsize, HIT_INVALIDATE_I);
  76. }