diff options
author | David S. Miller <davem@davemloft.net> | 2021-02-16 01:59:35 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2021-02-16 01:59:35 +0300 |
commit | ec762403bbe95ded1e7dbca468e928535572da8b (patch) | |
tree | a97de6405cd92b30cafd27c6dc6cbb9d18cde874 | |
parent | 3a616b92a9d17448d96a33bf58e69f01457fd43a (diff) | |
parent | ec8a42e7343234802b9054874fe01810880289ce (diff) | |
download | linux-ec762403bbe95ded1e7dbca468e928535572da8b.tar.xz |
Merge branch 'net-stmmac-Add-Toshiba-Visconti-SoCs-glue-driver'
Nobuhiro Iwamatsu says:
====================
net: stmmac: Add Toshiba Visconti SoCs glue driver
This series is the ethernet driver for Toshiba's ARM SoC, Visconti[0].
This provides DT binding documentation, device driver, MAINTAINER files,
and updates to DT files.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml | 85 | ||||
-rw-r--r-- | MAINTAINERS | 2 | ||||
-rw-r--r-- | arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts | 18 | ||||
-rw-r--r-- | arch/arm64/boot/dts/toshiba/tmpv7708.dtsi | 25 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/Kconfig | 8 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c | 285 |
7 files changed, 424 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml b/Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml new file mode 100644 index 000000000000..59724d18e6f3 --- /dev/null +++ b/Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml @@ -0,0 +1,85 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/net/toshiba,visconti-dwmac.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Toshiba Visconti DWMAC Ethernet controller + +maintainers: + - Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp> + +select: + properties: + compatible: + contains: + enum: + - toshiba,visconti-dwmac + required: + - compatible + +allOf: + - $ref: "snps,dwmac.yaml#" + +properties: + compatible: + oneOf: + - items: + - enum: + - toshiba,visconti-dwmac + - const: snps,dwmac-4.20a + + reg: + maxItems: 1 + + clocks: + items: + - description: main clock + - description: PHY reference clock + + clock-names: + items: + - const: stmmaceth + - const: phy_ref_clk + +required: + - compatible + - reg + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + + soc { + #address-cells = <2>; + #size-cells = <2>; + + piether: ethernet@28000000 { + compatible = "toshiba,visconti-dwmac", "snps,dwmac-4.20a"; + reg = <0 0x28000000 0 0x10000>; + interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + clocks = <&clk300mhz>, <&clk125mhz>; + clock-names = "stmmaceth", "phy_ref_clk"; + snps,txpbl = <4>; + snps,rxpbl = <4>; + snps,tso; + phy-mode = "rgmii-id"; + phy-handle = <&phy0>; + + mdio0 { + #address-cells = <0x1>; + #size-cells = <0x0>; + compatible = "snps,dwmac-mdio"; + + phy0: ethernet-phy@1 { + device_type = "ethernet-phy"; + reg = <0x1>; + }; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 99335fd22c0a..986a8eef8633 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2641,8 +2641,10 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwamatsu/linux-visconti.git F: Documentation/devicetree/bindings/arm/toshiba.yaml +F: Documentation/devicetree/bindings/net/toshiba,visconti-dwmac.yaml F: Documentation/devicetree/bindings/pinctrl/toshiba,tmpv7700-pinctrl.yaml F: arch/arm64/boot/dts/toshiba/ +F: drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c F: drivers/pinctrl/visconti/ N: visconti diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts b/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts index ed0bf7f13f54..48fa8776e36f 100644 --- a/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts +++ b/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts @@ -41,3 +41,21 @@ clocks = <&uart_clk>; clock-names = "apb_pclk"; }; + +&piether { + status = "okay"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + clocks = <&clk300mhz>, <&clk125mhz>; + clock-names = "stmmaceth", "phy_ref_clk"; + + mdio0 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,dwmac-mdio"; + phy0: ethernet-phy@1 { + device_type = "ethernet-phy"; + reg = <0x1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi b/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi index 242f25f4e12a..3366786699fc 100644 --- a/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi +++ b/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi @@ -134,6 +134,20 @@ #clock-cells = <0>; }; + clk125mhz: clk125mhz { + compatible = "fixed-clock"; + clock-frequency = <125000000>; + #clock-cells = <0>; + clock-output-names = "clk125mhz"; + }; + + clk300mhz: clk300mhz { + compatible = "fixed-clock"; + clock-frequency = <300000000>; + #clock-cells = <0>; + clock-output-names = "clk300mhz"; + }; + soc { #address-cells = <2>; #size-cells = <2>; @@ -384,6 +398,17 @@ #size-cells = <0>; status = "disabled"; }; + + piether: ethernet@28000000 { + compatible = "toshiba,visconti-dwmac", "snps,dwmac-4.20a"; + reg = <0 0x28000000 0 0x10000>; + interrupts = <GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "macirq"; + snps,txpbl = <4>; + snps,rxpbl = <4>; + snps,tso; + status = "disabled"; + }; }; }; diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 53f14c5a9e02..e675ba12fde2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -219,6 +219,14 @@ config DWMAC_INTEL_PLAT This selects the Intel platform specific glue layer support for the stmmac device driver. This driver is used for the Intel Keem Bay SoC. + +config DWMAC_VISCONTI + tristate "Toshiba Visconti DWMAC support" + default ARCH_VISCONTI + depends on OF && COMMON_CLK && (ARCH_VISCONTI || COMPILE_TEST) + help + Support for ethernet controller on Visconti SoCs. + endif config DWMAC_INTEL diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 24e6145d4eae..366740ab9c5a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o obj-$(CONFIG_DWMAC_INTEL_PLAT) += dwmac-intel-plat.o obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o obj-$(CONFIG_DWMAC_IMX8) += dwmac-imx.o +obj-$(CONFIG_DWMAC_VISCONTI) += dwmac-visconti.o stmmac-platform-objs:= stmmac_platform.o dwmac-altr-socfpga-objs := altr_tse_pcs.o dwmac-socfpga.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c new file mode 100644 index 000000000000..b7a0c57dfbfb --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Toshiba Visconti Ethernet Support + * + * (C) Copyright 2020 TOSHIBA CORPORATION + * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation + */ + +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of_net.h> +#include <linux/stmmac.h> + +#include "stmmac_platform.h" +#include "dwmac4.h" + +#define REG_ETHER_CONTROL 0x52D4 +#define ETHER_ETH_CONTROL_RESET BIT(17) + +#define REG_ETHER_CLOCK_SEL 0x52D0 +#define ETHER_CLK_SEL_TX_CLK_EN BIT(0) +#define ETHER_CLK_SEL_RX_CLK_EN BIT(1) +#define ETHER_CLK_SEL_RMII_CLK_EN BIT(2) +#define ETHER_CLK_SEL_RMII_CLK_RST BIT(3) +#define ETHER_CLK_SEL_DIV_SEL_2 BIT(4) +#define ETHER_CLK_SEL_DIV_SEL_20 BIT(0) +#define ETHER_CLK_SEL_FREQ_SEL_125M (BIT(9) | BIT(8)) +#define ETHER_CLK_SEL_FREQ_SEL_50M BIT(9) +#define ETHER_CLK_SEL_FREQ_SEL_25M BIT(8) +#define ETHER_CLK_SEL_FREQ_SEL_2P5M BIT(0) +#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN BIT(0) +#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC BIT(10) +#define ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV BIT(11) +#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_IN BIT(0) +#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC BIT(12) +#define ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV BIT(13) +#define ETHER_CLK_SEL_TX_CLK_O_TX_I BIT(0) +#define ETHER_CLK_SEL_TX_CLK_O_RMII_I BIT(14) +#define ETHER_CLK_SEL_TX_O_E_N_IN BIT(15) +#define ETHER_CLK_SEL_RMII_CLK_SEL_IN BIT(0) +#define ETHER_CLK_SEL_RMII_CLK_SEL_RX_C BIT(16) + +#define ETHER_CLK_SEL_RX_TX_CLK_EN (ETHER_CLK_SEL_RX_CLK_EN | ETHER_CLK_SEL_TX_CLK_EN) + +#define ETHER_CONFIG_INTF_MII 0 +#define ETHER_CONFIG_INTF_RGMII BIT(0) +#define ETHER_CONFIG_INTF_RMII BIT(2) + +struct visconti_eth { + void __iomem *reg; + u32 phy_intf_sel; + struct clk *phy_ref_clk; + spinlock_t lock; /* lock to protect register update */ +}; + +static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed) +{ + struct visconti_eth *dwmac = priv; + unsigned int val, clk_sel_val; + unsigned long flags; + + spin_lock_irqsave(&dwmac->lock, flags); + + /* adjust link */ + val = readl(dwmac->reg + MAC_CTRL_REG); + val &= ~(GMAC_CONFIG_PS | GMAC_CONFIG_FES); + + switch (speed) { + case SPEED_1000: + if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) + clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M; + break; + case SPEED_100: + if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) + clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_25M; + if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII) + clk_sel_val = ETHER_CLK_SEL_DIV_SEL_2; + val |= GMAC_CONFIG_PS | GMAC_CONFIG_FES; + break; + case SPEED_10: + if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) + clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_2P5M; + if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII) + clk_sel_val = ETHER_CLK_SEL_DIV_SEL_20; + val |= GMAC_CONFIG_PS; + break; + default: + /* No bit control */ + break; + } + + writel(val, dwmac->reg + MAC_CTRL_REG); + + /* Stop internal clock */ + val = readl(dwmac->reg + REG_ETHER_CLOCK_SEL); + val &= ~(ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN); + val |= ETHER_CLK_SEL_TX_O_E_N_IN; + writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); + + switch (dwmac->phy_intf_sel) { + case ETHER_CONFIG_INTF_RGMII: + val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC; + break; + case ETHER_CONFIG_INTF_RMII: + val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV | + ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN | + ETHER_CLK_SEL_RMII_CLK_SEL_RX_C; + break; + case ETHER_CONFIG_INTF_MII: + default: + val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC | + ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN | + ETHER_CLK_SEL_RMII_CLK_EN; + break; + } + + /* Start clock */ + writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); + val |= ETHER_CLK_SEL_RX_TX_CLK_EN; + writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); + + val &= ~ETHER_CLK_SEL_TX_O_E_N_IN; + writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); + + spin_unlock_irqrestore(&dwmac->lock, flags); +} + +static int visconti_eth_init_hw(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat) +{ + struct visconti_eth *dwmac = plat_dat->bsp_priv; + unsigned int reg_val, clk_sel_val; + + switch (plat_dat->phy_interface) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RGMII; + break; + case PHY_INTERFACE_MODE_MII: + dwmac->phy_intf_sel = ETHER_CONFIG_INTF_MII; + break; + case PHY_INTERFACE_MODE_RMII: + dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RMII; + break; + default: + dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n", plat_dat->phy_interface); + return -EOPNOTSUPP; + } + + reg_val = dwmac->phy_intf_sel; + writel(reg_val, dwmac->reg + REG_ETHER_CONTROL); + + /* Enable TX/RX clock */ + clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M; + writel(clk_sel_val, dwmac->reg + REG_ETHER_CLOCK_SEL); + + writel((clk_sel_val | ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN), + dwmac->reg + REG_ETHER_CLOCK_SEL); + + /* release internal-reset */ + reg_val |= ETHER_ETH_CONTROL_RESET; + writel(reg_val, dwmac->reg + REG_ETHER_CONTROL); + + return 0; +} + +static int visconti_eth_clock_probe(struct platform_device *pdev, + struct plat_stmmacenet_data *plat_dat) +{ + struct visconti_eth *dwmac = plat_dat->bsp_priv; + int err; + + dwmac->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk"); + if (IS_ERR(dwmac->phy_ref_clk)) { + dev_err(&pdev->dev, "phy_ref_clk clock not found.\n"); + return PTR_ERR(dwmac->phy_ref_clk); + } + + err = clk_prepare_enable(dwmac->phy_ref_clk); + if (err < 0) { + dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n", err); + return err; + } + + return 0; +} + +static int visconti_eth_clock_remove(struct platform_device *pdev) +{ + struct visconti_eth *dwmac = get_stmmac_bsp_priv(&pdev->dev); + struct net_device *ndev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(ndev); + + clk_disable_unprepare(dwmac->phy_ref_clk); + clk_disable_unprepare(priv->plat->stmmac_clk); + + return 0; +} + +static int visconti_eth_dwmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + struct visconti_eth *dwmac; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); + + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); + if (!dwmac) { + ret = -ENOMEM; + goto remove_config; + } + + dwmac->reg = stmmac_res.addr; + plat_dat->bsp_priv = dwmac; + plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed; + + ret = visconti_eth_clock_probe(pdev, plat_dat); + if (ret) + goto remove_config; + + visconti_eth_init_hw(pdev, plat_dat); + + plat_dat->dma_cfg->aal = 1; + + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (ret) + goto remove; + + return ret; + +remove: + visconti_eth_clock_remove(pdev); +remove_config: + stmmac_remove_config_dt(pdev, plat_dat); + + return ret; +} + +static int visconti_eth_dwmac_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(ndev); + int err; + + err = stmmac_pltfr_remove(pdev); + if (err < 0) + dev_err(&pdev->dev, "failed to remove platform: %d\n", err); + + err = visconti_eth_clock_remove(pdev); + if (err < 0) + dev_err(&pdev->dev, "failed to remove clock: %d\n", err); + + stmmac_remove_config_dt(pdev, priv->plat); + + return err; +} + +static const struct of_device_id visconti_eth_dwmac_match[] = { + { .compatible = "toshiba,visconti-dwmac" }, + { } +}; +MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match); + +static struct platform_driver visconti_eth_dwmac_driver = { + .probe = visconti_eth_dwmac_probe, + .remove = visconti_eth_dwmac_remove, + .driver = { + .name = "visconti-eth-dwmac", + .of_match_table = visconti_eth_dwmac_match, + }, +}; +module_platform_driver(visconti_eth_dwmac_driver); + +MODULE_AUTHOR("Toshiba"); +MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver"); +MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp"); +MODULE_LICENSE("GPL v2"); |