mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-10 15:13:44 -04:00
Merge branch 'dpaa-phylink'
Sean Anderson says: ==================== net: dpaa: Convert to phylink This series converts the DPAA driver to phylink. I have tried to maintain backwards compatibility with existing device trees whereever possible. However, one area where I was unable to achieve this was with QSGMII. Please refer to patch 2 for details. All mac drivers have now been converted. I would greatly appreciate if anyone has T-series or P-series boards they can test/debug this series on. I only have an LS1046ARDB. Everything but QSGMII should work without breakage; QSGMII needs patches 7 and 8. For this reason, the last 4 patches in this series should be applied together (and should not go through separate trees). Changes in v7: - provide phylink_validate_mask_caps() helper - Fix oops if memac_pcs_create returned -EPROBE_DEFER - Fix using pcs-names instead of pcs-handle-names - Fix not checking for -ENODATA when looking for sgmii pcs - Fix 81-character line - Simplify memac_validate with phylink_validate_mask_caps Changes in v6: - Remove unnecessary $ref from renesas,rzn1-a5psw - Remove unnecessary type from pcs-handle-names - Add maxItems to pcs-handle - Fix 81-character line - Fix uninitialized variable in dtsec_mac_config Changes in v5: - Add Lynx PCS binding Changes in v4: - Use pcs-handle-names instead of pcs-names, as discussed - Don't fail if phy support was not compiled in - Split off rate adaptation series - Split off DPAA "preparation" series - Split off Lynx 10G support - t208x: Mark MAC1 and MAC2 as 10G - Add XFI PCS for t208x MAC1/MAC2 Changes in v3: - Expand pcs-handle to an array - Add vendor prefix 'fsl,' to rgmii and mii properties. - Set maxItems for pcs-names - Remove phy-* properties from example because dt-schema complains and I can't be bothered to figure out how to make it work. - Add pcs-handle as a preferred version of pcsphy-handle - Deprecate pcsphy-handle - Remove mii/rmii properties - Put the PCS mdiodev only after we are done with it (since the PCS does not perform a get itself). - Remove _return label from memac_initialization in favor of returning directly - Fix grabbing the default PCS not checking for -ENODATA from of_property_match_string - Set DTSEC_ECNTRL_R100M in dtsec_link_up instead of dtsec_mac_config - Remove rmii/mii properties - Replace 1000Base... with 1000BASE... to match IEEE capitalization - Add compatibles for QSGMII PCSs - Split arm and powerpcs dts updates Changes in v2: - Better document how we select which PCS to use in the default case - Move PCS_LYNX dependency to fman Kconfig - Remove unused variable slow_10g_if - Restrict valid link modes based on the phy interface. This is easier to set up, and mostly captures what I intended to do the first time. We now have a custom validate which restricts half-duplex for some SoCs for RGMII, but generally just uses the default phylink validate. - Configure the SerDes in enable/disable - Properly implement all ethtool ops and ioctls. These were mostly stubbed out just enough to compile last time. - Convert 10GEC and dTSEC as well - Fix capitalization of mEMAC in commit messages - Add nodes for QSGMII PCSs - Add nodes for QSGMII PCSs ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -74,10 +74,10 @@ properties:
|
||||
|
||||
properties:
|
||||
pcs-handle:
|
||||
maxItems: 1
|
||||
description:
|
||||
phandle pointing to a PCS sub-node compatible with
|
||||
renesas,rzn1-miic.yaml#
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
||||
@@ -108,11 +108,17 @@ properties:
|
||||
$ref: "#/properties/phy-connection-type"
|
||||
|
||||
pcs-handle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
items:
|
||||
maxItems: 1
|
||||
description:
|
||||
Specifies a reference to a node representing a PCS PHY device on a MDIO
|
||||
bus to link with an external PHY (phy-handle) if exists.
|
||||
|
||||
pcs-handle-names:
|
||||
description:
|
||||
The name of each PCS in pcs-handle.
|
||||
|
||||
phy-handle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
@@ -216,6 +222,9 @@ properties:
|
||||
required:
|
||||
- speed
|
||||
|
||||
dependencies:
|
||||
pcs-handle-names: [pcs-handle]
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
|
||||
@@ -85,9 +85,39 @@ properties:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: A reference to the IEEE1588 timer
|
||||
|
||||
phys:
|
||||
description: A reference to the SerDes lane(s)
|
||||
maxItems: 1
|
||||
|
||||
phy-names:
|
||||
items:
|
||||
- const: serdes
|
||||
|
||||
pcsphy-handle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: A reference to the PCS (typically found on the SerDes)
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
deprecated: true
|
||||
description: See pcs-handle.
|
||||
|
||||
pcs-handle:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
description: |
|
||||
A reference to the various PCSs (typically found on the SerDes). If
|
||||
pcs-handle-names is absent, and phy-connection-type is "xgmii", then the first
|
||||
reference will be assumed to be for "xfi". Otherwise, if pcs-handle-names is
|
||||
absent, then the first reference will be assumed to be for "sgmii".
|
||||
|
||||
pcs-handle-names:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
items:
|
||||
enum:
|
||||
- sgmii
|
||||
- qsgmii
|
||||
- xfi
|
||||
description: The type of each PCS in pcsphy-handle.
|
||||
|
||||
tbi-handle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
@@ -100,6 +130,10 @@ required:
|
||||
- fsl,fman-ports
|
||||
- ptp-timer
|
||||
|
||||
dependencies:
|
||||
pcs-handle-names:
|
||||
- pcs-handle
|
||||
|
||||
allOf:
|
||||
- $ref: ethernet-controller.yaml#
|
||||
- if:
|
||||
@@ -110,14 +144,6 @@ allOf:
|
||||
then:
|
||||
required:
|
||||
- tbi-handle
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: fsl,fman-memac
|
||||
then:
|
||||
required:
|
||||
- pcsphy-handle
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
@@ -138,8 +164,9 @@ examples:
|
||||
reg = <0xe8000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x0c &fman0_tx_0x2c>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy4>;
|
||||
phy-handle = <&sgmii_phy1>;
|
||||
phy-connection-type = "sgmii";
|
||||
pcs-handle = <&pcsphy4>, <&qsgmiib_pcs1>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
phys = <&serdes1 1>;
|
||||
phy-names = "serdes";
|
||||
};
|
||||
...
|
||||
|
||||
@@ -31,7 +31,7 @@ properties:
|
||||
phy-mode: true
|
||||
|
||||
pcs-handle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
maxItems: 1
|
||||
description:
|
||||
A reference to a node representing a PCS PHY device found on
|
||||
the internal MDIO bus.
|
||||
|
||||
@@ -320,8 +320,9 @@ For internal PHY device on internal mdio bus, a PHY node should be created.
|
||||
See the definition of the PHY node in booting-without-of.txt for an
|
||||
example of how to define a PHY (Internal PHY has no interrupt line).
|
||||
- For "fsl,fman-mdio" compatible internal mdio bus, the PHY is TBI PHY.
|
||||
- For "fsl,fman-memac-mdio" compatible internal mdio bus, the PHY is PCS PHY,
|
||||
PCS PHY addr must be '0'.
|
||||
- For "fsl,fman-memac-mdio" compatible internal mdio bus, the PHY is PCS PHY.
|
||||
The PCS PHY address should correspond to the value of the appropriate
|
||||
MDEV_PORT.
|
||||
|
||||
EXAMPLE
|
||||
|
||||
|
||||
40
Documentation/devicetree/bindings/net/pcs/fsl,lynx-pcs.yaml
Normal file
40
Documentation/devicetree/bindings/net/pcs/fsl,lynx-pcs.yaml
Normal file
@@ -0,0 +1,40 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/pcs/fsl,lynx-pcs.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: NXP Lynx PCS
|
||||
|
||||
maintainers:
|
||||
- Ioana Ciornei <ioana.ciornei@nxp.com>
|
||||
|
||||
description: |
|
||||
NXP Lynx 10G and 28G SerDes have Ethernet PCS devices which can be used as
|
||||
protocol controllers. They are accessible over the Ethernet interface's MDIO
|
||||
bus.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: fsl,lynx-pcs
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
mdio-bus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
qsgmii_pcs1: ethernet-pcs@1 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
@@ -24,9 +24,12 @@ &fman0 {
|
||||
|
||||
/* these aliases provide the FMan ports mapping */
|
||||
enet0: ethernet@e0000 {
|
||||
pcs-handle-names = "qsgmii";
|
||||
};
|
||||
|
||||
enet1: ethernet@e2000 {
|
||||
pcsphy-handle = <&pcsphy1>, <&qsgmiib_pcs1>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
enet2: ethernet@e4000 {
|
||||
@@ -36,11 +39,32 @@ enet3: ethernet@e6000 {
|
||||
};
|
||||
|
||||
enet4: ethernet@e8000 {
|
||||
pcsphy-handle = <&pcsphy4>, <&qsgmiib_pcs2>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
enet5: ethernet@ea000 {
|
||||
pcsphy-handle = <&pcsphy5>, <&qsgmiib_pcs3>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
enet6: ethernet@f0000 {
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
qsgmiib_pcs1: ethernet-pcs@1 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <0x1>;
|
||||
};
|
||||
|
||||
qsgmiib_pcs2: ethernet-pcs@2 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <0x2>;
|
||||
};
|
||||
|
||||
qsgmiib_pcs3: ethernet-pcs@3 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <0x3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -23,6 +23,8 @@ &soc {
|
||||
&fman0 {
|
||||
/* these aliases provide the FMan ports mapping */
|
||||
enet0: ethernet@e0000 {
|
||||
pcsphy-handle = <&qsgmiib_pcs3>;
|
||||
pcs-handle-names = "qsgmii";
|
||||
};
|
||||
|
||||
enet1: ethernet@e2000 {
|
||||
@@ -35,14 +37,37 @@ enet3: ethernet@e6000 {
|
||||
};
|
||||
|
||||
enet4: ethernet@e8000 {
|
||||
pcsphy-handle = <&pcsphy4>, <&qsgmiib_pcs1>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
enet5: ethernet@ea000 {
|
||||
pcsphy-handle = <&pcsphy5>, <&pcsphy5>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
enet6: ethernet@f0000 {
|
||||
};
|
||||
|
||||
enet7: ethernet@f2000 {
|
||||
pcsphy-handle = <&pcsphy7>, <&qsgmiib_pcs2>, <&pcsphy7>;
|
||||
pcs-handle-names = "sgmii", "qsgmii", "xfi";
|
||||
};
|
||||
|
||||
mdio@eb000 {
|
||||
qsgmiib_pcs1: ethernet-pcs@1 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <0x1>;
|
||||
};
|
||||
|
||||
qsgmiib_pcs2: ethernet-pcs@2 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <0x2>;
|
||||
};
|
||||
|
||||
qsgmiib_pcs3: ethernet-pcs@3 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <0x3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -55,7 +55,8 @@ ethernet@e0000 {
|
||||
reg = <0xe0000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy0>;
|
||||
pcsphy-handle = <&pcsphy0>, <&pcsphy0>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
|
||||
@@ -52,7 +52,15 @@ ethernet@f0000 {
|
||||
compatible = "fsl,fman-memac";
|
||||
reg = <0xf0000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x10 &fman0_tx_0x30>;
|
||||
pcsphy-handle = <&pcsphy6>;
|
||||
pcsphy-handle = <&pcsphy6>, <&qsgmiib_pcs2>, <&pcsphy6>;
|
||||
pcs-handle-names = "sgmii", "qsgmii", "xfi";
|
||||
};
|
||||
|
||||
mdio@e9000 {
|
||||
qsgmiib_pcs2: ethernet-pcs@2 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@f1000 {
|
||||
|
||||
@@ -55,7 +55,15 @@ ethernet@e2000 {
|
||||
reg = <0xe2000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy1>;
|
||||
pcsphy-handle = <&pcsphy1>, <&qsgmiia_pcs1>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
qsgmiia_pcs1: ethernet-pcs@1 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@e3000 {
|
||||
|
||||
@@ -52,7 +52,15 @@ ethernet@f2000 {
|
||||
compatible = "fsl,fman-memac";
|
||||
reg = <0xf2000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x11 &fman0_tx_0x31>;
|
||||
pcsphy-handle = <&pcsphy7>;
|
||||
pcsphy-handle = <&pcsphy7>, <&qsgmiib_pcs3>, <&pcsphy7>;
|
||||
pcs-handle-names = "sgmii", "qsgmii", "xfi";
|
||||
};
|
||||
|
||||
mdio@e9000 {
|
||||
qsgmiib_pcs3: ethernet-pcs@3 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <3>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@f3000 {
|
||||
|
||||
45
arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-2.dtsi
Normal file
45
arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-2.dtsi
Normal file
@@ -0,0 +1,45 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
|
||||
/*
|
||||
* QorIQ FMan v3 10g port #2 device tree stub [ controller @ offset 0x400000 ]
|
||||
*
|
||||
* Copyright 2022 Sean Anderson <sean.anderson@seco.com>
|
||||
* Copyright 2012 - 2015 Freescale Semiconductor Inc.
|
||||
*/
|
||||
|
||||
fman@400000 {
|
||||
fman0_rx_0x08: port@88000 {
|
||||
cell-index = <0x8>;
|
||||
compatible = "fsl,fman-v3-port-rx";
|
||||
reg = <0x88000 0x1000>;
|
||||
fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
fman0_tx_0x28: port@a8000 {
|
||||
cell-index = <0x28>;
|
||||
compatible = "fsl,fman-v3-port-tx";
|
||||
reg = <0xa8000 0x1000>;
|
||||
fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
ethernet@e0000 {
|
||||
cell-index = <0>;
|
||||
compatible = "fsl,fman-memac";
|
||||
reg = <0xe0000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy0>, <&pcsphy0>;
|
||||
pcs-handle-names = "sgmii", "xfi";
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
|
||||
reg = <0xe1000 0x1000>;
|
||||
fsl,erratum-a011043; /* must ignore read errors */
|
||||
|
||||
pcsphy0: ethernet-phy@0 {
|
||||
reg = <0x0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
45
arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-3.dtsi
Normal file
45
arch/powerpc/boot/dts/fsl/qoriq-fman3-0-10g-3.dtsi
Normal file
@@ -0,0 +1,45 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
|
||||
/*
|
||||
* QorIQ FMan v3 10g port #3 device tree stub [ controller @ offset 0x400000 ]
|
||||
*
|
||||
* Copyright 2022 Sean Anderson <sean.anderson@seco.com>
|
||||
* Copyright 2012 - 2015 Freescale Semiconductor Inc.
|
||||
*/
|
||||
|
||||
fman@400000 {
|
||||
fman0_rx_0x09: port@89000 {
|
||||
cell-index = <0x9>;
|
||||
compatible = "fsl,fman-v3-port-rx";
|
||||
reg = <0x89000 0x1000>;
|
||||
fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
fman0_tx_0x29: port@a9000 {
|
||||
cell-index = <0x29>;
|
||||
compatible = "fsl,fman-v3-port-tx";
|
||||
reg = <0xa9000 0x1000>;
|
||||
fsl,fman-10g-port;
|
||||
};
|
||||
|
||||
ethernet@e2000 {
|
||||
cell-index = <1>;
|
||||
compatible = "fsl,fman-memac";
|
||||
reg = <0xe2000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy1>, <&pcsphy1>;
|
||||
pcs-handle-names = "sgmii", "xfi";
|
||||
};
|
||||
|
||||
mdio@e3000 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
compatible = "fsl,fman-memac-mdio", "fsl,fman-xmdio";
|
||||
reg = <0xe3000 0x1000>;
|
||||
fsl,erratum-a011043; /* must ignore read errors */
|
||||
|
||||
pcsphy1: ethernet-phy@0 {
|
||||
reg = <0x0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -51,7 +51,8 @@ ethernet@e0000 {
|
||||
reg = <0xe0000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x08 &fman0_tx_0x28>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy0>;
|
||||
pcsphy-handle = <&pcsphy0>, <&pcsphy0>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
|
||||
@@ -51,7 +51,15 @@ ethernet@e2000 {
|
||||
reg = <0xe2000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x09 &fman0_tx_0x29>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy1>;
|
||||
pcsphy-handle = <&pcsphy1>, <&qsgmiia_pcs1>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
qsgmiia_pcs1: ethernet-pcs@1 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@e3000 {
|
||||
|
||||
@@ -51,7 +51,15 @@ ethernet@e4000 {
|
||||
reg = <0xe4000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x0a &fman0_tx_0x2a>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy2>;
|
||||
pcsphy-handle = <&pcsphy2>, <&qsgmiia_pcs2>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
qsgmiia_pcs2: ethernet-pcs@2 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@e5000 {
|
||||
|
||||
@@ -51,7 +51,15 @@ ethernet@e6000 {
|
||||
reg = <0xe6000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x0b &fman0_tx_0x2b>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy3>;
|
||||
pcsphy-handle = <&pcsphy3>, <&qsgmiia_pcs3>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
qsgmiia_pcs3: ethernet-pcs@3 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <3>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@e7000 {
|
||||
|
||||
@@ -51,7 +51,8 @@ ethernet@e8000 {
|
||||
reg = <0xe8000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x0c &fman0_tx_0x2c>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy4>;
|
||||
pcsphy-handle = <&pcsphy4>, <&pcsphy4>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e9000 {
|
||||
|
||||
@@ -51,7 +51,15 @@ ethernet@ea000 {
|
||||
reg = <0xea000 0x1000>;
|
||||
fsl,fman-ports = <&fman0_rx_0x0d &fman0_tx_0x2d>;
|
||||
ptp-timer = <&ptp_timer0>;
|
||||
pcsphy-handle = <&pcsphy5>;
|
||||
pcsphy-handle = <&pcsphy5>, <&qsgmiib_pcs1>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e9000 {
|
||||
qsgmiib_pcs1: ethernet-pcs@1 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@eb000 {
|
||||
|
||||
@@ -52,7 +52,15 @@ ethernet@f0000 {
|
||||
compatible = "fsl,fman-memac";
|
||||
reg = <0xf0000 0x1000>;
|
||||
fsl,fman-ports = <&fman1_rx_0x10 &fman1_tx_0x30>;
|
||||
pcsphy-handle = <&pcsphy14>;
|
||||
pcsphy-handle = <&pcsphy14>, <&qsgmiid_pcs2>, <&pcsphy14>;
|
||||
pcs-handle-names = "sgmii", "qsgmii", "xfi";
|
||||
};
|
||||
|
||||
mdio@e9000 {
|
||||
qsgmiid_pcs2: ethernet-pcs@2 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@f1000 {
|
||||
|
||||
@@ -52,7 +52,15 @@ ethernet@f2000 {
|
||||
compatible = "fsl,fman-memac";
|
||||
reg = <0xf2000 0x1000>;
|
||||
fsl,fman-ports = <&fman1_rx_0x11 &fman1_tx_0x31>;
|
||||
pcsphy-handle = <&pcsphy15>;
|
||||
pcsphy-handle = <&pcsphy15>, <&qsgmiid_pcs3>, <&pcsphy15>;
|
||||
pcs-handle-names = "sgmii", "qsgmii", "xfi";
|
||||
};
|
||||
|
||||
mdio@e9000 {
|
||||
qsgmiid_pcs3: ethernet-pcs@3 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <3>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@f3000 {
|
||||
|
||||
@@ -51,7 +51,8 @@ ethernet@e0000 {
|
||||
reg = <0xe0000 0x1000>;
|
||||
fsl,fman-ports = <&fman1_rx_0x08 &fman1_tx_0x28>;
|
||||
ptp-timer = <&ptp_timer1>;
|
||||
pcsphy-handle = <&pcsphy8>;
|
||||
pcsphy-handle = <&pcsphy8>, <&pcsphy8>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
|
||||
@@ -51,7 +51,15 @@ ethernet@e2000 {
|
||||
reg = <0xe2000 0x1000>;
|
||||
fsl,fman-ports = <&fman1_rx_0x09 &fman1_tx_0x29>;
|
||||
ptp-timer = <&ptp_timer1>;
|
||||
pcsphy-handle = <&pcsphy9>;
|
||||
pcsphy-handle = <&pcsphy9>, <&qsgmiic_pcs1>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
qsgmiic_pcs1: ethernet-pcs@1 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@e3000 {
|
||||
|
||||
@@ -51,7 +51,15 @@ ethernet@e4000 {
|
||||
reg = <0xe4000 0x1000>;
|
||||
fsl,fman-ports = <&fman1_rx_0x0a &fman1_tx_0x2a>;
|
||||
ptp-timer = <&ptp_timer1>;
|
||||
pcsphy-handle = <&pcsphy10>;
|
||||
pcsphy-handle = <&pcsphy10>, <&qsgmiic_pcs2>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
qsgmiic_pcs2: ethernet-pcs@2 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@e5000 {
|
||||
|
||||
@@ -51,7 +51,15 @@ ethernet@e6000 {
|
||||
reg = <0xe6000 0x1000>;
|
||||
fsl,fman-ports = <&fman1_rx_0x0b &fman1_tx_0x2b>;
|
||||
ptp-timer = <&ptp_timer1>;
|
||||
pcsphy-handle = <&pcsphy11>;
|
||||
pcsphy-handle = <&pcsphy11>, <&qsgmiic_pcs3>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e1000 {
|
||||
qsgmiic_pcs3: ethernet-pcs@3 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <3>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@e7000 {
|
||||
|
||||
@@ -51,7 +51,8 @@ ethernet@e8000 {
|
||||
reg = <0xe8000 0x1000>;
|
||||
fsl,fman-ports = <&fman1_rx_0x0c &fman1_tx_0x2c>;
|
||||
ptp-timer = <&ptp_timer1>;
|
||||
pcsphy-handle = <&pcsphy12>;
|
||||
pcsphy-handle = <&pcsphy12>, <&pcsphy12>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e9000 {
|
||||
|
||||
@@ -51,7 +51,15 @@ ethernet@ea000 {
|
||||
reg = <0xea000 0x1000>;
|
||||
fsl,fman-ports = <&fman1_rx_0x0d &fman1_tx_0x2d>;
|
||||
ptp-timer = <&ptp_timer1>;
|
||||
pcsphy-handle = <&pcsphy13>;
|
||||
pcsphy-handle = <&pcsphy13>, <&qsgmiid_pcs1>;
|
||||
pcs-handle-names = "sgmii", "qsgmii";
|
||||
};
|
||||
|
||||
mdio@e9000 {
|
||||
qsgmiid_pcs1: ethernet-pcs@1 {
|
||||
compatible = "fsl,lynx-pcs";
|
||||
reg = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
mdio@eb000 {
|
||||
|
||||
@@ -609,8 +609,8 @@ usb1: usb@211000 {
|
||||
/include/ "qoriq-bman1.dtsi"
|
||||
|
||||
/include/ "qoriq-fman3-0.dtsi"
|
||||
/include/ "qoriq-fman3-0-1g-0.dtsi"
|
||||
/include/ "qoriq-fman3-0-1g-1.dtsi"
|
||||
/include/ "qoriq-fman3-0-10g-2.dtsi"
|
||||
/include/ "qoriq-fman3-0-10g-3.dtsi"
|
||||
/include/ "qoriq-fman3-0-1g-2.dtsi"
|
||||
/include/ "qoriq-fman3-0-1g-3.dtsi"
|
||||
/include/ "qoriq-fman3-0-1g-4.dtsi"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
menuconfig FSL_DPAA_ETH
|
||||
tristate "DPAA Ethernet"
|
||||
depends on FSL_DPAA && FSL_FMAN
|
||||
select PHYLIB
|
||||
select FIXED_PHY
|
||||
select PHYLINK
|
||||
select PCS_LYNX
|
||||
help
|
||||
Data Path Acceleration Architecture Ethernet driver,
|
||||
supporting the Freescale QorIQ chips.
|
||||
|
||||
@@ -264,8 +264,19 @@ static int dpaa_netdev_init(struct net_device *net_dev,
|
||||
net_dev->needed_headroom = priv->tx_headroom;
|
||||
net_dev->watchdog_timeo = msecs_to_jiffies(tx_timeout);
|
||||
|
||||
mac_dev->net_dev = net_dev;
|
||||
/* The rest of the config is filled in by the mac device already */
|
||||
mac_dev->phylink_config.dev = &net_dev->dev;
|
||||
mac_dev->phylink_config.type = PHYLINK_NETDEV;
|
||||
mac_dev->update_speed = dpaa_eth_cgr_set_speed;
|
||||
mac_dev->phylink = phylink_create(&mac_dev->phylink_config,
|
||||
dev_fwnode(mac_dev->dev),
|
||||
mac_dev->phy_if,
|
||||
mac_dev->phylink_ops);
|
||||
if (IS_ERR(mac_dev->phylink)) {
|
||||
err = PTR_ERR(mac_dev->phylink);
|
||||
dev_err_probe(dev, err, "Could not create phylink\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* start without the RUNNING flag, phylib controls it later */
|
||||
netif_carrier_off(net_dev);
|
||||
@@ -273,6 +284,7 @@ static int dpaa_netdev_init(struct net_device *net_dev,
|
||||
err = register_netdev(net_dev);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "register_netdev() = %d\n", err);
|
||||
phylink_destroy(mac_dev->phylink);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -294,8 +306,7 @@ static int dpaa_stop(struct net_device *net_dev)
|
||||
*/
|
||||
msleep(200);
|
||||
|
||||
if (mac_dev->phy_dev)
|
||||
phy_stop(mac_dev->phy_dev);
|
||||
phylink_stop(mac_dev->phylink);
|
||||
mac_dev->disable(mac_dev->fman_mac);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) {
|
||||
@@ -304,8 +315,7 @@ static int dpaa_stop(struct net_device *net_dev)
|
||||
err = error;
|
||||
}
|
||||
|
||||
if (net_dev->phydev)
|
||||
phy_disconnect(net_dev->phydev);
|
||||
phylink_disconnect_phy(mac_dev->phylink);
|
||||
net_dev->phydev = NULL;
|
||||
|
||||
msleep(200);
|
||||
@@ -833,10 +843,10 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv)
|
||||
|
||||
/* Set different thresholds based on the configured MAC speed.
|
||||
* This may turn suboptimal if the MAC is reconfigured at another
|
||||
* speed, so MACs must call dpaa_eth_cgr_set_speed in their adjust_link
|
||||
* speed, so MACs must call dpaa_eth_cgr_set_speed in their link_up
|
||||
* callback.
|
||||
*/
|
||||
if (priv->mac_dev->if_support & SUPPORTED_10000baseT_Full)
|
||||
if (priv->mac_dev->phylink_config.mac_capabilities & MAC_10000FD)
|
||||
cs_th = DPAA_CS_THRESHOLD_10G;
|
||||
else
|
||||
cs_th = DPAA_CS_THRESHOLD_1G;
|
||||
@@ -865,7 +875,7 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv)
|
||||
|
||||
static void dpaa_eth_cgr_set_speed(struct mac_device *mac_dev, int speed)
|
||||
{
|
||||
struct net_device *net_dev = mac_dev->net_dev;
|
||||
struct net_device *net_dev = to_net_dev(mac_dev->phylink_config.dev);
|
||||
struct dpaa_priv *priv = netdev_priv(net_dev);
|
||||
struct qm_mcc_initcgr opts = { };
|
||||
u32 cs_th;
|
||||
@@ -2904,58 +2914,6 @@ static void dpaa_eth_napi_disable(struct dpaa_priv *priv)
|
||||
}
|
||||
}
|
||||
|
||||
static void dpaa_adjust_link(struct net_device *net_dev)
|
||||
{
|
||||
struct mac_device *mac_dev;
|
||||
struct dpaa_priv *priv;
|
||||
|
||||
priv = netdev_priv(net_dev);
|
||||
mac_dev = priv->mac_dev;
|
||||
mac_dev->adjust_link(mac_dev);
|
||||
}
|
||||
|
||||
/* The Aquantia PHYs are capable of performing rate adaptation */
|
||||
#define PHY_VEND_AQUANTIA 0x03a1b400
|
||||
#define PHY_VEND_AQUANTIA2 0x31c31c00
|
||||
|
||||
static int dpaa_phy_init(struct net_device *net_dev)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
|
||||
struct mac_device *mac_dev;
|
||||
struct phy_device *phy_dev;
|
||||
struct dpaa_priv *priv;
|
||||
u32 phy_vendor;
|
||||
|
||||
priv = netdev_priv(net_dev);
|
||||
mac_dev = priv->mac_dev;
|
||||
|
||||
phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
|
||||
&dpaa_adjust_link, 0,
|
||||
mac_dev->phy_if);
|
||||
if (!phy_dev) {
|
||||
netif_err(priv, ifup, net_dev, "init_phy() failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
phy_vendor = phy_dev->drv->phy_id & GENMASK(31, 10);
|
||||
/* Unless the PHY is capable of rate adaptation */
|
||||
if (mac_dev->phy_if != PHY_INTERFACE_MODE_XGMII ||
|
||||
(phy_vendor != PHY_VEND_AQUANTIA &&
|
||||
phy_vendor != PHY_VEND_AQUANTIA2)) {
|
||||
/* remove any features not supported by the controller */
|
||||
ethtool_convert_legacy_u32_to_link_mode(mask,
|
||||
mac_dev->if_support);
|
||||
linkmode_and(phy_dev->supported, phy_dev->supported, mask);
|
||||
}
|
||||
|
||||
phy_support_asym_pause(phy_dev);
|
||||
|
||||
mac_dev->phy_dev = phy_dev;
|
||||
net_dev->phydev = phy_dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dpaa_open(struct net_device *net_dev)
|
||||
{
|
||||
struct mac_device *mac_dev;
|
||||
@@ -2966,7 +2924,8 @@ static int dpaa_open(struct net_device *net_dev)
|
||||
mac_dev = priv->mac_dev;
|
||||
dpaa_eth_napi_enable(priv);
|
||||
|
||||
err = dpaa_phy_init(net_dev);
|
||||
err = phylink_of_phy_connect(mac_dev->phylink,
|
||||
mac_dev->dev->of_node, 0);
|
||||
if (err)
|
||||
goto phy_init_failed;
|
||||
|
||||
@@ -2981,7 +2940,7 @@ static int dpaa_open(struct net_device *net_dev)
|
||||
netif_err(priv, ifup, net_dev, "mac_dev->enable() = %d\n", err);
|
||||
goto mac_start_failed;
|
||||
}
|
||||
phy_start(priv->mac_dev->phy_dev);
|
||||
phylink_start(mac_dev->phylink);
|
||||
|
||||
netif_tx_start_all_queues(net_dev);
|
||||
|
||||
@@ -2990,6 +2949,7 @@ static int dpaa_open(struct net_device *net_dev)
|
||||
mac_start_failed:
|
||||
for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++)
|
||||
fman_port_disable(mac_dev->port[i]);
|
||||
phylink_disconnect_phy(mac_dev->phylink);
|
||||
|
||||
phy_init_failed:
|
||||
dpaa_eth_napi_disable(priv);
|
||||
@@ -3145,10 +3105,12 @@ static int dpaa_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||
static int dpaa_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
struct dpaa_priv *priv = netdev_priv(net_dev);
|
||||
|
||||
if (cmd == SIOCGMIIREG) {
|
||||
if (net_dev->phydev)
|
||||
return phy_mii_ioctl(net_dev->phydev, rq, cmd);
|
||||
return phylink_mii_ioctl(priv->mac_dev->phylink, rq,
|
||||
cmd);
|
||||
}
|
||||
|
||||
if (cmd == SIOCSHWTSTAMP)
|
||||
@@ -3551,6 +3513,7 @@ static int dpaa_remove(struct platform_device *pdev)
|
||||
|
||||
dev_set_drvdata(dev, NULL);
|
||||
unregister_netdev(net_dev);
|
||||
phylink_destroy(priv->mac_dev->phylink);
|
||||
|
||||
err = dpaa_fq_free(dev, &priv->dpaa_fq_list);
|
||||
|
||||
|
||||
@@ -54,27 +54,19 @@ static char dpaa_stats_global[][ETH_GSTRING_LEN] = {
|
||||
static int dpaa_get_link_ksettings(struct net_device *net_dev,
|
||||
struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
if (!net_dev->phydev)
|
||||
return 0;
|
||||
struct dpaa_priv *priv = netdev_priv(net_dev);
|
||||
struct mac_device *mac_dev = priv->mac_dev;
|
||||
|
||||
phy_ethtool_ksettings_get(net_dev->phydev, cmd);
|
||||
|
||||
return 0;
|
||||
return phylink_ethtool_ksettings_get(mac_dev->phylink, cmd);
|
||||
}
|
||||
|
||||
static int dpaa_set_link_ksettings(struct net_device *net_dev,
|
||||
const struct ethtool_link_ksettings *cmd)
|
||||
{
|
||||
int err;
|
||||
struct dpaa_priv *priv = netdev_priv(net_dev);
|
||||
struct mac_device *mac_dev = priv->mac_dev;
|
||||
|
||||
if (!net_dev->phydev)
|
||||
return -ENODEV;
|
||||
|
||||
err = phy_ethtool_ksettings_set(net_dev->phydev, cmd);
|
||||
if (err < 0)
|
||||
netdev_err(net_dev, "phy_ethtool_ksettings_set() = %d\n", err);
|
||||
|
||||
return err;
|
||||
return phylink_ethtool_ksettings_set(mac_dev->phylink, cmd);
|
||||
}
|
||||
|
||||
static void dpaa_get_drvinfo(struct net_device *net_dev,
|
||||
@@ -99,80 +91,28 @@ static void dpaa_set_msglevel(struct net_device *net_dev,
|
||||
|
||||
static int dpaa_nway_reset(struct net_device *net_dev)
|
||||
{
|
||||
int err;
|
||||
struct dpaa_priv *priv = netdev_priv(net_dev);
|
||||
struct mac_device *mac_dev = priv->mac_dev;
|
||||
|
||||
if (!net_dev->phydev)
|
||||
return -ENODEV;
|
||||
|
||||
err = 0;
|
||||
if (net_dev->phydev->autoneg) {
|
||||
err = phy_start_aneg(net_dev->phydev);
|
||||
if (err < 0)
|
||||
netdev_err(net_dev, "phy_start_aneg() = %d\n",
|
||||
err);
|
||||
}
|
||||
|
||||
return err;
|
||||
return phylink_ethtool_nway_reset(mac_dev->phylink);
|
||||
}
|
||||
|
||||
static void dpaa_get_pauseparam(struct net_device *net_dev,
|
||||
struct ethtool_pauseparam *epause)
|
||||
{
|
||||
struct mac_device *mac_dev;
|
||||
struct dpaa_priv *priv;
|
||||
struct dpaa_priv *priv = netdev_priv(net_dev);
|
||||
struct mac_device *mac_dev = priv->mac_dev;
|
||||
|
||||
priv = netdev_priv(net_dev);
|
||||
mac_dev = priv->mac_dev;
|
||||
|
||||
if (!net_dev->phydev)
|
||||
return;
|
||||
|
||||
epause->autoneg = mac_dev->autoneg_pause;
|
||||
epause->rx_pause = mac_dev->rx_pause_active;
|
||||
epause->tx_pause = mac_dev->tx_pause_active;
|
||||
phylink_ethtool_get_pauseparam(mac_dev->phylink, epause);
|
||||
}
|
||||
|
||||
static int dpaa_set_pauseparam(struct net_device *net_dev,
|
||||
struct ethtool_pauseparam *epause)
|
||||
{
|
||||
struct mac_device *mac_dev;
|
||||
struct phy_device *phydev;
|
||||
bool rx_pause, tx_pause;
|
||||
struct dpaa_priv *priv;
|
||||
int err;
|
||||
struct dpaa_priv *priv = netdev_priv(net_dev);
|
||||
struct mac_device *mac_dev = priv->mac_dev;
|
||||
|
||||
priv = netdev_priv(net_dev);
|
||||
mac_dev = priv->mac_dev;
|
||||
|
||||
phydev = net_dev->phydev;
|
||||
if (!phydev) {
|
||||
netdev_err(net_dev, "phy device not initialized\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!phy_validate_pause(phydev, epause))
|
||||
return -EINVAL;
|
||||
|
||||
/* The MAC should know how to handle PAUSE frame autonegotiation before
|
||||
* adjust_link is triggered by a forced renegotiation of sym/asym PAUSE
|
||||
* settings.
|
||||
*/
|
||||
mac_dev->autoneg_pause = !!epause->autoneg;
|
||||
mac_dev->rx_pause_req = !!epause->rx_pause;
|
||||
mac_dev->tx_pause_req = !!epause->tx_pause;
|
||||
|
||||
/* Determine the sym/asym advertised PAUSE capabilities from the desired
|
||||
* rx/tx pause settings.
|
||||
*/
|
||||
|
||||
phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause);
|
||||
|
||||
fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
|
||||
err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause);
|
||||
if (err < 0)
|
||||
netdev_err(net_dev, "set_mac_active_pause() = %d\n", err);
|
||||
|
||||
return err;
|
||||
return phylink_ethtool_set_pauseparam(mac_dev->phylink, epause);
|
||||
}
|
||||
|
||||
static int dpaa_get_sset_count(struct net_device *net_dev, int type)
|
||||
|
||||
@@ -3,7 +3,9 @@ config FSL_FMAN
|
||||
tristate "FMan support"
|
||||
depends on FSL_SOC || ARCH_LAYERSCAPE || COMPILE_TEST
|
||||
select GENERIC_ALLOCATOR
|
||||
select PHYLIB
|
||||
select PHYLINK
|
||||
select PCS
|
||||
select PCS_LYNX
|
||||
select CRC32
|
||||
default n
|
||||
help
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/of_mdio.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
/* TBI register addresses */
|
||||
#define MII_TBICON 0x11
|
||||
@@ -29,9 +30,6 @@
|
||||
#define TBICON_CLK_SELECT 0x0020 /* Clock select */
|
||||
#define TBICON_MI_MODE 0x0010 /* GMII mode (TBI if not set) */
|
||||
|
||||
#define TBIANA_SGMII 0x4001
|
||||
#define TBIANA_1000X 0x01a0
|
||||
|
||||
/* Interrupt Mask Register (IMASK) */
|
||||
#define DTSEC_IMASK_BREN 0x80000000
|
||||
#define DTSEC_IMASK_RXCEN 0x40000000
|
||||
@@ -92,9 +90,10 @@
|
||||
|
||||
#define DTSEC_ECNTRL_GMIIM 0x00000040
|
||||
#define DTSEC_ECNTRL_TBIM 0x00000020
|
||||
#define DTSEC_ECNTRL_SGMIIM 0x00000002
|
||||
#define DTSEC_ECNTRL_RPM 0x00000010
|
||||
#define DTSEC_ECNTRL_R100M 0x00000008
|
||||
#define DTSEC_ECNTRL_RMM 0x00000004
|
||||
#define DTSEC_ECNTRL_SGMIIM 0x00000002
|
||||
#define DTSEC_ECNTRL_QSGMIIM 0x00000001
|
||||
|
||||
#define TCTRL_TTSE 0x00000040
|
||||
@@ -318,7 +317,8 @@ struct fman_mac {
|
||||
void *fm;
|
||||
struct fman_rev_info fm_rev_info;
|
||||
bool basex_if;
|
||||
struct phy_device *tbiphy;
|
||||
struct mdio_device *tbidev;
|
||||
struct phylink_pcs pcs;
|
||||
};
|
||||
|
||||
static void set_dflts(struct dtsec_cfg *cfg)
|
||||
@@ -356,56 +356,14 @@ static int init(struct dtsec_regs __iomem *regs, struct dtsec_cfg *cfg,
|
||||
phy_interface_t iface, u16 iface_speed, u64 addr,
|
||||
u32 exception_mask, u8 tbi_addr)
|
||||
{
|
||||
bool is_rgmii, is_sgmii, is_qsgmii;
|
||||
enet_addr_t eth_addr;
|
||||
u32 tmp;
|
||||
u32 tmp = 0;
|
||||
int i;
|
||||
|
||||
/* Soft reset */
|
||||
iowrite32be(MACCFG1_SOFT_RESET, ®s->maccfg1);
|
||||
iowrite32be(0, ®s->maccfg1);
|
||||
|
||||
/* dtsec_id2 */
|
||||
tmp = ioread32be(®s->tsec_id2);
|
||||
|
||||
/* check RGMII support */
|
||||
if (iface == PHY_INTERFACE_MODE_RGMII ||
|
||||
iface == PHY_INTERFACE_MODE_RGMII_ID ||
|
||||
iface == PHY_INTERFACE_MODE_RGMII_RXID ||
|
||||
iface == PHY_INTERFACE_MODE_RGMII_TXID ||
|
||||
iface == PHY_INTERFACE_MODE_RMII)
|
||||
if (tmp & DTSEC_ID2_INT_REDUCED_OFF)
|
||||
return -EINVAL;
|
||||
|
||||
if (iface == PHY_INTERFACE_MODE_SGMII ||
|
||||
iface == PHY_INTERFACE_MODE_MII)
|
||||
if (tmp & DTSEC_ID2_INT_REDUCED_OFF)
|
||||
return -EINVAL;
|
||||
|
||||
is_rgmii = iface == PHY_INTERFACE_MODE_RGMII ||
|
||||
iface == PHY_INTERFACE_MODE_RGMII_ID ||
|
||||
iface == PHY_INTERFACE_MODE_RGMII_RXID ||
|
||||
iface == PHY_INTERFACE_MODE_RGMII_TXID;
|
||||
is_sgmii = iface == PHY_INTERFACE_MODE_SGMII;
|
||||
is_qsgmii = iface == PHY_INTERFACE_MODE_QSGMII;
|
||||
|
||||
tmp = 0;
|
||||
if (is_rgmii || iface == PHY_INTERFACE_MODE_GMII)
|
||||
tmp |= DTSEC_ECNTRL_GMIIM;
|
||||
if (is_sgmii)
|
||||
tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM);
|
||||
if (is_qsgmii)
|
||||
tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM |
|
||||
DTSEC_ECNTRL_QSGMIIM);
|
||||
if (is_rgmii)
|
||||
tmp |= DTSEC_ECNTRL_RPM;
|
||||
if (iface_speed == SPEED_100)
|
||||
tmp |= DTSEC_ECNTRL_R100M;
|
||||
|
||||
iowrite32be(tmp, ®s->ecntrl);
|
||||
|
||||
tmp = 0;
|
||||
|
||||
if (cfg->tx_pause_time)
|
||||
tmp |= cfg->tx_pause_time;
|
||||
if (cfg->tx_pause_time_extd)
|
||||
@@ -446,17 +404,10 @@ static int init(struct dtsec_regs __iomem *regs, struct dtsec_cfg *cfg,
|
||||
|
||||
tmp = 0;
|
||||
|
||||
if (iface_speed < SPEED_1000)
|
||||
tmp |= MACCFG2_NIBBLE_MODE;
|
||||
else if (iface_speed == SPEED_1000)
|
||||
tmp |= MACCFG2_BYTE_MODE;
|
||||
|
||||
tmp |= (cfg->preamble_len << MACCFG2_PREAMBLE_LENGTH_SHIFT) &
|
||||
MACCFG2_PREAMBLE_LENGTH_MASK;
|
||||
if (cfg->tx_pad_crc)
|
||||
tmp |= MACCFG2_PAD_CRC_EN;
|
||||
/* Full Duplex */
|
||||
tmp |= MACCFG2_FULL_DUPLEX;
|
||||
iowrite32be(tmp, ®s->maccfg2);
|
||||
|
||||
tmp = (((cfg->non_back_to_back_ipg1 <<
|
||||
@@ -525,10 +476,6 @@ static void set_bucket(struct dtsec_regs __iomem *regs, int bucket,
|
||||
|
||||
static int check_init_parameters(struct fman_mac *dtsec)
|
||||
{
|
||||
if (dtsec->max_speed >= SPEED_10000) {
|
||||
pr_err("1G MAC driver supports 1G or lower speeds\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((dtsec->dtsec_drv_param)->rx_prepend >
|
||||
MAX_PACKET_ALIGNMENT) {
|
||||
pr_err("packetAlignmentPadding can't be > than %d\n",
|
||||
@@ -630,22 +577,10 @@ static int get_exception_flag(enum fman_mac_exceptions exception)
|
||||
return bit_mask;
|
||||
}
|
||||
|
||||
static bool is_init_done(struct dtsec_cfg *dtsec_drv_params)
|
||||
{
|
||||
/* Checks if dTSEC driver parameters were initialized */
|
||||
if (!dtsec_drv_params)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static u16 dtsec_get_max_frame_length(struct fman_mac *dtsec)
|
||||
{
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
|
||||
if (is_init_done(dtsec->dtsec_drv_param))
|
||||
return 0;
|
||||
|
||||
return (u16)ioread32be(®s->maxfrm);
|
||||
}
|
||||
|
||||
@@ -682,6 +617,7 @@ static void dtsec_isr(void *handle)
|
||||
dtsec->exception_cb(dtsec->dev_id, FM_MAC_EX_1G_COL_RET_LMT);
|
||||
if (event & DTSEC_IMASK_XFUNEN) {
|
||||
/* FM_TX_LOCKUP_ERRATA_DTSEC6 Errata workaround */
|
||||
/* FIXME: This races with the rest of the driver! */
|
||||
if (dtsec->fm_rev_info.major == 2) {
|
||||
u32 tpkt1, tmp_reg1, tpkt2, tmp_reg2, i;
|
||||
/* a. Write 0x00E0_0C00 to DTSEC_ID
|
||||
@@ -814,6 +750,43 @@ static void free_init_resources(struct fman_mac *dtsec)
|
||||
dtsec->unicast_addr_hash = NULL;
|
||||
}
|
||||
|
||||
static struct fman_mac *pcs_to_dtsec(struct phylink_pcs *pcs)
|
||||
{
|
||||
return container_of(pcs, struct fman_mac, pcs);
|
||||
}
|
||||
|
||||
static void dtsec_pcs_get_state(struct phylink_pcs *pcs,
|
||||
struct phylink_link_state *state)
|
||||
{
|
||||
struct fman_mac *dtsec = pcs_to_dtsec(pcs);
|
||||
|
||||
phylink_mii_c22_pcs_get_state(dtsec->tbidev, state);
|
||||
}
|
||||
|
||||
static int dtsec_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
|
||||
phy_interface_t interface,
|
||||
const unsigned long *advertising,
|
||||
bool permit_pause_to_mac)
|
||||
{
|
||||
struct fman_mac *dtsec = pcs_to_dtsec(pcs);
|
||||
|
||||
return phylink_mii_c22_pcs_config(dtsec->tbidev, mode, interface,
|
||||
advertising);
|
||||
}
|
||||
|
||||
static void dtsec_pcs_an_restart(struct phylink_pcs *pcs)
|
||||
{
|
||||
struct fman_mac *dtsec = pcs_to_dtsec(pcs);
|
||||
|
||||
phylink_mii_c22_pcs_an_restart(dtsec->tbidev);
|
||||
}
|
||||
|
||||
static const struct phylink_pcs_ops dtsec_pcs_ops = {
|
||||
.pcs_get_state = dtsec_pcs_get_state,
|
||||
.pcs_config = dtsec_pcs_config,
|
||||
.pcs_an_restart = dtsec_pcs_an_restart,
|
||||
};
|
||||
|
||||
static void graceful_start(struct fman_mac *dtsec)
|
||||
{
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
@@ -854,36 +827,11 @@ static void graceful_stop(struct fman_mac *dtsec)
|
||||
|
||||
static int dtsec_enable(struct fman_mac *dtsec)
|
||||
{
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
/* Enable */
|
||||
tmp = ioread32be(®s->maccfg1);
|
||||
tmp |= MACCFG1_RX_EN | MACCFG1_TX_EN;
|
||||
iowrite32be(tmp, ®s->maccfg1);
|
||||
|
||||
/* Graceful start - clear the graceful Rx/Tx stop bit */
|
||||
graceful_start(dtsec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dtsec_disable(struct fman_mac *dtsec)
|
||||
{
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
u32 tmp;
|
||||
|
||||
WARN_ON_ONCE(!is_init_done(dtsec->dtsec_drv_param));
|
||||
|
||||
/* Graceful stop - Assert the graceful Rx/Tx stop bit */
|
||||
graceful_stop(dtsec);
|
||||
|
||||
tmp = ioread32be(®s->maccfg1);
|
||||
tmp &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
|
||||
iowrite32be(tmp, ®s->maccfg1);
|
||||
}
|
||||
|
||||
static int dtsec_set_tx_pause_frames(struct fman_mac *dtsec,
|
||||
@@ -894,11 +842,6 @@ static int dtsec_set_tx_pause_frames(struct fman_mac *dtsec,
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
u32 ptv = 0;
|
||||
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
graceful_stop(dtsec);
|
||||
|
||||
if (pause_time) {
|
||||
/* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 Errata workaround */
|
||||
if (dtsec->fm_rev_info.major == 2 && pause_time <= 320) {
|
||||
@@ -919,8 +862,6 @@ static int dtsec_set_tx_pause_frames(struct fman_mac *dtsec,
|
||||
iowrite32be(ioread32be(®s->maccfg1) & ~MACCFG1_TX_FLOW,
|
||||
®s->maccfg1);
|
||||
|
||||
graceful_start(dtsec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -929,11 +870,6 @@ static int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en)
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
graceful_stop(dtsec);
|
||||
|
||||
tmp = ioread32be(®s->maccfg1);
|
||||
if (en)
|
||||
tmp |= MACCFG1_RX_FLOW;
|
||||
@@ -941,17 +877,125 @@ static int dtsec_accept_rx_pause_frames(struct fman_mac *dtsec, bool en)
|
||||
tmp &= ~MACCFG1_RX_FLOW;
|
||||
iowrite32be(tmp, ®s->maccfg1);
|
||||
|
||||
graceful_start(dtsec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phylink_pcs *dtsec_select_pcs(struct phylink_config *config,
|
||||
phy_interface_t iface)
|
||||
{
|
||||
struct fman_mac *dtsec = fman_config_to_mac(config)->fman_mac;
|
||||
|
||||
switch (iface) {
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
return &dtsec->pcs;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void dtsec_mac_config(struct phylink_config *config, unsigned int mode,
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
struct mac_device *mac_dev = fman_config_to_mac(config);
|
||||
struct dtsec_regs __iomem *regs = mac_dev->fman_mac->regs;
|
||||
u32 tmp;
|
||||
|
||||
switch (state->interface) {
|
||||
case PHY_INTERFACE_MODE_RMII:
|
||||
tmp = DTSEC_ECNTRL_RMM;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
tmp = DTSEC_ECNTRL_GMIIM | DTSEC_ECNTRL_RPM;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
tmp = DTSEC_ECNTRL_TBIM | DTSEC_ECNTRL_SGMIIM;
|
||||
break;
|
||||
default:
|
||||
dev_warn(mac_dev->dev, "cannot configure dTSEC for %s\n",
|
||||
phy_modes(state->interface));
|
||||
return;
|
||||
}
|
||||
|
||||
iowrite32be(tmp, ®s->ecntrl);
|
||||
}
|
||||
|
||||
static void dtsec_link_up(struct phylink_config *config, struct phy_device *phy,
|
||||
unsigned int mode, phy_interface_t interface,
|
||||
int speed, int duplex, bool tx_pause, bool rx_pause)
|
||||
{
|
||||
struct mac_device *mac_dev = fman_config_to_mac(config);
|
||||
struct fman_mac *dtsec = mac_dev->fman_mac;
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
u16 pause_time = tx_pause ? FSL_FM_PAUSE_TIME_ENABLE :
|
||||
FSL_FM_PAUSE_TIME_DISABLE;
|
||||
u32 tmp;
|
||||
|
||||
dtsec_set_tx_pause_frames(dtsec, 0, pause_time, 0);
|
||||
dtsec_accept_rx_pause_frames(dtsec, rx_pause);
|
||||
|
||||
tmp = ioread32be(®s->ecntrl);
|
||||
if (speed == SPEED_100)
|
||||
tmp |= DTSEC_ECNTRL_R100M;
|
||||
else
|
||||
tmp &= ~DTSEC_ECNTRL_R100M;
|
||||
iowrite32be(tmp, ®s->ecntrl);
|
||||
|
||||
tmp = ioread32be(®s->maccfg2);
|
||||
tmp &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE | MACCFG2_FULL_DUPLEX);
|
||||
if (speed >= SPEED_1000)
|
||||
tmp |= MACCFG2_BYTE_MODE;
|
||||
else
|
||||
tmp |= MACCFG2_NIBBLE_MODE;
|
||||
|
||||
if (duplex == DUPLEX_FULL)
|
||||
tmp |= MACCFG2_FULL_DUPLEX;
|
||||
|
||||
iowrite32be(tmp, ®s->maccfg2);
|
||||
|
||||
mac_dev->update_speed(mac_dev, speed);
|
||||
|
||||
/* Enable */
|
||||
tmp = ioread32be(®s->maccfg1);
|
||||
tmp |= MACCFG1_RX_EN | MACCFG1_TX_EN;
|
||||
iowrite32be(tmp, ®s->maccfg1);
|
||||
|
||||
/* Graceful start - clear the graceful Rx/Tx stop bit */
|
||||
graceful_start(dtsec);
|
||||
}
|
||||
|
||||
static void dtsec_link_down(struct phylink_config *config, unsigned int mode,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
struct fman_mac *dtsec = fman_config_to_mac(config)->fman_mac;
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
u32 tmp;
|
||||
|
||||
/* Graceful stop - Assert the graceful Rx/Tx stop bit */
|
||||
graceful_stop(dtsec);
|
||||
|
||||
tmp = ioread32be(®s->maccfg1);
|
||||
tmp &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
|
||||
iowrite32be(tmp, ®s->maccfg1);
|
||||
}
|
||||
|
||||
static const struct phylink_mac_ops dtsec_mac_ops = {
|
||||
.validate = phylink_generic_validate,
|
||||
.mac_select_pcs = dtsec_select_pcs,
|
||||
.mac_config = dtsec_mac_config,
|
||||
.mac_link_up = dtsec_link_up,
|
||||
.mac_link_down = dtsec_link_down,
|
||||
};
|
||||
|
||||
static int dtsec_modify_mac_address(struct fman_mac *dtsec,
|
||||
const enet_addr_t *enet_addr)
|
||||
{
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
graceful_stop(dtsec);
|
||||
|
||||
/* Initialize MAC Station Address registers (1 & 2)
|
||||
@@ -975,9 +1019,6 @@ static int dtsec_add_hash_mac_address(struct fman_mac *dtsec,
|
||||
u32 crc = 0xFFFFFFFF;
|
||||
bool mcast, ghtx;
|
||||
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
addr = ENET_ADDR_TO_UINT64(*eth_addr);
|
||||
|
||||
ghtx = (bool)((ioread32be(®s->rctrl) & RCTRL_GHTX) ? true : false);
|
||||
@@ -1037,9 +1078,6 @@ static int dtsec_set_allmulti(struct fman_mac *dtsec, bool enable)
|
||||
u32 tmp;
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = ioread32be(®s->rctrl);
|
||||
if (enable)
|
||||
tmp |= RCTRL_MPROM;
|
||||
@@ -1056,9 +1094,6 @@ static int dtsec_set_tstamp(struct fman_mac *dtsec, bool enable)
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
u32 rctrl, tctrl;
|
||||
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
rctrl = ioread32be(®s->rctrl);
|
||||
tctrl = ioread32be(®s->tctrl);
|
||||
|
||||
@@ -1087,9 +1122,6 @@ static int dtsec_del_hash_mac_address(struct fman_mac *dtsec,
|
||||
u32 crc = 0xFFFFFFFF;
|
||||
bool mcast, ghtx;
|
||||
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
addr = ENET_ADDR_TO_UINT64(*eth_addr);
|
||||
|
||||
ghtx = (bool)((ioread32be(®s->rctrl) & RCTRL_GHTX) ? true : false);
|
||||
@@ -1153,9 +1185,6 @@ static int dtsec_set_promiscuous(struct fman_mac *dtsec, bool new_val)
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
/* Set unicast promiscuous */
|
||||
tmp = ioread32be(®s->rctrl);
|
||||
if (new_val)
|
||||
@@ -1177,90 +1206,12 @@ static int dtsec_set_promiscuous(struct fman_mac *dtsec, bool new_val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtsec_adjust_link(struct fman_mac *dtsec, u16 speed)
|
||||
{
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
graceful_stop(dtsec);
|
||||
|
||||
tmp = ioread32be(®s->maccfg2);
|
||||
|
||||
/* Full Duplex */
|
||||
tmp |= MACCFG2_FULL_DUPLEX;
|
||||
|
||||
tmp &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE);
|
||||
if (speed < SPEED_1000)
|
||||
tmp |= MACCFG2_NIBBLE_MODE;
|
||||
else if (speed == SPEED_1000)
|
||||
tmp |= MACCFG2_BYTE_MODE;
|
||||
iowrite32be(tmp, ®s->maccfg2);
|
||||
|
||||
tmp = ioread32be(®s->ecntrl);
|
||||
if (speed == SPEED_100)
|
||||
tmp |= DTSEC_ECNTRL_R100M;
|
||||
else
|
||||
tmp &= ~DTSEC_ECNTRL_R100M;
|
||||
iowrite32be(tmp, ®s->ecntrl);
|
||||
|
||||
graceful_start(dtsec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dtsec_restart_autoneg(struct fman_mac *dtsec)
|
||||
{
|
||||
u16 tmp_reg16;
|
||||
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
tmp_reg16 = phy_read(dtsec->tbiphy, MII_BMCR);
|
||||
|
||||
tmp_reg16 &= ~(BMCR_SPEED100 | BMCR_SPEED1000);
|
||||
tmp_reg16 |= (BMCR_ANENABLE | BMCR_ANRESTART |
|
||||
BMCR_FULLDPLX | BMCR_SPEED1000);
|
||||
|
||||
phy_write(dtsec->tbiphy, MII_BMCR, tmp_reg16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adjust_link_dtsec(struct mac_device *mac_dev)
|
||||
{
|
||||
struct phy_device *phy_dev = mac_dev->phy_dev;
|
||||
struct fman_mac *fman_mac;
|
||||
bool rx_pause, tx_pause;
|
||||
int err;
|
||||
|
||||
fman_mac = mac_dev->fman_mac;
|
||||
if (!phy_dev->link) {
|
||||
dtsec_restart_autoneg(fman_mac);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
dtsec_adjust_link(fman_mac, phy_dev->speed);
|
||||
mac_dev->update_speed(mac_dev, phy_dev->speed);
|
||||
fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
|
||||
err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause);
|
||||
if (err < 0)
|
||||
dev_err(mac_dev->dev, "fman_set_mac_active_pause() = %d\n",
|
||||
err);
|
||||
}
|
||||
|
||||
static int dtsec_set_exception(struct fman_mac *dtsec,
|
||||
enum fman_mac_exceptions exception, bool enable)
|
||||
{
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
u32 bit_mask = 0;
|
||||
|
||||
if (!is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
if (exception != FM_MAC_EX_1G_1588_TS_RX_ERR) {
|
||||
bit_mask = get_exception_flag(exception);
|
||||
if (bit_mask) {
|
||||
@@ -1310,12 +1261,9 @@ static int dtsec_init(struct fman_mac *dtsec)
|
||||
{
|
||||
struct dtsec_regs __iomem *regs = dtsec->regs;
|
||||
struct dtsec_cfg *dtsec_drv_param;
|
||||
u16 max_frm_ln;
|
||||
u16 max_frm_ln, tbicon;
|
||||
int err;
|
||||
|
||||
if (is_init_done(dtsec->dtsec_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
if (DEFAULT_RESET_ON_INIT &&
|
||||
(fman_reset_mac(dtsec->fm, dtsec->mac_id) != 0)) {
|
||||
pr_err("Can't reset MAC!\n");
|
||||
@@ -1330,38 +1278,19 @@ static int dtsec_init(struct fman_mac *dtsec)
|
||||
|
||||
err = init(dtsec->regs, dtsec_drv_param, dtsec->phy_if,
|
||||
dtsec->max_speed, dtsec->addr, dtsec->exceptions,
|
||||
dtsec->tbiphy->mdio.addr);
|
||||
dtsec->tbidev->addr);
|
||||
if (err) {
|
||||
free_init_resources(dtsec);
|
||||
pr_err("DTSEC version doesn't support this i/f mode\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (dtsec->phy_if == PHY_INTERFACE_MODE_SGMII) {
|
||||
u16 tmp_reg16;
|
||||
/* Configure the TBI PHY Control Register */
|
||||
tbicon = TBICON_CLK_SELECT | TBICON_SOFT_RESET;
|
||||
mdiodev_write(dtsec->tbidev, MII_TBICON, tbicon);
|
||||
|
||||
/* Configure the TBI PHY Control Register */
|
||||
tmp_reg16 = TBICON_CLK_SELECT | TBICON_SOFT_RESET;
|
||||
phy_write(dtsec->tbiphy, MII_TBICON, tmp_reg16);
|
||||
|
||||
tmp_reg16 = TBICON_CLK_SELECT;
|
||||
phy_write(dtsec->tbiphy, MII_TBICON, tmp_reg16);
|
||||
|
||||
tmp_reg16 = (BMCR_RESET | BMCR_ANENABLE |
|
||||
BMCR_FULLDPLX | BMCR_SPEED1000);
|
||||
phy_write(dtsec->tbiphy, MII_BMCR, tmp_reg16);
|
||||
|
||||
if (dtsec->basex_if)
|
||||
tmp_reg16 = TBIANA_1000X;
|
||||
else
|
||||
tmp_reg16 = TBIANA_SGMII;
|
||||
phy_write(dtsec->tbiphy, MII_ADVERTISE, tmp_reg16);
|
||||
|
||||
tmp_reg16 = (BMCR_ANENABLE | BMCR_ANRESTART |
|
||||
BMCR_FULLDPLX | BMCR_SPEED1000);
|
||||
|
||||
phy_write(dtsec->tbiphy, MII_BMCR, tmp_reg16);
|
||||
}
|
||||
tbicon = TBICON_CLK_SELECT;
|
||||
mdiodev_write(dtsec->tbidev, MII_TBICON, tbicon);
|
||||
|
||||
/* Max Frame Length */
|
||||
max_frm_ln = (u16)ioread32be(®s->maxfrm);
|
||||
@@ -1406,6 +1335,8 @@ static int dtsec_free(struct fman_mac *dtsec)
|
||||
|
||||
kfree(dtsec->dtsec_drv_param);
|
||||
dtsec->dtsec_drv_param = NULL;
|
||||
if (!IS_ERR_OR_NULL(dtsec->tbidev))
|
||||
put_device(&dtsec->tbidev->dev);
|
||||
kfree(dtsec);
|
||||
|
||||
return 0;
|
||||
@@ -1434,7 +1365,6 @@ static struct fman_mac *dtsec_config(struct mac_device *mac_dev,
|
||||
|
||||
dtsec->regs = mac_dev->vaddr;
|
||||
dtsec->addr = ENET_ADDR_TO_UINT64(mac_dev->addr);
|
||||
dtsec->max_speed = params->max_speed;
|
||||
dtsec->phy_if = mac_dev->phy_if;
|
||||
dtsec->mac_id = params->mac_id;
|
||||
dtsec->exceptions = (DTSEC_IMASK_BREN |
|
||||
@@ -1457,7 +1387,6 @@ static struct fman_mac *dtsec_config(struct mac_device *mac_dev,
|
||||
dtsec->en_tsu_err_exception = dtsec->dtsec_drv_param->ptp_exception_en;
|
||||
|
||||
dtsec->fm = params->fm;
|
||||
dtsec->basex_if = params->basex_if;
|
||||
|
||||
/* Save FMan revision */
|
||||
fman_get_revision(dtsec->fm, &dtsec->fm_rev_info);
|
||||
@@ -1476,18 +1405,18 @@ int dtsec_initialization(struct mac_device *mac_dev,
|
||||
int err;
|
||||
struct fman_mac *dtsec;
|
||||
struct device_node *phy_node;
|
||||
unsigned long capabilities;
|
||||
unsigned long *supported;
|
||||
|
||||
mac_dev->phylink_ops = &dtsec_mac_ops;
|
||||
mac_dev->set_promisc = dtsec_set_promiscuous;
|
||||
mac_dev->change_addr = dtsec_modify_mac_address;
|
||||
mac_dev->add_hash_mac_addr = dtsec_add_hash_mac_address;
|
||||
mac_dev->remove_hash_mac_addr = dtsec_del_hash_mac_address;
|
||||
mac_dev->set_tx_pause = dtsec_set_tx_pause_frames;
|
||||
mac_dev->set_rx_pause = dtsec_accept_rx_pause_frames;
|
||||
mac_dev->set_exception = dtsec_set_exception;
|
||||
mac_dev->set_allmulti = dtsec_set_allmulti;
|
||||
mac_dev->set_tstamp = dtsec_set_tstamp;
|
||||
mac_dev->set_multi = fman_set_multi;
|
||||
mac_dev->adjust_link = adjust_link_dtsec;
|
||||
mac_dev->enable = dtsec_enable;
|
||||
mac_dev->disable = dtsec_disable;
|
||||
|
||||
@@ -1502,19 +1431,56 @@ int dtsec_initialization(struct mac_device *mac_dev,
|
||||
dtsec->dtsec_drv_param->tx_pad_crc = true;
|
||||
|
||||
phy_node = of_parse_phandle(mac_node, "tbi-handle", 0);
|
||||
if (!phy_node) {
|
||||
pr_err("TBI PHY node is not available\n");
|
||||
if (!phy_node || of_device_is_available(phy_node)) {
|
||||
of_node_put(phy_node);
|
||||
err = -EINVAL;
|
||||
dev_err_probe(mac_dev->dev, err,
|
||||
"TBI PCS node is not available\n");
|
||||
goto _return_fm_mac_free;
|
||||
}
|
||||
|
||||
dtsec->tbiphy = of_phy_find_device(phy_node);
|
||||
if (!dtsec->tbiphy) {
|
||||
pr_err("of_phy_find_device (TBI PHY) failed\n");
|
||||
err = -EINVAL;
|
||||
dtsec->tbidev = of_mdio_find_device(phy_node);
|
||||
of_node_put(phy_node);
|
||||
if (!dtsec->tbidev) {
|
||||
err = -EPROBE_DEFER;
|
||||
dev_err_probe(mac_dev->dev, err,
|
||||
"could not find mdiodev for PCS\n");
|
||||
goto _return_fm_mac_free;
|
||||
}
|
||||
put_device(&dtsec->tbiphy->mdio.dev);
|
||||
dtsec->pcs.ops = &dtsec_pcs_ops;
|
||||
dtsec->pcs.poll = true;
|
||||
|
||||
supported = mac_dev->phylink_config.supported_interfaces;
|
||||
|
||||
/* FIXME: Can we use DTSEC_ID2_INT_FULL_OFF to determine if these are
|
||||
* supported? If not, we can determine support via the phy if SerDes
|
||||
* support is added.
|
||||
*/
|
||||
if (mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII ||
|
||||
mac_dev->phy_if == PHY_INTERFACE_MODE_1000BASEX) {
|
||||
__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
|
||||
__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
|
||||
} else if (mac_dev->phy_if == PHY_INTERFACE_MODE_2500BASEX) {
|
||||
__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
|
||||
}
|
||||
|
||||
if (!(ioread32be(&dtsec->regs->tsec_id2) & DTSEC_ID2_INT_REDUCED_OFF)) {
|
||||
phy_interface_set_rgmii(supported);
|
||||
|
||||
/* DTSEC_ID2_INT_REDUCED_OFF indicates that the dTSEC supports
|
||||
* RMII and RGMII. However, the only SoCs which support RMII
|
||||
* are the P1017 and P1023. Avoid advertising this mode on
|
||||
* other SoCs. This is a bit of a moot point, since there's no
|
||||
* in-tree support for ethernet on these platforms...
|
||||
*/
|
||||
if (of_machine_is_compatible("fsl,P1023") ||
|
||||
of_machine_is_compatible("fsl,P1023RDB"))
|
||||
__set_bit(PHY_INTERFACE_MODE_RMII, supported);
|
||||
}
|
||||
|
||||
capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
|
||||
capabilities |= MAC_10 | MAC_100 | MAC_1000FD | MAC_2500FD;
|
||||
mac_dev->phylink_config.mac_capabilities = capabilities;
|
||||
|
||||
err = dtsec_init(dtsec);
|
||||
if (err < 0)
|
||||
|
||||
@@ -170,20 +170,10 @@ struct fman_mac_params {
|
||||
* 0 - FM_MAX_NUM_OF_10G_MACS
|
||||
*/
|
||||
u8 mac_id;
|
||||
/* Note that the speed should indicate the maximum rate that
|
||||
* this MAC should support rather than the actual speed;
|
||||
*/
|
||||
u16 max_speed;
|
||||
/* A handle to the FM object this port related to */
|
||||
void *fm;
|
||||
fman_mac_exception_cb *event_cb; /* MDIO Events Callback Routine */
|
||||
fman_mac_exception_cb *exception_cb;/* Exception Callback Routine */
|
||||
/* SGMII/QSGII interface with 1000BaseX auto-negotiation between MAC
|
||||
* and phy or backplane; Note: 1000BaseX auto-negotiation relates only
|
||||
* to interface between MAC and phy/backplane, SGMII phy can still
|
||||
* synchronize with far-end phy at 10Mbps, 100Mbps or 1000Mbps
|
||||
*/
|
||||
bool basex_if;
|
||||
};
|
||||
|
||||
struct eth_hash_t {
|
||||
|
||||
@@ -11,42 +11,12 @@
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/pcs-lynx.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phy_fixed.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/of_mdio.h>
|
||||
|
||||
/* PCS registers */
|
||||
#define MDIO_SGMII_CR 0x00
|
||||
#define MDIO_SGMII_DEV_ABIL_SGMII 0x04
|
||||
#define MDIO_SGMII_LINK_TMR_L 0x12
|
||||
#define MDIO_SGMII_LINK_TMR_H 0x13
|
||||
#define MDIO_SGMII_IF_MODE 0x14
|
||||
|
||||
/* SGMII Control defines */
|
||||
#define SGMII_CR_AN_EN 0x1000
|
||||
#define SGMII_CR_RESTART_AN 0x0200
|
||||
#define SGMII_CR_FD 0x0100
|
||||
#define SGMII_CR_SPEED_SEL1_1G 0x0040
|
||||
#define SGMII_CR_DEF_VAL (SGMII_CR_AN_EN | SGMII_CR_FD | \
|
||||
SGMII_CR_SPEED_SEL1_1G)
|
||||
|
||||
/* SGMII Device Ability for SGMII defines */
|
||||
#define MDIO_SGMII_DEV_ABIL_SGMII_MODE 0x4001
|
||||
#define MDIO_SGMII_DEV_ABIL_BASEX_MODE 0x01A0
|
||||
|
||||
/* Link timer define */
|
||||
#define LINK_TMR_L 0xa120
|
||||
#define LINK_TMR_H 0x0007
|
||||
#define LINK_TMR_L_BASEX 0xaf08
|
||||
#define LINK_TMR_H_BASEX 0x002f
|
||||
|
||||
/* SGMII IF Mode defines */
|
||||
#define IF_MODE_USE_SGMII_AN 0x0002
|
||||
#define IF_MODE_SGMII_EN 0x0001
|
||||
#define IF_MODE_SGMII_SPEED_100M 0x0004
|
||||
#define IF_MODE_SGMII_SPEED_1G 0x0008
|
||||
#define IF_MODE_SGMII_DUPLEX_HALF 0x0010
|
||||
|
||||
/* Num of additional exact match MAC adr regs */
|
||||
#define MEMAC_NUM_OF_PADDRS 7
|
||||
|
||||
@@ -308,9 +278,6 @@ struct fman_mac {
|
||||
struct memac_regs __iomem *regs;
|
||||
/* MAC address of device */
|
||||
u64 addr;
|
||||
/* Ethernet physical interface */
|
||||
phy_interface_t phy_if;
|
||||
u16 max_speed;
|
||||
struct mac_device *dev_id; /* device cookie used by the exception cbs */
|
||||
fman_mac_exception_cb *exception_cb;
|
||||
fman_mac_exception_cb *event_cb;
|
||||
@@ -323,9 +290,12 @@ struct fman_mac {
|
||||
struct memac_cfg *memac_drv_param;
|
||||
void *fm;
|
||||
struct fman_rev_info fm_rev_info;
|
||||
bool basex_if;
|
||||
struct phy_device *pcsphy;
|
||||
struct phy *serdes;
|
||||
struct phylink_pcs *sgmii_pcs;
|
||||
struct phylink_pcs *qsgmii_pcs;
|
||||
struct phylink_pcs *xfi_pcs;
|
||||
bool allmulti_enabled;
|
||||
bool rgmii_no_half_duplex;
|
||||
};
|
||||
|
||||
static void add_addr_in_paddr(struct memac_regs __iomem *regs, const u8 *adr,
|
||||
@@ -383,7 +353,6 @@ static void set_exception(struct memac_regs __iomem *regs, u32 val,
|
||||
}
|
||||
|
||||
static int init(struct memac_regs __iomem *regs, struct memac_cfg *cfg,
|
||||
phy_interface_t phy_if, u16 speed, bool slow_10g_if,
|
||||
u32 exceptions)
|
||||
{
|
||||
u32 tmp;
|
||||
@@ -411,41 +380,6 @@ static int init(struct memac_regs __iomem *regs, struct memac_cfg *cfg,
|
||||
iowrite32be((u32)cfg->pause_quanta, ®s->pause_quanta[0]);
|
||||
iowrite32be((u32)0, ®s->pause_thresh[0]);
|
||||
|
||||
/* IF_MODE */
|
||||
tmp = 0;
|
||||
switch (phy_if) {
|
||||
case PHY_INTERFACE_MODE_XGMII:
|
||||
tmp |= IF_MODE_10G;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_MII:
|
||||
tmp |= IF_MODE_MII;
|
||||
break;
|
||||
default:
|
||||
tmp |= IF_MODE_GMII;
|
||||
if (phy_if == PHY_INTERFACE_MODE_RGMII ||
|
||||
phy_if == PHY_INTERFACE_MODE_RGMII_ID ||
|
||||
phy_if == PHY_INTERFACE_MODE_RGMII_RXID ||
|
||||
phy_if == PHY_INTERFACE_MODE_RGMII_TXID)
|
||||
tmp |= IF_MODE_RGMII | IF_MODE_RGMII_AUTO;
|
||||
}
|
||||
iowrite32be(tmp, ®s->if_mode);
|
||||
|
||||
/* TX_FIFO_SECTIONS */
|
||||
tmp = 0;
|
||||
if (phy_if == PHY_INTERFACE_MODE_XGMII) {
|
||||
if (slow_10g_if) {
|
||||
tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G |
|
||||
TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G);
|
||||
} else {
|
||||
tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_10G |
|
||||
TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G);
|
||||
}
|
||||
} else {
|
||||
tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_1G |
|
||||
TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G);
|
||||
}
|
||||
iowrite32be(tmp, ®s->tx_fifo_sections);
|
||||
|
||||
/* clear all pending events and set-up interrupts */
|
||||
iowrite32be(0xffffffff, ®s->ievent);
|
||||
set_exception(regs, exceptions, true);
|
||||
@@ -485,93 +419,6 @@ static u32 get_mac_addr_hash_code(u64 eth_addr)
|
||||
return xor_val;
|
||||
}
|
||||
|
||||
static void setup_sgmii_internal_phy(struct fman_mac *memac,
|
||||
struct fixed_phy_status *fixed_link)
|
||||
{
|
||||
u16 tmp_reg16;
|
||||
|
||||
if (WARN_ON(!memac->pcsphy))
|
||||
return;
|
||||
|
||||
/* SGMII mode */
|
||||
tmp_reg16 = IF_MODE_SGMII_EN;
|
||||
if (!fixed_link)
|
||||
/* AN enable */
|
||||
tmp_reg16 |= IF_MODE_USE_SGMII_AN;
|
||||
else {
|
||||
switch (fixed_link->speed) {
|
||||
case 10:
|
||||
/* For 10M: IF_MODE[SPEED_10M] = 0 */
|
||||
break;
|
||||
case 100:
|
||||
tmp_reg16 |= IF_MODE_SGMII_SPEED_100M;
|
||||
break;
|
||||
case 1000:
|
||||
default:
|
||||
tmp_reg16 |= IF_MODE_SGMII_SPEED_1G;
|
||||
break;
|
||||
}
|
||||
if (!fixed_link->duplex)
|
||||
tmp_reg16 |= IF_MODE_SGMII_DUPLEX_HALF;
|
||||
}
|
||||
phy_write(memac->pcsphy, MDIO_SGMII_IF_MODE, tmp_reg16);
|
||||
|
||||
/* Device ability according to SGMII specification */
|
||||
tmp_reg16 = MDIO_SGMII_DEV_ABIL_SGMII_MODE;
|
||||
phy_write(memac->pcsphy, MDIO_SGMII_DEV_ABIL_SGMII, tmp_reg16);
|
||||
|
||||
/* Adjust link timer for SGMII -
|
||||
* According to Cisco SGMII specification the timer should be 1.6 ms.
|
||||
* The link_timer register is configured in units of the clock.
|
||||
* - When running as 1G SGMII, Serdes clock is 125 MHz, so
|
||||
* unit = 1 / (125*10^6 Hz) = 8 ns.
|
||||
* 1.6 ms in units of 8 ns = 1.6ms / 8ns = 2*10^5 = 0x30d40
|
||||
* - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so
|
||||
* unit = 1 / (312.5*10^6 Hz) = 3.2 ns.
|
||||
* 1.6 ms in units of 3.2 ns = 1.6ms / 3.2ns = 5*10^5 = 0x7a120.
|
||||
* Since link_timer value of 1G SGMII will be too short for 2.5 SGMII,
|
||||
* we always set up here a value of 2.5 SGMII.
|
||||
*/
|
||||
phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_H, LINK_TMR_H);
|
||||
phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_L, LINK_TMR_L);
|
||||
|
||||
if (!fixed_link)
|
||||
/* Restart AN */
|
||||
tmp_reg16 = SGMII_CR_DEF_VAL | SGMII_CR_RESTART_AN;
|
||||
else
|
||||
/* AN disabled */
|
||||
tmp_reg16 = SGMII_CR_DEF_VAL & ~SGMII_CR_AN_EN;
|
||||
phy_write(memac->pcsphy, 0x0, tmp_reg16);
|
||||
}
|
||||
|
||||
static void setup_sgmii_internal_phy_base_x(struct fman_mac *memac)
|
||||
{
|
||||
u16 tmp_reg16;
|
||||
|
||||
/* AN Device capability */
|
||||
tmp_reg16 = MDIO_SGMII_DEV_ABIL_BASEX_MODE;
|
||||
phy_write(memac->pcsphy, MDIO_SGMII_DEV_ABIL_SGMII, tmp_reg16);
|
||||
|
||||
/* Adjust link timer for SGMII -
|
||||
* For Serdes 1000BaseX auto-negotiation the timer should be 10 ms.
|
||||
* The link_timer register is configured in units of the clock.
|
||||
* - When running as 1G SGMII, Serdes clock is 125 MHz, so
|
||||
* unit = 1 / (125*10^6 Hz) = 8 ns.
|
||||
* 10 ms in units of 8 ns = 10ms / 8ns = 1250000 = 0x1312d0
|
||||
* - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so
|
||||
* unit = 1 / (312.5*10^6 Hz) = 3.2 ns.
|
||||
* 10 ms in units of 3.2 ns = 10ms / 3.2ns = 3125000 = 0x2faf08.
|
||||
* Since link_timer value of 1G SGMII will be too short for 2.5 SGMII,
|
||||
* we always set up here a value of 2.5 SGMII.
|
||||
*/
|
||||
phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_H, LINK_TMR_H_BASEX);
|
||||
phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_L, LINK_TMR_L_BASEX);
|
||||
|
||||
/* Restart AN */
|
||||
tmp_reg16 = SGMII_CR_DEF_VAL | SGMII_CR_RESTART_AN;
|
||||
phy_write(memac->pcsphy, 0x0, tmp_reg16);
|
||||
}
|
||||
|
||||
static int check_init_parameters(struct fman_mac *memac)
|
||||
{
|
||||
if (!memac->exception_cb) {
|
||||
@@ -677,41 +524,31 @@ static void free_init_resources(struct fman_mac *memac)
|
||||
memac->unicast_addr_hash = NULL;
|
||||
}
|
||||
|
||||
static bool is_init_done(struct memac_cfg *memac_drv_params)
|
||||
{
|
||||
/* Checks if mEMAC driver parameters were initialized */
|
||||
if (!memac_drv_params)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int memac_enable(struct fman_mac *memac)
|
||||
{
|
||||
struct memac_regs __iomem *regs = memac->regs;
|
||||
u32 tmp;
|
||||
int ret;
|
||||
|
||||
if (!is_init_done(memac->memac_drv_param))
|
||||
return -EINVAL;
|
||||
ret = phy_init(memac->serdes);
|
||||
if (ret) {
|
||||
dev_err(memac->dev_id->dev,
|
||||
"could not initialize serdes: %pe\n", ERR_PTR(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN;
|
||||
iowrite32be(tmp, ®s->command_config);
|
||||
ret = phy_power_on(memac->serdes);
|
||||
if (ret) {
|
||||
dev_err(memac->dev_id->dev,
|
||||
"could not power on serdes: %pe\n", ERR_PTR(ret));
|
||||
phy_exit(memac->serdes);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void memac_disable(struct fman_mac *memac)
|
||||
|
||||
{
|
||||
struct memac_regs __iomem *regs = memac->regs;
|
||||
u32 tmp;
|
||||
|
||||
WARN_ON_ONCE(!is_init_done(memac->memac_drv_param));
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN);
|
||||
iowrite32be(tmp, ®s->command_config);
|
||||
phy_power_off(memac->serdes);
|
||||
phy_exit(memac->serdes);
|
||||
}
|
||||
|
||||
static int memac_set_promiscuous(struct fman_mac *memac, bool new_val)
|
||||
@@ -719,9 +556,6 @@ static int memac_set_promiscuous(struct fman_mac *memac, bool new_val)
|
||||
struct memac_regs __iomem *regs = memac->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(memac->memac_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
if (new_val)
|
||||
tmp |= CMD_CFG_PROMIS_EN;
|
||||
@@ -733,73 +567,12 @@ static int memac_set_promiscuous(struct fman_mac *memac, bool new_val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int memac_adjust_link(struct fman_mac *memac, u16 speed)
|
||||
{
|
||||
struct memac_regs __iomem *regs = memac->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(memac->memac_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = ioread32be(®s->if_mode);
|
||||
|
||||
/* Set full duplex */
|
||||
tmp &= ~IF_MODE_HD;
|
||||
|
||||
if (phy_interface_mode_is_rgmii(memac->phy_if)) {
|
||||
/* Configure RGMII in manual mode */
|
||||
tmp &= ~IF_MODE_RGMII_AUTO;
|
||||
tmp &= ~IF_MODE_RGMII_SP_MASK;
|
||||
/* Full duplex */
|
||||
tmp |= IF_MODE_RGMII_FD;
|
||||
|
||||
switch (speed) {
|
||||
case SPEED_1000:
|
||||
tmp |= IF_MODE_RGMII_1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
tmp |= IF_MODE_RGMII_100;
|
||||
break;
|
||||
case SPEED_10:
|
||||
tmp |= IF_MODE_RGMII_10;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iowrite32be(tmp, ®s->if_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void adjust_link_memac(struct mac_device *mac_dev)
|
||||
{
|
||||
struct phy_device *phy_dev = mac_dev->phy_dev;
|
||||
struct fman_mac *fman_mac;
|
||||
bool rx_pause, tx_pause;
|
||||
int err;
|
||||
|
||||
fman_mac = mac_dev->fman_mac;
|
||||
memac_adjust_link(fman_mac, phy_dev->speed);
|
||||
mac_dev->update_speed(mac_dev, phy_dev->speed);
|
||||
|
||||
fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
|
||||
err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause);
|
||||
if (err < 0)
|
||||
dev_err(mac_dev->dev, "fman_set_mac_active_pause() = %d\n",
|
||||
err);
|
||||
}
|
||||
|
||||
static int memac_set_tx_pause_frames(struct fman_mac *memac, u8 priority,
|
||||
u16 pause_time, u16 thresh_time)
|
||||
{
|
||||
struct memac_regs __iomem *regs = memac->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(memac->memac_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = ioread32be(®s->tx_fifo_sections);
|
||||
|
||||
GET_TX_EMPTY_DEFAULT_VALUE(tmp);
|
||||
@@ -834,9 +607,6 @@ static int memac_accept_rx_pause_frames(struct fman_mac *memac, bool en)
|
||||
struct memac_regs __iomem *regs = memac->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(memac->memac_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
if (en)
|
||||
tmp &= ~CMD_CFG_PAUSE_IGNORE;
|
||||
@@ -848,12 +618,175 @@ static int memac_accept_rx_pause_frames(struct fman_mac *memac, bool en)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void memac_validate(struct phylink_config *config,
|
||||
unsigned long *supported,
|
||||
struct phylink_link_state *state)
|
||||
{
|
||||
struct fman_mac *memac = fman_config_to_mac(config)->fman_mac;
|
||||
unsigned long caps = config->mac_capabilities;
|
||||
|
||||
if (phy_interface_mode_is_rgmii(state->interface) &&
|
||||
memac->rgmii_no_half_duplex)
|
||||
caps &= ~(MAC_10HD | MAC_100HD);
|
||||
|
||||
phylink_validate_mask_caps(supported, state, caps);
|
||||
}
|
||||
|
||||
/**
|
||||
* memac_if_mode() - Convert an interface mode into an IF_MODE config
|
||||
* @interface: A phy interface mode
|
||||
*
|
||||
* Return: A configuration word, suitable for programming into the lower bits
|
||||
* of %IF_MODE.
|
||||
*/
|
||||
static u32 memac_if_mode(phy_interface_t interface)
|
||||
{
|
||||
switch (interface) {
|
||||
case PHY_INTERFACE_MODE_MII:
|
||||
return IF_MODE_MII;
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||
case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||
return IF_MODE_GMII | IF_MODE_RGMII;
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
||||
case PHY_INTERFACE_MODE_QSGMII:
|
||||
return IF_MODE_GMII;
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
return IF_MODE_10G;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct phylink_pcs *memac_select_pcs(struct phylink_config *config,
|
||||
phy_interface_t iface)
|
||||
{
|
||||
struct fman_mac *memac = fman_config_to_mac(config)->fman_mac;
|
||||
|
||||
switch (iface) {
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
||||
return memac->sgmii_pcs;
|
||||
case PHY_INTERFACE_MODE_QSGMII:
|
||||
return memac->qsgmii_pcs;
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
return memac->xfi_pcs;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int memac_prepare(struct phylink_config *config, unsigned int mode,
|
||||
phy_interface_t iface)
|
||||
{
|
||||
struct fman_mac *memac = fman_config_to_mac(config)->fman_mac;
|
||||
|
||||
switch (iface) {
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
||||
case PHY_INTERFACE_MODE_QSGMII:
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
return phy_set_mode_ext(memac->serdes, PHY_MODE_ETHERNET,
|
||||
iface);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void memac_mac_config(struct phylink_config *config, unsigned int mode,
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
struct mac_device *mac_dev = fman_config_to_mac(config);
|
||||
struct memac_regs __iomem *regs = mac_dev->fman_mac->regs;
|
||||
u32 tmp = ioread32be(®s->if_mode);
|
||||
|
||||
tmp &= ~(IF_MODE_MASK | IF_MODE_RGMII);
|
||||
tmp |= memac_if_mode(state->interface);
|
||||
if (phylink_autoneg_inband(mode))
|
||||
tmp |= IF_MODE_RGMII_AUTO;
|
||||
iowrite32be(tmp, ®s->if_mode);
|
||||
}
|
||||
|
||||
static void memac_link_up(struct phylink_config *config, struct phy_device *phy,
|
||||
unsigned int mode, phy_interface_t interface,
|
||||
int speed, int duplex, bool tx_pause, bool rx_pause)
|
||||
{
|
||||
struct mac_device *mac_dev = fman_config_to_mac(config);
|
||||
struct fman_mac *memac = mac_dev->fman_mac;
|
||||
struct memac_regs __iomem *regs = memac->regs;
|
||||
u32 tmp = memac_if_mode(interface);
|
||||
u16 pause_time = tx_pause ? FSL_FM_PAUSE_TIME_ENABLE :
|
||||
FSL_FM_PAUSE_TIME_DISABLE;
|
||||
|
||||
memac_set_tx_pause_frames(memac, 0, pause_time, 0);
|
||||
memac_accept_rx_pause_frames(memac, rx_pause);
|
||||
|
||||
if (duplex == DUPLEX_HALF)
|
||||
tmp |= IF_MODE_HD;
|
||||
|
||||
switch (speed) {
|
||||
case SPEED_1000:
|
||||
tmp |= IF_MODE_RGMII_1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
tmp |= IF_MODE_RGMII_100;
|
||||
break;
|
||||
case SPEED_10:
|
||||
tmp |= IF_MODE_RGMII_10;
|
||||
break;
|
||||
}
|
||||
iowrite32be(tmp, ®s->if_mode);
|
||||
|
||||
/* TODO: EEE? */
|
||||
|
||||
if (speed == SPEED_10000) {
|
||||
if (memac->fm_rev_info.major == 6 &&
|
||||
memac->fm_rev_info.minor == 4)
|
||||
tmp = TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G;
|
||||
else
|
||||
tmp = TX_FIFO_SECTIONS_TX_AVAIL_10G;
|
||||
tmp |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G;
|
||||
} else {
|
||||
tmp = TX_FIFO_SECTIONS_TX_AVAIL_1G |
|
||||
TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G;
|
||||
}
|
||||
iowrite32be(tmp, ®s->tx_fifo_sections);
|
||||
|
||||
mac_dev->update_speed(mac_dev, speed);
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN;
|
||||
iowrite32be(tmp, ®s->command_config);
|
||||
}
|
||||
|
||||
static void memac_link_down(struct phylink_config *config, unsigned int mode,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
struct fman_mac *memac = fman_config_to_mac(config)->fman_mac;
|
||||
struct memac_regs __iomem *regs = memac->regs;
|
||||
u32 tmp;
|
||||
|
||||
/* TODO: graceful */
|
||||
tmp = ioread32be(®s->command_config);
|
||||
tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN);
|
||||
iowrite32be(tmp, ®s->command_config);
|
||||
}
|
||||
|
||||
static const struct phylink_mac_ops memac_mac_ops = {
|
||||
.validate = memac_validate,
|
||||
.mac_select_pcs = memac_select_pcs,
|
||||
.mac_prepare = memac_prepare,
|
||||
.mac_config = memac_mac_config,
|
||||
.mac_link_up = memac_link_up,
|
||||
.mac_link_down = memac_link_down,
|
||||
};
|
||||
|
||||
static int memac_modify_mac_address(struct fman_mac *memac,
|
||||
const enet_addr_t *enet_addr)
|
||||
{
|
||||
if (!is_init_done(memac->memac_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
add_addr_in_paddr(memac->regs, (const u8 *)(*enet_addr), 0);
|
||||
|
||||
return 0;
|
||||
@@ -867,9 +800,6 @@ static int memac_add_hash_mac_address(struct fman_mac *memac,
|
||||
u32 hash;
|
||||
u64 addr;
|
||||
|
||||
if (!is_init_done(memac->memac_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
addr = ENET_ADDR_TO_UINT64(*eth_addr);
|
||||
|
||||
if (!(addr & GROUP_ADDRESS)) {
|
||||
@@ -898,9 +828,6 @@ static int memac_set_allmulti(struct fman_mac *memac, bool enable)
|
||||
u32 entry;
|
||||
struct memac_regs __iomem *regs = memac->regs;
|
||||
|
||||
if (!is_init_done(memac->memac_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
if (enable) {
|
||||
for (entry = 0; entry < HASH_TABLE_SIZE; entry++)
|
||||
iowrite32be(entry | HASH_CTRL_MCAST_EN,
|
||||
@@ -930,9 +857,6 @@ static int memac_del_hash_mac_address(struct fman_mac *memac,
|
||||
u32 hash;
|
||||
u64 addr;
|
||||
|
||||
if (!is_init_done(memac->memac_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
addr = ENET_ADDR_TO_UINT64(*eth_addr);
|
||||
|
||||
hash = get_mac_addr_hash_code(addr) & HASH_CTRL_ADDR_MASK;
|
||||
@@ -960,9 +884,6 @@ static int memac_set_exception(struct fman_mac *memac,
|
||||
{
|
||||
u32 bit_mask = 0;
|
||||
|
||||
if (!is_init_done(memac->memac_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
bit_mask = get_exception_flag(exception);
|
||||
if (bit_mask) {
|
||||
if (enable)
|
||||
@@ -981,25 +902,16 @@ static int memac_set_exception(struct fman_mac *memac,
|
||||
static int memac_init(struct fman_mac *memac)
|
||||
{
|
||||
struct memac_cfg *memac_drv_param;
|
||||
u8 i;
|
||||
enet_addr_t eth_addr;
|
||||
bool slow_10g_if = false;
|
||||
struct fixed_phy_status *fixed_link = NULL;
|
||||
int err;
|
||||
u32 reg32 = 0;
|
||||
|
||||
if (is_init_done(memac->memac_drv_param))
|
||||
return -EINVAL;
|
||||
|
||||
err = check_init_parameters(memac);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memac_drv_param = memac->memac_drv_param;
|
||||
|
||||
if (memac->fm_rev_info.major == 6 && memac->fm_rev_info.minor == 4)
|
||||
slow_10g_if = true;
|
||||
|
||||
/* First, reset the MAC if desired. */
|
||||
if (memac_drv_param->reset_on_init) {
|
||||
err = reset(memac->regs);
|
||||
@@ -1015,10 +927,7 @@ static int memac_init(struct fman_mac *memac)
|
||||
add_addr_in_paddr(memac->regs, (const u8 *)eth_addr, 0);
|
||||
}
|
||||
|
||||
fixed_link = memac_drv_param->fixed_link;
|
||||
|
||||
init(memac->regs, memac->memac_drv_param, memac->phy_if,
|
||||
memac->max_speed, slow_10g_if, memac->exceptions);
|
||||
init(memac->regs, memac->memac_drv_param, memac->exceptions);
|
||||
|
||||
/* FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 errata workaround
|
||||
* Exists only in FMan 6.0 and 6.3.
|
||||
@@ -1034,33 +943,6 @@ static int memac_init(struct fman_mac *memac)
|
||||
iowrite32be(reg32, &memac->regs->command_config);
|
||||
}
|
||||
|
||||
if (memac->phy_if == PHY_INTERFACE_MODE_SGMII) {
|
||||
/* Configure internal SGMII PHY */
|
||||
if (memac->basex_if)
|
||||
setup_sgmii_internal_phy_base_x(memac);
|
||||
else
|
||||
setup_sgmii_internal_phy(memac, fixed_link);
|
||||
} else if (memac->phy_if == PHY_INTERFACE_MODE_QSGMII) {
|
||||
/* Configure 4 internal SGMII PHYs */
|
||||
for (i = 0; i < 4; i++) {
|
||||
u8 qsmgii_phy_addr, phy_addr;
|
||||
/* QSGMII PHY address occupies 3 upper bits of 5-bit
|
||||
* phy_address; the lower 2 bits are used to extend
|
||||
* register address space and access each one of 4
|
||||
* ports inside QSGMII.
|
||||
*/
|
||||
phy_addr = memac->pcsphy->mdio.addr;
|
||||
qsmgii_phy_addr = (u8)((phy_addr << 2) | i);
|
||||
memac->pcsphy->mdio.addr = qsmgii_phy_addr;
|
||||
if (memac->basex_if)
|
||||
setup_sgmii_internal_phy_base_x(memac);
|
||||
else
|
||||
setup_sgmii_internal_phy(memac, fixed_link);
|
||||
|
||||
memac->pcsphy->mdio.addr = phy_addr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Max Frame Length */
|
||||
err = fman_set_mac_max_frame(memac->fm, memac->mac_id,
|
||||
memac_drv_param->max_frame_length);
|
||||
@@ -1089,19 +971,28 @@ static int memac_init(struct fman_mac *memac)
|
||||
fman_register_intr(memac->fm, FMAN_MOD_MAC, memac->mac_id,
|
||||
FMAN_INTR_TYPE_NORMAL, memac_exception, memac);
|
||||
|
||||
kfree(memac_drv_param);
|
||||
memac->memac_drv_param = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pcs_put(struct phylink_pcs *pcs)
|
||||
{
|
||||
struct mdio_device *mdiodev;
|
||||
|
||||
if (IS_ERR_OR_NULL(pcs))
|
||||
return;
|
||||
|
||||
mdiodev = lynx_get_mdio_device(pcs);
|
||||
lynx_pcs_destroy(pcs);
|
||||
mdio_device_free(mdiodev);
|
||||
}
|
||||
|
||||
static int memac_free(struct fman_mac *memac)
|
||||
{
|
||||
free_init_resources(memac);
|
||||
|
||||
if (memac->pcsphy)
|
||||
put_device(&memac->pcsphy->mdio.dev);
|
||||
|
||||
pcs_put(memac->sgmii_pcs);
|
||||
pcs_put(memac->qsgmii_pcs);
|
||||
pcs_put(memac->xfi_pcs);
|
||||
kfree(memac->memac_drv_param);
|
||||
kfree(memac);
|
||||
|
||||
@@ -1134,8 +1025,6 @@ static struct fman_mac *memac_config(struct mac_device *mac_dev,
|
||||
memac->addr = ENET_ADDR_TO_UINT64(mac_dev->addr);
|
||||
|
||||
memac->regs = mac_dev->vaddr;
|
||||
memac->max_speed = params->max_speed;
|
||||
memac->phy_if = mac_dev->phy_if;
|
||||
memac->mac_id = params->mac_id;
|
||||
memac->exceptions = (MEMAC_IMASK_TSECC_ER | MEMAC_IMASK_TECC_ER |
|
||||
MEMAC_IMASK_RECC_ER | MEMAC_IMASK_MGI);
|
||||
@@ -1143,7 +1032,6 @@ static struct fman_mac *memac_config(struct mac_device *mac_dev,
|
||||
memac->event_cb = params->event_cb;
|
||||
memac->dev_id = mac_dev;
|
||||
memac->fm = params->fm;
|
||||
memac->basex_if = params->basex_if;
|
||||
|
||||
/* Save FMan revision */
|
||||
fman_get_revision(memac->fm, &memac->fm_rev_info);
|
||||
@@ -1151,101 +1039,221 @@ static struct fman_mac *memac_config(struct mac_device *mac_dev,
|
||||
return memac;
|
||||
}
|
||||
|
||||
static struct phylink_pcs *memac_pcs_create(struct device_node *mac_node,
|
||||
int index)
|
||||
{
|
||||
struct device_node *node;
|
||||
struct mdio_device *mdiodev = NULL;
|
||||
struct phylink_pcs *pcs;
|
||||
|
||||
node = of_parse_phandle(mac_node, "pcsphy-handle", index);
|
||||
if (node && of_device_is_available(node))
|
||||
mdiodev = of_mdio_find_device(node);
|
||||
of_node_put(node);
|
||||
|
||||
if (!mdiodev)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
pcs = lynx_pcs_create(mdiodev);
|
||||
return pcs;
|
||||
}
|
||||
|
||||
static bool memac_supports(struct mac_device *mac_dev, phy_interface_t iface)
|
||||
{
|
||||
/* If there's no serdes device, assume that it's been configured for
|
||||
* whatever the default interface mode is.
|
||||
*/
|
||||
if (!mac_dev->fman_mac->serdes)
|
||||
return mac_dev->phy_if == iface;
|
||||
/* Otherwise, ask the serdes */
|
||||
return !phy_validate(mac_dev->fman_mac->serdes, PHY_MODE_ETHERNET,
|
||||
iface, NULL);
|
||||
}
|
||||
|
||||
int memac_initialization(struct mac_device *mac_dev,
|
||||
struct device_node *mac_node,
|
||||
struct fman_mac_params *params)
|
||||
{
|
||||
int err;
|
||||
struct device_node *phy_node;
|
||||
struct fixed_phy_status *fixed_link;
|
||||
struct device_node *fixed;
|
||||
struct phylink_pcs *pcs;
|
||||
struct fman_mac *memac;
|
||||
unsigned long capabilities;
|
||||
unsigned long *supported;
|
||||
|
||||
mac_dev->phylink_ops = &memac_mac_ops;
|
||||
mac_dev->set_promisc = memac_set_promiscuous;
|
||||
mac_dev->change_addr = memac_modify_mac_address;
|
||||
mac_dev->add_hash_mac_addr = memac_add_hash_mac_address;
|
||||
mac_dev->remove_hash_mac_addr = memac_del_hash_mac_address;
|
||||
mac_dev->set_tx_pause = memac_set_tx_pause_frames;
|
||||
mac_dev->set_rx_pause = memac_accept_rx_pause_frames;
|
||||
mac_dev->set_exception = memac_set_exception;
|
||||
mac_dev->set_allmulti = memac_set_allmulti;
|
||||
mac_dev->set_tstamp = memac_set_tstamp;
|
||||
mac_dev->set_multi = fman_set_multi;
|
||||
mac_dev->adjust_link = adjust_link_memac;
|
||||
mac_dev->enable = memac_enable;
|
||||
mac_dev->disable = memac_disable;
|
||||
|
||||
if (params->max_speed == SPEED_10000)
|
||||
mac_dev->phy_if = PHY_INTERFACE_MODE_XGMII;
|
||||
|
||||
mac_dev->fman_mac = memac_config(mac_dev, params);
|
||||
if (!mac_dev->fman_mac) {
|
||||
err = -EINVAL;
|
||||
goto _return;
|
||||
}
|
||||
if (!mac_dev->fman_mac)
|
||||
return -EINVAL;
|
||||
|
||||
memac = mac_dev->fman_mac;
|
||||
memac->memac_drv_param->max_frame_length = fman_get_max_frm();
|
||||
memac->memac_drv_param->reset_on_init = true;
|
||||
if (memac->phy_if == PHY_INTERFACE_MODE_SGMII ||
|
||||
memac->phy_if == PHY_INTERFACE_MODE_QSGMII) {
|
||||
phy_node = of_parse_phandle(mac_node, "pcsphy-handle", 0);
|
||||
if (!phy_node) {
|
||||
pr_err("PCS PHY node is not available\n");
|
||||
err = -EINVAL;
|
||||
goto _return_fm_mac_free;
|
||||
}
|
||||
|
||||
memac->pcsphy = of_phy_find_device(phy_node);
|
||||
if (!memac->pcsphy) {
|
||||
pr_err("of_phy_find_device (PCS PHY) failed\n");
|
||||
err = -EINVAL;
|
||||
err = of_property_match_string(mac_node, "pcs-handle-names", "xfi");
|
||||
if (err >= 0) {
|
||||
memac->xfi_pcs = memac_pcs_create(mac_node, err);
|
||||
if (IS_ERR(memac->xfi_pcs)) {
|
||||
err = PTR_ERR(memac->xfi_pcs);
|
||||
dev_err_probe(mac_dev->dev, err, "missing xfi pcs\n");
|
||||
goto _return_fm_mac_free;
|
||||
}
|
||||
} else if (err != -EINVAL && err != -ENODATA) {
|
||||
goto _return_fm_mac_free;
|
||||
}
|
||||
|
||||
if (!mac_dev->phy_node && of_phy_is_fixed_link(mac_node)) {
|
||||
struct phy_device *phy;
|
||||
|
||||
err = of_phy_register_fixed_link(mac_node);
|
||||
if (err)
|
||||
goto _return_fm_mac_free;
|
||||
|
||||
fixed_link = kzalloc(sizeof(*fixed_link), GFP_KERNEL);
|
||||
if (!fixed_link) {
|
||||
err = -ENOMEM;
|
||||
err = of_property_match_string(mac_node, "pcs-handle-names", "qsgmii");
|
||||
if (err >= 0) {
|
||||
memac->qsgmii_pcs = memac_pcs_create(mac_node, err);
|
||||
if (IS_ERR(memac->qsgmii_pcs)) {
|
||||
err = PTR_ERR(memac->qsgmii_pcs);
|
||||
dev_err_probe(mac_dev->dev, err,
|
||||
"missing qsgmii pcs\n");
|
||||
goto _return_fm_mac_free;
|
||||
}
|
||||
|
||||
mac_dev->phy_node = of_node_get(mac_node);
|
||||
phy = of_phy_find_device(mac_dev->phy_node);
|
||||
if (!phy) {
|
||||
err = -EINVAL;
|
||||
of_node_put(mac_dev->phy_node);
|
||||
goto _return_fixed_link_free;
|
||||
}
|
||||
|
||||
fixed_link->link = phy->link;
|
||||
fixed_link->speed = phy->speed;
|
||||
fixed_link->duplex = phy->duplex;
|
||||
fixed_link->pause = phy->pause;
|
||||
fixed_link->asym_pause = phy->asym_pause;
|
||||
|
||||
put_device(&phy->mdio.dev);
|
||||
memac->memac_drv_param->fixed_link = fixed_link;
|
||||
} else if (err != -EINVAL && err != -ENODATA) {
|
||||
goto _return_fm_mac_free;
|
||||
}
|
||||
|
||||
/* For compatibility, if pcs-handle-names is missing, we assume this
|
||||
* phy is the first one in pcsphy-handle
|
||||
*/
|
||||
err = of_property_match_string(mac_node, "pcs-handle-names", "sgmii");
|
||||
if (err == -EINVAL || err == -ENODATA)
|
||||
pcs = memac_pcs_create(mac_node, 0);
|
||||
else if (err < 0)
|
||||
goto _return_fm_mac_free;
|
||||
else
|
||||
pcs = memac_pcs_create(mac_node, err);
|
||||
|
||||
if (IS_ERR(pcs)) {
|
||||
err = PTR_ERR(pcs);
|
||||
dev_err_probe(mac_dev->dev, err, "missing pcs\n");
|
||||
goto _return_fm_mac_free;
|
||||
}
|
||||
|
||||
/* If err is set here, it means that pcs-handle-names was missing above
|
||||
* (and therefore that xfi_pcs cannot be set). If we are defaulting to
|
||||
* XGMII, assume this is for XFI. Otherwise, assume it is for SGMII.
|
||||
*/
|
||||
if (err && mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
|
||||
memac->xfi_pcs = pcs;
|
||||
else
|
||||
memac->sgmii_pcs = pcs;
|
||||
|
||||
memac->serdes = devm_of_phy_get(mac_dev->dev, mac_node, "serdes");
|
||||
err = PTR_ERR(memac->serdes);
|
||||
if (err == -ENODEV || err == -ENOSYS) {
|
||||
dev_dbg(mac_dev->dev, "could not get (optional) serdes\n");
|
||||
memac->serdes = NULL;
|
||||
} else if (IS_ERR(memac->serdes)) {
|
||||
dev_err_probe(mac_dev->dev, err, "could not get serdes\n");
|
||||
goto _return_fm_mac_free;
|
||||
}
|
||||
|
||||
/* The internal connection to the serdes is XGMII, but this isn't
|
||||
* really correct for the phy mode (which is the external connection).
|
||||
* However, this is how all older device trees say that they want
|
||||
* 10GBASE-R (aka XFI), so just convert it for them.
|
||||
*/
|
||||
if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
|
||||
mac_dev->phy_if = PHY_INTERFACE_MODE_10GBASER;
|
||||
|
||||
/* TODO: The following interface modes are supported by (some) hardware
|
||||
* but not by this driver:
|
||||
* - 1000BASE-KX
|
||||
* - 10GBASE-KR
|
||||
* - XAUI/HiGig
|
||||
*/
|
||||
supported = mac_dev->phylink_config.supported_interfaces;
|
||||
|
||||
/* Note that half duplex is only supported on 10/100M interfaces. */
|
||||
|
||||
if (memac->sgmii_pcs &&
|
||||
(memac_supports(mac_dev, PHY_INTERFACE_MODE_SGMII) ||
|
||||
memac_supports(mac_dev, PHY_INTERFACE_MODE_1000BASEX))) {
|
||||
__set_bit(PHY_INTERFACE_MODE_SGMII, supported);
|
||||
__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
|
||||
}
|
||||
|
||||
if (memac->sgmii_pcs &&
|
||||
memac_supports(mac_dev, PHY_INTERFACE_MODE_2500BASEX))
|
||||
__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
|
||||
|
||||
if (memac->qsgmii_pcs &&
|
||||
memac_supports(mac_dev, PHY_INTERFACE_MODE_QSGMII))
|
||||
__set_bit(PHY_INTERFACE_MODE_QSGMII, supported);
|
||||
else if (mac_dev->phy_if == PHY_INTERFACE_MODE_QSGMII)
|
||||
dev_warn(mac_dev->dev, "no QSGMII pcs specified\n");
|
||||
|
||||
if (memac->xfi_pcs &&
|
||||
memac_supports(mac_dev, PHY_INTERFACE_MODE_10GBASER)) {
|
||||
__set_bit(PHY_INTERFACE_MODE_10GBASER, supported);
|
||||
} else {
|
||||
/* From what I can tell, no 10g macs support RGMII. */
|
||||
phy_interface_set_rgmii(supported);
|
||||
__set_bit(PHY_INTERFACE_MODE_MII, supported);
|
||||
}
|
||||
|
||||
capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE | MAC_10 | MAC_100;
|
||||
capabilities |= MAC_1000FD | MAC_2500FD | MAC_10000FD;
|
||||
|
||||
/* These SoCs don't support half duplex at all; there's no different
|
||||
* FMan version or compatible, so we just have to check the machine
|
||||
* compatible instead
|
||||
*/
|
||||
if (of_machine_is_compatible("fsl,ls1043a") ||
|
||||
of_machine_is_compatible("fsl,ls1046a") ||
|
||||
of_machine_is_compatible("fsl,B4QDS"))
|
||||
capabilities &= ~(MAC_10HD | MAC_100HD);
|
||||
|
||||
mac_dev->phylink_config.mac_capabilities = capabilities;
|
||||
|
||||
/* The T2080 and T4240 don't support half duplex RGMII. There is no
|
||||
* other way to identify these SoCs, so just use the machine
|
||||
* compatible.
|
||||
*/
|
||||
if (of_machine_is_compatible("fsl,T2080QDS") ||
|
||||
of_machine_is_compatible("fsl,T2080RDB") ||
|
||||
of_machine_is_compatible("fsl,T2081QDS") ||
|
||||
of_machine_is_compatible("fsl,T4240QDS") ||
|
||||
of_machine_is_compatible("fsl,T4240RDB"))
|
||||
memac->rgmii_no_half_duplex = true;
|
||||
|
||||
/* Most boards should use MLO_AN_INBAND, but existing boards don't have
|
||||
* a managed property. Default to MLO_AN_INBAND if nothing else is
|
||||
* specified. We need to be careful and not enable this if we have a
|
||||
* fixed link or if we are using MII or RGMII, since those
|
||||
* configurations modes don't use in-band autonegotiation.
|
||||
*/
|
||||
fixed = of_get_child_by_name(mac_node, "fixed-link");
|
||||
if (!fixed && !of_property_read_bool(mac_node, "fixed-link") &&
|
||||
!of_property_read_bool(mac_node, "managed") &&
|
||||
mac_dev->phy_if != PHY_INTERFACE_MODE_MII &&
|
||||
!phy_interface_mode_is_rgmii(mac_dev->phy_if))
|
||||
mac_dev->phylink_config.ovr_an_inband = true;
|
||||
of_node_put(fixed);
|
||||
|
||||
err = memac_init(mac_dev->fman_mac);
|
||||
if (err < 0)
|
||||
goto _return_fixed_link_free;
|
||||
goto _return_fm_mac_free;
|
||||
|
||||
dev_info(mac_dev->dev, "FMan MEMAC\n");
|
||||
|
||||
goto _return;
|
||||
return 0;
|
||||
|
||||
_return_fixed_link_free:
|
||||
kfree(fixed_link);
|
||||
_return_fm_mac_free:
|
||||
memac_free(mac_dev->fman_mac);
|
||||
_return:
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/bitrev.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
/* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */
|
||||
#define TGEC_TX_IPG_LENGTH_MASK 0x000003ff
|
||||
@@ -243,10 +244,6 @@ static int init(struct tgec_regs __iomem *regs, struct tgec_cfg *cfg,
|
||||
|
||||
static int check_init_parameters(struct fman_mac *tgec)
|
||||
{
|
||||
if (tgec->max_speed < SPEED_10000) {
|
||||
pr_err("10G MAC driver only support 10G speed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!tgec->exception_cb) {
|
||||
pr_err("uninitialized exception_cb\n");
|
||||
return -EINVAL;
|
||||
@@ -384,40 +381,13 @@ static void free_init_resources(struct fman_mac *tgec)
|
||||
tgec->unicast_addr_hash = NULL;
|
||||
}
|
||||
|
||||
static bool is_init_done(struct tgec_cfg *cfg)
|
||||
{
|
||||
/* Checks if tGEC driver parameters were initialized */
|
||||
if (!cfg)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int tgec_enable(struct fman_mac *tgec)
|
||||
{
|
||||
struct tgec_regs __iomem *regs = tgec->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(tgec->cfg))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN;
|
||||
iowrite32be(tmp, ®s->command_config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tgec_disable(struct fman_mac *tgec)
|
||||
{
|
||||
struct tgec_regs __iomem *regs = tgec->regs;
|
||||
u32 tmp;
|
||||
|
||||
WARN_ON_ONCE(!is_init_done(tgec->cfg));
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN);
|
||||
iowrite32be(tmp, ®s->command_config);
|
||||
}
|
||||
|
||||
static int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val)
|
||||
@@ -425,9 +395,6 @@ static int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val)
|
||||
struct tgec_regs __iomem *regs = tgec->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(tgec->cfg))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
if (new_val)
|
||||
tmp |= CMD_CFG_PROMIS_EN;
|
||||
@@ -444,9 +411,6 @@ static int tgec_set_tx_pause_frames(struct fman_mac *tgec,
|
||||
{
|
||||
struct tgec_regs __iomem *regs = tgec->regs;
|
||||
|
||||
if (!is_init_done(tgec->cfg))
|
||||
return -EINVAL;
|
||||
|
||||
iowrite32be((u32)pause_time, ®s->pause_quant);
|
||||
|
||||
return 0;
|
||||
@@ -457,9 +421,6 @@ static int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en)
|
||||
struct tgec_regs __iomem *regs = tgec->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(tgec->cfg))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
if (!en)
|
||||
tmp |= CMD_CFG_PAUSE_IGNORE;
|
||||
@@ -470,12 +431,53 @@ static int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tgec_mac_config(struct phylink_config *config, unsigned int mode,
|
||||
const struct phylink_link_state *state)
|
||||
{
|
||||
}
|
||||
|
||||
static void tgec_link_up(struct phylink_config *config, struct phy_device *phy,
|
||||
unsigned int mode, phy_interface_t interface,
|
||||
int speed, int duplex, bool tx_pause, bool rx_pause)
|
||||
{
|
||||
struct mac_device *mac_dev = fman_config_to_mac(config);
|
||||
struct fman_mac *tgec = mac_dev->fman_mac;
|
||||
struct tgec_regs __iomem *regs = tgec->regs;
|
||||
u16 pause_time = tx_pause ? FSL_FM_PAUSE_TIME_ENABLE :
|
||||
FSL_FM_PAUSE_TIME_DISABLE;
|
||||
u32 tmp;
|
||||
|
||||
tgec_set_tx_pause_frames(tgec, 0, pause_time, 0);
|
||||
tgec_accept_rx_pause_frames(tgec, rx_pause);
|
||||
mac_dev->update_speed(mac_dev, speed);
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN;
|
||||
iowrite32be(tmp, ®s->command_config);
|
||||
}
|
||||
|
||||
static void tgec_link_down(struct phylink_config *config, unsigned int mode,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
struct fman_mac *tgec = fman_config_to_mac(config)->fman_mac;
|
||||
struct tgec_regs __iomem *regs = tgec->regs;
|
||||
u32 tmp;
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN);
|
||||
iowrite32be(tmp, ®s->command_config);
|
||||
}
|
||||
|
||||
static const struct phylink_mac_ops tgec_mac_ops = {
|
||||
.validate = phylink_generic_validate,
|
||||
.mac_config = tgec_mac_config,
|
||||
.mac_link_up = tgec_link_up,
|
||||
.mac_link_down = tgec_link_down,
|
||||
};
|
||||
|
||||
static int tgec_modify_mac_address(struct fman_mac *tgec,
|
||||
const enet_addr_t *p_enet_addr)
|
||||
{
|
||||
if (!is_init_done(tgec->cfg))
|
||||
return -EINVAL;
|
||||
|
||||
tgec->addr = ENET_ADDR_TO_UINT64(*p_enet_addr);
|
||||
set_mac_address(tgec->regs, (const u8 *)(*p_enet_addr));
|
||||
|
||||
@@ -490,9 +492,6 @@ static int tgec_add_hash_mac_address(struct fman_mac *tgec,
|
||||
u32 crc = 0xFFFFFFFF, hash;
|
||||
u64 addr;
|
||||
|
||||
if (!is_init_done(tgec->cfg))
|
||||
return -EINVAL;
|
||||
|
||||
addr = ENET_ADDR_TO_UINT64(*eth_addr);
|
||||
|
||||
if (!(addr & GROUP_ADDRESS)) {
|
||||
@@ -525,9 +524,6 @@ static int tgec_set_allmulti(struct fman_mac *tgec, bool enable)
|
||||
u32 entry;
|
||||
struct tgec_regs __iomem *regs = tgec->regs;
|
||||
|
||||
if (!is_init_done(tgec->cfg))
|
||||
return -EINVAL;
|
||||
|
||||
if (enable) {
|
||||
for (entry = 0; entry < TGEC_HASH_TABLE_SIZE; entry++)
|
||||
iowrite32be(entry | TGEC_HASH_MCAST_EN,
|
||||
@@ -548,9 +544,6 @@ static int tgec_set_tstamp(struct fman_mac *tgec, bool enable)
|
||||
struct tgec_regs __iomem *regs = tgec->regs;
|
||||
u32 tmp;
|
||||
|
||||
if (!is_init_done(tgec->cfg))
|
||||
return -EINVAL;
|
||||
|
||||
tmp = ioread32be(®s->command_config);
|
||||
|
||||
if (enable)
|
||||
@@ -572,9 +565,6 @@ static int tgec_del_hash_mac_address(struct fman_mac *tgec,
|
||||
u32 crc = 0xFFFFFFFF, hash;
|
||||
u64 addr;
|
||||
|
||||
if (!is_init_done(tgec->cfg))
|
||||
return -EINVAL;
|
||||
|
||||
addr = ((*(u64 *)eth_addr) >> 16);
|
||||
|
||||
/* CRC calculation */
|
||||
@@ -601,22 +591,12 @@ static int tgec_del_hash_mac_address(struct fman_mac *tgec,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tgec_adjust_link(struct mac_device *mac_dev)
|
||||
{
|
||||
struct phy_device *phy_dev = mac_dev->phy_dev;
|
||||
|
||||
mac_dev->update_speed(mac_dev, phy_dev->speed);
|
||||
}
|
||||
|
||||
static int tgec_set_exception(struct fman_mac *tgec,
|
||||
enum fman_mac_exceptions exception, bool enable)
|
||||
{
|
||||
struct tgec_regs __iomem *regs = tgec->regs;
|
||||
u32 bit_mask = 0;
|
||||
|
||||
if (!is_init_done(tgec->cfg))
|
||||
return -EINVAL;
|
||||
|
||||
bit_mask = get_exception_flag(exception);
|
||||
if (bit_mask) {
|
||||
if (enable)
|
||||
@@ -641,9 +621,6 @@ static int tgec_init(struct fman_mac *tgec)
|
||||
enet_addr_t eth_addr;
|
||||
int err;
|
||||
|
||||
if (is_init_done(tgec->cfg))
|
||||
return -EINVAL;
|
||||
|
||||
if (DEFAULT_RESET_ON_INIT &&
|
||||
(fman_reset_mac(tgec->fm, tgec->mac_id) != 0)) {
|
||||
pr_err("Can't reset MAC!\n");
|
||||
@@ -753,7 +730,6 @@ static struct fman_mac *tgec_config(struct mac_device *mac_dev,
|
||||
|
||||
tgec->regs = mac_dev->vaddr;
|
||||
tgec->addr = ENET_ADDR_TO_UINT64(mac_dev->addr);
|
||||
tgec->max_speed = params->max_speed;
|
||||
tgec->mac_id = params->mac_id;
|
||||
tgec->exceptions = (TGEC_IMASK_MDIO_SCAN_EVENT |
|
||||
TGEC_IMASK_REM_FAULT |
|
||||
@@ -788,17 +764,15 @@ int tgec_initialization(struct mac_device *mac_dev,
|
||||
int err;
|
||||
struct fman_mac *tgec;
|
||||
|
||||
mac_dev->phylink_ops = &tgec_mac_ops;
|
||||
mac_dev->set_promisc = tgec_set_promiscuous;
|
||||
mac_dev->change_addr = tgec_modify_mac_address;
|
||||
mac_dev->add_hash_mac_addr = tgec_add_hash_mac_address;
|
||||
mac_dev->remove_hash_mac_addr = tgec_del_hash_mac_address;
|
||||
mac_dev->set_tx_pause = tgec_set_tx_pause_frames;
|
||||
mac_dev->set_rx_pause = tgec_accept_rx_pause_frames;
|
||||
mac_dev->set_exception = tgec_set_exception;
|
||||
mac_dev->set_allmulti = tgec_set_allmulti;
|
||||
mac_dev->set_tstamp = tgec_set_tstamp;
|
||||
mac_dev->set_multi = fman_set_multi;
|
||||
mac_dev->adjust_link = tgec_adjust_link;
|
||||
mac_dev->enable = tgec_enable;
|
||||
mac_dev->disable = tgec_disable;
|
||||
|
||||
@@ -808,6 +782,19 @@ int tgec_initialization(struct mac_device *mac_dev,
|
||||
goto _return;
|
||||
}
|
||||
|
||||
/* The internal connection to the serdes is XGMII, but this isn't
|
||||
* really correct for the phy mode (which is the external connection).
|
||||
* However, this is how all older device trees say that they want
|
||||
* XAUI, so just convert it for them.
|
||||
*/
|
||||
if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
|
||||
mac_dev->phy_if = PHY_INTERFACE_MODE_XAUI;
|
||||
|
||||
__set_bit(PHY_INTERFACE_MODE_XAUI,
|
||||
mac_dev->phylink_config.supported_interfaces);
|
||||
mac_dev->phylink_config.mac_capabilities =
|
||||
MAC_SYM_PAUSE | MAC_ASYM_PAUSE | MAC_10000FD;
|
||||
|
||||
tgec = mac_dev->fman_mac;
|
||||
tgec->cfg->max_frame_length = fman_get_max_frm();
|
||||
err = tgec_init(tgec);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/phy.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/phy_fixed.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/libfdt_env.h>
|
||||
|
||||
@@ -93,130 +94,8 @@ int fman_set_multi(struct net_device *net_dev, struct mac_device *mac_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fman_set_mac_active_pause
|
||||
* @mac_dev: A pointer to the MAC device
|
||||
* @rx: Pause frame setting for RX
|
||||
* @tx: Pause frame setting for TX
|
||||
*
|
||||
* Set the MAC RX/TX PAUSE frames settings
|
||||
*
|
||||
* Avoid redundant calls to FMD, if the MAC driver already contains the desired
|
||||
* active PAUSE settings. Otherwise, the new active settings should be reflected
|
||||
* in FMan.
|
||||
*
|
||||
* Return: 0 on success; Error code otherwise.
|
||||
*/
|
||||
int fman_set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx)
|
||||
{
|
||||
struct fman_mac *fman_mac = mac_dev->fman_mac;
|
||||
int err = 0;
|
||||
|
||||
if (rx != mac_dev->rx_pause_active) {
|
||||
err = mac_dev->set_rx_pause(fman_mac, rx);
|
||||
if (likely(err == 0))
|
||||
mac_dev->rx_pause_active = rx;
|
||||
}
|
||||
|
||||
if (tx != mac_dev->tx_pause_active) {
|
||||
u16 pause_time = (tx ? FSL_FM_PAUSE_TIME_ENABLE :
|
||||
FSL_FM_PAUSE_TIME_DISABLE);
|
||||
|
||||
err = mac_dev->set_tx_pause(fman_mac, 0, pause_time, 0);
|
||||
|
||||
if (likely(err == 0))
|
||||
mac_dev->tx_pause_active = tx;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(fman_set_mac_active_pause);
|
||||
|
||||
/**
|
||||
* fman_get_pause_cfg
|
||||
* @mac_dev: A pointer to the MAC device
|
||||
* @rx_pause: Return value for RX setting
|
||||
* @tx_pause: Return value for TX setting
|
||||
*
|
||||
* Determine the MAC RX/TX PAUSE frames settings based on PHY
|
||||
* autonegotiation or values set by eththool.
|
||||
*
|
||||
* Return: Pointer to FMan device.
|
||||
*/
|
||||
void fman_get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause,
|
||||
bool *tx_pause)
|
||||
{
|
||||
struct phy_device *phy_dev = mac_dev->phy_dev;
|
||||
u16 lcl_adv, rmt_adv;
|
||||
u8 flowctrl;
|
||||
|
||||
*rx_pause = *tx_pause = false;
|
||||
|
||||
if (!phy_dev->duplex)
|
||||
return;
|
||||
|
||||
/* If PAUSE autonegotiation is disabled, the TX/RX PAUSE settings
|
||||
* are those set by ethtool.
|
||||
*/
|
||||
if (!mac_dev->autoneg_pause) {
|
||||
*rx_pause = mac_dev->rx_pause_req;
|
||||
*tx_pause = mac_dev->tx_pause_req;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Else if PAUSE autonegotiation is enabled, the TX/RX PAUSE
|
||||
* settings depend on the result of the link negotiation.
|
||||
*/
|
||||
|
||||
/* get local capabilities */
|
||||
lcl_adv = linkmode_adv_to_lcl_adv_t(phy_dev->advertising);
|
||||
|
||||
/* get link partner capabilities */
|
||||
rmt_adv = 0;
|
||||
if (phy_dev->pause)
|
||||
rmt_adv |= LPA_PAUSE_CAP;
|
||||
if (phy_dev->asym_pause)
|
||||
rmt_adv |= LPA_PAUSE_ASYM;
|
||||
|
||||
/* Calculate TX/RX settings based on local and peer advertised
|
||||
* symmetric/asymmetric PAUSE capabilities.
|
||||
*/
|
||||
flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
|
||||
if (flowctrl & FLOW_CTRL_RX)
|
||||
*rx_pause = true;
|
||||
if (flowctrl & FLOW_CTRL_TX)
|
||||
*tx_pause = true;
|
||||
}
|
||||
EXPORT_SYMBOL(fman_get_pause_cfg);
|
||||
|
||||
#define DTSEC_SUPPORTED \
|
||||
(SUPPORTED_10baseT_Half \
|
||||
| SUPPORTED_10baseT_Full \
|
||||
| SUPPORTED_100baseT_Half \
|
||||
| SUPPORTED_100baseT_Full \
|
||||
| SUPPORTED_Autoneg \
|
||||
| SUPPORTED_Pause \
|
||||
| SUPPORTED_Asym_Pause \
|
||||
| SUPPORTED_FIBRE \
|
||||
| SUPPORTED_MII)
|
||||
|
||||
static DEFINE_MUTEX(eth_lock);
|
||||
|
||||
static const u16 phy2speed[] = {
|
||||
[PHY_INTERFACE_MODE_MII] = SPEED_100,
|
||||
[PHY_INTERFACE_MODE_GMII] = SPEED_1000,
|
||||
[PHY_INTERFACE_MODE_SGMII] = SPEED_1000,
|
||||
[PHY_INTERFACE_MODE_TBI] = SPEED_1000,
|
||||
[PHY_INTERFACE_MODE_RMII] = SPEED_100,
|
||||
[PHY_INTERFACE_MODE_RGMII] = SPEED_1000,
|
||||
[PHY_INTERFACE_MODE_RGMII_ID] = SPEED_1000,
|
||||
[PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000,
|
||||
[PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000,
|
||||
[PHY_INTERFACE_MODE_RTBI] = SPEED_1000,
|
||||
[PHY_INTERFACE_MODE_QSGMII] = SPEED_1000,
|
||||
[PHY_INTERFACE_MODE_XGMII] = SPEED_10000
|
||||
};
|
||||
|
||||
static struct platform_device *dpaa_eth_add_device(int fman_id,
|
||||
struct mac_device *mac_dev)
|
||||
{
|
||||
@@ -263,8 +142,8 @@ static struct platform_device *dpaa_eth_add_device(int fman_id,
|
||||
}
|
||||
|
||||
static const struct of_device_id mac_match[] = {
|
||||
{ .compatible = "fsl,fman-dtsec", .data = dtsec_initialization },
|
||||
{ .compatible = "fsl,fman-xgec", .data = tgec_initialization },
|
||||
{ .compatible = "fsl,fman-dtsec", .data = dtsec_initialization },
|
||||
{ .compatible = "fsl,fman-xgec", .data = tgec_initialization },
|
||||
{ .compatible = "fsl,fman-memac", .data = memac_initialization },
|
||||
{}
|
||||
};
|
||||
@@ -296,6 +175,7 @@ static int mac_probe(struct platform_device *_of_dev)
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(_of_dev, mac_dev);
|
||||
|
||||
/* Save private information */
|
||||
mac_dev->priv = priv;
|
||||
@@ -424,57 +304,21 @@ static int mac_probe(struct platform_device *_of_dev)
|
||||
}
|
||||
mac_dev->phy_if = phy_if;
|
||||
|
||||
priv->speed = phy2speed[mac_dev->phy_if];
|
||||
params.max_speed = priv->speed;
|
||||
mac_dev->if_support = DTSEC_SUPPORTED;
|
||||
/* We don't support half-duplex in SGMII mode */
|
||||
if (mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII)
|
||||
mac_dev->if_support &= ~(SUPPORTED_10baseT_Half |
|
||||
SUPPORTED_100baseT_Half);
|
||||
|
||||
/* Gigabit support (no half-duplex) */
|
||||
if (params.max_speed == 1000)
|
||||
mac_dev->if_support |= SUPPORTED_1000baseT_Full;
|
||||
|
||||
/* The 10G interface only supports one mode */
|
||||
if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
|
||||
mac_dev->if_support = SUPPORTED_10000baseT_Full;
|
||||
|
||||
/* Get the rest of the PHY information */
|
||||
mac_dev->phy_node = of_parse_phandle(mac_node, "phy-handle", 0);
|
||||
|
||||
params.basex_if = false;
|
||||
params.mac_id = priv->cell_index;
|
||||
params.fm = (void *)priv->fman;
|
||||
params.exception_cb = mac_exception;
|
||||
params.event_cb = mac_exception;
|
||||
|
||||
err = init(mac_dev, mac_node, ¶ms);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "mac_dev->init() = %d\n", err);
|
||||
of_node_put(mac_dev->phy_node);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* pause frame autonegotiation enabled */
|
||||
mac_dev->autoneg_pause = true;
|
||||
|
||||
/* By intializing the values to false, force FMD to enable PAUSE frames
|
||||
* on RX and TX
|
||||
*/
|
||||
mac_dev->rx_pause_req = true;
|
||||
mac_dev->tx_pause_req = true;
|
||||
mac_dev->rx_pause_active = false;
|
||||
mac_dev->tx_pause_active = false;
|
||||
err = fman_set_mac_active_pause(mac_dev, true, true);
|
||||
if (err < 0)
|
||||
dev_err(dev, "fman_set_mac_active_pause() = %d\n", err);
|
||||
return err;
|
||||
|
||||
if (!is_zero_ether_addr(mac_dev->addr))
|
||||
dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr);
|
||||
|
||||
priv->eth_dev = dpaa_eth_add_device(fman_id, mac_dev);
|
||||
if (IS_ERR(priv->eth_dev)) {
|
||||
err = PTR_ERR(priv->eth_dev);
|
||||
dev_err(dev, "failed to add Ethernet platform device for MAC %d\n",
|
||||
priv->cell_index);
|
||||
priv->eth_dev = NULL;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "fman_port.h"
|
||||
@@ -24,32 +25,22 @@ struct mac_device {
|
||||
struct device *dev;
|
||||
u8 addr[ETH_ALEN];
|
||||
struct fman_port *port[2];
|
||||
u32 if_support;
|
||||
struct phy_device *phy_dev;
|
||||
struct phylink *phylink;
|
||||
struct phylink_config phylink_config;
|
||||
phy_interface_t phy_if;
|
||||
struct device_node *phy_node;
|
||||
struct net_device *net_dev;
|
||||
|
||||
bool autoneg_pause;
|
||||
bool rx_pause_req;
|
||||
bool tx_pause_req;
|
||||
bool rx_pause_active;
|
||||
bool tx_pause_active;
|
||||
bool promisc;
|
||||
bool allmulti;
|
||||
|
||||
const struct phylink_mac_ops *phylink_ops;
|
||||
int (*enable)(struct fman_mac *mac_dev);
|
||||
void (*disable)(struct fman_mac *mac_dev);
|
||||
void (*adjust_link)(struct mac_device *mac_dev);
|
||||
int (*set_promisc)(struct fman_mac *mac_dev, bool enable);
|
||||
int (*change_addr)(struct fman_mac *mac_dev, const enet_addr_t *enet_addr);
|
||||
int (*set_allmulti)(struct fman_mac *mac_dev, bool enable);
|
||||
int (*set_tstamp)(struct fman_mac *mac_dev, bool enable);
|
||||
int (*set_multi)(struct net_device *net_dev,
|
||||
struct mac_device *mac_dev);
|
||||
int (*set_rx_pause)(struct fman_mac *mac_dev, bool en);
|
||||
int (*set_tx_pause)(struct fman_mac *mac_dev, u8 priority,
|
||||
u16 pause_time, u16 thresh_time);
|
||||
int (*set_exception)(struct fman_mac *mac_dev,
|
||||
enum fman_mac_exceptions exception, bool enable);
|
||||
int (*add_hash_mac_addr)(struct fman_mac *mac_dev,
|
||||
@@ -63,6 +54,12 @@ struct mac_device {
|
||||
struct mac_priv_s *priv;
|
||||
};
|
||||
|
||||
static inline struct mac_device
|
||||
*fman_config_to_mac(struct phylink_config *config)
|
||||
{
|
||||
return container_of(config, struct mac_device, phylink_config);
|
||||
}
|
||||
|
||||
struct dpaa_eth_data {
|
||||
struct mac_device *mac_dev;
|
||||
int mac_hw_id;
|
||||
|
||||
@@ -561,6 +561,35 @@ unsigned long phylink_get_capabilities(phy_interface_t interface,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phylink_get_capabilities);
|
||||
|
||||
/**
|
||||
* phylink_validate_mask_caps() - Restrict link modes based on caps
|
||||
* @supported: ethtool bitmask for supported link modes.
|
||||
* @state: an (optional) pointer to a &struct phylink_link_state.
|
||||
* @mac_capabilities: bitmask of MAC capabilities
|
||||
*
|
||||
* Calculate the supported link modes based on @mac_capabilities, and restrict
|
||||
* @supported and @state based on that. Use this function if your capabiliies
|
||||
* aren't constant, such as if they vary depending on the interface.
|
||||
*/
|
||||
void phylink_validate_mask_caps(unsigned long *supported,
|
||||
struct phylink_link_state *state,
|
||||
unsigned long mac_capabilities)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
|
||||
unsigned long caps;
|
||||
|
||||
phylink_set_port_modes(mask);
|
||||
phylink_set(mask, Autoneg);
|
||||
caps = phylink_get_capabilities(state->interface, mac_capabilities,
|
||||
state->rate_matching);
|
||||
phylink_caps_to_linkmodes(mask, caps);
|
||||
|
||||
linkmode_and(supported, supported, mask);
|
||||
if (state)
|
||||
linkmode_and(state->advertising, state->advertising, mask);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phylink_validate_mask_caps);
|
||||
|
||||
/**
|
||||
* phylink_generic_validate() - generic validate() callback implementation
|
||||
* @config: a pointer to a &struct phylink_config.
|
||||
@@ -569,24 +598,12 @@ EXPORT_SYMBOL_GPL(phylink_get_capabilities);
|
||||
*
|
||||
* Generic implementation of the validate() callback that MAC drivers can
|
||||
* use when they pass the range of supported interfaces and MAC capabilities.
|
||||
* This makes use of phylink_get_linkmodes().
|
||||
*/
|
||||
void phylink_generic_validate(struct phylink_config *config,
|
||||
unsigned long *supported,
|
||||
struct phylink_link_state *state)
|
||||
{
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
|
||||
unsigned long caps;
|
||||
|
||||
phylink_set_port_modes(mask);
|
||||
phylink_set(mask, Autoneg);
|
||||
caps = phylink_get_capabilities(state->interface,
|
||||
config->mac_capabilities,
|
||||
state->rate_matching);
|
||||
phylink_caps_to_linkmodes(mask, caps);
|
||||
|
||||
linkmode_and(supported, supported, mask);
|
||||
linkmode_and(state->advertising, state->advertising, mask);
|
||||
phylink_validate_mask_caps(supported, state, config->mac_capabilities);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phylink_generic_validate);
|
||||
|
||||
|
||||
@@ -556,6 +556,9 @@ void phylink_caps_to_linkmodes(unsigned long *linkmodes, unsigned long caps);
|
||||
unsigned long phylink_get_capabilities(phy_interface_t interface,
|
||||
unsigned long mac_capabilities,
|
||||
int rate_matching);
|
||||
void phylink_validate_mask_caps(unsigned long *supported,
|
||||
struct phylink_link_state *state,
|
||||
unsigned long caps);
|
||||
void phylink_generic_validate(struct phylink_config *config,
|
||||
unsigned long *supported,
|
||||
struct phylink_link_state *state);
|
||||
|
||||
Reference in New Issue
Block a user