aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/oki-semi
diff options
context:
space:
mode:
authorDarren Hart <dvhart@linux.intel.com>2013-05-18 17:46:00 -0400
committerDarren Hart <dvhart@linux.intel.com>2013-07-25 04:31:52 -0400
commitf1a26fdf5944ff950888ae0017e546690353f85f (patch)
tree3d154515f88a0c6386765ef53ecaf49840101545 /drivers/net/ethernet/oki-semi
parentb04d68ebb04aa2d4ab9392c5353a53c81be7b847 (diff)
pch_gbe: Add MinnowBoard support
The MinnowBoard uses an AR803x PHY with the PCH GBE which requires special handling. Use the MinnowBoard PCI Subsystem ID to detect this and add a pci_device_id.driver_data structure and functions to handle platform setup. The AR803x does not implement the RGMII 2ns TX clock delay in the trace routing nor via strapping. Add a detection method for the board and the PHY and enable the TX clock delay via the registers. This PHY will hibernate without link for 10 seconds. Ensure the PHY is awake for probe and then disable hibernation. A future improvement would be to convert pch_gbe to using PHYLIB and making sure we can wake the PHY at the necessary times rather than permanently disabling it. Signed-off-by: Darren Hart <dvhart@linux.intel.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Peter Waskiewicz <peter.p.waskiewicz.jr@intel.com> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Joe Perches <joe@perches.com> Cc: netdev@vger.kernel.org
Diffstat (limited to 'drivers/net/ethernet/oki-semi')
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h15
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c49
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c98
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h1
4 files changed, 163 insertions, 0 deletions
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
index 7779036690cc..6797b1075874 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h
@@ -582,6 +582,19 @@ struct pch_gbe_hw_stats {
582}; 582};
583 583
584/** 584/**
585 * struct pch_gbe_privdata - PCI Device ID driver data
586 * @phy_tx_clk_delay: Bool, configure the PHY TX delay in software
587 * @phy_disable_hibernate: Bool, disable PHY hibernation
588 * @platform_init: Platform initialization callback, called from
589 * probe, prior to PHY initialization.
590 */
591struct pch_gbe_privdata {
592 bool phy_tx_clk_delay;
593 bool phy_disable_hibernate;
594 int (*platform_init)(struct pci_dev *pdev);
595};
596
597/**
585 * struct pch_gbe_adapter - board specific private data structure 598 * struct pch_gbe_adapter - board specific private data structure
586 * @stats_lock: Spinlock structure for status 599 * @stats_lock: Spinlock structure for status
587 * @ethtool_lock: Spinlock structure for ethtool 600 * @ethtool_lock: Spinlock structure for ethtool
@@ -604,6 +617,7 @@ struct pch_gbe_hw_stats {
604 * @rx_buffer_len: Receive buffer length 617 * @rx_buffer_len: Receive buffer length
605 * @tx_queue_len: Transmit queue length 618 * @tx_queue_len: Transmit queue length
606 * @have_msi: PCI MSI mode flag 619 * @have_msi: PCI MSI mode flag
620 * @pch_gbe_privdata: PCI Device ID driver_data
607 */ 621 */
608 622
609struct pch_gbe_adapter { 623struct pch_gbe_adapter {
@@ -631,6 +645,7 @@ struct pch_gbe_adapter {
631 int hwts_tx_en; 645 int hwts_tx_en;
632 int hwts_rx_en; 646 int hwts_rx_en;
633 struct pci_dev *ptp_pdev; 647 struct pci_dev *ptp_pdev;
648 struct pch_gbe_privdata *pdata;
634}; 649};
635 650
636#define pch_gbe_hw_to_adapter(hw) container_of(hw, struct pch_gbe_adapter, hw) 651#define pch_gbe_hw_to_adapter(hw) container_of(hw, struct pch_gbe_adapter, hw)
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index 749ddd918282..e19f1be60d5e 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -23,6 +23,7 @@
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/net_tstamp.h> 24#include <linux/net_tstamp.h>
25#include <linux/ptp_classify.h> 25#include <linux/ptp_classify.h>
26#include <linux/gpio.h>
26 27
27#define DRV_VERSION "1.01" 28#define DRV_VERSION "1.01"
28const char pch_driver_version[] = DRV_VERSION; 29const char pch_driver_version[] = DRV_VERSION;
@@ -111,6 +112,8 @@ const char pch_driver_version[] = DRV_VERSION;
111#define PTP_L4_MULTICAST_SA "01:00:5e:00:01:81" 112#define PTP_L4_MULTICAST_SA "01:00:5e:00:01:81"
112#define PTP_L2_MULTICAST_SA "01:1b:19:00:00:00" 113#define PTP_L2_MULTICAST_SA "01:1b:19:00:00:00"
113 114
115#define MINNOW_PHY_RESET_GPIO 13
116
114static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT; 117static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT;
115 118
116static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg); 119static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg);
@@ -2635,6 +2638,9 @@ static int pch_gbe_probe(struct pci_dev *pdev,
2635 adapter->pdev = pdev; 2638 adapter->pdev = pdev;
2636 adapter->hw.back = adapter; 2639 adapter->hw.back = adapter;
2637 adapter->hw.reg = pcim_iomap_table(pdev)[PCH_GBE_PCI_BAR]; 2640 adapter->hw.reg = pcim_iomap_table(pdev)[PCH_GBE_PCI_BAR];
2641 adapter->pdata = (struct pch_gbe_privdata *)pci_id->driver_data;
2642 if (adapter->pdata && adapter->pdata->platform_init)
2643 adapter->pdata->platform_init(pdev);
2638 2644
2639 adapter->ptp_pdev = pci_get_bus_and_slot(adapter->pdev->bus->number, 2645 adapter->ptp_pdev = pci_get_bus_and_slot(adapter->pdev->bus->number,
2640 PCI_DEVFN(12, 4)); 2646 PCI_DEVFN(12, 4));
@@ -2710,6 +2716,10 @@ static int pch_gbe_probe(struct pci_dev *pdev,
2710 2716
2711 dev_dbg(&pdev->dev, "PCH Network Connection\n"); 2717 dev_dbg(&pdev->dev, "PCH Network Connection\n");
2712 2718
2719 /* Disable hibernation on certain platforms */
2720 if (adapter->pdata && adapter->pdata->phy_disable_hibernate)
2721 pch_gbe_phy_disable_hibernate(&adapter->hw);
2722
2713 device_set_wakeup_enable(&pdev->dev, 1); 2723 device_set_wakeup_enable(&pdev->dev, 1);
2714 return 0; 2724 return 0;
2715 2725
@@ -2720,9 +2730,48 @@ err_free_netdev:
2720 return ret; 2730 return ret;
2721} 2731}
2722 2732
2733/* The AR803X PHY on the MinnowBoard requires a physical pin to be toggled to
2734 * ensure it is awake for probe and init. Request the line and reset the PHY.
2735 */
2736static int pch_gbe_minnow_platform_init(struct pci_dev *pdev)
2737{
2738 unsigned long flags = GPIOF_DIR_OUT | GPIOF_INIT_HIGH | GPIOF_EXPORT;
2739 unsigned gpio = MINNOW_PHY_RESET_GPIO;
2740 int ret;
2741
2742 ret = devm_gpio_request_one(&pdev->dev, gpio, flags,
2743 "minnow_phy_reset");
2744 if (ret) {
2745 dev_err(&pdev->dev,
2746 "ERR: Can't request PHY reset GPIO line '%d'\n", gpio);
2747 return ret;
2748 }
2749
2750 gpio_set_value(gpio, 0);
2751 usleep_range(1250, 1500);
2752 gpio_set_value(gpio, 1);
2753 usleep_range(1250, 1500);
2754
2755 return ret;
2756}
2757
2758static struct pch_gbe_privdata pch_gbe_minnow_privdata = {
2759 .phy_tx_clk_delay = true,
2760 .phy_disable_hibernate = true,
2761 .platform_init = pch_gbe_minnow_platform_init,
2762};
2763
2723static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = { 2764static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = {
2724 {.vendor = PCI_VENDOR_ID_INTEL, 2765 {.vendor = PCI_VENDOR_ID_INTEL,
2725 .device = PCI_DEVICE_ID_INTEL_IOH1_GBE, 2766 .device = PCI_DEVICE_ID_INTEL_IOH1_GBE,
2767 .subvendor = PCI_VENDOR_ID_CIRCUITCO,
2768 .subdevice = PCI_SUBSYSTEM_ID_CIRCUITCO_MINNOWBOARD,
2769 .class = (PCI_CLASS_NETWORK_ETHERNET << 8),
2770 .class_mask = (0xFFFF00),
2771 .driver_data = (kernel_ulong_t)&pch_gbe_minnow_privdata
2772 },
2773 {.vendor = PCI_VENDOR_ID_INTEL,
2774 .device = PCI_DEVICE_ID_INTEL_IOH1_GBE,
2726 .subvendor = PCI_ANY_ID, 2775 .subvendor = PCI_ANY_ID,
2727 .subdevice = PCI_ANY_ID, 2776 .subdevice = PCI_ANY_ID,
2728 .class = (PCI_CLASS_NETWORK_ETHERNET << 8), 2777 .class = (PCI_CLASS_NETWORK_ETHERNET << 8),
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c
index da079073a6c6..8b7ff75fc8e0 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c
@@ -74,6 +74,15 @@
74#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ 74#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
75#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ 75#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
76 76
77/* AR8031 PHY Debug Registers */
78#define PHY_AR803X_ID 0x00001374
79#define PHY_AR8031_DBG_OFF 0x1D
80#define PHY_AR8031_DBG_DAT 0x1E
81#define PHY_AR8031_SERDES 0x05
82#define PHY_AR8031_HIBERNATE 0x0B
83#define PHY_AR8031_SERDES_TX_CLK_DLY 0x0100 /* TX clock delay of 2.0ns */
84#define PHY_AR8031_PS_HIB_EN 0x8000 /* Hibernate enable */
85
77/* Phy Id Register (word 2) */ 86/* Phy Id Register (word 2) */
78#define PHY_REVISION_MASK 0x000F 87#define PHY_REVISION_MASK 0x000F
79 88
@@ -249,6 +258,51 @@ void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw)
249} 258}
250 259
251/** 260/**
261 * pch_gbe_phy_tx_clk_delay - Setup TX clock delay via the PHY
262 * @hw: Pointer to the HW structure
263 * Returns
264 * 0: Successful.
265 * -EINVAL: Invalid argument.
266 */
267static int pch_gbe_phy_tx_clk_delay(struct pch_gbe_hw *hw)
268{
269 /* The RGMII interface requires a ~2ns TX clock delay. This is typically
270 * done in layout with a longer trace or via PHY strapping, but can also
271 * be done via PHY configuration registers.
272 */
273 struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
274 u16 mii_reg;
275 int ret = 0;
276
277 switch (hw->phy.id) {
278 case PHY_AR803X_ID:
279 netdev_dbg(adapter->netdev,
280 "Configuring AR803X PHY for 2ns TX clock delay\n");
281 pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_OFF, &mii_reg);
282 ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_OFF,
283 PHY_AR8031_SERDES);
284 if (ret)
285 break;
286
287 pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_DAT, &mii_reg);
288 mii_reg |= PHY_AR8031_SERDES_TX_CLK_DLY;
289 ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_DAT,
290 mii_reg);
291 break;
292 default:
293 netdev_err(adapter->netdev,
294 "Unknown PHY (%x), could not set TX clock delay\n",
295 hw->phy.id);
296 return -EINVAL;
297 }
298
299 if (ret)
300 netdev_err(adapter->netdev,
301 "Could not configure tx clock delay for PHY\n");
302 return ret;
303}
304
305/**
252 * pch_gbe_phy_init_setting - PHY initial setting 306 * pch_gbe_phy_init_setting - PHY initial setting
253 * @hw: Pointer to the HW structure 307 * @hw: Pointer to the HW structure
254 */ 308 */
@@ -277,4 +331,48 @@ void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw)
277 pch_gbe_phy_read_reg_miic(hw, PHY_PHYSP_CONTROL, &mii_reg); 331 pch_gbe_phy_read_reg_miic(hw, PHY_PHYSP_CONTROL, &mii_reg);
278 mii_reg |= PHYSP_CTRL_ASSERT_CRS_TX; 332 mii_reg |= PHYSP_CTRL_ASSERT_CRS_TX;
279 pch_gbe_phy_write_reg_miic(hw, PHY_PHYSP_CONTROL, mii_reg); 333 pch_gbe_phy_write_reg_miic(hw, PHY_PHYSP_CONTROL, mii_reg);
334
335 /* Setup a TX clock delay on certain platforms */
336 if (adapter->pdata && adapter->pdata->phy_tx_clk_delay)
337 pch_gbe_phy_tx_clk_delay(hw);
338}
339
340/**
341 * pch_gbe_phy_disable_hibernate - Disable the PHY low power state
342 * @hw: Pointer to the HW structure
343 * Returns
344 * 0: Successful.
345 * -EINVAL: Invalid argument.
346 */
347int pch_gbe_phy_disable_hibernate(struct pch_gbe_hw *hw)
348{
349 struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
350 u16 mii_reg;
351 int ret = 0;
352
353 switch (hw->phy.id) {
354 case PHY_AR803X_ID:
355 netdev_dbg(adapter->netdev,
356 "Disabling hibernation for AR803X PHY\n");
357 ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_OFF,
358 PHY_AR8031_HIBERNATE);
359 if (ret)
360 break;
361
362 pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_DAT, &mii_reg);
363 mii_reg &= ~PHY_AR8031_PS_HIB_EN;
364 ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_DAT,
365 mii_reg);
366 break;
367 default:
368 netdev_err(adapter->netdev,
369 "Unknown PHY (%x), could not disable hibernation\n",
370 hw->phy.id);
371 return -EINVAL;
372 }
373
374 if (ret)
375 netdev_err(adapter->netdev,
376 "Could not disable PHY hibernation\n");
377 return ret;
280} 378}
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h
index 03264dc7b5ec..0cbe69206e04 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.h
@@ -33,5 +33,6 @@ void pch_gbe_phy_power_up(struct pch_gbe_hw *hw);
33void pch_gbe_phy_power_down(struct pch_gbe_hw *hw); 33void pch_gbe_phy_power_down(struct pch_gbe_hw *hw);
34void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw); 34void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw);
35void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw); 35void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw);
36int pch_gbe_phy_disable_hibernate(struct pch_gbe_hw *hw);
36 37
37#endif /* _PCH_GBE_PHY_H_ */ 38#endif /* _PCH_GBE_PHY_H_ */