diff options
4 files changed, 164 insertions, 1 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 | */ | ||
591 | struct 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 | ||
609 | struct pch_gbe_adapter { | 623 | struct 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 ab1039a95bf9..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" |
28 | const char pch_driver_version[] = DRV_VERSION; | 29 | const 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 | |||
114 | static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT; | 117 | static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT; |
115 | 118 | ||
116 | static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg); | 119 | 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) | |||
682 | } | 685 | } |
683 | adapter->hw.phy.addr = adapter->mii.phy_id; | 686 | adapter->hw.phy.addr = adapter->mii.phy_id; |
684 | netdev_dbg(netdev, "phy_addr = %d\n", adapter->mii.phy_id); | 687 | netdev_dbg(netdev, "phy_addr = %d\n", adapter->mii.phy_id); |
685 | if (addr == 32) | 688 | if (addr == PCH_GBE_PHY_REGS_LEN) |
686 | return -EAGAIN; | 689 | return -EAGAIN; |
687 | /* Selected the phy and isolate the rest */ | 690 | /* Selected the phy and isolate the rest */ |
688 | for (addr = 0; addr < PCH_GBE_PHY_REGS_LEN; addr++) { | 691 | for (addr = 0; addr < PCH_GBE_PHY_REGS_LEN; addr++) { |
@@ -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 | */ | ||
2736 | static 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 | |||
2758 | static 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 | |||
2723 | static DEFINE_PCI_DEVICE_TABLE(pch_gbe_pcidev_id) = { | 2764 | static 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 | */ | ||
267 | static 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 | */ | ||
347 | int 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); | |||
33 | void pch_gbe_phy_power_down(struct pch_gbe_hw *hw); | 33 | void pch_gbe_phy_power_down(struct pch_gbe_hw *hw); |
34 | void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw); | 34 | void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw); |
35 | void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw); | 35 | void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw); |
36 | int pch_gbe_phy_disable_hibernate(struct pch_gbe_hw *hw); | ||
36 | 37 | ||
37 | #endif /* _PCH_GBE_PHY_H_ */ | 38 | #endif /* _PCH_GBE_PHY_H_ */ |