xref: /openbmc/linux/arch/mips/mm/sc-mips.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
29318c51aSChris Dearman /*
39318c51aSChris Dearman  * Copyright (C) 2006 Chris Dearman (chris@mips.com),
49318c51aSChris Dearman  */
59318c51aSChris Dearman #include <linux/init.h>
69318c51aSChris Dearman #include <linux/kernel.h>
79318c51aSChris Dearman #include <linux/sched.h>
89318c51aSChris Dearman #include <linux/mm.h>
99318c51aSChris Dearman 
1069f24d17SRalf Baechle #include <asm/cpu-type.h>
119318c51aSChris Dearman #include <asm/mipsregs.h>
129318c51aSChris Dearman #include <asm/bcache.h>
139318c51aSChris Dearman #include <asm/cacheops.h>
149318c51aSChris Dearman #include <asm/page.h>
159318c51aSChris Dearman #include <asm/mmu_context.h>
169318c51aSChris Dearman #include <asm/r4kcache.h>
17e83f7e02SPaul Burton #include <asm/mips-cps.h>
181f7412e0SMaarten ter Huurne #include <asm/bootinfo.h>
199318c51aSChris Dearman 
209318c51aSChris Dearman /*
219318c51aSChris Dearman  * MIPS32/MIPS64 L2 cache handling
229318c51aSChris Dearman  */
239318c51aSChris Dearman 
249318c51aSChris Dearman /*
259318c51aSChris Dearman  * Writeback and invalidate the secondary cache before DMA.
269318c51aSChris Dearman  */
mips_sc_wback_inv(unsigned long addr,unsigned long size)279318c51aSChris Dearman static void mips_sc_wback_inv(unsigned long addr, unsigned long size)
289318c51aSChris Dearman {
29a2c2bc4bSAtsushi Nemoto 	blast_scache_range(addr, addr + size);
309318c51aSChris Dearman }
319318c51aSChris Dearman 
329318c51aSChris Dearman /*
339318c51aSChris Dearman  * Invalidate the secondary cache before DMA.
349318c51aSChris Dearman  */
mips_sc_inv(unsigned long addr,unsigned long size)359318c51aSChris Dearman static void mips_sc_inv(unsigned long addr, unsigned long size)
369318c51aSChris Dearman {
3796983ffeSKevin Cernekee 	unsigned long lsize = cpu_scache_line_size();
3896983ffeSKevin Cernekee 	unsigned long almask = ~(lsize - 1);
3996983ffeSKevin Cernekee 
4096983ffeSKevin Cernekee 	cache_op(Hit_Writeback_Inv_SD, addr & almask);
4196983ffeSKevin Cernekee 	cache_op(Hit_Writeback_Inv_SD, (addr + size - 1) & almask);
42a2c2bc4bSAtsushi Nemoto 	blast_inv_scache_range(addr, addr + size);
439318c51aSChris Dearman }
449318c51aSChris Dearman 
mips_sc_enable(void)459318c51aSChris Dearman static void mips_sc_enable(void)
469318c51aSChris Dearman {
479318c51aSChris Dearman 	/* L2 cache is permanently enabled */
489318c51aSChris Dearman }
499318c51aSChris Dearman 
mips_sc_disable(void)509318c51aSChris Dearman static void mips_sc_disable(void)
519318c51aSChris Dearman {
529318c51aSChris Dearman 	/* L2 cache is permanently enabled */
539318c51aSChris Dearman }
549318c51aSChris Dearman 
mips_sc_prefetch_enable(void)554d035516SPaul Burton static void mips_sc_prefetch_enable(void)
564d035516SPaul Burton {
574d035516SPaul Burton 	unsigned long pftctl;
584d035516SPaul Burton 
594d035516SPaul Burton 	if (mips_cm_revision() < CM_REV_CM2_5)
604d035516SPaul Burton 		return;
614d035516SPaul Burton 
624d035516SPaul Burton 	/*
634d035516SPaul Burton 	 * If there is one or more L2 prefetch unit present then enable
644d035516SPaul Burton 	 * prefetching for both code & data, for all ports.
654d035516SPaul Burton 	 */
664d035516SPaul Burton 	pftctl = read_gcr_l2_pft_control();
6793c5bba5SPaul Burton 	if (pftctl & CM_GCR_L2_PFT_CONTROL_NPFT) {
6893c5bba5SPaul Burton 		pftctl &= ~CM_GCR_L2_PFT_CONTROL_PAGEMASK;
6993c5bba5SPaul Burton 		pftctl |= PAGE_MASK & CM_GCR_L2_PFT_CONTROL_PAGEMASK;
7093c5bba5SPaul Burton 		pftctl |= CM_GCR_L2_PFT_CONTROL_PFTEN;
714d035516SPaul Burton 		write_gcr_l2_pft_control(pftctl);
724d035516SPaul Burton 
73846e1913SPaul Burton 		set_gcr_l2_pft_control_b(CM_GCR_L2_PFT_CONTROL_B_PORTID |
74846e1913SPaul Burton 					 CM_GCR_L2_PFT_CONTROL_B_CEN);
754d035516SPaul Burton 	}
764d035516SPaul Burton }
774d035516SPaul Burton 
mips_sc_prefetch_disable(void)784d035516SPaul Burton static void mips_sc_prefetch_disable(void)
794d035516SPaul Burton {
804d035516SPaul Burton 	if (mips_cm_revision() < CM_REV_CM2_5)
814d035516SPaul Burton 		return;
824d035516SPaul Burton 
83846e1913SPaul Burton 	clear_gcr_l2_pft_control(CM_GCR_L2_PFT_CONTROL_PFTEN);
84846e1913SPaul Burton 	clear_gcr_l2_pft_control_b(CM_GCR_L2_PFT_CONTROL_B_PORTID |
85846e1913SPaul Burton 				   CM_GCR_L2_PFT_CONTROL_B_CEN);
864d035516SPaul Burton }
874d035516SPaul Burton 
mips_sc_prefetch_is_enabled(void)884d035516SPaul Burton static bool mips_sc_prefetch_is_enabled(void)
894d035516SPaul Burton {
904d035516SPaul Burton 	unsigned long pftctl;
914d035516SPaul Burton 
924d035516SPaul Burton 	if (mips_cm_revision() < CM_REV_CM2_5)
934d035516SPaul Burton 		return false;
944d035516SPaul Burton 
954d035516SPaul Burton 	pftctl = read_gcr_l2_pft_control();
9693c5bba5SPaul Burton 	if (!(pftctl & CM_GCR_L2_PFT_CONTROL_NPFT))
974d035516SPaul Burton 		return false;
9893c5bba5SPaul Burton 	return !!(pftctl & CM_GCR_L2_PFT_CONTROL_PFTEN);
994d035516SPaul Burton }
1004d035516SPaul Burton 
1019318c51aSChris Dearman static struct bcache_ops mips_sc_ops = {
1029318c51aSChris Dearman 	.bc_enable = mips_sc_enable,
1039318c51aSChris Dearman 	.bc_disable = mips_sc_disable,
1049318c51aSChris Dearman 	.bc_wback_inv = mips_sc_wback_inv,
1054d035516SPaul Burton 	.bc_inv = mips_sc_inv,
1064d035516SPaul Burton 	.bc_prefetch_enable = mips_sc_prefetch_enable,
1074d035516SPaul Burton 	.bc_prefetch_disable = mips_sc_prefetch_disable,
1084d035516SPaul Burton 	.bc_prefetch_is_enabled = mips_sc_prefetch_is_enabled,
1099318c51aSChris Dearman };
1109318c51aSChris Dearman 
111ea31a6b2SKevin Cernekee /*
112ea31a6b2SKevin Cernekee  * Check if the L2 cache controller is activated on a particular platform.
113ea31a6b2SKevin Cernekee  * MTI's L2 controller and the L2 cache controller of Broadcom's BMIPS
114ea31a6b2SKevin Cernekee  * cores both use c0_config2's bit 12 as "L2 Bypass" bit, that is the
115ea31a6b2SKevin Cernekee  * cache being disabled.  However there is no guarantee for this to be
116ea31a6b2SKevin Cernekee  * true on all platforms.  In an act of stupidity the spec defined bits
117ea31a6b2SKevin Cernekee  * 12..15 as implementation defined so below function will eventually have
118ea31a6b2SKevin Cernekee  * to be replaced by a platform specific probe.
119ea31a6b2SKevin Cernekee  */
mips_sc_is_activated(struct cpuinfo_mips * c)120ea31a6b2SKevin Cernekee static inline int mips_sc_is_activated(struct cpuinfo_mips *c)
121ea31a6b2SKevin Cernekee {
122081d835fSKevin Cernekee 	unsigned int config2 = read_c0_config2();
123081d835fSKevin Cernekee 	unsigned int tmp;
124081d835fSKevin Cernekee 
125ea31a6b2SKevin Cernekee 	/* Check the bypass bit (L2B) */
12669f24d17SRalf Baechle 	switch (current_cpu_type()) {
127ea31a6b2SKevin Cernekee 	case CPU_34K:
128ea31a6b2SKevin Cernekee 	case CPU_74K:
129ea31a6b2SKevin Cernekee 	case CPU_1004K:
130442e14a2SSteven J. Hill 	case CPU_1074K:
13126ab96dfSLeonid Yegoshin 	case CPU_INTERAPTIV:
132708ac4b8SLeonid Yegoshin 	case CPU_PROAPTIV:
133aced4cbdSJames Hogan 	case CPU_P5600:
134ea31a6b2SKevin Cernekee 	case CPU_BMIPS5000:
1354695089fSLeonid Yegoshin 	case CPU_QEMU_GENERIC:
1361091bfa2SPaul Burton 	case CPU_P6600:
137ea31a6b2SKevin Cernekee 		if (config2 & (1 << 12))
138ea31a6b2SKevin Cernekee 			return 0;
139ea31a6b2SKevin Cernekee 	}
140ea31a6b2SKevin Cernekee 
141ea31a6b2SKevin Cernekee 	tmp = (config2 >> 4) & 0x0f;
142ea31a6b2SKevin Cernekee 	if (0 < tmp && tmp <= 7)
143ea31a6b2SKevin Cernekee 		c->scache.linesz = 2 << tmp;
144ea31a6b2SKevin Cernekee 	else
145ea31a6b2SKevin Cernekee 		return 0;
146081d835fSKevin Cernekee 	return 1;
147ea31a6b2SKevin Cernekee }
148ea31a6b2SKevin Cernekee 
mips_sc_probe_cm3(void)149*ad4fddefSAnders Roxell static int mips_sc_probe_cm3(void)
1507d53e9c4SPaul Burton {
1517d53e9c4SPaul Burton 	struct cpuinfo_mips *c = &current_cpu_data;
1527d53e9c4SPaul Burton 	unsigned long cfg = read_gcr_l2_config();
1537d53e9c4SPaul Burton 	unsigned long sets, line_sz, assoc;
1547d53e9c4SPaul Burton 
15593c5bba5SPaul Burton 	if (cfg & CM_GCR_L2_CONFIG_BYPASS)
1567d53e9c4SPaul Burton 		return 0;
1577d53e9c4SPaul Burton 
15893c5bba5SPaul Burton 	sets = cfg & CM_GCR_L2_CONFIG_SET_SIZE;
15993c5bba5SPaul Burton 	sets >>= __ffs(CM_GCR_L2_CONFIG_SET_SIZE);
16056fa81fcSGovindraj Raja 	if (sets)
1617d53e9c4SPaul Burton 		c->scache.sets = 64 << sets;
1627d53e9c4SPaul Burton 
16393c5bba5SPaul Burton 	line_sz = cfg & CM_GCR_L2_CONFIG_LINE_SIZE;
16493c5bba5SPaul Burton 	line_sz >>= __ffs(CM_GCR_L2_CONFIG_LINE_SIZE);
16556fa81fcSGovindraj Raja 	if (line_sz)
1667d53e9c4SPaul Burton 		c->scache.linesz = 2 << line_sz;
1677d53e9c4SPaul Burton 
16893c5bba5SPaul Burton 	assoc = cfg & CM_GCR_L2_CONFIG_ASSOC;
16993c5bba5SPaul Burton 	assoc >>= __ffs(CM_GCR_L2_CONFIG_ASSOC);
1707d53e9c4SPaul Burton 	c->scache.ways = assoc + 1;
1717d53e9c4SPaul Burton 	c->scache.waysize = c->scache.sets * c->scache.linesz;
1727d53e9c4SPaul Burton 	c->scache.waybit = __ffs(c->scache.waysize);
1737d53e9c4SPaul Burton 
17456fa81fcSGovindraj Raja 	if (c->scache.linesz) {
1757d53e9c4SPaul Burton 		c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
17648ed33c1SPaul Burton 		c->options |= MIPS_CPU_INCLUSIVE_CACHES;
1777d53e9c4SPaul Burton 		return 1;
1787d53e9c4SPaul Burton 	}
1797d53e9c4SPaul Burton 
18056fa81fcSGovindraj Raja 	return 0;
18156fa81fcSGovindraj Raja }
18256fa81fcSGovindraj Raja 
mips_sc_probe(void)183*ad4fddefSAnders Roxell static inline int mips_sc_probe(void)
1849318c51aSChris Dearman {
1859318c51aSChris Dearman 	struct cpuinfo_mips *c = &current_cpu_data;
1869318c51aSChris Dearman 	unsigned int config1, config2;
1879318c51aSChris Dearman 	unsigned int tmp;
1889318c51aSChris Dearman 
1899318c51aSChris Dearman 	/* Mark as not present until probe completed */
1909318c51aSChris Dearman 	c->scache.flags |= MIPS_CACHE_NOT_PRESENT;
1919318c51aSChris Dearman 
1927d53e9c4SPaul Burton 	if (mips_cm_revision() >= CM_REV_CM3)
1937d53e9c4SPaul Burton 		return mips_sc_probe_cm3();
1947d53e9c4SPaul Burton 
1959318c51aSChris Dearman 	/* Ignore anything but MIPSxx processors */
196ab7c01fdSSerge Semin 	if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M64R1 |
197ab7c01fdSSerge Semin 			      MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M64R2 |
198ab7c01fdSSerge Semin 			      MIPS_CPU_ISA_M32R5 | MIPS_CPU_ISA_M64R5 |
199ab7c01fdSSerge Semin 			      MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R6)))
2009318c51aSChris Dearman 		return 0;
2019318c51aSChris Dearman 
2029318c51aSChris Dearman 	/* Does this MIPS32/MIPS64 CPU have a config2 register? */
2039318c51aSChris Dearman 	config1 = read_c0_config1();
2049318c51aSChris Dearman 	if (!(config1 & MIPS_CONF_M))
2059318c51aSChris Dearman 		return 0;
2069318c51aSChris Dearman 
2079318c51aSChris Dearman 	config2 = read_c0_config2();
208ea31a6b2SKevin Cernekee 
209ea31a6b2SKevin Cernekee 	if (!mips_sc_is_activated(c))
2109318c51aSChris Dearman 		return 0;
2119318c51aSChris Dearman 
2129318c51aSChris Dearman 	tmp = (config2 >> 8) & 0x0f;
21305513992SAndrzej Hajda 	if (tmp <= 7)
2149318c51aSChris Dearman 		c->scache.sets = 64 << tmp;
2159318c51aSChris Dearman 	else
2169318c51aSChris Dearman 		return 0;
2179318c51aSChris Dearman 
2189318c51aSChris Dearman 	tmp = (config2 >> 0) & 0x0f;
21905513992SAndrzej Hajda 	if (tmp <= 7)
2209318c51aSChris Dearman 		c->scache.ways = tmp + 1;
2219318c51aSChris Dearman 	else
2229318c51aSChris Dearman 		return 0;
2239318c51aSChris Dearman 
224579de8f8SZhou Yanjie 	if (current_cpu_type() == CPU_XBURST) {
225579de8f8SZhou Yanjie 		switch (mips_machtype) {
2261f7412e0SMaarten ter Huurne 		/*
227579de8f8SZhou Yanjie 		 * According to config2 it would be 5-ways, but that is
228579de8f8SZhou Yanjie 		 * contradicted by all documentation.
2291f7412e0SMaarten ter Huurne 		 */
230579de8f8SZhou Yanjie 		case MACH_INGENIC_JZ4770:
231a5ce8523S周琰杰 (Zhou Yanjie) 		case MACH_INGENIC_JZ4775:
2321f7412e0SMaarten ter Huurne 			c->scache.ways = 4;
233579de8f8SZhou Yanjie 			break;
234579de8f8SZhou Yanjie 
235579de8f8SZhou Yanjie 		/*
236579de8f8SZhou Yanjie 		 * According to config2 it would be 5-ways and 512-sets,
237579de8f8SZhou Yanjie 		 * but that is contradicted by all documentation.
238579de8f8SZhou Yanjie 		 */
239579de8f8SZhou Yanjie 		case MACH_INGENIC_X1000:
240a5ce8523S周琰杰 (Zhou Yanjie) 		case MACH_INGENIC_X1000E:
241579de8f8SZhou Yanjie 			c->scache.sets = 256;
242579de8f8SZhou Yanjie 			c->scache.ways = 4;
243579de8f8SZhou Yanjie 			break;
244579de8f8SZhou Yanjie 		}
245579de8f8SZhou Yanjie 	}
2461f7412e0SMaarten ter Huurne 
2479318c51aSChris Dearman 	c->scache.waysize = c->scache.sets * c->scache.linesz;
248a2c2bc4bSAtsushi Nemoto 	c->scache.waybit = __ffs(c->scache.waysize);
2499318c51aSChris Dearman 
2509318c51aSChris Dearman 	c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT;
2519318c51aSChris Dearman 
2529318c51aSChris Dearman 	return 1;
2539318c51aSChris Dearman }
2549318c51aSChris Dearman 
mips_sc_init(void)255078a55fcSPaul Gortmaker int mips_sc_init(void)
2569318c51aSChris Dearman {
2579318c51aSChris Dearman 	int found = mips_sc_probe();
2589318c51aSChris Dearman 	if (found) {
2599318c51aSChris Dearman 		mips_sc_enable();
2604d035516SPaul Burton 		mips_sc_prefetch_enable();
2619318c51aSChris Dearman 		bcops = &mips_sc_ops;
2629318c51aSChris Dearman 	}
2639318c51aSChris Dearman 	return found;
2649318c51aSChris Dearman }
265