1 // SPDX-License-Identifier: GPL-2.0 2 /* Toshiba Visconti Ethernet Support 3 * 4 * (C) Copyright 2020 TOSHIBA CORPORATION 5 * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation 6 */ 7 8 #include <linux/module.h> 9 #include <linux/of.h> 10 #include <linux/platform_device.h> 11 #include <linux/of_net.h> 12 #include <linux/stmmac.h> 13 14 #include "stmmac_platform.h" 15 #include "dwmac4.h" 16 17 #define REG_ETHER_CONTROL 0x52D4 18 #define ETHER_ETH_CONTROL_RESET BIT(17) 19 20 #define REG_ETHER_CLOCK_SEL 0x52D0 21 #define ETHER_CLK_SEL_TX_CLK_EN BIT(0) 22 #define ETHER_CLK_SEL_RX_CLK_EN BIT(1) 23 #define ETHER_CLK_SEL_RMII_CLK_EN BIT(2) 24 #define ETHER_CLK_SEL_RMII_CLK_RST BIT(3) 25 #define ETHER_CLK_SEL_DIV_SEL_2 BIT(4) 26 #define ETHER_CLK_SEL_DIV_SEL_20 0 27 #define ETHER_CLK_SEL_FREQ_SEL_125M (BIT(9) | BIT(8)) 28 #define ETHER_CLK_SEL_FREQ_SEL_50M BIT(9) 29 #define ETHER_CLK_SEL_FREQ_SEL_25M BIT(8) 30 #define ETHER_CLK_SEL_FREQ_SEL_2P5M 0 31 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_IN 0 32 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC BIT(10) 33 #define ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV BIT(11) 34 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_IN 0 35 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC BIT(12) 36 #define ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV BIT(13) 37 #define ETHER_CLK_SEL_TX_CLK_O_TX_I 0 38 #define ETHER_CLK_SEL_TX_CLK_O_RMII_I BIT(14) 39 #define ETHER_CLK_SEL_TX_O_E_N_IN BIT(15) 40 #define ETHER_CLK_SEL_RMII_CLK_SEL_IN 0 41 #define ETHER_CLK_SEL_RMII_CLK_SEL_RX_C BIT(16) 42 43 #define ETHER_CLK_SEL_RX_TX_CLK_EN (ETHER_CLK_SEL_RX_CLK_EN | ETHER_CLK_SEL_TX_CLK_EN) 44 45 #define ETHER_CONFIG_INTF_MII 0 46 #define ETHER_CONFIG_INTF_RGMII BIT(0) 47 #define ETHER_CONFIG_INTF_RMII BIT(2) 48 49 struct visconti_eth { 50 void __iomem *reg; 51 u32 phy_intf_sel; 52 struct clk *phy_ref_clk; 53 struct device *dev; 54 spinlock_t lock; /* lock to protect register update */ 55 }; 56 57 static void visconti_eth_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode) 58 { 59 struct visconti_eth *dwmac = priv; 60 struct net_device *netdev = dev_get_drvdata(dwmac->dev); 61 unsigned int val, clk_sel_val = 0; 62 unsigned long flags; 63 64 spin_lock_irqsave(&dwmac->lock, flags); 65 66 /* adjust link */ 67 val = readl(dwmac->reg + MAC_CTRL_REG); 68 val &= ~(GMAC_CONFIG_PS | GMAC_CONFIG_FES); 69 70 switch (speed) { 71 case SPEED_1000: 72 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) 73 clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M; 74 break; 75 case SPEED_100: 76 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) 77 clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_25M; 78 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII) 79 clk_sel_val = ETHER_CLK_SEL_DIV_SEL_2; 80 val |= GMAC_CONFIG_PS | GMAC_CONFIG_FES; 81 break; 82 case SPEED_10: 83 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) 84 clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_2P5M; 85 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII) 86 clk_sel_val = ETHER_CLK_SEL_DIV_SEL_20; 87 val |= GMAC_CONFIG_PS; 88 break; 89 default: 90 /* No bit control */ 91 netdev_err(netdev, "Unsupported speed request (%d)", speed); 92 spin_unlock_irqrestore(&dwmac->lock, flags); 93 return; 94 } 95 96 writel(val, dwmac->reg + MAC_CTRL_REG); 97 98 /* Stop internal clock */ 99 val = readl(dwmac->reg + REG_ETHER_CLOCK_SEL); 100 val &= ~(ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN); 101 val |= ETHER_CLK_SEL_TX_O_E_N_IN; 102 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 103 104 /* Set Clock-Mux, Start clock, Set TX_O direction */ 105 switch (dwmac->phy_intf_sel) { 106 case ETHER_CONFIG_INTF_RGMII: 107 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC; 108 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 109 110 val |= ETHER_CLK_SEL_RX_TX_CLK_EN; 111 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 112 113 val &= ~ETHER_CLK_SEL_TX_O_E_N_IN; 114 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 115 break; 116 case ETHER_CONFIG_INTF_RMII: 117 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV | 118 ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN | 119 ETHER_CLK_SEL_RMII_CLK_SEL_RX_C; 120 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 121 122 val |= ETHER_CLK_SEL_RMII_CLK_RST; 123 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 124 125 val |= ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN; 126 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 127 break; 128 case ETHER_CONFIG_INTF_MII: 129 default: 130 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC | 131 ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN; 132 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 133 134 val |= ETHER_CLK_SEL_RX_TX_CLK_EN; 135 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 136 break; 137 } 138 139 spin_unlock_irqrestore(&dwmac->lock, flags); 140 } 141 142 static int visconti_eth_init_hw(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat) 143 { 144 struct visconti_eth *dwmac = plat_dat->bsp_priv; 145 unsigned int reg_val, clk_sel_val; 146 147 switch (plat_dat->phy_interface) { 148 case PHY_INTERFACE_MODE_RGMII: 149 case PHY_INTERFACE_MODE_RGMII_ID: 150 case PHY_INTERFACE_MODE_RGMII_RXID: 151 case PHY_INTERFACE_MODE_RGMII_TXID: 152 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RGMII; 153 break; 154 case PHY_INTERFACE_MODE_MII: 155 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_MII; 156 break; 157 case PHY_INTERFACE_MODE_RMII: 158 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RMII; 159 break; 160 default: 161 dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n", plat_dat->phy_interface); 162 return -EOPNOTSUPP; 163 } 164 165 reg_val = dwmac->phy_intf_sel; 166 writel(reg_val, dwmac->reg + REG_ETHER_CONTROL); 167 168 /* Enable TX/RX clock */ 169 clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M; 170 writel(clk_sel_val, dwmac->reg + REG_ETHER_CLOCK_SEL); 171 172 writel((clk_sel_val | ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN), 173 dwmac->reg + REG_ETHER_CLOCK_SEL); 174 175 /* release internal-reset */ 176 reg_val |= ETHER_ETH_CONTROL_RESET; 177 writel(reg_val, dwmac->reg + REG_ETHER_CONTROL); 178 179 return 0; 180 } 181 182 static int visconti_eth_clock_probe(struct platform_device *pdev, 183 struct plat_stmmacenet_data *plat_dat) 184 { 185 struct visconti_eth *dwmac = plat_dat->bsp_priv; 186 int err; 187 188 dwmac->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk"); 189 if (IS_ERR(dwmac->phy_ref_clk)) 190 return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->phy_ref_clk), 191 "phy_ref_clk clock not found.\n"); 192 193 err = clk_prepare_enable(dwmac->phy_ref_clk); 194 if (err < 0) { 195 dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n", err); 196 return err; 197 } 198 199 return 0; 200 } 201 202 static void visconti_eth_clock_remove(struct platform_device *pdev) 203 { 204 struct visconti_eth *dwmac = get_stmmac_bsp_priv(&pdev->dev); 205 struct net_device *ndev = platform_get_drvdata(pdev); 206 struct stmmac_priv *priv = netdev_priv(ndev); 207 208 clk_disable_unprepare(dwmac->phy_ref_clk); 209 clk_disable_unprepare(priv->plat->stmmac_clk); 210 } 211 212 static int visconti_eth_dwmac_probe(struct platform_device *pdev) 213 { 214 struct plat_stmmacenet_data *plat_dat; 215 struct stmmac_resources stmmac_res; 216 struct visconti_eth *dwmac; 217 int ret; 218 219 ret = stmmac_get_platform_resources(pdev, &stmmac_res); 220 if (ret) 221 return ret; 222 223 plat_dat = stmmac_probe_config_dt(pdev, stmmac_res.mac); 224 if (IS_ERR(plat_dat)) 225 return PTR_ERR(plat_dat); 226 227 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); 228 if (!dwmac) { 229 ret = -ENOMEM; 230 goto remove_config; 231 } 232 233 spin_lock_init(&dwmac->lock); 234 dwmac->reg = stmmac_res.addr; 235 dwmac->dev = &pdev->dev; 236 plat_dat->bsp_priv = dwmac; 237 plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed; 238 239 ret = visconti_eth_clock_probe(pdev, plat_dat); 240 if (ret) 241 goto remove_config; 242 243 visconti_eth_init_hw(pdev, plat_dat); 244 245 plat_dat->dma_cfg->aal = 1; 246 247 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 248 if (ret) 249 goto remove; 250 251 return ret; 252 253 remove: 254 visconti_eth_clock_remove(pdev); 255 remove_config: 256 stmmac_remove_config_dt(pdev, plat_dat); 257 258 return ret; 259 } 260 261 static void visconti_eth_dwmac_remove(struct platform_device *pdev) 262 { 263 struct net_device *ndev = platform_get_drvdata(pdev); 264 struct stmmac_priv *priv = netdev_priv(ndev); 265 266 stmmac_pltfr_remove(pdev); 267 268 visconti_eth_clock_remove(pdev); 269 270 stmmac_remove_config_dt(pdev, priv->plat); 271 } 272 273 static const struct of_device_id visconti_eth_dwmac_match[] = { 274 { .compatible = "toshiba,visconti-dwmac" }, 275 { } 276 }; 277 MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match); 278 279 static struct platform_driver visconti_eth_dwmac_driver = { 280 .probe = visconti_eth_dwmac_probe, 281 .remove_new = visconti_eth_dwmac_remove, 282 .driver = { 283 .name = "visconti-eth-dwmac", 284 .of_match_table = visconti_eth_dwmac_match, 285 }, 286 }; 287 module_platform_driver(visconti_eth_dwmac_driver); 288 289 MODULE_AUTHOR("Toshiba"); 290 MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver"); 291 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp"); 292 MODULE_LICENSE("GPL v2"); 293