0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include "ssb_private.h"
0012
0013 #include <linux/ssb/ssb.h>
0014 #include <linux/ssb/ssb_regs.h>
0015 #include <linux/ssb/ssb_driver_chipcommon.h>
0016 #include <linux/delay.h>
0017 #include <linux/export.h>
0018 #ifdef CONFIG_BCM47XX
0019 #include <linux/bcm47xx_nvram.h>
0020 #endif
0021
0022 static u32 ssb_chipco_pll_read(struct ssb_chipcommon *cc, u32 offset)
0023 {
0024 chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, offset);
0025 return chipco_read32(cc, SSB_CHIPCO_PLLCTL_DATA);
0026 }
0027
0028 static void ssb_chipco_pll_write(struct ssb_chipcommon *cc,
0029 u32 offset, u32 value)
0030 {
0031 chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, offset);
0032 chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, value);
0033 }
0034
0035 static void ssb_chipco_regctl_maskset(struct ssb_chipcommon *cc,
0036 u32 offset, u32 mask, u32 set)
0037 {
0038 u32 value;
0039
0040 chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR);
0041 chipco_write32(cc, SSB_CHIPCO_REGCTL_ADDR, offset);
0042 chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR);
0043 value = chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA);
0044 value &= mask;
0045 value |= set;
0046 chipco_write32(cc, SSB_CHIPCO_REGCTL_DATA, value);
0047 chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA);
0048 }
0049
0050 struct pmu0_plltab_entry {
0051 u16 freq;
0052 u8 xf;
0053 u8 wb_int;
0054 u32 wb_frac;
0055 };
0056
0057 static const struct pmu0_plltab_entry pmu0_plltab[] = {
0058 { .freq = 12000, .xf = 1, .wb_int = 73, .wb_frac = 349525, },
0059 { .freq = 13000, .xf = 2, .wb_int = 67, .wb_frac = 725937, },
0060 { .freq = 14400, .xf = 3, .wb_int = 61, .wb_frac = 116508, },
0061 { .freq = 15360, .xf = 4, .wb_int = 57, .wb_frac = 305834, },
0062 { .freq = 16200, .xf = 5, .wb_int = 54, .wb_frac = 336579, },
0063 { .freq = 16800, .xf = 6, .wb_int = 52, .wb_frac = 399457, },
0064 { .freq = 19200, .xf = 7, .wb_int = 45, .wb_frac = 873813, },
0065 { .freq = 19800, .xf = 8, .wb_int = 44, .wb_frac = 466033, },
0066 { .freq = 20000, .xf = 9, .wb_int = 44, .wb_frac = 0, },
0067 { .freq = 25000, .xf = 10, .wb_int = 70, .wb_frac = 419430, },
0068 { .freq = 26000, .xf = 11, .wb_int = 67, .wb_frac = 725937, },
0069 { .freq = 30000, .xf = 12, .wb_int = 58, .wb_frac = 699050, },
0070 { .freq = 38400, .xf = 13, .wb_int = 45, .wb_frac = 873813, },
0071 { .freq = 40000, .xf = 14, .wb_int = 45, .wb_frac = 0, },
0072 };
0073 #define SSB_PMU0_DEFAULT_XTALFREQ 20000
0074
0075 static const struct pmu0_plltab_entry * pmu0_plltab_find_entry(u32 crystalfreq)
0076 {
0077 const struct pmu0_plltab_entry *e;
0078 unsigned int i;
0079
0080 for (i = 0; i < ARRAY_SIZE(pmu0_plltab); i++) {
0081 e = &pmu0_plltab[i];
0082 if (e->freq == crystalfreq)
0083 return e;
0084 }
0085
0086 return NULL;
0087 }
0088
0089
0090 static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,
0091 u32 crystalfreq)
0092 {
0093 struct ssb_bus *bus = cc->dev->bus;
0094 const struct pmu0_plltab_entry *e = NULL;
0095 u32 pmuctl, tmp, pllctl;
0096 unsigned int i;
0097
0098 if (crystalfreq)
0099 e = pmu0_plltab_find_entry(crystalfreq);
0100 if (!e)
0101 e = pmu0_plltab_find_entry(SSB_PMU0_DEFAULT_XTALFREQ);
0102 BUG_ON(!e);
0103 crystalfreq = e->freq;
0104 cc->pmu.crystalfreq = e->freq;
0105
0106
0107 pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
0108 if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) {
0109
0110 return;
0111 }
0112
0113 dev_info(cc->dev->dev, "Programming PLL to %u.%03u MHz\n",
0114 crystalfreq / 1000, crystalfreq % 1000);
0115
0116
0117 switch (bus->chip_id) {
0118 case 0x4328:
0119 chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
0120 ~(1 << SSB_PMURES_4328_BB_PLL_PU));
0121 chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
0122 ~(1 << SSB_PMURES_4328_BB_PLL_PU));
0123 break;
0124 case 0x5354:
0125 chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
0126 ~(1 << SSB_PMURES_5354_BB_PLL_PU));
0127 chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
0128 ~(1 << SSB_PMURES_5354_BB_PLL_PU));
0129 break;
0130 default:
0131 WARN_ON(1);
0132 }
0133 for (i = 1500; i; i--) {
0134 tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
0135 if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT))
0136 break;
0137 udelay(10);
0138 }
0139 tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
0140 if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
0141 dev_emerg(cc->dev->dev, "Failed to turn the PLL off!\n");
0142
0143
0144 pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL0);
0145 if (crystalfreq >= SSB_PMU0_PLLCTL0_PDIV_FREQ)
0146 pllctl |= SSB_PMU0_PLLCTL0_PDIV_MSK;
0147 else
0148 pllctl &= ~SSB_PMU0_PLLCTL0_PDIV_MSK;
0149 ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL0, pllctl);
0150
0151
0152 pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL1);
0153 pllctl &= ~SSB_PMU0_PLLCTL1_STOPMOD;
0154 pllctl &= ~(SSB_PMU0_PLLCTL1_WILD_IMSK | SSB_PMU0_PLLCTL1_WILD_FMSK);
0155 pllctl |= ((u32)e->wb_int << SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_IMSK;
0156 pllctl |= ((u32)e->wb_frac << SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_FMSK;
0157 if (e->wb_frac == 0)
0158 pllctl |= SSB_PMU0_PLLCTL1_STOPMOD;
0159 ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL1, pllctl);
0160
0161
0162 pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL2);
0163 pllctl &= ~SSB_PMU0_PLLCTL2_WILD_IMSKHI;
0164 pllctl |= (((u32)e->wb_int >> 4) << SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT) & SSB_PMU0_PLLCTL2_WILD_IMSKHI;
0165 ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL2, pllctl);
0166
0167
0168 pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
0169 pmuctl &= ~SSB_CHIPCO_PMU_CTL_ILP_DIV;
0170 pmuctl |= (((crystalfreq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT)
0171 & SSB_CHIPCO_PMU_CTL_ILP_DIV;
0172 pmuctl &= ~SSB_CHIPCO_PMU_CTL_XTALFREQ;
0173 pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ;
0174 chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl);
0175 }
0176
0177 struct pmu1_plltab_entry {
0178 u16 freq;
0179 u8 xf;
0180 u8 ndiv_int;
0181 u32 ndiv_frac;
0182 u8 p1div;
0183 u8 p2div;
0184 };
0185
0186 static const struct pmu1_plltab_entry pmu1_plltab[] = {
0187 { .freq = 12000, .xf = 1, .p1div = 3, .p2div = 22, .ndiv_int = 0x9, .ndiv_frac = 0xFFFFEF, },
0188 { .freq = 13000, .xf = 2, .p1div = 1, .p2div = 6, .ndiv_int = 0xb, .ndiv_frac = 0x483483, },
0189 { .freq = 14400, .xf = 3, .p1div = 1, .p2div = 10, .ndiv_int = 0xa, .ndiv_frac = 0x1C71C7, },
0190 { .freq = 15360, .xf = 4, .p1div = 1, .p2div = 5, .ndiv_int = 0xb, .ndiv_frac = 0x755555, },
0191 { .freq = 16200, .xf = 5, .p1div = 1, .p2div = 10, .ndiv_int = 0x5, .ndiv_frac = 0x6E9E06, },
0192 { .freq = 16800, .xf = 6, .p1div = 1, .p2div = 10, .ndiv_int = 0x5, .ndiv_frac = 0x3CF3CF, },
0193 { .freq = 19200, .xf = 7, .p1div = 1, .p2div = 9, .ndiv_int = 0x5, .ndiv_frac = 0x17B425, },
0194 { .freq = 19800, .xf = 8, .p1div = 1, .p2div = 11, .ndiv_int = 0x4, .ndiv_frac = 0xA57EB, },
0195 { .freq = 20000, .xf = 9, .p1div = 1, .p2div = 11, .ndiv_int = 0x4, .ndiv_frac = 0, },
0196 { .freq = 24000, .xf = 10, .p1div = 3, .p2div = 11, .ndiv_int = 0xa, .ndiv_frac = 0, },
0197 { .freq = 25000, .xf = 11, .p1div = 5, .p2div = 16, .ndiv_int = 0xb, .ndiv_frac = 0, },
0198 { .freq = 26000, .xf = 12, .p1div = 1, .p2div = 2, .ndiv_int = 0x10, .ndiv_frac = 0xEC4EC4, },
0199 { .freq = 30000, .xf = 13, .p1div = 3, .p2div = 8, .ndiv_int = 0xb, .ndiv_frac = 0, },
0200 { .freq = 38400, .xf = 14, .p1div = 1, .p2div = 5, .ndiv_int = 0x4, .ndiv_frac = 0x955555, },
0201 { .freq = 40000, .xf = 15, .p1div = 1, .p2div = 2, .ndiv_int = 0xb, .ndiv_frac = 0, },
0202 };
0203
0204 #define SSB_PMU1_DEFAULT_XTALFREQ 15360
0205
0206 static const struct pmu1_plltab_entry * pmu1_plltab_find_entry(u32 crystalfreq)
0207 {
0208 const struct pmu1_plltab_entry *e;
0209 unsigned int i;
0210
0211 for (i = 0; i < ARRAY_SIZE(pmu1_plltab); i++) {
0212 e = &pmu1_plltab[i];
0213 if (e->freq == crystalfreq)
0214 return e;
0215 }
0216
0217 return NULL;
0218 }
0219
0220
0221 static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,
0222 u32 crystalfreq)
0223 {
0224 struct ssb_bus *bus = cc->dev->bus;
0225 const struct pmu1_plltab_entry *e = NULL;
0226 u32 buffer_strength = 0;
0227 u32 tmp, pllctl, pmuctl;
0228 unsigned int i;
0229
0230 if (bus->chip_id == 0x4312) {
0231
0232
0233 cc->pmu.crystalfreq = 20000;
0234 return;
0235 }
0236
0237 if (crystalfreq)
0238 e = pmu1_plltab_find_entry(crystalfreq);
0239 if (!e)
0240 e = pmu1_plltab_find_entry(SSB_PMU1_DEFAULT_XTALFREQ);
0241 BUG_ON(!e);
0242 crystalfreq = e->freq;
0243 cc->pmu.crystalfreq = e->freq;
0244
0245
0246 pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
0247 if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) {
0248
0249 return;
0250 }
0251
0252 dev_info(cc->dev->dev, "Programming PLL to %u.%03u MHz\n",
0253 crystalfreq / 1000, crystalfreq % 1000);
0254
0255
0256 switch (bus->chip_id) {
0257 case 0x4325:
0258 chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
0259 ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) |
0260 (1 << SSB_PMURES_4325_HT_AVAIL)));
0261 chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
0262 ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) |
0263 (1 << SSB_PMURES_4325_HT_AVAIL)));
0264
0265 buffer_strength = 0x222222;
0266 break;
0267 default:
0268 WARN_ON(1);
0269 }
0270 for (i = 1500; i; i--) {
0271 tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
0272 if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT))
0273 break;
0274 udelay(10);
0275 }
0276 tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
0277 if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
0278 dev_emerg(cc->dev->dev, "Failed to turn the PLL off!\n");
0279
0280
0281 pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL0);
0282 pllctl &= ~(SSB_PMU1_PLLCTL0_P1DIV | SSB_PMU1_PLLCTL0_P2DIV);
0283 pllctl |= ((u32)e->p1div << SSB_PMU1_PLLCTL0_P1DIV_SHIFT) & SSB_PMU1_PLLCTL0_P1DIV;
0284 pllctl |= ((u32)e->p2div << SSB_PMU1_PLLCTL0_P2DIV_SHIFT) & SSB_PMU1_PLLCTL0_P2DIV;
0285 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, pllctl);
0286
0287
0288 pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL2);
0289 pllctl &= ~(SSB_PMU1_PLLCTL2_NDIVINT | SSB_PMU1_PLLCTL2_NDIVMODE);
0290 pllctl |= ((u32)e->ndiv_int << SSB_PMU1_PLLCTL2_NDIVINT_SHIFT) & SSB_PMU1_PLLCTL2_NDIVINT;
0291 pllctl |= (1 << SSB_PMU1_PLLCTL2_NDIVMODE_SHIFT) & SSB_PMU1_PLLCTL2_NDIVMODE;
0292 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, pllctl);
0293
0294
0295 pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL3);
0296 pllctl &= ~SSB_PMU1_PLLCTL3_NDIVFRAC;
0297 pllctl |= ((u32)e->ndiv_frac << SSB_PMU1_PLLCTL3_NDIVFRAC_SHIFT) & SSB_PMU1_PLLCTL3_NDIVFRAC;
0298 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, pllctl);
0299
0300
0301 if (buffer_strength) {
0302 pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL5);
0303 pllctl &= ~SSB_PMU1_PLLCTL5_CLKDRV;
0304 pllctl |= (buffer_strength << SSB_PMU1_PLLCTL5_CLKDRV_SHIFT) & SSB_PMU1_PLLCTL5_CLKDRV;
0305 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, pllctl);
0306 }
0307
0308
0309 pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
0310 pmuctl &= ~(SSB_CHIPCO_PMU_CTL_ILP_DIV | SSB_CHIPCO_PMU_CTL_XTALFREQ);
0311 pmuctl |= ((((u32)e->freq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT)
0312 & SSB_CHIPCO_PMU_CTL_ILP_DIV;
0313 pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ;
0314 chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl);
0315 }
0316
0317 static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
0318 {
0319 struct ssb_bus *bus = cc->dev->bus;
0320 u32 crystalfreq = 0;
0321
0322 if (bus->bustype == SSB_BUSTYPE_SSB) {
0323 #ifdef CONFIG_BCM47XX
0324 char buf[20];
0325 if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
0326 crystalfreq = simple_strtoul(buf, NULL, 0);
0327 #endif
0328 }
0329
0330 switch (bus->chip_id) {
0331 case 0x4312:
0332 case 0x4325:
0333 ssb_pmu1_pllinit_r0(cc, crystalfreq);
0334 break;
0335 case 0x4328:
0336 ssb_pmu0_pllinit_r0(cc, crystalfreq);
0337 break;
0338 case 0x5354:
0339 if (crystalfreq == 0)
0340 crystalfreq = 25000;
0341 ssb_pmu0_pllinit_r0(cc, crystalfreq);
0342 break;
0343 case 0x4322:
0344 if (cc->pmu.rev == 2) {
0345 chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, 0x0000000A);
0346 chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0);
0347 }
0348 break;
0349 case 43222:
0350 break;
0351 default:
0352 dev_err(cc->dev->dev, "ERROR: PLL init unknown for device %04X\n",
0353 bus->chip_id);
0354 }
0355 }
0356
0357 struct pmu_res_updown_tab_entry {
0358 u8 resource;
0359 u16 updown;
0360 };
0361
0362 enum pmu_res_depend_tab_task {
0363 PMU_RES_DEP_SET = 1,
0364 PMU_RES_DEP_ADD,
0365 PMU_RES_DEP_REMOVE,
0366 };
0367
0368 struct pmu_res_depend_tab_entry {
0369 u8 resource;
0370 u8 task;
0371 u32 depend;
0372 };
0373
0374 static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4328a0[] = {
0375 { .resource = SSB_PMURES_4328_EXT_SWITCHER_PWM, .updown = 0x0101, },
0376 { .resource = SSB_PMURES_4328_BB_SWITCHER_PWM, .updown = 0x1F01, },
0377 { .resource = SSB_PMURES_4328_BB_SWITCHER_BURST, .updown = 0x010F, },
0378 { .resource = SSB_PMURES_4328_BB_EXT_SWITCHER_BURST, .updown = 0x0101, },
0379 { .resource = SSB_PMURES_4328_ILP_REQUEST, .updown = 0x0202, },
0380 { .resource = SSB_PMURES_4328_RADIO_SWITCHER_PWM, .updown = 0x0F01, },
0381 { .resource = SSB_PMURES_4328_RADIO_SWITCHER_BURST, .updown = 0x0F01, },
0382 { .resource = SSB_PMURES_4328_ROM_SWITCH, .updown = 0x0101, },
0383 { .resource = SSB_PMURES_4328_PA_REF_LDO, .updown = 0x0F01, },
0384 { .resource = SSB_PMURES_4328_RADIO_LDO, .updown = 0x0F01, },
0385 { .resource = SSB_PMURES_4328_AFE_LDO, .updown = 0x0F01, },
0386 { .resource = SSB_PMURES_4328_PLL_LDO, .updown = 0x0F01, },
0387 { .resource = SSB_PMURES_4328_BG_FILTBYP, .updown = 0x0101, },
0388 { .resource = SSB_PMURES_4328_TX_FILTBYP, .updown = 0x0101, },
0389 { .resource = SSB_PMURES_4328_RX_FILTBYP, .updown = 0x0101, },
0390 { .resource = SSB_PMURES_4328_XTAL_PU, .updown = 0x0101, },
0391 { .resource = SSB_PMURES_4328_XTAL_EN, .updown = 0xA001, },
0392 { .resource = SSB_PMURES_4328_BB_PLL_FILTBYP, .updown = 0x0101, },
0393 { .resource = SSB_PMURES_4328_RF_PLL_FILTBYP, .updown = 0x0101, },
0394 { .resource = SSB_PMURES_4328_BB_PLL_PU, .updown = 0x0701, },
0395 };
0396
0397 static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4328a0[] = {
0398 {
0399
0400 .resource = SSB_PMURES_4328_ILP_REQUEST,
0401 .task = PMU_RES_DEP_SET,
0402 .depend = ((1 << SSB_PMURES_4328_EXT_SWITCHER_PWM) |
0403 (1 << SSB_PMURES_4328_BB_SWITCHER_PWM)),
0404 },
0405 };
0406
0407 static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4325a0[] = {
0408 { .resource = SSB_PMURES_4325_XTAL_PU, .updown = 0x1501, },
0409 };
0410
0411 static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4325a0[] = {
0412 {
0413
0414 .resource = SSB_PMURES_4325_HT_AVAIL,
0415 .task = PMU_RES_DEP_ADD,
0416 .depend = ((1 << SSB_PMURES_4325_RX_PWRSW_PU) |
0417 (1 << SSB_PMURES_4325_TX_PWRSW_PU) |
0418 (1 << SSB_PMURES_4325_LOGEN_PWRSW_PU) |
0419 (1 << SSB_PMURES_4325_AFE_PWRSW_PU)),
0420 },
0421 };
0422
0423 static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
0424 {
0425 struct ssb_bus *bus = cc->dev->bus;
0426 u32 min_msk = 0, max_msk = 0;
0427 unsigned int i;
0428 const struct pmu_res_updown_tab_entry *updown_tab = NULL;
0429 unsigned int updown_tab_size = 0;
0430 const struct pmu_res_depend_tab_entry *depend_tab = NULL;
0431 unsigned int depend_tab_size = 0;
0432
0433 switch (bus->chip_id) {
0434 case 0x4312:
0435 min_msk = 0xCBB;
0436 break;
0437 case 0x4322:
0438 case 43222:
0439
0440
0441
0442
0443 break;
0444 case 0x4325:
0445
0446 min_msk = (1 << SSB_PMURES_4325_CBUCK_BURST) |
0447 (1 << SSB_PMURES_4325_LNLDO2_PU);
0448 if (chipco_read32(cc, SSB_CHIPCO_CHIPSTAT) &
0449 SSB_CHIPCO_CHST_4325_PMUTOP_2B)
0450 min_msk |= (1 << SSB_PMURES_4325_CLDO_CBUCK_BURST);
0451
0452 max_msk = 0xFFFFF;
0453 updown_tab = pmu_res_updown_tab_4325a0;
0454 updown_tab_size = ARRAY_SIZE(pmu_res_updown_tab_4325a0);
0455 depend_tab = pmu_res_depend_tab_4325a0;
0456 depend_tab_size = ARRAY_SIZE(pmu_res_depend_tab_4325a0);
0457 break;
0458 case 0x4328:
0459 min_msk = (1 << SSB_PMURES_4328_EXT_SWITCHER_PWM) |
0460 (1 << SSB_PMURES_4328_BB_SWITCHER_PWM) |
0461 (1 << SSB_PMURES_4328_XTAL_EN);
0462
0463 max_msk = 0xFFFFF;
0464 updown_tab = pmu_res_updown_tab_4328a0;
0465 updown_tab_size = ARRAY_SIZE(pmu_res_updown_tab_4328a0);
0466 depend_tab = pmu_res_depend_tab_4328a0;
0467 depend_tab_size = ARRAY_SIZE(pmu_res_depend_tab_4328a0);
0468 break;
0469 case 0x5354:
0470
0471 max_msk = 0xFFFFF;
0472 break;
0473 default:
0474 dev_err(cc->dev->dev, "ERROR: PMU resource config unknown for device %04X\n",
0475 bus->chip_id);
0476 }
0477
0478 if (updown_tab) {
0479 for (i = 0; i < updown_tab_size; i++) {
0480 chipco_write32(cc, SSB_CHIPCO_PMU_RES_TABSEL,
0481 updown_tab[i].resource);
0482 chipco_write32(cc, SSB_CHIPCO_PMU_RES_UPDNTM,
0483 updown_tab[i].updown);
0484 }
0485 }
0486 if (depend_tab) {
0487 for (i = 0; i < depend_tab_size; i++) {
0488 chipco_write32(cc, SSB_CHIPCO_PMU_RES_TABSEL,
0489 depend_tab[i].resource);
0490 switch (depend_tab[i].task) {
0491 case PMU_RES_DEP_SET:
0492 chipco_write32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
0493 depend_tab[i].depend);
0494 break;
0495 case PMU_RES_DEP_ADD:
0496 chipco_set32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
0497 depend_tab[i].depend);
0498 break;
0499 case PMU_RES_DEP_REMOVE:
0500 chipco_mask32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
0501 ~(depend_tab[i].depend));
0502 break;
0503 default:
0504 WARN_ON(1);
0505 }
0506 }
0507 }
0508
0509
0510 if (min_msk)
0511 chipco_write32(cc, SSB_CHIPCO_PMU_MINRES_MSK, min_msk);
0512 if (max_msk)
0513 chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk);
0514 }
0515
0516
0517 void ssb_pmu_init(struct ssb_chipcommon *cc)
0518 {
0519 u32 pmucap;
0520
0521 if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU))
0522 return;
0523
0524 pmucap = chipco_read32(cc, SSB_CHIPCO_PMU_CAP);
0525 cc->pmu.rev = (pmucap & SSB_CHIPCO_PMU_CAP_REVISION);
0526
0527 dev_dbg(cc->dev->dev, "Found rev %u PMU (capabilities 0x%08X)\n",
0528 cc->pmu.rev, pmucap);
0529
0530 if (cc->pmu.rev == 1)
0531 chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
0532 ~SSB_CHIPCO_PMU_CTL_NOILPONW);
0533 else
0534 chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
0535 SSB_CHIPCO_PMU_CTL_NOILPONW);
0536 ssb_pmu_pll_init(cc);
0537 ssb_pmu_resources_init(cc);
0538 }
0539
0540 void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc,
0541 enum ssb_pmu_ldo_volt_id id, u32 voltage)
0542 {
0543 struct ssb_bus *bus = cc->dev->bus;
0544 u32 addr, shift, mask;
0545
0546 switch (bus->chip_id) {
0547 case 0x4328:
0548 case 0x5354:
0549 switch (id) {
0550 case LDO_VOLT1:
0551 addr = 2;
0552 shift = 25;
0553 mask = 0xF;
0554 break;
0555 case LDO_VOLT2:
0556 addr = 3;
0557 shift = 1;
0558 mask = 0xF;
0559 break;
0560 case LDO_VOLT3:
0561 addr = 3;
0562 shift = 9;
0563 mask = 0xF;
0564 break;
0565 case LDO_PAREF:
0566 addr = 3;
0567 shift = 17;
0568 mask = 0x3F;
0569 break;
0570 default:
0571 WARN_ON(1);
0572 return;
0573 }
0574 break;
0575 case 0x4312:
0576 if (WARN_ON(id != LDO_PAREF))
0577 return;
0578 addr = 0;
0579 shift = 21;
0580 mask = 0x3F;
0581 break;
0582 default:
0583 return;
0584 }
0585
0586 ssb_chipco_regctl_maskset(cc, addr, ~(mask << shift),
0587 (voltage & mask) << shift);
0588 }
0589
0590 void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on)
0591 {
0592 struct ssb_bus *bus = cc->dev->bus;
0593 int ldo;
0594
0595 switch (bus->chip_id) {
0596 case 0x4312:
0597 ldo = SSB_PMURES_4312_PA_REF_LDO;
0598 break;
0599 case 0x4328:
0600 ldo = SSB_PMURES_4328_PA_REF_LDO;
0601 break;
0602 case 0x5354:
0603 ldo = SSB_PMURES_5354_PA_REF_LDO;
0604 break;
0605 default:
0606 return;
0607 }
0608
0609 if (on)
0610 chipco_set32(cc, SSB_CHIPCO_PMU_MINRES_MSK, 1 << ldo);
0611 else
0612 chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, ~(1 << ldo));
0613 chipco_read32(cc, SSB_CHIPCO_PMU_MINRES_MSK);
0614 }
0615
0616 EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);
0617 EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);
0618
0619 static u32 ssb_pmu_get_alp_clock_clk0(struct ssb_chipcommon *cc)
0620 {
0621 u32 crystalfreq;
0622 const struct pmu0_plltab_entry *e = NULL;
0623
0624 crystalfreq = (chipco_read32(cc, SSB_CHIPCO_PMU_CTL) &
0625 SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT;
0626 e = pmu0_plltab_find_entry(crystalfreq);
0627 BUG_ON(!e);
0628 return e->freq * 1000;
0629 }
0630
0631 u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc)
0632 {
0633 struct ssb_bus *bus = cc->dev->bus;
0634
0635 switch (bus->chip_id) {
0636 case 0x5354:
0637 return ssb_pmu_get_alp_clock_clk0(cc);
0638 default:
0639 dev_err(cc->dev->dev, "ERROR: PMU alp clock unknown for device %04X\n",
0640 bus->chip_id);
0641 return 0;
0642 }
0643 }
0644
0645 u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc)
0646 {
0647 struct ssb_bus *bus = cc->dev->bus;
0648
0649 switch (bus->chip_id) {
0650 case 0x5354:
0651
0652 return 240000000;
0653 default:
0654 dev_err(cc->dev->dev, "ERROR: PMU cpu clock unknown for device %04X\n",
0655 bus->chip_id);
0656 return 0;
0657 }
0658 }
0659
0660 u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc)
0661 {
0662 struct ssb_bus *bus = cc->dev->bus;
0663
0664 switch (bus->chip_id) {
0665 case 0x5354:
0666 return 120000000;
0667 default:
0668 dev_err(cc->dev->dev, "ERROR: PMU controlclock unknown for device %04X\n",
0669 bus->chip_id);
0670 return 0;
0671 }
0672 }
0673
0674 void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon *cc, int spuravoid)
0675 {
0676 u32 pmu_ctl = 0;
0677
0678 switch (cc->dev->bus->chip_id) {
0679 case 0x4322:
0680 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100070);
0681 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x1014140a);
0682 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888854);
0683 if (spuravoid == 1)
0684 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05201828);
0685 else
0686 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05001828);
0687 pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
0688 break;
0689 case 43222:
0690 if (spuravoid == 1) {
0691 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11500008);
0692 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0C000C06);
0693 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x0F600a08);
0694 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000);
0695 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x2001E920);
0696 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888815);
0697 } else {
0698 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100008);
0699 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0c000c06);
0700 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x03000a08);
0701 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000);
0702 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x200005c0);
0703 ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888855);
0704 }
0705 pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
0706 break;
0707 default:
0708 dev_err(cc->dev->dev,
0709 "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
0710 cc->dev->bus->chip_id);
0711 return;
0712 }
0713
0714 chipco_set32(cc, SSB_CHIPCO_PMU_CTL, pmu_ctl);
0715 }
0716 EXPORT_SYMBOL_GPL(ssb_pmu_spuravoid_pllupdate);