cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

driver_chipcommon_pmu.c (22521B)


      1/*
      2 * Sonics Silicon Backplane
      3 * Broadcom ChipCommon Power Management Unit driver
      4 *
      5 * Copyright 2009, Michael Buesch <m@bues.ch>
      6 * Copyright 2007, Broadcom Corporation
      7 *
      8 * Licensed under the GNU/GPL. See COPYING for details.
      9 */
     10
     11#include "ssb_private.h"
     12
     13#include <linux/ssb/ssb.h>
     14#include <linux/ssb/ssb_regs.h>
     15#include <linux/ssb/ssb_driver_chipcommon.h>
     16#include <linux/delay.h>
     17#include <linux/export.h>
     18#ifdef CONFIG_BCM47XX
     19#include <linux/bcm47xx_nvram.h>
     20#endif
     21
     22static u32 ssb_chipco_pll_read(struct ssb_chipcommon *cc, u32 offset)
     23{
     24	chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, offset);
     25	return chipco_read32(cc, SSB_CHIPCO_PLLCTL_DATA);
     26}
     27
     28static void ssb_chipco_pll_write(struct ssb_chipcommon *cc,
     29				 u32 offset, u32 value)
     30{
     31	chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, offset);
     32	chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, value);
     33}
     34
     35static void ssb_chipco_regctl_maskset(struct ssb_chipcommon *cc,
     36				   u32 offset, u32 mask, u32 set)
     37{
     38	u32 value;
     39
     40	chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR);
     41	chipco_write32(cc, SSB_CHIPCO_REGCTL_ADDR, offset);
     42	chipco_read32(cc, SSB_CHIPCO_REGCTL_ADDR);
     43	value = chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA);
     44	value &= mask;
     45	value |= set;
     46	chipco_write32(cc, SSB_CHIPCO_REGCTL_DATA, value);
     47	chipco_read32(cc, SSB_CHIPCO_REGCTL_DATA);
     48}
     49
     50struct pmu0_plltab_entry {
     51	u16 freq;	/* Crystal frequency in kHz.*/
     52	u8 xf;		/* Crystal frequency value for PMU control */
     53	u8 wb_int;
     54	u32 wb_frac;
     55};
     56
     57static const struct pmu0_plltab_entry pmu0_plltab[] = {
     58	{ .freq = 12000, .xf =  1, .wb_int = 73, .wb_frac = 349525, },
     59	{ .freq = 13000, .xf =  2, .wb_int = 67, .wb_frac = 725937, },
     60	{ .freq = 14400, .xf =  3, .wb_int = 61, .wb_frac = 116508, },
     61	{ .freq = 15360, .xf =  4, .wb_int = 57, .wb_frac = 305834, },
     62	{ .freq = 16200, .xf =  5, .wb_int = 54, .wb_frac = 336579, },
     63	{ .freq = 16800, .xf =  6, .wb_int = 52, .wb_frac = 399457, },
     64	{ .freq = 19200, .xf =  7, .wb_int = 45, .wb_frac = 873813, },
     65	{ .freq = 19800, .xf =  8, .wb_int = 44, .wb_frac = 466033, },
     66	{ .freq = 20000, .xf =  9, .wb_int = 44, .wb_frac = 0,      },
     67	{ .freq = 25000, .xf = 10, .wb_int = 70, .wb_frac = 419430, },
     68	{ .freq = 26000, .xf = 11, .wb_int = 67, .wb_frac = 725937, },
     69	{ .freq = 30000, .xf = 12, .wb_int = 58, .wb_frac = 699050, },
     70	{ .freq = 38400, .xf = 13, .wb_int = 45, .wb_frac = 873813, },
     71	{ .freq = 40000, .xf = 14, .wb_int = 45, .wb_frac = 0,      },
     72};
     73#define SSB_PMU0_DEFAULT_XTALFREQ	20000
     74
     75static const struct pmu0_plltab_entry * pmu0_plltab_find_entry(u32 crystalfreq)
     76{
     77	const struct pmu0_plltab_entry *e;
     78	unsigned int i;
     79
     80	for (i = 0; i < ARRAY_SIZE(pmu0_plltab); i++) {
     81		e = &pmu0_plltab[i];
     82		if (e->freq == crystalfreq)
     83			return e;
     84	}
     85
     86	return NULL;
     87}
     88
     89/* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
     90static void ssb_pmu0_pllinit_r0(struct ssb_chipcommon *cc,
     91				u32 crystalfreq)
     92{
     93	struct ssb_bus *bus = cc->dev->bus;
     94	const struct pmu0_plltab_entry *e = NULL;
     95	u32 pmuctl, tmp, pllctl;
     96	unsigned int i;
     97
     98	if (crystalfreq)
     99		e = pmu0_plltab_find_entry(crystalfreq);
    100	if (!e)
    101		e = pmu0_plltab_find_entry(SSB_PMU0_DEFAULT_XTALFREQ);
    102	BUG_ON(!e);
    103	crystalfreq = e->freq;
    104	cc->pmu.crystalfreq = e->freq;
    105
    106	/* Check if the PLL already is programmed to this frequency. */
    107	pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
    108	if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) {
    109		/* We're already there... */
    110		return;
    111	}
    112
    113	dev_info(cc->dev->dev, "Programming PLL to %u.%03u MHz\n",
    114		 crystalfreq / 1000, crystalfreq % 1000);
    115
    116	/* First turn the PLL off. */
    117	switch (bus->chip_id) {
    118	case 0x4328:
    119		chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
    120			      ~(1 << SSB_PMURES_4328_BB_PLL_PU));
    121		chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
    122			      ~(1 << SSB_PMURES_4328_BB_PLL_PU));
    123		break;
    124	case 0x5354:
    125		chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
    126			      ~(1 << SSB_PMURES_5354_BB_PLL_PU));
    127		chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
    128			      ~(1 << SSB_PMURES_5354_BB_PLL_PU));
    129		break;
    130	default:
    131		WARN_ON(1);
    132	}
    133	for (i = 1500; i; i--) {
    134		tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
    135		if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT))
    136			break;
    137		udelay(10);
    138	}
    139	tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
    140	if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
    141		dev_emerg(cc->dev->dev, "Failed to turn the PLL off!\n");
    142
    143	/* Set PDIV in PLL control 0. */
    144	pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL0);
    145	if (crystalfreq >= SSB_PMU0_PLLCTL0_PDIV_FREQ)
    146		pllctl |= SSB_PMU0_PLLCTL0_PDIV_MSK;
    147	else
    148		pllctl &= ~SSB_PMU0_PLLCTL0_PDIV_MSK;
    149	ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL0, pllctl);
    150
    151	/* Set WILD in PLL control 1. */
    152	pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL1);
    153	pllctl &= ~SSB_PMU0_PLLCTL1_STOPMOD;
    154	pllctl &= ~(SSB_PMU0_PLLCTL1_WILD_IMSK | SSB_PMU0_PLLCTL1_WILD_FMSK);
    155	pllctl |= ((u32)e->wb_int << SSB_PMU0_PLLCTL1_WILD_IMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_IMSK;
    156	pllctl |= ((u32)e->wb_frac << SSB_PMU0_PLLCTL1_WILD_FMSK_SHIFT) & SSB_PMU0_PLLCTL1_WILD_FMSK;
    157	if (e->wb_frac == 0)
    158		pllctl |= SSB_PMU0_PLLCTL1_STOPMOD;
    159	ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL1, pllctl);
    160
    161	/* Set WILD in PLL control 2. */
    162	pllctl = ssb_chipco_pll_read(cc, SSB_PMU0_PLLCTL2);
    163	pllctl &= ~SSB_PMU0_PLLCTL2_WILD_IMSKHI;
    164	pllctl |= (((u32)e->wb_int >> 4) << SSB_PMU0_PLLCTL2_WILD_IMSKHI_SHIFT) & SSB_PMU0_PLLCTL2_WILD_IMSKHI;
    165	ssb_chipco_pll_write(cc, SSB_PMU0_PLLCTL2, pllctl);
    166
    167	/* Set the crystalfrequency and the divisor. */
    168	pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
    169	pmuctl &= ~SSB_CHIPCO_PMU_CTL_ILP_DIV;
    170	pmuctl |= (((crystalfreq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT)
    171			& SSB_CHIPCO_PMU_CTL_ILP_DIV;
    172	pmuctl &= ~SSB_CHIPCO_PMU_CTL_XTALFREQ;
    173	pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ;
    174	chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl);
    175}
    176
    177struct pmu1_plltab_entry {
    178	u16 freq;	/* Crystal frequency in kHz.*/
    179	u8 xf;		/* Crystal frequency value for PMU control */
    180	u8 ndiv_int;
    181	u32 ndiv_frac;
    182	u8 p1div;
    183	u8 p2div;
    184};
    185
    186static const struct pmu1_plltab_entry pmu1_plltab[] = {
    187	{ .freq = 12000, .xf =  1, .p1div = 3, .p2div = 22, .ndiv_int =  0x9, .ndiv_frac = 0xFFFFEF, },
    188	{ .freq = 13000, .xf =  2, .p1div = 1, .p2div =  6, .ndiv_int =  0xb, .ndiv_frac = 0x483483, },
    189	{ .freq = 14400, .xf =  3, .p1div = 1, .p2div = 10, .ndiv_int =  0xa, .ndiv_frac = 0x1C71C7, },
    190	{ .freq = 15360, .xf =  4, .p1div = 1, .p2div =  5, .ndiv_int =  0xb, .ndiv_frac = 0x755555, },
    191	{ .freq = 16200, .xf =  5, .p1div = 1, .p2div = 10, .ndiv_int =  0x5, .ndiv_frac = 0x6E9E06, },
    192	{ .freq = 16800, .xf =  6, .p1div = 1, .p2div = 10, .ndiv_int =  0x5, .ndiv_frac = 0x3CF3CF, },
    193	{ .freq = 19200, .xf =  7, .p1div = 1, .p2div =  9, .ndiv_int =  0x5, .ndiv_frac = 0x17B425, },
    194	{ .freq = 19800, .xf =  8, .p1div = 1, .p2div = 11, .ndiv_int =  0x4, .ndiv_frac = 0xA57EB,  },
    195	{ .freq = 20000, .xf =  9, .p1div = 1, .p2div = 11, .ndiv_int =  0x4, .ndiv_frac = 0,        },
    196	{ .freq = 24000, .xf = 10, .p1div = 3, .p2div = 11, .ndiv_int =  0xa, .ndiv_frac = 0,        },
    197	{ .freq = 25000, .xf = 11, .p1div = 5, .p2div = 16, .ndiv_int =  0xb, .ndiv_frac = 0,        },
    198	{ .freq = 26000, .xf = 12, .p1div = 1, .p2div =  2, .ndiv_int = 0x10, .ndiv_frac = 0xEC4EC4, },
    199	{ .freq = 30000, .xf = 13, .p1div = 3, .p2div =  8, .ndiv_int =  0xb, .ndiv_frac = 0,        },
    200	{ .freq = 38400, .xf = 14, .p1div = 1, .p2div =  5, .ndiv_int =  0x4, .ndiv_frac = 0x955555, },
    201	{ .freq = 40000, .xf = 15, .p1div = 1, .p2div =  2, .ndiv_int =  0xb, .ndiv_frac = 0,        },
    202};
    203
    204#define SSB_PMU1_DEFAULT_XTALFREQ	15360
    205
    206static const struct pmu1_plltab_entry * pmu1_plltab_find_entry(u32 crystalfreq)
    207{
    208	const struct pmu1_plltab_entry *e;
    209	unsigned int i;
    210
    211	for (i = 0; i < ARRAY_SIZE(pmu1_plltab); i++) {
    212		e = &pmu1_plltab[i];
    213		if (e->freq == crystalfreq)
    214			return e;
    215	}
    216
    217	return NULL;
    218}
    219
    220/* Tune the PLL to the crystal speed. crystalfreq is in kHz. */
    221static void ssb_pmu1_pllinit_r0(struct ssb_chipcommon *cc,
    222				u32 crystalfreq)
    223{
    224	struct ssb_bus *bus = cc->dev->bus;
    225	const struct pmu1_plltab_entry *e = NULL;
    226	u32 buffer_strength = 0;
    227	u32 tmp, pllctl, pmuctl;
    228	unsigned int i;
    229
    230	if (bus->chip_id == 0x4312) {
    231		/* We do not touch the BCM4312 PLL and assume
    232		 * the default crystal settings work out-of-the-box. */
    233		cc->pmu.crystalfreq = 20000;
    234		return;
    235	}
    236
    237	if (crystalfreq)
    238		e = pmu1_plltab_find_entry(crystalfreq);
    239	if (!e)
    240		e = pmu1_plltab_find_entry(SSB_PMU1_DEFAULT_XTALFREQ);
    241	BUG_ON(!e);
    242	crystalfreq = e->freq;
    243	cc->pmu.crystalfreq = e->freq;
    244
    245	/* Check if the PLL already is programmed to this frequency. */
    246	pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
    247	if (((pmuctl & SSB_CHIPCO_PMU_CTL_XTALFREQ) >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) == e->xf) {
    248		/* We're already there... */
    249		return;
    250	}
    251
    252	dev_info(cc->dev->dev, "Programming PLL to %u.%03u MHz\n",
    253		 crystalfreq / 1000, crystalfreq % 1000);
    254
    255	/* First turn the PLL off. */
    256	switch (bus->chip_id) {
    257	case 0x4325:
    258		chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK,
    259			      ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) |
    260				(1 << SSB_PMURES_4325_HT_AVAIL)));
    261		chipco_mask32(cc, SSB_CHIPCO_PMU_MAXRES_MSK,
    262			      ~((1 << SSB_PMURES_4325_BBPLL_PWRSW_PU) |
    263				(1 << SSB_PMURES_4325_HT_AVAIL)));
    264		/* Adjust the BBPLL to 2 on all channels later. */
    265		buffer_strength = 0x222222;
    266		break;
    267	default:
    268		WARN_ON(1);
    269	}
    270	for (i = 1500; i; i--) {
    271		tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
    272		if (!(tmp & SSB_CHIPCO_CLKCTLST_HAVEHT))
    273			break;
    274		udelay(10);
    275	}
    276	tmp = chipco_read32(cc, SSB_CHIPCO_CLKCTLST);
    277	if (tmp & SSB_CHIPCO_CLKCTLST_HAVEHT)
    278		dev_emerg(cc->dev->dev, "Failed to turn the PLL off!\n");
    279
    280	/* Set p1div and p2div. */
    281	pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL0);
    282	pllctl &= ~(SSB_PMU1_PLLCTL0_P1DIV | SSB_PMU1_PLLCTL0_P2DIV);
    283	pllctl |= ((u32)e->p1div << SSB_PMU1_PLLCTL0_P1DIV_SHIFT) & SSB_PMU1_PLLCTL0_P1DIV;
    284	pllctl |= ((u32)e->p2div << SSB_PMU1_PLLCTL0_P2DIV_SHIFT) & SSB_PMU1_PLLCTL0_P2DIV;
    285	ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, pllctl);
    286
    287	/* Set ndiv int and ndiv mode */
    288	pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL2);
    289	pllctl &= ~(SSB_PMU1_PLLCTL2_NDIVINT | SSB_PMU1_PLLCTL2_NDIVMODE);
    290	pllctl |= ((u32)e->ndiv_int << SSB_PMU1_PLLCTL2_NDIVINT_SHIFT) & SSB_PMU1_PLLCTL2_NDIVINT;
    291	pllctl |= (1 << SSB_PMU1_PLLCTL2_NDIVMODE_SHIFT) & SSB_PMU1_PLLCTL2_NDIVMODE;
    292	ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, pllctl);
    293
    294	/* Set ndiv frac */
    295	pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL3);
    296	pllctl &= ~SSB_PMU1_PLLCTL3_NDIVFRAC;
    297	pllctl |= ((u32)e->ndiv_frac << SSB_PMU1_PLLCTL3_NDIVFRAC_SHIFT) & SSB_PMU1_PLLCTL3_NDIVFRAC;
    298	ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, pllctl);
    299
    300	/* Change the drive strength, if required. */
    301	if (buffer_strength) {
    302		pllctl = ssb_chipco_pll_read(cc, SSB_PMU1_PLLCTL5);
    303		pllctl &= ~SSB_PMU1_PLLCTL5_CLKDRV;
    304		pllctl |= (buffer_strength << SSB_PMU1_PLLCTL5_CLKDRV_SHIFT) & SSB_PMU1_PLLCTL5_CLKDRV;
    305		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, pllctl);
    306	}
    307
    308	/* Tune the crystalfreq and the divisor. */
    309	pmuctl = chipco_read32(cc, SSB_CHIPCO_PMU_CTL);
    310	pmuctl &= ~(SSB_CHIPCO_PMU_CTL_ILP_DIV | SSB_CHIPCO_PMU_CTL_XTALFREQ);
    311	pmuctl |= ((((u32)e->freq + 127) / 128 - 1) << SSB_CHIPCO_PMU_CTL_ILP_DIV_SHIFT)
    312			& SSB_CHIPCO_PMU_CTL_ILP_DIV;
    313	pmuctl |= ((u32)e->xf << SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT) & SSB_CHIPCO_PMU_CTL_XTALFREQ;
    314	chipco_write32(cc, SSB_CHIPCO_PMU_CTL, pmuctl);
    315}
    316
    317static void ssb_pmu_pll_init(struct ssb_chipcommon *cc)
    318{
    319	struct ssb_bus *bus = cc->dev->bus;
    320	u32 crystalfreq = 0; /* in kHz. 0 = keep default freq. */
    321
    322	if (bus->bustype == SSB_BUSTYPE_SSB) {
    323#ifdef CONFIG_BCM47XX
    324		char buf[20];
    325		if (bcm47xx_nvram_getenv("xtalfreq", buf, sizeof(buf)) >= 0)
    326			crystalfreq = simple_strtoul(buf, NULL, 0);
    327#endif
    328	}
    329
    330	switch (bus->chip_id) {
    331	case 0x4312:
    332	case 0x4325:
    333		ssb_pmu1_pllinit_r0(cc, crystalfreq);
    334		break;
    335	case 0x4328:
    336		ssb_pmu0_pllinit_r0(cc, crystalfreq);
    337		break;
    338	case 0x5354:
    339		if (crystalfreq == 0)
    340			crystalfreq = 25000;
    341		ssb_pmu0_pllinit_r0(cc, crystalfreq);
    342		break;
    343	case 0x4322:
    344		if (cc->pmu.rev == 2) {
    345			chipco_write32(cc, SSB_CHIPCO_PLLCTL_ADDR, 0x0000000A);
    346			chipco_write32(cc, SSB_CHIPCO_PLLCTL_DATA, 0x380005C0);
    347		}
    348		break;
    349	case 43222:
    350		break;
    351	default:
    352		dev_err(cc->dev->dev, "ERROR: PLL init unknown for device %04X\n",
    353			bus->chip_id);
    354	}
    355}
    356
    357struct pmu_res_updown_tab_entry {
    358	u8 resource;	/* The resource number */
    359	u16 updown;	/* The updown value */
    360};
    361
    362enum pmu_res_depend_tab_task {
    363	PMU_RES_DEP_SET = 1,
    364	PMU_RES_DEP_ADD,
    365	PMU_RES_DEP_REMOVE,
    366};
    367
    368struct pmu_res_depend_tab_entry {
    369	u8 resource;	/* The resource number */
    370	u8 task;	/* SET | ADD | REMOVE */
    371	u32 depend;	/* The depend mask */
    372};
    373
    374static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4328a0[] = {
    375	{ .resource = SSB_PMURES_4328_EXT_SWITCHER_PWM,		.updown = 0x0101, },
    376	{ .resource = SSB_PMURES_4328_BB_SWITCHER_PWM,		.updown = 0x1F01, },
    377	{ .resource = SSB_PMURES_4328_BB_SWITCHER_BURST,	.updown = 0x010F, },
    378	{ .resource = SSB_PMURES_4328_BB_EXT_SWITCHER_BURST,	.updown = 0x0101, },
    379	{ .resource = SSB_PMURES_4328_ILP_REQUEST,		.updown = 0x0202, },
    380	{ .resource = SSB_PMURES_4328_RADIO_SWITCHER_PWM,	.updown = 0x0F01, },
    381	{ .resource = SSB_PMURES_4328_RADIO_SWITCHER_BURST,	.updown = 0x0F01, },
    382	{ .resource = SSB_PMURES_4328_ROM_SWITCH,		.updown = 0x0101, },
    383	{ .resource = SSB_PMURES_4328_PA_REF_LDO,		.updown = 0x0F01, },
    384	{ .resource = SSB_PMURES_4328_RADIO_LDO,		.updown = 0x0F01, },
    385	{ .resource = SSB_PMURES_4328_AFE_LDO,			.updown = 0x0F01, },
    386	{ .resource = SSB_PMURES_4328_PLL_LDO,			.updown = 0x0F01, },
    387	{ .resource = SSB_PMURES_4328_BG_FILTBYP,		.updown = 0x0101, },
    388	{ .resource = SSB_PMURES_4328_TX_FILTBYP,		.updown = 0x0101, },
    389	{ .resource = SSB_PMURES_4328_RX_FILTBYP,		.updown = 0x0101, },
    390	{ .resource = SSB_PMURES_4328_XTAL_PU,			.updown = 0x0101, },
    391	{ .resource = SSB_PMURES_4328_XTAL_EN,			.updown = 0xA001, },
    392	{ .resource = SSB_PMURES_4328_BB_PLL_FILTBYP,		.updown = 0x0101, },
    393	{ .resource = SSB_PMURES_4328_RF_PLL_FILTBYP,		.updown = 0x0101, },
    394	{ .resource = SSB_PMURES_4328_BB_PLL_PU,		.updown = 0x0701, },
    395};
    396
    397static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4328a0[] = {
    398	{
    399		/* Adjust ILP Request to avoid forcing EXT/BB into burst mode. */
    400		.resource = SSB_PMURES_4328_ILP_REQUEST,
    401		.task = PMU_RES_DEP_SET,
    402		.depend = ((1 << SSB_PMURES_4328_EXT_SWITCHER_PWM) |
    403			   (1 << SSB_PMURES_4328_BB_SWITCHER_PWM)),
    404	},
    405};
    406
    407static const struct pmu_res_updown_tab_entry pmu_res_updown_tab_4325a0[] = {
    408	{ .resource = SSB_PMURES_4325_XTAL_PU,			.updown = 0x1501, },
    409};
    410
    411static const struct pmu_res_depend_tab_entry pmu_res_depend_tab_4325a0[] = {
    412	{
    413		/* Adjust HT-Available dependencies. */
    414		.resource = SSB_PMURES_4325_HT_AVAIL,
    415		.task = PMU_RES_DEP_ADD,
    416		.depend = ((1 << SSB_PMURES_4325_RX_PWRSW_PU) |
    417			   (1 << SSB_PMURES_4325_TX_PWRSW_PU) |
    418			   (1 << SSB_PMURES_4325_LOGEN_PWRSW_PU) |
    419			   (1 << SSB_PMURES_4325_AFE_PWRSW_PU)),
    420	},
    421};
    422
    423static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
    424{
    425	struct ssb_bus *bus = cc->dev->bus;
    426	u32 min_msk = 0, max_msk = 0;
    427	unsigned int i;
    428	const struct pmu_res_updown_tab_entry *updown_tab = NULL;
    429	unsigned int updown_tab_size = 0;
    430	const struct pmu_res_depend_tab_entry *depend_tab = NULL;
    431	unsigned int depend_tab_size = 0;
    432
    433	switch (bus->chip_id) {
    434	case 0x4312:
    435		 min_msk = 0xCBB;
    436		 break;
    437	case 0x4322:
    438	case 43222:
    439		/* We keep the default settings:
    440		 * min_msk = 0xCBB
    441		 * max_msk = 0x7FFFF
    442		 */
    443		break;
    444	case 0x4325:
    445		/* Power OTP down later. */
    446		min_msk = (1 << SSB_PMURES_4325_CBUCK_BURST) |
    447			  (1 << SSB_PMURES_4325_LNLDO2_PU);
    448		if (chipco_read32(cc, SSB_CHIPCO_CHIPSTAT) &
    449		    SSB_CHIPCO_CHST_4325_PMUTOP_2B)
    450			min_msk |= (1 << SSB_PMURES_4325_CLDO_CBUCK_BURST);
    451		/* The PLL may turn on, if it decides so. */
    452		max_msk = 0xFFFFF;
    453		updown_tab = pmu_res_updown_tab_4325a0;
    454		updown_tab_size = ARRAY_SIZE(pmu_res_updown_tab_4325a0);
    455		depend_tab = pmu_res_depend_tab_4325a0;
    456		depend_tab_size = ARRAY_SIZE(pmu_res_depend_tab_4325a0);
    457		break;
    458	case 0x4328:
    459		min_msk = (1 << SSB_PMURES_4328_EXT_SWITCHER_PWM) |
    460			  (1 << SSB_PMURES_4328_BB_SWITCHER_PWM) |
    461			  (1 << SSB_PMURES_4328_XTAL_EN);
    462		/* The PLL may turn on, if it decides so. */
    463		max_msk = 0xFFFFF;
    464		updown_tab = pmu_res_updown_tab_4328a0;
    465		updown_tab_size = ARRAY_SIZE(pmu_res_updown_tab_4328a0);
    466		depend_tab = pmu_res_depend_tab_4328a0;
    467		depend_tab_size = ARRAY_SIZE(pmu_res_depend_tab_4328a0);
    468		break;
    469	case 0x5354:
    470		/* The PLL may turn on, if it decides so. */
    471		max_msk = 0xFFFFF;
    472		break;
    473	default:
    474		dev_err(cc->dev->dev, "ERROR: PMU resource config unknown for device %04X\n",
    475			bus->chip_id);
    476	}
    477
    478	if (updown_tab) {
    479		for (i = 0; i < updown_tab_size; i++) {
    480			chipco_write32(cc, SSB_CHIPCO_PMU_RES_TABSEL,
    481				       updown_tab[i].resource);
    482			chipco_write32(cc, SSB_CHIPCO_PMU_RES_UPDNTM,
    483				       updown_tab[i].updown);
    484		}
    485	}
    486	if (depend_tab) {
    487		for (i = 0; i < depend_tab_size; i++) {
    488			chipco_write32(cc, SSB_CHIPCO_PMU_RES_TABSEL,
    489				       depend_tab[i].resource);
    490			switch (depend_tab[i].task) {
    491			case PMU_RES_DEP_SET:
    492				chipco_write32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
    493					       depend_tab[i].depend);
    494				break;
    495			case PMU_RES_DEP_ADD:
    496				chipco_set32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
    497					     depend_tab[i].depend);
    498				break;
    499			case PMU_RES_DEP_REMOVE:
    500				chipco_mask32(cc, SSB_CHIPCO_PMU_RES_DEPMSK,
    501					      ~(depend_tab[i].depend));
    502				break;
    503			default:
    504				WARN_ON(1);
    505			}
    506		}
    507	}
    508
    509	/* Set the resource masks. */
    510	if (min_msk)
    511		chipco_write32(cc, SSB_CHIPCO_PMU_MINRES_MSK, min_msk);
    512	if (max_msk)
    513		chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk);
    514}
    515
    516/* https://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
    517void ssb_pmu_init(struct ssb_chipcommon *cc)
    518{
    519	u32 pmucap;
    520
    521	if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU))
    522		return;
    523
    524	pmucap = chipco_read32(cc, SSB_CHIPCO_PMU_CAP);
    525	cc->pmu.rev = (pmucap & SSB_CHIPCO_PMU_CAP_REVISION);
    526
    527	dev_dbg(cc->dev->dev, "Found rev %u PMU (capabilities 0x%08X)\n",
    528		cc->pmu.rev, pmucap);
    529
    530	if (cc->pmu.rev == 1)
    531		chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
    532			      ~SSB_CHIPCO_PMU_CTL_NOILPONW);
    533	else
    534		chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
    535			     SSB_CHIPCO_PMU_CTL_NOILPONW);
    536	ssb_pmu_pll_init(cc);
    537	ssb_pmu_resources_init(cc);
    538}
    539
    540void ssb_pmu_set_ldo_voltage(struct ssb_chipcommon *cc,
    541			     enum ssb_pmu_ldo_volt_id id, u32 voltage)
    542{
    543	struct ssb_bus *bus = cc->dev->bus;
    544	u32 addr, shift, mask;
    545
    546	switch (bus->chip_id) {
    547	case 0x4328:
    548	case 0x5354:
    549		switch (id) {
    550		case LDO_VOLT1:
    551			addr = 2;
    552			shift = 25;
    553			mask = 0xF;
    554			break;
    555		case LDO_VOLT2:
    556			addr = 3;
    557			shift = 1;
    558			mask = 0xF;
    559			break;
    560		case LDO_VOLT3:
    561			addr = 3;
    562			shift = 9;
    563			mask = 0xF;
    564			break;
    565		case LDO_PAREF:
    566			addr = 3;
    567			shift = 17;
    568			mask = 0x3F;
    569			break;
    570		default:
    571			WARN_ON(1);
    572			return;
    573		}
    574		break;
    575	case 0x4312:
    576		if (WARN_ON(id != LDO_PAREF))
    577			return;
    578		addr = 0;
    579		shift = 21;
    580		mask = 0x3F;
    581		break;
    582	default:
    583		return;
    584	}
    585
    586	ssb_chipco_regctl_maskset(cc, addr, ~(mask << shift),
    587				  (voltage & mask) << shift);
    588}
    589
    590void ssb_pmu_set_ldo_paref(struct ssb_chipcommon *cc, bool on)
    591{
    592	struct ssb_bus *bus = cc->dev->bus;
    593	int ldo;
    594
    595	switch (bus->chip_id) {
    596	case 0x4312:
    597		ldo = SSB_PMURES_4312_PA_REF_LDO;
    598		break;
    599	case 0x4328:
    600		ldo = SSB_PMURES_4328_PA_REF_LDO;
    601		break;
    602	case 0x5354:
    603		ldo = SSB_PMURES_5354_PA_REF_LDO;
    604		break;
    605	default:
    606		return;
    607	}
    608
    609	if (on)
    610		chipco_set32(cc, SSB_CHIPCO_PMU_MINRES_MSK, 1 << ldo);
    611	else
    612		chipco_mask32(cc, SSB_CHIPCO_PMU_MINRES_MSK, ~(1 << ldo));
    613	chipco_read32(cc, SSB_CHIPCO_PMU_MINRES_MSK); //SPEC FIXME found via mmiotrace - dummy read?
    614}
    615
    616EXPORT_SYMBOL(ssb_pmu_set_ldo_voltage);
    617EXPORT_SYMBOL(ssb_pmu_set_ldo_paref);
    618
    619static u32 ssb_pmu_get_alp_clock_clk0(struct ssb_chipcommon *cc)
    620{
    621	u32 crystalfreq;
    622	const struct pmu0_plltab_entry *e = NULL;
    623
    624	crystalfreq = (chipco_read32(cc, SSB_CHIPCO_PMU_CTL) &
    625		       SSB_CHIPCO_PMU_CTL_XTALFREQ)  >> SSB_CHIPCO_PMU_CTL_XTALFREQ_SHIFT;
    626	e = pmu0_plltab_find_entry(crystalfreq);
    627	BUG_ON(!e);
    628	return e->freq * 1000;
    629}
    630
    631u32 ssb_pmu_get_alp_clock(struct ssb_chipcommon *cc)
    632{
    633	struct ssb_bus *bus = cc->dev->bus;
    634
    635	switch (bus->chip_id) {
    636	case 0x5354:
    637		return ssb_pmu_get_alp_clock_clk0(cc);
    638	default:
    639		dev_err(cc->dev->dev, "ERROR: PMU alp clock unknown for device %04X\n",
    640			bus->chip_id);
    641		return 0;
    642	}
    643}
    644
    645u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc)
    646{
    647	struct ssb_bus *bus = cc->dev->bus;
    648
    649	switch (bus->chip_id) {
    650	case 0x5354:
    651		/* 5354 chip uses a non programmable PLL of frequency 240MHz */
    652		return 240000000;
    653	default:
    654		dev_err(cc->dev->dev, "ERROR: PMU cpu clock unknown for device %04X\n",
    655			bus->chip_id);
    656		return 0;
    657	}
    658}
    659
    660u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc)
    661{
    662	struct ssb_bus *bus = cc->dev->bus;
    663
    664	switch (bus->chip_id) {
    665	case 0x5354:
    666		return 120000000;
    667	default:
    668		dev_err(cc->dev->dev, "ERROR: PMU controlclock unknown for device %04X\n",
    669			bus->chip_id);
    670		return 0;
    671	}
    672}
    673
    674void ssb_pmu_spuravoid_pllupdate(struct ssb_chipcommon *cc, int spuravoid)
    675{
    676	u32 pmu_ctl = 0;
    677
    678	switch (cc->dev->bus->chip_id) {
    679	case 0x4322:
    680		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100070);
    681		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x1014140a);
    682		ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888854);
    683		if (spuravoid == 1)
    684			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05201828);
    685		else
    686			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x05001828);
    687		pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
    688		break;
    689	case 43222:
    690		if (spuravoid == 1) {
    691			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11500008);
    692			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0C000C06);
    693			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x0F600a08);
    694			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000);
    695			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x2001E920);
    696			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888815);
    697		} else {
    698			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL0, 0x11100008);
    699			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL1, 0x0c000c06);
    700			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL2, 0x03000a08);
    701			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL3, 0x00000000);
    702			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL4, 0x200005c0);
    703			ssb_chipco_pll_write(cc, SSB_PMU1_PLLCTL5, 0x88888855);
    704		}
    705		pmu_ctl = SSB_CHIPCO_PMU_CTL_PLL_UPD;
    706		break;
    707	default:
    708		dev_err(cc->dev->dev,
    709			"Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n",
    710			cc->dev->bus->chip_id);
    711		return;
    712	}
    713
    714	chipco_set32(cc, SSB_CHIPCO_PMU_CTL, pmu_ctl);
    715}
    716EXPORT_SYMBOL_GPL(ssb_pmu_spuravoid_pllupdate);