diff options
Diffstat (limited to 'drivers/bcma/driver_chipcommon_pmu.c')
-rw-r--r-- | drivers/bcma/driver_chipcommon_pmu.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index 354caeea6397..5940c81e7e12 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c | |||
@@ -11,6 +11,13 @@ | |||
11 | #include "bcma_private.h" | 11 | #include "bcma_private.h" |
12 | #include <linux/bcma/bcma.h> | 12 | #include <linux/bcma/bcma.h> |
13 | 13 | ||
14 | static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset) | ||
15 | { | ||
16 | bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset); | ||
17 | bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR); | ||
18 | return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA); | ||
19 | } | ||
20 | |||
14 | static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, | 21 | static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, |
15 | u32 offset, u32 mask, u32 set) | 22 | u32 offset, u32 mask, u32 set) |
16 | { | 23 | { |
@@ -162,3 +169,103 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc) | |||
162 | } | 169 | } |
163 | return BCMA_CC_PMU_ALP_CLOCK; | 170 | return BCMA_CC_PMU_ALP_CLOCK; |
164 | } | 171 | } |
172 | |||
173 | /* Find the output of the "m" pll divider given pll controls that start with | ||
174 | * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc. | ||
175 | */ | ||
176 | static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m) | ||
177 | { | ||
178 | u32 tmp, div, ndiv, p1, p2, fc; | ||
179 | struct bcma_bus *bus = cc->core->bus; | ||
180 | |||
181 | BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0)); | ||
182 | |||
183 | BUG_ON(!m || m > 4); | ||
184 | |||
185 | if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) { | ||
186 | /* Detect failure in clock setting */ | ||
187 | tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); | ||
188 | if (tmp & 0x40000) | ||
189 | return 133 * 1000000; | ||
190 | } | ||
191 | |||
192 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF); | ||
193 | p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT; | ||
194 | p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT; | ||
195 | |||
196 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF); | ||
197 | div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) & | ||
198 | BCMA_CC_PPL_MDIV_MASK; | ||
199 | |||
200 | tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF); | ||
201 | ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT; | ||
202 | |||
203 | /* Do calculation in Mhz */ | ||
204 | fc = bcma_pmu_alp_clock(cc) / 1000000; | ||
205 | fc = (p1 * ndiv * fc) / p2; | ||
206 | |||
207 | /* Return clock in Hertz */ | ||
208 | return (fc / div) * 1000000; | ||
209 | } | ||
210 | |||
211 | /* query bus clock frequency for PMU-enabled chipcommon */ | ||
212 | u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc) | ||
213 | { | ||
214 | struct bcma_bus *bus = cc->core->bus; | ||
215 | |||
216 | switch (bus->chipinfo.id) { | ||
217 | case 0x4716: | ||
218 | case 0x4748: | ||
219 | case 47162: | ||
220 | return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0, | ||
221 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
222 | case 0x5356: | ||
223 | return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0, | ||
224 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
225 | case 0x5357: | ||
226 | case 0x4749: | ||
227 | return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0, | ||
228 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
229 | case 0x5300: | ||
230 | return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0, | ||
231 | BCMA_CC_PMU5_MAINPLL_SSB); | ||
232 | case 53572: | ||
233 | return 75000000; | ||
234 | default: | ||
235 | pr_warn("No backplane clock specified for %04X device, " | ||
236 | "pmu rev. %d, using default %d Hz\n", | ||
237 | bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK); | ||
238 | } | ||
239 | return BCMA_CC_PMU_HT_CLOCK; | ||
240 | } | ||
241 | |||
242 | /* query cpu clock frequency for PMU-enabled chipcommon */ | ||
243 | u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc) | ||
244 | { | ||
245 | struct bcma_bus *bus = cc->core->bus; | ||
246 | |||
247 | if (bus->chipinfo.id == 53572) | ||
248 | return 300000000; | ||
249 | |||
250 | if (cc->pmu.rev >= 5) { | ||
251 | u32 pll; | ||
252 | switch (bus->chipinfo.id) { | ||
253 | case 0x5356: | ||
254 | pll = BCMA_CC_PMU5356_MAINPLL_PLL0; | ||
255 | break; | ||
256 | case 0x5357: | ||
257 | case 0x4749: | ||
258 | pll = BCMA_CC_PMU5357_MAINPLL_PLL0; | ||
259 | break; | ||
260 | default: | ||
261 | pll = BCMA_CC_PMU4716_MAINPLL_PLL0; | ||
262 | break; | ||
263 | } | ||
264 | |||
265 | /* TODO: if (bus->chipinfo.id == 0x5300) | ||
266 | return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */ | ||
267 | return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU); | ||
268 | } | ||
269 | |||
270 | return bcma_pmu_get_clockcontrol(cc); | ||
271 | } | ||