Merge branch 'minnow/net-next' of git://git.infradead.org/users/dvhart/linux-2.6 into minnow

Darren Hart says:

====================
Add support for the MinnowBoard in the pch_gbe driver. This was
originally sent to LKML as part of the MinnowBoard support series. That
is now partially merged and this version of the patch has been isolated
from those changes and is now completely self-contained.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2013-07-27 20:22:56 -07:00
commit a648ab58f2
4 changed files with 164 additions and 1 deletions

View File

@ -581,6 +581,19 @@ struct pch_gbe_hw_stats {
u32 intr_tcpip_err_count;
};
/**
* struct pch_gbe_privdata - PCI Device ID driver data
* @phy_tx_clk_delay: Bool, configure the PHY TX delay in software
* @phy_disable_hibernate: Bool, disable PHY hibernation
* @platform_init: Platform initialization callback, called from
* probe, prior to PHY initialization.
*/
struct pch_gbe_privdata {
bool phy_tx_clk_delay;
bool phy_disable_hibernate;
int (*platform_init)(struct pci_dev *pdev);
};
/**
* struct pch_gbe_adapter - board specific private data structure
* @stats_lock: Spinlock structure for status
@ -604,6 +617,7 @@ struct pch_gbe_hw_stats {
* @rx_buffer_len: Receive buffer length
* @tx_queue_len: Transmit queue length
* @have_msi: PCI MSI mode flag
* @pch_gbe_privdata: PCI Device ID driver_data
*/
struct pch_gbe_adapter {
@ -631,6 +645,7 @@ struct pch_gbe_adapter {
int hwts_tx_en;
int hwts_rx_en;
struct pci_dev *ptp_pdev;
struct pch_gbe_privdata *pdata;
};
#define pch_gbe_hw_to_adapter(hw) container_of(hw, struct pch_gbe_adapter, hw)

View File

@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_classify.h>
#include <linux/gpio.h>
#define DRV_VERSION "1.01"
const char pch_driver_version[] = DRV_VERSION;
@ -111,6 +112,8 @@ const char pch_driver_version[] = DRV_VERSION;
#define PTP_L4_MULTICAST_SA "01:00:5e:00:01:81"
#define PTP_L2_MULTICAST_SA "01:1b:19:00:00:00"
#define MINNOW_PHY_RESET_GPIO 13
static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT;
static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg);
@ -682,7 +685,7 @@ static int pch_gbe_init_phy(struct pch_gbe_adapter *adapter)
}
adapter->hw.phy.addr = adapter->mii.phy_id;
netdev_dbg(netdev, "phy_addr = %d\n", adapter->mii.phy_id);
if (addr == 32)
if (addr == PCH_GBE_PHY_REGS_LEN)
return -EAGAIN;
/* Selected the phy and isolate the rest */
for (addr = 0; addr < PCH_GBE_PHY_REGS_LEN; addr++) {
@ -2635,6 +2638,9 @@ static int pch_gbe_probe(struct pci_dev *pdev,
adapter->pdev = pdev;
adapter->hw.back = adapter;
adapter->hw.reg = pcim_iomap_table(pdev)[PCH_GBE_PCI_BAR];
adapter->pdata = (struct pch_gbe_privdata *)pci_id->driver_data;
if (adapter->pdata && adapter->pdata->platform_init)
adapter->pdata->platform_init(pdev);
adapter->ptp_pdev = pci_get_bus_and_slot(adapter->pdev->bus->number,
PCI_DEVFN(12, 4));
@ -2710,6 +2716,10 @@ static int pch_gbe_probe(struct pci_dev *pdev,
dev_dbg(&pdev->dev, "PCH Network Connection\n");
/* Disable hibernation on certain platforms */
if (adapter->pdata && adapter->pdata->phy_disable_hibernate)
pch_gbe_phy_disable_hibernate(&adapter->hw);
device_set_wakeup_enable(&pdev->dev, 1);
return 0;
@ -2720,7 +2730,46 @@ err_free_netdev:
return ret;
}
/* The AR803X PHY on the MinnowBoard requires a physical pin to be toggled to
* ensure it is awake for probe and init. Request the line and reset the PHY.
*/
static int pch_gbe_minnow_platform_init(struct pci_dev *pdev)
{
unsigned long flags = GPIOF_DIR_OUT | GPIOF_INIT_HIGH | GPIOF_EXPORT;
unsigned gpio = MINNOW_PHY_RESET_GPIO;
int ret;
ret = devm_gpio_request_one(&pdev->dev, gpio, flags,
"minnow_phy_reset");
if (ret) {
dev_err(&pdev->dev,
"ERR: Can't request PHY reset GPIO line '%d'\n", gpio);
return ret;
}
gpio_set_value(gpio, 0);
usleep_range(1250, 1500);
gpio_set_value(gpio, 1);
usleep_range(1250, 1500);
return ret;
}
static struct pch_gbe_privdata pch_gbe_minnow_privdata = {
.phy_tx_clk_delay = true,
.phy_disable_hibernate = true,
.platform_init = pch_gbe_minnow_platform_init,
};
static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = {
{.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_IOH1_GBE,
.subvendor = PCI_VENDOR_ID_CIRCUITCO,
.subdevice = PCI_SUBSYSTEM_ID_CIRCUITCO_MINNOWBOARD,
.class = (PCI_CLASS_NETWORK_ETHERNET << 8),
.class_mask = (0xFFFF00),
.driver_data = (kernel_ulong_t)&pch_gbe_minnow_privdata
},
{.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_IOH1_GBE,
.subvendor = PCI_ANY_ID,

View File

@ -74,6 +74,15 @@
#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
/* AR8031 PHY Debug Registers */
#define PHY_AR803X_ID 0x00001374
#define PHY_AR8031_DBG_OFF 0x1D
#define PHY_AR8031_DBG_DAT 0x1E
#define PHY_AR8031_SERDES 0x05
#define PHY_AR8031_HIBERNATE 0x0B
#define PHY_AR8031_SERDES_TX_CLK_DLY 0x0100 /* TX clock delay of 2.0ns */
#define PHY_AR8031_PS_HIB_EN 0x8000 /* Hibernate enable */
/* Phy Id Register (word 2) */
#define PHY_REVISION_MASK 0x000F
@ -248,6 +257,51 @@ void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw)
pch_gbe_phy_sw_reset(hw);
}
/**
* pch_gbe_phy_tx_clk_delay - Setup TX clock delay via the PHY
* @hw: Pointer to the HW structure
* Returns
* 0: Successful.
* -EINVAL: Invalid argument.
*/
static int pch_gbe_phy_tx_clk_delay(struct pch_gbe_hw *hw)
{
/* The RGMII interface requires a ~2ns TX clock delay. This is typically
* done in layout with a longer trace or via PHY strapping, but can also
* be done via PHY configuration registers.
*/
struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
u16 mii_reg;
int ret = 0;
switch (hw->phy.id) {
case PHY_AR803X_ID:
netdev_dbg(adapter->netdev,
"Configuring AR803X PHY for 2ns TX clock delay\n");
pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_OFF, &mii_reg);
ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_OFF,
PHY_AR8031_SERDES);
if (ret)
break;
pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_DAT, &mii_reg);
mii_reg |= PHY_AR8031_SERDES_TX_CLK_DLY;
ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_DAT,
mii_reg);
break;
default:
netdev_err(adapter->netdev,
"Unknown PHY (%x), could not set TX clock delay\n",
hw->phy.id);
return -EINVAL;
}
if (ret)
netdev_err(adapter->netdev,
"Could not configure tx clock delay for PHY\n");
return ret;
}
/**
* pch_gbe_phy_init_setting - PHY initial setting
* @hw: Pointer to the HW structure
@ -277,4 +331,48 @@ void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw)
pch_gbe_phy_read_reg_miic(hw, PHY_PHYSP_CONTROL, &mii_reg);
mii_reg |= PHYSP_CTRL_ASSERT_CRS_TX;
pch_gbe_phy_write_reg_miic(hw, PHY_PHYSP_CONTROL, mii_reg);
/* Setup a TX clock delay on certain platforms */
if (adapter->pdata && adapter->pdata->phy_tx_clk_delay)
pch_gbe_phy_tx_clk_delay(hw);
}
/**
* pch_gbe_phy_disable_hibernate - Disable the PHY low power state
* @hw: Pointer to the HW structure
* Returns
* 0: Successful.
* -EINVAL: Invalid argument.
*/
int pch_gbe_phy_disable_hibernate(struct pch_gbe_hw *hw)
{
struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
u16 mii_reg;
int ret = 0;
switch (hw->phy.id) {
case PHY_AR803X_ID:
netdev_dbg(adapter->netdev,
"Disabling hibernation for AR803X PHY\n");
ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_OFF,
PHY_AR8031_HIBERNATE);
if (ret)
break;
pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_DAT, &mii_reg);
mii_reg &= ~PHY_AR8031_PS_HIB_EN;
ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_DAT,
mii_reg);
break;
default:
netdev_err(adapter->netdev,
"Unknown PHY (%x), could not disable hibernation\n",
hw->phy.id);
return -EINVAL;
}
if (ret)
netdev_err(adapter->netdev,
"Could not disable PHY hibernation\n");
return ret;
}

View File

@ -33,5 +33,6 @@ void pch_gbe_phy_power_up(struct pch_gbe_hw *hw);
void pch_gbe_phy_power_down(struct pch_gbe_hw *hw);
void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw);
void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw);
int pch_gbe_phy_disable_hibernate(struct pch_gbe_hw *hw);
#endif /* _PCH_GBE_PHY_H_ */