xref: /rk3399_rockchip-uboot/arch/arm/lib/cache-cp15.c (revision 579dfca2ef2fdff93ae78a942fef49f3d1da3f8c)
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
698f894a4dSStefan 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;
7406d43c80SKeerthy #ifdef CONFIG_ARMV7_LPAE
7506d43c80SKeerthy 	debug("%s: start=%pa, size=%zu, option=%llx\n", __func__, &start, size,
7606d43c80SKeerthy 	      option);
7706d43c80SKeerthy #else
782b373cb8SKeerthy 	debug("%s: start=%pa, size=%zu, option=0x%x\n", __func__, &start, size,
790dde7f53SSimon Glass 	      option);
8006d43c80SKeerthy #endif
810dde7f53SSimon Glass 	for (upto = start; upto < end; upto++)
820dde7f53SSimon Glass 		set_section_dcache(upto, option);
838f894a4dSStefan Agner 
848f894a4dSStefan Agner 	/*
858f894a4dSStefan Agner 	 * Make sure range is cache line aligned
868f894a4dSStefan Agner 	 * Only CPU maintains page tables, hence it is safe to always
878f894a4dSStefan Agner 	 * flush complete cache lines...
888f894a4dSStefan Agner 	 */
898f894a4dSStefan Agner 
908f894a4dSStefan Agner 	startpt = (unsigned long)&page_table[start];
918f894a4dSStefan Agner 	startpt &= ~(CONFIG_SYS_CACHELINE_SIZE - 1);
928f894a4dSStefan Agner 	stoppt = (unsigned long)&page_table[end];
938f894a4dSStefan Agner 	stoppt = ALIGN(stoppt, CONFIG_SYS_CACHELINE_SIZE);
948f894a4dSStefan Agner 	mmu_page_table_flush(startpt, stoppt);
950dde7f53SSimon Glass }
960dde7f53SSimon Glass 
9796fdbec2SR Sricharan __weak void dram_bank_mmu_setup(int bank)
980dde7f53SSimon Glass {
99f1d2b313SHeiko Schocher 	bd_t *bd = gd->bd;
100f1d2b313SHeiko Schocher 	int	i;
101f1d2b313SHeiko Schocher 
102f1d2b313SHeiko Schocher 	debug("%s: bank: %d\n", __func__, bank);
103d990f5c8SAlexander Graf 	for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT;
104d990f5c8SAlexander Graf 	     i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) +
105d990f5c8SAlexander Graf 		 (bd->bi_dram[bank].size >> MMU_SECTION_SHIFT);
106f1d2b313SHeiko Schocher 	     i++) {
1070dde7f53SSimon Glass #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
1080dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_WRITETHROUGH);
109ff7e9700SMarek Vasut #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
110ff7e9700SMarek Vasut 		set_section_dcache(i, DCACHE_WRITEALLOC);
1110dde7f53SSimon Glass #else
1120dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_WRITEBACK);
1130dde7f53SSimon Glass #endif
114f1d2b313SHeiko Schocher 	}
115f1d2b313SHeiko Schocher }
116f1d2b313SHeiko Schocher 
117f1d2b313SHeiko Schocher /* to activate the MMU we need to set up virtual memory: use 1M areas */
118880eff5cSHeiko Schocher static inline void mmu_setup(void)
119880eff5cSHeiko Schocher {
120f1d2b313SHeiko Schocher 	int i;
121880eff5cSHeiko Schocher 	u32 reg;
122880eff5cSHeiko Schocher 
123c2dd0d45SAneesh V 	arm_init_before_mmu();
124880eff5cSHeiko Schocher 	/* Set up an identity-mapping for all 4GB, rw for everyone */
125d990f5c8SAlexander Graf 	for (i = 0; i < ((4096ULL * 1024 * 1024) >> MMU_SECTION_SHIFT); i++)
1260dde7f53SSimon Glass 		set_section_dcache(i, DCACHE_OFF);
127f1d2b313SHeiko Schocher 
128f1d2b313SHeiko Schocher 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
129f1d2b313SHeiko Schocher 		dram_bank_mmu_setup(i);
130f1d2b313SHeiko Schocher 	}
131880eff5cSHeiko Schocher 
132d990f5c8SAlexander Graf #ifdef CONFIG_ARMV7_LPAE
133d990f5c8SAlexander Graf 	/* Set up 4 PTE entries pointing to our 4 1GB page tables */
134d990f5c8SAlexander Graf 	for (i = 0; i < 4; i++) {
135d990f5c8SAlexander Graf 		u64 *page_table = (u64 *)(gd->arch.tlb_addr + (4096 * 4));
136d990f5c8SAlexander Graf 		u64 tpt = gd->arch.tlb_addr + (4096 * i);
137d990f5c8SAlexander Graf 		page_table[i] = tpt | TTB_PAGETABLE;
138d990f5c8SAlexander Graf 	}
139d990f5c8SAlexander Graf 
140d990f5c8SAlexander Graf 	reg = TTBCR_EAE;
141d990f5c8SAlexander Graf #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
142d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WT | TTBCR_IRGN0_WT;
143d990f5c8SAlexander Graf #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
144d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WBWA | TTBCR_IRGN0_WBWA;
145d990f5c8SAlexander Graf #else
146d990f5c8SAlexander Graf 	reg |= TTBCR_ORGN0_WBNWA | TTBCR_IRGN0_WBNWA;
147d990f5c8SAlexander Graf #endif
148d990f5c8SAlexander Graf 
149d990f5c8SAlexander Graf 	if (is_hyp()) {
150*579dfca2SSimon Glass 		/* Set HTCR to enable LPAE */
151d990f5c8SAlexander Graf 		asm volatile("mcr p15, 4, %0, c2, c0, 2"
152d990f5c8SAlexander Graf 			: : "r" (reg) : "memory");
153d990f5c8SAlexander Graf 		/* Set HTTBR0 */
154d990f5c8SAlexander Graf 		asm volatile("mcrr p15, 4, %0, %1, c2"
155d990f5c8SAlexander Graf 			:
156d990f5c8SAlexander Graf 			: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
157d990f5c8SAlexander Graf 			: "memory");
158d990f5c8SAlexander Graf 		/* Set HMAIR */
159d990f5c8SAlexander Graf 		asm volatile("mcr p15, 4, %0, c10, c2, 0"
160d990f5c8SAlexander Graf 			: : "r" (MEMORY_ATTRIBUTES) : "memory");
161d990f5c8SAlexander Graf 	} else {
162d990f5c8SAlexander Graf 		/* Set TTBCR to enable LPAE */
163d990f5c8SAlexander Graf 		asm volatile("mcr p15, 0, %0, c2, c0, 2"
164d990f5c8SAlexander Graf 			: : "r" (reg) : "memory");
165d990f5c8SAlexander Graf 		/* Set 64-bit TTBR0 */
166d990f5c8SAlexander Graf 		asm volatile("mcrr p15, 0, %0, %1, c2"
167d990f5c8SAlexander Graf 			:
168d990f5c8SAlexander Graf 			: "r"(gd->arch.tlb_addr + (4096 * 4)), "r"(0)
169d990f5c8SAlexander Graf 			: "memory");
170d990f5c8SAlexander Graf 		/* Set MAIR */
171d990f5c8SAlexander Graf 		asm volatile("mcr p15, 0, %0, c10, c2, 0"
172d990f5c8SAlexander Graf 			: : "r" (MEMORY_ATTRIBUTES) : "memory");
173d990f5c8SAlexander Graf 	}
174d990f5c8SAlexander Graf #elif defined(CONFIG_CPU_V7)
17597840b5dSBryan Brinsko 	/* Set TTBR0 */
17697840b5dSBryan Brinsko 	reg = gd->arch.tlb_addr & TTBR0_BASE_ADDR_MASK;
17797840b5dSBryan Brinsko #if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
17897840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WT | TTBR0_IRGN_WT;
17997840b5dSBryan Brinsko #elif defined(CONFIG_SYS_ARM_CACHE_WRITEALLOC)
18097840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WBWA | TTBR0_IRGN_WBWA;
18197840b5dSBryan Brinsko #else
18297840b5dSBryan Brinsko 	reg |= TTBR0_RGN_WB | TTBR0_IRGN_WB;
18397840b5dSBryan Brinsko #endif
18497840b5dSBryan Brinsko 	asm volatile("mcr p15, 0, %0, c2, c0, 0"
18597840b5dSBryan Brinsko 		     : : "r" (reg) : "memory");
18697840b5dSBryan Brinsko #else
187880eff5cSHeiko Schocher 	/* Copy the page table address to cp15 */
188880eff5cSHeiko Schocher 	asm volatile("mcr p15, 0, %0, c2, c0, 0"
18934fd5d25SSimon Glass 		     : : "r" (gd->arch.tlb_addr) : "memory");
19097840b5dSBryan Brinsko #endif
191880eff5cSHeiko Schocher 	/* Set the access control to all-supervisor */
192880eff5cSHeiko Schocher 	asm volatile("mcr p15, 0, %0, c3, c0, 0"
193880eff5cSHeiko Schocher 		     : : "r" (~0));
194de63ac27SR Sricharan 
195de63ac27SR Sricharan 	arm_init_domains();
196de63ac27SR Sricharan 
197880eff5cSHeiko Schocher 	/* and enable the mmu */
198880eff5cSHeiko Schocher 	reg = get_cr();	/* get control reg. */
199880eff5cSHeiko Schocher 	cp_delay();
200880eff5cSHeiko Schocher 	set_cr(reg | CR_M);
201ea0364f1SPeter Tyser }
202ea0364f1SPeter Tyser 
203e05f0079SAneesh V static int mmu_enabled(void)
204e05f0079SAneesh V {
205e05f0079SAneesh V 	return get_cr() & CR_M;
206e05f0079SAneesh V }
207e05f0079SAneesh V 
208ea0364f1SPeter Tyser /* cache_bit must be either CR_I or CR_C */
209ea0364f1SPeter Tyser static void cache_enable(uint32_t cache_bit)
210ea0364f1SPeter Tyser {
211ea0364f1SPeter Tyser 	uint32_t reg;
212ea0364f1SPeter Tyser 
213880eff5cSHeiko Schocher 	/* The data cache is not active unless the mmu is enabled too */
214e05f0079SAneesh V 	if ((cache_bit == CR_C) && !mmu_enabled())
215880eff5cSHeiko Schocher 		mmu_setup();
216ea0364f1SPeter Tyser 	reg = get_cr();	/* get control reg. */
217ea0364f1SPeter Tyser 	cp_delay();
218ea0364f1SPeter Tyser 	set_cr(reg | cache_bit);
219ea0364f1SPeter Tyser }
220ea0364f1SPeter Tyser 
221ea0364f1SPeter Tyser /* cache_bit must be either CR_I or CR_C */
222ea0364f1SPeter Tyser static void cache_disable(uint32_t cache_bit)
223ea0364f1SPeter Tyser {
224ea0364f1SPeter Tyser 	uint32_t reg;
225ea0364f1SPeter Tyser 
226d702b081SSRICHARAN R 	reg = get_cr();
227d702b081SSRICHARAN R 	cp_delay();
228d702b081SSRICHARAN R 
229880eff5cSHeiko Schocher 	if (cache_bit == CR_C) {
230f1d2b313SHeiko Schocher 		/* if cache isn;t enabled no need to disable */
231f1d2b313SHeiko Schocher 		if ((reg & CR_C) != CR_C)
232f1d2b313SHeiko Schocher 			return;
233880eff5cSHeiko Schocher 		/* if disabling data cache, disable mmu too */
234880eff5cSHeiko Schocher 		cache_bit |= CR_M;
235880eff5cSHeiko Schocher 	}
23644df5e8dSArun Mankuzhi 	reg = get_cr();
23744df5e8dSArun Mankuzhi 	cp_delay();
23844df5e8dSArun Mankuzhi 	if (cache_bit == (CR_C | CR_M))
23944df5e8dSArun Mankuzhi 		flush_dcache_all();
240ea0364f1SPeter Tyser 	set_cr(reg & ~cache_bit);
241ea0364f1SPeter Tyser }
242ea0364f1SPeter Tyser #endif
243ea0364f1SPeter Tyser 
244e47f2db5SAneesh V #ifdef CONFIG_SYS_ICACHE_OFF
245ea0364f1SPeter Tyser void icache_enable (void)
246ea0364f1SPeter Tyser {
247ea0364f1SPeter Tyser 	return;
248ea0364f1SPeter Tyser }
249ea0364f1SPeter Tyser 
250ea0364f1SPeter Tyser void icache_disable (void)
251ea0364f1SPeter Tyser {
252ea0364f1SPeter Tyser 	return;
253ea0364f1SPeter Tyser }
254ea0364f1SPeter Tyser 
255ea0364f1SPeter Tyser int icache_status (void)
256ea0364f1SPeter Tyser {
257ea0364f1SPeter Tyser 	return 0;					/* always off */
258ea0364f1SPeter Tyser }
259ea0364f1SPeter Tyser #else
260ea0364f1SPeter Tyser void icache_enable(void)
261ea0364f1SPeter Tyser {
262ea0364f1SPeter Tyser 	cache_enable(CR_I);
263ea0364f1SPeter Tyser }
264ea0364f1SPeter Tyser 
265ea0364f1SPeter Tyser void icache_disable(void)
266ea0364f1SPeter Tyser {
267ea0364f1SPeter Tyser 	cache_disable(CR_I);
268ea0364f1SPeter Tyser }
269ea0364f1SPeter Tyser 
270ea0364f1SPeter Tyser int icache_status(void)
271ea0364f1SPeter Tyser {
272ea0364f1SPeter Tyser 	return (get_cr() & CR_I) != 0;
273ea0364f1SPeter Tyser }
274ea0364f1SPeter Tyser #endif
275ea0364f1SPeter Tyser 
276e47f2db5SAneesh V #ifdef CONFIG_SYS_DCACHE_OFF
277ea0364f1SPeter Tyser void dcache_enable (void)
278ea0364f1SPeter Tyser {
279ea0364f1SPeter Tyser 	return;
280ea0364f1SPeter Tyser }
281ea0364f1SPeter Tyser 
282ea0364f1SPeter Tyser void dcache_disable (void)
283ea0364f1SPeter Tyser {
284ea0364f1SPeter Tyser 	return;
285ea0364f1SPeter Tyser }
286ea0364f1SPeter Tyser 
287ea0364f1SPeter Tyser int dcache_status (void)
288ea0364f1SPeter Tyser {
289ea0364f1SPeter Tyser 	return 0;					/* always off */
290ea0364f1SPeter Tyser }
291ea0364f1SPeter Tyser #else
292ea0364f1SPeter Tyser void dcache_enable(void)
293ea0364f1SPeter Tyser {
294ea0364f1SPeter Tyser 	cache_enable(CR_C);
295ea0364f1SPeter Tyser }
296ea0364f1SPeter Tyser 
297ea0364f1SPeter Tyser void dcache_disable(void)
298ea0364f1SPeter Tyser {
299ea0364f1SPeter Tyser 	cache_disable(CR_C);
300ea0364f1SPeter Tyser }
301ea0364f1SPeter Tyser 
302ea0364f1SPeter Tyser int dcache_status(void)
303ea0364f1SPeter Tyser {
304ea0364f1SPeter Tyser 	return (get_cr() & CR_C) != 0;
305ea0364f1SPeter Tyser }
306ea0364f1SPeter Tyser #endif
307