diff options
Diffstat (limited to 'drivers/net/wireless/b43/phy_ht.c')
-rw-r--r-- | drivers/net/wireless/b43/phy_ht.c | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index 7c40919651a..7416c5e9154 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -3,6 +3,8 @@ Broadcom B43 wireless driver IEEE 802.11n HT-PHY support + Copyright (c) 2011 Rafał Miłecki <zajec5@gmail.com> + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -152,6 +154,92 @@ static void b43_radio_2059_init(struct b43_wldev *dev) } /************************************************** + * Various PHY ops + **************************************************/ + +static void b43_phy_ht_zero_extg(struct b43_wldev *dev) +{ + u8 i, j; + u16 base[] = { 0x40, 0x60, 0x80 }; + + for (i = 0; i < ARRAY_SIZE(base); i++) { + for (j = 0; j < 4; j++) + b43_phy_write(dev, B43_PHY_EXTG(base[i] + j), 0); + } + + for (i = 0; i < ARRAY_SIZE(base); i++) + b43_phy_write(dev, B43_PHY_EXTG(base[i] + 0xc), 0); +} + +/* Some unknown AFE (Analog Frondned) op */ +static void b43_phy_ht_afe_unk1(struct b43_wldev *dev) +{ + u8 i; + + const u16 ctl_regs[3][2] = { + { B43_PHY_HT_AFE_CTL1, B43_PHY_HT_AFE_CTL2 }, + { B43_PHY_HT_AFE_CTL3, B43_PHY_HT_AFE_CTL4 }, + { B43_PHY_HT_AFE_CTL5, B43_PHY_HT_AFE_CTL6}, + }; + + for (i = 0; i < 3; i++) { + /* TODO: verify masks&sets */ + b43_phy_set(dev, ctl_regs[i][1], 0x4); + b43_phy_set(dev, ctl_regs[i][0], 0x4); + b43_phy_mask(dev, ctl_regs[i][1], ~0x1); + b43_phy_set(dev, ctl_regs[i][0], 0x1); + b43_httab_write(dev, B43_HTTAB16(8, 5 + (i * 0x10)), 0); + b43_phy_mask(dev, ctl_regs[i][0], ~0x4); + } +} + +static void b43_phy_ht_force_rf_sequence(struct b43_wldev *dev, u16 rf_seq) +{ + u8 i; + + u16 save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE); + b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE, 0x3); + + b43_phy_set(dev, B43_PHY_HT_RF_SEQ_TRIG, rf_seq); + for (i = 0; i < 200; i++) { + if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & rf_seq)) { + i = 0; + break; + } + msleep(1); + } + if (i) + b43err(dev->wl, "Forcing RF sequence timeout\n"); + + b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode); +} + +static void b43_phy_ht_read_clip_detection(struct b43_wldev *dev, u16 *clip_st) +{ + clip_st[0] = b43_phy_read(dev, B43_PHY_HT_C1_CLIP1THRES); + clip_st[1] = b43_phy_read(dev, B43_PHY_HT_C2_CLIP1THRES); + clip_st[2] = b43_phy_read(dev, B43_PHY_HT_C3_CLIP1THRES); +} + +static void b43_phy_ht_bphy_init(struct b43_wldev *dev) +{ + unsigned int i; + u16 val; + + val = 0x1E1F; + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val); + val -= 0x202; + } + val = 0x3E3F; + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x98 + i), val); + val -= 0x202; + } + b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); +} + +/************************************************** * Channel switching ops. **************************************************/ @@ -255,8 +343,125 @@ static void b43_phy_ht_op_prepare_structs(struct b43_wldev *dev) static int b43_phy_ht_op_init(struct b43_wldev *dev) { + u16 tmp; + u16 clip_state[3]; + b43_phy_ht_tables_init(dev); + b43_phy_mask(dev, 0x0be, ~0x2); + b43_phy_set(dev, 0x23f, 0x7ff); + b43_phy_set(dev, 0x240, 0x7ff); + b43_phy_set(dev, 0x241, 0x7ff); + + b43_phy_ht_zero_extg(dev); + + b43_phy_mask(dev, B43_PHY_EXTG(0), ~0x3); + + b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0); + b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0); + b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0); + + b43_phy_write(dev, B43_PHY_EXTG(0x103), 0x20); + b43_phy_write(dev, B43_PHY_EXTG(0x101), 0x20); + b43_phy_write(dev, 0x20d, 0xb8); + b43_phy_write(dev, B43_PHY_EXTG(0x14f), 0xc8); + b43_phy_write(dev, 0x70, 0x50); + b43_phy_write(dev, 0x1ff, 0x30); + + if (0) /* TODO: condition */ + ; /* TODO: PHY op on reg 0x217 */ + + b43_phy_read(dev, 0xb0); /* TODO: what for? */ + b43_phy_set(dev, 0xb0, 0x1); + + b43_phy_set(dev, 0xb1, 0x91); + b43_phy_write(dev, 0x32f, 0x0003); + b43_phy_write(dev, 0x077, 0x0010); + b43_phy_write(dev, 0x0b4, 0x0258); + b43_phy_mask(dev, 0x17e, ~0x4000); + + b43_phy_write(dev, 0x0b9, 0x0072); + + b43_httab_write_few(dev, B43_HTTAB16(7, 0x14e), 2, 0x010f, 0x010f); + b43_httab_write_few(dev, B43_HTTAB16(7, 0x15e), 2, 0x010f, 0x010f); + b43_httab_write_few(dev, B43_HTTAB16(7, 0x16e), 2, 0x010f, 0x010f); + + b43_phy_ht_afe_unk1(dev); + + b43_httab_write_few(dev, B43_HTTAB16(7, 0x130), 9, 0x777, 0x111, 0x111, + 0x777, 0x111, 0x111, 0x777, 0x111, 0x111); + + b43_httab_write(dev, B43_HTTAB16(7, 0x120), 0x0777); + b43_httab_write(dev, B43_HTTAB16(7, 0x124), 0x0777); + + b43_httab_write(dev, B43_HTTAB16(8, 0x00), 0x02); + b43_httab_write(dev, B43_HTTAB16(8, 0x10), 0x02); + b43_httab_write(dev, B43_HTTAB16(8, 0x20), 0x02); + + b43_httab_write_few(dev, B43_HTTAB16(8, 0x08), 4, + 0x8e, 0x96, 0x96, 0x96); + b43_httab_write_few(dev, B43_HTTAB16(8, 0x18), 4, + 0x8f, 0x9f, 0x9f, 0x9f); + b43_httab_write_few(dev, B43_HTTAB16(8, 0x28), 4, + 0x8f, 0x9f, 0x9f, 0x9f); + + b43_httab_write_few(dev, B43_HTTAB16(8, 0x0c), 4, 0x2, 0x2, 0x2, 0x2); + b43_httab_write_few(dev, B43_HTTAB16(8, 0x1c), 4, 0x2, 0x2, 0x2, 0x2); + b43_httab_write_few(dev, B43_HTTAB16(8, 0x2c), 4, 0x2, 0x2, 0x2, 0x2); + + b43_phy_maskset(dev, 0x0280, 0xff00, 0x3e); + b43_phy_maskset(dev, 0x0283, 0xff00, 0x3e); + b43_phy_maskset(dev, B43_PHY_OFDM(0x0141), 0xff00, 0x46); + b43_phy_maskset(dev, 0x0283, 0xff00, 0x40); + + b43_httab_write_few(dev, B43_HTTAB16(00, 0x8), 4, + 0x09, 0x0e, 0x13, 0x18); + b43_httab_write_few(dev, B43_HTTAB16(01, 0x8), 4, + 0x09, 0x0e, 0x13, 0x18); + /* TODO: Did wl mean 2 instead of 40? */ + b43_httab_write_few(dev, B43_HTTAB16(40, 0x8), 4, + 0x09, 0x0e, 0x13, 0x18); + + b43_phy_maskset(dev, B43_PHY_OFDM(0x24), 0x3f, 0xd); + b43_phy_maskset(dev, B43_PHY_OFDM(0x64), 0x3f, 0xd); + b43_phy_maskset(dev, B43_PHY_OFDM(0xa4), 0x3f, 0xd); + + b43_phy_set(dev, B43_PHY_EXTG(0x060), 0x1); + b43_phy_set(dev, B43_PHY_EXTG(0x064), 0x1); + b43_phy_set(dev, B43_PHY_EXTG(0x080), 0x1); + b43_phy_set(dev, B43_PHY_EXTG(0x084), 0x1); + + /* Copy some tables entries */ + tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x144)); + b43_httab_write(dev, B43_HTTAB16(7, 0x14a), tmp); + tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x154)); + b43_httab_write(dev, B43_HTTAB16(7, 0x15a), tmp); + tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x164)); + b43_httab_write(dev, B43_HTTAB16(7, 0x16a), tmp); + + /* Reset CCA */ + b43_phy_force_clock(dev, true); + tmp = b43_phy_read(dev, B43_PHY_HT_BBCFG); + b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp | B43_PHY_HT_BBCFG_RSTCCA); + b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp & ~B43_PHY_HT_BBCFG_RSTCCA); + b43_phy_force_clock(dev, false); + + b43_mac_phy_clock_set(dev, true); + + b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RX2TX); + b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RST2RX); + + /* TODO: PHY op on reg 0xb0 */ + + /* TODO: Should we restore it? Or store it in global PHY info? */ + b43_phy_ht_read_clip_detection(dev, clip_state); + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + b43_phy_ht_bphy_init(dev); + + b43_httab_write_bulk(dev, B43_HTTAB32(0x1a, 0xc0), + B43_HTTAB_1A_C0_LATE_SIZE, b43_httab_0x1a_0xc0_late); + return 0; } |