1 /* 2 3 Broadcom B43 wireless driver 4 5 PHY workarounds. 6 7 Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> 8 Copyright (c) 2005-2007 Michael Buesch <m@bues.ch> 9 10 This program is free software; you can redistribute it and/or modify 11 it under the terms of the GNU General Public License as published by 12 the Free Software Foundation; either version 2 of the License, or 13 (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; see the file COPYING. If not, write to 22 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, 23 Boston, MA 02110-1301, USA. 24 25 */ 26 27 #include "b43.h" 28 #include "main.h" 29 #include "tables.h" 30 #include "phy_common.h" 31 #include "wa.h" 32 33 void b43_wa_initgains(struct b43_wldev *dev) 34 { 35 struct b43_phy *phy = &dev->phy; 36 37 b43_phy_write(dev, B43_PHY_LNAHPFCTL, 0x1FF9); 38 b43_phy_mask(dev, B43_PHY_LPFGAINCTL, 0xFF0F); 39 if (phy->rev <= 2) 40 b43_ofdmtab_write16(dev, B43_OFDMTAB_LPFGAIN, 0, 0x1FBF); 41 b43_radio_write16(dev, 0x0002, 0x1FBF); 42 43 b43_phy_write(dev, 0x0024, 0x4680); 44 b43_phy_write(dev, 0x0020, 0x0003); 45 b43_phy_write(dev, 0x001D, 0x0F40); 46 b43_phy_write(dev, 0x001F, 0x1C00); 47 if (phy->rev <= 3) 48 b43_phy_maskset(dev, 0x002A, 0x00FF, 0x0400); 49 else if (phy->rev == 5) { 50 b43_phy_maskset(dev, 0x002A, 0x00FF, 0x1A00); 51 b43_phy_write(dev, 0x00CC, 0x2121); 52 } 53 if (phy->rev >= 3) 54 b43_phy_write(dev, 0x00BA, 0x3ED5); 55 } 56 57 static void b43_wa_rssi_lt(struct b43_wldev *dev) /* RSSI lookup table */ 58 { 59 int i; 60 61 if (0 /* FIXME: For APHY.rev=2 this might be needed */) { 62 for (i = 0; i < 8; i++) 63 b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i + 8); 64 for (i = 8; i < 16; i++) 65 b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i - 8); 66 } else { 67 for (i = 0; i < 64; i++) 68 b43_ofdmtab_write16(dev, B43_OFDMTAB_RSSI, i, i); 69 } 70 } 71 72 static void b43_wa_analog(struct b43_wldev *dev) 73 { 74 u16 ofdmrev; 75 76 ofdmrev = b43_phy_read(dev, B43_PHY_VERSION_OFDM) & B43_PHYVER_VERSION; 77 if (ofdmrev > 2) { 78 b43_phy_write(dev, B43_PHY_PWRDOWN, 0x1000); 79 } else { 80 b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 3, 0x1044); 81 b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 4, 0x7201); 82 b43_ofdmtab_write16(dev, B43_OFDMTAB_DAC, 6, 0x0040); 83 } 84 } 85 86 static void b43_wa_fft(struct b43_wldev *dev) /* Fine frequency table */ 87 { 88 int i; 89 90 for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++) 91 b43_ofdmtab_write16(dev, B43_OFDMTAB_DACRFPABB, i, 92 b43_tab_finefreqg[i]); 93 } 94 95 static void b43_wa_nft(struct b43_wldev *dev) /* Noise figure table */ 96 { 97 struct b43_phy *phy = &dev->phy; 98 int i; 99 100 if (phy->rev == 1) 101 for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++) 102 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, 103 b43_tab_noiseg1[i]); 104 else 105 for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++) 106 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, i, 107 b43_tab_noiseg2[i]); 108 } 109 110 static void b43_wa_rt(struct b43_wldev *dev) /* Rotor table */ 111 { 112 int i; 113 114 for (i = 0; i < B43_TAB_ROTOR_SIZE; i++) 115 b43_ofdmtab_write32(dev, B43_OFDMTAB_ROTOR, i, b43_tab_rotor[i]); 116 } 117 118 static void b43_write_nst(struct b43_wldev *dev, const u16 *nst) 119 { 120 int i; 121 122 for (i = 0; i < B43_TAB_NOISESCALE_SIZE; i++) 123 b43_ofdmtab_write16(dev, B43_OFDMTAB_NOISESCALE, i, nst[i]); 124 } 125 126 static void b43_wa_nst(struct b43_wldev *dev) /* Noise scale table */ 127 { 128 struct b43_phy *phy = &dev->phy; 129 130 if (phy->rev >= 6) { 131 if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN) 132 b43_write_nst(dev, b43_tab_noisescaleg3); 133 else 134 b43_write_nst(dev, b43_tab_noisescaleg2); 135 } else { 136 b43_write_nst(dev, b43_tab_noisescaleg1); 137 } 138 } 139 140 static void b43_wa_art(struct b43_wldev *dev) /* ADV retard table */ 141 { 142 int i; 143 144 for (i = 0; i < B43_TAB_RETARD_SIZE; i++) 145 b43_ofdmtab_write32(dev, B43_OFDMTAB_ADVRETARD, 146 i, b43_tab_retard[i]); 147 } 148 149 static void b43_wa_msst(struct b43_wldev *dev) /* Min sigma square table */ 150 { 151 struct b43_phy *phy = &dev->phy; 152 int i; 153 const u16 *tab; 154 155 if (phy->type == B43_PHYTYPE_G) { 156 tab = b43_tab_sigmasqr2; 157 } else { 158 B43_WARN_ON(1); 159 return; 160 } 161 162 for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) { 163 b43_ofdmtab_write16(dev, B43_OFDMTAB_MINSIGSQ, 164 i, tab[i]); 165 } 166 } 167 168 static void b43_wa_crs_ed(struct b43_wldev *dev) 169 { 170 struct b43_phy *phy = &dev->phy; 171 172 if (phy->rev == 1) { 173 b43_phy_write(dev, B43_PHY_CRSTHRES1_R1, 0x4F19); 174 } else if (phy->rev == 2) { 175 b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x1861); 176 b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0271); 177 b43_phy_set(dev, B43_PHY_ANTDWELL, 0x0800); 178 } else { 179 b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x0098); 180 b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0070); 181 b43_phy_write(dev, B43_PHY_OFDM(0xC9), 0x0080); 182 b43_phy_set(dev, B43_PHY_ANTDWELL, 0x0800); 183 } 184 } 185 186 static void b43_wa_crs_thr(struct b43_wldev *dev) 187 { 188 b43_phy_maskset(dev, B43_PHY_CRS0, ~0x03C0, 0xD000); 189 } 190 191 static void b43_wa_crs_blank(struct b43_wldev *dev) 192 { 193 b43_phy_write(dev, B43_PHY_OFDM(0x2C), 0x005A); 194 } 195 196 static void b43_wa_cck_shiftbits(struct b43_wldev *dev) 197 { 198 b43_phy_write(dev, B43_PHY_CCKSHIFTBITS, 0x0026); 199 } 200 201 static void b43_wa_wrssi_offset(struct b43_wldev *dev) 202 { 203 int i; 204 205 if (dev->phy.rev == 1) { 206 for (i = 0; i < 16; i++) { 207 b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI_R1, 208 i, 0x0020); 209 } 210 } else { 211 for (i = 0; i < 32; i++) { 212 b43_ofdmtab_write16(dev, B43_OFDMTAB_WRSSI, 213 i, 0x0820); 214 } 215 } 216 } 217 218 static void b43_wa_txpuoff_rxpuon(struct b43_wldev *dev) 219 { 220 b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 2, 15); 221 b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_0F, 3, 20); 222 } 223 224 static void b43_wa_altagc(struct b43_wldev *dev) 225 { 226 struct b43_phy *phy = &dev->phy; 227 228 if (phy->rev == 1) { 229 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 254); 230 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 1, 13); 231 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 2, 19); 232 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 3, 25); 233 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 0, 0x2710); 234 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 1, 0x9B83); 235 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 2, 0x9B83); 236 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC2, 3, 0x0F8D); 237 b43_phy_write(dev, B43_PHY_LMS, 4); 238 } else { 239 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0, 254); 240 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 1, 13); 241 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 2, 19); 242 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25); 243 } 244 245 b43_phy_maskset(dev, B43_PHY_CCKSHIFTBITS_WA, 0x00FF, 0x5700); 246 b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), ~0x007F, 0x000F); 247 b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), ~0x3F80, 0x2B80); 248 b43_phy_maskset(dev, B43_PHY_ANTWRSETT, 0xF0FF, 0x0300); 249 b43_radio_set(dev, 0x7A, 0x0008); 250 b43_phy_maskset(dev, B43_PHY_N1P1GAIN, ~0x000F, 0x0008); 251 b43_phy_maskset(dev, B43_PHY_P1P2GAIN, ~0x0F00, 0x0600); 252 b43_phy_maskset(dev, B43_PHY_N1N2GAIN, ~0x0F00, 0x0700); 253 b43_phy_maskset(dev, B43_PHY_N1P1GAIN, ~0x0F00, 0x0100); 254 if (phy->rev == 1) { 255 b43_phy_maskset(dev, B43_PHY_N1N2GAIN, ~0x000F, 0x0007); 256 } 257 b43_phy_maskset(dev, B43_PHY_OFDM(0x88), ~0x00FF, 0x001C); 258 b43_phy_maskset(dev, B43_PHY_OFDM(0x88), ~0x3F00, 0x0200); 259 b43_phy_maskset(dev, B43_PHY_OFDM(0x96), ~0x00FF, 0x001C); 260 b43_phy_maskset(dev, B43_PHY_OFDM(0x89), ~0x00FF, 0x0020); 261 b43_phy_maskset(dev, B43_PHY_OFDM(0x89), ~0x3F00, 0x0200); 262 b43_phy_maskset(dev, B43_PHY_OFDM(0x82), ~0x00FF, 0x002E); 263 b43_phy_maskset(dev, B43_PHY_OFDM(0x96), 0x00FF, 0x1A00); 264 b43_phy_maskset(dev, B43_PHY_OFDM(0x81), ~0x00FF, 0x0028); 265 b43_phy_maskset(dev, B43_PHY_OFDM(0x81), 0x00FF, 0x2C00); 266 if (phy->rev == 1) { 267 b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B); 268 b43_phy_maskset(dev, B43_PHY_OFDM(0x1B), ~0x001E, 0x0002); 269 } else { 270 b43_phy_mask(dev, B43_PHY_OFDM(0x1B), ~0x001E); 271 b43_phy_write(dev, B43_PHY_OFDM(0x1F), 0x287A); 272 b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, ~0x000F, 0x0004); 273 if (phy->rev >= 6) { 274 b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A); 275 b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, 0x0FFF, 0x3000); 276 } 277 } 278 b43_phy_maskset(dev, B43_PHY_DIVSRCHIDX, 0x8080, 0x7874); 279 b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x1C00); 280 if (phy->rev == 1) { 281 b43_phy_maskset(dev, B43_PHY_DIVP1P2GAIN, ~0x0F00, 0x0600); 282 b43_phy_write(dev, B43_PHY_OFDM(0x8B), 0x005E); 283 b43_phy_maskset(dev, B43_PHY_ANTWRSETT, ~0x00FF, 0x001E); 284 b43_phy_write(dev, B43_PHY_OFDM(0x8D), 0x0002); 285 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 0, 0); 286 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 1, 7); 287 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 2, 16); 288 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 3, 28); 289 } else { 290 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 0, 0); 291 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 1, 7); 292 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 2, 16); 293 b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 3, 28); 294 } 295 if (phy->rev >= 6) { 296 b43_phy_mask(dev, B43_PHY_OFDM(0x26), ~0x0003); 297 b43_phy_mask(dev, B43_PHY_OFDM(0x26), ~0x1000); 298 } 299 b43_phy_read(dev, B43_PHY_VERSION_OFDM); /* Dummy read */ 300 } 301 302 static void b43_wa_tr_ltov(struct b43_wldev *dev) /* TR Lookup Table Original Values */ 303 { 304 b43_gtab_write(dev, B43_GTAB_ORIGTR, 0, 0x7654); 305 } 306 307 static void b43_wa_cpll_nonpilot(struct b43_wldev *dev) 308 { 309 b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 0, 0); 310 b43_ofdmtab_write16(dev, B43_OFDMTAB_UNKNOWN_11, 1, 0); 311 } 312 313 static void b43_wa_boards_g(struct b43_wldev *dev) 314 { 315 struct ssb_sprom *sprom = dev->dev->bus_sprom; 316 struct b43_phy *phy = &dev->phy; 317 318 if (dev->dev->board_vendor != SSB_BOARDVENDOR_BCM || 319 dev->dev->board_type != SSB_BOARD_BU4306 || 320 dev->dev->board_rev != 0x17) { 321 if (phy->rev < 2) { 322 b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 1, 0x0002); 323 b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 2, 0x0001); 324 } else { 325 b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 1, 0x0002); 326 b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001); 327 if ((sprom->boardflags_lo & B43_BFL_EXTLNA) && 328 (phy->rev >= 7)) { 329 b43_phy_mask(dev, B43_PHY_EXTG(0x11), 0xF7FF); 330 b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001); 331 b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0021, 0x0001); 332 b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0022, 0x0001); 333 b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0023, 0x0000); 334 b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0000, 0x0000); 335 b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0003, 0x0002); 336 } 337 } 338 } 339 if (sprom->boardflags_lo & B43_BFL_FEM) { 340 b43_phy_write(dev, B43_PHY_GTABCTL, 0x3120); 341 b43_phy_write(dev, B43_PHY_GTABDATA, 0xC480); 342 } 343 } 344 345 void b43_wa_all(struct b43_wldev *dev) 346 { 347 struct b43_phy *phy = &dev->phy; 348 349 if (phy->type == B43_PHYTYPE_G) { 350 switch (phy->rev) { 351 case 1://XXX review rev1 352 b43_wa_crs_ed(dev); 353 b43_wa_crs_thr(dev); 354 b43_wa_crs_blank(dev); 355 b43_wa_cck_shiftbits(dev); 356 b43_wa_fft(dev); 357 b43_wa_nft(dev); 358 b43_wa_rt(dev); 359 b43_wa_nst(dev); 360 b43_wa_art(dev); 361 b43_wa_wrssi_offset(dev); 362 b43_wa_altagc(dev); 363 break; 364 case 2: 365 case 6: 366 case 7: 367 case 8: 368 case 9: 369 b43_wa_tr_ltov(dev); 370 b43_wa_crs_ed(dev); 371 b43_wa_rssi_lt(dev); 372 b43_wa_nft(dev); 373 b43_wa_nst(dev); 374 b43_wa_msst(dev); 375 b43_wa_wrssi_offset(dev); 376 b43_wa_altagc(dev); 377 b43_wa_analog(dev); 378 b43_wa_txpuoff_rxpuon(dev); 379 break; 380 default: 381 B43_WARN_ON(1); 382 } 383 b43_wa_boards_g(dev); 384 } else { /* No N PHY support so far, LP PHY is in phy_lp.c */ 385 B43_WARN_ON(1); 386 } 387 388 b43_wa_cpll_nonpilot(dev); 389 } 390