blob: e245614d1688e22cf325e2f8eaa4c79ca39a0fa3 [file] [log] [blame]
Paul Burton4ff6b102015-01-29 01:27:57 +00001/*
2 * (C) Copyright 2003
3 * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8#include <common.h>
9#include <asm/cacheops.h>
10#include <asm/mipsregs.h>
11
12#ifdef CONFIG_SYS_CACHELINE_SIZE
13
14static inline unsigned long icache_line_size(void)
15{
16 return CONFIG_SYS_CACHELINE_SIZE;
17}
18
19static inline unsigned long dcache_line_size(void)
20{
21 return CONFIG_SYS_CACHELINE_SIZE;
22}
23
24#else /* !CONFIG_SYS_CACHELINE_SIZE */
25
26static inline unsigned long icache_line_size(void)
27{
28 unsigned long conf1, il;
29 conf1 = read_c0_config1();
30 il = (conf1 & MIPS_CONF1_IL) >> MIPS_CONF1_IL_SHIFT;
31 if (!il)
32 return 0;
33 return 2 << il;
34}
35
36static inline unsigned long dcache_line_size(void)
37{
38 unsigned long conf1, dl;
39 conf1 = read_c0_config1();
40 dl = (conf1 & MIPS_CONF1_DL) >> MIPS_CONF1_DL_SHIFT;
41 if (!dl)
42 return 0;
43 return 2 << dl;
44}
45
46#endif /* !CONFIG_SYS_CACHELINE_SIZE */
47
48void flush_cache(ulong start_addr, ulong size)
49{
50 unsigned long ilsize = icache_line_size();
51 unsigned long dlsize = dcache_line_size();
52 const void *addr, *aend;
53
54 /* aend will be miscalculated when size is zero, so we return here */
55 if (size == 0)
56 return;
57
58 addr = (const void *)(start_addr & ~(dlsize - 1));
59 aend = (const void *)((start_addr + size - 1) & ~(dlsize - 1));
60
61 if (ilsize == dlsize) {
62 /* flush I-cache & D-cache simultaneously */
63 while (1) {
64 mips_cache(HIT_WRITEBACK_INV_D, addr);
65 mips_cache(HIT_INVALIDATE_I, addr);
66 if (addr == aend)
67 break;
68 addr += dlsize;
69 }
70 return;
71 }
72
73 /* flush D-cache */
74 while (1) {
75 mips_cache(HIT_WRITEBACK_INV_D, addr);
76 if (addr == aend)
77 break;
78 addr += dlsize;
79 }
80
81 /* flush I-cache */
82 addr = (const void *)(start_addr & ~(ilsize - 1));
83 aend = (const void *)((start_addr + size - 1) & ~(ilsize - 1));
84 while (1) {
85 mips_cache(HIT_INVALIDATE_I, addr);
86 if (addr == aend)
87 break;
88 addr += ilsize;
89 }
90}
91
92void flush_dcache_range(ulong start_addr, ulong stop)
93{
94 unsigned long lsize = dcache_line_size();
95 const void *addr = (const void *)(start_addr & ~(lsize - 1));
96 const void *aend = (const void *)((stop - 1) & ~(lsize - 1));
97
98 while (1) {
99 mips_cache(HIT_WRITEBACK_INV_D, addr);
100 if (addr == aend)
101 break;
102 addr += lsize;
103 }
104}
105
106void invalidate_dcache_range(ulong start_addr, ulong stop)
107{
108 unsigned long lsize = dcache_line_size();
109 const void *addr = (const void *)(start_addr & ~(lsize - 1));
110 const void *aend = (const void *)((stop - 1) & ~(lsize - 1));
111
112 while (1) {
113 mips_cache(HIT_INVALIDATE_D, addr);
114 if (addr == aend)
115 break;
116 addr += lsize;
117 }
118}