Commit | Line | Data |
---|---|---|
5b435de0 AS |
1 | /* |
2 | * Copyright (c) 2010 Broadcom Corporation | |
3 | * | |
4 | * Permission to use, copy, modify, and/or distribute this software for any | |
5 | * purpose with or without fee is hereby granted, provided that the above | |
6 | * copyright notice and this permission notice appear in all copies. | |
7 | * | |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
11 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |
13 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
14 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 | * | |
16 | * File contents: support functions for PCI/PCIe | |
17 | */ | |
18 | ||
8505a7e6 JP |
19 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
20 | ||
5b435de0 AS |
21 | #include <linux/delay.h> |
22 | #include <linux/pci.h> | |
23 | ||
24 | #include <defs.h> | |
25 | #include <chipcommon.h> | |
26 | #include <brcmu_utils.h> | |
27 | #include <brcm_hw_ids.h> | |
28 | #include <soc.h> | |
29 | #include "types.h" | |
30 | #include "pub.h" | |
31 | #include "pmu.h" | |
32 | #include "srom.h" | |
33 | #include "nicpci.h" | |
34 | #include "aiutils.h" | |
35 | ||
36 | /* slow_clk_ctl */ | |
37 | /* slow clock source mask */ | |
38 | #define SCC_SS_MASK 0x00000007 | |
39 | /* source of slow clock is LPO */ | |
40 | #define SCC_SS_LPO 0x00000000 | |
41 | /* source of slow clock is crystal */ | |
42 | #define SCC_SS_XTAL 0x00000001 | |
43 | /* source of slow clock is PCI */ | |
44 | #define SCC_SS_PCI 0x00000002 | |
45 | /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ | |
46 | #define SCC_LF 0x00000200 | |
47 | /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */ | |
48 | #define SCC_LP 0x00000400 | |
49 | /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */ | |
50 | #define SCC_FS 0x00000800 | |
51 | /* IgnorePllOffReq, 1/0: | |
52 | * power logic ignores/honors PLL clock disable requests from core | |
53 | */ | |
54 | #define SCC_IP 0x00001000 | |
55 | /* XtalControlEn, 1/0: | |
56 | * power logic does/doesn't disable crystal when appropriate | |
57 | */ | |
58 | #define SCC_XC 0x00002000 | |
59 | /* XtalPU (RO), 1/0: crystal running/disabled */ | |
60 | #define SCC_XP 0x00004000 | |
61 | /* ClockDivider (SlowClk = 1/(4+divisor)) */ | |
62 | #define SCC_CD_MASK 0xffff0000 | |
63 | #define SCC_CD_SHIFT 16 | |
64 | ||
65 | /* system_clk_ctl */ | |
66 | /* ILPen: Enable Idle Low Power */ | |
67 | #define SYCC_IE 0x00000001 | |
68 | /* ALPen: Enable Active Low Power */ | |
69 | #define SYCC_AE 0x00000002 | |
70 | /* ForcePLLOn */ | |
71 | #define SYCC_FP 0x00000004 | |
72 | /* Force ALP (or HT if ALPen is not set */ | |
73 | #define SYCC_AR 0x00000008 | |
74 | /* Force HT */ | |
75 | #define SYCC_HR 0x00000010 | |
76 | /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */ | |
77 | #define SYCC_CD_MASK 0xffff0000 | |
78 | #define SYCC_CD_SHIFT 16 | |
79 | ||
80 | #define CST4329_SPROM_OTP_SEL_MASK 0x00000003 | |
81 | /* OTP is powered up, use def. CIS, no SPROM */ | |
82 | #define CST4329_DEFCIS_SEL 0 | |
83 | /* OTP is powered up, SPROM is present */ | |
84 | #define CST4329_SPROM_SEL 1 | |
85 | /* OTP is powered up, no SPROM */ | |
86 | #define CST4329_OTP_SEL 2 | |
87 | /* OTP is powered down, SPROM is present */ | |
88 | #define CST4329_OTP_PWRDN 3 | |
89 | ||
90 | #define CST4329_SPI_SDIO_MODE_MASK 0x00000004 | |
91 | #define CST4329_SPI_SDIO_MODE_SHIFT 2 | |
92 | ||
93 | /* 43224 chip-specific ChipControl register bits */ | |
94 | #define CCTRL43224_GPIO_TOGGLE 0x8000 | |
95 | /* 12 mA drive strength */ | |
96 | #define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 | |
97 | /* 12 mA drive strength for later 43224s */ | |
98 | #define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 | |
99 | ||
100 | /* 43236 Chip specific ChipStatus register bits */ | |
101 | #define CST43236_SFLASH_MASK 0x00000040 | |
102 | #define CST43236_OTP_MASK 0x00000080 | |
103 | #define CST43236_HSIC_MASK 0x00000100 /* USB/HSIC */ | |
104 | #define CST43236_BP_CLK 0x00000200 /* 120/96Mbps */ | |
105 | #define CST43236_BOOT_MASK 0x00001800 | |
106 | #define CST43236_BOOT_SHIFT 11 | |
107 | #define CST43236_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ | |
108 | #define CST43236_BOOT_FROM_ROM 1 /* boot from ROM */ | |
109 | #define CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */ | |
110 | #define CST43236_BOOT_FROM_INVALID 3 | |
111 | ||
112 | /* 4331 chip-specific ChipControl register bits */ | |
113 | /* 0 disable */ | |
114 | #define CCTRL4331_BT_COEXIST (1<<0) | |
115 | /* 0 SECI is disabled (JTAG functional) */ | |
116 | #define CCTRL4331_SECI (1<<1) | |
117 | /* 0 disable */ | |
118 | #define CCTRL4331_EXT_LNA (1<<2) | |
119 | /* sprom/gpio13-15 mux */ | |
120 | #define CCTRL4331_SPROM_GPIO13_15 (1<<3) | |
121 | /* 0 ext pa disable, 1 ext pa enabled */ | |
122 | #define CCTRL4331_EXTPA_EN (1<<4) | |
123 | /* set drive out GPIO_CLK on sprom_cs pin */ | |
124 | #define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) | |
125 | /* use sprom_cs pin as PCIE mdio interface */ | |
126 | #define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) | |
127 | /* aband extpa will be at gpio2/5 and sprom_dout */ | |
128 | #define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) | |
129 | /* override core control on pipe_AuxClkEnable */ | |
130 | #define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) | |
131 | /* override core control on pipe_AuxPowerDown */ | |
132 | #define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) | |
133 | /* pcie_auxclkenable */ | |
134 | #define CCTRL4331_PCIE_AUXCLKEN (1<<10) | |
135 | /* pcie_pipe_pllpowerdown */ | |
136 | #define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) | |
137 | /* enable bt_shd0 at gpio4 */ | |
138 | #define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) | |
139 | /* enable bt_shd1 at gpio5 */ | |
140 | #define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) | |
141 | ||
142 | /* 4331 Chip specific ChipStatus register bits */ | |
143 | /* crystal frequency 20/40Mhz */ | |
144 | #define CST4331_XTAL_FREQ 0x00000001 | |
145 | #define CST4331_SPROM_PRESENT 0x00000002 | |
146 | #define CST4331_OTP_PRESENT 0x00000004 | |
147 | #define CST4331_LDO_RF 0x00000008 | |
148 | #define CST4331_LDO_PAR 0x00000010 | |
149 | ||
150 | /* 4319 chip-specific ChipStatus register bits */ | |
151 | #define CST4319_SPI_CPULESSUSB 0x00000001 | |
152 | #define CST4319_SPI_CLK_POL 0x00000002 | |
153 | #define CST4319_SPI_CLK_PH 0x00000008 | |
154 | /* gpio [7:6], SDIO CIS selection */ | |
155 | #define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 | |
156 | #define CST4319_SPROM_OTP_SEL_SHIFT 6 | |
157 | /* use default CIS, OTP is powered up */ | |
158 | #define CST4319_DEFCIS_SEL 0x00000000 | |
159 | /* use SPROM, OTP is powered up */ | |
160 | #define CST4319_SPROM_SEL 0x00000040 | |
161 | /* use OTP, OTP is powered up */ | |
162 | #define CST4319_OTP_SEL 0x00000080 | |
163 | /* use SPROM, OTP is powered down */ | |
164 | #define CST4319_OTP_PWRDN 0x000000c0 | |
165 | /* gpio [8], sdio/usb mode */ | |
166 | #define CST4319_SDIO_USB_MODE 0x00000100 | |
167 | #define CST4319_REMAP_SEL_MASK 0x00000600 | |
168 | #define CST4319_ILPDIV_EN 0x00000800 | |
169 | #define CST4319_XTAL_PD_POL 0x00001000 | |
170 | #define CST4319_LPO_SEL 0x00002000 | |
171 | #define CST4319_RES_INIT_MODE 0x0000c000 | |
172 | /* PALDO is configured with external PNP */ | |
173 | #define CST4319_PALDO_EXTPNP 0x00010000 | |
174 | #define CST4319_CBUCK_MODE_MASK 0x00060000 | |
175 | #define CST4319_CBUCK_MODE_BURST 0x00020000 | |
176 | #define CST4319_CBUCK_MODE_LPBURST 0x00060000 | |
177 | #define CST4319_RCAL_VALID 0x01000000 | |
178 | #define CST4319_RCAL_VALUE_MASK 0x3e000000 | |
179 | #define CST4319_RCAL_VALUE_SHIFT 25 | |
180 | ||
181 | /* 4336 chip-specific ChipStatus register bits */ | |
182 | #define CST4336_SPI_MODE_MASK 0x00000001 | |
183 | #define CST4336_SPROM_PRESENT 0x00000002 | |
184 | #define CST4336_OTP_PRESENT 0x00000004 | |
185 | #define CST4336_ARMREMAP_0 0x00000008 | |
186 | #define CST4336_ILPDIV_EN_MASK 0x00000010 | |
187 | #define CST4336_ILPDIV_EN_SHIFT 4 | |
188 | #define CST4336_XTAL_PD_POL_MASK 0x00000020 | |
189 | #define CST4336_XTAL_PD_POL_SHIFT 5 | |
190 | #define CST4336_LPO_SEL_MASK 0x00000040 | |
191 | #define CST4336_LPO_SEL_SHIFT 6 | |
192 | #define CST4336_RES_INIT_MODE_MASK 0x00000180 | |
193 | #define CST4336_RES_INIT_MODE_SHIFT 7 | |
194 | #define CST4336_CBUCK_MODE_MASK 0x00000600 | |
195 | #define CST4336_CBUCK_MODE_SHIFT 9 | |
196 | ||
197 | /* 4313 chip-specific ChipStatus register bits */ | |
198 | #define CST4313_SPROM_PRESENT 1 | |
199 | #define CST4313_OTP_PRESENT 2 | |
200 | #define CST4313_SPROM_OTP_SEL_MASK 0x00000002 | |
201 | #define CST4313_SPROM_OTP_SEL_SHIFT 0 | |
202 | ||
203 | /* 4313 Chip specific ChipControl register bits */ | |
204 | /* 12 mA drive strengh for later 4313 */ | |
205 | #define CCTRL_4313_12MA_LED_DRIVE 0x00000007 | |
206 | ||
207 | /* Manufacturer Ids */ | |
208 | #define MFGID_ARM 0x43b | |
209 | #define MFGID_BRCM 0x4bf | |
210 | #define MFGID_MIPS 0x4a7 | |
211 | ||
212 | /* Enumeration ROM registers */ | |
213 | #define ER_EROMENTRY 0x000 | |
214 | #define ER_REMAPCONTROL 0xe00 | |
215 | #define ER_REMAPSELECT 0xe04 | |
216 | #define ER_MASTERSELECT 0xe10 | |
217 | #define ER_ITCR 0xf00 | |
218 | #define ER_ITIP 0xf04 | |
219 | ||
220 | /* Erom entries */ | |
221 | #define ER_TAG 0xe | |
222 | #define ER_TAG1 0x6 | |
223 | #define ER_VALID 1 | |
224 | #define ER_CI 0 | |
225 | #define ER_MP 2 | |
226 | #define ER_ADD 4 | |
227 | #define ER_END 0xe | |
228 | #define ER_BAD 0xffffffff | |
229 | ||
230 | /* EROM CompIdentA */ | |
231 | #define CIA_MFG_MASK 0xfff00000 | |
232 | #define CIA_MFG_SHIFT 20 | |
233 | #define CIA_CID_MASK 0x000fff00 | |
234 | #define CIA_CID_SHIFT 8 | |
235 | #define CIA_CCL_MASK 0x000000f0 | |
236 | #define CIA_CCL_SHIFT 4 | |
237 | ||
238 | /* EROM CompIdentB */ | |
239 | #define CIB_REV_MASK 0xff000000 | |
240 | #define CIB_REV_SHIFT 24 | |
241 | #define CIB_NSW_MASK 0x00f80000 | |
242 | #define CIB_NSW_SHIFT 19 | |
243 | #define CIB_NMW_MASK 0x0007c000 | |
244 | #define CIB_NMW_SHIFT 14 | |
245 | #define CIB_NSP_MASK 0x00003e00 | |
246 | #define CIB_NSP_SHIFT 9 | |
247 | #define CIB_NMP_MASK 0x000001f0 | |
248 | #define CIB_NMP_SHIFT 4 | |
249 | ||
250 | /* EROM AddrDesc */ | |
251 | #define AD_ADDR_MASK 0xfffff000 | |
252 | #define AD_SP_MASK 0x00000f00 | |
253 | #define AD_SP_SHIFT 8 | |
254 | #define AD_ST_MASK 0x000000c0 | |
255 | #define AD_ST_SHIFT 6 | |
256 | #define AD_ST_SLAVE 0x00000000 | |
257 | #define AD_ST_BRIDGE 0x00000040 | |
258 | #define AD_ST_SWRAP 0x00000080 | |
259 | #define AD_ST_MWRAP 0x000000c0 | |
260 | #define AD_SZ_MASK 0x00000030 | |
261 | #define AD_SZ_SHIFT 4 | |
262 | #define AD_SZ_4K 0x00000000 | |
263 | #define AD_SZ_8K 0x00000010 | |
264 | #define AD_SZ_16K 0x00000020 | |
265 | #define AD_SZ_SZD 0x00000030 | |
266 | #define AD_AG32 0x00000008 | |
267 | #define AD_ADDR_ALIGN 0x00000fff | |
268 | #define AD_SZ_BASE 0x00001000 /* 4KB */ | |
269 | ||
270 | /* EROM SizeDesc */ | |
271 | #define SD_SZ_MASK 0xfffff000 | |
272 | #define SD_SG32 0x00000008 | |
273 | #define SD_SZ_ALIGN 0x00000fff | |
274 | ||
275 | /* PCI config space bit 4 for 4306c0 slow clock source */ | |
276 | #define PCI_CFG_GPIO_SCS 0x10 | |
277 | /* PCI config space GPIO 14 for Xtal power-up */ | |
278 | #define PCI_CFG_GPIO_XTAL 0x40 | |
279 | /* PCI config space GPIO 15 for PLL power-down */ | |
280 | #define PCI_CFG_GPIO_PLL 0x80 | |
281 | ||
282 | /* power control defines */ | |
283 | #define PLL_DELAY 150 /* us pll on delay */ | |
284 | #define FREF_DELAY 200 /* us fref change delay */ | |
285 | #define XTAL_ON_DELAY 1000 /* us crystal power-on delay */ | |
286 | ||
287 | /* resetctrl */ | |
288 | #define AIRC_RESET 1 | |
289 | ||
290 | #define NOREV -1 /* Invalid rev */ | |
291 | ||
292 | /* GPIO Based LED powersave defines */ | |
293 | #define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ | |
294 | #define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ | |
295 | ||
296 | /* When Srom support present, fields in sromcontrol */ | |
297 | #define SRC_START 0x80000000 | |
298 | #define SRC_BUSY 0x80000000 | |
299 | #define SRC_OPCODE 0x60000000 | |
300 | #define SRC_OP_READ 0x00000000 | |
301 | #define SRC_OP_WRITE 0x20000000 | |
302 | #define SRC_OP_WRDIS 0x40000000 | |
303 | #define SRC_OP_WREN 0x60000000 | |
304 | #define SRC_OTPSEL 0x00000010 | |
305 | #define SRC_LOCK 0x00000008 | |
306 | #define SRC_SIZE_MASK 0x00000006 | |
307 | #define SRC_SIZE_1K 0x00000000 | |
308 | #define SRC_SIZE_4K 0x00000002 | |
309 | #define SRC_SIZE_16K 0x00000004 | |
310 | #define SRC_SIZE_SHIFT 1 | |
311 | #define SRC_PRESENT 0x00000001 | |
312 | ||
313 | /* External PA enable mask */ | |
314 | #define GPIO_CTRL_EPA_EN_MASK 0x40 | |
315 | ||
316 | #define DEFAULT_GPIOTIMERVAL \ | |
317 | ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME) | |
318 | ||
319 | #define BADIDX (SI_MAXCORES + 1) | |
320 | ||
321 | /* Newer chips can access PCI/PCIE and CC core without requiring to change | |
322 | * PCI BAR0 WIN | |
323 | */ | |
324 | #define SI_FAST(si) (((si)->pub.buscoretype == PCIE_CORE_ID) || \ | |
325 | (((si)->pub.buscoretype == PCI_CORE_ID) && \ | |
326 | (si)->pub.buscorerev >= 13)) | |
327 | ||
328 | #define CCREGS_FAST(si) (((char __iomem *)((si)->curmap) + \ | |
329 | PCI_16KB0_CCREGS_OFFSET)) | |
330 | ||
331 | #define IS_SIM(chippkg) \ | |
332 | ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) | |
333 | ||
334 | /* | |
335 | * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts | |
336 | * before after core switching to avoid invalid register accesss inside ISR. | |
337 | */ | |
338 | #define INTR_OFF(si, intr_val) \ | |
339 | if ((si)->intrsoff_fn && \ | |
340 | (si)->coreid[(si)->curidx] == (si)->dev_coreid) \ | |
341 | intr_val = (*(si)->intrsoff_fn)((si)->intr_arg) | |
342 | ||
343 | #define INTR_RESTORE(si, intr_val) \ | |
344 | if ((si)->intrsrestore_fn && \ | |
345 | (si)->coreid[(si)->curidx] == (si)->dev_coreid) \ | |
346 | (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val) | |
347 | ||
348 | #define PCI(si) ((si)->pub.buscoretype == PCI_CORE_ID) | |
349 | #define PCIE(si) ((si)->pub.buscoretype == PCIE_CORE_ID) | |
350 | ||
351 | #define PCI_FORCEHT(si) (PCIE(si) && (si->pub.chip == BCM4716_CHIP_ID)) | |
352 | ||
353 | #ifdef BCMDBG | |
8505a7e6 | 354 | #define SI_MSG(fmt, ...) pr_debug(fmt, ##__VA_ARGS__) |
5b435de0 | 355 | #else |
8505a7e6 | 356 | #define SI_MSG(fmt, ...) no_printk(fmt, ##__VA_ARGS__) |
5b435de0 AS |
357 | #endif /* BCMDBG */ |
358 | ||
359 | #define GOODCOREADDR(x, b) \ | |
360 | (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ | |
361 | IS_ALIGNED((x), SI_CORE_SIZE)) | |
362 | ||
363 | #define PCIEREGS(si) ((__iomem char *)((si)->curmap) + \ | |
364 | PCI_16KB0_PCIREGS_OFFSET) | |
365 | ||
366 | struct aidmp { | |
367 | u32 oobselina30; /* 0x000 */ | |
368 | u32 oobselina74; /* 0x004 */ | |
369 | u32 PAD[6]; | |
370 | u32 oobselinb30; /* 0x020 */ | |
371 | u32 oobselinb74; /* 0x024 */ | |
372 | u32 PAD[6]; | |
373 | u32 oobselinc30; /* 0x040 */ | |
374 | u32 oobselinc74; /* 0x044 */ | |
375 | u32 PAD[6]; | |
376 | u32 oobselind30; /* 0x060 */ | |
377 | u32 oobselind74; /* 0x064 */ | |
378 | u32 PAD[38]; | |
379 | u32 oobselouta30; /* 0x100 */ | |
380 | u32 oobselouta74; /* 0x104 */ | |
381 | u32 PAD[6]; | |
382 | u32 oobseloutb30; /* 0x120 */ | |
383 | u32 oobseloutb74; /* 0x124 */ | |
384 | u32 PAD[6]; | |
385 | u32 oobseloutc30; /* 0x140 */ | |
386 | u32 oobseloutc74; /* 0x144 */ | |
387 | u32 PAD[6]; | |
388 | u32 oobseloutd30; /* 0x160 */ | |
389 | u32 oobseloutd74; /* 0x164 */ | |
390 | u32 PAD[38]; | |
391 | u32 oobsynca; /* 0x200 */ | |
392 | u32 oobseloutaen; /* 0x204 */ | |
393 | u32 PAD[6]; | |
394 | u32 oobsyncb; /* 0x220 */ | |
395 | u32 oobseloutben; /* 0x224 */ | |
396 | u32 PAD[6]; | |
397 | u32 oobsyncc; /* 0x240 */ | |
398 | u32 oobseloutcen; /* 0x244 */ | |
399 | u32 PAD[6]; | |
400 | u32 oobsyncd; /* 0x260 */ | |
401 | u32 oobseloutden; /* 0x264 */ | |
402 | u32 PAD[38]; | |
403 | u32 oobaextwidth; /* 0x300 */ | |
404 | u32 oobainwidth; /* 0x304 */ | |
405 | u32 oobaoutwidth; /* 0x308 */ | |
406 | u32 PAD[5]; | |
407 | u32 oobbextwidth; /* 0x320 */ | |
408 | u32 oobbinwidth; /* 0x324 */ | |
409 | u32 oobboutwidth; /* 0x328 */ | |
410 | u32 PAD[5]; | |
411 | u32 oobcextwidth; /* 0x340 */ | |
412 | u32 oobcinwidth; /* 0x344 */ | |
413 | u32 oobcoutwidth; /* 0x348 */ | |
414 | u32 PAD[5]; | |
415 | u32 oobdextwidth; /* 0x360 */ | |
416 | u32 oobdinwidth; /* 0x364 */ | |
417 | u32 oobdoutwidth; /* 0x368 */ | |
418 | u32 PAD[37]; | |
419 | u32 ioctrlset; /* 0x400 */ | |
420 | u32 ioctrlclear; /* 0x404 */ | |
421 | u32 ioctrl; /* 0x408 */ | |
422 | u32 PAD[61]; | |
423 | u32 iostatus; /* 0x500 */ | |
424 | u32 PAD[127]; | |
425 | u32 ioctrlwidth; /* 0x700 */ | |
426 | u32 iostatuswidth; /* 0x704 */ | |
427 | u32 PAD[62]; | |
428 | u32 resetctrl; /* 0x800 */ | |
429 | u32 resetstatus; /* 0x804 */ | |
430 | u32 resetreadid; /* 0x808 */ | |
431 | u32 resetwriteid; /* 0x80c */ | |
432 | u32 PAD[60]; | |
433 | u32 errlogctrl; /* 0x900 */ | |
434 | u32 errlogdone; /* 0x904 */ | |
435 | u32 errlogstatus; /* 0x908 */ | |
436 | u32 errlogaddrlo; /* 0x90c */ | |
437 | u32 errlogaddrhi; /* 0x910 */ | |
438 | u32 errlogid; /* 0x914 */ | |
439 | u32 errloguser; /* 0x918 */ | |
440 | u32 errlogflags; /* 0x91c */ | |
441 | u32 PAD[56]; | |
442 | u32 intstatus; /* 0xa00 */ | |
443 | u32 PAD[127]; | |
444 | u32 config; /* 0xe00 */ | |
445 | u32 PAD[63]; | |
446 | u32 itcr; /* 0xf00 */ | |
447 | u32 PAD[3]; | |
448 | u32 itipooba; /* 0xf10 */ | |
449 | u32 itipoobb; /* 0xf14 */ | |
450 | u32 itipoobc; /* 0xf18 */ | |
451 | u32 itipoobd; /* 0xf1c */ | |
452 | u32 PAD[4]; | |
453 | u32 itipoobaout; /* 0xf30 */ | |
454 | u32 itipoobbout; /* 0xf34 */ | |
455 | u32 itipoobcout; /* 0xf38 */ | |
456 | u32 itipoobdout; /* 0xf3c */ | |
457 | u32 PAD[4]; | |
458 | u32 itopooba; /* 0xf50 */ | |
459 | u32 itopoobb; /* 0xf54 */ | |
460 | u32 itopoobc; /* 0xf58 */ | |
461 | u32 itopoobd; /* 0xf5c */ | |
462 | u32 PAD[4]; | |
463 | u32 itopoobain; /* 0xf70 */ | |
464 | u32 itopoobbin; /* 0xf74 */ | |
465 | u32 itopoobcin; /* 0xf78 */ | |
466 | u32 itopoobdin; /* 0xf7c */ | |
467 | u32 PAD[4]; | |
468 | u32 itopreset; /* 0xf90 */ | |
469 | u32 PAD[15]; | |
470 | u32 peripherialid4; /* 0xfd0 */ | |
471 | u32 peripherialid5; /* 0xfd4 */ | |
472 | u32 peripherialid6; /* 0xfd8 */ | |
473 | u32 peripherialid7; /* 0xfdc */ | |
474 | u32 peripherialid0; /* 0xfe0 */ | |
475 | u32 peripherialid1; /* 0xfe4 */ | |
476 | u32 peripherialid2; /* 0xfe8 */ | |
477 | u32 peripherialid3; /* 0xfec */ | |
478 | u32 componentid0; /* 0xff0 */ | |
479 | u32 componentid1; /* 0xff4 */ | |
480 | u32 componentid2; /* 0xff8 */ | |
481 | u32 componentid3; /* 0xffc */ | |
482 | }; | |
483 | ||
484 | /* EROM parsing */ | |
485 | ||
486 | static u32 | |
487 | get_erom_ent(struct si_pub *sih, u32 __iomem **eromptr, u32 mask, u32 match) | |
488 | { | |
489 | u32 ent; | |
490 | uint inv = 0, nom = 0; | |
491 | ||
492 | while (true) { | |
493 | ent = R_REG(*eromptr); | |
494 | (*eromptr)++; | |
495 | ||
496 | if (mask == 0) | |
497 | break; | |
498 | ||
499 | if ((ent & ER_VALID) == 0) { | |
500 | inv++; | |
501 | continue; | |
502 | } | |
503 | ||
504 | if (ent == (ER_END | ER_VALID)) | |
505 | break; | |
506 | ||
507 | if ((ent & mask) == match) | |
508 | break; | |
509 | ||
510 | nom++; | |
511 | } | |
512 | ||
513 | return ent; | |
514 | } | |
515 | ||
516 | static u32 | |
517 | get_asd(struct si_pub *sih, u32 __iomem **eromptr, uint sp, uint ad, uint st, | |
518 | u32 *addrl, u32 *addrh, u32 *sizel, u32 *sizeh) | |
519 | { | |
520 | u32 asd, sz, szd; | |
521 | ||
522 | asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); | |
523 | if (((asd & ER_TAG1) != ER_ADD) || | |
524 | (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || | |
525 | ((asd & AD_ST_MASK) != st)) { | |
526 | /* This is not what we want, "push" it back */ | |
527 | (*eromptr)--; | |
528 | return 0; | |
529 | } | |
530 | *addrl = asd & AD_ADDR_MASK; | |
531 | if (asd & AD_AG32) | |
532 | *addrh = get_erom_ent(sih, eromptr, 0, 0); | |
533 | else | |
534 | *addrh = 0; | |
535 | *sizeh = 0; | |
536 | sz = asd & AD_SZ_MASK; | |
537 | if (sz == AD_SZ_SZD) { | |
538 | szd = get_erom_ent(sih, eromptr, 0, 0); | |
539 | *sizel = szd & SD_SZ_MASK; | |
540 | if (szd & SD_SG32) | |
541 | *sizeh = get_erom_ent(sih, eromptr, 0, 0); | |
542 | } else | |
543 | *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT); | |
544 | ||
545 | return asd; | |
546 | } | |
547 | ||
548 | static void ai_hwfixup(struct si_info *sii) | |
549 | { | |
550 | } | |
551 | ||
552 | /* parse the enumeration rom to identify all cores */ | |
553 | static void ai_scan(struct si_pub *sih, struct chipcregs __iomem *cc) | |
554 | { | |
555 | struct si_info *sii = (struct si_info *)sih; | |
556 | ||
557 | u32 erombase; | |
558 | u32 __iomem *eromptr, *eromlim; | |
559 | void __iomem *regs = cc; | |
560 | ||
561 | erombase = R_REG(&cc->eromptr); | |
562 | ||
563 | /* Set wrappers address */ | |
564 | sii->curwrap = (void *)((unsigned long)cc + SI_CORE_SIZE); | |
565 | ||
566 | /* Now point the window at the erom */ | |
567 | pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, erombase); | |
568 | eromptr = regs; | |
569 | eromlim = eromptr + (ER_REMAPCONTROL / sizeof(u32)); | |
570 | ||
571 | while (eromptr < eromlim) { | |
572 | u32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; | |
573 | u32 mpd, asd, addrl, addrh, sizel, sizeh; | |
574 | u32 __iomem *base; | |
575 | uint i, j, idx; | |
576 | bool br; | |
577 | ||
578 | br = false; | |
579 | ||
580 | /* Grok a component */ | |
581 | cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); | |
582 | if (cia == (ER_END | ER_VALID)) { | |
583 | /* Found END of erom */ | |
584 | ai_hwfixup(sii); | |
585 | return; | |
586 | } | |
587 | base = eromptr - 1; | |
588 | cib = get_erom_ent(sih, &eromptr, 0, 0); | |
589 | ||
590 | if ((cib & ER_TAG) != ER_CI) { | |
591 | /* CIA not followed by CIB */ | |
592 | goto error; | |
593 | } | |
594 | ||
595 | cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT; | |
596 | mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; | |
597 | crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; | |
598 | nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT; | |
599 | nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT; | |
600 | nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; | |
601 | nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; | |
602 | ||
603 | if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) | |
604 | continue; | |
605 | if ((nmw + nsw == 0)) { | |
606 | /* A component which is not a core */ | |
607 | if (cid == OOB_ROUTER_CORE_ID) { | |
608 | asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, | |
609 | &addrl, &addrh, &sizel, &sizeh); | |
610 | if (asd != 0) | |
611 | sii->oob_router = addrl; | |
612 | } | |
613 | continue; | |
614 | } | |
615 | ||
616 | idx = sii->numcores; | |
617 | /* sii->eromptr[idx] = base; */ | |
618 | sii->cia[idx] = cia; | |
619 | sii->cib[idx] = cib; | |
620 | sii->coreid[idx] = cid; | |
621 | ||
622 | for (i = 0; i < nmp; i++) { | |
623 | mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); | |
624 | if ((mpd & ER_TAG) != ER_MP) { | |
625 | /* Not enough MP entries for component */ | |
626 | goto error; | |
627 | } | |
628 | } | |
629 | ||
630 | /* First Slave Address Descriptor should be port 0: | |
631 | * the main register space for the core | |
632 | */ | |
633 | asd = | |
634 | get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, | |
635 | &sizel, &sizeh); | |
636 | if (asd == 0) { | |
637 | /* Try again to see if it is a bridge */ | |
638 | asd = | |
639 | get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, | |
640 | &addrh, &sizel, &sizeh); | |
641 | if (asd != 0) | |
642 | br = true; | |
643 | else if ((addrh != 0) || (sizeh != 0) | |
644 | || (sizel != SI_CORE_SIZE)) { | |
645 | /* First Slave ASD for core malformed */ | |
646 | goto error; | |
647 | } | |
648 | } | |
649 | sii->coresba[idx] = addrl; | |
650 | sii->coresba_size[idx] = sizel; | |
651 | /* Get any more ASDs in port 0 */ | |
652 | j = 1; | |
653 | do { | |
654 | asd = | |
655 | get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, | |
656 | &addrh, &sizel, &sizeh); | |
657 | if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { | |
658 | sii->coresba2[idx] = addrl; | |
659 | sii->coresba2_size[idx] = sizel; | |
660 | } | |
661 | j++; | |
662 | } while (asd != 0); | |
663 | ||
664 | /* Go through the ASDs for other slave ports */ | |
665 | for (i = 1; i < nsp; i++) { | |
666 | j = 0; | |
667 | do { | |
668 | asd = | |
669 | get_asd(sih, &eromptr, i, j++, AD_ST_SLAVE, | |
670 | &addrl, &addrh, &sizel, &sizeh); | |
671 | } while (asd != 0); | |
672 | if (j == 0) { | |
673 | /* SP has no address descriptors */ | |
674 | goto error; | |
675 | } | |
676 | } | |
677 | ||
678 | /* Now get master wrappers */ | |
679 | for (i = 0; i < nmw; i++) { | |
680 | asd = | |
681 | get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, | |
682 | &addrh, &sizel, &sizeh); | |
683 | if (asd == 0) { | |
684 | /* Missing descriptor for MW */ | |
685 | goto error; | |
686 | } | |
687 | if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { | |
688 | /* Master wrapper %d is not 4KB */ | |
689 | goto error; | |
690 | } | |
691 | if (i == 0) | |
692 | sii->wrapba[idx] = addrl; | |
693 | } | |
694 | ||
695 | /* And finally slave wrappers */ | |
696 | for (i = 0; i < nsw; i++) { | |
697 | uint fwp = (nsp == 1) ? 0 : 1; | |
698 | asd = | |
699 | get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, | |
700 | &addrl, &addrh, &sizel, &sizeh); | |
701 | if (asd == 0) { | |
702 | /* Missing descriptor for SW */ | |
703 | goto error; | |
704 | } | |
705 | if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { | |
706 | /* Slave wrapper is not 4KB */ | |
707 | goto error; | |
708 | } | |
709 | if ((nmw == 0) && (i == 0)) | |
710 | sii->wrapba[idx] = addrl; | |
711 | } | |
712 | ||
713 | /* Don't record bridges */ | |
714 | if (br) | |
715 | continue; | |
716 | ||
717 | /* Done with core */ | |
718 | sii->numcores++; | |
719 | } | |
720 | ||
721 | error: | |
722 | /* Reached end of erom without finding END */ | |
723 | sii->numcores = 0; | |
724 | return; | |
725 | } | |
726 | ||
727 | /* | |
728 | * This function changes the logical "focus" to the indicated core. | |
729 | * Return the current core's virtual address. Since each core starts with the | |
730 | * same set of registers (BIST, clock control, etc), the returned address | |
731 | * contains the first register of this 'common' register block (not to be | |
732 | * confused with 'common core'). | |
733 | */ | |
734 | void __iomem *ai_setcoreidx(struct si_pub *sih, uint coreidx) | |
735 | { | |
736 | struct si_info *sii = (struct si_info *)sih; | |
737 | u32 addr = sii->coresba[coreidx]; | |
738 | u32 wrap = sii->wrapba[coreidx]; | |
739 | ||
740 | if (coreidx >= sii->numcores) | |
741 | return NULL; | |
742 | ||
743 | /* point bar0 window */ | |
744 | pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, addr); | |
745 | /* point bar0 2nd 4KB window */ | |
746 | pci_write_config_dword(sii->pbus, PCI_BAR0_WIN2, wrap); | |
747 | sii->curidx = coreidx; | |
748 | ||
749 | return sii->curmap; | |
750 | } | |
751 | ||
752 | /* Return the number of address spaces in current core */ | |
753 | int ai_numaddrspaces(struct si_pub *sih) | |
754 | { | |
755 | return 2; | |
756 | } | |
757 | ||
758 | /* Return the address of the nth address space in the current core */ | |
759 | u32 ai_addrspace(struct si_pub *sih, uint asidx) | |
760 | { | |
761 | struct si_info *sii; | |
762 | uint cidx; | |
763 | ||
764 | sii = (struct si_info *)sih; | |
765 | cidx = sii->curidx; | |
766 | ||
767 | if (asidx == 0) | |
768 | return sii->coresba[cidx]; | |
769 | else if (asidx == 1) | |
770 | return sii->coresba2[cidx]; | |
771 | else { | |
772 | /* Need to parse the erom again to find addr space */ | |
773 | return 0; | |
774 | } | |
775 | } | |
776 | ||
777 | /* Return the size of the nth address space in the current core */ | |
778 | u32 ai_addrspacesize(struct si_pub *sih, uint asidx) | |
779 | { | |
780 | struct si_info *sii; | |
781 | uint cidx; | |
782 | ||
783 | sii = (struct si_info *)sih; | |
784 | cidx = sii->curidx; | |
785 | ||
786 | if (asidx == 0) | |
787 | return sii->coresba_size[cidx]; | |
788 | else if (asidx == 1) | |
789 | return sii->coresba2_size[cidx]; | |
790 | else { | |
791 | /* Need to parse the erom again to find addr */ | |
792 | return 0; | |
793 | } | |
794 | } | |
795 | ||
796 | uint ai_flag(struct si_pub *sih) | |
797 | { | |
798 | struct si_info *sii; | |
799 | struct aidmp *ai; | |
800 | ||
801 | sii = (struct si_info *)sih; | |
802 | ai = sii->curwrap; | |
803 | ||
804 | return R_REG(&ai->oobselouta30) & 0x1f; | |
805 | } | |
806 | ||
807 | void ai_setint(struct si_pub *sih, int siflag) | |
808 | { | |
809 | } | |
810 | ||
811 | uint ai_corevendor(struct si_pub *sih) | |
812 | { | |
813 | struct si_info *sii; | |
814 | u32 cia; | |
815 | ||
816 | sii = (struct si_info *)sih; | |
817 | cia = sii->cia[sii->curidx]; | |
818 | return (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; | |
819 | } | |
820 | ||
821 | uint ai_corerev(struct si_pub *sih) | |
822 | { | |
823 | struct si_info *sii; | |
824 | u32 cib; | |
825 | ||
826 | sii = (struct si_info *)sih; | |
827 | cib = sii->cib[sii->curidx]; | |
828 | return (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; | |
829 | } | |
830 | ||
831 | bool ai_iscoreup(struct si_pub *sih) | |
832 | { | |
833 | struct si_info *sii; | |
834 | struct aidmp *ai; | |
835 | ||
836 | sii = (struct si_info *)sih; | |
837 | ai = sii->curwrap; | |
838 | ||
839 | return (((R_REG(&ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == | |
840 | SICF_CLOCK_EN) | |
841 | && ((R_REG(&ai->resetctrl) & AIRC_RESET) == 0)); | |
842 | } | |
843 | ||
844 | void ai_core_cflags_wo(struct si_pub *sih, u32 mask, u32 val) | |
845 | { | |
846 | struct si_info *sii; | |
847 | struct aidmp *ai; | |
848 | u32 w; | |
849 | ||
850 | sii = (struct si_info *)sih; | |
851 | ||
852 | ai = sii->curwrap; | |
853 | ||
854 | if (mask || val) { | |
855 | w = ((R_REG(&ai->ioctrl) & ~mask) | val); | |
856 | W_REG(&ai->ioctrl, w); | |
857 | } | |
858 | } | |
859 | ||
860 | u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val) | |
861 | { | |
862 | struct si_info *sii; | |
863 | struct aidmp *ai; | |
864 | u32 w; | |
865 | ||
866 | sii = (struct si_info *)sih; | |
867 | ai = sii->curwrap; | |
868 | ||
869 | if (mask || val) { | |
870 | w = ((R_REG(&ai->ioctrl) & ~mask) | val); | |
871 | W_REG(&ai->ioctrl, w); | |
872 | } | |
873 | ||
874 | return R_REG(&ai->ioctrl); | |
875 | } | |
876 | ||
877 | /* return true if PCIE capability exists in the pci config space */ | |
878 | static bool ai_ispcie(struct si_info *sii) | |
879 | { | |
880 | u8 cap_ptr; | |
881 | ||
882 | cap_ptr = | |
883 | pcicore_find_pci_capability(sii->pbus, PCI_CAP_ID_EXP, NULL, | |
884 | NULL); | |
885 | if (!cap_ptr) | |
886 | return false; | |
887 | ||
888 | return true; | |
889 | } | |
890 | ||
891 | static bool ai_buscore_prep(struct si_info *sii) | |
892 | { | |
893 | /* kludge to enable the clock on the 4306 which lacks a slowclock */ | |
894 | if (!ai_ispcie(sii)) | |
895 | ai_clkctl_xtal(&sii->pub, XTAL | PLL, ON); | |
896 | return true; | |
897 | } | |
898 | ||
899 | u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val) | |
900 | { | |
901 | struct si_info *sii; | |
902 | struct aidmp *ai; | |
903 | u32 w; | |
904 | ||
905 | sii = (struct si_info *)sih; | |
906 | ai = sii->curwrap; | |
907 | ||
908 | if (mask || val) { | |
909 | w = ((R_REG(&ai->iostatus) & ~mask) | val); | |
910 | W_REG(&ai->iostatus, w); | |
911 | } | |
912 | ||
913 | return R_REG(&ai->iostatus); | |
914 | } | |
915 | ||
916 | static bool | |
917 | ai_buscore_setup(struct si_info *sii, u32 savewin, uint *origidx) | |
918 | { | |
919 | bool pci, pcie; | |
920 | uint i; | |
921 | uint pciidx, pcieidx, pcirev, pcierev; | |
922 | struct chipcregs __iomem *cc; | |
923 | ||
924 | cc = ai_setcoreidx(&sii->pub, SI_CC_IDX); | |
925 | ||
926 | /* get chipcommon rev */ | |
927 | sii->pub.ccrev = (int)ai_corerev(&sii->pub); | |
928 | ||
929 | /* get chipcommon chipstatus */ | |
930 | if (sii->pub.ccrev >= 11) | |
931 | sii->pub.chipst = R_REG(&cc->chipstatus); | |
932 | ||
933 | /* get chipcommon capabilites */ | |
934 | sii->pub.cccaps = R_REG(&cc->capabilities); | |
935 | /* get chipcommon extended capabilities */ | |
936 | ||
937 | if (sii->pub.ccrev >= 35) | |
938 | sii->pub.cccaps_ext = R_REG(&cc->capabilities_ext); | |
939 | ||
940 | /* get pmu rev and caps */ | |
941 | if (sii->pub.cccaps & CC_CAP_PMU) { | |
942 | sii->pub.pmucaps = R_REG(&cc->pmucapabilities); | |
943 | sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; | |
944 | } | |
945 | ||
946 | /* figure out bus/orignal core idx */ | |
947 | sii->pub.buscoretype = NODEV_CORE_ID; | |
948 | sii->pub.buscorerev = NOREV; | |
949 | sii->pub.buscoreidx = BADIDX; | |
950 | ||
951 | pci = pcie = false; | |
952 | pcirev = pcierev = NOREV; | |
953 | pciidx = pcieidx = BADIDX; | |
954 | ||
955 | for (i = 0; i < sii->numcores; i++) { | |
956 | uint cid, crev; | |
957 | ||
958 | ai_setcoreidx(&sii->pub, i); | |
959 | cid = ai_coreid(&sii->pub); | |
960 | crev = ai_corerev(&sii->pub); | |
961 | ||
962 | if (cid == PCI_CORE_ID) { | |
963 | pciidx = i; | |
964 | pcirev = crev; | |
965 | pci = true; | |
966 | } else if (cid == PCIE_CORE_ID) { | |
967 | pcieidx = i; | |
968 | pcierev = crev; | |
969 | pcie = true; | |
970 | } | |
971 | ||
972 | /* find the core idx before entering this func. */ | |
973 | if ((savewin && (savewin == sii->coresba[i])) || | |
974 | (cc == sii->regs[i])) | |
975 | *origidx = i; | |
976 | } | |
977 | ||
978 | if (pci && pcie) { | |
979 | if (ai_ispcie(sii)) | |
980 | pci = false; | |
981 | else | |
982 | pcie = false; | |
983 | } | |
984 | if (pci) { | |
985 | sii->pub.buscoretype = PCI_CORE_ID; | |
986 | sii->pub.buscorerev = pcirev; | |
987 | sii->pub.buscoreidx = pciidx; | |
988 | } else if (pcie) { | |
989 | sii->pub.buscoretype = PCIE_CORE_ID; | |
990 | sii->pub.buscorerev = pcierev; | |
991 | sii->pub.buscoreidx = pcieidx; | |
992 | } | |
993 | ||
994 | /* fixup necessary chip/core configurations */ | |
995 | if (SI_FAST(sii)) { | |
996 | if (!sii->pch) { | |
997 | sii->pch = pcicore_init(&sii->pub, sii->pbus, | |
998 | (__iomem void *)PCIEREGS(sii)); | |
999 | if (sii->pch == NULL) | |
1000 | return false; | |
1001 | } | |
1002 | } | |
1003 | if (ai_pci_fixcfg(&sii->pub)) { | |
1004 | /* si_doattach: si_pci_fixcfg failed */ | |
1005 | return false; | |
1006 | } | |
1007 | ||
1008 | /* return to the original core */ | |
1009 | ai_setcoreidx(&sii->pub, *origidx); | |
1010 | ||
1011 | return true; | |
1012 | } | |
1013 | ||
1014 | /* | |
1015 | * get boardtype and boardrev | |
1016 | */ | |
1017 | static __used void ai_nvram_process(struct si_info *sii) | |
1018 | { | |
1019 | uint w = 0; | |
1020 | ||
1021 | /* do a pci config read to get subsystem id and subvendor id */ | |
1022 | pci_read_config_dword(sii->pbus, PCI_SUBSYSTEM_VENDOR_ID, &w); | |
1023 | ||
1024 | sii->pub.boardvendor = w & 0xffff; | |
1025 | sii->pub.boardtype = (w >> 16) & 0xffff; | |
1026 | sii->pub.boardflags = getintvar(&sii->pub, BRCMS_SROM_BOARDFLAGS); | |
1027 | } | |
1028 | ||
1029 | static struct si_info *ai_doattach(struct si_info *sii, | |
1030 | void __iomem *regs, struct pci_dev *pbus) | |
1031 | { | |
1032 | struct si_pub *sih = &sii->pub; | |
1033 | u32 w, savewin; | |
1034 | struct chipcregs __iomem *cc; | |
1035 | uint socitype; | |
1036 | uint origidx; | |
1037 | ||
1038 | memset((unsigned char *) sii, 0, sizeof(struct si_info)); | |
1039 | ||
1040 | savewin = 0; | |
1041 | ||
1042 | sih->buscoreidx = BADIDX; | |
1043 | ||
1044 | sii->curmap = regs; | |
1045 | sii->pbus = pbus; | |
1046 | ||
1047 | /* find Chipcommon address */ | |
1048 | pci_read_config_dword(sii->pbus, PCI_BAR0_WIN, &savewin); | |
1049 | if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) | |
1050 | savewin = SI_ENUM_BASE; | |
1051 | ||
1052 | pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, | |
1053 | SI_ENUM_BASE); | |
1054 | cc = (struct chipcregs __iomem *) regs; | |
1055 | ||
1056 | /* bus/core/clk setup for register access */ | |
1057 | if (!ai_buscore_prep(sii)) | |
1058 | return NULL; | |
1059 | ||
1060 | /* | |
1061 | * ChipID recognition. | |
1062 | * We assume we can read chipid at offset 0 from the regs arg. | |
1063 | * If we add other chiptypes (or if we need to support old sdio | |
1064 | * hosts w/o chipcommon), some way of recognizing them needs to | |
1065 | * be added here. | |
1066 | */ | |
1067 | w = R_REG(&cc->chipid); | |
1068 | socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; | |
1069 | /* Might as wll fill in chip id rev & pkg */ | |
1070 | sih->chip = w & CID_ID_MASK; | |
1071 | sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; | |
1072 | sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; | |
1073 | ||
1074 | sih->issim = false; | |
1075 | ||
1076 | /* scan for cores */ | |
1077 | if (socitype == SOCI_AI) { | |
8505a7e6 | 1078 | SI_MSG("Found chip type AI (0x%08x)\n", w); |
5b435de0 AS |
1079 | /* pass chipc address instead of original core base */ |
1080 | ai_scan(&sii->pub, cc); | |
1081 | } else { | |
1082 | /* Found chip of unknown type */ | |
1083 | return NULL; | |
1084 | } | |
1085 | /* no cores found, bail out */ | |
1086 | if (sii->numcores == 0) | |
1087 | return NULL; | |
1088 | ||
1089 | /* bus/core/clk setup */ | |
1090 | origidx = SI_CC_IDX; | |
1091 | if (!ai_buscore_setup(sii, savewin, &origidx)) | |
1092 | goto exit; | |
1093 | ||
1094 | /* Init nvram from sprom/otp if they exist */ | |
1095 | if (srom_var_init(&sii->pub, cc)) | |
1096 | goto exit; | |
1097 | ||
1098 | ai_nvram_process(sii); | |
1099 | ||
1100 | /* === NVRAM, clock is ready === */ | |
1101 | cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0); | |
1102 | W_REG(&cc->gpiopullup, 0); | |
1103 | W_REG(&cc->gpiopulldown, 0); | |
1104 | ai_setcoreidx(sih, origidx); | |
1105 | ||
1106 | /* PMU specific initializations */ | |
1107 | if (sih->cccaps & CC_CAP_PMU) { | |
1108 | u32 xtalfreq; | |
1109 | si_pmu_init(sih); | |
1110 | si_pmu_chip_init(sih); | |
1111 | ||
1112 | xtalfreq = si_pmu_measure_alpclk(sih); | |
1113 | si_pmu_pll_init(sih, xtalfreq); | |
1114 | si_pmu_res_init(sih); | |
1115 | si_pmu_swreg_init(sih); | |
1116 | } | |
1117 | ||
1118 | /* setup the GPIO based LED powersave register */ | |
1119 | w = getintvar(sih, BRCMS_SROM_LEDDC); | |
1120 | if (w == 0) | |
1121 | w = DEFAULT_GPIOTIMERVAL; | |
1122 | ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, gpiotimerval), | |
1123 | ~0, w); | |
1124 | ||
1125 | if (PCIE(sii)) | |
1126 | pcicore_attach(sii->pch, SI_DOATTACH); | |
1127 | ||
1128 | if (sih->chip == BCM43224_CHIP_ID) { | |
1129 | /* | |
1130 | * enable 12 mA drive strenth for 43224 and | |
1131 | * set chipControl register bit 15 | |
1132 | */ | |
1133 | if (sih->chiprev == 0) { | |
8505a7e6 | 1134 | SI_MSG("Applying 43224A0 WARs\n"); |
5b435de0 AS |
1135 | ai_corereg(sih, SI_CC_IDX, |
1136 | offsetof(struct chipcregs, chipcontrol), | |
1137 | CCTRL43224_GPIO_TOGGLE, | |
1138 | CCTRL43224_GPIO_TOGGLE); | |
1139 | si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE, | |
1140 | CCTRL_43224A0_12MA_LED_DRIVE); | |
1141 | } | |
1142 | if (sih->chiprev >= 1) { | |
8505a7e6 | 1143 | SI_MSG("Applying 43224B0+ WARs\n"); |
5b435de0 AS |
1144 | si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE, |
1145 | CCTRL_43224B0_12MA_LED_DRIVE); | |
1146 | } | |
1147 | } | |
1148 | ||
1149 | if (sih->chip == BCM4313_CHIP_ID) { | |
1150 | /* | |
1151 | * enable 12 mA drive strenth for 4313 and | |
1152 | * set chipControl register bit 1 | |
1153 | */ | |
8505a7e6 | 1154 | SI_MSG("Applying 4313 WARs\n"); |
5b435de0 AS |
1155 | si_pmu_chipcontrol(sih, 0, CCTRL_4313_12MA_LED_DRIVE, |
1156 | CCTRL_4313_12MA_LED_DRIVE); | |
1157 | } | |
1158 | ||
1159 | return sii; | |
1160 | ||
1161 | exit: | |
1162 | if (sii->pch) | |
1163 | pcicore_deinit(sii->pch); | |
1164 | sii->pch = NULL; | |
1165 | ||
1166 | return NULL; | |
1167 | } | |
1168 | ||
1169 | /* | |
1170 | * Allocate a si handle. | |
1171 | * devid - pci device id (used to determine chip#) | |
1172 | * osh - opaque OS handle | |
1173 | * regs - virtual address of initial core registers | |
1174 | */ | |
1175 | struct si_pub * | |
1176 | ai_attach(void __iomem *regs, struct pci_dev *sdh) | |
1177 | { | |
1178 | struct si_info *sii; | |
1179 | ||
1180 | /* alloc struct si_info */ | |
1181 | sii = kmalloc(sizeof(struct si_info), GFP_ATOMIC); | |
1182 | if (sii == NULL) | |
1183 | return NULL; | |
1184 | ||
1185 | if (ai_doattach(sii, regs, sdh) == NULL) { | |
1186 | kfree(sii); | |
1187 | return NULL; | |
1188 | } | |
1189 | ||
1190 | return (struct si_pub *) sii; | |
1191 | } | |
1192 | ||
1193 | /* may be called with core in reset */ | |
1194 | void ai_detach(struct si_pub *sih) | |
1195 | { | |
1196 | struct si_info *sii; | |
1197 | ||
1198 | struct si_pub *si_local = NULL; | |
1199 | memcpy(&si_local, &sih, sizeof(struct si_pub **)); | |
1200 | ||
1201 | sii = (struct si_info *)sih; | |
1202 | ||
1203 | if (sii == NULL) | |
1204 | return; | |
1205 | ||
1206 | if (sii->pch) | |
1207 | pcicore_deinit(sii->pch); | |
1208 | sii->pch = NULL; | |
1209 | ||
1210 | srom_free_vars(sih); | |
1211 | kfree(sii); | |
1212 | } | |
1213 | ||
1214 | /* register driver interrupt disabling and restoring callback functions */ | |
1215 | void | |
1216 | ai_register_intr_callback(struct si_pub *sih, void *intrsoff_fn, | |
1217 | void *intrsrestore_fn, | |
1218 | void *intrsenabled_fn, void *intr_arg) | |
1219 | { | |
1220 | struct si_info *sii; | |
1221 | ||
1222 | sii = (struct si_info *)sih; | |
1223 | sii->intr_arg = intr_arg; | |
1224 | sii->intrsoff_fn = (u32 (*)(void *)) intrsoff_fn; | |
1225 | sii->intrsrestore_fn = (void (*) (void *, u32)) intrsrestore_fn; | |
1226 | sii->intrsenabled_fn = (bool (*)(void *)) intrsenabled_fn; | |
1227 | /* save current core id. when this function called, the current core | |
1228 | * must be the core which provides driver functions(il, et, wl, etc.) | |
1229 | */ | |
1230 | sii->dev_coreid = sii->coreid[sii->curidx]; | |
1231 | } | |
1232 | ||
1233 | void ai_deregister_intr_callback(struct si_pub *sih) | |
1234 | { | |
1235 | struct si_info *sii; | |
1236 | ||
1237 | sii = (struct si_info *)sih; | |
1238 | sii->intrsoff_fn = NULL; | |
1239 | } | |
1240 | ||
1241 | uint ai_coreid(struct si_pub *sih) | |
1242 | { | |
1243 | struct si_info *sii; | |
1244 | ||
1245 | sii = (struct si_info *)sih; | |
1246 | return sii->coreid[sii->curidx]; | |
1247 | } | |
1248 | ||
1249 | uint ai_coreidx(struct si_pub *sih) | |
1250 | { | |
1251 | struct si_info *sii; | |
1252 | ||
1253 | sii = (struct si_info *)sih; | |
1254 | return sii->curidx; | |
1255 | } | |
1256 | ||
1257 | bool ai_backplane64(struct si_pub *sih) | |
1258 | { | |
1259 | return (sih->cccaps & CC_CAP_BKPLN64) != 0; | |
1260 | } | |
1261 | ||
1262 | /* return index of coreid or BADIDX if not found */ | |
1263 | uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit) | |
1264 | { | |
1265 | struct si_info *sii; | |
1266 | uint found; | |
1267 | uint i; | |
1268 | ||
1269 | sii = (struct si_info *)sih; | |
1270 | ||
1271 | found = 0; | |
1272 | ||
1273 | for (i = 0; i < sii->numcores; i++) | |
1274 | if (sii->coreid[i] == coreid) { | |
1275 | if (found == coreunit) | |
1276 | return i; | |
1277 | found++; | |
1278 | } | |
1279 | ||
1280 | return BADIDX; | |
1281 | } | |
1282 | ||
1283 | /* | |
1284 | * This function changes logical "focus" to the indicated core; | |
1285 | * must be called with interrupts off. | |
1286 | * Moreover, callers should keep interrupts off during switching | |
1287 | * out of and back to d11 core. | |
1288 | */ | |
1289 | void __iomem *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit) | |
1290 | { | |
1291 | uint idx; | |
1292 | ||
1293 | idx = ai_findcoreidx(sih, coreid, coreunit); | |
1294 | if (idx >= SI_MAXCORES) | |
1295 | return NULL; | |
1296 | ||
1297 | return ai_setcoreidx(sih, idx); | |
1298 | } | |
1299 | ||
1300 | /* Turn off interrupt as required by ai_setcore, before switch core */ | |
1301 | void __iomem *ai_switch_core(struct si_pub *sih, uint coreid, uint *origidx, | |
1302 | uint *intr_val) | |
1303 | { | |
1304 | void __iomem *cc; | |
1305 | struct si_info *sii; | |
1306 | ||
1307 | sii = (struct si_info *)sih; | |
1308 | ||
1309 | if (SI_FAST(sii)) { | |
1310 | /* Overloading the origidx variable to remember the coreid, | |
1311 | * this works because the core ids cannot be confused with | |
1312 | * core indices. | |
1313 | */ | |
1314 | *origidx = coreid; | |
1315 | if (coreid == CC_CORE_ID) | |
1316 | return CCREGS_FAST(sii); | |
1317 | else if (coreid == sih->buscoretype) | |
1318 | return PCIEREGS(sii); | |
1319 | } | |
1320 | INTR_OFF(sii, *intr_val); | |
1321 | *origidx = sii->curidx; | |
1322 | cc = ai_setcore(sih, coreid, 0); | |
1323 | return cc; | |
1324 | } | |
1325 | ||
1326 | /* restore coreidx and restore interrupt */ | |
1327 | void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val) | |
1328 | { | |
1329 | struct si_info *sii; | |
1330 | ||
1331 | sii = (struct si_info *)sih; | |
1332 | if (SI_FAST(sii) | |
1333 | && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) | |
1334 | return; | |
1335 | ||
1336 | ai_setcoreidx(sih, coreid); | |
1337 | INTR_RESTORE(sii, intr_val); | |
1338 | } | |
1339 | ||
1340 | void ai_write_wrapperreg(struct si_pub *sih, u32 offset, u32 val) | |
1341 | { | |
1342 | struct si_info *sii = (struct si_info *)sih; | |
1343 | u32 *w = (u32 *) sii->curwrap; | |
1344 | W_REG(w + (offset / 4), val); | |
1345 | return; | |
1346 | } | |
1347 | ||
1348 | /* | |
1349 | * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set | |
1350 | * operation, switch back to the original core, and return the new value. | |
1351 | * | |
1352 | * When using the silicon backplane, no fiddling with interrupts or core | |
1353 | * switches is needed. | |
1354 | * | |
1355 | * Also, when using pci/pcie, we can optimize away the core switching for pci | |
1356 | * registers and (on newer pci cores) chipcommon registers. | |
1357 | */ | |
1358 | uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask, | |
1359 | uint val) | |
1360 | { | |
1361 | uint origidx = 0; | |
1362 | u32 __iomem *r = NULL; | |
1363 | uint w; | |
1364 | uint intr_val = 0; | |
1365 | bool fast = false; | |
1366 | struct si_info *sii; | |
1367 | ||
1368 | sii = (struct si_info *)sih; | |
1369 | ||
1370 | if (coreidx >= SI_MAXCORES) | |
1371 | return 0; | |
1372 | ||
1373 | /* | |
1374 | * If pci/pcie, we can get at pci/pcie regs | |
1375 | * and on newer cores to chipc | |
1376 | */ | |
1377 | if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { | |
1378 | /* Chipc registers are mapped at 12KB */ | |
1379 | fast = true; | |
1380 | r = (u32 __iomem *)((__iomem char *)sii->curmap + | |
1381 | PCI_16KB0_CCREGS_OFFSET + regoff); | |
1382 | } else if (sii->pub.buscoreidx == coreidx) { | |
1383 | /* | |
1384 | * pci registers are at either in the last 2KB of | |
1385 | * an 8KB window or, in pcie and pci rev 13 at 8KB | |
1386 | */ | |
1387 | fast = true; | |
1388 | if (SI_FAST(sii)) | |
1389 | r = (u32 __iomem *)((__iomem char *)sii->curmap + | |
1390 | PCI_16KB0_PCIREGS_OFFSET + regoff); | |
1391 | else | |
1392 | r = (u32 __iomem *)((__iomem char *)sii->curmap + | |
1393 | ((regoff >= SBCONFIGOFF) ? | |
1394 | PCI_BAR0_PCISBR_OFFSET : | |
1395 | PCI_BAR0_PCIREGS_OFFSET) + regoff); | |
1396 | } | |
1397 | ||
1398 | if (!fast) { | |
1399 | INTR_OFF(sii, intr_val); | |
1400 | ||
1401 | /* save current core index */ | |
1402 | origidx = ai_coreidx(&sii->pub); | |
1403 | ||
1404 | /* switch core */ | |
1405 | r = (u32 __iomem *) ((unsigned char __iomem *) | |
1406 | ai_setcoreidx(&sii->pub, coreidx) + regoff); | |
1407 | } | |
1408 | ||
1409 | /* mask and set */ | |
1410 | if (mask || val) { | |
1411 | w = (R_REG(r) & ~mask) | val; | |
1412 | W_REG(r, w); | |
1413 | } | |
1414 | ||
1415 | /* readback */ | |
1416 | w = R_REG(r); | |
1417 | ||
1418 | if (!fast) { | |
1419 | /* restore core index */ | |
1420 | if (origidx != coreidx) | |
1421 | ai_setcoreidx(&sii->pub, origidx); | |
1422 | ||
1423 | INTR_RESTORE(sii, intr_val); | |
1424 | } | |
1425 | ||
1426 | return w; | |
1427 | } | |
1428 | ||
1429 | void ai_core_disable(struct si_pub *sih, u32 bits) | |
1430 | { | |
1431 | struct si_info *sii; | |
1432 | u32 dummy; | |
1433 | struct aidmp *ai; | |
1434 | ||
1435 | sii = (struct si_info *)sih; | |
1436 | ||
1437 | ai = sii->curwrap; | |
1438 | ||
1439 | /* if core is already in reset, just return */ | |
1440 | if (R_REG(&ai->resetctrl) & AIRC_RESET) | |
1441 | return; | |
1442 | ||
1443 | W_REG(&ai->ioctrl, bits); | |
1444 | dummy = R_REG(&ai->ioctrl); | |
1445 | udelay(10); | |
1446 | ||
1447 | W_REG(&ai->resetctrl, AIRC_RESET); | |
1448 | udelay(1); | |
1449 | } | |
1450 | ||
1451 | /* reset and re-enable a core | |
1452 | * inputs: | |
1453 | * bits - core specific bits that are set during and after reset sequence | |
1454 | * resetbits - core specific bits that are set only during reset sequence | |
1455 | */ | |
1456 | void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits) | |
1457 | { | |
1458 | struct si_info *sii; | |
1459 | struct aidmp *ai; | |
1460 | u32 dummy; | |
1461 | ||
1462 | sii = (struct si_info *)sih; | |
1463 | ai = sii->curwrap; | |
1464 | ||
1465 | /* | |
1466 | * Must do the disable sequence first to work | |
1467 | * for arbitrary current core state. | |
1468 | */ | |
1469 | ai_core_disable(sih, (bits | resetbits)); | |
1470 | ||
1471 | /* | |
1472 | * Now do the initialization sequence. | |
1473 | */ | |
1474 | W_REG(&ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN)); | |
1475 | dummy = R_REG(&ai->ioctrl); | |
1476 | W_REG(&ai->resetctrl, 0); | |
1477 | udelay(1); | |
1478 | ||
1479 | W_REG(&ai->ioctrl, (bits | SICF_CLOCK_EN)); | |
1480 | dummy = R_REG(&ai->ioctrl); | |
1481 | udelay(1); | |
1482 | } | |
1483 | ||
1484 | /* return the slow clock source - LPO, XTAL, or PCI */ | |
1485 | static uint ai_slowclk_src(struct si_info *sii) | |
1486 | { | |
1487 | struct chipcregs __iomem *cc; | |
1488 | u32 val; | |
1489 | ||
1490 | if (sii->pub.ccrev < 6) { | |
1491 | pci_read_config_dword(sii->pbus, PCI_GPIO_OUT, | |
1492 | &val); | |
1493 | if (val & PCI_CFG_GPIO_SCS) | |
1494 | return SCC_SS_PCI; | |
1495 | return SCC_SS_XTAL; | |
1496 | } else if (sii->pub.ccrev < 10) { | |
1497 | cc = (struct chipcregs __iomem *) | |
1498 | ai_setcoreidx(&sii->pub, sii->curidx); | |
1499 | return R_REG(&cc->slow_clk_ctl) & SCC_SS_MASK; | |
1500 | } else /* Insta-clock */ | |
1501 | return SCC_SS_XTAL; | |
1502 | } | |
1503 | ||
1504 | /* | |
1505 | * return the ILP (slowclock) min or max frequency | |
1506 | * precondition: we've established the chip has dynamic clk control | |
1507 | */ | |
1508 | static uint ai_slowclk_freq(struct si_info *sii, bool max_freq, | |
1509 | struct chipcregs __iomem *cc) | |
1510 | { | |
1511 | u32 slowclk; | |
1512 | uint div; | |
1513 | ||
1514 | slowclk = ai_slowclk_src(sii); | |
1515 | if (sii->pub.ccrev < 6) { | |
1516 | if (slowclk == SCC_SS_PCI) | |
1517 | return max_freq ? (PCIMAXFREQ / 64) | |
1518 | : (PCIMINFREQ / 64); | |
1519 | else | |
1520 | return max_freq ? (XTALMAXFREQ / 32) | |
1521 | : (XTALMINFREQ / 32); | |
1522 | } else if (sii->pub.ccrev < 10) { | |
1523 | div = 4 * | |
1524 | (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> | |
1525 | SCC_CD_SHIFT) + 1); | |
1526 | if (slowclk == SCC_SS_LPO) | |
1527 | return max_freq ? LPOMAXFREQ : LPOMINFREQ; | |
1528 | else if (slowclk == SCC_SS_XTAL) | |
1529 | return max_freq ? (XTALMAXFREQ / div) | |
1530 | : (XTALMINFREQ / div); | |
1531 | else if (slowclk == SCC_SS_PCI) | |
1532 | return max_freq ? (PCIMAXFREQ / div) | |
1533 | : (PCIMINFREQ / div); | |
1534 | } else { | |
1535 | /* Chipc rev 10 is InstaClock */ | |
1536 | div = R_REG(&cc->system_clk_ctl) >> SYCC_CD_SHIFT; | |
1537 | div = 4 * (div + 1); | |
1538 | return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div); | |
1539 | } | |
1540 | return 0; | |
1541 | } | |
1542 | ||
1543 | static void | |
1544 | ai_clkctl_setdelay(struct si_info *sii, struct chipcregs __iomem *cc) | |
1545 | { | |
1546 | uint slowmaxfreq, pll_delay, slowclk; | |
1547 | uint pll_on_delay, fref_sel_delay; | |
1548 | ||
1549 | pll_delay = PLL_DELAY; | |
1550 | ||
1551 | /* | |
1552 | * If the slow clock is not sourced by the xtal then | |
1553 | * add the xtal_on_delay since the xtal will also be | |
1554 | * powered down by dynamic clk control logic. | |
1555 | */ | |
1556 | ||
1557 | slowclk = ai_slowclk_src(sii); | |
1558 | if (slowclk != SCC_SS_XTAL) | |
1559 | pll_delay += XTAL_ON_DELAY; | |
1560 | ||
1561 | /* Starting with 4318 it is ILP that is used for the delays */ | |
1562 | slowmaxfreq = | |
1563 | ai_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? false : true, cc); | |
1564 | ||
1565 | pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; | |
1566 | fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; | |
1567 | ||
1568 | W_REG(&cc->pll_on_delay, pll_on_delay); | |
1569 | W_REG(&cc->fref_sel_delay, fref_sel_delay); | |
1570 | } | |
1571 | ||
1572 | /* initialize power control delay registers */ | |
1573 | void ai_clkctl_init(struct si_pub *sih) | |
1574 | { | |
1575 | struct si_info *sii; | |
1576 | uint origidx = 0; | |
1577 | struct chipcregs __iomem *cc; | |
1578 | bool fast; | |
1579 | ||
1580 | if (!(sih->cccaps & CC_CAP_PWR_CTL)) | |
1581 | return; | |
1582 | ||
1583 | sii = (struct si_info *)sih; | |
1584 | fast = SI_FAST(sii); | |
1585 | if (!fast) { | |
1586 | origidx = sii->curidx; | |
1587 | cc = (struct chipcregs __iomem *) | |
1588 | ai_setcore(sih, CC_CORE_ID, 0); | |
1589 | if (cc == NULL) | |
1590 | return; | |
1591 | } else { | |
1592 | cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); | |
1593 | if (cc == NULL) | |
1594 | return; | |
1595 | } | |
1596 | ||
1597 | /* set all Instaclk chip ILP to 1 MHz */ | |
1598 | if (sih->ccrev >= 10) | |
1599 | SET_REG(&cc->system_clk_ctl, SYCC_CD_MASK, | |
1600 | (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); | |
1601 | ||
1602 | ai_clkctl_setdelay(sii, cc); | |
1603 | ||
1604 | if (!fast) | |
1605 | ai_setcoreidx(sih, origidx); | |
1606 | } | |
1607 | ||
1608 | /* | |
1609 | * return the value suitable for writing to the | |
1610 | * dot11 core FAST_PWRUP_DELAY register | |
1611 | */ | |
1612 | u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih) | |
1613 | { | |
1614 | struct si_info *sii; | |
1615 | uint origidx = 0; | |
1616 | struct chipcregs __iomem *cc; | |
1617 | uint slowminfreq; | |
1618 | u16 fpdelay; | |
1619 | uint intr_val = 0; | |
1620 | bool fast; | |
1621 | ||
1622 | sii = (struct si_info *)sih; | |
1623 | if (sih->cccaps & CC_CAP_PMU) { | |
1624 | INTR_OFF(sii, intr_val); | |
1625 | fpdelay = si_pmu_fast_pwrup_delay(sih); | |
1626 | INTR_RESTORE(sii, intr_val); | |
1627 | return fpdelay; | |
1628 | } | |
1629 | ||
1630 | if (!(sih->cccaps & CC_CAP_PWR_CTL)) | |
1631 | return 0; | |
1632 | ||
1633 | fast = SI_FAST(sii); | |
1634 | fpdelay = 0; | |
1635 | if (!fast) { | |
1636 | origidx = sii->curidx; | |
1637 | INTR_OFF(sii, intr_val); | |
1638 | cc = (struct chipcregs __iomem *) | |
1639 | ai_setcore(sih, CC_CORE_ID, 0); | |
1640 | if (cc == NULL) | |
1641 | goto done; | |
1642 | } else { | |
1643 | cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); | |
1644 | if (cc == NULL) | |
1645 | goto done; | |
1646 | } | |
1647 | ||
1648 | slowminfreq = ai_slowclk_freq(sii, false, cc); | |
1649 | fpdelay = (((R_REG(&cc->pll_on_delay) + 2) * 1000000) + | |
1650 | (slowminfreq - 1)) / slowminfreq; | |
1651 | ||
1652 | done: | |
1653 | if (!fast) { | |
1654 | ai_setcoreidx(sih, origidx); | |
1655 | INTR_RESTORE(sii, intr_val); | |
1656 | } | |
1657 | return fpdelay; | |
1658 | } | |
1659 | ||
1660 | /* turn primary xtal and/or pll off/on */ | |
1661 | int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on) | |
1662 | { | |
1663 | struct si_info *sii; | |
1664 | u32 in, out, outen; | |
1665 | ||
1666 | sii = (struct si_info *)sih; | |
1667 | ||
1668 | /* pcie core doesn't have any mapping to control the xtal pu */ | |
1669 | if (PCIE(sii)) | |
1670 | return -1; | |
1671 | ||
1672 | pci_read_config_dword(sii->pbus, PCI_GPIO_IN, &in); | |
1673 | pci_read_config_dword(sii->pbus, PCI_GPIO_OUT, &out); | |
1674 | pci_read_config_dword(sii->pbus, PCI_GPIO_OUTEN, &outen); | |
1675 | ||
1676 | /* | |
1677 | * Avoid glitching the clock if GPRS is already using it. | |
1678 | * We can't actually read the state of the PLLPD so we infer it | |
1679 | * by the value of XTAL_PU which *is* readable via gpioin. | |
1680 | */ | |
1681 | if (on && (in & PCI_CFG_GPIO_XTAL)) | |
1682 | return 0; | |
1683 | ||
1684 | if (what & XTAL) | |
1685 | outen |= PCI_CFG_GPIO_XTAL; | |
1686 | if (what & PLL) | |
1687 | outen |= PCI_CFG_GPIO_PLL; | |
1688 | ||
1689 | if (on) { | |
1690 | /* turn primary xtal on */ | |
1691 | if (what & XTAL) { | |
1692 | out |= PCI_CFG_GPIO_XTAL; | |
1693 | if (what & PLL) | |
1694 | out |= PCI_CFG_GPIO_PLL; | |
1695 | pci_write_config_dword(sii->pbus, | |
1696 | PCI_GPIO_OUT, out); | |
1697 | pci_write_config_dword(sii->pbus, | |
1698 | PCI_GPIO_OUTEN, outen); | |
1699 | udelay(XTAL_ON_DELAY); | |
1700 | } | |
1701 | ||
1702 | /* turn pll on */ | |
1703 | if (what & PLL) { | |
1704 | out &= ~PCI_CFG_GPIO_PLL; | |
1705 | pci_write_config_dword(sii->pbus, | |
1706 | PCI_GPIO_OUT, out); | |
1707 | mdelay(2); | |
1708 | } | |
1709 | } else { | |
1710 | if (what & XTAL) | |
1711 | out &= ~PCI_CFG_GPIO_XTAL; | |
1712 | if (what & PLL) | |
1713 | out |= PCI_CFG_GPIO_PLL; | |
1714 | pci_write_config_dword(sii->pbus, | |
1715 | PCI_GPIO_OUT, out); | |
1716 | pci_write_config_dword(sii->pbus, | |
1717 | PCI_GPIO_OUTEN, outen); | |
1718 | } | |
1719 | ||
1720 | return 0; | |
1721 | } | |
1722 | ||
1723 | /* clk control mechanism through chipcommon, no policy checking */ | |
1724 | static bool _ai_clkctl_cc(struct si_info *sii, uint mode) | |
1725 | { | |
1726 | uint origidx = 0; | |
1727 | struct chipcregs __iomem *cc; | |
1728 | u32 scc; | |
1729 | uint intr_val = 0; | |
1730 | bool fast = SI_FAST(sii); | |
1731 | ||
1732 | /* chipcommon cores prior to rev6 don't support dynamic clock control */ | |
1733 | if (sii->pub.ccrev < 6) | |
1734 | return false; | |
1735 | ||
1736 | if (!fast) { | |
1737 | INTR_OFF(sii, intr_val); | |
1738 | origidx = sii->curidx; | |
1739 | cc = (struct chipcregs __iomem *) | |
1740 | ai_setcore(&sii->pub, CC_CORE_ID, 0); | |
1741 | } else { | |
1742 | cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); | |
1743 | if (cc == NULL) | |
1744 | goto done; | |
1745 | } | |
1746 | ||
1747 | if (!(sii->pub.cccaps & CC_CAP_PWR_CTL) && (sii->pub.ccrev < 20)) | |
1748 | goto done; | |
1749 | ||
1750 | switch (mode) { | |
1751 | case CLK_FAST: /* FORCEHT, fast (pll) clock */ | |
1752 | if (sii->pub.ccrev < 10) { | |
1753 | /* | |
1754 | * don't forget to force xtal back | |
1755 | * on before we clear SCC_DYN_XTAL.. | |
1756 | */ | |
1757 | ai_clkctl_xtal(&sii->pub, XTAL, ON); | |
1758 | SET_REG(&cc->slow_clk_ctl, | |
1759 | (SCC_XC | SCC_FS | SCC_IP), SCC_IP); | |
1760 | } else if (sii->pub.ccrev < 20) { | |
1761 | OR_REG(&cc->system_clk_ctl, SYCC_HR); | |
1762 | } else { | |
1763 | OR_REG(&cc->clk_ctl_st, CCS_FORCEHT); | |
1764 | } | |
1765 | ||
1766 | /* wait for the PLL */ | |
1767 | if (sii->pub.cccaps & CC_CAP_PMU) { | |
1768 | u32 htavail = CCS_HTAVAIL; | |
1769 | SPINWAIT(((R_REG(&cc->clk_ctl_st) & htavail) | |
1770 | == 0), PMU_MAX_TRANSITION_DLY); | |
1771 | } else { | |
1772 | udelay(PLL_DELAY); | |
1773 | } | |
1774 | break; | |
1775 | ||
1776 | case CLK_DYNAMIC: /* enable dynamic clock control */ | |
1777 | if (sii->pub.ccrev < 10) { | |
1778 | scc = R_REG(&cc->slow_clk_ctl); | |
1779 | scc &= ~(SCC_FS | SCC_IP | SCC_XC); | |
1780 | if ((scc & SCC_SS_MASK) != SCC_SS_XTAL) | |
1781 | scc |= SCC_XC; | |
1782 | W_REG(&cc->slow_clk_ctl, scc); | |
1783 | ||
1784 | /* | |
1785 | * for dynamic control, we have to | |
1786 | * release our xtal_pu "force on" | |
1787 | */ | |
1788 | if (scc & SCC_XC) | |
1789 | ai_clkctl_xtal(&sii->pub, XTAL, OFF); | |
1790 | } else if (sii->pub.ccrev < 20) { | |
1791 | /* Instaclock */ | |
1792 | AND_REG(&cc->system_clk_ctl, ~SYCC_HR); | |
1793 | } else { | |
1794 | AND_REG(&cc->clk_ctl_st, ~CCS_FORCEHT); | |
1795 | } | |
1796 | break; | |
1797 | ||
1798 | default: | |
1799 | break; | |
1800 | } | |
1801 | ||
1802 | done: | |
1803 | if (!fast) { | |
1804 | ai_setcoreidx(&sii->pub, origidx); | |
1805 | INTR_RESTORE(sii, intr_val); | |
1806 | } | |
1807 | return mode == CLK_FAST; | |
1808 | } | |
1809 | ||
1810 | /* | |
1811 | * clock control policy function throught chipcommon | |
1812 | * | |
1813 | * set dynamic clk control mode (forceslow, forcefast, dynamic) | |
1814 | * returns true if we are forcing fast clock | |
1815 | * this is a wrapper over the next internal function | |
1816 | * to allow flexible policy settings for outside caller | |
1817 | */ | |
1818 | bool ai_clkctl_cc(struct si_pub *sih, uint mode) | |
1819 | { | |
1820 | struct si_info *sii; | |
1821 | ||
1822 | sii = (struct si_info *)sih; | |
1823 | ||
1824 | /* chipcommon cores prior to rev6 don't support dynamic clock control */ | |
1825 | if (sih->ccrev < 6) | |
1826 | return false; | |
1827 | ||
1828 | if (PCI_FORCEHT(sii)) | |
1829 | return mode == CLK_FAST; | |
1830 | ||
1831 | return _ai_clkctl_cc(sii, mode); | |
1832 | } | |
1833 | ||
1834 | /* Build device path */ | |
1835 | int ai_devpath(struct si_pub *sih, char *path, int size) | |
1836 | { | |
1837 | int slen; | |
1838 | ||
1839 | if (!path || size <= 0) | |
1840 | return -1; | |
1841 | ||
1842 | slen = snprintf(path, (size_t) size, "pci/%u/%u/", | |
1843 | ((struct si_info *)sih)->pbus->bus->number, | |
1844 | PCI_SLOT(((struct pci_dev *) | |
1845 | (((struct si_info *)(sih))->pbus))->devfn)); | |
1846 | ||
1847 | if (slen < 0 || slen >= size) { | |
1848 | path[0] = '\0'; | |
1849 | return -1; | |
1850 | } | |
1851 | ||
1852 | return 0; | |
1853 | } | |
1854 | ||
1855 | void ai_pci_up(struct si_pub *sih) | |
1856 | { | |
1857 | struct si_info *sii; | |
1858 | ||
1859 | sii = (struct si_info *)sih; | |
1860 | ||
1861 | if (PCI_FORCEHT(sii)) | |
1862 | _ai_clkctl_cc(sii, CLK_FAST); | |
1863 | ||
1864 | if (PCIE(sii)) | |
1865 | pcicore_up(sii->pch, SI_PCIUP); | |
1866 | ||
1867 | } | |
1868 | ||
1869 | /* Unconfigure and/or apply various WARs when system is going to sleep mode */ | |
1870 | void ai_pci_sleep(struct si_pub *sih) | |
1871 | { | |
1872 | struct si_info *sii; | |
1873 | ||
1874 | sii = (struct si_info *)sih; | |
1875 | ||
1876 | pcicore_sleep(sii->pch); | |
1877 | } | |
1878 | ||
1879 | /* Unconfigure and/or apply various WARs when going down */ | |
1880 | void ai_pci_down(struct si_pub *sih) | |
1881 | { | |
1882 | struct si_info *sii; | |
1883 | ||
1884 | sii = (struct si_info *)sih; | |
1885 | ||
1886 | /* release FORCEHT since chip is going to "down" state */ | |
1887 | if (PCI_FORCEHT(sii)) | |
1888 | _ai_clkctl_cc(sii, CLK_DYNAMIC); | |
1889 | ||
1890 | pcicore_down(sii->pch, SI_PCIDOWN); | |
1891 | } | |
1892 | ||
1893 | /* | |
1894 | * Configure the pci core for pci client (NIC) action | |
1895 | * coremask is the bitvec of cores by index to be enabled. | |
1896 | */ | |
1897 | void ai_pci_setup(struct si_pub *sih, uint coremask) | |
1898 | { | |
1899 | struct si_info *sii; | |
1900 | struct sbpciregs __iomem *regs = NULL; | |
1901 | u32 siflag = 0, w; | |
1902 | uint idx = 0; | |
1903 | ||
1904 | sii = (struct si_info *)sih; | |
1905 | ||
1906 | if (PCI(sii)) { | |
1907 | /* get current core index */ | |
1908 | idx = sii->curidx; | |
1909 | ||
1910 | /* we interrupt on this backplane flag number */ | |
1911 | siflag = ai_flag(sih); | |
1912 | ||
1913 | /* switch over to pci core */ | |
1914 | regs = ai_setcoreidx(sih, sii->pub.buscoreidx); | |
1915 | } | |
1916 | ||
1917 | /* | |
1918 | * Enable sb->pci interrupts. Assume | |
1919 | * PCI rev 2.3 support was added in pci core rev 6 and things changed.. | |
1920 | */ | |
1921 | if (PCIE(sii) || (PCI(sii) && ((sii->pub.buscorerev) >= 6))) { | |
1922 | /* pci config write to set this core bit in PCIIntMask */ | |
1923 | pci_read_config_dword(sii->pbus, PCI_INT_MASK, &w); | |
1924 | w |= (coremask << PCI_SBIM_SHIFT); | |
1925 | pci_write_config_dword(sii->pbus, PCI_INT_MASK, w); | |
1926 | } else { | |
1927 | /* set sbintvec bit for our flag number */ | |
1928 | ai_setint(sih, siflag); | |
1929 | } | |
1930 | ||
1931 | if (PCI(sii)) { | |
1932 | pcicore_pci_setup(sii->pch, regs); | |
1933 | ||
1934 | /* switch back to previous core */ | |
1935 | ai_setcoreidx(sih, idx); | |
1936 | } | |
1937 | } | |
1938 | ||
1939 | /* | |
1940 | * Fixup SROMless PCI device's configuration. | |
1941 | * The current core may be changed upon return. | |
1942 | */ | |
1943 | int ai_pci_fixcfg(struct si_pub *sih) | |
1944 | { | |
1945 | uint origidx; | |
1946 | void __iomem *regs = NULL; | |
1947 | struct si_info *sii = (struct si_info *)sih; | |
1948 | ||
1949 | /* Fixup PI in SROM shadow area to enable the correct PCI core access */ | |
1950 | /* save the current index */ | |
1951 | origidx = ai_coreidx(&sii->pub); | |
1952 | ||
1953 | /* check 'pi' is correct and fix it if not */ | |
1954 | regs = ai_setcore(&sii->pub, sii->pub.buscoretype, 0); | |
1955 | if (sii->pub.buscoretype == PCIE_CORE_ID) | |
1956 | pcicore_fixcfg_pcie(sii->pch, | |
1957 | (struct sbpcieregs __iomem *)regs); | |
1958 | else if (sii->pub.buscoretype == PCI_CORE_ID) | |
1959 | pcicore_fixcfg_pci(sii->pch, (struct sbpciregs __iomem *)regs); | |
1960 | ||
1961 | /* restore the original index */ | |
1962 | ai_setcoreidx(&sii->pub, origidx); | |
1963 | ||
1964 | pcicore_hwup(sii->pch); | |
1965 | return 0; | |
1966 | } | |
1967 | ||
1968 | /* mask&set gpiocontrol bits */ | |
1969 | u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, u8 priority) | |
1970 | { | |
1971 | uint regoff; | |
1972 | ||
1973 | regoff = offsetof(struct chipcregs, gpiocontrol); | |
1974 | return ai_corereg(sih, SI_CC_IDX, regoff, mask, val); | |
1975 | } | |
1976 | ||
1977 | void ai_chipcontrl_epa4331(struct si_pub *sih, bool on) | |
1978 | { | |
1979 | struct si_info *sii; | |
1980 | struct chipcregs __iomem *cc; | |
1981 | uint origidx; | |
1982 | u32 val; | |
1983 | ||
1984 | sii = (struct si_info *)sih; | |
1985 | origidx = ai_coreidx(sih); | |
1986 | ||
1987 | cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0); | |
1988 | ||
1989 | val = R_REG(&cc->chipcontrol); | |
1990 | ||
1991 | if (on) { | |
1992 | if (sih->chippkg == 9 || sih->chippkg == 0xb) | |
1993 | /* Ext PA Controls for 4331 12x9 Package */ | |
1994 | W_REG(&cc->chipcontrol, val | | |
1995 | CCTRL4331_EXTPA_EN | | |
1996 | CCTRL4331_EXTPA_ON_GPIO2_5); | |
1997 | else | |
1998 | /* Ext PA Controls for 4331 12x12 Package */ | |
1999 | W_REG(&cc->chipcontrol, | |
2000 | val | CCTRL4331_EXTPA_EN); | |
2001 | } else { | |
2002 | val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); | |
2003 | W_REG(&cc->chipcontrol, val); | |
2004 | } | |
2005 | ||
2006 | ai_setcoreidx(sih, origidx); | |
2007 | } | |
2008 | ||
2009 | /* Enable BT-COEX & Ex-PA for 4313 */ | |
2010 | void ai_epa_4313war(struct si_pub *sih) | |
2011 | { | |
2012 | struct si_info *sii; | |
2013 | struct chipcregs __iomem *cc; | |
2014 | uint origidx; | |
2015 | ||
2016 | sii = (struct si_info *)sih; | |
2017 | origidx = ai_coreidx(sih); | |
2018 | ||
2019 | cc = ai_setcore(sih, CC_CORE_ID, 0); | |
2020 | ||
2021 | /* EPA Fix */ | |
2022 | W_REG(&cc->gpiocontrol, | |
2023 | R_REG(&cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); | |
2024 | ||
2025 | ai_setcoreidx(sih, origidx); | |
2026 | } | |
2027 | ||
2028 | /* check if the device is removed */ | |
2029 | bool ai_deviceremoved(struct si_pub *sih) | |
2030 | { | |
2031 | u32 w; | |
2032 | struct si_info *sii; | |
2033 | ||
2034 | sii = (struct si_info *)sih; | |
2035 | ||
2036 | pci_read_config_dword(sii->pbus, PCI_VENDOR_ID, &w); | |
2037 | if ((w & 0xFFFF) != PCI_VENDOR_ID_BROADCOM) | |
2038 | return true; | |
2039 | ||
2040 | return false; | |
2041 | } | |
2042 | ||
2043 | bool ai_is_sprom_available(struct si_pub *sih) | |
2044 | { | |
2045 | if (sih->ccrev >= 31) { | |
2046 | struct si_info *sii; | |
2047 | uint origidx; | |
2048 | struct chipcregs __iomem *cc; | |
2049 | u32 sromctrl; | |
2050 | ||
2051 | if ((sih->cccaps & CC_CAP_SROM) == 0) | |
2052 | return false; | |
2053 | ||
2054 | sii = (struct si_info *)sih; | |
2055 | origidx = sii->curidx; | |
2056 | cc = ai_setcoreidx(sih, SI_CC_IDX); | |
2057 | sromctrl = R_REG(&cc->sromcontrol); | |
2058 | ai_setcoreidx(sih, origidx); | |
2059 | return sromctrl & SRC_PRESENT; | |
2060 | } | |
2061 | ||
2062 | switch (sih->chip) { | |
2063 | case BCM4313_CHIP_ID: | |
2064 | return (sih->chipst & CST4313_SPROM_PRESENT) != 0; | |
2065 | default: | |
2066 | return true; | |
2067 | } | |
2068 | } | |
2069 | ||
2070 | bool ai_is_otp_disabled(struct si_pub *sih) | |
2071 | { | |
2072 | switch (sih->chip) { | |
2073 | case BCM4313_CHIP_ID: | |
2074 | return (sih->chipst & CST4313_OTP_PRESENT) == 0; | |
2075 | /* These chips always have their OTP on */ | |
2076 | case BCM43224_CHIP_ID: | |
2077 | case BCM43225_CHIP_ID: | |
2078 | default: | |
2079 | return false; | |
2080 | } | |
2081 | } |