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 }; 55 56 static int visconti_eth_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, 57 phy_interface_t interface, int speed) 58 { 59 struct visconti_eth *dwmac = bsp_priv; 60 struct net_device *netdev = dev_get_drvdata(dwmac->dev); 61 unsigned int val, clk_sel_val = 0; 62 63 switch (speed) { 64 case SPEED_1000: 65 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) 66 clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M; 67 break; 68 case SPEED_100: 69 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) 70 clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_25M; 71 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII) 72 clk_sel_val = ETHER_CLK_SEL_DIV_SEL_2; 73 break; 74 case SPEED_10: 75 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) 76 clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_2P5M; 77 if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII) 78 clk_sel_val = ETHER_CLK_SEL_DIV_SEL_20; 79 break; 80 default: 81 /* No bit control */ 82 netdev_err(netdev, "Unsupported speed request (%d)", speed); 83 return -EINVAL; 84 } 85 86 /* Stop internal clock */ 87 val = readl(dwmac->reg + REG_ETHER_CLOCK_SEL); 88 val &= ~(ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN); 89 val |= ETHER_CLK_SEL_TX_O_E_N_IN; 90 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 91 92 /* Set Clock-Mux, Start clock, Set TX_O direction */ 93 switch (dwmac->phy_intf_sel) { 94 case ETHER_CONFIG_INTF_RGMII: 95 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC; 96 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 97 98 val |= ETHER_CLK_SEL_RX_TX_CLK_EN; 99 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 100 101 val &= ~ETHER_CLK_SEL_TX_O_E_N_IN; 102 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 103 break; 104 case ETHER_CONFIG_INTF_RMII: 105 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV | 106 ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN | 107 ETHER_CLK_SEL_RMII_CLK_SEL_RX_C; 108 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 109 110 val |= ETHER_CLK_SEL_RMII_CLK_RST; 111 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 112 113 val |= ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN; 114 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 115 break; 116 case ETHER_CONFIG_INTF_MII: 117 default: 118 val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC | 119 ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN; 120 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 121 122 val |= ETHER_CLK_SEL_RX_TX_CLK_EN; 123 writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); 124 break; 125 } 126 127 return 0; 128 } 129 130 static int visconti_eth_init_hw(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat) 131 { 132 struct visconti_eth *dwmac = plat_dat->bsp_priv; 133 unsigned int reg_val, clk_sel_val; 134 135 switch (plat_dat->phy_interface) { 136 case PHY_INTERFACE_MODE_RGMII: 137 case PHY_INTERFACE_MODE_RGMII_ID: 138 case PHY_INTERFACE_MODE_RGMII_RXID: 139 case PHY_INTERFACE_MODE_RGMII_TXID: 140 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RGMII; 141 break; 142 case PHY_INTERFACE_MODE_MII: 143 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_MII; 144 break; 145 case PHY_INTERFACE_MODE_RMII: 146 dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RMII; 147 break; 148 default: 149 dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n", plat_dat->phy_interface); 150 return -EOPNOTSUPP; 151 } 152 153 reg_val = dwmac->phy_intf_sel; 154 writel(reg_val, dwmac->reg + REG_ETHER_CONTROL); 155 156 /* Enable TX/RX clock */ 157 clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M; 158 writel(clk_sel_val, dwmac->reg + REG_ETHER_CLOCK_SEL); 159 160 writel((clk_sel_val | ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN), 161 dwmac->reg + REG_ETHER_CLOCK_SEL); 162 163 /* release internal-reset */ 164 reg_val |= ETHER_ETH_CONTROL_RESET; 165 writel(reg_val, dwmac->reg + REG_ETHER_CONTROL); 166 167 return 0; 168 } 169 170 static int visconti_eth_clock_probe(struct platform_device *pdev, 171 struct plat_stmmacenet_data *plat_dat) 172 { 173 struct visconti_eth *dwmac = plat_dat->bsp_priv; 174 int err; 175 176 dwmac->phy_ref_clk = devm_clk_get(&pdev->dev, "phy_ref_clk"); 177 if (IS_ERR(dwmac->phy_ref_clk)) 178 return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->phy_ref_clk), 179 "phy_ref_clk clock not found.\n"); 180 181 err = clk_prepare_enable(dwmac->phy_ref_clk); 182 if (err < 0) { 183 dev_err(&pdev->dev, "failed to enable phy_ref clock: %d\n", err); 184 return err; 185 } 186 187 return 0; 188 } 189 190 static void visconti_eth_clock_remove(struct platform_device *pdev) 191 { 192 struct visconti_eth *dwmac = get_stmmac_bsp_priv(&pdev->dev); 193 struct net_device *ndev = platform_get_drvdata(pdev); 194 struct stmmac_priv *priv = netdev_priv(ndev); 195 196 clk_disable_unprepare(dwmac->phy_ref_clk); 197 clk_disable_unprepare(priv->plat->stmmac_clk); 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 = devm_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 return -ENOMEM; 218 219 dwmac->reg = stmmac_res.addr; 220 dwmac->dev = &pdev->dev; 221 plat_dat->bsp_priv = dwmac; 222 plat_dat->set_clk_tx_rate = visconti_eth_set_clk_tx_rate; 223 224 ret = visconti_eth_clock_probe(pdev, plat_dat); 225 if (ret) 226 return ret; 227 228 visconti_eth_init_hw(pdev, plat_dat); 229 230 plat_dat->dma_cfg->aal = 1; 231 232 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 233 if (ret) 234 goto remove; 235 236 return ret; 237 238 remove: 239 visconti_eth_clock_remove(pdev); 240 241 return ret; 242 } 243 244 static void visconti_eth_dwmac_remove(struct platform_device *pdev) 245 { 246 stmmac_pltfr_remove(pdev); 247 visconti_eth_clock_remove(pdev); 248 } 249 250 static const struct of_device_id visconti_eth_dwmac_match[] = { 251 { .compatible = "toshiba,visconti-dwmac" }, 252 { } 253 }; 254 MODULE_DEVICE_TABLE(of, visconti_eth_dwmac_match); 255 256 static struct platform_driver visconti_eth_dwmac_driver = { 257 .probe = visconti_eth_dwmac_probe, 258 .remove = visconti_eth_dwmac_remove, 259 .driver = { 260 .name = "visconti-eth-dwmac", 261 .of_match_table = visconti_eth_dwmac_match, 262 }, 263 }; 264 module_platform_driver(visconti_eth_dwmac_driver); 265 266 MODULE_AUTHOR("Toshiba"); 267 MODULE_DESCRIPTION("Toshiba Visconti Ethernet DWMAC glue driver"); 268 MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp"); 269 MODULE_LICENSE("GPL v2"); 270