Merge tag 'lsk-v4.4-16.06-android'
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rkwifi / bcmdhd / hndpmu.c
1 /*
2  * Misc utility routines for accessing PMU corerev specific features
3  * of the SiliconBackplane-based Broadcom chips.
4  *
5  * Copyright (C) 1999-2016, 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 530092 2015-01-29 04:44:58Z $
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
53 #define PMU_ERROR(args)
54
55 #define PMU_MSG(args)
56
57 /* To check in verbose debugging messages not intended
58  * to be on except on private builds.
59  */
60 #define PMU_NONE(args)
61
62 /** contains resource bit positions for a specific chip */
63 struct rsc_per_chip_s {
64         uint8 ht_avail;
65         uint8 macphy_clkavail;
66         uint8 ht_start;
67         uint8 otp_pu;
68 };
69
70 typedef struct rsc_per_chip_s rsc_per_chip_t;
71
72
73 /* SDIO Pad drive strength to select value mappings.
74  * The last strength value in each table must be 0 (the tri-state value).
75  */
76 typedef struct {
77         uint8 strength;                 /* Pad Drive Strength in mA */
78         uint8 sel;                      /* Chip-specific select value */
79 } sdiod_drive_str_t;
80
81 /* SDIO Drive Strength to sel value table for PMU Rev 1 */
82 static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = {
83         {4, 0x2},
84         {2, 0x3},
85         {1, 0x0},
86         {0, 0x0} };
87
88 /* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
89 static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = {
90         {12, 0x7},
91         {10, 0x6},
92         {8, 0x5},
93         {6, 0x4},
94         {4, 0x2},
95         {2, 0x1},
96         {0, 0x0} };
97
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[] = {
100         {32, 0x7},
101         {26, 0x6},
102         {22, 0x5},
103         {16, 0x4},
104         {12, 0x3},
105         {8, 0x2},
106         {4, 0x1},
107         {0, 0x0} };
108
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[] = {
111         {32, 0x6},
112         {26, 0x7},
113         {22, 0x4},
114         {16, 0x5},
115         {12, 0x2},
116         {8, 0x3},
117         {4, 0x0},
118         {0, 0x1} };
119
120 /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */
121
122 /* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */
123
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[] = {
126         {6, 0x7},
127         {5, 0x6},
128         {4, 0x5},
129         {3, 0x4},
130         {2, 0x2},
131         {1, 0x1},
132         {0, 0x0} };
133
134 /* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */
135
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[] = {
138         {3, 0x3},
139         {2, 0x2},
140         {1, 0x1},
141         {0, 0x0} };
142
143
144 /**
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
148  * been written '1'.
149  */
150 #if !defined(BCM_SDIO_VDDIO) || BCM_SDIO_VDDIO == 33
151
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 */
154         {16, 0x7},
155         {12, 0x5},
156         {8,  0x3},
157         {4,  0x1} }; /* note: 43143 does not support tristate */
158
159 #else
160
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 */
163         {8, 0x7},
164         {6, 0x5},
165         {4,  0x3},
166         {2,  0x1} }; /* note: 43143 does not support tristate */
167
168 #endif /* BCM_SDIO_VDDIO */
169
170 #define SDIOD_DRVSTR_KEY(chip, pmu)     (((chip) << 16) | (pmu))
171
172 /**
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.
177  *
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.
180  */
181 void
182 si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength)
183 {
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 */
189         pmuregs_t *pmu;
190         uint origidx;
191
192         if (!(sih->cccaps & CC_CAP_PMU)) {
193                 return;
194         }
195
196         /* Remember original core before switch to chipc/pmu */
197         origidx = si_coreidx(sih);
198         if (AOB_ENAB(sih)) {
199                 pmu = si_setcore(sih, PMU_CORE_ID, 0);
200         } else {
201                 pmu = si_setcoreidx(sih, SI_CC_IDX);
202         }
203         ASSERT(pmu != NULL);
204
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;
209                 str_shift = 28;
210                 break;
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;
216                 str_shift = 11;
217                 break;
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;
222                 }
223                 else if (sih->pmurev == 11) {
224                         str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8;
225                 }
226                 str_mask = 0x00003800;
227                 str_shift = 11;
228                 break;
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;
232                 str_shift = 11;
233                 break;
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;
237                 str_shift = 11;
238                 break;
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;
242                 str_shift = 11;
243                 break;
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;
248                 }
249 #else
250                 if (drivestrength >=  ARRAYLAST(sdiod_drive_strength_tab7_1v8)->strength) {
251                         str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab7_1v8;
252                 }
253 #endif /* BCM_SDIO_VDDIO */
254                 str_mask = 0x00000007;
255                 str_ovr_pmuval = PMU43143_CC0_SDIO_DRSTR_OVR;
256                 break;
257         default:
258                 PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
259                          bcm_chipname(
260                          CHIPID(sih->chip), chn, 8), CHIPREV(sih->chiprev), sih->pmurev));
261                 break;
262         }
263
264         if (str_tab != NULL) {
265                 uint32 cc_data_temp;
266                 int i;
267
268                 /* Pick the lowest available drive strength equal or greater than the
269                  * requested strength.  Drive strength of 0 requests tri-state.
270                  */
271                 for (i = 0; drivestrength < str_tab[i].strength; i++)
272                         ;
273
274                 if (i > 0 && drivestrength > str_tab[i].strength)
275                         i--;
276
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);
285                 }
286                 PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n",
287                          drivestrength, str_tab[i].strength));
288         }
289
290         /* Return to original core */
291         si_setcoreidx(sih, origidx);
292 } /* si_sdiod_drive_strength_init */