File Index
Files and directories
Sign in
FILE

dwmac-sti.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * dwmac-sti.c - STMicroelectronics DWMAC Specific Glue layer
  4 *
  5 * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited
  6 * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com>
  7 * Contributors: Giuseppe Cavallaro <peppe.cavallaro@st.com>
  8 */
  9
 10#include <linux/kernel.h>
 11#include <linux/slab.h>
 12#include <linux/platform_device.h>
 13#include <linux/stmmac.h>
 14#include <linux/phy.h>
 15#include <linux/mfd/syscon.h>
 16#include <linux/module.h>
 17#include <linux/regmap.h>
 18#include <linux/clk.h>
 19#include <linux/of.h>
 20#include <linux/of_net.h>
 21
 22#include "stmmac_platform.h"
 23
 24#define DWMAC_50MHZ	50000000
 25
 26#define IS_PHY_IF_MODE_GBIT(iface)	(phy_interface_mode_is_rgmii(iface) || \
 27					 iface == PHY_INTERFACE_MODE_GMII)
 28
 29/* STiH4xx register definitions (STiH407/STiH410 families)
 30 *
 31 * Below table summarizes the clock requirement and clock sources for
 32 * supported phy interface modes with link speeds.
 33 * ________________________________________________
 34 *|  PHY_MODE	| 1000 Mbit Link | 100 Mbit Link   |
 35 * ------------------------------------------------
 36 *|	MII	|	n/a	 |	25Mhz	   |
 37 *|		|		 |	txclk	   |
 38 * ------------------------------------------------
 39 *|	GMII	|     125Mhz	 |	25Mhz	   |
 40 *|		|  clk-125/txclk |	txclk	   |
 41 * ------------------------------------------------
 42 *|	RGMII	|     125Mhz	 |	25Mhz	   |
 43 *|		|  clk-125/txclk |	clkgen     |
 44 *|		|    clkgen	 |		   |
 45 * ------------------------------------------------
 46 *|	RMII	|	n/a	 |	25Mhz	   |
 47 *|		|		 |clkgen/phyclk-in |
 48 * ------------------------------------------------
 49 *
 50 *	  Register Configuration
 51 *-------------------------------
 52 * src	 |BIT(8)| BIT(7)| BIT(6)|
 53 *-------------------------------
 54 * txclk |   0	|  n/a	|   1	|
 55 *-------------------------------
 56 * ck_125|   0	|  n/a	|   0	|
 57 *-------------------------------
 58 * phyclk|   1	|   0	|  n/a	|
 59 *-------------------------------
 60 * clkgen|   1	|   1	|  n/a	|
 61 *-------------------------------
 62 */
 63
 64#define STIH4XX_RETIME_SRC_MASK			GENMASK(8, 6)
 65#define STIH4XX_ETH_SEL_TX_RETIME_CLK		BIT(8)
 66#define STIH4XX_ETH_SEL_INTERNAL_NOTEXT_PHYCLK	BIT(7)
 67#define STIH4XX_ETH_SEL_TXCLK_NOT_CLK125	BIT(6)
 68
 69#define ENMII_MASK	GENMASK(5, 5)
 70#define ENMII		BIT(5)
 71#define EN_MASK		GENMASK(1, 1)
 72#define EN		BIT(1)
 73
 74/*
 75 * 3 bits [4:2]
 76 *	000-GMII/MII
 77 *	001-RGMII
 78 *	010-SGMII
 79 *	100-RMII
 80 * These are the DW MAC phy_intf_sel values.
 81 */
 82#define MII_PHY_SEL_MASK	GENMASK(4, 2)
 83
 84struct sti_dwmac {
 85	phy_interface_t interface;	/* MII interface */
 86	bool ext_phyclk;	/* Clock from external PHY */
 87	u32 tx_retime_src;	/* TXCLK Retiming*/
 88	struct clk *clk;	/* PHY clock */
 89	u32 ctrl_reg;		/* GMAC glue-logic control register */
 90	int clk_sel_reg;	/* GMAC ext clk selection register */
 91	struct regmap *regmap;
 92	bool gmac_en;
 93	int speed;
 94	void (*fix_retime_src)(void *priv, int speed, unsigned int mode);
 95};
 96
 97struct sti_dwmac_of_data {
 98	void (*fix_retime_src)(void *priv, int speed, unsigned int mode);
 99};
