> 
> Hi tech@,
> 
> the diff below adds support for the Intel Centrino Wireless-N 2230 
> card found in my Lenovo E330 to iwn(4). 
> 
> iwn0 at pci2 dev 0 function 0 "Intel Centrino Wireless-N 2230" rev 0xc4: msi, 
> MIMO 2T2R, BGN, address 60:6c:66:3b:ea:39
> 
> This is the 0x0888 version.
> 
> I've got most changes from
> https://github.com/seanbruno/freebsd-iwl/commit/53e6056c2df7355650abab77068943ac097a70c6#diff-7a5322b995ac8545b4f5d9096c3b5a5aR5445
>  
> which (i think) mostly landed in freebsd as part of
> http://svnweb.freebsd.org/base?view=revision&revision=258035
> 
> This is the only iwn(4) device i have, so hopefully i did not broke 
> another supported device.
> Any feedback and tests are welcome.
> 
> Regards,
> Fabian Raetz

Hi Fabian,

Finally had some time to look at this.  I cleaned your diff up a bit.
Also noticed that the sensitivy limits didn't match the Linux driver I
was looking at.  Does the diff below still result in working hardware
for you?

Thanks,

Mark


Index: if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.127
diff -u -p -r1.127 if_iwn.c
--- if_iwn.c    6 Dec 2013 21:03:04 -0000       1.127
+++ if_iwn.c    8 Feb 2014 22:31:37 -0000
@@ -94,6 +94,8 @@ static const struct pci_matchid iwn_devi
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_130_2 },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6235_1 },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6235_2 },
+       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2030_1 },
+       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2030_2 },
 };
 
 int            iwn_match(struct device *, void *, void *);
@@ -244,6 +246,7 @@ int         iwn5000_send_calibration(struct iwn
 int            iwn5000_send_wimax_coex(struct iwn_softc *);
 int            iwn5000_crystal_calib(struct iwn_softc *);
 int            iwn5000_temp_offset_calib(struct iwn_softc *);
+int            iwn2000_temp_offset_calib(struct iwn_softc *);
 int            iwn4965_post_alive(struct iwn_softc *);
 int            iwn5000_post_alive(struct iwn_softc *);
 int            iwn4965_load_bootcode(struct iwn_softc *, const uint8_t *,
@@ -651,6 +654,11 @@ iwn5000_attach(struct iwn_softc *sc, pci
                } else
                        sc->fwname = "iwn-6005";
                break;
+       case IWN_HW_REV_TYPE_2030:
+               sc->limits = &iwn2000_sensitivity_limits;
+               sc->fwname = "iwn-2030";
+               sc->sc_flags |= IWN_FLAG_ADV_BT_COEX;
+               break;
        default:
                printf(": adapter type %d not supported\n", sc->hw_type);
                return ENOTSUP;
@@ -1529,6 +1537,14 @@ iwn5000_read_eeprom(struct iwn_softc *sc
            hdr.version, hdr.pa_type, letoh16(hdr.volt)));
        sc->calib_ver = hdr.version;
 
+       if (sc->hw_type == IWN_HW_REV_TYPE_2030) {
+               sc->eeprom_voltage = letoh16(hdr.volt);
+               iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2);
+               sc->eeprom_temp = letoh16(val);
+               iwn_read_prom_data(sc, base + IWN2000_EEPROM_RAWTEMP, &val, 2);
+               sc->eeprom_rawtemp = letoh16(val);
+       }
+
        if (sc->hw_type == IWN_HW_REV_TYPE_5150) {
                /* Compute temperature offset. */
                iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2);
