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 dev_err(&pdev->dev, "phy_ref_clk clock not found.\n"); 176 return PTR_ERR(dwmac->phy_ref_clk); 177 } 178 179 err = clk_prepare_enable(dwmac->phy_ref_clk); 180 if (err < 0) { 181 dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n", err); 182 return err; 183 } 184 185 return 0; 186 } 187 188 static int visconti_eth_clock_remove(struct platform_device *pdev) 189 { 190 struct visconti_eth *dwmac = get_stmmac_bsp_priv(&pdev->dev); 191 struct net_device *ndev = platform_get_drvdata(pdev); 192 struct stmmac_priv *priv = netdev_priv(ndev); 193 194 clk_disable_unprepare(dwmac->phy_ref_clk); 195 clk_disable_unprepare(priv->plat->stmmac_clk); 196 197 return 0; 198 } 199 200 static int visconti_eth_dwmac_probe(struct platform_device *pdev) 201 { 202 struct plat_stmmacenet_data *plat_dat; 203 struct stmmac_resources stmmac_res; 204 struct visconti_eth *dwmac; 205 int ret; 206 207 ret = stmmac_get_platform_resources(pdev, &stmmac_res); 208 if (ret) 209 return ret; 210 211 plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); 212 if (IS_ERR(plat_dat)) 213 return PTR_ERR(plat_dat); 214 215 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); 216 if (!dwmac) { 217 ret = -ENOMEM; 218 goto remove_config; 219 } 220 221 spin_lock_init(&dwmac->lock); 222 dwmac->reg = stmmac_res.addr; 223 plat_dat->bsp_priv = dwmac; 224 plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed; 225 226 ret = visconti_eth_clock_probe(pdev, plat_dat); 227 if (ret) 228 goto remove_config; 229 230 visconti_eth_init_hw(pdev, plat_dat); 231 232 plat_dat->dma_cfg->aal = 1; 233 234 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 235 if (ret) 236 goto remove; 237 238 return ret; 239 240 remove: 241 visconti_eth_clock_remove(pdev); 242 remove_config: 243 stmmac_remove_config_dt(pdev, plat_dat); 244 245 return ret; 246 } 247 248 static int visconti_eth_dwmac_remove(struct platform_device *pdev) 249 { 250 struct net_device *ndev = platform_get_drvdata(pdev); 251 struct stmmac_priv *priv = netdev_priv(ndev); 252 int err; 253 254 err = stmmac_pltfr_remove(pdev); 255 if (err < 0) 256 dev_err(&pdev->dev, "failed to remove platform: %d\n", err); 257 258 err = visconti_eth_clock_remove(pdev); 259 if (err < 0) 260 dev_err(&pdev->dev, "failed to remove clock: %d\n", err); 261 262 stmmac_remove_config_dt(pdev, priv->plat); 263 264 return err; 265 } 266 267 static const struct of_device_id visconti_eth_dwmac_match[] = { 268 { .compatible = "toshiba,visconti-dwmac" }, 269 { } 270 }; 271 MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match); 272 273 static struct platform_driver visconti_eth_dwmac_driver = { 274 .probe = visconti_eth_dwmac_probe, 275 .remove = visconti_eth_dwmac_remove, 276 .driver = { 277 .name = "visconti-eth-dwmac", 278 .of_match_table = visconti_eth_dwmac_match, 279 }, 280 }; 281 module_platform_driver(visconti_eth_dwmac_driver); 282 283 MODULE_AUTHOR("Toshiba"); 284 MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver"); 285 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp"); 286 MODULE_LICENSE("GPL v2"); 287