From eb175e8bfb9b2f7616d27148d917cd41cd6b1767 Mon Sep 17 00:00:00 2001 From: "Landon J. Fuller" Date: Sat, 27 Aug 2016 00:06:20 +0000 Subject: [PATCH] [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 --- sys/dev/bhnd/cores/chipc/chipcreg.h | 20 +- .../cores/chipc/pwrctl/bhnd_pwrctl_subr.c | 149 ++++++-- .../bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h | 15 + sys/dev/bhnd/cores/pmu/bhnd_pmu.c | 48 ++- sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h | 33 +- sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c | 356 ++++++++++-------- sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h | 82 +++- sys/mips/broadcom/bcm_machdep.c | 35 +- sys/mips/broadcom/bcm_machdep.h | 56 +-- sys/mips/broadcom/bcm_pmu.c | 298 +++++++++++++++ sys/mips/broadcom/bcm_socinfo.c | 95 ----- sys/mips/broadcom/bcm_socinfo.h | 47 --- sys/mips/broadcom/files.broadcom | 2 +- sys/mips/broadcom/uart_bus_chipc.c | 10 +- sys/mips/broadcom/uart_cpu_chipc.c | 10 +- 15 files changed, 845 insertions(+), 411 deletions(-) create mode 100644 sys/mips/broadcom/bcm_pmu.c delete mode 100644 sys/mips/broadcom/bcm_socinfo.c delete mode 100644 sys/mips/broadcom/bcm_socinfo.h diff --git a/sys/dev/bhnd/cores/chipc/chipcreg.h b/sys/dev/bhnd/cores/chipc/chipcreg.h index ccbc97e05081..58be59587eec 100644 --- a/sys/dev/bhnd/cores/chipc/chipcreg.h +++ b/sys/dev/bhnd/cores/chipc/chipcreg.h @@ -31,6 +31,10 @@ required during bus 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 * the core count via the chip identification register. */ #define CHIPC_NCORES_MIN_HWREV(hwrev) ((hwrev) == 4 || (hwrev) >= 6) @@ -278,14 +282,14 @@ enum { #define CHIPC_CST_SPROM_OTP_SEL_R23_SHIFT 6 /* PLL type */ -#define CHIPC_PLL_NONE 0x00 -#define CHIPC_PLL_TYPE1 0x10 /* 48MHz base, 3 dividers */ -#define CHIPC_PLL_TYPE2 0x20 /* 48MHz, 4 dividers */ -#define CHIPC_PLL_TYPE3 0x30 /* 25MHz, 2 dividers */ -#define CHIPC_PLL_TYPE4 0x08 /* 48MHz, 4 dividers */ -#define CHIPC_PLL_TYPE5 0x18 /* 25MHz, 4 dividers */ -#define CHIPC_PLL_TYPE6 0x28 /* 100/200 or 120/240 only */ -#define CHIPC_PLL_TYPE7 0x38 /* 25MHz, 4 dividers */ +#define CHIPC_PLL_NONE 0x0 +#define CHIPC_PLL_TYPE1 0x2 /* 48MHz base, 3 dividers */ +#define CHIPC_PLL_TYPE2 0x4 /* 48MHz, 4 dividers */ +#define CHIPC_PLL_TYPE3 0x6 /* 25MHz, 2 dividers */ +#define CHIPC_PLL_TYPE4 0x8 /* 48MHz, 4 dividers */ +#define CHIPC_PLL_TYPE5 0x3 /* 25MHz, 4 dividers */ +#define CHIPC_PLL_TYPE6 0x5 /* 100/200 or 120/240 only */ +#define CHIPC_PLL_TYPE7 0x7 /* 25MHz, 4 dividers */ /* dynamic clock control defines */ #define CHIPC_LPOMINFREQ 25000 /* low power oscillator min */ diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c index 9f6f400390ff..4cd23b3e2dac 100644 --- a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c +++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c @@ -46,8 +46,6 @@ __FBSDID("$FreeBSD$"); #include "bhnd_pwrctl_private.h" 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 @@ -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 * values. * * @param pll_type PLL type (CHIPC_PLL_TYPE*) * @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) { uint32_t clk_base; @@ -195,38 +301,27 @@ bhnd_pwrctl_clock_rate(uint32_t pll_type, uint32_t n, uint32_t m) uint32_t bhnd_pwrctl_getclk_speed(struct bhnd_pwrctl_softc *sc) { - struct chipc_caps *ccaps; - bus_size_t creg; - uint32_t n, m; - uint32_t rate; + const struct bhnd_chipid *cid; + struct chipc_caps *ccaps; + bus_size_t creg; + uint32_t n, m; + uint32_t rate; PWRCTL_LOCK_ASSERT(sc, MA_OWNED); + cid = bhnd_get_chipid(sc->chipc_dev); ccaps = BHND_CHIPC_GET_CAPS(sc->chipc_dev); n = bhnd_bus_read_4(sc->res, CHIPC_CLKC_N); - switch (ccaps->pll_type) { - case CHIPC_PLL_TYPE6: - creg = CHIPC_CLKC_M3; /* non-extif regster */ - break; - case CHIPC_PLL_TYPE3: - creg = CHIPC_CLKC_M2; - break; - default: - creg = CHIPC_CLKC_SB; - break; - } - - m = bhnd_bus_read_4(sc->res, creg); + /* Get M register offset */ + creg = bhnd_pwrctl_si_clkreg_m(cid, ccaps->pll_type, &rate); + if (creg == 0) /* fixed rate */ + return (rate); /* calculate rate */ - rate = bhnd_pwrctl_clock_rate(ccaps->pll_type, n, m); - - if (ccaps->pll_type == CHIPC_PLL_TYPE3) - rate /= 2; - - return (rate); + m = bhnd_bus_read_4(sc->res, creg); + return (bhnd_pwrctl_si_clock_rate(cid, ccaps->pll_type, n, m)); } /* return the slow clock source */ diff --git a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h index 67b5015d03c4..2952bbf7ee9c 100644 --- a/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h +++ b/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h @@ -36,6 +36,21 @@ #include #include +#include + +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. */ diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu.c b/sys/dev/bhnd/cores/pmu/bhnd_pmu.c index 6cc657f0e6ac..0d24392f0da8 100644 --- a/sys/dev/bhnd/cores/pmu/bhnd_pmu.c +++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu.c @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #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_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) \ 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); } + /* 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); /* Set quirk flags */ @@ -183,6 +202,7 @@ bhnd_pmu_attach(device_t dev, struct bhnd_resource *res) failed: BPMU_LOCK_DESTROY(sc); + bhnd_pmu_query_fini(&sc->query); return (error); } @@ -197,6 +217,7 @@ bhnd_pmu_detach(device_t dev) sc = device_get_softc(dev); BPMU_LOCK_DESTROY(sc); + bhnd_pmu_query_fini(&sc->query); return (0); } @@ -239,7 +260,7 @@ bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS) sc = arg1; BPMU_LOCK(sc); - freq = bhnd_pmu_si_clock(sc); + freq = bhnd_pmu_si_clock(&sc->query); BPMU_UNLOCK(sc); return (sysctl_handle_32(oidp, NULL, freq, req)); @@ -254,7 +275,7 @@ bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS) sc = arg1; BPMU_LOCK(sc); - freq = bhnd_pmu_cpu_clock(sc); + freq = bhnd_pmu_cpu_clock(&sc->query); BPMU_UNLOCK(sc); return (sysctl_handle_32(oidp, NULL, freq, req)); @@ -269,7 +290,7 @@ bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS) sc = arg1; BPMU_LOCK(sc); - freq = bhnd_pmu_mem_clock(sc); + freq = bhnd_pmu_mem_clock(&sc->query); BPMU_UNLOCK(sc); 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); } +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[] = { /* Device interface */ DEVMETHOD(device_probe, bhnd_pmu_probe), diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h b/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h index ee705eac880c..786c0b871937 100644 --- a/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h +++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h @@ -30,15 +30,9 @@ #include "bhnd_pmuvar.h" /* Register I/O */ -#define BHND_PMU_READ_1(_sc, _reg) bhnd_bus_read_1((_sc)->res, (_reg)) -#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_READ_4(_sc, _reg) (_sc)->io->rd4((_reg), (_sc)->io_ctx) #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) \ BHND_PMU_WRITE_4((_sc), (_reg), \ @@ -49,10 +43,11 @@ /* Indirect register support */ #define BHND_PMU_IND_READ(_sc, _src, _reg) \ - bhnd_pmu_ind_read((_sc), BHND_PMU_ ## _src ## _ADDR, \ - BHND_PMU_ ## _src ## _DATA, (_reg)) + bhnd_pmu_ind_read((_sc)->io, (_sc)->io_ctx, \ + BHND_PMU_ ## _src ## _ADDR, BHND_PMU_ ## _src ## _DATA, (_reg)) #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)) /* Chip Control indirect registers */ @@ -96,10 +91,12 @@ enum { 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); -void bhnd_pmu_ind_write(struct bhnd_pmu_softc *sc, bus_size_t addr, - bus_size_t data, uint32_t reg, uint32_t val, uint32_t mask); + +uint32_t bhnd_pmu_ind_read(const struct bhnd_pmu_io *io, void *io_ctx, + bus_size_t addr, bus_size_t data, uint32_t reg); +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, 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_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, uint8_t bb_voltage, uint8_t rf_voltage); void bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc, diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c b/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c index 682baf17ce8e..db84bdc093e5 100644 --- a/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c +++ b/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c @@ -38,33 +38,36 @@ __FBSDID("$FreeBSD$"); #include "bhnd_pmu_private.h" -#ifdef BCMDBG -#define PMU_MSG(args) printf args -#define PMU_ERROR(args) do { \ - panic args; \ +#define PMU_LOG(_sc, _fmt, ...) do { \ + if (_sc->dev != NULL) \ + device_printf(_sc->dev, _fmt, ##__VA_ARGS__); \ + else \ + printf(_fmt, ##__VA_ARGS__); \ } while (0) + +#ifdef BCMDBG +#define PMU_DEBUG(_sc, _fmt, ...) PMU_LOG(_sc, _fmt, ##__VA_ARGS__) #else -#define PMU_MSG(args) -#define PMU_ERROR(args) printf args +#define PMU_DEBUG(_sc, _fmt, ...) #endif typedef struct pmu0_xtaltab0 pmu0_xtaltab0_t; typedef struct pmu1_xtaltab0 pmu1_xtaltab0_t; /* PLL controls/clocks */ -static const pmu1_xtaltab0_t *bhnd_pmu1_xtaltab0(struct bhnd_pmu_softc *sc); -static const pmu1_xtaltab0_t *bhnd_pmu1_xtaldef0(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_query *sc); 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_alpclk0(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_query *sc); 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_cpuclk0(struct bhnd_pmu_softc *sc); -static uint32_t bhnd_pmu1_alpclk0(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_query *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 */ 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)) #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. @@ -103,11 +144,11 @@ static void bhnd_pmu_set_4330_plldivs(struct bhnd_pmu_softc *sc); * @param reg Indirect register to be read. */ uint32_t -bhnd_pmu_ind_read(struct bhnd_pmu_softc *sc, bus_size_t addr, bus_size_t data, - uint32_t reg) +bhnd_pmu_ind_read(const struct bhnd_pmu_io *io, void *io_ctx, bus_size_t addr, + bus_size_t data, uint32_t reg) { - BHND_PMU_WRITE_4(sc, addr, reg); - return (BHND_PMU_READ_4(sc, data)); + io->wr4(addr, reg, io_ctx); + 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. */ 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) { uint32_t rval; - BHND_PMU_WRITE_4(sc, addr, reg); + io->wr4(addr, reg, io_ctx); if (mask != UINT32_MAX) { - rval = BHND_PMU_READ_4(sc, data); + rval = io->rd4(data, io_ctx); rval &= ~mask | (val & mask); } else { 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) return (error); - ilp = bhnd_pmu_ilp_clock(sc); + ilp = bhnd_pmu_ilp_clock(&sc->query); delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) * ((1000000 + ilp - 1) / ilp); delay = (11 * delay) / 10; @@ -387,7 +428,7 @@ bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, uint16_t *pwrup_delay) if (error) return (error); - ilp = bhnd_pmu_ilp_clock(sc); + ilp = bhnd_pmu_ilp_clock(&sc->query); delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) * ((1000000 + ilp - 1) / ilp); delay = (11 * delay) / 10; @@ -403,7 +444,7 @@ bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, uint16_t *pwrup_delay) if (error) return (error); - ilp = bhnd_pmu_ilp_clock(sc); + ilp = bhnd_pmu_ilp_clock(&sc->query); delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) * ((1000000 + ilp - 1) / ilp); delay = (11 * delay) / 10; @@ -415,7 +456,7 @@ bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, uint16_t *pwrup_delay) if (error) return (error); - ilp = bhnd_pmu_ilp_clock(sc); + ilp = bhnd_pmu_ilp_clock(&sc->query); delay = (uptime + D11SCC_SLOW2FAST_TRANSITION) * ((1000000 + ilp - 1) / ilp); 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 */ error = bhnd_nvram_getvar_uint32(sc->chipc_dev, BHND_NVAR_RMIN, &nval); 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); return (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; } /* Apply nvram override to max mask */ error = bhnd_nvram_getvar_uint32(sc->chipc_dev, BHND_NVAR_RMAX, &nval); 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); return (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; } @@ -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]; - PMU_MSG(("Changing rsrc %d res_updn_timer to %#x\n", - updt->resnum, updt->updown)); + PMU_DEBUG(sc, "Changing rsrc %d res_updn_timer to %#x\n", + updt->resnum, updt->updown); BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, updt->resnum); 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) { continue; } else if (error) { - device_printf(sc->dev, "NVRAM error reading %s: %d\n", + PMU_LOG(sc, "NVRAM error reading %s: %d\n", name, error); return (error); } - PMU_MSG(("Applying %s=%s to rsrc %d res_updn_timer\n", name, - val, i)); + PMU_DEBUG(sc, "Applying %s=%s to rsrc %d res_updn_timer\n", + name, val, i); BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i); 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); switch (rdep->action) { case RES_DEPEND_SET: - PMU_MSG(("Changing rsrc %hhu res_dep_mask to " - "%#x\n", i, table->depend_mask)); + PMU_DEBUG(sc, "Changing rsrc %hhu res_dep_mask to " + "%#x\n", i, table->depend_mask); depend_mask = rdep->depend_mask; break; case RES_DEPEND_ADD: - PMU_MSG(("Adding %#x to rsrc %hhu " - "res_dep_mask\n", table->depend_mask, i)); + PMU_DEBUG(sc, "Adding %#x to rsrc %hhu " + "res_dep_mask\n", table->depend_mask, i); depend_mask |= rdep->depend_mask; break; case RES_DEPEND_REMOVE: - PMU_MSG(("Removing %#x from rsrc %hhu " - "res_dep_mask\n", table->depend_mask, i)); + PMU_DEBUG(sc, "Removing %#x from rsrc %hhu " + "res_dep_mask\n", table->depend_mask, i); depend_mask &= ~(rdep->depend_mask); break; @@ -1106,13 +1147,13 @@ bhnd_pmu_res_init(struct bhnd_pmu_softc *sc) if (error == ENOENT) { continue; } else if (error) { - device_printf(sc->dev, "NVRAM error reading %s: %d\n", - name, error); + PMU_LOG(sc, "NVRAM error reading %s: %d\n", name, + error); return (error); } - PMU_MSG(("Applying %s=%s to rsrc %d res_dep_mask\n", name, val, - i)); + PMU_DEBUG(sc, "Applying %s=%s to rsrc %d res_dep_mask\n", name, + val, i); BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i); 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 */ 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); } /* Program min resource mask */ 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); } @@ -1367,7 +1408,7 @@ static const pmu1_xtaltab0_t pmu1_xtaltab0_960[] = { /* select xtal table for each chip */ 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) { case BHND_CHIPID_BCM4315: @@ -1386,15 +1427,15 @@ bhnd_pmu1_xtaltab0(struct bhnd_pmu_softc *sc) else return (pmu1_xtaltab0_1440); default: - PMU_MSG(("bhnd_pmu1_xtaltab0: Unknown chipid %#hx\n", - sc->cid.chip_id)); + PMU_DEBUG(sc, "bhnd_pmu1_xtaltab0: Unknown chipid %#hx\n", + sc->cid.chip_id); return (NULL); } } /* select default xtal frequency for each chip */ 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) { case BHND_CHIPID_BCM4315: @@ -1419,15 +1460,15 @@ bhnd_pmu1_xtaldef0(struct bhnd_pmu_softc *sc) else return (&pmu1_xtaltab0_1440[PMU1_XTALTAB0_1440_37400K]); default: - PMU_MSG(("bhnd_pmu1_xtaldef0: Unknown chipid %#hx\n", - sc->cid.chip_id)); + PMU_DEBUG(sc, "bhnd_pmu1_xtaldef0: Unknown chipid %#hx\n", + sc->cid.chip_id); return (NULL); } } /* select default pll fvco for each chip */ static uint32_t -bhnd_pmu1_pllfvco0(struct bhnd_pmu_softc *sc) +bhnd_pmu1_pllfvco0(struct bhnd_pmu_query *sc) { switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4329: @@ -1442,15 +1483,15 @@ bhnd_pmu1_pllfvco0(struct bhnd_pmu_softc *sc) else return (FVCO_1440); default: - PMU_MSG(("bhnd_pmu1_pllfvco0: Unknown chipid %#hx\n", - sc->cid.chip_id)); + PMU_DEBUG(sc, "bhnd_pmu1_pllfvco0: Unknown chipid %#hx\n", + sc->cid.chip_id); return (0); } } /* query alp/xtal clock frequency */ static uint32_t -bhnd_pmu1_alpclk0(struct bhnd_pmu_softc *sc) +bhnd_pmu1_alpclk0(struct bhnd_pmu_query *sc) { const pmu1_xtaltab0_t *xt; uint32_t xf; @@ -1469,8 +1510,7 @@ bhnd_pmu1_alpclk0(struct bhnd_pmu_softc *sc) xt = bhnd_pmu1_xtaldef0(sc); if (xt == NULL || xt->fref == 0) { - device_printf(sc->dev, - "no matching ALP/XTAL frequency found\n"); + PMU_LOG(sc, "no matching ALP/XTAL frequency found\n"); return (0); } @@ -1489,8 +1529,8 @@ bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal) /* Use h/w default PLL config */ if (xtal == 0) { - PMU_MSG(("Unspecified xtal frequency, skipping PLL " - "configuration\n")); + PMU_DEBUG(sc, "Unspecified xtal frequency, skipping PLL " + "configuration\n"); return; } @@ -1503,7 +1543,8 @@ bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal) if (xt->freq == 0) 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 */ 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 */ - PMU_MSG(("PLL already programmed for %d.%d MHz\n", - xt->freq / 1000, xt->freq % 1000)); + PMU_DEBUG(sc, "PLL already programmed for %d.%d MHz\n", + xt->freq / 1000, xt->freq % 1000); return; } 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, pmu0_xtaltab0[tmp-1].freq / 1000, - pmu0_xtaltab0[tmp-1].freq % 1000)); + pmu0_xtaltab0[tmp-1].freq % 1000); } else { - PMU_MSG(("Programming PLL for %d.%d MHz\n", - xt->freq / 1000, xt->freq % 1000)); + PMU_DEBUG(sc, "Programming PLL for %d.%d MHz\n", + xt->freq / 1000, xt->freq % 1000); } /* 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. */ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL); - PMU_MSG(("Done masking\n")); + PMU_DEBUG(sc, "Done masking\n"); /* Write PDIV in pllcontrol[0] */ 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; 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. */ 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 */ static uint32_t -bhnd_pmu0_alpclk0(struct bhnd_pmu_softc *sc) +bhnd_pmu0_alpclk0(struct bhnd_pmu_query *sc) { const pmu0_xtaltab0_t *xt; uint32_t xf; @@ -1618,7 +1660,7 @@ bhnd_pmu0_alpclk0(struct bhnd_pmu_softc *sc) /* query CPU clock frequency */ 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 FVCO; @@ -1654,8 +1696,8 @@ bhnd_pmu0_cpuclk0(struct bhnd_pmu_softc *sc) fvco /= 1000; fvco *= 1000; - PMU_MSG(("bhnd_pmu0_cpuclk0: wbint %u wbfrac %u fvco %u\n", - wbint, wbfrac, fvco)); + PMU_DEBUG(sc, "bhnd_pmu0_cpuclk0: wbint %u wbfrac %u fvco %u\n", + wbint, wbfrac, fvco); FVCO = fvco; #endif /* BCMDBG */ @@ -1677,19 +1719,21 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal) uint32_t FVCO; uint8_t ndiv_mode; - FVCO = bhnd_pmu1_pllfvco0(sc) / 1000; + FVCO = bhnd_pmu1_pllfvco0(&sc->query) / 1000; buf_strength = 0; ndiv_mode = 1; /* Use h/w default PLL config */ if (xtal == 0) { - PMU_MSG(("Unspecified xtal frequency, skipping PLL " - "configuration\n")); + PMU_DEBUG(sc, "Unspecified xtal frequency, skipping PLL " + "configuration\n"); return; } /* 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) break; } @@ -1698,8 +1742,8 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal) * we don't know how to program it. */ if (xt == NULL || xt->fref == 0) { - device_printf(sc->dev, "Unsupported XTAL frequency %d.%dMHz, " - "skipping PLL configuration\n", xtal / 1000, xtal % 1000); + PMU_LOG(sc, "Unsupported XTAL frequency %d.%dMHz, skipping PLL " + "configuration\n", xtal / 1000, xtal % 1000); 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_BCM4330) { - PMU_MSG(("PLL already programmed for %d.%dMHz\n", - xt->fref / 1000, xt->fref % 1000)); + PMU_DEBUG(sc, "PLL already programmed for %d.%dMHz\n", + xt->fref / 1000, xt->fref % 1000); return; } - PMU_MSG(("XTAL %d.%dMHz (%d)\n", xtal / 1000, xtal % 1000, xt->xf)); - PMU_MSG(("Programming PLL for %d.%dMHz\n", xt->fref / 1000, - xt->fref % 1000)); + PMU_DEBUG(sc, "XTAL %d.%dMHz (%d)\n", xtal / 1000, xtal % 1000, xt->xf); + PMU_DEBUG(sc, "Programming PLL for %d.%dMHz\n", xt->fref / 1000, + xt->fref % 1000); switch (sc->cid.chip_id) { 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); } - PMU_MSG(("Done masking\n")); + PMU_DEBUG(sc, "Done masking\n"); /* Write p1div and p2div to pllcontrol[0] */ plldata = @@ -1916,8 +1960,8 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal) /* Write clock driving strength to pllcontrol[5] */ if (buf_strength) { - PMU_MSG(("Adjusting PLL buffer drive strength: %x\n", - buf_strength)); + PMU_DEBUG(sc, "Adjusting PLL buffer drive strength: %x\n", + buf_strength); plldata = BHND_PMU_SET_BITS(buf_strength, BHND_PMU1_PLL0_PC5_CLK_DRV); @@ -1946,7 +1990,7 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal) 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 be updated. @@ -1995,7 +2039,7 @@ bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal) /* query the CPU clock frequency */ static uint32_t -bhnd_pmu1_cpuclk0(struct bhnd_pmu_softc *sc) +bhnd_pmu1_cpuclk0(struct bhnd_pmu_query *sc) { uint32_t tmp, m1div; #ifdef BCMDBG @@ -2032,8 +2076,8 @@ bhnd_pmu1_cpuclk0(struct bhnd_pmu_softc *sc) fvco /= 1000; fvco *= 1000; - PMU_MSG(("bhnd_pmu1_cpuclk0: ndiv_int %u ndiv_frac %u p2div %u " - "p1div %u fvco %u\n", ndiv_int, ndiv_frac, p2div, p1div, fvco)); + 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); FVCO = fvco; #endif /* BCMDBG */ @@ -2134,15 +2178,19 @@ bhnd_pmu_pll_init(struct bhnd_pmu_softc *sc, u_int xtalfreq) bhnd_pmu1_pllinit0(sc, xtalfreq); break; default: - PMU_MSG(("No PLL init done for chip %#hx rev %d pmurev %d\n", - sc->cid.chip_id, sc->cid.chip_rev, BHND_PMU_REV(sc))); + 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)); break; } } -/* query alp/xtal clock frequency */ +/** + * Return the ALP/XTAL clock frequency, in Hz. + * + * @param sc PMU query instance. + */ uint32_t -bhnd_pmu_alp_clock(struct bhnd_pmu_softc *sc) +bhnd_pmu_alp_clock(struct bhnd_pmu_query *sc) { uint32_t clock; @@ -2201,10 +2249,10 @@ bhnd_pmu_alp_clock(struct bhnd_pmu_softc *sc) clock = 25000 * 1000; break; 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", bcm_chipname(sih->chip, chn, 8), sih->chiprev, - sih->pmurev, clock)); + sih->pmurev, clock); 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. */ 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 fc; @@ -2224,13 +2272,13 @@ bhnd_pmu5_clock(struct bhnd_pmu_softc *sc, u_int pll0, u_int m) uint32_t tmp; 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); } /* Strictly there is an m5 divider, but I'm not sure we use it */ 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); } @@ -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) { /* 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) 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 = (p1 * ndiv * fc) / p2; - PMU_MSG(("%s: p1=%d, p2=%d, ndiv=%d(0x%x), m%d=%d; fc=%d, clock=%d\n", - __func__, p1, p2, ndiv, ndiv, m, div, fc, fc / div)); + PMU_DEBUG(sc, "%s: p1=%d, p2=%d, ndiv=%d(0x%x), m%d=%d; fc=%d, " + "clock=%d\n", __func__, p1, p2, ndiv, ndiv, m, div, fc, fc / div); /* Return clock in Hertz */ return ((fc / div) * 1000000); } -/* query backplane clock frequency */ -/* For designs that feed the same clock to both backplane - * and CPU just return the CPU clock speed. +/** + * Return the backplane clock frequency, in Hz. + * + * 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 -bhnd_pmu_si_clock(struct bhnd_pmu_softc *sc) +bhnd_pmu_si_clock(struct bhnd_pmu_query *sc) { uint32_t chipst; uint32_t clock; @@ -2351,14 +2403,14 @@ bhnd_pmu_si_clock(struct bhnd_pmu_softc *sc) case BHND_CHIPID_BCM43235: case BHND_CHIPID_BCM43236: 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) clock = 120000 * 1000; else clock = 96000 * 1000; break; 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) clock = 96000 * 1000; else @@ -2377,8 +2429,8 @@ bhnd_pmu_si_clock(struct bhnd_pmu_softc *sc) clock = 75000000; break; default: - device_printf(sc->dev, "No backplane clock specified for chip " - "%#hx rev %hhd pmurev %hhd, using default %dHz\n", + PMU_LOG(sc, "No backplane clock specified for chip %#hx rev " + "%hhd pmurev %hhd, using default %dHz\n", sc->cid.chip_id, sc->cid.chip_rev, BHND_PMU_REV(sc), clock); break; } @@ -2386,18 +2438,19 @@ bhnd_pmu_si_clock(struct bhnd_pmu_softc *sc) return (clock); } -/* query CPU clock frequency */ +/** + * Return the CPU clock frequency, in Hz. + * + * @param sc PMU query instance. + */ 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 */ if (sc->cid.chip_id == BHND_CHIPID_BCM5354) - return (240000000); + return (240 * 1000 * 1000); /* 240MHz */ if (sc->cid.chip_id == BHND_CHIPID_BCM53572) return (300000000); @@ -2436,9 +2489,13 @@ bhnd_pmu_cpu_clock(struct bhnd_pmu_softc *sc) return (clock); } -/* query memory clock frequency */ +/** + * Return the memory clock frequency, in Hz. + * + * @param sc PMU query instance. + */ uint32_t -bhnd_pmu_mem_clock(struct bhnd_pmu_softc *sc) +bhnd_pmu_mem_clock(struct bhnd_pmu_query *sc) { uint32_t clock; @@ -2479,8 +2536,13 @@ bhnd_pmu_mem_clock(struct bhnd_pmu_softc *sc) /* Measure ILP clock frequency */ #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 -bhnd_pmu_ilp_clock(struct bhnd_pmu_softc *sc) +bhnd_pmu_ilp_clock(struct bhnd_pmu_query *sc) { uint32_t start, end, delta; @@ -2572,9 +2634,9 @@ bhnd_pmu_sdiod_drive_strength_init(struct bhnd_pmu_softc *sc, break; default: - device_printf(sc->dev, "No SDIO Drive strength init done for " - "chip %#x rev %hhd pmurev %hhd\n", sc->cid.chip_id, - sc->cid.chip_rev, BHND_PMU_REV(sc)); + PMU_LOG(sc, "No SDIO Drive strength init done for chip %#x " + "rev %hhd pmurev %hhd\n", sc->cid.chip_id, sc->cid.chip_rev, + BHND_PMU_REV(sc)); break; } @@ -2595,8 +2657,8 @@ bhnd_pmu_sdiod_drive_strength_init(struct bhnd_pmu_softc *sc, cc_data_temp |= drivestrength_sel; BHND_PMU_CCTRL_WRITE(sc, 1, cc_data_temp, ~0); - PMU_MSG(("SDIO: %dmA drive strength selected, set to 0x%08x\n", - drivestrength, cc_data_temp)); + PMU_DEBUG(sc, "SDIO: %dmA drive strength selected, set to " + "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 (error) { - if (error != ENOENT) { - device_printf(sc->dev, "error fetching xtalfreq: %d\n", - error); - } + if (error != ENOENT) + PMU_LOG(sc, "error fetching xtalfreq: %d\n", error); 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; } - PMU_MSG(("bhnd_pmu_res_uptime: rsrc %hhu uptime %u(deps 0x%08x " - "uptime %u)\n", rsrc, up, deps, dmax)); + PMU_DEBUG(sc, "bhnd_pmu_res_uptime: rsrc %hhu uptime %u(deps 0x%08x " + "uptime %u)\n", rsrc, up, deps, dmax); *uptime = (up + dmax + BHND_PMURES_UP_TRANSITION); return (0); @@ -2779,8 +2839,8 @@ bhnd_pmu_otp_power(struct bhnd_pmu_softc *sc, bool on) if (on) { uint32_t state; - PMU_MSG(("Adding rsrc 0x%x to min_res_mask\n", - rsrcs | deps)); + PMU_DEBUG(sc, "Adding rsrc 0x%x to min_res_mask\n", + rsrcs | deps); BHND_PMU_OR_4(sc, BHND_PMU_MIN_RES_MASK, (rsrcs|deps)); /* 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) { - device_printf(sc->dev, "timeout waiting for OTP " - "resource enable\n"); + PMU_LOG(sc, "timeout waiting for OTP resource " + "enable\n"); return (ENXIO); } } else { - PMU_MSG(("Removing rsrc 0x%x from min_res_mask\n", - rsrcs | deps)); + PMU_DEBUG(sc, "Removing rsrc 0x%x from min_res_mask\n", + 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; } - PMU_MSG(("RCal completed, status 0x%x, code 0x%x\n", - R_REG(&cc->chipstatus), rcal_code)); + PMU_DEBUG("RCal completed, status 0x%x, code 0x%x\n", + R_REG(&cc->chipstatus), rcal_code); /* Write RCal code into pmu_vreg_ctrl[32:29] */ 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; case BHND_CHIPID_BCM4319: + pmuctrl = 0; break; 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); - pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD; break; 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; break; default: - PMU_ERROR(("%s: unknown spuravoidance settings for chip %#hx, " - "not changing PLL\n", __func__, sc->cid.chip_id)); + PMU_LOG(sc, "%s: unknown spuravoidance settings for chip %#hx, " + "not changing PLL", __func__, sc->cid.chip_id); + pmuctrl = 0; break; } - BHND_PMU_OR_4(sc, BHND_PMU_CTRL, pmuctrl); + if (pmuctrl != 0) + BHND_PMU_OR_4(sc, BHND_PMU_CTRL, pmuctrl); } bool @@ -3417,7 +3479,7 @@ bhnd_pmu_measure_alpclk(struct bhnd_pmu_softc *sc) static void 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 pllc1, pllc2; diff --git a/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h b/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h index 14c26dbcb1e7..0f6246d405e4 100644 --- a/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h +++ b/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h @@ -37,15 +37,28 @@ #include "bhnd_pmu.h" +struct bhnd_pmu_query; +struct bhnd_pmu_io; + DECLARE_CLASS(bhnd_pmu_driver); 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_detach(device_t dev); -int bhnd_pmu_suspend(device_t dev); -int bhnd_pmu_resume(device_t dev); +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); +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 @@ -60,25 +73,62 @@ enum { 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. */ struct bhnd_pmu_softc { - device_t dev; - uint32_t quirks; /**< device quirk flags */ - uint32_t caps; /**< pmu capability flags. */ + device_t dev; + uint32_t quirks; /**< device quirk flags */ + uint32_t caps; /**< pmu capability flags. */ + struct bhnd_chipid cid; /**< chip identification */ - struct bhnd_chipid cid; /**< chip identification */ - struct bhnd_board_info board; /**< board identification */ - device_t chipc_dev; /**< chipcommon device */ + struct bhnd_pmu_query query; /**< query instance */ - struct bhnd_resource *res; /**< pmu register block. */ - int rid; /**< pmu register RID */ + struct bhnd_board_info board; /**< board identification */ + 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) \ diff --git a/sys/mips/broadcom/bcm_machdep.c b/sys/mips/broadcom/bcm_machdep.c index 2d288a15ecd8..9a241b898e04 100644 --- a/sys/mips/broadcom/bcm_machdep.c +++ b/sys/mips/broadcom/bcm_machdep.c @@ -85,7 +85,6 @@ __FBSDID("$FreeBSD$"); #include "bcm_machdep.h" #include "bcm_mips_exts.h" -#include "bcm_socinfo.h" #ifdef CFE #include @@ -238,6 +237,16 @@ bcm_init_platform_data(struct bcm_platform *pdata) 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; return (0); } @@ -318,7 +327,8 @@ mips_init(void) void platform_reset(void) { - bool bcm4785war; + struct bcm_platform *bp; + bool bcm4785war; printf("bcm::platform_reset()\n"); intr_disable(); @@ -332,9 +342,11 @@ platform_reset(void) } #endif - /* Handle BCM4785-specific behavior */ + bp = bcm_get_platform(); 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; /* Switch to async mode */ @@ -342,10 +354,10 @@ platform_reset(void) } /* Set watchdog (PMU or ChipCommon) */ - if (bcm_get_platform()->pmu_addr != 0x0) { - BCM_CHIPC_WRITE_4(BHND_PMU_WATCHDOG, 1); + if (bp->pmu_addr != 0x0) { + BCM_PMU_WRITE_4(bp, BHND_PMU_WATCHDOG, 1); } else - BCM_CHIPC_WRITE_4(CHIPC_WATCHDOG, 1); + BCM_CHIPC_WRITE_4(bp, CHIPC_WATCHDOG, 1); /* BCM4785 */ if (bcm4785war) { @@ -362,7 +374,6 @@ platform_start(__register_t a0, __register_t a1, __register_t a2, { vm_offset_t kernend; uint64_t platform_counter_freq; - struct bcm_socinfo *socinfo; int error; /* 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))) panic("bcm_init_platform_data() failed: %d", error); - socinfo = bcm_get_socinfo(); - platform_counter_freq = socinfo->cpurate * 1000 * 1000; /* BCM4718 is 480MHz */ + platform_counter_freq = bcm_get_cpufreq(bcm_get_platform()); - mips_timer_early_init(platform_counter_freq); + /* CP0 ticks every two cycles */ + mips_timer_early_init(platform_counter_freq / 2); cninit(); mips_init(); - mips_timer_init_params(platform_counter_freq, socinfo->double_count); + mips_timer_init_params(platform_counter_freq, 1); } /* diff --git a/sys/mips/broadcom/bcm_machdep.h b/sys/mips/broadcom/bcm_machdep.h index 1a33c61788be..d8d551f3ac1a 100644 --- a/sys/mips/broadcom/bcm_machdep.h +++ b/sys/mips/broadcom/bcm_machdep.h @@ -36,6 +36,13 @@ #include #include +#include + +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 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 * and cc_addr. */ 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 int cfe_console; /**< Console handle, or -1 */ #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); +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_bcma; 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)) -#define BCM_SOC_READ_4(_addr, _offset) \ +#define BCM_SOC_READ_4(_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)) -#define BCM_CORE_ADDR(_name, _reg) \ - BCM_SOC_ADDR(bcm_get_platform()->_name, (_reg)) +#define BCM_CORE_ADDR(_bp, _name, _reg) \ + BCM_SOC_ADDR(_bp->_name, (_reg)) -#define BCM_CORE_READ_4(_name, _reg) \ - readl(BCM_CORE_ADDR(_name, (_reg))) -#define BCM_CORE_WRITE_4(_name, _reg, _val) \ - writel(BCM_CORE_ADDR(_name, (_reg)), (_val)) +#define BCM_CORE_READ_4(_bp, _name, _reg) \ + readl(BCM_CORE_ADDR(_bp, _name, (_reg))) +#define BCM_CORE_WRITE_4(_bp, _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_WRITE_4(_reg, _val) \ - BCM_CORE_WRITE_4(cc_addr, (_reg), (_val)) +#define BCM_CHIPC_READ_4(_bp, _reg) \ + BCM_CORE_READ_4(_bp, cc_addr, (_reg)) +#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_WRITE_4(_reg, _val) \ - BCM_CORE_WRITE_4(pmu_addr, (_reg), (_val)) +#define BCM_PMU_READ_4(_bp, _reg) \ + BCM_CORE_READ_4(_bp, pmu_addr, (_reg)) +#define BCM_PMU_WRITE_4(_bp, _reg, _val) \ + BCM_CORE_WRITE_4(_bp, pmu_addr, (_reg), (_val)) #endif /* _MIPS_BROADCOM_BCM_MACHDEP_H_ */ diff --git a/sys/mips/broadcom/bcm_pmu.c b/sys/mips/broadcom/bcm_pmu.c new file mode 100644 index 000000000000..9ded7cc3840f --- /dev/null +++ b/sys/mips/broadcom/bcm_pmu.c @@ -0,0 +1,298 @@ +/*- + * Copyright (c) 2016 Landon Fuller + * + * 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 +__FBSDID("$FreeBSD$"); + +#include + +#include + +#include + +#include +#include + +#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))); +} diff --git a/sys/mips/broadcom/bcm_socinfo.c b/sys/mips/broadcom/bcm_socinfo.c deleted file mode 100644 index fba5d0e9e056..000000000000 --- a/sys/mips/broadcom/bcm_socinfo.c +++ /dev/null @@ -1,95 +0,0 @@ -/*- - * Copyright (c) 2016 Michael Zhilin - * - * 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 -__FBSDID("$FreeBSD$"); - -#include - -#include - -#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; -} diff --git a/sys/mips/broadcom/bcm_socinfo.h b/sys/mips/broadcom/bcm_socinfo.h deleted file mode 100644 index d4f34a8207eb..000000000000 --- a/sys/mips/broadcom/bcm_socinfo.h +++ /dev/null @@ -1,47 +0,0 @@ -/*- - * Copyright (c) 2016 Michael Zhilin - * - * 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 - -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_ */ diff --git a/sys/mips/broadcom/files.broadcom b/sys/mips/broadcom/files.broadcom index aa784b4dda6d..61b120073e48 100644 --- a/sys/mips/broadcom/files.broadcom +++ b/sys/mips/broadcom/files.broadcom @@ -6,6 +6,7 @@ # 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_machdep.c standard +mips/broadcom/bcm_pmu.c standard mips/broadcom/bcm_siba.c optional siba_nexus siba mips/mips/tick.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_bus_chipc.c optional uart -mips/broadcom/bcm_socinfo.c standard mips/broadcom/bcm_mipscore.c standard # TODO: Replace with BCM47xx/57xx/etc-aware geom_map diff --git a/sys/mips/broadcom/uart_bus_chipc.c b/sys/mips/broadcom/uart_bus_chipc.c index 84d2c7aa1647..69c2fa779c69 100644 --- a/sys/mips/broadcom/uart_bus_chipc.c +++ b/sys/mips/broadcom/uart_bus_chipc.c @@ -48,22 +48,20 @@ __FBSDID("$FreeBSD$"); #include "uart_if.h" #include "bhnd_chipc_if.h" -#include "bcm_socinfo.h" +#include "bcm_machdep.h" static int uart_chipc_probe(device_t dev) { struct uart_softc *sc; - struct bcm_socinfo *socinfo; + u_int rclk; sc = device_get_softc(dev); sc->sc_class = &uart_ns8250_class; - /* TODO: UART rate should be calculated from CPU clock speed - * as fetched from bhnd bus */ - socinfo = bcm_get_socinfo(); - return (uart_bus_probe(dev, 0, socinfo->uartrate, 0, 0)); + rclk = bcm_get_uart_rclk(bcm_get_platform()); + return (uart_bus_probe(dev, 0, rclk, 0, 0)); } static device_method_t uart_chipc_methods[] = { diff --git a/sys/mips/broadcom/uart_cpu_chipc.c b/sys/mips/broadcom/uart_cpu_chipc.c index 91548a424a0a..2120cf0ba4f5 100644 --- a/sys/mips/broadcom/uart_cpu_chipc.c +++ b/sys/mips/broadcom/uart_cpu_chipc.c @@ -52,7 +52,6 @@ __FBSDID("$FreeBSD$"); #endif #include "bcm_machdep.h" -#include "bcm_socinfo.h" bus_space_tag_t uart_bus_space_io; 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 uart_cpu_init(struct uart_devinfo *di, u_int uart, int baudrate) { - struct bcm_socinfo *socinfo; - if (uart >= CHIPC_UART_MAX) return (EINVAL); - socinfo = bcm_get_socinfo(); di->ops = uart_getops(chipc_uart_class); di->bas.chan = 0; di->bas.bst = uart_bus_space_mem; - di->bas.bsh = (bus_space_handle_t) BCM_CORE_ADDR(cc_addr, - CHIPC_UART(uart)); + di->bas.bsh = (bus_space_handle_t) BCM_CORE_ADDR(bcm_get_platform(), + cc_addr, CHIPC_UART(uart)); 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->databits = 8; di->stopbits = 1;