1 // SPDX-License-Identifier: GPL-2.0 2 /* Intel DWMAC platform driver 3 * 4 * Copyright(C) 2020 Intel Corporation 5 */ 6 7 #include <linux/ethtool.h> 8 #include <linux/module.h> 9 #include <linux/of.h> 10 #include <linux/platform_device.h> 11 #include <linux/property.h> 12 #include <linux/stmmac.h> 13 14 #include "dwmac4.h" 15 #include "stmmac.h" 16 #include "stmmac_platform.h" 17 18 struct intel_dwmac { 19 struct device *dev; 20 struct clk *tx_clk; 21 const struct intel_dwmac_data *data; 22 }; 23 24 struct intel_dwmac_data { 25 unsigned long ptp_ref_clk_rate; 26 unsigned long tx_clk_rate; 27 bool tx_clk_en; 28 }; 29 30 static const struct intel_dwmac_data kmb_data = { 31 .ptp_ref_clk_rate = 200000000, 32 .tx_clk_rate = 125000000, 33 .tx_clk_en = true, 34 }; 35 36 static const struct of_device_id intel_eth_plat_match[] = { 37 { .compatible = "intel,keembay-dwmac", .data = &kmb_data }, 38 { } 39 }; 40 MODULE_DEVICE_TABLE(of, intel_eth_plat_match); 41 42 static int intel_eth_plat_probe(struct platform_device *pdev) 43 { 44 struct plat_stmmacenet_data *plat_dat; 45 struct stmmac_resources stmmac_res; 46 struct intel_dwmac *dwmac; 47 unsigned long rate; 48 int ret; 49 50 ret = stmmac_get_platform_resources(pdev, &stmmac_res); 51 if (ret) 52 return ret; 53 54 plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); 55 if (IS_ERR(plat_dat)) { 56 dev_err(&pdev->dev, "dt configuration failed\n"); 57 return PTR_ERR(plat_dat); 58 } 59 60 dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); 61 if (!dwmac) 62 return -ENOMEM; 63 64 dwmac->dev = &pdev->dev; 65 dwmac->tx_clk = NULL; 66 67 /* 68 * This cannot return NULL at this point because the driver’s 69 * compatibility with the device has already been validated in 70 * platform_match(). 71 */ 72 dwmac->data = device_get_match_data(&pdev->dev); 73 74 /* Enable TX clock */ 75 if (dwmac->data->tx_clk_en) { 76 dwmac->tx_clk = devm_clk_get(&pdev->dev, "tx_clk"); 77 if (IS_ERR(dwmac->tx_clk)) 78 return PTR_ERR(dwmac->tx_clk); 79 80 ret = clk_prepare_enable(dwmac->tx_clk); 81 if (ret) { 82 dev_err(&pdev->dev, 83 "Failed to enable tx_clk\n"); 84 return ret; 85 } 86 87 /* Check and configure TX clock rate */ 88 rate = clk_get_rate(dwmac->tx_clk); 89 if (dwmac->data->tx_clk_rate && 90 rate != dwmac->data->tx_clk_rate) { 91 rate = dwmac->data->tx_clk_rate; 92 ret = clk_set_rate(dwmac->tx_clk, rate); 93 if (ret) { 94 dev_err(&pdev->dev, 95 "Failed to set tx_clk\n"); 96 goto err_tx_clk_disable; 97 } 98 } 99 100 /* Check and configure PTP ref clock rate */ 101 rate = clk_get_rate(plat_dat->clk_ptp_ref); 102 if (dwmac->data->ptp_ref_clk_rate && 103 rate != dwmac->data->ptp_ref_clk_rate) { 104 rate = dwmac->data->ptp_ref_clk_rate; 105 ret = clk_set_rate(plat_dat->clk_ptp_ref, rate); 106 if (ret) { 107 dev_err(&pdev->dev, 108 "Failed to set clk_ptp_ref\n"); 109 goto err_tx_clk_disable; 110 } 111 } 112 } 113 114 plat_dat->clk_tx_i = dwmac->tx_clk; 115 plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate; 116 117 plat_dat->bsp_priv = dwmac; 118 plat_dat->eee_usecs_rate = plat_dat->clk_ptp_rate; 119 120 if (plat_dat->eee_usecs_rate > 0) { 121 u32 tx_lpi_usec; 122 123 tx_lpi_usec = (plat_dat->eee_usecs_rate / 1000000) - 1; 124 writel(tx_lpi_usec, stmmac_res.addr + GMAC_1US_TIC_COUNTER); 125 } 126 127 ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); 128 if (ret) 129 goto err_tx_clk_disable; 130 131 return 0; 132 133 err_tx_clk_disable: 134 if (dwmac->data->tx_clk_en) 135 clk_disable_unprepare(dwmac->tx_clk); 136 return ret; 137 } 138 139 static void intel_eth_plat_remove(struct platform_device *pdev) 140 { 141 struct intel_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev); 142 143 stmmac_pltfr_remove(pdev); 144 if (dwmac->data->tx_clk_en) 145 clk_disable_unprepare(dwmac->tx_clk); 146 } 147 148 static struct platform_driver intel_eth_plat_driver = { 149 .probe = intel_eth_plat_probe, 150 .remove = intel_eth_plat_remove, 151 .driver = { 152 .name = "intel-eth-plat", 153 .pm = &stmmac_pltfr_pm_ops, 154 .of_match_table = intel_eth_plat_match, 155 }, 156 }; 157 module_platform_driver(intel_eth_plat_driver); 158 159 MODULE_LICENSE("GPL v2"); 160 MODULE_DESCRIPTION("Intel DWMAC platform driver"); 161