?? bcm43xx_phy.c
字號:
bcm43xx_radio_write16(bcm, 0x007A, regstack[10] & 0xFFF0); bcm43xx_phy_write(bcm, 0x002B, 0x0203); bcm43xx_phy_write(bcm, 0x002A, 0x08A3); if (phy->connected) { bcm43xx_phy_write(bcm, 0x0814, regstack[14] | 0x0003); bcm43xx_phy_write(bcm, 0x0815, regstack[15] & 0xFFFC); bcm43xx_phy_write(bcm, 0x0811, 0x01B3); bcm43xx_phy_write(bcm, 0x0812, 0x00B2); } if (is_initializing) bcm43xx_phy_lo_g_measure_txctl2(bcm); bcm43xx_phy_write(bcm, 0x080F, 0x8078); /* Measure */ control.low = 0; control.high = 0; for (h = 0; h < 10; h++) { /* Loop over each possible RadioAttenuation (0-9) */ i = pairorder[h]; if (is_initializing) { if (i == 3) { control.low = 0; control.high = 0; } else if (((i % 2 == 1) && (oldi % 2 == 1)) || ((i % 2 == 0) && (oldi % 2 == 0))) { tmp_control = bcm43xx_get_lopair(phy, oldi, 0); memcpy(&control, tmp_control, sizeof(control)); } else { tmp_control = bcm43xx_get_lopair(phy, 3, 0); memcpy(&control, tmp_control, sizeof(control)); } } /* Loop over each possible BasebandAttenuation/2 */ for (j = 0; j < 4; j++) { if (is_initializing) { tmp = i * 2 + j; r27 = 0; r31 = 0; if (tmp > 14) { r31 = 1; if (tmp > 17) r27 = 1; if (tmp > 19) r27 = 2; } } else { tmp_control = bcm43xx_get_lopair(phy, i, j * 2); if (!tmp_control->used) continue; memcpy(&control, tmp_control, sizeof(control)); r27 = 3; r31 = 0; } bcm43xx_radio_write16(bcm, 0x43, i); bcm43xx_radio_write16(bcm, 0x52, radio->txctl2); udelay(10); bcm43xx_voluntary_preempt(); bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); tmp = (regstack[10] & 0xFFF0); if (r31) tmp |= 0x0008; bcm43xx_radio_write16(bcm, 0x007A, tmp); tmp_control = bcm43xx_get_lopair(phy, i, j * 2); bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); } oldi = i; } /* Loop over each possible RadioAttenuation (10-13) */ for (i = 10; i < 14; i++) { /* Loop over each possible BasebandAttenuation/2 */ for (j = 0; j < 4; j++) { if (is_initializing) { tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); memcpy(&control, tmp_control, sizeof(control)); tmp = (i - 9) * 2 + j - 5;//FIXME: This is wrong, as the following if statement can never trigger. r27 = 0; r31 = 0; if (tmp > 14) { r31 = 1; if (tmp > 17) r27 = 1; if (tmp > 19) r27 = 2; } } else { tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); if (!tmp_control->used) continue; memcpy(&control, tmp_control, sizeof(control)); r27 = 3; r31 = 0; } bcm43xx_radio_write16(bcm, 0x43, i - 9); bcm43xx_radio_write16(bcm, 0x52, radio->txctl2 | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? udelay(10); bcm43xx_voluntary_preempt(); bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); tmp = (regstack[10] & 0xFFF0); if (r31) tmp |= 0x0008; bcm43xx_radio_write16(bcm, 0x7A, tmp); tmp_control = bcm43xx_get_lopair(phy, i, j * 2); bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); } } /* Restoration */ if (phy->connected) { bcm43xx_phy_write(bcm, 0x0015, 0xE300); bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA0); udelay(5); bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2); udelay(2); bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3); bcm43xx_voluntary_preempt(); } else bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0); bcm43xx_phy_lo_adjust(bcm, is_initializing); bcm43xx_phy_write(bcm, 0x002E, 0x807F); if (phy->connected) bcm43xx_phy_write(bcm, 0x002F, 0x0202); else bcm43xx_phy_write(bcm, 0x002F, 0x0101); bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, regstack[4]); bcm43xx_phy_write(bcm, 0x0015, regstack[5]); bcm43xx_phy_write(bcm, 0x002A, regstack[6]); bcm43xx_phy_write(bcm, 0x0035, regstack[7]); bcm43xx_phy_write(bcm, 0x0060, regstack[8]); bcm43xx_radio_write16(bcm, 0x0043, regstack[9]); bcm43xx_radio_write16(bcm, 0x007A, regstack[10]); regstack[11] &= 0x00F0; regstack[11] |= (bcm43xx_radio_read16(bcm, 0x52) & 0x000F); bcm43xx_radio_write16(bcm, 0x52, regstack[11]); bcm43xx_write16(bcm, 0x03E2, regstack[3]); if (phy->connected) { bcm43xx_phy_write(bcm, 0x0811, regstack[12]); bcm43xx_phy_write(bcm, 0x0812, regstack[13]); bcm43xx_phy_write(bcm, 0x0814, regstack[14]); bcm43xx_phy_write(bcm, 0x0815, regstack[15]); bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0]); bcm43xx_phy_write(bcm, 0x0802, regstack[1]); } bcm43xx_radio_selectchannel(bcm, oldchannel, 1);#ifdef CONFIG_BCM43XX_DEBUG { /* Sanity check for all lopairs. */ for (i = 0; i < BCM43xx_LO_COUNT; i++) { tmp_control = phy->_lo_pairs + i; if (tmp_control->low < -8 || tmp_control->low > 8 || tmp_control->high < -8 || tmp_control->high > 8) { printk(KERN_WARNING PFX "WARNING: Invalid LOpair (low: %d, high: %d, index: %d)\n", tmp_control->low, tmp_control->high, i); } } }#endif /* CONFIG_BCM43XX_DEBUG */}staticvoid bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm){ struct bcm43xx_lopair *pair; pair = bcm43xx_current_lopair(bcm); pair->used = 1;}void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm){ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_lopair *pair; int i; for (i = 0; i < BCM43xx_LO_COUNT; i++) { pair = phy->_lo_pairs + i; pair->used = 0; }}/* http://bcm-specs.sipsolutions.net/EstimatePowerOut * This function converts a TSSI value to dBm in Q5.2 */static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi){ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); s8 dbm = 0; s32 tmp; tmp = phy->idle_tssi; tmp += tssi; tmp -= phy->savedpctlreg; switch (phy->type) { case BCM43xx_PHYTYPE_A: tmp += 0x80; tmp = limit_value(tmp, 0x00, 0xFF); dbm = phy->tssi2dbm[tmp]; TODO(); //TODO: There's a FIXME on the specs break; case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: tmp = limit_value(tmp, 0x00, 0x3F); dbm = phy->tssi2dbm[tmp]; break; default: assert(0); } return dbm;}/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm){ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (phy->savedpctlreg == 0xFFFF) return; if ((bcm->board_type == 0x0416) && (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM)) return; switch (phy->type) { case BCM43xx_PHYTYPE_A: { TODO(); //TODO: Nothing for A PHYs yet :-/ break; } case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: { u16 tmp; u16 txpower; s8 v0, v1, v2, v3; s8 average; u8 max_pwr; s16 desired_pwr, estimated_pwr, pwr_adjust; s16 radio_att_delta, baseband_att_delta; s16 radio_attenuation, baseband_attenuation; unsigned long phylock_flags; tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0058); v0 = (s8)(tmp & 0x00FF); v1 = (s8)((tmp & 0xFF00) >> 8); tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005A); v2 = (s8)(tmp & 0x00FF); v3 = (s8)((tmp & 0xFF00) >> 8); tmp = 0; if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) { tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0070); v0 = (s8)(tmp & 0x00FF); v1 = (s8)((tmp & 0xFF00) >> 8); tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0072); v2 = (s8)(tmp & 0x00FF); v3 = (s8)((tmp & 0xFF00) >> 8); if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) return; v0 = (v0 + 0x20) & 0x3F; v1 = (v1 + 0x20) & 0x3F; v2 = (v2 + 0x20) & 0x3F; v3 = (v3 + 0x20) & 0x3F; tmp = 1; } bcm43xx_radio_clear_tssi(bcm); average = (v0 + v1 + v2 + v3 + 2) / 4; if (tmp && (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005E) & 0x8)) average -= 13; estimated_pwr = bcm43xx_phy_estimate_power_out(bcm, average); max_pwr = bcm->sprom.maxpower_bgphy; if ((bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) && (phy->type == BCM43xx_PHYTYPE_G)) max_pwr -= 0x3; /*TODO: max_pwr = min(REG - bcm->sprom.antennagain_bgphy - 0x6, max_pwr) where REG is the max power as per the regulatory domain */ desired_pwr = limit_value(radio->txpower_desired, 0, max_pwr); /* Check if we need to adjust the current power. */ pwr_adjust = desired_pwr - estimated_pwr; radio_att_delta = -(pwr_adjust + 7) >> 3; baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { bcm43xx_phy_lo_mark_current_used(bcm); return; } /* Calculate the new attenuation values. */ baseband_attenuation = radio->baseband_atten; baseband_attenuation += baseband_att_delta; radio_attenuation = radio->radio_atten; radio_attenuation += radio_att_delta; /* Get baseband and radio attenuation values into their permitted ranges. * baseband 0-11, radio 0-9. * Radio attenuation affects power level 4 times as much as baseband. */ if (radio_attenuation < 0) { baseband_attenuation -= (4 * -radio_attenuation); radio_attenuation = 0; } else if (radio_attenuation > 9) { baseband_attenuation += (4 * (radio_attenuation - 9)); radio_attenuation = 9; } else { while (baseband_attenuation < 0 && radio_attenuation > 0) { baseband_attenuation += 4; radio_attenuation--; } while (baseband_attenuation > 11 && radio_attenuation < 9) { baseband_attenuation -= 4; radio_attenuation++; } } baseband_attenuation = limit_value(baseband_attenuation, 0, 11); txpower = radio->txctl1; if ((radio->version == 0x2050) && (radio->revision == 2)) { if (radio_attenuation <= 1) { if (txpower == 0) { txpower = 3; radio_attenuation += 2; baseband_attenuation += 2; } else if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { baseband_attenuation += 4 * (radio_attenuation - 2); radio_attenuation = 2; } } else if (radio_attenuation > 4 && txpower != 0) { txpower = 0; if (baseband_attenuation < 3) { radio_attenuation -= 3; baseband_attenuation += 2; } else { radio_attenuation -= 2; baseband_attenuation -= 2; } } } radio->txctl1 = txpower; baseband_attenuation = limit_value(baseband_attenuation, 0, 11); radio_attenuation = limit_value(radio_attenuation, 0, 9); bcm43xx_phy_lock(bcm, phylock_flags); bcm43xx_radio_lock(bcm); bcm43xx_radio_set_txpower_bg(bcm, baseband_attenuation, radio_attenuation, txpower); bcm43xx_phy_lo_mark_current_used(bcm); bcm43xx_radio_unlock(bcm); bcm43xx_phy_unlock(bcm, phylock_flags); break; } default: assert(0); }}static inlines32 bcm43xx_tssi2dbm_ad(s32 num, s32 den){ if (num < 0) return num/den; else return (num+den/2)/den;}static inlines8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2){ s32 m1, m2, f = 256, q, delta; s8 i = 0; m1 = bcm43xx_tssi2dbm_ad(16 * pab0 + index * pab1, 32); m2 = max(bcm43xx_tssi2dbm_ad(32768 + index * pab2, 256), 1); do { if (i > 15) return -EINVAL; q = bcm43xx_tssi2dbm_ad(f * 4096 - bcm43xx_tssi2dbm_ad(m2 * f, 16) * f, 2048); delta = abs(q - f); f = q; i++; } while (delta >= 2); entry[index] = limit_value(bcm43xx_tssi2dbm_ad(m1 * f, 8192), -127, 128); return 0;}/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm){ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); s16 pab0, pab1, pab2; u8 idx; s8 *dyn_tssi2dbm; if (phy->type == BCM43xx_PHYTYPE_A) { pab0 = (s16)(bcm->sprom.pa1b0); pab1 = (s16)(bcm->sprom.pa1b1); pab2 = (s16)(bcm->sprom.pa1b2); } else { pab0 = (s16)(bcm->sprom.pa0b0); pab1 = (s16)(bcm->sprom.pa0b1); pab2 = (s16)(bcm->sprom.pa0b2); } if ((bcm->chip_id == 0x4301) &
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -