blob: 1a9ff1a895c29e4c1702e4a70facc359922fab87 [file] [log] [blame]
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001/*
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
Brett Rudley33279892010-10-01 18:03:27 -070017#include <linux/kernel.h>
18#include <linux/string.h>
Greg Kroah-Hartmana1c16ed2010-10-21 11:17:44 -070019#include <bcmdefs.h>
Brett Rudleyc6ac24e2010-10-26 11:55:23 -070020#ifdef BRCM_FULLMAC
21#include <linux/netdevice.h>
22#endif
Greg Kroah-Hartmana1c16ed2010-10-21 11:17:44 -070023#include <osl.h>
Brett Rudleyc6ac24e2010-10-26 11:55:23 -070024#include <linux/module.h>
25#include <linux/pci.h>
Henry Ptasinskia9533e72010-09-08 21:04:42 -070026#include <bcmutils.h>
27#include <siutils.h>
28#include <bcmdevs.h>
29#include <hndsoc.h>
30#include <sbchipc.h>
31#include <pci_core.h>
32#include <pcie_core.h>
33#include <nicpci.h>
34#include <bcmnvram.h>
35#include <bcmsrom.h>
Henry Ptasinskia9533e72010-09-08 21:04:42 -070036#include <pcicfg.h>
37#include <sbsocram.h>
38#ifdef BCMSDIO
39#include <bcmsdh.h>
40#include <sdio.h>
41#include <sbsdio.h>
42#include <sbhnddma.h>
43#include <sbsdpcmdev.h>
44#include <bcmsdpcm.h>
45#endif /* BCMSDIO */
46#include <hndpmu.h>
47
48/* this file now contains only definitions for sb functions, only necessary
49*for devices using Sonics backplanes (bcm4329)
50*/
51
52/* if an amba SDIO device is supported, please further restrict the inclusion
53 * of this file
54 */
55#ifdef BCMSDIO
56#include "siutils_priv.h"
57#endif
58
59/* local prototypes */
Brett Rudleye69284f2010-11-16 15:45:48 -080060static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh,
Henry Ptasinskia9533e72010-09-08 21:04:42 -070061 void *regs, uint bustype, void *sdh, char **vars,
Jason Cooper7cc4a4c2010-09-14 09:45:30 -040062 uint *varsz);
63static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid,
Henry Ptasinskia9533e72010-09-08 21:04:42 -070064 void *sdh);
Jason Cooper7cc4a4c2010-09-14 09:45:30 -040065static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype,
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -070066 u32 savewin, uint *origidx, void *regs);
Jason Cooper7cc4a4c2010-09-14 09:45:30 -040067static void si_nvram_process(si_info_t *sii, char *pvars);
Henry Ptasinskia9533e72010-09-08 21:04:42 -070068
69/* dev path concatenation util */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -040070static char *si_devpathvar(si_t *sih, char *var, int len, const char *name);
71static bool _si_clkctl_cc(si_info_t *sii, uint mode);
72static bool si_ispcie(si_info_t *sii);
Jason Cooperb4f790e2010-10-11 10:02:58 -040073static uint socram_banksize(si_info_t *sii, sbsocramregs_t *r,
Greg Kroah-Hartman36ef9a12010-10-05 10:02:49 -070074 u8 idx, u8 mtype);
Henry Ptasinskia9533e72010-09-08 21:04:42 -070075
76/* global variable to indicate reservation/release of gpio's */
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -070077static u32 si_gpioreservation;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070078
Henry Ptasinskia9533e72010-09-08 21:04:42 -070079/*
80 * Allocate a si handle.
81 * devid - pci device id (used to determine chip#)
82 * osh - opaque OS handle
83 * regs - virtual address of initial core registers
84 * bustype - pci/sb/sdio/etc
85 * vars - pointer to a pointer area for "environment" variables
86 * varsz - pointer to int to return the size of the vars
87 */
Brett Rudleye69284f2010-11-16 15:45:48 -080088si_t *si_attach(uint devid, struct osl_info *osh, void *regs, uint bustype,
89 void *sdh, char **vars, uint *varsz)
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -070090{
Henry Ptasinskia9533e72010-09-08 21:04:42 -070091 si_info_t *sii;
92
93 /* alloc si_info_t */
mike.rapoport@gmail.com5fcc1fc2010-10-13 00:09:10 +020094 sii = kmalloc(sizeof(si_info_t), GFP_ATOMIC);
Jason Cooperca8c1e52010-09-14 09:45:33 -040095 if (sii == NULL) {
mike.rapoport@gmail.com97e17d02010-10-13 00:09:09 +020096 SI_ERROR(("si_attach: malloc failed!\n"));
Jason Cooper90ea2292010-09-14 09:45:32 -040097 return NULL;
Henry Ptasinskia9533e72010-09-08 21:04:42 -070098 }
99
100 if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) ==
101 NULL) {
mike.rapoport@gmail.com182acb32010-10-13 00:09:12 +0200102 kfree(sii);
Jason Cooper90ea2292010-09-14 09:45:32 -0400103 return NULL;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700104 }
105 sii->vars = vars ? *vars : NULL;
106 sii->varsz = varsz ? *varsz : 0;
107
108 return (si_t *) sii;
109}
110
111/* global kernel resource */
112static si_info_t ksii;
113
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700114static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid,
115 void *sdh)
116{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700117
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700118#ifndef BRCM_FULLMAC
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700119 /* kludge to enable the clock on the 4306 which lacks a slowclock */
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800120 if (bustype == PCI_BUS && !si_ispcie(sii))
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700121 si_clkctl_xtal(&sii->pub, XTAL | PLL, ON);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700122#endif
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700123
124#if defined(BCMSDIO)
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800125 if (bustype == SDIO_BUS) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700126 int err;
Greg Kroah-Hartman36ef9a12010-10-05 10:02:49 -0700127 u8 clkset;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700128
129 /* Try forcing SDIO core to do ALPAvail request only */
130 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
131 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
132 clkset, &err);
133 if (!err) {
Greg Kroah-Hartman36ef9a12010-10-05 10:02:49 -0700134 u8 clkval;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700135
136 /* If register supported, wait for ALPAvail and then force ALP */
137 clkval =
138 bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
139 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
140 if ((clkval & ~SBSDIO_AVBITS) == clkset) {
141 SPINWAIT(((clkval =
142 bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
143 SBSDIO_FUNC1_CHIPCLKCSR,
144 NULL)),
145 !SBSDIO_ALPAV(clkval)),
146 PMU_MAX_TRANSITION_DLY);
147 if (!SBSDIO_ALPAV(clkval)) {
148 SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n", clkval));
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700149 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700150 }
151 clkset =
152 SBSDIO_FORCE_HW_CLKREQ_OFF |
153 SBSDIO_FORCE_ALP;
154 bcmsdh_cfg_write(sdh, SDIO_FUNC_1,
155 SBSDIO_FUNC1_CHIPCLKCSR,
156 clkset, &err);
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +0200157 udelay(65);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700158 }
159 }
160
161 /* Also, disable the extra SDIO pull-ups */
162 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0,
163 NULL);
164 }
165#endif /* defined(BCMSDIO) */
166
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700167 return true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700168}
169
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700170static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype,
171 u32 savewin, uint *origidx, void *regs)
172{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700173 bool pci, pcie;
174 uint i;
175 uint pciidx, pcieidx, pcirev, pcierev;
176
177 cc = si_setcoreidx(&sii->pub, SI_CC_IDX);
Greg Kroah-Hartmanc03b63c2010-10-08 11:20:01 -0700178 ASSERT(cc);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700179
180 /* get chipcommon rev */
181 sii->pub.ccrev = (int)si_corerev(&sii->pub);
182
183 /* get chipcommon chipstatus */
184 if (sii->pub.ccrev >= 11)
185 sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus);
186
187 /* get chipcommon capabilites */
188 sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities);
189 /* get chipcommon extended capabilities */
190
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700191#ifndef BRCM_FULLMAC
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700192 if (sii->pub.ccrev >= 35)
193 sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700194#endif
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700195 /* get pmu rev and caps */
196 if (sii->pub.cccaps & CC_CAP_PMU) {
197 sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities);
198 sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK;
199 }
200
201 /*
202 SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n",
203 sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev,
204 sii->pub.pmucaps));
205 */
206
207 /* figure out bus/orignal core idx */
208 sii->pub.buscoretype = NODEV_CORE_ID;
209 sii->pub.buscorerev = NOREV;
210 sii->pub.buscoreidx = BADIDX;
211
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700212 pci = pcie = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700213 pcirev = pcierev = NOREV;
214 pciidx = pcieidx = BADIDX;
215
216 for (i = 0; i < sii->numcores; i++) {
217 uint cid, crev;
218
219 si_setcoreidx(&sii->pub, i);
220 cid = si_coreid(&sii->pub);
221 crev = si_corerev(&sii->pub);
222
223 /* Display cores found */
224 SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n",
225 i, cid, crev, sii->coresba[i], sii->regs[i]));
226
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800227 if (bustype == PCI_BUS) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700228 if (cid == PCI_CORE_ID) {
229 pciidx = i;
230 pcirev = crev;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700231 pci = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700232 } else if (cid == PCIE_CORE_ID) {
233 pcieidx = i;
234 pcierev = crev;
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700235 pcie = true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700236 }
237 }
238#ifdef BCMSDIO
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800239 else if (((bustype == SDIO_BUS) ||
240 (bustype == SPI_BUS)) &&
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700241 ((cid == PCMCIA_CORE_ID) || (cid == SDIOD_CORE_ID))) {
242 sii->pub.buscorerev = crev;
243 sii->pub.buscoretype = cid;
244 sii->pub.buscoreidx = i;
245 }
246#endif /* BCMSDIO */
247
248 /* find the core idx before entering this func. */
249 if ((savewin && (savewin == sii->coresba[i])) ||
250 (regs == sii->regs[i]))
251 *origidx = i;
252 }
253
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700254#ifdef BRCM_FULLMAC
255 SI_MSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx,
256 sii->pub.buscoretype, sii->pub.buscorerev));
257
258 /* Make sure any on-chip ARM is off (in case strapping is wrong),
259 * or downloaded code was
260 * already running.
261 */
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800262 if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) {
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700263 if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) ||
264 si_setcore(&sii->pub, ARMCM3_CORE_ID, 0))
265 si_core_disable(&sii->pub, 0);
266 }
267#else
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700268 if (pci && pcie) {
269 if (si_ispcie(sii))
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700270 pci = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700271 else
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700272 pcie = false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700273 }
274 if (pci) {
275 sii->pub.buscoretype = PCI_CORE_ID;
276 sii->pub.buscorerev = pcirev;
277 sii->pub.buscoreidx = pciidx;
278 } else if (pcie) {
279 sii->pub.buscoretype = PCIE_CORE_ID;
280 sii->pub.buscorerev = pcierev;
281 sii->pub.buscoreidx = pcieidx;
282 }
283
284 SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx,
285 sii->pub.buscoretype, sii->pub.buscorerev));
286
287 /* fixup necessary chip/core configurations */
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800288 if (sii->pub.bustype == PCI_BUS) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700289 if (SI_FAST(sii)) {
Jason Cooperca8c1e52010-09-14 09:45:33 -0400290 if (!sii->pch) {
Greg Kroah-Hartmanc03b63c2010-10-08 11:20:01 -0700291 sii->pch = (void *)pcicore_init(
Jason Cooperca8c1e52010-09-14 09:45:33 -0400292 &sii->pub, sii->osh,
293 (void *)PCIEREGS(sii));
294 if (sii->pch == NULL)
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700295 return false;
Jason Cooperca8c1e52010-09-14 09:45:33 -0400296 }
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700297 }
298 if (si_pci_fixcfg(&sii->pub)) {
299 SI_ERROR(("si_doattach: sb_pci_fixcfg failed\n"));
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700300 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700301 }
302 }
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700303#endif
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700304 /* return to the original core */
305 si_setcoreidx(&sii->pub, *origidx);
306
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700307 return true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700308}
309
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700310static __used void si_nvram_process(si_info_t *sii, char *pvars)
Jason Coopera2627bc2010-09-14 09:45:31 -0400311{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700312 uint w = 0;
313
314 /* get boardtype and boardrev */
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800315 switch (sii->pub.bustype) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700316 case PCI_BUS:
317 /* do a pci config read to get subsystem id and subvendor id */
Brett Rudley57d8cd22010-11-22 16:58:52 -0800318 pci_read_config_dword(sii->osh->pdev, PCI_CFG_SVID, &w);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700319 /* Let nvram variables override subsystem Vend/ID */
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700320 sii->pub.boardvendor = (u16)si_getdevpathintvar(&sii->pub,
Jason Cooperca8c1e52010-09-14 09:45:33 -0400321 "boardvendor");
322 if (sii->pub.boardvendor == 0)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700323 sii->pub.boardvendor = w & 0xffff;
324 else
325 SI_ERROR(("Overriding boardvendor: 0x%x instead of 0x%x\n", sii->pub.boardvendor, w & 0xffff));
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -0700326 sii->pub.boardtype = (u16)si_getdevpathintvar(&sii->pub,
Jason Cooperca8c1e52010-09-14 09:45:33 -0400327 "boardtype");
328 if (sii->pub.boardtype == 0)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700329 sii->pub.boardtype = (w >> 16) & 0xffff;
330 else
331 SI_ERROR(("Overriding boardtype: 0x%x instead of 0x%x\n", sii->pub.boardtype, (w >> 16) & 0xffff));
332 break;
333
334#ifdef BCMSDIO
335 case SDIO_BUS:
336#endif
337 sii->pub.boardvendor = getintvar(pvars, "manfid");
338 sii->pub.boardtype = getintvar(pvars, "prodid");
339 break;
340
341#ifdef BCMSDIO
342 case SPI_BUS:
343 sii->pub.boardvendor = VENDOR_BROADCOM;
344 sii->pub.boardtype = SPI_BOARD;
345 break;
346#endif
347
348 case SI_BUS:
349 case JTAG_BUS:
350 sii->pub.boardvendor = VENDOR_BROADCOM;
Jason Cooperca8c1e52010-09-14 09:45:33 -0400351 sii->pub.boardtype = getintvar(pvars, "prodid");
352 if (pvars == NULL || (sii->pub.boardtype == 0)) {
353 sii->pub.boardtype = getintvar(NULL, "boardtype");
354 if (sii->pub.boardtype == 0)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700355 sii->pub.boardtype = 0xffff;
Jason Cooperca8c1e52010-09-14 09:45:33 -0400356 }
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700357 break;
358 }
359
360 if (sii->pub.boardtype == 0) {
361 SI_ERROR(("si_doattach: unknown board type\n"));
362 ASSERT(sii->pub.boardtype);
363 }
364
365 sii->pub.boardflags = getintvar(pvars, "boardflags");
366}
367
368/* this is will make Sonics calls directly, since Sonics is no longer supported in the Si abstraction */
369/* this has been customized for the bcm 4329 ONLY */
370#ifdef BCMSDIO
Brett Rudleye69284f2010-11-16 15:45:48 -0800371static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh,
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700372 void *regs, uint bustype, void *sdh,
373 char **vars, uint *varsz)
374{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700375 struct si_pub *sih = &sii->pub;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700376 u32 w, savewin;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700377 chipcregs_t *cc;
378 char *pvars = NULL;
379 uint origidx;
380
381 ASSERT(GOODREGS(regs));
382
Brett Rudley9249ede2010-11-30 20:09:49 -0800383 memset((unsigned char *) sii, 0, sizeof(si_info_t));
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700384
385 savewin = 0;
386
387 sih->buscoreidx = BADIDX;
388
389 sii->curmap = regs;
390 sii->sdh = sdh;
391 sii->osh = osh;
392
393 /* find Chipcommon address */
394 cc = (chipcregs_t *) sii->curmap;
395 sih->bustype = bustype;
396
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700397 /* bus/core/clk setup for register access */
398 if (!si_buscore_prep(sii, bustype, devid, sdh)) {
399 SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n",
400 bustype));
401 return NULL;
402 }
403
404 /* ChipID recognition.
405 * We assume we can read chipid at offset 0 from the regs arg.
406 * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon),
407 * some way of recognizing them needs to be added here.
408 */
409 w = R_REG(osh, &cc->chipid);
410 sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
411 /* Might as wll fill in chip id rev & pkg */
412 sih->chip = w & CID_ID_MASK;
413 sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
414 sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
415
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700416 if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) &&
417 (sih->chippkg != BCM4329_289PIN_PKG_ID))
418 sih->chippkg = BCM4329_182PIN_PKG_ID;
419
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700420 sih->issim = IS_SIM(sih->chippkg);
421
422 /* scan for cores */
423 /* SI_MSG(("Found chip type SB (0x%08x)\n", w)); */
424 sb_scan(&sii->pub, regs, devid);
425
426 /* no cores found, bail out */
427 if (sii->numcores == 0) {
428 SI_ERROR(("si_doattach: could not find any cores\n"));
429 return NULL;
430 }
431 /* bus/core/clk setup */
432 origidx = SI_CC_IDX;
433 if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) {
434 SI_ERROR(("si_doattach: si_buscore_setup failed\n"));
435 goto exit;
436 }
437
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700438#ifdef BRCM_FULLMAC
439 pvars = NULL;
440#else
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700441 /* Init nvram from flash if it exists */
442 nvram_init((void *)&(sii->pub));
443
444 /* Init nvram from sprom/otp if they exist */
445 if (srom_var_init
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800446 (&sii->pub, bustype, regs, sii->osh, vars, varsz)) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700447 SI_ERROR(("si_doattach: srom_var_init failed: bad srom\n"));
448 goto exit;
449 }
450 pvars = vars ? *vars : NULL;
451 si_nvram_process(sii, pvars);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700452#endif
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700453
454 /* === NVRAM, clock is ready === */
455
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700456#ifdef BRCM_FULLMAC
457 if (sii->pub.ccrev >= 20) {
458#endif
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700459 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
460 W_REG(osh, &cc->gpiopullup, 0);
461 W_REG(osh, &cc->gpiopulldown, 0);
462 sb_setcoreidx(sih, origidx);
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700463#ifdef BRCM_FULLMAC
464 }
465#endif
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700466
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700467#ifndef BRCM_FULLMAC
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700468 /* PMU specific initializations */
469 if (PMUCTL_ENAB(sih)) {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700470 u32 xtalfreq;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700471 si_pmu_init(sih, sii->osh);
472 si_pmu_chip_init(sih, sii->osh);
473 xtalfreq = getintvar(pvars, "xtalfreq");
474 /* If xtalfreq var not available, try to measure it */
475 if (xtalfreq == 0)
476 xtalfreq = si_pmu_measure_alpclk(sih, sii->osh);
477 si_pmu_pll_init(sih, sii->osh, xtalfreq);
478 si_pmu_res_init(sih, sii->osh);
479 si_pmu_swreg_init(sih, sii->osh);
480 }
481
482 /* setup the GPIO based LED powersave register */
Jason Cooperca8c1e52010-09-14 09:45:33 -0400483 w = getintvar(pvars, "leddc");
484 if (w == 0)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700485 w = DEFAULT_GPIOTIMERVAL;
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -0700486 sb_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, gpiotimerval), ~0, w);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700487
488#ifdef BCMDBG
489 /* clear any previous epidiag-induced target abort */
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700490 sb_taclear(sih, false);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700491#endif /* BCMDBG */
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700492#endif
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700493
Jason Cooper90ea2292010-09-14 09:45:32 -0400494 return sii;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700495
496 exit:
497 return NULL;
498}
499
500#else /* BCMSDIO */
Brett Rudleye69284f2010-11-16 15:45:48 -0800501static si_info_t *si_doattach(si_info_t *sii, uint devid, struct osl_info *osh,
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700502 void *regs, uint bustype, void *sdh,
503 char **vars, uint *varsz)
504{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700505 struct si_pub *sih = &sii->pub;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700506 u32 w, savewin;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700507 chipcregs_t *cc;
508 char *pvars = NULL;
509 uint origidx;
510
511 ASSERT(GOODREGS(regs));
512
Brett Rudley9249ede2010-11-30 20:09:49 -0800513 memset((unsigned char *) sii, 0, sizeof(si_info_t));
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700514
515 savewin = 0;
516
517 sih->buscoreidx = BADIDX;
518
519 sii->curmap = regs;
520 sii->sdh = sdh;
521 sii->osh = osh;
522
523 /* check to see if we are a si core mimic'ing a pci core */
Brett Rudley57d8cd22010-11-22 16:58:52 -0800524 if (bustype == PCI_BUS) {
525 pci_read_config_dword(sii->osh->pdev, PCI_SPROM_CONTROL, &w);
526 if (w == 0xffffffff) {
527 SI_ERROR(("%s: incoming bus is PCI but it's a lie, "
528 " switching to SI devid:0x%x\n",
529 __func__, devid));
530 bustype = SI_BUS;
531 }
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700532 }
533
534 /* find Chipcommon address */
535 if (bustype == PCI_BUS) {
Brett Rudley57d8cd22010-11-22 16:58:52 -0800536 pci_read_config_dword(sii->osh->pdev, PCI_BAR0_WIN, &savewin);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700537 if (!GOODCOREADDR(savewin, SI_ENUM_BASE))
538 savewin = SI_ENUM_BASE;
Brett Rudley57d8cd22010-11-22 16:58:52 -0800539 pci_write_config_dword(sii->osh->pdev, PCI_BAR0_WIN,
540 SI_ENUM_BASE);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700541 cc = (chipcregs_t *) regs;
542 } else {
543 cc = (chipcregs_t *) REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
544 }
545
546 sih->bustype = bustype;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700547
548 /* bus/core/clk setup for register access */
549 if (!si_buscore_prep(sii, bustype, devid, sdh)) {
550 SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n",
551 bustype));
552 return NULL;
553 }
554
555 /* ChipID recognition.
556 * We assume we can read chipid at offset 0 from the regs arg.
557 * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon),
558 * some way of recognizing them needs to be added here.
559 */
560 w = R_REG(osh, &cc->chipid);
561 sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
562 /* Might as wll fill in chip id rev & pkg */
563 sih->chip = w & CID_ID_MASK;
564 sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
565 sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
566
567 sih->issim = IS_SIM(sih->chippkg);
568
569 /* scan for cores */
570 if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) {
571 SI_MSG(("Found chip type AI (0x%08x)\n", w));
572 /* pass chipc address instead of original core base */
Greg Kroah-Hartmanc03b63c2010-10-08 11:20:01 -0700573 ai_scan(&sii->pub, (void *)cc, devid);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700574 } else {
575 SI_ERROR(("Found chip of unknown type (0x%08x)\n", w));
576 return NULL;
577 }
578 /* no cores found, bail out */
579 if (sii->numcores == 0) {
580 SI_ERROR(("si_doattach: could not find any cores\n"));
581 return NULL;
582 }
583 /* bus/core/clk setup */
584 origidx = SI_CC_IDX;
585 if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) {
586 SI_ERROR(("si_doattach: si_buscore_setup failed\n"));
587 goto exit;
588 }
589
590 /* assume current core is CC */
591 if ((sii->pub.ccrev == 0x25)
592 &&
593 ((CHIPID(sih->chip) == BCM43236_CHIP_ID
594 || CHIPID(sih->chip) == BCM43235_CHIP_ID
595 || CHIPID(sih->chip) == BCM43238_CHIP_ID)
596 && (CHIPREV(sii->pub.chiprev) <= 2))) {
597
598 if ((cc->chipstatus & CST43236_BP_CLK) != 0) {
599 uint clkdiv;
600 clkdiv = R_REG(osh, &cc->clkdiv);
601 /* otp_clk_div is even number, 120/14 < 9mhz */
602 clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT);
603 W_REG(osh, &cc->clkdiv, clkdiv);
604 SI_ERROR(("%s: set clkdiv to %x\n", __func__, clkdiv));
605 }
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +0200606 udelay(10);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700607 }
608
609 /* Init nvram from flash if it exists */
610 nvram_init((void *)&(sii->pub));
611
612 /* Init nvram from sprom/otp if they exist */
613 if (srom_var_init
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800614 (&sii->pub, bustype, regs, sii->osh, vars, varsz)) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700615 SI_ERROR(("si_doattach: srom_var_init failed: bad srom\n"));
616 goto exit;
617 }
618 pvars = vars ? *vars : NULL;
619 si_nvram_process(sii, pvars);
620
621 /* === NVRAM, clock is ready === */
622 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
623 W_REG(osh, &cc->gpiopullup, 0);
624 W_REG(osh, &cc->gpiopulldown, 0);
625 si_setcoreidx(sih, origidx);
626
627 /* PMU specific initializations */
628 if (PMUCTL_ENAB(sih)) {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700629 u32 xtalfreq;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700630 si_pmu_init(sih, sii->osh);
631 si_pmu_chip_init(sih, sii->osh);
632 xtalfreq = getintvar(pvars, "xtalfreq");
633 /* If xtalfreq var not available, try to measure it */
634 if (xtalfreq == 0)
635 xtalfreq = si_pmu_measure_alpclk(sih, sii->osh);
636 si_pmu_pll_init(sih, sii->osh, xtalfreq);
637 si_pmu_res_init(sih, sii->osh);
638 si_pmu_swreg_init(sih, sii->osh);
639 }
640
641 /* setup the GPIO based LED powersave register */
Jason Cooperca8c1e52010-09-14 09:45:33 -0400642 w = getintvar(pvars, "leddc");
643 if (w == 0)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700644 w = DEFAULT_GPIOTIMERVAL;
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -0700645 si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, gpiotimerval), ~0, w);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700646
647 if (PCIE(sii)) {
648 ASSERT(sii->pch != NULL);
649 pcicore_attach(sii->pch, pvars, SI_DOATTACH);
650 }
651
652 if ((CHIPID(sih->chip) == BCM43224_CHIP_ID) ||
653 (CHIPID(sih->chip) == BCM43421_CHIP_ID)) {
654 /* enable 12 mA drive strenth for 43224 and set chipControl register bit 15 */
655 if (CHIPREV(sih->chiprev) == 0) {
656 SI_MSG(("Applying 43224A0 WARs\n"));
657 si_corereg(sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -0700658 offsetof(chipcregs_t, chipcontrol),
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700659 CCTRL43224_GPIO_TOGGLE,
660 CCTRL43224_GPIO_TOGGLE);
661 si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE,
662 CCTRL_43224A0_12MA_LED_DRIVE);
663 }
664 if (CHIPREV(sih->chiprev) >= 1) {
665 SI_MSG(("Applying 43224B0+ WARs\n"));
666 si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE,
667 CCTRL_43224B0_12MA_LED_DRIVE);
668 }
669 }
670
671 if (CHIPID(sih->chip) == BCM4313_CHIP_ID) {
672 /* enable 12 mA drive strenth for 4313 and set chipControl register bit 1 */
673 SI_MSG(("Applying 4313 WARs\n"));
674 si_pmu_chipcontrol(sih, 0, CCTRL_4313_12MA_LED_DRIVE,
675 CCTRL_4313_12MA_LED_DRIVE);
676 }
677
678 if (CHIPID(sih->chip) == BCM4331_CHIP_ID) {
679 /* Enable Ext PA lines depending on chip package option */
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -0700680 si_chipcontrl_epa4331(sih, true);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700681 }
682
Jason Cooper90ea2292010-09-14 09:45:32 -0400683 return sii;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700684 exit:
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800685 if (sih->bustype == PCI_BUS) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700686 if (sii->pch)
687 pcicore_deinit(sii->pch);
688 sii->pch = NULL;
689 }
690
691 return NULL;
692}
693#endif /* BCMSDIO */
694
695/* may be called with core in reset */
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -0700696void si_detach(si_t *sih)
Jason Coopera2627bc2010-09-14 09:45:31 -0400697{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700698 si_info_t *sii;
699 uint idx;
700
701 struct si_pub *si_local = NULL;
702 bcopy(&sih, &si_local, sizeof(si_t **));
703
704 sii = SI_INFO(sih);
705
706 if (sii == NULL)
707 return;
708
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800709 if (sih->bustype == SI_BUS)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700710 for (idx = 0; idx < SI_MAXCORES; idx++)
711 if (sii->regs[idx]) {
712 REG_UNMAP(sii->regs[idx]);
713 sii->regs[idx] = NULL;
714 }
715
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700716#ifndef BRCM_FULLMAC
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700717 nvram_exit((void *)si_local); /* free up nvram buffers */
718
Brett Rudleyfa7a1db2010-11-23 15:30:02 -0800719 if (sih->bustype == PCI_BUS) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700720 if (sii->pch)
721 pcicore_deinit(sii->pch);
722 sii->pch = NULL;
723 }
Henry Ptasinskicf2b4482010-09-20 22:33:12 -0700724#endif
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700725#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS)
726 if (sii != &ksii)
727#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */
mike.rapoport@gmail.com182acb32010-10-13 00:09:12 +0200728 kfree(sii);
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700729}
730
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400731void *si_osh(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700732{
733 si_info_t *sii;
734
735 sii = SI_INFO(sih);
736 return sii->osh;
737}
738
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700739/* register driver interrupt disabling and restoring callback functions */
740void
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400741si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn,
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700742 void *intrsenabled_fn, void *intr_arg)
743{
744 si_info_t *sii;
745
746 sii = SI_INFO(sih);
747 sii->intr_arg = intr_arg;
748 sii->intrsoff_fn = (si_intrsoff_t) intrsoff_fn;
749 sii->intrsrestore_fn = (si_intrsrestore_t) intrsrestore_fn;
750 sii->intrsenabled_fn = (si_intrsenabled_t) intrsenabled_fn;
751 /* save current core id. when this function called, the current core
752 * must be the core which provides driver functions(il, et, wl, etc.)
753 */
754 sii->dev_coreid = sii->coreid[sii->curidx];
755}
756
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400757void si_deregister_intr_callback(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700758{
759 si_info_t *sii;
760
761 sii = SI_INFO(sih);
762 sii->intrsoff_fn = NULL;
763}
764
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400765uint si_flag(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700766{
767 if (CHIPTYPE(sih->socitype) == SOCI_AI)
768 return ai_flag(sih);
769 else {
770 ASSERT(0);
771 return 0;
772 }
773}
774
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400775void si_setint(si_t *sih, int siflag)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700776{
777 if (CHIPTYPE(sih->socitype) == SOCI_AI)
778 ai_setint(sih, siflag);
779 else
780 ASSERT(0);
781}
782
783#ifndef BCMSDIO
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400784uint si_coreid(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700785{
786 si_info_t *sii;
787
788 sii = SI_INFO(sih);
789 return sii->coreid[sii->curidx];
790}
791#endif
792
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400793uint si_coreidx(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700794{
795 si_info_t *sii;
796
797 sii = SI_INFO(sih);
798 return sii->curidx;
799}
800
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400801bool si_backplane64(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700802{
Jason Cooper90ea2292010-09-14 09:45:32 -0400803 return (sih->cccaps & CC_CAP_BKPLN64) != 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700804}
805
806#ifndef BCMSDIO
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400807uint si_corerev(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700808{
809 if (CHIPTYPE(sih->socitype) == SOCI_AI)
810 return ai_corerev(sih);
811 else {
812 ASSERT(0);
813 return 0;
814 }
815}
816#endif
817
818/* return index of coreid or BADIDX if not found */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400819uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700820{
821 si_info_t *sii;
822 uint found;
823 uint i;
824
825 sii = SI_INFO(sih);
826
827 found = 0;
828
829 for (i = 0; i < sii->numcores; i++)
830 if (sii->coreid[i] == coreid) {
831 if (found == coreunit)
Jason Cooper90ea2292010-09-14 09:45:32 -0400832 return i;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700833 found++;
834 }
835
Jason Cooper90ea2292010-09-14 09:45:32 -0400836 return BADIDX;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700837}
838
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700839/*
840 * This function changes logical "focus" to the indicated core;
841 * must be called with interrupts off.
842 * Moreover, callers should keep interrupts off during switching out of and back to d11 core
843 */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400844void *si_setcore(si_t *sih, uint coreid, uint coreunit)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700845{
846 uint idx;
847
848 idx = si_findcoreidx(sih, coreid, coreunit);
849 if (!GOODIDX(idx))
Jason Cooper90ea2292010-09-14 09:45:32 -0400850 return NULL;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700851
852 if (CHIPTYPE(sih->socitype) == SOCI_AI)
853 return ai_setcoreidx(sih, idx);
854 else {
855#ifdef BCMSDIO
856 return sb_setcoreidx(sih, idx);
857#else
858 ASSERT(0);
859 return NULL;
860#endif
861 }
862}
863
864#ifndef BCMSDIO
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400865void *si_setcoreidx(si_t *sih, uint coreidx)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700866{
867 if (CHIPTYPE(sih->socitype) == SOCI_AI)
868 return ai_setcoreidx(sih, coreidx);
869 else {
870 ASSERT(0);
871 return NULL;
872 }
873}
874#endif
875
876/* Turn off interrupt as required by sb_setcore, before switch core */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400877void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700878{
879 void *cc;
880 si_info_t *sii;
881
882 sii = SI_INFO(sih);
883
884 if (SI_FAST(sii)) {
885 /* Overloading the origidx variable to remember the coreid,
886 * this works because the core ids cannot be confused with
887 * core indices.
888 */
889 *origidx = coreid;
890 if (coreid == CC_CORE_ID)
891 return (void *)CCREGS_FAST(sii);
892 else if (coreid == sih->buscoretype)
893 return (void *)PCIEREGS(sii);
894 }
895 INTR_OFF(sii, *intr_val);
896 *origidx = sii->curidx;
897 cc = si_setcore(sih, coreid, 0);
898 ASSERT(cc != NULL);
899
900 return cc;
901}
902
903/* restore coreidx and restore interrupt */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400904void si_restore_core(si_t *sih, uint coreid, uint intr_val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700905{
906 si_info_t *sii;
907
908 sii = SI_INFO(sih);
909 if (SI_FAST(sii)
910 && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype)))
911 return;
912
913 si_setcoreidx(sih, coreid);
914 INTR_RESTORE(sii, intr_val);
915}
916
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700917u32 si_core_cflags(si_t *sih, u32 mask, u32 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700918{
919 if (CHIPTYPE(sih->socitype) == SOCI_AI)
920 return ai_core_cflags(sih, mask, val);
921 else {
922 ASSERT(0);
923 return 0;
924 }
925}
926
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700927u32 si_core_sflags(si_t *sih, u32 mask, u32 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700928{
929 if (CHIPTYPE(sih->socitype) == SOCI_AI)
930 return ai_core_sflags(sih, mask, val);
931 else {
932 ASSERT(0);
933 return 0;
934 }
935}
936
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400937bool si_iscoreup(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700938{
939 if (CHIPTYPE(sih->socitype) == SOCI_AI)
940 return ai_iscoreup(sih);
941 else {
942#ifdef BCMSDIO
943 return sb_iscoreup(sih);
944#else
945 ASSERT(0);
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -0700946 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700947#endif
948 }
949}
950
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700951void si_write_wrapperreg(si_t *sih, u32 offset, u32 val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700952{
953 /* only for 4319, no requirement for SOCI_SB */
954 if (CHIPTYPE(sih->socitype) == SOCI_AI) {
955 ai_write_wrap_reg(sih, offset, val);
956 }
957}
958
Jason Cooper7cc4a4c2010-09-14 09:45:30 -0400959uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700960{
961
962 if (CHIPTYPE(sih->socitype) == SOCI_AI)
963 return ai_corereg(sih, coreidx, regoff, mask, val);
964 else {
965#ifdef BCMSDIO
966 return sb_corereg(sih, coreidx, regoff, mask, val);
967#else
968 ASSERT(0);
969 return 0;
970#endif
971 }
972}
973
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700974void si_core_disable(si_t *sih, u32 bits)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700975{
976
977 if (CHIPTYPE(sih->socitype) == SOCI_AI)
978 ai_core_disable(sih, bits);
979#ifdef BCMSDIO
980 else
981 sb_core_disable(sih, bits);
982#endif
983}
984
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -0700985void si_core_reset(si_t *sih, u32 bits, u32 resetbits)
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700986{
987 if (CHIPTYPE(sih->socitype) == SOCI_AI)
988 ai_core_reset(sih, bits, resetbits);
989#ifdef BCMSDIO
990 else
991 sb_core_reset(sih, bits, resetbits);
992#endif
993}
994
Jason Cooperb4f790e2010-10-11 10:02:58 -0400995u32 si_alp_clock(si_t *sih)
Jason Coopera2627bc2010-09-14 09:45:31 -0400996{
Henry Ptasinskia9533e72010-09-08 21:04:42 -0700997 if (PMUCTL_ENAB(sih))
998 return si_pmu_alp_clock(sih, si_osh(sih));
999
1000 return ALP_CLOCK;
1001}
1002
Jason Cooperb4f790e2010-10-11 10:02:58 -04001003u32 si_ilp_clock(si_t *sih)
Jason Coopera2627bc2010-09-14 09:45:31 -04001004{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001005 if (PMUCTL_ENAB(sih))
1006 return si_pmu_ilp_clock(sih, si_osh(sih));
1007
1008 return ILP_CLOCK;
1009}
1010
1011/* set chip watchdog reset timer to fire in 'ticks' */
Henry Ptasinskicf2b4482010-09-20 22:33:12 -07001012#ifdef BRCM_FULLMAC
1013void
1014si_watchdog(si_t *sih, uint ticks)
1015{
1016 if (PMUCTL_ENAB(sih)) {
1017
1018 if ((sih->chip == BCM4319_CHIP_ID) && (sih->chiprev == 0) &&
1019 (ticks != 0)) {
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07001020 si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t,
Henry Ptasinskicf2b4482010-09-20 22:33:12 -07001021 clk_ctl_st), ~0, 0x2);
1022 si_setcore(sih, USB20D_CORE_ID, 0);
1023 si_core_disable(sih, 1);
1024 si_setcore(sih, CC_CORE_ID, 0);
1025 }
1026
1027 if (ticks == 1)
1028 ticks = 2;
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07001029 si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, pmuwatchdog),
Henry Ptasinskicf2b4482010-09-20 22:33:12 -07001030 ~0, ticks);
1031 } else {
1032 /* instant NMI */
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07001033 si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, watchdog),
Henry Ptasinskicf2b4482010-09-20 22:33:12 -07001034 ~0, ticks);
1035 }
1036}
1037#else
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001038void si_watchdog(si_t *sih, uint ticks)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001039{
1040 uint nb, maxt;
1041
1042 if (PMUCTL_ENAB(sih)) {
1043
1044 if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) &&
1045 (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) {
1046 si_corereg(sih, SI_CC_IDX,
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07001047 offsetof(chipcregs_t, clk_ctl_st), ~0, 0x2);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001048 si_setcore(sih, USB20D_CORE_ID, 0);
1049 si_core_disable(sih, 1);
1050 si_setcore(sih, CC_CORE_ID, 0);
1051 }
1052
1053 nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24);
1054 /* The mips compiler uses the sllv instruction,
1055 * so we specially handle the 32-bit case.
1056 */
1057 if (nb == 32)
1058 maxt = 0xffffffff;
1059 else
1060 maxt = ((1 << nb) - 1);
1061
1062 if (ticks == 1)
1063 ticks = 2;
1064 else if (ticks > maxt)
1065 ticks = maxt;
1066
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07001067 si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, pmuwatchdog),
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001068 ~0, ticks);
1069 } else {
1070 /* make sure we come up in fast clock mode; or if clearing, clear clock */
1071 si_clkctl_cc(sih, ticks ? CLK_FAST : CLK_DYNAMIC);
1072 maxt = (1 << 28) - 1;
1073 if (ticks > maxt)
1074 ticks = maxt;
1075
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07001076 si_corereg(sih, SI_CC_IDX, offsetof(chipcregs_t, watchdog), ~0,
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001077 ticks);
1078 }
1079}
Henry Ptasinskicf2b4482010-09-20 22:33:12 -07001080#endif
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001081
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001082/* return the slow clock source - LPO, XTAL, or PCI */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001083static uint si_slowclk_src(si_info_t *sii)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001084{
1085 chipcregs_t *cc;
Brett Rudley57d8cd22010-11-22 16:58:52 -08001086 u32 val;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001087
1088 ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID);
1089
1090 if (sii->pub.ccrev < 6) {
Brett Rudleyfa7a1db2010-11-23 15:30:02 -08001091 if (sii->pub.bustype == PCI_BUS) {
Brett Rudley57d8cd22010-11-22 16:58:52 -08001092 pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUT,
1093 &val);
1094 if (val & PCI_CFG_GPIO_SCS)
1095 return SCC_SS_PCI;
1096 }
1097 return SCC_SS_XTAL;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001098 } else if (sii->pub.ccrev < 10) {
1099 cc = (chipcregs_t *) si_setcoreidx(&sii->pub, sii->curidx);
Jason Cooper90ea2292010-09-14 09:45:32 -04001100 return R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001101 } else /* Insta-clock */
Jason Cooper90ea2292010-09-14 09:45:32 -04001102 return SCC_SS_XTAL;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001103}
1104
1105/* return the ILP (slowclock) min or max frequency */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001106static uint si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001107{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001108 u32 slowclk;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001109 uint div;
1110
1111 ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID);
1112
1113 /* shouldn't be here unless we've established the chip has dynamic clk control */
1114 ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL);
1115
1116 slowclk = si_slowclk_src(sii);
1117 if (sii->pub.ccrev < 6) {
1118 if (slowclk == SCC_SS_PCI)
Jason Cooper90ea2292010-09-14 09:45:32 -04001119 return max_freq ? (PCIMAXFREQ / 64)
1120 : (PCIMINFREQ / 64);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001121 else
Jason Cooper90ea2292010-09-14 09:45:32 -04001122 return max_freq ? (XTALMAXFREQ / 32)
1123 : (XTALMINFREQ / 32);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001124 } else if (sii->pub.ccrev < 10) {
1125 div = 4 *
1126 (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >>
1127 SCC_CD_SHIFT) + 1);
1128 if (slowclk == SCC_SS_LPO)
Jason Cooper90ea2292010-09-14 09:45:32 -04001129 return max_freq ? LPOMAXFREQ : LPOMINFREQ;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001130 else if (slowclk == SCC_SS_XTAL)
Jason Cooper90ea2292010-09-14 09:45:32 -04001131 return max_freq ? (XTALMAXFREQ / div)
1132 : (XTALMINFREQ / div);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001133 else if (slowclk == SCC_SS_PCI)
Jason Cooper90ea2292010-09-14 09:45:32 -04001134 return max_freq ? (PCIMAXFREQ / div)
1135 : (PCIMINFREQ / div);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001136 else
1137 ASSERT(0);
1138 } else {
1139 /* Chipc rev 10 is InstaClock */
1140 div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT;
1141 div = 4 * (div + 1);
Jason Cooper90ea2292010-09-14 09:45:32 -04001142 return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001143 }
Jason Cooper90ea2292010-09-14 09:45:32 -04001144 return 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001145}
1146
Jason Cooperb4f790e2010-10-11 10:02:58 -04001147static void si_clkctl_setdelay(si_info_t *sii, void *chipcregs)
Jason Coopera2627bc2010-09-14 09:45:31 -04001148{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001149 chipcregs_t *cc = (chipcregs_t *) chipcregs;
1150 uint slowmaxfreq, pll_delay, slowclk;
1151 uint pll_on_delay, fref_sel_delay;
1152
1153 pll_delay = PLL_DELAY;
1154
1155 /* If the slow clock is not sourced by the xtal then add the xtal_on_delay
1156 * since the xtal will also be powered down by dynamic clk control logic.
1157 */
1158
1159 slowclk = si_slowclk_src(sii);
1160 if (slowclk != SCC_SS_XTAL)
1161 pll_delay += XTAL_ON_DELAY;
1162
1163 /* Starting with 4318 it is ILP that is used for the delays */
1164 slowmaxfreq =
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001165 si_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? false : true, cc);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001166
1167 pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
1168 fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
1169
1170 W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay);
1171 W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay);
1172}
1173
1174/* initialize power control delay registers */
Jason Cooperb4f790e2010-10-11 10:02:58 -04001175void si_clkctl_init(si_t *sih)
Jason Coopera2627bc2010-09-14 09:45:31 -04001176{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001177 si_info_t *sii;
1178 uint origidx = 0;
1179 chipcregs_t *cc;
1180 bool fast;
1181
1182 if (!CCCTL_ENAB(sih))
1183 return;
1184
1185 sii = SI_INFO(sih);
1186 fast = SI_FAST(sii);
1187 if (!fast) {
1188 origidx = sii->curidx;
Jason Cooperca8c1e52010-09-14 09:45:33 -04001189 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
1190 if (cc == NULL)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001191 return;
Jason Cooperca8c1e52010-09-14 09:45:33 -04001192 } else {
1193 cc = (chipcregs_t *) CCREGS_FAST(sii);
1194 if (cc == NULL)
1195 return;
1196 }
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001197 ASSERT(cc != NULL);
1198
1199 /* set all Instaclk chip ILP to 1 MHz */
1200 if (sih->ccrev >= 10)
1201 SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK,
1202 (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
1203
Greg Kroah-Hartmanc03b63c2010-10-08 11:20:01 -07001204 si_clkctl_setdelay(sii, (void *)cc);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001205
1206 if (!fast)
1207 si_setcoreidx(sih, origidx);
1208}
1209
1210/* return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */
Jason Cooperb4f790e2010-10-11 10:02:58 -04001211u16 si_clkctl_fast_pwrup_delay(si_t *sih)
Jason Coopera2627bc2010-09-14 09:45:31 -04001212{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001213 si_info_t *sii;
1214 uint origidx = 0;
1215 chipcregs_t *cc;
1216 uint slowminfreq;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001217 u16 fpdelay;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001218 uint intr_val = 0;
1219 bool fast;
1220
1221 sii = SI_INFO(sih);
1222 if (PMUCTL_ENAB(sih)) {
1223 INTR_OFF(sii, intr_val);
1224 fpdelay = si_pmu_fast_pwrup_delay(sih, sii->osh);
1225 INTR_RESTORE(sii, intr_val);
1226 return fpdelay;
1227 }
1228
1229 if (!CCCTL_ENAB(sih))
1230 return 0;
1231
1232 fast = SI_FAST(sii);
1233 fpdelay = 0;
1234 if (!fast) {
1235 origidx = sii->curidx;
1236 INTR_OFF(sii, intr_val);
Jason Cooperca8c1e52010-09-14 09:45:33 -04001237 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
1238 if (cc == NULL)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001239 goto done;
Jason Cooperca8c1e52010-09-14 09:45:33 -04001240 } else {
1241 cc = (chipcregs_t *) CCREGS_FAST(sii);
1242 if (cc == NULL)
1243 goto done;
1244 }
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001245 ASSERT(cc != NULL);
1246
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001247 slowminfreq = si_slowclk_freq(sii, false, cc);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001248 fpdelay = (((R_REG(sii->osh, &cc->pll_on_delay) + 2) * 1000000) +
1249 (slowminfreq - 1)) / slowminfreq;
1250
1251 done:
1252 if (!fast) {
1253 si_setcoreidx(sih, origidx);
1254 INTR_RESTORE(sii, intr_val);
1255 }
1256 return fpdelay;
1257}
1258
1259/* turn primary xtal and/or pll off/on */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001260int si_clkctl_xtal(si_t *sih, uint what, bool on)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001261{
1262 si_info_t *sii;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001263 u32 in, out, outen;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001264
1265 sii = SI_INFO(sih);
1266
Brett Rudleyfa7a1db2010-11-23 15:30:02 -08001267 switch (sih->bustype) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001268
1269#ifdef BCMSDIO
1270 case SDIO_BUS:
Jason Cooper90ea2292010-09-14 09:45:32 -04001271 return -1;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001272#endif /* BCMSDIO */
1273
1274 case PCI_BUS:
1275 /* pcie core doesn't have any mapping to control the xtal pu */
1276 if (PCIE(sii))
1277 return -1;
1278
Brett Rudley57d8cd22010-11-22 16:58:52 -08001279 pci_read_config_dword(sii->osh->pdev, PCI_GPIO_IN, &in);
1280 pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUT, &out);
1281 pci_read_config_dword(sii->osh->pdev, PCI_GPIO_OUTEN, &outen);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001282
1283 /*
1284 * Avoid glitching the clock if GPRS is already using it.
1285 * We can't actually read the state of the PLLPD so we infer it
1286 * by the value of XTAL_PU which *is* readable via gpioin.
1287 */
1288 if (on && (in & PCI_CFG_GPIO_XTAL))
Jason Cooper90ea2292010-09-14 09:45:32 -04001289 return 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001290
1291 if (what & XTAL)
1292 outen |= PCI_CFG_GPIO_XTAL;
1293 if (what & PLL)
1294 outen |= PCI_CFG_GPIO_PLL;
1295
1296 if (on) {
1297 /* turn primary xtal on */
1298 if (what & XTAL) {
1299 out |= PCI_CFG_GPIO_XTAL;
1300 if (what & PLL)
1301 out |= PCI_CFG_GPIO_PLL;
Brett Rudley57d8cd22010-11-22 16:58:52 -08001302 pci_write_config_dword(sii->osh->pdev,
1303 PCI_GPIO_OUT, out);
1304 pci_write_config_dword(sii->osh->pdev,
1305 PCI_GPIO_OUTEN, outen);
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +02001306 udelay(XTAL_ON_DELAY);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001307 }
1308
1309 /* turn pll on */
1310 if (what & PLL) {
1311 out &= ~PCI_CFG_GPIO_PLL;
Brett Rudley57d8cd22010-11-22 16:58:52 -08001312 pci_write_config_dword(sii->osh->pdev,
1313 PCI_GPIO_OUT, out);
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +02001314 mdelay(2);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001315 }
1316 } else {
1317 if (what & XTAL)
1318 out &= ~PCI_CFG_GPIO_XTAL;
1319 if (what & PLL)
1320 out |= PCI_CFG_GPIO_PLL;
Brett Rudley57d8cd22010-11-22 16:58:52 -08001321 pci_write_config_dword(sii->osh->pdev,
1322 PCI_GPIO_OUT, out);
1323 pci_write_config_dword(sii->osh->pdev,
1324 PCI_GPIO_OUTEN, outen);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001325 }
1326
1327 default:
Jason Cooper90ea2292010-09-14 09:45:32 -04001328 return -1;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001329 }
1330
Jason Cooper90ea2292010-09-14 09:45:32 -04001331 return 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001332}
1333
1334/*
1335 * clock control policy function throught chipcommon
1336 *
1337 * set dynamic clk control mode (forceslow, forcefast, dynamic)
1338 * returns true if we are forcing fast clock
1339 * this is a wrapper over the next internal function
1340 * to allow flexible policy settings for outside caller
1341 */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001342bool si_clkctl_cc(si_t *sih, uint mode)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001343{
1344 si_info_t *sii;
1345
1346 sii = SI_INFO(sih);
1347
1348 /* chipcommon cores prior to rev6 don't support dynamic clock control */
1349 if (sih->ccrev < 6)
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001350 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001351
1352 if (PCI_FORCEHT(sii))
Jason Cooper90ea2292010-09-14 09:45:32 -04001353 return mode == CLK_FAST;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001354
1355 return _si_clkctl_cc(sii, mode);
1356}
1357
1358/* clk control mechanism through chipcommon, no policy checking */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001359static bool _si_clkctl_cc(si_info_t *sii, uint mode)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001360{
1361 uint origidx = 0;
1362 chipcregs_t *cc;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001363 u32 scc;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001364 uint intr_val = 0;
1365 bool fast = SI_FAST(sii);
1366
1367 /* chipcommon cores prior to rev6 don't support dynamic clock control */
1368 if (sii->pub.ccrev < 6)
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001369 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001370
1371 /* Chips with ccrev 10 are EOL and they don't have SYCC_HR which we use below */
1372 ASSERT(sii->pub.ccrev != 10);
1373
1374 if (!fast) {
1375 INTR_OFF(sii, intr_val);
1376 origidx = sii->curidx;
1377
Brett Rudleyfa7a1db2010-11-23 15:30:02 -08001378 if ((sii->pub.bustype == SI_BUS) &&
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001379 si_setcore(&sii->pub, MIPS33_CORE_ID, 0) &&
1380 (si_corerev(&sii->pub) <= 7) && (sii->pub.ccrev >= 10))
1381 goto done;
1382
1383 cc = (chipcregs_t *) si_setcore(&sii->pub, CC_CORE_ID, 0);
Jason Cooperca8c1e52010-09-14 09:45:33 -04001384 } else {
1385 cc = (chipcregs_t *) CCREGS_FAST(sii);
1386 if (cc == NULL)
1387 goto done;
1388 }
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001389 ASSERT(cc != NULL);
1390
1391 if (!CCCTL_ENAB(&sii->pub) && (sii->pub.ccrev < 20))
1392 goto done;
1393
1394 switch (mode) {
1395 case CLK_FAST: /* FORCEHT, fast (pll) clock */
1396 if (sii->pub.ccrev < 10) {
1397 /* don't forget to force xtal back on before we clear SCC_DYN_XTAL.. */
1398 si_clkctl_xtal(&sii->pub, XTAL, ON);
1399 SET_REG(sii->osh, &cc->slow_clk_ctl,
1400 (SCC_XC | SCC_FS | SCC_IP), SCC_IP);
1401 } else if (sii->pub.ccrev < 20) {
1402 OR_REG(sii->osh, &cc->system_clk_ctl, SYCC_HR);
1403 } else {
1404 OR_REG(sii->osh, &cc->clk_ctl_st, CCS_FORCEHT);
1405 }
1406
1407 /* wait for the PLL */
1408 if (PMUCTL_ENAB(&sii->pub)) {
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001409 u32 htavail = CCS_HTAVAIL;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001410 SPINWAIT(((R_REG(sii->osh, &cc->clk_ctl_st) & htavail)
1411 == 0), PMU_MAX_TRANSITION_DLY);
1412 ASSERT(R_REG(sii->osh, &cc->clk_ctl_st) & htavail);
1413 } else {
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +02001414 udelay(PLL_DELAY);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001415 }
1416 break;
1417
1418 case CLK_DYNAMIC: /* enable dynamic clock control */
1419 if (sii->pub.ccrev < 10) {
1420 scc = R_REG(sii->osh, &cc->slow_clk_ctl);
1421 scc &= ~(SCC_FS | SCC_IP | SCC_XC);
1422 if ((scc & SCC_SS_MASK) != SCC_SS_XTAL)
1423 scc |= SCC_XC;
1424 W_REG(sii->osh, &cc->slow_clk_ctl, scc);
1425
1426 /* for dynamic control, we have to release our xtal_pu "force on" */
1427 if (scc & SCC_XC)
1428 si_clkctl_xtal(&sii->pub, XTAL, OFF);
1429 } else if (sii->pub.ccrev < 20) {
1430 /* Instaclock */
1431 AND_REG(sii->osh, &cc->system_clk_ctl, ~SYCC_HR);
1432 } else {
1433 AND_REG(sii->osh, &cc->clk_ctl_st, ~CCS_FORCEHT);
1434 }
1435 break;
1436
1437 default:
1438 ASSERT(0);
1439 }
1440
1441 done:
1442 if (!fast) {
1443 si_setcoreidx(&sii->pub, origidx);
1444 INTR_RESTORE(sii, intr_val);
1445 }
Jason Cooper90ea2292010-09-14 09:45:32 -04001446 return mode == CLK_FAST;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001447}
1448
1449/* Build device path. Support SI, PCI, and JTAG for now. */
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -07001450int si_devpath(si_t *sih, char *path, int size)
Jason Coopera2627bc2010-09-14 09:45:31 -04001451{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001452 int slen;
1453
1454 ASSERT(path != NULL);
1455 ASSERT(size >= SI_DEVPATH_BUFSZ);
1456
1457 if (!path || size <= 0)
1458 return -1;
1459
Brett Rudleyfa7a1db2010-11-23 15:30:02 -08001460 switch (sih->bustype) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001461 case SI_BUS:
1462 case JTAG_BUS:
1463 slen = snprintf(path, (size_t) size, "sb/%u/", si_coreidx(sih));
1464 break;
1465 case PCI_BUS:
1466 ASSERT((SI_INFO(sih))->osh != NULL);
1467 slen = snprintf(path, (size_t) size, "pci/%u/%u/",
1468 OSL_PCI_BUS((SI_INFO(sih))->osh),
1469 OSL_PCI_SLOT((SI_INFO(sih))->osh));
1470 break;
1471
1472#ifdef BCMSDIO
1473 case SDIO_BUS:
1474 SI_ERROR(("si_devpath: device 0 assumed\n"));
1475 slen = snprintf(path, (size_t) size, "sd/%u/", si_coreidx(sih));
1476 break;
1477#endif
1478 default:
1479 slen = -1;
1480 ASSERT(0);
1481 break;
1482 }
1483
1484 if (slen < 0 || slen >= size) {
1485 path[0] = '\0';
1486 return -1;
1487 }
1488
1489 return 0;
1490}
1491
1492/* Get a variable, but only if it has a devpath prefix */
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -07001493char *si_getdevpathvar(si_t *sih, const char *name)
Jason Coopera2627bc2010-09-14 09:45:31 -04001494{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001495 char varname[SI_DEVPATH_BUFSZ + 32];
1496
1497 si_devpathvar(sih, varname, sizeof(varname), name);
1498
Jason Cooper90ea2292010-09-14 09:45:32 -04001499 return getvar(NULL, varname);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001500}
1501
1502/* Get a variable, but only if it has a devpath prefix */
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -07001503int si_getdevpathintvar(si_t *sih, const char *name)
Jason Coopera2627bc2010-09-14 09:45:31 -04001504{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001505#if defined(BCMBUSTYPE) && (BCMBUSTYPE == SI_BUS)
Jason Cooper90ea2292010-09-14 09:45:32 -04001506 return getintvar(NULL, name);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001507#else
1508 char varname[SI_DEVPATH_BUFSZ + 32];
1509
1510 si_devpathvar(sih, varname, sizeof(varname), name);
1511
Jason Cooper90ea2292010-09-14 09:45:32 -04001512 return getintvar(NULL, varname);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001513#endif
1514}
1515
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001516char *si_getnvramflvar(si_t *sih, const char *name)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001517{
Jason Cooper90ea2292010-09-14 09:45:32 -04001518 return getvar(NULL, name);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001519}
1520
1521/* Concatenate the dev path with a varname into the given 'var' buffer
1522 * and return the 'var' pointer.
1523 * Nothing is done to the arguments if len == 0 or var is NULL, var is still returned.
1524 * On overflow, the first char will be set to '\0'.
1525 */
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -07001526static char *si_devpathvar(si_t *sih, char *var, int len, const char *name)
1527{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001528 uint path_len;
1529
1530 if (!var || len <= 0)
1531 return var;
1532
1533 if (si_devpath(sih, var, len) == 0) {
1534 path_len = strlen(var);
1535
1536 if (strlen(name) + 1 > (uint) (len - path_len))
1537 var[0] = '\0';
1538 else
1539 strncpy(var + path_len, name, len - path_len - 1);
1540 }
1541
1542 return var;
1543}
1544
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001545/* return true if PCIE capability exists in the pci config space */
Nohee Ko84b9fac2010-09-29 15:56:49 -07001546static __used bool si_ispcie(si_info_t *sii)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001547{
Greg Kroah-Hartman36ef9a12010-10-05 10:02:49 -07001548 u8 cap_ptr;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001549
Brett Rudleyfa7a1db2010-11-23 15:30:02 -08001550 if (sii->pub.bustype != PCI_BUS)
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001551 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001552
1553 cap_ptr =
1554 pcicore_find_pci_capability(sii->osh, PCI_CAP_PCIECAP_ID, NULL,
1555 NULL);
1556 if (!cap_ptr)
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001557 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001558
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001559 return true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001560}
1561
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001562#ifdef BCMSDIO
1563/* initialize the sdio core */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001564void si_sdio_init(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001565{
1566 si_info_t *sii = SI_INFO(sih);
1567
1568 if (((sih->buscoretype == PCMCIA_CORE_ID) && (sih->buscorerev >= 8)) ||
1569 (sih->buscoretype == SDIOD_CORE_ID)) {
1570 uint idx;
1571 sdpcmd_regs_t *sdpregs;
1572
1573 /* get the current core index */
1574 idx = sii->curidx;
1575 ASSERT(idx == si_findcoreidx(sih, D11_CORE_ID, 0));
1576
1577 /* switch to sdio core */
Jason Cooperca8c1e52010-09-14 09:45:33 -04001578 sdpregs = (sdpcmd_regs_t *) si_setcore(sih, PCMCIA_CORE_ID, 0);
1579 if (!sdpregs)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001580 sdpregs =
1581 (sdpcmd_regs_t *) si_setcore(sih, SDIOD_CORE_ID, 0);
1582 ASSERT(sdpregs);
1583
1584 SI_MSG(("si_sdio_init: For PCMCIA/SDIO Corerev %d, enable ints from core %d " "through SD core %d (%p)\n", sih->buscorerev, idx, sii->curidx, sdpregs));
1585
1586 /* enable backplane error and core interrupts */
1587 W_REG(sii->osh, &sdpregs->hostintmask, I_SBINT);
1588 W_REG(sii->osh, &sdpregs->sbintmask,
1589 (I_SB_SERR | I_SB_RESPERR | (1 << idx)));
1590
1591 /* switch back to previous core */
1592 si_setcoreidx(sih, idx);
1593 }
1594
1595 /* enable interrupts */
1596 bcmsdh_intr_enable(sii->sdh);
1597
1598}
1599#endif /* BCMSDIO */
1600
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -07001601bool si_pci_war16165(si_t *sih)
Jason Coopera2627bc2010-09-14 09:45:31 -04001602{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001603 si_info_t *sii;
1604
1605 sii = SI_INFO(sih);
1606
Jason Cooper90ea2292010-09-14 09:45:32 -04001607 return PCI(sii) && (sih->buscorerev <= 10);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001608}
1609
Jason Cooperb4f790e2010-10-11 10:02:58 -04001610void si_pci_up(si_t *sih)
Jason Coopera2627bc2010-09-14 09:45:31 -04001611{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001612 si_info_t *sii;
1613
1614 sii = SI_INFO(sih);
1615
1616 /* if not pci bus, we're done */
Brett Rudleyfa7a1db2010-11-23 15:30:02 -08001617 if (sih->bustype != PCI_BUS)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001618 return;
1619
1620 if (PCI_FORCEHT(sii))
1621 _si_clkctl_cc(sii, CLK_FAST);
1622
1623 if (PCIE(sii))
1624 pcicore_up(sii->pch, SI_PCIUP);
1625
1626}
1627
1628/* Unconfigure and/or apply various WARs when system is going to sleep mode */
Jason Cooper9927fc22010-10-11 10:02:59 -04001629void si_pci_sleep(si_t *sih)
Jason Coopera2627bc2010-09-14 09:45:31 -04001630{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001631 si_info_t *sii;
1632
1633 sii = SI_INFO(sih);
1634
1635 pcicore_sleep(sii->pch);
1636}
1637
1638/* Unconfigure and/or apply various WARs when going down */
Jason Cooperb4f790e2010-10-11 10:02:58 -04001639void si_pci_down(si_t *sih)
Jason Coopera2627bc2010-09-14 09:45:31 -04001640{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001641 si_info_t *sii;
1642
1643 sii = SI_INFO(sih);
1644
1645 /* if not pci bus, we're done */
Brett Rudleyfa7a1db2010-11-23 15:30:02 -08001646 if (sih->bustype != PCI_BUS)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001647 return;
1648
1649 /* release FORCEHT since chip is going to "down" state */
1650 if (PCI_FORCEHT(sii))
1651 _si_clkctl_cc(sii, CLK_DYNAMIC);
1652
1653 pcicore_down(sii->pch, SI_PCIDOWN);
1654}
1655
1656/*
1657 * Configure the pci core for pci client (NIC) action
1658 * coremask is the bitvec of cores by index to be enabled.
1659 */
Greg Kroah-Hartman0d2f0722010-10-08 14:28:21 -07001660void si_pci_setup(si_t *sih, uint coremask)
Jason Coopera2627bc2010-09-14 09:45:31 -04001661{
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001662 si_info_t *sii;
Greg Kroah-Hartmanc11b0ef2010-10-12 14:04:26 -07001663 struct sbpciregs *pciregs = NULL;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001664 u32 siflag = 0, w;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001665 uint idx = 0;
1666
1667 sii = SI_INFO(sih);
1668
Brett Rudleyfa7a1db2010-11-23 15:30:02 -08001669 if (sii->pub.bustype != PCI_BUS)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001670 return;
1671
1672 ASSERT(PCI(sii) || PCIE(sii));
1673 ASSERT(sii->pub.buscoreidx != BADIDX);
1674
1675 if (PCI(sii)) {
1676 /* get current core index */
1677 idx = sii->curidx;
1678
1679 /* we interrupt on this backplane flag number */
1680 siflag = si_flag(sih);
1681
1682 /* switch over to pci core */
Greg Kroah-Hartmanc11b0ef2010-10-12 14:04:26 -07001683 pciregs = (struct sbpciregs *)si_setcoreidx(sih, sii->pub.buscoreidx);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001684 }
1685
1686 /*
1687 * Enable sb->pci interrupts. Assume
1688 * PCI rev 2.3 support was added in pci core rev 6 and things changed..
1689 */
1690 if (PCIE(sii) || (PCI(sii) && ((sii->pub.buscorerev) >= 6))) {
1691 /* pci config write to set this core bit in PCIIntMask */
Brett Rudley57d8cd22010-11-22 16:58:52 -08001692 pci_read_config_dword(sii->osh->pdev, PCI_INT_MASK, &w);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001693 w |= (coremask << PCI_SBIM_SHIFT);
Brett Rudley57d8cd22010-11-22 16:58:52 -08001694 pci_write_config_dword(sii->osh->pdev, PCI_INT_MASK, w);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001695 } else {
1696 /* set sbintvec bit for our flag number */
1697 si_setint(sih, siflag);
1698 }
1699
1700 if (PCI(sii)) {
1701 OR_REG(sii->osh, &pciregs->sbtopci2,
1702 (SBTOPCI_PREF | SBTOPCI_BURST));
1703 if (sii->pub.buscorerev >= 11) {
1704 OR_REG(sii->osh, &pciregs->sbtopci2,
1705 SBTOPCI_RC_READMULTI);
1706 w = R_REG(sii->osh, &pciregs->clkrun);
1707 W_REG(sii->osh, &pciregs->clkrun,
1708 (w | PCI_CLKRUN_DSBL));
1709 w = R_REG(sii->osh, &pciregs->clkrun);
1710 }
1711
1712 /* switch back to previous core */
1713 si_setcoreidx(sih, idx);
1714 }
1715}
1716
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001717/*
1718 * Fixup SROMless PCI device's configuration.
1719 * The current core may be changed upon return.
1720 */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001721int si_pci_fixcfg(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001722{
1723 uint origidx, pciidx;
Greg Kroah-Hartmanc11b0ef2010-10-12 14:04:26 -07001724 struct sbpciregs *pciregs = NULL;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001725 sbpcieregs_t *pcieregs = NULL;
1726 void *regs = NULL;
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001727 u16 val16, *reg16 = NULL;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001728
1729 si_info_t *sii = SI_INFO(sih);
1730
Brett Rudleyfa7a1db2010-11-23 15:30:02 -08001731 ASSERT(sii->pub.bustype == PCI_BUS);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001732
1733 /* Fixup PI in SROM shadow area to enable the correct PCI core access */
1734 /* save the current index */
1735 origidx = si_coreidx(&sii->pub);
1736
1737 /* check 'pi' is correct and fix it if not */
1738 if (sii->pub.buscoretype == PCIE_CORE_ID) {
1739 pcieregs =
1740 (sbpcieregs_t *) si_setcore(&sii->pub, PCIE_CORE_ID, 0);
1741 regs = pcieregs;
1742 ASSERT(pcieregs != NULL);
1743 reg16 = &pcieregs->sprom[SRSH_PI_OFFSET];
1744 } else if (sii->pub.buscoretype == PCI_CORE_ID) {
Greg Kroah-Hartmanc11b0ef2010-10-12 14:04:26 -07001745 pciregs = (struct sbpciregs *)si_setcore(&sii->pub, PCI_CORE_ID, 0);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001746 regs = pciregs;
1747 ASSERT(pciregs != NULL);
1748 reg16 = &pciregs->sprom[SRSH_PI_OFFSET];
1749 }
1750 pciidx = si_coreidx(&sii->pub);
1751 val16 = R_REG(sii->osh, reg16);
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001752 if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (u16) pciidx) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001753 val16 =
Greg Kroah-Hartman7d4df482010-10-07 17:04:47 -07001754 (u16) (pciidx << SRSH_PI_SHIFT) | (val16 &
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001755 ~SRSH_PI_MASK);
1756 W_REG(sii->osh, reg16, val16);
1757 }
1758
1759 /* restore the original index */
1760 si_setcoreidx(&sii->pub, origidx);
1761
1762 pcicore_hwup(sii->pch);
1763 return 0;
1764}
1765
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001766/* mask&set gpiocontrol bits */
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001767u32 si_gpiocontrol(si_t *sih, u32 mask, u32 val, u8 priority)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001768{
1769 uint regoff;
1770
1771 regoff = 0;
1772
1773 /* gpios could be shared on router platforms
1774 * ignore reservation if it's high priority (e.g., test apps)
1775 */
1776 if ((priority != GPIO_HI_PRIORITY) &&
Brett Rudleyfa7a1db2010-11-23 15:30:02 -08001777 (sih->bustype == SI_BUS) && (val || mask)) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001778 mask = priority ? (si_gpioreservation & mask) :
1779 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1780 val &= mask;
1781 }
1782
Greg Kroah-Hartmance0f1b82010-10-08 11:44:45 -07001783 regoff = offsetof(chipcregs_t, gpiocontrol);
Jason Cooper90ea2292010-09-14 09:45:32 -04001784 return si_corereg(sih, SI_CC_IDX, regoff, mask, val);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001785}
1786
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001787/* Return the size of the specified SOCRAM bank */
1788static uint
Greg Kroah-Hartman36ef9a12010-10-05 10:02:49 -07001789socram_banksize(si_info_t *sii, sbsocramregs_t *regs, u8 index,
1790 u8 mem_type)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001791{
1792 uint banksize, bankinfo;
1793 uint bankidx = index | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT);
1794
1795 ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM);
1796
1797 W_REG(sii->osh, &regs->bankidx, bankidx);
1798 bankinfo = R_REG(sii->osh, &regs->bankinfo);
1799 banksize =
1800 SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1);
1801 return banksize;
1802}
1803
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001804/* Return the RAM size of the SOCRAM core */
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001805u32 si_socram_size(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001806{
1807 si_info_t *sii;
1808 uint origidx;
1809 uint intr_val = 0;
1810
1811 sbsocramregs_t *regs;
1812 bool wasup;
1813 uint corerev;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001814 u32 coreinfo;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001815 uint memsize = 0;
1816
1817 sii = SI_INFO(sih);
1818
1819 /* Block ints and save current core */
1820 INTR_OFF(sii, intr_val);
1821 origidx = si_coreidx(sih);
1822
1823 /* Switch to SOCRAM core */
Jason Cooperca8c1e52010-09-14 09:45:33 -04001824 regs = si_setcore(sih, SOCRAM_CORE_ID, 0);
1825 if (!regs)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001826 goto done;
1827
1828 /* Get info for determining size */
Jason Cooperca8c1e52010-09-14 09:45:33 -04001829 wasup = si_iscoreup(sih);
1830 if (!wasup)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001831 si_core_reset(sih, 0, 0);
1832 corerev = si_corerev(sih);
1833 coreinfo = R_REG(sii->osh, &regs->coreinfo);
1834
1835 /* Calculate size from coreinfo based on rev */
1836 if (corerev == 0)
1837 memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK));
1838 else if (corerev < 3) {
1839 memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK));
1840 memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
1841 } else if ((corerev <= 7) || (corerev == 12)) {
1842 uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
1843 uint bsz = (coreinfo & SRCI_SRBSZ_MASK);
1844 uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT;
1845 if (lss != 0)
1846 nb--;
1847 memsize = nb * (1 << (bsz + SR_BSZ_BASE));
1848 if (lss != 0)
1849 memsize += (1 << ((lss - 1) + SR_BSZ_BASE));
1850 } else {
Greg Kroah-Hartman36ef9a12010-10-05 10:02:49 -07001851 u8 i;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001852 uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
1853 for (i = 0; i < nb; i++)
1854 memsize +=
1855 socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM);
1856 }
1857
1858 /* Return to previous state and core */
1859 if (!wasup)
1860 si_core_disable(sih, 0);
1861 si_setcoreidx(sih, origidx);
1862
1863 done:
1864 INTR_RESTORE(sii, intr_val);
1865
1866 return memsize;
1867}
1868
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001869void si_chipcontrl_epa4331(si_t *sih, bool on)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001870{
1871 si_info_t *sii;
1872 chipcregs_t *cc;
1873 uint origidx;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001874 u32 val;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001875
1876 sii = SI_INFO(sih);
1877 origidx = si_coreidx(sih);
1878
1879 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
1880
1881 val = R_REG(sii->osh, &cc->chipcontrol);
1882
1883 if (on) {
1884 if (sih->chippkg == 9 || sih->chippkg == 0xb) {
1885 /* Ext PA Controls for 4331 12x9 Package */
1886 W_REG(sii->osh, &cc->chipcontrol, val |
1887 (CCTRL4331_EXTPA_EN |
1888 CCTRL4331_EXTPA_ON_GPIO2_5));
1889 } else {
1890 /* Ext PA Controls for 4331 12x12 Package */
1891 W_REG(sii->osh, &cc->chipcontrol,
1892 val | (CCTRL4331_EXTPA_EN));
1893 }
1894 } else {
1895 val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5);
1896 W_REG(sii->osh, &cc->chipcontrol, val);
1897 }
1898
1899 si_setcoreidx(sih, origidx);
1900}
1901
1902/* Enable BT-COEX & Ex-PA for 4313 */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001903void si_epa_4313war(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001904{
1905 si_info_t *sii;
1906 chipcregs_t *cc;
1907 uint origidx;
1908
1909 sii = SI_INFO(sih);
1910 origidx = si_coreidx(sih);
1911
1912 cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
1913
1914 /* EPA Fix */
1915 W_REG(sii->osh, &cc->gpiocontrol,
1916 R_REG(sii->osh, &cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK);
1917
1918 si_setcoreidx(sih, origidx);
1919}
1920
1921/* check if the device is removed */
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001922bool si_deviceremoved(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001923{
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001924 u32 w;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001925 si_info_t *sii;
1926
1927 sii = SI_INFO(sih);
1928
Brett Rudleyfa7a1db2010-11-23 15:30:02 -08001929 switch (sih->bustype) {
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001930 case PCI_BUS:
1931 ASSERT(sii->osh != NULL);
Brett Rudley57d8cd22010-11-22 16:58:52 -08001932 pci_read_config_dword(sii->osh->pdev, PCI_CFG_VID, &w);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001933 if ((w & 0xFFFF) != VENDOR_BROADCOM)
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001934 return true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001935 break;
1936 }
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001937 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001938}
1939
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001940bool si_is_sprom_available(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001941{
1942 if (sih->ccrev >= 31) {
1943 si_info_t *sii;
1944 uint origidx;
1945 chipcregs_t *cc;
Greg Kroah-Hartman66cbd3a2010-10-08 11:05:47 -07001946 u32 sromctrl;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001947
1948 if ((sih->cccaps & CC_CAP_SROM) == 0)
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07001949 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001950
1951 sii = SI_INFO(sih);
1952 origidx = sii->curidx;
1953 cc = si_setcoreidx(sih, SI_CC_IDX);
1954 sromctrl = R_REG(sii->osh, &cc->sromcontrol);
1955 si_setcoreidx(sih, origidx);
Jason Cooper90ea2292010-09-14 09:45:32 -04001956 return sromctrl & SRC_PRESENT;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001957 }
1958
1959 switch (CHIPID(sih->chip)) {
1960 case BCM4329_CHIP_ID:
1961 return (sih->chipst & CST4329_SPROM_SEL) != 0;
1962 case BCM4319_CHIP_ID:
1963 return (sih->chipst & CST4319_SPROM_SEL) != 0;
1964 case BCM4336_CHIP_ID:
1965 return (sih->chipst & CST4336_SPROM_PRESENT) != 0;
1966 case BCM4330_CHIP_ID:
1967 return (sih->chipst & CST4330_SPROM_PRESENT) != 0;
1968 case BCM4313_CHIP_ID:
1969 return (sih->chipst & CST4313_SPROM_PRESENT) != 0;
1970 case BCM4331_CHIP_ID:
1971 return (sih->chipst & CST4331_SPROM_PRESENT) != 0;
1972 default:
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07001973 return true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001974 }
1975}
1976
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04001977bool si_is_otp_disabled(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001978{
1979 switch (CHIPID(sih->chip)) {
1980 case BCM4329_CHIP_ID:
1981 return (sih->chipst & CST4329_SPROM_OTP_SEL_MASK) ==
1982 CST4329_OTP_PWRDN;
1983 case BCM4319_CHIP_ID:
1984 return (sih->chipst & CST4319_SPROM_OTP_SEL_MASK) ==
1985 CST4319_OTP_PWRDN;
1986 case BCM4336_CHIP_ID:
Jason Cooper90ea2292010-09-14 09:45:32 -04001987 return (sih->chipst & CST4336_OTP_PRESENT) == 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001988 case BCM4330_CHIP_ID:
Jason Cooper90ea2292010-09-14 09:45:32 -04001989 return (sih->chipst & CST4330_OTP_PRESENT) == 0;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07001990 case BCM4313_CHIP_ID:
1991 return (sih->chipst & CST4313_OTP_PRESENT) == 0;
1992 /* These chips always have their OTP on */
1993 case BCM43224_CHIP_ID:
1994 case BCM43225_CHIP_ID:
1995 case BCM43421_CHIP_ID:
1996 case BCM43235_CHIP_ID:
1997 case BCM43236_CHIP_ID:
1998 case BCM43238_CHIP_ID:
1999 case BCM4331_CHIP_ID:
2000 default:
Greg Kroah-Hartman0965ae82010-10-12 12:50:15 -07002001 return false;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002002 }
2003}
2004
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002005bool si_is_otp_powered(si_t *sih)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002006{
2007 if (PMUCTL_ENAB(sih))
2008 return si_pmu_is_otp_powered(sih, si_osh(sih));
Greg Kroah-Hartman0f0881b2010-10-12 12:15:18 -07002009 return true;
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002010}
2011
Jason Cooper7cc4a4c2010-09-14 09:45:30 -04002012void si_otp_power(si_t *sih, bool on)
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002013{
2014 if (PMUCTL_ENAB(sih))
2015 si_pmu_otp_power(sih, si_osh(sih), on);
mike.rapoport@gmail.com73831412010-10-13 00:09:07 +02002016 udelay(1000);
Henry Ptasinskia9533e72010-09-08 21:04:42 -07002017}
2018