From: Michael Büsch Date: Sun, 1 Feb 2009 18:55:36 +0000 (+0000) Subject: bcm47xx: Add support for the 5354 PMU. X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=d070eb4c917ae4927e3a8cce1ff26d913394edc6;p=openwrt%2Fstaging%2Frobimarko.git bcm47xx: Add support for the 5354 PMU. SVN-Revision: 14347 --- diff --git a/target/linux/brcm47xx/patches-2.6.28/810-ssb-add-pmu-support.patch b/target/linux/brcm47xx/patches-2.6.28/810-ssb-add-pmu-support.patch new file mode 100644 index 0000000000..aa5374892e --- /dev/null +++ b/target/linux/brcm47xx/patches-2.6.28/810-ssb-add-pmu-support.patch @@ -0,0 +1,534 @@ +Index: linux-2.6.28.2/drivers/ssb/Makefile +=================================================================== +--- linux-2.6.28.2.orig/drivers/ssb/Makefile 2009-02-01 13:09:04.000000000 +0100 ++++ linux-2.6.28.2/drivers/ssb/Makefile 2009-02-01 13:09:31.000000000 +0100 +@@ -9,6 +9,7 @@ ssb-$(CONFIG_SSB_PCMCIAHOST) += pcmcia. + + # built-in drivers + ssb-y += driver_chipcommon.o ++ssb-y += driver_chipcommon_pmu.o + ssb-$(CONFIG_SSB_DRIVER_MIPS) += driver_mipscore.o + ssb-$(CONFIG_SSB_DRIVER_EXTIF) += driver_extif.o + ssb-$(CONFIG_SSB_DRIVER_PCICORE) += driver_pcicore.o +Index: linux-2.6.28.2/drivers/ssb/driver_chipcommon_pmu.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.28.2/drivers/ssb/driver_chipcommon_pmu.c 2009-02-01 19:51:46.000000000 +0100 +@@ -0,0 +1,259 @@ ++/* ++ * Sonics Silicon Backplane ++ * Broadcom ChipCommon Power Management Unit driver ++ * ++ * Copyright 2009, Michael Buesch ++ * Copyright 2007, Broadcom Corporation ++ * ++ * Licensed under the GNU/GPL. See COPYING for details. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "ssb_private.h" ++ ++static u32 ssb_chipco_pll_read(struct ssb_chipcommon *cc, u32 offset) ++{ ++ chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, offset); ++ return chipco_read32(cc, SSB_CHIPCO_PLLCTL_DATA); ++} ++ ++static void ssb_chipco_pll_write(struct ssb_chipcommon *cc, ++ u32 offset, u32 value) ++{ ++ chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, offset); ++ chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, value); ++} ++ ++struct pmu0_plltab_entry { ++ u16 freq; /* Crystal frequency in kHz.*/ ++ u8 xf; /* Crystal frequency value for PMU control */ ++ u8 wb_int; ++ u32 wb_frac; ++}; ++ ++static const struct pmu0_plltab_entry pmu0_plltab[] = { ++ { .freq = 12000, .xf = 1, .wb_int = 73, .wb_frac = 349525, }, ++ { .freq = 13000, .xf = 2, .wb_int = 67, .wb_frac = 725937, }, ++ { .freq = 14400, .xf = 3, .wb_int = 61, .wb_frac = 116508, }, ++ { .freq = 15360, .xf = 4, .wb_int = 57, .wb_frac = 305834, }, ++ { .freq = 16200, .xf = 5, .wb_int = 54, .wb_frac = 336579, }, ++ { .freq = 16800, .xf = 6, .wb_int = 52, .wb_frac = 399457, }, ++ { .freq = 19200, .xf = 7, .wb_int = 45, .wb_frac = 873813, }, ++ { .freq = 19800, .xf = 8, .wb_int = 44, .wb_frac = 466033, }, ++ { .freq = 20000, .xf = 9, .wb_int = 44, .wb_frac = 0, }, ++ { .freq = 25000, .xf = 10, .wb_int = 70, .wb_frac = 419430, }, ++ { .freq = 26000, .xf = 11, .wb_int = 67, .wb_frac = 725937, }, ++ { .freq = 30000, .xf = 12, .wb_int = 58, .wb_frac = 699050, }, ++ { .freq = 38400, .xf = 13, .wb_int = 45, .wb_frac = 873813, }, ++ { .freq = 40000, .xf = 14, .wb_int = 45, .wb_frac = 0, }, ++}; ++#define SSB_PMU0_DEFAULT_XTALFREQ 20000 ++ ++static const struct pmu0_plltab_entry * pmu0_plltab_find_entry(u32 crystalfreq) ++{ ++ const struct pmu0_plltab_entry *e; ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(pmu0_plltab); i++) { ++ e = &pmu0_plltab[i]; ++ if (e->freq == crystalfreq) ++ return e; ++ } ++ ++ return NULL; ++} ++ ++/* Tune the PLL to the crystal speed. crystalfreq is in kHz. */ ++static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc, ++ u32 crystalfreq) ++{ ++ struct ssb_bus *bus = cc->dev->bus; ++ const struct pmu0_plltab_entry *e; ++ u32 pmuctl, tmp, pllctl; ++ unsigned int i; ++ ++ if ((bus->chip_id == 0x5354) && !crystalfreq) { ++ /* The 5354 crystal freq is 25MHz */ ++ crystalfreq = 25000; ++ } ++ e = pmu0_plltab_find_entry(crystalfreq); ++ if (!e) ++ e = pmu0_plltab_find_entry(SSB_PMU0_DEFAULT_XTALFREQ); ++ BUG_ON(!e); ++ crystalfreq = e->freq; ++ cc->pmu.crystalfreq = e->freq; ++ ++ /* Check if the PLL already is programmed to this frequency. */ ++ pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL); ++ if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) { ++ /* We're already there... */ ++ return; ++ } ++ ++ ssb_printk(KERN_INFO PFX "Programming PLL to %u.%u MHz\n", ++ (crystalfreq / 1000), (crystalfreq % 1000)); ++ ++ /* First turn the PLL off. */ ++ switch (bus->chip_id) { ++ case 0x4328: ++ chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, ++ ~(1 << SSB_PLLRES_4328_BB_PLL_PU)); ++ chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, ++ ~(1 << SSB_PLLRES_4328_BB_PLL_PU)); ++ break; ++ case 0x5354: ++ chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, ++ ~(1 << SSB_PLLRES_5354_BB_PLL_PU)); ++ chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, ++ ~(1 << SSB_PLLRES_5354_BB_PLL_PU)); ++ break; ++ default: ++ SSB_WARN_ON(1); ++ } ++ for (i = 1500; i; i--) { ++ tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST); ++ if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)) ++ break; ++ udelay(10); ++ } ++ 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"); ++ ++ /* Set PDIV in PLL control 0. */ ++ pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL0); ++ if (crystalfreq >= SSB_PMU0_PLLCTL0_PDIV_FREQ) ++ pllctl |= SSB_PMU0_PLLCTL0_PDIV_MSK; ++ else ++ pllctl &= ~SSB_PMU0_PLLCTL0_PDIV_MSK; ++ ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL0, pllctl); ++ ++ /* Set WILD in PLL control 1. */ ++ pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL1); ++ pllctl &= ~SSB_PMU0_PLLCTL1_STOPMOD; ++ pllctl &= ~(SSB_PMU0_PLLCTL1_WILD_IMSK | SSB_PMU0_PLLCTL1_WILD_FMSK); ++ pllctl |= ((u32)e->wb_int << SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_IMSK; ++ pllctl |= ((u32)e->wb_frac << SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_FMSK; ++ if (e->wb_frac == 0) ++ pllctl |= SSB_PMU0_PLLCTL1_STOPMOD; ++ ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL1, pllctl); ++ ++ /* Set WILD in PLL control 2. */ ++ pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL2); ++ pllctl &= ~SSB_PMU0_PLLCTL2_WILD_IMSKHI; ++ pllctl |= (((u32)e->wb_int >> 4) << SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT) & SSB_PMU0_PLLCTL2_WILD_IMSKHI; ++ ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL2, pllctl); ++ ++ /* Set the crystalfrequency and the divisor. */ ++ pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL); ++ pmuctl &= ~SSB_CHIPCO_PMU_CTL_ILP_DIV; ++ pmuctl |= (((crystalfreq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT) ++ & SSB_CHIPCO_PMU_CTL_ILP_DIV; ++ pmuctl &= ~SSB_CHIPCO_PMU_CTL_XTALFREQ; ++ pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ; ++ chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl); ++} ++ ++/* Tune the PLL to the crystal speed. crystalfreq is in kHz. */ ++static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc, ++ u32 crystalfreq) ++{ ++ WARN_ON(1); ++ //TODO ++} ++ ++static void ssb_pmu_pll_init(struct ssb_chipcommon *cc) ++{ ++ struct ssb_bus *bus = cc->dev->bus; ++ u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */ ++ ++ if (bus->bustype == SSB_BUSTYPE_SSB) { ++ /* TODO: The user may override the crystal frequency. */ ++ } ++ ++ switch (bus->chip_id) { ++ case 0x4312: ++ case 0x4325: ++ ssb_pmu1_pllinit_r0(cc, crystalfreq); ++ break; ++ case 0x4328: ++ case 0x5354: ++ ssb_pmu0_pllinit_r0(cc, crystalfreq); ++ break; ++ default: ++ ssb_printk(KERN_ERR PFX ++ "ERROR: PLL init unknown for device %04X\n", ++ bus->chip_id); ++ } ++} ++ ++static void ssb_pmu_resources_init(struct ssb_chipcommon *cc) ++{ ++ struct ssb_bus *bus = cc->dev->bus; ++ u32 min_msk = 0, max_msk = 0; ++ ++ switch (bus->chip_id) { ++ case 0x4312: ++ /* We keep the default settings: ++ * min_msk = 0xCBB ++ * max_msk = 0x7FFFF ++ * updown table size = 0 ++ * depend table size = 0 ++ */ ++ break; ++ case 0x4325: ++ //TODO ++ break; ++ case 0x4328: ++ //TODO ++ break; ++ case 0x5354: ++ /* The PLL may turn on, if it decides so. */ ++ max_msk = 0xFFFFF; ++ break; ++ default: ++ ssb_printk(KERN_ERR PFX ++ "ERROR: PMU resource config unknown for device %04X\n", ++ bus->chip_id); ++ } ++ //TODO table upload ++ ++ /* Set the resource masks. */ ++ if (min_msk) ++ chipco_write32(cc, SSB_CHIPCO_PMU_MINRES_MSK, min_msk); ++ if (max_msk) ++ chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk); ++} ++ ++void ssb_pmu_init(struct ssb_chipcommon *cc) ++{ ++ struct ssb_bus *bus = cc->dev->bus; ++ u32 pmucap; ++ ++if (bus->chip_id != 0x5354) return; //FIXME currently only 5354 code implemented. ++ ++ if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU)) ++ return; ++ ++ 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); ++ ++ if (cc->pmu.rev >= 1) { ++ if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) { ++ chipco_mask32(cc, SSB_CHIPCO_PMU_CTL, ++ ~SSB_CHIPCO_PMU_CTL_NOILPONW); ++ } else { ++ chipco_set32(cc, SSB_CHIPCO_PMU_CTL, ++ SSB_CHIPCO_PMU_CTL_NOILPONW); ++ } ++ } ++ ssb_pmu_pll_init(cc); ++ ssb_pmu_resources_init(cc); ++} +Index: linux-2.6.28.2/drivers/ssb/driver_chipcommon.c +=================================================================== +--- linux-2.6.28.2.orig/drivers/ssb/driver_chipcommon.c 2009-02-01 13:07:03.000000000 +0100 ++++ linux-2.6.28.2/drivers/ssb/driver_chipcommon.c 2009-02-01 13:47:17.000000000 +0100 +@@ -26,19 +26,6 @@ enum ssb_clksrc { + }; + + +-static inline u32 chipco_read32(struct ssb_chipcommon *cc, +- u16 offset) +-{ +- return ssb_read32(cc->dev, offset); +-} +- +-static inline void chipco_write32(struct ssb_chipcommon *cc, +- u16 offset, +- u32 value) +-{ +- ssb_write32(cc->dev, offset, value); +-} +- + static inline u32 chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset, + u32 mask, u32 value) + { +@@ -246,6 +233,7 @@ void ssb_chipcommon_init(struct ssb_chip + { + if (!cc->dev) + return; /* We don't have a ChipCommon */ ++ ssb_pmu_init(cc); + chipco_powercontrol_init(cc); + ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST); + calc_fast_powerup_delay(cc); +Index: linux-2.6.28.2/include/linux/ssb/ssb_driver_chipcommon.h +=================================================================== +--- linux-2.6.28.2.orig/include/linux/ssb/ssb_driver_chipcommon.h 2009-02-01 13:22:59.000000000 +0100 ++++ linux-2.6.28.2/include/linux/ssb/ssb_driver_chipcommon.h 2009-02-01 19:17:25.000000000 +0100 +@@ -181,6 +181,16 @@ + #define SSB_CHIPCO_PROG_WAITCNT 0x0124 + #define SSB_CHIPCO_FLASH_CFG 0x0128 + #define SSB_CHIPCO_FLASH_WAITCNT 0x012C ++#define SSB_CHIPCO_CLKCTLST 0x01E0 /* Clock control and status (rev >= 20) */ ++#define SSB_CHIPCO_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */ ++#define SSB_CHIPCO_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */ ++#define SSB_CHIPCO_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */ ++#define SSB_CHIPCO_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */ ++#define SSB_CHIPCO_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */ ++#define SSB_CHIPCO_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */ ++#define SSB_CHIPCO_CLKCTLST_HAVEHT 0x00010000 /* HT available */ ++#define SSB_CHIPCO_CLKCTLST_HAVEALP 0x00020000 /* APL available */ ++#define SSB_CHIPCO_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */ + #define SSB_CHIPCO_UART0_DATA 0x0300 + #define SSB_CHIPCO_UART0_IMR 0x0304 + #define SSB_CHIPCO_UART0_FCR 0x0308 +@@ -197,6 +207,156 @@ + #define SSB_CHIPCO_UART1_LSR 0x0414 + #define SSB_CHIPCO_UART1_MSR 0x0418 + #define SSB_CHIPCO_UART1_SCRATCH 0x041C ++/* PMU registers (rev >= 20) */ ++#define SSB_CHIPCO_PMU_CTL 0x0600 /* PMU control */ ++#define SSB_CHIPCO_PMU_CTL_ILP_DIV 0xFFFF0000 /* ILP div mask */ ++#define SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT 16 ++#define SSB_CHIPCO_PMU_CTL_NOILPONW 0x00000200 /* No ILP on wait */ ++#define SSB_CHIPCO_PMU_CTL_HTREQEN 0x00000100 /* HT req enable */ ++#define SSB_CHIPCO_PMU_CTL_ALPREQEN 0x00000080 /* ALP req enable */ ++#define SSB_CHIPCO_PMU_CTL_XTALFREQ 0x0000007C /* Crystal freq */ ++#define SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT 2 ++#define SSB_CHIPCO_PMU_CTL_ILPDIVEN 0x00000002 /* ILP div enable */ ++#define SSB_CHIPCO_PMU_CTL_LPOSEL 0x00000001 /* LPO sel */ ++#define SSB_CHIPCO_PMU_CAP 0x0604 /* PMU capabilities */ ++#define SSB_CHIPCO_PMU_CAP_REVISION 0x000000FF /* Revision mask */ ++#define SSB_CHIPCO_PMU_STAT 0x0608 /* PMU status */ ++#define SSB_CHIPCO_PMU_STAT_INTPEND 0x00000040 /* Interrupt pending */ ++#define SSB_CHIPCO_PMU_STAT_SBCLKST 0x00000030 /* Backplane clock status? */ ++#define SSB_CHIPCO_PMU_STAT_HAVEALP 0x00000008 /* ALP available */ ++#define SSB_CHIPCO_PMU_STAT_HAVEHT 0x00000004 /* HT available */ ++#define SSB_CHIPCO_PMU_STAT_RESINIT 0x00000003 /* Res init */ ++#define SSB_CHIPCO_PMU_RES_STAT 0x060C /* PMU res status */ ++#define SSB_CHIPCO_PMU_RES_PEND 0x0610 /* PMU res pending */ ++#define SSB_CHIPCO_PMU_TIMER 0x0614 /* PMU timer */ ++#define SSB_CHIPCO_PMU_MINRES_MSK 0x0618 /* PMU min res mask */ ++#define SSB_CHIPCO_PMU_MAXRES_MSK 0x061C /* PMU max res mask */ ++#define SSB_CHIPCO_PMU_RES_TABSEL 0x0620 /* PMU res table sel */ ++#define SSB_CHIPCO_PMU_RES_DEPMSK 0x0624 /* PMU res dep mask */ ++#define SSB_CHIPCO_PMU_RES_UPDNTM 0x0628 /* PMU res updown timer */ ++#define SSB_CHIPCO_PMU_RES_TIMER 0x062C /* PMU res timer */ ++#define SSB_CHIPCO_PMU_CLKSTRETCH 0x0630 /* PMU clockstretch */ ++#define SSB_CHIPCO_PMU_WATCHDOG 0x0634 /* PMU watchdog */ ++#define SSB_CHIPCO_PMU_RES_REQTS 0x0640 /* PMU res req timer sel */ ++#define SSB_CHIPCO_PMU_RES_REQT 0x0644 /* PMU res req timer */ ++#define SSB_CHIPCO_PMU_RES_REQM 0x0648 /* PMU res req mask */ ++#define SSB_CHIPCO_CHIPCTL_ADDR 0x0650 ++#define SSB_CHIPCO_CHIPCTL_DATA 0x0654 ++#define SSB_CHIPCO_REGCTL_ADDR 0x0658 ++#define SSB_CHIPCO_REGCTL_DATA 0x065C ++#define SSB_CHIPCO_PLLCTL_ADDR 0x0660 ++#define SSB_CHIPCO_PLLCTL_DATA 0x0664 ++ ++ ++ ++/** PMU PLL registers */ ++ ++/* PMU rev 0 PLL registers */ ++#define SSB_PMU0_PLLCTL0 0 ++#define SSB_PMU0_PLLCTL0_PDIV_MSK 0x00000001 ++#define SSB_PMU0_PLLCTL0_PDIV_FREQ 25000 /* kHz */ ++#define SSB_PMU0_PLLCTL1 1 ++#define SSB_PMU0_PLLCTL1_WILD_IMSK 0xF0000000 /* Wild int mask (low nibble) */ ++#define SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT 28 ++#define SSB_PMU0_PLLCTL1_WILD_FMSK 0x0FFFFF00 /* Wild frac mask */ ++#define SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT 8 ++#define SSB_PMU0_PLLCTL1_STOPMOD 0x00000040 /* Stop mod */ ++#define SSB_PMU0_PLLCTL2 2 ++#define SSB_PMU0_PLLCTL2_WILD_IMSKHI 0x0000000F /* Wild int mask (high nibble) */ ++#define SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT 0 ++ ++/* PMU rev 1 PLL registers */ ++#define SSB_PMU1_PLLCTL0 0 ++#define SSB_PMU1_PLLCTL1 1 ++#define SSB_PMU1_PLLCTL2 2 ++#define SSB_PMU1_PLLCTL3 3 ++#define SSB_PMU1_PLLCTL4 4 ++#define SSB_PMU1_PLLCTL5 5 ++ ++/* BCM4312 PLL resource numbers. */ ++#define SSB_PLLRES_4312_SWITCHER_BURST 0 ++#define SSB_PLLRES_4312_SWITCHER_PWM 1 ++#define SSB_PLLRES_4312_PA_REF_LDO 2 ++#define SSB_PLLRES_4312_CORE_LDO_BURST 3 ++#define SSB_PLLRES_4312_CORE_LDO_PWM 4 ++#define SSB_PLLRES_4312_RADIO_LDO 5 ++#define SSB_PLLRES_4312_ILP_REQUEST 6 ++#define SSB_PLLRES_4312_BG_FILTBYP 7 ++#define SSB_PLLRES_4312_TX_FILTBYP 8 ++#define SSB_PLLRES_4312_RX_FILTBYP 9 ++#define SSB_PLLRES_4312_XTAL_PU 10 ++#define SSB_PLLRES_4312_ALP_AVAIL 11 ++#define SSB_PLLRES_4312_BB_PLL_FILTBYP 12 ++#define SSB_PLLRES_4312_RF_PLL_FILTBYP 13 ++#define SSB_PLLRES_4312_HT_AVAIL 14 ++ ++/* BCM4325 PLL resource numbers. */ ++#define SSB_PLLRES_4325_BUCK_BOOST_BURST 0 ++#define SSB_PLLRES_4325_CBUCK_BURST 1 ++#define SSB_PLLRES_4325_CBUCK_PWM 2 ++#define SSB_PLLRES_4325_CLDO_CBUCK_BURST 3 ++#define SSB_PLLRES_4325_CLDO_CBUCK_PWM 4 ++#define SSB_PLLRES_4325_BUCK_BOOST_PWM 5 ++#define SSB_PLLRES_4325_ILP_REQUEST 6 ++#define SSB_PLLRES_4325_ABUCK_BURST 7 ++#define SSB_PLLRES_4325_ABUCK_PWM 8 ++#define SSB_PLLRES_4325_LNLDO1_PU 9 ++#define SSB_PLLRES_4325_LNLDO2_PU 10 ++#define SSB_PLLRES_4325_LNLDO3_PU 11 ++#define SSB_PLLRES_4325_LNLDO4_PU 12 ++#define SSB_PLLRES_4325_XTAL_PU 13 ++#define SSB_PLLRES_4325_ALP_AVAIL 14 ++#define SSB_PLLRES_4325_RX_PWRSW_PU 15 ++#define SSB_PLLRES_4325_TX_PWRSW_PU 16 ++#define SSB_PLLRES_4325_RFPLL_PWRSW_PU 17 ++#define SSB_PLLRES_4325_LOGEN_PWRSW_PU 18 ++#define SSB_PLLRES_4325_AFE_PWRSW_PU 19 ++#define SSB_PLLRES_4325_BBPLL_PWRSW_PU 20 ++#define SSB_PLLRES_4325_HT_AVAIL 21 ++ ++/* BCM4328 PLL resource numbers. */ ++#define SSB_PLLRES_4328_EXT_SWITCHER_PWM 0 ++#define SSB_PLLRES_4328_BB_SWITCHER_PWM 1 ++#define SSB_PLLRES_4328_BB_SWITCHER_BURST 2 ++#define SSB_PLLRES_4328_BB_EXT_SWITCHER_BURST 3 ++#define SSB_PLLRES_4328_ILP_REQUEST 4 ++#define SSB_PLLRES_4328_RADIO_SWITCHER_PWM 5 ++#define SSB_PLLRES_4328_RADIO_SWITCHER_BURST 6 ++#define SSB_PLLRES_4328_ROM_SWITCH 7 ++#define SSB_PLLRES_4328_PA_REF_LDO 8 ++#define SSB_PLLRES_4328_RADIO_LDO 9 ++#define SSB_PLLRES_4328_AFE_LDO 10 ++#define SSB_PLLRES_4328_PLL_LDO 11 ++#define SSB_PLLRES_4328_BG_FILTBYP 12 ++#define SSB_PLLRES_4328_TX_FILTBYP 13 ++#define SSB_PLLRES_4328_RX_FILTBYP 14 ++#define SSB_PLLRES_4328_XTAL_PU 15 ++#define SSB_PLLRES_4328_XTAL_EN 16 ++#define SSB_PLLRES_4328_BB_PLL_FILTBYP 17 ++#define SSB_PLLRES_4328_RF_PLL_FILTBYP 18 ++#define SSB_PLLRES_4328_BB_PLL_PU 19 ++ ++/* BCM5354 PLL resource numbers. */ ++#define SSB_PLLRES_5354_EXT_SWITCHER_PWM 0 ++#define SSB_PLLRES_5354_BB_SWITCHER_PWM 1 ++#define SSB_PLLRES_5354_BB_SWITCHER_BURST 2 ++#define SSB_PLLRES_5354_BB_EXT_SWITCHER_BURST 3 ++#define SSB_PLLRES_5354_ILP_REQUEST 4 ++#define SSB_PLLRES_5354_RADIO_SWITCHER_PWM 5 ++#define SSB_PLLRES_5354_RADIO_SWITCHER_BURST 6 ++#define SSB_PLLRES_5354_ROM_SWITCH 7 ++#define SSB_PLLRES_5354_PA_REF_LDO 8 ++#define SSB_PLLRES_5354_RADIO_LDO 9 ++#define SSB_PLLRES_5354_AFE_LDO 10 ++#define SSB_PLLRES_5354_PLL_LDO 11 ++#define SSB_PLLRES_5354_BG_FILTBYP 12 ++#define SSB_PLLRES_5354_TX_FILTBYP 13 ++#define SSB_PLLRES_5354_RX_FILTBYP 14 ++#define SSB_PLLRES_5354_XTAL_PU 15 ++#define SSB_PLLRES_5354_XTAL_EN 16 ++#define SSB_PLLRES_5354_BB_PLL_FILTBYP 17 ++#define SSB_PLLRES_5354_RF_PLL_FILTBYP 18 ++#define SSB_PLLRES_5354_BB_PLL_PU 19 + + + +@@ -353,11 +513,20 @@ + struct ssb_device; + struct ssb_serial_port; + ++/* Data for the PMU, if available. ++ * Check availability with ((struct ssb_chipcommon)->capabilities & SSB_CHIPCO_CAP_PMU) ++ */ ++struct ssb_chipcommon_pmu { ++ u8 rev; /* PMU revision */ ++ u32 crystalfreq; /* The active crystal frequency (in kHz) */ ++}; ++ + struct ssb_chipcommon { + struct ssb_device *dev; + u32 capabilities; + /* Fast Powerup Delay constant */ + u16 fast_pwrup_delay; ++ struct ssb_chipcommon_pmu pmu; + }; + + static inline bool ssb_chipco_available(struct ssb_chipcommon *cc) +@@ -365,6 +534,17 @@ static inline bool ssb_chipco_available( + return (cc->dev != NULL); + } + ++/* Register access */ ++#define chipco_read32(cc, offset) ssb_read32((cc)->dev, offset) ++#define chipco_write32(cc, offset, val) ssb_write32((cc)->dev, offset, val) ++ ++#define chipco_mask32(cc, offset, mask) \ ++ chipco_write32(cc, offset, chipco_read32(cc, offset) & (mask)) ++#define chipco_set32(cc, offset, set) \ ++ chipco_write32(cc, offset, chipco_read32(cc, offset) | (set)) ++#define chipco_maskset32(cc, offset, mask, set) \ ++ chipco_write32(cc, offset, (chipco_read32(cc, offset) & (mask)) | (set)) ++ + extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); + + extern void ssb_chipco_suspend(struct ssb_chipcommon *cc); +@@ -406,4 +586,8 @@ extern int ssb_chipco_serial_init(struct + struct ssb_serial_port *ports); + #endif /* CONFIG_SSB_SERIAL */ + ++/* PMU support */ ++extern void ssb_pmu_init(struct ssb_chipcommon *cc); ++ ++ + #endif /* LINUX_SSB_CHIPCO_H_ */