xref: /OK3568_Linux_fs/kernel/arch/powerpc/platforms/4xx/soc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * IBM/AMCC PPC4xx SoC setup code
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2008 DENX Software Engineering, Stefan Roese <sr@denx.de>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * L2 cache routines cloned from arch/ppc/syslib/ibm440gx_common.c which is:
8*4882a593Smuzhiyun  *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
9*4882a593Smuzhiyun  *   Copyright (c) 2003 - 2006 Zultys Technologies
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/stddef.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/errno.h>
16*4882a593Smuzhiyun #include <linux/interrupt.h>
17*4882a593Smuzhiyun #include <linux/irq.h>
18*4882a593Smuzhiyun #include <linux/of_irq.h>
19*4882a593Smuzhiyun #include <linux/of_platform.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include <asm/dcr.h>
22*4882a593Smuzhiyun #include <asm/dcr-regs.h>
23*4882a593Smuzhiyun #include <asm/reg.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun static u32 dcrbase_l2c;
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * L2-cache
29*4882a593Smuzhiyun  */
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /* Issue L2C diagnostic command */
l2c_diag(u32 addr)32*4882a593Smuzhiyun static inline u32 l2c_diag(u32 addr)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun 	mtdcr(dcrbase_l2c + DCRN_L2C0_ADDR, addr);
35*4882a593Smuzhiyun 	mtdcr(dcrbase_l2c + DCRN_L2C0_CMD, L2C_CMD_DIAG);
36*4882a593Smuzhiyun 	while (!(mfdcr(dcrbase_l2c + DCRN_L2C0_SR) & L2C_SR_CC))
37*4882a593Smuzhiyun 		;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	return mfdcr(dcrbase_l2c + DCRN_L2C0_DATA);
40*4882a593Smuzhiyun }
41*4882a593Smuzhiyun 
l2c_error_handler(int irq,void * dev)42*4882a593Smuzhiyun static irqreturn_t l2c_error_handler(int irq, void *dev)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun 	u32 sr = mfdcr(dcrbase_l2c + DCRN_L2C0_SR);
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	if (sr & L2C_SR_CPE) {
47*4882a593Smuzhiyun 		/* Read cache trapped address */
48*4882a593Smuzhiyun 		u32 addr = l2c_diag(0x42000000);
49*4882a593Smuzhiyun 		printk(KERN_EMERG "L2C: Cache Parity Error, addr[16:26] = 0x%08x\n",
50*4882a593Smuzhiyun 		       addr);
51*4882a593Smuzhiyun 	}
52*4882a593Smuzhiyun 	if (sr & L2C_SR_TPE) {
53*4882a593Smuzhiyun 		/* Read tag trapped address */
54*4882a593Smuzhiyun 		u32 addr = l2c_diag(0x82000000) >> 16;
55*4882a593Smuzhiyun 		printk(KERN_EMERG "L2C: Tag Parity Error, addr[16:26] = 0x%08x\n",
56*4882a593Smuzhiyun 		       addr);
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	/* Clear parity errors */
60*4882a593Smuzhiyun 	if (sr & (L2C_SR_CPE | L2C_SR_TPE)){
61*4882a593Smuzhiyun 		mtdcr(dcrbase_l2c + DCRN_L2C0_ADDR, 0);
62*4882a593Smuzhiyun 		mtdcr(dcrbase_l2c + DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
63*4882a593Smuzhiyun 	} else {
64*4882a593Smuzhiyun 		printk(KERN_EMERG "L2C: LRU error\n");
65*4882a593Smuzhiyun 	}
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	return IRQ_HANDLED;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
ppc4xx_l2c_probe(void)70*4882a593Smuzhiyun static int __init ppc4xx_l2c_probe(void)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	struct device_node *np;
73*4882a593Smuzhiyun 	u32 r;
74*4882a593Smuzhiyun 	unsigned long flags;
75*4882a593Smuzhiyun 	int irq;
76*4882a593Smuzhiyun 	const u32 *dcrreg;
77*4882a593Smuzhiyun 	u32 dcrbase_isram;
78*4882a593Smuzhiyun 	int len;
79*4882a593Smuzhiyun 	const u32 *prop;
80*4882a593Smuzhiyun 	u32 l2_size;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	np = of_find_compatible_node(NULL, NULL, "ibm,l2-cache");
83*4882a593Smuzhiyun 	if (!np)
84*4882a593Smuzhiyun 		return 0;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	/* Get l2 cache size */
87*4882a593Smuzhiyun 	prop = of_get_property(np, "cache-size", NULL);
88*4882a593Smuzhiyun 	if (prop == NULL) {
89*4882a593Smuzhiyun 		printk(KERN_ERR "%pOF: Can't get cache-size!\n", np);
90*4882a593Smuzhiyun 		of_node_put(np);
91*4882a593Smuzhiyun 		return -ENODEV;
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun 	l2_size = prop[0];
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	/* Map DCRs */
96*4882a593Smuzhiyun 	dcrreg = of_get_property(np, "dcr-reg", &len);
97*4882a593Smuzhiyun 	if (!dcrreg || (len != 4 * sizeof(u32))) {
98*4882a593Smuzhiyun 		printk(KERN_ERR "%pOF: Can't get DCR register base !", np);
99*4882a593Smuzhiyun 		of_node_put(np);
100*4882a593Smuzhiyun 		return -ENODEV;
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 	dcrbase_isram = dcrreg[0];
103*4882a593Smuzhiyun 	dcrbase_l2c = dcrreg[2];
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	/* Get and map irq number from device tree */
106*4882a593Smuzhiyun 	irq = irq_of_parse_and_map(np, 0);
107*4882a593Smuzhiyun 	if (!irq) {
108*4882a593Smuzhiyun 		printk(KERN_ERR "irq_of_parse_and_map failed\n");
109*4882a593Smuzhiyun 		of_node_put(np);
110*4882a593Smuzhiyun 		return -ENODEV;
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	/* Install error handler */
114*4882a593Smuzhiyun 	if (request_irq(irq, l2c_error_handler, 0, "L2C", 0) < 0) {
115*4882a593Smuzhiyun 		printk(KERN_ERR "Cannot install L2C error handler"
116*4882a593Smuzhiyun 		       ", cache is not enabled\n");
117*4882a593Smuzhiyun 		of_node_put(np);
118*4882a593Smuzhiyun 		return -ENODEV;
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	local_irq_save(flags);
122*4882a593Smuzhiyun 	asm volatile ("sync" ::: "memory");
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	/* Disable SRAM */
125*4882a593Smuzhiyun 	mtdcr(dcrbase_isram + DCRN_SRAM0_DPC,
126*4882a593Smuzhiyun 	      mfdcr(dcrbase_isram + DCRN_SRAM0_DPC) & ~SRAM_DPC_ENABLE);
127*4882a593Smuzhiyun 	mtdcr(dcrbase_isram + DCRN_SRAM0_SB0CR,
128*4882a593Smuzhiyun 	      mfdcr(dcrbase_isram + DCRN_SRAM0_SB0CR) & ~SRAM_SBCR_BU_MASK);
129*4882a593Smuzhiyun 	mtdcr(dcrbase_isram + DCRN_SRAM0_SB1CR,
130*4882a593Smuzhiyun 	      mfdcr(dcrbase_isram + DCRN_SRAM0_SB1CR) & ~SRAM_SBCR_BU_MASK);
131*4882a593Smuzhiyun 	mtdcr(dcrbase_isram + DCRN_SRAM0_SB2CR,
132*4882a593Smuzhiyun 	      mfdcr(dcrbase_isram + DCRN_SRAM0_SB2CR) & ~SRAM_SBCR_BU_MASK);
133*4882a593Smuzhiyun 	mtdcr(dcrbase_isram + DCRN_SRAM0_SB3CR,
134*4882a593Smuzhiyun 	      mfdcr(dcrbase_isram + DCRN_SRAM0_SB3CR) & ~SRAM_SBCR_BU_MASK);
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	/* Enable L2_MODE without ICU/DCU */
137*4882a593Smuzhiyun 	r = mfdcr(dcrbase_l2c + DCRN_L2C0_CFG) &
138*4882a593Smuzhiyun 		~(L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_SS_MASK);
139*4882a593Smuzhiyun 	r |= L2C_CFG_L2M | L2C_CFG_SS_256;
140*4882a593Smuzhiyun 	mtdcr(dcrbase_l2c + DCRN_L2C0_CFG, r);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	mtdcr(dcrbase_l2c + DCRN_L2C0_ADDR, 0);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	/* Hardware Clear Command */
145*4882a593Smuzhiyun 	mtdcr(dcrbase_l2c + DCRN_L2C0_CMD, L2C_CMD_HCC);
146*4882a593Smuzhiyun 	while (!(mfdcr(dcrbase_l2c + DCRN_L2C0_SR) & L2C_SR_CC))
147*4882a593Smuzhiyun 		;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	/* Clear Cache Parity and Tag Errors */
150*4882a593Smuzhiyun 	mtdcr(dcrbase_l2c + DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	/* Enable 64G snoop region starting at 0 */
153*4882a593Smuzhiyun 	r = mfdcr(dcrbase_l2c + DCRN_L2C0_SNP0) &
154*4882a593Smuzhiyun 		~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK);
155*4882a593Smuzhiyun 	r |= L2C_SNP_SSR_32G | L2C_SNP_ESR;
156*4882a593Smuzhiyun 	mtdcr(dcrbase_l2c + DCRN_L2C0_SNP0, r);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	r = mfdcr(dcrbase_l2c + DCRN_L2C0_SNP1) &
159*4882a593Smuzhiyun 		~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK);
160*4882a593Smuzhiyun 	r |= 0x80000000 | L2C_SNP_SSR_32G | L2C_SNP_ESR;
161*4882a593Smuzhiyun 	mtdcr(dcrbase_l2c + DCRN_L2C0_SNP1, r);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	asm volatile ("sync" ::: "memory");
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/* Enable ICU/DCU ports */
166*4882a593Smuzhiyun 	r = mfdcr(dcrbase_l2c + DCRN_L2C0_CFG);
167*4882a593Smuzhiyun 	r &= ~(L2C_CFG_DCW_MASK | L2C_CFG_PMUX_MASK | L2C_CFG_PMIM
168*4882a593Smuzhiyun 	       | L2C_CFG_TPEI | L2C_CFG_CPEI | L2C_CFG_NAM | L2C_CFG_NBRM);
169*4882a593Smuzhiyun 	r |= L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_TPC | L2C_CFG_CPC | L2C_CFG_FRAN
170*4882a593Smuzhiyun 		| L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM | L2C_CFG_SMCM;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	/* Check for 460EX/GT special handling */
173*4882a593Smuzhiyun 	if (of_device_is_compatible(np, "ibm,l2-cache-460ex") ||
174*4882a593Smuzhiyun 	    of_device_is_compatible(np, "ibm,l2-cache-460gt"))
175*4882a593Smuzhiyun 		r |= L2C_CFG_RDBW;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	mtdcr(dcrbase_l2c + DCRN_L2C0_CFG, r);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	asm volatile ("sync; isync" ::: "memory");
180*4882a593Smuzhiyun 	local_irq_restore(flags);
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	printk(KERN_INFO "%dk L2-cache enabled\n", l2_size >> 10);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	of_node_put(np);
185*4882a593Smuzhiyun 	return 0;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun arch_initcall(ppc4xx_l2c_probe);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun /*
190*4882a593Smuzhiyun  * Apply a system reset. Alternatively a board specific value may be
191*4882a593Smuzhiyun  * provided via the "reset-type" property in the cpu node.
192*4882a593Smuzhiyun  */
ppc4xx_reset_system(char * cmd)193*4882a593Smuzhiyun void ppc4xx_reset_system(char *cmd)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	struct device_node *np;
196*4882a593Smuzhiyun 	u32 reset_type = DBCR0_RST_SYSTEM;
197*4882a593Smuzhiyun 	const u32 *prop;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	np = of_get_cpu_node(0, NULL);
200*4882a593Smuzhiyun 	if (np) {
201*4882a593Smuzhiyun 		prop = of_get_property(np, "reset-type", NULL);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 		/*
204*4882a593Smuzhiyun 		 * Check if property exists and if it is in range:
205*4882a593Smuzhiyun 		 * 1 - PPC4xx core reset
206*4882a593Smuzhiyun 		 * 2 - PPC4xx chip reset
207*4882a593Smuzhiyun 		 * 3 - PPC4xx system reset (default)
208*4882a593Smuzhiyun 		 */
209*4882a593Smuzhiyun 		if ((prop) && ((prop[0] >= 1) && (prop[0] <= 3)))
210*4882a593Smuzhiyun 			reset_type = prop[0] << 28;
211*4882a593Smuzhiyun 	}
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | reset_type);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	while (1)
216*4882a593Smuzhiyun 		;	/* Just in case the reset doesn't work */
217*4882a593Smuzhiyun }
218