• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/src/linux/linux-2.6/drivers/net/wireless/bcm43xx/
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 */
39static 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 */
74static 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 */
151int 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
188out:
189	return err;
190}
191
192u16 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
216out:
217	return delay;
218}
219
220/* set the powercontrol clock
221 * as described in http://bcm-specs.sipsolutions.net/PowerControl
222 */
223int 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
269out:
270	return err;
271}
272
273int 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
316		err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
317		if (err)
318			goto out;
319		out &= ~BCM43xx_PCTL_XTAL_POWERUP;
320		out |= BCM43xx_PCTL_PLL_POWERDOWN;
321		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out);
322		if (err)
323			goto err_pci;
324		err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable);
325		if (err)
326			goto err_pci;
327	}
328
329out:
330	return err;
331
332err_pci:
333	printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n");
334	err = -EBUSY;
335	goto out;
336}
337
338/* Set the PowerSavingControlBits.
339 * Bitvalues:
340 *   0  => unset the bit
341 *   1  => set the bit
342 *   -1 => calculate the bit
343 */
344void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm,
345				   int bit25, int bit26)
346{
347	int i;
348	u32 status;
349
350bit25 = 0;
351bit26 = 1;
352
353	if (bit25 == -1) {
354		//	and thus is not an AP and we are associated, set bit 25
355	}
356	if (bit26 == -1) {
357		//	successful, set bit26
358	}
359	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
360	if (bit25)
361		status |= BCM43xx_SBF_PS1;
362	else
363		status &= ~BCM43xx_SBF_PS1;
364	if (bit26)
365		status |= BCM43xx_SBF_PS2;
366	else
367		status &= ~BCM43xx_SBF_PS2;
368	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
369	if (bit26 && bcm->current_core->rev >= 5) {
370		for (i = 0; i < 100; i++) {
371			if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4)
372				break;
373			udelay(10);
374		}
375	}
376}
377