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