100
101enum {
102	TX_RETIME_SRC_NA = 0,
103	TX_RETIME_SRC_TXCLK = 1,
104	TX_RETIME_SRC_CLK_125,
105	TX_RETIME_SRC_PHYCLK,
106	TX_RETIME_SRC_CLKGEN,
107};
108
109static u32 stih4xx_tx_retime_val[] = {
110	[TX_RETIME_SRC_TXCLK] = STIH4XX_ETH_SEL_TXCLK_NOT_CLK125,
111	[TX_RETIME_SRC_CLK_125] = 0x0,
112	[TX_RETIME_SRC_PHYCLK] = STIH4XX_ETH_SEL_TX_RETIME_CLK,
113	[TX_RETIME_SRC_CLKGEN] = STIH4XX_ETH_SEL_TX_RETIME_CLK
114				 | STIH4XX_ETH_SEL_INTERNAL_NOTEXT_PHYCLK,
115};
116
117static void stih4xx_fix_retime_src(void *priv, int spd, unsigned int mode)
118{
119	struct sti_dwmac *dwmac = priv;
120	u32 src = dwmac->tx_retime_src;
121	u32 reg = dwmac->ctrl_reg;
122	long freq = 0;
123
124	if (dwmac->interface == PHY_INTERFACE_MODE_MII) {
125		src = TX_RETIME_SRC_TXCLK;
126	} else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) {
127		if (dwmac->ext_phyclk) {
128			src = TX_RETIME_SRC_PHYCLK;
129		} else {
130			src = TX_RETIME_SRC_CLKGEN;
131			freq = DWMAC_50MHZ;
132		}
133	} else if (phy_interface_mode_is_rgmii(dwmac->interface)) {
134		/* On GiGa clk source can be either ext or from clkgen */
135		freq = rgmii_clock(spd);
136
137		if (spd != SPEED_1000 && freq > 0)
138			/* Switch to clkgen for these speeds */
139			src = TX_RETIME_SRC_CLKGEN;
140	}
141
142	if (src == TX_RETIME_SRC_CLKGEN && freq > 0)
143		clk_set_rate(dwmac->clk, freq);
144
145	regmap_update_bits(dwmac->regmap, reg, STIH4XX_RETIME_SRC_MASK,
146			   stih4xx_tx_retime_val[src]);
147}
148
149static int sti_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel)
150{
151	struct sti_dwmac *dwmac = bsp_priv;
152	struct regmap *regmap;
153	u32 reg, val;
154
155	regmap = dwmac->regmap;
156	reg = dwmac->ctrl_reg;
157
158	if (dwmac->gmac_en)
159		regmap_update_bits(regmap, reg, EN_MASK, EN);
160
161	if (phy_intf_sel != PHY_INTF_SEL_GMII_MII &&
162	    phy_intf_sel != PHY_INTF_SEL_RGMII &&
163	    phy_intf_sel != PHY_INTF_SEL_SGMII &&
164	    phy_intf_sel != PHY_INTF_SEL_RMII)
165		phy_intf_sel = PHY_INTF_SEL_GMII_MII;
166
167	regmap_update_bits(regmap, reg, MII_PHY_SEL_MASK,
168			   FIELD_PREP(MII_PHY_SEL_MASK, phy_intf_sel));
169
170	val = (dwmac->interface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII;
171	regmap_update_bits(regmap, reg, ENMII_MASK, val);
172
173	dwmac->fix_retime_src(dwmac, dwmac->speed, 0);
174
175	return 0;
176}
177
178static int sti_dwmac_parse_data(struct sti_dwmac *dwmac,
179				struct platform_device *pdev,
180				struct plat_stmmacenet_data *plat_dat)
181{
182	struct resource *res;
183	struct device *dev = &pdev->dev;
184	struct device_node *np = dev->of_node;
185	struct regmap *regmap;
186	int err;
187
188	/* clk selection from extra syscfg register */
189	dwmac->clk_sel_reg = -ENXIO;
190	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-clkconf");
191	if (res)
192		dwmac->clk_sel_reg = res->start;
193
194	regmap = syscon_regmap_lookup_by_phandle_args(np, "st,syscon",
195						      1, &dwmac->ctrl_reg);
196	if (IS_ERR(regmap))
197		return PTR_ERR(regmap);
198
199	dwmac->interface = plat_dat->phy_interface;
200	dwmac->regmap = regmap;
201	dwmac->gmac_en = of_property_read_bool(np, "st,gmac_en");
202	dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk");
203	dwmac->tx_retime_src = TX_RETIME_SRC_NA;
204	dwmac->speed = SPEED_100;
205
206	if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) {
207		const char *rs;
208
209		dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN;
210
211		err = of_property_read_string(np, "st,tx-retime-src", &rs);
212		if (err < 0) {
213			dev_warn(dev, "Use internal clock source\n");
214		} else {
215			if (!strcasecmp(rs, "clk_125"))
216				dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125;
217			else if (!strcasecmp(rs, "txclk"))
218				dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK;
219		}
220		dwmac->speed = SPEED_1000;
221	}
222
223	dwmac->clk = devm_clk_get(dev, "sti-ethclk");
224	if (IS_ERR(dwmac->clk)) {
225		dev_warn(dev, "No phy clock provided...\n");
226		dwmac->clk = NULL;
227	}
228
229	return 0;
230}
231
232static int sti_dwmac_init(struct device *dev, void *bsp_priv)
233{
234	struct sti_dwmac *dwmac = bsp_priv;
235
236	return clk_prepare_enable(dwmac->clk);
237}
238
239static void sti_dwmac_exit(struct device *dev, void *bsp_priv)
240{
241	struct sti_dwmac *dwmac = bsp_priv;
242
243	clk_disable_unprepare(dwmac->clk);
244}
245
246static int sti_dwmac_probe(struct platform_device *pdev)
247{
248	struct plat_stmmacenet_data *plat_dat;
249	const struct sti_dwmac_of_data *data;
250	struct stmmac_resources stmmac_res;
251	struct sti_dwmac *dwmac;
252	int ret;
253
254	data = of_device_get_match_data(&pdev->dev);
255	if (!data) {
256		dev_err(&pdev->dev, "No OF match data provided\n");
257		return -EINVAL;
258	}
259
260	ret = stmmac_get_platform_resources(pdev, &stmmac_res);
261	if (ret)
262		return ret;
263
264	plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
265	if (IS_ERR(plat_dat))
266		return PTR_ERR(plat_dat);
267
268	dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
269	if (!dwmac)
270		return -ENOMEM;
271
272	ret = sti_dwmac_parse_data(dwmac, pdev, plat_dat);
273	if (ret) {
274		dev_err(&pdev->dev, "Unable to parse OF data\n");
275		return ret;
276	}
277
278	dwmac->fix_retime_src = data->fix_retime_src;
279
280	plat_dat->bsp_priv = dwmac;
281	plat_dat->set_phy_intf_sel = sti_set_phy_intf_sel;
282	plat_dat->fix_mac_speed = data->fix_retime_src;
283	plat_dat->init = sti_dwmac_init;
284	plat_dat->exit = sti_dwmac_exit;
285
286	return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
287}
288
289static const struct sti_dwmac_of_data stih4xx_dwmac_data = {
290	.fix_retime_src = stih4xx_fix_retime_src,
291};
292
293static const struct of_device_id sti_dwmac_match[] = {
294	{ .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data},
295	{ }
296};
297MODULE_DEVICE_TABLE(of, sti_dwmac_match);
298
299static struct platform_driver sti_dwmac_driver = {
300	.probe  = sti_dwmac_probe,
301	.driver = {
302		.name           = "sti-dwmac",
303		.pm		= &stmmac_pltfr_pm_ops,
304		.of_match_table = sti_dwmac_match,
305	},
306};
307module_platform_driver(sti_dwmac_driver);
308
309MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@st.com>");
310MODULE_DESCRIPTION("STMicroelectronics DWMAC Specific Glue layer");
311MODULE_LICENSE("GPL");
~/ Read-only file preview.