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