xref: /rk3399_rockchip-uboot/arch/arm/cpu/armv8/cache_v8.c (revision 22932ffc03e521130cfd33cae1fc2531eb42604a)
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
15*22932ffcSYork Sun void set_pgtable_section(u64 *page_table, u64 index, u64 section,
16*22932ffcSYork Sun 			 u64 memory_type)
170ae76531SDavid Feng {
180ae76531SDavid Feng 	u64 value;
190ae76531SDavid Feng 
20*22932ffcSYork Sun 	value = section | PMD_TYPE_SECT | PMD_SECT_AF;
210ae76531SDavid Feng 	value |= PMD_ATTRINDX(memory_type);
22*22932ffcSYork 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 	int i, j, el;
290ae76531SDavid Feng 	bd_t *bd = gd->bd;
30*22932ffcSYork Sun 	u64 *page_table = (u64 *)gd->arch.tlb_addr;
310ae76531SDavid Feng 
320ae76531SDavid Feng 	/* Setup an identity-mapping for all spaces */
33*22932ffcSYork Sun 	for (i = 0; i < (PGTABLE_SIZE >> 3); i++) {
34*22932ffcSYork Sun 		set_pgtable_section(page_table, i, i << SECTION_SHIFT,
35*22932ffcSYork Sun 				    MT_DEVICE_NGNRNE);
36*22932ffcSYork 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++) {
44*22932ffcSYork Sun 			set_pgtable_section(page_table, j, j << SECTION_SHIFT,
45*22932ffcSYork Sun 					    MT_NORMAL);
460ae76531SDavid Feng 		}
470ae76531SDavid Feng 	}
480ae76531SDavid Feng 
490ae76531SDavid Feng 	/* load TTBR0 */
500ae76531SDavid Feng 	el = current_el();
51f5222cfdSYork Sun 	if (el == 1) {
52*22932ffcSYork Sun 		set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
53*22932ffcSYork Sun 				  TCR_FLAGS | TCR_EL1_IPS_BITS,
54*22932ffcSYork Sun 				  MEMORY_ATTRIBUTES);
55f5222cfdSYork Sun 	} else if (el == 2) {
56*22932ffcSYork Sun 		set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
57*22932ffcSYork Sun 				  TCR_FLAGS | TCR_EL2_IPS_BITS,
58*22932ffcSYork Sun 				  MEMORY_ATTRIBUTES);
59f5222cfdSYork Sun 	} else {
60*22932ffcSYork Sun 		set_ttbr_tcr_mair(el, gd->arch.tlb_addr,
61*22932ffcSYork Sun 				  TCR_FLAGS | TCR_EL3_IPS_BITS,
62*22932ffcSYork 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 /*
770ae76531SDavid Feng  * Performs a clean & invalidation of the entire data cache at all levels
780ae76531SDavid Feng  */
790ae76531SDavid Feng void flush_dcache_all(void)
800ae76531SDavid Feng {
810ae76531SDavid Feng 	__asm_flush_dcache_all();
820ae76531SDavid Feng }
830ae76531SDavid Feng 
840ae76531SDavid Feng /*
850ae76531SDavid Feng  * Invalidates range in all levels of D-cache/unified cache
860ae76531SDavid Feng  */
870ae76531SDavid Feng void invalidate_dcache_range(unsigned long start, unsigned long stop)
880ae76531SDavid Feng {
890ae76531SDavid Feng 	__asm_flush_dcache_range(start, stop);
900ae76531SDavid Feng }
910ae76531SDavid Feng 
920ae76531SDavid Feng /*
930ae76531SDavid Feng  * Flush range(clean & invalidate) from all levels of D-cache/unified cache
940ae76531SDavid Feng  */
950ae76531SDavid Feng void flush_dcache_range(unsigned long start, unsigned long stop)
960ae76531SDavid Feng {
970ae76531SDavid Feng 	__asm_flush_dcache_range(start, stop);
980ae76531SDavid Feng }
990ae76531SDavid Feng 
1000ae76531SDavid Feng void dcache_enable(void)
1010ae76531SDavid Feng {
1020ae76531SDavid Feng 	/* The data cache is not active unless the mmu is enabled */
1030ae76531SDavid Feng 	if (!(get_sctlr() & CR_M)) {
1040ae76531SDavid Feng 		invalidate_dcache_all();
1050ae76531SDavid Feng 		__asm_invalidate_tlb_all();
1060ae76531SDavid Feng 		mmu_setup();
1070ae76531SDavid Feng 	}
1080ae76531SDavid Feng 
1090ae76531SDavid Feng 	set_sctlr(get_sctlr() | CR_C);
1100ae76531SDavid Feng }
1110ae76531SDavid Feng 
1120ae76531SDavid Feng void dcache_disable(void)
1130ae76531SDavid Feng {
1140ae76531SDavid Feng 	uint32_t sctlr;
1150ae76531SDavid Feng 
1160ae76531SDavid Feng 	sctlr = get_sctlr();
1170ae76531SDavid Feng 
1180ae76531SDavid Feng 	/* if cache isn't enabled no need to disable */
1190ae76531SDavid Feng 	if (!(sctlr & CR_C))
1200ae76531SDavid Feng 		return;
1210ae76531SDavid Feng 
1220ae76531SDavid Feng 	set_sctlr(sctlr & ~(CR_C|CR_M));
1230ae76531SDavid Feng 
1240ae76531SDavid Feng 	flush_dcache_all();
1250ae76531SDavid Feng 	__asm_invalidate_tlb_all();
1260ae76531SDavid Feng }
1270ae76531SDavid Feng 
1280ae76531SDavid Feng int dcache_status(void)
1290ae76531SDavid Feng {
1300ae76531SDavid Feng 	return (get_sctlr() & CR_C) != 0;
1310ae76531SDavid Feng }
1320ae76531SDavid Feng 
1330ae76531SDavid Feng #else	/* CONFIG_SYS_DCACHE_OFF */
1340ae76531SDavid Feng 
1350ae76531SDavid Feng void invalidate_dcache_all(void)
1360ae76531SDavid Feng {
1370ae76531SDavid Feng }
1380ae76531SDavid Feng 
1390ae76531SDavid Feng void flush_dcache_all(void)
1400ae76531SDavid Feng {
1410ae76531SDavid Feng }
1420ae76531SDavid Feng 
1430ae76531SDavid Feng void invalidate_dcache_range(unsigned long start, unsigned long stop)
1440ae76531SDavid Feng {
1450ae76531SDavid Feng }
1460ae76531SDavid Feng 
1470ae76531SDavid Feng void flush_dcache_range(unsigned long start, unsigned long stop)
1480ae76531SDavid Feng {
1490ae76531SDavid Feng }
1500ae76531SDavid Feng 
1510ae76531SDavid Feng void dcache_enable(void)
1520ae76531SDavid Feng {
1530ae76531SDavid Feng }
1540ae76531SDavid Feng 
1550ae76531SDavid Feng void dcache_disable(void)
1560ae76531SDavid Feng {
1570ae76531SDavid Feng }
1580ae76531SDavid Feng 
1590ae76531SDavid Feng int dcache_status(void)
1600ae76531SDavid Feng {
1610ae76531SDavid Feng 	return 0;
1620ae76531SDavid Feng }
1630ae76531SDavid Feng 
1640ae76531SDavid Feng #endif	/* CONFIG_SYS_DCACHE_OFF */
1650ae76531SDavid Feng 
1660ae76531SDavid Feng #ifndef CONFIG_SYS_ICACHE_OFF
1670ae76531SDavid Feng 
1680ae76531SDavid Feng void icache_enable(void)
1690ae76531SDavid Feng {
1701e6ad55cSYork Sun 	__asm_invalidate_icache_all();
1710ae76531SDavid Feng 	set_sctlr(get_sctlr() | CR_I);
1720ae76531SDavid Feng }
1730ae76531SDavid Feng 
1740ae76531SDavid Feng void icache_disable(void)
1750ae76531SDavid Feng {
1760ae76531SDavid Feng 	set_sctlr(get_sctlr() & ~CR_I);
1770ae76531SDavid Feng }
1780ae76531SDavid Feng 
1790ae76531SDavid Feng int icache_status(void)
1800ae76531SDavid Feng {
1810ae76531SDavid Feng 	return (get_sctlr() & CR_I) != 0;
1820ae76531SDavid Feng }
1830ae76531SDavid Feng 
1840ae76531SDavid Feng void invalidate_icache_all(void)
1850ae76531SDavid Feng {
1860ae76531SDavid Feng 	__asm_invalidate_icache_all();
1870ae76531SDavid Feng }
1880ae76531SDavid Feng 
1890ae76531SDavid Feng #else	/* CONFIG_SYS_ICACHE_OFF */
1900ae76531SDavid Feng 
1910ae76531SDavid Feng void icache_enable(void)
1920ae76531SDavid Feng {
1930ae76531SDavid Feng }
1940ae76531SDavid Feng 
1950ae76531SDavid Feng void icache_disable(void)
1960ae76531SDavid Feng {
1970ae76531SDavid Feng }
1980ae76531SDavid Feng 
1990ae76531SDavid Feng int icache_status(void)
2000ae76531SDavid Feng {
2010ae76531SDavid Feng 	return 0;
2020ae76531SDavid Feng }
2030ae76531SDavid Feng 
2040ae76531SDavid Feng void invalidate_icache_all(void)
2050ae76531SDavid Feng {
2060ae76531SDavid Feng }
2070ae76531SDavid Feng 
2080ae76531SDavid Feng #endif	/* CONFIG_SYS_ICACHE_OFF */
2090ae76531SDavid Feng 
2100ae76531SDavid Feng /*
2110ae76531SDavid Feng  * Enable dCache & iCache, whether cache is actually enabled
2120ae76531SDavid Feng  * depend on CONFIG_SYS_DCACHE_OFF and CONFIG_SYS_ICACHE_OFF
2130ae76531SDavid Feng  */
2140ae76531SDavid Feng void enable_caches(void)
2150ae76531SDavid Feng {
2160ae76531SDavid Feng 	icache_enable();
2170ae76531SDavid Feng 	dcache_enable();
2180ae76531SDavid Feng }
2190ae76531SDavid Feng 
2200ae76531SDavid Feng /*
2210ae76531SDavid Feng  * Flush range from all levels of d-cache/unified-cache
2220ae76531SDavid Feng  */
2230ae76531SDavid Feng void flush_cache(unsigned long start, unsigned long size)
2240ae76531SDavid Feng {
2250ae76531SDavid Feng 	flush_dcache_range(start, start + size);
2260ae76531SDavid Feng }
227