mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-04 20:19:47 +08:00 
			
		
		
		
	 400d221274
			
		
	
	
		400d221274
		
	
	
	
	
		
			
			Changed ppc32 so that cur_cpu_spec is just a single pointer for all CPUs. Additionally, made call_setup_cpu check to see if the cpu_setup pointer is NULL or not before calling the function. This lets remove the dummy cpu_setup calls that just return. Signed-off-by: Kumar Gala <kumar.gala@freescale.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
		
			
				
	
	
		
			287 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * arch/ppc/kernel/ibm440gx_common.c
 | |
|  *
 | |
|  * PPC440GX system library
 | |
|  *
 | |
|  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
 | |
|  * Copyright (c) 2003, 2004 Zultys Technologies
 | |
|  *
 | |
|  * This program is free software; you can redistribute  it and/or modify it
 | |
|  * under  the terms of  the GNU General  Public License as published by the
 | |
|  * Free Software Foundation;  either version 2 of the  License, or (at your
 | |
|  * option) any later version.
 | |
|  *
 | |
|  */
 | |
| #include <linux/config.h>
 | |
| #include <linux/kernel.h>
 | |
| #include <linux/interrupt.h>
 | |
| #include <asm/ibm44x.h>
 | |
| #include <asm/mmu.h>
 | |
| #include <asm/processor.h>
 | |
| #include <syslib/ibm440gx_common.h>
 | |
| 
 | |
| /*
 | |
|  * Calculate 440GX clocks
 | |
|  */
 | |
| static inline u32 __fix_zero(u32 v, u32 def){
 | |
| 	return v ? v : def;
 | |
| }
 | |
| 
 | |
| void __init ibm440gx_get_clocks(struct ibm44x_clocks* p, unsigned int sys_clk,
 | |
| 	unsigned int ser_clk)
 | |
