xref: /rk3399_rockchip-uboot/arch/arm/lib/cache-cp15.c (revision 1d22de7f19c7dbc24915ea41f28c37b9224493d1)
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 
arm_init_before_mmu(void)17fcfddfd5SJeroen Hofstee __weak void arm_init_before_mmu(void)
18c2dd0d45SAneesh V {
19c2dd0d45SAneesh V }
20c2dd0d45SAneesh V 
arm_init_domains(void)21de63ac27SR Sricharan __weak void arm_init_domains(void)
22de63ac27SR Sricharan {
23de63ac27SR Sricharan }
24de63ac27SR Sricharan 
set_section_dcache(int section,enum dcache_option option)250dde7f53SSimon Glass void set_section_dcache(int section, enum dcache_option option)
26f1d2b313SHeiko Schocher {
27d990f5c8SAlexander Graf #ifdef CONFIG_ARMV7_LPAE
28d990f5c8SAlexander Graf 	u64 *page_table = (u64 *)gd->arch.tlb_addr;
29d990f5c8SAlexander Graf 	/* Need to set the access flag to not fault */
30d990f5c8SAlexander Graf 	u64 value = TTB_SECT_AP | TTB_SECT_AF;
31d990f5c8SAlexander Graf #else
3234fd5d25SSimon Glass 	u32 *page_table = (u32 *)gd->arch.tlb_addr;
33d990f5c8SAlexander Graf 	u32 value = TTB_SECT_AP;
34d990f5c8SAlexander Graf #endif
350dde7f53SSimon Glass 
36d990f5c8SAlexander Graf 	/* Add the page offset */
37d990f5c8SAlexander Graf 	value |= ((u32)section << MMU_SECTION_SHIFT);
38d990f5c8SAlexander Graf 
39d990f5c8SAlexander Graf 	/* Add caching bits */
400dde7f53SSimon Glass 	value |= option;
41d990f5c8SAlexander Graf 
42d990f5c8SAlexander Graf 	/* Set PTE */
430dde7f53SSimon Glass 	page_table[section] = value;
440dde7f53SSimon Glass }
450dde7f53SSimon Glass 
mmu_page_table_flush(unsigned long start,unsigned long stop)46fcfddfd5SJeroen Hofstee __weak void mmu_page_table_flush(unsigned long start, unsigned long stop)
470dde7f53SSimon Glass {
480dde7f53SSimon Glass 	debug("%s: Warning: not implemented\n", __func__);
490dde7f53SSimon Glass }
500dde7f53SSimon Glass 
mmu_set_region_dcache_behaviour(phys_addr_t start,size_t size,enum dcache_option option)5125026fa9SThierry Reding void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size,
520dde7f53SSimon Glass 				     enum dcache_option option)
530dde7f53SSimon Glass {
54c5b3cabfSStefan Agner #ifdef CONFIG_ARMV7_LPAE
55c5b3cabfSStefan Agner 	u64 *page_table = (u64 *)gd->arch.tlb_addr;
56c5b3cabfSStefan Agner #else
5734fd5d25SSimon Glass 	u32 *page_table = (u32 *)gd->arch.tlb_addr;
58c5b3cabfSStefan Agner #endif
598f894a4dSStefan Agner 	unsigned long startpt, stoppt;
6025026fa9SThierry Reding 	unsigned long upto, end;
610dde7f53SSimon Glass 
620dde7f53SSimon Glass 	end = ALIGN(start + size, MMU_SECTION_SIZE) >> MMU_SECTION_SHIFT;
630dde7f53SSimon Glass 	start = start >> MMU_SECTION_SHIFT;
6406d43c80SKeerthy #ifdef CONFIG_ARMV7_LPAE
6506d43c80SKeerthy 	debug("%s: start=%pa, size=%zu, option=%llx\n", __func__, &start, size,
6606d43c80SKeerthy 	      option);
6706d43c80SKeerthy #else
682b373cb8SKeerthy 	debug("%s: start=%pa, size=%zu, option=0x%x\n", __func__, &start, size,
690dde7f53SSimon Glass 	      option);
7006d43c80SKeerthy #endif
710dde7f53SSimon Glass 	for (upto = start; upto < end; upto++)
720dde7f53SSimon Glass 		set_section_dcache(upto, option);
738f894a4dSStefan Agner 
748f894a4dSStefan Agner 	/*
758f894a4dSStefan Agner 	 * Make sure range is cache line aligned
768f894a4dSStefan Agner 	 * Only CPU maintains page tables, hence it is safe to always
778f894a4dSStefan Agner 	 * flush complete cache lines...
788f894a4dSStefan Agner 	 */
798f894a4dSStefan Agner 
808f894a4dSStefan Agner 	startpt = (unsigned long)&page_table[start];
818f894a4dSStefan Agner 	startpt &= ~(CONFIG_SYS_CACHELINE_SIZE - 1);
828f894a4dSStefan Agner 	stoppt = (unsigned long)&page_table[end];
838f894a4dSStefan Agner 	stoppt = ALIGN(stoppt, CONFIG_SYS_CACHELINE_SIZE);
848f894a4dSStefan Agner 	mmu_page_table_flush(startpt, stoppt);
850dde7f53SSimon Glass }
860dde7f53SSimon Glass 
dram_bank_mmu_setup(int bank)8796fdbec2SR Sricharan __weak void dram_bank_mmu_setup(int bank)
880dde7f53SSimon Glass {
89f1d2b313SHeiko Schocher 	bd_t *bd = gd->bd;
90f1d2b313SHeiko Schocher 	int	i;
91f1d2b313SHeiko Schocher 
92f1d2b313SHeiko Schocher 	debug("%s: bank: %d\n", __func__, bank);
93d990f5c8SAlexander Graf 	for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT;
94d990f5c8SAlexander Graf 	     i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) +
95d990f5c8SAlexander Graf 		 (bd->bi_dram[bank].size >> MMU_SECTION_SHIFT);
96f1d2b313SHeiko Schocher 	     i++) {
970dde7f53SSimon Glass #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
980dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_WRITETHROUGH);
99ff7e9700SMarek Vasut #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
100ff7e9700SMarek Vasut 		set_section_dcache(i, DCACHE_WRITEALLOC);
1010dde7f53SSimon Glass #else
1020dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_WRITEBACK);
1030dde7f53SSimon Glass #endif
104f1d2b313SHeiko Schocher 	}
105f1d2b313SHeiko Schocher }
106f1d2b313SHeiko Schocher 
107f1d2b313SHeiko Schocher /* to activate the MMU we need to set up virtual memory: use 1M areas */
mmu_setup(void)108880eff5cSHeiko Schocher static inline void mmu_setup(void)
109880eff5cSHeiko Schocher {
1102a3fb7bbSJoseph Chen 	int i, end;
111880eff5cSHeiko Schocher 	u32 reg;
112880eff5cSHeiko Schocher 
1135c8c82beSJason Zhu #ifndef CONFIG_SPL_BUILD
1145c8c82beSJason Zhu 	/* bootrom and ddr didn't initial dcache,
1155c8c82beSJason Zhu 	 * skip this to save boot time.
1165c8c82beSJason Zhu 	 */
117c2dd0d45SAneesh V 	arm_init_before_mmu();
1185c8c82beSJason Zhu #endif
1192a3fb7bbSJoseph Chen 
1202a3fb7bbSJoseph Chen 	/*
1212a3fb7bbSJoseph Chen 	 * SPL thunder-boot:
1222a3fb7bbSJoseph Chen 	 * only map periph device region to save boot time.
1232a3fb7bbSJoseph Chen 	 */
1242a3fb7bbSJoseph Chen #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_KERNEL_BOOT) && \
125*1d22de7fSJoseph Chen     defined(CONFIG_PERIPH_DEVICE_START_ADDR)
126*1d22de7fSJoseph Chen 	i = CONFIG_PERIPH_DEVICE_START_ADDR >> MMU_SECTION_SHIFT;
127*1d22de7fSJoseph Chen 	end = CONFIG_PERIPH_DEVICE_END_ADDR >> MMU_SECTION_SHIFT;
1282a3fb7bbSJoseph Chen #else
1292a3fb7bbSJoseph Chen 	i = 0;
1302a3fb7bbSJoseph Chen 	end = (4096ULL * 1024 * 1024) >> MMU_SECTION_SHIFT;
1312a3fb7bbSJoseph Chen #endif
132880eff5cSHeiko Schocher 	/* Set up an identity-mapping for all 4GB, rw for everyone */
1332a3fb7bbSJoseph Chen 	for (; i < end; i++)
1340dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_OFF);
135f1d2b313SHeiko Schocher 
136f1d2b313SHeiko Schocher 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
137f1d2b313SHeiko Schocher 		dram_bank_mmu_setup(i);
138f1d2b313SHeiko Schocher 	}
139880eff5cSHeiko Schocher 
14010d602acSSimon Glass #if defined(CONFIG_ARMV7_LPAE) && __LINUX_ARM_ARCH__ != 4
141d990f5c8SAlexander Graf 	/* Set up 4 PTE entries pointing to our 4 1GB page tables */
142d990f5c8SAlexander Graf 	for (i = 0; i < 4; i++) {
143d990f5c8SAlexander Graf 		u64 *page_table = (u64 *)(gd->arch.tlb_addr + (4096 * 4));
144d990f5c8SAlexander Graf 		u64 tpt = gd->arch.tlb_addr + (4096 * i);
145d990f5c8SAlexander Graf 		page_table[i] = tpt | TTB_PAGETABLE;
146d990f5c8SAlexander Graf 	}
147d990f5c8SAlexander Graf 
148d990f5c8SAlexander Graf 	reg = TTBCR_EAE;
149d990f5c8SAlexander Graf #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
150d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WT | TTBCR_IRGN0_WT;
151d990f5c8SAlexander Graf #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
152d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WBWA | TTBCR_IRGN0_WBWA;
153d990f5c8SAlexander Graf #else
154d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WBNWA | TTBCR_IRGN0_WBNWA;
155d990f5c8SAlexander Graf #endif
156d990f5c8SAlexander Graf 
157d990f5c8SAlexander Graf 	if (is_hyp()) {
158579dfca2SSimon Glass 		/* Set HTCR to enable LPAE */
159d990f5c8SAlexander Graf 		asm volatile("mcr p15, 4, %0, c2, c0, 2"
160d990f5c8SAlexander Graf 			: : "r" (reg) : "memory");
161d990f5c8SAlexander Graf 		/* Set HTTBR0 */
162d990f5c8SAlexander Graf 		asm volatile("mcrr p15, 4, %0, %1, c2"
163d990f5c8SAlexander Graf 			:
164d990f5c8SAlexander Graf 			: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
165d990f5c8SAlexander Graf 			: "memory");
166d990f5c8SAlexander Graf 		/* Set HMAIR */
167d990f5c8SAlexander Graf 		asm volatile("mcr p15, 4, %0, c10, c2, 0"
168d990f5c8SAlexander Graf 			: : "r" (MEMORY_ATTRIBUTES) : "memory");
169d990f5c8SAlexander Graf 	} else {
170d990f5c8SAlexander Graf 		/* Set TTBCR to enable LPAE */
171d990f5c8SAlexander Graf 		asm volatile("mcr p15, 0, %0, c2, c0, 2"
172d990f5c8SAlexander Graf 			: : "r" (reg) : "memory");
173d990f5c8SAlexander Graf 		/* Set 64-bit TTBR0 */
174d990f5c8SAlexander Graf 		asm volatile("mcrr p15, 0, %0, %1, c2"
175d990f5c8SAlexander Graf 			:
176d990f5c8SAlexander Graf 			: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
177d990f5c8SAlexander Graf 			: "memory");
178d990f5c8SAlexander Graf 		/* Set MAIR */
179d990f5c8SAlexander Graf 		asm volatile("mcr p15, 0, %0, c10, c2, 0"
180d990f5c8SAlexander Graf 			: : "r" (MEMORY_ATTRIBUTES) : "memory");
181d990f5c8SAlexander Graf 	}
182d990f5c8SAlexander Graf #elif defined(CONFIG_CPU_V7)
18350a4886bSSimon Glass 	if (is_hyp()) {
18450a4886bSSimon Glass 		/* Set HTCR to disable LPAE */
18550a4886bSSimon Glass 		asm volatile("mcr p15, 4, %0, c2, c0, 2"
18650a4886bSSimon Glass 			: : "r" (0) : "memory");
18750a4886bSSimon Glass 	} else {
18850a4886bSSimon Glass 		/* Set TTBCR to disable LPAE */
18950a4886bSSimon Glass 		asm volatile("mcr p15, 0, %0, c2, c0, 2"
19050a4886bSSimon Glass 			: : "r" (0) : "memory");
19150a4886bSSimon Glass 	}
19297840b5dSBryan Brinsko 	/* Set TTBR0 */
19397840b5dSBryan Brinsko 	reg = gd->arch.tlb_addr & TTBR0_BASE_ADDR_MASK;
19497840b5dSBryan Brinsko #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
19597840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WT | TTBR0_IRGN_WT;
19697840b5dSBryan Brinsko #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
19797840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WBWA | TTBR0_IRGN_WBWA;
19897840b5dSBryan Brinsko #else
19997840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WB | TTBR0_IRGN_WB;
20097840b5dSBryan Brinsko #endif
20197840b5dSBryan Brinsko 	asm volatile("mcr p15, 0, %0, c2, c0, 0"
20297840b5dSBryan Brinsko 		     : : "r" (reg) : "memory");
20397840b5dSBryan Brinsko #else
204880eff5cSHeiko Schocher 	/* Copy the page table address to cp15 */
205880eff5cSHeiko Schocher 	asm volatile("mcr p15, 0, %0, c2, c0, 0"
20634fd5d25SSimon Glass 		     : : "r" (gd->arch.tlb_addr) : "memory");
20797840b5dSBryan Brinsko #endif
208880eff5cSHeiko Schocher 	/* Set the access control to all-supervisor */
209880eff5cSHeiko Schocher 	asm volatile("mcr p15, 0, %0, c3, c0, 0"
210880eff5cSHeiko Schocher 		     : : "r" (~0));
211de63ac27SR Sricharan 
212de63ac27SR Sricharan 	arm_init_domains();
213de63ac27SR Sricharan 
214880eff5cSHeiko Schocher 	/* and enable the mmu */
215880eff5cSHeiko Schocher 	reg = get_cr();	/* get control reg. */
216880eff5cSHeiko Schocher 	set_cr(reg | CR_M);
217ea0364f1SPeter Tyser }
218ea0364f1SPeter Tyser 
mmu_enabled(void)219e05f0079SAneesh V static int mmu_enabled(void)
220e05f0079SAneesh V {
221e05f0079SAneesh V 	return get_cr() & CR_M;
222e05f0079SAneesh V }
223e05f0079SAneesh V 
224ea0364f1SPeter Tyser /* cache_bit must be either CR_I or CR_C */
cache_enable(uint32_t cache_bit)225ea0364f1SPeter Tyser static void cache_enable(uint32_t cache_bit)
226ea0364f1SPeter Tyser {
227ea0364f1SPeter Tyser 	uint32_t reg;
228ea0364f1SPeter Tyser 
229880eff5cSHeiko Schocher 	/* The data cache is not active unless the mmu is enabled too */
230e05f0079SAneesh V 	if ((cache_bit == CR_C) && !mmu_enabled())
231880eff5cSHeiko Schocher 		mmu_setup();
232ea0364f1SPeter Tyser 	reg = get_cr();	/* get control reg. */
233ea0364f1SPeter Tyser 	set_cr(reg | cache_bit);
234ea0364f1SPeter Tyser }
235ea0364f1SPeter Tyser 
236ea0364f1SPeter Tyser /* cache_bit must be either CR_I or CR_C */
cache_disable(uint32_t cache_bit)237ea0364f1SPeter Tyser static void cache_disable(uint32_t cache_bit)
238ea0364f1SPeter Tyser {
239ea0364f1SPeter Tyser 	uint32_t reg;
240ea0364f1SPeter Tyser 
241d702b081SSRICHARAN R 	reg = get_cr();
242d702b081SSRICHARAN R 
243880eff5cSHeiko Schocher 	if (cache_bit == CR_C) {
244f1d2b313SHeiko Schocher 		/* if cache isn;t enabled no need to disable */
245f1d2b313SHeiko Schocher 		if ((reg & CR_C) != CR_C)
246f1d2b313SHeiko Schocher 			return;
247880eff5cSHeiko Schocher 		/* if disabling data cache, disable mmu too */
248880eff5cSHeiko Schocher 		cache_bit |= CR_M;
249880eff5cSHeiko Schocher 	}
25044df5e8dSArun Mankuzhi 	reg = get_cr();
25153d4ed70SLothar Waßmann 
25244df5e8dSArun Mankuzhi 	if (cache_bit == (CR_C | CR_M))
25344df5e8dSArun Mankuzhi 		flush_dcache_all();
254ea0364f1SPeter Tyser 	set_cr(reg & ~cache_bit);
255ea0364f1SPeter Tyser }
256ea0364f1SPeter Tyser #endif
257ea0364f1SPeter Tyser 
258e47f2db5SAneesh V #ifdef CONFIG_SYS_ICACHE_OFF
icache_enable(void)259ea0364f1SPeter Tyser void icache_enable (void)
260ea0364f1SPeter Tyser {
261ea0364f1SPeter Tyser 	return;
262ea0364f1SPeter Tyser }
263ea0364f1SPeter Tyser 
icache_disable(void)264ea0364f1SPeter Tyser void icache_disable (void)
265ea0364f1SPeter Tyser {
266ea0364f1SPeter Tyser 	return;
267ea0364f1SPeter Tyser }
268ea0364f1SPeter Tyser 
icache_status(void)269ea0364f1SPeter Tyser int icache_status (void)
270ea0364f1SPeter Tyser {
271ea0364f1SPeter Tyser 	return 0;					/* always off */
272ea0364f1SPeter Tyser }
273ea0364f1SPeter Tyser #else
icache_enable(void)274ea0364f1SPeter Tyser void icache_enable(void)
275ea0364f1SPeter Tyser {
276ea0364f1SPeter Tyser 	cache_enable(CR_I);
277ea0364f1SPeter Tyser }
278ea0364f1SPeter Tyser 
icache_disable(void)279ea0364f1SPeter Tyser void icache_disable(void)
280ea0364f1SPeter Tyser {
281ea0364f1SPeter Tyser 	cache_disable(CR_I);
282ea0364f1SPeter Tyser }
283ea0364f1SPeter Tyser 
icache_status(void)284ea0364f1SPeter Tyser int icache_status(void)
285ea0364f1SPeter Tyser {
286ea0364f1SPeter Tyser 	return (get_cr() & CR_I) != 0;
287ea0364f1SPeter Tyser }
288ea0364f1SPeter Tyser #endif
289ea0364f1SPeter Tyser 
290e47f2db5SAneesh V #ifdef CONFIG_SYS_DCACHE_OFF
dcache_enable(void)291ea0364f1SPeter Tyser void dcache_enable (void)
292ea0364f1SPeter Tyser {
293ea0364f1SPeter Tyser 	return;
294ea0364f1SPeter Tyser }
295ea0364f1SPeter Tyser 
dcache_disable(void)296ea0364f1SPeter Tyser void dcache_disable (void)
297ea0364f1SPeter Tyser {
298ea0364f1SPeter Tyser 	return;
299ea0364f1SPeter Tyser }
300ea0364f1SPeter Tyser 
dcache_status(void)301ea0364f1SPeter Tyser int dcache_status (void)
302ea0364f1SPeter Tyser {
303ea0364f1SPeter Tyser 	return 0;					/* always off */
304ea0364f1SPeter Tyser }
305ea0364f1SPeter Tyser #else
dcache_enable(void)306ea0364f1SPeter Tyser void dcache_enable(void)
307ea0364f1SPeter Tyser {
308ea0364f1SPeter Tyser 	cache_enable(CR_C);
309ea0364f1SPeter Tyser }
310ea0364f1SPeter Tyser 
dcache_disable(void)311ea0364f1SPeter Tyser void dcache_disable(void)
312ea0364f1SPeter Tyser {
313ea0364f1SPeter Tyser 	cache_disable(CR_C);
314ea0364f1SPeter Tyser }
315ea0364f1SPeter Tyser 
dcache_status(void)316ea0364f1SPeter Tyser int dcache_status(void)
317ea0364f1SPeter Tyser {
318ea0364f1SPeter Tyser 	return (get_cr() & CR_C) != 0;
319ea0364f1SPeter Tyser }
320ea0364f1SPeter Tyser #endif
321