1 /*
2 * Misc utility routines for accessing PMU corerev specific features
3 * of the SiliconBackplane-based Broadcom chips.
4 *
5 * Copyright (C) 1999-2017, Broadcom Corporation
6 *
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:
12 *
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.
20 *
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.
24 *
25 *
26 * <<Broadcom-WL-IPTag/Open:>>
27 *
28 * $Id: hndpmu.c 657872 2016-09-02 22:17:34Z $
29 */
30
31
32 /*
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.
35 *
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.
40 */
41
42 #include <bcm_cfg.h>
43 #include <typedefs.h>
44 #include <bcmdefs.h>
45 #include <osl.h>
46 #include <bcmutils.h>
47 #include <siutils.h>
48 #include <bcmdevs.h>
49 #include <hndsoc.h>
50 #include <sbchipc.h>
51 #include <hndpmu.h>
52 #if defined(BCMULP)
53 #include <ulp.h>
54 #endif /* defined(BCMULP) */
55 #include <sbgci.h>
56 #ifdef EVENT_LOG_COMPILE
57 #include <event_log.h>
58 #endif
59 #include <sbgci.h>
60
61 #define PMU_ERROR(args)
62
63 #define PMU_MSG(args)
64
65 /* To check in verbose debugging messages not intended
66 * to be on except on private builds.
67 */
68 #define PMU_NONE(args)
69
70 /** contains resource bit positions for a specific chip */
71 struct rsc_per_chip_s {
72 uint8 ht_avail;
73 uint8 macphy_clkavail;
74 uint8 ht_start;
75 uint8 otp_pu;
76 };
77
78 typedef struct rsc_per_chip_s rsc_per_chip_t;
79
80
81 /* SDIO Pad drive strength to select value mappings.
82 * The last strength value in each table must be 0 (the tri-state value).
83 */
84 typedef struct {
85 uint8 strength; /* Pad Drive Strength in mA */
86 uint8 sel; /* Chip-specific select value */
87 } sdiod_drive_str_t;
88
89 /* SDIO Drive Strength to sel value table for PMU Rev 1 */
90 static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = {
91 {4, 0x2},
92 {2, 0x3},
93 {1, 0x0},
94 {0, 0x0} };
95
96 /* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
97 static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = {
98 {12, 0x7},
99 {10, 0x6},
100 {8, 0x5},
101 {6, 0x4},
102 {4, 0x2},
103 {2, 0x1},
104 {0, 0x0} };
105
106
107 /* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
108 static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = {
109 {32, 0x7},
110 {26, 0x6},
111 {22, 0x5},
112 {16, 0x4},
113 {12, 0x3},
114 {8, 0x2},
115 {4, 0x1},
116 {0, 0x0} };
117
118 /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */
119 static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = {
120 {32, 0x6},
121 {26, 0x7},
122 {22, 0x4},
123 {16, 0x5},
124 {12, 0x2},
125 {8, 0x3},
126 {4, 0x0},
127 {0, 0x1} };
128
129 /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */
130
131 /* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */
132
133 /* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
134 static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = {
135 {6, 0x7},
136 {5, 0x6},
137 {4, 0x5},
138 {3, 0x4},
139 {2, 0x2},
140 {1, 0x1},
141 {0, 0x0} };
142
143 /* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */
144
145 /** SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
146 static const sdiod_drive_str_t sdiod_drive_strength_tab6_1v8[] = {
147 {3, 0x3},
148 {2, 0x2},
149 {1, 0x1},
150 {0, 0x0} };
151
152
153 /**
154 * SDIO Drive Strength to sel value table for 43143 PMU Rev 17, see Confluence 43143 Toplevel
155 * architecture page, section 'PMU Chip Control 1 Register definition', click link to picture
156 * BCM43143_sel_sdio_signals.jpg. Valid after PMU Chip Control 0 Register, bit31 (override) has
157 * been written '1'.
158 */
159 #if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33
160
161 static const sdiod_drive_str_t sdiod_drive_strength_tab7_3v3[] = {
162 /* note: for 14, 10, 6 and 2mA hw timing is not met according to rtl team */
163 {16, 0x7},
164 {12, 0x5},
165 {8, 0x3},
166 {4, 0x1} }; /* note: 43143 does not support tristate */
167
168 #else
169
170 static const sdiod_drive_str_t sdiod_drive_strength_tab7_1v8[] = {
171 /* note: for 7, 5, 3 and 1mA hw timing is not met according to rtl team */
172 {8, 0x7},
173 {6, 0x5},
174 {4, 0x3},
175 {2, 0x1} }; /* note: 43143 does not support tristate */
176
177 #endif /* BCM_SDIO_VDDIO */
178
179 #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
180
181 /**
182 * Balance between stable SDIO operation and power consumption is achieved using this function.
183 * Note that each drive strength table is for a specific VDDIO of the SDIO pads, ideally this
184 * function should read the VDDIO itself to select the correct table. For now it has been solved
185 * with the 'BCM_SDIO_VDDIO' preprocessor constant.
186 *
187 * 'drivestrength': desired pad drive strength in mA. Drive strength of 0 requests tri-state (if
188 * hardware supports this), if no hw support drive strength is not programmed.
189 */
190 void
si_sdiod_drive_strength_init(si_t * sih,osl_t * osh,uint32 drivestrength)191 si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength)
192 {
193 sdiod_drive_str_t *str_tab = NULL;
194 uint32 str_mask = 0; /* only alter desired bits in PMU chipcontrol 1 register */
195 uint32 str_shift = 0;
196 uint32 str_ovr_pmuctl = PMU_CHIPCTL0; /* PMU chipcontrol register containing override bit */
197 uint32 str_ovr_pmuval = 0; /* position of bit within this register */
198 pmuregs_t *pmu;
199 uint origidx;
200
201 if (!(sih->cccaps & CC_CAP_PMU)) {
202 return;
203 }
204 BCM_REFERENCE(sdiod_drive_strength_tab1);
205 BCM_REFERENCE(sdiod_drive_strength_tab2);
206 /* Remember original core before switch to chipc/pmu */
207 origidx = si_coreidx(sih);
208 if (AOB_ENAB(sih)) {
209 pmu = si_setcore(sih, PMU_CORE_ID, 0);
210 } else {
211 pmu = si_setcoreidx(sih, SI_CC_IDX);
212 }
213 ASSERT(pmu != NULL);
214
215 switch (SDIOD_DRVSTR_KEY(CHIPID(sih->chip), PMUREV(sih->pmurev))) {
216 case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
217 case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11):
218 if (PMUREV(sih->pmurev) == 8) {
219 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3;
220 } else if (PMUREV(sih->pmurev) == 11) {
221 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8;
222 }
223 str_mask = 0x00003800;
224 str_shift = 11;
225 break;
226 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
227 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8;
228 str_mask = 0x00003800;
229 str_shift = 11;
230 break;
231 case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
232 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8;
233 str_mask = 0x00003800;
234 str_shift = 11;
235 break;
236 case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
237 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab6_1v8;
238 str_mask = 0x00001800;
239 str_shift = 11;
240 break;
241 case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
242 #if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33
243 if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_3v3)->strength) {
244 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_3v3;
245 }
246 #else
247 if (drivestrength >= ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) {
248 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8;
249 }
250 #endif /* BCM_SDIO_VDDIO */
251 str_mask = 0x00000007;
252 str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR;
253 break;
254 default:
255 PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
256 bcm_chipname(
257 CHIPID(sih->chip), chn, 8), CHIPREV(sih->chiprev), PMUREV(sih->pmurev)));
258 break;
259 }
260
261 if (str_tab != NULL) {
262 uint32 cc_data_temp;
263 int i;
264
265 /* Pick the lowest available drive strength equal or greater than the
266 * requested strength. Drive strength of 0 requests tri-state.
267 */
268 for (i = 0; drivestrength < str_tab[i].strength; i++)
269 ;
270
271 if (i > 0 && drivestrength > str_tab[i].strength)
272 i--;
273
274 W_REG(osh, &pmu->chipcontrol_addr, PMU_CHIPCTL1);
275 cc_data_temp = R_REG(osh, &pmu->chipcontrol_data);
276 cc_data_temp &= ~str_mask;
277 cc_data_temp |= str_tab[i].sel << str_shift;
278 W_REG(osh, &pmu->chipcontrol_data, cc_data_temp);
279 if (str_ovr_pmuval) { /* enables the selected drive strength */
280 W_REG(osh, &pmu->chipcontrol_addr, str_ovr_pmuctl);
281 OR_REG(osh, &pmu->chipcontrol_data, str_ovr_pmuval);
282 }
283 PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n",
284 drivestrength, str_tab[i].strength));
285 }
286
287 /* Return to original core */
288 si_setcoreidx(sih, origidx);
289 } /* si_sdiod_drive_strength_init */
290
291
292 #if defined(BCMULP)
293 int
si_pmu_ulp_register(si_t * sih)294 si_pmu_ulp_register(si_t *sih)
295 {
296 return ulp_p1_module_register(ULP_MODULE_ID_PMU, &ulp_pmu_ctx, (void *)sih);
297 }
298
299 static uint
si_pmu_ulp_get_retention_size_cb(void * handle,ulp_ext_info_t * einfo)300 si_pmu_ulp_get_retention_size_cb(void *handle, ulp_ext_info_t *einfo)
301 {
302 ULP_DBG(("%s: sz: %d\n", __FUNCTION__, sizeof(si_pmu_ulp_cr_dat_t)));
303 return sizeof(si_pmu_ulp_cr_dat_t);
304 }
305
306 static int
si_pmu_ulp_enter_cb(void * handle,ulp_ext_info_t * einfo,uint8 * cache_data)307 si_pmu_ulp_enter_cb(void *handle, ulp_ext_info_t *einfo, uint8 *cache_data)
308 {
309 si_pmu_ulp_cr_dat_t crinfo = {0};
310 crinfo.ilpcycles_per_sec = ilpcycles_per_sec;
311 ULP_DBG(("%s: ilpcycles_per_sec: %x\n", __FUNCTION__, ilpcycles_per_sec));
312 memcpy(cache_data, (void*)&crinfo, sizeof(crinfo));
313 return BCME_OK;
314 }
315
316 static int
si_pmu_ulp_exit_cb(void * handle,uint8 * cache_data,uint8 * p2_cache_data)317 si_pmu_ulp_exit_cb(void *handle, uint8 *cache_data,
318 uint8 *p2_cache_data)
319 {
320 si_pmu_ulp_cr_dat_t *crinfo = (si_pmu_ulp_cr_dat_t *)cache_data;
321
322 ilpcycles_per_sec = crinfo->ilpcycles_per_sec;
323 ULP_DBG(("%s: ilpcycles_per_sec: %x, cache_data: %p\n", __FUNCTION__,
324 ilpcycles_per_sec, cache_data));
325 return BCME_OK;
326 }
327
328 void
si_pmu_ulp_ilp_config(si_t * sih,osl_t * osh,uint32 ilp_period)329 si_pmu_ulp_ilp_config(si_t *sih, osl_t *osh, uint32 ilp_period)
330 {
331 pmuregs_t *pmu;
332 pmu = si_setcoreidx(sih, si_findcoreidx(sih, PMU_CORE_ID, 0));
333 W_REG(osh, &pmu->ILPPeriod, ilp_period);
334 }
335 #endif /* defined(BCMULP) */
336
337
338
si_pmu_set_min_res_mask(si_t * sih,osl_t * osh,uint min_res_mask)339 void si_pmu_set_min_res_mask(si_t *sih, osl_t *osh, uint min_res_mask)
340 {
341 pmuregs_t *pmu;
342 uint origidx;
343
344 /* Remember original core before switch to chipc/pmu */
345 origidx = si_coreidx(sih);
346 if (AOB_ENAB(sih)) {
347 pmu = si_setcore(sih, PMU_CORE_ID, 0);
348 }
349 else {
350 pmu = si_setcoreidx(sih, SI_CC_IDX);
351 }
352 ASSERT(pmu != NULL);
353
354 W_REG(osh, &pmu->min_res_mask, min_res_mask);
355 OSL_DELAY(100);
356
357 /* Return to original core */
358 si_setcoreidx(sih, origidx);
359 }
360
361 bool
si_pmu_cap_fast_lpo(si_t * sih)362 si_pmu_cap_fast_lpo(si_t *sih)
363 {
364 return (PMU_REG(sih, core_cap_ext, 0, 0) & PCAP_EXT_USE_MUXED_ILP_CLK_MASK) ? TRUE : FALSE;
365 }
366
367 int
si_pmu_fast_lpo_disable(si_t * sih)368 si_pmu_fast_lpo_disable(si_t *sih)
369 {
370 if (!si_pmu_cap_fast_lpo(sih)) {
371 PMU_ERROR(("%s: No Fast LPO capability\n", __FUNCTION__));
372 return BCME_ERROR;
373 }
374
375 PMU_REG(sih, pmucontrol_ext,
376 PCTL_EXT_FASTLPO_ENAB |
377 PCTL_EXT_FASTLPO_SWENAB |
378 PCTL_EXT_FASTLPO_PCIE_SWENAB,
379 0);
380 OSL_DELAY(1000);
381 return BCME_OK;
382 }
383