cfg80211: keep track of supported interface modes
[safe/jmp/linux-2.6] / drivers / net / wireless / b43 / phy.c
1 /*
2
3   Broadcom B43 wireless driver
4
5   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6   Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
7   Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
8   Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
9   Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10
11   This program is free software; you can redistribute it and/or modify
12   it under the terms of the GNU General Public License as published by
13   the Free Software Foundation; either version 2 of the License, or
14   (at your option) any later version.
15
16   This program is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with this program; see the file COPYING.  If not, write to
23   the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
24   Boston, MA 02110-1301, USA.
25
26 */
27
28 #include <linux/delay.h>
29 #include <linux/io.h>
30 #include <linux/types.h>
31 #include <linux/bitrev.h>
32
33 #include "b43.h"
34 #include "phy.h"
35 #include "nphy.h"
36 #include "main.h"
37 #include "tables.h"
38 #include "lo.h"
39 #include "wa.h"
40
41
42 static void b43_shm_clear_tssi(struct b43_wldev *dev)
43 {
44         struct b43_phy *phy = &dev->phy;
45
46         switch (phy->type) {
47         case B43_PHYTYPE_A:
48                 b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F);
49                 b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F);
50                 break;
51         case B43_PHYTYPE_B:
52         case B43_PHYTYPE_G:
53                 b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F);
54                 b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F);
55                 b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F);
56                 b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F);
57                 break;
58         }
59 }
60
61 /* http://bcm-specs.sipsolutions.net/EstimatePowerOut
62  * This function converts a TSSI value to dBm in Q5.2
63  */
64 static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
65 {
66         struct b43_phy *phy = &dev->phy;
67         s8 dbm = 0;
68         s32 tmp;
69
70         tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi);
71
72         switch (phy->type) {
73         case B43_PHYTYPE_A:
74                 tmp += 0x80;
75                 tmp = clamp_val(tmp, 0x00, 0xFF);
76                 dbm = phy->tssi2dbm[tmp];
77                 //TODO: There's a FIXME on the specs
78                 break;
79         case B43_PHYTYPE_B:
80         case B43_PHYTYPE_G:
81                 tmp = clamp_val(tmp, 0x00, 0x3F);
82                 dbm = phy->tssi2dbm[tmp];
83                 break;
84         default:
85                 B43_WARN_ON(1);
86         }
87
88         return dbm;
89 }
90
91 void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
92                                      int *_bbatt, int *_rfatt)
93 {
94         int rfatt = *_rfatt;
95         int bbatt = *_bbatt;
96         struct b43_txpower_lo_control *lo = dev->phy.lo_control;
97
98         /* Get baseband and radio attenuation values into their permitted ranges.
99          * Radio attenuation affects power level 4 times as much as baseband. */
100
101         /* Range constants */
102         const int rf_min = lo->rfatt_list.min_val;
103         const int rf_max = lo->rfatt_list.max_val;
104         const int bb_min = lo->bbatt_list.min_val;
105         const int bb_max = lo->bbatt_list.max_val;
106
107         while (1) {
108                 if (rfatt > rf_max && bbatt > bb_max - 4)
109                         break;  /* Can not get it into ranges */
110                 if (rfatt < rf_min && bbatt < bb_min + 4)
111                         break;  /* Can not get it into ranges */
112                 if (bbatt > bb_max && rfatt > rf_max - 1)
113                         break;  /* Can not get it into ranges */
114                 if (bbatt < bb_min && rfatt < rf_min + 1)
115                         break;  /* Can not get it into ranges */
116
117                 if (bbatt > bb_max) {
118                         bbatt -= 4;
119                         rfatt += 1;
120                         continue;
121                 }
122                 if (bbatt < bb_min) {
123                         bbatt += 4;
124                         rfatt -= 1;
125                         continue;
126                 }
127                 if (rfatt > rf_max) {
128                         rfatt -= 1;
129                         bbatt += 4;
130                         continue;
131                 }
132                 if (rfatt < rf_min) {
133                         rfatt += 1;
134                         bbatt -= 4;
135                         continue;
136                 }
137                 break;
138         }
139
140         *_rfatt = clamp_val(rfatt, rf_min, rf_max);
141         *_bbatt = clamp_val(bbatt, bb_min, bb_max);
142 }
143
144 /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
145 void b43_phy_xmitpower(struct b43_wldev *dev)
146 {
147         struct ssb_bus *bus = dev->dev->bus;
148         struct b43_phy *phy = &dev->phy;
149
150         if (phy->cur_idle_tssi == 0)
151                 return;
152         if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
153             (bus->boardinfo.type == SSB_BOARD_BU4306))
154                 return;
155 #ifdef CONFIG_B43_DEBUG
156         if (phy->manual_txpower_control)
157                 return;
158 #endif
159
160         switch (phy->type) {
161         case B43_PHYTYPE_A:{
162
163                         //TODO: Nothing for A PHYs yet :-/
164
165                         break;
166                 }
167         case B43_PHYTYPE_B:
168         case B43_PHYTYPE_G:{
169                         u16 tmp;
170                         s8 v0, v1, v2, v3;
171                         s8 average;
172                         int max_pwr;
173                         int desired_pwr, estimated_pwr, pwr_adjust;
174                         int rfatt_delta, bbatt_delta;
175                         int rfatt, bbatt;
176                         u8 tx_control;
177
178                         tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058);
179                         v0 = (s8) (tmp & 0x00FF);
180                         v1 = (s8) ((tmp & 0xFF00) >> 8);
181                         tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A);
182                         v2 = (s8) (tmp & 0x00FF);
183                         v3 = (s8) ((tmp & 0xFF00) >> 8);
184                         tmp = 0;
185
186                         if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
187                             || v3 == 0x7F) {
188                                 tmp =
189                                     b43_shm_read16(dev, B43_SHM_SHARED, 0x0070);
190                                 v0 = (s8) (tmp & 0x00FF);
191                                 v1 = (s8) ((tmp & 0xFF00) >> 8);
192                                 tmp =
193                                     b43_shm_read16(dev, B43_SHM_SHARED, 0x0072);
194                                 v2 = (s8) (tmp & 0x00FF);
195                                 v3 = (s8) ((tmp & 0xFF00) >> 8);
196                                 if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
197                                     || v3 == 0x7F)
198                                         return;
199                                 v0 = (v0 + 0x20) & 0x3F;
200                                 v1 = (v1 + 0x20) & 0x3F;
201                                 v2 = (v2 + 0x20) & 0x3F;
202                                 v3 = (v3 + 0x20) & 0x3F;
203                                 tmp = 1;
204                         }
205                         b43_shm_clear_tssi(dev);
206
207                         average = (v0 + v1 + v2 + v3 + 2) / 4;
208
209                         if (tmp
210                             && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) &
211                                 0x8))
212                                 average -= 13;
213
214                         estimated_pwr =
215                             b43_phy_estimate_power_out(dev, average);
216
217                         max_pwr = dev->dev->bus->sprom.maxpwr_bg;
218                         if ((dev->dev->bus->sprom.boardflags_lo
219                             & B43_BFL_PACTRL) && (phy->type == B43_PHYTYPE_G))
220                                 max_pwr -= 0x3;
221                         if (unlikely(max_pwr <= 0)) {
222                                 b43warn(dev->wl,
223                                         "Invalid max-TX-power value in SPROM.\n");
224                                 max_pwr = 60;   /* fake it */
225                                 dev->dev->bus->sprom.maxpwr_bg = max_pwr;
226                         }
227
228                         /*TODO:
229                            max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr)
230                            where REG is the max power as per the regulatory domain
231                          */
232
233                         /* Get desired power (in Q5.2) */
234                         desired_pwr = INT_TO_Q52(phy->power_level);
235                         /* And limit it. max_pwr already is Q5.2 */
236                         desired_pwr = clamp_val(desired_pwr, 0, max_pwr);
237                         if (b43_debug(dev, B43_DBG_XMITPOWER)) {
238                                 b43dbg(dev->wl,
239                                        "Current TX power output: " Q52_FMT
240                                        " dBm, " "Desired TX power output: "
241                                        Q52_FMT " dBm\n", Q52_ARG(estimated_pwr),
242                                        Q52_ARG(desired_pwr));
243                         }
244
245                         /* Calculate the adjustment delta. */
246                         pwr_adjust = desired_pwr - estimated_pwr;
247
248                         /* RF attenuation delta. */
249                         rfatt_delta = ((pwr_adjust + 7) / 8);
250                         /* Lower attenuation => Bigger power output. Negate it. */
251                         rfatt_delta = -rfatt_delta;
252
253                         /* Baseband attenuation delta. */
254                         bbatt_delta = pwr_adjust / 2;
255                         /* Lower attenuation => Bigger power output. Negate it. */
256                         bbatt_delta = -bbatt_delta;
257                         /* RF att affects power level 4 times as much as
258                          * Baseband attennuation. Subtract it. */
259                         bbatt_delta -= 4 * rfatt_delta;
260
261                         /* So do we finally need to adjust something? */
262                         if ((rfatt_delta == 0) && (bbatt_delta == 0))
263                                 return;
264
265                         /* Calculate the new attenuation values. */
266                         bbatt = phy->bbatt.att;
267                         bbatt += bbatt_delta;
268                         rfatt = phy->rfatt.att;
269                         rfatt += rfatt_delta;
270
271                         b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
272                         tx_control = phy->tx_control;
273                         if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
274                                 if (rfatt <= 1) {
275                                         if (tx_control == 0) {
276                                                 tx_control =
277                                                     B43_TXCTL_PA2DB |
278                                                     B43_TXCTL_TXMIX;
279                                                 rfatt += 2;
280                                                 bbatt += 2;
281                                         } else if (dev->dev->bus->sprom.
282                                                    boardflags_lo &
283                                                    B43_BFL_PACTRL) {
284                                                 bbatt += 4 * (rfatt - 2);
285                                                 rfatt = 2;
286                                         }
287                                 } else if (rfatt > 4 && tx_control) {
288                                         tx_control = 0;
289                                         if (bbatt < 3) {
290                                                 rfatt -= 3;
291                                                 bbatt += 2;
292                                         } else {
293                                                 rfatt -= 2;
294                                                 bbatt -= 2;
295                                         }
296                                 }
297                         }
298                         /* Save the control values */
299                         phy->tx_control = tx_control;
300                         b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
301                         phy->rfatt.att = rfatt;
302                         phy->bbatt.att = bbatt;
303
304                         /* Adjust the hardware */
305                         b43_phy_lock(dev);
306                         b43_radio_lock(dev);
307                         b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
308                                           phy->tx_control);
309                         b43_radio_unlock(dev);
310                         b43_phy_unlock(dev);
311                         break;
312                 }
313         case B43_PHYTYPE_N:
314                 b43_nphy_xmitpower(dev);
315                 break;
316         default:
317                 B43_WARN_ON(1);
318         }
319 }
320
321 static inline s32 b43_tssi2dbm_ad(s32 num, s32 den)
322 {
323         if (num < 0)
324                 return num / den;
325         else
326                 return (num + den / 2) / den;
327 }
328
329 static inline
330     s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2)
331 {
332         s32 m1, m2, f = 256, q, delta;
333         s8 i = 0;
334
335         m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
336         m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1);
337         do {
338                 if (i > 15)
339                         return -EINVAL;
340                 q = b43_tssi2dbm_ad(f * 4096 -
341                                     b43_tssi2dbm_ad(m2 * f, 16) * f, 2048);
342                 delta = abs(q - f);
343                 f = q;
344                 i++;
345         } while (delta >= 2);
346         entry[index] = clamp_val(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
347         return 0;
348 }
349
350 /* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
351 int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
352 {
353         struct b43_phy *phy = &dev->phy;
354         s16 pab0, pab1, pab2;
355         u8 idx;
356         s8 *dyn_tssi2dbm;
357
358         if (phy->type == B43_PHYTYPE_A) {
359                 pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
360                 pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
361                 pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
362         } else {
363                 pab0 = (s16) (dev->dev->bus->sprom.pa0b0);
364                 pab1 = (s16) (dev->dev->bus->sprom.pa0b1);
365                 pab2 = (s16) (dev->dev->bus->sprom.pa0b2);
366         }
367
368         if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
369                 phy->tgt_idle_tssi = 0x34;
370                 phy->tssi2dbm = b43_tssi2dbm_b_table;
371                 return 0;
372         }
373
374         if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
375             pab0 != -1 && pab1 != -1 && pab2 != -1) {
376                 /* The pabX values are set in SPROM. Use them. */
377                 if (phy->type == B43_PHYTYPE_A) {
378                         if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
379                             (s8) dev->dev->bus->sprom.itssi_a != -1)
380                                 phy->tgt_idle_tssi =
381                                     (s8) (dev->dev->bus->sprom.itssi_a);
382                         else
383                                 phy->tgt_idle_tssi = 62;
384                 } else {
385                         if ((s8) dev->dev->bus->sprom.itssi_bg != 0 &&
386                             (s8) dev->dev->bus->sprom.itssi_bg != -1)
387                                 phy->tgt_idle_tssi =
388                                     (s8) (dev->dev->bus->sprom.itssi_bg);
389                         else
390                                 phy->tgt_idle_tssi = 62;
391                 }
392                 dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
393                 if (dyn_tssi2dbm == NULL) {
394                         b43err(dev->wl, "Could not allocate memory "
395                                "for tssi2dbm table\n");
396                         return -ENOMEM;
397                 }
398                 for (idx = 0; idx < 64; idx++)
399                         if (b43_tssi2dbm_entry
400                             (dyn_tssi2dbm, idx, pab0, pab1, pab2)) {
401                                 phy->tssi2dbm = NULL;
402                                 b43err(dev->wl, "Could not generate "
403                                        "tssi2dBm table\n");
404                                 kfree(dyn_tssi2dbm);
405                                 return -ENODEV;
406                         }
407                 phy->tssi2dbm = dyn_tssi2dbm;
408                 phy->dyn_tssi_tbl = 1;
409         } else {
410                 /* pabX values not set in SPROM. */
411                 switch (phy->type) {
412                 case B43_PHYTYPE_A:
413                         /* APHY needs a generated table. */
414                         phy->tssi2dbm = NULL;
415                         b43err(dev->wl, "Could not generate tssi2dBm "
416                                "table (wrong SPROM info)!\n");
417                         return -ENODEV;
418                 case B43_PHYTYPE_B:
419                         phy->tgt_idle_tssi = 0x34;
420                         phy->tssi2dbm = b43_tssi2dbm_b_table;
421                         break;
422                 case B43_PHYTYPE_G:
423                         phy->tgt_idle_tssi = 0x34;
424                         phy->tssi2dbm = b43_tssi2dbm_g_table;
425                         break;
426                 }
427         }
428
429         return 0;
430 }
431
432 void b43_radio_turn_on(struct b43_wldev *dev)
433 {
434         struct b43_phy *phy = &dev->phy;
435         int err;
436         u8 channel;
437
438         might_sleep();
439
440         if (phy->radio_on)
441                 return;
442
443         switch (phy->type) {
444         case B43_PHYTYPE_A:
445                 b43_radio_write16(dev, 0x0004, 0x00C0);
446                 b43_radio_write16(dev, 0x0005, 0x0008);
447                 b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7);
448                 b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7);
449                 b43_radio_init2060(dev);
450                 break;
451         case B43_PHYTYPE_B:
452         case B43_PHYTYPE_G:
453                 //XXX
454                 break;
455         case B43_PHYTYPE_N:
456                 b43_nphy_radio_turn_on(dev);
457                 break;
458         default:
459                 B43_WARN_ON(1);
460         }
461         phy->radio_on = 1;
462 }
463
464 void b43_radio_turn_off(struct b43_wldev *dev, bool force)
465 {
466         struct b43_phy *phy = &dev->phy;
467
468         if (!phy->radio_on && !force)
469                 return;
470
471         switch (phy->type) {
472         case B43_PHYTYPE_N:
473                 b43_nphy_radio_turn_off(dev);
474                 break;
475         case B43_PHYTYPE_A:
476                 b43_radio_write16(dev, 0x0004, 0x00FF);
477                 b43_radio_write16(dev, 0x0005, 0x00FB);
478                 b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
479                 b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
480                 break;
481         case B43_PHYTYPE_G: {
482                 //XXX
483                 break;
484         }
485         default:
486                 B43_WARN_ON(1);
487         }
488         phy->radio_on = 0;
489 }