diff --git a/Documentation/devicetree/bindings/net/hisilicon,hisi-femac-mdio.yaml b/Documentation/devicetree/bindings/net/hisilicon,hisi-femac-mdio.yaml new file mode 100644 index 00000000000000..dea1bcc2738156 --- /dev/null +++ b/Documentation/devicetree/bindings/net/hisilicon,hisi-femac-mdio.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/hisilicon,hisi-femac-mdio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HiSilicon FEMAC MDIO bus + +maintainers: + - Yang Xiwen + +allOf: + - $ref: mdio.yaml# + +properties: + compatible: + const: hisilicon,hisi-femac-mdio + + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + mdio@10091100 { + compatible = "hisilicon,hisi-femac-mdio"; + reg = <0x10091100 0x20>; + #address-cells = <1>; + #size-cells = <0>; + + phy@1 { + reg = <1>; + }; + }; diff --git a/Documentation/devicetree/bindings/net/hisilicon,hisi-femac.yaml b/Documentation/devicetree/bindings/net/hisilicon,hisi-femac.yaml new file mode 100644 index 00000000000000..4f51c5ec90b3bd --- /dev/null +++ b/Documentation/devicetree/bindings/net/hisilicon,hisi-femac.yaml @@ -0,0 +1,120 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/hisilicon,hisi-femac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Hisilicon Fast Ethernet MAC controller + +maintainers: + - Yang Xiwen + +allOf: + - $ref: ethernet-controller.yaml + +properties: + compatible: + items: + - enum: + - hisilicon,hi3516cv300-femac + - hisilicon,hi3798mv200-femac + - const: hisilicon,hisi-femac + + reg: + items: + - description: The first region is the MAC core register base and size. + - description: The second region is the global MAC control register. + + ranges: + maxItems: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: MAC main clock + - description: MAC bus interface clock + - description: PHY clock + + clock-names: + items: + - const: mac + - const: macif + - const: phy + + resets: + items: + - description: MAC reset signal + - description: PHY reset signal + + reset-names: + items: + - const: mac + - const: phy + + hisilicon,phy-reset-delays-us: + description: PHY reset timing requirement (in micro seconds). + The integrated PHY usually have a special reset timing sequence and must + interact with MAC controller to accomplish the entire reset procedure. So + these properties belong to MAC controller, not PHY. + items: + - description: pre-reset delay for PHY + - description: reset pulse for PHY + - description: post-reset delay for PHY + +patternProperties: + 'mdio@[0-9a-f]+': + $ref: hisilicon,hisi-femac-mdio.yaml# + +required: + - compatible + - reg + - ranges + - '#address-cells' + - '#size-cells' + - interrupts + - clocks + - resets + - reset-names + - phy-mode + - phy-handle + - hisilicon,phy-reset-delays-us + +unevaluatedProperties: false + +examples: + - | + ethernet@10090000 { + compatible = "hisilicon,hi3516cv300-femac", "hisilicon,hisi-femac"; + reg = <0x10090000 0x1000>, <0x10091300 0x200>; + ranges = <0x0 0x10090000 0x10000>; + #address-cells = <1>; + #size-cells = <1>; + interrupts = <12>; + clocks = <&clk_femac>, <&clk_femacif>, <&clk_fephy>; + clock-names = "mac", "macif", "phy"; + resets = <&crg 0xec 0>, <&crg 0xec 3>; + reset-names = "mac", "phy"; + mac-address = [00 00 00 00 00 00]; + phy-mode = "mii"; + phy-handle = <&fephy>; + hisilicon,phy-reset-delays-us = <10000 20000 20000>; + + mdio@1100 { + compatible = "hisilicon,hisi-femac-mdio"; + reg = <0x1100 0x20>; + #address-cells = <1>; + #size-cells = <0>; + + phy@1 { + reg = <1>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/net/hisilicon-femac-mdio.txt b/Documentation/devicetree/bindings/net/hisilicon-femac-mdio.txt deleted file mode 100644 index 23a39a309d17d3..00000000000000 --- a/Documentation/devicetree/bindings/net/hisilicon-femac-mdio.txt +++ /dev/null @@ -1,22 +0,0 @@ -Hisilicon Fast Ethernet MDIO Controller interface - -Required properties: -- compatible: should be "hisilicon,hisi-femac-mdio". -- reg: address and length of the register set for the device. -- clocks: A phandle to the reference clock for this device. - -- PHY subnode: inherits from phy binding [1] -[1] Documentation/devicetree/bindings/net/phy.txt - -Example: -mdio: mdio@10091100 { - compatible = "hisilicon,hisi-femac-mdio"; - reg = <0x10091100 0x10>; - clocks = <&crg HI3516CV300_MDIO_CLK>; - #address-cells = <1>; - #size-cells = <0>; - - phy0: phy@1 { - reg = <1>; - }; -}; diff --git a/Documentation/devicetree/bindings/net/hisilicon-femac.txt b/Documentation/devicetree/bindings/net/hisilicon-femac.txt deleted file mode 100644 index 5f96976f3cea7a..00000000000000 --- a/Documentation/devicetree/bindings/net/hisilicon-femac.txt +++ /dev/null @@ -1,41 +0,0 @@ -Hisilicon Fast Ethernet MAC controller - -Required properties: -- compatible: should contain one of the following version strings: - * "hisilicon,hisi-femac-v1" - * "hisilicon,hisi-femac-v2" - and the soc string "hisilicon,hi3516cv300-femac". -- reg: specifies base physical address(s) and size of the device registers. - The first region is the MAC core register base and size. - The second region is the global MAC control register. -- interrupts: should contain the MAC interrupt. -- clocks: A phandle to the MAC main clock. -- resets: should contain the phandle to the MAC reset signal(required) and - the PHY reset signal(optional). -- reset-names: should contain the reset signal name "mac"(required) - and "phy"(optional). -- phy-mode: see ethernet.txt [1]. -- phy-handle: see ethernet.txt [1]. -- hisilicon,phy-reset-delays-us: triplet of delays if PHY reset signal given. - The 1st cell is reset pre-delay in micro seconds. - The 2nd cell is reset pulse in micro seconds. - The 3rd cell is reset post-delay in micro seconds. - -The MAC address will be determined using the optional properties -defined in ethernet.txt[1]. - -[1] Documentation/devicetree/bindings/net/ethernet.txt - -Example: - hisi_femac: ethernet@10090000 { - compatible = "hisilicon,hi3516cv300-femac","hisilicon,hisi-femac-v2"; - reg = <0x10090000 0x1000>,<0x10091300 0x200>; - interrupts = <12>; - clocks = <&crg HI3518EV200_ETH_CLK>; - resets = <&crg 0xec 0>,<&crg 0xec 3>; - reset-names = "mac","phy"; - mac-address = [00 00 00 00 00 00]; - phy-mode = "mii"; - phy-handle = <&phy0>; - hisilicon,phy-reset-delays-us = <10000 20000 20000>; - }; diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c index 2406263c9dd3ad..2ecc10a9ca2862 100644 --- a/drivers/net/ethernet/hisilicon/hisi_femac.c +++ b/drivers/net/ethernet/hisilicon/hisi_femac.c @@ -10,8 +10,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -97,6 +99,13 @@ enum phy_reset_delays { DELAYS_NUM, }; +enum clk_type { + CLK_MAC, + CLK_MACIF, + CLK_PHY, + CLK_NUM, +}; + struct hisi_femac_queue { struct sk_buff **skb; dma_addr_t *dma_phys; @@ -108,7 +117,7 @@ struct hisi_femac_queue { struct hisi_femac_priv { void __iomem *port_base; void __iomem *glb_base; - struct clk *clk; + struct clk_bulk_data *clks; struct reset_control *mac_rst; struct reset_control *phy_rst; u32 phy_reset_delays[DELAYS_NUM]; @@ -116,6 +125,7 @@ struct hisi_femac_priv { struct device *dev; struct net_device *ndev; + struct platform_device *mdio_pdev; struct hisi_femac_queue txq; struct hisi_femac_queue rxq; @@ -693,6 +703,7 @@ static const struct net_device_ops hisi_femac_netdev_ops = { static void hisi_femac_core_reset(struct hisi_femac_priv *priv) { reset_control_assert(priv->mac_rst); + usleep_range(200, 300); reset_control_deassert(priv->mac_rst); } @@ -712,6 +723,10 @@ static void hisi_femac_sleep_us(u32 time_us) static void hisi_femac_phy_reset(struct hisi_femac_priv *priv) { + /* MAC clock must be disabled before PHY reset + */ + clk_disable(priv->clks[CLK_MAC].clk); + clk_disable(priv->clks[CLK_MACIF].clk); /* To make sure PHY hardware reset success, * we must keep PHY in deassert state first and * then complete the hardware reset operation @@ -727,6 +742,9 @@ static void hisi_femac_phy_reset(struct hisi_femac_priv *priv) reset_control_deassert(priv->phy_rst); /* delay some time to ensure later MDIO access */ hisi_femac_sleep_us(priv->phy_reset_delays[POST_DELAY]); + + clk_enable(priv->clks[CLK_MAC].clk); + clk_enable(priv->clks[CLK_MACIF].clk); } static void hisi_femac_port_init(struct hisi_femac_priv *priv) @@ -768,11 +786,12 @@ static void hisi_femac_port_init(struct hisi_femac_priv *priv) static int hisi_femac_drv_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; + struct device_node *node = dev->of_node, *mdio_np; struct net_device *ndev; struct hisi_femac_priv *priv; struct phy_device *phy; int ret; + bool mdio_registered = false; ndev = alloc_etherdev(sizeof(*priv)); if (!ndev) @@ -797,17 +816,16 @@ static int hisi_femac_drv_probe(struct platform_device *pdev) goto out_free_netdev; } - priv->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(priv->clk)) { - dev_err(dev, "failed to get clk\n"); - ret = -ENODEV; + ret = devm_clk_bulk_get_all(&pdev->dev, &priv->clks); + if (ret < 0 || ret != CLK_NUM) { + dev_err(dev, "failed to get clk bulk: %d\n", ret); goto out_free_netdev; } - ret = clk_prepare_enable(priv->clk); + ret = clk_bulk_prepare_enable(CLK_NUM, priv->clks); if (ret) { - dev_err(dev, "failed to enable clk %d\n", ret); - goto out_free_netdev; + dev_err(dev, "failed to enable clk bulk: %d\n", ret); + goto out_disable_clk; } priv->mac_rst = devm_reset_control_get(dev, "mac"); @@ -830,11 +848,29 @@ static int hisi_femac_drv_probe(struct platform_device *pdev) hisi_femac_phy_reset(priv); } + // Register the optional MDIO bus + for_each_available_child_of_node(node, mdio_np) { + if (of_node_name_prefix(mdio_np, "mdio")) { + priv->mdio_pdev = of_platform_device_create(mdio_np, NULL, dev); + of_node_put(mdio_np); + if (!priv->mdio_pdev) { + dev_err(dev, "failed to register MDIO bus device\n"); + ret = -ENODEV; + goto out_disable_clk; + } + mdio_registered = true; + break; + } + } + + if (!mdio_registered) + dev_warn(dev, "MDIO subnode not found. This is usually a bug.\n"); + phy = of_phy_get_and_connect(ndev, node, hisi_femac_adjust_link); if (!phy) { dev_err(dev, "connect to PHY failed!\n"); ret = -ENODEV; - goto out_disable_clk; + goto out_unregister_mdio_bus; } phy_attached_print(phy, "phy_id=0x%.8lx, phy_mode=%s\n", @@ -885,8 +921,10 @@ static int hisi_femac_drv_probe(struct platform_device *pdev) out_disconnect_phy: netif_napi_del(&priv->napi); phy_disconnect(phy); +out_unregister_mdio_bus: + platform_device_unregister(priv->mdio_pdev); out_disable_clk: - clk_disable_unprepare(priv->clk); + clk_bulk_disable_unprepare(CLK_NUM, priv->clks); out_free_netdev: free_netdev(ndev); @@ -902,7 +940,8 @@ static void hisi_femac_drv_remove(struct platform_device *pdev) unregister_netdev(ndev); phy_disconnect(ndev->phydev); - clk_disable_unprepare(priv->clk); + platform_device_unregister(priv->mdio_pdev); + clk_bulk_disable_unprepare(CLK_NUM, priv->clks); free_netdev(ndev); } @@ -919,7 +958,7 @@ static int hisi_femac_drv_suspend(struct platform_device *pdev, netif_device_detach(ndev); } - clk_disable_unprepare(priv->clk); + clk_bulk_disable_unprepare(CLK_NUM, priv->clks); return 0; } @@ -928,8 +967,14 @@ static int hisi_femac_drv_resume(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct hisi_femac_priv *priv = netdev_priv(ndev); + int ret; + + ret = clk_bulk_prepare_enable(CLK_NUM, priv->clks); + if (ret) { + dev_err(&pdev->dev, "failed to enable clk bulk: %d\n", ret); + return ret; + } - clk_prepare_enable(priv->clk); if (priv->phy_rst) hisi_femac_phy_reset(priv); @@ -945,9 +990,7 @@ static int hisi_femac_drv_resume(struct platform_device *pdev) #endif static const struct of_device_id hisi_femac_match[] = { - {.compatible = "hisilicon,hisi-femac-v1",}, - {.compatible = "hisilicon,hisi-femac-v2",}, - {.compatible = "hisilicon,hi3516cv300-femac",}, + {.compatible = "hisilicon,hisi-femac",}, {}, }; @@ -971,4 +1014,3 @@ module_platform_driver(hisi_femac_driver); MODULE_DESCRIPTION("Hisilicon Fast Ethernet MAC driver"); MODULE_AUTHOR("Dongpo Li "); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:hisi-femac"); diff --git a/drivers/net/mdio/mdio-hisi-femac.c b/drivers/net/mdio/mdio-hisi-femac.c index 6703f626ee833b..faf4688eb1ab67 100644 --- a/drivers/net/mdio/mdio-hisi-femac.c +++ b/drivers/net/mdio/mdio-hisi-femac.c @@ -5,7 +5,6 @@ * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. */ -#include #include #include #include @@ -21,7 +20,6 @@ #define BIT_WR_DATA_OFFSET 16 struct hisi_femac_mdio_data { - struct clk *clk; void __iomem *membase; }; @@ -93,26 +91,14 @@ static int hisi_femac_mdio_probe(struct platform_device *pdev) goto err_out_free_mdiobus; } - data->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(data->clk)) { - ret = PTR_ERR(data->clk); - goto err_out_free_mdiobus; - } - - ret = clk_prepare_enable(data->clk); - if (ret) - goto err_out_free_mdiobus; - ret = of_mdiobus_register(bus, np); if (ret) - goto err_out_disable_clk; + goto err_out_free_mdiobus; platform_set_drvdata(pdev, bus); return 0; -err_out_disable_clk: - clk_disable_unprepare(data->clk); err_out_free_mdiobus: mdiobus_free(bus); return ret; @@ -121,10 +107,8 @@ static int hisi_femac_mdio_probe(struct platform_device *pdev) static void hisi_femac_mdio_remove(struct platform_device *pdev) { struct mii_bus *bus = platform_get_drvdata(pdev); - struct hisi_femac_mdio_data *data = bus->priv; mdiobus_unregister(bus); - clk_disable_unprepare(data->clk); mdiobus_free(bus); }