xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: ISC
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2014 Broadcom Corporation
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun #include <linux/kernel.h>
6*4882a593Smuzhiyun #include <linux/delay.h>
7*4882a593Smuzhiyun #include <linux/list.h>
8*4882a593Smuzhiyun #include <linux/ssb/ssb_regs.h>
9*4882a593Smuzhiyun #include <linux/bcma/bcma.h>
10*4882a593Smuzhiyun #include <linux/bcma/bcma_regs.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <defs.h>
13*4882a593Smuzhiyun #include <soc.h>
14*4882a593Smuzhiyun #include <brcm_hw_ids.h>
15*4882a593Smuzhiyun #include <brcmu_utils.h>
16*4882a593Smuzhiyun #include <chipcommon.h>
17*4882a593Smuzhiyun #include "debug.h"
18*4882a593Smuzhiyun #include "chip.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /* SOC Interconnect types (aka chip types) */
21*4882a593Smuzhiyun #define SOCI_SB		0
22*4882a593Smuzhiyun #define SOCI_AI		1
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun /* PL-368 DMP definitions */
25*4882a593Smuzhiyun #define DMP_DESC_TYPE_MSK	0x0000000F
26*4882a593Smuzhiyun #define  DMP_DESC_EMPTY		0x00000000
27*4882a593Smuzhiyun #define  DMP_DESC_VALID		0x00000001
28*4882a593Smuzhiyun #define  DMP_DESC_COMPONENT	0x00000001
29*4882a593Smuzhiyun #define  DMP_DESC_MASTER_PORT	0x00000003
30*4882a593Smuzhiyun #define  DMP_DESC_ADDRESS	0x00000005
31*4882a593Smuzhiyun #define  DMP_DESC_ADDRSIZE_GT32	0x00000008
32*4882a593Smuzhiyun #define  DMP_DESC_EOT		0x0000000F
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define DMP_COMP_DESIGNER	0xFFF00000
35*4882a593Smuzhiyun #define DMP_COMP_DESIGNER_S	20
36*4882a593Smuzhiyun #define DMP_COMP_PARTNUM	0x000FFF00
37*4882a593Smuzhiyun #define DMP_COMP_PARTNUM_S	8
38*4882a593Smuzhiyun #define DMP_COMP_CLASS		0x000000F0
39*4882a593Smuzhiyun #define DMP_COMP_CLASS_S	4
40*4882a593Smuzhiyun #define DMP_COMP_REVISION	0xFF000000
41*4882a593Smuzhiyun #define DMP_COMP_REVISION_S	24
42*4882a593Smuzhiyun #define DMP_COMP_NUM_SWRAP	0x00F80000
43*4882a593Smuzhiyun #define DMP_COMP_NUM_SWRAP_S	19
44*4882a593Smuzhiyun #define DMP_COMP_NUM_MWRAP	0x0007C000
45*4882a593Smuzhiyun #define DMP_COMP_NUM_MWRAP_S	14
46*4882a593Smuzhiyun #define DMP_COMP_NUM_SPORT	0x00003E00
47*4882a593Smuzhiyun #define DMP_COMP_NUM_SPORT_S	9
48*4882a593Smuzhiyun #define DMP_COMP_NUM_MPORT	0x000001F0
49*4882a593Smuzhiyun #define DMP_COMP_NUM_MPORT_S	4
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun #define DMP_MASTER_PORT_UID	0x0000FF00
52*4882a593Smuzhiyun #define DMP_MASTER_PORT_UID_S	8
53*4882a593Smuzhiyun #define DMP_MASTER_PORT_NUM	0x000000F0
54*4882a593Smuzhiyun #define DMP_MASTER_PORT_NUM_S	4
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define DMP_SLAVE_ADDR_BASE	0xFFFFF000
57*4882a593Smuzhiyun #define DMP_SLAVE_ADDR_BASE_S	12
58*4882a593Smuzhiyun #define DMP_SLAVE_PORT_NUM	0x00000F00
59*4882a593Smuzhiyun #define DMP_SLAVE_PORT_NUM_S	8
60*4882a593Smuzhiyun #define DMP_SLAVE_TYPE		0x000000C0
61*4882a593Smuzhiyun #define DMP_SLAVE_TYPE_S	6
62*4882a593Smuzhiyun #define  DMP_SLAVE_TYPE_SLAVE	0
63*4882a593Smuzhiyun #define  DMP_SLAVE_TYPE_BRIDGE	1
64*4882a593Smuzhiyun #define  DMP_SLAVE_TYPE_SWRAP	2
65*4882a593Smuzhiyun #define  DMP_SLAVE_TYPE_MWRAP	3
66*4882a593Smuzhiyun #define DMP_SLAVE_SIZE_TYPE	0x00000030
67*4882a593Smuzhiyun #define DMP_SLAVE_SIZE_TYPE_S	4
68*4882a593Smuzhiyun #define  DMP_SLAVE_SIZE_4K	0
69*4882a593Smuzhiyun #define  DMP_SLAVE_SIZE_8K	1
70*4882a593Smuzhiyun #define  DMP_SLAVE_SIZE_16K	2
71*4882a593Smuzhiyun #define  DMP_SLAVE_SIZE_DESC	3
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun /* EROM CompIdentB */
74*4882a593Smuzhiyun #define CIB_REV_MASK		0xff000000
75*4882a593Smuzhiyun #define CIB_REV_SHIFT		24
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun /* ARM CR4 core specific control flag bits */
78*4882a593Smuzhiyun #define ARMCR4_BCMA_IOCTL_CPUHALT	0x0020
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun /* D11 core specific control flag bits */
81*4882a593Smuzhiyun #define D11_BCMA_IOCTL_PHYCLOCKEN	0x0004
82*4882a593Smuzhiyun #define D11_BCMA_IOCTL_PHYRESET		0x0008
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun /* chip core base & ramsize */
85*4882a593Smuzhiyun /* bcm4329 */
86*4882a593Smuzhiyun /* SDIO device core, ID 0x829 */
87*4882a593Smuzhiyun #define BCM4329_CORE_BUS_BASE		0x18011000
88*4882a593Smuzhiyun /* internal memory core, ID 0x80e */
89*4882a593Smuzhiyun #define BCM4329_CORE_SOCRAM_BASE	0x18003000
90*4882a593Smuzhiyun /* ARM Cortex M3 core, ID 0x82a */
91*4882a593Smuzhiyun #define BCM4329_CORE_ARM_BASE		0x18002000
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /* Max possibly supported memory size (limited by IO mapped memory) */
94*4882a593Smuzhiyun #define BRCMF_CHIP_MAX_MEMSIZE		(4 * 1024 * 1024)
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun #define CORE_SB(base, field) \
97*4882a593Smuzhiyun 		(base + SBCONFIGOFF + offsetof(struct sbconfig, field))
98*4882a593Smuzhiyun #define	SBCOREREV(sbidh) \
99*4882a593Smuzhiyun 	((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
100*4882a593Smuzhiyun 	  ((sbidh) & SSB_IDHIGH_RCLO))
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun struct sbconfig {
103*4882a593Smuzhiyun 	u32 PAD[2];
104*4882a593Smuzhiyun 	u32 sbipsflag;	/* initiator port ocp slave flag */
105*4882a593Smuzhiyun 	u32 PAD[3];
106*4882a593Smuzhiyun 	u32 sbtpsflag;	/* target port ocp slave flag */
107*4882a593Smuzhiyun 	u32 PAD[11];
108*4882a593Smuzhiyun 	u32 sbtmerrloga;	/* (sonics >= 2.3) */
109*4882a593Smuzhiyun 	u32 PAD;
110*4882a593Smuzhiyun 	u32 sbtmerrlog;	/* (sonics >= 2.3) */
111*4882a593Smuzhiyun 	u32 PAD[3];
112*4882a593Smuzhiyun 	u32 sbadmatch3;	/* address match3 */
113*4882a593Smuzhiyun 	u32 PAD;
114*4882a593Smuzhiyun 	u32 sbadmatch2;	/* address match2 */
115*4882a593Smuzhiyun 	u32 PAD;
116*4882a593Smuzhiyun 	u32 sbadmatch1;	/* address match1 */
117*4882a593Smuzhiyun 	u32 PAD[7];
118*4882a593Smuzhiyun 	u32 sbimstate;	/* initiator agent state */
119*4882a593Smuzhiyun 	u32 sbintvec;	/* interrupt mask */
120*4882a593Smuzhiyun 	u32 sbtmstatelow;	/* target state */
121*4882a593Smuzhiyun 	u32 sbtmstatehigh;	/* target state */
122*4882a593Smuzhiyun 	u32 sbbwa0;		/* bandwidth allocation table0 */
123*4882a593Smuzhiyun 	u32 PAD;
124*4882a593Smuzhiyun 	u32 sbimconfiglow;	/* initiator configuration */
125*4882a593Smuzhiyun 	u32 sbimconfighigh;	/* initiator configuration */
126*4882a593Smuzhiyun 	u32 sbadmatch0;	/* address match0 */
127*4882a593Smuzhiyun 	u32 PAD;
128*4882a593Smuzhiyun 	u32 sbtmconfiglow;	/* target configuration */
129*4882a593Smuzhiyun 	u32 sbtmconfighigh;	/* target configuration */
130*4882a593Smuzhiyun 	u32 sbbconfig;	/* broadcast configuration */
131*4882a593Smuzhiyun 	u32 PAD;
132*4882a593Smuzhiyun 	u32 sbbstate;	/* broadcast state */
133*4882a593Smuzhiyun 	u32 PAD[3];
134*4882a593Smuzhiyun 	u32 sbactcnfg;	/* activate configuration */
135*4882a593Smuzhiyun 	u32 PAD[3];
136*4882a593Smuzhiyun 	u32 sbflagst;	/* current sbflags */
137*4882a593Smuzhiyun 	u32 PAD[3];
138*4882a593Smuzhiyun 	u32 sbidlow;		/* identification */
139*4882a593Smuzhiyun 	u32 sbidhigh;	/* identification */
140*4882a593Smuzhiyun };
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun /* bankidx and bankinfo reg defines corerev >= 8 */
143*4882a593Smuzhiyun #define SOCRAM_BANKINFO_RETNTRAM_MASK	0x00010000
144*4882a593Smuzhiyun #define SOCRAM_BANKINFO_SZMASK		0x0000007f
145*4882a593Smuzhiyun #define SOCRAM_BANKIDX_ROM_MASK		0x00000100
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun #define SOCRAM_BANKIDX_MEMTYPE_SHIFT	8
148*4882a593Smuzhiyun /* socram bankinfo memtype */
149*4882a593Smuzhiyun #define SOCRAM_MEMTYPE_RAM		0
150*4882a593Smuzhiyun #define SOCRAM_MEMTYPE_R0M		1
151*4882a593Smuzhiyun #define SOCRAM_MEMTYPE_DEVRAM		2
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun #define SOCRAM_BANKINFO_SZBASE		8192
154*4882a593Smuzhiyun #define SRCI_LSS_MASK		0x00f00000
155*4882a593Smuzhiyun #define SRCI_LSS_SHIFT		20
156*4882a593Smuzhiyun #define	SRCI_SRNB_MASK		0xf0
157*4882a593Smuzhiyun #define	SRCI_SRNB_MASK_EXT	0x100
158*4882a593Smuzhiyun #define	SRCI_SRNB_SHIFT		4
159*4882a593Smuzhiyun #define	SRCI_SRBSZ_MASK		0xf
160*4882a593Smuzhiyun #define	SRCI_SRBSZ_SHIFT	0
161*4882a593Smuzhiyun #define SR_BSZ_BASE		14
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun struct sbsocramregs {
164*4882a593Smuzhiyun 	u32 coreinfo;
165*4882a593Smuzhiyun 	u32 bwalloc;
166*4882a593Smuzhiyun 	u32 extracoreinfo;
167*4882a593Smuzhiyun 	u32 biststat;
168*4882a593Smuzhiyun 	u32 bankidx;
169*4882a593Smuzhiyun 	u32 standbyctrl;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	u32 errlogstatus;	/* rev 6 */
172*4882a593Smuzhiyun 	u32 errlogaddr;	/* rev 6 */
173*4882a593Smuzhiyun 	/* used for patching rev 3 & 5 */
174*4882a593Smuzhiyun 	u32 cambankidx;
175*4882a593Smuzhiyun 	u32 cambankstandbyctrl;
176*4882a593Smuzhiyun 	u32 cambankpatchctrl;
177*4882a593Smuzhiyun 	u32 cambankpatchtblbaseaddr;
178*4882a593Smuzhiyun 	u32 cambankcmdreg;
179*4882a593Smuzhiyun 	u32 cambankdatareg;
180*4882a593Smuzhiyun 	u32 cambankmaskreg;
181*4882a593Smuzhiyun 	u32 PAD[1];
182*4882a593Smuzhiyun 	u32 bankinfo;	/* corev 8 */
183*4882a593Smuzhiyun 	u32 bankpda;
184*4882a593Smuzhiyun 	u32 PAD[14];
185*4882a593Smuzhiyun 	u32 extmemconfig;
186*4882a593Smuzhiyun 	u32 extmemparitycsr;
187*4882a593Smuzhiyun 	u32 extmemparityerrdata;
188*4882a593Smuzhiyun 	u32 extmemparityerrcnt;
189*4882a593Smuzhiyun 	u32 extmemwrctrlandsize;
190*4882a593Smuzhiyun 	u32 PAD[84];
191*4882a593Smuzhiyun 	u32 workaround;
192*4882a593Smuzhiyun 	u32 pwrctl;		/* corerev >= 2 */
193*4882a593Smuzhiyun 	u32 PAD[133];
194*4882a593Smuzhiyun 	u32 sr_control;     /* corerev >= 15 */
195*4882a593Smuzhiyun 	u32 sr_status;      /* corerev >= 15 */
196*4882a593Smuzhiyun 	u32 sr_address;     /* corerev >= 15 */
197*4882a593Smuzhiyun 	u32 sr_data;        /* corerev >= 15 */
198*4882a593Smuzhiyun };
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun #define SOCRAMREGOFFS(_f)	offsetof(struct sbsocramregs, _f)
201*4882a593Smuzhiyun #define SYSMEMREGOFFS(_f)	offsetof(struct sbsocramregs, _f)
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun #define ARMCR4_CAP		(0x04)
204*4882a593Smuzhiyun #define ARMCR4_BANKIDX		(0x40)
205*4882a593Smuzhiyun #define ARMCR4_BANKINFO		(0x44)
206*4882a593Smuzhiyun #define ARMCR4_BANKPDA		(0x4C)
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun #define	ARMCR4_TCBBNB_MASK	0xf0
209*4882a593Smuzhiyun #define	ARMCR4_TCBBNB_SHIFT	4
210*4882a593Smuzhiyun #define	ARMCR4_TCBANB_MASK	0xf
211*4882a593Smuzhiyun #define	ARMCR4_TCBANB_SHIFT	0
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun #define	ARMCR4_BSZ_MASK		0x3f
214*4882a593Smuzhiyun #define	ARMCR4_BSZ_MULT		8192
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun struct brcmf_core_priv {
217*4882a593Smuzhiyun 	struct brcmf_core pub;
218*4882a593Smuzhiyun 	u32 wrapbase;
219*4882a593Smuzhiyun 	struct list_head list;
220*4882a593Smuzhiyun 	struct brcmf_chip_priv *chip;
221*4882a593Smuzhiyun };
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun struct brcmf_chip_priv {
224*4882a593Smuzhiyun 	struct brcmf_chip pub;
225*4882a593Smuzhiyun 	const struct brcmf_buscore_ops *ops;
226*4882a593Smuzhiyun 	void *ctx;
227*4882a593Smuzhiyun 	/* assured first core is chipcommon, second core is buscore */
228*4882a593Smuzhiyun 	struct list_head cores;
229*4882a593Smuzhiyun 	u16 num_cores;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	bool (*iscoreup)(struct brcmf_core_priv *core);
232*4882a593Smuzhiyun 	void (*coredisable)(struct brcmf_core_priv *core, u32 prereset,
233*4882a593Smuzhiyun 			    u32 reset);
234*4882a593Smuzhiyun 	void (*resetcore)(struct brcmf_core_priv *core, u32 prereset, u32 reset,
235*4882a593Smuzhiyun 			  u32 postreset);
236*4882a593Smuzhiyun };
237*4882a593Smuzhiyun 
brcmf_chip_sb_corerev(struct brcmf_chip_priv * ci,struct brcmf_core * core)238*4882a593Smuzhiyun static void brcmf_chip_sb_corerev(struct brcmf_chip_priv *ci,
239*4882a593Smuzhiyun 				  struct brcmf_core *core)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	u32 regdata;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	regdata = ci->ops->read32(ci->ctx, CORE_SB(core->base, sbidhigh));
244*4882a593Smuzhiyun 	core->rev = SBCOREREV(regdata);
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
brcmf_chip_sb_iscoreup(struct brcmf_core_priv * core)247*4882a593Smuzhiyun static bool brcmf_chip_sb_iscoreup(struct brcmf_core_priv *core)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	struct brcmf_chip_priv *ci;
250*4882a593Smuzhiyun 	u32 regdata;
251*4882a593Smuzhiyun 	u32 address;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	ci = core->chip;
254*4882a593Smuzhiyun 	address = CORE_SB(core->pub.base, sbtmstatelow);
255*4882a593Smuzhiyun 	regdata = ci->ops->read32(ci->ctx, address);
256*4882a593Smuzhiyun 	regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
257*4882a593Smuzhiyun 		    SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
258*4882a593Smuzhiyun 	return SSB_TMSLOW_CLOCK == regdata;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun 
brcmf_chip_ai_iscoreup(struct brcmf_core_priv * core)261*4882a593Smuzhiyun static bool brcmf_chip_ai_iscoreup(struct brcmf_core_priv *core)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun 	struct brcmf_chip_priv *ci;
264*4882a593Smuzhiyun 	u32 regdata;
265*4882a593Smuzhiyun 	bool ret;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	ci = core->chip;
268*4882a593Smuzhiyun 	regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
269*4882a593Smuzhiyun 	ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL);
272*4882a593Smuzhiyun 	ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	return ret;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
brcmf_chip_sb_coredisable(struct brcmf_core_priv * core,u32 prereset,u32 reset)277*4882a593Smuzhiyun static void brcmf_chip_sb_coredisable(struct brcmf_core_priv *core,
278*4882a593Smuzhiyun 				      u32 prereset, u32 reset)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	struct brcmf_chip_priv *ci;
281*4882a593Smuzhiyun 	u32 val, base;
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	ci = core->chip;
284*4882a593Smuzhiyun 	base = core->pub.base;
285*4882a593Smuzhiyun 	val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
286*4882a593Smuzhiyun 	if (val & SSB_TMSLOW_RESET)
287*4882a593Smuzhiyun 		return;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
290*4882a593Smuzhiyun 	if ((val & SSB_TMSLOW_CLOCK) != 0) {
291*4882a593Smuzhiyun 		/*
292*4882a593Smuzhiyun 		 * set target reject and spin until busy is clear
293*4882a593Smuzhiyun 		 * (preserve core-specific bits)
294*4882a593Smuzhiyun 		 */
295*4882a593Smuzhiyun 		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
296*4882a593Smuzhiyun 		ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow),
297*4882a593Smuzhiyun 					 val | SSB_TMSLOW_REJECT);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
300*4882a593Smuzhiyun 		udelay(1);
301*4882a593Smuzhiyun 		SPINWAIT((ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh))
302*4882a593Smuzhiyun 			  & SSB_TMSHIGH_BUSY), 100000);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh));
305*4882a593Smuzhiyun 		if (val & SSB_TMSHIGH_BUSY)
306*4882a593Smuzhiyun 			brcmf_err("core state still busy\n");
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbidlow));
309*4882a593Smuzhiyun 		if (val & SSB_IDLOW_INITIATOR) {
310*4882a593Smuzhiyun 			val = ci->ops->read32(ci->ctx,
311*4882a593Smuzhiyun 					      CORE_SB(base, sbimstate));
312*4882a593Smuzhiyun 			val |= SSB_IMSTATE_REJECT;
313*4882a593Smuzhiyun 			ci->ops->write32(ci->ctx,
314*4882a593Smuzhiyun 					 CORE_SB(base, sbimstate), val);
315*4882a593Smuzhiyun 			val = ci->ops->read32(ci->ctx,
316*4882a593Smuzhiyun 					      CORE_SB(base, sbimstate));
317*4882a593Smuzhiyun 			udelay(1);
318*4882a593Smuzhiyun 			SPINWAIT((ci->ops->read32(ci->ctx,
319*4882a593Smuzhiyun 						  CORE_SB(base, sbimstate)) &
320*4882a593Smuzhiyun 				  SSB_IMSTATE_BUSY), 100000);
321*4882a593Smuzhiyun 		}
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 		/* set reset and reject while enabling the clocks */
324*4882a593Smuzhiyun 		val = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
325*4882a593Smuzhiyun 		      SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
326*4882a593Smuzhiyun 		ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow), val);
327*4882a593Smuzhiyun 		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
328*4882a593Smuzhiyun 		udelay(10);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 		/* clear the initiator reject bit */
331*4882a593Smuzhiyun 		val = ci->ops->read32(ci->ctx, CORE_SB(base, sbidlow));
332*4882a593Smuzhiyun 		if (val & SSB_IDLOW_INITIATOR) {
333*4882a593Smuzhiyun 			val = ci->ops->read32(ci->ctx,
334*4882a593Smuzhiyun 					      CORE_SB(base, sbimstate));
335*4882a593Smuzhiyun 			val &= ~SSB_IMSTATE_REJECT;
336*4882a593Smuzhiyun 			ci->ops->write32(ci->ctx,
337*4882a593Smuzhiyun 					 CORE_SB(base, sbimstate), val);
338*4882a593Smuzhiyun 		}
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	/* leave reset and reject asserted */
342*4882a593Smuzhiyun 	ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow),
343*4882a593Smuzhiyun 			 (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
344*4882a593Smuzhiyun 	udelay(1);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
brcmf_chip_ai_coredisable(struct brcmf_core_priv * core,u32 prereset,u32 reset)347*4882a593Smuzhiyun static void brcmf_chip_ai_coredisable(struct brcmf_core_priv *core,
348*4882a593Smuzhiyun 				      u32 prereset, u32 reset)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	struct brcmf_chip_priv *ci;
351*4882a593Smuzhiyun 	u32 regdata;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	ci = core->chip;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	/* if core is already in reset, skip reset */
356*4882a593Smuzhiyun 	regdata = ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL);
357*4882a593Smuzhiyun 	if ((regdata & BCMA_RESET_CTL_RESET) != 0)
358*4882a593Smuzhiyun 		goto in_reset_configure;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	/* configure reset */
361*4882a593Smuzhiyun 	ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
362*4882a593Smuzhiyun 			 prereset | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
363*4882a593Smuzhiyun 	ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	/* put in reset */
366*4882a593Smuzhiyun 	ci->ops->write32(ci->ctx, core->wrapbase + BCMA_RESET_CTL,
367*4882a593Smuzhiyun 			 BCMA_RESET_CTL_RESET);
368*4882a593Smuzhiyun 	usleep_range(10, 20);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	/* wait till reset is 1 */
371*4882a593Smuzhiyun 	SPINWAIT(ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) !=
372*4882a593Smuzhiyun 		 BCMA_RESET_CTL_RESET, 300);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun in_reset_configure:
375*4882a593Smuzhiyun 	/* in-reset configure */
376*4882a593Smuzhiyun 	ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
377*4882a593Smuzhiyun 			 reset | BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
378*4882a593Smuzhiyun 	ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun 
brcmf_chip_sb_resetcore(struct brcmf_core_priv * core,u32 prereset,u32 reset,u32 postreset)381*4882a593Smuzhiyun static void brcmf_chip_sb_resetcore(struct brcmf_core_priv *core, u32 prereset,
382*4882a593Smuzhiyun 				    u32 reset, u32 postreset)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	struct brcmf_chip_priv *ci;
385*4882a593Smuzhiyun 	u32 regdata;
386*4882a593Smuzhiyun 	u32 base;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	ci = core->chip;
389*4882a593Smuzhiyun 	base = core->pub.base;
390*4882a593Smuzhiyun 	/*
391*4882a593Smuzhiyun 	 * Must do the disable sequence first to work for
392*4882a593Smuzhiyun 	 * arbitrary current core state.
393*4882a593Smuzhiyun 	 */
394*4882a593Smuzhiyun 	brcmf_chip_sb_coredisable(core, 0, 0);
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	/*
397*4882a593Smuzhiyun 	 * Now do the initialization sequence.
398*4882a593Smuzhiyun 	 * set reset while enabling the clock and
399*4882a593Smuzhiyun 	 * forcing them on throughout the core
400*4882a593Smuzhiyun 	 */
401*4882a593Smuzhiyun 	ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow),
402*4882a593Smuzhiyun 			 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
403*4882a593Smuzhiyun 			 SSB_TMSLOW_RESET);
404*4882a593Smuzhiyun 	regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
405*4882a593Smuzhiyun 	udelay(1);
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	/* clear any serror */
408*4882a593Smuzhiyun 	regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatehigh));
409*4882a593Smuzhiyun 	if (regdata & SSB_TMSHIGH_SERR)
410*4882a593Smuzhiyun 		ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatehigh), 0);
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbimstate));
413*4882a593Smuzhiyun 	if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) {
414*4882a593Smuzhiyun 		regdata &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO);
415*4882a593Smuzhiyun 		ci->ops->write32(ci->ctx, CORE_SB(base, sbimstate), regdata);
416*4882a593Smuzhiyun 	}
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	/* clear reset and allow it to propagate throughout the core */
419*4882a593Smuzhiyun 	ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow),
420*4882a593Smuzhiyun 			 SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
421*4882a593Smuzhiyun 	regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
422*4882a593Smuzhiyun 	udelay(1);
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	/* leave clock enabled */
425*4882a593Smuzhiyun 	ci->ops->write32(ci->ctx, CORE_SB(base, sbtmstatelow),
426*4882a593Smuzhiyun 			 SSB_TMSLOW_CLOCK);
427*4882a593Smuzhiyun 	regdata = ci->ops->read32(ci->ctx, CORE_SB(base, sbtmstatelow));
428*4882a593Smuzhiyun 	udelay(1);
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun 
brcmf_chip_ai_resetcore(struct brcmf_core_priv * core,u32 prereset,u32 reset,u32 postreset)431*4882a593Smuzhiyun static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset,
432*4882a593Smuzhiyun 				    u32 reset, u32 postreset)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun 	struct brcmf_chip_priv *ci;
435*4882a593Smuzhiyun 	int count;
436*4882a593Smuzhiyun 	struct brcmf_core *d11core2 = NULL;
437*4882a593Smuzhiyun 	struct brcmf_core_priv *d11priv2 = NULL;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	ci = core->chip;
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	/* special handle two D11 cores reset */
442*4882a593Smuzhiyun 	if (core->pub.id == BCMA_CORE_80211) {
443*4882a593Smuzhiyun 		d11core2 = brcmf_chip_get_d11core(&ci->pub, 1);
444*4882a593Smuzhiyun 		if (d11core2) {
445*4882a593Smuzhiyun 			brcmf_dbg(INFO, "found two d11 cores, reset both\n");
446*4882a593Smuzhiyun 			d11priv2 = container_of(d11core2,
447*4882a593Smuzhiyun 						struct brcmf_core_priv, pub);
448*4882a593Smuzhiyun 		}
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	/* must disable first to work for arbitrary current core state */
452*4882a593Smuzhiyun 	brcmf_chip_ai_coredisable(core, prereset, reset);
453*4882a593Smuzhiyun 	if (d11priv2)
454*4882a593Smuzhiyun 		brcmf_chip_ai_coredisable(d11priv2, prereset, reset);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	count = 0;
457*4882a593Smuzhiyun 	while (ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) &
458*4882a593Smuzhiyun 	       BCMA_RESET_CTL_RESET) {
459*4882a593Smuzhiyun 		ci->ops->write32(ci->ctx, core->wrapbase + BCMA_RESET_CTL, 0);
460*4882a593Smuzhiyun 		count++;
461*4882a593Smuzhiyun 		if (count > 50)
462*4882a593Smuzhiyun 			break;
463*4882a593Smuzhiyun 		usleep_range(40, 60);
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	if (d11priv2) {
467*4882a593Smuzhiyun 		count = 0;
468*4882a593Smuzhiyun 		while (ci->ops->read32(ci->ctx,
469*4882a593Smuzhiyun 				       d11priv2->wrapbase + BCMA_RESET_CTL) &
470*4882a593Smuzhiyun 				       BCMA_RESET_CTL_RESET) {
471*4882a593Smuzhiyun 			ci->ops->write32(ci->ctx,
472*4882a593Smuzhiyun 					 d11priv2->wrapbase + BCMA_RESET_CTL,
473*4882a593Smuzhiyun 					 0);
474*4882a593Smuzhiyun 			count++;
475*4882a593Smuzhiyun 			if (count > 50)
476*4882a593Smuzhiyun 				break;
477*4882a593Smuzhiyun 			usleep_range(40, 60);
478*4882a593Smuzhiyun 		}
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
482*4882a593Smuzhiyun 			 postreset | BCMA_IOCTL_CLK);
483*4882a593Smuzhiyun 	ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	if (d11priv2) {
486*4882a593Smuzhiyun 		ci->ops->write32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL,
487*4882a593Smuzhiyun 				 postreset | BCMA_IOCTL_CLK);
488*4882a593Smuzhiyun 		ci->ops->read32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL);
489*4882a593Smuzhiyun 	}
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun 
brcmf_chip_name(u32 id,u32 rev,char * buf,uint len)492*4882a593Smuzhiyun char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun 	const char *fmt;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	fmt = ((id > 0xa000) || (id < 0x4000)) ? "BCM%d/%u" : "BCM%x/%u";
497*4882a593Smuzhiyun 	snprintf(buf, len, fmt, id, rev);
498*4882a593Smuzhiyun 	return buf;
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
brcmf_chip_add_core(struct brcmf_chip_priv * ci,u16 coreid,u32 base,u32 wrapbase)501*4882a593Smuzhiyun static struct brcmf_core *brcmf_chip_add_core(struct brcmf_chip_priv *ci,
502*4882a593Smuzhiyun 					      u16 coreid, u32 base,
503*4882a593Smuzhiyun 					      u32 wrapbase)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun 	struct brcmf_core_priv *core;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	core = kzalloc(sizeof(*core), GFP_KERNEL);
508*4882a593Smuzhiyun 	if (!core)
509*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	core->pub.id = coreid;
512*4882a593Smuzhiyun 	core->pub.base = base;
513*4882a593Smuzhiyun 	core->chip = ci;
514*4882a593Smuzhiyun 	core->wrapbase = wrapbase;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	list_add_tail(&core->list, &ci->cores);
517*4882a593Smuzhiyun 	return &core->pub;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun /* safety check for chipinfo */
brcmf_chip_cores_check(struct brcmf_chip_priv * ci)521*4882a593Smuzhiyun static int brcmf_chip_cores_check(struct brcmf_chip_priv *ci)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun 	struct brcmf_core_priv *core;
524*4882a593Smuzhiyun 	bool need_socram = false;
525*4882a593Smuzhiyun 	bool has_socram = false;
526*4882a593Smuzhiyun 	bool cpu_found = false;
527*4882a593Smuzhiyun 	int idx = 1;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	list_for_each_entry(core, &ci->cores, list) {
530*4882a593Smuzhiyun 		brcmf_dbg(INFO, " [%-2d] core 0x%x:%-2d base 0x%08x wrap 0x%08x\n",
531*4882a593Smuzhiyun 			  idx++, core->pub.id, core->pub.rev, core->pub.base,
532*4882a593Smuzhiyun 			  core->wrapbase);
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 		switch (core->pub.id) {
535*4882a593Smuzhiyun 		case BCMA_CORE_ARM_CM3:
536*4882a593Smuzhiyun 			cpu_found = true;
537*4882a593Smuzhiyun 			need_socram = true;
538*4882a593Smuzhiyun 			break;
539*4882a593Smuzhiyun 		case BCMA_CORE_INTERNAL_MEM:
540*4882a593Smuzhiyun 			has_socram = true;
541*4882a593Smuzhiyun 			break;
542*4882a593Smuzhiyun 		case BCMA_CORE_ARM_CR4:
543*4882a593Smuzhiyun 			cpu_found = true;
544*4882a593Smuzhiyun 			break;
545*4882a593Smuzhiyun 		case BCMA_CORE_ARM_CA7:
546*4882a593Smuzhiyun 			cpu_found = true;
547*4882a593Smuzhiyun 			break;
548*4882a593Smuzhiyun 		default:
549*4882a593Smuzhiyun 			break;
550*4882a593Smuzhiyun 		}
551*4882a593Smuzhiyun 	}
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	if (!cpu_found) {
554*4882a593Smuzhiyun 		brcmf_err("CPU core not detected\n");
555*4882a593Smuzhiyun 		return -ENXIO;
556*4882a593Smuzhiyun 	}
557*4882a593Smuzhiyun 	/* check RAM core presence for ARM CM3 core */
558*4882a593Smuzhiyun 	if (need_socram && !has_socram) {
559*4882a593Smuzhiyun 		brcmf_err("RAM core not provided with ARM CM3 core\n");
560*4882a593Smuzhiyun 		return -ENODEV;
561*4882a593Smuzhiyun 	}
562*4882a593Smuzhiyun 	return 0;
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun 
brcmf_chip_core_read32(struct brcmf_core_priv * core,u16 reg)565*4882a593Smuzhiyun static u32 brcmf_chip_core_read32(struct brcmf_core_priv *core, u16 reg)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun 	return core->chip->ops->read32(core->chip->ctx, core->pub.base + reg);
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun 
brcmf_chip_core_write32(struct brcmf_core_priv * core,u16 reg,u32 val)570*4882a593Smuzhiyun static void brcmf_chip_core_write32(struct brcmf_core_priv *core,
571*4882a593Smuzhiyun 				    u16 reg, u32 val)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun 	core->chip->ops->write32(core->chip->ctx, core->pub.base + reg, val);
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun 
brcmf_chip_socram_banksize(struct brcmf_core_priv * core,u8 idx,u32 * banksize)576*4882a593Smuzhiyun static bool brcmf_chip_socram_banksize(struct brcmf_core_priv *core, u8 idx,
577*4882a593Smuzhiyun 				       u32 *banksize)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun 	u32 bankinfo;
580*4882a593Smuzhiyun 	u32 bankidx = (SOCRAM_MEMTYPE_RAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT);
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	bankidx |= idx;
583*4882a593Smuzhiyun 	brcmf_chip_core_write32(core, SOCRAMREGOFFS(bankidx), bankidx);
584*4882a593Smuzhiyun 	bankinfo = brcmf_chip_core_read32(core, SOCRAMREGOFFS(bankinfo));
585*4882a593Smuzhiyun 	*banksize = (bankinfo & SOCRAM_BANKINFO_SZMASK) + 1;
586*4882a593Smuzhiyun 	*banksize *= SOCRAM_BANKINFO_SZBASE;
587*4882a593Smuzhiyun 	return !!(bankinfo & SOCRAM_BANKINFO_RETNTRAM_MASK);
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun 
brcmf_chip_socram_ramsize(struct brcmf_core_priv * sr,u32 * ramsize,u32 * srsize)590*4882a593Smuzhiyun static void brcmf_chip_socram_ramsize(struct brcmf_core_priv *sr, u32 *ramsize,
591*4882a593Smuzhiyun 				      u32 *srsize)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun 	u32 coreinfo;
594*4882a593Smuzhiyun 	uint nb, banksize, lss;
595*4882a593Smuzhiyun 	bool retent;
596*4882a593Smuzhiyun 	int i;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	*ramsize = 0;
599*4882a593Smuzhiyun 	*srsize = 0;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	if (WARN_ON(sr->pub.rev < 4))
602*4882a593Smuzhiyun 		return;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	if (!brcmf_chip_iscoreup(&sr->pub))
605*4882a593Smuzhiyun 		brcmf_chip_resetcore(&sr->pub, 0, 0, 0);
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	/* Get info for determining size */
608*4882a593Smuzhiyun 	coreinfo = brcmf_chip_core_read32(sr, SOCRAMREGOFFS(coreinfo));
609*4882a593Smuzhiyun 	nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	if ((sr->pub.rev <= 7) || (sr->pub.rev == 12)) {
612*4882a593Smuzhiyun 		banksize = (coreinfo & SRCI_SRBSZ_MASK);
613*4882a593Smuzhiyun 		lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT;
614*4882a593Smuzhiyun 		if (lss != 0)
615*4882a593Smuzhiyun 			nb--;
616*4882a593Smuzhiyun 		*ramsize = nb * (1 << (banksize + SR_BSZ_BASE));
617*4882a593Smuzhiyun 		if (lss != 0)
618*4882a593Smuzhiyun 			*ramsize += (1 << ((lss - 1) + SR_BSZ_BASE));
619*4882a593Smuzhiyun 	} else {
620*4882a593Smuzhiyun 		/* length of SRAM Banks increased for corerev greater than 23 */
621*4882a593Smuzhiyun 		if (sr->pub.rev >= 23) {
622*4882a593Smuzhiyun 			nb = (coreinfo & (SRCI_SRNB_MASK | SRCI_SRNB_MASK_EXT))
623*4882a593Smuzhiyun 				>> SRCI_SRNB_SHIFT;
624*4882a593Smuzhiyun 		} else {
625*4882a593Smuzhiyun 			nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
626*4882a593Smuzhiyun 		}
627*4882a593Smuzhiyun 		for (i = 0; i < nb; i++) {
628*4882a593Smuzhiyun 			retent = brcmf_chip_socram_banksize(sr, i, &banksize);
629*4882a593Smuzhiyun 			*ramsize += banksize;
630*4882a593Smuzhiyun 			if (retent)
631*4882a593Smuzhiyun 				*srsize += banksize;
632*4882a593Smuzhiyun 		}
633*4882a593Smuzhiyun 	}
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	/* hardcoded save&restore memory sizes */
636*4882a593Smuzhiyun 	switch (sr->chip->pub.chip) {
637*4882a593Smuzhiyun 	case BRCM_CC_4334_CHIP_ID:
638*4882a593Smuzhiyun 		if (sr->chip->pub.chiprev < 2)
639*4882a593Smuzhiyun 			*srsize = (32 * 1024);
640*4882a593Smuzhiyun 		break;
641*4882a593Smuzhiyun 	case BRCM_CC_43430_CHIP_ID:
642*4882a593Smuzhiyun 		/* assume sr for now as we can not check
643*4882a593Smuzhiyun 		 * firmware sr capability at this point.
644*4882a593Smuzhiyun 		 */
645*4882a593Smuzhiyun 		*srsize = (64 * 1024);
646*4882a593Smuzhiyun 		break;
647*4882a593Smuzhiyun 	default:
648*4882a593Smuzhiyun 		break;
649*4882a593Smuzhiyun 	}
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun /** Return the SYS MEM size */
brcmf_chip_sysmem_ramsize(struct brcmf_core_priv * sysmem)653*4882a593Smuzhiyun static u32 brcmf_chip_sysmem_ramsize(struct brcmf_core_priv *sysmem)
654*4882a593Smuzhiyun {
655*4882a593Smuzhiyun 	u32 memsize = 0;
656*4882a593Smuzhiyun 	u32 coreinfo;
657*4882a593Smuzhiyun 	u32 idx;
658*4882a593Smuzhiyun 	u32 nb;
659*4882a593Smuzhiyun 	u32 banksize;
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	if (!brcmf_chip_iscoreup(&sysmem->pub))
662*4882a593Smuzhiyun 		brcmf_chip_resetcore(&sysmem->pub, 0, 0, 0);
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	coreinfo = brcmf_chip_core_read32(sysmem, SYSMEMREGOFFS(coreinfo));
665*4882a593Smuzhiyun 	nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	for (idx = 0; idx < nb; idx++) {
668*4882a593Smuzhiyun 		brcmf_chip_socram_banksize(sysmem, idx, &banksize);
669*4882a593Smuzhiyun 		memsize += banksize;
670*4882a593Smuzhiyun 	}
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	return memsize;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun /** Return the TCM-RAM size of the ARMCR4 core. */
brcmf_chip_tcm_ramsize(struct brcmf_core_priv * cr4)676*4882a593Smuzhiyun static u32 brcmf_chip_tcm_ramsize(struct brcmf_core_priv *cr4)
677*4882a593Smuzhiyun {
678*4882a593Smuzhiyun 	u32 corecap;
679*4882a593Smuzhiyun 	u32 memsize = 0;
680*4882a593Smuzhiyun 	u32 nab;
681*4882a593Smuzhiyun 	u32 nbb;
682*4882a593Smuzhiyun 	u32 totb;
683*4882a593Smuzhiyun 	u32 bxinfo;
684*4882a593Smuzhiyun 	u32 idx;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	corecap = brcmf_chip_core_read32(cr4, ARMCR4_CAP);
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	nab = (corecap & ARMCR4_TCBANB_MASK) >> ARMCR4_TCBANB_SHIFT;
689*4882a593Smuzhiyun 	nbb = (corecap & ARMCR4_TCBBNB_MASK) >> ARMCR4_TCBBNB_SHIFT;
690*4882a593Smuzhiyun 	totb = nab + nbb;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	for (idx = 0; idx < totb; idx++) {
693*4882a593Smuzhiyun 		brcmf_chip_core_write32(cr4, ARMCR4_BANKIDX, idx);
694*4882a593Smuzhiyun 		bxinfo = brcmf_chip_core_read32(cr4, ARMCR4_BANKINFO);
695*4882a593Smuzhiyun 		memsize += ((bxinfo & ARMCR4_BSZ_MASK) + 1) * ARMCR4_BSZ_MULT;
696*4882a593Smuzhiyun 	}
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	return memsize;
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun 
brcmf_chip_tcm_rambase(struct brcmf_chip_priv * ci)701*4882a593Smuzhiyun static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci)
702*4882a593Smuzhiyun {
703*4882a593Smuzhiyun 	switch (ci->pub.chip) {
704*4882a593Smuzhiyun 	case BRCM_CC_4345_CHIP_ID:
705*4882a593Smuzhiyun 		return 0x198000;
706*4882a593Smuzhiyun 	case BRCM_CC_4335_CHIP_ID:
707*4882a593Smuzhiyun 	case BRCM_CC_4339_CHIP_ID:
708*4882a593Smuzhiyun 	case BRCM_CC_4350_CHIP_ID:
709*4882a593Smuzhiyun 	case BRCM_CC_4354_CHIP_ID:
710*4882a593Smuzhiyun 	case BRCM_CC_4356_CHIP_ID:
711*4882a593Smuzhiyun 	case BRCM_CC_43567_CHIP_ID:
712*4882a593Smuzhiyun 	case BRCM_CC_43569_CHIP_ID:
713*4882a593Smuzhiyun 	case BRCM_CC_43570_CHIP_ID:
714*4882a593Smuzhiyun 	case BRCM_CC_4358_CHIP_ID:
715*4882a593Smuzhiyun 	case BRCM_CC_43602_CHIP_ID:
716*4882a593Smuzhiyun 	case BRCM_CC_4371_CHIP_ID:
717*4882a593Smuzhiyun 		return 0x180000;
718*4882a593Smuzhiyun 	case BRCM_CC_43465_CHIP_ID:
719*4882a593Smuzhiyun 	case BRCM_CC_43525_CHIP_ID:
720*4882a593Smuzhiyun 	case BRCM_CC_4365_CHIP_ID:
721*4882a593Smuzhiyun 	case BRCM_CC_4366_CHIP_ID:
722*4882a593Smuzhiyun 	case BRCM_CC_43664_CHIP_ID:
723*4882a593Smuzhiyun 		return 0x200000;
724*4882a593Smuzhiyun 	case BRCM_CC_4359_CHIP_ID:
725*4882a593Smuzhiyun 		return (ci->pub.chiprev < 9) ? 0x180000 : 0x160000;
726*4882a593Smuzhiyun 	case BRCM_CC_4364_CHIP_ID:
727*4882a593Smuzhiyun 	case CY_CC_4373_CHIP_ID:
728*4882a593Smuzhiyun 		return 0x160000;
729*4882a593Smuzhiyun 	default:
730*4882a593Smuzhiyun 		brcmf_err("unknown chip: %s\n", ci->pub.name);
731*4882a593Smuzhiyun 		break;
732*4882a593Smuzhiyun 	}
733*4882a593Smuzhiyun 	return 0;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
brcmf_chip_get_raminfo(struct brcmf_chip * pub)736*4882a593Smuzhiyun int brcmf_chip_get_raminfo(struct brcmf_chip *pub)
737*4882a593Smuzhiyun {
738*4882a593Smuzhiyun 	struct brcmf_chip_priv *ci = container_of(pub, struct brcmf_chip_priv,
739*4882a593Smuzhiyun 						  pub);
740*4882a593Smuzhiyun 	struct brcmf_core_priv *mem_core;
741*4882a593Smuzhiyun 	struct brcmf_core *mem;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_ARM_CR4);
744*4882a593Smuzhiyun 	if (mem) {
745*4882a593Smuzhiyun 		mem_core = container_of(mem, struct brcmf_core_priv, pub);
746*4882a593Smuzhiyun 		ci->pub.ramsize = brcmf_chip_tcm_ramsize(mem_core);
747*4882a593Smuzhiyun 		ci->pub.rambase = brcmf_chip_tcm_rambase(ci);
748*4882a593Smuzhiyun 		if (!ci->pub.rambase) {
749*4882a593Smuzhiyun 			brcmf_err("RAM base not provided with ARM CR4 core\n");
750*4882a593Smuzhiyun 			return -EINVAL;
751*4882a593Smuzhiyun 		}
752*4882a593Smuzhiyun 	} else {
753*4882a593Smuzhiyun 		mem = brcmf_chip_get_core(&ci->pub, BCMA_CORE_SYS_MEM);
754*4882a593Smuzhiyun 		if (mem) {
755*4882a593Smuzhiyun 			mem_core = container_of(mem, struct brcmf_core_priv,
756*4882a593Smuzhiyun 						pub);
757*4882a593Smuzhiyun 			ci->pub.ramsize = brcmf_chip_sysmem_ramsize(mem_core);
758*4882a593Smuzhiyun 			ci->pub.rambase = brcmf_chip_tcm_rambase(ci);
759*4882a593Smuzhiyun 			if (!ci->pub.rambase) {
760*4882a593Smuzhiyun 				brcmf_err("RAM base not provided with ARM CA7 core\n");
761*4882a593Smuzhiyun 				return -EINVAL;
762*4882a593Smuzhiyun 			}
763*4882a593Smuzhiyun 		} else {
764*4882a593Smuzhiyun 			mem = brcmf_chip_get_core(&ci->pub,
765*4882a593Smuzhiyun 						  BCMA_CORE_INTERNAL_MEM);
766*4882a593Smuzhiyun 			if (!mem) {
767*4882a593Smuzhiyun 				brcmf_err("No memory cores found\n");
768*4882a593Smuzhiyun 				return -ENOMEM;
769*4882a593Smuzhiyun 			}
770*4882a593Smuzhiyun 			mem_core = container_of(mem, struct brcmf_core_priv,
771*4882a593Smuzhiyun 						pub);
772*4882a593Smuzhiyun 			brcmf_chip_socram_ramsize(mem_core, &ci->pub.ramsize,
773*4882a593Smuzhiyun 						  &ci->pub.srsize);
774*4882a593Smuzhiyun 		}
775*4882a593Smuzhiyun 	}
776*4882a593Smuzhiyun 	brcmf_dbg(INFO, "RAM: base=0x%x size=%d (0x%x) sr=%d (0x%x)\n",
777*4882a593Smuzhiyun 		  ci->pub.rambase, ci->pub.ramsize, ci->pub.ramsize,
778*4882a593Smuzhiyun 		  ci->pub.srsize, ci->pub.srsize);
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	if (!ci->pub.ramsize) {
781*4882a593Smuzhiyun 		brcmf_err("RAM size is undetermined\n");
782*4882a593Smuzhiyun 		return -ENOMEM;
783*4882a593Smuzhiyun 	}
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	if (ci->pub.ramsize > BRCMF_CHIP_MAX_MEMSIZE) {
786*4882a593Smuzhiyun 		brcmf_err("RAM size is incorrect\n");
787*4882a593Smuzhiyun 		return -ENOMEM;
788*4882a593Smuzhiyun 	}
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	return 0;
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun 
brcmf_chip_dmp_get_desc(struct brcmf_chip_priv * ci,u32 * eromaddr,u8 * type)793*4882a593Smuzhiyun static u32 brcmf_chip_dmp_get_desc(struct brcmf_chip_priv *ci, u32 *eromaddr,
794*4882a593Smuzhiyun 				   u8 *type)
795*4882a593Smuzhiyun {
796*4882a593Smuzhiyun 	u32 val;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	/* read next descriptor */
799*4882a593Smuzhiyun 	val = ci->ops->read32(ci->ctx, *eromaddr);
800*4882a593Smuzhiyun 	*eromaddr += 4;
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	if (!type)
803*4882a593Smuzhiyun 		return val;
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	/* determine descriptor type */
806*4882a593Smuzhiyun 	*type = (val & DMP_DESC_TYPE_MSK);
807*4882a593Smuzhiyun 	if ((*type & ~DMP_DESC_ADDRSIZE_GT32) == DMP_DESC_ADDRESS)
808*4882a593Smuzhiyun 		*type = DMP_DESC_ADDRESS;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 	return val;
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun 
brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv * ci,u32 * eromaddr,u32 * regbase,u32 * wrapbase)813*4882a593Smuzhiyun static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr,
814*4882a593Smuzhiyun 				      u32 *regbase, u32 *wrapbase)
815*4882a593Smuzhiyun {
816*4882a593Smuzhiyun 	u8 desc;
817*4882a593Smuzhiyun 	u32 val, szdesc;
818*4882a593Smuzhiyun 	u8 stype, sztype, wraptype;
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	*regbase = 0;
821*4882a593Smuzhiyun 	*wrapbase = 0;
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc);
824*4882a593Smuzhiyun 	if (desc == DMP_DESC_MASTER_PORT) {
825*4882a593Smuzhiyun 		wraptype = DMP_SLAVE_TYPE_MWRAP;
826*4882a593Smuzhiyun 	} else if (desc == DMP_DESC_ADDRESS) {
827*4882a593Smuzhiyun 		/* revert erom address */
828*4882a593Smuzhiyun 		*eromaddr -= 4;
829*4882a593Smuzhiyun 		wraptype = DMP_SLAVE_TYPE_SWRAP;
830*4882a593Smuzhiyun 	} else {
831*4882a593Smuzhiyun 		*eromaddr -= 4;
832*4882a593Smuzhiyun 		return -EILSEQ;
833*4882a593Smuzhiyun 	}
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	do {
836*4882a593Smuzhiyun 		/* locate address descriptor */
837*4882a593Smuzhiyun 		do {
838*4882a593Smuzhiyun 			val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc);
839*4882a593Smuzhiyun 			/* unexpected table end */
840*4882a593Smuzhiyun 			if (desc == DMP_DESC_EOT) {
841*4882a593Smuzhiyun 				*eromaddr -= 4;
842*4882a593Smuzhiyun 				return -EFAULT;
843*4882a593Smuzhiyun 			}
844*4882a593Smuzhiyun 		} while (desc != DMP_DESC_ADDRESS &&
845*4882a593Smuzhiyun 			 desc != DMP_DESC_COMPONENT);
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 		/* stop if we crossed current component border */
848*4882a593Smuzhiyun 		if (desc == DMP_DESC_COMPONENT) {
849*4882a593Smuzhiyun 			*eromaddr -= 4;
850*4882a593Smuzhiyun 			return 0;
851*4882a593Smuzhiyun 		}
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 		/* skip upper 32-bit address descriptor */
854*4882a593Smuzhiyun 		if (val & DMP_DESC_ADDRSIZE_GT32)
855*4882a593Smuzhiyun 			brcmf_chip_dmp_get_desc(ci, eromaddr, NULL);
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 		sztype = (val & DMP_SLAVE_SIZE_TYPE) >> DMP_SLAVE_SIZE_TYPE_S;
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 		/* next size descriptor can be skipped */
860*4882a593Smuzhiyun 		if (sztype == DMP_SLAVE_SIZE_DESC) {
861*4882a593Smuzhiyun 			szdesc = brcmf_chip_dmp_get_desc(ci, eromaddr, NULL);
862*4882a593Smuzhiyun 			/* skip upper size descriptor if present */
863*4882a593Smuzhiyun 			if (szdesc & DMP_DESC_ADDRSIZE_GT32)
864*4882a593Smuzhiyun 				brcmf_chip_dmp_get_desc(ci, eromaddr, NULL);
865*4882a593Smuzhiyun 		}
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 		/* look for 4K or 8K register regions */
868*4882a593Smuzhiyun 		if (sztype != DMP_SLAVE_SIZE_4K &&
869*4882a593Smuzhiyun 		    sztype != DMP_SLAVE_SIZE_8K)
870*4882a593Smuzhiyun 			continue;
871*4882a593Smuzhiyun 
872*4882a593Smuzhiyun 		stype = (val & DMP_SLAVE_TYPE) >> DMP_SLAVE_TYPE_S;
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 		/* only regular slave and wrapper */
875*4882a593Smuzhiyun 		if (*regbase == 0 && stype == DMP_SLAVE_TYPE_SLAVE)
876*4882a593Smuzhiyun 			*regbase = val & DMP_SLAVE_ADDR_BASE;
877*4882a593Smuzhiyun 		if (*wrapbase == 0 && stype == wraptype)
878*4882a593Smuzhiyun 			*wrapbase = val & DMP_SLAVE_ADDR_BASE;
879*4882a593Smuzhiyun 	} while (*regbase == 0 || *wrapbase == 0);
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	return 0;
882*4882a593Smuzhiyun }
883*4882a593Smuzhiyun 
884*4882a593Smuzhiyun static
brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv * ci)885*4882a593Smuzhiyun int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci)
886*4882a593Smuzhiyun {
887*4882a593Smuzhiyun 	struct brcmf_core *core;
888*4882a593Smuzhiyun 	u32 eromaddr;
889*4882a593Smuzhiyun 	u8 desc_type = 0;
890*4882a593Smuzhiyun 	u32 val;
891*4882a593Smuzhiyun 	u16 id;
892*4882a593Smuzhiyun 	u8 nmw, nsw, rev;
893*4882a593Smuzhiyun 	u32 base, wrap;
894*4882a593Smuzhiyun 	int err;
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	eromaddr = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, eromptr));
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	while (desc_type != DMP_DESC_EOT) {
899*4882a593Smuzhiyun 		val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type);
900*4882a593Smuzhiyun 		if (!(val & DMP_DESC_VALID))
901*4882a593Smuzhiyun 			continue;
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 		if (desc_type == DMP_DESC_EMPTY)
904*4882a593Smuzhiyun 			continue;
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 		/* need a component descriptor */
907*4882a593Smuzhiyun 		if (desc_type != DMP_DESC_COMPONENT)
908*4882a593Smuzhiyun 			continue;
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 		id = (val & DMP_COMP_PARTNUM) >> DMP_COMP_PARTNUM_S;
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 		/* next descriptor must be component as well */
913*4882a593Smuzhiyun 		val = brcmf_chip_dmp_get_desc(ci, &eromaddr, &desc_type);
914*4882a593Smuzhiyun 		if (WARN_ON((val & DMP_DESC_TYPE_MSK) != DMP_DESC_COMPONENT))
915*4882a593Smuzhiyun 			return -EFAULT;
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 		/* only look at cores with master port(s) */
918*4882a593Smuzhiyun 		nmw = (val & DMP_COMP_NUM_MWRAP) >> DMP_COMP_NUM_MWRAP_S;
919*4882a593Smuzhiyun 		nsw = (val & DMP_COMP_NUM_SWRAP) >> DMP_COMP_NUM_SWRAP_S;
920*4882a593Smuzhiyun 		rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S;
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 		/* need core with ports */
923*4882a593Smuzhiyun 		if (nmw + nsw == 0 &&
924*4882a593Smuzhiyun 		    id != BCMA_CORE_PMU &&
925*4882a593Smuzhiyun 		    id != BCMA_CORE_GCI)
926*4882a593Smuzhiyun 			continue;
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 		/* try to obtain register address info */
929*4882a593Smuzhiyun 		err = brcmf_chip_dmp_get_regaddr(ci, &eromaddr, &base, &wrap);
930*4882a593Smuzhiyun 		if (err)
931*4882a593Smuzhiyun 			continue;
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 		/* finally a core to be added */
934*4882a593Smuzhiyun 		core = brcmf_chip_add_core(ci, id, base, wrap);
935*4882a593Smuzhiyun 		if (IS_ERR(core))
936*4882a593Smuzhiyun 			return PTR_ERR(core);
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 		core->rev = rev;
939*4882a593Smuzhiyun 	}
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	return 0;
942*4882a593Smuzhiyun }
943*4882a593Smuzhiyun 
brcmf_chip_recognition(struct brcmf_chip_priv * ci)944*4882a593Smuzhiyun static int brcmf_chip_recognition(struct brcmf_chip_priv *ci)
945*4882a593Smuzhiyun {
946*4882a593Smuzhiyun 	struct brcmf_core *core;
947*4882a593Smuzhiyun 	u32 regdata;
948*4882a593Smuzhiyun 	u32 socitype;
949*4882a593Smuzhiyun 	int ret;
950*4882a593Smuzhiyun 
951*4882a593Smuzhiyun 	/* Get CC core rev
952*4882a593Smuzhiyun 	 * Chipid is assume to be at offset 0 from SI_ENUM_BASE
953*4882a593Smuzhiyun 	 * For different chiptypes or old sdio hosts w/o chipcommon,
954*4882a593Smuzhiyun 	 * other ways of recognition should be added here.
955*4882a593Smuzhiyun 	 */
956*4882a593Smuzhiyun 	regdata = ci->ops->read32(ci->ctx, CORE_CC_REG(SI_ENUM_BASE, chipid));
957*4882a593Smuzhiyun 	ci->pub.chip = regdata & CID_ID_MASK;
958*4882a593Smuzhiyun 	ci->pub.chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
959*4882a593Smuzhiyun 	socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun 	brcmf_chip_name(ci->pub.chip, ci->pub.chiprev,
962*4882a593Smuzhiyun 			ci->pub.name, sizeof(ci->pub.name));
963*4882a593Smuzhiyun 	brcmf_dbg(INFO, "found %s chip: %s\n",
964*4882a593Smuzhiyun 		  socitype == SOCI_SB ? "SB" : "AXI", ci->pub.name);
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	if (socitype == SOCI_SB) {
967*4882a593Smuzhiyun 		if (ci->pub.chip != BRCM_CC_4329_CHIP_ID) {
968*4882a593Smuzhiyun 			brcmf_err("SB chip is not supported\n");
969*4882a593Smuzhiyun 			return -ENODEV;
970*4882a593Smuzhiyun 		}
971*4882a593Smuzhiyun 		ci->iscoreup = brcmf_chip_sb_iscoreup;
972*4882a593Smuzhiyun 		ci->coredisable = brcmf_chip_sb_coredisable;
973*4882a593Smuzhiyun 		ci->resetcore = brcmf_chip_sb_resetcore;
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun 		core = brcmf_chip_add_core(ci, BCMA_CORE_CHIPCOMMON,
976*4882a593Smuzhiyun 					   SI_ENUM_BASE, 0);
977*4882a593Smuzhiyun 		brcmf_chip_sb_corerev(ci, core);
978*4882a593Smuzhiyun 		core = brcmf_chip_add_core(ci, BCMA_CORE_SDIO_DEV,
979*4882a593Smuzhiyun 					   BCM4329_CORE_BUS_BASE, 0);
980*4882a593Smuzhiyun 		brcmf_chip_sb_corerev(ci, core);
981*4882a593Smuzhiyun 		core = brcmf_chip_add_core(ci, BCMA_CORE_INTERNAL_MEM,
982*4882a593Smuzhiyun 					   BCM4329_CORE_SOCRAM_BASE, 0);
983*4882a593Smuzhiyun 		brcmf_chip_sb_corerev(ci, core);
984*4882a593Smuzhiyun 		core = brcmf_chip_add_core(ci, BCMA_CORE_ARM_CM3,
985*4882a593Smuzhiyun 					   BCM4329_CORE_ARM_BASE, 0);
986*4882a593Smuzhiyun 		brcmf_chip_sb_corerev(ci, core);
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 		core = brcmf_chip_add_core(ci, BCMA_CORE_80211, 0x18001000, 0);
989*4882a593Smuzhiyun 		brcmf_chip_sb_corerev(ci, core);
990*4882a593Smuzhiyun 	} else if (socitype == SOCI_AI) {
991*4882a593Smuzhiyun 		ci->iscoreup = brcmf_chip_ai_iscoreup;
992*4882a593Smuzhiyun 		ci->coredisable = brcmf_chip_ai_coredisable;
993*4882a593Smuzhiyun 		ci->resetcore = brcmf_chip_ai_resetcore;
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 		brcmf_chip_dmp_erom_scan(ci);
996*4882a593Smuzhiyun 	} else {
997*4882a593Smuzhiyun 		brcmf_err("chip backplane type %u is not supported\n",
998*4882a593Smuzhiyun 			  socitype);
999*4882a593Smuzhiyun 		return -ENODEV;
1000*4882a593Smuzhiyun 	}
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	ret = brcmf_chip_cores_check(ci);
1003*4882a593Smuzhiyun 	if (ret)
1004*4882a593Smuzhiyun 		return ret;
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	/* assure chip is passive for core access */
1007*4882a593Smuzhiyun 	brcmf_chip_set_passive(&ci->pub);
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 	/* Call bus specific reset function now. Cores have been determined
1010*4882a593Smuzhiyun 	 * but further access may require a chip specific reset at this point.
1011*4882a593Smuzhiyun 	 */
1012*4882a593Smuzhiyun 	if (ci->ops->reset) {
1013*4882a593Smuzhiyun 		ci->ops->reset(ci->ctx, &ci->pub);
1014*4882a593Smuzhiyun 		brcmf_chip_set_passive(&ci->pub);
1015*4882a593Smuzhiyun 	}
1016*4882a593Smuzhiyun 
1017*4882a593Smuzhiyun 	return brcmf_chip_get_raminfo(&ci->pub);
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun 
brcmf_chip_disable_arm(struct brcmf_chip_priv * chip,u16 id)1020*4882a593Smuzhiyun static void brcmf_chip_disable_arm(struct brcmf_chip_priv *chip, u16 id)
1021*4882a593Smuzhiyun {
1022*4882a593Smuzhiyun 	struct brcmf_core *core;
1023*4882a593Smuzhiyun 	struct brcmf_core_priv *cpu;
1024*4882a593Smuzhiyun 	u32 val;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun 	core = brcmf_chip_get_core(&chip->pub, id);
1028*4882a593Smuzhiyun 	if (!core)
1029*4882a593Smuzhiyun 		return;
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	switch (id) {
1032*4882a593Smuzhiyun 	case BCMA_CORE_ARM_CM3:
1033*4882a593Smuzhiyun 		brcmf_chip_coredisable(core, 0, 0);
1034*4882a593Smuzhiyun 		break;
1035*4882a593Smuzhiyun 	case BCMA_CORE_ARM_CR4:
1036*4882a593Smuzhiyun 	case BCMA_CORE_ARM_CA7:
1037*4882a593Smuzhiyun 		cpu = container_of(core, struct brcmf_core_priv, pub);
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 		/* clear all IOCTL bits except HALT bit */
1040*4882a593Smuzhiyun 		val = chip->ops->read32(chip->ctx, cpu->wrapbase + BCMA_IOCTL);
1041*4882a593Smuzhiyun 		val &= ARMCR4_BCMA_IOCTL_CPUHALT;
1042*4882a593Smuzhiyun 		brcmf_chip_resetcore(core, val, ARMCR4_BCMA_IOCTL_CPUHALT,
1043*4882a593Smuzhiyun 				     ARMCR4_BCMA_IOCTL_CPUHALT);
1044*4882a593Smuzhiyun 		break;
1045*4882a593Smuzhiyun 	default:
1046*4882a593Smuzhiyun 		brcmf_err("unknown id: %u\n", id);
1047*4882a593Smuzhiyun 		break;
1048*4882a593Smuzhiyun 	}
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun 
brcmf_chip_setup(struct brcmf_chip_priv * chip)1051*4882a593Smuzhiyun static int brcmf_chip_setup(struct brcmf_chip_priv *chip)
1052*4882a593Smuzhiyun {
1053*4882a593Smuzhiyun 	struct brcmf_chip *pub;
1054*4882a593Smuzhiyun 	struct brcmf_core_priv *cc;
1055*4882a593Smuzhiyun 	struct brcmf_core *pmu;
1056*4882a593Smuzhiyun 	u32 base;
1057*4882a593Smuzhiyun 	u32 val;
1058*4882a593Smuzhiyun 	int ret = 0;
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	pub = &chip->pub;
1061*4882a593Smuzhiyun 	cc = list_first_entry(&chip->cores, struct brcmf_core_priv, list);
1062*4882a593Smuzhiyun 	base = cc->pub.base;
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 	/* get chipcommon capabilites */
1065*4882a593Smuzhiyun 	pub->cc_caps = chip->ops->read32(chip->ctx,
1066*4882a593Smuzhiyun 					 CORE_CC_REG(base, capabilities));
1067*4882a593Smuzhiyun 	pub->cc_caps_ext = chip->ops->read32(chip->ctx,
1068*4882a593Smuzhiyun 					     CORE_CC_REG(base,
1069*4882a593Smuzhiyun 							 capabilities_ext));
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 	/* get pmu caps & rev */
1072*4882a593Smuzhiyun 	pmu = brcmf_chip_get_pmu(pub); /* after reading cc_caps_ext */
1073*4882a593Smuzhiyun 	if (pub->cc_caps & CC_CAP_PMU) {
1074*4882a593Smuzhiyun 		val = chip->ops->read32(chip->ctx,
1075*4882a593Smuzhiyun 					CORE_CC_REG(pmu->base, pmucapabilities));
1076*4882a593Smuzhiyun 		pub->pmurev = val & PCAP_REV_MASK;
1077*4882a593Smuzhiyun 		pub->pmucaps = val;
1078*4882a593Smuzhiyun 	}
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun 	brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, pmucaps=0x%x\n",
1081*4882a593Smuzhiyun 		  cc->pub.rev, pub->pmurev, pub->pmucaps);
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	/* execute bus core specific setup */
1084*4882a593Smuzhiyun 	if (chip->ops->setup)
1085*4882a593Smuzhiyun 		ret = chip->ops->setup(chip->ctx, pub);
1086*4882a593Smuzhiyun 
1087*4882a593Smuzhiyun 	return ret;
1088*4882a593Smuzhiyun }
1089*4882a593Smuzhiyun 
brcmf_chip_attach(void * ctx,const struct brcmf_buscore_ops * ops)1090*4882a593Smuzhiyun struct brcmf_chip *brcmf_chip_attach(void *ctx,
1091*4882a593Smuzhiyun 				     const struct brcmf_buscore_ops *ops)
1092*4882a593Smuzhiyun {
1093*4882a593Smuzhiyun 	struct brcmf_chip_priv *chip;
1094*4882a593Smuzhiyun 	int err = 0;
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun 	if (WARN_ON(!ops->read32))
1097*4882a593Smuzhiyun 		err = -EINVAL;
1098*4882a593Smuzhiyun 	if (WARN_ON(!ops->write32))
1099*4882a593Smuzhiyun 		err = -EINVAL;
1100*4882a593Smuzhiyun 	if (WARN_ON(!ops->prepare))
1101*4882a593Smuzhiyun 		err = -EINVAL;
1102*4882a593Smuzhiyun 	if (WARN_ON(!ops->activate))
1103*4882a593Smuzhiyun 		err = -EINVAL;
1104*4882a593Smuzhiyun 	if (err < 0)
1105*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun 	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
1108*4882a593Smuzhiyun 	if (!chip)
1109*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun 	INIT_LIST_HEAD(&chip->cores);
1112*4882a593Smuzhiyun 	chip->num_cores = 0;
1113*4882a593Smuzhiyun 	chip->ops = ops;
1114*4882a593Smuzhiyun 	chip->ctx = ctx;
1115*4882a593Smuzhiyun 
1116*4882a593Smuzhiyun 	err = ops->prepare(ctx);
1117*4882a593Smuzhiyun 	if (err < 0)
1118*4882a593Smuzhiyun 		goto fail;
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 	err = brcmf_chip_recognition(chip);
1121*4882a593Smuzhiyun 	if (err < 0)
1122*4882a593Smuzhiyun 		goto fail;
1123*4882a593Smuzhiyun 
1124*4882a593Smuzhiyun 	err = brcmf_chip_setup(chip);
1125*4882a593Smuzhiyun 	if (err < 0)
1126*4882a593Smuzhiyun 		goto fail;
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun 	return &chip->pub;
1129*4882a593Smuzhiyun 
1130*4882a593Smuzhiyun fail:
1131*4882a593Smuzhiyun 	brcmf_chip_detach(&chip->pub);
1132*4882a593Smuzhiyun 	return ERR_PTR(err);
1133*4882a593Smuzhiyun }
1134*4882a593Smuzhiyun 
brcmf_chip_detach(struct brcmf_chip * pub)1135*4882a593Smuzhiyun void brcmf_chip_detach(struct brcmf_chip *pub)
1136*4882a593Smuzhiyun {
1137*4882a593Smuzhiyun 	struct brcmf_chip_priv *chip;
1138*4882a593Smuzhiyun 	struct brcmf_core_priv *core;
1139*4882a593Smuzhiyun 	struct brcmf_core_priv *tmp;
1140*4882a593Smuzhiyun 
1141*4882a593Smuzhiyun 	chip = container_of(pub, struct brcmf_chip_priv, pub);
1142*4882a593Smuzhiyun 	list_for_each_entry_safe(core, tmp, &chip->cores, list) {
1143*4882a593Smuzhiyun 		list_del(&core->list);
1144*4882a593Smuzhiyun 		kfree(core);
1145*4882a593Smuzhiyun 	}
1146*4882a593Smuzhiyun 	kfree(chip);
1147*4882a593Smuzhiyun }
1148*4882a593Smuzhiyun 
brcmf_chip_get_d11core(struct brcmf_chip * pub,u8 unit)1149*4882a593Smuzhiyun struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit)
1150*4882a593Smuzhiyun {
1151*4882a593Smuzhiyun 	struct brcmf_chip_priv *chip;
1152*4882a593Smuzhiyun 	struct brcmf_core_priv *core;
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 	chip = container_of(pub, struct brcmf_chip_priv, pub);
1155*4882a593Smuzhiyun 	list_for_each_entry(core, &chip->cores, list) {
1156*4882a593Smuzhiyun 		if (core->pub.id == BCMA_CORE_80211) {
1157*4882a593Smuzhiyun 			if (unit-- == 0)
1158*4882a593Smuzhiyun 				return &core->pub;
1159*4882a593Smuzhiyun 		}
1160*4882a593Smuzhiyun 	}
1161*4882a593Smuzhiyun 	return NULL;
1162*4882a593Smuzhiyun }
1163*4882a593Smuzhiyun 
brcmf_chip_get_core(struct brcmf_chip * pub,u16 coreid)1164*4882a593Smuzhiyun struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *pub, u16 coreid)
1165*4882a593Smuzhiyun {
1166*4882a593Smuzhiyun 	struct brcmf_chip_priv *chip;
1167*4882a593Smuzhiyun 	struct brcmf_core_priv *core;
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun 	chip = container_of(pub, struct brcmf_chip_priv, pub);
1170*4882a593Smuzhiyun 	list_for_each_entry(core, &chip->cores, list)
1171*4882a593Smuzhiyun 		if (core->pub.id == coreid)
1172*4882a593Smuzhiyun 			return &core->pub;
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	return NULL;
1175*4882a593Smuzhiyun }
1176*4882a593Smuzhiyun 
brcmf_chip_get_chipcommon(struct brcmf_chip * pub)1177*4882a593Smuzhiyun struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *pub)
1178*4882a593Smuzhiyun {
1179*4882a593Smuzhiyun 	struct brcmf_chip_priv *chip;
1180*4882a593Smuzhiyun 	struct brcmf_core_priv *cc;
1181*4882a593Smuzhiyun 
1182*4882a593Smuzhiyun 	chip = container_of(pub, struct brcmf_chip_priv, pub);
1183*4882a593Smuzhiyun 	cc = list_first_entry(&chip->cores, struct brcmf_core_priv, list);
1184*4882a593Smuzhiyun 	if (WARN_ON(!cc || cc->pub.id != BCMA_CORE_CHIPCOMMON))
1185*4882a593Smuzhiyun 		return brcmf_chip_get_core(pub, BCMA_CORE_CHIPCOMMON);
1186*4882a593Smuzhiyun 	return &cc->pub;
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun 
brcmf_chip_get_pmu(struct brcmf_chip * pub)1189*4882a593Smuzhiyun struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub)
1190*4882a593Smuzhiyun {
1191*4882a593Smuzhiyun 	struct brcmf_core *cc = brcmf_chip_get_chipcommon(pub);
1192*4882a593Smuzhiyun 	struct brcmf_core *pmu;
1193*4882a593Smuzhiyun 
1194*4882a593Smuzhiyun 	/* See if there is separated PMU core available */
1195*4882a593Smuzhiyun 	if (cc->rev >= 35 &&
1196*4882a593Smuzhiyun 	    pub->cc_caps_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
1197*4882a593Smuzhiyun 		pmu = brcmf_chip_get_core(pub, BCMA_CORE_PMU);
1198*4882a593Smuzhiyun 		if (pmu)
1199*4882a593Smuzhiyun 			return pmu;
1200*4882a593Smuzhiyun 	}
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	/* Fallback to ChipCommon core for older hardware */
1203*4882a593Smuzhiyun 	return cc;
1204*4882a593Smuzhiyun }
1205*4882a593Smuzhiyun 
brcmf_chip_iscoreup(struct brcmf_core * pub)1206*4882a593Smuzhiyun bool brcmf_chip_iscoreup(struct brcmf_core *pub)
1207*4882a593Smuzhiyun {
1208*4882a593Smuzhiyun 	struct brcmf_core_priv *core;
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 	core = container_of(pub, struct brcmf_core_priv, pub);
1211*4882a593Smuzhiyun 	return core->chip->iscoreup(core);
1212*4882a593Smuzhiyun }
1213*4882a593Smuzhiyun 
brcmf_chip_coredisable(struct brcmf_core * pub,u32 prereset,u32 reset)1214*4882a593Smuzhiyun void brcmf_chip_coredisable(struct brcmf_core *pub, u32 prereset, u32 reset)
1215*4882a593Smuzhiyun {
1216*4882a593Smuzhiyun 	struct brcmf_core_priv *core;
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun 	core = container_of(pub, struct brcmf_core_priv, pub);
1219*4882a593Smuzhiyun 	core->chip->coredisable(core, prereset, reset);
1220*4882a593Smuzhiyun }
1221*4882a593Smuzhiyun 
brcmf_chip_resetcore(struct brcmf_core * pub,u32 prereset,u32 reset,u32 postreset)1222*4882a593Smuzhiyun void brcmf_chip_resetcore(struct brcmf_core *pub, u32 prereset, u32 reset,
1223*4882a593Smuzhiyun 			  u32 postreset)
1224*4882a593Smuzhiyun {
1225*4882a593Smuzhiyun 	struct brcmf_core_priv *core;
1226*4882a593Smuzhiyun 
1227*4882a593Smuzhiyun 	core = container_of(pub, struct brcmf_core_priv, pub);
1228*4882a593Smuzhiyun 	core->chip->resetcore(core, prereset, reset, postreset);
1229*4882a593Smuzhiyun }
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun static void
brcmf_chip_cm3_set_passive(struct brcmf_chip_priv * chip)1232*4882a593Smuzhiyun brcmf_chip_cm3_set_passive(struct brcmf_chip_priv *chip)
1233*4882a593Smuzhiyun {
1234*4882a593Smuzhiyun 	struct brcmf_core *core;
1235*4882a593Smuzhiyun 	struct brcmf_core_priv *sr;
1236*4882a593Smuzhiyun 
1237*4882a593Smuzhiyun 	brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CM3);
1238*4882a593Smuzhiyun 	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211);
1239*4882a593Smuzhiyun 	brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET |
1240*4882a593Smuzhiyun 				   D11_BCMA_IOCTL_PHYCLOCKEN,
1241*4882a593Smuzhiyun 			     D11_BCMA_IOCTL_PHYCLOCKEN,
1242*4882a593Smuzhiyun 			     D11_BCMA_IOCTL_PHYCLOCKEN);
1243*4882a593Smuzhiyun 	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM);
1244*4882a593Smuzhiyun 	brcmf_chip_resetcore(core, 0, 0, 0);
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 	/* disable bank #3 remap for this device */
1247*4882a593Smuzhiyun 	if (chip->pub.chip == BRCM_CC_43430_CHIP_ID) {
1248*4882a593Smuzhiyun 		sr = container_of(core, struct brcmf_core_priv, pub);
1249*4882a593Smuzhiyun 		brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankidx), 3);
1250*4882a593Smuzhiyun 		brcmf_chip_core_write32(sr, SOCRAMREGOFFS(bankpda), 0);
1251*4882a593Smuzhiyun 	}
1252*4882a593Smuzhiyun }
1253*4882a593Smuzhiyun 
brcmf_chip_cm3_set_active(struct brcmf_chip_priv * chip)1254*4882a593Smuzhiyun static bool brcmf_chip_cm3_set_active(struct brcmf_chip_priv *chip)
1255*4882a593Smuzhiyun {
1256*4882a593Smuzhiyun 	struct brcmf_core *core;
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun 	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_INTERNAL_MEM);
1259*4882a593Smuzhiyun 	if (!brcmf_chip_iscoreup(core)) {
1260*4882a593Smuzhiyun 		brcmf_err("SOCRAM core is down after reset?\n");
1261*4882a593Smuzhiyun 		return false;
1262*4882a593Smuzhiyun 	}
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun 	chip->ops->activate(chip->ctx, &chip->pub, 0);
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun 	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CM3);
1267*4882a593Smuzhiyun 	brcmf_chip_resetcore(core, 0, 0, 0);
1268*4882a593Smuzhiyun 
1269*4882a593Smuzhiyun 	return true;
1270*4882a593Smuzhiyun }
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun static inline void
brcmf_chip_cr4_set_passive(struct brcmf_chip_priv * chip)1273*4882a593Smuzhiyun brcmf_chip_cr4_set_passive(struct brcmf_chip_priv *chip)
1274*4882a593Smuzhiyun {
1275*4882a593Smuzhiyun 	struct brcmf_core *core;
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CR4);
1278*4882a593Smuzhiyun 
1279*4882a593Smuzhiyun 	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211);
1280*4882a593Smuzhiyun 	brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET |
1281*4882a593Smuzhiyun 				   D11_BCMA_IOCTL_PHYCLOCKEN,
1282*4882a593Smuzhiyun 			     D11_BCMA_IOCTL_PHYCLOCKEN,
1283*4882a593Smuzhiyun 			     D11_BCMA_IOCTL_PHYCLOCKEN);
1284*4882a593Smuzhiyun }
1285*4882a593Smuzhiyun 
brcmf_chip_cr4_set_active(struct brcmf_chip_priv * chip,u32 rstvec)1286*4882a593Smuzhiyun static bool brcmf_chip_cr4_set_active(struct brcmf_chip_priv *chip, u32 rstvec)
1287*4882a593Smuzhiyun {
1288*4882a593Smuzhiyun 	struct brcmf_core *core;
1289*4882a593Smuzhiyun 
1290*4882a593Smuzhiyun 	chip->ops->activate(chip->ctx, &chip->pub, rstvec);
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun 	/* restore ARM */
1293*4882a593Smuzhiyun 	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CR4);
1294*4882a593Smuzhiyun 	brcmf_chip_resetcore(core, ARMCR4_BCMA_IOCTL_CPUHALT, 0, 0);
1295*4882a593Smuzhiyun 
1296*4882a593Smuzhiyun 	return true;
1297*4882a593Smuzhiyun }
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun static inline void
brcmf_chip_ca7_set_passive(struct brcmf_chip_priv * chip)1300*4882a593Smuzhiyun brcmf_chip_ca7_set_passive(struct brcmf_chip_priv *chip)
1301*4882a593Smuzhiyun {
1302*4882a593Smuzhiyun 	struct brcmf_core *core;
1303*4882a593Smuzhiyun 
1304*4882a593Smuzhiyun 	brcmf_chip_disable_arm(chip, BCMA_CORE_ARM_CA7);
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_80211);
1307*4882a593Smuzhiyun 	brcmf_chip_resetcore(core, D11_BCMA_IOCTL_PHYRESET |
1308*4882a593Smuzhiyun 				   D11_BCMA_IOCTL_PHYCLOCKEN,
1309*4882a593Smuzhiyun 			     D11_BCMA_IOCTL_PHYCLOCKEN,
1310*4882a593Smuzhiyun 			     D11_BCMA_IOCTL_PHYCLOCKEN);
1311*4882a593Smuzhiyun }
1312*4882a593Smuzhiyun 
brcmf_chip_ca7_set_active(struct brcmf_chip_priv * chip,u32 rstvec)1313*4882a593Smuzhiyun static bool brcmf_chip_ca7_set_active(struct brcmf_chip_priv *chip, u32 rstvec)
1314*4882a593Smuzhiyun {
1315*4882a593Smuzhiyun 	struct brcmf_core *core;
1316*4882a593Smuzhiyun 
1317*4882a593Smuzhiyun 	chip->ops->activate(chip->ctx, &chip->pub, rstvec);
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun 	/* restore ARM */
1320*4882a593Smuzhiyun 	core = brcmf_chip_get_core(&chip->pub, BCMA_CORE_ARM_CA7);
1321*4882a593Smuzhiyun 	brcmf_chip_resetcore(core, ARMCR4_BCMA_IOCTL_CPUHALT, 0, 0);
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun 	return true;
1324*4882a593Smuzhiyun }
1325*4882a593Smuzhiyun 
brcmf_chip_set_passive(struct brcmf_chip * pub)1326*4882a593Smuzhiyun void brcmf_chip_set_passive(struct brcmf_chip *pub)
1327*4882a593Smuzhiyun {
1328*4882a593Smuzhiyun 	struct brcmf_chip_priv *chip;
1329*4882a593Smuzhiyun 	struct brcmf_core *arm;
1330*4882a593Smuzhiyun 
1331*4882a593Smuzhiyun 	brcmf_dbg(TRACE, "Enter\n");
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun 	chip = container_of(pub, struct brcmf_chip_priv, pub);
1334*4882a593Smuzhiyun 	arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4);
1335*4882a593Smuzhiyun 	if (arm) {
1336*4882a593Smuzhiyun 		brcmf_chip_cr4_set_passive(chip);
1337*4882a593Smuzhiyun 		return;
1338*4882a593Smuzhiyun 	}
1339*4882a593Smuzhiyun 	arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CA7);
1340*4882a593Smuzhiyun 	if (arm) {
1341*4882a593Smuzhiyun 		brcmf_chip_ca7_set_passive(chip);
1342*4882a593Smuzhiyun 		return;
1343*4882a593Smuzhiyun 	}
1344*4882a593Smuzhiyun 	arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CM3);
1345*4882a593Smuzhiyun 	if (arm) {
1346*4882a593Smuzhiyun 		brcmf_chip_cm3_set_passive(chip);
1347*4882a593Smuzhiyun 		return;
1348*4882a593Smuzhiyun 	}
1349*4882a593Smuzhiyun }
1350*4882a593Smuzhiyun 
brcmf_chip_set_active(struct brcmf_chip * pub,u32 rstvec)1351*4882a593Smuzhiyun bool brcmf_chip_set_active(struct brcmf_chip *pub, u32 rstvec)
1352*4882a593Smuzhiyun {
1353*4882a593Smuzhiyun 	struct brcmf_chip_priv *chip;
1354*4882a593Smuzhiyun 	struct brcmf_core *arm;
1355*4882a593Smuzhiyun 
1356*4882a593Smuzhiyun 	brcmf_dbg(TRACE, "Enter\n");
1357*4882a593Smuzhiyun 
1358*4882a593Smuzhiyun 	chip = container_of(pub, struct brcmf_chip_priv, pub);
1359*4882a593Smuzhiyun 	arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CR4);
1360*4882a593Smuzhiyun 	if (arm)
1361*4882a593Smuzhiyun 		return brcmf_chip_cr4_set_active(chip, rstvec);
1362*4882a593Smuzhiyun 	arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CA7);
1363*4882a593Smuzhiyun 	if (arm)
1364*4882a593Smuzhiyun 		return brcmf_chip_ca7_set_active(chip, rstvec);
1365*4882a593Smuzhiyun 	arm = brcmf_chip_get_core(pub, BCMA_CORE_ARM_CM3);
1366*4882a593Smuzhiyun 	if (arm)
1367*4882a593Smuzhiyun 		return brcmf_chip_cm3_set_active(chip);
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun 	return false;
1370*4882a593Smuzhiyun }
1371*4882a593Smuzhiyun 
brcmf_chip_sr_capable(struct brcmf_chip * pub)1372*4882a593Smuzhiyun bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
1373*4882a593Smuzhiyun {
1374*4882a593Smuzhiyun 	u32 base, addr, reg, pmu_cc3_mask = ~0;
1375*4882a593Smuzhiyun 	struct brcmf_chip_priv *chip;
1376*4882a593Smuzhiyun 	struct brcmf_core *pmu = brcmf_chip_get_pmu(pub);
1377*4882a593Smuzhiyun 
1378*4882a593Smuzhiyun 	brcmf_dbg(TRACE, "Enter\n");
1379*4882a593Smuzhiyun 
1380*4882a593Smuzhiyun 	/* old chips with PMU version less than 17 don't support save restore */
1381*4882a593Smuzhiyun 	if (pub->pmurev < 17)
1382*4882a593Smuzhiyun 		return false;
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun 	base = brcmf_chip_get_chipcommon(pub)->base;
1385*4882a593Smuzhiyun 	chip = container_of(pub, struct brcmf_chip_priv, pub);
1386*4882a593Smuzhiyun 
1387*4882a593Smuzhiyun 	switch (pub->chip) {
1388*4882a593Smuzhiyun 	case BRCM_CC_4354_CHIP_ID:
1389*4882a593Smuzhiyun 	case BRCM_CC_4356_CHIP_ID:
1390*4882a593Smuzhiyun 	case BRCM_CC_4345_CHIP_ID:
1391*4882a593Smuzhiyun 		/* explicitly check SR engine enable bit */
1392*4882a593Smuzhiyun 		pmu_cc3_mask = BIT(2);
1393*4882a593Smuzhiyun 		fallthrough;
1394*4882a593Smuzhiyun 	case BRCM_CC_43241_CHIP_ID:
1395*4882a593Smuzhiyun 	case BRCM_CC_4335_CHIP_ID:
1396*4882a593Smuzhiyun 	case BRCM_CC_4339_CHIP_ID:
1397*4882a593Smuzhiyun 		/* read PMU chipcontrol register 3 */
1398*4882a593Smuzhiyun 		addr = CORE_CC_REG(pmu->base, chipcontrol_addr);
1399*4882a593Smuzhiyun 		chip->ops->write32(chip->ctx, addr, 3);
1400*4882a593Smuzhiyun 		addr = CORE_CC_REG(pmu->base, chipcontrol_data);
1401*4882a593Smuzhiyun 		reg = chip->ops->read32(chip->ctx, addr);
1402*4882a593Smuzhiyun 		return (reg & pmu_cc3_mask) != 0;
1403*4882a593Smuzhiyun 	case BRCM_CC_43430_CHIP_ID:
1404*4882a593Smuzhiyun 		addr = CORE_CC_REG(base, sr_control1);
1405*4882a593Smuzhiyun 		reg = chip->ops->read32(chip->ctx, addr);
1406*4882a593Smuzhiyun 		return reg != 0;
1407*4882a593Smuzhiyun 	case CY_CC_4373_CHIP_ID:
1408*4882a593Smuzhiyun 		/* explicitly check SR engine enable bit */
1409*4882a593Smuzhiyun 		addr = CORE_CC_REG(base, sr_control0);
1410*4882a593Smuzhiyun 		reg = chip->ops->read32(chip->ctx, addr);
1411*4882a593Smuzhiyun 		return (reg & CC_SR_CTL0_ENABLE_MASK) != 0;
1412*4882a593Smuzhiyun 	case BRCM_CC_4359_CHIP_ID:
1413*4882a593Smuzhiyun 	case CY_CC_43012_CHIP_ID:
1414*4882a593Smuzhiyun 		addr = CORE_CC_REG(pmu->base, retention_ctl);
1415*4882a593Smuzhiyun 		reg = chip->ops->read32(chip->ctx, addr);
1416*4882a593Smuzhiyun 		return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK |
1417*4882a593Smuzhiyun 			       PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
1418*4882a593Smuzhiyun 	default:
1419*4882a593Smuzhiyun 		addr = CORE_CC_REG(pmu->base, pmucapabilities_ext);
1420*4882a593Smuzhiyun 		reg = chip->ops->read32(chip->ctx, addr);
1421*4882a593Smuzhiyun 		if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0)
1422*4882a593Smuzhiyun 			return false;
1423*4882a593Smuzhiyun 
1424*4882a593Smuzhiyun 		addr = CORE_CC_REG(pmu->base, retention_ctl);
1425*4882a593Smuzhiyun 		reg = chip->ops->read32(chip->ctx, addr);
1426*4882a593Smuzhiyun 		return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK |
1427*4882a593Smuzhiyun 			       PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
1428*4882a593Smuzhiyun 	}
1429*4882a593Smuzhiyun }
1430