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