From cde9070d9970eef1f7ec2360586c802a16230ad8 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Fri, 10 May 2024 07:43:50 +0000 Subject: [PATCH] rtl88x2CE_WiFi_linux driver --- kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/hndpmu.c | 887 ++++++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 692 insertions(+), 195 deletions(-) diff --git a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/hndpmu.c b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/hndpmu.c index bd1e450..8add713 100644 --- a/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/hndpmu.c +++ b/kernel/drivers/net/wireless/rockchip_wlan/cywdhd/bcmdhd/hndpmu.c @@ -1,16 +1,17 @@ -/* SPDX-License-Identifier: GPL-2.0 */ /* * Misc utility routines for accessing PMU corerev specific features * of the SiliconBackplane-based Broadcom chips. * - * Copyright (C) 1999-2019, Broadcom Corporation - * + * Portions of this code are copyright (c) 2022 Cypress Semiconductor Corporation + * + * Copyright (C) 1999-2017, Broadcom Corporation + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -18,7 +19,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -26,15 +27,15 @@ * * <<Broadcom-WL-IPTag/Open:>> * - * $Id: hndpmu.c 530092 2015-01-29 04:44:58Z $ + * $Id: hndpmu.c 700652 2017-05-20 02:44:31Z $ */ - -/* +/** + * @file * Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs. * However, in the context of this file the baseband ('BB') PLL/FLL is referred to. * - * Throughout this code, the prefixes 'pmu0_', 'pmu1_' and 'pmu2_' are used. + * Throughout this code, the prefixes 'pmu1_' and 'pmu2_' are used. * They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012) * pmu1_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop). It supports * fractional frequency generation. pmu2_ does not support fractional frequency generation. @@ -49,7 +50,18 @@ #include <bcmdevs.h> #include <hndsoc.h> #include <sbchipc.h> +#include <hndchipc.h> #include <hndpmu.h> +#include <hndlhl.h> +#if defined(BCMULP) +#include <ulp.h> +#endif /* defined(BCMULP) */ +#include <sbgci.h> +#ifdef EVENT_LOG_COMPILE +#include <event_log.h> +#endif // endif +#include <sbgci.h> +#include <lpflags.h> #define PMU_ERROR(args) @@ -59,6 +71,7 @@ * to be on except on private builds. */ #define PMU_NONE(args) +#define flags_shift 14 /** contains resource bit positions for a specific chip */ struct rsc_per_chip_s { @@ -66,109 +79,16 @@ uint8 macphy_clkavail; uint8 ht_start; uint8 otp_pu; + uint8 macphy_aux_clkavail; }; typedef struct rsc_per_chip_s rsc_per_chip_t; - -/* SDIO Pad drive strength to select value mappings. - * The last strength value in each table must be 0 (the tri-state value). - */ -typedef struct { - uint8 strength; /* Pad Drive Strength in mA */ - uint8 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} }; - -/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { - {32, 0x6}, - {26, 0x7}, - {22, 0x4}, - {16, 0x5}, - {12, 0x2}, - {8, 0x3}, - {4, 0x0}, - {0, 0x1} }; - -/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ - -/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ - -/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { - {6, 0x7}, - {5, 0x6}, - {4, 0x5}, - {3, 0x4}, - {2, 0x2}, - {1, 0x1}, - {0, 0x0} }; - -/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ - -/** SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = { - {3, 0x3}, - {2, 0x2}, - {1, 0x1}, - {0, 0x0} }; - - -/** - * SDIO Drive Strength to sel value table for 43143 PMU Rev 17, see Confluence 43143 Toplevel - * architecture page, section 'PMU Chip Control 1 Register definition', click link to picture - * BCM43143_sel_sdio_signals.jpg. Valid after PMU Chip Control 0 Register, bit31 (override) has - * been written '1'. - */ -#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 - -static const sdiod_drive_str_t sdiod_drive_strength_tab7_3v3[] = { - /* note: for 14, 10, 6 and 2mA hw timing is not met according to rtl team */ - {16, 0x7}, - {12, 0x5}, - {8, 0x3}, - {4, 0x1} }; /* note: 43143 does not support tristate */ - +#if defined(BCMPMU_STATS) && !defined(BCMPMU_STATS_DISABLED) +bool _pmustatsenab = TRUE; #else - -static const sdiod_drive_str_t sdiod_drive_strength_tab7_1v8[] = { - /* note: for 7, 5, 3 and 1mA hw timing is not met according to rtl team */ - {8, 0x7}, - {6, 0x5}, - {4, 0x3}, - {2, 0x1} }; /* note: 43143 does not support tristate */ - -#endif /* BCM_SDIO_VDDIO */ - -#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) +bool _pmustatsenab = FALSE; +#endif /* BCMPMU_STATS */ /** * Balance between stable SDIO operation and power consumption is achieved using this function. @@ -182,17 +102,236 @@ void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) { - sdiod_drive_str_t *str_tab = NULL; - uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */ - uint32 str_shift = 0; - uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */ - uint32 str_ovr_pmuval = 0; /* position of bit within this register */ + /* + * Note: + * This function used to set the SDIO drive strength via PMU_CHIPCTL1 for the + * 43143, 4330, 4334, 4336, 43362 chips. These chips are now no longer supported, so + * the code has been deleted. + * Newer chips have the SDIO drive strength setting via a GCI Chip Control register, + * but the bit definitions are chip-specific. We are keeping this function available + * (accessed via DHD 'sdiod_drive' IOVar) in case these newer chips need to provide access. + */ + UNUSED_PARAMETER(sih); + UNUSED_PARAMETER(osh); + UNUSED_PARAMETER(drivestrength); +} + +void +si_switch_pmu_dependency(si_t *sih, uint mode) +{ +#ifdef DUAL_PMU_SEQUENCE + osl_t *osh = si_osh(sih); + uint32 current_res_state; + uint32 min_mask, max_mask; + const pmu_res_depend_t *pmu_res_depend_table = NULL; + uint pmu_res_depend_table_sz = 0; + uint origidx; + pmuregs_t *pmu; + chipcregs_t *cc; + BCM_REFERENCE(cc); + + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + cc = si_setcore(sih, CC_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + cc = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + current_res_state = R_REG(osh, &pmu->res_state); + min_mask = R_REG(osh, &pmu->min_res_mask); + max_mask = R_REG(osh, &pmu->max_res_mask); + W_REG(osh, &pmu->min_res_mask, (min_mask | current_res_state)); + switch (mode) { + case PMU_4364_1x1_MODE: + { + if (CHIPID(sih->chip) == BCM4364_CHIP_ID) { + pmu_res_depend_table = bcm4364a0_res_depend_1x1; + pmu_res_depend_table_sz = + ARRAYSIZE(bcm4364a0_res_depend_1x1); + max_mask = PMU_4364_MAX_MASK_1x1; + W_REG(osh, &pmu->res_table_sel, RES4364_SR_SAVE_RESTORE); + W_REG(osh, &pmu->res_updn_timer, PMU_4364_SAVE_RESTORE_UPDNTIME_1x1); +#if defined(SAVERESTORE) + if (SR_ENAB()) { + /* Disable 3x3 SR engine */ + W_REG(osh, &cc->sr1_control0, + CC_SR0_4364_SR_ENG_CLK_EN | + CC_SR0_4364_SR_RSRC_TRIGGER | + CC_SR0_4364_SR_WD_MEM_MIN_DIV | + CC_SR0_4364_SR_INVERT_CLK | + CC_SR0_4364_SR_ENABLE_HT | + CC_SR0_4364_SR_ALLOW_PIC | + CC_SR0_4364_SR_PMU_MEM_DISABLE); + } +#endif /* SAVERESTORE */ + } + break; + } + case PMU_4364_3x3_MODE: + { + if (CHIPID(sih->chip) == BCM4364_CHIP_ID) { + W_REG(osh, &pmu->res_table_sel, RES4364_SR_SAVE_RESTORE); + W_REG(osh, &pmu->res_updn_timer, + PMU_4364_SAVE_RESTORE_UPDNTIME_3x3); + /* Change the dependency table only if required */ + if ((max_mask != PMU_4364_MAX_MASK_3x3) || + (max_mask != PMU_4364_MAX_MASK_RSDB)) { + pmu_res_depend_table = bcm4364a0_res_depend_rsdb; + pmu_res_depend_table_sz = + ARRAYSIZE(bcm4364a0_res_depend_rsdb); + max_mask = PMU_4364_MAX_MASK_3x3; + } +#if defined(SAVERESTORE) + if (SR_ENAB()) { + /* Enable 3x3 SR engine */ + W_REG(osh, &cc->sr1_control0, + CC_SR0_4364_SR_ENG_CLK_EN | + CC_SR0_4364_SR_RSRC_TRIGGER | + CC_SR0_4364_SR_WD_MEM_MIN_DIV | + CC_SR0_4364_SR_INVERT_CLK | + CC_SR0_4364_SR_ENABLE_HT | + CC_SR0_4364_SR_ALLOW_PIC | + CC_SR0_4364_SR_PMU_MEM_DISABLE | + CC_SR0_4364_SR_ENG_EN_MASK); + } +#endif /* SAVERESTORE */ + } + break; + } + case PMU_4364_RSDB_MODE: + default: + { + if (CHIPID(sih->chip) == BCM4364_CHIP_ID) { + W_REG(osh, &pmu->res_table_sel, RES4364_SR_SAVE_RESTORE); + W_REG(osh, &pmu->res_updn_timer, + PMU_4364_SAVE_RESTORE_UPDNTIME_3x3); + /* Change the dependency table only if required */ + if ((max_mask != PMU_4364_MAX_MASK_3x3) || + (max_mask != PMU_4364_MAX_MASK_RSDB)) { + pmu_res_depend_table = + bcm4364a0_res_depend_rsdb; + pmu_res_depend_table_sz = + ARRAYSIZE(bcm4364a0_res_depend_rsdb); + max_mask = PMU_4364_MAX_MASK_RSDB; + } +#if defined(SAVERESTORE) + if (SR_ENAB()) { + /* Enable 3x3 SR engine */ + W_REG(osh, &cc->sr1_control0, + CC_SR0_4364_SR_ENG_CLK_EN | + CC_SR0_4364_SR_RSRC_TRIGGER | + CC_SR0_4364_SR_WD_MEM_MIN_DIV | + CC_SR0_4364_SR_INVERT_CLK | + CC_SR0_4364_SR_ENABLE_HT | + CC_SR0_4364_SR_ALLOW_PIC | + CC_SR0_4364_SR_PMU_MEM_DISABLE | + CC_SR0_4364_SR_ENG_EN_MASK); + } +#endif /* SAVERESTORE */ + } + break; + } + } + si_pmu_resdeptbl_upd(sih, osh, pmu, pmu_res_depend_table, pmu_res_depend_table_sz); + W_REG(osh, &pmu->max_res_mask, max_mask); + W_REG(osh, &pmu->min_res_mask, min_mask); + si_pmu_wait_for_steady_state(sih, osh, pmu); + /* Add some delay; allow resources to come up and settle. */ + OSL_DELAY(200); + si_setcoreidx(sih, origidx); +#endif /* DUAL_PMU_SEQUENCE */ +} + +#if defined(BCMULP) + +int +si_pmu_ulp_register(si_t *sih) +{ + return ulp_p1_module_register(ULP_MODULE_ID_PMU, &ulp_pmu_ctx, (void *)sih); +} + +static uint +si_pmu_ulp_get_retention_size_cb(void *handle, ulp_ext_info_t *einfo) +{ + ULP_DBG(("%s: sz: %d\n", __FUNCTION__, sizeof(si_pmu_ulp_cr_dat_t))); + return sizeof(si_pmu_ulp_cr_dat_t); +} + +static int +si_pmu_ulp_enter_cb(void *handle, ulp_ext_info_t *einfo, uint8 *cache_data) +{ + si_pmu_ulp_cr_dat_t crinfo = {0}; + crinfo.ilpcycles_per_sec = ilpcycles_per_sec; + ULP_DBG(("%s: ilpcycles_per_sec: %x\n", __FUNCTION__, ilpcycles_per_sec)); + memcpy(cache_data, (void*)&crinfo, sizeof(crinfo)); + return BCME_OK; +} + +static int +si_pmu_ulp_exit_cb(void *handle, uint8 *cache_data, + uint8 *p2_cache_data) +{ + si_pmu_ulp_cr_dat_t *crinfo = (si_pmu_ulp_cr_dat_t *)cache_data; + + ilpcycles_per_sec = crinfo->ilpcycles_per_sec; + ULP_DBG(("%s: ilpcycles_per_sec: %x, cache_data: %p\n", __FUNCTION__, + ilpcycles_per_sec, cache_data)); + return BCME_OK; +} + +void +si_pmu_ulp_chipconfig(si_t *sih, osl_t *osh) +{ + uint32 reg_val; + + BCM_REFERENCE(reg_val); + + if (CHIPID(sih->chip) == BCM43012_CHIP_ID) { + /* DS1 reset and clk enable init value config */ + si_pmu_chipcontrol(sih, PMU_CHIPCTL14, ~0x0, + (PMUCCTL14_43012_ARMCM3_RESET_INITVAL | + PMUCCTL14_43012_DOT11MAC_CLKEN_INITVAL | + PMUCCTL14_43012_SDIOD_RESET_INIVAL | + PMUCCTL14_43012_SDIO_CLK_DMN_RESET_INITVAL | + PMUCCTL14_43012_SOCRAM_CLKEN_INITVAL | + PMUCCTL14_43012_M2MDMA_RESET_INITVAL | + PMUCCTL14_43012_DOT11MAC_PHY_CLK_EN_INITVAL | + PMUCCTL14_43012_DOT11MAC_PHY_CNTL_EN_INITVAL)); + + /* Clear SFlash clock request and enable High Quality clock */ + CHIPC_REG(sih, clk_ctl_st, CCS_SFLASH_CLKREQ | CCS_HQCLKREQ, CCS_HQCLKREQ); + + reg_val = PMU_REG(sih, min_res_mask, ~0x0, ULP_MIN_RES_MASK); + ULP_DBG(("si_pmu_ulp_chipconfig: min_res_mask: 0x%08x\n", reg_val)); + + /* Force power switch off */ + si_pmu_chipcontrol(sih, PMU_CHIPCTL2, + (PMUCCTL02_43012_SUBCORE_PWRSW_FORCE_ON | + PMUCCTL02_43012_PHY_PWRSW_FORCE_ON), 0); + + } +} + +void +si_pmu_ulp_ilp_config(si_t *sih, osl_t *osh, uint32 ilp_period) +{ + pmuregs_t *pmu; + pmu = si_setcoreidx(sih, si_findcoreidx(sih, PMU_CORE_ID, 0)); + W_REG(osh, &pmu->ILPPeriod, ilp_period); + si_lhl_ilp_config(sih, osh, ilp_period); +} + +/** Initialize DS1 PMU hardware resources */ +void +si_pmu_ds1_res_init(si_t *sih, osl_t *osh) +{ pmuregs_t *pmu; uint origidx; - - if (!(sih->cccaps & CC_CAP_PMU)) { - return; - } + const pmu_res_updown_t *pmu_res_updown_table = NULL; + uint pmu_res_updown_table_sz = 0; /* Remember original core before switch to chipc/pmu */ origidx = si_coreidx(sih); @@ -203,91 +342,449 @@ } ASSERT(pmu != NULL); - switch (SDIOD_DRVSTR_KEY(CHIPID(sih->chip), sih->pmurev)) { - case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1; - str_mask = 0x30000000; - str_shift = 28; + switch (CHIPID(sih->chip)) { + case BCM43012_CHIP_ID: + pmu_res_updown_table = bcm43012a0_res_updown_ds1; + pmu_res_updown_table_sz = ARRAYSIZE(bcm43012a0_res_updown_ds1); break; - case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): - case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): - case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2; - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): - case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): - if (sih->pmurev == 8) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; - } - else if (sih->pmurev == 11) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; - } - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; - str_mask = 0x00003800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8; - str_mask = 0x00001800; - str_shift = 11; - break; - case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): -#if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33 - if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3; - } -#else - if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8; - } -#endif /* BCM_SDIO_VDDIO */ - str_mask = 0x00000007; - str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR; - break; + default: - PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", - bcm_chipname( - CHIPID(sih->chip), chn, 8), CHIPREV(sih->chiprev), sih->pmurev)); break; } - if (str_tab != NULL) { - uint32 cc_data_temp; - int i; - - /* Pick the lowest available drive strength equal or greater than the - * requested strength. Drive strength of 0 requests tri-state. - */ - for (i = 0; drivestrength < str_tab[i].strength; i++) - ; - - if (i > 0 && drivestrength > str_tab[i].strength) - i--; - - W_REG(osh, &pmu->chipcontrol_addr, PMU_CHIPCTL1); - cc_data_temp = R_REG(osh, &pmu->chipcontrol_data); - cc_data_temp &= ~str_mask; - cc_data_temp |= str_tab[i].sel << str_shift; - W_REG(osh, &pmu->chipcontrol_data, cc_data_temp); - if (str_ovr_pmuval) { /* enables the selected drive strength */ - W_REG(osh, &pmu->chipcontrol_addr, str_ovr_pmuctl); - OR_REG(osh, &pmu->chipcontrol_data, str_ovr_pmuval); - } - PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n", - drivestrength, str_tab[i].strength)); + /* Program up/down timers */ + while (pmu_res_updown_table_sz--) { + ASSERT(pmu_res_updown_table != NULL); + PMU_MSG(("DS1: Changing rsrc %d res_updn_timer to 0x%x\n", + pmu_res_updown_table[pmu_res_updown_table_sz].resnum, + pmu_res_updown_table[pmu_res_updown_table_sz].updown)); + W_REG(osh, &pmu->res_table_sel, + pmu_res_updown_table[pmu_res_updown_table_sz].resnum); + W_REG(osh, &pmu->res_updn_timer, + pmu_res_updown_table[pmu_res_updown_table_sz].updown); } /* Return to original core */ si_setcoreidx(sih, origidx); -} /* si_sdiod_drive_strength_init */ +} + +#endif /* defined(BCMULP) */ + +uint32 +si_pmu_wake_bit_offset(si_t *sih) +{ + uint32 wakebit; + + switch (CHIPID(sih->chip)) { + case BCM4347_CHIP_GRPID: + wakebit = CC2_4347_GCI2WAKE_MASK; + break; + default: + wakebit = 0; + ASSERT(0); + break; + } + + return wakebit; +} + +void si_pmu_set_min_res_mask(si_t *sih, osl_t *osh, uint min_res_mask) +{ + pmuregs_t *pmu; + uint origidx; + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } + else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + W_REG(osh, &pmu->min_res_mask, min_res_mask); + OSL_DELAY(100); + + /* Return to original core */ + si_setcoreidx(sih, origidx); +} + +bool +si_pmu_cap_fast_lpo(si_t *sih) +{ + return (PMU_REG(sih, core_cap_ext, 0, 0) & PCAP_EXT_USE_MUXED_ILP_CLK_MASK) ? TRUE : FALSE; +} + +int +si_pmu_fast_lpo_disable(si_t *sih) +{ + if (!si_pmu_cap_fast_lpo(sih)) { + PMU_ERROR(("%s: No Fast LPO capability\n", __FUNCTION__)); + return BCME_ERROR; + } + + PMU_REG(sih, pmucontrol_ext, + PCTL_EXT_FASTLPO_ENAB | + PCTL_EXT_FASTLPO_SWENAB | + PCTL_EXT_FASTLPO_PCIE_SWENAB, + 0); + OSL_DELAY(1000); + return BCME_OK; +} + +#ifdef BCMPMU_STATS +/* + * 8 pmu statistics timer default map + * + * for CORE_RDY_AUX measure, set as below for timer 6 and 7 instead of CORE_RDY_MAIN. + * //core-n active duration : pmu_rsrc_state(CORE_RDY_AUX) + * { SRC_CORE_RDY_AUX, FALSE, TRUE, LEVEL_HIGH}, + * //core-n active duration : pmu_rsrc_state(CORE_RDY_AUX) + * { SRC_CORE_RDY_AUX, FALSE, TRUE, EDGE_RISE} + */ +static pmu_stats_timer_t pmustatstimer[] = { + { SRC_LINK_IN_L12, FALSE, TRUE, PMU_STATS_LEVEL_HIGH}, //link_in_l12 + { SRC_LINK_IN_L23, FALSE, TRUE, PMU_STATS_LEVEL_HIGH}, //link_in_l23 + { SRC_PM_ST_IN_D0, FALSE, TRUE, PMU_STATS_LEVEL_HIGH}, //pm_st_in_d0 + { SRC_PM_ST_IN_D3, FALSE, TRUE, PMU_STATS_LEVEL_HIGH}, //pm_st_in_d3 + //deep-sleep duration : pmu_rsrc_state(XTAL_PU) + { SRC_XTAL_PU, FALSE, TRUE, PMU_STATS_LEVEL_LOW}, + //deep-sleep entry count : pmu_rsrc_state(XTAL_PU) + { SRC_XTAL_PU, FALSE, TRUE, PMU_STATS_EDGE_FALL}, + //core-n active duration : pmu_rsrc_state(CORE_RDY_MAIN) + { SRC_CORE_RDY_MAIN, FALSE, TRUE, PMU_STATS_LEVEL_HIGH}, + //core-n active duration : pmu_rsrc_state(CORE_RDY_MAIN) + { SRC_CORE_RDY_MAIN, FALSE, TRUE, PMU_STATS_EDGE_RISE} +}; + +static void +si_pmustatstimer_update(osl_t *osh, pmuregs_t *pmu, uint8 timerid) +{ + uint32 stats_timer_ctrl; + + W_REG(osh, &pmu->pmu_statstimer_addr, timerid); + stats_timer_ctrl = + ((pmustatstimer[timerid].src_num << PMU_ST_SRC_SHIFT) & + PMU_ST_SRC_MASK) | + ((pmustatstimer[timerid].cnt_mode << PMU_ST_CNT_MODE_SHIFT) & + PMU_ST_CNT_MODE_MASK) | + ((pmustatstimer[timerid].enable << PMU_ST_EN_SHIFT) & PMU_ST_EN_MASK) | + ((pmustatstimer[timerid].int_enable << PMU_ST_INT_EN_SHIFT) & PMU_ST_INT_EN_MASK); + W_REG(osh, &pmu->pmu_statstimer_ctrl, stats_timer_ctrl); + W_REG(osh, &pmu->pmu_statstimer_N, 0); +} + +void +si_pmustatstimer_int_enable(si_t *sih) +{ + pmuregs_t *pmu; + uint origidx; + osl_t *osh = si_osh(sih); + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + OR_REG(osh, &pmu->pmuintmask0, PMU_INT_STAT_TIMER_INT_MASK); + + /* Return to original core */ + si_setcoreidx(sih, origidx); +} + +void +si_pmustatstimer_int_disable(si_t *sih) +{ + pmuregs_t *pmu; + uint origidx; + osl_t *osh = si_osh(sih); + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + AND_REG(osh, &pmu->pmuintmask0, ~PMU_INT_STAT_TIMER_INT_MASK); + + /* Return to original core */ + si_setcoreidx(sih, origidx); +} + +void +si_pmustatstimer_init(si_t *sih) +{ + pmuregs_t *pmu; + uint origidx; + osl_t *osh = si_osh(sih); + uint32 core_cap_ext; + uint8 max_stats_timer_num; + int8 i; + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + core_cap_ext = R_REG(osh, &pmu->core_cap_ext); + + max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >> PCAP_EXT_ST_NUM_SHIFT) + 1; + + for (i = 0; i < max_stats_timer_num; i++) { + si_pmustatstimer_update(osh, pmu, i); + } + + OR_REG(osh, &pmu->pmuintmask0, PMU_INT_STAT_TIMER_INT_MASK); + + /* Return to original core */ + si_setcoreidx(sih, origidx); +} + +void +si_pmustatstimer_dump(si_t *sih) +{ + pmuregs_t *pmu; + uint origidx; + osl_t *osh = si_osh(sih); + uint32 core_cap_ext, pmucapabilities, AlpPeriod, ILPPeriod, pmuintmask0, pmuintstatus; + uint8 max_stats_timer_num, max_stats_timer_src_num; + uint32 stat_timer_ctrl, stat_timer_N; + uint8 i; + uint32 current_time_ms = OSL_SYSUPTIME(); + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + pmucapabilities = R_REG(osh, &pmu->pmucapabilities); + core_cap_ext = R_REG(osh, &pmu->core_cap_ext); + AlpPeriod = R_REG(osh, &pmu->slowclkperiod); + ILPPeriod = R_REG(osh, &pmu->ILPPeriod); + + max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >> + PCAP_EXT_ST_NUM_SHIFT) + 1; + max_stats_timer_src_num = ((core_cap_ext & PCAP_EXT_ST_SRC_NUM_MASK) >> + PCAP_EXT_ST_SRC_NUM_SHIFT) + 1; + + pmuintstatus = R_REG(osh, &pmu->pmuintstatus); + pmuintmask0 = R_REG(osh, &pmu->pmuintmask0); + + PMU_ERROR(("%s : TIME %d\n", __FUNCTION__, current_time_ms)); + + PMU_ERROR(("\tMAX Timer Num %d, MAX Source Num %d\n", + max_stats_timer_num, max_stats_timer_src_num)); + PMU_ERROR(("\tpmucapabilities 0x%8x, core_cap_ext 0x%8x, AlpPeriod 0x%8x, ILPPeriod 0x%8x, " + "pmuintmask0 0x%8x, pmuintstatus 0x%8x, pmurev %d\n", + pmucapabilities, core_cap_ext, AlpPeriod, ILPPeriod, + pmuintmask0, pmuintstatus, PMUREV(sih->pmurev))); + + for (i = 0; i < max_stats_timer_num; i++) { + W_REG(osh, &pmu->pmu_statstimer_addr, i); + stat_timer_ctrl = R_REG(osh, &pmu->pmu_statstimer_ctrl); + stat_timer_N = R_REG(osh, &pmu->pmu_statstimer_N); + PMU_ERROR(("\t Timer %d : control 0x%8x, %d\n", + i, stat_timer_ctrl, stat_timer_N)); + } + + /* Return to original core */ + si_setcoreidx(sih, origidx); +} + +void +si_pmustatstimer_start(si_t *sih, uint8 timerid) +{ + pmuregs_t *pmu; + uint origidx; + osl_t *osh = si_osh(sih); + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + pmustatstimer[timerid].enable = TRUE; + + W_REG(osh, &pmu->pmu_statstimer_addr, timerid); + OR_REG(osh, &pmu->pmu_statstimer_ctrl, PMU_ST_ENAB << PMU_ST_EN_SHIFT); + + /* Return to original core */ + si_setcoreidx(sih, origidx); +} + +void +si_pmustatstimer_stop(si_t *sih, uint8 timerid) +{ + pmuregs_t *pmu; + uint origidx; + osl_t *osh = si_osh(sih); + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + pmustatstimer[timerid].enable = FALSE; + + W_REG(osh, &pmu->pmu_statstimer_addr, timerid); + AND_REG(osh, &pmu->pmu_statstimer_ctrl, ~(PMU_ST_ENAB << PMU_ST_EN_SHIFT)); + + /* Return to original core */ + si_setcoreidx(sih, origidx); +} + +void +si_pmustatstimer_clear(si_t *sih, uint8 timerid) +{ + pmuregs_t *pmu; + uint origidx; + osl_t *osh = si_osh(sih); + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + W_REG(osh, &pmu->pmu_statstimer_addr, timerid); + W_REG(osh, &pmu->pmu_statstimer_N, 0); + + /* Return to original core */ + si_setcoreidx(sih, origidx); +} + +void +si_pmustatstimer_clear_overflow(si_t *sih) +{ + uint8 i; + uint32 core_cap_ext; + uint8 max_stats_timer_num; + uint32 timerN; + pmuregs_t *pmu; + uint origidx; + osl_t *osh = si_osh(sih); + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + core_cap_ext = R_REG(osh, &pmu->core_cap_ext); + max_stats_timer_num = ((core_cap_ext & PCAP_EXT_ST_NUM_MASK) >> PCAP_EXT_ST_NUM_SHIFT) + 1; + + for (i = 0; i < max_stats_timer_num; i++) { + W_REG(osh, &pmu->pmu_statstimer_addr, i); + timerN = R_REG(osh, &pmu->pmu_statstimer_N); + if (timerN == 0xFFFFFFFF) { + PMU_ERROR(("pmustatstimer overflow clear - timerid : %d\n", i)); + si_pmustatstimer_clear(sih, i); + } + } + + /* Return to original core */ + si_setcoreidx(sih, origidx); +} + +uint32 +si_pmustatstimer_read(si_t *sih, uint8 timerid) +{ + pmuregs_t *pmu; + uint origidx; + osl_t *osh = si_osh(sih); + uint32 stats_timer_N; + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + W_REG(osh, &pmu->pmu_statstimer_addr, timerid); + stats_timer_N = R_REG(osh, &pmu->pmu_statstimer_N); + + /* Return to original core */ + si_setcoreidx(sih, origidx); + + return stats_timer_N; +} + +void +si_pmustatstimer_cfg_src_num(si_t *sih, uint8 src_num, uint8 timerid) +{ + pmuregs_t *pmu; + uint origidx; + osl_t *osh = si_osh(sih); + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + pmustatstimer[timerid].src_num = src_num; + si_pmustatstimer_update(osh, pmu, timerid); + + /* Return to original core */ + si_setcoreidx(sih, origidx); +} + +void +si_pmustatstimer_cfg_cnt_mode(si_t *sih, uint8 cnt_mode, uint8 timerid) +{ + pmuregs_t *pmu; + uint origidx; + osl_t *osh = si_osh(sih); + + /* Remember original core before switch to chipc/pmu */ + origidx = si_coreidx(sih); + if (AOB_ENAB(sih)) { + pmu = si_setcore(sih, PMU_CORE_ID, 0); + } else { + pmu = si_setcoreidx(sih, SI_CC_IDX); + } + ASSERT(pmu != NULL); + + pmustatstimer[timerid].cnt_mode = cnt_mode; + si_pmustatstimer_update(osh, pmu, timerid); + + /* Return to original core */ + si_setcoreidx(sih, origidx); +} +#endif /* BCMPMU_STATS */ -- Gitblit v1.6.2