File Index
Files and directories
Sign in
FILE

r8a779f0-ether-serdes.c

File preview with syntax highlighting.

linux-6.19.14/drivers/phy/renesas/r8a779f0-ether-serdes.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Renesas Ethernet SERDES device driver
  3 *
  4 * Copyright (C) 2022-2025 Renesas Electronics Corporation
  5 */
  6
  7#include <linux/delay.h>
  8#include <linux/err.h>
  9#include <linux/iopoll.h>
 10#include <linux/kernel.h>
 11#include <linux/of.h>
 12#include <linux/phy.h>
 13#include <linux/phy/phy.h>
 14#include <linux/platform_device.h>
 15#include <linux/reset.h>
 16
 17#define R8A779F0_ETH_SERDES_NUM			3
 18#define R8A779F0_ETH_SERDES_OFFSET		0x0400
 19#define R8A779F0_ETH_SERDES_BANK_SELECT		0x03fc
 20#define R8A779F0_ETH_SERDES_TIMEOUT_US		100000
 21#define R8A779F0_ETH_SERDES_NUM_RETRY_LINKUP	3
 22
 23struct r8a779f0_eth_serdes_drv_data;
 24struct r8a779f0_eth_serdes_channel {
 25	struct r8a779f0_eth_serdes_drv_data *dd;
 26	struct phy *phy;
 27	void __iomem *addr;
 28	phy_interface_t phy_interface;
 29	int speed;
 30	int index;
 31};
 32
 33struct r8a779f0_eth_serdes_drv_data {
 34	void __iomem *addr;
 35	struct platform_device *pdev;
 36	struct reset_control *reset;
 37	struct r8a779f0_eth_serdes_channel channel[R8A779F0_ETH_SERDES_NUM];
 38	bool initialized;
 39};
 40
 41/*
 42 * The datasheet describes initialization procedure without any information
 43 * about registers' name/bits. So, this is all black magic to initialize
 44 * the hardware.
 45 */
 46static void r8a779f0_eth_serdes_write32(void __iomem *addr, u32 offs, u32 bank, u32 data)
 47{
 48	iowrite32(bank, addr + R8A779F0_ETH_SERDES_BANK_SELECT);
 49	iowrite32(data, addr + offs);
 50}
 51
 52static u32 r8a779f0_eth_serdes_read32(void __iomem *addr, u32 offs,  u32 bank)
 53{
 54	iowrite32(bank, addr + R8A779F0_ETH_SERDES_BANK_SELECT);
 55
 56	return ioread32(addr + offs);
 57}
 58
 59static int
 60r8a779f0_eth_serdes_reg_wait(struct r8a779f0_eth_serdes_channel *channel,
 61			     u32 offs, u32 bank, u32 mask, u32 expected)
 62{
 63	int ret;
 64	u32 val;
 65
 66	iowrite32(bank, channel->addr + R8A779F0_ETH_SERDES_BANK_SELECT);
 67
 68	ret = readl_poll_timeout_atomic(channel->addr + offs, val,
 69					(val & mask) == expected,
 70					1, R8A779F0_ETH_SERDES_TIMEOUT_US);
 71	if (ret)
 72		dev_dbg(&channel->phy->dev,
 73			"%s: index %d, offs %x, bank %x, mask %x, expected %x\n",
 74			 __func__, channel->index, offs, bank, mask, expected);
 75
 76	return ret;
 77}
 78
 79static int
 80r8a779f0_eth_serdes_common_init_ram(struct r8a779f0_eth_serdes_drv_data *dd)
 81{
 82	struct r8a779f0_eth_serdes_channel *channel;
 83	int i, ret;
 84
 85	for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
 86		channel = &dd->channel[i];
 87		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x026c, 0x180, BIT(0), 0x01);
 88		if (ret)
 89			return ret;
 90	}
 91
 92	r8a779f0_eth_serdes_write32(dd->addr, 0x026c, 0x180, 0x03);
 93
 94	return ret;
 95}
 96
 97static int
 98r8a779f0_eth_serdes_common_setting(struct r8a779f0_eth_serdes_channel *channel)
 99{
100	struct r8a779f0_eth_serdes_drv_data *dd = channel->dd;
101
102	/* Set combination mode */
103	r8a779f0_eth_serdes_write32(dd->addr, 0x0244, 0x180, 0x00d7);
104	r8a779f0_eth_serdes_write32(dd->addr, 0x01cc, 0x180, 0xc200);
105	r8a779f0_eth_serdes_write32(dd->addr, 0x01c4, 0x180, 0x0042);
106	r8a779f0_eth_serdes_write32(dd->addr, 0x01c8, 0x180, 0x0000);
107	r8a779f0_eth_serdes_write32(dd->addr, 0x01dc, 0x180, 0x002f);
108	r8a779f0_eth_serdes_write32(dd->addr, 0x01d0, 0x180, 0x0060);
109	r8a779f0_eth_serdes_write32(dd->addr, 0x01d8, 0x180, 0x2200);
110	r8a779f0_eth_serdes_write32(dd->addr, 0x01d4, 0x180, 0x0000);
111	r8a779f0_eth_serdes_write32(dd->addr, 0x01e0, 0x180, 0x003d);
112
113	return 0;
114}
115
116static int
117r8a779f0_eth_serdes_chan_setting(struct r8a779f0_eth_serdes_channel *channel)
118{
119	int ret;
120
121	switch (channel->phy_interface) {
122	case PHY_INTERFACE_MODE_SGMII:
123		r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2000);
124		r8a779f0_eth_serdes_write32(channel->addr, 0x01c0, 0x180, 0x0011);
125		r8a779f0_eth_serdes_write32(channel->addr, 0x0248, 0x180, 0x0540);
126		r8a779f0_eth_serdes_write32(channel->addr, 0x0258, 0x180, 0x0015);
127		r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0100);
128		r8a779f0_eth_serdes_write32(channel->addr, 0x01a0, 0x180, 0x0000);
129		r8a779f0_eth_serdes_write32(channel->addr, 0x00d0, 0x180, 0x0002);
130		r8a779f0_eth_serdes_write32(channel->addr, 0x0150, 0x180, 0x0003);
131		r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0100);
132		r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0100);
133		r8a779f0_eth_serdes_write32(channel->addr, 0x0174, 0x180, 0x0000);
134		r8a779f0_eth_serdes_write32(channel->addr, 0x0160, 0x180, 0x0007);
135		r8a779f0_eth_serdes_write32(channel->addr, 0x01ac, 0x180, 0x0000);
136		r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x0310);
137		r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0101);
138		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x00c8, 0x0180, BIT(0), 0);
139		if (ret)
140			return ret;
141
142		r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0101);
143		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0148, 0x0180, BIT(0), 0);
144		if (ret)
145			return ret;
146
147		r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x1310);
148		r8a779f0_eth_serdes_write32(channel->addr, 0x00d8, 0x180, 0x1800);
149		r8a779f0_eth_serdes_write32(channel->addr, 0x00dc, 0x180, 0x0000);
150		r8a779f0_eth_serdes_write32(channel->addr, 0x001c, 0x300, 0x0001);
151		r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2100);
152		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0000, 0x0380, BIT(8), 0);
153		if (ret)
154			return ret;
155
156		if (channel->speed == 1000)
157			r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x0140);
158		else if (channel->speed == 100)
159			r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x2100);
160
161		/* For AN_ON */
162		r8a779f0_eth_serdes_write32(channel->addr, 0x0004, 0x1f80, 0x0005);
163		r8a779f0_eth_serdes_write32(channel->addr, 0x0028, 0x1f80, 0x07a1);
164		r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f80, 0x0208);
165		break;
166
167	case PHY_INTERFACE_MODE_USXGMII:
168		r8a779f0_eth_serdes_write32(channel->addr, 0x001c, 0x300, 0x0000);
169		r8a779f0_eth_serdes_write32(channel->addr, 0x0014, 0x380, 0x0050);
170		r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2200);
171		r8a779f0_eth_serdes_write32(channel->addr, 0x001c, 0x380, 0x0400);
172		r8a779f0_eth_serdes_write32(channel->addr, 0x01c0, 0x180, 0x0001);
173		r8a779f0_eth_serdes_write32(channel->addr, 0x0248, 0x180, 0x056a);
174		r8a779f0_eth_serdes_write32(channel->addr, 0x0258, 0x180, 0x0015);
175		r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x1100);
176		r8a779f0_eth_serdes_write32(channel->addr, 0x01a0, 0x180, 0x0001);
177		r8a779f0_eth_serdes_write32(channel->addr, 0x00d0, 0x180, 0x0001);
178		r8a779f0_eth_serdes_write32(channel->addr, 0x0150, 0x180, 0x0001);
179		r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0300);
180		r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0300);
181		r8a779f0_eth_serdes_write32(channel->addr, 0x0174, 0x180, 0x0000);
182		r8a779f0_eth_serdes_write32(channel->addr, 0x0160, 0x180, 0x0004);
183		r8a779f0_eth_serdes_write32(channel->addr, 0x01ac, 0x180, 0x0000);
184		r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x0310);
185		r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0301);
186		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x00c8, 0x180, BIT(0), 0);
187		if (ret)
188			return ret;
189		r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0301);
190		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0148, 0x180, BIT(0), 0);
191		if (ret)
192			return ret;
193		r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x1310);
194		r8a779f0_eth_serdes_write32(channel->addr, 0x00d8, 0x180, 0x1800);
195		r8a779f0_eth_serdes_write32(channel->addr, 0x00dc, 0x180, 0x0000);
196		r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2300);
197		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0000, 0x380, BIT(8), 0);
198		if (ret)
199			return ret;
200		break;
201
202	default:
203		return -EOPNOTSUPP;
204	}
205
206	return 0;
207}
208
209static int
210r8a779f0_eth_serdes_chan_speed(struct r8a779f0_eth_serdes_channel *channel)
211{
212	int ret;
213
214	switch (channel->phy_interface) {
215	case PHY_INTERFACE_MODE_SGMII:
216		/* For AN_ON */
217		if (channel->speed == 1000)
218			r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x1140);
219		else if (channel->speed == 100)
220			r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x3100);
221		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0008, 0x1f80, BIT(0), 1);
222		if (ret)
223			return ret;
224		r8a779f0_eth_serdes_write32(channel->addr, 0x0008, 0x1f80, 0x0000);
225		break;
226	case PHY_INTERFACE_MODE_USXGMII:
227		r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x0120);
228		usleep_range(10, 20);
229		r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2600);
230		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0000, 0x380, BIT(10), 0);
231		if (ret)
232			return ret;
233		break;
234	default:
235		return -EOPNOTSUPP;
236	}
237
238	return 0;
239}
240
241
242static int r8a779f0_eth_serdes_monitor_linkup(struct r8a779f0_eth_serdes_channel *channel)
243{
244	int i, ret;
245
246	for (i = 0; i < R8A779F0_ETH_SERDES_NUM_RETRY_LINKUP; i++) {
247		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0004, 0x300,
248						   BIT(2), BIT(2));
249		if (!ret)
250			break;
251
252		/* restart */
253		r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0100);
254		udelay(1);
255		r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0000);
256	}
257
258	return ret;
259}
260
261static int r8a779f0_eth_serdes_hw_init(struct r8a779f0_eth_serdes_channel *channel)
262{
263	struct r8a779f0_eth_serdes_drv_data *dd = channel->dd;
264	int i, ret;
265
266	if (dd->initialized)
267		return 0;
268
269	reset_control_reset(dd->reset);
270
271	usleep_range(1000, 2000);
272
273	ret = r8a779f0_eth_serdes_common_init_ram(dd);
274	if (ret)
275		return ret;
276
277	for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
278		ret = r8a779f0_eth_serdes_reg_wait(&dd->channel[i], 0x0000,
279						   0x300, BIT(15), 0);
280		if (ret)
281			return ret;
282	}
283
284	for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++)
285		r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03d4, 0x380, 0x0443);
286
287	ret = r8a779f0_eth_serdes_common_setting(channel);
288	if (ret)
289		return ret;
290
291	for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++)
292		r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03d0, 0x380, 0x0001);
293
294
295	r8a779f0_eth_serdes_write32(dd->addr, 0x0000, 0x380, 0x8000);
296
297	ret = r8a779f0_eth_serdes_common_init_ram(dd);
298	if (ret)
299		return ret;
300
301	return r8a779f0_eth_serdes_reg_wait(&dd->channel[0], 0x0000, 0x380, BIT(15), 0);
302}
303
304static int r8a779f0_eth_serdes_init(struct phy *p)
305{
306	struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
307	int ret;
308
309	ret = r8a779f0_eth_serdes_hw_init(channel);
310	if (!ret)
311		channel->dd->initialized = true;
312
313	return ret;
314}
315
316static int r8a779f0_eth_serdes_exit(struct phy *p)
317{
318	struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
319
320	channel->dd->initialized = false;
321
322	return 0;
323}
324
325static int r8a779f0_eth_serdes_hw_init_late(struct r8a779f0_eth_serdes_channel
326*channel)
327{
328	int ret;
329	u32 val;
330
331	ret = r8a779f0_eth_serdes_chan_setting(channel);
332	if (ret)
333		return ret;
334
335	ret = r8a779f0_eth_serdes_chan_speed(channel);
336	if (ret)
337		return ret;
338
339	r8a779f0_eth_serdes_write32(channel->addr, 0x03c0, 0x380, 0x0000);
340
341	r8a779f0_eth_serdes_write32(channel->addr, 0x03d0, 0x380, 0x0000);
342
343	val = r8a779f0_eth_serdes_read32(channel->addr, 0x00c0, 0x180);
344	r8a779f0_eth_serdes_write32(channel->addr, 0x00c0, 0x180, val | BIT(8));
345	ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0100, 0x180, BIT(0), 1);
346	if (ret)
347		return ret;
348	r8a779f0_eth_serdes_write32(channel->addr, 0x00c0, 0x180, val & ~BIT(8));
349	ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0100, 0x180, BIT(0), 0);
350	if (ret)
351		return ret;
352
353	val = r8a779f0_eth_serdes_read32(channel->addr, 0x0144, 0x180);
354	r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, val | BIT(4));
355	ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0180, 0x180, BIT(0), 1);
356	if (ret)
357		return ret;
358	r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, val & ~BIT(4));
359	ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0180, 0x180, BIT(0), 0);
360	if (ret)
361		return ret;
362
363	return r8a779f0_eth_serdes_monitor_linkup(channel);
364}
365
366static int r8a779f0_eth_serdes_power_on(struct phy *p)
367{
368	struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
369
370	return r8a779f0_eth_serdes_hw_init_late(channel);
371}
372
373static int r8a779f0_eth_serdes_set_mode(struct phy *p, enum phy_mode mode,
374					int submode)
375{
376	struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
377
378	if (mode != PHY_MODE_ETHERNET)
379		return -EOPNOTSUPP;
380
381	switch (submode) {
382	case PHY_INTERFACE_MODE_GMII:
383	case PHY_INTERFACE_MODE_SGMII:
384	case PHY_INTERFACE_MODE_USXGMII:
385		channel->phy_interface = submode;
386		return 0;
387	default:
388		return -EOPNOTSUPP;
389	}
390}
391
392static int r8a779f0_eth_serdes_set_speed(struct phy *p, int speed)
393{
394	struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
395
396	channel->speed = speed;
397
398	return 0;
399}
400
401static const struct phy_ops r8a779f0_eth_serdes_ops = {
402	.init		= r8a779f0_eth_serdes_init,
403	.exit		= r8a779f0_eth_serdes_exit,
404	.power_on	= r8a779f0_eth_serdes_power_on,
405	.set_mode	= r8a779f0_eth_serdes_set_mode,
406	.set_speed	= r8a779f0_eth_serdes_set_speed,
407};
408
409static struct phy *r8a779f0_eth_serdes_xlate(struct device *dev,
410					     const struct of_phandle_args *args)
411{
412	struct r8a779f0_eth_serdes_drv_data *dd = dev_get_drvdata(dev);
413
414	if (args->args[0] >= R8A779F0_ETH_SERDES_NUM)
415		return ERR_PTR(-ENODEV);
416
417	return dd->channel[args->args[0]].phy;
418}
419
420static const struct of_device_id r8a779f0_eth_serdes_of_table[] = {
421	{ .compatible = "renesas,r8a779f0-ether-serdes", },
422	{ }
423};
424MODULE_DEVICE_TABLE(of, r8a779f0_eth_serdes_of_table);
425
426static int r8a779f0_eth_serdes_probe(struct platform_device *pdev)
427{
428	struct r8a779f0_eth_serdes_drv_data *dd;
429	struct phy_provider *provider;
430	int i;
431
432	dd = devm_kzalloc(&pdev->dev, sizeof(*dd), GFP_KERNEL);
433	if (!dd)
434		return -ENOMEM;
435
436	platform_set_drvdata(pdev, dd);
437	dd->pdev = pdev;
438	dd->addr = devm_platform_ioremap_resource(pdev, 0);
439	if (IS_ERR(dd->addr))
440		return PTR_ERR(dd->addr);
441
442	dd->reset = devm_reset_control_get(&pdev->dev, NULL);
443	if (IS_ERR(dd->reset))
444		return PTR_ERR(dd->reset);
445
446	for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
447		struct r8a779f0_eth_serdes_channel *channel = &dd->channel[i];
448
449		channel->phy = devm_phy_create(&pdev->dev, NULL,
450					       &r8a779f0_eth_serdes_ops);
451		if (IS_ERR(channel->phy))
452			return PTR_ERR(channel->phy);
453		channel->addr = dd->addr + R8A779F0_ETH_SERDES_OFFSET * i;
454		channel->dd = dd;
455		channel->index = i;
456		phy_set_drvdata(channel->phy, channel);
457	}
458
459	provider = devm_of_phy_provider_register(&pdev->dev,
460						 r8a779f0_eth_serdes_xlate);
461	if (IS_ERR(provider))
462		return PTR_ERR(provider);
463
464	pm_runtime_enable(&pdev->dev);
465	pm_runtime_get_sync(&pdev->dev);
466
467	return 0;
468}
469
470static void r8a779f0_eth_serdes_remove(struct platform_device *pdev)
471{
472	pm_runtime_put(&pdev->dev);
473	pm_runtime_disable(&pdev->dev);
474
475	platform_set_drvdata(pdev, NULL);
476}
477
478static struct platform_driver r8a779f0_eth_serdes_driver_platform = {
479	.probe = r8a779f0_eth_serdes_probe,
480	.remove = r8a779f0_eth_serdes_remove,
481	.driver = {
482		.name = "r8a779f0_eth_serdes",
483		.of_match_table = r8a779f0_eth_serdes_of_table,
484	}
485};
486module_platform_driver(r8a779f0_eth_serdes_driver_platform);
487MODULE_AUTHOR("Yoshihiro Shimoda");
488MODULE_DESCRIPTION("Renesas Ethernet SERDES device driver");
489MODULE_LICENSE("GPL");
~/ Read-only file preview.