• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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