• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2013 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * cache.c: Cache maintenance routines for ARMv7-A and ARMv7-R
29  *
30  * Reference: ARM Architecture Reference Manual, ARMv7-A and ARMv7-R edition
31  */
32 
33 #include <stdint.h>
34 
35 #include <arch/cache.h>
36 #include <arch/virtual.h>
37 
tlb_invalidate_all(void)38 void tlb_invalidate_all(void)
39 {
40 	/* TLBIALL includes dTLB and iTLB on systems that have them. */
41 	tlbiall();
42 	dsb();
43 	isb();
44 }
45 
46 enum dcache_op {
47 	OP_DCCSW,
48 	OP_DCCISW,
49 	OP_DCISW,
50 	OP_DCCIMVAC,
51 	OP_DCCMVAC,
52 	OP_DCIMVAC,
53 };
54 
dcache_line_bytes(void)55 unsigned int dcache_line_bytes(void)
56 {
57 	uint32_t ccsidr;
58 	static unsigned int line_bytes = 0;
59 
60 	if (line_bytes)
61 		return line_bytes;
62 
63 	ccsidr = read_ccsidr();
64 	/* [2:0] - Indicates (Log2(number of words in cache line)) - 2 */
65 	line_bytes = 1 << ((ccsidr & 0x7) + 2);	/* words per line */
66 	line_bytes *= sizeof(unsigned int);	/* bytes per line */
67 
68 	return line_bytes;
69 }
70 
71 /*
72  * Do a dcache operation by modified virtual address. This is useful for
73  * maintaining coherency in drivers which do DMA transfers and only need to
74  * perform cache maintenance on a particular memory range rather than the
75  * entire cache.
76  */
dcache_op_mva(void const * vaddr,size_t len,enum dcache_op op)77 static void dcache_op_mva(void const *vaddr, size_t len, enum dcache_op op)
78 {
79 	unsigned long line, linesize;
80 	unsigned long paddr = virt_to_phys(vaddr);
81 
82 	linesize = dcache_line_bytes();
83 	line = paddr & ~(linesize - 1);
84 
85 	dsb();
86 	while (line < paddr + len) {
87 		switch(op) {
88 		case OP_DCCIMVAC:
89 			dccimvac(line);
90 			break;
91 		case OP_DCCMVAC:
92 			dccmvac(line);
93 			break;
94 		case OP_DCIMVAC:
95 			dcimvac(line);
96 			break;
97 		default:
98 			break;
99 		}
100 		line += linesize;
101 	}
102 	isb();
103 }
104 
dcache_clean_by_mva(void const * addr,size_t len)105 void dcache_clean_by_mva(void const *addr, size_t len)
106 {
107 	dcache_op_mva(addr, len, OP_DCCMVAC);
108 }
109 
dcache_clean_invalidate_by_mva(void const * addr,size_t len)110 void dcache_clean_invalidate_by_mva(void const *addr, size_t len)
111 {
112 	dcache_op_mva(addr, len, OP_DCCIMVAC);
113 }
114 
dcache_invalidate_by_mva(void const * addr,size_t len)115 void dcache_invalidate_by_mva(void const *addr, size_t len)
116 {
117 	dcache_op_mva(addr, len, OP_DCIMVAC);
118 }
119 
120 /*
121  * CAUTION: This implementation assumes that coreboot never uses non-identity
122  * page tables for pages containing executed code. If you ever want to violate
123  * this assumption, have fun figuring out the associated problems on your own.
124  */
dcache_mmu_disable(void)125 void dcache_mmu_disable(void)
126 {
127 	uint32_t sctlr;
128 
129 	dcache_clean_invalidate_all();
130 	sctlr = read_sctlr();
131 	sctlr &= ~(SCTLR_C | SCTLR_M);
132 	write_sctlr(sctlr);
133 }
134 
dcache_mmu_enable(void)135 void dcache_mmu_enable(void)
136 {
137 	uint32_t sctlr;
138 
139 	sctlr = read_sctlr();
140 	sctlr |= SCTLR_C | SCTLR_M;
141 	write_sctlr(sctlr);
142 }
143 
cache_sync_instructions(void)144 void cache_sync_instructions(void)
145 {
146 	uint32_t sctlr;
147 
148 	sctlr = read_sctlr();
149 
150 	if (sctlr & SCTLR_C)
151 		dcache_clean_all();
152 	else if (sctlr & SCTLR_I)
153 		dcache_clean_invalidate_all();
154 
155 	iciallu();		/* includes BPIALLU (architecturally) */
156 	dsb();
157 	isb();
158 }
159