Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: ethernet: dwmac: add Ethernet glue logic for stm32 chip

stm324xx family chips support Synopsys MAC 3.510 IP.
This patch adds settings for logical glue logic:
-clocks
-mode selection MII or RMII.

Reviewed-by: Joachim Eastwood <manabian@gmail.com>
Acked-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Tested-by: Maxime Coquelin <maxime.coquelin@st.com>
Signed-off-by: Alexandre TORGUE <alexandre.torgue@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Alexandre TORGUE and committed by
David S. Miller
c6eec6f3 ce927bf1

+206
+12
drivers/net/ethernet/stmicro/stmmac/Kconfig
··· 104 104 device driver. This driver is used on for the STi series 105 105 SOCs GMAC ethernet controller. 106 106 107 + config DWMAC_STM32 108 + tristate "STM32 DWMAC support" 109 + default ARCH_STM32 110 + depends on OF && HAS_IOMEM 111 + select MFD_SYSCON 112 + ---help--- 113 + Support for ethernet controller on STM32 SOCs. 114 + 115 + This selects STM32 SoC glue layer support for the stmmac 116 + device driver. This driver is used on for the STM32 series 117 + SOCs GMAC ethernet controller. 118 + 107 119 config DWMAC_SUNXI 108 120 tristate "Allwinner GMAC support" 109 121 default ARCH_SUNXI
+1
drivers/net/ethernet/stmicro/stmmac/Makefile
··· 13 13 obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o 14 14 obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o 15 15 obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o 16 + obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o 16 17 obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o 17 18 obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o 18 19 stmmac-platform-objs:= stmmac_platform.o
+193
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
··· 1 + /* 2 + * dwmac-stm32.c - DWMAC Specific Glue layer for STM32 MCU 3 + * 4 + * Copyright (C) Alexandre Torgue 2015 5 + * Author: Alexandre Torgue <alexandre.torgue@gmail.com> 6 + * License terms: GNU General Public License (GPL), version 2 7 + * 8 + */ 9 + 10 + #include <linux/clk.h> 11 + #include <linux/kernel.h> 12 + #include <linux/mfd/syscon.h> 13 + #include <linux/module.h> 14 + #include <linux/of.h> 15 + #include <linux/of_device.h> 16 + #include <linux/of_net.h> 17 + #include <linux/phy.h> 18 + #include <linux/platform_device.h> 19 + #include <linux/regmap.h> 20 + #include <linux/slab.h> 21 + #include <linux/stmmac.h> 22 + 23 + #include "stmmac_platform.h" 24 + 25 + #define MII_PHY_SEL_MASK BIT(23) 26 + 27 + struct stm32_dwmac { 28 + struct clk *clk_tx; 29 + struct clk *clk_rx; 30 + u32 mode_reg; /* MAC glue-logic mode register */ 31 + struct regmap *regmap; 32 + u32 speed; 33 + }; 34 + 35 + static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat) 36 + { 37 + struct stm32_dwmac *dwmac = plat_dat->bsp_priv; 38 + u32 reg = dwmac->mode_reg; 39 + u32 val; 40 + int ret; 41 + 42 + val = (plat_dat->interface == PHY_INTERFACE_MODE_MII) ? 0 : 1; 43 + ret = regmap_update_bits(dwmac->regmap, reg, MII_PHY_SEL_MASK, val); 44 + if (ret) 45 + return ret; 46 + 47 + ret = clk_prepare_enable(dwmac->clk_tx); 48 + if (ret) 49 + return ret; 50 + 51 + ret = clk_prepare_enable(dwmac->clk_rx); 52 + if (ret) 53 + clk_disable_unprepare(dwmac->clk_tx); 54 + 55 + return ret; 56 + } 57 + 58 + static void stm32_dwmac_clk_disable(struct stm32_dwmac *dwmac) 59 + { 60 + clk_disable_unprepare(dwmac->clk_tx); 61 + clk_disable_unprepare(dwmac->clk_rx); 62 + } 63 + 64 + static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac, 65 + struct device *dev) 66 + { 67 + struct device_node *np = dev->of_node; 68 + int err; 69 + 70 + /* Get TX/RX clocks */ 71 + dwmac->clk_tx = devm_clk_get(dev, "mac-clk-tx"); 72 + if (IS_ERR(dwmac->clk_tx)) { 73 + dev_err(dev, "No tx clock provided...\n"); 74 + return PTR_ERR(dwmac->clk_tx); 75 + } 76 + dwmac->clk_rx = devm_clk_get(dev, "mac-clk-rx"); 77 + if (IS_ERR(dwmac->clk_rx)) { 78 + dev_err(dev, "No rx clock provided...\n"); 79 + return PTR_ERR(dwmac->clk_rx); 80 + } 81 + 82 + /* Get mode register */ 83 + dwmac->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscon"); 84 + if (IS_ERR(dwmac->regmap)) 85 + return PTR_ERR(dwmac->regmap); 86 + 87 + err = of_property_read_u32_index(np, "st,syscon", 1, &dwmac->mode_reg); 88 + if (err) 89 + dev_err(dev, "Can't get sysconfig mode offset (%d)\n", err); 90 + 91 + return err; 92 + } 93 + 94 + static int stm32_dwmac_probe(struct platform_device *pdev) 95 + { 96 + struct plat_stmmacenet_data *plat_dat; 97 + struct stmmac_resources stmmac_res; 98 + struct stm32_dwmac *dwmac; 99 + int ret; 100 + 101 + ret = stmmac_get_platform_resources(pdev, &stmmac_res); 102 + if (ret) 103 + return ret; 104 + 105 + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); 106 + if (IS_ERR(plat_dat)) 107 + return PTR_ERR(plat_dat); 108 + 109 + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); 110 + if (!dwmac) 111 + return -ENOMEM; 112 + 113 + ret = stm32_dwmac_parse_data(dwmac, &pdev->dev); 114 + if (ret) { 115 + dev_err(&pdev->dev, "Unable to parse OF data\n"); 116 + return ret; 117 + } 118 + 119 + plat_dat->bsp_priv = dwmac; 120 + 121 + ret = stm32_dwmac_init(plat_dat); 122 + if (ret) 123 + return ret; 124 + 125 + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 126 + if (ret) 127 + stm32_dwmac_clk_disable(dwmac); 128 + 129 + return ret; 130 + } 131 + 132 + static int stm32_dwmac_remove(struct platform_device *pdev) 133 + { 134 + struct net_device *ndev = platform_get_drvdata(pdev); 135 + struct stmmac_priv *priv = netdev_priv(ndev); 136 + int ret = stmmac_dvr_remove(&pdev->dev); 137 + 138 + stm32_dwmac_clk_disable(priv->plat->bsp_priv); 139 + 140 + return ret; 141 + } 142 + 143 + #ifdef CONFIG_PM_SLEEP 144 + static int stm32_dwmac_suspend(struct device *dev) 145 + { 146 + struct net_device *ndev = dev_get_drvdata(dev); 147 + struct stmmac_priv *priv = netdev_priv(ndev); 148 + int ret; 149 + 150 + ret = stmmac_suspend(dev); 151 + stm32_dwmac_clk_disable(priv->plat->bsp_priv); 152 + 153 + return ret; 154 + } 155 + 156 + static int stm32_dwmac_resume(struct device *dev) 157 + { 158 + struct net_device *ndev = dev_get_drvdata(dev); 159 + struct stmmac_priv *priv = netdev_priv(ndev); 160 + int ret; 161 + 162 + ret = stm32_dwmac_init(priv->plat); 163 + if (ret) 164 + return ret; 165 + 166 + ret = stmmac_resume(dev); 167 + 168 + return ret; 169 + } 170 + #endif /* CONFIG_PM_SLEEP */ 171 + 172 + SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops, stm32_dwmac_suspend, stm32_dwmac_resume); 173 + 174 + static const struct of_device_id stm32_dwmac_match[] = { 175 + { .compatible = "st,stm32-dwmac"}, 176 + { } 177 + }; 178 + MODULE_DEVICE_TABLE(of, stm32_dwmac_match); 179 + 180 + static struct platform_driver stm32_dwmac_driver = { 181 + .probe = stm32_dwmac_probe, 182 + .remove = stm32_dwmac_remove, 183 + .driver = { 184 + .name = "stm32-dwmac", 185 + .pm = &stm32_dwmac_pm_ops, 186 + .of_match_table = stm32_dwmac_match, 187 + }, 188 + }; 189 + module_platform_driver(stm32_dwmac_driver); 190 + 191 + MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@gmail.com>"); 192 + MODULE_DESCRIPTION("STMicroelectronics MCU DWMAC Specific Glue layer"); 193 + MODULE_LICENSE("GPL v2");