@@ -2095,7 +2111,8 @@ iwn5000_rx_calib_results(struct iwn_soft
 
        switch (calib->code) {
        case IWN5000_PHY_CALIB_DC:
-               if (sc->hw_type == IWN_HW_REV_TYPE_5150)
+               if (sc->hw_type == IWN_HW_REV_TYPE_5150 ||
+                   sc->hw_type == IWN_HW_REV_TYPE_2030)
                        idx = 0;
                break;
        case IWN5000_PHY_CALIB_LO:
@@ -4160,29 +4177,55 @@ iwn_send_advanced_btcoex(struct iwn_soft
                0xcc00ff28, 0x0000aaaa, 0xcc00aaaa, 0x0000aaaa,
                0xc0004000, 0x00004000, 0xf0005000, 0xf0005000,
        };
-       struct iwn6000_btcoex_config btconfig;
        struct iwn_btcoex_priotable btprio;
        struct iwn_btcoex_prot btprot;
        int error, i;
 
-       memset(&btconfig, 0, sizeof btconfig);
-       btconfig.flags = IWN_BT_FLAG_COEX6000_CHAN_INHIBITION |
-           (IWN_BT_FLAG_COEX6000_MODE_3W << IWN_BT_FLAG_COEX6000_MODE_SHIFT) |
-           IWN_BT_FLAG_SYNC_2_BT_DISABLE;
-       btconfig.max_kill = 5;
-       btconfig.bt3_t7_timer = 1;
-       btconfig.kill_ack = htole32(0xffff0000);
-       btconfig.kill_cts = htole32(0xffff0000);
-       btconfig.sample_time = 2;
-       btconfig.bt3_t2_timer = 0xc;
-       for (i = 0; i < 12; i++)
-               btconfig.lookup_table[i] = htole32(btcoex_3wire[i]);
-       btconfig.valid = htole16(0xff);
-       btconfig.prio_boost = 0xf0;
-       DPRINTF(("configuring advanced bluetooth coexistence\n"));
-       error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig, sizeof(btconfig), 1);
-       if (error != 0)
-               return (error);
+       if (sc->hw_type == IWN_HW_REV_TYPE_2030) {
+               struct iwn2000_btcoex_config btconfig;
+
+               memset(&btconfig, 0, sizeof btconfig);
+               btconfig.flags = IWN_BT_COEX6000_CHAN_INHIBITION |
+                   (IWN_BT_COEX6000_MODE_3W << IWN_BT_COEX6000_MODE_SHIFT) |
+                   IWN_BT_SYNC_2_BT_DISABLE;
+               btconfig.max_kill = 5;
+               btconfig.bt3_t7_timer = 1;
+               btconfig.kill_ack = htole32(0xffff0000);
+               btconfig.kill_cts = htole32(0xffff0000);
+               btconfig.sample_time = 2;
+               btconfig.bt3_t2_timer = 0xc;
+               for (i = 0; i < 12; i++)
+                       btconfig.lookup_table[i] = htole32(btcoex_3wire[i]);
+               btconfig.valid = htole16(0xff);
+               btconfig.prio_boost = htole32(0xf0);
+               DPRINTF(("configuring advanced bluetooth coexistence\n"));
+               error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig,
+                   sizeof(btconfig), 1);
+               if (error != 0)
+                       return (error);
+       } else {
+               struct iwn6000_btcoex_config btconfig;
+
+               memset(&btconfig, 0, sizeof btconfig);
+               btconfig.flags = IWN_BT_COEX6000_CHAN_INHIBITION |
+                   (IWN_BT_COEX6000_MODE_3W << IWN_BT_COEX6000_MODE_SHIFT) |
+                   IWN_BT_SYNC_2_BT_DISABLE;
+               btconfig.max_kill = 5;
+               btconfig.bt3_t7_timer = 1;
+               btconfig.kill_ack = htole32(0xffff0000);
+               btconfig.kill_cts = htole32(0xffff0000);
+               btconfig.sample_time = 2;
+               btconfig.bt3_t2_timer = 0xc;
+               for (i = 0; i < 12; i++)
+                       btconfig.lookup_table[i] = htole32(btcoex_3wire[i]);
+               btconfig.valid = htole16(0xff);
+               btconfig.prio_boost = 0xf0;
+               DPRINTF(("configuring advanced bluetooth coexistence\n"));
+               error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig,
+                   sizeof(btconfig), 1);
+               if (error != 0)
+                       return (error);
+       }
 
        memset(&btprio, 0, sizeof btprio);
        btprio.calib_init1 = 0x6;
@@ -4233,14 +4276,21 @@ iwn_config(struct iwn_softc *sc)
        uint16_t rxchain;
        int error;
 
