3 Broadcom BCM43xx wireless driver
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6 Stefano Brivio <st3@riseup.net>
7 Michael Buesch <mbuesch@freenet.de>
8 Danny van Dyk <kugelfang@gentoo.org>
9 Andreas Jaggi <andreas.jaggi@waterwave.ch>
11 Some parts of the code in this file are derived from the ipw2200
12 driver Copyright(c) 2003 - 2004 Intel Corporation.
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING. If not, write to
26 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
27 Boston, MA 02110-1301, USA.
31 #include <linux/delay.h>
34 #include "bcm43xx_power.h"
35 #include "bcm43xx_main.h"
38 /* Get the Slow Clock Source */
39 static int bcm43xx_pctl_get_slowclksrc(struct bcm43xx_private
*bcm
)
44 assert(bcm
->current_core
== &bcm
->core_chipcommon
);
45 if (bcm
->current_core
->rev
< 6) {
46 if (bcm
->bustype
== BCM43xx_BUSTYPE_PCMCIA
||
47 bcm
->bustype
== BCM43xx_BUSTYPE_SB
)
48 return BCM43xx_PCTL_CLKSRC_XTALOS
;
49 if (bcm
->bustype
== BCM43xx_BUSTYPE_PCI
) {
50 err
= bcm43xx_pci_read_config32(bcm
, BCM43xx_PCTL_OUT
, &tmp
);
53 return BCM43xx_PCTL_CLKSRC_PCI
;
54 return BCM43xx_PCTL_CLKSRC_XTALOS
;
57 if (bcm
->current_core
->rev
< 10) {
58 tmp
= bcm43xx_read32(bcm
, BCM43xx_CHIPCOMMON_SLOWCLKCTL
);
61 return BCM43xx_PCTL_CLKSRC_LOPWROS
;
63 return BCM43xx_PCTL_CLKSRC_XTALOS
;
65 return BCM43xx_PCTL_CLKSRC_PCI
;
68 return BCM43xx_PCTL_CLKSRC_XTALOS
;
71 /* Get max/min slowclock frequency
72 * as described in http://bcm-specs.sipsolutions.net/PowerControl
74 static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private
*bcm
,
82 assert(bcm
->chipcommon_capabilities
& BCM43xx_CAPABILITIES_PCTL
);
83 assert(bcm
->current_core
== &bcm
->core_chipcommon
);
85 clocksrc
= bcm43xx_pctl_get_slowclksrc(bcm
);
86 if (bcm
->current_core
->rev
< 6) {
88 case BCM43xx_PCTL_CLKSRC_PCI
:
91 case BCM43xx_PCTL_CLKSRC_XTALOS
:
98 } else if (bcm
->current_core
->rev
< 10) {
100 case BCM43xx_PCTL_CLKSRC_LOPWROS
:
103 case BCM43xx_PCTL_CLKSRC_XTALOS
:
104 case BCM43xx_PCTL_CLKSRC_PCI
:
105 tmp
= bcm43xx_read32(bcm
, BCM43xx_CHIPCOMMON_SLOWCLKCTL
);
106 divisor
= ((tmp
& 0xFFFF0000) >> 16) + 1;
114 tmp
= bcm43xx_read32(bcm
, BCM43xx_CHIPCOMMON_SYSCLKCTL
);
115 divisor
= ((tmp
& 0xFFFF0000) >> 16) + 1;
120 case BCM43xx_PCTL_CLKSRC_LOPWROS
:
126 case BCM43xx_PCTL_CLKSRC_XTALOS
:
132 case BCM43xx_PCTL_CLKSRC_PCI
:
148 /* init power control
149 * as described in http://bcm-specs.sipsolutions.net/PowerControl
151 int bcm43xx_pctl_init(struct bcm43xx_private
*bcm
)
154 struct bcm43xx_coreinfo
*old_core
;
156 old_core
= bcm
->current_core
;
157 err
= bcm43xx_switch_core(bcm
, &bcm
->core_chipcommon
);
163 if (bcm
->chip_id
== 0x4321) {
164 if (bcm
->chip_rev
== 0)
165 bcm43xx_write32(bcm
, BCM43xx_CHIPCOMMON_CTL
, 0x03A4);
166 if (bcm
->chip_rev
== 1)
167 bcm43xx_write32(bcm
, BCM43xx_CHIPCOMMON_CTL
, 0x00A4);
170 if (bcm
->chipcommon_capabilities
& BCM43xx_CAPABILITIES_PCTL
) {
171 if (bcm
->current_core
->rev
>= 10) {
172 /* Set Idle Power clock rate to 1Mhz */
173 bcm43xx_write32(bcm
, BCM43xx_CHIPCOMMON_SYSCLKCTL
,
174 (bcm43xx_read32(bcm
, BCM43xx_CHIPCOMMON_SYSCLKCTL
)
175 & 0x0000FFFF) | 0x40000);
177 maxfreq
= bcm43xx_pctl_clockfreqlimit(bcm
, 1);
178 bcm43xx_write32(bcm
, BCM43xx_CHIPCOMMON_PLLONDELAY
,
179 (maxfreq
* 150 + 999999) / 1000000);
180 bcm43xx_write32(bcm
, BCM43xx_CHIPCOMMON_FREFSELDELAY
,
181 (maxfreq
* 15 + 999999) / 1000000);
185 err
= bcm43xx_switch_core(bcm
, old_core
);
192 u16
bcm43xx_pctl_powerup_delay(struct bcm43xx_private
*bcm
)
197 struct bcm43xx_coreinfo
*old_core
;
200 if (bcm
->bustype
!= BCM43xx_BUSTYPE_PCI
)
202 if (!(bcm
->chipcommon_capabilities
& BCM43xx_CAPABILITIES_PCTL
))
204 old_core
= bcm
->current_core
;
205 err
= bcm43xx_switch_core(bcm
, &bcm
->core_chipcommon
);
209 minfreq
= bcm43xx_pctl_clockfreqlimit(bcm
, 0);
210 pll_on_delay
= bcm43xx_read32(bcm
, BCM43xx_CHIPCOMMON_PLLONDELAY
);
211 delay
= (((pll_on_delay
+ 2) * 1000000) + (minfreq
- 1)) / minfreq
;
213 err
= bcm43xx_switch_core(bcm
, old_core
);
220 /* set the powercontrol clock
221 * as described in http://bcm-specs.sipsolutions.net/PowerControl
223 int bcm43xx_pctl_set_clock(struct bcm43xx_private
*bcm
, u16 mode
)
226 struct bcm43xx_coreinfo
*old_core
;
229 old_core
= bcm
->current_core
;
230 err
= bcm43xx_switch_core(bcm
, &bcm
->core_chipcommon
);
236 if (bcm
->core_chipcommon
.rev
< 6) {
237 if (mode
== BCM43xx_PCTL_CLK_FAST
) {
238 err
= bcm43xx_pctl_set_crystal(bcm
, 1);
243 if ((bcm
->chipcommon_capabilities
& BCM43xx_CAPABILITIES_PCTL
) &&
244 (bcm
->core_chipcommon
.rev
< 10)) {
246 case BCM43xx_PCTL_CLK_FAST
:
247 tmp
= bcm43xx_read32(bcm
, BCM43xx_CHIPCOMMON_SLOWCLKCTL
);
248 tmp
= (tmp
& ~BCM43xx_PCTL_FORCE_SLOW
) | BCM43xx_PCTL_FORCE_PLL
;
249 bcm43xx_write32(bcm
, BCM43xx_CHIPCOMMON_SLOWCLKCTL
, tmp
);
251 case BCM43xx_PCTL_CLK_SLOW
:
252 tmp
= bcm43xx_read32(bcm
, BCM43xx_CHIPCOMMON_SLOWCLKCTL
);
253 tmp
|= BCM43xx_PCTL_FORCE_SLOW
;
254 bcm43xx_write32(bcm
, BCM43xx_CHIPCOMMON_SLOWCLKCTL
, tmp
);
256 case BCM43xx_PCTL_CLK_DYNAMIC
:
257 tmp
= bcm43xx_read32(bcm
, BCM43xx_CHIPCOMMON_SLOWCLKCTL
);
258 tmp
&= ~BCM43xx_PCTL_FORCE_SLOW
;
259 tmp
|= BCM43xx_PCTL_FORCE_PLL
;
260 tmp
&= ~BCM43xx_PCTL_DYN_XTAL
;
261 bcm43xx_write32(bcm
, BCM43xx_CHIPCOMMON_SLOWCLKCTL
, tmp
);
266 err
= bcm43xx_switch_core(bcm
, old_core
);
273 int bcm43xx_pctl_set_crystal(struct bcm43xx_private
*bcm
, int on
)
276 u32 in
, out
, outenable
;
278 err
= bcm43xx_pci_read_config32(bcm
, BCM43xx_PCTL_IN
, &in
);
281 err
= bcm43xx_pci_read_config32(bcm
, BCM43xx_PCTL_OUT
, &out
);
284 err
= bcm43xx_pci_read_config32(bcm
, BCM43xx_PCTL_OUTENABLE
, &outenable
);
288 outenable
|= (BCM43xx_PCTL_XTAL_POWERUP
| BCM43xx_PCTL_PLL_POWERDOWN
);
294 out
|= (BCM43xx_PCTL_XTAL_POWERUP
| BCM43xx_PCTL_PLL_POWERDOWN
);
296 err
= bcm43xx_pci_write_config32(bcm
, BCM43xx_PCTL_OUT
, out
);
299 err
= bcm43xx_pci_write_config32(bcm
, BCM43xx_PCTL_OUTENABLE
, outenable
);
304 out
&= ~BCM43xx_PCTL_PLL_POWERDOWN
;
305 err
= bcm43xx_pci_write_config32(bcm
, BCM43xx_PCTL_OUT
, out
);
310 if (bcm
->current_core
->rev
< 5)
312 if (bcm
->sprom
.boardflags
& BCM43xx_BFL_XTAL_NOSLOW
)
315 /* XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time?
316 * err = bcm43xx_switch_core(bcm, bcm->active_80211_core);
319 * if (((bcm->current_core->rev >= 3) &&
320 * (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) ||
321 * ((bcm->current_core->rev < 3) &&
322 * !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4))))
324 * err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
329 err
= bcm43xx_pctl_set_clock(bcm
, BCM43xx_PCTL_CLK_SLOW
);
332 out
&= ~BCM43xx_PCTL_XTAL_POWERUP
;
333 out
|= BCM43xx_PCTL_PLL_POWERDOWN
;
334 err
= bcm43xx_pci_write_config32(bcm
, BCM43xx_PCTL_OUT
, out
);
337 err
= bcm43xx_pci_write_config32(bcm
, BCM43xx_PCTL_OUTENABLE
, outenable
);
346 printk(KERN_ERR PFX
"Error: pctl_set_clock() could not access PCI config space!\n");
351 /* Set the PowerSavingControlBits.
355 * -1 => calculate the bit
357 void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private
*bcm
,
358 int bit25
, int bit26
)
363 //FIXME: Force 25 to off and 26 to on for now:
368 //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
369 // and thus is not an AP and we are associated, set bit 25
372 //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
373 // or we are associated, or FIXME, or the latest PS-Poll packet sent was
374 // successful, set bit26
376 status
= bcm43xx_read32(bcm
, BCM43xx_MMIO_STATUS_BITFIELD
);
378 status
|= BCM43xx_SBF_PS1
;
380 status
&= ~BCM43xx_SBF_PS1
;
382 status
|= BCM43xx_SBF_PS2
;
384 status
&= ~BCM43xx_SBF_PS2
;
385 bcm43xx_write32(bcm
, BCM43xx_MMIO_STATUS_BITFIELD
, status
);
386 if (bit26
&& bcm
->current_core
->rev
>= 5) {
387 for (i
= 0; i
< 100; i
++) {
388 if (bcm43xx_shm_read32(bcm
, BCM43xx_SHM_SHARED
, 0x0040) != 4)