jme: PHY Power control for new chip
authorGuo-Fu Tseng <cooldavid@cooldavid.org>
Tue, 14 Dec 2010 18:00:01 +0000 (02:00 +0800)
committerGuo-Fu Tseng <cooldavid@cooldavid.org>
Sat, 12 Feb 2011 17:57:36 +0000 (01:57 +0800)
After main chip rev 5, the hardware support more power saving
control registers.
Some Non-Linux drivers might turn off the phy power with new
interfaces, this patch makes it possible for Linux to turn it
on again.

jme.c
jme.h

diff --git a/jme.c b/jme.c
index 992b624..f918302 100644 (file)
--- a/jme.c
+++ b/jme.c
@@ -1603,6 +1603,38 @@ jme_free_irq(struct jme_adapter *jme)
 }
 
 static inline void
+jme_new_phy_on(struct jme_adapter *jme)
+{
+       u32 reg;
+
+       reg = jread32(jme, JME_PHY_PWR);
+       reg &= ~(PHY_PWR_DWN1SEL | PHY_PWR_DWN1SW |
+                PHY_PWR_DWN2 | PHY_PWR_CLKSEL);
+       jwrite32(jme, JME_PHY_PWR, reg);
+
+       pci_read_config_dword(jme->pdev, PCI_PRIV_PE1, &reg);
+       reg &= ~PE1_GPREG0_PBG;
+       reg |= PE1_GPREG0_ENBG;
+       pci_write_config_dword(jme->pdev, PCI_PRIV_PE1, reg);
+}
+
+static inline void
+jme_new_phy_off(struct jme_adapter *jme)
+{
+       u32 reg;
+
+       reg = jread32(jme, JME_PHY_PWR);
+       reg |= PHY_PWR_DWN1SEL | PHY_PWR_DWN1SW |
+              PHY_PWR_DWN2 | PHY_PWR_CLKSEL;
+       jwrite32(jme, JME_PHY_PWR, reg);
+
+       pci_read_config_dword(jme->pdev, PCI_PRIV_PE1, &reg);
+       reg &= ~PE1_GPREG0_PBG;
+       reg |= PE1_GPREG0_PDD3COLD;
+       pci_write_config_dword(jme->pdev, PCI_PRIV_PE1, reg);
+}
+
+static inline void
 jme_phy_on(struct jme_adapter *jme)
 {
        u32 bmcr;
@@ -1610,6 +1642,22 @@ jme_phy_on(struct jme_adapter *jme)
        bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
        bmcr &= ~BMCR_PDOWN;
        jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr);
+
+       if (new_phy_power_ctrl(jme->chip_main_rev))
+               jme_new_phy_on(jme);
+}
+
+static inline void
+jme_phy_off(struct jme_adapter *jme)
+{
+       u32 bmcr;
+
+       bmcr = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_BMCR);
+       bmcr |= BMCR_PDOWN;
+       jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, bmcr);
+
+       if (new_phy_power_ctrl(jme->chip_main_rev))
+               jme_new_phy_off(jme);
 }
 
 static int
@@ -1632,12 +1680,11 @@ jme_open(struct net_device *netdev)
 
        jme_start_irq(jme);
 
-       if (test_bit(JME_FLAG_SSET, &jme->flags)) {
-               jme_phy_on(jme);
+       jme_phy_on(jme);
+       if (test_bit(JME_FLAG_SSET, &jme->flags))
                jme_set_settings(netdev, &jme->old_ecmd);
-       } else {
+       else
                jme_reset_phy_processor(jme);
-       }
 
        jme_reset_link(jme);
 
@@ -1683,12 +1730,6 @@ jme_wait_link(struct jme_adapter *jme)
        }
 }
 
