| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 |  | 
|  | 3 | Broadcom B43legacy wireless driver | 
|  | 4 |  | 
|  | 5 | Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, | 
| Stefano Brivio | 1f21ad2 | 2007-11-06 22:49:20 +0100 | [diff] [blame] | 6 | Stefano Brivio <stefano.brivio@polimi.it> | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 7 | Michael Buesch <mbuesch@freenet.de> | 
|  | 8 | Danny van Dyk <kugelfang@gentoo.org> | 
|  | 9 | Andreas Jaggi <andreas.jaggi@waterwave.ch> | 
|  | 10 | Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net> | 
|  | 11 |  | 
|  | 12 | Some parts of the code in this file are derived from the ipw2200 | 
|  | 13 | driver  Copyright(c) 2003 - 2004 Intel Corporation. | 
|  | 14 |  | 
|  | 15 | This program is free software; you can redistribute it and/or modify | 
|  | 16 | it under the terms of the GNU General Public License as published by | 
|  | 17 | the Free Software Foundation; either version 2 of the License, or | 
|  | 18 | (at your option) any later version. | 
|  | 19 |  | 
|  | 20 | This program is distributed in the hope that it will be useful, | 
|  | 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 23 | GNU General Public License for more details. | 
|  | 24 |  | 
|  | 25 | You should have received a copy of the GNU General Public License | 
|  | 26 | along with this program; see the file COPYING.  If not, write to | 
|  | 27 | the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, | 
|  | 28 | Boston, MA 02110-1301, USA. | 
|  | 29 |  | 
|  | 30 | */ | 
|  | 31 |  | 
|  | 32 | #include <linux/delay.h> | 
|  | 33 |  | 
|  | 34 | #include "b43legacy.h" | 
|  | 35 | #include "main.h" | 
|  | 36 | #include "phy.h" | 
|  | 37 | #include "radio.h" | 
|  | 38 | #include "ilt.h" | 
|  | 39 |  | 
|  | 40 |  | 
|  | 41 | /* Table for b43legacy_radio_calibrationvalue() */ | 
|  | 42 | static const u16 rcc_table[16] = { | 
|  | 43 | 0x0002, 0x0003, 0x0001, 0x000F, | 
|  | 44 | 0x0006, 0x0007, 0x0005, 0x000F, | 
|  | 45 | 0x000A, 0x000B, 0x0009, 0x000F, | 
|  | 46 | 0x000E, 0x000F, 0x000D, 0x000F, | 
|  | 47 | }; | 
|  | 48 |  | 
|  | 49 | /* Reverse the bits of a 4bit value. | 
|  | 50 | * Example:  1101 is flipped 1011 | 
|  | 51 | */ | 
|  | 52 | static u16 flip_4bit(u16 value) | 
|  | 53 | { | 
|  | 54 | u16 flipped = 0x0000; | 
|  | 55 |  | 
|  | 56 | B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000)); | 
|  | 57 |  | 
|  | 58 | flipped |= (value & 0x0001) << 3; | 
|  | 59 | flipped |= (value & 0x0002) << 1; | 
|  | 60 | flipped |= (value & 0x0004) >> 1; | 
|  | 61 | flipped |= (value & 0x0008) >> 3; | 
|  | 62 |  | 
|  | 63 | return flipped; | 
|  | 64 | } | 
|  | 65 |  | 
|  | 66 | /* Get the freq, as it has to be written to the device. */ | 
|  | 67 | static inline | 
|  | 68 | u16 channel2freq_bg(u8 channel) | 
|  | 69 | { | 
|  | 70 | /* Frequencies are given as frequencies_bg[index] + 2.4GHz | 
|  | 71 | * Starting with channel 1 | 
|  | 72 | */ | 
|  | 73 | static const u16 frequencies_bg[14] = { | 
|  | 74 | 12, 17, 22, 27, | 
|  | 75 | 32, 37, 42, 47, | 
|  | 76 | 52, 57, 62, 67, | 
|  | 77 | 72, 84, | 
|  | 78 | }; | 
|  | 79 |  | 
|  | 80 | if (unlikely(channel < 1 || channel > 14)) { | 
|  | 81 | printk(KERN_INFO "b43legacy: Channel %d is out of range\n", | 
|  | 82 | channel); | 
|  | 83 | dump_stack(); | 
|  | 84 | return 2412; | 
|  | 85 | } | 
|  | 86 |  | 
|  | 87 | return frequencies_bg[channel - 1]; | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | void b43legacy_radio_lock(struct b43legacy_wldev *dev) | 
|  | 91 | { | 
|  | 92 | u32 status; | 
|  | 93 |  | 
| Stefano Brivio | e78c9d2 | 2008-01-23 14:48:50 +0100 | [diff] [blame] | 94 | status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL); | 
|  | 95 | B43legacy_WARN_ON(status & B43legacy_MACCTL_RADIOLOCK); | 
|  | 96 | status |= B43legacy_MACCTL_RADIOLOCK; | 
|  | 97 | b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 98 | mmiowb(); | 
|  | 99 | udelay(10); | 
|  | 100 | } | 
|  | 101 |  | 
|  | 102 | void b43legacy_radio_unlock(struct b43legacy_wldev *dev) | 
|  | 103 | { | 
|  | 104 | u32 status; | 
|  | 105 |  | 
|  | 106 | b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */ | 
| Stefano Brivio | e78c9d2 | 2008-01-23 14:48:50 +0100 | [diff] [blame] | 107 | status = b43legacy_read32(dev, B43legacy_MMIO_MACCTL); | 
|  | 108 | B43legacy_WARN_ON(!(status & B43legacy_MACCTL_RADIOLOCK)); | 
|  | 109 | status &= ~B43legacy_MACCTL_RADIOLOCK; | 
|  | 110 | b43legacy_write32(dev, B43legacy_MMIO_MACCTL, status); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 111 | mmiowb(); | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset) | 
|  | 115 | { | 
|  | 116 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 117 |  | 
|  | 118 | switch (phy->type) { | 
|  | 119 | case B43legacy_PHYTYPE_B: | 
|  | 120 | if (phy->radio_ver == 0x2053) { | 
|  | 121 | if (offset < 0x70) | 
|  | 122 | offset += 0x80; | 
|  | 123 | else if (offset < 0x80) | 
|  | 124 | offset += 0x70; | 
|  | 125 | } else if (phy->radio_ver == 0x2050) | 
|  | 126 | offset |= 0x80; | 
|  | 127 | else | 
|  | 128 | B43legacy_WARN_ON(1); | 
|  | 129 | break; | 
|  | 130 | case B43legacy_PHYTYPE_G: | 
|  | 131 | offset |= 0x80; | 
|  | 132 | break; | 
|  | 133 | default: | 
|  | 134 | B43legacy_BUG_ON(1); | 
|  | 135 | } | 
|  | 136 |  | 
|  | 137 | b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset); | 
|  | 138 | return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW); | 
|  | 139 | } | 
|  | 140 |  | 
|  | 141 | void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val) | 
|  | 142 | { | 
|  | 143 | b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset); | 
|  | 144 | mmiowb(); | 
|  | 145 | b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val); | 
|  | 146 | } | 
|  | 147 |  | 
|  | 148 | static void b43legacy_set_all_gains(struct b43legacy_wldev *dev, | 
|  | 149 | s16 first, s16 second, s16 third) | 
|  | 150 | { | 
|  | 151 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 152 | u16 i; | 
|  | 153 | u16 start = 0x08; | 
|  | 154 | u16 end = 0x18; | 
|  | 155 | u16 offset = 0x0400; | 
|  | 156 | u16 tmp; | 
|  | 157 |  | 
|  | 158 | if (phy->rev <= 1) { | 
|  | 159 | offset = 0x5000; | 
|  | 160 | start = 0x10; | 
|  | 161 | end = 0x20; | 
|  | 162 | } | 
|  | 163 |  | 
|  | 164 | for (i = 0; i < 4; i++) | 
|  | 165 | b43legacy_ilt_write(dev, offset + i, first); | 
|  | 166 |  | 
|  | 167 | for (i = start; i < end; i++) | 
|  | 168 | b43legacy_ilt_write(dev, offset + i, second); | 
|  | 169 |  | 
|  | 170 | if (third != -1) { | 
|  | 171 | tmp = ((u16)third << 14) | ((u16)third << 6); | 
|  | 172 | b43legacy_phy_write(dev, 0x04A0, | 
|  | 173 | (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF) | 
|  | 174 | | tmp); | 
|  | 175 | b43legacy_phy_write(dev, 0x04A1, | 
|  | 176 | (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF) | 
|  | 177 | | tmp); | 
|  | 178 | b43legacy_phy_write(dev, 0x04A2, | 
|  | 179 | (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF) | 
|  | 180 | | tmp); | 
|  | 181 | } | 
|  | 182 | b43legacy_dummy_transmission(dev); | 
|  | 183 | } | 
|  | 184 |  | 
|  | 185 | static void b43legacy_set_original_gains(struct b43legacy_wldev *dev) | 
|  | 186 | { | 
|  | 187 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 188 | u16 i; | 
|  | 189 | u16 tmp; | 
|  | 190 | u16 offset = 0x0400; | 
|  | 191 | u16 start = 0x0008; | 
|  | 192 | u16 end = 0x0018; | 
|  | 193 |  | 
|  | 194 | if (phy->rev <= 1) { | 
|  | 195 | offset = 0x5000; | 
|  | 196 | start = 0x0010; | 
|  | 197 | end = 0x0020; | 
|  | 198 | } | 
|  | 199 |  | 
|  | 200 | for (i = 0; i < 4; i++) { | 
|  | 201 | tmp = (i & 0xFFFC); | 
|  | 202 | tmp |= (i & 0x0001) << 1; | 
|  | 203 | tmp |= (i & 0x0002) >> 1; | 
|  | 204 |  | 
|  | 205 | b43legacy_ilt_write(dev, offset + i, tmp); | 
|  | 206 | } | 
|  | 207 |  | 
|  | 208 | for (i = start; i < end; i++) | 
|  | 209 | b43legacy_ilt_write(dev, offset + i, i - start); | 
|  | 210 |  | 
|  | 211 | b43legacy_phy_write(dev, 0x04A0, | 
|  | 212 | (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF) | 
|  | 213 | | 0x4040); | 
|  | 214 | b43legacy_phy_write(dev, 0x04A1, | 
|  | 215 | (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF) | 
|  | 216 | | 0x4040); | 
|  | 217 | b43legacy_phy_write(dev, 0x04A2, | 
|  | 218 | (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF) | 
|  | 219 | | 0x4000); | 
|  | 220 | b43legacy_dummy_transmission(dev); | 
|  | 221 | } | 
|  | 222 |  | 
|  | 223 | /* Synthetic PU workaround */ | 
|  | 224 | static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev, | 
|  | 225 | u8 channel) | 
|  | 226 | { | 
|  | 227 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 228 |  | 
|  | 229 | might_sleep(); | 
|  | 230 |  | 
|  | 231 | if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) | 
|  | 232 | /* We do not need the workaround. */ | 
|  | 233 | return; | 
|  | 234 |  | 
|  | 235 | if (channel <= 10) | 
|  | 236 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, | 
|  | 237 | channel2freq_bg(channel + 4)); | 
|  | 238 | else | 
|  | 239 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, | 
|  | 240 | channel2freq_bg(channel)); | 
|  | 241 | msleep(1); | 
|  | 242 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, | 
|  | 243 | channel2freq_bg(channel)); | 
|  | 244 | } | 
|  | 245 |  | 
|  | 246 | u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel) | 
|  | 247 | { | 
|  | 248 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 249 | u8 ret = 0; | 
|  | 250 | u16 saved; | 
|  | 251 | u16 rssi; | 
|  | 252 | u16 temp; | 
|  | 253 | int i; | 
|  | 254 | int j = 0; | 
|  | 255 |  | 
|  | 256 | saved = b43legacy_phy_read(dev, 0x0403); | 
|  | 257 | b43legacy_radio_selectchannel(dev, channel, 0); | 
|  | 258 | b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5); | 
|  | 259 | if (phy->aci_hw_rssi) | 
|  | 260 | rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F; | 
|  | 261 | else | 
|  | 262 | rssi = saved & 0x3F; | 
|  | 263 | /* clamp temp to signed 5bit */ | 
|  | 264 | if (rssi > 32) | 
|  | 265 | rssi -= 64; | 
|  | 266 | for (i = 0; i < 100; i++) { | 
|  | 267 | temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F; | 
|  | 268 | if (temp > 32) | 
|  | 269 | temp -= 64; | 
|  | 270 | if (temp < rssi) | 
|  | 271 | j++; | 
|  | 272 | if (j >= 20) | 
|  | 273 | ret = 1; | 
|  | 274 | } | 
|  | 275 | b43legacy_phy_write(dev, 0x0403, saved); | 
|  | 276 |  | 
|  | 277 | return ret; | 
|  | 278 | } | 
|  | 279 |  | 
|  | 280 | u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev) | 
|  | 281 | { | 
|  | 282 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 283 | u8 ret[13]; | 
|  | 284 | unsigned int channel = phy->channel; | 
|  | 285 | unsigned int i; | 
|  | 286 | unsigned int j; | 
|  | 287 | unsigned int start; | 
|  | 288 | unsigned int end; | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 289 |  | 
|  | 290 | if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0))) | 
|  | 291 | return 0; | 
|  | 292 |  | 
| Michael Buesch | bfe6a50 | 2008-01-09 20:15:31 +0100 | [diff] [blame] | 293 | b43legacy_phy_lock(dev); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 294 | b43legacy_radio_lock(dev); | 
|  | 295 | b43legacy_phy_write(dev, 0x0802, | 
|  | 296 | b43legacy_phy_read(dev, 0x0802) & 0xFFFC); | 
|  | 297 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, | 
|  | 298 | b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) | 
|  | 299 | & 0x7FFF); | 
|  | 300 | b43legacy_set_all_gains(dev, 3, 8, 1); | 
|  | 301 |  | 
|  | 302 | start = (channel - 5 > 0) ? channel - 5 : 1; | 
|  | 303 | end = (channel + 5 < 14) ? channel + 5 : 13; | 
|  | 304 |  | 
|  | 305 | for (i = start; i <= end; i++) { | 
|  | 306 | if (abs(channel - i) > 2) | 
|  | 307 | ret[i-1] = b43legacy_radio_aci_detect(dev, i); | 
|  | 308 | } | 
|  | 309 | b43legacy_radio_selectchannel(dev, channel, 0); | 
|  | 310 | b43legacy_phy_write(dev, 0x0802, | 
|  | 311 | (b43legacy_phy_read(dev, 0x0802) & 0xFFFC) | 
|  | 312 | | 0x0003); | 
|  | 313 | b43legacy_phy_write(dev, 0x0403, | 
|  | 314 | b43legacy_phy_read(dev, 0x0403) & 0xFFF8); | 
|  | 315 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, | 
|  | 316 | b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) | 
|  | 317 | | 0x8000); | 
|  | 318 | b43legacy_set_original_gains(dev); | 
|  | 319 | for (i = 0; i < 13; i++) { | 
|  | 320 | if (!ret[i]) | 
|  | 321 | continue; | 
|  | 322 | end = (i + 5 < 13) ? i + 5 : 13; | 
|  | 323 | for (j = i; j < end; j++) | 
|  | 324 | ret[j] = 1; | 
|  | 325 | } | 
|  | 326 | b43legacy_radio_unlock(dev); | 
| Michael Buesch | bfe6a50 | 2008-01-09 20:15:31 +0100 | [diff] [blame] | 327 | b43legacy_phy_unlock(dev); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 328 |  | 
|  | 329 | return ret[channel - 1]; | 
|  | 330 | } | 
|  | 331 |  | 
|  | 332 | /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ | 
|  | 333 | void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val) | 
|  | 334 | { | 
|  | 335 | b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset); | 
|  | 336 | mmiowb(); | 
|  | 337 | b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val); | 
|  | 338 | } | 
|  | 339 |  | 
|  | 340 | /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ | 
|  | 341 | s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset) | 
|  | 342 | { | 
|  | 343 | u16 val; | 
|  | 344 |  | 
|  | 345 | b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset); | 
|  | 346 | val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA); | 
|  | 347 |  | 
|  | 348 | return (s16)val; | 
|  | 349 | } | 
|  | 350 |  | 
|  | 351 | /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ | 
|  | 352 | void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val) | 
|  | 353 | { | 
|  | 354 | u16 i; | 
|  | 355 | s16 tmp; | 
|  | 356 |  | 
|  | 357 | for (i = 0; i < 64; i++) { | 
|  | 358 | tmp = b43legacy_nrssi_hw_read(dev, i); | 
|  | 359 | tmp -= val; | 
| Harvey Harrison | ca21614 | 2008-05-02 13:47:49 -0700 | [diff] [blame] | 360 | tmp = clamp_val(tmp, -32, 31); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 361 | b43legacy_nrssi_hw_write(dev, i, tmp); | 
|  | 362 | } | 
|  | 363 | } | 
|  | 364 |  | 
|  | 365 | /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ | 
|  | 366 | void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev) | 
|  | 367 | { | 
|  | 368 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 369 | s16 i; | 
|  | 370 | s16 delta; | 
|  | 371 | s32 tmp; | 
|  | 372 |  | 
|  | 373 | delta = 0x1F - phy->nrssi[0]; | 
|  | 374 | for (i = 0; i < 64; i++) { | 
|  | 375 | tmp = (i - delta) * phy->nrssislope; | 
|  | 376 | tmp /= 0x10000; | 
|  | 377 | tmp += 0x3A; | 
| Harvey Harrison | ca21614 | 2008-05-02 13:47:49 -0700 | [diff] [blame] | 378 | tmp = clamp_val(tmp, 0, 0x3F); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 379 | phy->nrssi_lt[i] = tmp; | 
|  | 380 | } | 
|  | 381 | } | 
|  | 382 |  | 
|  | 383 | static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev) | 
|  | 384 | { | 
|  | 385 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 386 | u16 backup[20] = { 0 }; | 
|  | 387 | s16 v47F; | 
|  | 388 | u16 i; | 
|  | 389 | u16 saved = 0xFFFF; | 
|  | 390 |  | 
|  | 391 | backup[0] = b43legacy_phy_read(dev, 0x0001); | 
|  | 392 | backup[1] = b43legacy_phy_read(dev, 0x0811); | 
|  | 393 | backup[2] = b43legacy_phy_read(dev, 0x0812); | 
|  | 394 | backup[3] = b43legacy_phy_read(dev, 0x0814); | 
|  | 395 | backup[4] = b43legacy_phy_read(dev, 0x0815); | 
|  | 396 | backup[5] = b43legacy_phy_read(dev, 0x005A); | 
|  | 397 | backup[6] = b43legacy_phy_read(dev, 0x0059); | 
|  | 398 | backup[7] = b43legacy_phy_read(dev, 0x0058); | 
|  | 399 | backup[8] = b43legacy_phy_read(dev, 0x000A); | 
|  | 400 | backup[9] = b43legacy_phy_read(dev, 0x0003); | 
|  | 401 | backup[10] = b43legacy_radio_read16(dev, 0x007A); | 
|  | 402 | backup[11] = b43legacy_radio_read16(dev, 0x0043); | 
|  | 403 |  | 
|  | 404 | b43legacy_phy_write(dev, 0x0429, | 
|  | 405 | b43legacy_phy_read(dev, 0x0429) & 0x7FFF); | 
|  | 406 | b43legacy_phy_write(dev, 0x0001, | 
|  | 407 | (b43legacy_phy_read(dev, 0x0001) & 0x3FFF) | 
|  | 408 | | 0x4000); | 
|  | 409 | b43legacy_phy_write(dev, 0x0811, | 
|  | 410 | b43legacy_phy_read(dev, 0x0811) | 0x000C); | 
|  | 411 | b43legacy_phy_write(dev, 0x0812, | 
|  | 412 | (b43legacy_phy_read(dev, 0x0812) & 0xFFF3) | 
|  | 413 | | 0x0004); | 
|  | 414 | b43legacy_phy_write(dev, 0x0802, | 
|  | 415 | b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2)); | 
|  | 416 | if (phy->rev >= 6) { | 
|  | 417 | backup[12] = b43legacy_phy_read(dev, 0x002E); | 
|  | 418 | backup[13] = b43legacy_phy_read(dev, 0x002F); | 
|  | 419 | backup[14] = b43legacy_phy_read(dev, 0x080F); | 
|  | 420 | backup[15] = b43legacy_phy_read(dev, 0x0810); | 
|  | 421 | backup[16] = b43legacy_phy_read(dev, 0x0801); | 
|  | 422 | backup[17] = b43legacy_phy_read(dev, 0x0060); | 
|  | 423 | backup[18] = b43legacy_phy_read(dev, 0x0014); | 
|  | 424 | backup[19] = b43legacy_phy_read(dev, 0x0478); | 
|  | 425 |  | 
|  | 426 | b43legacy_phy_write(dev, 0x002E, 0); | 
|  | 427 | b43legacy_phy_write(dev, 0x002F, 0); | 
|  | 428 | b43legacy_phy_write(dev, 0x080F, 0); | 
|  | 429 | b43legacy_phy_write(dev, 0x0810, 0); | 
|  | 430 | b43legacy_phy_write(dev, 0x0478, | 
|  | 431 | b43legacy_phy_read(dev, 0x0478) | 0x0100); | 
|  | 432 | b43legacy_phy_write(dev, 0x0801, | 
|  | 433 | b43legacy_phy_read(dev, 0x0801) | 0x0040); | 
|  | 434 | b43legacy_phy_write(dev, 0x0060, | 
|  | 435 | b43legacy_phy_read(dev, 0x0060) | 0x0040); | 
|  | 436 | b43legacy_phy_write(dev, 0x0014, | 
|  | 437 | b43legacy_phy_read(dev, 0x0014) | 0x0200); | 
|  | 438 | } | 
|  | 439 | b43legacy_radio_write16(dev, 0x007A, | 
|  | 440 | b43legacy_radio_read16(dev, 0x007A) | 0x0070); | 
|  | 441 | b43legacy_radio_write16(dev, 0x007A, | 
|  | 442 | b43legacy_radio_read16(dev, 0x007A) | 0x0080); | 
|  | 443 | udelay(30); | 
|  | 444 |  | 
|  | 445 | v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); | 
|  | 446 | if (v47F >= 0x20) | 
|  | 447 | v47F -= 0x40; | 
|  | 448 | if (v47F == 31) { | 
|  | 449 | for (i = 7; i >= 4; i--) { | 
|  | 450 | b43legacy_radio_write16(dev, 0x007B, i); | 
|  | 451 | udelay(20); | 
|  | 452 | v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) | 
|  | 453 | & 0x003F); | 
|  | 454 | if (v47F >= 0x20) | 
|  | 455 | v47F -= 0x40; | 
|  | 456 | if (v47F < 31 && saved == 0xFFFF) | 
|  | 457 | saved = i; | 
|  | 458 | } | 
|  | 459 | if (saved == 0xFFFF) | 
|  | 460 | saved = 4; | 
|  | 461 | } else { | 
|  | 462 | b43legacy_radio_write16(dev, 0x007A, | 
|  | 463 | b43legacy_radio_read16(dev, 0x007A) | 
|  | 464 | & 0x007F); | 
|  | 465 | b43legacy_phy_write(dev, 0x0814, | 
|  | 466 | b43legacy_phy_read(dev, 0x0814) | 0x0001); | 
|  | 467 | b43legacy_phy_write(dev, 0x0815, | 
|  | 468 | b43legacy_phy_read(dev, 0x0815) & 0xFFFE); | 
|  | 469 | b43legacy_phy_write(dev, 0x0811, | 
|  | 470 | b43legacy_phy_read(dev, 0x0811) | 0x000C); | 
|  | 471 | b43legacy_phy_write(dev, 0x0812, | 
|  | 472 | b43legacy_phy_read(dev, 0x0812) | 0x000C); | 
|  | 473 | b43legacy_phy_write(dev, 0x0811, | 
|  | 474 | b43legacy_phy_read(dev, 0x0811) | 0x0030); | 
|  | 475 | b43legacy_phy_write(dev, 0x0812, | 
|  | 476 | b43legacy_phy_read(dev, 0x0812) | 0x0030); | 
|  | 477 | b43legacy_phy_write(dev, 0x005A, 0x0480); | 
|  | 478 | b43legacy_phy_write(dev, 0x0059, 0x0810); | 
|  | 479 | b43legacy_phy_write(dev, 0x0058, 0x000D); | 
|  | 480 | if (phy->analog == 0) | 
|  | 481 | b43legacy_phy_write(dev, 0x0003, 0x0122); | 
|  | 482 | else | 
|  | 483 | b43legacy_phy_write(dev, 0x000A, | 
|  | 484 | b43legacy_phy_read(dev, 0x000A) | 
|  | 485 | | 0x2000); | 
|  | 486 | b43legacy_phy_write(dev, 0x0814, | 
|  | 487 | b43legacy_phy_read(dev, 0x0814) | 0x0004); | 
|  | 488 | b43legacy_phy_write(dev, 0x0815, | 
|  | 489 | b43legacy_phy_read(dev, 0x0815) & 0xFFFB); | 
|  | 490 | b43legacy_phy_write(dev, 0x0003, | 
|  | 491 | (b43legacy_phy_read(dev, 0x0003) & 0xFF9F) | 
|  | 492 | | 0x0040); | 
|  | 493 | b43legacy_radio_write16(dev, 0x007A, | 
|  | 494 | b43legacy_radio_read16(dev, 0x007A) | 
|  | 495 | | 0x000F); | 
|  | 496 | b43legacy_set_all_gains(dev, 3, 0, 1); | 
|  | 497 | b43legacy_radio_write16(dev, 0x0043, | 
|  | 498 | (b43legacy_radio_read16(dev, 0x0043) | 
|  | 499 | & 0x00F0) | 0x000F); | 
|  | 500 | udelay(30); | 
|  | 501 | v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); | 
|  | 502 | if (v47F >= 0x20) | 
|  | 503 | v47F -= 0x40; | 
|  | 504 | if (v47F == -32) { | 
|  | 505 | for (i = 0; i < 4; i++) { | 
|  | 506 | b43legacy_radio_write16(dev, 0x007B, i); | 
|  | 507 | udelay(20); | 
|  | 508 | v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> | 
|  | 509 | 8) & 0x003F); | 
|  | 510 | if (v47F >= 0x20) | 
|  | 511 | v47F -= 0x40; | 
|  | 512 | if (v47F > -31 && saved == 0xFFFF) | 
|  | 513 | saved = i; | 
|  | 514 | } | 
|  | 515 | if (saved == 0xFFFF) | 
|  | 516 | saved = 3; | 
|  | 517 | } else | 
|  | 518 | saved = 0; | 
|  | 519 | } | 
|  | 520 | b43legacy_radio_write16(dev, 0x007B, saved); | 
|  | 521 |  | 
|  | 522 | if (phy->rev >= 6) { | 
|  | 523 | b43legacy_phy_write(dev, 0x002E, backup[12]); | 
|  | 524 | b43legacy_phy_write(dev, 0x002F, backup[13]); | 
|  | 525 | b43legacy_phy_write(dev, 0x080F, backup[14]); | 
|  | 526 | b43legacy_phy_write(dev, 0x0810, backup[15]); | 
|  | 527 | } | 
|  | 528 | b43legacy_phy_write(dev, 0x0814, backup[3]); | 
|  | 529 | b43legacy_phy_write(dev, 0x0815, backup[4]); | 
|  | 530 | b43legacy_phy_write(dev, 0x005A, backup[5]); | 
|  | 531 | b43legacy_phy_write(dev, 0x0059, backup[6]); | 
|  | 532 | b43legacy_phy_write(dev, 0x0058, backup[7]); | 
|  | 533 | b43legacy_phy_write(dev, 0x000A, backup[8]); | 
|  | 534 | b43legacy_phy_write(dev, 0x0003, backup[9]); | 
|  | 535 | b43legacy_radio_write16(dev, 0x0043, backup[11]); | 
|  | 536 | b43legacy_radio_write16(dev, 0x007A, backup[10]); | 
|  | 537 | b43legacy_phy_write(dev, 0x0802, | 
|  | 538 | b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2); | 
|  | 539 | b43legacy_phy_write(dev, 0x0429, | 
|  | 540 | b43legacy_phy_read(dev, 0x0429) | 0x8000); | 
|  | 541 | b43legacy_set_original_gains(dev); | 
|  | 542 | if (phy->rev >= 6) { | 
|  | 543 | b43legacy_phy_write(dev, 0x0801, backup[16]); | 
|  | 544 | b43legacy_phy_write(dev, 0x0060, backup[17]); | 
|  | 545 | b43legacy_phy_write(dev, 0x0014, backup[18]); | 
|  | 546 | b43legacy_phy_write(dev, 0x0478, backup[19]); | 
|  | 547 | } | 
|  | 548 | b43legacy_phy_write(dev, 0x0001, backup[0]); | 
|  | 549 | b43legacy_phy_write(dev, 0x0812, backup[2]); | 
|  | 550 | b43legacy_phy_write(dev, 0x0811, backup[1]); | 
|  | 551 | } | 
|  | 552 |  | 
|  | 553 | void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev) | 
|  | 554 | { | 
|  | 555 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 556 | u16 backup[18] = { 0 }; | 
|  | 557 | u16 tmp; | 
|  | 558 | s16 nrssi0; | 
|  | 559 | s16 nrssi1; | 
|  | 560 |  | 
|  | 561 | switch (phy->type) { | 
|  | 562 | case B43legacy_PHYTYPE_B: | 
|  | 563 | backup[0] = b43legacy_radio_read16(dev, 0x007A); | 
|  | 564 | backup[1] = b43legacy_radio_read16(dev, 0x0052); | 
|  | 565 | backup[2] = b43legacy_radio_read16(dev, 0x0043); | 
|  | 566 | backup[3] = b43legacy_phy_read(dev, 0x0030); | 
|  | 567 | backup[4] = b43legacy_phy_read(dev, 0x0026); | 
|  | 568 | backup[5] = b43legacy_phy_read(dev, 0x0015); | 
|  | 569 | backup[6] = b43legacy_phy_read(dev, 0x002A); | 
|  | 570 | backup[7] = b43legacy_phy_read(dev, 0x0020); | 
|  | 571 | backup[8] = b43legacy_phy_read(dev, 0x005A); | 
|  | 572 | backup[9] = b43legacy_phy_read(dev, 0x0059); | 
|  | 573 | backup[10] = b43legacy_phy_read(dev, 0x0058); | 
|  | 574 | backup[11] = b43legacy_read16(dev, 0x03E2); | 
|  | 575 | backup[12] = b43legacy_read16(dev, 0x03E6); | 
|  | 576 | backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); | 
|  | 577 |  | 
|  | 578 | tmp  = b43legacy_radio_read16(dev, 0x007A); | 
|  | 579 | tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; | 
|  | 580 | b43legacy_radio_write16(dev, 0x007A, tmp); | 
|  | 581 | b43legacy_phy_write(dev, 0x0030, 0x00FF); | 
|  | 582 | b43legacy_write16(dev, 0x03EC, 0x7F7F); | 
|  | 583 | b43legacy_phy_write(dev, 0x0026, 0x0000); | 
|  | 584 | b43legacy_phy_write(dev, 0x0015, | 
|  | 585 | b43legacy_phy_read(dev, 0x0015) | 0x0020); | 
|  | 586 | b43legacy_phy_write(dev, 0x002A, 0x08A3); | 
|  | 587 | b43legacy_radio_write16(dev, 0x007A, | 
|  | 588 | b43legacy_radio_read16(dev, 0x007A) | 
|  | 589 | | 0x0080); | 
|  | 590 |  | 
|  | 591 | nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027); | 
|  | 592 | b43legacy_radio_write16(dev, 0x007A, | 
|  | 593 | b43legacy_radio_read16(dev, 0x007A) | 
|  | 594 | & 0x007F); | 
|  | 595 | if (phy->analog >= 2) | 
|  | 596 | b43legacy_write16(dev, 0x03E6, 0x0040); | 
|  | 597 | else if (phy->analog == 0) | 
|  | 598 | b43legacy_write16(dev, 0x03E6, 0x0122); | 
|  | 599 | else | 
|  | 600 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, | 
|  | 601 | b43legacy_read16(dev, | 
|  | 602 | B43legacy_MMIO_CHANNEL_EXT) & 0x2000); | 
|  | 603 | b43legacy_phy_write(dev, 0x0020, 0x3F3F); | 
|  | 604 | b43legacy_phy_write(dev, 0x0015, 0xF330); | 
|  | 605 | b43legacy_radio_write16(dev, 0x005A, 0x0060); | 
|  | 606 | b43legacy_radio_write16(dev, 0x0043, | 
|  | 607 | b43legacy_radio_read16(dev, 0x0043) | 
|  | 608 | & 0x00F0); | 
|  | 609 | b43legacy_phy_write(dev, 0x005A, 0x0480); | 
|  | 610 | b43legacy_phy_write(dev, 0x0059, 0x0810); | 
|  | 611 | b43legacy_phy_write(dev, 0x0058, 0x000D); | 
|  | 612 | udelay(20); | 
|  | 613 |  | 
|  | 614 | nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027); | 
|  | 615 | b43legacy_phy_write(dev, 0x0030, backup[3]); | 
|  | 616 | b43legacy_radio_write16(dev, 0x007A, backup[0]); | 
|  | 617 | b43legacy_write16(dev, 0x03E2, backup[11]); | 
|  | 618 | b43legacy_phy_write(dev, 0x0026, backup[4]); | 
|  | 619 | b43legacy_phy_write(dev, 0x0015, backup[5]); | 
|  | 620 | b43legacy_phy_write(dev, 0x002A, backup[6]); | 
|  | 621 | b43legacy_synth_pu_workaround(dev, phy->channel); | 
|  | 622 | if (phy->analog != 0) | 
|  | 623 | b43legacy_write16(dev, 0x03F4, backup[13]); | 
|  | 624 |  | 
|  | 625 | b43legacy_phy_write(dev, 0x0020, backup[7]); | 
|  | 626 | b43legacy_phy_write(dev, 0x005A, backup[8]); | 
|  | 627 | b43legacy_phy_write(dev, 0x0059, backup[9]); | 
|  | 628 | b43legacy_phy_write(dev, 0x0058, backup[10]); | 
|  | 629 | b43legacy_radio_write16(dev, 0x0052, backup[1]); | 
|  | 630 | b43legacy_radio_write16(dev, 0x0043, backup[2]); | 
|  | 631 |  | 
|  | 632 | if (nrssi0 == nrssi1) | 
|  | 633 | phy->nrssislope = 0x00010000; | 
|  | 634 | else | 
|  | 635 | phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); | 
|  | 636 |  | 
|  | 637 | if (nrssi0 <= -4) { | 
|  | 638 | phy->nrssi[0] = nrssi0; | 
|  | 639 | phy->nrssi[1] = nrssi1; | 
|  | 640 | } | 
|  | 641 | break; | 
|  | 642 | case B43legacy_PHYTYPE_G: | 
|  | 643 | if (phy->radio_rev >= 9) | 
|  | 644 | return; | 
|  | 645 | if (phy->radio_rev == 8) | 
|  | 646 | b43legacy_calc_nrssi_offset(dev); | 
|  | 647 |  | 
|  | 648 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, | 
|  | 649 | b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) | 
|  | 650 | & 0x7FFF); | 
|  | 651 | b43legacy_phy_write(dev, 0x0802, | 
|  | 652 | b43legacy_phy_read(dev, 0x0802) & 0xFFFC); | 
|  | 653 | backup[7] = b43legacy_read16(dev, 0x03E2); | 
|  | 654 | b43legacy_write16(dev, 0x03E2, | 
|  | 655 | b43legacy_read16(dev, 0x03E2) | 0x8000); | 
|  | 656 | backup[0] = b43legacy_radio_read16(dev, 0x007A); | 
|  | 657 | backup[1] = b43legacy_radio_read16(dev, 0x0052); | 
|  | 658 | backup[2] = b43legacy_radio_read16(dev, 0x0043); | 
|  | 659 | backup[3] = b43legacy_phy_read(dev, 0x0015); | 
|  | 660 | backup[4] = b43legacy_phy_read(dev, 0x005A); | 
|  | 661 | backup[5] = b43legacy_phy_read(dev, 0x0059); | 
|  | 662 | backup[6] = b43legacy_phy_read(dev, 0x0058); | 
|  | 663 | backup[8] = b43legacy_read16(dev, 0x03E6); | 
|  | 664 | backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); | 
|  | 665 | if (phy->rev >= 3) { | 
|  | 666 | backup[10] = b43legacy_phy_read(dev, 0x002E); | 
|  | 667 | backup[11] = b43legacy_phy_read(dev, 0x002F); | 
|  | 668 | backup[12] = b43legacy_phy_read(dev, 0x080F); | 
|  | 669 | backup[13] = b43legacy_phy_read(dev, | 
|  | 670 | B43legacy_PHY_G_LO_CONTROL); | 
|  | 671 | backup[14] = b43legacy_phy_read(dev, 0x0801); | 
|  | 672 | backup[15] = b43legacy_phy_read(dev, 0x0060); | 
|  | 673 | backup[16] = b43legacy_phy_read(dev, 0x0014); | 
|  | 674 | backup[17] = b43legacy_phy_read(dev, 0x0478); | 
|  | 675 | b43legacy_phy_write(dev, 0x002E, 0); | 
|  | 676 | b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0); | 
|  | 677 | switch (phy->rev) { | 
|  | 678 | case 4: case 6: case 7: | 
|  | 679 | b43legacy_phy_write(dev, 0x0478, | 
|  | 680 | b43legacy_phy_read(dev, | 
|  | 681 | 0x0478) | 0x0100); | 
|  | 682 | b43legacy_phy_write(dev, 0x0801, | 
|  | 683 | b43legacy_phy_read(dev, | 
|  | 684 | 0x0801) | 0x0040); | 
|  | 685 | break; | 
|  | 686 | case 3: case 5: | 
|  | 687 | b43legacy_phy_write(dev, 0x0801, | 
|  | 688 | b43legacy_phy_read(dev, | 
|  | 689 | 0x0801) & 0xFFBF); | 
|  | 690 | break; | 
|  | 691 | } | 
|  | 692 | b43legacy_phy_write(dev, 0x0060, | 
|  | 693 | b43legacy_phy_read(dev, 0x0060) | 
|  | 694 | | 0x0040); | 
|  | 695 | b43legacy_phy_write(dev, 0x0014, | 
|  | 696 | b43legacy_phy_read(dev, 0x0014) | 
|  | 697 | | 0x0200); | 
|  | 698 | } | 
|  | 699 | b43legacy_radio_write16(dev, 0x007A, | 
|  | 700 | b43legacy_radio_read16(dev, 0x007A) | 
|  | 701 | | 0x0070); | 
|  | 702 | b43legacy_set_all_gains(dev, 0, 8, 0); | 
|  | 703 | b43legacy_radio_write16(dev, 0x007A, | 
|  | 704 | b43legacy_radio_read16(dev, 0x007A) | 
|  | 705 | & 0x00F7); | 
|  | 706 | if (phy->rev >= 2) { | 
|  | 707 | b43legacy_phy_write(dev, 0x0811, | 
|  | 708 | (b43legacy_phy_read(dev, 0x0811) | 
|  | 709 | & 0xFFCF) | 0x0030); | 
|  | 710 | b43legacy_phy_write(dev, 0x0812, | 
|  | 711 | (b43legacy_phy_read(dev, 0x0812) | 
|  | 712 | & 0xFFCF) | 0x0010); | 
|  | 713 | } | 
|  | 714 | b43legacy_radio_write16(dev, 0x007A, | 
|  | 715 | b43legacy_radio_read16(dev, 0x007A) | 
|  | 716 | | 0x0080); | 
|  | 717 | udelay(20); | 
|  | 718 |  | 
|  | 719 | nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); | 
|  | 720 | if (nrssi0 >= 0x0020) | 
|  | 721 | nrssi0 -= 0x0040; | 
|  | 722 |  | 
|  | 723 | b43legacy_radio_write16(dev, 0x007A, | 
|  | 724 | b43legacy_radio_read16(dev, 0x007A) | 
|  | 725 | & 0x007F); | 
|  | 726 | if (phy->analog >= 2) | 
|  | 727 | b43legacy_phy_write(dev, 0x0003, | 
|  | 728 | (b43legacy_phy_read(dev, 0x0003) | 
|  | 729 | & 0xFF9F) | 0x0040); | 
|  | 730 |  | 
|  | 731 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, | 
|  | 732 | b43legacy_read16(dev, | 
|  | 733 | B43legacy_MMIO_CHANNEL_EXT) | 0x2000); | 
|  | 734 | b43legacy_radio_write16(dev, 0x007A, | 
|  | 735 | b43legacy_radio_read16(dev, 0x007A) | 
|  | 736 | | 0x000F); | 
|  | 737 | b43legacy_phy_write(dev, 0x0015, 0xF330); | 
|  | 738 | if (phy->rev >= 2) { | 
|  | 739 | b43legacy_phy_write(dev, 0x0812, | 
|  | 740 | (b43legacy_phy_read(dev, 0x0812) | 
|  | 741 | & 0xFFCF) | 0x0020); | 
|  | 742 | b43legacy_phy_write(dev, 0x0811, | 
|  | 743 | (b43legacy_phy_read(dev, 0x0811) | 
|  | 744 | & 0xFFCF) | 0x0020); | 
|  | 745 | } | 
|  | 746 |  | 
|  | 747 | b43legacy_set_all_gains(dev, 3, 0, 1); | 
|  | 748 | if (phy->radio_rev == 8) | 
|  | 749 | b43legacy_radio_write16(dev, 0x0043, 0x001F); | 
|  | 750 | else { | 
|  | 751 | tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F; | 
|  | 752 | b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060); | 
|  | 753 | tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0; | 
|  | 754 | b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009); | 
|  | 755 | } | 
|  | 756 | b43legacy_phy_write(dev, 0x005A, 0x0480); | 
|  | 757 | b43legacy_phy_write(dev, 0x0059, 0x0810); | 
|  | 758 | b43legacy_phy_write(dev, 0x0058, 0x000D); | 
|  | 759 | udelay(20); | 
|  | 760 | nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F); | 
|  | 761 | if (nrssi1 >= 0x0020) | 
|  | 762 | nrssi1 -= 0x0040; | 
|  | 763 | if (nrssi0 == nrssi1) | 
|  | 764 | phy->nrssislope = 0x00010000; | 
|  | 765 | else | 
|  | 766 | phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1); | 
|  | 767 | if (nrssi0 >= -4) { | 
|  | 768 | phy->nrssi[0] = nrssi1; | 
|  | 769 | phy->nrssi[1] = nrssi0; | 
|  | 770 | } | 
|  | 771 | if (phy->rev >= 3) { | 
|  | 772 | b43legacy_phy_write(dev, 0x002E, backup[10]); | 
|  | 773 | b43legacy_phy_write(dev, 0x002F, backup[11]); | 
|  | 774 | b43legacy_phy_write(dev, 0x080F, backup[12]); | 
|  | 775 | b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, | 
|  | 776 | backup[13]); | 
|  | 777 | } | 
|  | 778 | if (phy->rev >= 2) { | 
|  | 779 | b43legacy_phy_write(dev, 0x0812, | 
|  | 780 | b43legacy_phy_read(dev, 0x0812) | 
|  | 781 | & 0xFFCF); | 
|  | 782 | b43legacy_phy_write(dev, 0x0811, | 
|  | 783 | b43legacy_phy_read(dev, 0x0811) | 
|  | 784 | & 0xFFCF); | 
|  | 785 | } | 
|  | 786 |  | 
|  | 787 | b43legacy_radio_write16(dev, 0x007A, backup[0]); | 
|  | 788 | b43legacy_radio_write16(dev, 0x0052, backup[1]); | 
|  | 789 | b43legacy_radio_write16(dev, 0x0043, backup[2]); | 
|  | 790 | b43legacy_write16(dev, 0x03E2, backup[7]); | 
|  | 791 | b43legacy_write16(dev, 0x03E6, backup[8]); | 
|  | 792 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]); | 
|  | 793 | b43legacy_phy_write(dev, 0x0015, backup[3]); | 
|  | 794 | b43legacy_phy_write(dev, 0x005A, backup[4]); | 
|  | 795 | b43legacy_phy_write(dev, 0x0059, backup[5]); | 
|  | 796 | b43legacy_phy_write(dev, 0x0058, backup[6]); | 
|  | 797 | b43legacy_synth_pu_workaround(dev, phy->channel); | 
|  | 798 | b43legacy_phy_write(dev, 0x0802, | 
|  | 799 | b43legacy_phy_read(dev, 0x0802) | 0x0003); | 
|  | 800 | b43legacy_set_original_gains(dev); | 
|  | 801 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, | 
|  | 802 | b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) | 
|  | 803 | | 0x8000); | 
|  | 804 | if (phy->rev >= 3) { | 
|  | 805 | b43legacy_phy_write(dev, 0x0801, backup[14]); | 
|  | 806 | b43legacy_phy_write(dev, 0x0060, backup[15]); | 
|  | 807 | b43legacy_phy_write(dev, 0x0014, backup[16]); | 
|  | 808 | b43legacy_phy_write(dev, 0x0478, backup[17]); | 
|  | 809 | } | 
|  | 810 | b43legacy_nrssi_mem_update(dev); | 
|  | 811 | b43legacy_calc_nrssi_threshold(dev); | 
|  | 812 | break; | 
|  | 813 | default: | 
|  | 814 | B43legacy_BUG_ON(1); | 
|  | 815 | } | 
|  | 816 | } | 
|  | 817 |  | 
|  | 818 | void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev) | 
|  | 819 | { | 
|  | 820 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 821 | s32 threshold; | 
|  | 822 | s32 a; | 
|  | 823 | s32 b; | 
|  | 824 | s16 tmp16; | 
|  | 825 | u16 tmp_u16; | 
|  | 826 |  | 
|  | 827 | switch (phy->type) { | 
|  | 828 | case B43legacy_PHYTYPE_B: { | 
|  | 829 | if (phy->radio_ver != 0x2050) | 
|  | 830 | return; | 
| Larry Finger | 7797aa3 | 2007-11-09 16:57:34 -0600 | [diff] [blame] | 831 | if (!(dev->dev->bus->sprom.boardflags_lo & | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 832 | B43legacy_BFL_RSSI)) | 
|  | 833 | return; | 
|  | 834 |  | 
|  | 835 | if (phy->radio_rev >= 6) { | 
|  | 836 | threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32; | 
|  | 837 | threshold += 20 * (phy->nrssi[0] + 1); | 
|  | 838 | threshold /= 40; | 
|  | 839 | } else | 
|  | 840 | threshold = phy->nrssi[1] - 5; | 
|  | 841 |  | 
| Harvey Harrison | ca21614 | 2008-05-02 13:47:49 -0700 | [diff] [blame] | 842 | threshold = clamp_val(threshold, 0, 0x3E); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 843 | b43legacy_phy_read(dev, 0x0020); /* dummy read */ | 
|  | 844 | b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8) | 
|  | 845 | | 0x001C); | 
|  | 846 |  | 
|  | 847 | if (phy->radio_rev >= 6) { | 
|  | 848 | b43legacy_phy_write(dev, 0x0087, 0x0E0D); | 
|  | 849 | b43legacy_phy_write(dev, 0x0086, 0x0C0B); | 
|  | 850 | b43legacy_phy_write(dev, 0x0085, 0x0A09); | 
|  | 851 | b43legacy_phy_write(dev, 0x0084, 0x0808); | 
|  | 852 | b43legacy_phy_write(dev, 0x0083, 0x0808); | 
|  | 853 | b43legacy_phy_write(dev, 0x0082, 0x0604); | 
|  | 854 | b43legacy_phy_write(dev, 0x0081, 0x0302); | 
|  | 855 | b43legacy_phy_write(dev, 0x0080, 0x0100); | 
|  | 856 | } | 
|  | 857 | break; | 
|  | 858 | } | 
|  | 859 | case B43legacy_PHYTYPE_G: | 
|  | 860 | if (!phy->gmode || | 
| Larry Finger | 7797aa3 | 2007-11-09 16:57:34 -0600 | [diff] [blame] | 861 | !(dev->dev->bus->sprom.boardflags_lo & | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 862 | B43legacy_BFL_RSSI)) { | 
|  | 863 | tmp16 = b43legacy_nrssi_hw_read(dev, 0x20); | 
|  | 864 | if (tmp16 >= 0x20) | 
|  | 865 | tmp16 -= 0x40; | 
|  | 866 | if (tmp16 < 3) | 
|  | 867 | b43legacy_phy_write(dev, 0x048A, | 
|  | 868 | (b43legacy_phy_read(dev, | 
|  | 869 | 0x048A) & 0xF000) | 0x09EB); | 
|  | 870 | else | 
|  | 871 | b43legacy_phy_write(dev, 0x048A, | 
|  | 872 | (b43legacy_phy_read(dev, | 
|  | 873 | 0x048A) & 0xF000) | 0x0AED); | 
|  | 874 | } else { | 
|  | 875 | if (phy->interfmode == | 
|  | 876 | B43legacy_RADIO_INTERFMODE_NONWLAN) { | 
|  | 877 | a = 0xE; | 
|  | 878 | b = 0xA; | 
|  | 879 | } else if (!phy->aci_wlan_automatic && | 
|  | 880 | phy->aci_enable) { | 
|  | 881 | a = 0x13; | 
|  | 882 | b = 0x12; | 
|  | 883 | } else { | 
|  | 884 | a = 0xE; | 
|  | 885 | b = 0x11; | 
|  | 886 | } | 
|  | 887 |  | 
|  | 888 | a = a * (phy->nrssi[1] - phy->nrssi[0]); | 
|  | 889 | a += (phy->nrssi[0] << 6); | 
|  | 890 | if (a < 32) | 
|  | 891 | a += 31; | 
|  | 892 | else | 
|  | 893 | a += 32; | 
|  | 894 | a = a >> 6; | 
| Harvey Harrison | ca21614 | 2008-05-02 13:47:49 -0700 | [diff] [blame] | 895 | a = clamp_val(a, -31, 31); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 896 |  | 
|  | 897 | b = b * (phy->nrssi[1] - phy->nrssi[0]); | 
|  | 898 | b += (phy->nrssi[0] << 6); | 
|  | 899 | if (b < 32) | 
|  | 900 | b += 31; | 
|  | 901 | else | 
|  | 902 | b += 32; | 
|  | 903 | b = b >> 6; | 
| Harvey Harrison | ca21614 | 2008-05-02 13:47:49 -0700 | [diff] [blame] | 904 | b = clamp_val(b, -31, 31); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 905 |  | 
|  | 906 | tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000; | 
|  | 907 | tmp_u16 |= ((u32)b & 0x0000003F); | 
|  | 908 | tmp_u16 |= (((u32)a & 0x0000003F) << 6); | 
|  | 909 | b43legacy_phy_write(dev, 0x048A, tmp_u16); | 
|  | 910 | } | 
|  | 911 | break; | 
|  | 912 | default: | 
|  | 913 | B43legacy_BUG_ON(1); | 
|  | 914 | } | 
|  | 915 | } | 
|  | 916 |  | 
|  | 917 | /* Stack implementation to save/restore values from the | 
|  | 918 | * interference mitigation code. | 
|  | 919 | * It is save to restore values in random order. | 
|  | 920 | */ | 
|  | 921 | static void _stack_save(u32 *_stackptr, size_t *stackidx, | 
|  | 922 | u8 id, u16 offset, u16 value) | 
|  | 923 | { | 
|  | 924 | u32 *stackptr = &(_stackptr[*stackidx]); | 
|  | 925 |  | 
|  | 926 | B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000)); | 
|  | 927 | B43legacy_WARN_ON(!((id & 0xF8) == 0x00)); | 
|  | 928 | *stackptr = offset; | 
|  | 929 | *stackptr |= ((u32)id) << 13; | 
|  | 930 | *stackptr |= ((u32)value) << 16; | 
|  | 931 | (*stackidx)++; | 
|  | 932 | B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE)); | 
|  | 933 | } | 
|  | 934 |  | 
|  | 935 | static u16 _stack_restore(u32 *stackptr, | 
|  | 936 | u8 id, u16 offset) | 
|  | 937 | { | 
|  | 938 | size_t i; | 
|  | 939 |  | 
|  | 940 | B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000)); | 
|  | 941 | B43legacy_WARN_ON(!((id & 0xF8) == 0x00)); | 
|  | 942 | for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) { | 
|  | 943 | if ((*stackptr & 0x00001FFF) != offset) | 
|  | 944 | continue; | 
|  | 945 | if (((*stackptr & 0x00007000) >> 13) != id) | 
|  | 946 | continue; | 
|  | 947 | return ((*stackptr & 0xFFFF0000) >> 16); | 
|  | 948 | } | 
|  | 949 | B43legacy_BUG_ON(1); | 
|  | 950 |  | 
|  | 951 | return 0; | 
|  | 952 | } | 
|  | 953 |  | 
|  | 954 | #define phy_stacksave(offset)					\ | 
|  | 955 | do {							\ | 
|  | 956 | _stack_save(stack, &stackidx, 0x1, (offset),	\ | 
|  | 957 | b43legacy_phy_read(dev, (offset)));	\ | 
|  | 958 | } while (0) | 
|  | 959 | #define phy_stackrestore(offset)				\ | 
|  | 960 | do {							\ | 
|  | 961 | b43legacy_phy_write(dev, (offset),		\ | 
|  | 962 | _stack_restore(stack, 0x1,	\ | 
|  | 963 | (offset)));			\ | 
|  | 964 | } while (0) | 
|  | 965 | #define radio_stacksave(offset)						\ | 
|  | 966 | do {								\ | 
|  | 967 | _stack_save(stack, &stackidx, 0x2, (offset),		\ | 
|  | 968 | b43legacy_radio_read16(dev, (offset)));	\ | 
|  | 969 | } while (0) | 
|  | 970 | #define radio_stackrestore(offset)					\ | 
|  | 971 | do {								\ | 
|  | 972 | b43legacy_radio_write16(dev, (offset),			\ | 
|  | 973 | _stack_restore(stack, 0x2,	\ | 
|  | 974 | (offset)));			\ | 
|  | 975 | } while (0) | 
|  | 976 | #define ilt_stacksave(offset)					\ | 
|  | 977 | do {							\ | 
|  | 978 | _stack_save(stack, &stackidx, 0x3, (offset),	\ | 
|  | 979 | b43legacy_ilt_read(dev, (offset)));	\ | 
|  | 980 | } while (0) | 
|  | 981 | #define ilt_stackrestore(offset)				\ | 
|  | 982 | do {							\ | 
|  | 983 | b43legacy_ilt_write(dev, (offset),		\ | 
|  | 984 | _stack_restore(stack, 0x3,	\ | 
|  | 985 | (offset)));	\ | 
|  | 986 | } while (0) | 
|  | 987 |  | 
|  | 988 | static void | 
|  | 989 | b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev, | 
|  | 990 | int mode) | 
|  | 991 | { | 
|  | 992 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 993 | u16 tmp; | 
|  | 994 | u16 flipped; | 
|  | 995 | u32 tmp32; | 
|  | 996 | size_t stackidx = 0; | 
|  | 997 | u32 *stack = phy->interfstack; | 
|  | 998 |  | 
|  | 999 | switch (mode) { | 
|  | 1000 | case B43legacy_RADIO_INTERFMODE_NONWLAN: | 
|  | 1001 | if (phy->rev != 1) { | 
|  | 1002 | b43legacy_phy_write(dev, 0x042B, | 
|  | 1003 | b43legacy_phy_read(dev, 0x042B) | 
|  | 1004 | | 0x0800); | 
|  | 1005 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, | 
|  | 1006 | b43legacy_phy_read(dev, | 
|  | 1007 | B43legacy_PHY_G_CRS) & ~0x4000); | 
|  | 1008 | break; | 
|  | 1009 | } | 
|  | 1010 | radio_stacksave(0x0078); | 
|  | 1011 | tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E); | 
|  | 1012 | flipped = flip_4bit(tmp); | 
|  | 1013 | if (flipped < 10 && flipped >= 8) | 
|  | 1014 | flipped = 7; | 
|  | 1015 | else if (flipped >= 10) | 
|  | 1016 | flipped -= 3; | 
|  | 1017 | flipped = flip_4bit(flipped); | 
|  | 1018 | flipped = (flipped << 1) | 0x0020; | 
|  | 1019 | b43legacy_radio_write16(dev, 0x0078, flipped); | 
|  | 1020 |  | 
|  | 1021 | b43legacy_calc_nrssi_threshold(dev); | 
|  | 1022 |  | 
|  | 1023 | phy_stacksave(0x0406); | 
|  | 1024 | b43legacy_phy_write(dev, 0x0406, 0x7E28); | 
|  | 1025 |  | 
|  | 1026 | b43legacy_phy_write(dev, 0x042B, | 
|  | 1027 | b43legacy_phy_read(dev, 0x042B) | 0x0800); | 
|  | 1028 | b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, | 
|  | 1029 | b43legacy_phy_read(dev, | 
|  | 1030 | B43legacy_PHY_RADIO_BITFIELD) | 0x1000); | 
|  | 1031 |  | 
|  | 1032 | phy_stacksave(0x04A0); | 
|  | 1033 | b43legacy_phy_write(dev, 0x04A0, | 
|  | 1034 | (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0) | 
|  | 1035 | | 0x0008); | 
|  | 1036 | phy_stacksave(0x04A1); | 
|  | 1037 | b43legacy_phy_write(dev, 0x04A1, | 
|  | 1038 | (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0) | 
|  | 1039 | | 0x0605); | 
|  | 1040 | phy_stacksave(0x04A2); | 
|  | 1041 | b43legacy_phy_write(dev, 0x04A2, | 
|  | 1042 | (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0) | 
|  | 1043 | | 0x0204); | 
|  | 1044 | phy_stacksave(0x04A8); | 
|  | 1045 | b43legacy_phy_write(dev, 0x04A8, | 
|  | 1046 | (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0) | 
|  | 1047 | | 0x0803); | 
|  | 1048 | phy_stacksave(0x04AB); | 
|  | 1049 | b43legacy_phy_write(dev, 0x04AB, | 
|  | 1050 | (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0) | 
|  | 1051 | | 0x0605); | 
|  | 1052 |  | 
|  | 1053 | phy_stacksave(0x04A7); | 
|  | 1054 | b43legacy_phy_write(dev, 0x04A7, 0x0002); | 
|  | 1055 | phy_stacksave(0x04A3); | 
|  | 1056 | b43legacy_phy_write(dev, 0x04A3, 0x287A); | 
|  | 1057 | phy_stacksave(0x04A9); | 
|  | 1058 | b43legacy_phy_write(dev, 0x04A9, 0x2027); | 
|  | 1059 | phy_stacksave(0x0493); | 
|  | 1060 | b43legacy_phy_write(dev, 0x0493, 0x32F5); | 
|  | 1061 | phy_stacksave(0x04AA); | 
|  | 1062 | b43legacy_phy_write(dev, 0x04AA, 0x2027); | 
|  | 1063 | phy_stacksave(0x04AC); | 
|  | 1064 | b43legacy_phy_write(dev, 0x04AC, 0x32F5); | 
|  | 1065 | break; | 
|  | 1066 | case B43legacy_RADIO_INTERFMODE_MANUALWLAN: | 
|  | 1067 | if (b43legacy_phy_read(dev, 0x0033) & 0x0800) | 
|  | 1068 | break; | 
|  | 1069 |  | 
|  | 1070 | phy->aci_enable = 1; | 
|  | 1071 |  | 
|  | 1072 | phy_stacksave(B43legacy_PHY_RADIO_BITFIELD); | 
|  | 1073 | phy_stacksave(B43legacy_PHY_G_CRS); | 
|  | 1074 | if (phy->rev < 2) | 
|  | 1075 | phy_stacksave(0x0406); | 
|  | 1076 | else { | 
|  | 1077 | phy_stacksave(0x04C0); | 
|  | 1078 | phy_stacksave(0x04C1); | 
|  | 1079 | } | 
|  | 1080 | phy_stacksave(0x0033); | 
|  | 1081 | phy_stacksave(0x04A7); | 
|  | 1082 | phy_stacksave(0x04A3); | 
|  | 1083 | phy_stacksave(0x04A9); | 
|  | 1084 | phy_stacksave(0x04AA); | 
|  | 1085 | phy_stacksave(0x04AC); | 
|  | 1086 | phy_stacksave(0x0493); | 
|  | 1087 | phy_stacksave(0x04A1); | 
|  | 1088 | phy_stacksave(0x04A0); | 
|  | 1089 | phy_stacksave(0x04A2); | 
|  | 1090 | phy_stacksave(0x048A); | 
|  | 1091 | phy_stacksave(0x04A8); | 
|  | 1092 | phy_stacksave(0x04AB); | 
|  | 1093 | if (phy->rev == 2) { | 
|  | 1094 | phy_stacksave(0x04AD); | 
|  | 1095 | phy_stacksave(0x04AE); | 
|  | 1096 | } else if (phy->rev >= 3) { | 
|  | 1097 | phy_stacksave(0x04AD); | 
|  | 1098 | phy_stacksave(0x0415); | 
|  | 1099 | phy_stacksave(0x0416); | 
|  | 1100 | phy_stacksave(0x0417); | 
|  | 1101 | ilt_stacksave(0x1A00 + 0x2); | 
|  | 1102 | ilt_stacksave(0x1A00 + 0x3); | 
|  | 1103 | } | 
|  | 1104 | phy_stacksave(0x042B); | 
|  | 1105 | phy_stacksave(0x048C); | 
|  | 1106 |  | 
|  | 1107 | b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, | 
|  | 1108 | b43legacy_phy_read(dev, | 
|  | 1109 | B43legacy_PHY_RADIO_BITFIELD) & ~0x1000); | 
|  | 1110 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, | 
|  | 1111 | (b43legacy_phy_read(dev, | 
|  | 1112 | B43legacy_PHY_G_CRS) | 
|  | 1113 | & 0xFFFC) | 0x0002); | 
|  | 1114 |  | 
|  | 1115 | b43legacy_phy_write(dev, 0x0033, 0x0800); | 
|  | 1116 | b43legacy_phy_write(dev, 0x04A3, 0x2027); | 
|  | 1117 | b43legacy_phy_write(dev, 0x04A9, 0x1CA8); | 
|  | 1118 | b43legacy_phy_write(dev, 0x0493, 0x287A); | 
|  | 1119 | b43legacy_phy_write(dev, 0x04AA, 0x1CA8); | 
|  | 1120 | b43legacy_phy_write(dev, 0x04AC, 0x287A); | 
|  | 1121 |  | 
|  | 1122 | b43legacy_phy_write(dev, 0x04A0, | 
|  | 1123 | (b43legacy_phy_read(dev, 0x04A0) | 
|  | 1124 | & 0xFFC0) | 0x001A); | 
|  | 1125 | b43legacy_phy_write(dev, 0x04A7, 0x000D); | 
|  | 1126 |  | 
|  | 1127 | if (phy->rev < 2) | 
|  | 1128 | b43legacy_phy_write(dev, 0x0406, 0xFF0D); | 
|  | 1129 | else if (phy->rev == 2) { | 
|  | 1130 | b43legacy_phy_write(dev, 0x04C0, 0xFFFF); | 
|  | 1131 | b43legacy_phy_write(dev, 0x04C1, 0x00A9); | 
|  | 1132 | } else { | 
|  | 1133 | b43legacy_phy_write(dev, 0x04C0, 0x00C1); | 
|  | 1134 | b43legacy_phy_write(dev, 0x04C1, 0x0059); | 
|  | 1135 | } | 
|  | 1136 |  | 
|  | 1137 | b43legacy_phy_write(dev, 0x04A1, | 
|  | 1138 | (b43legacy_phy_read(dev, 0x04A1) | 
|  | 1139 | & 0xC0FF) | 0x1800); | 
|  | 1140 | b43legacy_phy_write(dev, 0x04A1, | 
|  | 1141 | (b43legacy_phy_read(dev, 0x04A1) | 
|  | 1142 | & 0xFFC0) | 0x0015); | 
|  | 1143 | b43legacy_phy_write(dev, 0x04A8, | 
|  | 1144 | (b43legacy_phy_read(dev, 0x04A8) | 
|  | 1145 | & 0xCFFF) | 0x1000); | 
|  | 1146 | b43legacy_phy_write(dev, 0x04A8, | 
|  | 1147 | (b43legacy_phy_read(dev, 0x04A8) | 
|  | 1148 | & 0xF0FF) | 0x0A00); | 
|  | 1149 | b43legacy_phy_write(dev, 0x04AB, | 
|  | 1150 | (b43legacy_phy_read(dev, 0x04AB) | 
|  | 1151 | & 0xCFFF) | 0x1000); | 
|  | 1152 | b43legacy_phy_write(dev, 0x04AB, | 
|  | 1153 | (b43legacy_phy_read(dev, 0x04AB) | 
|  | 1154 | & 0xF0FF) | 0x0800); | 
|  | 1155 | b43legacy_phy_write(dev, 0x04AB, | 
|  | 1156 | (b43legacy_phy_read(dev, 0x04AB) | 
|  | 1157 | & 0xFFCF) | 0x0010); | 
|  | 1158 | b43legacy_phy_write(dev, 0x04AB, | 
|  | 1159 | (b43legacy_phy_read(dev, 0x04AB) | 
|  | 1160 | & 0xFFF0) | 0x0005); | 
|  | 1161 | b43legacy_phy_write(dev, 0x04A8, | 
|  | 1162 | (b43legacy_phy_read(dev, 0x04A8) | 
|  | 1163 | & 0xFFCF) | 0x0010); | 
|  | 1164 | b43legacy_phy_write(dev, 0x04A8, | 
|  | 1165 | (b43legacy_phy_read(dev, 0x04A8) | 
|  | 1166 | & 0xFFF0) | 0x0006); | 
|  | 1167 | b43legacy_phy_write(dev, 0x04A2, | 
|  | 1168 | (b43legacy_phy_read(dev, 0x04A2) | 
|  | 1169 | & 0xF0FF) | 0x0800); | 
|  | 1170 | b43legacy_phy_write(dev, 0x04A0, | 
|  | 1171 | (b43legacy_phy_read(dev, 0x04A0) | 
|  | 1172 | & 0xF0FF) | 0x0500); | 
|  | 1173 | b43legacy_phy_write(dev, 0x04A2, | 
|  | 1174 | (b43legacy_phy_read(dev, 0x04A2) | 
|  | 1175 | & 0xFFF0) | 0x000B); | 
|  | 1176 |  | 
|  | 1177 | if (phy->rev >= 3) { | 
|  | 1178 | b43legacy_phy_write(dev, 0x048A, | 
|  | 1179 | b43legacy_phy_read(dev, 0x048A) | 
|  | 1180 | & ~0x8000); | 
|  | 1181 | b43legacy_phy_write(dev, 0x0415, | 
|  | 1182 | (b43legacy_phy_read(dev, 0x0415) | 
|  | 1183 | & 0x8000) | 0x36D8); | 
|  | 1184 | b43legacy_phy_write(dev, 0x0416, | 
|  | 1185 | (b43legacy_phy_read(dev, 0x0416) | 
|  | 1186 | & 0x8000) | 0x36D8); | 
|  | 1187 | b43legacy_phy_write(dev, 0x0417, | 
|  | 1188 | (b43legacy_phy_read(dev, 0x0417) | 
|  | 1189 | & 0xFE00) | 0x016D); | 
|  | 1190 | } else { | 
|  | 1191 | b43legacy_phy_write(dev, 0x048A, | 
|  | 1192 | b43legacy_phy_read(dev, 0x048A) | 
|  | 1193 | | 0x1000); | 
|  | 1194 | b43legacy_phy_write(dev, 0x048A, | 
|  | 1195 | (b43legacy_phy_read(dev, 0x048A) | 
|  | 1196 | & 0x9FFF) | 0x2000); | 
|  | 1197 | tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, | 
|  | 1198 | B43legacy_UCODEFLAGS_OFFSET); | 
|  | 1199 | if (!(tmp32 & 0x800)) { | 
|  | 1200 | tmp32 |= 0x800; | 
|  | 1201 | b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, | 
|  | 1202 | B43legacy_UCODEFLAGS_OFFSET, | 
|  | 1203 | tmp32); | 
|  | 1204 | } | 
|  | 1205 | } | 
|  | 1206 | if (phy->rev >= 2) | 
|  | 1207 | b43legacy_phy_write(dev, 0x042B, | 
|  | 1208 | b43legacy_phy_read(dev, 0x042B) | 
|  | 1209 | | 0x0800); | 
|  | 1210 | b43legacy_phy_write(dev, 0x048C, | 
|  | 1211 | (b43legacy_phy_read(dev, 0x048C) | 
|  | 1212 | & 0xF0FF) | 0x0200); | 
|  | 1213 | if (phy->rev == 2) { | 
|  | 1214 | b43legacy_phy_write(dev, 0x04AE, | 
|  | 1215 | (b43legacy_phy_read(dev, 0x04AE) | 
|  | 1216 | & 0xFF00) | 0x007F); | 
|  | 1217 | b43legacy_phy_write(dev, 0x04AD, | 
|  | 1218 | (b43legacy_phy_read(dev, 0x04AD) | 
|  | 1219 | & 0x00FF) | 0x1300); | 
|  | 1220 | } else if (phy->rev >= 6) { | 
|  | 1221 | b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F); | 
|  | 1222 | b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F); | 
|  | 1223 | b43legacy_phy_write(dev, 0x04AD, | 
|  | 1224 | b43legacy_phy_read(dev, 0x04AD) | 
|  | 1225 | & 0x00FF); | 
|  | 1226 | } | 
|  | 1227 | b43legacy_calc_nrssi_slope(dev); | 
|  | 1228 | break; | 
|  | 1229 | default: | 
|  | 1230 | B43legacy_BUG_ON(1); | 
|  | 1231 | } | 
|  | 1232 | } | 
|  | 1233 |  | 
|  | 1234 | static void | 
|  | 1235 | b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev, | 
|  | 1236 | int mode) | 
|  | 1237 | { | 
|  | 1238 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 1239 | u32 tmp32; | 
|  | 1240 | u32 *stack = phy->interfstack; | 
|  | 1241 |  | 
|  | 1242 | switch (mode) { | 
|  | 1243 | case B43legacy_RADIO_INTERFMODE_NONWLAN: | 
|  | 1244 | if (phy->rev != 1) { | 
|  | 1245 | b43legacy_phy_write(dev, 0x042B, | 
|  | 1246 | b43legacy_phy_read(dev, 0x042B) | 
|  | 1247 | & ~0x0800); | 
|  | 1248 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, | 
|  | 1249 | b43legacy_phy_read(dev, | 
|  | 1250 | B43legacy_PHY_G_CRS) | 0x4000); | 
|  | 1251 | break; | 
|  | 1252 | } | 
|  | 1253 | phy_stackrestore(0x0078); | 
|  | 1254 | b43legacy_calc_nrssi_threshold(dev); | 
|  | 1255 | phy_stackrestore(0x0406); | 
|  | 1256 | b43legacy_phy_write(dev, 0x042B, | 
|  | 1257 | b43legacy_phy_read(dev, 0x042B) & ~0x0800); | 
|  | 1258 | if (!dev->bad_frames_preempt) | 
|  | 1259 | b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD, | 
|  | 1260 | b43legacy_phy_read(dev, | 
|  | 1261 | B43legacy_PHY_RADIO_BITFIELD) | 
|  | 1262 | & ~(1 << 11)); | 
|  | 1263 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, | 
|  | 1264 | b43legacy_phy_read(dev, B43legacy_PHY_G_CRS) | 
|  | 1265 | | 0x4000); | 
|  | 1266 | phy_stackrestore(0x04A0); | 
|  | 1267 | phy_stackrestore(0x04A1); | 
|  | 1268 | phy_stackrestore(0x04A2); | 
|  | 1269 | phy_stackrestore(0x04A8); | 
|  | 1270 | phy_stackrestore(0x04AB); | 
|  | 1271 | phy_stackrestore(0x04A7); | 
|  | 1272 | phy_stackrestore(0x04A3); | 
|  | 1273 | phy_stackrestore(0x04A9); | 
|  | 1274 | phy_stackrestore(0x0493); | 
|  | 1275 | phy_stackrestore(0x04AA); | 
|  | 1276 | phy_stackrestore(0x04AC); | 
|  | 1277 | break; | 
|  | 1278 | case B43legacy_RADIO_INTERFMODE_MANUALWLAN: | 
|  | 1279 | if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800)) | 
|  | 1280 | break; | 
|  | 1281 |  | 
|  | 1282 | phy->aci_enable = 0; | 
|  | 1283 |  | 
|  | 1284 | phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD); | 
|  | 1285 | phy_stackrestore(B43legacy_PHY_G_CRS); | 
|  | 1286 | phy_stackrestore(0x0033); | 
|  | 1287 | phy_stackrestore(0x04A3); | 
|  | 1288 | phy_stackrestore(0x04A9); | 
|  | 1289 | phy_stackrestore(0x0493); | 
|  | 1290 | phy_stackrestore(0x04AA); | 
|  | 1291 | phy_stackrestore(0x04AC); | 
|  | 1292 | phy_stackrestore(0x04A0); | 
|  | 1293 | phy_stackrestore(0x04A7); | 
|  | 1294 | if (phy->rev >= 2) { | 
|  | 1295 | phy_stackrestore(0x04C0); | 
|  | 1296 | phy_stackrestore(0x04C1); | 
|  | 1297 | } else | 
|  | 1298 | phy_stackrestore(0x0406); | 
|  | 1299 | phy_stackrestore(0x04A1); | 
|  | 1300 | phy_stackrestore(0x04AB); | 
|  | 1301 | phy_stackrestore(0x04A8); | 
|  | 1302 | if (phy->rev == 2) { | 
|  | 1303 | phy_stackrestore(0x04AD); | 
|  | 1304 | phy_stackrestore(0x04AE); | 
|  | 1305 | } else if (phy->rev >= 3) { | 
|  | 1306 | phy_stackrestore(0x04AD); | 
|  | 1307 | phy_stackrestore(0x0415); | 
|  | 1308 | phy_stackrestore(0x0416); | 
|  | 1309 | phy_stackrestore(0x0417); | 
|  | 1310 | ilt_stackrestore(0x1A00 + 0x2); | 
|  | 1311 | ilt_stackrestore(0x1A00 + 0x3); | 
|  | 1312 | } | 
|  | 1313 | phy_stackrestore(0x04A2); | 
|  | 1314 | phy_stackrestore(0x04A8); | 
|  | 1315 | phy_stackrestore(0x042B); | 
|  | 1316 | phy_stackrestore(0x048C); | 
|  | 1317 | tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, | 
|  | 1318 | B43legacy_UCODEFLAGS_OFFSET); | 
|  | 1319 | if (tmp32 & 0x800) { | 
|  | 1320 | tmp32 &= ~0x800; | 
|  | 1321 | b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, | 
|  | 1322 | B43legacy_UCODEFLAGS_OFFSET, | 
|  | 1323 | tmp32); | 
|  | 1324 | } | 
|  | 1325 | b43legacy_calc_nrssi_slope(dev); | 
|  | 1326 | break; | 
|  | 1327 | default: | 
|  | 1328 | B43legacy_BUG_ON(1); | 
|  | 1329 | } | 
|  | 1330 | } | 
|  | 1331 |  | 
|  | 1332 | #undef phy_stacksave | 
|  | 1333 | #undef phy_stackrestore | 
|  | 1334 | #undef radio_stacksave | 
|  | 1335 | #undef radio_stackrestore | 
|  | 1336 | #undef ilt_stacksave | 
|  | 1337 | #undef ilt_stackrestore | 
|  | 1338 |  | 
|  | 1339 | int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev, | 
|  | 1340 | int mode) | 
|  | 1341 | { | 
|  | 1342 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 1343 | int currentmode; | 
|  | 1344 |  | 
|  | 1345 | if ((phy->type != B43legacy_PHYTYPE_G) || | 
|  | 1346 | (phy->rev == 0) || (!phy->gmode)) | 
|  | 1347 | return -ENODEV; | 
|  | 1348 |  | 
|  | 1349 | phy->aci_wlan_automatic = 0; | 
|  | 1350 | switch (mode) { | 
|  | 1351 | case B43legacy_RADIO_INTERFMODE_AUTOWLAN: | 
|  | 1352 | phy->aci_wlan_automatic = 1; | 
|  | 1353 | if (phy->aci_enable) | 
|  | 1354 | mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN; | 
|  | 1355 | else | 
|  | 1356 | mode = B43legacy_RADIO_INTERFMODE_NONE; | 
|  | 1357 | break; | 
|  | 1358 | case B43legacy_RADIO_INTERFMODE_NONE: | 
|  | 1359 | case B43legacy_RADIO_INTERFMODE_NONWLAN: | 
|  | 1360 | case B43legacy_RADIO_INTERFMODE_MANUALWLAN: | 
|  | 1361 | break; | 
|  | 1362 | default: | 
|  | 1363 | return -EINVAL; | 
|  | 1364 | } | 
|  | 1365 |  | 
|  | 1366 | currentmode = phy->interfmode; | 
|  | 1367 | if (currentmode == mode) | 
|  | 1368 | return 0; | 
|  | 1369 | if (currentmode != B43legacy_RADIO_INTERFMODE_NONE) | 
|  | 1370 | b43legacy_radio_interference_mitigation_disable(dev, | 
|  | 1371 | currentmode); | 
|  | 1372 |  | 
|  | 1373 | if (mode == B43legacy_RADIO_INTERFMODE_NONE) { | 
|  | 1374 | phy->aci_enable = 0; | 
|  | 1375 | phy->aci_hw_rssi = 0; | 
|  | 1376 | } else | 
|  | 1377 | b43legacy_radio_interference_mitigation_enable(dev, mode); | 
|  | 1378 | phy->interfmode = mode; | 
|  | 1379 |  | 
|  | 1380 | return 0; | 
|  | 1381 | } | 
|  | 1382 |  | 
|  | 1383 | u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev) | 
|  | 1384 | { | 
|  | 1385 | u16 reg; | 
|  | 1386 | u16 index; | 
|  | 1387 | u16 ret; | 
|  | 1388 |  | 
|  | 1389 | reg = b43legacy_radio_read16(dev, 0x0060); | 
|  | 1390 | index = (reg & 0x001E) >> 1; | 
|  | 1391 | ret = rcc_table[index] << 1; | 
|  | 1392 | ret |= (reg & 0x0001); | 
|  | 1393 | ret |= 0x0020; | 
|  | 1394 |  | 
|  | 1395 | return ret; | 
|  | 1396 | } | 
|  | 1397 |  | 
|  | 1398 | #define LPD(L, P, D)    (((L) << 2) | ((P) << 1) | ((D) << 0)) | 
|  | 1399 | static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd) | 
|  | 1400 | { | 
|  | 1401 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 1402 | u16 loop_or = 0; | 
|  | 1403 | u16 adj_loopback_gain = phy->loopback_gain[0]; | 
|  | 1404 | u8 loop; | 
|  | 1405 | u16 extern_lna_control; | 
|  | 1406 |  | 
|  | 1407 | if (!phy->gmode) | 
|  | 1408 | return 0; | 
|  | 1409 | if (!has_loopback_gain(phy)) { | 
| Larry Finger | 7797aa3 | 2007-11-09 16:57:34 -0600 | [diff] [blame] | 1410 | if (phy->rev < 7 || !(dev->dev->bus->sprom.boardflags_lo | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 1411 | & B43legacy_BFL_EXTLNA)) { | 
|  | 1412 | switch (lpd) { | 
|  | 1413 | case LPD(0, 1, 1): | 
|  | 1414 | return 0x0FB2; | 
|  | 1415 | case LPD(0, 0, 1): | 
|  | 1416 | return 0x00B2; | 
|  | 1417 | case LPD(1, 0, 1): | 
|  | 1418 | return 0x30B2; | 
|  | 1419 | case LPD(1, 0, 0): | 
|  | 1420 | return 0x30B3; | 
|  | 1421 | default: | 
|  | 1422 | B43legacy_BUG_ON(1); | 
|  | 1423 | } | 
|  | 1424 | } else { | 
|  | 1425 | switch (lpd) { | 
|  | 1426 | case LPD(0, 1, 1): | 
|  | 1427 | return 0x8FB2; | 
|  | 1428 | case LPD(0, 0, 1): | 
|  | 1429 | return 0x80B2; | 
|  | 1430 | case LPD(1, 0, 1): | 
|  | 1431 | return 0x20B2; | 
|  | 1432 | case LPD(1, 0, 0): | 
|  | 1433 | return 0x20B3; | 
|  | 1434 | default: | 
|  | 1435 | B43legacy_BUG_ON(1); | 
|  | 1436 | } | 
|  | 1437 | } | 
|  | 1438 | } else { | 
|  | 1439 | if (phy->radio_rev == 8) | 
|  | 1440 | adj_loopback_gain += 0x003E; | 
|  | 1441 | else | 
|  | 1442 | adj_loopback_gain += 0x0026; | 
|  | 1443 | if (adj_loopback_gain >= 0x46) { | 
|  | 1444 | adj_loopback_gain -= 0x46; | 
|  | 1445 | extern_lna_control = 0x3000; | 
|  | 1446 | } else if (adj_loopback_gain >= 0x3A) { | 
|  | 1447 | adj_loopback_gain -= 0x3A; | 
|  | 1448 | extern_lna_control = 0x2000; | 
|  | 1449 | } else if (adj_loopback_gain >= 0x2E) { | 
|  | 1450 | adj_loopback_gain -= 0x2E; | 
|  | 1451 | extern_lna_control = 0x1000; | 
|  | 1452 | } else { | 
|  | 1453 | adj_loopback_gain -= 0x10; | 
|  | 1454 | extern_lna_control = 0x0000; | 
|  | 1455 | } | 
|  | 1456 | for (loop = 0; loop < 16; loop++) { | 
|  | 1457 | u16 tmp = adj_loopback_gain - 6 * loop; | 
|  | 1458 | if (tmp < 6) | 
|  | 1459 | break; | 
|  | 1460 | } | 
|  | 1461 |  | 
|  | 1462 | loop_or = (loop << 8) | extern_lna_control; | 
| Larry Finger | 7797aa3 | 2007-11-09 16:57:34 -0600 | [diff] [blame] | 1463 | if (phy->rev >= 7 && dev->dev->bus->sprom.boardflags_lo | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 1464 | & B43legacy_BFL_EXTLNA) { | 
|  | 1465 | if (extern_lna_control) | 
|  | 1466 | loop_or |= 0x8000; | 
|  | 1467 | switch (lpd) { | 
|  | 1468 | case LPD(0, 1, 1): | 
|  | 1469 | return 0x8F92; | 
|  | 1470 | case LPD(0, 0, 1): | 
|  | 1471 | return (0x8092 | loop_or); | 
|  | 1472 | case LPD(1, 0, 1): | 
|  | 1473 | return (0x2092 | loop_or); | 
|  | 1474 | case LPD(1, 0, 0): | 
|  | 1475 | return (0x2093 | loop_or); | 
|  | 1476 | default: | 
|  | 1477 | B43legacy_BUG_ON(1); | 
|  | 1478 | } | 
|  | 1479 | } else { | 
|  | 1480 | switch (lpd) { | 
|  | 1481 | case LPD(0, 1, 1): | 
|  | 1482 | return 0x0F92; | 
|  | 1483 | case LPD(0, 0, 1): | 
|  | 1484 | case LPD(1, 0, 1): | 
|  | 1485 | return (0x0092 | loop_or); | 
|  | 1486 | case LPD(1, 0, 0): | 
|  | 1487 | return (0x0093 | loop_or); | 
|  | 1488 | default: | 
|  | 1489 | B43legacy_BUG_ON(1); | 
|  | 1490 | } | 
|  | 1491 | } | 
|  | 1492 | } | 
|  | 1493 | return 0; | 
|  | 1494 | } | 
|  | 1495 |  | 
|  | 1496 | u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev) | 
|  | 1497 | { | 
|  | 1498 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 1499 | u16 backup[21] = { 0 }; | 
|  | 1500 | u16 ret; | 
|  | 1501 | u16 i; | 
|  | 1502 | u16 j; | 
|  | 1503 | u32 tmp1 = 0; | 
|  | 1504 | u32 tmp2 = 0; | 
|  | 1505 |  | 
|  | 1506 | backup[0] = b43legacy_radio_read16(dev, 0x0043); | 
|  | 1507 | backup[14] = b43legacy_radio_read16(dev, 0x0051); | 
|  | 1508 | backup[15] = b43legacy_radio_read16(dev, 0x0052); | 
|  | 1509 | backup[1] = b43legacy_phy_read(dev, 0x0015); | 
|  | 1510 | backup[16] = b43legacy_phy_read(dev, 0x005A); | 
|  | 1511 | backup[17] = b43legacy_phy_read(dev, 0x0059); | 
|  | 1512 | backup[18] = b43legacy_phy_read(dev, 0x0058); | 
|  | 1513 | if (phy->type == B43legacy_PHYTYPE_B) { | 
|  | 1514 | backup[2] = b43legacy_phy_read(dev, 0x0030); | 
|  | 1515 | backup[3] = b43legacy_read16(dev, 0x03EC); | 
|  | 1516 | b43legacy_phy_write(dev, 0x0030, 0x00FF); | 
|  | 1517 | b43legacy_write16(dev, 0x03EC, 0x3F3F); | 
|  | 1518 | } else { | 
|  | 1519 | if (phy->gmode) { | 
|  | 1520 | backup[4] = b43legacy_phy_read(dev, 0x0811); | 
|  | 1521 | backup[5] = b43legacy_phy_read(dev, 0x0812); | 
|  | 1522 | backup[6] = b43legacy_phy_read(dev, 0x0814); | 
|  | 1523 | backup[7] = b43legacy_phy_read(dev, 0x0815); | 
|  | 1524 | backup[8] = b43legacy_phy_read(dev, | 
|  | 1525 | B43legacy_PHY_G_CRS); | 
|  | 1526 | backup[9] = b43legacy_phy_read(dev, 0x0802); | 
|  | 1527 | b43legacy_phy_write(dev, 0x0814, | 
|  | 1528 | (b43legacy_phy_read(dev, 0x0814) | 
|  | 1529 | | 0x0003)); | 
|  | 1530 | b43legacy_phy_write(dev, 0x0815, | 
|  | 1531 | (b43legacy_phy_read(dev, 0x0815) | 
|  | 1532 | & 0xFFFC)); | 
|  | 1533 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, | 
|  | 1534 | (b43legacy_phy_read(dev, | 
|  | 1535 | B43legacy_PHY_G_CRS) & 0x7FFF)); | 
|  | 1536 | b43legacy_phy_write(dev, 0x0802, | 
|  | 1537 | (b43legacy_phy_read(dev, 0x0802) | 
|  | 1538 | & 0xFFFC)); | 
|  | 1539 | if (phy->rev > 1) { /* loopback gain enabled */ | 
|  | 1540 | backup[19] = b43legacy_phy_read(dev, 0x080F); | 
|  | 1541 | backup[20] = b43legacy_phy_read(dev, 0x0810); | 
|  | 1542 | if (phy->rev >= 3) | 
|  | 1543 | b43legacy_phy_write(dev, 0x080F, | 
|  | 1544 | 0xC020); | 
|  | 1545 | else | 
|  | 1546 | b43legacy_phy_write(dev, 0x080F, | 
|  | 1547 | 0x8020); | 
|  | 1548 | b43legacy_phy_write(dev, 0x0810, 0x0000); | 
|  | 1549 | } | 
|  | 1550 | b43legacy_phy_write(dev, 0x0812, | 
|  | 1551 | b43legacy_get_812_value(dev, | 
|  | 1552 | LPD(0, 1, 1))); | 
|  | 1553 | if (phy->rev < 7 || | 
| Larry Finger | 7797aa3 | 2007-11-09 16:57:34 -0600 | [diff] [blame] | 1554 | !(dev->dev->bus->sprom.boardflags_lo | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 1555 | & B43legacy_BFL_EXTLNA)) | 
|  | 1556 | b43legacy_phy_write(dev, 0x0811, 0x01B3); | 
|  | 1557 | else | 
|  | 1558 | b43legacy_phy_write(dev, 0x0811, 0x09B3); | 
|  | 1559 | } | 
|  | 1560 | } | 
|  | 1561 | b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, | 
|  | 1562 | (b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO) | 
|  | 1563 | | 0x8000)); | 
|  | 1564 | backup[10] = b43legacy_phy_read(dev, 0x0035); | 
|  | 1565 | b43legacy_phy_write(dev, 0x0035, | 
|  | 1566 | (b43legacy_phy_read(dev, 0x0035) & 0xFF7F)); | 
|  | 1567 | backup[11] = b43legacy_read16(dev, 0x03E6); | 
|  | 1568 | backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT); | 
|  | 1569 |  | 
|  | 1570 | /* Initialization */ | 
|  | 1571 | if (phy->analog == 0) | 
|  | 1572 | b43legacy_write16(dev, 0x03E6, 0x0122); | 
|  | 1573 | else { | 
|  | 1574 | if (phy->analog >= 2) | 
|  | 1575 | b43legacy_phy_write(dev, 0x0003, | 
|  | 1576 | (b43legacy_phy_read(dev, 0x0003) | 
|  | 1577 | & 0xFFBF) | 0x0040); | 
|  | 1578 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, | 
|  | 1579 | (b43legacy_read16(dev, | 
|  | 1580 | B43legacy_MMIO_CHANNEL_EXT) | 0x2000)); | 
|  | 1581 | } | 
|  | 1582 |  | 
|  | 1583 | ret = b43legacy_radio_calibrationvalue(dev); | 
|  | 1584 |  | 
|  | 1585 | if (phy->type == B43legacy_PHYTYPE_B) | 
|  | 1586 | b43legacy_radio_write16(dev, 0x0078, 0x0026); | 
|  | 1587 |  | 
|  | 1588 | if (phy->gmode) | 
|  | 1589 | b43legacy_phy_write(dev, 0x0812, | 
|  | 1590 | b43legacy_get_812_value(dev, | 
|  | 1591 | LPD(0, 1, 1))); | 
|  | 1592 | b43legacy_phy_write(dev, 0x0015, 0xBFAF); | 
|  | 1593 | b43legacy_phy_write(dev, 0x002B, 0x1403); | 
|  | 1594 | if (phy->gmode) | 
|  | 1595 | b43legacy_phy_write(dev, 0x0812, | 
|  | 1596 | b43legacy_get_812_value(dev, | 
|  | 1597 | LPD(0, 0, 1))); | 
|  | 1598 | b43legacy_phy_write(dev, 0x0015, 0xBFA0); | 
|  | 1599 | b43legacy_radio_write16(dev, 0x0051, | 
|  | 1600 | (b43legacy_radio_read16(dev, 0x0051) | 
|  | 1601 | | 0x0004)); | 
|  | 1602 | if (phy->radio_rev == 8) | 
|  | 1603 | b43legacy_radio_write16(dev, 0x0043, 0x001F); | 
|  | 1604 | else { | 
|  | 1605 | b43legacy_radio_write16(dev, 0x0052, 0x0000); | 
|  | 1606 | b43legacy_radio_write16(dev, 0x0043, | 
|  | 1607 | (b43legacy_radio_read16(dev, 0x0043) | 
|  | 1608 | & 0xFFF0) | 0x0009); | 
|  | 1609 | } | 
|  | 1610 | b43legacy_phy_write(dev, 0x0058, 0x0000); | 
|  | 1611 |  | 
|  | 1612 | for (i = 0; i < 16; i++) { | 
|  | 1613 | b43legacy_phy_write(dev, 0x005A, 0x0480); | 
|  | 1614 | b43legacy_phy_write(dev, 0x0059, 0xC810); | 
|  | 1615 | b43legacy_phy_write(dev, 0x0058, 0x000D); | 
|  | 1616 | if (phy->gmode) | 
|  | 1617 | b43legacy_phy_write(dev, 0x0812, | 
|  | 1618 | b43legacy_get_812_value(dev, | 
|  | 1619 | LPD(1, 0, 1))); | 
|  | 1620 | b43legacy_phy_write(dev, 0x0015, 0xAFB0); | 
|  | 1621 | udelay(10); | 
|  | 1622 | if (phy->gmode) | 
|  | 1623 | b43legacy_phy_write(dev, 0x0812, | 
|  | 1624 | b43legacy_get_812_value(dev, | 
|  | 1625 | LPD(1, 0, 1))); | 
|  | 1626 | b43legacy_phy_write(dev, 0x0015, 0xEFB0); | 
|  | 1627 | udelay(10); | 
|  | 1628 | if (phy->gmode) | 
|  | 1629 | b43legacy_phy_write(dev, 0x0812, | 
|  | 1630 | b43legacy_get_812_value(dev, | 
|  | 1631 | LPD(1, 0, 0))); | 
|  | 1632 | b43legacy_phy_write(dev, 0x0015, 0xFFF0); | 
|  | 1633 | udelay(20); | 
|  | 1634 | tmp1 += b43legacy_phy_read(dev, 0x002D); | 
|  | 1635 | b43legacy_phy_write(dev, 0x0058, 0x0000); | 
|  | 1636 | if (phy->gmode) | 
|  | 1637 | b43legacy_phy_write(dev, 0x0812, | 
|  | 1638 | b43legacy_get_812_value(dev, | 
|  | 1639 | LPD(1, 0, 1))); | 
|  | 1640 | b43legacy_phy_write(dev, 0x0015, 0xAFB0); | 
|  | 1641 | } | 
|  | 1642 |  | 
|  | 1643 | tmp1++; | 
|  | 1644 | tmp1 >>= 9; | 
|  | 1645 | udelay(10); | 
|  | 1646 | b43legacy_phy_write(dev, 0x0058, 0x0000); | 
|  | 1647 |  | 
|  | 1648 | for (i = 0; i < 16; i++) { | 
|  | 1649 | b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1) | 
|  | 1650 | | 0x0020); | 
|  | 1651 | backup[13] = b43legacy_radio_read16(dev, 0x0078); | 
|  | 1652 | udelay(10); | 
|  | 1653 | for (j = 0; j < 16; j++) { | 
|  | 1654 | b43legacy_phy_write(dev, 0x005A, 0x0D80); | 
|  | 1655 | b43legacy_phy_write(dev, 0x0059, 0xC810); | 
|  | 1656 | b43legacy_phy_write(dev, 0x0058, 0x000D); | 
|  | 1657 | if (phy->gmode) | 
|  | 1658 | b43legacy_phy_write(dev, 0x0812, | 
|  | 1659 | b43legacy_get_812_value(dev, | 
|  | 1660 | LPD(1, 0, 1))); | 
|  | 1661 | b43legacy_phy_write(dev, 0x0015, 0xAFB0); | 
|  | 1662 | udelay(10); | 
|  | 1663 | if (phy->gmode) | 
|  | 1664 | b43legacy_phy_write(dev, 0x0812, | 
|  | 1665 | b43legacy_get_812_value(dev, | 
|  | 1666 | LPD(1, 0, 1))); | 
|  | 1667 | b43legacy_phy_write(dev, 0x0015, 0xEFB0); | 
|  | 1668 | udelay(10); | 
|  | 1669 | if (phy->gmode) | 
|  | 1670 | b43legacy_phy_write(dev, 0x0812, | 
|  | 1671 | b43legacy_get_812_value(dev, | 
|  | 1672 | LPD(1, 0, 0))); | 
|  | 1673 | b43legacy_phy_write(dev, 0x0015, 0xFFF0); | 
|  | 1674 | udelay(10); | 
|  | 1675 | tmp2 += b43legacy_phy_read(dev, 0x002D); | 
|  | 1676 | b43legacy_phy_write(dev, 0x0058, 0x0000); | 
|  | 1677 | if (phy->gmode) | 
|  | 1678 | b43legacy_phy_write(dev, 0x0812, | 
|  | 1679 | b43legacy_get_812_value(dev, | 
|  | 1680 | LPD(1, 0, 1))); | 
|  | 1681 | b43legacy_phy_write(dev, 0x0015, 0xAFB0); | 
|  | 1682 | } | 
|  | 1683 | tmp2++; | 
|  | 1684 | tmp2 >>= 8; | 
|  | 1685 | if (tmp1 < tmp2) | 
|  | 1686 | break; | 
|  | 1687 | } | 
|  | 1688 |  | 
|  | 1689 | /* Restore the registers */ | 
|  | 1690 | b43legacy_phy_write(dev, 0x0015, backup[1]); | 
|  | 1691 | b43legacy_radio_write16(dev, 0x0051, backup[14]); | 
|  | 1692 | b43legacy_radio_write16(dev, 0x0052, backup[15]); | 
|  | 1693 | b43legacy_radio_write16(dev, 0x0043, backup[0]); | 
|  | 1694 | b43legacy_phy_write(dev, 0x005A, backup[16]); | 
|  | 1695 | b43legacy_phy_write(dev, 0x0059, backup[17]); | 
|  | 1696 | b43legacy_phy_write(dev, 0x0058, backup[18]); | 
|  | 1697 | b43legacy_write16(dev, 0x03E6, backup[11]); | 
|  | 1698 | if (phy->analog != 0) | 
|  | 1699 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]); | 
|  | 1700 | b43legacy_phy_write(dev, 0x0035, backup[10]); | 
|  | 1701 | b43legacy_radio_selectchannel(dev, phy->channel, 1); | 
|  | 1702 | if (phy->type == B43legacy_PHYTYPE_B) { | 
|  | 1703 | b43legacy_phy_write(dev, 0x0030, backup[2]); | 
|  | 1704 | b43legacy_write16(dev, 0x03EC, backup[3]); | 
|  | 1705 | } else { | 
|  | 1706 | if (phy->gmode) { | 
|  | 1707 | b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, | 
|  | 1708 | (b43legacy_read16(dev, | 
|  | 1709 | B43legacy_MMIO_PHY_RADIO) & 0x7FFF)); | 
|  | 1710 | b43legacy_phy_write(dev, 0x0811, backup[4]); | 
|  | 1711 | b43legacy_phy_write(dev, 0x0812, backup[5]); | 
|  | 1712 | b43legacy_phy_write(dev, 0x0814, backup[6]); | 
|  | 1713 | b43legacy_phy_write(dev, 0x0815, backup[7]); | 
|  | 1714 | b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, | 
|  | 1715 | backup[8]); | 
|  | 1716 | b43legacy_phy_write(dev, 0x0802, backup[9]); | 
|  | 1717 | if (phy->rev > 1) { | 
|  | 1718 | b43legacy_phy_write(dev, 0x080F, backup[19]); | 
|  | 1719 | b43legacy_phy_write(dev, 0x0810, backup[20]); | 
|  | 1720 | } | 
|  | 1721 | } | 
|  | 1722 | } | 
|  | 1723 | if (i >= 15) | 
|  | 1724 | ret = backup[13]; | 
|  | 1725 |  | 
|  | 1726 | return ret; | 
|  | 1727 | } | 
|  | 1728 |  | 
|  | 1729 | static inline | 
|  | 1730 | u16 freq_r3A_value(u16 frequency) | 
|  | 1731 | { | 
|  | 1732 | u16 value; | 
|  | 1733 |  | 
|  | 1734 | if (frequency < 5091) | 
|  | 1735 | value = 0x0040; | 
|  | 1736 | else if (frequency < 5321) | 
|  | 1737 | value = 0x0000; | 
|  | 1738 | else if (frequency < 5806) | 
|  | 1739 | value = 0x0080; | 
|  | 1740 | else | 
|  | 1741 | value = 0x0040; | 
|  | 1742 |  | 
|  | 1743 | return value; | 
|  | 1744 | } | 
|  | 1745 |  | 
|  | 1746 | void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev) | 
|  | 1747 | { | 
|  | 1748 | static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; | 
|  | 1749 | static const u8 data_low[5]  = { 0x00, 0x01, 0x05, 0x06, 0x0A }; | 
|  | 1750 | u16 tmp = b43legacy_radio_read16(dev, 0x001E); | 
|  | 1751 | int i; | 
|  | 1752 | int j; | 
|  | 1753 |  | 
|  | 1754 | for (i = 0; i < 5; i++) { | 
|  | 1755 | for (j = 0; j < 5; j++) { | 
|  | 1756 | if (tmp == (data_high[i] | data_low[j])) { | 
|  | 1757 | b43legacy_phy_write(dev, 0x0069, (i - j) << 8 | | 
|  | 1758 | 0x00C0); | 
|  | 1759 | return; | 
|  | 1760 | } | 
|  | 1761 | } | 
|  | 1762 | } | 
|  | 1763 | } | 
|  | 1764 |  | 
|  | 1765 | int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, | 
|  | 1766 | u8 channel, | 
|  | 1767 | int synthetic_pu_workaround) | 
|  | 1768 | { | 
|  | 1769 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 1770 |  | 
| Larry Finger | 42a9174 | 2007-09-20 21:11:02 -0500 | [diff] [blame] | 1771 | if (channel == 0xFF) { | 
|  | 1772 | switch (phy->type) { | 
|  | 1773 | case B43legacy_PHYTYPE_B: | 
|  | 1774 | case B43legacy_PHYTYPE_G: | 
|  | 1775 | channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG; | 
|  | 1776 | break; | 
|  | 1777 | default: | 
|  | 1778 | B43legacy_WARN_ON(1); | 
|  | 1779 | } | 
|  | 1780 | } | 
|  | 1781 |  | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 1782 | /* TODO: Check if channel is valid - return -EINVAL if not */ | 
|  | 1783 | if (synthetic_pu_workaround) | 
|  | 1784 | b43legacy_synth_pu_workaround(dev, channel); | 
|  | 1785 |  | 
|  | 1786 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL, | 
|  | 1787 | channel2freq_bg(channel)); | 
|  | 1788 |  | 
|  | 1789 | if (channel == 14) { | 
| Larry Finger | 7797aa3 | 2007-11-09 16:57:34 -0600 | [diff] [blame] | 1790 | if (dev->dev->bus->sprom.country_code == 5)   /* JAPAN) */ | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 1791 | b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, | 
|  | 1792 | B43legacy_UCODEFLAGS_OFFSET, | 
|  | 1793 | b43legacy_shm_read32(dev, | 
|  | 1794 | B43legacy_SHM_SHARED, | 
|  | 1795 | B43legacy_UCODEFLAGS_OFFSET) | 
|  | 1796 | & ~(1 << 7)); | 
|  | 1797 | else | 
|  | 1798 | b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, | 
|  | 1799 | B43legacy_UCODEFLAGS_OFFSET, | 
|  | 1800 | b43legacy_shm_read32(dev, | 
|  | 1801 | B43legacy_SHM_SHARED, | 
|  | 1802 | B43legacy_UCODEFLAGS_OFFSET) | 
|  | 1803 | | (1 << 7)); | 
|  | 1804 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, | 
|  | 1805 | b43legacy_read16(dev, | 
|  | 1806 | B43legacy_MMIO_CHANNEL_EXT) | (1 << 11)); | 
|  | 1807 | } else | 
|  | 1808 | b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, | 
|  | 1809 | b43legacy_read16(dev, | 
|  | 1810 | B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF); | 
|  | 1811 |  | 
|  | 1812 | phy->channel = channel; | 
|  | 1813 | /*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states | 
|  | 1814 | *     that 2000 usecs might suffice. */ | 
|  | 1815 | msleep(8); | 
|  | 1816 |  | 
|  | 1817 | return 0; | 
|  | 1818 | } | 
|  | 1819 |  | 
|  | 1820 | void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val) | 
|  | 1821 | { | 
|  | 1822 | u16 tmp; | 
|  | 1823 |  | 
|  | 1824 | val <<= 8; | 
|  | 1825 | tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF; | 
|  | 1826 | b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val); | 
|  | 1827 | tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF; | 
|  | 1828 | b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val); | 
|  | 1829 | tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF; | 
|  | 1830 | b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val); | 
|  | 1831 | } | 
|  | 1832 |  | 
|  | 1833 | /* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ | 
|  | 1834 | static u16 b43legacy_get_txgain_base_band(u16 txpower) | 
|  | 1835 | { | 
|  | 1836 | u16 ret; | 
|  | 1837 |  | 
|  | 1838 | B43legacy_WARN_ON(txpower > 63); | 
|  | 1839 |  | 
|  | 1840 | if (txpower >= 54) | 
|  | 1841 | ret = 2; | 
|  | 1842 | else if (txpower >= 49) | 
|  | 1843 | ret = 4; | 
|  | 1844 | else if (txpower >= 44) | 
|  | 1845 | ret = 5; | 
|  | 1846 | else | 
|  | 1847 | ret = 6; | 
|  | 1848 |  | 
|  | 1849 | return ret; | 
|  | 1850 | } | 
|  | 1851 |  | 
|  | 1852 | /* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ | 
|  | 1853 | static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower) | 
|  | 1854 | { | 
|  | 1855 | u16 ret; | 
|  | 1856 |  | 
|  | 1857 | B43legacy_WARN_ON(txpower > 63); | 
|  | 1858 |  | 
|  | 1859 | if (txpower >= 32) | 
|  | 1860 | ret = 0; | 
|  | 1861 | else if (txpower >= 25) | 
|  | 1862 | ret = 1; | 
|  | 1863 | else if (txpower >= 20) | 
|  | 1864 | ret = 2; | 
|  | 1865 | else if (txpower >= 12) | 
|  | 1866 | ret = 3; | 
|  | 1867 | else | 
|  | 1868 | ret = 4; | 
|  | 1869 |  | 
|  | 1870 | return ret; | 
|  | 1871 | } | 
|  | 1872 |  | 
|  | 1873 | /* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ | 
|  | 1874 | static u16 b43legacy_get_txgain_dac(u16 txpower) | 
|  | 1875 | { | 
|  | 1876 | u16 ret; | 
|  | 1877 |  | 
|  | 1878 | B43legacy_WARN_ON(txpower > 63); | 
|  | 1879 |  | 
|  | 1880 | if (txpower >= 54) | 
|  | 1881 | ret = txpower - 53; | 
|  | 1882 | else if (txpower >= 49) | 
|  | 1883 | ret = txpower - 42; | 
|  | 1884 | else if (txpower >= 44) | 
|  | 1885 | ret = txpower - 37; | 
|  | 1886 | else if (txpower >= 32) | 
|  | 1887 | ret = txpower - 32; | 
|  | 1888 | else if (txpower >= 25) | 
|  | 1889 | ret = txpower - 20; | 
|  | 1890 | else if (txpower >= 20) | 
|  | 1891 | ret = txpower - 13; | 
|  | 1892 | else if (txpower >= 12) | 
|  | 1893 | ret = txpower - 8; | 
|  | 1894 | else | 
|  | 1895 | ret = txpower; | 
|  | 1896 |  | 
|  | 1897 | return ret; | 
|  | 1898 | } | 
|  | 1899 |  | 
|  | 1900 | void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower) | 
|  | 1901 | { | 
|  | 1902 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 1903 | u16 pamp; | 
|  | 1904 | u16 base; | 
|  | 1905 | u16 dac; | 
|  | 1906 | u16 ilt; | 
|  | 1907 |  | 
| Harvey Harrison | ca21614 | 2008-05-02 13:47:49 -0700 | [diff] [blame] | 1908 | txpower = clamp_val(txpower, 0, 63); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 1909 |  | 
|  | 1910 | pamp = b43legacy_get_txgain_freq_power_amp(txpower); | 
|  | 1911 | pamp <<= 5; | 
|  | 1912 | pamp &= 0x00E0; | 
|  | 1913 | b43legacy_phy_write(dev, 0x0019, pamp); | 
|  | 1914 |  | 
|  | 1915 | base = b43legacy_get_txgain_base_band(txpower); | 
|  | 1916 | base &= 0x000F; | 
|  | 1917 | b43legacy_phy_write(dev, 0x0017, base | 0x0020); | 
|  | 1918 |  | 
|  | 1919 | ilt = b43legacy_ilt_read(dev, 0x3001); | 
|  | 1920 | ilt &= 0x0007; | 
|  | 1921 |  | 
|  | 1922 | dac = b43legacy_get_txgain_dac(txpower); | 
|  | 1923 | dac <<= 3; | 
|  | 1924 | dac |= ilt; | 
|  | 1925 |  | 
|  | 1926 | b43legacy_ilt_write(dev, 0x3001, dac); | 
|  | 1927 |  | 
|  | 1928 | phy->txpwr_offset = txpower; | 
|  | 1929 |  | 
|  | 1930 | /* TODO: FuncPlaceholder (Adjust BB loft cancel) */ | 
|  | 1931 | } | 
|  | 1932 |  | 
|  | 1933 | void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev, | 
|  | 1934 | u16 baseband_attenuation, | 
|  | 1935 | u16 radio_attenuation, | 
|  | 1936 | u16 txpower) | 
|  | 1937 | { | 
|  | 1938 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 1939 |  | 
|  | 1940 | if (baseband_attenuation == 0xFFFF) | 
|  | 1941 | baseband_attenuation = phy->bbatt; | 
|  | 1942 | if (radio_attenuation == 0xFFFF) | 
|  | 1943 | radio_attenuation = phy->rfatt; | 
|  | 1944 | if (txpower == 0xFFFF) | 
|  | 1945 | txpower = phy->txctl1; | 
|  | 1946 | phy->bbatt = baseband_attenuation; | 
|  | 1947 | phy->rfatt = radio_attenuation; | 
|  | 1948 | phy->txctl1 = txpower; | 
|  | 1949 |  | 
|  | 1950 | B43legacy_WARN_ON(baseband_attenuation > 11); | 
|  | 1951 | if (phy->radio_rev < 6) | 
|  | 1952 | B43legacy_WARN_ON(radio_attenuation > 9); | 
|  | 1953 | else | 
|  | 1954 | B43legacy_WARN_ON(radio_attenuation > 31); | 
|  | 1955 | B43legacy_WARN_ON(txpower > 7); | 
|  | 1956 |  | 
|  | 1957 | b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation); | 
|  | 1958 | b43legacy_radio_write16(dev, 0x0043, radio_attenuation); | 
|  | 1959 | b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064, | 
|  | 1960 | radio_attenuation); | 
|  | 1961 | if (phy->radio_ver == 0x2050) | 
|  | 1962 | b43legacy_radio_write16(dev, 0x0052, | 
|  | 1963 | (b43legacy_radio_read16(dev, 0x0052) | 
|  | 1964 | & ~0x0070) | ((txpower << 4) & 0x0070)); | 
|  | 1965 | /* FIXME: The spec is very weird and unclear here. */ | 
|  | 1966 | if (phy->type == B43legacy_PHYTYPE_G) | 
|  | 1967 | b43legacy_phy_lo_adjust(dev, 0); | 
|  | 1968 | } | 
|  | 1969 |  | 
|  | 1970 | u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev) | 
|  | 1971 | { | 
|  | 1972 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 1973 |  | 
|  | 1974 | if (phy->radio_ver == 0x2050 && phy->radio_rev < 6) | 
|  | 1975 | return 0; | 
|  | 1976 | return 2; | 
|  | 1977 | } | 
|  | 1978 |  | 
|  | 1979 | u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) | 
|  | 1980 | { | 
|  | 1981 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 1982 | u16 att = 0xFFFF; | 
|  | 1983 |  | 
|  | 1984 | switch (phy->radio_ver) { | 
|  | 1985 | case 0x2053: | 
|  | 1986 | switch (phy->radio_rev) { | 
|  | 1987 | case 1: | 
|  | 1988 | att = 6; | 
|  | 1989 | break; | 
|  | 1990 | } | 
|  | 1991 | break; | 
|  | 1992 | case 0x2050: | 
|  | 1993 | switch (phy->radio_rev) { | 
|  | 1994 | case 0: | 
|  | 1995 | att = 5; | 
|  | 1996 | break; | 
|  | 1997 | case 1: | 
|  | 1998 | if (phy->type == B43legacy_PHYTYPE_G) { | 
|  | 1999 | if (is_bcm_board_vendor(dev) && | 
|  | 2000 | dev->dev->bus->boardinfo.type == 0x421 && | 
|  | 2001 | dev->dev->bus->boardinfo.rev >= 30) | 
|  | 2002 | att = 3; | 
|  | 2003 | else if (is_bcm_board_vendor(dev) && | 
|  | 2004 | dev->dev->bus->boardinfo.type == 0x416) | 
|  | 2005 | att = 3; | 
|  | 2006 | else | 
|  | 2007 | att = 1; | 
|  | 2008 | } else { | 
|  | 2009 | if (is_bcm_board_vendor(dev) && | 
|  | 2010 | dev->dev->bus->boardinfo.type == 0x421 && | 
|  | 2011 | dev->dev->bus->boardinfo.rev >= 30) | 
|  | 2012 | att = 7; | 
|  | 2013 | else | 
|  | 2014 | att = 6; | 
|  | 2015 | } | 
|  | 2016 | break; | 
|  | 2017 | case 2: | 
|  | 2018 | if (phy->type == B43legacy_PHYTYPE_G) { | 
|  | 2019 | if (is_bcm_board_vendor(dev) && | 
|  | 2020 | dev->dev->bus->boardinfo.type == 0x421 && | 
|  | 2021 | dev->dev->bus->boardinfo.rev >= 30) | 
|  | 2022 | att = 3; | 
|  | 2023 | else if (is_bcm_board_vendor(dev) && | 
|  | 2024 | dev->dev->bus->boardinfo.type == | 
|  | 2025 | 0x416) | 
|  | 2026 | att = 5; | 
|  | 2027 | else if (dev->dev->bus->chip_id == 0x4320) | 
|  | 2028 | att = 4; | 
|  | 2029 | else | 
|  | 2030 | att = 3; | 
|  | 2031 | } else | 
|  | 2032 | att = 6; | 
|  | 2033 | break; | 
|  | 2034 | case 3: | 
|  | 2035 | att = 5; | 
|  | 2036 | break; | 
|  | 2037 | case 4: | 
|  | 2038 | case 5: | 
|  | 2039 | att = 1; | 
|  | 2040 | break; | 
|  | 2041 | case 6: | 
|  | 2042 | case 7: | 
|  | 2043 | att = 5; | 
|  | 2044 | break; | 
|  | 2045 | case 8: | 
|  | 2046 | att = 0x1A; | 
|  | 2047 | break; | 
|  | 2048 | case 9: | 
|  | 2049 | default: | 
|  | 2050 | att = 5; | 
|  | 2051 | } | 
|  | 2052 | } | 
|  | 2053 | if (is_bcm_board_vendor(dev) && | 
|  | 2054 | dev->dev->bus->boardinfo.type == 0x421) { | 
|  | 2055 | if (dev->dev->bus->boardinfo.rev < 0x43) | 
|  | 2056 | att = 2; | 
|  | 2057 | else if (dev->dev->bus->boardinfo.rev < 0x51) | 
|  | 2058 | att = 3; | 
|  | 2059 | } | 
|  | 2060 | if (att == 0xFFFF) | 
|  | 2061 | att = 5; | 
|  | 2062 |  | 
|  | 2063 | return att; | 
|  | 2064 | } | 
|  | 2065 |  | 
|  | 2066 | u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev) | 
|  | 2067 | { | 
|  | 2068 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 2069 |  | 
|  | 2070 | if (phy->radio_ver != 0x2050) | 
|  | 2071 | return 0; | 
|  | 2072 | if (phy->radio_rev == 1) | 
|  | 2073 | return 3; | 
|  | 2074 | if (phy->radio_rev < 6) | 
|  | 2075 | return 2; | 
|  | 2076 | if (phy->radio_rev == 8) | 
|  | 2077 | return 1; | 
|  | 2078 | return 0; | 
|  | 2079 | } | 
|  | 2080 |  | 
|  | 2081 | void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) | 
|  | 2082 | { | 
|  | 2083 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 2084 | int err; | 
| Larry Finger | 42a9174 | 2007-09-20 21:11:02 -0500 | [diff] [blame] | 2085 | u8 channel; | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 2086 |  | 
|  | 2087 | might_sleep(); | 
|  | 2088 |  | 
|  | 2089 | if (phy->radio_on) | 
|  | 2090 | return; | 
|  | 2091 |  | 
|  | 2092 | switch (phy->type) { | 
|  | 2093 | case B43legacy_PHYTYPE_B: | 
|  | 2094 | case B43legacy_PHYTYPE_G: | 
|  | 2095 | b43legacy_phy_write(dev, 0x0015, 0x8000); | 
|  | 2096 | b43legacy_phy_write(dev, 0x0015, 0xCC00); | 
|  | 2097 | b43legacy_phy_write(dev, 0x0015, | 
|  | 2098 | (phy->gmode ? 0x00C0 : 0x0000)); | 
| Larry Finger | 42a9174 | 2007-09-20 21:11:02 -0500 | [diff] [blame] | 2099 | if (phy->radio_off_context.valid) { | 
|  | 2100 | /* Restore the RFover values. */ | 
|  | 2101 | b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, | 
|  | 2102 | phy->radio_off_context.rfover); | 
|  | 2103 | b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL, | 
|  | 2104 | phy->radio_off_context.rfoverval); | 
|  | 2105 | phy->radio_off_context.valid = 0; | 
|  | 2106 | } | 
|  | 2107 | channel = phy->channel; | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 2108 | err = b43legacy_radio_selectchannel(dev, | 
|  | 2109 | B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1); | 
| Larry Finger | 42a9174 | 2007-09-20 21:11:02 -0500 | [diff] [blame] | 2110 | err |= b43legacy_radio_selectchannel(dev, channel, 0); | 
|  | 2111 | B43legacy_WARN_ON(err); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 2112 | break; | 
|  | 2113 | default: | 
|  | 2114 | B43legacy_BUG_ON(1); | 
|  | 2115 | } | 
|  | 2116 | phy->radio_on = 1; | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 2117 | } | 
|  | 2118 |  | 
| Larry Finger | 93bb7f3 | 2007-10-10 22:44:22 -0500 | [diff] [blame] | 2119 | void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force) | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 2120 | { | 
|  | 2121 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 2122 |  | 
| Larry Finger | 93bb7f3 | 2007-10-10 22:44:22 -0500 | [diff] [blame] | 2123 | if (!phy->radio_on && !force) | 
|  | 2124 | return; | 
|  | 2125 |  | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 2126 | if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) { | 
| Larry Finger | 42a9174 | 2007-09-20 21:11:02 -0500 | [diff] [blame] | 2127 | u16 rfover, rfoverval; | 
|  | 2128 |  | 
|  | 2129 | rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER); | 
|  | 2130 | rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL); | 
| Larry Finger | 93bb7f3 | 2007-10-10 22:44:22 -0500 | [diff] [blame] | 2131 | if (!force) { | 
|  | 2132 | phy->radio_off_context.rfover = rfover; | 
|  | 2133 | phy->radio_off_context.rfoverval = rfoverval; | 
|  | 2134 | phy->radio_off_context.valid = 1; | 
|  | 2135 | } | 
| Larry Finger | 42a9174 | 2007-09-20 21:11:02 -0500 | [diff] [blame] | 2136 | b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C); | 
|  | 2137 | b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL, | 
|  | 2138 | rfoverval & 0xFF73); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 2139 | } else | 
|  | 2140 | b43legacy_phy_write(dev, 0x0015, 0xAA00); | 
|  | 2141 | phy->radio_on = 0; | 
| Larry Finger | 1065de1 | 2007-09-20 20:10:07 -0500 | [diff] [blame] | 2142 | b43legacydbg(dev->wl, "Radio initialized\n"); | 
| Larry Finger | 75388ac | 2007-09-25 16:46:54 -0700 | [diff] [blame] | 2143 | } | 
|  | 2144 |  | 
|  | 2145 | void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev) | 
|  | 2146 | { | 
|  | 2147 | struct b43legacy_phy *phy = &dev->phy; | 
|  | 2148 |  | 
|  | 2149 | switch (phy->type) { | 
|  | 2150 | case B43legacy_PHYTYPE_B: | 
|  | 2151 | case B43legacy_PHYTYPE_G: | 
|  | 2152 | b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058, | 
|  | 2153 | 0x7F7F); | 
|  | 2154 | b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a, | 
|  | 2155 | 0x7F7F); | 
|  | 2156 | b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070, | 
|  | 2157 | 0x7F7F); | 
|  | 2158 | b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072, | 
|  | 2159 | 0x7F7F); | 
|  | 2160 | break; | 
|  | 2161 | } | 
|  | 2162 | } |