diff options
Diffstat (limited to 'drivers/ssb/driver_chipcommon_pmu.c')
| -rw-r--r-- | drivers/ssb/driver_chipcommon_pmu.c | 154 | 
1 files changed, 132 insertions, 22 deletions
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c index 5732bb2c357..1173a091b40 100644 --- a/drivers/ssb/driver_chipcommon_pmu.c +++ b/drivers/ssb/driver_chipcommon_pmu.c @@ -2,7 +2,7 @@   * Sonics Silicon Backplane   * Broadcom ChipCommon Power Management Unit driver   * - * Copyright 2009, Michael Buesch <mb@bu3sch.de> + * Copyright 2009, Michael Buesch <m@bues.ch>   * Copyright 2007, Broadcom Corporation   *   * Licensed under the GNU/GPL. See COPYING for details. @@ -12,6 +12,10 @@  #include <linux/ssb/ssb_regs.h>  #include <linux/ssb/ssb_driver_chipcommon.h>  #include <linux/delay.h> +#include <linux/export.h> +#ifdef CONFIG_BCM47XX +#include <bcm47xx_nvram.h> +#endif  #include "ssb_private.h" @@ -91,10 +95,6 @@ static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,  	u32 pmuctl, tmp, pllctl;  	unsigned int i; -	if ((bus->chip_id == 0x5354) && !crystalfreq) { -		/* The 5354 crystal freq is 25MHz */ -		crystalfreq = 25000; -	}  	if (crystalfreq)  		e = pmu0_plltab_find_entry(crystalfreq);  	if (!e) @@ -110,8 +110,8 @@ static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,  		return;  	} -	ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n", -		   (crystalfreq / 1000), (crystalfreq % 1000)); +	ssb_info("Programming PLL to %u.%03u MHz\n", +		 crystalfreq / 1000, crystalfreq % 1000);  	/* First turn the PLL off. */  	switch (bus->chip_id) { @@ -138,7 +138,7 @@ static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,  	}  	tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);  	if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT) -		ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n"); +		ssb_emerg("Failed to turn the PLL off!\n");  	/* Set PDIV in PLL control 0. */  	pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL0); @@ -249,8 +249,8 @@ static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,  		return;  	} -	ssb_printk(KERN_INFO PFX "Programming PLL to %u.%03u MHz\n", -		   (crystalfreq / 1000), (crystalfreq % 1000)); +	ssb_info("Programming PLL to %u.%03u MHz\n", +		 crystalfreq / 1000, crystalfreq % 1000);  	/* First turn the PLL off. */  	switch (bus->chip_id) { @@ -275,7 +275,7 @@ static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,  	}  	tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);  	if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT) -		ssb_printk(KERN_EMERG PFX "Failed to turn the PLL off!\n"); +		ssb_emerg("Failed to turn the PLL off!\n");  	/* Set p1div and p2div. */  	pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL0); @@ -320,7 +320,11 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)  	u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */  	if (bus->bustype == SSB_BUSTYPE_SSB) { -		/* TODO: The user may override the crystal frequency. */ +#ifdef CONFIG_BCM47XX +		char buf[20]; +		if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0) +			crystalfreq = simple_strtoul(buf, NULL, 0); +#endif  	}  	switch (bus->chip_id) { @@ -329,7 +333,11 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)  		ssb_pmu1_pllinit_r0(cc, crystalfreq);  		break;  	case 0x4328: +		ssb_pmu0_pllinit_r0(cc, crystalfreq); +		break;  	case 0x5354: +		if (crystalfreq == 0) +			crystalfreq = 25000;  		ssb_pmu0_pllinit_r0(cc, crystalfreq);  		break;  	case 0x4322: @@ -338,10 +346,11 @@ static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)  			chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0);  		}  		break; +	case 43222: +		break;  	default: -		ssb_printk(KERN_ERR PFX -			   "ERROR: PLL init unknown for device %04X\n", -			   bus->chip_id); +		ssb_err("ERROR: PLL init unknown for device %04X\n", +			bus->chip_id);  	}  } @@ -417,13 +426,16 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)  	u32 min_msk = 0, max_msk = 0;  	unsigned int i;  	const struct pmu_res_updown_tab_entry *updown_tab = NULL; -	unsigned int updown_tab_size; +	unsigned int updown_tab_size = 0;  	const struct pmu_res_depend_tab_entry *depend_tab = NULL; -	unsigned int depend_tab_size; +	unsigned int depend_tab_size = 0;  	switch (bus->chip_id) {  	case 0x4312: +		 min_msk = 0xCBB; +		 break;  	case 0x4322: +	case 43222:  		/* We keep the default settings:  		 * min_msk = 0xCBB  		 * max_msk = 0x7FFFF @@ -459,9 +471,8 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)  		max_msk = 0xFFFFF;  		break;  	default: -		ssb_printk(KERN_ERR PFX -			   "ERROR: PMU resource config unknown for device %04X\n", -			   bus->chip_id); +		ssb_err("ERROR: PMU resource config unknown for device %04X\n", +			bus->chip_id);  	}  	if (updown_tab) { @@ -513,8 +524,8 @@ void ssb_pmu_init(struct ssb_chipcommon *cc)  	pmucap = chipco_read32(cc, SSB_CHIPCO_PMU_CAP);  	cc->pmu.rev = (pmucap & SSB_CHIPCO_PMU_CAP_REVISION); -	ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n", -		    cc->pmu.rev, pmucap); +	ssb_dbg("Found rev %u PMU (capabilities 0x%08X)\n", +		cc->pmu.rev, pmucap);  	if (cc->pmu.rev == 1)  		chipco_mask32(cc, SSB_CHIPCO_PMU_CTL, @@ -604,3 +615,102 @@ void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on)  EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);  EXPORT_SYMBOL(ssb_pmu_set_ldo_paref); + +static u32 ssb_pmu_get_alp_clock_clk0(struct ssb_chipcommon *cc) +{ +	u32 crystalfreq; +	const struct pmu0_plltab_entry *e = NULL; + +	crystalfreq = chipco_read32(cc, SSB_CHIPCO_PMU_CTL) & +		      SSB_CHIPCO_PMU_CTL_XTALFREQ >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT; +	e = pmu0_plltab_find_entry(crystalfreq); +	BUG_ON(!e); +	return e->freq * 1000; +} + +u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc) +{ +	struct ssb_bus *bus = cc->dev->bus; + +	switch (bus->chip_id) { +	case 0x5354: +		ssb_pmu_get_alp_clock_clk0(cc); +	default: +		ssb_err("ERROR: PMU alp clock unknown for device %04X\n", +			bus->chip_id); +		return 0; +	} +} + +u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc) +{ +	struct ssb_bus *bus = cc->dev->bus; + +	switch (bus->chip_id) { +	case 0x5354: +		/* 5354 chip uses a non programmable PLL of frequency 240MHz */ +		return 240000000; +	default: +		ssb_err("ERROR: PMU cpu clock unknown for device %04X\n", +			bus->chip_id); +		return 0; +	} +} + +u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc) +{ +	struct ssb_bus *bus = cc->dev->bus; + +	switch (bus->chip_id) { +	case 0x5354: +		return 120000000; +	default: +		ssb_err("ERROR: PMU controlclock unknown for device %04X\n", +			bus->chip_id); +		return 0; +	} +} + +void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon *cc, int spuravoid) +{ +	u32 pmu_ctl = 0; + +	switch (cc->dev->bus->chip_id) { +	case 0x4322: +		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100070); +		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x1014140a); +		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888854); +		if (spuravoid == 1) +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05201828); +		else +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05001828); +		pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD; +		break; +	case 43222: +		if (spuravoid == 1) { +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11500008); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0C000C06); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x0F600a08); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x2001E920); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888815); +		} else { +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100008); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0c000c06); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x03000a08); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x200005c0); +			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888855); +		} +		pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD; +		break; +	default: +		ssb_printk(KERN_ERR PFX +			   "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n", +			   cc->dev->bus->chip_id); +		return; +	} + +	chipco_set32(cc, SSB_CHIPCO_PMU_CTL, pmu_ctl); +} +EXPORT_SYMBOL_GPL(ssb_pmu_spuravoid_pllupdate);  | 
