Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

b43: Add parts of LP-PHY TX power control

This adds the initial parts of the LP-PHY TX power control.
This also adds helper functions for bulk access of LP tables.

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Michael Buesch and committed by
John W. Linville
ce1a9ee3 7a947080

+262 -3
+3
drivers/net/wireless/b43/b43.h
··· 120 120 #define B43_MMIO_IFSCTL 0x688 /* Interframe space control */ 121 121 #define B43_MMIO_IFSCTL_USE_EDCF 0x0004 122 122 #define B43_MMIO_POWERUP_DELAY 0x6A8 123 + #define B43_MMIO_BTCOEX_CTL 0x6B4 /* Bluetooth Coexistence Control */ 124 + #define B43_MMIO_BTCOEX_STAT 0x6B6 /* Bluetooth Coexistence Status */ 125 + #define B43_MMIO_BTCOEX_TXCTL 0x6B8 /* Bluetooth Coexistence Transmit Control */ 123 126 124 127 /* SPROM boardflags_lo values */ 125 128 #define B43_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */
+175 -2
drivers/net/wireless/b43/phy_lp.c
··· 23 23 */ 24 24 25 25 #include "b43.h" 26 + #include "main.h" 26 27 #include "phy_lp.h" 27 28 #include "phy_common.h" 28 29 #include "tables_lpphy.h" ··· 268 267 } 269 268 } 270 269 270 + /* Read the TX power control mode from hardware. */ 271 + static void lpphy_read_tx_pctl_mode_from_hardware(struct b43_wldev *dev) 272 + { 273 + struct b43_phy_lp *lpphy = dev->phy.lp; 274 + u16 ctl; 275 + 276 + ctl = b43_phy_read(dev, B43_LPPHY_TX_PWR_CTL_CMD); 277 + switch (ctl & B43_LPPHY_TX_PWR_CTL_CMD_MODE) { 278 + case B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF: 279 + lpphy->txpctl_mode = B43_LPPHY_TXPCTL_OFF; 280 + break; 281 + case B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW: 282 + lpphy->txpctl_mode = B43_LPPHY_TXPCTL_SW; 283 + break; 284 + case B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW: 285 + lpphy->txpctl_mode = B43_LPPHY_TXPCTL_HW; 286 + break; 287 + default: 288 + lpphy->txpctl_mode = B43_LPPHY_TXPCTL_UNKNOWN; 289 + B43_WARN_ON(1); 290 + break; 291 + } 292 + } 293 + 294 + /* Set the TX power control mode in hardware. */ 295 + static void lpphy_write_tx_pctl_mode_to_hardware(struct b43_wldev *dev) 296 + { 297 + struct b43_phy_lp *lpphy = dev->phy.lp; 298 + u16 ctl; 299 + 300 + switch (lpphy->txpctl_mode) { 301 + case B43_LPPHY_TXPCTL_OFF: 302 + ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF; 303 + break; 304 + case B43_LPPHY_TXPCTL_HW: 305 + ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW; 306 + break; 307 + case B43_LPPHY_TXPCTL_SW: 308 + ctl = B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW; 309 + break; 310 + default: 311 + ctl = 0; 312 + B43_WARN_ON(1); 313 + } 314 + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD, 315 + (u16)~B43_LPPHY_TX_PWR_CTL_CMD_MODE, ctl); 316 + } 317 + 318 + static void lpphy_set_tx_power_control(struct b43_wldev *dev, 319 + enum b43_lpphy_txpctl_mode mode) 320 + { 321 + struct b43_phy_lp *lpphy = dev->phy.lp; 322 + enum b43_lpphy_txpctl_mode oldmode; 323 + 324 + oldmode = lpphy->txpctl_mode; 325 + lpphy_read_tx_pctl_mode_from_hardware(dev); 326 + if (lpphy->txpctl_mode == mode) 327 + return; 328 + lpphy->txpctl_mode = mode; 329 + 330 + if (oldmode == B43_LPPHY_TXPCTL_HW) { 331 + //TODO Update TX Power NPT 332 + //TODO Clear all TX Power offsets 333 + } else { 334 + if (mode == B43_LPPHY_TXPCTL_HW) { 335 + //TODO Recalculate target TX power 336 + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_CMD, 337 + 0xFF80, lpphy->tssi_idx); 338 + b43_phy_maskset(dev, B43_LPPHY_TX_PWR_CTL_NNUM, 339 + 0x8FFF, ((u16)lpphy->tssi_npt << 16)); 340 + //TODO Set "TSSI Transmit Count" variable to total transmitted frame count 341 + //TODO Disable TX gain override 342 + lpphy->tx_pwr_idx_over = -1; 343 + } 344 + } 345 + if (dev->phy.rev >= 2) { 346 + if (mode == B43_LPPHY_TXPCTL_HW) 347 + b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0x2); 348 + else 349 + b43_phy_maskset(dev, B43_PHY_OFDM(0xD0), 0xFD, 0); 350 + } 351 + lpphy_write_tx_pctl_mode_to_hardware(dev); 352 + } 353 + 354 + static void lpphy_set_tx_power_by_index(struct b43_wldev *dev, u8 index) 355 + { 356 + struct b43_phy_lp *lpphy = dev->phy.lp; 357 + 358 + lpphy->tx_pwr_idx_over = index; 359 + if (lpphy->txpctl_mode != B43_LPPHY_TXPCTL_OFF) 360 + lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_SW); 361 + 362 + //TODO 363 + } 364 + 365 + static void lpphy_btcoex_override(struct b43_wldev *dev) 366 + { 367 + b43_write16(dev, B43_MMIO_BTCOEX_CTL, 0x3); 368 + b43_write16(dev, B43_MMIO_BTCOEX_TXCTL, 0xFF); 369 + } 370 + 371 + static void lpphy_pr41573_workaround(struct b43_wldev *dev) 372 + { 373 + struct b43_phy_lp *lpphy = dev->phy.lp; 374 + u32 *saved_tab; 375 + const unsigned int saved_tab_size = 256; 376 + enum b43_lpphy_txpctl_mode txpctl_mode; 377 + s8 tx_pwr_idx_over; 378 + u16 tssi_npt, tssi_idx; 379 + 380 + saved_tab = kcalloc(saved_tab_size, sizeof(saved_tab[0]), GFP_KERNEL); 381 + if (!saved_tab) { 382 + b43err(dev->wl, "PR41573 failed. Out of memory!\n"); 383 + return; 384 + } 385 + 386 + lpphy_read_tx_pctl_mode_from_hardware(dev); 387 + txpctl_mode = lpphy->txpctl_mode; 388 + tx_pwr_idx_over = lpphy->tx_pwr_idx_over; 389 + tssi_npt = lpphy->tssi_npt; 390 + tssi_idx = lpphy->tssi_idx; 391 + 392 + if (dev->phy.rev < 2) { 393 + b43_lptab_read_bulk(dev, B43_LPTAB32(10, 0x140), 394 + saved_tab_size, saved_tab); 395 + } else { 396 + b43_lptab_read_bulk(dev, B43_LPTAB32(7, 0x140), 397 + saved_tab_size, saved_tab); 398 + } 399 + //TODO 400 + 401 + kfree(saved_tab); 402 + } 403 + 404 + static void lpphy_calibration(struct b43_wldev *dev) 405 + { 406 + struct b43_phy_lp *lpphy = dev->phy.lp; 407 + enum b43_lpphy_txpctl_mode saved_pctl_mode; 408 + 409 + b43_mac_suspend(dev); 410 + 411 + lpphy_btcoex_override(dev); 412 + lpphy_read_tx_pctl_mode_from_hardware(dev); 413 + saved_pctl_mode = lpphy->txpctl_mode; 414 + lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF); 415 + //TODO Perform transmit power table I/Q LO calibration 416 + if ((dev->phy.rev == 0) && (saved_pctl_mode != B43_LPPHY_TXPCTL_OFF)) 417 + lpphy_pr41573_workaround(dev); 418 + //TODO If a full calibration has not been performed on this channel yet, perform PAPD TX-power calibration 419 + lpphy_set_tx_power_control(dev, saved_pctl_mode); 420 + //TODO Perform I/Q calibration with a single control value set 421 + 422 + b43_mac_enable(dev); 423 + } 424 + 425 + /* Initialize TX power control */ 426 + static void lpphy_tx_pctl_init(struct b43_wldev *dev) 427 + { 428 + if (0/*FIXME HWPCTL capable */) { 429 + //TODO 430 + } else { /* This device is only software TX power control capable. */ 431 + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { 432 + //TODO 433 + } else { 434 + //TODO 435 + } 436 + //TODO set BB multiplier to 0x0096 437 + } 438 + } 439 + 271 440 static int b43_lpphy_op_init(struct b43_wldev *dev) 272 441 { 273 442 /* TODO: band SPROM */ 274 443 lpphy_baseband_init(dev); 275 444 lpphy_radio_init(dev); 276 - 277 - //TODO 445 + //TODO calibrate RC 446 + //TODO set channel 447 + lpphy_tx_pctl_init(dev); 448 + //TODO full calib 278 449 279 450 return 0; 280 451 }
+15 -1
drivers/net/wireless/b43/phy_lp.h
··· 247 247 #define B43_LPPHY_FOURWIRE_CTL B43_PHY_OFDM(0xA2) /* fourwire Control */ 248 248 #define B43_LPPHY_CPA_TAILCOUNT_VAL B43_PHY_OFDM(0xA3) /* CPA TailCount Value */ 249 249 #define B43_LPPHY_TX_PWR_CTL_CMD B43_PHY_OFDM(0xA4) /* TX Power Control Cmd */ 250 + #define B43_LPPHY_TX_PWR_CTL_CMD_MODE 0xE000 /* TX power control mode mask */ 251 + #define B43_LPPHY_TX_PWR_CTL_CMD_MODE_OFF 0x0000 /* TX power control is OFF */ 252 + #define B43_LPPHY_TX_PWR_CTL_CMD_MODE_SW 0x8000 /* TX power control is SOFTWARE */ 253 + #define B43_LPPHY_TX_PWR_CTL_CMD_MODE_HW 0xE000 /* TX power control is HARDWARE */ 250 254 #define B43_LPPHY_TX_PWR_CTL_NNUM B43_PHY_OFDM(0xA5) /* TX Power Control Nnum */ 251 255 #define B43_LPPHY_TX_PWR_CTL_IDLETSSI B43_PHY_OFDM(0xA6) /* TX Power Control IdleTssi */ 252 256 #define B43_LPPHY_TX_PWR_CTL_TARGETPWR B43_PHY_OFDM(0xA7) /* TX Power Control TargetPower */ ··· 806 802 807 803 808 804 805 + enum b43_lpphy_txpctl_mode { 806 + B43_LPPHY_TXPCTL_UNKNOWN = 0, 807 + B43_LPPHY_TXPCTL_OFF, /* TX power control is OFF */ 808 + B43_LPPHY_TXPCTL_SW, /* TX power control is set to Software */ 809 + B43_LPPHY_TXPCTL_HW, /* TX power control is set to Hardware */ 810 + }; 811 + 809 812 struct b43_phy_lp { 813 + /* Current TX power control mode. */ 814 + enum b43_lpphy_txpctl_mode txpctl_mode; 815 + 810 816 /* Transmit isolation medium band */ 811 817 u8 tx_isolation_med_band; /* FIXME initial value? */ 812 818 /* Transmit isolation low band */ ··· 828 814 u8 rx_pwr_offset; /* FIXME initial value? */ 829 815 830 816 /* TSSI transmit count */ 831 - u16 tssi_tx_count; /* FIXME initial value? */ 817 + u16 tssi_tx_count; 832 818 /* TSSI index */ 833 819 u16 tssi_idx; /* FIXME initial value? */ 834 820 /* TSSI npt */
+61
drivers/net/wireless/b43/tables_lpphy.c
··· 303 303 return value; 304 304 } 305 305 306 + void b43_lptab_read_bulk(struct b43_wldev *dev, u32 offset, 307 + unsigned int nr_elements, void *_data) 308 + { 309 + u32 type, value; 310 + u8 *data = _data; 311 + unsigned int i; 312 + 313 + type = offset & B43_LPTAB_TYPEMASK; 314 + for (i = 0; i < nr_elements; i++) { 315 + value = b43_lptab_read(dev, offset); 316 + switch (type) { 317 + case B43_LPTAB_8BIT: 318 + *data = value; 319 + data++; 320 + break; 321 + case B43_LPTAB_16BIT: 322 + *((u16 *)data) = value; 323 + data += 2; 324 + break; 325 + case B43_LPTAB_32BIT: 326 + *((u32 *)data) = value; 327 + data += 4; 328 + break; 329 + default: 330 + B43_WARN_ON(1); 331 + } 332 + offset++; 333 + } 334 + } 335 + 306 336 void b43_lptab_write(struct b43_wldev *dev, u32 offset, u32 value) 307 337 { 308 338 u32 type; ··· 359 329 break; 360 330 default: 361 331 B43_WARN_ON(1); 332 + } 333 + } 334 + 335 + void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, 336 + unsigned int nr_elements, const void *_data) 337 + { 338 + u32 type, value; 339 + const u8 *data = _data; 340 + unsigned int i; 341 + 342 + type = offset & B43_LPTAB_TYPEMASK; 343 + for (i = 0; i < nr_elements; i++) { 344 + switch (type) { 345 + case B43_LPTAB_8BIT: 346 + value = *data; 347 + data++; 348 + break; 349 + case B43_LPTAB_16BIT: 350 + value = *((u16 *)data); 351 + data += 2; 352 + break; 353 + case B43_LPTAB_32BIT: 354 + value = *((u32 *)data); 355 + data += 4; 356 + break; 357 + default: 358 + B43_WARN_ON(1); 359 + value = 0; 360 + } 361 + b43_lptab_write(dev, offset, value); 362 + offset++; 362 363 } 363 364 }
+8
drivers/net/wireless/b43/tables_lpphy.h
··· 17 17 u32 b43_lptab_read(struct b43_wldev *dev, u32 offset); 18 18 void b43_lptab_write(struct b43_wldev *dev, u32 offset, u32 value); 19 19 20 + /* Bulk table access. Note that these functions return the bulk data in 21 + * host endianness! The returned data is _not_ a bytearray, but an array 22 + * consisting of nr_elements of the data type. */ 23 + void b43_lptab_read_bulk(struct b43_wldev *dev, u32 offset, 24 + unsigned int nr_elements, void *data); 25 + void b43_lptab_write_bulk(struct b43_wldev *dev, u32 offset, 26 + unsigned int nr_elements, const void *data); 27 + 20 28 void b2062_upload_init_table(struct b43_wldev *dev); 21 29 22 30