1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * NXP S32G/R GMAC glue layer 4 * 5 * Copyright 2019-2024 NXP 6 * 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/clk-provider.h> 11 #include <linux/device.h> 12 #include <linux/ethtool.h> 13 #include <linux/io.h> 14 #include <linux/mfd/syscon.h> 15 #include <linux/module.h> 16 #include <linux/of_mdio.h> 17 #include <linux/of_address.h> 18 #include <linux/phy.h> 19 #include <linux/phylink.h> 20 #include <linux/platform_device.h> 21 #include <linux/regmap.h> 22 #include <linux/stmmac.h> 23 24 #include "stmmac_platform.h" 25 26 #define GMAC_INTF_RATE_125M 125000000 /* 125MHz */ 27 28 /* SoC PHY interface control register */ 29 #define S32_PHY_INTF_SEL_MII 0x00 30 #define S32_PHY_INTF_SEL_SGMII 0x01 31 #define S32_PHY_INTF_SEL_RGMII 0x02 32 #define S32_PHY_INTF_SEL_RMII 0x08 33 34 struct s32_priv_data { 35 void __iomem *ioaddr; 36 void __iomem *ctrl_sts; 37 struct regmap *sts_regmap; 38 unsigned int sts_offset; 39 struct device *dev; 40 phy_interface_t *intf_mode; 41 struct clk *tx_clk; 42 struct clk *rx_clk; 43 }; 44 45 static int s32_gmac_write_phy_intf_select(struct s32_priv_data *gmac) 46 { 47 int ret = 0; 48 49 if (gmac->ctrl_sts) 50 writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts); 51 else 52 ret = regmap_write(gmac->sts_regmap, gmac->sts_offset, 53 S32_PHY_INTF_SEL_RGMII); 54 55 dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(*gmac->intf_mode)); 56 57 return ret; 58 } 59 60 static int s32_gmac_init(struct device *dev, void *priv) 61 { 62 struct s32_priv_data *gmac = priv; 63 int ret; 64 65 /* Set initial TX interface clock */ 66 ret = clk_prepare_enable(gmac->tx_clk); 67 if (ret) { 68 dev_err(dev, "Can't enable tx clock\n"); 69 return ret; 70 } 71 ret = clk_set_rate(gmac->tx_clk, GMAC_INTF_RATE_125M); 72 if (ret) { 73 dev_err(dev, "Can't set tx clock\n"); 74 goto err_tx_disable; 75 } 76 77 /* Set initial RX interface clock */ 78 ret = clk_prepare_enable(gmac->rx_clk); 79 if (ret) { 80 dev_err(dev, "Can't enable rx clock\n"); 81 goto err_tx_disable; 82 } 83 ret = clk_set_rate(gmac->rx_clk, GMAC_INTF_RATE_125M); 84 if (ret) { 85 dev_err(dev, "Can't set rx clock\n"); 86 goto err_txrx_disable; 87 } 88 89 /* Set interface mode */ 90 ret = s32_gmac_write_phy_intf_select(gmac); 91 if (ret) { 92 dev_err(dev, "Can't set PHY interface mode\n"); 93 goto err_txrx_disable; 94 } 95 96 return 0; 97 98 err_txrx_disable: 99 clk_disable_unprepare(gmac->rx_clk); 100 err_tx_disable: 101 clk_disable_unprepare(gmac->tx_clk); 102 return ret; 103 } 104 105 static void s32_gmac_exit(struct device *dev, void *priv) 106 { 107 struct s32_priv_data *gmac = priv; 108 109 clk_disable_unprepare(gmac->tx_clk); 110 clk_disable_unprepare(gmac->rx_clk); 111 } 112 113 static int s32_dwmac_probe(struct platform_device *pdev) 114 { 115 struct plat_stmmacenet_data *plat; 116 struct device *dev = &pdev->dev; 117 struct stmmac_resources res; 118 struct s32_priv_data *gmac; 119 int ret; 120 121 gmac = devm_kzalloc(&pdev->dev, sizeof(*gmac), GFP_KERNEL); 122 if (!gmac) 123 return -ENOMEM; 124 125 gmac->dev = &pdev->dev; 126 127 ret = stmmac_get_platform_resources(pdev, &res); 128 if (ret) 129 return dev_err_probe(dev, ret, 130 "Failed to get platform resources\n"); 131 132 plat = devm_stmmac_probe_config_dt(pdev, res.mac); 133 if (IS_ERR(plat)) 134 return dev_err_probe(dev, PTR_ERR(plat), 135 "dt configuration failed\n"); 136 137 /* PHY interface mode control reg */ 138 gmac->sts_regmap = syscon_regmap_lookup_by_phandle_args(dev->of_node, 139 "nxp,phy-sel", 1, &gmac->sts_offset); 140 if (gmac->sts_regmap == ERR_PTR(-EPROBE_DEFER)) 141 return PTR_ERR(gmac->sts_regmap); 142 if (IS_ERR(gmac->sts_regmap)) { 143 gmac->ctrl_sts = devm_platform_get_and_ioremap_resource(pdev, 1, NULL); 144 if (IS_ERR(gmac->ctrl_sts)) 145 return dev_err_probe(dev, PTR_ERR(gmac->ctrl_sts), 146 "S32CC config region is missing\n"); 147 } 148 149 /* tx clock */ 150 gmac->tx_clk = devm_clk_get(&pdev->dev, "tx"); 151 if (IS_ERR(gmac->tx_clk)) 152 return dev_err_probe(dev, PTR_ERR(gmac->tx_clk), 153 "tx clock not found\n"); 154 155 /* rx clock */ 156 gmac->rx_clk = devm_clk_get(&pdev->dev, "rx"); 157 if (IS_ERR(gmac->rx_clk)) 158 return dev_err_probe(dev, PTR_ERR(gmac->rx_clk), 159 "rx clock not found\n"); 160 161 gmac->intf_mode = &plat->phy_interface; 162 gmac->ioaddr = res.addr; 163 164 /* S32CC core feature set */ 165 plat->core_type = DWMAC_CORE_GMAC4; 166 plat->pmt = 1; 167 plat->flags |= STMMAC_FLAG_SPH_DISABLE; 168 plat->rx_fifo_size = 20480; 169 plat->tx_fifo_size = 20480; 170 171 plat->init = s32_gmac_init; 172 plat->exit = s32_gmac_exit; 173 174 plat->clk_tx_i = gmac->tx_clk; 175 plat->set_clk_tx_rate = stmmac_set_clk_tx_rate; 176 177 plat->bsp_priv = gmac; 178 179 return stmmac_pltfr_probe(pdev, plat, &res); 180 } 181 182 static const struct of_device_id s32_dwmac_match[] = { 183 { .compatible = "nxp,s32g2-dwmac" }, 184 { } 185 }; 186 MODULE_DEVICE_TABLE(of, s32_dwmac_match); 187 188 static struct platform_driver s32_dwmac_driver = { 189 .probe = s32_dwmac_probe, 190 .remove = stmmac_pltfr_remove, 191 .driver = { 192 .name = "s32-dwmac", 193 .pm = &stmmac_pltfr_pm_ops, 194 .of_match_table = s32_dwmac_match, 195 }, 196 }; 197 module_platform_driver(s32_dwmac_driver); 198 199 MODULE_AUTHOR("Jan Petrous (OSS) <jan.petrous@oss.nxp.com>"); 200 MODULE_DESCRIPTION("NXP S32G/R common chassis GMAC driver"); 201 MODULE_LICENSE("GPL"); 202 203