xref: /linux/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c (revision a34b0e4e21d6be3c3d620aa7f9dfbf0e9550c19e)
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