diff options
Diffstat (limited to 'drivers/bcma/driver_chipcommon_pmu.c')
| -rw-r--r-- | drivers/bcma/driver_chipcommon_pmu.c | 192 |
1 files changed, 182 insertions, 10 deletions
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index fcc63db0ce75..800163c8c2e7 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c | |||
| @@ -9,22 +9,50 @@ | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include "bcma_private.h" | 11 | #include "bcma_private.h" |
| 12 | #include <linux/export.h> | ||
| 12 | #include <linux/bcma/bcma.h> | 13 | #include <linux/bcma/bcma.h> |
| 13 | 14 | ||
| 14 | static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, | 15 | static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset) |
| 15 | u32 offset, u32 mask, u32 set) | ||
| 16 | { | 16 | { |
| 17 | u32 value; | 17 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); |
| 18 | bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); | ||
| 19 | return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA); | ||
| 20 | } | ||
| 18 | 21 | ||
| 19 | bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); | 22 | void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value) |
| 23 | { | ||
| 24 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); | ||
| 25 | bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); | ||
| 26 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value); | ||
| 27 | } | ||
| 28 | EXPORT_SYMBOL_GPL(bcma_chipco_pll_write); | ||
| 29 | |||
| 30 | void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, | ||
| 31 | u32 set) | ||
| 32 | { | ||
| 33 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); | ||
| 34 | bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); | ||
| 35 | bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set); | ||
| 36 | } | ||
| 37 | EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset); | ||
| 38 | |||
| 39 | void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, | ||
| 40 | u32 offset, u32 mask, u32 set) | ||
| 41 | { | ||
| 20 | bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset); | 42 | bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset); |
| 21 | bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); | 43 | bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR); |
| 22 | value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); | 44 | bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set); |
| 23 | value &= mask; | 45 | } |
| 24 | value |= set; | 46 | EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset); |
| 25 | bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value); | 47 | |
| 26 | bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA); | 48 | void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, |
| 49 | u32 set) | ||
| 50 | { | ||
| 51 | bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset); | ||
| 52 | bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR); | ||
| 53 | bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set); | ||
| 27 | } | 54 | } |
| 55 | EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset); | ||
| 28 | 56 | ||
| 29 | static void bcma_pmu_pll_init(struct bcma_drv_cc *cc) | 57 | static void bcma_pmu_pll_init(struct bcma_drv_cc *cc) |
| 30 | { | 58 | { |
| @@ -83,6 +111,24 @@ void bcma_pmu_swreg_init(struct bcma_drv_cc *cc) | |||
| 83 | } | 111 | } |
| 84 | } | 112 | } |
| 85 | 113 | ||
| 114 | /* Disable to allow reading SPROM. Don't know the adventages of enabling it. */ | ||
| 115 | void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable) | ||
| 116 | { | ||
| 117 | struct bcma_bus *bus = cc->core->bus; | ||
| 118 | u32 val; | ||
| 119 | |||
| 120 | val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL); | ||
| 121 | if (enable) { | ||
| 122 | val |= BCMA_CHIPCTL_4331_EXTPA_EN; | ||
| 123 | if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11) | ||
| 124 | val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; | ||
| 125 | } else { | ||
| 126 | val &= ~BCMA_CHIPCTL_4331_EXTPA_EN; | ||
| 127 | val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; | ||
| 128 | } | ||
| 129 | bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val); | ||
| 130 | } | ||
| 131 | |||
| 86 | void bcma_pmu_workarounds(struct bcma_drv_cc *cc) | 132 | void bcma_pmu_workarounds(struct bcma_drv_cc *cc) |
| 87 | { | 133 | { |
| 88 | struct bcma_bus *bus = cc->core->bus; | 134 | struct bcma_bus *bus = cc->core->bus; |
| @@ -92,7 +138,7 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc) | |||
| 92 | bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); | 138 | bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); |
| 93 | break; | 139 | break; |
| 94 | case 0x4331: | 140 | case 0x4331: |
| 95 | pr_err("Enabling Ext PA lines not implemented\n"); | 141 | /* BCM4331 workaround is SPROM-related, we put it in sprom.c */ |
| 96 | break; | 142 | break; |
| 97 | case 43224: | 143 | case 43224: |
| 98 | if (bus->chipinfo.rev == 0) { | 144 | if (bus->chipinfo.rev == 0) { |
| @@ -136,3 +182,129 @@ void bcma_pmu_init(struct bcma_drv_cc *cc) | |||
| 136 | bcma_pmu_swreg_init(cc); | 182 | bcma_pmu_swreg_init(cc); |
| 137 | bcma_pmu_workarounds(cc); | 183 | bcma_pmu_workarounds(cc); |
| 138 | } | 184 | } |
| 185 | |||
| 186 | u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc) | ||
| 187 | { | ||
| 188 | struct bcma_bus *bus = cc->core->bus; | ||
| 189 | |||
| 190 | switch (bus->chipinfo.id) { | ||
| 191 | case 0x4716: | ||
| 192 | case 0x4748: | ||
| 193 | case 47162: | ||
| 194 | case 0x4313: | ||
| 195 | case 0x5357: | ||
| 196 | case 0x4749: | ||
| 197 | case 53572: | ||
| 198 | /* always 20Mhz */ | ||
| 199 | return 20000 * 1000; | ||
| 200 | case 0x5356: | ||
| 201 | case 0x5300: | ||
| 202 | /* always 25Mhz */ | ||
| 203 | return 25000 * 1000; | ||
| 204 | default: | ||
| 205 | pr_warn("No ALP clock specified for %04X device, " | ||
| 206 | "pmu rev. %d, using default %d Hz\n", | ||
| 207 | bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK); | ||
| 208 | } | ||
| 209 | return BCMA_CC_PMU_ALP_CLOCK; | ||
| 210 | } | ||
| 211 | |||
| 212 | /* Find the output of the "m" pll divider given pll controls that start with | ||
| 213 | * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc. | ||
| 214 | */ | ||
| 215 | static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m) | ||
| 216 | { | ||
| 217 | u32 tmp, div, ndiv, p1, p2, fc; | ||
| 218 | struct bcma_bus *bus = cc->core->bus; | ||
| 219 | |||
| 220 | BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0)); | ||
| 221 | |||
| 222 | BUG_ON(!m || m > 4); | ||
| 223 | |||
| 224 | if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) { | ||
| 225 | /* Detect failure in clock setting */ | ||
| 226 | tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); | ||
| 227 | if (tmp & 0x40000) | ||
| 228 | return 133 * 1000000; | ||
| 229 | } | ||
| 230 | |||
| 231 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF); | ||
| 232 | p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT; | ||
| 233 | p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT; | ||
| 234 | |||
| 235 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF); | ||
| 236 | div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) & | ||
| 237 | BCMA_CC_PPL_MDIV_MASK; | ||
| 238 | |||
| 239 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF); | ||
| 240 | ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT; | ||
| 241 | |||
| 242 | /* Do calculation in Mhz */ | ||
| 243 | fc = bcma_pmu_alp_clock(cc) / 1000000; | ||
| 244 | fc = (p1 * ndiv * fc) / p2; | ||
| 245 | |||
| 246 | /* Return clock in Hertz */ | ||
| 247 | return (fc / div) * 1000000; | ||
| 248 | } | ||
| 249 | |||
| 250 | /* query bus clock frequency for PMU-enabled chipcommon */ | ||
| 251 | u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc) | ||
| 252 | { | ||
| 253 | struct bcma_bus *bus = cc->core->bus; | ||
| 254 | |||
| 255 | switch (bus->chipinfo.id) { | ||
| 256 | case 0x4716: | ||
| 257 | case 0x4748: | ||
| 258 | case 47162: | ||
| 259 | return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0, | ||
| 260 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
| 261 | case 0x5356: | ||
| 262 | return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0, | ||
| 263 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
| 264 | case 0x5357: | ||
| 265 | case 0x4749: | ||
| 266 | return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0, | ||
| 267 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
| 268 | case 0x5300: | ||
| 269 | return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0, | ||
| 270 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
| 271 | case 53572: | ||
| 272 | return 75000000; | ||
| 273 | default: | ||
| 274 | pr_warn("No backplane clock specified for %04X device, " | ||
| 275 | "pmu rev. %d, using default %d Hz\n", | ||
| 276 | bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK); | ||
| 277 | } | ||
| 278 | return BCMA_CC_PMU_HT_CLOCK; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* query cpu clock frequency for PMU-enabled chipcommon */ | ||
| 282 | u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc) | ||
| 283 | { | ||
| 284 | struct bcma_bus *bus = cc->core->bus; | ||
| 285 | |||
| 286 | if (bus->chipinfo.id == 53572) | ||
| 287 | return 300000000; | ||
| 288 | |||
| 289 | if (cc->pmu.rev >= 5) { | ||
| 290 | u32 pll; | ||
| 291 | switch (bus->chipinfo.id) { | ||
| 292 | case 0x5356: | ||
| 293 | pll = BCMA_CC_PMU5356_MAINPLL_PLL0; | ||
| 294 | break; | ||
| 295 | case 0x5357: | ||
| 296 | case 0x4749: | ||
| 297 | pll = BCMA_CC_PMU5357_MAINPLL_PLL0; | ||
| 298 | break; | ||
| 299 | default: | ||
| 300 | pll = BCMA_CC_PMU4716_MAINPLL_PLL0; | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | |||
| 304 | /* TODO: if (bus->chipinfo.id == 0x5300) | ||
| 305 | return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */ | ||
| 306 | return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU); | ||
| 307 | } | ||
| 308 | |||
| 309 | return bcma_pmu_get_clockcontrol(cc); | ||
| 310 | } | ||
