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 = ¤t_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 = ¤t_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