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
s32_gmac_write_phy_intf_select(struct s32_priv_data * gmac)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
s32_gmac_init(struct platform_device * pdev,void * priv)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
s32_gmac_exit(struct platform_device * pdev,void * priv)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
s32_fix_mac_speed(void * priv,unsigned int speed,unsigned int mode)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
s32_dwmac_probe(struct platform_device * pdev)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) <[email protected]>");
200 MODULE_DESCRIPTION("NXP S32G/R common chassis GMAC driver");
201 MODULE_LICENSE("GPL");
202
203