+       /* Set radio temperature sensor offset. */
        if (sc->hw_type == IWN_HW_REV_TYPE_6005) {
-               /* Set radio temperature sensor offset. */
                error = iwn5000_temp_offset_calib(sc);
                if (error != 0) {
                        printf("%s: could not set temperature offset\n",
                            sc->sc_dev.dv_xname);
                        return error;
                }
+       } else if (sc->hw_type == IWN_HW_REV_TYPE_2030) {
+               error = iwn2000_temp_offset_calib(sc);
+               if (error != 0) {
+                       printf("%s: could not set temperature offset\n",
+                           sc->sc_dev.dv_xname);
+                       return error;
+               }
        }
 
        if (sc->hw_type == IWN_HW_REV_TYPE_6050 ||
@@ -5005,6 +5055,29 @@ iwn5000_temp_offset_calib(struct iwn_sof
        return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
 }
 
+int
+iwn2000_temp_offset_calib(struct iwn_softc *sc)
+{
+       struct iwn2000_phy_calib_temp_offset cmd;
+
+       memset(&cmd, 0, sizeof cmd);
+       cmd.code = IWN2000_PHY_CALIB_TEMP_OFFSET;
+       cmd.ngroups = 1;
+       cmd.isvalid = 1;
+       if (sc->eeprom_temp != 0) {
+               cmd.offset_low = htole16(sc->eeprom_rawtemp);
+               cmd.offset_high = htole16(sc->eeprom_temp);
+       } else {
+               cmd.offset_low = htole16(IWN_DEFAULT_TEMP_OFFSET);
+               cmd.offset_high = htole16(IWN_DEFAULT_TEMP_OFFSET);
+       }
+       cmd.burnt_voltage_ref = htole16(sc->eeprom_voltage);
+       DPRINTF(("setting radio sensor offset to %d:%d, voltage to %d\n",
+           letoh16(cmd.offset_low), letoh16(cmd.offset_high),
+           letoh16(cmd.burnt_voltage_ref)));
+       return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
+}
+
 /*
  * This function is called after the runtime firmware notifies us of its
  * readiness (called in a process context).
@@ -5681,6 +5754,8 @@ iwn5000_nic_config(struct iwn_softc *sc)
        }
        if (sc->hw_type == IWN_HW_REV_TYPE_6005)
                IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_6050_1X2);
+       if (sc->hw_type == IWN_HW_REV_TYPE_2030)
+               IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_IQ_INVERT);
        return 0;
 }
 
Index: if_iwnreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwnreg.h,v
retrieving revision 1.45
diff -u -p -r1.45 if_iwnreg.h
--- if_iwnreg.h 26 Nov 2013 20:33:17 -0000      1.45
+++ if_iwnreg.h 8 Feb 2014 22:31:37 -0000
@@ -205,6 +205,7 @@
 #define IWN_HW_REV_TYPE_6000   7
 #define IWN_HW_REV_TYPE_6050   8
 #define IWN_HW_REV_TYPE_6005   11
+#define IWN_HW_REV_TYPE_2030   12
 
 /* Possible flags for register IWN_GIO_CHICKEN. */
 #define IWN_GIO_CHICKEN_L1A_NO_L0S_RX  (1 << 23)
@@ -219,6 +220,7 @@
 #define IWN_GP_DRIVER_RADIO_2X2_IPA    (2 << 0)
 #define IWN_GP_DRIVER_CALIB_VER6       (1 << 2)
 #define IWN_GP_DRIVER_6050_1X2         (1 << 3)
+#define IWN_GP_DRIVER_RADIO_IQ_INVERT   (1 << 7)
 
 /* Possible flags for register IWN_UCODE_GP1_CLR. */
 #define IWN_UCODE_GP1_RFKILL           (1 << 1)
@@ -852,15 +854,15 @@ struct iwn_bluetooth {
 
 struct iwn6000_btcoex_config {
        uint8_t         flags;
-#define        IWN_BT_FLAG_COEX6000_CHAN_INHIBITION    1
-#define        IWN_BT_FLAG_COEX6000_MODE_MASK          ((1 << 3) | (1 << 4) | 
(1 << 5))
-#define        IWN_BT_FLAG_COEX6000_MODE_SHIFT         3
-#define        IWN_BT_FLAG_COEX6000_MODE_DISABLED      0
-#define        IWN_BT_FLAG_COEX6000_MODE_LEGACY_2W     1
-#define        IWN_BT_FLAG_COEX6000_MODE_3W            2
-#define        IWN_BT_FLAG_COEX6000_MODE_4W            3
-#define        IWN_BT_FLAG_UCODE_DEFAULT               (1<<6)
-#define        IWN_BT_FLAG_SYNC_2_BT_DISABLE           (1<<7)
+#define        IWN_BT_COEX6000_CHAN_INHIBITION 1
+#define        IWN_BT_COEX6000_MODE_MASK       ((1 << 3) | (1 << 4) | (1 << 5))
+#define        IWN_BT_COEX6000_MODE_SHIFT      3
+#define        IWN_BT_COEX6000_MODE_DISABLED   0
+#define        IWN_BT_COEX6000_MODE_LEGACY_2W  1
+#define        IWN_BT_COEX6000_MODE_3W         2
+#define        IWN_BT_COEX6000_MODE_4W         3
+#define        IWN_BT_UCODE_DEFAULT            (1<<6)
+#define        IWN_BT_SYNC_2_BT_DISABLE        (1<<7)
 
        uint8_t         lead_time;
        uint8_t         max_kill;
@@ -878,6 +880,25 @@ struct iwn6000_btcoex_config {
        uint16_t        rx_prio_boost;
 } __packed;
 
+struct iwn2000_btcoex_config {
+       uint8_t         flags;          /* same as in iwn6000_btcoex_config */
+       uint8_t         lead_time;
+       uint8_t         max_kill;
+       uint8_t         bt3_t7_timer;
+       uint32_t        kill_ack;
+       uint32_t        kill_cts;
+       uint8_t         sample_time;
+       uint8_t         bt3_t2_timer;
+       uint16_t        bt4_reaction;
+       uint32_t        lookup_table[12];
+       uint16_t        bt4_decision;
+       uint16_t        valid;
+       uint32_t        prio_boost;
+       uint8_t         reserved;
+       uint8_t         tx_prio_boost;
+       uint16_t        rx_prio_boost;
+} __packed;
+
 /* Structure for command IWN_CMD_BT_COEX_PRIOTABLE */
 struct iwn_btcoex_priotable {
        uint8_t         calib_init1;
@@ -972,6 +993,8 @@ struct iwn_phy_calib {
 #define IWN5000_PHY_CALIB_RESET_NOISE_GAIN     18
 #define IWN5000_PHY_CALIB_NOISE_GAIN           19
 
+#define IWN2000_PHY_CALIB_TEMP_OFFSET          18
+
        uint8_t group;
        uint8_t ngroups;
        uint8_t isvalid;
@@ -998,6 +1021,17 @@ struct iwn5000_phy_calib_temp_offset {
        uint16_t        reserved;
 } __packed;
 
+struct iwn2000_phy_calib_temp_offset {
+       uint8_t         code;
+       uint8_t         group;
+       uint8_t         ngroups;
+       uint8_t         isvalid;
+       int16_t         offset_high;
+       int16_t         offset_low;
+       int16_t         burnt_voltage_ref;
+       int16_t     reserved;
+} __packed;
+
 struct iwn_phy_calib_gain {
        uint8_t code;
        uint8_t group;
@@ -1411,6 +1445,7 @@ struct iwn_fw_tlv {
 #define IWN5000_EEPROM_CRYSTAL 0x128
 #define IWN5000_EEPROM_TEMP    0x12a
 #define IWN5000_EEPROM_VOLT    0x12b
+#define IWN2000_EEPROM_RAWTEMP 0x12b
 
 /* Possible flags for IWN_EEPROM_SKU_CAP. */
 #define IWN_EEPROM_SKU_CAP_11N (1 << 6)
@@ -1718,6 +1753,18 @@ static const struct iwn_sensitivity_limi
         97,
        100
 };
+
+static const struct iwn_sensitivity_limits iwn2000_sensitivity_limits = {
+       105, 110,
+       192, 232,
+        80, 145,
+       128, 232,
+       125, 175,
+       160, 310,
+        97,
+        97,
+       100
+ };
 
 /* Map TID to TX scheduler's FIFO. */
 static const uint8_t iwn_tid2fifo[] = {
Index: if_iwnvar.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwnvar.h,v
retrieving revision 1.26
diff -u -p -r1.26 if_iwnvar.h
--- if_iwnvar.h 30 Nov 2013 19:41:21 -0000      1.26
+++ if_iwnvar.h 8 Feb 2014 22:31:37 -0000
@@ -275,6 +275,7 @@ struct iwn_softc {
        uint32_t                eeprom_crystal;
        int16_t                 eeprom_temp;
        int16_t                 eeprom_voltage;
+       int16_t                 eeprom_rawtemp;
        int8_t                  maxpwr2GHz;
        int8_t                  maxpwr5GHz;
        int8_t                  maxpwr[IEEE80211_CHAN_MAX];

Reply via email to