xref: /rk3399_rockchip-uboot/arch/arm/lib/cache-cp15.c (revision 8f894a4d38adff26733225fb170f2a2d3e2b3054)
1ea0364f1SPeter Tyser /*
2ea0364f1SPeter Tyser  * (C) Copyright 2002
3ea0364f1SPeter Tyser  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4ea0364f1SPeter Tyser  *
51a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
6ea0364f1SPeter Tyser  */
7ea0364f1SPeter Tyser 
8ea0364f1SPeter Tyser #include <common.h>
9ea0364f1SPeter Tyser #include <asm/system.h>
1096fdbec2SR Sricharan #include <asm/cache.h>
1196fdbec2SR Sricharan #include <linux/compiler.h>
12ea0364f1SPeter Tyser 
13e47f2db5SAneesh V #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
14880eff5cSHeiko Schocher 
15880eff5cSHeiko Schocher DECLARE_GLOBAL_DATA_PTR;
16880eff5cSHeiko Schocher 
17fcfddfd5SJeroen Hofstee __weak void arm_init_before_mmu(void)
18c2dd0d45SAneesh V {
19c2dd0d45SAneesh V }
20c2dd0d45SAneesh V 
21de63ac27SR Sricharan __weak void arm_init_domains(void)
22de63ac27SR Sricharan {
23de63ac27SR Sricharan }
24de63ac27SR Sricharan 
25ea0364f1SPeter Tyser static void cp_delay (void)
26ea0364f1SPeter Tyser {
27ea0364f1SPeter Tyser 	volatile int i;
28ea0364f1SPeter Tyser 
29ea0364f1SPeter Tyser 	/* copro seems to need some delay between reading and writing */
30ea0364f1SPeter Tyser 	for (i = 0; i < 100; i++)
31ea0364f1SPeter Tyser 		nop();
32880eff5cSHeiko Schocher 	asm volatile("" : : : "memory");
33880eff5cSHeiko Schocher }
34880eff5cSHeiko Schocher 
350dde7f53SSimon Glass void set_section_dcache(int section, enum dcache_option option)
36f1d2b313SHeiko Schocher {
37d990f5c8SAlexander Graf #ifdef CONFIG_ARMV7_LPAE
38d990f5c8SAlexander Graf 	u64 *page_table = (u64 *)gd->arch.tlb_addr;
39d990f5c8SAlexander Graf 	/* Need to set the access flag to not fault */
40d990f5c8SAlexander Graf 	u64 value = TTB_SECT_AP | TTB_SECT_AF;
41d990f5c8SAlexander Graf #else
4234fd5d25SSimon Glass 	u32 *page_table = (u32 *)gd->arch.tlb_addr;
43d990f5c8SAlexander Graf 	u32 value = TTB_SECT_AP;
44d990f5c8SAlexander Graf #endif
450dde7f53SSimon Glass 
46d990f5c8SAlexander Graf 	/* Add the page offset */
47d990f5c8SAlexander Graf 	value |= ((u32)section << MMU_SECTION_SHIFT);
48d990f5c8SAlexander Graf 
49d990f5c8SAlexander Graf 	/* Add caching bits */
500dde7f53SSimon Glass 	value |= option;
51d990f5c8SAlexander Graf 
52d990f5c8SAlexander Graf 	/* Set PTE */
530dde7f53SSimon Glass 	page_table[section] = value;
540dde7f53SSimon Glass }
550dde7f53SSimon Glass 
56fcfddfd5SJeroen Hofstee __weak void mmu_page_table_flush(unsigned long start, unsigned long stop)
570dde7f53SSimon Glass {
580dde7f53SSimon Glass 	debug("%s: Warning: not implemented\n", __func__);
590dde7f53SSimon Glass }
600dde7f53SSimon Glass 
6125026fa9SThierry Reding void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
620dde7f53SSimon Glass 				     enum dcache_option option)
630dde7f53SSimon Glass {
64c5b3cabfSStefan Agner #ifdef CONFIG_ARMV7_LPAE
65c5b3cabfSStefan Agner 	u64 *page_table = (u64 *)gd->arch.tlb_addr;
66c5b3cabfSStefan Agner #else
6734fd5d25SSimon Glass 	u32 *page_table = (u32 *)gd->arch.tlb_addr;
68c5b3cabfSStefan Agner #endif
69*8f894a4dSStefan Agner 	unsigned long startpt, stoppt;
7025026fa9SThierry Reding 	unsigned long upto, end;
710dde7f53SSimon Glass 
720dde7f53SSimon Glass 	end = ALIGN(start + size, MMU_SECTION_SIZE) >> MMU_SECTION_SHIFT;
730dde7f53SSimon Glass 	start = start >> MMU_SECTION_SHIFT;
7425026fa9SThierry Reding 	debug("%s: start=%pa, size=%zu, option=%d\n", __func__, &start, size,
750dde7f53SSimon Glass 	      option);
760dde7f53SSimon Glass 	for (upto = start; upto < end; upto++)
770dde7f53SSimon Glass 		set_section_dcache(upto, option);
78*8f894a4dSStefan Agner 
79*8f894a4dSStefan Agner 	/*
80*8f894a4dSStefan Agner 	 * Make sure range is cache line aligned
81*8f894a4dSStefan Agner 	 * Only CPU maintains page tables, hence it is safe to always
82*8f894a4dSStefan Agner 	 * flush complete cache lines...
83*8f894a4dSStefan Agner 	 */
84*8f894a4dSStefan Agner 
85*8f894a4dSStefan Agner 	startpt = (unsigned long)&page_table[start];
86*8f894a4dSStefan Agner 	startpt &= ~(CONFIG_SYS_CACHELINE_SIZE - 1);
87*8f894a4dSStefan Agner 	stoppt = (unsigned long)&page_table[end];
88*8f894a4dSStefan Agner 	stoppt = ALIGN(stoppt, CONFIG_SYS_CACHELINE_SIZE);
89*8f894a4dSStefan Agner 	mmu_page_table_flush(startpt, stoppt);
900dde7f53SSimon Glass }
910dde7f53SSimon Glass 
9296fdbec2SR Sricharan __weak void dram_bank_mmu_setup(int bank)
930dde7f53SSimon Glass {
94f1d2b313SHeiko Schocher 	bd_t *bd = gd->bd;
95f1d2b313SHeiko Schocher 	int	i;
96f1d2b313SHeiko Schocher 
97f1d2b313SHeiko Schocher 	debug("%s: bank: %d\n", __func__, bank);
98d990f5c8SAlexander Graf 	for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT;
99d990f5c8SAlexander Graf 	     i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) +
100d990f5c8SAlexander Graf 		 (bd->bi_dram[bank].size >> MMU_SECTION_SHIFT);
101f1d2b313SHeiko Schocher 	     i++) {
1020dde7f53SSimon Glass #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
1030dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_WRITETHROUGH);
104ff7e9700SMarek Vasut #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
105ff7e9700SMarek Vasut 		set_section_dcache(i, DCACHE_WRITEALLOC);
1060dde7f53SSimon Glass #else
1070dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_WRITEBACK);
1080dde7f53SSimon Glass #endif
109f1d2b313SHeiko Schocher 	}
110f1d2b313SHeiko Schocher }
111f1d2b313SHeiko Schocher 
112f1d2b313SHeiko Schocher /* to activate the MMU we need to set up virtual memory: use 1M areas */
113880eff5cSHeiko Schocher static inline void mmu_setup(void)
114880eff5cSHeiko Schocher {
115f1d2b313SHeiko Schocher 	int i;
116880eff5cSHeiko Schocher 	u32 reg;
117880eff5cSHeiko Schocher 
118c2dd0d45SAneesh V 	arm_init_before_mmu();
119880eff5cSHeiko Schocher 	/* Set up an identity-mapping for all 4GB, rw for everyone */
120d990f5c8SAlexander Graf 	for (i = 0; i < ((4096ULL * 1024 * 1024) >> MMU_SECTION_SHIFT); i++)
1210dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_OFF);
122f1d2b313SHeiko Schocher 
123f1d2b313SHeiko Schocher 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
124f1d2b313SHeiko Schocher 		dram_bank_mmu_setup(i);
125f1d2b313SHeiko Schocher 	}
126880eff5cSHeiko Schocher 
127d990f5c8SAlexander Graf #ifdef CONFIG_ARMV7_LPAE
128d990f5c8SAlexander Graf 	/* Set up 4 PTE entries pointing to our 4 1GB page tables */
129d990f5c8SAlexander Graf 	for (i = 0; i < 4; i++) {
130d990f5c8SAlexander Graf 		u64 *page_table = (u64 *)(gd->arch.tlb_addr + (4096 * 4));
131d990f5c8SAlexander Graf 		u64 tpt = gd->arch.tlb_addr + (4096 * i);
132d990f5c8SAlexander Graf 		page_table[i] = tpt | TTB_PAGETABLE;
133d990f5c8SAlexander Graf 	}
134d990f5c8SAlexander Graf 
135d990f5c8SAlexander Graf 	reg = TTBCR_EAE;
136d990f5c8SAlexander Graf #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
137d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WT | TTBCR_IRGN0_WT;
138d990f5c8SAlexander Graf #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
139d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WBWA | TTBCR_IRGN0_WBWA;
140d990f5c8SAlexander Graf #else
141d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WBNWA | TTBCR_IRGN0_WBNWA;
142d990f5c8SAlexander Graf #endif
143d990f5c8SAlexander Graf 
144d990f5c8SAlexander Graf 	if (is_hyp()) {
145d990f5c8SAlexander Graf 		/* Set HCTR to enable LPAE */
146d990f5c8SAlexander Graf 		asm volatile("mcr p15, 4, %0, c2, c0, 2"
147d990f5c8SAlexander Graf 			: : "r" (reg) : "memory");
148d990f5c8SAlexander Graf 		/* Set HTTBR0 */
149d990f5c8SAlexander Graf 		asm volatile("mcrr p15, 4, %0, %1, c2"
150d990f5c8SAlexander Graf 			:
151d990f5c8SAlexander Graf 			: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
152d990f5c8SAlexander Graf 			: "memory");
153d990f5c8SAlexander Graf 		/* Set HMAIR */
154d990f5c8SAlexander Graf 		asm volatile("mcr p15, 4, %0, c10, c2, 0"
155d990f5c8SAlexander Graf 			: : "r" (MEMORY_ATTRIBUTES) : "memory");
156d990f5c8SAlexander Graf 	} else {
157d990f5c8SAlexander Graf 		/* Set TTBCR to enable LPAE */
158d990f5c8SAlexander Graf 		asm volatile("mcr p15, 0, %0, c2, c0, 2"
159d990f5c8SAlexander Graf 			: : "r" (reg) : "memory");
160d990f5c8SAlexander Graf 		/* Set 64-bit TTBR0 */
161d990f5c8SAlexander Graf 		asm volatile("mcrr p15, 0, %0, %1, c2"
162d990f5c8SAlexander Graf 			:
163d990f5c8SAlexander Graf 			: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
164d990f5c8SAlexander Graf 			: "memory");
165d990f5c8SAlexander Graf 		/* Set MAIR */
166d990f5c8SAlexander Graf 		asm volatile("mcr p15, 0, %0, c10, c2, 0"
167d990f5c8SAlexander Graf 			: : "r" (MEMORY_ATTRIBUTES) : "memory");
168d990f5c8SAlexander Graf 	}
169d990f5c8SAlexander Graf #elif defined(CONFIG_CPU_V7)
17097840b5dSBryan Brinsko 	/* Set TTBR0 */
17197840b5dSBryan Brinsko 	reg = gd->arch.tlb_addr & TTBR0_BASE_ADDR_MASK;
17297840b5dSBryan Brinsko #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
17397840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WT | TTBR0_IRGN_WT;
17497840b5dSBryan Brinsko #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
17597840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WBWA | TTBR0_IRGN_WBWA;
17697840b5dSBryan Brinsko #else
17797840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WB | TTBR0_IRGN_WB;
17897840b5dSBryan Brinsko #endif
17997840b5dSBryan Brinsko 	asm volatile("mcr p15, 0, %0, c2, c0, 0"
18097840b5dSBryan Brinsko 		     : : "r" (reg) : "memory");
18197840b5dSBryan Brinsko #else
182880eff5cSHeiko Schocher 	/* Copy the page table address to cp15 */
183880eff5cSHeiko Schocher 	asm volatile("mcr p15, 0, %0, c2, c0, 0"
18434fd5d25SSimon Glass 		     : : "r" (gd->arch.tlb_addr) : "memory");
18597840b5dSBryan Brinsko #endif
186880eff5cSHeiko Schocher 	/* Set the access control to all-supervisor */
187880eff5cSHeiko Schocher 	asm volatile("mcr p15, 0, %0, c3, c0, 0"
188880eff5cSHeiko Schocher 		     : : "r" (~0));
189de63ac27SR Sricharan 
190de63ac27SR Sricharan 	arm_init_domains();
191de63ac27SR Sricharan 
192880eff5cSHeiko Schocher 	/* and enable the mmu */
193880eff5cSHeiko Schocher 	reg = get_cr();	/* get control reg. */
194880eff5cSHeiko Schocher 	cp_delay();
195880eff5cSHeiko Schocher 	set_cr(reg | CR_M);
196ea0364f1SPeter Tyser }
197ea0364f1SPeter Tyser 
198e05f0079SAneesh V static int mmu_enabled(void)
199e05f0079SAneesh V {
200e05f0079SAneesh V 	return get_cr() & CR_M;
201e05f0079SAneesh V }
202e05f0079SAneesh V 
203ea0364f1SPeter Tyser /* cache_bit must be either CR_I or CR_C */
204ea0364f1SPeter Tyser static void cache_enable(uint32_t cache_bit)
205ea0364f1SPeter Tyser {
206ea0364f1SPeter Tyser 	uint32_t reg;
207ea0364f1SPeter Tyser 
208880eff5cSHeiko Schocher 	/* The data cache is not active unless the mmu is enabled too */
209e05f0079SAneesh V 	if ((cache_bit == CR_C) && !mmu_enabled())
210880eff5cSHeiko Schocher 		mmu_setup();
211ea0364f1SPeter Tyser 	reg = get_cr();	/* get control reg. */
212ea0364f1SPeter Tyser 	cp_delay();
213ea0364f1SPeter Tyser 	set_cr(reg | cache_bit);
214ea0364f1SPeter Tyser }
215ea0364f1SPeter Tyser 
216ea0364f1SPeter Tyser /* cache_bit must be either CR_I or CR_C */
217ea0364f1SPeter Tyser static void cache_disable(uint32_t cache_bit)
218ea0364f1SPeter Tyser {
219ea0364f1SPeter Tyser 	uint32_t reg;
220ea0364f1SPeter Tyser 
221d702b081SSRICHARAN R 	reg = get_cr();
222d702b081SSRICHARAN R 	cp_delay();
223d702b081SSRICHARAN R 
224880eff5cSHeiko Schocher 	if (cache_bit == CR_C) {
225f1d2b313SHeiko Schocher 		/* if cache isn;t enabled no need to disable */
226f1d2b313SHeiko Schocher 		if ((reg & CR_C) != CR_C)
227f1d2b313SHeiko Schocher 			return;
228880eff5cSHeiko Schocher 		/* if disabling data cache, disable mmu too */
229880eff5cSHeiko Schocher 		cache_bit |= CR_M;
230880eff5cSHeiko Schocher 	}
23144df5e8dSArun Mankuzhi 	reg = get_cr();
23244df5e8dSArun Mankuzhi 	cp_delay();
23344df5e8dSArun Mankuzhi 	if (cache_bit == (CR_C | CR_M))
23444df5e8dSArun Mankuzhi 		flush_dcache_all();
235ea0364f1SPeter Tyser 	set_cr(reg & ~cache_bit);
236ea0364f1SPeter Tyser }
237ea0364f1SPeter Tyser #endif
238ea0364f1SPeter Tyser 
239e47f2db5SAneesh V #ifdef CONFIG_SYS_ICACHE_OFF
240ea0364f1SPeter Tyser void icache_enable (void)
241ea0364f1SPeter Tyser {
242ea0364f1SPeter Tyser 	return;
243ea0364f1SPeter Tyser }
244ea0364f1SPeter Tyser 
245ea0364f1SPeter Tyser void icache_disable (void)
246ea0364f1SPeter Tyser {
247ea0364f1SPeter Tyser 	return;
248ea0364f1SPeter Tyser }
249ea0364f1SPeter Tyser 
250ea0364f1SPeter Tyser int icache_status (void)
251ea0364f1SPeter Tyser {
252ea0364f1SPeter Tyser 	return 0;					/* always off */
253ea0364f1SPeter Tyser }
254ea0364f1SPeter Tyser #else
255ea0364f1SPeter Tyser void icache_enable(void)
256ea0364f1SPeter Tyser {
257ea0364f1SPeter Tyser 	cache_enable(CR_I);
258ea0364f1SPeter Tyser }
259ea0364f1SPeter Tyser 
260ea0364f1SPeter Tyser void icache_disable(void)
261ea0364f1SPeter Tyser {
262ea0364f1SPeter Tyser 	cache_disable(CR_I);
263ea0364f1SPeter Tyser }
264ea0364f1SPeter Tyser 
265ea0364f1SPeter Tyser int icache_status(void)
266ea0364f1SPeter Tyser {
267ea0364f1SPeter Tyser 	return (get_cr() & CR_I) != 0;
268ea0364f1SPeter Tyser }
269ea0364f1SPeter Tyser #endif
270ea0364f1SPeter Tyser 
271e47f2db5SAneesh V #ifdef CONFIG_SYS_DCACHE_OFF
272ea0364f1SPeter Tyser void dcache_enable (void)
273ea0364f1SPeter Tyser {
274ea0364f1SPeter Tyser 	return;
275ea0364f1SPeter Tyser }
276ea0364f1SPeter Tyser 
277ea0364f1SPeter Tyser void dcache_disable (void)
278ea0364f1SPeter Tyser {
279ea0364f1SPeter Tyser 	return;
280ea0364f1SPeter Tyser }
281ea0364f1SPeter Tyser 
282ea0364f1SPeter Tyser int dcache_status (void)
283ea0364f1SPeter Tyser {
284ea0364f1SPeter Tyser 	return 0;					/* always off */
285ea0364f1SPeter Tyser }
286ea0364f1SPeter Tyser #else
287ea0364f1SPeter Tyser void dcache_enable(void)
288ea0364f1SPeter Tyser {
289ea0364f1SPeter Tyser 	cache_enable(CR_C);
290ea0364f1SPeter Tyser }
291ea0364f1SPeter Tyser 
292ea0364f1SPeter Tyser void dcache_disable(void)
293ea0364f1SPeter Tyser {
294ea0364f1SPeter Tyser 	cache_disable(CR_C);
295ea0364f1SPeter Tyser }
296ea0364f1SPeter Tyser 
297ea0364f1SPeter Tyser int dcache_status(void)
298ea0364f1SPeter Tyser {
299ea0364f1SPeter Tyser 	return (get_cr() & CR_C) != 0;
300ea0364f1SPeter Tyser }
301ea0364f1SPeter Tyser #endif
302