xref: /rk3399_rockchip-uboot/arch/arm/lib/cache-cp15.c (revision c5b3cabf4a2f78b126a7da92c20b781a52d5307f)
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 {
64*c5b3cabfSStefan Agner #ifdef CONFIG_ARMV7_LPAE
65*c5b3cabfSStefan Agner 	u64 *page_table = (u64 *)gd->arch.tlb_addr;
66*c5b3cabfSStefan Agner #else
6734fd5d25SSimon Glass 	u32 *page_table = (u32 *)gd->arch.tlb_addr;
68*c5b3cabfSStefan Agner #endif
6925026fa9SThierry Reding 	unsigned long upto, end;
700dde7f53SSimon Glass 
710dde7f53SSimon Glass 	end = ALIGN(start + size, MMU_SECTION_SIZE) >> MMU_SECTION_SHIFT;
720dde7f53SSimon Glass 	start = start >> MMU_SECTION_SHIFT;
7325026fa9SThierry Reding 	debug("%s: start=%pa, size=%zu, option=%d\n", __func__, &start, size,
740dde7f53SSimon Glass 	      option);
750dde7f53SSimon Glass 	for (upto = start; upto < end; upto++)
760dde7f53SSimon Glass 		set_section_dcache(upto, option);
770dde7f53SSimon Glass 	mmu_page_table_flush((u32)&page_table[start], (u32)&page_table[end]);
780dde7f53SSimon Glass }
790dde7f53SSimon Glass 
8096fdbec2SR Sricharan __weak void dram_bank_mmu_setup(int bank)
810dde7f53SSimon Glass {
82f1d2b313SHeiko Schocher 	bd_t *bd = gd->bd;
83f1d2b313SHeiko Schocher 	int	i;
84f1d2b313SHeiko Schocher 
85f1d2b313SHeiko Schocher 	debug("%s: bank: %d\n", __func__, bank);
86d990f5c8SAlexander Graf 	for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT;
87d990f5c8SAlexander Graf 	     i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) +
88d990f5c8SAlexander Graf 		 (bd->bi_dram[bank].size >> MMU_SECTION_SHIFT);
89f1d2b313SHeiko Schocher 	     i++) {
900dde7f53SSimon Glass #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
910dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_WRITETHROUGH);
92ff7e9700SMarek Vasut #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
93ff7e9700SMarek Vasut 		set_section_dcache(i, DCACHE_WRITEALLOC);
940dde7f53SSimon Glass #else
950dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_WRITEBACK);
960dde7f53SSimon Glass #endif
97f1d2b313SHeiko Schocher 	}
98f1d2b313SHeiko Schocher }
99f1d2b313SHeiko Schocher 
100f1d2b313SHeiko Schocher /* to activate the MMU we need to set up virtual memory: use 1M areas */
101880eff5cSHeiko Schocher static inline void mmu_setup(void)
102880eff5cSHeiko Schocher {
103f1d2b313SHeiko Schocher 	int i;
104880eff5cSHeiko Schocher 	u32 reg;
105880eff5cSHeiko Schocher 
106c2dd0d45SAneesh V 	arm_init_before_mmu();
107880eff5cSHeiko Schocher 	/* Set up an identity-mapping for all 4GB, rw for everyone */
108d990f5c8SAlexander Graf 	for (i = 0; i < ((4096ULL * 1024 * 1024) >> MMU_SECTION_SHIFT); i++)
1090dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_OFF);
110f1d2b313SHeiko Schocher 
111f1d2b313SHeiko Schocher 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
112f1d2b313SHeiko Schocher 		dram_bank_mmu_setup(i);
113f1d2b313SHeiko Schocher 	}
114880eff5cSHeiko Schocher 
115d990f5c8SAlexander Graf #ifdef CONFIG_ARMV7_LPAE
116d990f5c8SAlexander Graf 	/* Set up 4 PTE entries pointing to our 4 1GB page tables */
117d990f5c8SAlexander Graf 	for (i = 0; i < 4; i++) {
118d990f5c8SAlexander Graf 		u64 *page_table = (u64 *)(gd->arch.tlb_addr + (4096 * 4));
119d990f5c8SAlexander Graf 		u64 tpt = gd->arch.tlb_addr + (4096 * i);
120d990f5c8SAlexander Graf 		page_table[i] = tpt | TTB_PAGETABLE;
121d990f5c8SAlexander Graf 	}
122d990f5c8SAlexander Graf 
123d990f5c8SAlexander Graf 	reg = TTBCR_EAE;
124d990f5c8SAlexander Graf #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
125d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WT | TTBCR_IRGN0_WT;
126d990f5c8SAlexander Graf #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
127d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WBWA | TTBCR_IRGN0_WBWA;
128d990f5c8SAlexander Graf #else
129d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WBNWA | TTBCR_IRGN0_WBNWA;
130d990f5c8SAlexander Graf #endif
131d990f5c8SAlexander Graf 
132d990f5c8SAlexander Graf 	if (is_hyp()) {
133d990f5c8SAlexander Graf 		/* Set HCTR to enable LPAE */
134d990f5c8SAlexander Graf 		asm volatile("mcr p15, 4, %0, c2, c0, 2"
135d990f5c8SAlexander Graf 			: : "r" (reg) : "memory");
136d990f5c8SAlexander Graf 		/* Set HTTBR0 */
137d990f5c8SAlexander Graf 		asm volatile("mcrr p15, 4, %0, %1, c2"
138d990f5c8SAlexander Graf 			:
139d990f5c8SAlexander Graf 			: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
140d990f5c8SAlexander Graf 			: "memory");
141d990f5c8SAlexander Graf 		/* Set HMAIR */
142d990f5c8SAlexander Graf 		asm volatile("mcr p15, 4, %0, c10, c2, 0"
143d990f5c8SAlexander Graf 			: : "r" (MEMORY_ATTRIBUTES) : "memory");
144d990f5c8SAlexander Graf 	} else {
145d990f5c8SAlexander Graf 		/* Set TTBCR to enable LPAE */
146d990f5c8SAlexander Graf 		asm volatile("mcr p15, 0, %0, c2, c0, 2"
147d990f5c8SAlexander Graf 			: : "r" (reg) : "memory");
148d990f5c8SAlexander Graf 		/* Set 64-bit TTBR0 */
149d990f5c8SAlexander Graf 		asm volatile("mcrr p15, 0, %0, %1, c2"
150d990f5c8SAlexander Graf 			:
151d990f5c8SAlexander Graf 			: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
152d990f5c8SAlexander Graf 			: "memory");
153d990f5c8SAlexander Graf 		/* Set MAIR */
154d990f5c8SAlexander Graf 		asm volatile("mcr p15, 0, %0, c10, c2, 0"
155d990f5c8SAlexander Graf 			: : "r" (MEMORY_ATTRIBUTES) : "memory");
156d990f5c8SAlexander Graf 	}
157d990f5c8SAlexander Graf #elif defined(CONFIG_CPU_V7)
15897840b5dSBryan Brinsko 	/* Set TTBR0 */
15997840b5dSBryan Brinsko 	reg = gd->arch.tlb_addr & TTBR0_BASE_ADDR_MASK;
16097840b5dSBryan Brinsko #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
16197840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WT | TTBR0_IRGN_WT;
16297840b5dSBryan Brinsko #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
16397840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WBWA | TTBR0_IRGN_WBWA;
16497840b5dSBryan Brinsko #else
16597840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WB | TTBR0_IRGN_WB;
16697840b5dSBryan Brinsko #endif
16797840b5dSBryan Brinsko 	asm volatile("mcr p15, 0, %0, c2, c0, 0"
16897840b5dSBryan Brinsko 		     : : "r" (reg) : "memory");
16997840b5dSBryan Brinsko #else
170880eff5cSHeiko Schocher 	/* Copy the page table address to cp15 */
171880eff5cSHeiko Schocher 	asm volatile("mcr p15, 0, %0, c2, c0, 0"
17234fd5d25SSimon Glass 		     : : "r" (gd->arch.tlb_addr) : "memory");
17397840b5dSBryan Brinsko #endif
174880eff5cSHeiko Schocher 	/* Set the access control to all-supervisor */
175880eff5cSHeiko Schocher 	asm volatile("mcr p15, 0, %0, c3, c0, 0"
176880eff5cSHeiko Schocher 		     : : "r" (~0));
177de63ac27SR Sricharan 
178de63ac27SR Sricharan 	arm_init_domains();
179de63ac27SR Sricharan 
180880eff5cSHeiko Schocher 	/* and enable the mmu */
181880eff5cSHeiko Schocher 	reg = get_cr();	/* get control reg. */
182880eff5cSHeiko Schocher 	cp_delay();
183880eff5cSHeiko Schocher 	set_cr(reg | CR_M);
184ea0364f1SPeter Tyser }
185ea0364f1SPeter Tyser 
186e05f0079SAneesh V static int mmu_enabled(void)
187e05f0079SAneesh V {
188e05f0079SAneesh V 	return get_cr() & CR_M;
189e05f0079SAneesh V }
190e05f0079SAneesh V 
191ea0364f1SPeter Tyser /* cache_bit must be either CR_I or CR_C */
192ea0364f1SPeter Tyser static void cache_enable(uint32_t cache_bit)
193ea0364f1SPeter Tyser {
194ea0364f1SPeter Tyser 	uint32_t reg;
195ea0364f1SPeter Tyser 
196880eff5cSHeiko Schocher 	/* The data cache is not active unless the mmu is enabled too */
197e05f0079SAneesh V 	if ((cache_bit == CR_C) && !mmu_enabled())
198880eff5cSHeiko Schocher 		mmu_setup();
199ea0364f1SPeter Tyser 	reg = get_cr();	/* get control reg. */
200ea0364f1SPeter Tyser 	cp_delay();
201ea0364f1SPeter Tyser 	set_cr(reg | cache_bit);
202ea0364f1SPeter Tyser }
203ea0364f1SPeter Tyser 
204ea0364f1SPeter Tyser /* cache_bit must be either CR_I or CR_C */
205ea0364f1SPeter Tyser static void cache_disable(uint32_t cache_bit)
206ea0364f1SPeter Tyser {
207ea0364f1SPeter Tyser 	uint32_t reg;
208ea0364f1SPeter Tyser 
209d702b081SSRICHARAN R 	reg = get_cr();
210d702b081SSRICHARAN R 	cp_delay();
211d702b081SSRICHARAN R 
212880eff5cSHeiko Schocher 	if (cache_bit == CR_C) {
213f1d2b313SHeiko Schocher 		/* if cache isn;t enabled no need to disable */
214f1d2b313SHeiko Schocher 		if ((reg & CR_C) != CR_C)
215f1d2b313SHeiko Schocher 			return;
216880eff5cSHeiko Schocher 		/* if disabling data cache, disable mmu too */
217880eff5cSHeiko Schocher 		cache_bit |= CR_M;
218880eff5cSHeiko Schocher 	}
21944df5e8dSArun Mankuzhi 	reg = get_cr();
22044df5e8dSArun Mankuzhi 	cp_delay();
22144df5e8dSArun Mankuzhi 	if (cache_bit == (CR_C | CR_M))
22244df5e8dSArun Mankuzhi 		flush_dcache_all();
223ea0364f1SPeter Tyser 	set_cr(reg & ~cache_bit);
224ea0364f1SPeter Tyser }
225ea0364f1SPeter Tyser #endif
226ea0364f1SPeter Tyser 
227e47f2db5SAneesh V #ifdef CONFIG_SYS_ICACHE_OFF
228ea0364f1SPeter Tyser void icache_enable (void)
229ea0364f1SPeter Tyser {
230ea0364f1SPeter Tyser 	return;
231ea0364f1SPeter Tyser }
232ea0364f1SPeter Tyser 
233ea0364f1SPeter Tyser void icache_disable (void)
234ea0364f1SPeter Tyser {
235ea0364f1SPeter Tyser 	return;
236ea0364f1SPeter Tyser }
237ea0364f1SPeter Tyser 
238ea0364f1SPeter Tyser int icache_status (void)
239ea0364f1SPeter Tyser {
240ea0364f1SPeter Tyser 	return 0;					/* always off */
241ea0364f1SPeter Tyser }
242ea0364f1SPeter Tyser #else
243ea0364f1SPeter Tyser void icache_enable(void)
244ea0364f1SPeter Tyser {
245ea0364f1SPeter Tyser 	cache_enable(CR_I);
246ea0364f1SPeter Tyser }
247ea0364f1SPeter Tyser 
248ea0364f1SPeter Tyser void icache_disable(void)
249ea0364f1SPeter Tyser {
250ea0364f1SPeter Tyser 	cache_disable(CR_I);
251ea0364f1SPeter Tyser }
252ea0364f1SPeter Tyser 
253ea0364f1SPeter Tyser int icache_status(void)
254ea0364f1SPeter Tyser {
255ea0364f1SPeter Tyser 	return (get_cr() & CR_I) != 0;
256ea0364f1SPeter Tyser }
257ea0364f1SPeter Tyser #endif
258ea0364f1SPeter Tyser 
259e47f2db5SAneesh V #ifdef CONFIG_SYS_DCACHE_OFF
260ea0364f1SPeter Tyser void dcache_enable (void)
261ea0364f1SPeter Tyser {
262ea0364f1SPeter Tyser 	return;
263ea0364f1SPeter Tyser }
264ea0364f1SPeter Tyser 
265ea0364f1SPeter Tyser void dcache_disable (void)
266ea0364f1SPeter Tyser {
267ea0364f1SPeter Tyser 	return;
268ea0364f1SPeter Tyser }
269ea0364f1SPeter Tyser 
270ea0364f1SPeter Tyser int dcache_status (void)
271ea0364f1SPeter Tyser {
272ea0364f1SPeter Tyser 	return 0;					/* always off */
273ea0364f1SPeter Tyser }
274ea0364f1SPeter Tyser #else
275ea0364f1SPeter Tyser void dcache_enable(void)
276ea0364f1SPeter Tyser {
277ea0364f1SPeter Tyser 	cache_enable(CR_C);
278ea0364f1SPeter Tyser }
279ea0364f1SPeter Tyser 
280ea0364f1SPeter Tyser void dcache_disable(void)
281ea0364f1SPeter Tyser {
282ea0364f1SPeter Tyser 	cache_disable(CR_C);
283ea0364f1SPeter Tyser }
284ea0364f1SPeter Tyser 
285ea0364f1SPeter Tyser int dcache_status(void)
286ea0364f1SPeter Tyser {
287ea0364f1SPeter Tyser 	return (get_cr() & CR_C) != 0;
288ea0364f1SPeter Tyser }
289ea0364f1SPeter Tyser #endif
290