1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2018 MediaTek Inc. 4 */ 5 #include <linux/bitfield.h> 6 #include <linux/io.h> 7 #include <linux/mfd/syscon.h> 8 #include <linux/module.h> 9 #include <linux/of.h> 10 #include <linux/of_device.h> 11 #include <linux/of_net.h> 12 #include <linux/pm_runtime.h> 13 #include <linux/regmap.h> 14 #include <linux/stmmac.h> 15 16 #include "stmmac.h" 17 #include "stmmac_platform.h" 18 19 /* Peri Configuration register for mt2712 */ 20 #define PERI_ETH_PHY_INTF_SEL 0x418 21 #define PHY_INTF_MII 0 22 #define PHY_INTF_RGMII 1 23 #define PHY_INTF_RMII 4 24 #define RMII_CLK_SRC_RXC BIT(4) 25 #define RMII_CLK_SRC_INTERNAL BIT(5) 26 27 #define PERI_ETH_DLY 0x428 28 #define ETH_DLY_GTXC_INV BIT(6) 29 #define ETH_DLY_GTXC_ENABLE BIT(5) 30 #define ETH_DLY_GTXC_STAGES GENMASK(4, 0) 31 #define ETH_DLY_TXC_INV BIT(20) 32 #define ETH_DLY_TXC_ENABLE BIT(19) 33 #define ETH_DLY_TXC_STAGES GENMASK(18, 14) 34 #define ETH_DLY_RXC_INV BIT(13) 35 #define ETH_DLY_RXC_ENABLE BIT(12) 36 #define ETH_DLY_RXC_STAGES GENMASK(11, 7) 37 38 #define PERI_ETH_DLY_FINE 0x800 39 #define ETH_RMII_DLY_TX_INV BIT(2) 40 #define ETH_FINE_DLY_GTXC BIT(1) 41 #define ETH_FINE_DLY_RXC BIT(0) 42 43 struct mac_delay_struct { 44 u32 tx_delay; 45 u32 rx_delay; 46 bool tx_inv; 47 bool rx_inv; 48 }; 49 50 struct mediatek_dwmac_plat_data { 51 const struct mediatek_dwmac_variant *variant; 52 struct mac_delay_struct mac_delay; 53 struct clk_bulk_data *clks; 54 struct device_node *np; 55 struct regmap *peri_regmap; 56 struct device *dev; 57 int phy_mode; 58 bool rmii_rxc; 59 }; 60 61 struct mediatek_dwmac_variant { 62 int (*dwmac_set_phy_interface)(struct mediatek_dwmac_plat_data *plat); 63 int (*dwmac_set_delay)(struct mediatek_dwmac_plat_data *plat); 64 65 /* clock ids to be requested */ 66 const char * const *clk_list; 67 int num_clks; 68 69 u32 dma_bit_mask; 70 u32 rx_delay_max; 71 u32 tx_delay_max; 72 }; 73 74 /* list of clocks required for mac */ 75 static const char * const mt2712_dwmac_clk_l[] = { 76 "axi", "apb", "mac_main", "ptp_ref" 77 }; 78 79 static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat) 80 { 81 int rmii_rxc = plat->rmii_rxc ? RMII_CLK_SRC_RXC : 0; 82 u32 intf_val = 0; 83 84 /* select phy interface in top control domain */ 85 switch (plat->phy_mode) { 86 case PHY_INTERFACE_MODE_MII: 87 intf_val |= PHY_INTF_MII; 88 break; 89 case PHY_INTERFACE_MODE_RMII: 90 intf_val |= (PHY_INTF_RMII | rmii_rxc); 91 break; 92 case PHY_INTERFACE_MODE_RGMII: 93 case PHY_INTERFACE_MODE_RGMII_TXID: 94 case PHY_INTERFACE_MODE_RGMII_RXID: 95 case PHY_INTERFACE_MODE_RGMII_ID: 96 intf_val |= PHY_INTF_RGMII; 97 break; 98 default: 99 dev_err(plat->dev, "phy interface not supported\n"); 100 return -EINVAL; 101 } 102 103 regmap_write(plat->peri_regmap, PERI_ETH_PHY_INTF_SEL, intf_val); 104 105 return 0; 106 } 107 108 static void mt2712_delay_ps2stage(struct mediatek_dwmac_plat_data *plat) 109 { 110 struct mac_delay_struct *mac_delay = &plat->mac_delay; 111 112 switch (plat->phy_mode) { 113 case PHY_INTERFACE_MODE_MII: 114 case PHY_INTERFACE_MODE_RMII: 115 /* 550ps per stage for MII/RMII */ 116 mac_delay->tx_delay /= 550; 117 mac_delay->rx_delay /= 550; 118 break; 119 case PHY_INTERFACE_MODE_RGMII: 120 case PHY_INTERFACE_MODE_RGMII_TXID: 121 case PHY_INTERFACE_MODE_RGMII_RXID: 122 case PHY_INTERFACE_MODE_RGMII_ID: 123 /* 170ps per stage for RGMII */ 124 mac_delay->tx_delay /= 170; 125 mac_delay->rx_delay /= 170; 126 break; 127 default: 128 dev_err(plat->dev, "phy interface not supported\n"); 129 break; 130 } 131 } 132 133 static int mt2712_set_delay(struct mediatek_dwmac_plat_data *plat) 134 { 135 struct mac_delay_struct *mac_delay = &plat->mac_delay; 136 u32 delay_val = 0, fine_val = 0; 137 138 mt2712_delay_ps2stage(plat); 139 140 switch (plat->phy_mode) { 141 case PHY_INTERFACE_MODE_MII: 142 delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->tx_delay); 143 delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->tx_delay); 144 delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->tx_inv); 145 146 delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay); 147 delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay); 148 delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv); 149 break; 150 case PHY_INTERFACE_MODE_RMII: 151 /* the rmii reference clock is from external phy, 152 * and the property "rmii_rxc" indicates which pin(TXC/RXC) 153 * the reference clk is connected to. The reference clock is a 154 * received signal, so rx_delay/rx_inv are used to indicate 155 * the reference clock timing adjustment 156 */ 157 if (plat->rmii_rxc) { 158 /* the rmii reference clock from outside is connected 159 * to RXC pin, the reference clock will be adjusted 160 * by RXC delay macro circuit. 161 */ 162 delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay); 163 delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay); 164 delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv); 165 } else { 166 /* the rmii reference clock from outside is connected 167 * to TXC pin, the reference clock will be adjusted 168 * by TXC delay macro circuit. 169 */ 170 delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->rx_delay); 171 delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->rx_delay); 172 delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->rx_inv); 173 } 174 /* tx_inv will inverse the tx clock inside mac relateive to 175 * reference clock from external phy, 176 * and this bit is located in the same register with fine-tune 177 */ 178 if (mac_delay->tx_inv) 179 fine_val = ETH_RMII_DLY_TX_INV; 180 break; 181 case PHY_INTERFACE_MODE_RGMII: 182 case PHY_INTERFACE_MODE_RGMII_TXID: 183 case PHY_INTERFACE_MODE_RGMII_RXID: 184 case PHY_INTERFACE_MODE_RGMII_ID: 185 fine_val = ETH_FINE_DLY_GTXC | ETH_FINE_DLY_RXC; 186 187 delay_val |= FIELD_PREP(ETH_DLY_GTXC_ENABLE, !!mac_delay->tx_delay); 188 delay_val |= FIELD_PREP(ETH_DLY_GTXC_STAGES, mac_delay->tx_delay); 189 delay_val |= FIELD_PREP(ETH_DLY_GTXC_INV, mac_delay->tx_inv); 190 191 delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay); 192 delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay); 193 delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv); 194 break; 195 default: 196 dev_err(plat->dev, "phy interface not supported\n"); 197 return -EINVAL; 198 } 199 regmap_write(plat->peri_regmap, PERI_ETH_DLY, delay_val); 200 regmap_write(plat->peri_regmap, PERI_ETH_DLY_FINE, fine_val); 201 202 return 0; 203 } 204 205 static const struct mediatek_dwmac_variant mt2712_gmac_variant = { 206 .dwmac_set_phy_interface = mt2712_set_interface, 207 .dwmac_set_delay = mt2712_set_delay, 208 .clk_list = mt2712_dwmac_clk_l, 209 .num_clks = ARRAY_SIZE(mt2712_dwmac_clk_l), 210 .dma_bit_mask = 33, 211 .rx_delay_max = 17600, 212 .tx_delay_max = 17600, 213 }; 214 215 static int mediatek_dwmac_config_dt(struct mediatek_dwmac_plat_data *plat) 216 { 217 struct mac_delay_struct *mac_delay = &plat->mac_delay; 218 u32 tx_delay_ps, rx_delay_ps; 219 220 plat->peri_regmap = syscon_regmap_lookup_by_phandle(plat->np, "mediatek,pericfg"); 221 if (IS_ERR(plat->peri_regmap)) { 222 dev_err(plat->dev, "Failed to get pericfg syscon\n"); 223 return PTR_ERR(plat->peri_regmap); 224 } 225 226 plat->phy_mode = of_get_phy_mode(plat->np); 227 if (plat->phy_mode < 0) { 228 dev_err(plat->dev, "not find phy-mode\n"); 229 return -EINVAL; 230 } 231 232 if (!of_property_read_u32(plat->np, "mediatek,tx-delay-ps", &tx_delay_ps)) { 233 if (tx_delay_ps < plat->variant->tx_delay_max) { 234 mac_delay->tx_delay = tx_delay_ps; 235 } else { 236 dev_err(plat->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps); 237 return -EINVAL; 238 } 239 } 240 241 if (!of_property_read_u32(plat->np, "mediatek,rx-delay-ps", &rx_delay_ps)) { 242 if (rx_delay_ps < plat->variant->rx_delay_max) { 243 mac_delay->rx_delay = rx_delay_ps; 244 } else { 245 dev_err(plat->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps); 246 return -EINVAL; 247 } 248 } 249 250 mac_delay->tx_inv = of_property_read_bool(plat->np, "mediatek,txc-inverse"); 251 mac_delay->rx_inv = of_property_read_bool(plat->np, "mediatek,rxc-inverse"); 252 plat->rmii_rxc = of_property_read_bool(plat->np, "mediatek,rmii-rxc"); 253 254 return 0; 255 } 256 257 static int mediatek_dwmac_clk_init(struct mediatek_dwmac_plat_data *plat) 258 { 259 const struct mediatek_dwmac_variant *variant = plat->variant; 260 int i, num = variant->num_clks; 261 262 plat->clks = devm_kcalloc(plat->dev, num, sizeof(*plat->clks), GFP_KERNEL); 263 if (!plat->clks) 264 return -ENOMEM; 265 266 for (i = 0; i < num; i++) 267 plat->clks[i].id = variant->clk_list[i]; 268 269 return devm_clk_bulk_get(plat->dev, num, plat->clks); 270 } 271 272 static int mediatek_dwmac_init(struct platform_device *pdev, void *priv) 273 { 274 struct mediatek_dwmac_plat_data *plat = priv; 275 const struct mediatek_dwmac_variant *variant = plat->variant; 276 int ret; 277 278 ret = dma_set_mask_and_coherent(plat->dev, DMA_BIT_MASK(variant->dma_bit_mask)); 279 if (ret) { 280 dev_err(plat->dev, "No suitable DMA available, err = %d\n", ret); 281 return ret; 282 } 283 284 ret = variant->dwmac_set_phy_interface(plat); 285 if (ret) { 286 dev_err(plat->dev, "failed to set phy interface, err = %d\n", ret); 287 return ret; 288 } 289 290 ret = variant->dwmac_set_delay(plat); 291 if (ret) { 292 dev_err(plat->dev, "failed to set delay value, err = %d\n", ret); 293 return ret; 294 } 295 296 ret = clk_bulk_prepare_enable(variant->num_clks, plat->clks); 297 if (ret) { 298 dev_err(plat->dev, "failed to enable clks, err = %d\n", ret); 299 return ret; 300 } 301 302 pm_runtime_enable(&pdev->dev); 303 pm_runtime_get_sync(&pdev->dev); 304 305 return 0; 306 } 307 308 static void mediatek_dwmac_exit(struct platform_device *pdev, void *priv) 309 { 310 struct mediatek_dwmac_plat_data *plat = priv; 311 const struct mediatek_dwmac_variant *variant = plat->variant; 312 313 clk_bulk_disable_unprepare(variant->num_clks, plat->clks); 314 315 pm_runtime_put_sync(&pdev->dev); 316 pm_runtime_disable(&pdev->dev); 317 } 318 319 static int mediatek_dwmac_probe(struct platform_device *pdev) 320 { 321 struct mediatek_dwmac_plat_data *priv_plat; 322 struct plat_stmmacenet_data *plat_dat; 323 struct stmmac_resources stmmac_res; 324 int ret; 325 326 priv_plat = devm_kzalloc(&pdev->dev, sizeof(*priv_plat), GFP_KERNEL); 327 if (!priv_plat) 328 return -ENOMEM; 329 330 priv_plat->variant = of_device_get_match_data(&pdev->dev); 331 if (!priv_plat->variant) { 332 dev_err(&pdev->dev, "Missing dwmac-mediatek variant\n"); 333 return -EINVAL; 334 } 335 336 priv_plat->dev = &pdev->dev; 337 priv_plat->np = pdev->dev.of_node; 338 339 ret = mediatek_dwmac_config_dt(priv_plat); 340 if (ret) 341 return ret; 342 343 ret = mediatek_dwmac_clk_init(priv_plat); 344 if (ret) 345 return ret; 346 347 ret = stmmac_get_platform_resources(pdev, &stmmac_res); 348 if (ret) 349 return ret; 350 351 plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); 352 if (IS_ERR(plat_dat)) 353 return PTR_ERR(plat_dat); 354 355 plat_dat->interface = priv_plat->phy_mode; 356 plat_dat->has_gmac4 = 1; 357 plat_dat->has_gmac = 0; 358 plat_dat->pmt = 0; 359 plat_dat->riwt_off = 1; 360 plat_dat->maxmtu = ETH_DATA_LEN; 361 plat_dat->bsp_priv = priv_plat; 362 plat_dat->init = mediatek_dwmac_init; 363 plat_dat->exit = mediatek_dwmac_exit; 364 mediatek_dwmac_init(pdev, priv_plat); 365 366 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 367 if (ret) { 368 stmmac_remove_config_dt(pdev, plat_dat); 369 return ret; 370 } 371 372 return 0; 373 } 374 375 static const struct of_device_id mediatek_dwmac_match[] = { 376 { .compatible = "mediatek,mt2712-gmac", 377 .data = &mt2712_gmac_variant }, 378 { } 379 }; 380 381 MODULE_DEVICE_TABLE(of, mediatek_dwmac_match); 382 383 static struct platform_driver mediatek_dwmac_driver = { 384 .probe = mediatek_dwmac_probe, 385 .remove = stmmac_pltfr_remove, 386 .driver = { 387 .name = "dwmac-mediatek", 388 .pm = &stmmac_pltfr_pm_ops, 389 .of_match_table = mediatek_dwmac_match, 390 }, 391 }; 392 module_platform_driver(mediatek_dwmac_driver); 393 394 MODULE_AUTHOR("Biao Huang <biao.huang@mediatek.com>"); 395 MODULE_DESCRIPTION("MediaTek DWMAC specific glue layer"); 396 MODULE_LICENSE("GPL v2"); 397