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