| {
 | |
| 	u32 pllc  = CPR_READ(DCRN_CPR_PLLC);
 | |
| 	u32 plld  = CPR_READ(DCRN_CPR_PLLD);
 | |
| 	u32 uart0 = SDR_READ(DCRN_SDR_UART0);
 | |
| 	u32 uart1 = SDR_READ(DCRN_SDR_UART1);
 | |
| #ifdef CONFIG_440EP
 | |
| 	u32 uart2 = SDR_READ(DCRN_SDR_UART2);
 | |
| 	u32 uart3 = SDR_READ(DCRN_SDR_UART3);
 | |
| #endif
 | |
| 
 | |
| 	/* Dividers */
 | |
| 	u32 fbdv   = __fix_zero((plld >> 24) & 0x1f, 32);
 | |
| 	u32 fwdva  = __fix_zero((plld >> 16) & 0xf, 16);
 | |
| 	u32 fwdvb  = __fix_zero((plld >> 8) & 7, 8);
 | |
| 	u32 lfbdv  = __fix_zero(plld & 0x3f, 64);
 | |
| 	u32 pradv0 = __fix_zero((CPR_READ(DCRN_CPR_PRIMAD) >> 24) & 7, 8);
 | |
| 	u32 prbdv0 = __fix_zero((CPR_READ(DCRN_CPR_PRIMBD) >> 24) & 7, 8);
 | |
| 	u32 opbdv0 = __fix_zero((CPR_READ(DCRN_CPR_OPBD) >> 24) & 3, 4);
 | |
| 	u32 perdv0 = __fix_zero((CPR_READ(DCRN_CPR_PERD) >> 24) & 3, 4);
 | |
| 
 | |
| 	/* Input clocks for primary dividers */
 | |
| 	u32 clk_a, clk_b;
 | |
| 
 | |
| 	if (pllc & 0x40000000){
 | |
| 		u32 m;
 | |
| 
 | |
| 		/* Feedback path */
 | |
| 		switch ((pllc >> 24) & 7){
 | |
| 		case 0:
 | |
| 			/* PLLOUTx */
 | |
| 			m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv;
 | |
| 			break;
 | |
| 		case 1:
 | |
| 			/* CPU */
 | |
| 			m = fwdva * pradv0;
 | |
| 			break;
 | |
| 		case 5:
 | |
| 			/* PERClk */
 | |
| 			m = fwdvb * prbdv0 * opbdv0 * perdv0;
 | |
| 			break;
 | |
| 		default:
 | |
| 			printk(KERN_EMERG "invalid PLL feedback source\n");
 | |
| 			goto bypass;
 | |
| 		}
 | |
| 		m *= fbdv;
 | |
| 		p->vco = sys_clk * m;
 | |
| 		clk_a = p->vco / fwdva;
 | |
| 		clk_b = p->vco / fwdvb;
 | |
| 	}
 | |
| 	else {
 | |
| bypass:
 | |
| 		/* Bypass system PLL */
 | |
| 		p->vco = 0;
 | |
| 		clk_a = clk_b = sys_clk;
 | |
| 	}
 | |
| 
 | |
| 	p->cpu = clk_a / pradv0;
 | |
| 	p->plb = clk_b / prbdv0;
 | |
| 	p->opb = p->plb / opbdv0;
 | |
| 	p->ebc = p->opb / perdv0;
 | |
| 
 | |
| 	/* UARTs clock */
 | |
| 	if (uart0 & 0x00800000)
 | |
| 		p->uart0 = ser_clk;
 | |
| 	else
 | |
| 		p->uart0 = p->plb / __fix_zero(uart0 & 0xff, 256);
 | |
| 
 | |
| 	if (uart1 & 0x00800000)
 | |
| 		p->uart1 = ser_clk;
 | |
| 	else
 | |
| 		p->uart1 = p->plb / __fix_zero(uart1 & 0xff, 256);
 | |
| #ifdef CONFIG_440EP
 | |
| 	if (uart2 & 0x00800000)
 | |
| 		p->uart2 = ser_clk;
 | |
| 	else
 | |
| 		p->uart2 = p->plb / __fix_zero(uart2 & 0xff, 256);
 | |
| 
 | |
| 	if (uart3 & 0x00800000)
 | |
| 		p->uart3 = ser_clk;
 | |
| 	else
 | |
| 		p->uart3 = p->plb / __fix_zero(uart3 & 0xff, 256);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* Issue L2C diagnostic command */
 | |
| static inline u32 l2c_diag(u32 addr)
 | |
| {
 | |
| 	mtdcr(DCRN_L2C0_ADDR, addr);
 | |
| 	mtdcr(DCRN_L2C0_CMD, L2C_CMD_DIAG);
 | |
| 	while (!(mfdcr(DCRN_L2C0_SR) & L2C_SR_CC)) ;
 | |
| 	return mfdcr(DCRN_L2C0_DATA);
 | |
| }
 | |
| 
 | |
| static irqreturn_t l2c_error_handler(int irq, void* dev, struct pt_regs* regs)
 | |
| {
 | |
| 	u32 sr = mfdcr(DCRN_L2C0_SR);
 | |
| 	if (sr & L2C_SR_CPE){
 | |
| 		/* Read cache trapped address */
 | |
| 		u32 addr = l2c_diag(0x42000000);
 | |
| 		printk(KERN_EMERG "L2C: Cache Parity Error, addr[16:26] = 0x%08x\n", addr);
 | |
| 	}
 | |
| 	if (sr & L2C_SR_TPE){
 | |
| 		/* Read tag trapped address */
 | |
| 		u32 addr = l2c_diag(0x82000000) >> 16;
 | |
| 		printk(KERN_EMERG "L2C: Tag Parity Error, addr[16:26] = 0x%08x\n", addr);
 | |
| 	}
 | |
| 
 | |
| 	/* Clear parity errors */
 | |
| 	if (sr & (L2C_SR_CPE | L2C_SR_TPE)){
 | |
| 		mtdcr(DCRN_L2C0_ADDR, 0);
 | |
| 		mtdcr(DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
 | |
| 	} else
 | |
| 		printk(KERN_EMERG "L2C: LRU error\n");
 | |
| 
 | |
| 	return IRQ_HANDLED;
 | |
| }
 | |
| 
 | |
| /* Enable L2 cache */
 | |
| void __init ibm440gx_l2c_enable(void){
 | |
| 	u32 r;
 | |
| 	unsigned long flags;
 | |
| 
 | |
| 	/* Install error handler */
 | |
| 	if (request_irq(87, l2c_error_handler, SA_INTERRUPT, "L2C", 0) < 0){
 | |
| 		printk(KERN_ERR "Cannot install L2C error handler, cache is not enabled\n");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	local_irq_save(flags);
 | |
| 	asm volatile ("sync" ::: "memory");
 | |
| 
 | |
| 	/* Disable SRAM */
 | |
| 	mtdcr(DCRN_SRAM0_DPC,   mfdcr(DCRN_SRAM0_DPC)   & ~SRAM_DPC_ENABLE);
 | |
| 	mtdcr(DCRN_SRAM0_SB0CR, mfdcr(DCRN_SRAM0_SB0CR) & ~SRAM_SBCR_BU_MASK);
 | |
| 	mtdcr(DCRN_SRAM0_SB1CR, mfdcr(DCRN_SRAM0_SB1CR) & ~SRAM_SBCR_BU_MASK);
 | |
| 	mtdcr(DCRN_SRAM0_SB2CR, mfdcr(DCRN_SRAM0_SB2CR) & ~SRAM_SBCR_BU_MASK);
 | |
| 	mtdcr(DCRN_SRAM0_SB3CR, mfdcr(DCRN_SRAM0_SB3CR) & ~SRAM_SBCR_BU_MASK);
 | |
| 
 | |
| 	/* Enable L2_MODE without ICU/DCU */
 | |
| 	r = mfdcr(DCRN_L2C0_CFG) & ~(L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_SS_MASK);
 | |
| 	r |= L2C_CFG_L2M | L2C_CFG_SS_256;
 | |
| 	mtdcr(DCRN_L2C0_CFG, r);
 | |
| 
 | |
| 	mtdcr(DCRN_L2C0_ADDR, 0);
 | |
| 
 | |
| 	/* Hardware Clear Command */
 | |
| 	mtdcr(DCRN_L2C0_CMD, L2C_CMD_HCC);
 | |
| 	while (!(mfdcr(DCRN_L2C0_SR) & L2C_SR_CC)) ;
 | |
| 
 | |
| 	/* Clear Cache Parity and Tag Errors */
 | |
| 	mtdcr(DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
 | |
| 
 | |
| 	/* Enable 64G snoop region starting at 0 */
 | |
| 	r = mfdcr(DCRN_L2C0_SNP0) & ~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK);
 | |
| 	r |= L2C_SNP_SSR_32G | L2C_SNP_ESR;
 | |
| 	mtdcr(DCRN_L2C0_SNP0, r);
 | |
| 
 | |
| 	r = mfdcr(DCRN_L2C0_SNP1) & ~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK);
 | |
| 	r |= 0x80000000 | L2C_SNP_SSR_32G | L2C_SNP_ESR;
 | |
| 	mtdcr(DCRN_L2C0_SNP1, r);
 | |
| 
 | |
| 	asm volatile ("sync" ::: "memory");
 | |
| 
 | |
| 	/* Enable ICU/DCU ports */
 | |
| 	r = mfdcr(DCRN_L2C0_CFG);
 | |
| 	r &= ~(L2C_CFG_DCW_MASK | L2C_CFG_PMUX_MASK | L2C_CFG_PMIM | L2C_CFG_TPEI
 | |
| 		| L2C_CFG_CPEI | L2C_CFG_NAM | L2C_CFG_NBRM);
 | |
| 	r |= L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_TPC | L2C_CFG_CPC | L2C_CFG_FRAN
 | |
| 		| L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM | L2C_CFG_SMCM;
 | |
| 	mtdcr(DCRN_L2C0_CFG, r);
 | |
| 
 | |
| 	asm volatile ("sync; isync" ::: "memory");
 | |
| 	local_irq_restore(flags);
 | |
| }
 | |
| 
 | |
| /* Disable L2 cache */
 | |
| void __init ibm440gx_l2c_disable(void){
 | |
| 	u32 r;
 | |
| 	unsigned long flags;
 | |
| 
 | |
| 	local_irq_save(flags);
 | |
| 	asm volatile ("sync" ::: "memory");
 | |
| 
 | |
| 	/* Disable L2C mode */
 | |
| 	r = mfdcr(DCRN_L2C0_CFG) & ~(L2C_CFG_L2M | L2C_CFG_ICU | L2C_CFG_DCU);
 | |
| 	mtdcr(DCRN_L2C0_CFG, r);
 | |
| 
 | |
| 	/* Enable SRAM */
 | |
| 	mtdcr(DCRN_SRAM0_DPC, mfdcr(DCRN_SRAM0_DPC) | SRAM_DPC_ENABLE);
 | |
| 	mtdcr(DCRN_SRAM0_SB0CR,
 | |
| 	      SRAM_SBCR_BAS0 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
 | |
| 	mtdcr(DCRN_SRAM0_SB1CR,
 | |
| 	      SRAM_SBCR_BAS1 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
 | |
| 	mtdcr(DCRN_SRAM0_SB2CR,
 | |
| 	      SRAM_SBCR_BAS2 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
 | |
| 	mtdcr(DCRN_SRAM0_SB3CR,
 | |
| 	      SRAM_SBCR_BAS3 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
 | |
| 
 | |
| 	asm volatile ("sync; isync" ::: "memory");
 | |
| 	local_irq_restore(flags);
 | |
| }
 | |
| 
 | |
| void __init ibm440gx_l2c_setup(struct ibm44x_clocks* p)
 | |
| {
 | |
| 	/* Disable L2C on rev.A, rev.B and 800MHz version of rev.C,
 | |
| 	   enable it on all other revisions
 | |
| 	 */
 | |
| 	if (strcmp(cur_cpu_spec->cpu_name, "440GX Rev. A") == 0 ||
 | |
| 			strcmp(cur_cpu_spec->cpu_name, "440GX Rev. B") == 0
 | |
| 			|| (strcmp(cur_cpu_spec->cpu_name, "440GX Rev. C")
 | |
| 				== 0 && p->cpu > 667000000))
 | |
| 		ibm440gx_l2c_disable();
 | |
| 	else
 | |
| 		ibm440gx_l2c_enable();
 | |
| }
 | |
| 
 | |
| int __init ibm440gx_get_eth_grp(void)
 | |
| {
 | |
| 	return (SDR_READ(DCRN_SDR_PFC1) & DCRN_SDR_PFC1_EPS) >> DCRN_SDR_PFC1_EPS_SHIFT;
 | |
| }
 | |
| 
 | |
| void __init ibm440gx_set_eth_grp(int group)
 | |
| {
 | |
| 	SDR_WRITE(DCRN_SDR_PFC1, (SDR_READ(DCRN_SDR_PFC1) & ~DCRN_SDR_PFC1_EPS) | (group << DCRN_SDR_PFC1_EPS_SHIFT));
 | |
| }
 | |
| 
 | |
| void __init ibm440gx_tah_enable(void)
 | |
| {
 | |
| 	/* Enable TAH0 and TAH1 */
 | |
| 	SDR_WRITE(DCRN_SDR_MFR,SDR_READ(DCRN_SDR_MFR) &
 | |
| 			~DCRN_SDR_MFR_TAH0);
 | |
| 	SDR_WRITE(DCRN_SDR_MFR,SDR_READ(DCRN_SDR_MFR) &
 | |
| 			~DCRN_SDR_MFR_TAH1);
 | |
| }
 | |
| 
 | |
| int ibm440gx_show_cpuinfo(struct seq_file *m){
 | |
| 
 | |
| 	u32 l2c_cfg = mfdcr(DCRN_L2C0_CFG);
 | |
| 	const char* s;
 | |
| 	if (l2c_cfg & L2C_CFG_L2M){
 | |
| 	    switch (l2c_cfg & (L2C_CFG_ICU | L2C_CFG_DCU)){
 | |
| 		case L2C_CFG_ICU: s = "I-Cache only";    break;
 | |
| 		case L2C_CFG_DCU: s = "D-Cache only";    break;
 | |
| 		default:	  s = "I-Cache/D-Cache"; break;
 | |
| 	    }
 | |
| 	}
 | |
| 	else
 | |
| 	    s = "disabled";
 | |
| 
 | |
| 	seq_printf(m, "L2-Cache\t: %s (0x%08x 0x%08x)\n", s,
 | |
| 	    l2c_cfg, mfdcr(DCRN_L2C0_SR));
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 |