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 void s32_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode) 104 { 105 struct s32_priv_data *gmac = priv; 106 long tx_clk_rate; 107 int ret; 108 109 tx_clk_rate = rgmii_clock(speed); 110 if (tx_clk_rate < 0) { 111 dev_err(gmac->dev, "Unsupported/Invalid speed: %d\n", speed); 112 return; 113 } 114 115 dev_dbg(gmac->dev, "Set tx clock to %ld Hz\n", tx_clk_rate); 116 ret = clk_set_rate(gmac->tx_clk, tx_clk_rate); 117 if (ret) 118 dev_err(gmac->dev, "Can't set tx clock\n"); 119 } 120 121 static int s32_dwmac_probe(struct platform_device *pdev) 122 { 123 struct plat_stmmacenet_data *plat; 124 struct device *dev = &pdev->dev; 125 struct stmmac_resources res; 126 struct s32_priv_data *gmac; 127 int ret; 128 129 gmac = devm_kzalloc(&pdev->dev, sizeof(*gmac), GFP_KERNEL); 130 if (!gmac) 131 return -ENOMEM; 132 133 gmac->dev = &pdev->dev; 134 135 ret = stmmac_get_platform_resources(pdev, &res); 136 if (ret) 137 return dev_err_probe(dev, ret, 138 "Failed to get platform resources\n"); 139 140 plat = devm_stmmac_probe_config_dt(pdev, res.mac); 141 if (IS_ERR(plat)) 142 return dev_err_probe(dev, PTR_ERR(plat), 143 "dt configuration failed\n"); 144 145 /* PHY interface mode control reg */ 146 gmac->ctrl_sts = devm_platform_get_and_ioremap_resource(pdev, 1, NULL); 147 if (IS_ERR(gmac->ctrl_sts)) 148 return dev_err_probe(dev, PTR_ERR(gmac->ctrl_sts), 149 "S32CC config region is missing\n"); 150 151 /* tx clock */ 152 gmac->tx_clk = devm_clk_get(&pdev->dev, "tx"); 153 if (IS_ERR(gmac->tx_clk)) 154 return dev_err_probe(dev, PTR_ERR(gmac->tx_clk), 155 "tx clock not found\n"); 156 157 /* rx clock */ 158 gmac->rx_clk = devm_clk_get(&pdev->dev, "rx"); 159 if (IS_ERR(gmac->rx_clk)) 160 return dev_err_probe(dev, PTR_ERR(gmac->rx_clk), 161 "rx clock not found\n"); 162 163 gmac->intf_mode = &plat->phy_interface; 164 gmac->ioaddr = res.addr; 165 166 /* S32CC core feature set */ 167 plat->has_gmac4 = true; 168 plat->pmt = 1; 169 plat->flags |= STMMAC_FLAG_SPH_DISABLE; 170 plat->rx_fifo_size = 20480; 171 plat->tx_fifo_size = 20480; 172 173 plat->init = s32_gmac_init; 174 plat->exit = s32_gmac_exit; 175 plat->fix_mac_speed = s32_fix_mac_speed; 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