-static inline void
-jme_phy_off(struct jme_adapter *jme)
-{
-       jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_BMCR, BMCR_PDOWN);
-}
-
 static void
 jme_powersave_phy(struct jme_adapter *jme)
 {
@@ -3216,12 +3257,11 @@ jme_resume(struct pci_dev *pdev)
        jme_clear_pm(jme);
        pci_restore_state(pdev);
 
-       if (test_bit(JME_FLAG_SSET, &jme->flags)) {
-               jme_phy_on(jme);
+       jme_phy_on(jme);
+       if (test_bit(JME_FLAG_SSET, &jme->flags))
                jme_set_settings(netdev, &jme->old_ecmd);
-       } else {
+       else
                jme_reset_phy_processor(jme);
-       }
 
        jme_start_irq(jme);
        netif_device_attach(netdev);
diff --git a/jme.h b/jme.h
index 9300dca..a24cad1 100644 (file)
--- a/jme.h
+++ b/jme.h
@@ -157,6 +157,37 @@ enum jme_spi_op_bits {
 #define HALF_US 500    /* 500 ns */
 #define JMESPIIOCTL    SIOCDEVPRIVATE
 
+#define PCI_PRIV_PE1           0xE4
+
+enum pci_priv_pe1_bit_masks {
+       PE1_ASPMSUPRT   = 0x00000003, /*
+                                      * RW:
+                                      * Aspm_support[1:0]
+                                      * (R/W Port of 5C[11:10])
+                                      */
+       PE1_MULTIFUN    = 0x00000004, /* RW: Multi_fun_bit */
+       PE1_RDYDMA      = 0x00000008, /* RO: ~link.rdy_for_dma */
+       PE1_ASPMOPTL    = 0x00000030, /* RW: link.rx10s_option[1:0] */
+       PE1_ASPMOPTH    = 0x000000C0, /* RW: 10_req=[3]?HW:[2] */
+       PE1_GPREG0      = 0x0000FF00, /*
+                                      * SRW:
+                                      * Cfg_gp_reg0
+                                      * [7:6] phy_giga BG control
+                                      * [5] CREQ_N as CREQ_N1 (CPPE# as CREQ#)
+                                      * [4:0] Reserved
+                                      */
+       PE1_GPREG0_PBG  = 0x0000C000, /* phy_giga BG control */
+       PE1_GPREG1      = 0x00FF0000, /* RW: Cfg_gp_reg1 */
+       PE1_REVID       = 0xFF000000, /* RO: Rev ID */
+};
+
+enum pci_priv_pe1_values {
+       PE1_GPREG0_ENBG         = 0x00000000, /* en BG */
+       PE1_GPREG0_PDD3COLD     = 0x00004000, /* giga_PD + d3cold */
+       PE1_GPREG0_PDPCIESD     = 0x00008000, /* giga_PD + pcie_shutdown */
+       PE1_GPREG0_PDPCIEIDDQ   = 0x0000C000, /* giga_PD + pcie_iddq */
+};
+
 /*
  * Dynamic(adaptive)/Static PCC values
  */
@@ -639,6 +670,7 @@ enum jme_iomap_regs {
        JME_PMCS        = JME_MAC | 0x60, /* Power Management Control/Stat */
 
 
+       JME_PHY_PWR     = JME_PHY | 0x24, /* New PHY Power Ctrl Register */
        JME_PHY_CS      = JME_PHY | 0x28, /* PHY Ctrl and Status Register */
        JME_PHY_LINK    = JME_PHY | 0x30, /* PHY Link Status Register */
        JME_SMBCSR      = JME_PHY | 0x40, /* SMB Control and Status */
@@ -975,6 +1007,21 @@ enum jme_pmcs_bit_masks {
 };
 
 /*
+ * New PHY Power Control Register
+ */
+enum jme_phy_pwr_bit_masks {
+       PHY_PWR_DWN1SEL = 0x01000000, /* Phy_giga.p_PWR_DOWN1_SEL */
+       PHY_PWR_DWN1SW  = 0x02000000, /* Phy_giga.p_PWR_DOWN1_SW */
+       PHY_PWR_DWN2    = 0x04000000, /* Phy_giga.p_PWR_DOWN2 */
+       PHY_PWR_CLKSEL  = 0x08000000, /*
+                                      * XTL_OUT Clock select
+                                      * (an internal free-running clock)
+                                      * 0: xtl_out = phy_giga.A_XTL25_O
+                                      * 1: xtl_out = phy_giga.PD_OSC
+                                      */
+};
+
+/*
  * Giga PHY Status Registers
  */
 enum jme_phy_link_bit_mask {
@@ -1331,6 +1378,11 @@ static inline int is_buggy250(unsigned short device, u8 chiprev)
        return device == PCI_DEVICE_ID_JMICRON_JMC250 && chiprev == 0x11;
 }
 
+static inline int new_phy_power_ctrl(u8 chip_main_rev)
+{
+       return chip_main_rev >= 5;
+}
+
 /*
  * Function prototypes
  */