Index: head/sys/dev/bhnd/cores/chipc/chipcreg.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipcreg.h (revision 304870) +++ head/sys/dev/bhnd/cores/chipc/chipcreg.h (revision 304871) @@ -1,962 +1,966 @@ /*- * Copyright (c) 2015-2016 Landon Fuller * Copyright (c) 2010 Broadcom Corporation * All rights reserved. * * This file is derived from the sbchipc.h header distributed with * Broadcom's initial brcm80211 Linux driver release, as * contributed to the Linux staging repository. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #ifndef _BHND_CORES_CHIPC_CHIPCREG_H_ #define _BHND_CORES_CHIPC_CHIPCREG_H_ #define CHIPC_CHIPID_SIZE 0x100 /**< size of the register block containing the chip identification registers 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) /** Evaluates to true if the given ChipCommon core revision supports * the CHIPC_CAPABILITIES_EXT register */ #define CHIPC_HWREV_HAS_CAP_EXT(hwrev) ((hwrev) >= 35) /** Evaluates to true if the chipcommon core (determined from the provided * @p _chipid (CHIPC_ID) register value) provides a pointer to the enumeration * table via CHIPC_EROMPTR */ #define CHIPC_HAS_EROMPTR(_chipid) \ (CHIPC_GET_BITS((_chipid), CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA) #define CHIPC_GET_FLAG(_value, _flag) (((_value) & _flag) != 0) #define CHIPC_GET_BITS(_value, _field) \ ((_value & _field ## _MASK) >> _field ## _SHIFT) #define CHIPC_ID 0x00 #define CHIPC_CAPABILITIES 0x04 #define CHIPC_CORECTRL 0x08 /* rev >= 1 */ #define CHIPC_BIST 0x0C #define CHIPC_OTPST 0x10 /**< otp status */ #define CHIPC_OTPCTRL 0x14 /**< otp control */ #define CHIPC_OTPPROG 0x18 #define CHIPC_OTPLAYOUT 0x1C /**< otp layout (IPX OTP) */ #define CHIPC_INTST 0x20 /**< interrupt status */ #define CHIPC_INTM 0x24 /**< interrupt mask */ #define CHIPC_CHIPCTRL 0x28 /**< chip control (rev >= 11) */ #define CHIPC_CHIPST 0x2C /**< chip status (rev >= 11) */ #define CHIPC_JTAGCMD 0x30 #define CHIPC_JTAGIR 0x34 #define CHIPC_JTAGDR 0x38 #define CHIPC_JTAGCTRL 0x3c #define CHIPC_SFLASH_BASE 0x40 #define CHIPC_SFLASH_SIZE 12 #define CHIPC_SFLASHCTRL 0x40 #define CHIPC_SFLASHADDR 0x44 #define CHIPC_SFLASHDATA 0x48 /* siba backplane configuration broadcast (siba-only) */ #define CHIPC_SBBCAST_ADDR 0x50 #define CHIPC_SBBCAST_DATA 0x54 #define CHIPC_GPIOPU 0x58 /**< pull-up mask (rev >= 20) */ #define CHIPC_GPIOPD 0x5C /**< pull down mask (rev >= 20) */ #define CHIPC_GPIOIN 0x60 #define CHIPC_GPIOOUT 0x64 #define CHIPC_GPIOOUTEN 0x68 #define CHIPC_GPIOCTRL 0x6C #define CHIPC_GPIOPOL 0x70 #define CHIPC_GPIOINTM 0x74 /**< gpio interrupt mask */ #define CHIPC_GPIOEVENT 0x78 /**< gpio event (rev >= 11) */ #define CHIPC_GPIOEVENT_INTM 0x7C /**< gpio event interrupt mask (rev >= 11) */ #define CHIPC_WATCHDOG 0x80 /**< watchdog timer */ #define CHIPC_GPIOEVENT_INTPOLARITY 0x84 /**< gpio even interrupt polarity (rev >= 11) */ #define CHIPC_GPIOTIMERVAL 0x88 /**< gpio-based LED duty cycle (rev >= 16) */ #define CHIPC_GPIOTIMEROUTMASK 0x8C /* clock control registers (non-PMU devices) */ #define CHIPC_CLKC_N 0x90 #define CHIPC_CLKC_SB 0x94 /* m0 (backplane) */ #define CHIPC_CLKC_PCI 0x98 /* m1 */ #define CHIPC_CLKC_M2 0x9C /* mii/uart/mipsref */ #define CHIPC_CLKC_M3 0xA0 /* cpu */ #define CHIPC_CLKDIV 0xA4 /* rev >= 3 */ #define CHIPC_GPIODEBUGSEL 0xA8 /* rev >= 28 */ #define CHIPC_CAPABILITIES_EXT 0xAC /* pll/slowclk clock control registers (rev >= 4) */ #define CHIPC_PLL_ON_DELAY 0xB0 /* rev >= 4 */ #define CHIPC_PLL_FREFSEL_DELAY 0xB4 /* rev >= 4 */ #define CHIPC_PLL_SLOWCLK_CTL 0xB8 /* "slowclock" (rev 6-9) */ /* "instaclock" clock control registers */ #define CHIPC_SYS_CLK_CTL 0xC0 /* "instaclock" (rev >= 10) */ #define CHIPC_SYS_CLK_ST_STRETCH 0xC4 /* state strech (?) rev >= 10 */ /* indirect backplane access (rev >= 10) */ #define CHIPC_BP_ADDRLOW 0xD0 #define CHIPC_BP_ADDRHIGH 0xD4 #define CHIPC_BP_DATA 0xD8 #define CHIPC_BP_INDACCESS 0xE0 /* SPI/I2C (rev >= 37) */ #define CHIPC_GSIO_CTRL 0xE4 #define CHIPC_GSIO_ADDR 0xE8 #define CHIPC_GSIO_DATA 0xEC /* More clock dividers (corerev >= 32) */ #define CHIPC_CLKDIV2 0xF0 #define CHIPC_EROMPTR 0xFC /**< 32-bit EROM base address * on BCMA devices */ /* ExtBus control registers (rev >= 3) */ #define CHIPC_PCMCIA_CFG 0x100 #define CHIPC_PCMCIA_MEMWAIT 0x104 #define CHIPC_PCMCIA_ATTRWAIT 0x108 #define CHIPC_PCMCIA_IOWAIT 0x10C #define CHIPC_IDE_CFG 0x110 #define CHIPC_IDE_MEMWAIT 0x114 #define CHIPC_IDE_ATTRWAIT 0x118 #define CHIPC_IDE_IOWAIT 0x11C #define CHIPC_PROG_CFG 0x120 #define CHIPC_PROG_WAITCOUNT 0x124 #define CHIPC_FLASH_CFG 0x128 #define CHIPC_FLASH_WAITCOUNT 0x12C #define CHIPC_SECI_CFG 0x130 #define CHIPC_SECI_ST 0x134 #define CHIPC_SECI_STM 0x138 #define CHIPC_SECI_RXNBC 0x13C /* Enhanced Coexistence Interface (ECI) registers (rev 21-34) */ #define CHIPC_ECI_OUTPUT 0x140 #define CHIPC_ECI_CTRL 0x144 #define CHIPC_ECI_INPUTLO 0x148 #define CHIPC_ECI_INPUTMI 0x14C #define CHIPC_ECI_INPUTHI 0x150 #define CHIPC_ECI_INPUTINTPOLARITYLO 0x154 #define CHIPC_ECI_INPUTINTPOLARITYMI 0x158 #define CHIPC_ECI_INPUTINTPOLARITYHI 0x15C #define CHIPC_ECI_INTMASKLO 0x160 #define CHIPC_ECI_INTMASKMI 0x164 #define CHIPC_ECI_INTMASKHI 0x168 #define CHIPC_ECI_EVENTLO 0x16C #define CHIPC_ECI_EVENTMI 0x170 #define CHIPC_ECI_EVENTHI 0x174 #define CHIPC_ECI_EVENTMASKLO 0x178 #define CHIPC_ECI_EVENTMASKMI 0x17C #define CHIPC_ECI_EVENTMASKHI 0x180 #define CHIPC_FLASHSTRCFG 0x18C /**< BCM4706 NAND flash config */ #define CHIPC_SPROM_CTRL 0x190 /**< SPROM interface (rev >= 32) */ #define CHIPC_SPROM_ADDR 0x194 #define CHIPC_SPROM_DATA 0x198 /* Clock control and hardware workarounds (corerev >= 20) */ #define CHIPC_CLK_CTL_ST 0x1E0 #define CHIPC_SPROM_HWWAR 0x19 #define CHIPC_UART_BASE 0x300 #define CHIPC_UART_SIZE 0x100 #define CHIPC_UART_MAX 3 /**< max UART blocks */ #define CHIPC_UART(_n) (CHIPC_UART_BASE + (CHIPC_UART_SIZE*_n)) /* PMU register block (rev >= 20) */ #define CHIPC_PMU_BASE 0x600 #define CHIPC_PMU_SIZE 0x70 #define CHIPC_SPROM_OTP 0x800 /* SPROM/OTP address space */ #define CHIPC_SPROM_OTP_SIZE 0x400 /** chipid */ #define CHIPC_ID_CHIP_MASK 0x0000FFFF /**< chip id */ #define CHIPC_ID_CHIP_SHIFT 0 #define CHIPC_ID_REV_MASK 0x000F0000 /**< chip revision */ #define CHIPC_ID_REV_SHIFT 16 #define CHIPC_ID_PKG_MASK 0x00F00000 /**< physical package ID */ #define CHIPC_ID_PKG_SHIFT 20 #define CHIPC_ID_NUMCORE_MASK 0x0F000000 /**< number of cores on chip (rev >= 4) */ #define CHIPC_ID_NUMCORE_SHIFT 24 #define CHIPC_ID_BUS_MASK 0xF0000000 /**< chip/interconnect type (BHND_CHIPTYPE_*) */ #define CHIPC_ID_BUS_SHIFT 28 /* capabilities */ #define CHIPC_CAP_NUM_UART_MASK 0x00000003 /* Number of UARTs (1-3) */ #define CHIPC_CAP_NUM_UART_SHIFT 0 #define CHIPC_CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */ #define CHIPC_CAP_UCLKSEL_MASK 0x00000018 /* UARTs clock select */ #define CHIPC_CAP_UCLKSEL_SHIFT 3 #define CHIPC_CAP_UCLKSEL_UINTCLK 0x1 /* UARTs are driven by internal divided clock */ #define CHIPC_CAP_UARTGPIO 0x00000020 /* UARTs own GPIOs 15:12 */ #define CHIPC_CAP_EXTBUS_MASK 0x000000c0 /* External bus mask */ #define CHIPC_CAP_EXTBUS_SHIFT 6 #define CHIPC_CAP_EXTBUS_NONE 0x0 /* No ExtBus present */ #define CHIPC_CAP_EXTBUS_FULL 0x1 /* ExtBus: PCMCIA, IDE & Prog */ #define CHIPC_CAP_EXTBUS_PROG 0x2 /* ExtBus: ProgIf only */ #define CHIPC_CAP_FLASH_MASK 0x00000700 /* Type of flash */ #define CHIPC_CAP_FLASH_SHIFT 8 #define CHIPC_CAP_FLASH_NONE 0x0 /* No flash */ #define CHIPC_CAP_SFLASH_ST 0x1 /* ST serial flash */ #define CHIPC_CAP_SFLASH_AT 0x2 /* Atmel serial flash */ #define CHIPC_CAP_NFLASH 0x3 /* NAND flash */ #define CHIPC_CAP_PFLASH 0x7 /* Parallel flash */ #define CHIPC_CAP_PLL_MASK 0x00038000 /* Type of PLL */ #define CHIPC_CAP_PLL_SHIFT 15 #define CHIPC_CAP_PWR_CTL 0x00040000 /* Power/clock control */ #define CHIPC_CAP_OTP_SIZE_MASK 0x00380000 /* OTP Size (0 = none) */ #define CHIPC_CAP_OTP_SIZE_SHIFT 19 /* OTP Size shift */ #define CHIPC_CAP_OTP_SIZE_BASE 5 /* OTP Size base */ #define CHIPC_CAP_JTAGP 0x00400000 /* JTAG Master Present */ #define CHIPC_CAP_ROM 0x00800000 /* Internal boot rom active */ #define CHIPC_CAP_BKPLN64 0x08000000 /* 64-bit backplane */ #define CHIPC_CAP_PMU 0x10000000 /* PMU Present, rev >= 20 */ #define CHIPC_CAP_ECI 0x20000000 /* Enhanced Coexistence Interface */ #define CHIPC_CAP_SPROM 0x40000000 /* SPROM Present, rev >= 32 */ #define CHIPC_CAP_4706_NFLASH 0x80000000 /* NAND flash present, BCM4706 or chipc rev38 (BCM5357)? */ #define CHIPC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */ #define CHIPC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */ #define CHIPC_CAP2_GCI 0x00000004 /* GCI present (rev >= ??) */ #define CHIPC_CAP2_AOB 0x00000040 /* Always on Bus present (rev >= 49) * * If set, PMU and GCI registers * are found in dedicated cores. * * This appears to be a lower power * APB bus, bridged via ARM APB IP. */ /* * ChipStatus (Common) */ /** ChipStatus CIS/OTP/SPROM values used to advertise OTP/SPROM availability in * chipcommon revs 11-31. */ enum { CHIPC_CST_DEFCIS_SEL = 0, /**< OTP is powered up, use default CIS, no SPROM */ CHIPC_CST_SPROM_SEL = 1, /**< OTP is powered up, SPROM is present */ CHIPC_CST_OTP_SEL = 2, /**< OTP is powered up, no SPROM */ CHIPC_CST_OTP_PWRDN = 3 /**< OTP is powered down, SPROM is present (rev <= 22 only) */ }; #define CHIPC_CST_SPROM_OTP_SEL_R22_MASK 0x00000003 /**< chipstatus OTP/SPROM SEL value (rev 22) */ #define CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT 0 #define CHIPC_CST_SPROM_OTP_SEL_R23_MASK 0x000000c0 /**< chipstatus OTP/SPROM SEL value (revs 23-31) * * it is unknown whether this is supported on * any CC revs >= 32 that also vend CHIPC_CAP_* * constants for OTP/SPROM/NVRAM availability. */ #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 */ #define CHIPC_LPOMAXFREQ 43000 /* low power oscillator max */ #define CHIPC_XTALMINFREQ 19800000 /* 20 MHz - 1% */ #define CHIPC_XTALMAXFREQ 20200000 /* 20 MHz + 1% */ #define CHIPC_PCIMINFREQ 25000000 /* 25 MHz */ #define CHIPC_PCIMAXFREQ 34000000 /* 33 MHz + fudge */ #define CHIPC_ILP_DIV_5MHZ 0 /* ILP = 5 MHz */ #define CHIPC_ILP_DIV_1MHZ 4 /* ILP = 1 MHz */ /* Power Control Defines */ #define CHIPC_PLL_DELAY 150 /* us pll on delay */ #define CHIPC_FREF_DELAY 200 /* us fref change delay */ #define CHIPC_MIN_SLOW_CLK 32 /* us Slow clock period */ #define CHIPC_XTAL_ON_DELAY 1000 /* us crystal power-on delay */ /* corecontrol */ #define CHIPC_UARTCLKO 0x00000001 /* Drive UART with internal clock */ #define CHIPC_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ #define CHIPC_UARTCLKEN 0x00000008 /* enable UART Clock (corerev > = 21 */ /* chipcontrol */ #define CHIPCTRL_4321A0_DEFAULT 0x3a4 #define CHIPCTRL_4321A1_DEFAULT 0x0a4 #define CHIPCTRL_4321_PLL_DOWN 0x800000 /* serdes PLL down override */ /* Fields in the otpstatus register in rev >= 21 */ #define CHIPC_OTPS_OL_MASK 0x000000ff #define CHIPC_OTPS_OL_MFG 0x00000001 /* manuf row is locked */ #define CHIPC_OTPS_OL_OR1 0x00000002 /* otp redundancy row 1 is locked */ #define CHIPC_OTPS_OL_OR2 0x00000004 /* otp redundancy row 2 is locked */ #define CHIPC_OTPS_OL_GU 0x00000008 /* general use region is locked */ #define CHIPC_OTPS_GUP_MASK 0x00000f00 #define CHIPC_OTPS_GUP_SHIFT 8 #define CHIPC_OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */ #define CHIPC_OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */ #define CHIPC_OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */ #define CHIPC_OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */ #define CHIPC_OTPS_READY 0x00001000 #define CHIPC_OTPS_RV(x) (1 << (16 + (x))) /* redundancy entry valid */ #define CHIPC_OTPS_RV_MASK 0x0fff0000 /* IPX OTP fields in the otpcontrol register */ #define CHIPC_OTPC_PROGSEL 0x00000001 #define CHIPC_OTPC_PCOUNT_MASK 0x0000000e #define CHIPC_OTPC_PCOUNT_SHIFT 1 #define CHIPC_OTPC_VSEL_MASK 0x000000f0 #define CHIPC_OTPC_VSEL_SHIFT 4 #define CHIPC_OTPC_TMM_MASK 0x00000700 #define CHIPC_OTPC_TMM_SHIFT 8 #define CHIPC_OTPC_ODM 0x00000800 #define CHIPC_OTPC_PROGEN 0x80000000 /* Fields in otpprog in IPX OTP and HND OTP */ #define CHIPC_OTPP_COL_MASK 0x000000ff #define CHIPC_OTPP_COL_SHIFT 0 #define CHIPC_OTPP_ROW_MASK 0x0000ff00 #define CHIPC_OTPP_ROW_SHIFT 8 #define CHIPC_OTPP_OC_MASK 0x0f000000 #define CHIPC_OTPP_OC_SHIFT 24 #define CHIPC_OTPP_READERR 0x10000000 #define CHIPC_OTPP_VALUE_MASK 0x20000000 #define CHIPC_OTPP_VALUE_SHIFT 29 #define CHIPC_OTPP_START_BUSY 0x80000000 #define CHIPC_OTPP_READ 0x40000000 /* HND OTP */ /* otplayout */ #define CHIPC_OTPL_SIZE_MASK 0x0000f000 /* rev >= 49 */ #define CHIPC_OTPL_SIZE_SHIFT 12 #define CHIPC_OTPL_GUP_MASK 0x00000FFF /* bit offset to general use region */ #define CHIPC_OTPL_GUP_SHIFT 0 #define CHIPC_OTPL_CISFORMAT_NEW 0x80000000 /* rev >= 36 */ /* Opcodes for OTPP_OC field */ #define CHIPC_OTPPOC_READ 0 #define CHIPC_OTPPOC_BIT_PROG 1 #define CHIPC_OTPPOC_VERIFY 3 #define CHIPC_OTPPOC_INIT 4 #define CHIPC_OTPPOC_SET 5 #define CHIPC_OTPPOC_RESET 6 #define CHIPC_OTPPOC_OCST 7 #define CHIPC_OTPPOC_ROW_LOCK 8 #define CHIPC_OTPPOC_PRESCN_TEST 9 /* Jtagm characteristics that appeared at a given corerev */ #define CHIPC_JTAGM_CREV_OLD 10 /* Old command set, 16bit max IR */ #define CHIPC_JTAGM_CREV_IRP 22 /* Able to do pause-ir */ #define CHIPC_JTAGM_CREV_RTI 28 /* Able to do return-to-idle */ /* jtagcmd */ #define CHIPC_JCMD_START 0x80000000 #define CHIPC_JCMD_BUSY 0x80000000 #define CHIPC_JCMD_STATE_MASK 0x60000000 #define CHIPC_JCMD_STATE_TLR 0x00000000 /* Test-logic-reset */ #define CHIPC_JCMD_STATE_PIR 0x20000000 /* Pause IR */ #define CHIPC_JCMD_STATE_PDR 0x40000000 /* Pause DR */ #define CHIPC_JCMD_STATE_RTI 0x60000000 /* Run-test-idle */ #define CHIPC_JCMD0_ACC_MASK 0x0000f000 #define CHIPC_JCMD0_ACC_IRDR 0x00000000 #define CHIPC_JCMD0_ACC_DR 0x00001000 #define CHIPC_JCMD0_ACC_IR 0x00002000 #define CHIPC_JCMD0_ACC_RESET 0x00003000 #define CHIPC_JCMD0_ACC_IRPDR 0x00004000 #define CHIPC_JCMD0_ACC_PDR 0x00005000 #define CHIPC_JCMD0_IRW_MASK 0x00000f00 #define CHIPC_JCMD_ACC_MASK 0x000f0000 /* Changes for corerev 11 */ #define CHIPC_JCMD_ACC_IRDR 0x00000000 #define CHIPC_JCMD_ACC_DR 0x00010000 #define CHIPC_JCMD_ACC_IR 0x00020000 #define CHIPC_JCMD_ACC_RESET 0x00030000 #define CHIPC_JCMD_ACC_IRPDR 0x00040000 #define CHIPC_JCMD_ACC_PDR 0x00050000 #define CHIPC_JCMD_ACC_PIR 0x00060000 #define CHIPC_JCMD_ACC_IRDR_I 0x00070000 /* rev 28: return to run-test-idle */ #define CHIPC_JCMD_ACC_DR_I 0x00080000 /* rev 28: return to run-test-idle */ #define CHIPC_JCMD_IRW_MASK 0x00001f00 #define CHIPC_JCMD_IRW_SHIFT 8 #define CHIPC_JCMD_DRW_MASK 0x0000003f /* jtagctrl */ #define CHIPC_JCTRL_FORCE_CLK 4 /* Force clock */ #define CHIPC_JCTRL_EXT_EN 2 /* Enable external targets */ #define CHIPC_JCTRL_EN 1 /* Enable Jtag master */ /* Fields in clkdiv */ #define CHIPC_CLKD_SFLASH 0x0f000000 #define CHIPC_CLKD_SFLASH_SHIFT 24 #define CHIPC_CLKD_OTP 0x000f0000 #define CHIPC_CLKD_OTP_SHIFT 16 #define CHIPC_CLKD_JTAG 0x00000f00 #define CHIPC_CLKD_JTAG_SHIFT 8 #define CHIPC_CLKD_UART 0x000000ff #define CHIPC_CLKD2_SPROM 0x00000003 /* intstatus/intmask */ #define CHIPC_CI_GPIO 0x00000001 /* gpio intr */ #define CHIPC_CI_EI 0x00000002 /* extif intr (corerev >= 3) */ #define CHIPC_CI_TEMP 0x00000004 /* temp. ctrl intr (corerev >= 15) */ #define CHIPC_CI_SIRQ 0x00000008 /* serial IRQ intr (corerev >= 15) */ #define CHIPC_CI_PMU 0x00000020 /* pmu intr (corerev >= 21) */ #define CHIPC_CI_UART 0x00000040 /* uart intr (corerev >= 21) */ #define CHIPC_CI_WDRESET 0x80000000 /* watchdog reset occurred */ /* slow_clk_ctl */ #define CHIPC_SCC_SS_MASK 0x00000007 /* slow clock source mask */ #define CHIPC_SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */ #define CHIPC_SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */ #define CHIPC_SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */ #define CHIPC_SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ #define CHIPC_SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled, * 0: LPO is enabled */ #define CHIPC_SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, * 0: power logic control */ #define CHIPC_SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors * PLL clock disable requests from core */ #define CHIPC_SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't * disable crystal when appropriate */ #define CHIPC_SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ #define CHIPC_SCC_CD_MASK 0xffff0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ #define CHIPC_SCC_CD_SHIFT 16 /* system_clk_ctl */ #define CHIPC_SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */ #define CHIPC_SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */ #define CHIPC_SYCC_FP 0x00000004 /* ForcePLLOn */ #define CHIPC_SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */ #define CHIPC_SYCC_HR 0x00000010 /* Force HT */ #define CHIPC_SYCC_CD_MASK 0xffff0000 /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */ #define CHIPC_SYCC_CD_SHIFT 16 /* Indirect backplane access */ #define CHIPC_BPIA_BYTEEN 0x0000000f #define CHIPC_BPIA_SZ1 0x00000001 #define CHIPC_BPIA_SZ2 0x00000003 #define CHIPC_BPIA_SZ4 0x00000007 #define CHIPC_BPIA_SZ8 0x0000000f #define CHIPC_BPIA_WRITE 0x00000100 #define CHIPC_BPIA_START 0x00000200 #define CHIPC_BPIA_BUSY 0x00000200 #define CHIPC_BPIA_ERROR 0x00000400 /* pcmcia/prog/flash_config */ #define CHIPC_CF_EN 0x00000001 /* enable */ #define CHIPC_CF_EM_MASK 0x0000000e /* mode */ #define CHIPC_CF_EM_SHIFT 1 #define CHIPC_CF_EM_FLASH 0 /* flash/asynchronous mode */ #define CHIPC_CF_EM_SYNC 2 /* synchronous mode */ #define CHIPC_CF_EM_PCMCIA 4 /* pcmcia mode */ #define CHIPC_CF_DS 0x00000010 /* destsize: 0=8bit, 1=16bit */ #define CHIPC_CF_BS 0x00000020 /* byteswap */ #define CHIPC_CF_CD_MASK 0x000000c0 /* clock divider */ #define CHIPC_CF_CD_SHIFT 6 #define CHIPC_CF_CD_DIV2 0x00000000 /* backplane/2 */ #define CHIPC_CF_CD_DIV3 0x00000040 /* backplane/3 */ #define CHIPC_CF_CD_DIV4 0x00000080 /* backplane/4 */ #define CHIPC_CF_CE 0x00000100 /* clock enable */ #define CHIPC_CF_SB 0x00000200 /* size/bytestrobe (synch only) */ /* pcmcia_memwait */ #define CHIPC_PM_W0_MASK 0x0000003f /* waitcount0 */ #define CHIPC_PM_W1_MASK 0x00001f00 /* waitcount1 */ #define CHIPC_PM_W1_SHIFT 8 #define CHIPC_PM_W2_MASK 0x001f0000 /* waitcount2 */ #define CHIPC_PM_W2_SHIFT 16 #define CHIPC_PM_W3_MASK 0x1f000000 /* waitcount3 */ #define CHIPC_PM_W3_SHIFT 24 /* pcmcia_attrwait */ #define CHIPC_PA_W0_MASK 0x0000003f /* waitcount0 */ #define CHIPC_PA_W1_MASK 0x00001f00 /* waitcount1 */ #define CHIPC_PA_W1_SHIFT 8 #define CHIPC_PA_W2_MASK 0x001f0000 /* waitcount2 */ #define CHIPC_PA_W2_SHIFT 16 #define CHIPC_PA_W3_MASK 0x1f000000 /* waitcount3 */ #define CHIPC_PA_W3_SHIFT 24 /* pcmcia_iowait */ #define CHIPC_PI_W0_MASK 0x0000003f /* waitcount0 */ #define CHIPC_PI_W1_MASK 0x00001f00 /* waitcount1 */ #define CHIPC_PI_W1_SHIFT 8 #define CHIPC_PI_W2_MASK 0x001f0000 /* waitcount2 */ #define CHIPC_PI_W2_SHIFT 16 #define CHIPC_PI_W3_MASK 0x1f000000 /* waitcount3 */ #define CHIPC_PI_W3_SHIFT 24 /* prog_waitcount */ #define CHIPC_PW_W0_MASK 0x0000001f /* waitcount0 */ #define CHIPC_PW_W1_MASK 0x00001f00 /* waitcount1 */ #define CHIPC_PW_W1_SHIFT 8 #define CHIPC_PW_W2_MASK 0x001f0000 /* waitcount2 */ #define CHIPC_PW_W2_SHIFT 16 #define CHIPC_PW_W3_MASK 0x1f000000 /* waitcount3 */ #define CHIPC_PW_W3_SHIFT 24 #define CHIPC_PW_W0 0x0000000c #define CHIPC_PW_W1 0x00000a00 #define CHIPC_PW_W2 0x00020000 #define CHIPC_PW_W3 0x01000000 /* flash_waitcount */ #define CHIPC_FW_W0_MASK 0x0000003f /* waitcount0 */ #define CHIPC_FW_W1_MASK 0x00001f00 /* waitcount1 */ #define CHIPC_FW_W1_SHIFT 8 #define CHIPC_FW_W2_MASK 0x001f0000 /* waitcount2 */ #define CHIPC_FW_W2_SHIFT 16 #define CHIPC_FW_W3_MASK 0x1f000000 /* waitcount3 */ #define CHIPC_FW_W3_SHIFT 24 /* When SPROM support present, fields in spromcontrol */ #define CHIPC_SRC_START 0x80000000 #define CHIPC_SRC_BUSY 0x80000000 #define CHIPC_SRC_OPCODE 0x60000000 #define CHIPC_SRC_OP_READ 0x00000000 #define CHIPC_SRC_OP_WRITE 0x20000000 #define CHIPC_SRC_OP_WRDIS 0x40000000 #define CHIPC_SRC_OP_WREN 0x60000000 #define CHIPC_SRC_OTPSEL 0x00000010 #define CHIPC_SRC_LOCK 0x00000008 #define CHIPC_SRC_SIZE_MASK 0x00000006 #define CHIPC_SRC_SIZE_1K 0x00000000 #define CHIPC_SRC_SIZE_4K 0x00000002 #define CHIPC_SRC_SIZE_16K 0x00000004 #define CHIPC_SRC_SIZE_SHIFT 1 #define CHIPC_SRC_PRESENT 0x00000001 /* gpiotimerval */ #define CHIPC_GPIO_ONTIME_SHIFT 16 /* clockcontrol_n */ #define CHIPC_CN_N1_MASK 0x3f /* n1 control */ #define CHIPC_CN_N1_SHIFT 0 #define CHIPC_CN_N2_MASK 0x3f00 /* n2 control */ #define CHIPC_CN_N2_SHIFT 8 #define CHIPC_CN_PLLC_MASK 0xf0000 /* pll control */ #define CHIPC_CN_PLLC_SHIFT 16 /* clockcontrol_sb/pci/uart */ #define CHIPC_M1_MASK 0x3f /* m1 control */ #define CHIPC_M1_SHIFT 0 #define CHIPC_M2_MASK 0x3f00 /* m2 control */ #define CHIPC_M2_SHIFT 8 #define CHIPC_M3_MASK 0x3f0000 /* m3 control */ #define CHIPC_M3_SHIFT 16 #define CHIPC_MC_MASK 0x1f000000 /* mux control */ #define CHIPC_MC_SHIFT 24 /* N3M Clock control magic field values */ #define CHIPC_F6_2 0x02 /* A factor of 2 in */ #define CHIPC_F6_3 0x03 /* 6-bit fields like */ #define CHIPC_F6_4 0x05 /* N1, M1 or M3 */ #define CHIPC_F6_5 0x09 #define CHIPC_F6_6 0x11 #define CHIPC_F6_7 0x21 #define CHIPC_F5_BIAS 5 /* 5-bit fields get this added */ #define CHIPC_MC_BYPASS 0x08 #define CHIPC_MC_M1 0x04 #define CHIPC_MC_M1M2 0x02 #define CHIPC_MC_M1M2M3 0x01 #define CHIPC_MC_M1M3 0x11 /* Type 2 Clock control magic field values */ #define CHIPC_T2_BIAS 2 /* n1, n2, m1 & m3 bias */ #define CHIPC_T2M2_BIAS 3 /* m2 bias */ #define CHIPC_T2MC_M1BYP 1 #define CHIPC_T2MC_M2BYP 2 #define CHIPC_T2MC_M3BYP 4 /* Type 6 Clock control magic field values */ #define CHIPC_T6_MMASK 1 /* bits of interest in m */ #define CHIPC_T6_M0 120000000 /* sb clock for m = 0 */ #define CHIPC_T6_M1 100000000 /* sb clock for m = 1 */ #define CHIPC_SB2MIPS_T6(sb) (2 * (sb)) /* Common clock base */ #define CHIPC_CLOCK_BASE1 24000000 /* Half the clock freq */ #define CHIPC_CLOCK_BASE2 12500000 /* Alternate crystal on some PLLs */ /* Clock control values for 200MHz in 5350 */ #define CHIPC_CLKC_5350_N 0x0311 #define CHIPC_CLKC_5350_M 0x04020009 /* Bits in the ExtBus config registers */ #define CHIPC_CFG_EN 0x0001 /* Enable */ #define CHIPC_CFG_EM_MASK 0x000e /* Extif Mode */ #define CHIPC_CFG_EM_ASYNC 0x0000 /* Async/Parallel flash */ #define CHIPC_CFG_EM_SYNC 0x0002 /* Synchronous */ #define CHIPC_CFG_EM_PCMCIA 0x0004 /* PCMCIA */ #define CHIPC_CFG_EM_IDE 0x0006 /* IDE */ #define CHIPC_FLASH_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */ #define CHIPC_FLASH_CFG_CD_MASK 0x00e0 /* Sync: Clock divisor, rev >= 20 */ #define CHIPC_FLASH_CFG_CE 0x0100 /* Sync: Clock enable, rev >= 20 */ #define CHIPC_FLASH_CFG_SB 0x0200 /* Sync: Size/Bytestrobe, rev >= 20 */ #define CHIPC_FLASH_CFG_IS 0x0400 /* Extif Sync Clk Select, rev >= 20 */ /* ExtBus address space */ #define CHIPC_EB_BASE 0x1a000000 /* Chipc ExtBus base address */ #define CHIPC_EB_PCMCIA_MEM 0x1a000000 /* PCMCIA 0 memory base address */ #define CHIPC_EB_PCMCIA_IO 0x1a200000 /* PCMCIA 0 I/O base address */ #define CHIPC_EB_PCMCIA_CFG 0x1a400000 /* PCMCIA 0 config base address */ #define CHIPC_EB_IDE 0x1a800000 /* IDE memory base */ #define CHIPC_EB_PCMCIA1_MEM 0x1a800000 /* PCMCIA 1 memory base address */ #define CHIPC_EB_PCMCIA1_IO 0x1aa00000 /* PCMCIA 1 I/O base address */ #define CHIPC_EB_PCMCIA1_CFG 0x1ac00000 /* PCMCIA 1 config base address */ #define CHIPC_EB_PROGIF 0x1b000000 /* ProgIF Async/Sync base address */ /* Start/busy bit in flashcontrol */ #define CHIPC_SFLASH_OPCODE 0x000000ff #define CHIPC_SFLASH_ACTION 0x00000700 #define CHIPC_SFLASH_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */ #define CHIPC_SFLASH_START 0x80000000 #define CHIPC_SFLASH_BUSY SFLASH_START /* flashcontrol action codes */ #define CHIPC_SFLASH_ACT_OPONLY 0x0000 /* Issue opcode only */ #define CHIPC_SFLASH_ACT_OP1D 0x0100 /* opcode + 1 data byte */ #define CHIPC_SFLASH_ACT_OP3A 0x0200 /* opcode + 3 addr bytes */ #define CHIPC_SFLASH_ACT_OP3A1D 0x0300 /* opcode + 3 addr & 1 data bytes */ #define CHIPC_SFLASH_ACT_OP3A4D 0x0400 /* opcode + 3 addr & 4 data bytes */ #define CHIPC_SFLASH_ACT_OP3A4X4D 0x0500 /* opcode + 3 addr, 4 don't care & 4 data bytes */ #define CHIPC_SFLASH_ACT_OP3A1X4D 0x0700 /* opcode + 3 addr, 1 don't care & 4 data bytes */ /* flashcontrol action+opcodes for ST flashes */ #define CHIPC_SFLASH_ST_WREN 0x0006 /* Write Enable */ #define CHIPC_SFLASH_ST_WRDIS 0x0004 /* Write Disable */ #define CHIPC_SFLASH_ST_RDSR 0x0105 /* Read Status Register */ #define CHIPC_SFLASH_ST_WRSR 0x0101 /* Write Status Register */ #define CHIPC_SFLASH_ST_READ 0x0303 /* Read Data Bytes */ #define CHIPC_SFLASH_ST_PP 0x0302 /* Page Program */ #define CHIPC_SFLASH_ST_SE 0x02d8 /* Sector Erase */ #define CHIPC_SFLASH_ST_BE 0x00c7 /* Bulk Erase */ #define CHIPC_SFLASH_ST_DP 0x00b9 /* Deep Power-down */ #define CHIPC_SFLASH_ST_RES 0x03ab /* Read Electronic Signature */ #define CHIPC_SFLASH_ST_CSA 0x1000 /* Keep chip select asserted */ #define CHIPC_SFLASH_ST_SSE 0x0220 /* Sub-sector Erase */ /* Status register bits for ST flashes */ #define CHIPC_SFLASH_ST_WIP 0x01 /* Write In Progress */ #define CHIPC_SFLASH_ST_WEL 0x02 /* Write Enable Latch */ #define CHIPC_SFLASH_ST_BP_MASK 0x1c /* Block Protect */ #define CHIPC_SFLASH_ST_BP_SHIFT 2 #define CHIPC_SFLASH_ST_SRWD 0x80 /* Status Register Write Disable */ /* flashcontrol action+opcodes for Atmel flashes */ #define CHIPC_SFLASH_AT_READ 0x07e8 #define CHIPC_SFLASH_AT_PAGE_READ 0x07d2 #define CHIPC_SFLASH_AT_BUF1_READ #define CHIPC_SFLASH_AT_BUF2_READ #define CHIPC_SFLASH_AT_STATUS 0x01d7 #define CHIPC_SFLASH_AT_BUF1_WRITE 0x0384 #define CHIPC_SFLASH_AT_BUF2_WRITE 0x0387 #define CHIPC_SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283 #define CHIPC_SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286 #define CHIPC_SFLASH_AT_BUF1_PROGRAM 0x0288 #define CHIPC_SFLASH_AT_BUF2_PROGRAM 0x0289 #define CHIPC_SFLASH_AT_PAGE_ERASE 0x0281 #define CHIPC_SFLASH_AT_BLOCK_ERASE 0x0250 #define CHIPC_SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 #define CHIPC_SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 #define CHIPC_SFLASH_AT_BUF1_LOAD 0x0253 #define CHIPC_SFLASH_AT_BUF2_LOAD 0x0255 #define CHIPC_SFLASH_AT_BUF1_COMPARE 0x0260 #define CHIPC_SFLASH_AT_BUF2_COMPARE 0x0261 #define CHIPC_SFLASH_AT_BUF1_REPROGRAM 0x0258 #define CHIPC_SFLASH_AT_BUF2_REPROGRAM 0x0259 /* Status register bits for Atmel flashes */ #define CHIPC_SFLASH_AT_READY 0x80 #define CHIPC_SFLASH_AT_MISMATCH 0x40 #define CHIPC_SFLASH_AT_ID_MASK 0x38 #define CHIPC_SFLASH_AT_ID_SHIFT 3 /* * These are the UART port assignments, expressed as offsets from the base * register. These assignments should hold for any serial port based on * a 8250, 16450, or 16550(A). */ #define CHIPC_UART_RX 0 /* In: Receive buffer (DLAB=0) */ #define CHIPC_UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ #define CHIPC_UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ #define CHIPC_UART_IER 1 /* In/Out: Interrupt Enable Register (DLAB=0) */ #define CHIPC_UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */ #define CHIPC_UART_IIR 2 /* In: Interrupt Identity Register */ #define CHIPC_UART_FCR 2 /* Out: FIFO Control Register */ #define CHIPC_UART_LCR 3 /* Out: Line Control Register */ #define CHIPC_UART_MCR 4 /* Out: Modem Control Register */ #define CHIPC_UART_LSR 5 /* In: Line Status Register */ #define CHIPC_UART_MSR 6 /* In: Modem Status Register */ #define CHIPC_UART_SCR 7 /* I/O: Scratch Register */ #define CHIPC_UART_LCR_DLAB 0x80 /* Divisor latch access bit */ #define CHIPC_UART_LCR_WLEN8 0x03 /* Word length: 8 bits */ #define CHIPC_UART_MCR_OUT2 0x08 /* MCR GPIO out 2 */ #define CHIPC_UART_MCR_LOOP 0x10 /* Enable loopback test mode */ #define CHIPC_UART_LSR_RX_FIFO 0x80 /* Receive FIFO error */ #define CHIPC_UART_LSR_TDHR 0x40 /* Data-hold-register empty */ #define CHIPC_UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ #define CHIPC_UART_LSR_BREAK 0x10 /* Break interrupt */ #define CHIPC_UART_LSR_FRAMING 0x08 /* Framing error */ #define CHIPC_UART_LSR_PARITY 0x04 /* Parity error */ #define CHIPC_UART_LSR_OVERRUN 0x02 /* Overrun error */ #define CHIPC_UART_LSR_RXRDY 0x01 /* Receiver ready */ #define CHIPC_UART_FCR_FIFO_ENABLE 1 /* FIFO control register bit controlling FIFO enable/disable */ /* Interrupt Identity Register (IIR) bits */ #define CHIPC_UART_IIR_FIFO_MASK 0xc0 /* IIR FIFO disable/enabled mask */ #define CHIPC_UART_IIR_INT_MASK 0xf /* IIR interrupt ID source */ #define CHIPC_UART_IIR_MDM_CHG 0x0 /* Modem status changed */ #define CHIPC_UART_IIR_NOINT 0x1 /* No interrupt pending */ #define CHIPC_UART_IIR_THRE 0x2 /* THR empty */ #define CHIPC_UART_IIR_RCVD_DATA 0x4 /* Received data available */ #define CHIPC_UART_IIR_RCVR_STATUS 0x6 /* Receiver status */ #define CHIPC_UART_IIR_CHAR_TIME 0xc /* Character time */ /* Interrupt Enable Register (IER) bits */ #define CHIPC_UART_IER_EDSSI 8 /* enable modem status interrupt */ #define CHIPC_UART_IER_ELSI 4 /* enable receiver line status interrupt */ #define CHIPC_UART_IER_ETBEI 2 /* enable transmitter holding register empty interrupt */ #define CHIPC_UART_IER_ERBFI 1 /* enable data available interrupt */ /* 4325 chip-specific ChipStatus register bits */ #define CHIPC_CST4325_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK #define CHIPC_CST4325_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT #define CHIPC_CST4325_SDIO_USB_MODE_MASK 0x00000004 #define CHIPC_CST4325_SDIO_USB_MODE_SHIFT 2 #define CHIPC_CST4325_RCAL_VALID_MASK 0x00000008 #define CHIPC_CST4325_RCAL_VALID_SHIFT 3 #define CHIPC_CST4325_RCAL_VALUE_MASK 0x000001f0 #define CHIPC_CST4325_RCAL_VALUE_SHIFT 4 #define CHIPC_CST4325_PMUTOP_2B_MASK 0x00000200 /* 1 for 2b, 0 for to 2a */ #define CHIPC_CST4325_PMUTOP_2B_SHIFT 9 /* 4329 chip-specific ChipStatus register bits */ #define CHIPC_CST4329_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK #define CHIPC_CST4329_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT #define CHIPC_CST4329_SPI_SDIO_MODE_MASK 0x00000004 #define CHIPC_CST4329_SPI_SDIO_MODE_SHIFT 2 /* 4312 chip-specific ChipStatus register bits */ #define CHIPC_CST4312_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK #define CHIPC_CST4312_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT /* 4322 chip-specific ChipStatus register bits */ #define CHIPC_CST4322_XTAL_FREQ_20_40MHZ 0x00000020 #define CHIPC_CST4322_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R23_MASK #define CHIPC_CST4322_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R23_SHIFT #define CHIPC_CST4322_PCI_OR_USB 0x00000100 #define CHIPC_CST4322_BOOT_MASK 0x00000600 #define CHIPC_CST4322_BOOT_SHIFT 9 #define CHIPC_CST4322_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ #define CHIPC_CST4322_BOOT_FROM_ROM 1 /* boot from ROM */ #define CHIPC_CST4322_BOOT_FROM_FLASH 2 /* boot from FLASH */ #define CHIPC_CST4322_BOOT_FROM_INVALID 3 #define CHIPC_CST4322_ILP_DIV_EN 0x00000800 #define CHIPC_CST4322_FLASH_TYPE_MASK 0x00001000 #define CHIPC_CST4322_FLASH_TYPE_SHIFT 12 #define CHIPC_CST4322_FLASH_TYPE_SHIFT_ST 0 /* ST serial FLASH */ #define CHIPC_CST4322_FLASH_TYPE_SHIFT_ATMEL 1 /* ATMEL flash */ #define CHIPC_CST4322_ARM_TAP_SEL 0x00002000 #define CHIPC_CST4322_RES_INIT_MODE_MASK 0x0000c000 #define CHIPC_CST4322_RES_INIT_MODE_SHIFT 14 #define CHIPC_CST4322_RES_INIT_MODE_ILPAVAIL 0 /* resinitmode: ILP available */ #define CHIPC_CST4322_RES_INIT_MODE_ILPREQ 1 /* resinitmode: ILP request */ #define CHIPC_CST4322_RES_INIT_MODE_ALPAVAIL 2 /* resinitmode: ALP available */ #define CHIPC_CST4322_RES_INIT_MODE_HTAVAIL 3 /* resinitmode: HT available */ #define CHIPC_CST4322_PCIPLLCLK_GATING 0x00010000 #define CHIPC_CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000 #define CHIPC_CST4322_PCI_CARDBUS_MODE 0x00040000 /* 43236 Chip specific ChipStatus register bits */ #define CHIPC_CST43236_SFLASH_MASK 0x00000040 #define CHIPC_CST43236_OTP_SEL_MASK 0x00000080 #define CHIPC_CST43236_OTP_SEL_SHIFT 7 #define CHIPC_CST43236_HSIC_MASK 0x00000100 /* USB/HSIC */ #define CHIPC_CST43236_BP_CLK 0x00000200 /* 120/96Mbps */ #define CHIPC_CST43236_BOOT_MASK 0x00001800 #define CHIPC_CST43236_BOOT_SHIFT 11 #define CHIPC_CST43236_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ #define CHIPC_CST43236_BOOT_FROM_ROM 1 /* boot from ROM */ #define CHIPC_CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */ #define CHIPC_CST43236_BOOT_FROM_INVALID 3 /* 43237 Chip specific ChipStatus register bits */ #define CHIPC_CST43237_BP_CLK 0x00000200 /* 96/80Mbps */ /* 4331 Chip specific ChipStatus register bits */ #define CHIPC_CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */ #define CHIPC_CST4331_SPROM_PRESENT 0x00000002 #define CHIPC_CST4331_OTP_PRESENT 0x00000004 #define CHIPC_CST4331_LDO_RF 0x00000008 #define CHIPC_CST4331_LDO_PAR 0x00000010 /* 4331 chip-specific CHIPCTRL register bits */ #define CHIPC_CCTRL4331_BT_COEXIST (1<<0) /* 0 disable */ #define CHIPC_CCTRL4331_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ #define CHIPC_CCTRL4331_EXT_LNA (1<<2) /* 0 disable */ #define CHIPC_CCTRL4331_SPROM_GPIO13_15 (1<<3) /* sprom/gpio13-15 mux */ #define CHIPC_CCTRL4331_EXTPA_EN (1<<4) /* 0 ext pa disable, 1 ext pa enabled */ #define CHIPC_CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) /* set drive out GPIO_CLK on sprom_cs pin */ #define CHIPC_CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) /* use sprom_cs pin as PCIE mdio interface */ #define CHIPC_CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) /* aband extpa will be at gpio2/5 and sprom_dout */ #define CHIPC_CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) /* override core control on pipe_AuxClkEnable */ #define CHIPC_CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) /* override core control on pipe_AuxPowerDown */ #define CHIPC_CCTRL4331_PCIE_AUXCLKEN (1<<10) /* pcie_auxclkenable */ #define CHIPC_CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) /* pcie_pipe_pllpowerdown */ #define CHIPC_CCTRL4331_EXTPA_EN2 (1<<12) /* 0 ext pa2 disable, 1 ext pa2 enabled */ #define CHIPC_CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) /* enable bt_shd0 at gpio4 */ #define CHIPC_CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) /* enable bt_shd1 at gpio5 */ /* 4315 chip-specific ChipStatus register bits */ #define CHIPC_CST4315_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK #define CHIPC_CST4315_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT #define CHIPC_CST4315_SDIO_MODE 0x00000004 /* gpio [8], sdio/usb mode */ #define CHIPC_CST4315_RCAL_VALID 0x00000008 #define CHIPC_CST4315_RCAL_VALUE_MASK 0x000001f0 #define CHIPC_CST4315_RCAL_VALUE_SHIFT 4 #define CHIPC_CST4315_PALDO_EXTPNP 0x00000200 /* PALDO is configured with external PNP */ #define CHIPC_CST4315_CBUCK_MODE_MASK 0x00000c00 #define CHIPC_CST4315_CBUCK_MODE_BURST 0x00000400 #define CHIPC_CST4315_CBUCK_MODE_LPBURST 0x00000c00 /* 4319 chip-specific ChipStatus register bits */ #define CHIPC_CST4319_SPI_CPULESSUSB 0x00000001 #define CHIPC_CST4319_SPI_CLK_POL 0x00000002 #define CHIPC_CST4319_SPI_CLK_PH 0x00000008 #define CHIPC_CST4319_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R23_MASK /* gpio [7:6], SDIO CIS selection */ #define CHIPC_CST4319_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R23_SHIFT #define CHIPC_CST4319_SDIO_USB_MODE 0x00000100 /* gpio [8], sdio/usb mode */ #define CHIPC_CST4319_REMAP_SEL_MASK 0x00000600 #define CHIPC_CST4319_ILPDIV_EN 0x00000800 #define CHIPC_CST4319_XTAL_PD_POL 0x00001000 #define CHIPC_CST4319_LPO_SEL 0x00002000 #define CHIPC_CST4319_RES_INIT_MODE 0x0000c000 #define CHIPC_CST4319_PALDO_EXTPNP 0x00010000 /* PALDO is configured with external PNP */ #define CHIPC_CST4319_CBUCK_MODE_MASK 0x00060000 #define CHIPC_CST4319_CBUCK_MODE_BURST 0x00020000 #define CHIPC_CST4319_CBUCK_MODE_LPBURST 0x00060000 #define CHIPC_CST4319_RCAL_VALID 0x01000000 #define CHIPC_CST4319_RCAL_VALUE_MASK 0x3e000000 #define CHIPC_CST4319_RCAL_VALUE_SHIFT 25 /* 4336 chip-specific ChipStatus register bits */ #define CHIPC_CST4336_SPI_MODE_MASK 0x00000001 #define CHIPC_CST4336_SPROM_PRESENT 0x00000002 #define CHIPC_CST4336_OTP_PRESENT 0x00000004 #define CHIPC_CST4336_ARMREMAP_0 0x00000008 #define CHIPC_CST4336_ILPDIV_EN_MASK 0x00000010 #define CHIPC_CST4336_ILPDIV_EN_SHIFT 4 #define CHIPC_CST4336_XTAL_PD_POL_MASK 0x00000020 #define CHIPC_CST4336_XTAL_PD_POL_SHIFT 5 #define CHIPC_CST4336_LPO_SEL_MASK 0x00000040 #define CHIPC_CST4336_LPO_SEL_SHIFT 6 #define CHIPC_CST4336_RES_INIT_MODE_MASK 0x00000180 #define CHIPC_CST4336_RES_INIT_MODE_SHIFT 7 #define CHIPC_CST4336_CBUCK_MODE_MASK 0x00000600 #define CHIPC_CST4336_CBUCK_MODE_SHIFT 9 /* 4330 chip-specific ChipStatus register bits */ #define CHIPC_CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) /* SDIO || gSPI */ #define CHIPC_CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) /* USB || USBDA */ #define CHIPC_CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0) /* SDIO */ #define CHIPC_CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4) /* gSPI */ #define CHIPC_CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6) /* USB packet-oriented */ #define CHIPC_CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7) /* USB Direct Access */ #define CHIPC_CST4330_OTP_PRESENT 0x00000010 #define CHIPC_CST4330_LPO_AUTODET_EN 0x00000020 #define CHIPC_CST4330_ARMREMAP_0 0x00000040 #define CHIPC_CST4330_SPROM_PRESENT 0x00000080 /* takes priority over OTP if both set */ #define CHIPC_CST4330_ILPDIV_EN 0x00000100 #define CHIPC_CST4330_LPO_SEL 0x00000200 #define CHIPC_CST4330_RES_INIT_MODE_SHIFT 10 #define CHIPC_CST4330_RES_INIT_MODE_MASK 0x00000c00 #define CHIPC_CST4330_CBUCK_MODE_SHIFT 12 #define CHIPC_CST4330_CBUCK_MODE_MASK 0x00003000 #define CHIPC_CST4330_CBUCK_POWER_OK 0x00004000 #define CHIPC_CST4330_BB_PLL_LOCKED 0x00008000 #define CHIPC_SOCDEVRAM_4330_BP_ADDR 0x1E000000 #define CHIPC_SOCDEVRAM_4330_ARM_ADDR 0x00800000 /* 4313 chip-specific ChipStatus register bits */ #define CHIPC_CST4313_SPROM_PRESENT 1 #define CHIPC_CST4313_OTP_PRESENT 2 #define CHIPC_CST4313_SPROM_OTP_SEL_MASK 0x00000002 #define CHIPC_CST4313_SPROM_OTP_SEL_SHIFT 0 /* 43228 chipstatus reg bits */ #define CHIPC_CST43228_ILP_DIV_EN 0x1 #define CHIPC_CST43228_OTP_PRESENT 0x2 #define CHIPC_CST43228_SERDES_REFCLK_PADSEL 0x4 #define CHIPC_CST43228_SDIO_MODE 0x8 #define CHIPC_CST43228_SDIO_OTP_PRESENT 0x10 #define CHIPC_CST43228_SDIO_RESET 0x20 /* * Register eci_inputlo bitfield values. * - BT packet type information bits [7:0] */ /* [3:0] - Task (link) type */ #define CHIPC_BT_ACL 0x00 #define CHIPC_BT_SCO 0x01 #define CHIPC_BT_eSCO 0x02 #define CHIPC_BT_A2DP 0x03 #define CHIPC_BT_SNIFF 0x04 #define CHIPC_BT_PAGE_SCAN 0x05 #define CHIPC_BT_INQUIRY_SCAN 0x06 #define CHIPC_BT_PAGE 0x07 #define CHIPC_BT_INQUIRY 0x08 #define CHIPC_BT_MSS 0x09 #define CHIPC_BT_PARK 0x0a #define CHIPC_BT_RSSISCAN 0x0b #define CHIPC_BT_MD_ACL 0x0c #define CHIPC_BT_MD_eSCO 0x0d #define CHIPC_BT_SCAN_WITH_SCO_LINK 0x0e #define CHIPC_BT_SCAN_WITHOUT_SCO_LINK 0x0f /* [7:4] = packet duration code */ /* [8] - Master / Slave */ #define CHIPC_BT_MASTER 0 #define CHIPC_BT_SLAVE 1 /* [11:9] - multi-level priority */ #define CHIPC_BT_LOWEST_PRIO 0x0 #define CHIPC_BT_HIGHEST_PRIO 0x3 #endif /* _BHND_CORES_CHIPC_CHIPCREG_H_ */ Index: head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c (revision 304870) +++ head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctl_subr.c (revision 304871) @@ -1,463 +1,558 @@ /*- * Copyright (c) 2016 Landon Fuller * Copyright (c) 2010, Broadcom Corporation. * All rights reserved. * * This file is derived from the siutils.c source distributed with the * Asus RT-N16 firmware source code release. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: siutils.c,v 1.821.2.48 2011-02-11 20:59:28 Exp $ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bhnd_chipc_if.h" #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 * field value (CHIPC_F6_*). */ static uint32_t bhnd_pwrctl_factor6(uint32_t x) { switch (x) { case CHIPC_F6_2: return (2); case CHIPC_F6_3: return (3); case CHIPC_F6_4: return (4); case CHIPC_F6_5: return (5); case CHIPC_F6_6: return (6); case CHIPC_F6_7: return (7); default: return (0); } } /** + * 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; uint32_t n1, n2, clock, m1, m2, m3, mc; n1 = CHIPC_GET_BITS(n, CHIPC_CN_N1); n2 = CHIPC_GET_BITS(n, CHIPC_CN_N2); switch (pll_type) { case CHIPC_PLL_TYPE1: case CHIPC_PLL_TYPE3: case CHIPC_PLL_TYPE4: case CHIPC_PLL_TYPE7: n1 = bhnd_pwrctl_factor6(n1); n2 += CHIPC_F5_BIAS; break; case CHIPC_PLL_TYPE2: n1 += CHIPC_T2_BIAS; n2 += CHIPC_T2_BIAS; KASSERT(n1 >= 2 && n1 <= 7, ("invalid n1 value")); KASSERT(n2 >= 5 && n2 <= 23, ("invalid n2 value")); break; case CHIPC_PLL_TYPE5: return (100000000); case CHIPC_PLL_TYPE6: if (m & CHIPC_T6_MMASK) return (CHIPC_T6_M1); else return (CHIPC_T6_M0); default: printf("unsupported PLL type %u\n", pll_type); return (0); } /* PLL types 3 and 7 use BASE2 (25Mhz) */ if (pll_type == CHIPC_PLL_TYPE3 || pll_type == CHIPC_PLL_TYPE7) { clk_base = CHIPC_CLOCK_BASE2; } else { clk_base = CHIPC_CLOCK_BASE1; } clock = clk_base * n1 * n2; if (clock == 0) return (0); m1 = CHIPC_GET_BITS(m, CHIPC_M1); m2 = CHIPC_GET_BITS(m, CHIPC_M2); m3 = CHIPC_GET_BITS(m, CHIPC_M3); mc = CHIPC_GET_BITS(m, CHIPC_MC); switch (pll_type) { case CHIPC_PLL_TYPE1: case CHIPC_PLL_TYPE3: case CHIPC_PLL_TYPE4: case CHIPC_PLL_TYPE7: m1 = bhnd_pwrctl_factor6(m1); if (pll_type == CHIPC_PLL_TYPE1 || pll_type == CHIPC_PLL_TYPE3) m2 += CHIPC_F5_BIAS; else m2 = bhnd_pwrctl_factor6(m2); m3 = bhnd_pwrctl_factor6(m3); switch (mc) { case CHIPC_MC_BYPASS: return (clock); case CHIPC_MC_M1: return (clock / m1); case CHIPC_MC_M1M2: return (clock / (m1 * m2)); case CHIPC_MC_M1M2M3: return (clock / (m1 * m2 * m3)); case CHIPC_MC_M1M3: return (clock / (m1 * m3)); default: printf("unsupported pwrctl mc %#x\n", mc); return (0); } case CHIPC_PLL_TYPE2: m1 += CHIPC_T2_BIAS; m2 += CHIPC_T2M2_BIAS; m3 += CHIPC_T2_BIAS; KASSERT(m1 >= 2 && m1 <= 7, ("invalid m1 value")); KASSERT(m2 >= 3 && m2 <= 10, ("invalid m2 value")); KASSERT(m3 >= 2 && m3 <= 7, ("invalid m3 value")); if ((mc & CHIPC_T2MC_M1BYP) == 0) clock /= m1; if ((mc & CHIPC_T2MC_M2BYP) == 0) clock /= m2; if ((mc & CHIPC_T2MC_M3BYP) == 0) clock /= m3; return (clock); default: panic("unhandled PLL type %u\n", pll_type); } } /** * Return the backplane clock speed in Hz. * * @param sc driver instance state. */ 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; - } + /* Get M register offset */ + creg = bhnd_pwrctl_si_clkreg_m(cid, ccaps->pll_type, &rate); + if (creg == 0) /* fixed rate */ + return (rate); - m = bhnd_bus_read_4(sc->res, creg); - /* 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 */ static bhnd_clksrc bhnd_pwrctl_slowclk_src(struct bhnd_pwrctl_softc *sc) { uint32_t clkreg; uint32_t clksrc; /* Fetch clock source */ if (PWRCTL_QUIRK(sc, PCICLK_CTL)) { return (bhnd_pwrctl_get_clksrc(sc->chipc_dev, BHND_CLOCK_ILP)); } else if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) { clkreg = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL); clksrc = clkreg & CHIPC_SCC_SS_MASK; } else { /* Instaclock */ clksrc = CHIPC_SCC_SS_XTAL; } /* Map to bhnd_clksrc */ switch (clksrc) { case CHIPC_SCC_SS_PCI: return (BHND_CLKSRC_PCI); case CHIPC_SCC_SS_LPO: return (BHND_CLKSRC_LPO); case CHIPC_SCC_SS_XTAL: return (BHND_CLKSRC_XTAL); default: return (BHND_CLKSRC_UNKNOWN); } } /* return the ILP (slowclock) min or max frequency */ static uint32_t bhnd_pwrctl_slowclk_freq(struct bhnd_pwrctl_softc *sc, bool max_freq) { bhnd_clksrc slowclk; uint32_t div; uint32_t hz; slowclk = bhnd_pwrctl_slowclk_src(sc); /* Determine clock divisor */ if (PWRCTL_QUIRK(sc, PCICLK_CTL)) { if (slowclk == BHND_CLKSRC_PCI) div = 64; else div = 32; } else if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) { div = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL); div = CHIPC_GET_BITS(div, CHIPC_SCC_CD); div *= 4; } else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) { if (max_freq) { div = 1; } else { div = bhnd_bus_read_4(sc->res, CHIPC_SYS_CLK_CTL); div = CHIPC_GET_BITS(div, CHIPC_SYCC_CD); div = 4 * (div + 1); } } else { device_printf(sc->dev, "unknown device type\n"); return (0); } /* Determine clock frequency */ switch (slowclk) { case BHND_CLKSRC_LPO: hz = max_freq ? CHIPC_LPOMAXFREQ : CHIPC_LPOMINFREQ; break; case BHND_CLKSRC_XTAL: hz = max_freq ? CHIPC_XTALMAXFREQ : CHIPC_XTALMINFREQ; break; case BHND_CLKSRC_PCI: hz = max_freq ? CHIPC_PCIMAXFREQ : CHIPC_PCIMINFREQ; break; default: device_printf(sc->dev, "unknown slowclk source %#x\n", slowclk); return (0); } return (hz / div); } /** * Initialize power control registers. */ int bhnd_pwrctl_init(struct bhnd_pwrctl_softc *sc) { uint32_t clkctl; uint32_t pll_delay, slowclk, slowmaxfreq; uint32_t pll_on_delay, fref_sel_delay; int error; pll_delay = CHIPC_PLL_DELAY; /* set all Instaclk chip ILP to 1 MHz */ if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) { clkctl = (CHIPC_ILP_DIV_1MHZ << CHIPC_SYCC_CD_SHIFT); clkctl &= CHIPC_SYCC_CD_MASK; bhnd_bus_write_4(sc->res, CHIPC_SYS_CLK_CTL, clkctl); } /* * Initialize PLL/FREF delays. * * If the slow clock is not sourced by the xtal, include the * delay required to bring it up. */ slowclk = bhnd_pwrctl_slowclk_src(sc); if (slowclk != CHIPC_SCC_SS_XTAL) pll_delay += CHIPC_XTAL_ON_DELAY; /* Starting with 4318 it is ILP that is used for the delays */ if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) slowmaxfreq = bhnd_pwrctl_slowclk_freq(sc, false); else slowmaxfreq = bhnd_pwrctl_slowclk_freq(sc, true); pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; fref_sel_delay = ((slowmaxfreq * CHIPC_FREF_DELAY) + 999999) / 1000000; bhnd_bus_write_4(sc->res, CHIPC_PLL_ON_DELAY, pll_on_delay); bhnd_bus_write_4(sc->res, CHIPC_PLL_FREFSEL_DELAY, fref_sel_delay); /* If required, force HT */ if (PWRCTL_QUIRK(sc, FORCE_HT)) { if ((error = bhnd_pwrctl_setclk(sc, BHND_CLOCK_HT))) return (error); } return (0); } /* return the value suitable for writing to the dot11 core * FAST_PWRUP_DELAY register */ uint16_t bhnd_pwrctl_fast_pwrup_delay(struct bhnd_pwrctl_softc *sc) { uint32_t pll_on_delay, slowminfreq; uint16_t fpdelay; fpdelay = 0; slowminfreq = bhnd_pwrctl_slowclk_freq(sc, false); pll_on_delay = bhnd_bus_read_4(sc->res, CHIPC_PLL_ON_DELAY) + 2; pll_on_delay *= 1000000; pll_on_delay += (slowminfreq - 1); fpdelay = pll_on_delay / slowminfreq; return (fpdelay); } /** * Distribute @p clock on backplane. * * @param sc Driver instance state. * @param clock Clock to enable. * * @retval 0 success * @retval ENODEV If @p clock is unsupported, or if the device does not * support dynamic clock control. */ int bhnd_pwrctl_setclk(struct bhnd_pwrctl_softc *sc, bhnd_clock clock) { uint32_t scc; PWRCTL_LOCK_ASSERT(sc, MA_OWNED); /* Is dynamic clock control supported? */ if (PWRCTL_QUIRK(sc, FIXED_CLK)) return (ENODEV); /* Chips with ccrev 10 are EOL and they don't have SYCC_HR used below */ if (bhnd_get_hwrev(sc->chipc_dev) == 10) return (ENODEV); scc = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL); switch (clock) { case BHND_CLOCK_HT: /* fast (pll) clock */ if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) { scc &= ~(CHIPC_SCC_XC | CHIPC_SCC_FS | CHIPC_SCC_IP); scc |= CHIPC_SCC_IP; /* force xtal back on before clearing SCC_DYN_XTAL.. */ bhnd_pwrctl_ungate_clock(sc->chipc_dev, BHND_CLOCK_HT); } else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) { scc |= CHIPC_SYCC_HR; } else { return (ENODEV); } bhnd_bus_write_4(sc->res, CHIPC_PLL_SLOWCLK_CTL, scc); DELAY(CHIPC_PLL_DELAY); break; case BHND_CLOCK_DYN: /* enable dynamic clock control */ if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) { scc &= ~(CHIPC_SCC_FS | CHIPC_SCC_IP | CHIPC_SCC_XC); if ((scc & CHIPC_SCC_SS_MASK) != CHIPC_SCC_SS_XTAL) scc |= CHIPC_SCC_XC; bhnd_bus_write_4(sc->res, CHIPC_PLL_SLOWCLK_CTL, scc); /* for dynamic control, we have to release our xtal_pu * "force on" */ if (scc & CHIPC_SCC_XC) { bhnd_pwrctl_gate_clock(sc->chipc_dev, BHND_CLOCK_HT); } } else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) { /* Instaclock */ scc &= ~CHIPC_SYCC_HR; bhnd_bus_write_4(sc->res, CHIPC_SYS_CLK_CTL, scc); } else { return (ENODEV); } break; default: return (ENODEV); } return (0); } Index: head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h (revision 304870) +++ head/sys/dev/bhnd/cores/chipc/pwrctl/bhnd_pwrctlvar.h (revision 304871) @@ -1,120 +1,135 @@ /*- * Copyright (c) 2015-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, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. * * $FreeBSD$ */ #ifndef _BHND_PWRCTL_BHND_PWRCTLVAR_H_ #define _BHND_PWRCTL_BHND_PWRCTLVAR_H_ #include #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. */ enum { /** No quirks */ PWRCTL_QUIRK_NONE = 0, /** * Early ChipCommon revisions do not support dynamic clock control */ PWRCTL_QUIRK_FIXED_CLK = (1 << 0), /** * On PCI (not PCIe) devices, early ChipCommon revisions * (rev <= 5) vend xtal/pll and clock config registers via the PCI * config space. * * Dynamic clock control is not supported on these devices. */ PWRCTL_QUIRK_PCICLK_CTL = (1 << 1) | PWRCTL_QUIRK_FIXED_CLK, /** * On earliy BCM4311, BCM4321, and BCM4716 PCI(e) devices, no ALP * clock is available, and the HT clock must be enabled. */ PWRCTL_QUIRK_FORCE_HT = (1 << 2), /** * ChipCommon revisions 6-9 use the slowclk register layout. */ PWRCTL_QUIRK_SLOWCLK_CTL = (1 << 3), /** * ChipCommon revisions 10-19 support the instaclk register layout. */ PWRCTL_QUIRK_INSTACLK_CTL = (1 << 4), }; /** * device clock reservation. */ struct bhnd_pwrctl_clkres { device_t owner; /**< bhnd(4) device holding this reservation */ bhnd_clock clock; /**< requested clock */ STAILQ_ENTRY(bhnd_pwrctl_clkres) cr_link; }; /** * bhnd pwrctl driver instance state. */ struct bhnd_pwrctl_softc { device_t dev; uint32_t quirks; device_t chipc_dev; /**< core device */ struct bhnd_resource *res; /**< core register block. */ struct mtx mtx; /**< state mutex */ /** active clock reservations */ STAILQ_HEAD(, bhnd_pwrctl_clkres) clkres_list; }; #define PWRCTL_LOCK_INIT(sc) \ mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \ "bhnd pwrctl driver lock", MTX_DEF) #define PWRCTL_LOCK(sc) mtx_lock(&(sc)->mtx) #define PWRCTL_UNLOCK(sc) mtx_unlock(&(sc)->mtx) #define PWRCTL_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what) #define PWRCTL_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx) /* quirk convenience macro */ #define PWRCTL_QUIRK(_sc, _name) \ ((_sc)->quirks & PWRCTL_QUIRK_ ## _name) #define PWRCTL_ASSERT_QUIRK(_sc, name) \ KASSERT(PWRCTL_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set")) #endif /* _BHND_PWRCTL_BHND_PWRCTLVAR_H_ */ Index: head/sys/dev/bhnd/cores/pmu/bhnd_pmu.c =================================================================== --- head/sys/dev/bhnd/cores/pmu/bhnd_pmu.c (revision 304870) +++ head/sys/dev/bhnd/cores/pmu/bhnd_pmu.c (revision 304871) @@ -1,466 +1,508 @@ /*- * Copyright (c) 2015-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, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include +#include #include "bhnd_nvram_map.h" #include "bhnd_pmureg.h" #include "bhnd_pmuvar.h" #include "bhnd_pmu_private.h" /* * Broadcom PMU driver. * * On modern BHND chipsets, the PMU, GCI, and SRENG (Save/Restore Engine?) * register blocks are found within a dedicated PMU core (attached via * the AHB 'always on bus'). * * On earlier chipsets, these register blocks are found at the same * offsets within the ChipCommon core. */ devclass_t bhnd_pmu_devclass; /**< bhnd(4) PMU device class */ 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) #define BPMU_CLKCTL_WRITE_4(_pinfo, _val) \ bhnd_bus_write_4((_pinfo)->pm_res, (_pinfo)->pm_regs, (_val)) #define BPMU_CLKCTL_SET_4(_pinfo, _val, _mask) \ BPMU_CLKCTL_WRITE_4((_pinfo), \ ((_val) & (_mask)) | (BPMU_CLKCTL_READ_4(_pinfo) & ~(_mask))) /** * Default bhnd_pmu driver implementation of DEVICE_PROBE(). */ int bhnd_pmu_probe(device_t dev) { return (BUS_PROBE_DEFAULT); } /** * Default bhnd_pmu driver implementation of DEVICE_ATTACH(). * * @param dev PMU device. * @param res The PMU device registers. The driver will maintain a borrowed * reference to this resource for the lifetime of the device. */ int bhnd_pmu_attach(device_t dev, struct bhnd_resource *res) { struct bhnd_pmu_softc *sc; struct sysctl_ctx_list *ctx; struct sysctl_oid *tree; devclass_t bhnd_class; device_t core, bus; int error; sc = device_get_softc(dev); sc->dev = dev; sc->quirks = 0; sc->res = res; /* Fetch capability flags */ sc->caps = bhnd_bus_read_4(sc->res, BHND_PMU_CAP); /* Find the bus-attached core */ bhnd_class = devclass_find("bhnd"); core = sc->dev; while ((bus = device_get_parent(core)) != NULL) { if (device_get_devclass(bus) == bhnd_class) break; core = bus; } if (core == NULL) { device_printf(sc->dev, "bhnd bus not found\n"); return (ENXIO); } /* Fetch chip and board info */ sc->cid = *bhnd_get_chipid(core); if ((error = bhnd_read_board_info(core, &sc->board))) { device_printf(sc->dev, "error fetching board info: %d\n", error); return (ENXIO); } /* Locate ChipCommon device */ sc->chipc_dev = bhnd_find_child(bus, BHND_DEVCLASS_CC, 0); if (sc->chipc_dev == NULL) { device_printf(sc->dev, "chipcommon device not found\n"); 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 */ switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4328: case BHND_CHIPID_BCM5354: /* HTAVAIL/ALPAVAIL are bitswapped in CLKCTL */ sc->quirks |= BPMU_QUIRK_CLKCTL_CCS0; break; default: break; } /* Initialize PMU */ if ((error = bhnd_pmu_init(sc))) { device_printf(sc->dev, "PMU init failed: %d\n", error); goto failed; } /* Set up sysctl nodes */ ctx = device_get_sysctl_ctx(dev); tree = device_get_sysctl_tree(dev); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "bus_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0, bhnd_pmu_sysctl_bus_freq, "IU", "Bus clock frequency"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "cpu_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0, bhnd_pmu_sysctl_cpu_freq, "IU", "CPU clock frequency"); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "mem_freq", CTLTYPE_UINT | CTLFLAG_RD, sc, 0, bhnd_pmu_sysctl_mem_freq, "IU", "Memory clock frequency"); return (0); failed: BPMU_LOCK_DESTROY(sc); + bhnd_pmu_query_fini(&sc->query); return (error); } /** * Default bhnd_pmu driver implementation of DEVICE_DETACH(). */ int bhnd_pmu_detach(device_t dev) { struct bhnd_pmu_softc *sc; sc = device_get_softc(dev); BPMU_LOCK_DESTROY(sc); + bhnd_pmu_query_fini(&sc->query); return (0); } /** * Default bhnd_pmu driver implementation of DEVICE_SUSPEND(). */ int bhnd_pmu_suspend(device_t dev) { return (0); } /** * Default bhnd_pmu driver implementation of DEVICE_RESUME(). */ int bhnd_pmu_resume(device_t dev) { struct bhnd_pmu_softc *sc; int error; sc = device_get_softc(dev); /* Re-initialize PMU */ if ((error = bhnd_pmu_init(sc))) { device_printf(sc->dev, "PMU init failed: %d\n", error); return (error); } return (0); } static int bhnd_pmu_sysctl_bus_freq(SYSCTL_HANDLER_ARGS) { struct bhnd_pmu_softc *sc; uint32_t freq; 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)); } static int bhnd_pmu_sysctl_cpu_freq(SYSCTL_HANDLER_ARGS) { struct bhnd_pmu_softc *sc; uint32_t freq; 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)); } static int bhnd_pmu_sysctl_mem_freq(SYSCTL_HANDLER_ARGS) { struct bhnd_pmu_softc *sc; uint32_t freq; 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)); } static int bhnd_pmu_core_req_clock(device_t dev, struct bhnd_core_pmu_info *pinfo, bhnd_clock clock) { struct bhnd_pmu_softc *sc; uint32_t avail; uint32_t req; sc = device_get_softc(dev); avail = 0x0; req = 0x0; switch (clock) { case BHND_CLOCK_DYN: break; case BHND_CLOCK_ILP: req |= BHND_CCS_FORCEILP; break; case BHND_CLOCK_ALP: req |= BHND_CCS_FORCEALP; avail |= BHND_CCS_ALPAVAIL; break; case BHND_CLOCK_HT: req |= BHND_CCS_FORCEHT; avail |= BHND_CCS_HTAVAIL; break; default: device_printf(dev, "%s requested unknown clock: %#x\n", device_get_nameunit(pinfo->pm_dev), clock); return (ENODEV); } BPMU_LOCK(sc); /* Issue request */ BPMU_CLKCTL_SET_4(pinfo, req, BHND_CCS_FORCE_MASK); /* Wait for clock availability */ bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs, avail, avail); BPMU_UNLOCK(sc); return (0); } static int bhnd_pmu_core_en_clocks(device_t dev, struct bhnd_core_pmu_info *pinfo, uint32_t clocks) { struct bhnd_pmu_softc *sc; uint32_t avail; uint32_t req; sc = device_get_softc(dev); avail = 0x0; req = 0x0; /* Build clock request flags */ if (clocks & BHND_CLOCK_DYN) /* nothing to enable */ clocks &= ~BHND_CLOCK_DYN; if (clocks & BHND_CLOCK_ILP) /* nothing to enable */ clocks &= ~BHND_CLOCK_ILP; if (clocks & BHND_CLOCK_ALP) { req |= BHND_CCS_ALPAREQ; avail |= BHND_CCS_ALPAVAIL; clocks &= ~BHND_CLOCK_ALP; } if (clocks & BHND_CLOCK_HT) { req |= BHND_CCS_HTAREQ; avail |= BHND_CCS_HTAVAIL; clocks &= ~BHND_CLOCK_HT; } /* Check for unknown clock values */ if (clocks != 0x0) { device_printf(dev, "%s requested unknown clocks: %#x\n", device_get_nameunit(pinfo->pm_dev), clocks); return (ENODEV); } BPMU_LOCK(sc); /* Issue request */ BPMU_CLKCTL_SET_4(pinfo, req, BHND_CCS_AREQ_MASK); /* Wait for clock availability */ bhnd_pmu_wait_clkst(sc, pinfo->pm_dev, pinfo->pm_res, pinfo->pm_regs, avail, avail); BPMU_UNLOCK(sc); return (0); } static int bhnd_pmu_core_req_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo, u_int rsrc) { struct bhnd_pmu_softc *sc; uint32_t req; uint32_t avail; sc = device_get_softc(dev); if (rsrc > BHND_CCS_ERSRC_MAX) return (EINVAL); req = BHND_PMU_SET_BITS((1<pm_dev, pinfo->pm_res, pinfo->pm_regs, avail, avail); BPMU_UNLOCK(sc); return (0); } static int bhnd_pmu_core_release_ext_rsrc(device_t dev, struct bhnd_core_pmu_info *pinfo, u_int rsrc) { struct bhnd_pmu_softc *sc; uint32_t mask; sc = device_get_softc(dev); if (rsrc > BHND_CCS_ERSRC_MAX) return (EINVAL); mask = BHND_PMU_SET_BITS((1<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), DEVMETHOD(device_detach, bhnd_pmu_detach), DEVMETHOD(device_suspend, bhnd_pmu_suspend), DEVMETHOD(device_resume, bhnd_pmu_resume), /* BHND PMU interface */ DEVMETHOD(bhnd_pmu_core_req_clock, bhnd_pmu_core_req_clock), DEVMETHOD(bhnd_pmu_core_en_clocks, bhnd_pmu_core_en_clocks), DEVMETHOD(bhnd_pmu_core_req_ext_rsrc, bhnd_pmu_core_req_ext_rsrc), DEVMETHOD(bhnd_pmu_core_release_ext_rsrc, bhnd_pmu_core_release_ext_rsrc), DEVMETHOD(bhnd_pmu_core_release, bhnd_pmu_core_release), DEVMETHOD_END }; DEFINE_CLASS_0(bhnd_pmu, bhnd_pmu_driver, bhnd_pmu_methods, sizeof(struct bhnd_pmu_softc)); MODULE_VERSION(bhnd_pmu, 1); Index: head/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h =================================================================== --- head/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h (revision 304870) +++ head/sys/dev/bhnd/cores/pmu/bhnd_pmu_private.h (revision 304871) @@ -1,147 +1,138 @@ /*- * Copyright (c) 2016 Landon Fuller * Copyright (C) 2010, Broadcom Corporation. * All rights reserved. * * This file is derived from the hndpmu.h header contributed by Broadcom * to to the Linux staging repository, as well as later revisions of hndpmu.h * distributed with the Asus RT-N16 firmware source code release. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #ifndef _BHND_CORES_PMU_BHND_PMU_PRIVATE_H_ #define _BHND_CORES_PMU_BHND_PMU_PRIVATE_H_ #include #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), \ BHND_PMU_READ_4((_sc), (_reg)) & (_val)) #define BHND_PMU_OR_4(_sc, _reg, _val) \ BHND_PMU_WRITE_4((_sc), (_reg), \ BHND_PMU_READ_4((_sc), (_reg)) | (_val)) /* 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 */ #define BHND_PMU_CCTRL_READ(_sc, _reg) \ BHND_PMU_IND_READ((_sc), CHIPCTL, (_reg)) #define BHND_PMU_CCTRL_WRITE(_sc, _reg, _val, _mask) \ BHND_PMU_IND_WRITE((_sc), CHIPCTL, (_reg), (_val), (_mask)) /* Register Control indirect registers */ #define BHND_PMU_REGCTRL_READ(_sc, _reg) \ BHND_PMU_IND_READ((_sc), REG_CONTROL, (_reg)) #define BHND_PMU_REGCTRL_WRITE(_sc, _reg, _val, _mask) \ BHND_PMU_IND_WRITE((_sc), REG_CONTROL, (_reg), (_val), (_mask)) /* PLL Control indirect registers */ #define BHND_PMU_PLL_READ(_sc, _reg) \ BHND_PMU_IND_READ((_sc), PLL_CONTROL, (_reg)) #define BHND_PMU_PLL_WRITE(_sc, _reg, _val, _mask) \ BHND_PMU_IND_WRITE((_sc), PLL_CONTROL, (_reg), (_val), (_mask)) /** FVCO frequencies, in Hz */ enum { FVCO_880 = 880 * 1000, /**< 880MHz */ FVCO_1760 = 1760 * 1000, /**< 1760MHz */ FVCO_1440 = 1440 * 1000, /**< 1440MHz */ FVCO_960 = 960 * 1000, /**< 960MHz */ }; /** LDO voltage tunables */ enum { SET_LDO_VOLTAGE_LDO1 = 1, SET_LDO_VOLTAGE_LDO2 = 2, SET_LDO_VOLTAGE_LDO3 = 3, SET_LDO_VOLTAGE_PAREF = 4, SET_LDO_VOLTAGE_CLDO_PWM = 5, SET_LDO_VOLTAGE_CLDO_BURST = 6, SET_LDO_VOLTAGE_CBUCK_PWM = 7, SET_LDO_VOLTAGE_CBUCK_BURST = 8, SET_LDO_VOLTAGE_LNLDO1 = 9, 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, uint32_t value, uint32_t mask); int bhnd_pmu_init(struct bhnd_pmu_softc *sc); void bhnd_pmu_pll_init(struct bhnd_pmu_softc *sc, uint32_t xtalfreq); int bhnd_pmu_res_init(struct bhnd_pmu_softc *sc); 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, uint8_t ldo, uint8_t voltage); int bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, uint16_t *pwrup_delay); void bhnd_pmu_rcal(struct bhnd_pmu_softc *sc); void bhnd_pmu_spuravoid(struct bhnd_pmu_softc *sc, uint8_t spuravoid); bool bhnd_pmu_is_otp_powered(struct bhnd_pmu_softc *sc); uint32_t bhnd_pmu_measure_alpclk(struct bhnd_pmu_softc *sc); void bhnd_pmu_radio_enable(struct bhnd_pmu_softc *sc, device_t d11core, bool enable); uint32_t bhnd_pmu_waitforclk_on_backplane(struct bhnd_pmu_softc *sc, uint32_t clk, uint32_t delay); int bhnd_pmu_otp_power(struct bhnd_pmu_softc *sc, bool on); void bhnd_pmu_sdiod_drive_strength_init(struct bhnd_pmu_softc *sc, uint32_t drivestrength); void bhnd_pmu_paref_ldo_enable(struct bhnd_pmu_softc *sc, bool enable); #endif /* _BHND_CORES_PMU_BHND_PMU_PRIVATE_H_ */ Index: head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c =================================================================== --- head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c (revision 304870) +++ head/sys/dev/bhnd/cores/pmu/bhnd_pmu_subr.c (revision 304871) @@ -1,3446 +1,3508 @@ /*- * Copyright (c) 2016 Landon Fuller * Copyright (C) 2010, Broadcom Corporation. * All rights reserved. * * This file is derived from the hndpmu.c source contributed by Broadcom * to to the Linux staging repository, as well as later revisions of hndpmu.c * distributed with the Asus RT-N16 firmware source code release. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "bhnd_nvram_map.h" #include "bhnd_pmureg.h" #include "bhnd_pmuvar.h" #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); static bool bhnd_pmu_res_depfltr_ncb(struct bhnd_pmu_softc *sc); static bool bhnd_pmu_res_depfltr_paldo(struct bhnd_pmu_softc *sc); static bool bhnd_pmu_res_depfltr_npaldo(struct bhnd_pmu_softc *sc); static uint32_t bhnd_pmu_res_deps(struct bhnd_pmu_softc *sc, uint32_t rsrcs, bool all); static int bhnd_pmu_res_uptime(struct bhnd_pmu_softc *sc, uint8_t rsrc, uint32_t *uptime); static int bhnd_pmu_res_masks(struct bhnd_pmu_softc *sc, uint32_t *pmin, uint32_t *pmax); static void bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid); static void bhnd_pmu_set_4330_plldivs(struct bhnd_pmu_softc *sc); #define BHND_PMU_REV(_sc) \ ((uint8_t)BHND_PMU_GET_BITS((_sc)->caps, BHND_PMU_CAP_REV)) #define PMU_WAIT_CLKST(_sc, _val, _mask) \ bhnd_pmu_wait_clkst((_sc), (_sc)->dev, (_sc)->res, \ BHND_CLK_CTL_ST, (_val), (_mask)) #define PMURES_BIT(_bit) \ (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. * * @param addr Offset of the address register. * @param data Offset of the data register. * @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)); } /** * Perform an indirect register write. * * @param addr Offset of the address register. * @param data Offset of the data register. * @param reg Indirect register to be written. * @param val Value to be written to @p reg. * @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); } /** * Wait for up to BHND_PMU_MAX_TRANSITION_DLY microseconds for the per-core * clock status to be equal to @p value after applying @p mask. * * @param sc PMU driver state. * @param dev Requesting device. * @param r An active resource mapping the clock status register. * @param clkst_reg Offset to the CLK_CTL_ST register. * @param value Value to wait for. * @param mask Mask to apply prior to value comparison. */ bool bhnd_pmu_wait_clkst(struct bhnd_pmu_softc *sc, device_t dev, struct bhnd_resource *r, bus_size_t clkst_reg, uint32_t value, uint32_t mask) { uint32_t clkst; /* Bitswapped HTAVAIL/ALPAVAIL work-around */ if (sc->quirks & BPMU_QUIRK_CLKCTL_CCS0) { uint32_t fmask, fval; fmask = mask & ~(BHND_CCS_HTAVAIL | BHND_CCS_ALPAVAIL); fval = value & ~(BHND_CCS_HTAVAIL | BHND_CCS_ALPAVAIL); if (mask & BHND_CCS_HTAVAIL) fmask |= BHND_CCS0_HTAVAIL; if (value & BHND_CCS_HTAVAIL) fval |= BHND_CCS0_HTAVAIL; if (mask & BHND_CCS_ALPAVAIL) fmask |= BHND_CCS0_ALPAVAIL; if (value & BHND_CCS_ALPAVAIL) fval |= BHND_CCS0_ALPAVAIL; mask = fmask; value = fval; } for (uint32_t i = 0; i < BHND_PMU_MAX_TRANSITION_DLY; i += 10) { clkst = bhnd_bus_read_4(r, clkst_reg); if ((clkst & mask) == (value & mask)) return (true); DELAY(10); } device_printf(dev, "clkst wait timeout (value=%#x, " "mask=%#x)\n", value, mask); return (false); } /* Setup switcher voltage */ void bhnd_pmu_set_switcher_voltage(struct bhnd_pmu_softc *sc, uint8_t bb_voltage, uint8_t rf_voltage) { BHND_PMU_REGCTRL_WRITE(sc, 0x01, (bb_voltage & 0x1f) << 22, ~0); BHND_PMU_REGCTRL_WRITE(sc, 0x00, (rf_voltage & 0x1f) << 14, ~0); } void bhnd_pmu_set_ldo_voltage(struct bhnd_pmu_softc *sc, uint8_t ldo, uint8_t voltage) { uint32_t chipst; uint32_t regctrl; uint8_t shift; uint8_t mask; uint8_t addr; switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4328: case BHND_CHIPID_BCM5354: switch (ldo) { case SET_LDO_VOLTAGE_LDO1: addr = 2; shift = 17 + 8; mask = 0xf; break; case SET_LDO_VOLTAGE_LDO2: addr = 3; shift = 1; mask = 0xf; break; case SET_LDO_VOLTAGE_LDO3: addr = 3; shift = 9; mask = 0xf; break; case SET_LDO_VOLTAGE_PAREF: addr = 3; shift = 17; mask = 0x3f; break; default: panic("unknown BCM4328/BCM5354 LDO %hhu\n", ldo); } break; case BHND_CHIPID_BCM4312: switch (ldo) { case SET_LDO_VOLTAGE_PAREF: addr = 0; shift = 21; mask = 0x3f; break; default: panic("unknown BCM4312 LDO %hhu\n", ldo); } break; case BHND_CHIPID_BCM4325: switch (ldo) { case SET_LDO_VOLTAGE_CLDO_PWM: addr = 5; shift = 9; mask = 0xf; break; case SET_LDO_VOLTAGE_CLDO_BURST: addr = 5; shift = 13; mask = 0xf; break; case SET_LDO_VOLTAGE_CBUCK_PWM: addr = 3; shift = 20; mask = 0x1f; /* Bit 116 & 119 are inverted in CLB for opt 2b */ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev); if (BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_PMUTOP_2B)) voltage ^= 0x9; break; case SET_LDO_VOLTAGE_CBUCK_BURST: addr = 3; shift = 25; mask = 0x1f; /* Bit 121 & 124 are inverted in CLB for opt 2b */ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev); if (BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_PMUTOP_2B)) voltage ^= 0x9; break; case SET_LDO_VOLTAGE_LNLDO1: addr = 5; shift = 17; mask = 0x1f; break; case SET_LDO_VOLTAGE_LNLDO2_SEL: addr = 6; shift = 0; mask = 0x1; break; default: panic("unknown BCM4325 LDO %hhu\n", ldo); } break; case BHND_CHIPID_BCM4336: switch (ldo) { case SET_LDO_VOLTAGE_CLDO_PWM: addr = 4; shift = 1; mask = 0xf; break; case SET_LDO_VOLTAGE_CLDO_BURST: addr = 4; shift = 5; mask = 0xf; break; case SET_LDO_VOLTAGE_LNLDO1: addr = 4; shift = 17; mask = 0xf; break; default: panic("unknown BCM4336 LDO %hhu\n", ldo); } break; case BHND_CHIPID_BCM4330: switch (ldo) { case SET_LDO_VOLTAGE_CBUCK_PWM: addr = 3; shift = 0; mask = 0x1f; break; default: panic("unknown BCM4330 LDO %hhu\n", ldo); } break; case BHND_CHIPID_BCM4331: switch (ldo) { case SET_LDO_VOLTAGE_PAREF: addr = 1; shift = 0; mask = 0xf; break; default: panic("unknown BCM4331 LDO %hhu\n", ldo); } break; default: panic("cannot set LDO voltage on unsupported chip %hu\n", sc->cid.chip_id); return; } regctrl = (voltage & mask) << shift; BHND_PMU_REGCTRL_WRITE(sc, addr, regctrl, mask << shift); } /* d11 slow to fast clock transition time in slow clock cycles */ #define D11SCC_SLOW2FAST_TRANSITION 2 int bhnd_pmu_fast_pwrup_delay(struct bhnd_pmu_softc *sc, uint16_t *pwrup_delay) { uint32_t ilp; uint32_t uptime; u_int delay; int error; switch (sc->cid.chip_id) { case BHND_CHIPID_BCM43224: case BHND_CHIPID_BCM43225: case BHND_CHIPID_BCM43421: case BHND_CHIPID_BCM43235: case BHND_CHIPID_BCM43236: case BHND_CHIPID_BCM43238: case BHND_CHIPID_BCM4331: case BHND_CHIPID_BCM6362: case BHND_CHIPID_BCM4313: delay = 3700; break; case BHND_CHIPID_BCM4325: error = bhnd_pmu_res_uptime(sc, BHND_PMU_RES4325_HT_AVAIL, &uptime); 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; break; case BHND_CHIPID_BCM4329: error = bhnd_pmu_res_uptime(sc, BHND_PMU_RES4329_HT_AVAIL, &uptime); 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; break; case BHND_CHIPID_BCM4319: delay = 3700; break; case BHND_CHIPID_BCM4336: error = bhnd_pmu_res_uptime(sc, BHND_PMU_RES4336_HT_AVAIL, &uptime); 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; break; case BHND_CHIPID_BCM4330: error = bhnd_pmu_res_uptime(sc, BHND_PMU_RES4330_HT_AVAIL, &uptime); 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; break; default: delay = BHND_PMU_MAX_TRANSITION_DLY; break; } *pwrup_delay = (uint16_t)delay; return (0); } uint32_t bhnd_pmu_force_ilp(struct bhnd_pmu_softc *sc, bool force) { uint32_t orig; uint32_t pctrl; pctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL); orig = pctrl; if (force) pctrl &= ~(BHND_PMU_CTRL_HT_REQ_EN | BHND_PMU_CTRL_ALP_REQ_EN); else pctrl |= (BHND_PMU_CTRL_HT_REQ_EN | BHND_PMU_CTRL_ALP_REQ_EN); BHND_PMU_WRITE_4(sc, BHND_PMU_CTRL, pctrl); return (orig); } /* Setup resource up/down timers */ typedef struct { uint8_t resnum; uint16_t updown; } pmu_res_updown_t; typedef bool (*pmu_res_filter) (struct bhnd_pmu_softc *sc); /* Change resource dependencies masks */ typedef struct { uint32_t res_mask; /* resources (chip specific) */ int8_t action; /* action */ uint32_t depend_mask; /* changes to the dependencies mask */ pmu_res_filter filter; /* action is taken when filter is NULL or returns true */ } pmu_res_depend_t; /* Resource dependencies mask change action */ #define RES_DEPEND_SET 0 /* Override the dependencies mask */ #define RES_DEPEND_ADD 1 /* Add to the dependencies mask */ #define RES_DEPEND_REMOVE -1 /* Remove from the dependencies mask */ static const pmu_res_updown_t bcm4328a0_res_updown[] = { { BHND_PMU_RES4328_EXT_SWITCHER_PWM, 0x0101}, { BHND_PMU_RES4328_BB_SWITCHER_PWM, 0x1f01}, { BHND_PMU_RES4328_BB_SWITCHER_BURST, 0x010f}, { BHND_PMU_RES4328_BB_EXT_SWITCHER_BURST, 0x0101}, { BHND_PMU_RES4328_ILP_REQUEST, 0x0202}, { BHND_PMU_RES4328_RADIO_SWITCHER_PWM, 0x0f01}, { BHND_PMU_RES4328_RADIO_SWITCHER_BURST, 0x0f01}, { BHND_PMU_RES4328_ROM_SWITCH, 0x0101}, { BHND_PMU_RES4328_PA_REF_LDO, 0x0f01}, { BHND_PMU_RES4328_RADIO_LDO, 0x0f01}, { BHND_PMU_RES4328_AFE_LDO, 0x0f01}, { BHND_PMU_RES4328_PLL_LDO, 0x0f01}, { BHND_PMU_RES4328_BG_FILTBYP, 0x0101}, { BHND_PMU_RES4328_TX_FILTBYP, 0x0101}, { BHND_PMU_RES4328_RX_FILTBYP, 0x0101}, { BHND_PMU_RES4328_XTAL_PU, 0x0101}, { BHND_PMU_RES4328_XTAL_EN, 0xa001}, { BHND_PMU_RES4328_BB_PLL_FILTBYP, 0x0101}, { BHND_PMU_RES4328_RF_PLL_FILTBYP, 0x0101}, { BHND_PMU_RES4328_BB_PLL_PU, 0x0701} }; static const pmu_res_depend_t bcm4328a0_res_depend[] = { /* Adjust ILP request resource not to force ext/BB switchers into burst mode */ { PMURES_BIT(RES4328_ILP_REQUEST), RES_DEPEND_SET, PMURES_BIT(RES4328_EXT_SWITCHER_PWM) | PMURES_BIT(RES4328_BB_SWITCHER_PWM), NULL} }; static const pmu_res_updown_t bcm4325a0_res_updown[] = { { BHND_PMU_RES4325_XTAL_PU, 0x1501} }; static const pmu_res_depend_t bcm4325a0_res_depend[] = { /* Adjust OTP PU resource dependencies - remove BB BURST */ { PMURES_BIT(RES4325_OTP_PU), RES_DEPEND_REMOVE, PMURES_BIT(RES4325_BUCK_BOOST_BURST), NULL}, /* Adjust ALP/HT Avail resource dependencies - bring up BB along if it is used. */ { PMURES_BIT(RES4325_ALP_AVAIL) | PMURES_BIT(RES4325_HT_AVAIL), RES_DEPEND_ADD, PMURES_BIT(RES4325_BUCK_BOOST_BURST) | PMURES_BIT(RES4325_BUCK_BOOST_PWM), bhnd_pmu_res_depfltr_bb}, /* Adjust HT Avail resource dependencies - bring up RF switches along with HT. */ { PMURES_BIT(RES4325_HT_AVAIL), RES_DEPEND_ADD, PMURES_BIT(RES4325_RX_PWRSW_PU) | PMURES_BIT(RES4325_TX_PWRSW_PU) | PMURES_BIT(RES4325_LOGEN_PWRSW_PU) | PMURES_BIT(RES4325_AFE_PWRSW_PU), NULL}, /* Adjust ALL resource dependencies - remove CBUCK dependencies if it is not used. */ { PMURES_BIT(RES4325_ILP_REQUEST) | PMURES_BIT(RES4325_ABUCK_BURST) | PMURES_BIT(RES4325_ABUCK_PWM) | PMURES_BIT(RES4325_LNLDO1_PU) | PMURES_BIT(RES4325C1_LNLDO2_PU) | PMURES_BIT(RES4325_XTAL_PU) | PMURES_BIT(RES4325_ALP_AVAIL) | PMURES_BIT(RES4325_RX_PWRSW_PU) | PMURES_BIT(RES4325_TX_PWRSW_PU) | PMURES_BIT(RES4325_RFPLL_PWRSW_PU) | PMURES_BIT(RES4325_LOGEN_PWRSW_PU) | PMURES_BIT(RES4325_AFE_PWRSW_PU) | PMURES_BIT(RES4325_BBPLL_PWRSW_PU) | PMURES_BIT(RES4325_HT_AVAIL), RES_DEPEND_REMOVE, PMURES_BIT(RES4325B0_CBUCK_LPOM) | PMURES_BIT(RES4325B0_CBUCK_BURST) | PMURES_BIT(RES4325B0_CBUCK_PWM), bhnd_pmu_res_depfltr_ncb} }; static const pmu_res_updown_t bcm4315a0_res_updown[] = { { BHND_PMU_RES4315_XTAL_PU, 0x2501} }; static const pmu_res_depend_t bcm4315a0_res_depend[] = { /* Adjust OTP PU resource dependencies - not need PALDO unless write */ { PMURES_BIT(RES4315_OTP_PU), RES_DEPEND_REMOVE, PMURES_BIT(RES4315_PALDO_PU), bhnd_pmu_res_depfltr_npaldo}, /* Adjust ALP/HT Avail resource dependencies - bring up PALDO along if it is used. */ { PMURES_BIT(RES4315_ALP_AVAIL) | PMURES_BIT(RES4315_HT_AVAIL), RES_DEPEND_ADD, PMURES_BIT(RES4315_PALDO_PU), bhnd_pmu_res_depfltr_paldo}, /* Adjust HT Avail resource dependencies - bring up RF switches along with HT. */ { PMURES_BIT(RES4315_HT_AVAIL), RES_DEPEND_ADD, PMURES_BIT(RES4315_RX_PWRSW_PU) | PMURES_BIT(RES4315_TX_PWRSW_PU) | PMURES_BIT(RES4315_LOGEN_PWRSW_PU) | PMURES_BIT(RES4315_AFE_PWRSW_PU), NULL}, /* Adjust ALL resource dependencies - remove CBUCK dependencies if it is not used. */ { PMURES_BIT(RES4315_CLDO_PU) | PMURES_BIT(RES4315_ILP_REQUEST) | PMURES_BIT(RES4315_LNLDO1_PU) | PMURES_BIT(RES4315_OTP_PU) | PMURES_BIT(RES4315_LNLDO2_PU) | PMURES_BIT(RES4315_XTAL_PU) | PMURES_BIT(RES4315_ALP_AVAIL) | PMURES_BIT(RES4315_RX_PWRSW_PU) | PMURES_BIT(RES4315_TX_PWRSW_PU) | PMURES_BIT(RES4315_RFPLL_PWRSW_PU) | PMURES_BIT(RES4315_LOGEN_PWRSW_PU) | PMURES_BIT(RES4315_AFE_PWRSW_PU) | PMURES_BIT(RES4315_BBPLL_PWRSW_PU) | PMURES_BIT(RES4315_HT_AVAIL), RES_DEPEND_REMOVE, PMURES_BIT(RES4315_CBUCK_LPOM) | PMURES_BIT(RES4315_CBUCK_BURST) | PMURES_BIT(RES4315_CBUCK_PWM), bhnd_pmu_res_depfltr_ncb} }; /* 4329 specific. needs to come back this issue later */ static const pmu_res_updown_t bcm4329_res_updown[] = { { BHND_PMU_RES4329_XTAL_PU, 0x1501} }; static const pmu_res_depend_t bcm4329_res_depend[] = { /* Adjust HT Avail resource dependencies */ { PMURES_BIT(RES4329_HT_AVAIL), RES_DEPEND_ADD, PMURES_BIT(RES4329_CBUCK_LPOM) | PMURES_BIT(RES4329_CBUCK_BURST) | PMURES_BIT(RES4329_CBUCK_PWM) | PMURES_BIT(RES4329_CLDO_PU) | PMURES_BIT(RES4329_PALDO_PU) | PMURES_BIT(RES4329_LNLDO1_PU) | PMURES_BIT(RES4329_XTAL_PU) | PMURES_BIT(RES4329_ALP_AVAIL) | PMURES_BIT(RES4329_RX_PWRSW_PU) | PMURES_BIT(RES4329_TX_PWRSW_PU) | PMURES_BIT(RES4329_RFPLL_PWRSW_PU) | PMURES_BIT(RES4329_LOGEN_PWRSW_PU) | PMURES_BIT(RES4329_AFE_PWRSW_PU) | PMURES_BIT(RES4329_BBPLL_PWRSW_PU), NULL} }; static const pmu_res_updown_t bcm4319a0_res_updown[] = { { BHND_PMU_RES4319_XTAL_PU, 0x3f01} }; static const pmu_res_depend_t bcm4319a0_res_depend[] = { /* Adjust OTP PU resource dependencies - not need PALDO unless write */ { PMURES_BIT(RES4319_OTP_PU), RES_DEPEND_REMOVE, PMURES_BIT(RES4319_PALDO_PU), bhnd_pmu_res_depfltr_npaldo}, /* Adjust HT Avail resource dependencies - bring up PALDO along if it is used. */ { PMURES_BIT(RES4319_HT_AVAIL), RES_DEPEND_ADD, PMURES_BIT(RES4319_PALDO_PU), bhnd_pmu_res_depfltr_paldo}, /* Adjust HT Avail resource dependencies - bring up RF switches along with HT. */ { PMURES_BIT(RES4319_HT_AVAIL), RES_DEPEND_ADD, PMURES_BIT(RES4319_RX_PWRSW_PU) | PMURES_BIT(RES4319_TX_PWRSW_PU) | PMURES_BIT(RES4319_RFPLL_PWRSW_PU) | PMURES_BIT(RES4319_LOGEN_PWRSW_PU) | PMURES_BIT(RES4319_AFE_PWRSW_PU), NULL} }; static const pmu_res_updown_t bcm4336a0_res_updown[] = { { BHND_PMU_RES4336_HT_AVAIL, 0x0D01} }; static const pmu_res_depend_t bcm4336a0_res_depend[] = { /* Just a dummy entry for now */ { PMURES_BIT(RES4336_RSVD), RES_DEPEND_ADD, 0, NULL} }; static const pmu_res_updown_t bcm4330a0_res_updown[] = { { BHND_PMU_RES4330_HT_AVAIL, 0x0e02} }; static const pmu_res_depend_t bcm4330a0_res_depend[] = { /* Just a dummy entry for now */ { PMURES_BIT(RES4330_HT_AVAIL), RES_DEPEND_ADD, 0, NULL} }; /* true if the power topology uses the buck boost to provide 3.3V to VDDIO_RF * and WLAN PA */ static bool bhnd_pmu_res_depfltr_bb(struct bhnd_pmu_softc *sc) { return (BHND_PMU_GET_FLAG(sc->board.board_flags, BHND_BFL_BUCKBOOST)); } /* true if the power topology doesn't use the cbuck. Key on chiprev also if * the chip is BCM4325. */ static bool bhnd_pmu_res_depfltr_ncb(struct bhnd_pmu_softc *sc) { if (sc->cid.chip_id == BHND_CHIPID_BCM4325 && sc->cid.chip_rev <= 1) return (false); return (BHND_PMU_GET_FLAG(sc->board.board_flags, BHND_BFL_NOCBUCK)); } /* true if the power topology uses the PALDO */ static bool bhnd_pmu_res_depfltr_paldo(struct bhnd_pmu_softc *sc) { return (BHND_PMU_GET_FLAG(sc->board.board_flags, BHND_BFL_PALDO)); } /* true if the power topology doesn't use the PALDO */ static bool bhnd_pmu_res_depfltr_npaldo(struct bhnd_pmu_softc *sc) { return (!BHND_PMU_GET_FLAG(sc->board.board_flags, BHND_BFL_PALDO)); } /* Determine min/max rsrc masks. Value 0 leaves hardware at default. */ static int bhnd_pmu_res_masks(struct bhnd_pmu_softc *sc, uint32_t *pmin, uint32_t *pmax) { uint32_t max_mask, min_mask; uint32_t chipst, otpsel; uint32_t nval; uint8_t rsrcs; int error; max_mask = 0; min_mask = 0; /* # resources */ rsrcs = BHND_PMU_GET_BITS(sc->caps, BHND_PMU_CAP_RC); /* determine min/max rsrc masks */ switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4325: /* If used by this device, enable the CBUCK */ if (!bhnd_pmu_res_depfltr_ncb(sc)) min_mask |= PMURES_BIT(RES4325B0_CBUCK_LPOM); chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev); if (BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_PMUTOP_2B)) min_mask |= PMURES_BIT(RES4325B0_CLDO_PU); /* Is OTP required? */ otpsel = BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_SPROM_OTP_SEL); if (otpsel != CHIPC_CST_OTP_PWRDN) min_mask |= PMURES_BIT(RES4325_OTP_PU); /* Leave buck boost on in burst mode for certain boards */ if (sc->board.board_flags & BHND_BFL_BUCKBOOST) { switch (sc->board.board_type) { case BHND_BOARD_BCM94325DEVBU: case BHND_BOARD_BCM94325BGABU: min_mask |= PMURES_BIT( RES4325_BUCK_BOOST_BURST); break; } } /* Allow all resources to be turned on upon requests */ max_mask = ~(~0 << rsrcs); break; case BHND_CHIPID_BCM4312: /* default min_mask = 0x80000cbb is wrong */ min_mask = 0xcbb; /* * max_mask = 0x7fff; * pmu_res_updown_table_sz = 0; * pmu_res_depend_table_sz = 0; */ break; case BHND_CHIPID_BCM4322: case BHND_CHIPID_BCM43221: case BHND_CHIPID_BCM43231: case BHND_CHIPID_BCM4342: if (sc->cid.chip_rev >= 2) break; /* request ALP(can skip for A1) */ min_mask = PMURES_BIT(RES4322_RF_LDO) | PMURES_BIT(RES4322_XTAL_PU) | PMURES_BIT(RES4322_ALP_AVAIL); if (bhnd_get_attach_type(sc->chipc_dev) == BHND_ATTACH_NATIVE) { min_mask |= PMURES_BIT(RES4322_SI_PLL_ON) | PMURES_BIT(RES4322_HT_SI_AVAIL) | PMURES_BIT(RES4322_PHY_PLL_ON) | PMURES_BIT(RES4322_OTP_PU) | PMURES_BIT(RES4322_HT_PHY_AVAIL); max_mask = 0x1ff; } break; case BHND_CHIPID_BCM43222: case BHND_CHIPID_BCM43111: case BHND_CHIPID_BCM43112: case BHND_CHIPID_BCM43224: case BHND_CHIPID_BCM43225: case BHND_CHIPID_BCM43421: case BHND_CHIPID_BCM43226: case BHND_CHIPID_BCM43420: case BHND_CHIPID_BCM43235: case BHND_CHIPID_BCM43236: case BHND_CHIPID_BCM43238: case BHND_CHIPID_BCM43234: case BHND_CHIPID_BCM43237: case BHND_CHIPID_BCM4331: case BHND_CHIPID_BCM43431: case BHND_CHIPID_BCM6362: /* use chip default */ break; case BHND_CHIPID_BCM4328: min_mask = PMURES_BIT(RES4328_BB_SWITCHER_PWM) | PMURES_BIT(RES4328_EXT_SWITCHER_PWM) | PMURES_BIT(RES4328_XTAL_EN); max_mask = 0xfffffff; break; case BHND_CHIPID_BCM5354: /* Allow (but don't require) PLL to turn on */ max_mask = 0xfffffff; break; case BHND_CHIPID_BCM4329: /* Down to save the power. */ if (sc->cid.chip_rev >= 0x2) { min_mask = PMURES_BIT(RES4329_CBUCK_LPOM) | PMURES_BIT(RES4329_LNLDO1_PU) | PMURES_BIT(RES4329_CLDO_PU); } else { min_mask = PMURES_BIT(RES4329_CBUCK_LPOM) | PMURES_BIT(RES4329_CLDO_PU); } /* Is OTP required? */ chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev); otpsel = BHND_PMU_GET_BITS(chipst, CHIPC_CST4329_SPROM_OTP_SEL); if (otpsel != CHIPC_CST_OTP_PWRDN) min_mask |= PMURES_BIT(RES4329_OTP_PU); /* Allow (but don't require) PLL to turn on */ max_mask = 0x3ff63e; break; case BHND_CHIPID_BCM4319: /* We only need a few resources to be kept on all the time */ min_mask = PMURES_BIT(RES4319_CBUCK_LPOM) | PMURES_BIT(RES4319_CLDO_PU); /* Allow everything else to be turned on upon requests */ max_mask = ~(~0 << rsrcs); break; case BHND_CHIPID_BCM4336: /* Down to save the power. */ min_mask = PMURES_BIT(RES4336_CBUCK_LPOM) | PMURES_BIT(RES4336_CLDO_PU) | PMURES_BIT(RES4336_LDO3P3_PU) | PMURES_BIT(RES4336_OTP_PU) | PMURES_BIT(RES4336_DIS_INT_RESET_PD); /* Allow (but don't require) PLL to turn on */ max_mask = 0x1ffffff; break; case BHND_CHIPID_BCM4330: /* Down to save the power. */ min_mask = PMURES_BIT(RES4330_CBUCK_LPOM) | PMURES_BIT(RES4330_CLDO_PU) | PMURES_BIT(RES4330_DIS_INT_RESET_PD) | PMURES_BIT(RES4330_LDO3P3_PU) | PMURES_BIT(RES4330_OTP_PU); /* Allow (but don't require) PLL to turn on */ max_mask = 0xfffffff; break; case BHND_CHIPID_BCM4313: min_mask = PMURES_BIT(RES4313_BB_PU_RSRC) | PMURES_BIT(RES4313_XTAL_PU_RSRC) | PMURES_BIT(RES4313_ALP_AVAIL_RSRC) | PMURES_BIT(RES4313_BB_PLL_PWRSW_RSRC); max_mask = 0xffff; break; default: break; } /* 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; } if (pmin != NULL) *pmin = min_mask; if (pmax != NULL) *pmax = max_mask; return (0); } /* initialize PMU resources */ int bhnd_pmu_res_init(struct bhnd_pmu_softc *sc) { const pmu_res_updown_t *pmu_res_updown_table; const pmu_res_depend_t *pmu_res_depend_table; size_t pmu_res_updown_table_sz; size_t pmu_res_depend_table_sz; uint32_t max_mask, min_mask; uint8_t rsrcs; int error; pmu_res_depend_table = NULL; pmu_res_depend_table_sz = 0; pmu_res_updown_table = NULL; pmu_res_updown_table_sz = 0; switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4315: /* Optimize resources up/down timers */ pmu_res_updown_table = bcm4315a0_res_updown; pmu_res_updown_table_sz = nitems(bcm4315a0_res_updown); /* Optimize resources dependencies */ pmu_res_depend_table = bcm4315a0_res_depend; pmu_res_depend_table_sz = nitems(bcm4315a0_res_depend); break; case BHND_CHIPID_BCM4325: /* Optimize resources up/down timers */ pmu_res_updown_table = bcm4325a0_res_updown; pmu_res_updown_table_sz = nitems(bcm4325a0_res_updown); /* Optimize resources dependencies */ pmu_res_depend_table = bcm4325a0_res_depend; pmu_res_depend_table_sz = nitems(bcm4325a0_res_depend); break; case BHND_CHIPID_BCM4328: /* Optimize resources up/down timers */ pmu_res_updown_table = bcm4328a0_res_updown; pmu_res_updown_table_sz = nitems(bcm4328a0_res_updown); /* Optimize resources dependencies */ pmu_res_depend_table = bcm4328a0_res_depend; pmu_res_depend_table_sz = nitems(bcm4328a0_res_depend); break; case BHND_CHIPID_BCM4329: /* Optimize resources up/down timers */ pmu_res_updown_table = bcm4329_res_updown; pmu_res_updown_table_sz = nitems(bcm4329_res_updown); /* Optimize resources dependencies */ pmu_res_depend_table = bcm4329_res_depend; pmu_res_depend_table_sz = nitems(bcm4329_res_depend); break; case BHND_CHIPID_BCM4319: /* Optimize resources up/down timers */ pmu_res_updown_table = bcm4319a0_res_updown; pmu_res_updown_table_sz = nitems(bcm4319a0_res_updown); /* Optimize resources dependencies masks */ pmu_res_depend_table = bcm4319a0_res_depend; pmu_res_depend_table_sz = nitems(bcm4319a0_res_depend); break; case BHND_CHIPID_BCM4336: /* Optimize resources up/down timers */ pmu_res_updown_table = bcm4336a0_res_updown; pmu_res_updown_table_sz = nitems(bcm4336a0_res_updown); /* Optimize resources dependencies masks */ pmu_res_depend_table = bcm4336a0_res_depend; pmu_res_depend_table_sz = nitems(bcm4336a0_res_depend); break; case BHND_CHIPID_BCM4330: /* Optimize resources up/down timers */ pmu_res_updown_table = bcm4330a0_res_updown; pmu_res_updown_table_sz = nitems(bcm4330a0_res_updown); /* Optimize resources dependencies masks */ pmu_res_depend_table = bcm4330a0_res_depend; pmu_res_depend_table_sz = nitems(bcm4330a0_res_depend); break; default: break; } /* # resources */ rsrcs = BHND_PMU_GET_BITS(sc->caps, BHND_PMU_CAP_RC); /* Program up/down timers */ for (size_t i = 0; i < pmu_res_updown_table_sz; i++) { const pmu_res_updown_t *updt; KASSERT(pmu_res_updown_table != NULL, ("no updown tables")); 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); } /* Apply nvram overrides to up/down timers */ for (uint8_t i = 0; i < rsrcs; i++) { char name[6]; uint32_t val; snprintf(name, sizeof(name), "r%dt", i); error = bhnd_nvram_getvar_uint32(sc->chipc_dev, name, &val); 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); } /* Program resource dependencies table */ for (size_t i = 0; i < pmu_res_depend_table_sz; i++) { const pmu_res_depend_t *rdep; pmu_res_filter filter; uint32_t depend_mask; KASSERT(pmu_res_depend_table != NULL, ("no depend tables")); rdep = &pmu_res_depend_table[pmu_res_depend_table_sz - i - 1]; filter = rdep->filter; if (filter != NULL && !filter(sc)) continue; for (uint8_t i = 0; i < rsrcs; i++) { if ((rdep->res_mask & BHND_PMURES_BIT(i)) == 0) continue; BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i); depend_mask = BHND_PMU_READ_4(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; default: panic("unknown RES_DEPEND action: %d\n", rdep->action); break; } } } /* Apply nvram overrides to dependencies masks */ for (uint8_t i = 0; i < rsrcs; i++) { char name[6]; uint32_t val; snprintf(name, sizeof(name), "r%dd", i); error = bhnd_nvram_getvar_uint32(sc->chipc_dev, name, &val); 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); } /* Determine min/max rsrc masks */ if ((error = bhnd_pmu_res_masks(sc, &min_mask, &max_mask))) return (error); /* It is required to program max_mask first and then min_mask */ /* 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); } /* Add some delay; allow resources to come up and settle. */ DELAY(2000); return (0); } /* setup pll and query clock speed */ struct pmu0_xtaltab0 { uint16_t freq; uint8_t xf; uint8_t wbint; uint32_t wbfrac; }; /* the following table is based on 880Mhz fvco */ static const pmu0_xtaltab0_t pmu0_xtaltab0[] = { { 12000, 1, 73, 349525}, { 13000, 2, 67, 725937}, { 14400, 3, 61, 116508}, { 15360, 4, 57, 305834}, { 16200, 5, 54, 336579}, { 16800, 6, 52, 399457}, { 19200, 7, 45, 873813}, { 19800, 8, 44, 466033}, { 20000, 9, 44, 0}, { 25000, 10, 70, 419430}, { 26000, 11, 67, 725937}, { 30000, 12, 58, 699050}, { 38400, 13, 45, 873813}, { 40000, 14, 45, 0}, { 0, 0, 0, 0} }; #define PMU0_XTAL0_DEFAULT 8 /* setup pll and query clock speed */ struct pmu1_xtaltab0 { uint16_t fref; uint8_t xf; uint8_t p1div; uint8_t p2div; uint8_t ndiv_int; uint32_t ndiv_frac; }; static const pmu1_xtaltab0_t pmu1_xtaltab0_880_4329[] = { { 12000, 1, 3, 22, 0x9, 0xFFFFEF}, { 13000, 2, 1, 6, 0xb, 0x483483}, { 14400, 3, 1, 10, 0xa, 0x1C71C7}, { 15360, 4, 1, 5, 0xb, 0x755555}, { 16200, 5, 1, 10, 0x5, 0x6E9E06}, { 16800, 6, 1, 10, 0x5, 0x3Cf3Cf}, { 19200, 7, 1, 4, 0xb, 0x755555}, { 19800, 8, 1, 11, 0x4, 0xA57EB}, { 20000, 9, 1, 11, 0x4, 0x0}, { 24000, 10, 3, 11, 0xa, 0x0}, { 25000, 11, 5, 16, 0xb, 0x0}, { 26000, 12, 1, 1, 0x21, 0xD89D89}, { 30000, 13, 3, 8, 0xb, 0x0}, { 37400, 14, 3, 1, 0x46, 0x969696}, { 38400, 15, 1, 1, 0x16, 0xEAAAAA}, { 40000, 16, 1, 2, 0xb, 0}, { 0, 0, 0, 0, 0, 0} }; /* the following table is based on 880Mhz fvco */ static const pmu1_xtaltab0_t pmu1_xtaltab0_880[] = { { 12000, 1, 3, 22, 0x9, 0xFFFFEF}, { 13000, 2, 1, 6, 0xb, 0x483483}, { 14400, 3, 1, 10, 0xa, 0x1C71C7}, { 15360, 4, 1, 5, 0xb, 0x755555}, { 16200, 5, 1, 10, 0x5, 0x6E9E06}, { 16800, 6, 1, 10, 0x5, 0x3Cf3Cf}, { 19200, 7, 1, 4, 0xb, 0x755555}, { 19800, 8, 1, 11, 0x4, 0xA57EB}, { 20000, 9, 1, 11, 0x4, 0x0}, { 24000, 10, 3, 11, 0xa, 0x0}, { 25000, 11, 5, 16, 0xb, 0x0}, { 26000, 12, 1, 2, 0x10, 0xEC4EC4}, { 30000, 13, 3, 8, 0xb, 0x0}, { 33600, 14, 1, 2, 0xd, 0x186186}, { 38400, 15, 1, 2, 0xb, 0x755555}, { 40000, 16, 1, 2, 0xb, 0}, { 0, 0, 0, 0, 0, 0} }; #define PMU1_XTALTAB0_880_12000K 0 #define PMU1_XTALTAB0_880_13000K 1 #define PMU1_XTALTAB0_880_14400K 2 #define PMU1_XTALTAB0_880_15360K 3 #define PMU1_XTALTAB0_880_16200K 4 #define PMU1_XTALTAB0_880_16800K 5 #define PMU1_XTALTAB0_880_19200K 6 #define PMU1_XTALTAB0_880_19800K 7 #define PMU1_XTALTAB0_880_20000K 8 #define PMU1_XTALTAB0_880_24000K 9 #define PMU1_XTALTAB0_880_25000K 10 #define PMU1_XTALTAB0_880_26000K 11 #define PMU1_XTALTAB0_880_30000K 12 #define PMU1_XTALTAB0_880_37400K 13 #define PMU1_XTALTAB0_880_38400K 14 #define PMU1_XTALTAB0_880_40000K 15 /* the following table is based on 1760Mhz fvco */ static const pmu1_xtaltab0_t pmu1_xtaltab0_1760[] = { { 12000, 1, 3, 44, 0x9, 0xFFFFEF}, { 13000, 2, 1, 12, 0xb, 0x483483}, { 14400, 3, 1, 20, 0xa, 0x1C71C7}, { 15360, 4, 1, 10, 0xb, 0x755555}, { 16200, 5, 1, 20, 0x5, 0x6E9E06}, { 16800, 6, 1, 20, 0x5, 0x3Cf3Cf}, { 19200, 7, 1, 18, 0x5, 0x17B425}, { 19800, 8, 1, 22, 0x4, 0xA57EB}, { 20000, 9, 1, 22, 0x4, 0x0}, { 24000, 10, 3, 22, 0xa, 0x0}, { 25000, 11, 5, 32, 0xb, 0x0}, { 26000, 12, 1, 4, 0x10, 0xEC4EC4}, { 30000, 13, 3, 16, 0xb, 0x0}, { 38400, 14, 1, 10, 0x4, 0x955555}, { 40000, 15, 1, 4, 0xb, 0}, { 0, 0, 0, 0, 0, 0} }; /* table index */ #define PMU1_XTALTAB0_1760_12000K 0 #define PMU1_XTALTAB0_1760_13000K 1 #define PMU1_XTALTAB0_1760_14400K 2 #define PMU1_XTALTAB0_1760_15360K 3 #define PMU1_XTALTAB0_1760_16200K 4 #define PMU1_XTALTAB0_1760_16800K 5 #define PMU1_XTALTAB0_1760_19200K 6 #define PMU1_XTALTAB0_1760_19800K 7 #define PMU1_XTALTAB0_1760_20000K 8 #define PMU1_XTALTAB0_1760_24000K 9 #define PMU1_XTALTAB0_1760_25000K 10 #define PMU1_XTALTAB0_1760_26000K 11 #define PMU1_XTALTAB0_1760_30000K 12 #define PMU1_XTALTAB0_1760_38400K 13 #define PMU1_XTALTAB0_1760_40000K 14 /* the following table is based on 1440Mhz fvco */ static const pmu1_xtaltab0_t pmu1_xtaltab0_1440[] = { { 12000, 1, 1, 1, 0x78, 0x0}, { 13000, 2, 1, 1, 0x6E, 0xC4EC4E}, { 14400, 3, 1, 1, 0x64, 0x0}, { 15360, 4, 1, 1, 0x5D, 0xC00000}, { 16200, 5, 1, 1, 0x58, 0xE38E38}, { 16800, 6, 1, 1, 0x55, 0xB6DB6D}, { 19200, 7, 1, 1, 0x4B, 0}, { 19800, 8, 1, 1, 0x48, 0xBA2E8B}, { 20000, 9, 1, 1, 0x48, 0x0}, { 25000, 10, 1, 1, 0x39, 0x999999}, { 26000, 11, 1, 1, 0x37, 0x627627}, { 30000, 12, 1, 1, 0x30, 0x0}, { 37400, 13, 2, 1, 0x4D, 0x15E76}, { 38400, 13, 2, 1, 0x4B, 0x0}, { 40000, 14, 2, 1, 0x48, 0x0}, { 48000, 15, 2, 1, 0x3c, 0x0}, { 0, 0, 0, 0, 0, 0} }; /* table index */ #define PMU1_XTALTAB0_1440_12000K 0 #define PMU1_XTALTAB0_1440_13000K 1 #define PMU1_XTALTAB0_1440_14400K 2 #define PMU1_XTALTAB0_1440_15360K 3 #define PMU1_XTALTAB0_1440_16200K 4 #define PMU1_XTALTAB0_1440_16800K 5 #define PMU1_XTALTAB0_1440_19200K 6 #define PMU1_XTALTAB0_1440_19800K 7 #define PMU1_XTALTAB0_1440_20000K 8 #define PMU1_XTALTAB0_1440_25000K 9 #define PMU1_XTALTAB0_1440_26000K 10 #define PMU1_XTALTAB0_1440_30000K 11 #define PMU1_XTALTAB0_1440_37400K 12 #define PMU1_XTALTAB0_1440_38400K 13 #define PMU1_XTALTAB0_1440_40000K 14 #define PMU1_XTALTAB0_1440_48000K 15 #define XTAL_FREQ_24000MHZ 24000 #define XTAL_FREQ_30000MHZ 30000 #define XTAL_FREQ_37400MHZ 37400 #define XTAL_FREQ_48000MHZ 48000 static const pmu1_xtaltab0_t pmu1_xtaltab0_960[] = { { 12000, 1, 1, 1, 0x50, 0x0}, { 13000, 2, 1, 1, 0x49, 0xD89D89}, { 14400, 3, 1, 1, 0x42, 0xAAAAAA}, { 15360, 4, 1, 1, 0x3E, 0x800000}, { 16200, 5, 1, 1, 0x39, 0x425ED0}, { 16800, 6, 1, 1, 0x39, 0x249249}, { 19200, 7, 1, 1, 0x32, 0x0}, { 19800, 8, 1, 1, 0x30, 0x7C1F07}, { 20000, 9, 1, 1, 0x30, 0x0}, { 25000, 10, 1, 1, 0x26, 0x666666}, { 26000, 11, 1, 1, 0x24, 0xEC4EC4}, { 30000, 12, 1, 1, 0x20, 0x0}, { 37400, 13, 2, 1, 0x33, 0x563EF9}, { 38400, 14, 2, 1, 0x32, 0x0}, { 40000, 15, 2, 1, 0x30, 0x0}, { 48000, 16, 2, 1, 0x28, 0x0}, { 0, 0, 0, 0, 0, 0} }; /* table index */ #define PMU1_XTALTAB0_960_12000K 0 #define PMU1_XTALTAB0_960_13000K 1 #define PMU1_XTALTAB0_960_14400K 2 #define PMU1_XTALTAB0_960_15360K 3 #define PMU1_XTALTAB0_960_16200K 4 #define PMU1_XTALTAB0_960_16800K 5 #define PMU1_XTALTAB0_960_19200K 6 #define PMU1_XTALTAB0_960_19800K 7 #define PMU1_XTALTAB0_960_20000K 8 #define PMU1_XTALTAB0_960_25000K 9 #define PMU1_XTALTAB0_960_26000K 10 #define PMU1_XTALTAB0_960_30000K 11 #define PMU1_XTALTAB0_960_37400K 12 #define PMU1_XTALTAB0_960_38400K 13 #define PMU1_XTALTAB0_960_40000K 14 #define PMU1_XTALTAB0_960_48000K 15 /* 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: return (pmu1_xtaltab0_1760); case BHND_CHIPID_BCM4319: return (pmu1_xtaltab0_1440); case BHND_CHIPID_BCM4325: return (pmu1_xtaltab0_880); case BHND_CHIPID_BCM4329: return (pmu1_xtaltab0_880_4329); case BHND_CHIPID_BCM4336: return (pmu1_xtaltab0_960); case BHND_CHIPID_BCM4330: if (PMU_CST4330_SDIOD_CHIPMODE(sc)) return (pmu1_xtaltab0_960); 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: /* Default to 26000Khz */ return (&pmu1_xtaltab0_1760[PMU1_XTALTAB0_1760_26000K]); case BHND_CHIPID_BCM4319: /* Default to 30000Khz */ return (&pmu1_xtaltab0_1440[PMU1_XTALTAB0_1440_30000K]); case BHND_CHIPID_BCM4325: /* Default to 26000Khz */ return (&pmu1_xtaltab0_880[PMU1_XTALTAB0_880_26000K]); case BHND_CHIPID_BCM4329: /* Default to 38400Khz */ return (&pmu1_xtaltab0_880_4329[PMU1_XTALTAB0_880_38400K]); case BHND_CHIPID_BCM4336: /* Default to 26000Khz */ return (&pmu1_xtaltab0_960[PMU1_XTALTAB0_960_26000K]); case BHND_CHIPID_BCM4330: /* Default to 37400Khz */ if (PMU_CST4330_SDIOD_CHIPMODE(sc)) return (&pmu1_xtaltab0_960[PMU1_XTALTAB0_960_37400K]); 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: return (FVCO_880); case BHND_CHIPID_BCM4319: return (FVCO_1440); case BHND_CHIPID_BCM4336: return (FVCO_960); case BHND_CHIPID_BCM4330: if (PMU_CST4330_SDIOD_CHIPMODE(sc)) return (FVCO_960); 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; /* Find the frequency in the table */ xf = BHND_PMU_READ_4(sc, BHND_PMU_CTRL); xf = BHND_PMU_GET_BITS(xf, BHND_PMU_CTRL_XTALFREQ); for (xt = bhnd_pmu1_xtaltab0(sc); xt != NULL && xt->fref != 0; xt++) { if (xt->xf == xf) break; } /* Could not find it so assign a default value */ if (xt == NULL || xt->fref == 0) 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); } return (xt->fref * 1000); } /* Set up PLL registers in the PMU as per the crystal speed. */ static void bhnd_pmu0_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal) { const pmu0_xtaltab0_t *xt; uint32_t pll_data, pll_mask; uint32_t pll_res; uint32_t pmu_ctrl; uint32_t xf; /* 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 = pmu0_xtaltab0; xt->freq; xt ++) { if (xt->freq == xtal) break; } 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); xf = BHND_PMU_GET_BITS(pmu_ctrl, BHND_PMU_CTRL_XTALFREQ); if (xf == xt->xf) { #ifdef BCMUSBDEV if (sc->cid.chip_id == BHND_CHIPID_BCM4328) { bhnd_pmu0_sbclk4328(sc, BHND_PMU0_PLL0_PC0_DIV_ARM_88MHZ); return; } #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 */ switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4328: pll_res = PMURES_BIT(RES4328_BB_PLL_PU); break; case BHND_CHIPID_BCM5354: pll_res = PMURES_BIT(RES5354_BB_PLL_PU); break; default: panic("unsupported chipid %#hx\n", sc->cid.chip_id); } BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~pll_res); BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~pll_res); /* 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) { BHND_PMU_PLL_WRITE(sc, BHND_PMU0_PLL0_PLLCTL0, BHND_PMU0_PLL0_PC0_PDIV_MASK, BHND_PMU0_PLL0_PC0_PDIV_MASK); } else { BHND_PMU_PLL_WRITE(sc, BHND_PMU0_PLL0_PLLCTL0, 0, BHND_PMU0_PLL0_PC0_PDIV_MASK); } /* Write WILD in pllcontrol[1] */ pll_data = BHND_PMU_SET_BITS(xt->wbint, BHND_PMU0_PLL0_PC1_WILD_INT) | BHND_PMU_SET_BITS(xt->wbfrac, BHND_PMU0_PLL0_PC1_WILD_FRAC); if (xt->wbfrac == 0) { pll_data |= BHND_PMU0_PLL0_PC1_STOP_MOD; } else { pll_data &= ~BHND_PMU0_PLL0_PC1_STOP_MOD; } pll_mask = BHND_PMU0_PLL0_PC1_WILD_INT_MASK | BHND_PMU0_PLL0_PC1_WILD_FRAC_MASK; BHND_PMU_PLL_WRITE(sc, BHND_PMU0_PLL0_PLLCTL1, pll_data, pll_mask); /* Write WILD in pllcontrol[2] */ pll_data = BHND_PMU_SET_BITS(xt->wbint, BHND_PMU0_PLL0_PC2_WILD_INT); 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); pmu_ctrl &= ~(BHND_PMU_CTRL_ILP_DIV_MASK|BHND_PMU_CTRL_XTALFREQ_MASK); pmu_ctrl |= BHND_PMU_SET_BITS(((xt->freq + 127) / 128) - 1, BHND_PMU_CTRL_ILP_DIV); pmu_ctrl |= BHND_PMU_SET_BITS(xt->xf, BHND_PMU_CTRL_XTALFREQ); BHND_PMU_WRITE_4(sc, BHND_PMU_CTRL, pmu_ctrl); } /* 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; /* Find the frequency in the table */ xf = BHND_PMU_READ_4(sc, BHND_PMU_CTRL); xf = BHND_PMU_GET_BITS(xf, BHND_PMU_CTRL_XTALFREQ); for (xt = pmu0_xtaltab0; xt->freq; xt++) if (xt->xf == xf) break; /* PLL must be configured before */ if (xt == NULL || xt->freq == 0) panic("unsupported frequency: %u", xf); return (xt->freq * 1000); } /* 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; #ifdef BCMDBG uint32_t pdiv, wbint, wbfrac, fvco; uint32_t freq; #endif FVCO = FVCO_880; /* Read divarm from pllcontrol[0] */ tmp = BHND_PMU_PLL_READ(sc, BHND_PMU0_PLL0_PLLCTL0); divarm = BHND_PMU_GET_BITS(tmp, BHND_PMU0_PLL0_PC0_DIV_ARM); #ifdef BCMDBG /* Calculate fvco based on xtal freq, pdiv, and wild */ pdiv = tmp & BHND_PMU0_PLL0_PC0_PDIV_MASK; tmp = BHND_PMU_PLL_READ(sc, BHND_PMU0_PLL0_PLLCTL1); wbfrac = BHND_PMU_GET_BITS(tmp, BHND_PMU0_PLL0_PC1_WILD_FRAC); wbint = BHND_PMU_GET_BITS(tmp, PMU0_PLL0_PC1_WILD_INT); tmp = BHND_PMU_PLL_READ(sc, BHND_PMU0_PLL0_PLLCTL2); wbint += BHND_PMU_GET_BITS(tmp, BHND_PMU0_PLL0_PC2_WILD_INT); freq = bhnd_pmu0_alpclk0(sih, osh, cc) / 1000; fvco = (freq * wbint) << 8; fvco += (freq * (wbfrac >> 10)) >> 2; fvco += (freq * (wbfrac & 0x3ff)) >> 10; fvco >>= 8; fvco >>= pdiv; 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 */ /* Return ARM/SB clock */ return FVCO / (divarm + BHND_PMU0_PLL0_PC0_DIV_ARM_BASE) * 1000; } /* Set up PLL registers in the PMU as per the crystal speed. */ static void bhnd_pmu1_pllinit0(struct bhnd_pmu_softc *sc, uint32_t xtal) { const pmu1_xtaltab0_t *xt; uint32_t buf_strength; uint32_t plladdr, plldata, pllmask; uint32_t pmuctrl; 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; } /* Check current PLL state, bail out if it has been programmed or * 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; } /* For 4319 bootloader already programs the PLL but bootloader does not * program the PLL4 and PLL5. So Skip this check for 4319. */ pmuctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL); if (BHND_PMU_GET_BITS(pmuctrl, BHND_PMU_CTRL_XTALFREQ) == xt->xf && 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: /* Change the BBPLL drive strength to 2 for all channels */ buf_strength = 0x222222; BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~(PMURES_BIT(RES4325_BBPLL_PWRSW_PU) | PMURES_BIT(RES4325_HT_AVAIL))); BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~(PMURES_BIT(RES4325_BBPLL_PWRSW_PU) | PMURES_BIT(RES4325_HT_AVAIL))); /* Wait for HT clock to shutdown. */ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL); break; case BHND_CHIPID_BCM4329: /* Change the BBPLL drive strength to 8 for all channels */ buf_strength = 0x888888; BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~(PMURES_BIT(RES4329_BBPLL_PWRSW_PU) | PMURES_BIT(RES4329_HT_AVAIL))); BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~(PMURES_BIT(RES4329_BBPLL_PWRSW_PU) | PMURES_BIT(RES4329_HT_AVAIL))); /* Wait for HT clock to shutdown. */ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL); /* Initialize PLL4 */ plladdr = BHND_PMU1_PLL0_PLLCTL4; if (xt->fref == 38400) plldata = 0x200024C0; else if (xt->fref == 37400) plldata = 0x20004500; else if (xt->fref == 26000) plldata = 0x200024C0; else plldata = 0x200005C0; /* Chip Dflt Settings */ BHND_PMU_PLL_WRITE(sc, plladdr, plldata, ~0); /* Initialize PLL5 */ plladdr = BHND_PMU1_PLL0_PLLCTL5; plldata = BHND_PMU_PLL_READ(sc, plladdr); plldata &= BHND_PMU1_PLL0_PC5_CLK_DRV_MASK; if (xt->fref == 38400 || xt->fref == 37400 || xt->fref == 26000) { plldata |= 0x15; } else { plldata |= 0x25; /* Chip Dflt Settings */ } BHND_PMU_PLL_WRITE(sc, plladdr, plldata, ~0); break; case BHND_CHIPID_BCM4319: /* Change the BBPLL drive strength to 2 for all channels */ buf_strength = 0x222222; /* Make sure the PLL is off */ /* WAR65104: Disable the HT_AVAIL resource first and then * after a delay (more than downtime for HT_AVAIL) remove the * BBPLL resource; backplane clock moves to ALP from HT. */ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~(PMURES_BIT(RES4319_HT_AVAIL))); BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~(PMURES_BIT(RES4319_HT_AVAIL))); DELAY(100); BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~(PMURES_BIT(RES4319_BBPLL_PWRSW_PU))); BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~(PMURES_BIT(RES4319_BBPLL_PWRSW_PU))); DELAY(100); /* Wait for HT clock to shutdown. */ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL); plldata = 0x200005c0; BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, plldata, ~0); break; case BHND_CHIPID_BCM4336: BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~(PMURES_BIT(RES4336_HT_AVAIL) | PMURES_BIT(RES4336_MACPHY_CLKAVAIL))); BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~(PMURES_BIT(RES4336_HT_AVAIL) | PMURES_BIT(RES4336_MACPHY_CLKAVAIL))); DELAY(100); /* Wait for HT clock to shutdown. */ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL); break; case BHND_CHIPID_BCM4330: BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~(PMURES_BIT(RES4330_HT_AVAIL) | PMURES_BIT(RES4330_MACPHY_CLKAVAIL))); BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~(PMURES_BIT(RES4330_HT_AVAIL) | PMURES_BIT(RES4330_MACPHY_CLKAVAIL))); DELAY(100); /* Wait for HT clock to shutdown. */ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL); break; default: 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 = BHND_PMU_SET_BITS(xt->p1div, BHND_PMU1_PLL0_PC0_P1DIV) | BHND_PMU_SET_BITS(xt->p2div, BHND_PMU1_PLL0_PC0_P2DIV); pllmask = BHND_PMU1_PLL0_PC0_P1DIV_MASK|BHND_PMU1_PLL0_PC0_P2DIV_MASK; if (sc->cid.chip_id == BHND_CHIPID_BCM4319) { plldata &= ~(BHND_PMU1_PLL0_PC0_BYPASS_SDMOD_MASK); pllmask |= BHND_PMU1_PLL0_PC0_BYPASS_SDMOD_MASK; if (!xt->ndiv_frac) { plldata |= BHND_PMU_SET_BITS(1, BHND_PMU1_PLL0_PC0_BYPASS_SDMOD); } } BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, plldata, pllmask); if (sc->cid.chip_id == BHND_CHIPID_BCM4330) bhnd_pmu_set_4330_plldivs(sc); if (sc->cid.chip_id == BHND_CHIPID_BCM4329 && sc->cid.chip_rev == 0) { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, BHND_PMU_DOT11MAC_880MHZ_CLK_DIVISOR_VAL, BHND_PMU_DOT11MAC_880MHZ_CLK_DIVISOR_MASK); } /* Write ndiv_int and ndiv_mode to pllcontrol[2] */ if (sc->cid.chip_id == BHND_CHIPID_BCM4336 || sc->cid.chip_id == BHND_CHIPID_BCM4330) { ndiv_mode = BHND_PMU1_PLL0_PC2_NDIV_MODE_MFB; } else if (sc->cid.chip_id == BHND_CHIPID_BCM4319) { if (!(xt->ndiv_frac)) ndiv_mode = BHND_PMU1_PLL0_PC2_NDIV_MODE_INT; else ndiv_mode = BHND_PMU1_PLL0_PC2_NDIV_MODE_MFB; } else { ndiv_mode = BHND_PMU1_PLL0_PC2_NDIV_MODE_MASH; } BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, BHND_PMU_SET_BITS(xt->ndiv_int, BHND_PMU1_PLL0_PC2_NDIV_INT) | BHND_PMU_SET_BITS(ndiv_mode, BHND_PMU1_PLL0_PC2_NDIV_MODE), BHND_PMU1_PLL0_PC2_NDIV_INT_MASK | BHND_PMU1_PLL0_PC2_NDIV_MODE_MASK); /* Write ndiv_frac to pllcontrol[3] */ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, BHND_PMU_SET_BITS(xt->ndiv_frac, BHND_PMU1_PLL0_PC3_NDIV_FRAC), BHND_PMU1_PLL0_PC3_NDIV_FRAC_MASK); /* Writing to pllcontrol[4] */ if (sc->cid.chip_id == BHND_CHIPID_BCM4319) { uint8_t xs; if (!xt->ndiv_frac) plldata = 0x200005c0; else plldata = 0x202C2820; if (FVCO < 1600) xs = 4; else xs = 7; plldata &= ~(BHND_PMU1_PLL0_PC4_KVCO_XS_MASK); plldata |= BHND_PMU_SET_BITS(xs, BHND_PMU1_PLL0_PC4_KVCO_XS); BHND_PMU_WRITE_4(sc, BHND_PMU1_PLL0_PLLCTL4, plldata); } /* 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); pllmask = BHND_PMU1_PLL0_PC5_CLK_DRV_MASK; if (sc->cid.chip_id == BHND_CHIPID_BCM4319) { pllmask |= BHND_PMU1_PLL0_PC5_VCO_RNG_MASK | BHND_PMU1_PLL0_PC5_PLL_CTRL_37_32_MASK; if (!xt->ndiv_frac) { plldata |= BHND_PMU_SET_BITS(0x25, BHND_PMU1_PLL0_PC5_PLL_CTRL_37_32); } else { plldata |= BHND_PMU_SET_BITS(0x15, BHND_PMU1_PLL0_PC5_PLL_CTRL_37_32); } if (FVCO >= 1600) { plldata |= BHND_PMU_SET_BITS(0x1, BHND_PMU1_PLL0_PC5_VCO_RNG); } } BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, plldata, 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. */ if (sc->cid.chip_id == BHND_CHIPID_BCM4319 && xt->fref != XTAL_FREQ_30000MHZ) { uint32_t pll_sel; switch (xt->fref) { case XTAL_FREQ_24000MHZ: pll_sel = BHND_PMU_CCTL_4319USB_24MHZ_PLL_SEL; break; case XTAL_FREQ_48000MHZ: pll_sel = BHND_PMU_CCTL_4319USB_48MHZ_PLL_SEL; break; default: panic("unsupported 4319USB XTAL frequency: %hu\n", xt->fref); } BHND_PMU_CCTRL_WRITE(sc, BHND_PMU1_PLL0_CHIPCTL2, BHND_PMU_SET_BITS(pll_sel, BHND_PMU_CCTL_4319USB_XTAL_SEL), BHND_PMU_CCTL_4319USB_XTAL_SEL_MASK); } /* Flush deferred pll control registers writes */ if (BHND_PMU_REV(sc) >= 2) BHND_PMU_OR_4(sc, BHND_PMU_CTRL, BHND_PMU_CTRL_PLL_PLLCTL_UPD); /* Write XtalFreq. Set the divisor also. */ pmuctrl = BHND_PMU_READ_4(sc, BHND_PMU_CTRL); pmuctrl = ~(BHND_PMU_CTRL_ILP_DIV_MASK | BHND_PMU_CTRL_XTALFREQ_MASK); pmuctrl |= BHND_PMU_SET_BITS(((xt->fref + 127) / 128) - 1, BHND_PMU_CTRL_ILP_DIV); pmuctrl |= BHND_PMU_SET_BITS(xt->xf, BHND_PMU_CTRL_XTALFREQ); if (sc->cid.chip_id == BHND_CHIPID_BCM4329 && sc->cid.chip_rev == 0) { /* clear the htstretch before clearing HTReqEn */ BHND_PMU_AND_4(sc, BHND_PMU_CLKSTRETCH, ~BHND_PMU_CLKSTRETCH); pmuctrl &= ~BHND_PMU_CTRL_HT_REQ_EN; } BHND_PMU_WRITE_4(sc, BHND_PMU_CTRL, pmuctrl); } /* 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 uint32_t ndiv_int, ndiv_frac, p2div, p1div, fvco; uint32_t fref; #endif uint32_t FVCO = bhnd_pmu1_pllfvco0(sc); /* Read m1div from pllcontrol[1] */ tmp = BHND_PMU_PLL_READ(sc, BHND_PMU1_PLL0_PLLCTL1); m1div = BHND_PMU_GET_BITS(tmp, BHND_PMU1_PLL0_PC1_M1DIV); #ifdef BCMDBG /* Read p2div/p1div from pllcontrol[0] */ tmp = BHND_PMU_PLL_READ(sc, BHND_PMU1_PLL0_PLLCTL0); p2div = BHND_PMU_GET_BITS(tmp, BHND_PMU1_PLL0_PC0_P2DIV); p1div = BHND_PMU_GET_BITS(tmp, BHND_PMU1_PLL0_PC0_P1DIV); /* Calculate fvco based on xtal freq and ndiv and pdiv */ tmp = BHND_PMU_PLL_READ(sc, BHND_PMU1_PLL0_PLLCTL2); ndiv_int = BHND_PMU_GET_BITS(tmp, BHND_PMU1_PLL0_PC2_NDIV_INT); tmp = BHND_PMU_PLL_READ(sc, BHND_PMU1_PLL0_PLLCTL3); ndiv_frac = BHND_PMU_GET_BITS(tmp, BHND_PMU1_PLL0_PC3_NDIV_FRAC); fref = bhnd_pmu1_alpclk0(sc) / 1000; fvco = (fref * ndiv_int) << 8; fvco += (fref * (ndiv_frac >> 12)) >> 4; fvco += (fref * (ndiv_frac & 0xfff)) >> 12; fvco >>= 8; fvco *= p2div; fvco /= p1div; 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 */ /* Return ARM/SB clock */ return (FVCO / m1div * 1000); } /* initialize PLL */ void bhnd_pmu_pll_init(struct bhnd_pmu_softc *sc, u_int xtalfreq) { uint32_t max_mask, min_mask; uint32_t res_ht, res_pll; switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4312: /* assume default works */ break; case BHND_CHIPID_BCM4322: case BHND_CHIPID_BCM43221: case BHND_CHIPID_BCM43231: case BHND_CHIPID_BCM4342: if (sc->cid.chip_rev != 0) break; min_mask = BHND_PMU_READ_4(sc, BHND_PMU_MIN_RES_MASK); max_mask = BHND_PMU_READ_4(sc, BHND_PMU_MIN_RES_MASK); res_ht = PMURES_BIT(RES4322_HT_SI_AVAIL); res_pll = PMURES_BIT(RES4322_SI_PLL_ON); /* Have to remove HT Avail request before powering off PLL */ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~res_ht); BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~res_ht); PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL); /* Make sure the PLL is off */ BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~res_pll); BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~res_pll); PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL); DELAY(1000); BHND_PMU_PLL_WRITE(sc, BHND_PMU2_SI_PLL_PLLCTL, 0x380005c0, ~0); DELAY(100); BHND_PMU_WRITE_4(sc, BHND_PMU_MAX_RES_MASK, max_mask); DELAY(100); BHND_PMU_WRITE_4(sc, BHND_PMU_MIN_RES_MASK, min_mask); DELAY(100); break; case BHND_CHIPID_BCM4325: bhnd_pmu1_pllinit0(sc, xtalfreq); break; case BHND_CHIPID_BCM4328: bhnd_pmu0_pllinit0(sc, xtalfreq); break; case BHND_CHIPID_BCM5354: if (xtalfreq == 0) xtalfreq = 25000; bhnd_pmu0_pllinit0(sc, xtalfreq); break; case BHND_CHIPID_BCM4329: if (xtalfreq == 0) xtalfreq = 38400; bhnd_pmu1_pllinit0(sc, xtalfreq); break; case BHND_CHIPID_BCM4313: case BHND_CHIPID_BCM43222: case BHND_CHIPID_BCM43111: case BHND_CHIPID_BCM43112: case BHND_CHIPID_BCM43224: case BHND_CHIPID_BCM43225: case BHND_CHIPID_BCM43420: case BHND_CHIPID_BCM43421: case BHND_CHIPID_BCM43226: case BHND_CHIPID_BCM43235: case BHND_CHIPID_BCM43236: case BHND_CHIPID_BCM43238: case BHND_CHIPID_BCM43234: case BHND_CHIPID_BCM43237: case BHND_CHIPID_BCM4331: case BHND_CHIPID_BCM43431: case BHND_CHIPID_BCM43131: case BHND_CHIPID_BCM43227: case BHND_CHIPID_BCM43228: case BHND_CHIPID_BCM43428: case BHND_CHIPID_BCM6362: /* assume default works */ break; case BHND_CHIPID_BCM4315: case BHND_CHIPID_BCM4319: case BHND_CHIPID_BCM4336: case BHND_CHIPID_BCM4330: 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; clock = BHND_PMU_ALP_CLOCK; switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4328: case BHND_CHIPID_BCM5354: clock = bhnd_pmu0_alpclk0(sc); break; case BHND_CHIPID_BCM4315: case BHND_CHIPID_BCM4319: case BHND_CHIPID_BCM4325: case BHND_CHIPID_BCM4329: case BHND_CHIPID_BCM4330: case BHND_CHIPID_BCM4336: clock = bhnd_pmu1_alpclk0(sc); break; case BHND_CHIPID_BCM4312: case BHND_CHIPID_BCM4322: case BHND_CHIPID_BCM43221: case BHND_CHIPID_BCM43231: case BHND_CHIPID_BCM43222: case BHND_CHIPID_BCM43111: case BHND_CHIPID_BCM43112: case BHND_CHIPID_BCM43224: case BHND_CHIPID_BCM43225: case BHND_CHIPID_BCM43420: case BHND_CHIPID_BCM43421: case BHND_CHIPID_BCM43226: case BHND_CHIPID_BCM43235: case BHND_CHIPID_BCM43236: case BHND_CHIPID_BCM43238: case BHND_CHIPID_BCM43234: case BHND_CHIPID_BCM43237: case BHND_CHIPID_BCM4331: case BHND_CHIPID_BCM43431: case BHND_CHIPID_BCM43131: case BHND_CHIPID_BCM43227: case BHND_CHIPID_BCM43228: case BHND_CHIPID_BCM43428: case BHND_CHIPID_BCM6362: case BHND_CHIPID_BCM4342: case BHND_CHIPID_BCM4716: case BHND_CHIPID_BCM4748: case BHND_CHIPID_BCM47162: case BHND_CHIPID_BCM4313: case BHND_CHIPID_BCM5357: case BHND_CHIPID_BCM4749: case BHND_CHIPID_BCM53572: /* always 20Mhz */ clock = 20000 * 1000; break; case BHND_CHIPID_BCM5356: case BHND_CHIPID_BCM4706: /* always 25Mhz */ 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; } return (clock); } /* Find the output of the "m" pll divider given pll controls that start with * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc. */ static 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; uint32_t ndiv; uint32_t p1, p2; 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); } if (sc->cid.chip_id == BHND_CHIPID_BCM5357 || 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); } /* Fetch p1 and p2 */ BHND_PMU_WRITE_4(sc, BHND_PMU_PLL_CONTROL_ADDR, pll0 + BHND_PMU5_PLL_P1P2_OFF); BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_ADDR); tmp = BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_DATA); p1 = BHND_PMU_GET_BITS(tmp, BHND_PMU5_PLL_P1); p2 = BHND_PMU_GET_BITS(tmp, BHND_PMU5_PLL_P2); /* Fetch div */ BHND_PMU_WRITE_4(sc, BHND_PMU_PLL_CONTROL_ADDR, pll0 + BHND_PMU5_PLL_M14_OFF); BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_ADDR); tmp = BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_DATA); div = (tmp >> ((m - 1) * BHND_PMU5_PLL_MDIV_WIDTH)); div &= BHND_PMU5_PLL_MDIV_MASK; /* Fetch ndiv */ BHND_PMU_WRITE_4(sc, BHND_PMU_PLL_CONTROL_ADDR, pll0 + BHND_PMU5_PLL_NM5_OFF); BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_ADDR); tmp = BHND_PMU_READ_4(sc, BHND_PMU_PLL_CONTROL_DATA); ndiv = BHND_PMU_GET_BITS(tmp, BHND_PMU5_PLL_NDIV); /* Do calculation in Mhz */ 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; clock = BHND_PMU_HT_CLOCK; switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4322: case BHND_CHIPID_BCM43221: case BHND_CHIPID_BCM43231: case BHND_CHIPID_BCM43222: case BHND_CHIPID_BCM43111: case BHND_CHIPID_BCM43112: case BHND_CHIPID_BCM43224: case BHND_CHIPID_BCM43420: case BHND_CHIPID_BCM43225: case BHND_CHIPID_BCM43421: case BHND_CHIPID_BCM43226: case BHND_CHIPID_BCM4331: case BHND_CHIPID_BCM43431: case BHND_CHIPID_BCM6362: case BHND_CHIPID_BCM4342: /* 96MHz backplane clock */ clock = 96000 * 1000; break; case BHND_CHIPID_BCM4716: case BHND_CHIPID_BCM4748: case BHND_CHIPID_BCM47162: clock = bhnd_pmu5_clock(sc, BHND_PMU4716_MAINPLL_PLL0, BHND_PMU5_MAINPLL_SI); break; case BHND_CHIPID_BCM4325: clock = bhnd_pmu1_cpuclk0(sc); break; case BHND_CHIPID_BCM4328: clock = bhnd_pmu0_cpuclk0(sc); break; case BHND_CHIPID_BCM4329: if (sc->cid.chip_rev == 0) clock = 38400 * 1000; else clock = bhnd_pmu1_cpuclk0(sc); break; case BHND_CHIPID_BCM4315: case BHND_CHIPID_BCM4319: case BHND_CHIPID_BCM4336: case BHND_CHIPID_BCM4330: clock = bhnd_pmu1_cpuclk0(sc); break; case BHND_CHIPID_BCM4313: /* 80MHz backplane clock */ clock = 80000 * 1000; break; case BHND_CHIPID_BCM43234: 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 clock = 80000 * 1000; break; case BHND_CHIPID_BCM5356: clock = bhnd_pmu5_clock(sc, BHND_PMU5356_MAINPLL_PLL0, BHND_PMU5_MAINPLL_SI); break; case BHND_CHIPID_BCM5357: case BHND_CHIPID_BCM4749: clock = bhnd_pmu5_clock(sc, BHND_PMU5357_MAINPLL_PLL0, BHND_PMU5_MAINPLL_SI); break; case BHND_CHIPID_BCM53572: 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; } 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); if (BHND_PMU_REV(sc) >= 5 && sc->cid.chip_id != BHND_CHIPID_BCM4329 && sc->cid.chip_id != BHND_CHIPID_BCM4319 && sc->cid.chip_id != BHND_CHIPID_BCM43234 && sc->cid.chip_id != BHND_CHIPID_BCM43235 && sc->cid.chip_id != BHND_CHIPID_BCM43236 && sc->cid.chip_id != BHND_CHIPID_BCM43237 && sc->cid.chip_id != BHND_CHIPID_BCM43238 && sc->cid.chip_id != BHND_CHIPID_BCM4336 && sc->cid.chip_id != BHND_CHIPID_BCM4330) { u_int pll; switch (sc->cid.chip_id) { case BHND_CHIPID_BCM5356: pll = BHND_PMU5356_MAINPLL_PLL0; break; case BHND_CHIPID_BCM5357: case BHND_CHIPID_BCM4749: pll = BHND_PMU5357_MAINPLL_PLL0; break; default: pll = BHND_PMU4716_MAINPLL_PLL0; break; } clock = bhnd_pmu5_clock(sc, pll, BHND_PMU5_MAINPLL_CPU); } else { clock = bhnd_pmu_si_clock(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; if (BHND_PMU_REV(sc) >= 5 && sc->cid.chip_id != BHND_CHIPID_BCM4329 && sc->cid.chip_id != BHND_CHIPID_BCM4319 && sc->cid.chip_id != BHND_CHIPID_BCM43234 && sc->cid.chip_id != BHND_CHIPID_BCM43235 && sc->cid.chip_id != BHND_CHIPID_BCM43236 && sc->cid.chip_id != BHND_CHIPID_BCM43237 && sc->cid.chip_id != BHND_CHIPID_BCM43238 && sc->cid.chip_id != BHND_CHIPID_BCM4336 && sc->cid.chip_id != BHND_CHIPID_BCM4330) { u_int pll; switch (sc->cid.chip_id) { case BHND_CHIPID_BCM5356: pll = BHND_PMU5356_MAINPLL_PLL0; break; case BHND_CHIPID_BCM5357: case BHND_CHIPID_BCM4749: pll = BHND_PMU5357_MAINPLL_PLL0; break; default: pll = BHND_PMU4716_MAINPLL_PLL0; break; } clock = bhnd_pmu5_clock(sc, pll, BHND_PMU5_MAINPLL_MEM); } else { clock = bhnd_pmu_si_clock(sc); } return (clock); } /* 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; if (sc->ilp_cps == 0) { start = BHND_PMU_READ_4(sc, BHND_PMU_TIMER); DELAY(ILP_CALC_DUR); end = BHND_PMU_READ_4(sc, BHND_PMU_TIMER); delta = end - start; sc->ilp_cps = delta * (1000 / ILP_CALC_DUR); } return (sc->ilp_cps); } /* SDIO Pad drive strength to select value mappings */ typedef struct { uint8_t strength; /* Pad Drive Strength in mA */ uint8_t sel; /* Chip-specific select value */ } sdiod_drive_str_t; /* SDIO Drive Strength to sel value table for PMU Rev 1 */ static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = { { 4, 0x2}, { 2, 0x3}, { 1, 0x0}, { 0, 0x0} }; /* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = { { 12, 0x7}, { 10, 0x6}, { 8, 0x5}, { 6, 0x4}, { 4, 0x2}, { 2, 0x1}, { 0, 0x0} }; /* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = { { 32, 0x7}, { 26, 0x6}, { 22, 0x5}, { 16, 0x4}, { 12, 0x3}, { 8, 0x2}, { 4, 0x1}, { 0, 0x0} }; #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) void bhnd_pmu_sdiod_drive_strength_init(struct bhnd_pmu_softc *sc, uint32_t drivestrength) { const sdiod_drive_str_t *str_tab; uint32_t str_mask; uint32_t str_shift; u_int intr_val; str_tab = NULL; str_mask = 0; str_shift = 0; intr_val = 0; switch (SDIOD_DRVSTR_KEY(sc->cid.chip_id, BHND_PMU_REV(sc))) { case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4325, 1): str_tab = sdiod_drive_strength_tab1; str_mask = 0x30000000; str_shift = 28; break; case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4325, 2): case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4325, 3): case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4315, 4): case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4319, 7): str_tab = sdiod_drive_strength_tab2; str_mask = 0x00003800; str_shift = 11; break; case SDIOD_DRVSTR_KEY(BHND_CHIPID_BCM4336, 8): str_tab = sdiod_drive_strength_tab3; str_mask = 0x00003800; str_shift = 11; 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; } if (str_tab != NULL) { uint32_t drivestrength_sel = 0; uint32_t cc_data_temp; for (u_int i = 0; str_tab[i].strength != 0; i++) { if (drivestrength >= str_tab[i].strength) { drivestrength_sel = str_tab[i].sel; break; } } cc_data_temp = BHND_PMU_CCTRL_READ(sc, 1); cc_data_temp &= ~str_mask; drivestrength_sel <<= str_shift; 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); } } /** * Initialize the PMU. */ int bhnd_pmu_init(struct bhnd_pmu_softc *sc) { uint32_t xtalfreq; int error; if (BHND_PMU_REV(sc) == 1) { BHND_PMU_AND_4(sc, BHND_PMU_CTRL, ~BHND_PMU_CTRL_NOILP_ON_WAIT); } else if (BHND_PMU_REV(sc) >= 2) { BHND_PMU_OR_4(sc, BHND_PMU_CTRL, BHND_PMU_CTRL_NOILP_ON_WAIT); } if (sc->cid.chip_id == BHND_CHIPID_BCM4329 && sc->cid.chip_rev == 2) { /* Fix for 4329b0 bad LPOM state. */ BHND_PMU_REGCTRL_WRITE(sc, 2, 0x100, ~0); BHND_PMU_REGCTRL_WRITE(sc, 3, 0x4, ~0); } if (sc->cid.chip_id == BHND_CHIPID_BCM4319) { /* Limiting the PALDO spike during init time */ BHND_PMU_REGCTRL_WRITE(sc, 2, 0x00000005, 0x00000007); } /* Fetch target xtalfreq, in KHz */ error = bhnd_nvram_getvar_uint32(sc->chipc_dev, BHND_NVAR_XTALFREQ, &xtalfreq); /* 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); } /* Perform PLL initialization */ bhnd_pmu_pll_init(sc, xtalfreq); if ((error = bhnd_pmu_res_init(sc))) return (error); bhnd_pmu_swreg_init(sc); return (0); } /* Return up time in ILP cycles for the given resource. */ static int bhnd_pmu_res_uptime(struct bhnd_pmu_softc *sc, uint8_t rsrc, uint32_t *uptime) { uint32_t deps; uint32_t up, dup, dmax; uint32_t min_mask; int error; /* uptime of resource 'rsrc' */ BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, rsrc); up = BHND_PMU_READ_4(sc, BHND_PMU_RES_UPDN_TIMER); up = BHND_PMU_GET_BITS(up, BHND_PMU_RES_UPDN_UPTME); /* Find direct dependencies of resource 'rsrc' */ deps = bhnd_pmu_res_deps(sc, BHND_PMURES_BIT(rsrc), false); for (uint8_t i = 0; i <= BHND_PMU_RESNUM_MAX; i++) { if (!(deps & BHND_PMURES_BIT(i))) continue; deps &= ~bhnd_pmu_res_deps(sc, BHND_PMURES_BIT(i), true); } /* Exclude the minimum resource set */ if ((error = bhnd_pmu_res_masks(sc, &min_mask, NULL))) return (error); deps &= ~min_mask; /* max uptime of direct dependencies */ dmax = 0; for (uint8_t i = 0; i <= BHND_PMU_RESNUM_MAX; i++) { if (!(deps & BHND_PMURES_BIT(i))) continue; if ((error = bhnd_pmu_res_uptime(sc, i, &dup))) return (error); if (dmax < dup) 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); } /* Return dependencies (direct or all/indirect) for the given resources */ static uint32_t bhnd_pmu_res_deps(struct bhnd_pmu_softc *sc, uint32_t rsrcs, bool all) { uint32_t deps; deps = 0; for (uint8_t i = 0; i <= BHND_PMU_RESNUM_MAX; i++) { if (!(rsrcs & BHND_PMURES_BIT(i))) continue; BHND_PMU_WRITE_4(sc, BHND_PMU_RES_TABLE_SEL, i); deps |= BHND_PMU_READ_4(sc, BHND_PMU_RES_DEP_MASK); } /* None found? */ if (deps == 0) return (0); /* Recurse dependencies */ if (all) deps |= bhnd_pmu_res_deps(sc, deps, true); return (deps); } /* power up/down OTP through PMU resources */ int bhnd_pmu_otp_power(struct bhnd_pmu_softc *sc, bool on) { uint32_t deps; uint32_t min_mask; uint32_t rsrcs; int error; /* Determine rsrcs to turn on/off OTP power */ switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4322: case BHND_CHIPID_BCM43221: case BHND_CHIPID_BCM43231: case BHND_CHIPID_BCM4342: rsrcs = PMURES_BIT(RES4322_OTP_PU); break; case BHND_CHIPID_BCM4315: rsrcs = PMURES_BIT(RES4315_OTP_PU); break; case BHND_CHIPID_BCM4325: rsrcs = PMURES_BIT(RES4325_OTP_PU); break; case BHND_CHIPID_BCM4329: rsrcs = PMURES_BIT(RES4329_OTP_PU); break; case BHND_CHIPID_BCM4319: rsrcs = PMURES_BIT(RES4319_OTP_PU); break; case BHND_CHIPID_BCM4336: rsrcs = PMURES_BIT(RES4336_OTP_PU); break; case BHND_CHIPID_BCM4330: rsrcs = PMURES_BIT(RES4330_OTP_PU); break; default: /* Not required? */ return (0); } /* Fetch all dependencies */ deps = bhnd_pmu_res_deps(sc, rsrcs, true); /* Exclude the minimum resource set */ if ((error = bhnd_pmu_res_masks(sc, &min_mask, NULL))) return (error); deps &= ~min_mask; /* Turn on/off the power */ 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 */ for (int i = 0; i < BHND_PMU_MAX_TRANSITION_DLY; i += 10) { state = BHND_PMU_READ_4(sc, BHND_PMU_RES_STATE); if ((state & rsrcs) == rsrcs) break; DELAY(10); } 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)); } return (0); } void bhnd_pmu_rcal(struct bhnd_pmu_softc *sc) { uint32_t chipst; uint32_t val; uint8_t rcal_code; bool bluetooth_rcal; bluetooth_rcal = false; switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4325: case BHND_CHIPID_BCM4329: /* Kick RCal */ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 1); /* Power Down RCAL Block */ BHND_PMU_AND_4(sc, BHND_PMU_CHIPCTL_DATA, ~0x04); if (sc->cid.chip_id == BHND_CHIPID_BCM4325) { chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev); if (BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_RCAL_VALID)) bluetooth_rcal = true; } /* Power Up RCAL block */ BHND_PMU_AND_4(sc, BHND_PMU_CHIPCTL_DATA, 0x04); /* Wait for completion */ for (int i = 0; i < (10 * 1000 * 1000); i++) { chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev); if (chipst & 0x08) break; DELAY(10); } KASSERT((chipst & 0x08) != 0, ("rcal completion timeout")); if (bluetooth_rcal) { rcal_code = 0x6; } else { /* Drop LSB to convert from 5 bit code to 4 bit code */ 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); val = BHND_PMU_READ_4(sc, BHND_PMU_REG_CONTROL_DATA); val &= ~((uint32_t) 0x07 << 29); val |= (uint32_t) (rcal_code & 0x07) << 29; BHND_PMU_WRITE_4(sc, BHND_PMU_REG_CONTROL_DATA, val); BHND_PMU_WRITE_4(sc, BHND_PMU_REG_CONTROL_ADDR, 1); val = BHND_PMU_READ_4(sc, BHND_PMU_REG_CONTROL_DATA); val &= ~(uint32_t) 0x01; val |= (uint32_t) ((rcal_code >> 3) & 0x01); BHND_PMU_WRITE_4(sc, BHND_PMU_REG_CONTROL_DATA, val); /* Write RCal code into pmu_chip_ctrl[33:30] */ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 0); val = BHND_PMU_READ_4(sc, BHND_PMU_CHIPCTL_DATA); val &= ~((uint32_t) 0x03 << 30); val |= (uint32_t) (rcal_code & 0x03) << 30; BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_DATA, val); BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 1); val = BHND_PMU_READ_4(sc, BHND_PMU_CHIPCTL_DATA); val &= ~(uint32_t) 0x03; val |= (uint32_t) ((rcal_code >> 2) & 0x03); BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_DATA, val); /* Set override in pmu_chip_ctrl[29] */ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 0); BHND_PMU_OR_4(sc, BHND_PMU_CHIPCTL_DATA, (0x01 << 29)); /* Power off RCal block */ BHND_PMU_WRITE_4(sc, BHND_PMU_CHIPCTL_ADDR, 1); BHND_PMU_AND_4(sc, BHND_PMU_CHIPCTL_DATA, ~0x04); break; default: break; } } void bhnd_pmu_spuravoid(struct bhnd_pmu_softc *sc, uint8_t spuravoid) { /* force the HT off */ if (sc->cid.chip_id == BHND_CHIPID_BCM4336) { BHND_PMU_AND_4(sc, BHND_PMU_MAX_RES_MASK, ~BHND_PMU_RES4336_HT_AVAIL); /* wait for the ht to really go away */ PMU_WAIT_CLKST(sc, 0, BHND_CCS_HTAVAIL); } /* update the pll changes */ bhnd_pmu_spuravoid_pllupdate(sc, spuravoid); /* enable HT back on */ if (sc->cid.chip_id == BHND_CHIPID_BCM4336) { BHND_PMU_OR_4(sc, BHND_PMU_MAX_RES_MASK, BHND_PMU_RES4336_HT_AVAIL); } } static void bhnd_pmu_spuravoid_pllupdate(struct bhnd_pmu_softc *sc, uint8_t spuravoid) { uint16_t chip_id; uint32_t tmp; uint32_t pmuctrl; uint8_t phypll_offset; uint8_t bcm5357_bcm43236_p1div[] = { 0x1, 0x5, 0x5 }; uint8_t bcm5357_bcm43236_ndiv[] = { 0x30, 0xf6, 0xfc }; /* 6362a0 has same clks as 4322[4-6] */ chip_id = sc->cid.chip_id; if (chip_id == BHND_CHIPID_BCM6362 && sc->cid.chip_rev == 0) { chip_id = BHND_CHIPID_BCM43224; } switch (chip_id) { case BHND_CHIPID_BCM6362: KASSERT(sc->cid.chip_rev != 0, ("invalid clock config")); /* fallthrough */ case BHND_CHIPID_BCM5357: case BHND_CHIPID_BCM4749: case BHND_CHIPID_BCM43235: case BHND_CHIPID_BCM43236: case BHND_CHIPID_BCM43238: case BHND_CHIPID_BCM43234: case BHND_CHIPID_BCM43237: case BHND_CHIPID_BCM53572: KASSERT(spuravoid < nitems(bcm5357_bcm43236_p1div), ("spuravoid %hhu outside p1div table\n", spuravoid)); KASSERT(spuravoid < nitems(bcm5357_bcm43236_ndiv), ("spuravoid %hhu outside ndiv table\n", spuravoid)); /* BCM5357 needs to touch PLL1_PLLCTL[02], so offset * PLL0_PLLCTL[02] by 6 */ phypll_offset = 0; if (sc->cid.chip_id == BHND_CHIPID_BCM5357) phypll_offset = 6; /* RMW only the P1 divider */ tmp = BHND_PMU_SET_BITS(bcm5357_bcm43236_p1div[spuravoid], BHND_PMU1_PLL0_PC0_P1DIV); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0 + phypll_offset, tmp, BHND_PMU1_PLL0_PC0_P1DIV_MASK); /* RMW only the int feedback divider */ tmp = BHND_PMU_SET_BITS(bcm5357_bcm43236_ndiv[spuravoid], BHND_PMU1_PLL0_PC2_NDIV_INT); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2 + phypll_offset, tmp, BHND_PMU1_PLL0_PC0_P1DIV_MASK); pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD; break; case BHND_CHIPID_BCM4331: if (spuravoid == 2) { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11500014, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x0FC00a08, ~0); } else if (spuravoid == 1) { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11500014, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x0F600a08, ~0); } else { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11100014, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x03000a08, ~0); } pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD; break; case BHND_CHIPID_BCM43224: case BHND_CHIPID_BCM43225: case BHND_CHIPID_BCM43226: case BHND_CHIPID_BCM43421: if (spuravoid == 1) { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11500010, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x000C0C06, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x0F600a08, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, 0x00000000, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, 0x2001E920, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888815, ~0); } else { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11100010, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x000c0c06, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x03000a08, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, 0x00000000, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, 0x200005c0, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888815, ~0); } pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD; break; case BHND_CHIPID_BCM43111: case BHND_CHIPID_BCM43112: case BHND_CHIPID_BCM43222: case BHND_CHIPID_BCM43420: if (spuravoid == 1) { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11500008, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x0c000c06, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x0f600a08, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, 0x00000000, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, 0x2001e920, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888815, ~0); } else { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11100008, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x0c000c06, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x03000a08, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, 0x00000000, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, 0x200005c0, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888855, ~0); } pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD; break; case BHND_CHIPID_BCM4716: case BHND_CHIPID_BCM4748: case BHND_CHIPID_BCM47162: if (spuravoid == 1) { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11500060, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x080C0C06, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x0F600000, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, 0x00000000, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, 0x2001E924, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888815, ~0); } else { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11100060, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x080c0c06, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x03000000, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, 0x00000000, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, 0x200005c0, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888815, ~0); } pmuctrl = BHND_PMU_CTRL_NOILP_ON_WAIT | BHND_PMU_CTRL_PLL_PLLCTL_UPD; break; case BHND_CHIPID_BCM4319: + pmuctrl = 0; break; case BHND_CHIPID_BCM4322: case BHND_CHIPID_BCM43221: case BHND_CHIPID_BCM43231: case BHND_CHIPID_BCM4342: BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11100070, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x1014140a, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888854, ~0); if (spuravoid == 1) { /* spur_avoid ON, enable 41/82/164Mhz clock mode */ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x05201828, ~0); } else { /* enable 40/80/160Mhz clock mode */ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x05001828, ~0); } pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD; break; case BHND_CHIPID_BCM4336: /* Looks like these are only for default xtal freq 26MHz */ BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x02100020, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x0C0C0C0C, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x01240C0C, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, 0x202C2820, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888825, ~0); if (spuravoid == 1) { tmp = 0x00EC4EC4; } else { tmp = 0x00762762; } BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, tmp, ~0); - pmuctrl = BHND_PMU_CTRL_PLL_PLLCTL_UPD; break; case BHND_CHIPID_BCM43131: case BHND_CHIPID_BCM43227: case BHND_CHIPID_BCM43228: case BHND_CHIPID_BCM43428: /* LCNXN */ /* PLL Settings for spur avoidance on/off mode, no on2 support * for 43228A0 */ if (spuravoid == 1) { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x01100014, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x040C0C06, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x03140A08, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, 0x00333333, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, 0x202C2820, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888815, ~0); } else { BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL0, 0x11100014, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, 0x040c0c06, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, 0x03000a08, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL3, 0x00000000, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL4, 0x200005c0, ~0); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL5, 0x88888815, ~0); } 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 bhnd_pmu_is_otp_powered(struct bhnd_pmu_softc *sc) { uint32_t otp_res; /* Determine per-chip OTP resource */ switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4329: otp_res = PMURES_BIT(RES4329_OTP_PU); break; case BHND_CHIPID_BCM4319: otp_res = PMURES_BIT(RES4319_OTP_PU); break; case BHND_CHIPID_BCM4336: otp_res = PMURES_BIT(RES4336_OTP_PU); break; case BHND_CHIPID_BCM4330: otp_res = PMURES_BIT(RES4330_OTP_PU); break; /* These chips don't use PMU bit to power up/down OTP. OTP always on. * Use OTP_INIT command to reset/refresh state. */ case BHND_CHIPID_BCM43224: case BHND_CHIPID_BCM43225: case BHND_CHIPID_BCM43421: case BHND_CHIPID_BCM43236: case BHND_CHIPID_BCM43235: case BHND_CHIPID_BCM43238: return (true); default: return (true); } /* Check resource state */ if ((BHND_PMU_READ_4(sc, BHND_PMU_RES_STATE) & otp_res) == 0) return (false); return (true); } void bhnd_pmu_paref_ldo_enable(struct bhnd_pmu_softc *sc, bool enable) { uint32_t ldo; switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4328: ldo = PMURES_BIT(RES4328_PA_REF_LDO); break; case BHND_CHIPID_BCM5354: ldo = PMURES_BIT(RES5354_PA_REF_LDO); break; case BHND_CHIPID_BCM4312: ldo = PMURES_BIT(RES4312_PA_REF_LDO); break; default: return; } if (enable) { BHND_PMU_OR_4(sc, BHND_PMU_MIN_RES_MASK, ldo); } else { BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~ldo); } } /* initialize PMU switch/regulators */ void bhnd_pmu_swreg_init(struct bhnd_pmu_softc *sc) { uint32_t chipst; switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4325: if (sc->cid.chip_rev <= 2) break; chipst = BHND_CHIPC_READ_CHIPST(sc->chipc_dev); if (BHND_PMU_GET_BITS(chipst, CHIPC_CST4325_PMUTOP_2B)) { bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CLDO_PWM, 0xf); bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CLDO_BURST, 0xf); } bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CBUCK_PWM, 0xb); bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CBUCK_BURST, 0xb); bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_LNLDO1, 0x1); if (sc->board.board_flags & BHND_BFL_LNLDO2_2P5) { bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_LNLDO2_SEL, 0x1); } break; case BHND_CHIPID_BCM4336: /* Reduce CLDO PWM output voltage to 1.2V */ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CLDO_PWM, 0xe); /* Reduce CLDO BURST output voltage to 1.2V */ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CLDO_BURST, 0xe); /* Reduce LNLDO1 output voltage to 1.2V */ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_LNLDO1, 0xe); if (sc->cid.chip_rev == 0) BHND_PMU_REGCTRL_WRITE(sc, 2, 0x400000, 0x400000); break; case BHND_CHIPID_BCM4330: /* CBUCK Voltage is 1.8 by default and set that to 1.5 */ bhnd_pmu_set_ldo_voltage(sc, SET_LDO_VOLTAGE_CBUCK_PWM, 0); break; default: break; } } void bhnd_pmu_radio_enable(struct bhnd_pmu_softc *sc, device_t d11core, bool enable) { uint32_t oobsel; uint32_t rsrcs; if (bhnd_get_device(d11core) != BHND_COREID_D11) panic("bhnd_pmu_radio_enable() called on non-D11 core"); switch (sc->cid.chip_id) { case BHND_CHIPID_BCM4325: if (sc->board.board_flags & BHND_BFL_FASTPWR) break; if ((sc->board.board_flags & BHND_BFL_BUCKBOOST) == 0) break; rsrcs = PMURES_BIT(RES4325_BUCK_BOOST_BURST); if (enable) { BHND_PMU_OR_4(sc, BHND_PMU_MIN_RES_MASK, rsrcs); DELAY(100 * 1000); /* 100ms */ } else { BHND_PMU_AND_4(sc, BHND_PMU_MIN_RES_MASK, ~rsrcs); } break; case BHND_CHIPID_BCM4319: oobsel = bhnd_read_config(d11core, BCMA_DMP_OOBSELOUTB74, 4); if (enable) { oobsel |= BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN, BCMA_DMP_OOBSEL_1); oobsel |= BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN, BCMA_DMP_OOBSEL_2); } else { oobsel &= ~BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN, BCMA_DMP_OOBSEL_1); oobsel &= ~BHND_PMU_SET_BITS(BCMA_DMP_OOBSEL_EN, BCMA_DMP_OOBSEL_2); } bhnd_write_config(d11core, BCMA_DMP_OOBSELOUTB74, oobsel, 4); break; } } /* Wait for a particular clock level to be on the backplane */ uint32_t bhnd_pmu_waitforclk_on_backplane(struct bhnd_pmu_softc *sc, uint32_t clk, uint32_t delay) { uint32_t pmu_st; for (uint32_t i = 0; i < delay; i += 10) { pmu_st = BHND_PMU_READ_4(sc, BHND_PMU_ST); if ((pmu_st & clk) == clk) return (clk); DELAY(10); } pmu_st = BHND_PMU_READ_4(sc, BHND_PMU_ST); return (pmu_st & clk); } /* * Measures the ALP clock frequency in KHz. Returns 0 if not possible. * Possible only if PMU rev >= 10 and there is an external LPO 32768Hz crystal. */ #define EXT_ILP_HZ 32768 uint32_t bhnd_pmu_measure_alpclk(struct bhnd_pmu_softc *sc) { uint32_t alp_khz; uint32_t pmu_st; if (BHND_PMU_REV(sc) < 10) return (0); pmu_st = BHND_PMU_READ_4(sc, BHND_PMU_ST); if (pmu_st & BHND_PMU_ST_EXTLPOAVAIL) { uint32_t alp_hz, ilp_ctr; /* Enable frequency measurement */ BHND_PMU_WRITE_4(sc, BHND_PMU_XTALFREQ, 1U << BHND_PMU_XTALFREQ_REG_MEASURE_SHIFT); /* Delay for well over 4 ILP clocks */ DELAY(1000); /* Read the latched number of ALP ticks per 4 ILP ticks */ ilp_ctr = BHND_PMU_READ_4(sc, BHND_PMU_XTALFREQ); ilp_ctr = BHND_PMU_GET_BITS(ilp_ctr, BHND_PMU_XTALFREQ_REG_ILPCTR); /* Turn off PMU_XTALFREQ_REG_MEASURE to save power */ BHND_PMU_WRITE_4(sc, BHND_PMU_XTALFREQ, 0); /* Calculate ALP frequency */ alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4; /* Round to nearest 100KHz and convert to KHz */ alp_khz = (alp_hz + 50000) / 100000 * 100; } else { alp_khz = 0; } return (alp_khz); } 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; m2div = m3div = m4div = m6div = FVCO / 80; m5div = FVCO / 160; if (PMU_CST4330_SDIOD_CHIPMODE(sc)) m1div = FVCO / 80; else m1div = FVCO / 90; pllc1 = 0; pllc1 |= BHND_PMU_SET_BITS(m1div, BHND_PMU1_PLL0_PC1_M1DIV); pllc1 |= BHND_PMU_SET_BITS(m2div, BHND_PMU1_PLL0_PC1_M2DIV); pllc1 |= BHND_PMU_SET_BITS(m3div, BHND_PMU1_PLL0_PC1_M3DIV); pllc1 |= BHND_PMU_SET_BITS(m4div, BHND_PMU1_PLL0_PC1_M4DIV); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL1, pllc1, ~0); pllc2 = 0; pllc2 |= BHND_PMU_SET_BITS(m5div, BHND_PMU1_PLL0_PC2_M5DIV); pllc2 |= BHND_PMU_SET_BITS(m6div, BHND_PMU1_PLL0_PC2_M6DIV); BHND_PMU_PLL_WRITE(sc, BHND_PMU1_PLL0_PLLCTL2, pllc2, BHND_PMU1_PLL0_PC2_M5DIV_MASK | BHND_PMU1_PLL0_PC2_M6DIV_MASK); } Index: head/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h =================================================================== --- head/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h (revision 304870) +++ head/sys/dev/bhnd/cores/pmu/bhnd_pmuvar.h (revision 304871) @@ -1,92 +1,142 @@ /*- * Copyright (c) 2015 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, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. * * $FreeBSD$ */ #ifndef _BHND_CORES_PMU_BHND_PMUVAR_H_ #define _BHND_CORES_PMU_BHND_PMUVAR_H_ #include #include #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 */ enum { /** No quirks */ BPMU_QUIRK_NONE = 0, /** On BCM4328-derived chipsets, the CLK_CTL_ST register CCS_HTAVAIL * and CCS_ALPAVAIL bits are swapped; the BHND_CCS0_* constants should * be used. */ 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 */ - uint32_t ilp_cps; /**< measured ILP cycles per - second, or 0 */ + 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; + }; #define BPMU_LOCK_INIT(sc) \ mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \ "BHND chipc driver lock", MTX_DEF) #define BPMU_LOCK(sc) mtx_lock(&(sc)->mtx) #define BPMU_UNLOCK(sc) mtx_unlock(&(sc)->mtx) #define BPMU_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what) #define BPMU_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx) #endif /* _BHND_CORES_PMU_BHND_PMUVAR_H_ */ Index: head/sys/mips/broadcom/bcm_socinfo.c =================================================================== --- head/sys/mips/broadcom/bcm_socinfo.c (revision 304870) +++ head/sys/mips/broadcom/bcm_socinfo.c (nonexistent) @@ -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; -} Property changes on: head/sys/mips/broadcom/bcm_socinfo.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/sys/mips/broadcom/bcm_socinfo.h =================================================================== --- head/sys/mips/broadcom/bcm_socinfo.h (revision 304870) +++ head/sys/mips/broadcom/bcm_socinfo.h (nonexistent) @@ -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_ */ Property changes on: head/sys/mips/broadcom/bcm_socinfo.h ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/sys/mips/broadcom/bcm_machdep.c =================================================================== --- head/sys/mips/broadcom/bcm_machdep.c (revision 304870) +++ head/sys/mips/broadcom/bcm_machdep.c (revision 304871) @@ -1,437 +1,448 @@ /*- * Copyright (c) 2007 Bruce M. Simpson. * Copyright (c) 2016 Michael Zhilin * 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 "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bcm_machdep.h" #include "bcm_mips_exts.h" -#include "bcm_socinfo.h" #ifdef CFE #include #endif #if 0 #define BCM_TRACE(_fmt, ...) printf(_fmt, ##__VA_ARGS__) #else #define BCM_TRACE(_fmt, ...) #endif static int bcm_find_core(struct bhnd_chipid *chipid, bhnd_devclass_t devclass, int unit, struct bhnd_core_info *info, uintptr_t *addr); static int bcm_init_platform_data(struct bcm_platform *pdata); /* Allow bus-specific implementations to override bcm_find_core_(bcma|siba) * symbols, if included in the kernel build */ __weak_reference(bcm_find_core_default, bcm_find_core_bcma); __weak_reference(bcm_find_core_default, bcm_find_core_siba); extern int *edata; extern int *end; static struct bcm_platform bcm_platform_data; static bool bcm_platform_data_avail = false; struct bcm_platform * bcm_get_platform(void) { if (!bcm_platform_data_avail) panic("platform data not available"); return (&bcm_platform_data); } /* Default (no-op) bcm_find_core() implementation. */ int bcm_find_core_default(struct bhnd_chipid *chipid, bhnd_devclass_t devclass, int unit, struct bhnd_core_info *info, uintptr_t *addr) { return (ENODEV); } /** * Search @p chipid's enumeration table for a core with @p devclass and * @p unit. * * @param chipid Chip identification data, including the address * of the enumeration table to be searched. * @param devclass Search for a core matching this device class. * @param unit The core's required unit number. * @param[out] info On success, will be populated with the core * info. */ static int bcm_find_core(struct bhnd_chipid *chipid, bhnd_devclass_t devclass, int unit, struct bhnd_core_info *info, uintptr_t *addr) { switch (chipid->chip_type) { case BHND_CHIPTYPE_SIBA: return (bcm_find_core_siba(chipid, devclass, unit, info, addr)); break; default: if (!BHND_CHIPTYPE_HAS_EROM(chipid->chip_type)) { printf("%s: unsupported chip type: %d\n", __FUNCTION__, chipid->chip_type); return (ENXIO); } return (bcm_find_core_bcma(chipid, devclass, unit, info, addr)); } } /** * Populate platform configuration data. */ static int bcm_init_platform_data(struct bcm_platform *pdata) { uint32_t reg; bhnd_addr_t enum_addr; long maddr; uint8_t chip_type; bool aob, pmu; int error; /* Fetch CFE console handle (if any). Must be initialized before * any calls to printf/early_putc. */ #ifdef CFE if ((pdata->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0) pdata->cfe_console = -1; #endif /* Fetch bhnd/chipc address */ if (resource_long_value("bhnd", 0, "maddr", &maddr) == 0) pdata->cc_addr = (u_long)maddr; else pdata->cc_addr = BHND_DEFAULT_CHIPC_ADDR; /* Read chip identifier from ChipCommon */ reg = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_ID); chip_type = CHIPC_GET_BITS(reg, CHIPC_ID_BUS); if (BHND_CHIPTYPE_HAS_EROM(chip_type)) enum_addr = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_EROMPTR); else enum_addr = pdata->cc_addr; pdata->id = bhnd_parse_chipid(reg, enum_addr); /* Fetch chipc core info and capabilities */ pdata->cc_caps = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_CAPABILITIES); error = bcm_find_core(&pdata->id, BHND_DEVCLASS_CC, 0, &pdata->cc_id, NULL); if (error) { printf("%s: error locating chipc core: %d", __FUNCTION__, error); return (error); } if (CHIPC_HWREV_HAS_CAP_EXT(pdata->cc_id.hwrev)) { pdata->cc_caps_ext = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_CAPABILITIES_EXT); } else { pdata->cc_caps_ext = 0x0; } /* Fetch PMU info */ pmu = CHIPC_GET_FLAG(pdata->cc_caps, CHIPC_CAP_PMU); aob = CHIPC_GET_FLAG(pdata->cc_caps_ext, CHIPC_CAP2_AOB); if (pmu && aob) { /* PMU block mapped to a PMU core on the Always-on-Bus (aob) */ error = bcm_find_core(&pdata->id, BHND_DEVCLASS_PMU, 0, &pdata->pmu_id, &pdata->pmu_addr); if (error) { printf("%s: error locating pmu core: %d", __FUNCTION__, error); return (error); } } else if (pmu) { /* PMU block mapped to chipc */ pdata->pmu_addr = pdata->cc_addr; pdata->pmu_id = pdata->cc_id; } else { /* No PMU */ pdata->pmu_addr = 0x0; 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); } void platform_cpu_init() { /* Nothing special */ } static void mips_init(void) { int i, j; printf("entry: mips_init()\n"); #ifdef CFE /* * Query DRAM memory map from CFE. */ physmem = 0; for (i = 0; i < 10; i += 2) { int result; uint64_t addr, len, type; result = cfe_enummem(i / 2, 0, &addr, &len, &type); if (result < 0) { BCM_TRACE("There is no phys memory for: %d\n", i); phys_avail[i] = phys_avail[i + 1] = 0; break; } if (type != CFE_MI_AVAILABLE) { BCM_TRACE("phys memory is not available: %d\n", i); continue; } phys_avail[i] = addr; if (i == 0 && addr == 0) { /* * If this is the first physical memory segment probed * from CFE, omit the region at the start of physical * memory where the kernel has been loaded. */ phys_avail[i] += MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); } BCM_TRACE("phys memory is available for: %d\n", i); BCM_TRACE(" => addr = %jx\n", addr); BCM_TRACE(" => len = %jd\n", len); phys_avail[i + 1] = addr + len; physmem += len; } BCM_TRACE("Total phys memory is : %ld\n", physmem); realmem = btoc(physmem); #endif for (j = 0; j < i; j++) dump_avail[j] = phys_avail[j]; physmem = realmem; init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } void platform_reset(void) { - bool bcm4785war; + struct bcm_platform *bp; + bool bcm4785war; printf("bcm::platform_reset()\n"); intr_disable(); #ifdef CFE /* Fall back on CFE if reset requested during platform * data initialization */ if (!bcm_platform_data_avail) { cfe_exit(0, 0); while (1); } #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 */ bcm_mips_wr_pllcfg3(MIPS_BCMCFG_PLLCFG3_SM); } /* 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) { mips_sync(); __asm __volatile("wait"); } while (1); } void platform_start(__register_t a0, __register_t a1, __register_t a2, __register_t a3) { vm_offset_t kernend; uint64_t platform_counter_freq; - struct bcm_socinfo *socinfo; int error; /* clear the BSS and SBSS segments */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); /* Initialize pcpu stuff */ mips_pcpu0_init(); #ifdef CFE /* * Initialize CFE firmware trampolines. This must be done * before any CFE APIs are called, including writing * to the CFE console. * * CFE passes the following values in registers: * a0: firmware handle * a2: firmware entry point * a3: entry point seal */ if (a3 == CFE_EPTSEAL) cfe_init(a0, a2); #endif /* Init BCM platform data */ 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); } /* * CFE-based EARLY_PRINTF support. To use, add the following to the kernel * config: * option EARLY_PRINTF * option CFE * device cfe */ #if defined(EARLY_PRINTF) && defined(CFE) static void bcm_cfe_eputc(int c) { unsigned char ch; int handle; ch = (unsigned char) c; /* bcm_get_platform() cannot be used here, as we may be called * from bcm_init_platform_data(). */ if ((handle = bcm_platform_data.cfe_console) < 0) return; if (ch == '\n') early_putc('\r'); while ((cfe_write(handle, &ch, 1)) == 0) continue; } early_putc_t *early_putc = bcm_cfe_eputc; #endif /* EARLY_PRINTF */ Index: head/sys/mips/broadcom/bcm_machdep.h =================================================================== --- head/sys/mips/broadcom/bcm_machdep.h (revision 304870) +++ head/sys/mips/broadcom/bcm_machdep.h (revision 304871) @@ -1,93 +1,107 @@ /*- * 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, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. * * $FreeBSD$ */ #ifndef _MIPS_BROADCOM_BCM_MACHDEP_H_ #define _MIPS_BROADCOM_BCM_MACHDEP_H_ #include #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 */ struct bhnd_core_info cc_id; /**< chipc core info */ uintptr_t cc_addr; /**< chipc core phys address */ uint32_t cc_caps; /**< chipc capabilities */ uint32_t cc_caps_ext; /**< chipc extended capabilies */ /* On non-AOB devices, the PMU register block is mapped to chipc; * 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 }; +struct bcm_platform *bcm_get_platform(void); -typedef int (bcm_bus_find_core)(struct bhnd_chipid *chipid, - bhnd_devclass_t devclass, int unit, struct bhnd_core_info *info, - uintptr_t *addr); +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); -struct bcm_platform *bcm_get_platform(void); +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_ */ Index: head/sys/mips/broadcom/bcm_pmu.c =================================================================== --- head/sys/mips/broadcom/bcm_pmu.c (nonexistent) +++ head/sys/mips/broadcom/bcm_pmu.c (revision 304871) @@ -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))); +} Property changes on: head/sys/mips/broadcom/bcm_pmu.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/mips/broadcom/files.broadcom =================================================================== --- head/sys/mips/broadcom/files.broadcom (revision 304870) +++ head/sys/mips/broadcom/files.broadcom (revision 304871) @@ -1,23 +1,23 @@ # $FreeBSD$ # TODO: Add attachment elsewhere in the tree # for USB 1.1 OHCI, Ethernet and IPSEC cores # which are believed to be devices we have drivers for # 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 kern/subr_intr.c standard kern/pic_if.m standard 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 geom/geom_flashmap.c standard Index: head/sys/mips/broadcom/uart_bus_chipc.c =================================================================== --- head/sys/mips/broadcom/uart_bus_chipc.c (revision 304870) +++ head/sys/mips/broadcom/uart_bus_chipc.c (revision 304871) @@ -1,83 +1,81 @@ /*- * 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 "opt_uart.h" #include #include #include #include #include #include #include #include #include #include #include #include #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[] = { /* Device interface */ DEVMETHOD(device_probe, uart_chipc_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), { 0, 0 } }; static driver_t uart_chipc_driver = { uart_driver_name, uart_chipc_methods, sizeof(struct uart_softc), }; DRIVER_MODULE(uart, bhnd_chipc, uart_chipc_driver, uart_devclass, 0, 0); Index: head/sys/mips/broadcom/uart_cpu_chipc.c =================================================================== --- head/sys/mips/broadcom/uart_cpu_chipc.c (revision 304870) +++ head/sys/mips/broadcom/uart_cpu_chipc.c (revision 304871) @@ -1,175 +1,171 @@ /*- * 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 "opt_uart.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef CFE #include #include #include #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; static struct uart_class *chipc_uart_class = &uart_ns8250_class; #define CHIPC_UART_BAUDRATE 115200 int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } 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; di->parity = UART_PARITY_NONE; return (0); } #ifdef CFE static int uart_getenv_cfe(int devtype, struct uart_devinfo *di) { char device[sizeof("uartXX")]; int baud, fd, len; int ret; u_int uart; /* CFE only vends console configuration */ if (devtype != UART_DEV_CONSOLE) return (ENODEV); /* Fetch console device */ ret = cfe_getenv("BOOT_CONSOLE", device, sizeof(device)); if (ret != CFE_OK) return (ENXIO); /* Parse serial console unit. Fails on non-uart devices. */ if (sscanf(device, "uart%u", &uart) != 1) return (ENXIO); /* Fetch device handle */ fd = bcm_get_platform()->cfe_console; if (fd < 0) return (ENXIO); /* Fetch serial configuration */ ret = cfe_ioctl(fd, IOCTL_SERIAL_GETSPEED, (unsigned char *)&baud, sizeof(baud), &len, 0); if (ret != CFE_OK) baud = CHIPC_UART_BAUDRATE; /* Initialize device info */ return (uart_cpu_init(di, uart, baud)); } #endif /* CFE */ int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { int ivar; uart_bus_space_io = NULL; uart_bus_space_mem = mips_bus_space_generic; #ifdef CFE /* Check the CFE environment */ if (uart_getenv_cfe(devtype, di) == 0) return (0); #endif /* CFE */ /* Check the kernel environment. */ if (uart_getenv(devtype, di, chipc_uart_class) == 0) return (0); /* Scan the device hints for the first matching device */ for (u_int i = 0; i < CHIPC_UART_MAX; i++) { if (resource_int_value("uart", i, "flags", &ivar)) continue; /* Check usability */ if (devtype == UART_DEV_CONSOLE && !UART_FLAGS_CONSOLE(ivar)) continue; if (devtype == UART_DEV_DBGPORT && !UART_FLAGS_DBGPORT(ivar)) continue; if (resource_int_value("uart", i, "disabled", &ivar) == 0 && ivar == 0) continue; /* Found */ if (resource_int_value("uart", i, "baud", &ivar) != 0) ivar = CHIPC_UART_BAUDRATE; return (uart_cpu_init(di, i, ivar)); } /* Default to uart0/115200 */ return (uart_cpu_init(di, 0, CHIPC_UART_BAUDRATE)); }