[mips/broadcom]: Replace static frequency table with generic PMU clock
handling. - Extended PWRCTL/PMU APIs to support querying clock frequency during very early boot, prior to bus attach. - Implement generic PMU-based calculation of UART rclk values. - Replaced use of static frequency tables (bcm_socinfo) with runtime-determined values. Approved by: adrian (mentor) Differential Revision: https://reviews.freebsd.org/D7552
This commit is contained in:
parent
f90f4b6532
commit
eb175e8bfb
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=304871
@ -31,6 +31,10 @@
|
|||||||
required during bus
|
required during bus
|
||||||
enumeration */
|
enumeration */
|
||||||
|
|
||||||
|
/** Evaluates to true if the given ChipCommon core revision supports
|
||||||
|
* the CHIPC_CORECTRL register */
|
||||||
|
#define CHIPC_HWREV_HAS_CORECTRL(hwrev) ((hwrev) >= 1)
|
||||||
|
|
||||||
/** Evaluates to true if the given ChipCommon core revision provides
|
/** Evaluates to true if the given ChipCommon core revision provides
|
||||||
* the core count via the chip identification register. */
|
* the core count via the chip identification register. */
|
||||||
#define CHIPC_NCORES_MIN_HWREV(hwrev) ((hwrev) == 4 || (hwrev) >= 6)
|
#define CHIPC_NCORES_MIN_HWREV(hwrev) ((hwrev) == 4 || (hwrev) >= 6)
|
||||||
@ -278,14 +282,14 @@ enum {
|
|||||||
#define CHIPC_CST_SPROM_OTP_SEL_R23_SHIFT 6
|
#define CHIPC_CST_SPROM_OTP_SEL_R23_SHIFT 6
|
||||||
|
|
||||||
/* PLL type */
|
/* PLL type */
|
||||||
#define CHIPC_PLL_NONE 0x00
|
#define CHIPC_PLL_NONE 0x0
|
||||||
#define CHIPC_PLL_TYPE1 0x10 /* 48MHz base, 3 dividers */
|
#define CHIPC_PLL_TYPE1 0x2 /* 48MHz base, 3 dividers */
|
||||||
#define CHIPC_PLL_TYPE2 0x20 /* 48MHz, 4 dividers */
|
#define CHIPC_PLL_TYPE2 0x4 /* 48MHz, 4 dividers */
|
||||||
#define CHIPC_PLL_TYPE3 0x30 /* 25MHz, 2 dividers */
|
#define CHIPC_PLL_TYPE3 0x6 /* 25MHz, 2 dividers */
|
||||||
#define CHIPC_PLL_TYPE4 0x08 /* 48MHz, 4 dividers */
|
#define CHIPC_PLL_TYPE4 0x8 /* 48MHz, 4 dividers */
|
||||||
#define CHIPC_PLL_TYPE5 0x18 /* 25MHz, 4 dividers */
|
#define CHIPC_PLL_TYPE5 0x3 /* 25MHz, 4 dividers */
|
||||||
#define CHIPC_PLL_TYPE6 0x28 /* 100/200 or 120/240 only */
|
#define CHIPC_PLL_TYPE6 0x5 /* 100/200 or 120/240 only */
|
||||||
#define CHIPC_PLL_TYPE7 0x38 /* 25MHz, 4 dividers */
|
#define CHIPC_PLL_TYPE7 0x7 /* 25MHz, 4 dividers */
|
||||||
|
|
||||||
/* dynamic clock control defines */
|
/* dynamic clock control defines */
|
||||||
#define CHIPC_LPOMINFREQ 25000 /* low power oscillator min */
|
#define CHIPC_LPOMINFREQ 25000 /* low power oscillator min */
|
||||||
|
@ -46,8 +46,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include "bhnd_pwrctl_private.h"
|
#include "bhnd_pwrctl_private.h"
|
||||||
|
|
||||||
static uint32_t bhnd_pwrctl_factor6(uint32_t x);
|
static uint32_t bhnd_pwrctl_factor6(uint32_t x);
|
||||||
static uint32_t bhnd_pwrctl_clock_rate(uint32_t pll_type, uint32_t n,
|
|
||||||
uint32_t m);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the factor value corresponding to a given N3M clock control magic
|
* Return the factor value corresponding to a given N3M clock control magic
|
||||||
@ -74,15 +72,123 @@ bhnd_pwrctl_factor6(uint32_t x)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the backplane clock's chipc 'M' register offset for a given PLL type,
|
||||||
|
* or 0 if a fixed clock speed should be used.
|
||||||
|
*
|
||||||
|
* @param cid Chip identification.
|
||||||
|
* @param pll_type PLL type (CHIPC_PLL_TYPE*)
|
||||||
|
* @param[out] fixed_hz If 0 is returned, will be set to the fixed clock
|
||||||
|
* speed for this device.
|
||||||
|
*/
|
||||||
|
bus_size_t
|
||||||
|
bhnd_pwrctl_si_clkreg_m(const struct bhnd_chipid *cid,
|
||||||
|
uint8_t pll_type, uint32_t *fixed_hz)
|
||||||
|
{
|
||||||
|
switch (pll_type) {
|
||||||
|
case CHIPC_PLL_TYPE6:
|
||||||
|
return (CHIPC_CLKC_M3);
|
||||||
|
case CHIPC_PLL_TYPE3:
|
||||||
|
return (CHIPC_CLKC_M2);
|
||||||
|
default:
|
||||||
|
return (CHIPC_CLKC_SB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the backplane clock speed (in Hz) for a given a set of clock
|
||||||
|
* control values.
|
||||||
|
*
|
||||||
|
* @param cid Chip identification.
|
||||||
|
* @param pll_type PLL type (CHIPC_PLL_TYPE*)
|
||||||
|
* @param n clock control N register value.
|
||||||
|
* @param m clock control M register value.
|
||||||
|
*/
|
||||||
|
uint32_t
|
||||||
|
bhnd_pwrctl_si_clock_rate(const struct bhnd_chipid *cid,
|
||||||
|
uint32_t pll_type, uint32_t n, uint32_t m)
|
||||||
|
{
|
||||||
|
uint32_t rate;
|
||||||
|
|
||||||
|
KASSERT(bhnd_pwrctl_si_clkreg_m(cid, pll_type, NULL) != 0,
|
||||||
|
("can't compute clock rate on fixed clock"));
|
||||||
|
|
||||||
|
rate = bhnd_pwrctl_clock_rate(pll_type, n, m);
|
||||||
|
if (pll_type == CHIPC_PLL_TYPE3)
|
||||||
|
rate /= 2;
|
||||||
|
|
||||||
|
return (rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the CPU clock's chipc 'M' register offset for a given PLL type,
|
||||||
|
* or 0 if a fixed clock speed should be used.
|
||||||
|
*
|
||||||
|
* @param cid Chip identification.
|
||||||
|
* @param pll_type PLL type (CHIPC_PLL_TYPE*)
|
||||||
|
* @param[out] fixed_hz If 0 is returned, will be set to the fixed clock
|
||||||
|
* speed for this device.
|
||||||
|
*/
|
||||||
|
bus_size_t
|
||||||
|
bhnd_pwrctl_cpu_clkreg_m(const struct bhnd_chipid *cid,
|
||||||
|
uint8_t pll_type, uint32_t *fixed_hz)
|
||||||
|
{
|
||||||
|
switch (pll_type) {
|
||||||
|
case CHIPC_PLL_TYPE2:
|
||||||
|
case CHIPC_PLL_TYPE4:
|
||||||
|
case CHIPC_PLL_TYPE6:
|
||||||
|
case CHIPC_PLL_TYPE7:
|
||||||
|
return (CHIPC_CLKC_M3);
|
||||||
|
|
||||||
|
case CHIPC_PLL_TYPE5:
|
||||||
|
/* fixed 200MHz */
|
||||||
|
if (fixed_hz != NULL)
|
||||||
|
*fixed_hz = 200 * 1000 * 1000;
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
case CHIPC_PLL_TYPE3:
|
||||||
|
if (cid->chip_id == BHND_CHIPID_BCM5365) {
|
||||||
|
/* fixed 200MHz */
|
||||||
|
if (fixed_hz != NULL)
|
||||||
|
*fixed_hz = 200 * 1000 * 1000;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (CHIPC_CLKC_M2);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return (CHIPC_CLKC_SB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the CPU clock speed (in Hz) for a given a set of clock control
|
||||||
|
* values.
|
||||||
|
*
|
||||||
|
* @param cid Chip identification.
|
||||||
|
* @param pll_type PLL type (CHIPC_PLL_TYPE*)
|
||||||
|
* @param n clock control N register value.
|
||||||
|
* @param m clock control M register value.
|
||||||
|
*/
|
||||||
|
uint32_t
|
||||||
|
bhnd_pwrctl_cpu_clock_rate(const struct bhnd_chipid *cid,
|
||||||
|
uint32_t pll_type, uint32_t n, uint32_t m)
|
||||||
|
{
|
||||||
|
KASSERT(bhnd_pwrctl_cpu_clkreg_m(cid, pll_type, NULL) != 0,
|
||||||
|
("can't compute clock rate on fixed clock"));
|
||||||
|
|
||||||
|
return (bhnd_pwrctl_clock_rate(pll_type, n, m));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the clock speed (in Hz) for a given a set of clockcontrol
|
* Calculate the clock speed (in Hz) for a given a set of clockcontrol
|
||||||
* values.
|
* values.
|
||||||
*
|
*
|
||||||
* @param pll_type PLL type (CHIPC_PLL_TYPE*)
|
* @param pll_type PLL type (CHIPC_PLL_TYPE*)
|
||||||
* @param n clock control N register value.
|
* @param n clock control N register value.
|
||||||
* @param m clock control N register value.
|
* @param m clock control M register value.
|
||||||
*/
|
*/
|
||||||
static uint32_t
|
uint32_t
|
||||||
bhnd_pwrctl_clock_rate(uint32_t pll_type, uint32_t n, uint32_t m)
|
bhnd_pwrctl_clock_rate(uint32_t pll_type, uint32_t n, uint32_t m)
|
||||||
{
|
{
|
||||||
uint32_t clk_base;
|
uint32_t clk_base;
|
||||||
@ -195,38 +301,27 @@ bhnd_pwrctl_clock_rate(uint32_t pll_type, uint32_t n, uint32_t m)
|
|||||||
uint32_t
|
uint32_t
|
||||||
bhnd_pwrctl_getclk_speed(struct bhnd_pwrctl_softc *sc)
|
bhnd_pwrctl_getclk_speed(struct bhnd_pwrctl_softc *sc)
|
||||||
{
|
{
|
||||||
struct chipc_caps *ccaps;
|
const struct bhnd_chipid *cid;
|
||||||
bus_size_t creg;
|
struct chipc_caps *ccaps;
|
||||||
uint32_t n, m;
|
bus_size_t creg;
|
||||||
uint32_t rate;
|
uint32_t n, m;
|
||||||
|
uint32_t rate;
|
||||||
|
|
||||||
PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
|
PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
|
||||||
|
|
||||||
|
cid = bhnd_get_chipid(sc->chipc_dev);
|
||||||
ccaps = BHND_CHIPC_GET_CAPS(sc->chipc_dev);
|
ccaps = BHND_CHIPC_GET_CAPS(sc->chipc_dev);
|
||||||
|
|
||||||
n = bhnd_bus_read_4(sc->res, CHIPC_CLKC_N);
|
n = bhnd_bus_read_4(sc->res, CHIPC_CLKC_N);
|
||||||
|
|
||||||
switch (ccaps->pll_type) {
|
/* Get M register offset */
|
||||||
case CHIPC_PLL_TYPE6:
|
creg = bhnd_pwrctl_si_clkreg_m(cid, ccaps->pll_type, &rate);
|
||||||
creg = CHIPC_CLKC_M3; /* non-extif regster */
|
if (creg == 0) /* fixed rate */
|
||||||
break;
|
return (rate);
|
||||||
case CHIPC_PLL_TYPE3:
|
|
||||||
creg = CHIPC_CLKC_M2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
creg = CHIPC_CLKC_SB;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
m = bhnd_bus_read_4(sc->res, creg);
|
|
||||||
|
|
||||||
/* calculate rate */
|
/* calculate rate */
|
||||||
rate = bhnd_pwrctl_clock_rate(ccaps->pll_type, n, m);
|
m = bhnd_bus_read_4(sc->res, creg);
|
||||||
|
return (bhnd_pwrctl_si_clock_rate(cid, ccaps->pll_type, n, m));
|
||||||
if (ccaps->pll_type == CHIPC_PLL_TYPE3)
|
|
||||||
rate /= 2;
|
|
||||||
|
|
||||||
return (rate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return the slow clock source */
|
/* return the slow clock source */
|
||||||
|
@ -36,6 +36,21 @@
|
|||||||
#include <sys/bus.h>
|
#include <sys/bus.h>
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
|
|
||||||
|
#include <dev/bhnd/bhnd.h>
|
||||||
|
|
||||||
|
uint32_t bhnd_pwrctl_clock_rate(uint32_t pll_type, uint32_t n,
|
||||||
|
uint32_t m);
|
||||||
|
|
||||||
|
bus_size_t bhnd_pwrctl_si_clkreg_m(const struct bhnd_chipid *cid,
|
||||||
|
uint8_t pll_type, uint32_t *fixed_hz);
|
||||||
|
uint32_t bhnd_pwrctl_si_clock_rate(const struct bhnd_chipid *cid,
|
||||||
|
uint32_t pll_type, uint32_t n, uint32_t m);
|
||||||
|
|
||||||
|
bus_size_t bhnd_pwrctl_cpu_clkreg_m(const struct bhnd_chipid *cid,
|
||||||
|
uint8_t pll_type, uint32_t *fixed_hz);
|
||||||
|
uint32_t bhnd_pwrctl_cpu_clock_rate(const struct bhnd_chipid *cid,
|
||||||
|
uint32_t pll_type, uint32_t n, uint32_t m);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bhnd pwrctl device quirks.
|
* bhnd pwrctl device quirks.
|
||||||
*/
|
*/
|
||||||
|
@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <machine/resource.h>
|
#include <machine/resource.h>
|
||||||
|
|
||||||
#include <dev/bhnd/bhnd.h>
|
#include <dev/bhnd/bhnd.h>
|
||||||
|
#include <dev/bhnd/cores/chipc/chipc.h>
|
||||||
|
|
||||||
#include "bhnd_nvram_map.h"
|
#include "bhnd_nvram_map.h"
|
||||||
|
|
||||||
@ -69,6 +70,16 @@ static int bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS);
|
|||||||
static int bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS);
|
static int bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS);
|
||||||
static int bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS);
|
static int bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS);
|
||||||
|
|
||||||
|
static uint32_t bhnd_pmu_read_4(bus_size_t reg, void *ctx);
|
||||||
|
static void bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx);
|
||||||
|
static uint32_t bhnd_pmu_read_chipst(void *ctx);
|
||||||
|
|
||||||
|
static const struct bhnd_pmu_io bhnd_pmu_res_io = {
|
||||||
|
.rd4 = bhnd_pmu_read_4,
|
||||||
|
.wr4 = bhnd_pmu_write_4,
|
||||||
|
.rd_chipst = bhnd_pmu_read_chipst
|
||||||
|
};
|
||||||
|
|
||||||
#define BPMU_CLKCTL_READ_4(_pinfo) \
|
#define BPMU_CLKCTL_READ_4(_pinfo) \
|
||||||
bhnd_bus_read_4((_pinfo)->pm_res, (_pinfo)->pm_regs)
|
bhnd_bus_read_4((_pinfo)->pm_res, (_pinfo)->pm_regs)
|
||||||
|
|
||||||
@ -144,6 +155,14 @@ bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
|
|||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize query state */
|
||||||
|
error = bhnd_pmu_query_init(&sc->query, dev, sc->cid, &bhnd_pmu_res_io,
|
||||||
|
sc);
|
||||||
|
if (error)
|
||||||
|
return (error);
|
||||||
|
sc->io = sc->query.io;
|
||||||
|
sc->io_ctx = sc->query.io_ctx;
|
||||||
|
|
||||||
BPMU_LOCK_INIT(sc);
|
BPMU_LOCK_INIT(sc);
|
||||||
|
|
||||||
/* Set quirk flags */
|
/* Set quirk flags */
|
||||||
@ -183,6 +202,7 @@ bhnd_pmu_attach(device_t dev, struct bhnd_resource *res)
|
|||||||
|
|
||||||
failed:
|
failed:
|
||||||
BPMU_LOCK_DESTROY(sc);
|
BPMU_LOCK_DESTROY(sc);
|
||||||
|
bhnd_pmu_query_fini(&sc->query);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,6 +217,7 @@ bhnd_pmu_detach(device_t dev)
|
|||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
BPMU_LOCK_DESTROY(sc);
|
BPMU_LOCK_DESTROY(sc);
|
||||||
|
bhnd_pmu_query_fini(&sc->query);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -239,7 +260,7 @@ bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS)
|
|||||||
sc = arg1;
|
sc = arg1;
|
||||||
|
|
||||||
BPMU_LOCK(sc);
|
BPMU_LOCK(sc);
|
||||||
freq = bhnd_pmu_si_clock(sc);
|
freq = bhnd_pmu_si_clock(&sc->query);
|
||||||
BPMU_UNLOCK(sc);
|
BPMU_UNLOCK(sc);
|
||||||
|
|
||||||
return (sysctl_handle_32(oidp, NULL, freq, req));
|
return (sysctl_handle_32(oidp, NULL, freq, req));
|
||||||
@ -254,7 +275,7 @@ bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS)
|
|||||||
sc = arg1;
|
sc = arg1;
|
||||||
|
|
||||||
BPMU_LOCK(sc);
|
BPMU_LOCK(sc);
|
||||||
freq = bhnd_pmu_cpu_clock(sc);
|
freq = bhnd_pmu_cpu_clock(&sc->query);
|
||||||
BPMU_UNLOCK(sc);
|
BPMU_UNLOCK(sc);
|
||||||
|
|
||||||
return (sysctl_handle_32(oidp, NULL, freq, req));
|
return (sysctl_handle_32(oidp, NULL, freq, req));
|
||||||
@ -269,7 +290,7 @@ bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS)
|
|||||||
sc = arg1;
|
sc = arg1;
|
||||||
|
|
||||||
BPMU_LOCK(sc);
|
BPMU_LOCK(sc);
|
||||||
freq = bhnd_pmu_mem_clock(sc);
|
freq = bhnd_pmu_mem_clock(&sc->query);
|
||||||
BPMU_UNLOCK(sc);
|
BPMU_UNLOCK(sc);
|
||||||
|
|
||||||
return (sysctl_handle_32(oidp, NULL, freq, req));
|
return (sysctl_handle_32(oidp, NULL, freq, req));
|
||||||
@ -445,6 +466,27 @@ bhnd_pmu_core_release(device_t dev, struct bhnd_core_pmu_info *pinfo)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
bhnd_pmu_read_4(bus_size_t reg, void *ctx)
|
||||||
|
{
|
||||||
|
struct bhnd_pmu_softc *sc = ctx;
|
||||||
|
return (bhnd_bus_read_4(sc->res, reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bhnd_pmu_write_4(bus_size_t reg, uint32_t val, void *ctx)
|
||||||
|
{
|
||||||
|
struct bhnd_pmu_softc *sc = ctx;
|
||||||
|
return (bhnd_bus_write_4(sc->res, reg, val));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
bhnd_pmu_read_chipst(void *ctx)
|
||||||
|
{
|
||||||
|
struct bhnd_pmu_softc *sc = ctx;
|
||||||
|
return (BHND_CHIPC_READ_CHIPST(sc->chipc_dev));
|
||||||
|
}
|
||||||
|
|
||||||
static device_method_t bhnd_pmu_methods[] = {
|
static device_method_t bhnd_pmu_methods[] = {
|
||||||
/* Device interface */
|
/* Device interface */
|
||||||
DEVMETHOD(device_probe, bhnd_pmu_probe),
|
DEVMETHOD(device_probe, bhnd_pmu_probe),
|
||||||
|
@ -30,15 +30,9 @@
|
|||||||
#include "bhnd_pmuvar.h"
|
#include "bhnd_pmuvar.h"
|
||||||
|
|
||||||
/* Register I/O */
|
/* Register I/O */
|
||||||
#define BHND_PMU_READ_1(_sc, _reg) bhnd_bus_read_1((_sc)->res, (_reg))
|
#define BHND_PMU_READ_4(_sc, _reg) (_sc)->io->rd4((_reg), (_sc)->io_ctx)
|
||||||
#define BHND_PMU_READ_2(_sc, _reg) bhnd_bus_read_2((_sc)->res, (_reg))
|
|
||||||
#define BHND_PMU_READ_4(_sc, _reg) bhnd_bus_read_4((_sc)->res, (_reg))
|
|
||||||
#define BHND_PMU_WRITE_1(_sc, _reg, _val) \
|
|
||||||
bhnd_bus_write_1((_sc)->res, (_reg), (_val))
|
|
||||||
#define BHND_PMU_WRITE_2(_sc, _reg, _val) \
|
|
||||||
bhnd_bus_write_2((_sc)->res, (_reg), (_val))
|
|
||||||
#define BHND_PMU_WRITE_4(_sc, _reg, _val) \
|
#define BHND_PMU_WRITE_4(_sc, _reg, _val) \
|
||||||
bhnd_bus_write_4((_sc)->res, (_reg), (_val))
|
(_sc)->io->wr4((_reg), (_val), (_sc)->io_ctx)
|
||||||
|
|
||||||
#define BHND_PMU_AND_4(_sc, _reg, _val) \
|
#define BHND_PMU_AND_4(_sc, _reg, _val) \
|
||||||
BHND_PMU_WRITE_4((_sc), (_reg), \
|
BHND_PMU_WRITE_4((_sc), (_reg), \
|
||||||
@ -49,10 +43,11 @@
|
|||||||
|
|
||||||
/* Indirect register support */
|
/* Indirect register support */
|
||||||
#define BHND_PMU_IND_READ(_sc, _src, _reg) \
|
#define BHND_PMU_IND_READ(_sc, _src, _reg) \
|
||||||
bhnd_pmu_ind_read((_sc), BHND_PMU_ ## _src ## _ADDR, \
|
bhnd_pmu_ind_read((_sc)->io, (_sc)->io_ctx, \
|
||||||
BHND_PMU_ ## _src ## _DATA, (_reg))
|
BHND_PMU_ ## _src ## _ADDR, BHND_PMU_ ## _src ## _DATA, (_reg))
|
||||||
#define BHND_PMU_IND_WRITE(_sc, _src, _reg, _val, _mask) \
|
#define BHND_PMU_IND_WRITE(_sc, _src, _reg, _val, _mask) \
|
||||||
bhnd_pmu_ind_write(sc, BHND_PMU_ ## _src ## _ADDR, \
|
bhnd_pmu_ind_write((_sc)->io, (_sc)->io_ctx, \
|
||||||
|
BHND_PMU_ ## _src ## _ADDR, \
|
||||||
BHND_PMU_ ## _src ## _DATA, (_reg), (_val), (_mask))
|
BHND_PMU_ ## _src ## _DATA, (_reg), (_val), (_mask))
|
||||||
|
|
||||||
/* Chip Control indirect registers */
|
/* Chip Control indirect registers */
|
||||||
@ -96,10 +91,12 @@ enum {
|
|||||||
SET_LDO_VOLTAGE_LNLDO2_SEL = 10,
|
SET_LDO_VOLTAGE_LNLDO2_SEL = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t bhnd_pmu_ind_read(struct bhnd_pmu_softc *sc, bus_size_t addr,
|
|
||||||
bus_size_t data, uint32_t reg);
|
uint32_t bhnd_pmu_ind_read(const struct bhnd_pmu_io *io, void *io_ctx,
|
||||||
void bhnd_pmu_ind_write(struct bhnd_pmu_softc *sc, bus_size_t addr,
|
bus_size_t addr, bus_size_t data, uint32_t reg);
|
||||||
bus_size_t data, uint32_t reg, uint32_t val, uint32_t mask);
|
void bhnd_pmu_ind_write(const struct bhnd_pmu_io *io, void *io_ctx,
|
||||||
|
bus_size_t addr, bus_size_t data, uint32_t reg,
|
||||||
|
uint32_t val, uint32_t mask);
|
||||||
|
|
||||||
bool bhnd_pmu_wait_clkst(struct bhnd_pmu_softc *sc, device_t dev,
|
bool bhnd_pmu_wait_clkst(struct bhnd_pmu_softc *sc, device_t dev,
|
||||||
struct bhnd_resource *r, bus_size_t clkst_reg,
|
struct bhnd_resource *r, bus_size_t clkst_reg,
|
||||||
@ -112,12 +109,6 @@ void bhnd_pmu_swreg_init(struct bhnd_pmu_softc *sc);
|
|||||||
|
|
||||||
uint32_t bhnd_pmu_force_ilp(struct bhnd_pmu_softc *sc, bool force);
|
uint32_t bhnd_pmu_force_ilp(struct bhnd_pmu_softc *sc, bool force);
|
||||||
|
|
||||||
uint32_t bhnd_pmu_si_clock(struct bhnd_pmu_softc *sc);
|
|
||||||
uint32_t bhnd_pmu_cpu_clock(struct bhnd_pmu_softc *sc);
|
|
||||||
uint32_t bhnd_pmu_mem_clock(struct bhnd_pmu_softc *sc);
|
|
||||||
uint32_t bhnd_pmu_alp_clock(struct bhnd_pmu_softc *sc);
|
|
||||||
uint32_t bhnd_pmu_ilp_clock(struct bhnd_pmu_softc *sc);
|
|
||||||
|
|
||||||
void bhnd_pmu_set_switcher_voltage(struct bhnd_pmu_softc *sc,
|
void bhnd_pmu_set_switcher_voltage(struct bhnd_pmu_softc *sc,
|
||||||
uint8_t bb_voltage, uint8_t rf_voltage);
|
uint8_t bb_voltage, uint8_t rf_voltage);
|
||||||
void bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc,
|
void bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc,
|
||||||
|
@ -38,33 +38,36 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include "bhnd_pmu_private.h"
|
#include "bhnd_pmu_private.h"
|
||||||
|
|
||||||
#ifdef BCMDBG
|
#define PMU_LOG(_sc, _fmt, ...) do { \
|
||||||
#define PMU_MSG(args) printf args
|
if (_sc->dev != NULL) \
|
||||||
#define PMU_ERROR(args) do { \
|
device_printf(_sc->dev, _fmt, ##__VA_ARGS__); \
|
||||||
panic args; \
|
else \
|
||||||
|
printf(_fmt, ##__VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#ifdef BCMDBG
|
||||||
|
#define PMU_DEBUG(_sc, _fmt, ...) PMU_LOG(_sc, _fmt, ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define PMU_MSG(args)
|
#define PMU_DEBUG(_sc, _fmt, ...)
|
||||||
#define PMU_ERROR(args) printf args
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct pmu0_xtaltab0 pmu0_xtaltab0_t;
|
typedef struct pmu0_xtaltab0 pmu0_xtaltab0_t;
|
||||||
typedef struct pmu1_xtaltab0 pmu1_xtaltab0_t;
|
typedef struct pmu1_xtaltab0 pmu1_xtaltab0_t;
|
||||||
|
|
||||||
/* PLL controls/clocks */
|
/* PLL controls/clocks */
|
||||||
static const pmu1_xtaltab0_t *bhnd_pmu1_xtaltab0(struct bhnd_pmu_softc *sc);
|
static const pmu1_xtaltab0_t *bhnd_pmu1_xtaltab0(struct bhnd_pmu_query *sc);
|
||||||
static const pmu1_xtaltab0_t *bhnd_pmu1_xtaldef0(struct bhnd_pmu_softc *sc);
|
static const pmu1_xtaltab0_t *bhnd_pmu1_xtaldef0(struct bhnd_pmu_query *sc);
|
||||||
|
|
||||||
static void bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal);
|
static void bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal);
|
||||||
static uint32_t bhnd_pmu0_cpuclk0(struct bhnd_pmu_softc *sc);
|
static uint32_t bhnd_pmu0_cpuclk0(struct bhnd_pmu_query *sc);
|
||||||
static uint32_t bhnd_pmu0_alpclk0(struct bhnd_pmu_softc *sc);
|
static uint32_t bhnd_pmu0_alpclk0(struct bhnd_pmu_query *sc);
|
||||||
|
|
||||||
static void bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal);
|
static void bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal);
|
||||||
static uint32_t bhnd_pmu1_pllfvco0(struct bhnd_pmu_softc *sc);
|
static uint32_t bhnd_pmu1_pllfvco0(struct bhnd_pmu_query *sc);
|
||||||
static uint32_t bhnd_pmu1_cpuclk0(struct bhnd_pmu_softc *sc);
|
static uint32_t bhnd_pmu1_cpuclk0(struct bhnd_pmu_query *sc);
|
||||||
static uint32_t bhnd_pmu1_alpclk0(struct bhnd_pmu_softc *sc);
|
static uint32_t bhnd_pmu1_alpclk0(struct bhnd_pmu_query *sc);
|
||||||
|
|
||||||
static uint32_t bhnd_pmu5_clock(struct bhnd_pmu_softc *sc, u_int pll0, u_int m);
|
static uint32_t bhnd_pmu5_clock(struct bhnd_pmu_query *sc, u_int pll0, u_int m);
|
||||||
|
|
||||||
/* PMU resources */
|
/* PMU resources */
|
||||||
static bool bhnd_pmu_res_depfltr_bb(struct bhnd_pmu_softc *sc);
|
static bool bhnd_pmu_res_depfltr_bb(struct bhnd_pmu_softc *sc);
|
||||||
@ -93,7 +96,45 @@ static void bhnd_pmu_set_4330_plldivs(struct bhnd_pmu_softc *sc);
|
|||||||
(1 << (BHND_PMU_ ## _bit))
|
(1 << (BHND_PMU_ ## _bit))
|
||||||
|
|
||||||
#define PMU_CST4330_SDIOD_CHIPMODE(_sc) \
|
#define PMU_CST4330_SDIOD_CHIPMODE(_sc) \
|
||||||
CHIPC_CST4330_CHIPMODE_SDIOD(BHND_CHIPC_READ_CHIPST((_sc)->chipc_dev))
|
CHIPC_CST4330_CHIPMODE_SDIOD((_sc)->io->rd_chipst((_sc)->io_ctx))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize @p query state.
|
||||||
|
*
|
||||||
|
* @param[out] query On success, will be populated with a valid query instance
|
||||||
|
* state.
|
||||||
|
* @param dev The device owning @p query, or NULL.
|
||||||
|
* @param id The bhnd chip identification.
|
||||||
|
* @param io I/O callback functions.
|
||||||
|
* @param ctx I/O callback context.
|
||||||
|
*
|
||||||
|
* @retval 0 success
|
||||||
|
* @retval non-zero if the query state could not be initialized.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
bhnd_pmu_query_init(struct bhnd_pmu_query *query, device_t dev,
|
||||||
|
struct bhnd_chipid id, const struct bhnd_pmu_io *io, void *ctx)
|
||||||
|
{
|
||||||
|
query->dev = dev;
|
||||||
|
query->io = io;
|
||||||
|
query->io_ctx = ctx;
|
||||||
|
query->cid = id;
|
||||||
|
query->caps = BHND_PMU_READ_4(query, BHND_PMU_CAP);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release any resources held by @p query.
|
||||||
|
*
|
||||||
|
* @param query A query instance previously initialized via
|
||||||
|
* bhnd_pmu_query_init().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
bhnd_pmu_query_fini(struct bhnd_pmu_query *query)
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform an indirect register read.
|
* Perform an indirect register read.
|
||||||
@ -103,11 +144,11 @@ static void bhnd_pmu_set_4330_plldivs(struct bhnd_pmu_softc *sc);
|
|||||||
* @param reg Indirect register to be read.
|
* @param reg Indirect register to be read.
|
||||||
*/
|
*/
|
||||||
uint32_t
|
uint32_t
|
||||||
bhnd_pmu_ind_read(struct bhnd_pmu_softc *sc, bus_size_t addr, bus_size_t data,
|
bhnd_pmu_ind_read(const struct bhnd_pmu_io *io, void *io_ctx, bus_size_t addr,
|
||||||
uint32_t reg)
|
bus_size_t data, uint32_t reg)
|
||||||
{
|
{
|
||||||
BHND_PMU_WRITE_4(sc, addr, reg);
|
io->wr4(addr, reg, io_ctx);
|
||||||
return (BHND_PMU_READ_4(sc, data));
|
return (io->rd4(data, io_ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,21 +161,21 @@ bhnd_pmu_ind_read(struct bhnd_pmu_softc *sc, bus_size_t addr, bus_size_t data,
|
|||||||
* @param mask Only the bits defined by @p mask will be updated from @p val.
|
* @param mask Only the bits defined by @p mask will be updated from @p val.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
bhnd_pmu_ind_write(struct bhnd_pmu_softc *sc, bus_size_t addr,
|
bhnd_pmu_ind_write(const struct bhnd_pmu_io *io, void *io_ctx, bus_size_t addr,
|
||||||
bus_size_t data, uint32_t reg, uint32_t val, uint32_t mask)
|
bus_size_t data, uint32_t reg, uint32_t val, uint32_t mask)
|
||||||
{
|
{
|
||||||
uint32_t rval;
|
uint32_t rval;
|
||||||
|
|
||||||
BHND_PMU_WRITE_4(sc, addr, reg);
|
io->wr4(addr, reg, io_ctx);
|
||||||
|
|
||||||
if (mask != UINT32_MAX) {
|
if (mask != UINT32_MAX) {
|
||||||
rval = BHND_PMU_READ_4(sc, data);
|
rval = io->rd4(data, io_ctx);
|
||||||
rval &= ~mask | (val & mask);
|
rval &= ~mask | (val & mask);
|
||||||
} else {
|
} else {
|
||||||
rval = val;
|
rval = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
BHND_PMU_WRITE_4(sc, data, rval);
|
io->wr4(data, rval, io_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -375,7 +416,7 @@ bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, uint16_t *pwrup_delay)
|
|||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
ilp = bhnd_pmu_ilp_clock(sc);
|
ilp = bhnd_pmu_ilp_clock(&sc->query);
|
||||||
delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
|
delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
|
||||||
((1000000 + ilp - 1) / ilp);
|
((1000000 + ilp - 1) / ilp);
|
||||||
delay = (11 * delay) / 10;
|
delay = (11 * delay) / 10;
|
||||||
@ -387,7 +428,7 @@ bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, uint16_t *pwrup_delay)
|
|||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
ilp = bhnd_pmu_ilp_clock(sc);
|
ilp = bhnd_pmu_ilp_clock(&sc->query);
|
||||||
delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
|
delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
|
||||||
((1000000 + ilp - 1) / ilp);
|
((1000000 + ilp - 1) / ilp);
|
||||||
delay = (11 * delay) / 10;
|
delay = (11 * delay) / 10;
|
||||||
@ -403,7 +444,7 @@ bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, uint16_t *pwrup_delay)
|
|||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
ilp = bhnd_pmu_ilp_clock(sc);
|
ilp = bhnd_pmu_ilp_clock(&sc->query);
|
||||||
delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
|
delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
|
||||||
((1000000 + ilp - 1) / ilp);
|
((1000000 + ilp - 1) / ilp);
|
||||||
delay = (11 * delay) / 10;
|
delay = (11 * delay) / 10;
|
||||||
@ -415,7 +456,7 @@ bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, uint16_t *pwrup_delay)
|
|||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
|
|
||||||
ilp = bhnd_pmu_ilp_clock(sc);
|
ilp = bhnd_pmu_ilp_clock(&sc->query);
|
||||||
delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
|
delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) *
|
||||||
((1000000 + ilp - 1) / ilp);
|
((1000000 + ilp - 1) / ilp);
|
||||||
delay = (11 * delay) / 10;
|
delay = (11 * delay) / 10;
|
||||||
@ -882,22 +923,22 @@ bhnd_pmu_res_masks(struct bhnd_pmu_softc *sc, uint32_t *pmin, uint32_t *pmax)
|
|||||||
/* Apply nvram override to min mask */
|
/* Apply nvram override to min mask */
|
||||||
error = bhnd_nvram_getvar_uint32(sc->chipc_dev, BHND_NVAR_RMIN, &nval);
|
error = bhnd_nvram_getvar_uint32(sc->chipc_dev, BHND_NVAR_RMIN, &nval);
|
||||||
if (error && error != ENOENT) {
|
if (error && error != ENOENT) {
|
||||||
device_printf(sc->dev, "NVRAM error reading %s: %d\n",
|
PMU_LOG(sc, "NVRAM error reading %s: %d\n",
|
||||||
BHND_NVAR_RMIN, error);
|
BHND_NVAR_RMIN, error);
|
||||||
return (error);
|
return (error);
|
||||||
} else if (!error) {
|
} else if (!error) {
|
||||||
PMU_MSG(("Applying rmin=%#x to min_mask\n", nval));
|
PMU_DEBUG(sc, "Applying rmin=%#x to min_mask\n", nval);
|
||||||
min_mask = nval;
|
min_mask = nval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply nvram override to max mask */
|
/* Apply nvram override to max mask */
|
||||||
error = bhnd_nvram_getvar_uint32(sc->chipc_dev, BHND_NVAR_RMAX, &nval);
|
error = bhnd_nvram_getvar_uint32(sc->chipc_dev, BHND_NVAR_RMAX, &nval);
|
||||||
if (error && error != ENOENT) {
|
if (error && error != ENOENT) {
|
||||||
device_printf(sc->dev, "NVRAM error reading %s: %d\n",
|
PMU_LOG(sc, "NVRAM error reading %s: %d\n",
|
||||||
BHND_NVAR_RMAX, error);
|
BHND_NVAR_RMAX, error);
|
||||||
return (error);
|
return (error);
|
||||||
} else if (!error) {
|
} else if (!error) {
|
||||||
PMU_MSG(("Applying rmax=%#x to max_mask\n", nval));
|
PMU_DEBUG(sc, "Applying rmax=%#x to max_mask\n", nval);
|
||||||
min_mask = nval;
|
min_mask = nval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1013,8 +1054,8 @@ bhnd_pmu_res_init(struct bhnd_pmu_softc *sc)
|
|||||||
|
|
||||||
updt = &pmu_res_updown_table[pmu_res_updown_table_sz - i - 1];
|
updt = &pmu_res_updown_table[pmu_res_updown_table_sz - i - 1];
|
||||||
|
|
||||||
PMU_MSG(("Changing rsrc %d res_updn_timer to %#x\n",
|
PMU_DEBUG(sc, "Changing rsrc %d res_updn_timer to %#x\n",
|
||||||
updt->resnum, updt->updown));
|
updt->resnum, updt->updown);
|
||||||
|
|
||||||
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, updt->resnum);
|
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, updt->resnum);
|
||||||
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_UPDN_TIMER, updt->updown);
|
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_UPDN_TIMER, updt->updown);
|
||||||
@ -1031,13 +1072,13 @@ bhnd_pmu_res_init(struct bhnd_pmu_softc *sc)
|
|||||||
if (error == ENOENT) {
|
if (error == ENOENT) {
|
||||||
continue;
|
continue;
|
||||||
} else if (error) {
|
} else if (error) {
|
||||||
device_printf(sc->dev, "NVRAM error reading %s: %d\n",
|
PMU_LOG(sc, "NVRAM error reading %s: %d\n",
|
||||||
name, error);
|
name, error);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
PMU_MSG(("Applying %s=%s to rsrc %d res_updn_timer\n", name,
|
PMU_DEBUG(sc, "Applying %s=%s to rsrc %d res_updn_timer\n",
|
||||||
val, i));
|
name, val, i);
|
||||||
|
|
||||||
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i);
|
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i);
|
||||||
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_UPDN_TIMER, val);
|
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_UPDN_TIMER, val);
|
||||||
@ -1066,21 +1107,21 @@ bhnd_pmu_res_init(struct bhnd_pmu_softc *sc)
|
|||||||
BHND_PMU_RES_DEP_MASK);
|
BHND_PMU_RES_DEP_MASK);
|
||||||
switch (rdep->action) {
|
switch (rdep->action) {
|
||||||
case RES_DEPEND_SET:
|
case RES_DEPEND_SET:
|
||||||
PMU_MSG(("Changing rsrc %hhu res_dep_mask to "
|
PMU_DEBUG(sc, "Changing rsrc %hhu res_dep_mask to "
|
||||||
"%#x\n", i, table->depend_mask));
|
"%#x\n", i, table->depend_mask);
|
||||||
depend_mask = rdep->depend_mask;
|
depend_mask = rdep->depend_mask;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RES_DEPEND_ADD:
|
case RES_DEPEND_ADD:
|
||||||
PMU_MSG(("Adding %#x to rsrc %hhu "
|
PMU_DEBUG(sc, "Adding %#x to rsrc %hhu "
|
||||||
"res_dep_mask\n", table->depend_mask, i));
|
"res_dep_mask\n", table->depend_mask, i);
|
||||||
|
|
||||||
depend_mask |= rdep->depend_mask;
|
depend_mask |= rdep->depend_mask;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RES_DEPEND_REMOVE:
|
case RES_DEPEND_REMOVE:
|
||||||
PMU_MSG(("Removing %#x from rsrc %hhu "
|
PMU_DEBUG(sc, "Removing %#x from rsrc %hhu "
|
||||||
"res_dep_mask\n", table->depend_mask, i));
|
"res_dep_mask\n", table->depend_mask, i);
|
||||||
|
|
||||||
depend_mask &= ~(rdep->depend_mask);
|
depend_mask &= ~(rdep->depend_mask);
|
||||||
break;
|
break;
|
||||||
@ -1106,13 +1147,13 @@ bhnd_pmu_res_init(struct bhnd_pmu_softc *sc)
|
|||||||
if (error == ENOENT) {
|
if (error == ENOENT) {
|
||||||
continue;
|
continue;
|
||||||
} else if (error) {
|
} else if (error) {
|
||||||
device_printf(sc->dev, "NVRAM error reading %s: %d\n",
|
PMU_LOG(sc, "NVRAM error reading %s: %d\n", name,
|
||||||
name, error);
|
error);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
PMU_MSG(("Applying %s=%s to rsrc %d res_dep_mask\n", name, val,
|
PMU_DEBUG(sc, "Applying %s=%s to rsrc %d res_dep_mask\n", name,
|
||||||
i));
|
val, i);
|
||||||
|
|
||||||
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i);
|
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i);
|
||||||
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_DEP_MASK, val);
|
BHND_PMU_WRITE_4(sc, BHND_PMU_RES_DEP_MASK, val);
|
||||||
@ -1126,14 +1167,14 @@ bhnd_pmu_res_init(struct bhnd_pmu_softc *sc)
|
|||||||
|
|
||||||
/* Program max resource mask */
|
/* Program max resource mask */
|
||||||
if (max_mask != 0) {
|
if (max_mask != 0) {
|
||||||
PMU_MSG(("Changing max_res_mask to 0x%x\n", max_mask));
|
PMU_DEBUG(sc, "Changing max_res_mask to 0x%x\n", max_mask);
|
||||||
BHND_PMU_WRITE_4(sc, BHND_PMU_MAX_RES_MASK, max_mask);
|
BHND_PMU_WRITE_4(sc, BHND_PMU_MAX_RES_MASK, max_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Program min resource mask */
|
/* Program min resource mask */
|
||||||
|
|
||||||
if (min_mask != 0) {
|
if (min_mask != 0) {
|
||||||
PMU_MSG(("Changing min_res_mask to 0x%x\n", min_mask));
|
PMU_DEBUG(sc, "Changing min_res_mask to 0x%x\n", min_mask);
|
||||||
BHND_PMU_WRITE_4(sc, BHND_PMU_MIN_RES_MASK, min_mask);
|
BHND_PMU_WRITE_4(sc, BHND_PMU_MIN_RES_MASK, min_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1367,7 +1408,7 @@ static const pmu1_xtaltab0_t pmu1_xtaltab0_960[] = {
|
|||||||
|
|
||||||
/* select xtal table for each chip */
|
/* select xtal table for each chip */
|
||||||
static const pmu1_xtaltab0_t *
|
static const pmu1_xtaltab0_t *
|
||||||
bhnd_pmu1_xtaltab0(struct bhnd_pmu_softc *sc)
|
bhnd_pmu1_xtaltab0(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
switch (sc->cid.chip_id) {
|
switch (sc->cid.chip_id) {
|
||||||
case BHND_CHIPID_BCM4315:
|
case BHND_CHIPID_BCM4315:
|
||||||
@ -1386,15 +1427,15 @@ bhnd_pmu1_xtaltab0(struct bhnd_pmu_softc *sc)
|
|||||||
else
|
else
|
||||||
return (pmu1_xtaltab0_1440);
|
return (pmu1_xtaltab0_1440);
|
||||||
default:
|
default:
|
||||||
PMU_MSG(("bhnd_pmu1_xtaltab0: Unknown chipid %#hx\n",
|
PMU_DEBUG(sc, "bhnd_pmu1_xtaltab0: Unknown chipid %#hx\n",
|
||||||
sc->cid.chip_id));
|
sc->cid.chip_id);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* select default xtal frequency for each chip */
|
/* select default xtal frequency for each chip */
|
||||||
static const pmu1_xtaltab0_t *
|
static const pmu1_xtaltab0_t *
|
||||||
bhnd_pmu1_xtaldef0(struct bhnd_pmu_softc *sc)
|
bhnd_pmu1_xtaldef0(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
switch (sc->cid.chip_id) {
|
switch (sc->cid.chip_id) {
|
||||||
case BHND_CHIPID_BCM4315:
|
case BHND_CHIPID_BCM4315:
|
||||||
@ -1419,15 +1460,15 @@ bhnd_pmu1_xtaldef0(struct bhnd_pmu_softc *sc)
|
|||||||
else
|
else
|
||||||
return (&pmu1_xtaltab0_1440[PMU1_XTALTAB0_1440_37400K]);
|
return (&pmu1_xtaltab0_1440[PMU1_XTALTAB0_1440_37400K]);
|
||||||
default:
|
default:
|
||||||
PMU_MSG(("bhnd_pmu1_xtaldef0: Unknown chipid %#hx\n",
|
PMU_DEBUG(sc, "bhnd_pmu1_xtaldef0: Unknown chipid %#hx\n",
|
||||||
sc->cid.chip_id));
|
sc->cid.chip_id);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* select default pll fvco for each chip */
|
/* select default pll fvco for each chip */
|
||||||
static uint32_t
|
static uint32_t
|
||||||
bhnd_pmu1_pllfvco0(struct bhnd_pmu_softc *sc)
|
bhnd_pmu1_pllfvco0(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
switch (sc->cid.chip_id) {
|
switch (sc->cid.chip_id) {
|
||||||
case BHND_CHIPID_BCM4329:
|
case BHND_CHIPID_BCM4329:
|
||||||
@ -1442,15 +1483,15 @@ bhnd_pmu1_pllfvco0(struct bhnd_pmu_softc *sc)
|
|||||||
else
|
else
|
||||||
return (FVCO_1440);
|
return (FVCO_1440);
|
||||||
default:
|
default:
|
||||||
PMU_MSG(("bhnd_pmu1_pllfvco0: Unknown chipid %#hx\n",
|
PMU_DEBUG(sc, "bhnd_pmu1_pllfvco0: Unknown chipid %#hx\n",
|
||||||
sc->cid.chip_id));
|
sc->cid.chip_id);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* query alp/xtal clock frequency */
|
/* query alp/xtal clock frequency */
|
||||||
static uint32_t
|
static uint32_t
|
||||||
bhnd_pmu1_alpclk0(struct bhnd_pmu_softc *sc)
|
bhnd_pmu1_alpclk0(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
const pmu1_xtaltab0_t *xt;
|
const pmu1_xtaltab0_t *xt;
|
||||||
uint32_t xf;
|
uint32_t xf;
|
||||||
@ -1469,8 +1510,7 @@ bhnd_pmu1_alpclk0(struct bhnd_pmu_softc *sc)
|
|||||||
xt = bhnd_pmu1_xtaldef0(sc);
|
xt = bhnd_pmu1_xtaldef0(sc);
|
||||||
|
|
||||||
if (xt == NULL || xt->fref == 0) {
|
if (xt == NULL || xt->fref == 0) {
|
||||||
device_printf(sc->dev,
|
PMU_LOG(sc, "no matching ALP/XTAL frequency found\n");
|
||||||
"no matching ALP/XTAL frequency found\n");
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1489,8 +1529,8 @@ bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
|
|
||||||
/* Use h/w default PLL config */
|
/* Use h/w default PLL config */
|
||||||
if (xtal == 0) {
|
if (xtal == 0) {
|
||||||
PMU_MSG(("Unspecified xtal frequency, skipping PLL "
|
PMU_DEBUG(sc, "Unspecified xtal frequency, skipping PLL "
|
||||||
"configuration\n"));
|
"configuration\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1503,7 +1543,8 @@ bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
if (xt->freq == 0)
|
if (xt->freq == 0)
|
||||||
xt = &pmu0_xtaltab0[PMU0_XTAL0_DEFAULT];
|
xt = &pmu0_xtaltab0[PMU0_XTAL0_DEFAULT];
|
||||||
|
|
||||||
PMU_MSG(("XTAL %d.%d MHz (%d)\n", xtal / 1000, xtal % 1000, xt->xf));
|
PMU_DEBUG(sc, "XTAL %d.%d MHz (%d)\n", xtal / 1000, xtal % 1000,
|
||||||
|
xt->xf);
|
||||||
|
|
||||||
/* Check current PLL state */
|
/* Check current PLL state */
|
||||||
pmu_ctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
|
pmu_ctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
|
||||||
@ -1517,19 +1558,20 @@ bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
}
|
}
|
||||||
#endif /* BCMUSBDEV */
|
#endif /* BCMUSBDEV */
|
||||||
|
|
||||||
PMU_MSG(("PLL already programmed for %d.%d MHz\n",
|
PMU_DEBUG(sc, "PLL already programmed for %d.%d MHz\n",
|
||||||
xt->freq / 1000, xt->freq % 1000));
|
xt->freq / 1000, xt->freq % 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xf != 0) {
|
if (xf != 0) {
|
||||||
PMU_MSG(("Reprogramming PLL for %d.%d MHz (was %d.%dMHz)\n",
|
PMU_DEBUG(sc,
|
||||||
|
"Reprogramming PLL for %d.%d MHz (was %d.%dMHz)\n",
|
||||||
xt->freq / 1000, xt->freq % 1000,
|
xt->freq / 1000, xt->freq % 1000,
|
||||||
pmu0_xtaltab0[tmp-1].freq / 1000,
|
pmu0_xtaltab0[tmp-1].freq / 1000,
|
||||||
pmu0_xtaltab0[tmp-1].freq % 1000));
|
pmu0_xtaltab0[tmp-1].freq % 1000);
|
||||||
} else {
|
} else {
|
||||||
PMU_MSG(("Programming PLL for %d.%d MHz\n",
|
PMU_DEBUG(sc, "Programming PLL for %d.%d MHz\n",
|
||||||
xt->freq / 1000, xt->freq % 1000));
|
xt->freq / 1000, xt->freq % 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure the PLL is off */
|
/* Make sure the PLL is off */
|
||||||
@ -1549,7 +1591,7 @@ bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
/* Wait for HT clock to shutdown. */
|
/* Wait for HT clock to shutdown. */
|
||||||
PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL);
|
PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL);
|
||||||
|
|
||||||
PMU_MSG(("Done masking\n"));
|
PMU_DEBUG(sc, "Done masking\n");
|
||||||
|
|
||||||
/* Write PDIV in pllcontrol[0] */
|
/* Write PDIV in pllcontrol[0] */
|
||||||
if (xt->freq >= BHND_PMU0_PLL0_PC0_PDIV_FREQ) {
|
if (xt->freq >= BHND_PMU0_PLL0_PC0_PDIV_FREQ) {
|
||||||
@ -1582,7 +1624,7 @@ bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
pll_mask = BHND_PMU0_PLL0_PC2_WILD_INT_MASK;
|
pll_mask = BHND_PMU0_PLL0_PC2_WILD_INT_MASK;
|
||||||
BHND_PMU_PLL_WRITE(sc, BHND_PMU0_PLL0_PLLCTL2, pll_data, pll_mask);
|
BHND_PMU_PLL_WRITE(sc, BHND_PMU0_PLL0_PLLCTL2, pll_data, pll_mask);
|
||||||
|
|
||||||
PMU_MSG(("Done pll\n"));
|
PMU_DEBUG(sc, "Done pll\n");
|
||||||
|
|
||||||
/* Write XtalFreq. Set the divisor also. */
|
/* Write XtalFreq. Set the divisor also. */
|
||||||
pmu_ctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
|
pmu_ctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL);
|
||||||
@ -1597,7 +1639,7 @@ bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
|
|
||||||
/* query alp/xtal clock frequency */
|
/* query alp/xtal clock frequency */
|
||||||
static uint32_t
|
static uint32_t
|
||||||
bhnd_pmu0_alpclk0(struct bhnd_pmu_softc *sc)
|
bhnd_pmu0_alpclk0(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
const pmu0_xtaltab0_t *xt;
|
const pmu0_xtaltab0_t *xt;
|
||||||
uint32_t xf;
|
uint32_t xf;
|
||||||
@ -1618,7 +1660,7 @@ bhnd_pmu0_alpclk0(struct bhnd_pmu_softc *sc)
|
|||||||
|
|
||||||
/* query CPU clock frequency */
|
/* query CPU clock frequency */
|
||||||
static uint32_t
|
static uint32_t
|
||||||
bhnd_pmu0_cpuclk0(struct bhnd_pmu_softc *sc)
|
bhnd_pmu0_cpuclk0(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
uint32_t tmp, divarm;
|
uint32_t tmp, divarm;
|
||||||
uint32_t FVCO;
|
uint32_t FVCO;
|
||||||
@ -1654,8 +1696,8 @@ bhnd_pmu0_cpuclk0(struct bhnd_pmu_softc *sc)
|
|||||||
fvco /= 1000;
|
fvco /= 1000;
|
||||||
fvco *= 1000;
|
fvco *= 1000;
|
||||||
|
|
||||||
PMU_MSG(("bhnd_pmu0_cpuclk0: wbint %u wbfrac %u fvco %u\n",
|
PMU_DEBUG(sc, "bhnd_pmu0_cpuclk0: wbint %u wbfrac %u fvco %u\n",
|
||||||
wbint, wbfrac, fvco));
|
wbint, wbfrac, fvco);
|
||||||
|
|
||||||
FVCO = fvco;
|
FVCO = fvco;
|
||||||
#endif /* BCMDBG */
|
#endif /* BCMDBG */
|
||||||
@ -1677,19 +1719,21 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
uint32_t FVCO;
|
uint32_t FVCO;
|
||||||
uint8_t ndiv_mode;
|
uint8_t ndiv_mode;
|
||||||
|
|
||||||
FVCO = bhnd_pmu1_pllfvco0(sc) / 1000;
|
FVCO = bhnd_pmu1_pllfvco0(&sc->query) / 1000;
|
||||||
buf_strength = 0;
|
buf_strength = 0;
|
||||||
ndiv_mode = 1;
|
ndiv_mode = 1;
|
||||||
|
|
||||||
/* Use h/w default PLL config */
|
/* Use h/w default PLL config */
|
||||||
if (xtal == 0) {
|
if (xtal == 0) {
|
||||||
PMU_MSG(("Unspecified xtal frequency, skipping PLL "
|
PMU_DEBUG(sc, "Unspecified xtal frequency, skipping PLL "
|
||||||
"configuration\n"));
|
"configuration\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the frequency in the table */
|
/* Find the frequency in the table */
|
||||||
for (xt = bhnd_pmu1_xtaltab0(sc); xt != NULL && xt->fref != 0; xt++) {
|
for (xt = bhnd_pmu1_xtaltab0(&sc->query); xt != NULL && xt->fref != 0;
|
||||||
|
xt++)
|
||||||
|
{
|
||||||
if (xt->fref == xtal)
|
if (xt->fref == xtal)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1698,8 +1742,8 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
* we don't know how to program it.
|
* we don't know how to program it.
|
||||||
*/
|
*/
|
||||||
if (xt == NULL || xt->fref == 0) {
|
if (xt == NULL || xt->fref == 0) {
|
||||||
device_printf(sc->dev, "Unsupported XTAL frequency %d.%dMHz, "
|
PMU_LOG(sc, "Unsupported XTAL frequency %d.%dMHz, skipping PLL "
|
||||||
"skipping PLL configuration\n", xtal / 1000, xtal % 1000);
|
"configuration\n", xtal / 1000, xtal % 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1710,14 +1754,14 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
sc->cid.chip_id != BHND_CHIPID_BCM4319 &&
|
sc->cid.chip_id != BHND_CHIPID_BCM4319 &&
|
||||||
sc->cid.chip_id != BHND_CHIPID_BCM4330)
|
sc->cid.chip_id != BHND_CHIPID_BCM4330)
|
||||||
{
|
{
|
||||||
PMU_MSG(("PLL already programmed for %d.%dMHz\n",
|
PMU_DEBUG(sc, "PLL already programmed for %d.%dMHz\n",
|
||||||
xt->fref / 1000, xt->fref % 1000));
|
xt->fref / 1000, xt->fref % 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PMU_MSG(("XTAL %d.%dMHz (%d)\n", xtal / 1000, xtal % 1000, xt->xf));
|
PMU_DEBUG(sc, "XTAL %d.%dMHz (%d)\n", xtal / 1000, xtal % 1000, xt->xf);
|
||||||
PMU_MSG(("Programming PLL for %d.%dMHz\n", xt->fref / 1000,
|
PMU_DEBUG(sc, "Programming PLL for %d.%dMHz\n", xt->fref / 1000,
|
||||||
xt->fref % 1000));
|
xt->fref % 1000);
|
||||||
|
|
||||||
switch (sc->cid.chip_id) {
|
switch (sc->cid.chip_id) {
|
||||||
case BHND_CHIPID_BCM4325:
|
case BHND_CHIPID_BCM4325:
|
||||||
@ -1840,7 +1884,7 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
panic("unsupported chipid %#hx\n", sc->cid.chip_id);
|
panic("unsupported chipid %#hx\n", sc->cid.chip_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
PMU_MSG(("Done masking\n"));
|
PMU_DEBUG(sc, "Done masking\n");
|
||||||
|
|
||||||
/* Write p1div and p2div to pllcontrol[0] */
|
/* Write p1div and p2div to pllcontrol[0] */
|
||||||
plldata =
|
plldata =
|
||||||
@ -1916,8 +1960,8 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
|
|
||||||
/* Write clock driving strength to pllcontrol[5] */
|
/* Write clock driving strength to pllcontrol[5] */
|
||||||
if (buf_strength) {
|
if (buf_strength) {
|
||||||
PMU_MSG(("Adjusting PLL buffer drive strength: %x\n",
|
PMU_DEBUG(sc, "Adjusting PLL buffer drive strength: %x\n",
|
||||||
buf_strength));
|
buf_strength);
|
||||||
|
|
||||||
plldata = BHND_PMU_SET_BITS(buf_strength,
|
plldata = BHND_PMU_SET_BITS(buf_strength,
|
||||||
BHND_PMU1_PLL0_PC5_CLK_DRV);
|
BHND_PMU1_PLL0_PC5_CLK_DRV);
|
||||||
@ -1946,7 +1990,7 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
pllmask);
|
pllmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
PMU_MSG(("Done pll\n"));
|
PMU_DEBUG(sc, "Done pll\n");
|
||||||
|
|
||||||
/* to operate the 4319 usb in 24MHz/48MHz; chipcontrol[2][84:83] needs
|
/* to operate the 4319 usb in 24MHz/48MHz; chipcontrol[2][84:83] needs
|
||||||
* to be updated.
|
* to be updated.
|
||||||
@ -1995,7 +2039,7 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal)
|
|||||||
|
|
||||||
/* query the CPU clock frequency */
|
/* query the CPU clock frequency */
|
||||||
static uint32_t
|
static uint32_t
|
||||||
bhnd_pmu1_cpuclk0(struct bhnd_pmu_softc *sc)
|
bhnd_pmu1_cpuclk0(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
uint32_t tmp, m1div;
|
uint32_t tmp, m1div;
|
||||||
#ifdef BCMDBG
|
#ifdef BCMDBG
|
||||||
@ -2032,8 +2076,8 @@ bhnd_pmu1_cpuclk0(struct bhnd_pmu_softc *sc)
|
|||||||
fvco /= 1000;
|
fvco /= 1000;
|
||||||
fvco *= 1000;
|
fvco *= 1000;
|
||||||
|
|
||||||
PMU_MSG(("bhnd_pmu1_cpuclk0: ndiv_int %u ndiv_frac %u p2div %u "
|
PMU_DEBUG(sc, "bhnd_pmu1_cpuclk0: ndiv_int %u ndiv_frac %u p2div %u "
|
||||||
"p1div %u fvco %u\n", ndiv_int, ndiv_frac, p2div, p1div, fvco));
|
"p1div %u fvco %u\n", ndiv_int, ndiv_frac, p2div, p1div, fvco);
|
||||||
|
|
||||||
FVCO = fvco;
|
FVCO = fvco;
|
||||||
#endif /* BCMDBG */
|
#endif /* BCMDBG */
|
||||||
@ -2134,15 +2178,19 @@ bhnd_pmu_pll_init(struct bhnd_pmu_softc *sc, u_int xtalfreq)
|
|||||||
bhnd_pmu1_pllinit0(sc, xtalfreq);
|
bhnd_pmu1_pllinit0(sc, xtalfreq);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PMU_MSG(("No PLL init done for chip %#hx rev %d pmurev %d\n",
|
PMU_DEBUG("No PLL init done for chip %#hx rev %d pmurev %d\n",
|
||||||
sc->cid.chip_id, sc->cid.chip_rev, BHND_PMU_REV(sc)));
|
sc->cid.chip_id, sc->cid.chip_rev, BHND_PMU_REV(sc));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* query alp/xtal clock frequency */
|
/**
|
||||||
|
* Return the ALP/XTAL clock frequency, in Hz.
|
||||||
|
*
|
||||||
|
* @param sc PMU query instance.
|
||||||
|
*/
|
||||||
uint32_t
|
uint32_t
|
||||||
bhnd_pmu_alp_clock(struct bhnd_pmu_softc *sc)
|
bhnd_pmu_alp_clock(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
uint32_t clock;
|
uint32_t clock;
|
||||||
|
|
||||||
@ -2201,10 +2249,10 @@ bhnd_pmu_alp_clock(struct bhnd_pmu_softc *sc)
|
|||||||
clock = 25000 * 1000;
|
clock = 25000 * 1000;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PMU_MSG(("No ALP clock specified "
|
PMU_DEBUG("No ALP clock specified "
|
||||||
"for chip %s rev %d pmurev %d, using default %d Hz\n",
|
"for chip %s rev %d pmurev %d, using default %d Hz\n",
|
||||||
bcm_chipname(sih->chip, chn, 8), sih->chiprev,
|
bcm_chipname(sih->chip, chn, 8), sih->chiprev,
|
||||||
sih->pmurev, clock));
|
sih->pmurev, clock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2215,7 +2263,7 @@ bhnd_pmu_alp_clock(struct bhnd_pmu_softc *sc)
|
|||||||
* pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
|
* pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
|
||||||
*/
|
*/
|
||||||
static uint32_t
|
static uint32_t
|
||||||
bhnd_pmu5_clock(struct bhnd_pmu_softc *sc, u_int pll0, u_int m)
|
bhnd_pmu5_clock(struct bhnd_pmu_query *sc, u_int pll0, u_int m)
|
||||||
{
|
{
|
||||||
uint32_t div;
|
uint32_t div;
|
||||||
uint32_t fc;
|
uint32_t fc;
|
||||||
@ -2224,13 +2272,13 @@ bhnd_pmu5_clock(struct bhnd_pmu_softc *sc, u_int pll0, u_int m)
|
|||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
|
|
||||||
if ((pll0 & 3) || (pll0 > BHND_PMU4716_MAINPLL_PLL0)) {
|
if ((pll0 & 3) || (pll0 > BHND_PMU4716_MAINPLL_PLL0)) {
|
||||||
PMU_ERROR(("%s: Bad pll0: %d\n", __func__, pll0));
|
PMU_LOG(sc, "%s: Bad pll0: %d", __func__, pll0);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Strictly there is an m5 divider, but I'm not sure we use it */
|
/* Strictly there is an m5 divider, but I'm not sure we use it */
|
||||||
if ((m == 0) || (m > 4)) {
|
if ((m == 0) || (m > 4)) {
|
||||||
PMU_ERROR(("%s: Bad m divider: %d\n", __func__, m));
|
PMU_LOG(sc, "%s: Bad m divider: %d", __func__, m);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2238,7 +2286,7 @@ bhnd_pmu5_clock(struct bhnd_pmu_softc *sc, u_int pll0, u_int m)
|
|||||||
sc->cid.chip_id == BHND_CHIPID_BCM4749)
|
sc->cid.chip_id == BHND_CHIPID_BCM4749)
|
||||||
{
|
{
|
||||||
/* Detect failure in clock setting */
|
/* Detect failure in clock setting */
|
||||||
tmp = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
|
tmp = sc->io->rd_chipst(sc->io_ctx);
|
||||||
if ((tmp & 0x40000) != 0)
|
if ((tmp & 0x40000) != 0)
|
||||||
return (133 * 1000000);
|
return (133 * 1000000);
|
||||||
}
|
}
|
||||||
@ -2274,19 +2322,23 @@ bhnd_pmu5_clock(struct bhnd_pmu_softc *sc, u_int pll0, u_int m)
|
|||||||
fc = bhnd_pmu_alp_clock(sc) / 1000000;
|
fc = bhnd_pmu_alp_clock(sc) / 1000000;
|
||||||
fc = (p1 * ndiv * fc) / p2;
|
fc = (p1 * ndiv * fc) / p2;
|
||||||
|
|
||||||
PMU_MSG(("%s: p1=%d, p2=%d, ndiv=%d(0x%x), m%d=%d; fc=%d, clock=%d\n",
|
PMU_DEBUG(sc, "%s: p1=%d, p2=%d, ndiv=%d(0x%x), m%d=%d; fc=%d, "
|
||||||
__func__, p1, p2, ndiv, ndiv, m, div, fc, fc / div));
|
"clock=%d\n", __func__, p1, p2, ndiv, ndiv, m, div, fc, fc / div);
|
||||||
|
|
||||||
/* Return clock in Hertz */
|
/* Return clock in Hertz */
|
||||||
return ((fc / div) * 1000000);
|
return ((fc / div) * 1000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* query backplane clock frequency */
|
/**
|
||||||
/* For designs that feed the same clock to both backplane
|
* Return the backplane clock frequency, in Hz.
|
||||||
* and CPU just return the CPU clock speed.
|
*
|
||||||
|
* On designs that feed the same clock to both backplane
|
||||||
|
* and CPU, this returns the CPU clock speed.
|
||||||
|
*
|
||||||
|
* @param sc PMU query instance.
|
||||||
*/
|
*/
|
||||||
uint32_t
|
uint32_t
|
||||||
bhnd_pmu_si_clock(struct bhnd_pmu_softc *sc)
|
bhnd_pmu_si_clock(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
uint32_t chipst;
|
uint32_t chipst;
|
||||||
uint32_t clock;
|
uint32_t clock;
|
||||||
@ -2351,14 +2403,14 @@ bhnd_pmu_si_clock(struct bhnd_pmu_softc *sc)
|
|||||||
case BHND_CHIPID_BCM43235:
|
case BHND_CHIPID_BCM43235:
|
||||||
case BHND_CHIPID_BCM43236:
|
case BHND_CHIPID_BCM43236:
|
||||||
case BHND_CHIPID_BCM43238:
|
case BHND_CHIPID_BCM43238:
|
||||||
chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
|
chipst = sc->io->rd_chipst(sc->io_ctx);
|
||||||
if (chipst & CHIPC_CST43236_BP_CLK)
|
if (chipst & CHIPC_CST43236_BP_CLK)
|
||||||
clock = 120000 * 1000;
|
clock = 120000 * 1000;
|
||||||
else
|
else
|
||||||
clock = 96000 * 1000;
|
clock = 96000 * 1000;
|
||||||
break;
|
break;
|
||||||
case BHND_CHIPID_BCM43237:
|
case BHND_CHIPID_BCM43237:
|
||||||
chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev);
|
chipst = sc->io->rd_chipst(sc->io_ctx);
|
||||||
if (chipst & CHIPC_CST43237_BP_CLK)
|
if (chipst & CHIPC_CST43237_BP_CLK)
|
||||||
clock = 96000 * 1000;
|
clock = 96000 * 1000;
|
||||||
else
|
else
|
||||||
@ -2377,8 +2429,8 @@ bhnd_pmu_si_clock(struct bhnd_pmu_softc *sc)
|
|||||||
clock = 75000000;
|
clock = 75000000;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
device_printf(sc->dev, "No backplane clock specified for chip "
|
PMU_LOG(sc, "No backplane clock specified for chip %#hx rev "
|
||||||
"%#hx rev %hhd pmurev %hhd, using default %dHz\n",
|
"%hhd pmurev %hhd, using default %dHz\n",
|
||||||
sc->cid.chip_id, sc->cid.chip_rev, BHND_PMU_REV(sc), clock);
|
sc->cid.chip_id, sc->cid.chip_rev, BHND_PMU_REV(sc), clock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2386,18 +2438,19 @@ bhnd_pmu_si_clock(struct bhnd_pmu_softc *sc)
|
|||||||
return (clock);
|
return (clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* query CPU clock frequency */
|
/**
|
||||||
|
* Return the CPU clock frequency, in Hz.
|
||||||
|
*
|
||||||
|
* @param sc PMU query instance.
|
||||||
|
*/
|
||||||
uint32_t
|
uint32_t
|
||||||
bhnd_pmu_cpu_clock(struct bhnd_pmu_softc *sc)
|
bhnd_pmu_cpu_clock(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
uint32_t clock;
|
uint32_t clock;
|
||||||
|
|
||||||
if (sc->cid.chip_id == BHND_CHIPID_BCM5354)
|
|
||||||
return (240 * 1000 * 1000); /* 240MHz */
|
|
||||||
|
|
||||||
/* 5354 chip uses a non programmable PLL of frequency 240MHz */
|
/* 5354 chip uses a non programmable PLL of frequency 240MHz */
|
||||||
if (sc->cid.chip_id == BHND_CHIPID_BCM5354)
|
if (sc->cid.chip_id == BHND_CHIPID_BCM5354)
|
||||||
return (240000000);
|
return (240 * 1000 * 1000); /* 240MHz */
|
||||||
|
|
||||||
if (sc->cid.chip_id == BHND_CHIPID_BCM53572)
|
if (sc->cid.chip_id == BHND_CHIPID_BCM53572)
|
||||||
return (300000000);
|
return (300000000);
|
||||||
@ -2436,9 +2489,13 @@ bhnd_pmu_cpu_clock(struct bhnd_pmu_softc *sc)
|
|||||||
return (clock);
|
return (clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* query memory clock frequency */
|
/**
|
||||||
|
* Return the memory clock frequency, in Hz.
|
||||||
|
*
|
||||||
|
* @param sc PMU query instance.
|
||||||
|
*/
|
||||||
uint32_t
|
uint32_t
|
||||||
bhnd_pmu_mem_clock(struct bhnd_pmu_softc *sc)
|
bhnd_pmu_mem_clock(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
uint32_t clock;
|
uint32_t clock;
|
||||||
|
|
||||||
@ -2479,8 +2536,13 @@ bhnd_pmu_mem_clock(struct bhnd_pmu_softc *sc)
|
|||||||
/* Measure ILP clock frequency */
|
/* Measure ILP clock frequency */
|
||||||
#define ILP_CALC_DUR 10 /* ms, make sure 1000 can be divided by it. */
|
#define ILP_CALC_DUR 10 /* ms, make sure 1000 can be divided by it. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Measure and return the ILP clock frequency, in Hz.
|
||||||
|
*
|
||||||
|
* @param sc PMU query instance.
|
||||||
|
*/
|
||||||
uint32_t
|
uint32_t
|
||||||
bhnd_pmu_ilp_clock(struct bhnd_pmu_softc *sc)
|
bhnd_pmu_ilp_clock(struct bhnd_pmu_query *sc)
|
||||||
{
|
{
|
||||||
uint32_t start, end, delta;
|
uint32_t start, end, delta;
|
||||||
|
|
||||||
@ -2572,9 +2634,9 @@ bhnd_pmu_sdiod_drive_strength_init(struct bhnd_pmu_softc *sc,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
device_printf(sc->dev, "No SDIO Drive strength init done for "
|
PMU_LOG(sc, "No SDIO Drive strength init done for chip %#x "
|
||||||
"chip %#x rev %hhd pmurev %hhd\n", sc->cid.chip_id,
|
"rev %hhd pmurev %hhd\n", sc->cid.chip_id, sc->cid.chip_rev,
|
||||||
sc->cid.chip_rev, BHND_PMU_REV(sc));
|
BHND_PMU_REV(sc));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2595,8 +2657,8 @@ bhnd_pmu_sdiod_drive_strength_init(struct bhnd_pmu_softc *sc,
|
|||||||
cc_data_temp |= drivestrength_sel;
|
cc_data_temp |= drivestrength_sel;
|
||||||
BHND_PMU_CCTRL_WRITE(sc, 1, cc_data_temp, ~0);
|
BHND_PMU_CCTRL_WRITE(sc, 1, cc_data_temp, ~0);
|
||||||
|
|
||||||
PMU_MSG(("SDIO: %dmA drive strength selected, set to 0x%08x\n",
|
PMU_DEBUG(sc, "SDIO: %dmA drive strength selected, set to "
|
||||||
drivestrength, cc_data_temp));
|
"0x%08x\n", drivestrength, cc_data_temp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2633,10 +2695,8 @@ bhnd_pmu_init(struct bhnd_pmu_softc *sc)
|
|||||||
|
|
||||||
/* If not available, log any real errors, and then try to measure it */
|
/* If not available, log any real errors, and then try to measure it */
|
||||||
if (error) {
|
if (error) {
|
||||||
if (error != ENOENT) {
|
if (error != ENOENT)
|
||||||
device_printf(sc->dev, "error fetching xtalfreq: %d\n",
|
PMU_LOG(sc, "error fetching xtalfreq: %d\n", error);
|
||||||
error);
|
|
||||||
}
|
|
||||||
|
|
||||||
xtalfreq = bhnd_pmu_measure_alpclk(sc);
|
xtalfreq = bhnd_pmu_measure_alpclk(sc);
|
||||||
}
|
}
|
||||||
@ -2693,8 +2753,8 @@ bhnd_pmu_res_uptime(struct bhnd_pmu_softc *sc, uint8_t rsrc, uint32_t *uptime)
|
|||||||
dmax = dup;
|
dmax = dup;
|
||||||
}
|
}
|
||||||
|
|
||||||
PMU_MSG(("bhnd_pmu_res_uptime: rsrc %hhu uptime %u(deps 0x%08x "
|
PMU_DEBUG(sc, "bhnd_pmu_res_uptime: rsrc %hhu uptime %u(deps 0x%08x "
|
||||||
"uptime %u)\n", rsrc, up, deps, dmax));
|
"uptime %u)\n", rsrc, up, deps, dmax);
|
||||||
|
|
||||||
*uptime = (up + dmax + BHND_PMURES_UP_TRANSITION);
|
*uptime = (up + dmax + BHND_PMURES_UP_TRANSITION);
|
||||||
return (0);
|
return (0);
|
||||||
@ -2779,8 +2839,8 @@ bhnd_pmu_otp_power(struct bhnd_pmu_softc *sc, bool on)
|
|||||||
if (on) {
|
if (on) {
|
||||||
uint32_t state;
|
uint32_t state;
|
||||||
|
|
||||||
PMU_MSG(("Adding rsrc 0x%x to min_res_mask\n",
|
PMU_DEBUG(sc, "Adding rsrc 0x%x to min_res_mask\n",
|
||||||
rsrcs | deps));
|
rsrcs | deps);
|
||||||
BHND_PMU_OR_4(sc, BHND_PMU_MIN_RES_MASK, (rsrcs|deps));
|
BHND_PMU_OR_4(sc, BHND_PMU_MIN_RES_MASK, (rsrcs|deps));
|
||||||
|
|
||||||
/* Wait for all resources to become available */
|
/* Wait for all resources to become available */
|
||||||
@ -2793,13 +2853,13 @@ bhnd_pmu_otp_power(struct bhnd_pmu_softc *sc, bool on)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((state & rsrcs) != rsrcs) {
|
if ((state & rsrcs) != rsrcs) {
|
||||||
device_printf(sc->dev, "timeout waiting for OTP "
|
PMU_LOG(sc, "timeout waiting for OTP resource "
|
||||||
"resource enable\n");
|
"enable\n");
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PMU_MSG(("Removing rsrc 0x%x from min_res_mask\n",
|
PMU_DEBUG(sc, "Removing rsrc 0x%x from min_res_mask\n",
|
||||||
rsrcs | deps));
|
rsrcs | deps);
|
||||||
BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~(rsrcs|deps));
|
BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~(rsrcs|deps));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2853,8 +2913,8 @@ bhnd_pmu_rcal(struct bhnd_pmu_softc *sc)
|
|||||||
rcal_code = (uint8_t) (chipst >> 5) & 0x0f;
|
rcal_code = (uint8_t) (chipst >> 5) & 0x0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
PMU_MSG(("RCal completed, status 0x%x, code 0x%x\n",
|
PMU_DEBUG("RCal completed, status 0x%x, code 0x%x\n",
|
||||||
R_REG(&cc->chipstatus), rcal_code));
|
R_REG(&cc->chipstatus), rcal_code);
|
||||||
|
|
||||||
/* Write RCal code into pmu_vreg_ctrl[32:29] */
|
/* Write RCal code into pmu_vreg_ctrl[32:29] */
|
||||||
BHND_PMU_WRITE_4(sc, BHND_PMU_REG_CONTROL_ADDR, 0);
|
BHND_PMU_WRITE_4(sc, BHND_PMU_REG_CONTROL_ADDR, 0);
|
||||||
@ -3098,6 +3158,7 @@ bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BHND_CHIPID_BCM4319:
|
case BHND_CHIPID_BCM4319:
|
||||||
|
pmuctrl = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BHND_CHIPID_BCM4322:
|
case BHND_CHIPID_BCM4322:
|
||||||
@ -3136,7 +3197,6 @@ bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
|
|||||||
}
|
}
|
||||||
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, tmp, ~0);
|
BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, tmp, ~0);
|
||||||
|
|
||||||
|
|
||||||
pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
|
pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
|
||||||
break;
|
break;
|
||||||
case BHND_CHIPID_BCM43131:
|
case BHND_CHIPID_BCM43131:
|
||||||
@ -3176,12 +3236,14 @@ bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid)
|
|||||||
pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
|
pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PMU_ERROR(("%s: unknown spuravoidance settings for chip %#hx, "
|
PMU_LOG(sc, "%s: unknown spuravoidance settings for chip %#hx, "
|
||||||
"not changing PLL\n", __func__, sc->cid.chip_id));
|
"not changing PLL", __func__, sc->cid.chip_id);
|
||||||
|
pmuctrl = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
BHND_PMU_OR_4(sc, BHND_PMU_CTRL, pmuctrl);
|
if (pmuctrl != 0)
|
||||||
|
BHND_PMU_OR_4(sc, BHND_PMU_CTRL, pmuctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -3417,7 +3479,7 @@ bhnd_pmu_measure_alpclk(struct bhnd_pmu_softc *sc)
|
|||||||
static void
|
static void
|
||||||
bhnd_pmu_set_4330_plldivs(struct bhnd_pmu_softc *sc)
|
bhnd_pmu_set_4330_plldivs(struct bhnd_pmu_softc *sc)
|
||||||
{
|
{
|
||||||
uint32_t FVCO = bhnd_pmu1_pllfvco0(sc) / 1000;
|
uint32_t FVCO = bhnd_pmu1_pllfvco0(&sc->query) / 1000;
|
||||||
uint32_t m1div, m2div, m3div, m4div, m5div, m6div;
|
uint32_t m1div, m2div, m3div, m4div, m5div, m6div;
|
||||||
uint32_t pllc1, pllc2;
|
uint32_t pllc1, pllc2;
|
||||||
|
|
||||||
|
@ -37,15 +37,28 @@
|
|||||||
|
|
||||||
#include "bhnd_pmu.h"
|
#include "bhnd_pmu.h"
|
||||||
|
|
||||||
|
struct bhnd_pmu_query;
|
||||||
|
struct bhnd_pmu_io;
|
||||||
|
|
||||||
DECLARE_CLASS(bhnd_pmu_driver);
|
DECLARE_CLASS(bhnd_pmu_driver);
|
||||||
extern devclass_t bhnd_pmu_devclass;
|
extern devclass_t bhnd_pmu_devclass;
|
||||||
|
|
||||||
int bhnd_pmu_probe(device_t dev);
|
int bhnd_pmu_probe(device_t dev);
|
||||||
|
int bhnd_pmu_attach(device_t dev, struct bhnd_resource *res);
|
||||||
|
int bhnd_pmu_detach(device_t dev);
|
||||||
|
int bhnd_pmu_suspend(device_t dev);
|
||||||
|
int bhnd_pmu_resume(device_t dev);
|
||||||
|
|
||||||
int bhnd_pmu_attach(device_t dev, struct bhnd_resource *res);
|
int bhnd_pmu_query_init(struct bhnd_pmu_query *query, device_t dev,
|
||||||
int bhnd_pmu_detach(device_t dev);
|
struct bhnd_chipid id, const struct bhnd_pmu_io *io,
|
||||||
int bhnd_pmu_suspend(device_t dev);
|
void *ctx);
|
||||||
int bhnd_pmu_resume(device_t dev);
|
void bhnd_pmu_query_fini(struct bhnd_pmu_query *query);
|
||||||
|
|
||||||
|
uint32_t bhnd_pmu_si_clock(struct bhnd_pmu_query *sc);
|
||||||
|
uint32_t bhnd_pmu_cpu_clock(struct bhnd_pmu_query *sc);
|
||||||
|
uint32_t bhnd_pmu_mem_clock(struct bhnd_pmu_query *sc);
|
||||||
|
uint32_t bhnd_pmu_alp_clock(struct bhnd_pmu_query *sc);
|
||||||
|
uint32_t bhnd_pmu_ilp_clock(struct bhnd_pmu_query *sc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BHND PMU device quirks / features
|
* BHND PMU device quirks / features
|
||||||
@ -60,25 +73,62 @@ enum {
|
|||||||
BPMU_QUIRK_CLKCTL_CCS0 = 1
|
BPMU_QUIRK_CLKCTL_CCS0 = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PMU read-only query support.
|
||||||
|
*
|
||||||
|
* Provides support for querying PMU information prior to availability of
|
||||||
|
* the bhnd(4) bus.
|
||||||
|
*/
|
||||||
|
struct bhnd_pmu_query {
|
||||||
|
device_t dev; /**< owning device, or NULL */
|
||||||
|
struct bhnd_chipid cid; /**< chip identification */
|
||||||
|
uint32_t caps; /**< pmu capability flags. */
|
||||||
|
|
||||||
|
const struct bhnd_pmu_io *io; /**< I/O operations */
|
||||||
|
void *io_ctx; /**< I/O callback context */
|
||||||
|
|
||||||
|
uint32_t ilp_cps; /**< measured ILP cycles per second, or 0 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PMU abstract I/O operations.
|
||||||
|
*/
|
||||||
|
struct bhnd_pmu_io {
|
||||||
|
/* Read 4 bytes from PMU @p reg */
|
||||||
|
uint32_t (*rd4)(bus_size_t reg, void *ctx);
|
||||||
|
|
||||||
|
/* Read 4 bytes to PMU @p reg */
|
||||||
|
void (*wr4)(bus_size_t reg, uint32_t val, void *ctx);
|
||||||
|
|
||||||
|
/* Read ChipCommon's CHIP_ST register */
|
||||||
|
uint32_t (*rd_chipst)(void *ctx);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bhnd_pmu driver instance state.
|
* bhnd_pmu driver instance state.
|
||||||
*/
|
*/
|
||||||
struct bhnd_pmu_softc {
|
struct bhnd_pmu_softc {
|
||||||
device_t dev;
|
device_t dev;
|
||||||
uint32_t quirks; /**< device quirk flags */
|
uint32_t quirks; /**< device quirk flags */
|
||||||
uint32_t caps; /**< pmu capability flags. */
|
uint32_t caps; /**< pmu capability flags. */
|
||||||
|
struct bhnd_chipid cid; /**< chip identification */
|
||||||
|
|
||||||
struct bhnd_chipid cid; /**< chip identification */
|
struct bhnd_pmu_query query; /**< query instance */
|
||||||
struct bhnd_board_info board; /**< board identification */
|
|
||||||
device_t chipc_dev; /**< chipcommon device */
|
|
||||||
|
|
||||||
struct bhnd_resource *res; /**< pmu register block. */
|
struct bhnd_board_info board; /**< board identification */
|
||||||
int rid; /**< pmu register RID */
|
device_t chipc_dev; /**< chipcommon device */
|
||||||
|
|
||||||
struct mtx mtx; /**< state mutex */
|
struct bhnd_resource *res; /**< pmu register block. */
|
||||||
|
int rid; /**< pmu register RID */
|
||||||
|
|
||||||
|
struct mtx mtx; /**< state mutex */
|
||||||
|
|
||||||
|
/* For compatibility with bhnd_pmu_query APIs and the shared
|
||||||
|
* BHND_PMU_(READ|WRITE) macros. */
|
||||||
|
const struct bhnd_pmu_io *io;
|
||||||
|
void *io_ctx;
|
||||||
|
|
||||||
uint32_t ilp_cps; /**< measured ILP cycles per
|
|
||||||
second, or 0 */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BPMU_LOCK_INIT(sc) \
|
#define BPMU_LOCK_INIT(sc) \
|
||||||
|
@ -85,7 +85,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include "bcm_machdep.h"
|
#include "bcm_machdep.h"
|
||||||
#include "bcm_mips_exts.h"
|
#include "bcm_mips_exts.h"
|
||||||
#include "bcm_socinfo.h"
|
|
||||||
|
|
||||||
#ifdef CFE
|
#ifdef CFE
|
||||||
#include <dev/cfe/cfe_api.h>
|
#include <dev/cfe/cfe_api.h>
|
||||||
@ -238,6 +237,16 @@ bcm_init_platform_data(struct bcm_platform *pdata)
|
|||||||
memset(&pdata->pmu_id, 0, sizeof(pdata->pmu_id));
|
memset(&pdata->pmu_id, 0, sizeof(pdata->pmu_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pmu) {
|
||||||
|
error = bhnd_pmu_query_init(&pdata->pmu, NULL, pdata->id,
|
||||||
|
&bcm_pmu_soc_io, pdata);
|
||||||
|
if (error) {
|
||||||
|
printf("%s: bhnd_pmu_query_init() failed: %d\n",
|
||||||
|
__FUNCTION__, error);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bcm_platform_data_avail = true;
|
bcm_platform_data_avail = true;
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -318,7 +327,8 @@ mips_init(void)
|
|||||||
void
|
void
|
||||||
platform_reset(void)
|
platform_reset(void)
|
||||||
{
|
{
|
||||||
bool bcm4785war;
|
struct bcm_platform *bp;
|
||||||
|
bool bcm4785war;
|
||||||
|
|
||||||
printf("bcm::platform_reset()\n");
|
printf("bcm::platform_reset()\n");
|
||||||
intr_disable();
|
intr_disable();
|
||||||
@ -332,9 +342,11 @@ platform_reset(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Handle BCM4785-specific behavior */
|
bp = bcm_get_platform();
|
||||||
bcm4785war = false;
|
bcm4785war = false;
|
||||||
if (bcm_get_platform()->id.chip_id == BHND_CHIPID_BCM4785) {
|
|
||||||
|
/* Handle BCM4785-specific behavior */
|
||||||
|
if (bp->id.chip_id == BHND_CHIPID_BCM4785) {
|
||||||
bcm4785war = true;
|
bcm4785war = true;
|
||||||
|
|
||||||
/* Switch to async mode */
|
/* Switch to async mode */
|
||||||
@ -342,10 +354,10 @@ platform_reset(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set watchdog (PMU or ChipCommon) */
|
/* Set watchdog (PMU or ChipCommon) */
|
||||||
if (bcm_get_platform()->pmu_addr != 0x0) {
|
if (bp->pmu_addr != 0x0) {
|
||||||
BCM_CHIPC_WRITE_4(BHND_PMU_WATCHDOG, 1);
|
BCM_PMU_WRITE_4(bp, BHND_PMU_WATCHDOG, 1);
|
||||||
} else
|
} else
|
||||||
BCM_CHIPC_WRITE_4(CHIPC_WATCHDOG, 1);
|
BCM_CHIPC_WRITE_4(bp, CHIPC_WATCHDOG, 1);
|
||||||
|
|
||||||
/* BCM4785 */
|
/* BCM4785 */
|
||||||
if (bcm4785war) {
|
if (bcm4785war) {
|
||||||
@ -362,7 +374,6 @@ platform_start(__register_t a0, __register_t a1, __register_t a2,
|
|||||||
{
|
{
|
||||||
vm_offset_t kernend;
|
vm_offset_t kernend;
|
||||||
uint64_t platform_counter_freq;
|
uint64_t platform_counter_freq;
|
||||||
struct bcm_socinfo *socinfo;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
/* clear the BSS and SBSS segments */
|
/* clear the BSS and SBSS segments */
|
||||||
@ -393,16 +404,16 @@ platform_start(__register_t a0, __register_t a1, __register_t a2,
|
|||||||
if ((error = bcm_init_platform_data(&bcm_platform_data)))
|
if ((error = bcm_init_platform_data(&bcm_platform_data)))
|
||||||
panic("bcm_init_platform_data() failed: %d", error);
|
panic("bcm_init_platform_data() failed: %d", error);
|
||||||
|
|
||||||
socinfo = bcm_get_socinfo();
|
platform_counter_freq = bcm_get_cpufreq(bcm_get_platform());
|
||||||
platform_counter_freq = socinfo->cpurate * 1000 * 1000; /* BCM4718 is 480MHz */
|
|
||||||
|
|
||||||
mips_timer_early_init(platform_counter_freq);
|
/* CP0 ticks every two cycles */
|
||||||
|
mips_timer_early_init(platform_counter_freq / 2);
|
||||||
|
|
||||||
cninit();
|
cninit();
|
||||||
|
|
||||||
mips_init();
|
mips_init();
|
||||||
|
|
||||||
mips_timer_init_params(platform_counter_freq, socinfo->double_count);
|
mips_timer_init_params(platform_counter_freq, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -36,6 +36,13 @@
|
|||||||
#include <machine/cpuregs.h>
|
#include <machine/cpuregs.h>
|
||||||
|
|
||||||
#include <dev/bhnd/bhnd.h>
|
#include <dev/bhnd/bhnd.h>
|
||||||
|
#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
|
||||||
|
|
||||||
|
extern const struct bhnd_pmu_io bcm_pmu_soc_io;
|
||||||
|
|
||||||
|
typedef int (bcm_bus_find_core)(struct bhnd_chipid *chipid,
|
||||||
|
bhnd_devclass_t devclass, int unit, struct bhnd_core_info *info,
|
||||||
|
uintptr_t *addr);
|
||||||
|
|
||||||
struct bcm_platform {
|
struct bcm_platform {
|
||||||
struct bhnd_chipid id; /**< chip id */
|
struct bhnd_chipid id; /**< chip id */
|
||||||
@ -48,46 +55,53 @@ struct bcm_platform {
|
|||||||
* the pmu_id and pmu_addr values will be copied from cc_id
|
* the pmu_id and pmu_addr values will be copied from cc_id
|
||||||
* and cc_addr. */
|
* and cc_addr. */
|
||||||
struct bhnd_core_info pmu_id; /**< PMU core info */
|
struct bhnd_core_info pmu_id; /**< PMU core info */
|
||||||
uintptr_t pmu_addr; /**< PMU core phys address. */
|
uintptr_t pmu_addr; /**< PMU core phys address, or
|
||||||
|
0x0 if no PMU */
|
||||||
|
|
||||||
|
struct bhnd_pmu_query pmu; /**< PMU query instance */
|
||||||
|
|
||||||
#ifdef CFE
|
#ifdef CFE
|
||||||
int cfe_console; /**< Console handle, or -1 */
|
int cfe_console; /**< Console handle, or -1 */
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef int (bcm_bus_find_core)(struct bhnd_chipid *chipid,
|
|
||||||
bhnd_devclass_t devclass, int unit, struct bhnd_core_info *info,
|
|
||||||
uintptr_t *addr);
|
|
||||||
|
|
||||||
struct bcm_platform *bcm_get_platform(void);
|
struct bcm_platform *bcm_get_platform(void);
|
||||||
|
|
||||||
|
uint64_t bcm_get_cpufreq(struct bcm_platform *bp);
|
||||||
|
uint64_t bcm_get_sifreq(struct bcm_platform *bp);
|
||||||
|
uint64_t bcm_get_alpfreq(struct bcm_platform *bp);
|
||||||
|
uint64_t bcm_get_ilpfreq(struct bcm_platform *bp);
|
||||||
|
|
||||||
|
u_int bcm_get_uart_rclk(struct bcm_platform *bp);
|
||||||
|
|
||||||
bcm_bus_find_core bcm_find_core_default;
|
bcm_bus_find_core bcm_find_core_default;
|
||||||
bcm_bus_find_core bcm_find_core_bcma;
|
bcm_bus_find_core bcm_find_core_bcma;
|
||||||
bcm_bus_find_core bcm_find_core_siba;
|
bcm_bus_find_core bcm_find_core_siba;
|
||||||
|
|
||||||
#define BCM_SOC_ADDR(_addr, _offset) \
|
#define BCM_SOC_ADDR(_addr, _offset) \
|
||||||
MIPS_PHYS_TO_KSEG1((_addr) + (_offset))
|
MIPS_PHYS_TO_KSEG1((_addr) + (_offset))
|
||||||
|
|
||||||
#define BCM_SOC_READ_4(_addr, _offset) \
|
#define BCM_SOC_READ_4(_addr, _offset) \
|
||||||
readl(BCM_SOC_ADDR((_addr), (_offset)))
|
readl(BCM_SOC_ADDR((_addr), (_offset)))
|
||||||
#define BCM_SOC_WRITE_4(_addr, _reg, _val) \
|
#define BCM_SOC_WRITE_4(_addr, _reg, _val) \
|
||||||
writel(BCM_SOC_ADDR((_addr), (_offset)), (_val))
|
writel(BCM_SOC_ADDR((_addr), (_offset)), (_val))
|
||||||
|
|
||||||
#define BCM_CORE_ADDR(_name, _reg) \
|
#define BCM_CORE_ADDR(_bp, _name, _reg) \
|
||||||
BCM_SOC_ADDR(bcm_get_platform()->_name, (_reg))
|
BCM_SOC_ADDR(_bp->_name, (_reg))
|
||||||
|
|
||||||
#define BCM_CORE_READ_4(_name, _reg) \
|
#define BCM_CORE_READ_4(_bp, _name, _reg) \
|
||||||
readl(BCM_CORE_ADDR(_name, (_reg)))
|
readl(BCM_CORE_ADDR(_bp, _name, (_reg)))
|
||||||
#define BCM_CORE_WRITE_4(_name, _reg, _val) \
|
#define BCM_CORE_WRITE_4(_bp, _name, _reg, _val) \
|
||||||
writel(BCM_CORE_ADDR(_name, (_reg)), (_val))
|
writel(BCM_CORE_ADDR(_bp, _name, (_reg)), (_val))
|
||||||
|
|
||||||
#define BCM_CHIPC_READ_4(_reg) BCM_CORE_READ_4(cc_addr, (_reg))
|
#define BCM_CHIPC_READ_4(_bp, _reg) \
|
||||||
#define BCM_CHIPC_WRITE_4(_reg, _val) \
|
BCM_CORE_READ_4(_bp, cc_addr, (_reg))
|
||||||
BCM_CORE_WRITE_4(cc_addr, (_reg), (_val))
|
#define BCM_CHIPC_WRITE_4(_bp, _reg, _val) \
|
||||||
|
BCM_CORE_WRITE_4(_bp, cc_addr, (_reg), (_val))
|
||||||
|
|
||||||
#define BCM_PMU_READ_4(_reg) BCM_CORE_READ_4(pmu_addr, (_reg))
|
#define BCM_PMU_READ_4(_bp, _reg) \
|
||||||
#define BCM_PMU_WRITE_4(_reg, _val) \
|
BCM_CORE_READ_4(_bp, pmu_addr, (_reg))
|
||||||
BCM_CORE_WRITE_4(pmu_addr, (_reg), (_val))
|
#define BCM_PMU_WRITE_4(_bp, _reg, _val) \
|
||||||
|
BCM_CORE_WRITE_4(_bp, pmu_addr, (_reg), (_val))
|
||||||
|
|
||||||
#endif /* _MIPS_BROADCOM_BCM_MACHDEP_H_ */
|
#endif /* _MIPS_BROADCOM_BCM_MACHDEP_H_ */
|
||||||
|
298
sys/mips/broadcom/bcm_pmu.c
Normal file
298
sys/mips/broadcom/bcm_pmu.c
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
/*-
|
||||||
|
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <dev/bhnd/bhnd.h>
|
||||||
|
|
||||||
|
#include <dev/bhnd/cores/chipc/chipcreg.h>
|
||||||
|
|
||||||
|
#include <dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h>
|
||||||
|
|
||||||
|
#include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
|
||||||
|
#include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
|
||||||
|
|
||||||
|
#include "bcm_machdep.h"
|
||||||
|
|
||||||
|
static struct bhnd_pmu_query *bcm_get_pmu(struct bcm_platform *bp);
|
||||||
|
static bool bcm_has_pmu(struct bcm_platform *bp);
|
||||||
|
|
||||||
|
static uint32_t bcm_pmu_read4(bus_size_t reg, void *ctx);
|
||||||
|
static void bcm_pmu_write4(bus_size_t reg, uint32_t val,
|
||||||
|
void *ctx);
|
||||||
|
static uint32_t bcm_pmu_read_chipst(void *ctx);
|
||||||
|
|
||||||
|
const struct bhnd_pmu_io bcm_pmu_soc_io = {
|
||||||
|
.rd4 = bcm_pmu_read4,
|
||||||
|
.wr4 = bcm_pmu_write4,
|
||||||
|
.rd_chipst = bcm_pmu_read_chipst
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported UART clock sources.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
BCM_UART_RCLK_PLL_T1 = 0, /**< UART uses PLL m2 (mii/uart/mipsref) with no divisor */
|
||||||
|
BCM_UART_RCLK_ALP = 1, /**< UART uses ALP rclk with no divisor */
|
||||||
|
BCM_UART_RCLK_EXT = 2, /**< UART uses 1.8423 MHz external clock */
|
||||||
|
BCM_UART_RCLK_SI = 3, /**< UART uses backplane clock with divisor of two */
|
||||||
|
BCM_UART_RCLK_FIXED = 4, /**< UART uses fixed 88Mhz backplane clock with a divisor of 48 */
|
||||||
|
} bcm_uart_clksrc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UART clock configuration.
|
||||||
|
*/
|
||||||
|
struct bcm_uart_clkcfg {
|
||||||
|
bcm_uart_clksrc src; /**< clock source */
|
||||||
|
uint32_t div; /**< clock divisor */
|
||||||
|
uint32_t freq; /**< clock frequency (Hz) */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BCM_UART_RCLK_PLL_T1_DIV 1
|
||||||
|
#define BCM_UART_RCLK_ALP_DIV 1
|
||||||
|
#define BCM_UART_RCLK_EXT_HZ 1842300 /* 1.8423MHz */
|
||||||
|
#define BCM_UART_RCLK_EXT_DIV 1
|
||||||
|
#define BCM_UART_RCLK_FIXED_HZ 88000000 /* 88MHz */
|
||||||
|
#define BCM_UART_RCLK_FIXED_DIV 48
|
||||||
|
|
||||||
|
/* Fetch PLL type from ChipCommon capability flags */
|
||||||
|
#define BCM_PMU_PLL_TYPE(_bp) \
|
||||||
|
CHIPC_GET_BITS(_bp->cc_caps, CHIPC_CAP_PLL)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the PMU instance, or NULL if no PMU.
|
||||||
|
*/
|
||||||
|
static struct bhnd_pmu_query *
|
||||||
|
bcm_get_pmu(struct bcm_platform *bp)
|
||||||
|
{
|
||||||
|
if (!bcm_has_pmu(bp))
|
||||||
|
return (NULL);
|
||||||
|
return (&bp->pmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if a PMU is available, false otherwise.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
bcm_has_pmu(struct bcm_platform *bp)
|
||||||
|
{
|
||||||
|
return (bp->pmu_addr != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the UART clock source for @p bp and return the
|
||||||
|
* corresponding clock configuration, if any.
|
||||||
|
*/
|
||||||
|
static struct bcm_uart_clkcfg
|
||||||
|
bcm_get_uart_clkcfg(struct bcm_platform *bp)
|
||||||
|
{
|
||||||
|
struct bcm_uart_clkcfg cfg;
|
||||||
|
struct bhnd_core_info *cc_id;
|
||||||
|
|
||||||
|
cc_id = &bp->cc_id;
|
||||||
|
|
||||||
|
/* These tests are ordered by precedence. */
|
||||||
|
|
||||||
|
/* PLL M2 clock source? */
|
||||||
|
if (!bcm_has_pmu(bp) && BCM_PMU_PLL_TYPE(bp) == CHIPC_PLL_TYPE1) {
|
||||||
|
uint32_t n, m;
|
||||||
|
|
||||||
|
n = BCM_CHIPC_READ_4(bp, CHIPC_CLKC_N);
|
||||||
|
m = BCM_CHIPC_READ_4(bp, CHIPC_CLKC_M2);
|
||||||
|
|
||||||
|
cfg = (struct bcm_uart_clkcfg) {
|
||||||
|
BCM_UART_RCLK_PLL_T1,
|
||||||
|
BCM_UART_RCLK_PLL_T1_DIV,
|
||||||
|
bhnd_pwrctl_clock_rate(BCM_PMU_PLL_TYPE(bp), n, m)
|
||||||
|
};
|
||||||
|
|
||||||
|
return (cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ALP clock source? */
|
||||||
|
if (cc_id->hwrev != 15 && cc_id->hwrev >= 11) {
|
||||||
|
cfg = (struct bcm_uart_clkcfg) {
|
||||||
|
BCM_UART_RCLK_ALP,
|
||||||
|
BCM_UART_RCLK_ALP_DIV,
|
||||||
|
bcm_get_alpfreq(bp)
|
||||||
|
};
|
||||||
|
return (cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* External clock? */
|
||||||
|
if (CHIPC_HWREV_HAS_CORECTRL(cc_id->hwrev)) {
|
||||||
|
uint32_t corectrl, uclksel;
|
||||||
|
bool uintclk0;
|
||||||
|
|
||||||
|
/* Fetch UART clock support flag */
|
||||||
|
uclksel = CHIPC_GET_BITS(bp->cc_caps, CHIPC_CAP_UCLKSEL);
|
||||||
|
|
||||||
|
/* Is UART using internal clock? */
|
||||||
|
corectrl = BCM_CHIPC_READ_4(bp, CHIPC_CORECTRL);
|
||||||
|
uintclk0 = CHIPC_GET_FLAG(corectrl, CHIPC_UARTCLKO);
|
||||||
|
|
||||||
|
if (uintclk0 && uclksel == CHIPC_CAP_UCLKSEL_UINTCLK) {
|
||||||
|
cfg = (struct bcm_uart_clkcfg) {
|
||||||
|
BCM_UART_RCLK_EXT,
|
||||||
|
BCM_UART_RCLK_EXT_DIV,
|
||||||
|
BCM_UART_RCLK_EXT_HZ
|
||||||
|
};
|
||||||
|
return (cfg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UART uses backplane clock? */
|
||||||
|
if (cc_id->hwrev == 15 || (cc_id->hwrev >= 3 && cc_id->hwrev <= 10)) {
|
||||||
|
cfg = (struct bcm_uart_clkcfg) {
|
||||||
|
BCM_UART_RCLK_SI,
|
||||||
|
BCM_CHIPC_READ_4(bp, CHIPC_CLKDIV) & CHIPC_CLKD_UART,
|
||||||
|
bcm_get_sifreq(bp)
|
||||||
|
};
|
||||||
|
|
||||||
|
return (cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* UART uses fixed clock? */
|
||||||
|
if (cc_id->hwrev <= 2) {
|
||||||
|
cfg = (struct bcm_uart_clkcfg) {
|
||||||
|
BCM_UART_RCLK_FIXED,
|
||||||
|
BCM_UART_RCLK_FIXED_DIV,
|
||||||
|
BCM_UART_RCLK_FIXED_HZ
|
||||||
|
};
|
||||||
|
|
||||||
|
return (cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All cases must be accounted for above */
|
||||||
|
panic("unreachable - no clock config");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the UART reference clock frequency (in Hz).
|
||||||
|
*/
|
||||||
|
u_int
|
||||||
|
bcm_get_uart_rclk(struct bcm_platform *bp)
|
||||||
|
{
|
||||||
|
struct bcm_uart_clkcfg cfg;
|
||||||
|
|
||||||
|
cfg = bcm_get_uart_clkcfg(bp);
|
||||||
|
return (cfg.freq / cfg.div);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ALP clock frequency (in Hz) */
|
||||||
|
uint64_t
|
||||||
|
bcm_get_alpfreq(struct bcm_platform *bp) {
|
||||||
|
if (!bcm_has_pmu(bp))
|
||||||
|
panic("%s requires PMU\n", __FUNCTION__);
|
||||||
|
|
||||||
|
return (bhnd_pmu_alp_clock(bcm_get_pmu(bp)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ILP clock frequency (in Hz) */
|
||||||
|
uint64_t
|
||||||
|
bcm_get_ilpfreq(struct bcm_platform *bp) {
|
||||||
|
if (!bcm_has_pmu(bp))
|
||||||
|
panic("%s requires PMU\n", __FUNCTION__);
|
||||||
|
|
||||||
|
return (bhnd_pmu_ilp_clock(bcm_get_pmu(bp)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** CPU clock frequency (in Hz) */
|
||||||
|
uint64_t
|
||||||
|
bcm_get_cpufreq(struct bcm_platform *bp)
|
||||||
|
{
|
||||||
|
uint32_t fixed_hz;
|
||||||
|
uint32_t n, m;
|
||||||
|
bus_size_t mreg;
|
||||||
|
uint8_t pll_type;
|
||||||
|
|
||||||
|
/* PMU support */
|
||||||
|
if (bcm_has_pmu(bp))
|
||||||
|
return (bhnd_pmu_cpu_clock(bcm_get_pmu(bp)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PWRCTL support
|
||||||
|
*/
|
||||||
|
pll_type = CHIPC_GET_BITS(bp->cc_caps, CHIPC_CAP_PLL);
|
||||||
|
mreg = bhnd_pwrctl_cpu_clkreg_m(&bp->id, pll_type, &fixed_hz);
|
||||||
|
if (mreg == 0)
|
||||||
|
return (fixed_hz);
|
||||||
|
|
||||||
|
n = BCM_CHIPC_READ_4(bp, CHIPC_CLKC_N);
|
||||||
|
m = BCM_CHIPC_READ_4(bp, mreg);
|
||||||
|
|
||||||
|
return (bhnd_pwrctl_cpu_clock_rate(&bp->id, pll_type, n, m));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Backplane clock frequency (in Hz) */
|
||||||
|
uint64_t
|
||||||
|
bcm_get_sifreq(struct bcm_platform *bp)
|
||||||
|
{
|
||||||
|
uint32_t fixed_hz;
|
||||||
|
uint32_t n, m;
|
||||||
|
bus_size_t mreg;
|
||||||
|
uint8_t pll_type;
|
||||||
|
|
||||||
|
/* PMU support */
|
||||||
|
if (bcm_has_pmu(bp))
|
||||||
|
return (bhnd_pmu_si_clock(bcm_get_pmu(bp)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PWRCTL support
|
||||||
|
*/
|
||||||
|
pll_type = CHIPC_GET_BITS(bp->cc_caps, CHIPC_CAP_PLL);
|
||||||
|
mreg = bhnd_pwrctl_si_clkreg_m(&bp->id, pll_type, &fixed_hz);
|
||||||
|
if (mreg == 0)
|
||||||
|
return (fixed_hz);
|
||||||
|
|
||||||
|
n = BCM_CHIPC_READ_4(bp, CHIPC_CLKC_N);
|
||||||
|
m = BCM_CHIPC_READ_4(bp, mreg);
|
||||||
|
|
||||||
|
return (bhnd_pwrctl_si_clock_rate(&bp->id, pll_type, n, m));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
bcm_pmu_read4(bus_size_t reg, void *ctx) {
|
||||||
|
struct bcm_platform *bp = ctx;
|
||||||
|
return (readl(BCM_SOC_ADDR(bp->pmu_addr, reg)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bcm_pmu_write4(bus_size_t reg, uint32_t val, void *ctx) {
|
||||||
|
struct bcm_platform *bp = ctx;
|
||||||
|
writel(BCM_SOC_ADDR(bp->pmu_addr, reg), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
bcm_pmu_read_chipst(void *ctx)
|
||||||
|
{
|
||||||
|
struct bcm_platform *bp = ctx;
|
||||||
|
return (readl(BCM_SOC_ADDR(bp->cc_addr, CHIPC_CHIPST)));
|
||||||
|
}
|
@ -1,95 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
|
||||||
__FBSDID("$FreeBSD$");
|
|
||||||
|
|
||||||
#include <sys/param.h>
|
|
||||||
|
|
||||||
#include <dev/bhnd/cores/chipc/chipcreg.h>
|
|
||||||
|
|
||||||
#include "bcm_machdep.h"
|
|
||||||
#include "bcm_socinfo.h"
|
|
||||||
|
|
||||||
/* found on https://wireless.wiki.kernel.org/en/users/drivers/b43/soc */
|
|
||||||
struct bcm_socinfo bcm_socinfos[] = {
|
|
||||||
{0x00005300, 600, 25000000, 1}, /* BCM4706 to check */
|
|
||||||
{0x0022B83A, 300, 20000000, 1}, /* BCM4716B0 ASUS RT-N12 */
|
|
||||||
{0x00914716, 354, 20000000, 1}, /* BCM4717A1 to check */
|
|
||||||
{0x00A14716, 480, 20000000, 1}, /* BCM4718A1 ASUS RT-N16 */
|
|
||||||
{0x00435356, 300, 25000000, 1}, /* BCM5356A1 (RT-N10, WNR1000v3) */
|
|
||||||
{0x00825357, 500, 20000000, 1}, /* BCM5358UB0 ASUS RT-N53A1 */
|
|
||||||
{0x00845357, 300, 20000000, 1}, /* BCM5357B0 to check */
|
|
||||||
{0x00945357, 500, 20000000, 1}, /* BCM5358 */
|
|
||||||
{0x00A45357, 500, 20000000, 1}, /* BCM47186B0 Tenda N60 */
|
|
||||||
{0x0085D144, 300, 20000000, 1}, /* BCM5356C0 */
|
|
||||||
{0x00B5D144, 300, 20000000, 1}, /* BCM5357C0 */
|
|
||||||
{0x00015365, 200, 0, 1}, /* BCM5365 */
|
|
||||||
{0,0,0}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Most popular BCM SoC info */
|
|
||||||
struct bcm_socinfo BCM_DEFAULT_SOCINFO = {0x0, 300, 20000000, 0};
|
|
||||||
|
|
||||||
struct bcm_socinfo*
|
|
||||||
bcm_get_socinfo_by_socid(uint32_t key)
|
|
||||||
{
|
|
||||||
struct bcm_socinfo* start;
|
|
||||||
|
|
||||||
if(!key)
|
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
for(start = bcm_socinfos; start->id > 0; start++)
|
|
||||||
if(start->id == key)
|
|
||||||
return (start);
|
|
||||||
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct bcm_socinfo*
|
|
||||||
bcm_get_socinfo(void)
|
|
||||||
{
|
|
||||||
uint32_t socid;
|
|
||||||
struct bcm_socinfo *socinfo;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We need Chip ID + Revision + Package
|
|
||||||
* --------------------------------------------------------------
|
|
||||||
* | Mask | Usage |
|
|
||||||
* --------------------------------------------------------------
|
|
||||||
* | 0x0000FFFF | Chip ID |
|
|
||||||
* | 0x000F0000 | Chip Revision |
|
|
||||||
* | 0x00F00000 | Package Options |
|
|
||||||
* | 0x0F000000 | Number of Cores (ChipCommon Rev. >= 4)|
|
|
||||||
* | 0xF0000000 | Chip Type |
|
|
||||||
* --------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
socid = BCM_CHIPC_READ_4(CHIPC_ID) & 0x00FFFFFF;
|
|
||||||
socinfo = bcm_get_socinfo_by_socid(socid);
|
|
||||||
return (socinfo != NULL) ? socinfo : &BCM_DEFAULT_SOCINFO;
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* $FreeBSD$
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _MIPS_BROADCOM_BCM_SOCINFO_H_
|
|
||||||
#define _MIPS_BROADCOM_BCM_SOCINFO_H_
|
|
||||||
|
|
||||||
#include <machine/cpuregs.h>
|
|
||||||
|
|
||||||
struct bcm_socinfo {
|
|
||||||
uint32_t id;
|
|
||||||
uint32_t cpurate; /* in MHz */
|
|
||||||
uint32_t uartrate; /* in Hz */
|
|
||||||
int double_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct bcm_socinfo* bcm_get_socinfo_by_socid(uint32_t key);
|
|
||||||
struct bcm_socinfo* bcm_get_socinfo(void);
|
|
||||||
|
|
||||||
#endif /* _MIPS_BROADCOM_BCM_SOCINFO_H_ */
|
|
@ -6,6 +6,7 @@
|
|||||||
# which just need to be tweaked for attachment to an BHND system bus.
|
# which just need to be tweaked for attachment to an BHND system bus.
|
||||||
mips/broadcom/bcm_bcma.c optional bcma_nexus bcma
|
mips/broadcom/bcm_bcma.c optional bcma_nexus bcma
|
||||||
mips/broadcom/bcm_machdep.c standard
|
mips/broadcom/bcm_machdep.c standard
|
||||||
|
mips/broadcom/bcm_pmu.c standard
|
||||||
mips/broadcom/bcm_siba.c optional siba_nexus siba
|
mips/broadcom/bcm_siba.c optional siba_nexus siba
|
||||||
mips/mips/tick.c standard
|
mips/mips/tick.c standard
|
||||||
mips/mips/mips_pic.c standard
|
mips/mips/mips_pic.c standard
|
||||||
@ -16,7 +17,6 @@ kern/msi_if.m optional intrng
|
|||||||
|
|
||||||
mips/broadcom/uart_cpu_chipc.c optional uart
|
mips/broadcom/uart_cpu_chipc.c optional uart
|
||||||
mips/broadcom/uart_bus_chipc.c optional uart
|
mips/broadcom/uart_bus_chipc.c optional uart
|
||||||
mips/broadcom/bcm_socinfo.c standard
|
|
||||||
mips/broadcom/bcm_mipscore.c standard
|
mips/broadcom/bcm_mipscore.c standard
|
||||||
|
|
||||||
# TODO: Replace with BCM47xx/57xx/etc-aware geom_map
|
# TODO: Replace with BCM47xx/57xx/etc-aware geom_map
|
||||||
|
@ -48,22 +48,20 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include "uart_if.h"
|
#include "uart_if.h"
|
||||||
#include "bhnd_chipc_if.h"
|
#include "bhnd_chipc_if.h"
|
||||||
|
|
||||||
#include "bcm_socinfo.h"
|
#include "bcm_machdep.h"
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
uart_chipc_probe(device_t dev)
|
uart_chipc_probe(device_t dev)
|
||||||
{
|
{
|
||||||
struct uart_softc *sc;
|
struct uart_softc *sc;
|
||||||
struct bcm_socinfo *socinfo;
|
u_int rclk;
|
||||||
|
|
||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
sc->sc_class = &uart_ns8250_class;
|
sc->sc_class = &uart_ns8250_class;
|
||||||
|
|
||||||
/* TODO: UART rate should be calculated from CPU clock speed
|
rclk = bcm_get_uart_rclk(bcm_get_platform());
|
||||||
* as fetched from bhnd bus */
|
return (uart_bus_probe(dev, 0, rclk, 0, 0));
|
||||||
socinfo = bcm_get_socinfo();
|
|
||||||
return (uart_bus_probe(dev, 0, socinfo->uartrate, 0, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static device_method_t uart_chipc_methods[] = {
|
static device_method_t uart_chipc_methods[] = {
|
||||||
|
@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "bcm_machdep.h"
|
#include "bcm_machdep.h"
|
||||||
#include "bcm_socinfo.h"
|
|
||||||
|
|
||||||
bus_space_tag_t uart_bus_space_io;
|
bus_space_tag_t uart_bus_space_io;
|
||||||
bus_space_tag_t uart_bus_space_mem;
|
bus_space_tag_t uart_bus_space_mem;
|
||||||
@ -70,19 +69,16 @@ uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
|
|||||||
static int
|
static int
|
||||||
uart_cpu_init(struct uart_devinfo *di, u_int uart, int baudrate)
|
uart_cpu_init(struct uart_devinfo *di, u_int uart, int baudrate)
|
||||||
{
|
{
|
||||||
struct bcm_socinfo *socinfo;
|
|
||||||
|
|
||||||
if (uart >= CHIPC_UART_MAX)
|
if (uart >= CHIPC_UART_MAX)
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
|
|
||||||
socinfo = bcm_get_socinfo();
|
|
||||||
di->ops = uart_getops(chipc_uart_class);
|
di->ops = uart_getops(chipc_uart_class);
|
||||||
di->bas.chan = 0;
|
di->bas.chan = 0;
|
||||||
di->bas.bst = uart_bus_space_mem;
|
di->bas.bst = uart_bus_space_mem;
|
||||||
di->bas.bsh = (bus_space_handle_t) BCM_CORE_ADDR(cc_addr,
|
di->bas.bsh = (bus_space_handle_t) BCM_CORE_ADDR(bcm_get_platform(),
|
||||||
CHIPC_UART(uart));
|
cc_addr, CHIPC_UART(uart));
|
||||||
di->bas.regshft = 0;
|
di->bas.regshft = 0;
|
||||||
di->bas.rclk = socinfo->uartrate; /* in Hz */
|
di->bas.rclk = bcm_get_uart_rclk(bcm_get_platform());
|
||||||
di->baudrate = baudrate;
|
di->baudrate = baudrate;
|
||||||
di->databits = 8;
|
di->databits = 8;
|
||||||
di->stopbits = 1;
|
di->stopbits = 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user