162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Broadcom specific AMBA
362306a36Sopenharmony_ci * ChipCommon Power Management Unit driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2009, Michael Buesch <m@bues.ch>
662306a36Sopenharmony_ci * Copyright 2007, 2011, Broadcom Corporation
762306a36Sopenharmony_ci * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Licensed under the GNU/GPL. See COPYING for details.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "bcma_private.h"
1362306a36Sopenharmony_ci#include <linux/export.h>
1462306a36Sopenharmony_ci#include <linux/bcma/bcma.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciu32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
1962306a36Sopenharmony_ci	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
2062306a36Sopenharmony_ci	return bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
2162306a36Sopenharmony_ci}
2262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_civoid bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
2762306a36Sopenharmony_ci	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
2862306a36Sopenharmony_ci	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_civoid bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
3362306a36Sopenharmony_ci			     u32 set)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
3662306a36Sopenharmony_ci	bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
3762306a36Sopenharmony_ci	bcma_pmu_maskset32(cc, BCMA_CC_PMU_PLLCTL_DATA, mask, set);
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_civoid bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
4262306a36Sopenharmony_ci				 u32 offset, u32 mask, u32 set)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	bcma_pmu_write32(cc, BCMA_CC_PMU_CHIPCTL_ADDR, offset);
4562306a36Sopenharmony_ci	bcma_pmu_read32(cc, BCMA_CC_PMU_CHIPCTL_ADDR);
4662306a36Sopenharmony_ci	bcma_pmu_maskset32(cc, BCMA_CC_PMU_CHIPCTL_DATA, mask, set);
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_civoid bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
5162306a36Sopenharmony_ci				u32 set)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	bcma_pmu_write32(cc, BCMA_CC_PMU_REGCTL_ADDR, offset);
5462306a36Sopenharmony_ci	bcma_pmu_read32(cc, BCMA_CC_PMU_REGCTL_ADDR);
5562306a36Sopenharmony_ci	bcma_pmu_maskset32(cc, BCMA_CC_PMU_REGCTL_DATA, mask, set);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic u32 bcma_pmu_xtalfreq(struct bcma_drv_cc *cc)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	u32 ilp_ctl, alp_hz;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (!(bcma_pmu_read32(cc, BCMA_CC_PMU_STAT) &
6462306a36Sopenharmony_ci	      BCMA_CC_PMU_STAT_EXT_LPO_AVAIL))
6562306a36Sopenharmony_ci		return 0;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
6862306a36Sopenharmony_ci			 BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
6962306a36Sopenharmony_ci	usleep_range(1000, 2000);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	ilp_ctl = bcma_pmu_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
7262306a36Sopenharmony_ci	ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	alp_hz = ilp_ctl * 32768 / 4;
7762306a36Sopenharmony_ci	return (alp_hz + 50000) / 100000 * 100;
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic void bcma_pmu2_pll_init0(struct bcma_drv_cc *cc, u32 xtalfreq)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
8362306a36Sopenharmony_ci	u32 freq_tgt_target = 0, freq_tgt_current;
8462306a36Sopenharmony_ci	u32 pll0, mask;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	switch (bus->chipinfo.id) {
8762306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43142:
8862306a36Sopenharmony_ci		/* pmu2_xtaltab0_adfll_485 */
8962306a36Sopenharmony_ci		switch (xtalfreq) {
9062306a36Sopenharmony_ci		case 12000:
9162306a36Sopenharmony_ci			freq_tgt_target = 0x50D52;
9262306a36Sopenharmony_ci			break;
9362306a36Sopenharmony_ci		case 20000:
9462306a36Sopenharmony_ci			freq_tgt_target = 0x307FE;
9562306a36Sopenharmony_ci			break;
9662306a36Sopenharmony_ci		case 26000:
9762306a36Sopenharmony_ci			freq_tgt_target = 0x254EA;
9862306a36Sopenharmony_ci			break;
9962306a36Sopenharmony_ci		case 37400:
10062306a36Sopenharmony_ci			freq_tgt_target = 0x19EF8;
10162306a36Sopenharmony_ci			break;
10262306a36Sopenharmony_ci		case 52000:
10362306a36Sopenharmony_ci			freq_tgt_target = 0x12A75;
10462306a36Sopenharmony_ci			break;
10562306a36Sopenharmony_ci		}
10662306a36Sopenharmony_ci		break;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (!freq_tgt_target) {
11062306a36Sopenharmony_ci		bcma_err(bus, "Unknown TGT frequency for xtalfreq %d\n",
11162306a36Sopenharmony_ci			 xtalfreq);
11262306a36Sopenharmony_ci		return;
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	pll0 = bcma_chipco_pll_read(cc, BCMA_CC_PMU15_PLL_PLLCTL0);
11662306a36Sopenharmony_ci	freq_tgt_current = (pll0 & BCMA_CC_PMU15_PLL_PC0_FREQTGT_MASK) >>
11762306a36Sopenharmony_ci		BCMA_CC_PMU15_PLL_PC0_FREQTGT_SHIFT;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (freq_tgt_current == freq_tgt_target) {
12062306a36Sopenharmony_ci		bcma_debug(bus, "Target TGT frequency already set\n");
12162306a36Sopenharmony_ci		return;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	/* Turn off PLL */
12562306a36Sopenharmony_ci	switch (bus->chipinfo.id) {
12662306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43142:
12762306a36Sopenharmony_ci		mask = (u32)~(BCMA_RES_4314_HT_AVAIL |
12862306a36Sopenharmony_ci			      BCMA_RES_4314_MACPHY_CLK_AVAIL);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		bcma_pmu_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
13162306a36Sopenharmony_ci		bcma_pmu_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
13262306a36Sopenharmony_ci		bcma_wait_value(cc->core, BCMA_CLKCTLST,
13362306a36Sopenharmony_ci				BCMA_CLKCTLST_HAVEHT, 0, 20000);
13462306a36Sopenharmony_ci		break;
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	pll0 &= ~BCMA_CC_PMU15_PLL_PC0_FREQTGT_MASK;
13862306a36Sopenharmony_ci	pll0 |= freq_tgt_target << BCMA_CC_PMU15_PLL_PC0_FREQTGT_SHIFT;
13962306a36Sopenharmony_ci	bcma_chipco_pll_write(cc, BCMA_CC_PMU15_PLL_PLLCTL0, pll0);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* Flush */
14262306a36Sopenharmony_ci	if (cc->pmu.rev >= 2)
14362306a36Sopenharmony_ci		bcma_pmu_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/* TODO: Do we need to update OTP? */
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
15162306a36Sopenharmony_ci	u32 xtalfreq = bcma_pmu_xtalfreq(cc);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	switch (bus->chipinfo.id) {
15462306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43142:
15562306a36Sopenharmony_ci		if (xtalfreq == 0)
15662306a36Sopenharmony_ci			xtalfreq = 20000;
15762306a36Sopenharmony_ci		bcma_pmu2_pll_init0(cc, xtalfreq);
15862306a36Sopenharmony_ci		break;
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
16562306a36Sopenharmony_ci	u32 min_msk = 0, max_msk = 0;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	switch (bus->chipinfo.id) {
16862306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4313:
16962306a36Sopenharmony_ci		min_msk = 0x200D;
17062306a36Sopenharmony_ci		max_msk = 0xFFFF;
17162306a36Sopenharmony_ci		break;
17262306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43142:
17362306a36Sopenharmony_ci		min_msk = BCMA_RES_4314_LPLDO_PU |
17462306a36Sopenharmony_ci			  BCMA_RES_4314_PMU_SLEEP_DIS |
17562306a36Sopenharmony_ci			  BCMA_RES_4314_PMU_BG_PU |
17662306a36Sopenharmony_ci			  BCMA_RES_4314_CBUCK_LPOM_PU |
17762306a36Sopenharmony_ci			  BCMA_RES_4314_CBUCK_PFM_PU |
17862306a36Sopenharmony_ci			  BCMA_RES_4314_CLDO_PU |
17962306a36Sopenharmony_ci			  BCMA_RES_4314_LPLDO2_LVM |
18062306a36Sopenharmony_ci			  BCMA_RES_4314_WL_PMU_PU |
18162306a36Sopenharmony_ci			  BCMA_RES_4314_LDO3P3_PU |
18262306a36Sopenharmony_ci			  BCMA_RES_4314_OTP_PU |
18362306a36Sopenharmony_ci			  BCMA_RES_4314_WL_PWRSW_PU |
18462306a36Sopenharmony_ci			  BCMA_RES_4314_LQ_AVAIL |
18562306a36Sopenharmony_ci			  BCMA_RES_4314_LOGIC_RET |
18662306a36Sopenharmony_ci			  BCMA_RES_4314_MEM_SLEEP |
18762306a36Sopenharmony_ci			  BCMA_RES_4314_MACPHY_RET |
18862306a36Sopenharmony_ci			  BCMA_RES_4314_WL_CORE_READY;
18962306a36Sopenharmony_ci		max_msk = 0x3FFFFFFF;
19062306a36Sopenharmony_ci		break;
19162306a36Sopenharmony_ci	default:
19262306a36Sopenharmony_ci		bcma_debug(bus, "PMU resource config unknown or not needed for device 0x%04X\n",
19362306a36Sopenharmony_ci			   bus->chipinfo.id);
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* Set the resource masks. */
19762306a36Sopenharmony_ci	if (min_msk)
19862306a36Sopenharmony_ci		bcma_pmu_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
19962306a36Sopenharmony_ci	if (max_msk)
20062306a36Sopenharmony_ci		bcma_pmu_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/*
20362306a36Sopenharmony_ci	 * Add some delay; allow resources to come up and settle.
20462306a36Sopenharmony_ci	 * Delay is required for SoC (early init).
20562306a36Sopenharmony_ci	 */
20662306a36Sopenharmony_ci	usleep_range(2000, 2500);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci/* Disable to allow reading SPROM. Don't know the advantages of enabling it. */
21062306a36Sopenharmony_civoid bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
21362306a36Sopenharmony_ci	u32 val;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
21662306a36Sopenharmony_ci	if (enable) {
21762306a36Sopenharmony_ci		val |= BCMA_CHIPCTL_4331_EXTPA_EN;
21862306a36Sopenharmony_ci		if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
21962306a36Sopenharmony_ci			val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
22062306a36Sopenharmony_ci		else if (bus->chipinfo.rev > 0)
22162306a36Sopenharmony_ci			val |= BCMA_CHIPCTL_4331_EXTPA_EN2;
22262306a36Sopenharmony_ci	} else {
22362306a36Sopenharmony_ci		val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
22462306a36Sopenharmony_ci		val &= ~BCMA_CHIPCTL_4331_EXTPA_EN2;
22562306a36Sopenharmony_ci		val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci	bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	switch (bus->chipinfo.id) {
23562306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4313:
23662306a36Sopenharmony_ci		/*
23762306a36Sopenharmony_ci		 * enable 12 mA drive strength for 4313 and set chipControl
23862306a36Sopenharmony_ci		 * register bit 1
23962306a36Sopenharmony_ci		 */
24062306a36Sopenharmony_ci		bcma_chipco_chipctl_maskset(cc, 0,
24162306a36Sopenharmony_ci					    ~BCMA_CCTRL_4313_12MA_LED_DRIVE,
24262306a36Sopenharmony_ci					    BCMA_CCTRL_4313_12MA_LED_DRIVE);
24362306a36Sopenharmony_ci		break;
24462306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4331:
24562306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43431:
24662306a36Sopenharmony_ci		/* Ext PA lines must be enabled for tx on BCM4331 */
24762306a36Sopenharmony_ci		bcma_chipco_bcm4331_ext_pa_lines_ctl(cc, true);
24862306a36Sopenharmony_ci		break;
24962306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43224:
25062306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43421:
25162306a36Sopenharmony_ci		/*
25262306a36Sopenharmony_ci		 * enable 12 mA drive strength for 43224 and set chipControl
25362306a36Sopenharmony_ci		 * register bit 15
25462306a36Sopenharmony_ci		 */
25562306a36Sopenharmony_ci		if (bus->chipinfo.rev == 0) {
25662306a36Sopenharmony_ci			bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL,
25762306a36Sopenharmony_ci					  ~BCMA_CCTRL_43224_GPIO_TOGGLE,
25862306a36Sopenharmony_ci					  BCMA_CCTRL_43224_GPIO_TOGGLE);
25962306a36Sopenharmony_ci			bcma_chipco_chipctl_maskset(cc, 0,
26062306a36Sopenharmony_ci						    ~BCMA_CCTRL_43224A0_12MA_LED_DRIVE,
26162306a36Sopenharmony_ci						    BCMA_CCTRL_43224A0_12MA_LED_DRIVE);
26262306a36Sopenharmony_ci		} else {
26362306a36Sopenharmony_ci			bcma_chipco_chipctl_maskset(cc, 0,
26462306a36Sopenharmony_ci						    ~BCMA_CCTRL_43224B0_12MA_LED_DRIVE,
26562306a36Sopenharmony_ci						    BCMA_CCTRL_43224B0_12MA_LED_DRIVE);
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci		break;
26862306a36Sopenharmony_ci	default:
26962306a36Sopenharmony_ci		bcma_debug(bus, "Workarounds unknown or not needed for device 0x%04X\n",
27062306a36Sopenharmony_ci			   bus->chipinfo.id);
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_civoid bcma_pmu_early_init(struct bcma_drv_cc *cc)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
27762306a36Sopenharmony_ci	u32 pmucap;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	if (cc->core->id.rev >= 35 &&
28062306a36Sopenharmony_ci	    cc->capabilities_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
28162306a36Sopenharmony_ci		cc->pmu.core = bcma_find_core(bus, BCMA_CORE_PMU);
28262306a36Sopenharmony_ci		if (!cc->pmu.core)
28362306a36Sopenharmony_ci			bcma_warn(bus, "Couldn't find expected PMU core");
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci	if (!cc->pmu.core)
28662306a36Sopenharmony_ci		cc->pmu.core = cc->core;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	pmucap = bcma_pmu_read32(cc, BCMA_CC_PMU_CAP);
28962306a36Sopenharmony_ci	cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	bcma_debug(bus, "Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
29262306a36Sopenharmony_ci		   pmucap);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_civoid bcma_pmu_init(struct bcma_drv_cc *cc)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	if (cc->pmu.rev == 1)
29862306a36Sopenharmony_ci		bcma_pmu_mask32(cc, BCMA_CC_PMU_CTL,
29962306a36Sopenharmony_ci				~BCMA_CC_PMU_CTL_NOILPONW);
30062306a36Sopenharmony_ci	else
30162306a36Sopenharmony_ci		bcma_pmu_set32(cc, BCMA_CC_PMU_CTL,
30262306a36Sopenharmony_ci			       BCMA_CC_PMU_CTL_NOILPONW);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	bcma_pmu_pll_init(cc);
30562306a36Sopenharmony_ci	bcma_pmu_resources_init(cc);
30662306a36Sopenharmony_ci	bcma_pmu_workarounds(cc);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ciu32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	switch (bus->chipinfo.id) {
31462306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4313:
31562306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43224:
31662306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43225:
31762306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43227:
31862306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43228:
31962306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4331:
32062306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43421:
32162306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43428:
32262306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43431:
32362306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4716:
32462306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM47162:
32562306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4748:
32662306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4749:
32762306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM5357:
32862306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM53572:
32962306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM6362:
33062306a36Sopenharmony_ci		/* always 20Mhz */
33162306a36Sopenharmony_ci		return 20000 * 1000;
33262306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4706:
33362306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM5356:
33462306a36Sopenharmony_ci		/* always 25Mhz */
33562306a36Sopenharmony_ci		return 25000 * 1000;
33662306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43460:
33762306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4352:
33862306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4360:
33962306a36Sopenharmony_ci		if (cc->status & BCMA_CC_CHIPST_4360_XTAL_40MZ)
34062306a36Sopenharmony_ci			return 40000 * 1000;
34162306a36Sopenharmony_ci		else
34262306a36Sopenharmony_ci			return 20000 * 1000;
34362306a36Sopenharmony_ci	default:
34462306a36Sopenharmony_ci		bcma_warn(bus, "No ALP clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
34562306a36Sopenharmony_ci			  bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci	return BCMA_CC_PMU_ALP_CLOCK;
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci/* Find the output of the "m" pll divider given pll controls that start with
35162306a36Sopenharmony_ci * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
35262306a36Sopenharmony_ci */
35362306a36Sopenharmony_cistatic u32 bcma_pmu_pll_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	u32 tmp, div, ndiv, p1, p2, fc;
35662306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	BUG_ON(!m || m > 4);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 ||
36362306a36Sopenharmony_ci	    bus->chipinfo.id == BCMA_CHIP_ID_BCM4749) {
36462306a36Sopenharmony_ci		/* Detect failure in clock setting */
36562306a36Sopenharmony_ci		tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
36662306a36Sopenharmony_ci		if (tmp & 0x40000)
36762306a36Sopenharmony_ci			return 133 * 1000000;
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
37162306a36Sopenharmony_ci	p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
37262306a36Sopenharmony_ci	p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
37562306a36Sopenharmony_ci	div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
37662306a36Sopenharmony_ci		BCMA_CC_PPL_MDIV_MASK;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
37962306a36Sopenharmony_ci	ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* Do calculation in Mhz */
38262306a36Sopenharmony_ci	fc = bcma_pmu_get_alp_clock(cc) / 1000000;
38362306a36Sopenharmony_ci	fc = (p1 * ndiv * fc) / p2;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* Return clock in Hertz */
38662306a36Sopenharmony_ci	return (fc / div) * 1000000;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic u32 bcma_pmu_pll_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	u32 tmp, ndiv, p1div, p2div;
39262306a36Sopenharmony_ci	u32 clock;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	BUG_ON(!m || m > 4);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* Get N, P1 and P2 dividers to determine CPU clock */
39762306a36Sopenharmony_ci	tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PMU6_4706_PROCPLL_OFF);
39862306a36Sopenharmony_ci	ndiv = (tmp & BCMA_CC_PMU6_4706_PROC_NDIV_INT_MASK)
39962306a36Sopenharmony_ci		>> BCMA_CC_PMU6_4706_PROC_NDIV_INT_SHIFT;
40062306a36Sopenharmony_ci	p1div = (tmp & BCMA_CC_PMU6_4706_PROC_P1DIV_MASK)
40162306a36Sopenharmony_ci		>> BCMA_CC_PMU6_4706_PROC_P1DIV_SHIFT;
40262306a36Sopenharmony_ci	p2div = (tmp & BCMA_CC_PMU6_4706_PROC_P2DIV_MASK)
40362306a36Sopenharmony_ci		>> BCMA_CC_PMU6_4706_PROC_P2DIV_SHIFT;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
40662306a36Sopenharmony_ci	if (tmp & BCMA_CC_CHIPST_4706_PKG_OPTION)
40762306a36Sopenharmony_ci		/* Low cost bonding: Fixed reference clock 25MHz and m = 4 */
40862306a36Sopenharmony_ci		clock = (25000000 / 4) * ndiv * p2div / p1div;
40962306a36Sopenharmony_ci	else
41062306a36Sopenharmony_ci		/* Fixed reference clock 25MHz and m = 2 */
41162306a36Sopenharmony_ci		clock = (25000000 / 2) * ndiv * p2div / p1div;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (m == BCMA_CC_PMU5_MAINPLL_SSB)
41462306a36Sopenharmony_ci		clock = clock / 4;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	return clock;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci/* query bus clock frequency for PMU-enabled chipcommon */
42062306a36Sopenharmony_ciu32 bcma_pmu_get_bus_clock(struct bcma_drv_cc *cc)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	switch (bus->chipinfo.id) {
42562306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4716:
42662306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4748:
42762306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM47162:
42862306a36Sopenharmony_ci		return bcma_pmu_pll_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
42962306a36Sopenharmony_ci					  BCMA_CC_PMU5_MAINPLL_SSB);
43062306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM5356:
43162306a36Sopenharmony_ci		return bcma_pmu_pll_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
43262306a36Sopenharmony_ci					  BCMA_CC_PMU5_MAINPLL_SSB);
43362306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM5357:
43462306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4749:
43562306a36Sopenharmony_ci		return bcma_pmu_pll_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
43662306a36Sopenharmony_ci					  BCMA_CC_PMU5_MAINPLL_SSB);
43762306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4706:
43862306a36Sopenharmony_ci		return bcma_pmu_pll_clock_bcm4706(cc,
43962306a36Sopenharmony_ci						  BCMA_CC_PMU4706_MAINPLL_PLL0,
44062306a36Sopenharmony_ci						  BCMA_CC_PMU5_MAINPLL_SSB);
44162306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM53572:
44262306a36Sopenharmony_ci		return 75000000;
44362306a36Sopenharmony_ci	default:
44462306a36Sopenharmony_ci		bcma_warn(bus, "No bus clock specified for %04X device, pmu rev. %d, using default %d Hz\n",
44562306a36Sopenharmony_ci			  bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci	return BCMA_CC_PMU_HT_CLOCK;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_pmu_get_bus_clock);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci/* query cpu clock frequency for PMU-enabled chipcommon */
45262306a36Sopenharmony_ciu32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53572)
45762306a36Sopenharmony_ci		return 300000000;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/* New PMUs can have different clock for bus and CPU */
46062306a36Sopenharmony_ci	if (cc->pmu.rev >= 5) {
46162306a36Sopenharmony_ci		u32 pll;
46262306a36Sopenharmony_ci		switch (bus->chipinfo.id) {
46362306a36Sopenharmony_ci		case BCMA_CHIP_ID_BCM4706:
46462306a36Sopenharmony_ci			return bcma_pmu_pll_clock_bcm4706(cc,
46562306a36Sopenharmony_ci						BCMA_CC_PMU4706_MAINPLL_PLL0,
46662306a36Sopenharmony_ci						BCMA_CC_PMU5_MAINPLL_CPU);
46762306a36Sopenharmony_ci		case BCMA_CHIP_ID_BCM5356:
46862306a36Sopenharmony_ci			pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
46962306a36Sopenharmony_ci			break;
47062306a36Sopenharmony_ci		case BCMA_CHIP_ID_BCM5357:
47162306a36Sopenharmony_ci		case BCMA_CHIP_ID_BCM4749:
47262306a36Sopenharmony_ci			pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
47362306a36Sopenharmony_ci			break;
47462306a36Sopenharmony_ci		default:
47562306a36Sopenharmony_ci			pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
47662306a36Sopenharmony_ci			break;
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci		return bcma_pmu_pll_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	/* On old PMUs CPU has the same clock as the bus */
48362306a36Sopenharmony_ci	return bcma_pmu_get_bus_clock(cc);
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
48762306a36Sopenharmony_ci					 u32 value)
48862306a36Sopenharmony_ci{
48962306a36Sopenharmony_ci	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
49062306a36Sopenharmony_ci	bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_civoid bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	u32 tmp = 0;
49662306a36Sopenharmony_ci	u8 phypll_offset = 0;
49762306a36Sopenharmony_ci	u8 bcm5357_bcm43236_p1div[] = {0x1, 0x5, 0x5};
49862306a36Sopenharmony_ci	u8 bcm5357_bcm43236_ndiv[] = {0x30, 0xf6, 0xfc};
49962306a36Sopenharmony_ci	struct bcma_bus *bus = cc->core->bus;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	switch (bus->chipinfo.id) {
50262306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM5357:
50362306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4749:
50462306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM53572:
50562306a36Sopenharmony_ci		/* 5357[ab]0, 43236[ab]0, and 6362b0 */
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		/*
50862306a36Sopenharmony_ci		 * BCM5357 needs to touch PLL1_PLLCTL[02],
50962306a36Sopenharmony_ci		 * so offset PLL0_PLLCTL[02] by 6
51062306a36Sopenharmony_ci		 */
51162306a36Sopenharmony_ci		phypll_offset = (bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 ||
51262306a36Sopenharmony_ci		       bus->chipinfo.id == BCMA_CHIP_ID_BCM4749 ||
51362306a36Sopenharmony_ci		       bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci		/* RMW only the P1 divider */
51662306a36Sopenharmony_ci		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
51762306a36Sopenharmony_ci				BCMA_CC_PMU_PLL_CTL0 + phypll_offset);
51862306a36Sopenharmony_ci		tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
51962306a36Sopenharmony_ci		tmp &= (~(BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK));
52062306a36Sopenharmony_ci		tmp |= (bcm5357_bcm43236_p1div[spuravoid] << BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT);
52162306a36Sopenharmony_ci		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		/* RMW only the int feedback divider */
52462306a36Sopenharmony_ci		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
52562306a36Sopenharmony_ci				BCMA_CC_PMU_PLL_CTL2 + phypll_offset);
52662306a36Sopenharmony_ci		tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
52762306a36Sopenharmony_ci		tmp &= ~(BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK);
52862306a36Sopenharmony_ci		tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
52962306a36Sopenharmony_ci		bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci		tmp = BCMA_CC_PMU_CTL_PLL_UPD;
53262306a36Sopenharmony_ci		break;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4331:
53562306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43431:
53662306a36Sopenharmony_ci		if (spuravoid == 2) {
53762306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0,
53862306a36Sopenharmony_ci						     0x11500014);
53962306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
54062306a36Sopenharmony_ci						     0x0FC00a08);
54162306a36Sopenharmony_ci		} else if (spuravoid == 1) {
54262306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0,
54362306a36Sopenharmony_ci						     0x11500014);
54462306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
54562306a36Sopenharmony_ci						     0x0F600a08);
54662306a36Sopenharmony_ci		} else {
54762306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0,
54862306a36Sopenharmony_ci						     0x11100014);
54962306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
55062306a36Sopenharmony_ci						     0x03000a08);
55162306a36Sopenharmony_ci		}
55262306a36Sopenharmony_ci		tmp = BCMA_CC_PMU_CTL_PLL_UPD;
55362306a36Sopenharmony_ci		break;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43224:
55662306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43225:
55762306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43421:
55862306a36Sopenharmony_ci		if (spuravoid == 1) {
55962306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0,
56062306a36Sopenharmony_ci						     0x11500010);
56162306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1,
56262306a36Sopenharmony_ci						     0x000C0C06);
56362306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
56462306a36Sopenharmony_ci						     0x0F600a08);
56562306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3,
56662306a36Sopenharmony_ci						     0x00000000);
56762306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4,
56862306a36Sopenharmony_ci						     0x2001E920);
56962306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
57062306a36Sopenharmony_ci						     0x88888815);
57162306a36Sopenharmony_ci		} else {
57262306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0,
57362306a36Sopenharmony_ci						     0x11100010);
57462306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1,
57562306a36Sopenharmony_ci						     0x000c0c06);
57662306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
57762306a36Sopenharmony_ci						     0x03000a08);
57862306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3,
57962306a36Sopenharmony_ci						     0x00000000);
58062306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4,
58162306a36Sopenharmony_ci						     0x200005c0);
58262306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
58362306a36Sopenharmony_ci						     0x88888815);
58462306a36Sopenharmony_ci		}
58562306a36Sopenharmony_ci		tmp = BCMA_CC_PMU_CTL_PLL_UPD;
58662306a36Sopenharmony_ci		break;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4716:
58962306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM4748:
59062306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM47162:
59162306a36Sopenharmony_ci		if (spuravoid == 1) {
59262306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0,
59362306a36Sopenharmony_ci						     0x11500060);
59462306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1,
59562306a36Sopenharmony_ci						     0x080C0C06);
59662306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
59762306a36Sopenharmony_ci						     0x0F600000);
59862306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3,
59962306a36Sopenharmony_ci						     0x00000000);
60062306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4,
60162306a36Sopenharmony_ci						     0x2001E924);
60262306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
60362306a36Sopenharmony_ci						     0x88888815);
60462306a36Sopenharmony_ci		} else {
60562306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0,
60662306a36Sopenharmony_ci						     0x11100060);
60762306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1,
60862306a36Sopenharmony_ci						     0x080c0c06);
60962306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
61062306a36Sopenharmony_ci						     0x03000000);
61162306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3,
61262306a36Sopenharmony_ci						     0x00000000);
61362306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4,
61462306a36Sopenharmony_ci						     0x200005c0);
61562306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
61662306a36Sopenharmony_ci						     0x88888815);
61762306a36Sopenharmony_ci		}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		tmp = BCMA_CC_PMU_CTL_PLL_UPD | BCMA_CC_PMU_CTL_NOILPONW;
62062306a36Sopenharmony_ci		break;
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43131:
62362306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43217:
62462306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43227:
62562306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43228:
62662306a36Sopenharmony_ci	case BCMA_CHIP_ID_BCM43428:
62762306a36Sopenharmony_ci		/* LCNXN */
62862306a36Sopenharmony_ci		/*
62962306a36Sopenharmony_ci		 * PLL Settings for spur avoidance on/off mode,
63062306a36Sopenharmony_ci		 * no on2 support for 43228A0
63162306a36Sopenharmony_ci		 */
63262306a36Sopenharmony_ci		if (spuravoid == 1) {
63362306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0,
63462306a36Sopenharmony_ci						     0x01100014);
63562306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1,
63662306a36Sopenharmony_ci						     0x040C0C06);
63762306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
63862306a36Sopenharmony_ci						     0x03140A08);
63962306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3,
64062306a36Sopenharmony_ci						     0x00333333);
64162306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4,
64262306a36Sopenharmony_ci						     0x202C2820);
64362306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
64462306a36Sopenharmony_ci						     0x88888815);
64562306a36Sopenharmony_ci		} else {
64662306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0,
64762306a36Sopenharmony_ci						     0x11100014);
64862306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1,
64962306a36Sopenharmony_ci						     0x040c0c06);
65062306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2,
65162306a36Sopenharmony_ci						     0x03000a08);
65262306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3,
65362306a36Sopenharmony_ci						     0x00000000);
65462306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4,
65562306a36Sopenharmony_ci						     0x200005c0);
65662306a36Sopenharmony_ci			bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5,
65762306a36Sopenharmony_ci						     0x88888815);
65862306a36Sopenharmony_ci		}
65962306a36Sopenharmony_ci		tmp = BCMA_CC_PMU_CTL_PLL_UPD;
66062306a36Sopenharmony_ci		break;
66162306a36Sopenharmony_ci	default:
66262306a36Sopenharmony_ci		bcma_err(bus, "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
66362306a36Sopenharmony_ci			 bus->chipinfo.id);
66462306a36Sopenharmony_ci		break;
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	tmp |= bcma_pmu_read32(cc, BCMA_CC_PMU_CTL);
66862306a36Sopenharmony_ci	bcma_pmu_write32(cc, BCMA_CC_PMU_CTL, tmp);
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate);
671