xref: /rk3399_rockchip-uboot/arch/arm/cpu/armv8/cache_v8.c (revision 8b19dff579759719b83a3dcbeefecd774077dc08)
10ae76531SDavid Feng /*
20ae76531SDavid Feng  * (C) Copyright 2013
30ae76531SDavid Feng  * David Feng <fenghua@phytium.com.cn>
40ae76531SDavid Feng  *
50ae76531SDavid Feng  * SPDX-License-Identifier:	GPL-2.0+
60ae76531SDavid Feng  */
70ae76531SDavid Feng 
80ae76531SDavid Feng #include <common.h>
90ae76531SDavid Feng #include <asm/system.h>
100ae76531SDavid Feng #include <asm/armv8/mmu.h>
110ae76531SDavid Feng 
120ae76531SDavid Feng DECLARE_GLOBAL_DATA_PTR;
130ae76531SDavid Feng 
140ae76531SDavid Feng #ifndef CONFIG_SYS_DCACHE_OFF
1522932ffcSYork Sun void set_pgtable_section(u64 *page_table, u64 index, u64 section,
1622932ffcSYork Sun 			 u64 memory_type)
170ae76531SDavid Feng {
180ae76531SDavid Feng 	u64 value;
190ae76531SDavid Feng 
2022932ffcSYork Sun 	value = section | PMD_TYPE_SECT | PMD_SECT_AF;
210ae76531SDavid Feng 	value |= PMD_ATTRINDX(memory_type);
2222932ffcSYork Sun 	page_table[index] = value;
230ae76531SDavid Feng }
240ae76531SDavid Feng 
250ae76531SDavid Feng /* to activate the MMU we need to set up virtual memory */
260ae76531SDavid Feng static void mmu_setup(void)
270ae76531SDavid Feng {
280ae76531SDavid Feng 	bd_t *bd = gd->bd;
29*8b19dff5SThierry Reding 	u64 *page_table = (u64 *)gd->arch.tlb_addr, i, j;
30*8b19dff5SThierry Reding 	int el;
310ae76531SDavid Feng 
320ae76531SDavid Feng 	/* Setup an identity-mapping for all spaces */
3322932ffcSYork Sun 	for (i = 0; i < (PGTABLE_SIZE >> 3); i++) {
3422932ffcSYork Sun 		set_pgtable_section(page_table, i, i << SECTION_SHIFT,
3522932ffcSYork Sun 				    MT_DEVICE_NGNRNE);
3622932ffcSYork Sun 	}
370ae76531SDavid Feng 
380ae76531SDavid Feng 	/* Setup an identity-mapping for all RAM space */
390ae76531SDavid Feng 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
400ae76531SDavid Feng 		ulong start = bd->bi_dram[i].start;
410ae76531SDavid Feng 		ulong end = bd->bi_dram[i].start + bd->bi_dram[i].size;
420ae76531SDavid Feng 		for (j = start >> SECTION_SHIFT;
430ae76531SDavid Feng 		     j < end >> SECTION_SHIFT; j++) {
4422932ffcSYork Sun 			set_pgtable_section(page_table, j, j << SECTION_SHIFT,
4522932ffcSYork Sun 					    MT_NORMAL);
460ae76531SDavid Feng 		}
470ae76531SDavid Feng 	}
480ae76531SDavid Feng 
490ae76531SDavid Feng 	/* load TTBR0 */
500ae76531SDavid Feng 	el = current_el();
51f5222cfdSYork Sun 	if (el == 1) {
5222932ffcSYork Sun 		set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
5322932ffcSYork Sun 				  TCR_FLAGS | TCR_EL1_IPS_BITS,
5422932ffcSYork Sun 				  MEMORY_ATTRIBUTES);
55f5222cfdSYork Sun 	} else if (el == 2) {
5622932ffcSYork Sun 		set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
5722932ffcSYork Sun 				  TCR_FLAGS | TCR_EL2_IPS_BITS,
5822932ffcSYork Sun 				  MEMORY_ATTRIBUTES);
59f5222cfdSYork Sun 	} else {
6022932ffcSYork Sun 		set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
6122932ffcSYork Sun 				  TCR_FLAGS | TCR_EL3_IPS_BITS,
6222932ffcSYork Sun 				  MEMORY_ATTRIBUTES);
63f5222cfdSYork Sun 	}
640ae76531SDavid Feng 	/* enable the mmu */
650ae76531SDavid Feng 	set_sctlr(get_sctlr() | CR_M);
660ae76531SDavid Feng }
670ae76531SDavid Feng 
680ae76531SDavid Feng /*
690ae76531SDavid Feng  * Performs a invalidation of the entire data cache at all levels
700ae76531SDavid Feng  */
710ae76531SDavid Feng void invalidate_dcache_all(void)
720ae76531SDavid Feng {
731e6ad55cSYork Sun 	__asm_invalidate_dcache_all();
740ae76531SDavid Feng }
750ae76531SDavid Feng 
760ae76531SDavid Feng /*
77dcd468b8SYork Sun  * Performs a clean & invalidation of the entire data cache at all levels.
78dcd468b8SYork Sun  * This function needs to be inline to avoid using stack.
79dcd468b8SYork Sun  * __asm_flush_l3_cache return status of timeout
800ae76531SDavid Feng  */
81dcd468b8SYork Sun inline void flush_dcache_all(void)
820ae76531SDavid Feng {
83dcd468b8SYork Sun 	int ret;
84dcd468b8SYork Sun 
850ae76531SDavid Feng 	__asm_flush_dcache_all();
86dcd468b8SYork Sun 	ret = __asm_flush_l3_cache();
87dcd468b8SYork Sun 	if (ret)
88dcd468b8SYork Sun 		debug("flushing dcache returns 0x%x\n", ret);
89dcd468b8SYork Sun 	else
90dcd468b8SYork Sun 		debug("flushing dcache successfully.\n");
910ae76531SDavid Feng }
920ae76531SDavid Feng 
930ae76531SDavid Feng /*
940ae76531SDavid Feng  * Invalidates range in all levels of D-cache/unified cache
950ae76531SDavid Feng  */
960ae76531SDavid Feng void invalidate_dcache_range(unsigned long start, unsigned long stop)
970ae76531SDavid Feng {
980ae76531SDavid Feng 	__asm_flush_dcache_range(start, stop);
990ae76531SDavid Feng }
1000ae76531SDavid Feng 
1010ae76531SDavid Feng /*
1020ae76531SDavid Feng  * Flush range(clean & invalidate) from all levels of D-cache/unified cache
1030ae76531SDavid Feng  */
1040ae76531SDavid Feng void flush_dcache_range(unsigned long start, unsigned long stop)
1050ae76531SDavid Feng {
1060ae76531SDavid Feng 	__asm_flush_dcache_range(start, stop);
1070ae76531SDavid Feng }
1080ae76531SDavid Feng 
1090ae76531SDavid Feng void dcache_enable(void)
1100ae76531SDavid Feng {
1110ae76531SDavid Feng 	/* The data cache is not active unless the mmu is enabled */
1120ae76531SDavid Feng 	if (!(get_sctlr() & CR_M)) {
1130ae76531SDavid Feng 		invalidate_dcache_all();
1140ae76531SDavid Feng 		__asm_invalidate_tlb_all();
1150ae76531SDavid Feng 		mmu_setup();
1160ae76531SDavid Feng 	}
1170ae76531SDavid Feng 
1180ae76531SDavid Feng 	set_sctlr(get_sctlr() | CR_C);
1190ae76531SDavid Feng }
1200ae76531SDavid Feng 
1210ae76531SDavid Feng void dcache_disable(void)
1220ae76531SDavid Feng {
1230ae76531SDavid Feng 	uint32_t sctlr;
1240ae76531SDavid Feng 
1250ae76531SDavid Feng 	sctlr = get_sctlr();
1260ae76531SDavid Feng 
1270ae76531SDavid Feng 	/* if cache isn't enabled no need to disable */
1280ae76531SDavid Feng 	if (!(sctlr & CR_C))
1290ae76531SDavid Feng 		return;
1300ae76531SDavid Feng 
1310ae76531SDavid Feng 	set_sctlr(sctlr & ~(CR_C|CR_M));
1320ae76531SDavid Feng 
1330ae76531SDavid Feng 	flush_dcache_all();
1340ae76531SDavid Feng 	__asm_invalidate_tlb_all();
1350ae76531SDavid Feng }
1360ae76531SDavid Feng 
1370ae76531SDavid Feng int dcache_status(void)
1380ae76531SDavid Feng {
1390ae76531SDavid Feng 	return (get_sctlr() & CR_C) != 0;
1400ae76531SDavid Feng }
1410ae76531SDavid Feng 
1420ae76531SDavid Feng #else	/* CONFIG_SYS_DCACHE_OFF */
1430ae76531SDavid Feng 
1440ae76531SDavid Feng void invalidate_dcache_all(void)
1450ae76531SDavid Feng {
1460ae76531SDavid Feng }
1470ae76531SDavid Feng 
1480ae76531SDavid Feng void flush_dcache_all(void)
1490ae76531SDavid Feng {
1500ae76531SDavid Feng }
1510ae76531SDavid Feng 
1520ae76531SDavid Feng void invalidate_dcache_range(unsigned long start, unsigned long stop)
1530ae76531SDavid Feng {
1540ae76531SDavid Feng }
1550ae76531SDavid Feng 
1560ae76531SDavid Feng void flush_dcache_range(unsigned long start, unsigned long stop)
1570ae76531SDavid Feng {
1580ae76531SDavid Feng }
1590ae76531SDavid Feng 
1600ae76531SDavid Feng void dcache_enable(void)
1610ae76531SDavid Feng {
1620ae76531SDavid Feng }
1630ae76531SDavid Feng 
1640ae76531SDavid Feng void dcache_disable(void)
1650ae76531SDavid Feng {
1660ae76531SDavid Feng }
1670ae76531SDavid Feng 
1680ae76531SDavid Feng int dcache_status(void)
1690ae76531SDavid Feng {
1700ae76531SDavid Feng 	return 0;
1710ae76531SDavid Feng }
1720ae76531SDavid Feng 
1730ae76531SDavid Feng #endif	/* CONFIG_SYS_DCACHE_OFF */
1740ae76531SDavid Feng 
1750ae76531SDavid Feng #ifndef CONFIG_SYS_ICACHE_OFF
1760ae76531SDavid Feng 
1770ae76531SDavid Feng void icache_enable(void)
1780ae76531SDavid Feng {
1791e6ad55cSYork Sun 	__asm_invalidate_icache_all();
1800ae76531SDavid Feng 	set_sctlr(get_sctlr() | CR_I);
1810ae76531SDavid Feng }
1820ae76531SDavid Feng 
1830ae76531SDavid Feng void icache_disable(void)
1840ae76531SDavid Feng {
1850ae76531SDavid Feng 	set_sctlr(get_sctlr() & ~CR_I);
1860ae76531SDavid Feng }
1870ae76531SDavid Feng 
1880ae76531SDavid Feng int icache_status(void)
1890ae76531SDavid Feng {
1900ae76531SDavid Feng 	return (get_sctlr() & CR_I) != 0;
1910ae76531SDavid Feng }
1920ae76531SDavid Feng 
1930ae76531SDavid Feng void invalidate_icache_all(void)
1940ae76531SDavid Feng {
1950ae76531SDavid Feng 	__asm_invalidate_icache_all();
1960ae76531SDavid Feng }
1970ae76531SDavid Feng 
1980ae76531SDavid Feng #else	/* CONFIG_SYS_ICACHE_OFF */
1990ae76531SDavid Feng 
2000ae76531SDavid Feng void icache_enable(void)
2010ae76531SDavid Feng {
2020ae76531SDavid Feng }
2030ae76531SDavid Feng 
2040ae76531SDavid Feng void icache_disable(void)
2050ae76531SDavid Feng {
2060ae76531SDavid Feng }
2070ae76531SDavid Feng 
2080ae76531SDavid Feng int icache_status(void)
2090ae76531SDavid Feng {
2100ae76531SDavid Feng 	return 0;
2110ae76531SDavid Feng }
2120ae76531SDavid Feng 
2130ae76531SDavid Feng void invalidate_icache_all(void)
2140ae76531SDavid Feng {
2150ae76531SDavid Feng }
2160ae76531SDavid Feng 
2170ae76531SDavid Feng #endif	/* CONFIG_SYS_ICACHE_OFF */
2180ae76531SDavid Feng 
2190ae76531SDavid Feng /*
2200ae76531SDavid Feng  * Enable dCache & iCache, whether cache is actually enabled
2210ae76531SDavid Feng  * depend on CONFIG_SYS_DCACHE_OFF and CONFIG_SYS_ICACHE_OFF
2220ae76531SDavid Feng  */
2232f78eae5SYork Sun void __weak enable_caches(void)
2240ae76531SDavid Feng {
2250ae76531SDavid Feng 	icache_enable();
2260ae76531SDavid Feng 	dcache_enable();
2270ae76531SDavid Feng }
2280ae76531SDavid Feng 
2290ae76531SDavid Feng /*
2300ae76531SDavid Feng  * Flush range from all levels of d-cache/unified-cache
2310ae76531SDavid Feng  */
2320ae76531SDavid Feng void flush_cache(unsigned long start, unsigned long size)
2330ae76531SDavid Feng {
2340ae76531SDavid Feng 	flush_dcache_range(start, start + size);
2350ae76531SDavid Feng }
236