2 * Misc utility routines for accessing PMU corerev specific features
3 * of the SiliconBackplane-based Broadcom chips.
5 * Copyright (C) 1999-2016, Broadcom Corporation
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
26 * <<Broadcom-WL-IPTag/Open:>>
28 * $Id: hndpmu.c 530092 2015-01-29 04:44:58Z $
33 * Note: this file contains PLL/FLL related functions. A chip can contain multiple PLLs/FLLs.
34 * However, in the context of this file the baseband ('BB') PLL/FLL is referred to.
36 * Throughout this code, the prefixes 'pmu0_', 'pmu1_' and 'pmu2_' are used.
37 * They refer to different revisions of the PMU (which is at revision 18 @ Apr 25, 2012)
38 * pmu1_ marks the transition from PLL to ADFLL (Digital Frequency Locked Loop). It supports
39 * fractional frequency generation. pmu2_ does not support fractional frequency generation.
53 #define PMU_ERROR(args)
57 /* To check in verbose debugging messages not intended
58 * to be on except on private builds.
60 #define PMU_NONE(args)
62 /** contains resource bit positions for a specific chip */
63 struct rsc_per_chip_s {
65 uint8 macphy_clkavail;
70 typedef struct rsc_per_chip_s rsc_per_chip_t;
73 /* SDIO Pad drive strength to select value mappings.
74 * The last strength value in each table must be 0 (the tri-state value).
77 uint8 strength; /* Pad Drive Strength in mA */
78 uint8 sel; /* Chip-specific select value */
81 /* SDIO Drive Strength to sel value table for PMU Rev 1 */
82 static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = {
88 /* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
89 static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = {
98 /* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
99 static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = {
109 /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */
110 static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = {
120 /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */
122 /* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */
124 /* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
125 static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = {
134 /* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */
136 /** SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
137 static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = {
145 * SDIO Drive Strength to sel value table for 43143 PMU Rev 17, see Confluence 43143 Toplevel
146 * architecture page, section 'PMU Chip Control 1 Register definition', click link to picture
147 * BCM43143_sel_sdio_signals.jpg. Valid after PMU Chip Control 0 Register, bit31 (override) has
150 #if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33
152 static const sdiod_drive_str_t sdiod_drive_strength_tab7_3v3[] = {
153 /* note: for 14, 10, 6 and 2mA hw timing is not met according to rtl team */
157 {4, 0x1} }; /* note: 43143 does not support tristate */
161 static const sdiod_drive_str_t sdiod_drive_strength_tab7_1v8[] = {
162 /* note: for 7, 5, 3 and 1mA hw timing is not met according to rtl team */
166 {2, 0x1} }; /* note: 43143 does not support tristate */
168 #endif /* BCM_SDIO_VDDIO */
170 #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
173 * Balance between stable SDIO operation and power consumption is achieved using this function.
174 * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this
175 * function should read the VDDIO itself to select the correct table. For now it has been solved
176 * with the 'BCM_SDIO_VDDIO' preprocessor constant.
178 * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if
179 * hardware supports this), if no hw support drive strength is not programmed.
182 si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength)
184 sdiod_drive_str_t *str_tab = NULL;
185 uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */
186 uint32 str_shift = 0;
187 uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */
188 uint32 str_ovr_pmuval = 0; /* position of bit within this register */
192 if (!(sih->cccaps & CC_CAP_PMU)) {
196 /* Remember original core before switch to chipc/pmu */
197 origidx = si_coreidx(sih);
199 pmu = si_setcore(sih, PMU_CORE_ID, 0);
201 pmu = si_setcoreidx(sih, SI_CC_IDX);
205 switch (SDIOD_DRVSTR_KEY(CHIPID(sih->chip), sih->pmurev)) {
206 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
207 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1;
208 str_mask = 0x30000000;
211 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
212 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
213 case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4):
214 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2;
215 str_mask = 0x00003800;
218 case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
219 case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11):
220 if (sih->pmurev == 8) {
221 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3;
223 else if (sih->pmurev == 11) {
224 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8;
226 str_mask = 0x00003800;
229 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
230 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8;
231 str_mask = 0x00003800;
234 case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
235 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8;
236 str_mask = 0x00003800;
239 case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
240 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8;
241 str_mask = 0x00001800;
244 case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
245 #if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33
246 if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) {
247 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3;
250 if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) {
251 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8;
253 #endif /* BCM_SDIO_VDDIO */
254 str_mask = 0x00000007;
255 str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR;
258 PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
260 CHIPID(sih->chip), chn, 8), CHIPREV(sih->chiprev), sih->pmurev));
264 if (str_tab != NULL) {
268 /* Pick the lowest available drive strength equal or greater than the
269 * requested strength. Drive strength of 0 requests tri-state.
271 for (i = 0; drivestrength < str_tab[i].strength; i++)
274 if (i > 0 && drivestrength > str_tab[i].strength)
277 W_REG(osh, &pmu->chipcontrol_addr, PMU_CHIPCTL1);
278 cc_data_temp = R_REG(osh, &pmu->chipcontrol_data);
279 cc_data_temp &= ~str_mask;
280 cc_data_temp |= str_tab[i].sel << str_shift;
281 W_REG(osh, &pmu->chipcontrol_data, cc_data_temp);
282 if (str_ovr_pmuval) { /* enables the selected drive strength */
283 W_REG(osh, &pmu->chipcontrol_addr, str_ovr_pmuctl);
284 OR_REG(osh, &pmu->chipcontrol_data, str_ovr_pmuval);
286 PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n",
287 drivestrength, str_tab[i].strength));
290 /* Return to original core */
291 si_setcoreidx(sih, origidx);
292 } /* si_sdiod_drive_strength_init */