ath5k: Check EEPROM before tweaking SERDES
authorNick Kossifidis <mick@madwifi-project.org>
Mon, 10 Aug 2009 00:26:55 +0000 (03:26 +0300)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 14 Aug 2009 13:13:55 +0000 (09:13 -0400)
* Read PCI-E infos offset from EEPROM and if it points to
   serdes section (0x40), enable serdes programming (further tweaking
   of serdes values during attach). This follows Legacy and Sam's
   HAL sources.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
Acked-by: Bob Copeland <me@bobcopeland.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath5k/attach.c
drivers/net/wireless/ath/ath5k/eeprom.c
drivers/net/wireless/ath/ath5k/eeprom.h

index 9a84d9410b27c58bb6866f831b644082063f73e5..626306592cf8ac48ecd77095cd42f48138c71034 100644 (file)
@@ -252,28 +252,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
                goto err_free;
        }
 
-       /*
-        * Write PCI-E power save settings
-        */
-       if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
-               ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
-               ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
-               /* Shut off RX when elecidle is asserted */
-               ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
-               ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
-               /* TODO: EEPROM work */
-               ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
-               /* Shut off PLL and CLKREQ active in L1 */
-               ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
-               /* Preserce other settings */
-               ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
-               ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
-               ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
-               /* Reset SERDES to load new settings */
-               ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
-               mdelay(1);
-       }
-
        /*
         * POST
         */
@@ -295,6 +273,40 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
                goto err_free;
        }
 
+       /*
+        * Write PCI-E power save settings
+        */
+       if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
+               struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+
+               ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
+               ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
+
+               /* Shut off RX when elecidle is asserted */
+               ath5k_hw_reg_write(ah, 0x28000039, AR5K_PCIE_SERDES);
+               ath5k_hw_reg_write(ah, 0x53160824, AR5K_PCIE_SERDES);
+
+               /* If serdes programing is enabled, increase PCI-E
+                * tx power for systems with long trace from host
+                * to minicard connector. */
+               if (ee->ee_serdes)
+                       ath5k_hw_reg_write(ah, 0xe5980579, AR5K_PCIE_SERDES);
+               else
+                       ath5k_hw_reg_write(ah, 0xf6800579, AR5K_PCIE_SERDES);
+
+               /* Shut off PLL and CLKREQ active in L1 */
+               ath5k_hw_reg_write(ah, 0x001defff, AR5K_PCIE_SERDES);
+
+               /* Preserve other settings */
+               ath5k_hw_reg_write(ah, 0x1aaabe40, AR5K_PCIE_SERDES);
+               ath5k_hw_reg_write(ah, 0xbe105554, AR5K_PCIE_SERDES);
+               ath5k_hw_reg_write(ah, 0x000e3007, AR5K_PCIE_SERDES);
+
+               /* Reset SERDES to load new settings */
+               ath5k_hw_reg_write(ah, 0x00000000, AR5K_PCIE_SERDES_RESET);
+               mdelay(1);
+       }
+
        /* Get misc capabilities */
        ret = ath5k_hw_set_capabilities(ah);
        if (ret) {
index c56b494d417acd40d445d922f2861b53cc2315df..8af477dd6fc74a19ce7b92fc7ededa2da714cb5c 100644 (file)
@@ -167,6 +167,16 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah)
        ee->ee_rfkill_pin = (u8) AR5K_REG_MS(val, AR5K_EEPROM_RFKILL_GPIO_SEL);
        ee->ee_rfkill_pol = val & AR5K_EEPROM_RFKILL_POLARITY ? true : false;
 
+       /* Check if PCIE_OFFSET points to PCIE_SERDES_SECTION
+        * and enable serdes programming if needed.
+        *
+        * XXX: Serdes values seem to be fixed so
+        * no need to read them here, we write them
+        * during ath5k_hw_attach */
+       AR5K_EEPROM_READ(AR5K_EEPROM_PCIE_OFFSET, val);
+       ee->ee_serdes = (val == AR5K_EEPROM_PCIE_SERDES_SECTION) ?
+                                                       true : false;
+
        return 0;
 }
 
index 64be73a5edaeee6a2bd50d33e97bf140d5e6c614..0123f3521a0b5600726382b407e1548ac90c365f 100644 (file)
@@ -19,6 +19,9 @@
 /*
  * Common ar5xxx EEPROM data offsets (set these on AR5K_EEPROM_BASE)
  */
+#define        AR5K_EEPROM_PCIE_OFFSET         0x02    /* Contains offset to PCI-E infos */
+#define        AR5K_EEPROM_PCIE_SERDES_SECTION 0x40    /* PCIE_OFFSET points here when
+                                                * SERDES infos are present */
 #define AR5K_EEPROM_MAGIC              0x003d  /* EEPROM Magic number */
 #define AR5K_EEPROM_MAGIC_VALUE                0x5aa5  /* Default - found on EEPROM */
 #define AR5K_EEPROM_MAGIC_5212         0x0000145c /* 5212 */
@@ -391,6 +394,7 @@ struct ath5k_eeprom_info {
        u8      ee_rfkill_pin;
        bool    ee_rfkill_pol;
        bool    ee_is_hb63;
+       bool    ee_serdes;
        u16     ee_misc0;
        u16     ee_misc1;
        u16     ee_misc2;