Skip to content

Commit

Permalink
bcma: get CPU clock
Browse files Browse the repository at this point in the history
Add method to return the clock of the CPU. This is needed by the arch
code to calculate the mips_hpt_frequency.

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Acked-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Hauke Mehrtens authored and John W. Linville committed Aug 8, 2011
1 parent e3afe0e commit 908debc
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/bcma/bcma_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc);

/* driver_chipcommon_pmu.c */
u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc);
u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc);

#ifdef CONFIG_BCMA_HOST_PCI
/* host_pci.c */
Expand Down
107 changes: 107 additions & 0 deletions drivers/bcma/driver_chipcommon_pmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
#include "bcma_private.h"
#include <linux/bcma/bcma.h>

static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
{
bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
}

static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
u32 offset, u32 mask, u32 set)
{
Expand Down Expand Up @@ -162,3 +169,103 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
}
return BCMA_CC_PMU_ALP_CLOCK;
}

/* Find the output of the "m" pll divider given pll controls that start with
* pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
*/
static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
{
u32 tmp, div, ndiv, p1, p2, fc;
struct bcma_bus *bus = cc->core->bus;

BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));

BUG_ON(!m || m > 4);

if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
/* Detect failure in clock setting */
tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
if (tmp & 0x40000)
return 133 * 1000000;
}

tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;

tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
BCMA_CC_PPL_MDIV_MASK;

tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;

/* Do calculation in Mhz */
fc = bcma_pmu_alp_clock(cc) / 1000000;
fc = (p1 * ndiv * fc) / p2;

/* Return clock in Hertz */
return (fc / div) * 1000000;
}

/* query bus clock frequency for PMU-enabled chipcommon */
u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;

switch (bus->chipinfo.id) {
case 0x4716:
case 0x4748:
case 47162:
return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
BCMA_CC_PMU5_MAINPLL_SSB);
case 0x5356:
return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
BCMA_CC_PMU5_MAINPLL_SSB);
case 0x5357:
case 0x4749:
return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
BCMA_CC_PMU5_MAINPLL_SSB);
case 0x5300:
return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
BCMA_CC_PMU5_MAINPLL_SSB);
case 53572:
return 75000000;
default:
pr_warn("No backplane clock specified for %04X device, "
"pmu rev. %d, using default %d Hz\n",
bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
}
return BCMA_CC_PMU_HT_CLOCK;
}

/* query cpu clock frequency for PMU-enabled chipcommon */
u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;

if (bus->chipinfo.id == 53572)
return 300000000;

if (cc->pmu.rev >= 5) {
u32 pll;
switch (bus->chipinfo.id) {
case 0x5356:
pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
break;
case 0x5357:
case 0x4749:
pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
break;
default:
pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
break;
}

/* TODO: if (bus->chipinfo.id == 0x5300)
return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
}

return bcma_pmu_get_clockcontrol(cc);
}
12 changes: 12 additions & 0 deletions drivers/bcma/driver_mips.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,18 @@ static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
}
}

u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
{
struct bcma_bus *bus = mcore->core->bus;

if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
return bcma_pmu_get_clockcpu(&bus->drv_cc);

pr_err("No PMU available, need this to get the cpu clock\n");
return 0;
}
EXPORT_SYMBOL(bcma_cpu_clock);

static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
{
struct bcma_bus *bus = mcore->core->bus;
Expand Down
39 changes: 39 additions & 0 deletions include/linux/bcma/bcma_driver_chipcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,47 @@
#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
#define BCMA_CC_SPROM_PCIE6 0x0830 /* SPROM beginning on PCIe rev >= 6 */

/* Divider allocation in 4716/47162/5356 */
#define BCMA_CC_PMU5_MAINPLL_CPU 1
#define BCMA_CC_PMU5_MAINPLL_MEM 2
#define BCMA_CC_PMU5_MAINPLL_SSB 3

/* PLL usage in 4716/47162 */
#define BCMA_CC_PMU4716_MAINPLL_PLL0 12

/* PLL usage in 5356/5357 */
#define BCMA_CC_PMU5356_MAINPLL_PLL0 0
#define BCMA_CC_PMU5357_MAINPLL_PLL0 0

/* 4706 PMU */
#define BCMA_CC_PMU4706_MAINPLL_PLL0 0

/* ALP clock on pre-PMU chips */
#define BCMA_CC_PMU_ALP_CLOCK 20000000
/* HT clock for systems with PMU-enabled chipcommon */
#define BCMA_CC_PMU_HT_CLOCK 80000000

/* PMU rev 5 (& 6) */
#define BCMA_CC_PPL_P1P2_OFF 0
#define BCMA_CC_PPL_P1_MASK 0x0f000000
#define BCMA_CC_PPL_P1_SHIFT 24
#define BCMA_CC_PPL_P2_MASK 0x00f00000
#define BCMA_CC_PPL_P2_SHIFT 20
#define BCMA_CC_PPL_M14_OFF 1
#define BCMA_CC_PPL_MDIV_MASK 0x000000ff
#define BCMA_CC_PPL_MDIV_WIDTH 8
#define BCMA_CC_PPL_NM5_OFF 2
#define BCMA_CC_PPL_NDIV_MASK 0xfff00000
#define BCMA_CC_PPL_NDIV_SHIFT 20
#define BCMA_CC_PPL_FMAB_OFF 3
#define BCMA_CC_PPL_MRAT_MASK 0xf0000000
#define BCMA_CC_PPL_MRAT_SHIFT 28
#define BCMA_CC_PPL_ABRAT_MASK 0x08000000
#define BCMA_CC_PPL_ABRAT_SHIFT 27
#define BCMA_CC_PPL_FDIV_MASK 0x07ffffff
#define BCMA_CC_PPL_PLLCTL_OFF 4
#define BCMA_CC_PPL_PCHI_OFF 5
#define BCMA_CC_PPL_PCHI_MASK 0x0000003f

/* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
Expand Down
2 changes: 2 additions & 0 deletions include/linux/bcma/bcma_driver_mips.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
#endif

extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);

extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);

#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */

0 comments on commit 908debc

Please sign in to comment.