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