fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / net / wireless / bcm43xx / bcm43xx_power.c
1 /*
2
3   Broadcom BCM43xx wireless driver
4
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>
10
11   Some parts of the code in this file are derived from the ipw2200
12   driver  Copyright(c) 2003 - 2004 Intel Corporation.
13
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.
18
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.
23
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.
28
29 */
30
31 #include <linux/delay.h>
32
33 #include "bcm43xx.h"
34 #include "bcm43xx_power.h"
35 #include "bcm43xx_main.h"
36
37
38 /* Get the Slow Clock Source */
39 static int bcm43xx_pctl_get_slowclksrc(struct bcm43xx_private *bcm)
40 {
41         u32 tmp;
42         int err;
43
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);
51                         assert(!err);
52                         if (tmp & 0x10)
53                                 return BCM43xx_PCTL_CLKSRC_PCI;
54                         return BCM43xx_PCTL_CLKSRC_XTALOS;
55                 }
56         }
57         if (bcm->current_core->rev < 10) {
58                 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
59                 tmp &= 0x7;
60                 if (tmp == 0)
61                         return BCM43xx_PCTL_CLKSRC_LOPWROS;
62                 if (tmp == 1)
63                         return BCM43xx_PCTL_CLKSRC_XTALOS;
64                 if (tmp == 2)
65                         return BCM43xx_PCTL_CLKSRC_PCI;
66         }
67
68         return BCM43xx_PCTL_CLKSRC_XTALOS;
69 }
70
71 /* Get max/min slowclock frequency
72  * as described in http://bcm-specs.sipsolutions.net/PowerControl
73  */
74 static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
75                                        int get_max)
76 {
77         int limit;
78         int clocksrc;
79         int divisor;
80         u32 tmp;
81
82         assert(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL);
83         assert(bcm->current_core == &bcm->core_chipcommon);
84
85         clocksrc = bcm43xx_pctl_get_slowclksrc(bcm);
86         if (bcm->current_core->rev < 6) {
87                 switch (clocksrc) {
88                 case BCM43xx_PCTL_CLKSRC_PCI:
89                         divisor = 64;
90                         break;
91                 case BCM43xx_PCTL_CLKSRC_XTALOS:
92                         divisor = 32;
93                         break;
94                 default:
95                         assert(0);
96                         divisor = 1;
97                 }
98         } else if (bcm->current_core->rev < 10) {
99                 switch (clocksrc) {
100                 case BCM43xx_PCTL_CLKSRC_LOPWROS:
101                         divisor = 1;
102                         break;
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;
107                         divisor *= 4;
108                         break;
109                 default:
110                         assert(0);
111                         divisor = 1;
112                 }
113         } else {
114                 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL);
115                 divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
116                 divisor *= 4;
117         }
118
119         switch (clocksrc) {
120         case BCM43xx_PCTL_CLKSRC_LOPWROS:
121                 if (get_max)
122                         limit = 43000;
123                 else
124                         limit = 25000;
125                 break;
126         case BCM43xx_PCTL_CLKSRC_XTALOS:
127                 if (get_max)
128                         limit = 20200000;
129                 else
130                         limit = 19800000;
131                 break;
132         case BCM43xx_PCTL_CLKSRC_PCI:
133                 if (get_max)
134                         limit = 34000000;
135                 else
136                         limit = 25000000;
137                 break;
138         default:
139                 assert(0);
140                 limit = 0;
141         }
142         limit /= divisor;
143
144         return limit;
145 }
146
147
148 /* init power control
149  * as described in http://bcm-specs.sipsolutions.net/PowerControl
150  */
151 int bcm43xx_pctl_init(struct bcm43xx_private *bcm)
152 {
153         int err, maxfreq;
154         struct bcm43xx_coreinfo *old_core;
155
156         old_core = bcm->current_core;
157         err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
158         if (err == -ENODEV)
159                 return 0;
160         if (err)
161                 goto out;
162
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);
168         }
169
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);
176                 } else {
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);
182                 }
183         }
184
185         err = bcm43xx_switch_core(bcm, old_core);
186         assert(err == 0);
187
188 out:
189         return err;
190 }
191
192 u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm)
193 {
194         u16 delay = 0;
195         int err;
196         u32 pll_on_delay;
197         struct bcm43xx_coreinfo *old_core;
198         int minfreq;
199
200         if (bcm->bustype != BCM43xx_BUSTYPE_PCI)
201                 goto out;
202         if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL))
203                 goto out;
204         old_core = bcm->current_core;
205         err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
206         if (err == -ENODEV)
207                 goto out;
208
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;
212
213         err = bcm43xx_switch_core(bcm, old_core);
214         assert(err == 0);
215
216 out:
217         return delay;
218 }
219
220 /* set the powercontrol clock
221  * as described in http://bcm-specs.sipsolutions.net/PowerControl
222  */
223 int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode)
224 {
225         int err;
226         struct bcm43xx_coreinfo *old_core;
227         u32 tmp;
228
229         old_core = bcm->current_core;
230         err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
231         if (err == -ENODEV)
232                 return 0;
233         if (err)
234                 goto out;
235         
236         if (bcm->core_chipcommon.rev < 6) {
237                 if (mode == BCM43xx_PCTL_CLK_FAST) {
238                         err = bcm43xx_pctl_set_crystal(bcm, 1);
239                         if (err)
240                                 goto out;
241                 }
242         } else {
243                 if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) &&
244                         (bcm->core_chipcommon.rev < 10)) {
245                         switch (mode) {
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);
250                                 break;
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);
255                                 break;
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);
262                         }
263                 }
264         }
265         
266         err = bcm43xx_switch_core(bcm, old_core);
267         assert(err == 0);
268
269 out:
270         return err;
271 }
272
273 int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on)
274 {
275         int err;
276         u32 in, out, outenable;
277
278         err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in);
279         if (err)
280                 goto err_pci;
281         err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out);
282         if (err)
283                 goto err_pci;
284         err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable);
285         if (err)
286                 goto err_pci;
287
288         outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
289
290         if (on) {
291                 if (in & 0x40)
292                         return 0;
293
294                 out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN);
295
296                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
297                 if (err)
298                         goto err_pci;
299                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
300                 if (err)
301                         goto err_pci;
302                 udelay(1000);
303
304                 out &= ~BCM43xx_PCTL_PLL_POWERDOWN;
305                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
306                 if (err)
307                         goto err_pci;
308                 udelay(5000);
309         } else {
310                 if (bcm->current_core->rev < 5)
311                         return 0;
312                 if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW)
313                         return 0;
314
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);
317  *              if (err)
318  *                      return err;
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))))
323  *                      return 0;
324  *              err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
325  *              if (err)
326  *                      return err;
327  */
328                 
329                 err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
330                 if (err)
331                         goto out;
332                 out &= ~BCM43xx_PCTL_XTAL_POWERUP;
333                 out |= BCM43xx_PCTL_PLL_POWERDOWN;
334                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
335                 if (err)
336                         goto err_pci;
337                 err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
338                 if (err)
339                         goto err_pci;
340         }
341
342 out:
343         return err;
344
345 err_pci:
346         printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n");
347         err = -EBUSY;
348         goto out;
349 }
350
351 /* Set the PowerSavingControlBits.
352  * Bitvalues:
353  *   0  => unset the bit
354  *   1  => set the bit
355  *   -1 => calculate the bit
356  */
357 void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
358                                    int bit25, int bit26)
359 {
360         int i;
361         u32 status;
362
363 //FIXME: Force 25 to off and 26 to on for now:
364 bit25 = 0;
365 bit26 = 1;
366
367         if (bit25 == -1) {
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
370         }
371         if (bit26 == -1) {
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
375         }
376         status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
377         if (bit25)
378                 status |= BCM43xx_SBF_PS1;
379         else
380                 status &= ~BCM43xx_SBF_PS1;
381         if (bit26)
382                 status |= BCM43xx_SBF_PS2;
383         else
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)
389                                 break;
390                         udelay(10);
391                 }
392         }
393 }