xref: /openbmc/linux/drivers/phy/renesas/r8a779f0-ether-serdes.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
174285944SYoshihiro Shimoda // SPDX-License-Identifier: GPL-2.0
274285944SYoshihiro Shimoda /* Renesas Ethernet SERDES device driver
374285944SYoshihiro Shimoda  *
474285944SYoshihiro Shimoda  * Copyright (C) 2022 Renesas Electronics Corporation
574285944SYoshihiro Shimoda  */
674285944SYoshihiro Shimoda 
774285944SYoshihiro Shimoda #include <linux/delay.h>
874285944SYoshihiro Shimoda #include <linux/err.h>
974285944SYoshihiro Shimoda #include <linux/iopoll.h>
1074285944SYoshihiro Shimoda #include <linux/kernel.h>
11*7559e757SRob Herring #include <linux/of.h>
1274285944SYoshihiro Shimoda #include <linux/phy.h>
1374285944SYoshihiro Shimoda #include <linux/phy/phy.h>
1474285944SYoshihiro Shimoda #include <linux/platform_device.h>
1574285944SYoshihiro Shimoda #include <linux/reset.h>
1674285944SYoshihiro Shimoda 
1774285944SYoshihiro Shimoda #define R8A779F0_ETH_SERDES_NUM			3
1874285944SYoshihiro Shimoda #define R8A779F0_ETH_SERDES_OFFSET		0x0400
1974285944SYoshihiro Shimoda #define R8A779F0_ETH_SERDES_BANK_SELECT		0x03fc
2074285944SYoshihiro Shimoda #define R8A779F0_ETH_SERDES_TIMEOUT_US		100000
2174285944SYoshihiro Shimoda #define R8A779F0_ETH_SERDES_NUM_RETRY_LINKUP	3
2274285944SYoshihiro Shimoda 
2374285944SYoshihiro Shimoda struct r8a779f0_eth_serdes_drv_data;
2474285944SYoshihiro Shimoda struct r8a779f0_eth_serdes_channel {
2574285944SYoshihiro Shimoda 	struct r8a779f0_eth_serdes_drv_data *dd;
2674285944SYoshihiro Shimoda 	struct phy *phy;
2774285944SYoshihiro Shimoda 	void __iomem *addr;
2874285944SYoshihiro Shimoda 	phy_interface_t phy_interface;
2974285944SYoshihiro Shimoda 	int speed;
3074285944SYoshihiro Shimoda 	int index;
3174285944SYoshihiro Shimoda };
3274285944SYoshihiro Shimoda 
3374285944SYoshihiro Shimoda struct r8a779f0_eth_serdes_drv_data {
3474285944SYoshihiro Shimoda 	void __iomem *addr;
3574285944SYoshihiro Shimoda 	struct platform_device *pdev;
3674285944SYoshihiro Shimoda 	struct reset_control *reset;
3774285944SYoshihiro Shimoda 	struct r8a779f0_eth_serdes_channel channel[R8A779F0_ETH_SERDES_NUM];
3874285944SYoshihiro Shimoda 	bool initialized;
3974285944SYoshihiro Shimoda };
4074285944SYoshihiro Shimoda 
4174285944SYoshihiro Shimoda /*
4274285944SYoshihiro Shimoda  * The datasheet describes initialization procedure without any information
4374285944SYoshihiro Shimoda  * about registers' name/bits. So, this is all black magic to initialize
4474285944SYoshihiro Shimoda  * the hardware.
4574285944SYoshihiro Shimoda  */
r8a779f0_eth_serdes_write32(void __iomem * addr,u32 offs,u32 bank,u32 data)4674285944SYoshihiro Shimoda static void r8a779f0_eth_serdes_write32(void __iomem *addr, u32 offs, u32 bank, u32 data)
4774285944SYoshihiro Shimoda {
4874285944SYoshihiro Shimoda 	iowrite32(bank, addr + R8A779F0_ETH_SERDES_BANK_SELECT);
4974285944SYoshihiro Shimoda 	iowrite32(data, addr + offs);
5074285944SYoshihiro Shimoda }
5174285944SYoshihiro Shimoda 
5274285944SYoshihiro Shimoda static int
r8a779f0_eth_serdes_reg_wait(struct r8a779f0_eth_serdes_channel * channel,u32 offs,u32 bank,u32 mask,u32 expected)5374285944SYoshihiro Shimoda r8a779f0_eth_serdes_reg_wait(struct r8a779f0_eth_serdes_channel *channel,
5474285944SYoshihiro Shimoda 			     u32 offs, u32 bank, u32 mask, u32 expected)
5574285944SYoshihiro Shimoda {
5674285944SYoshihiro Shimoda 	int ret;
5774285944SYoshihiro Shimoda 	u32 val;
5874285944SYoshihiro Shimoda 
5974285944SYoshihiro Shimoda 	iowrite32(bank, channel->addr + R8A779F0_ETH_SERDES_BANK_SELECT);
6074285944SYoshihiro Shimoda 
6174285944SYoshihiro Shimoda 	ret = readl_poll_timeout_atomic(channel->addr + offs, val,
6274285944SYoshihiro Shimoda 					(val & mask) == expected,
6374285944SYoshihiro Shimoda 					1, R8A779F0_ETH_SERDES_TIMEOUT_US);
6474285944SYoshihiro Shimoda 	if (ret)
6574285944SYoshihiro Shimoda 		dev_dbg(&channel->phy->dev,
6674285944SYoshihiro Shimoda 			"%s: index %d, offs %x, bank %x, mask %x, expected %x\n",
6774285944SYoshihiro Shimoda 			 __func__, channel->index, offs, bank, mask, expected);
6874285944SYoshihiro Shimoda 
6974285944SYoshihiro Shimoda 	return ret;
7074285944SYoshihiro Shimoda }
7174285944SYoshihiro Shimoda 
7274285944SYoshihiro Shimoda static int
r8a779f0_eth_serdes_common_init_ram(struct r8a779f0_eth_serdes_drv_data * dd)7374285944SYoshihiro Shimoda r8a779f0_eth_serdes_common_init_ram(struct r8a779f0_eth_serdes_drv_data *dd)
7474285944SYoshihiro Shimoda {
7574285944SYoshihiro Shimoda 	struct r8a779f0_eth_serdes_channel *channel;
7674285944SYoshihiro Shimoda 	int i, ret;
7774285944SYoshihiro Shimoda 
7874285944SYoshihiro Shimoda 	for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
7974285944SYoshihiro Shimoda 		channel = &dd->channel[i];
8074285944SYoshihiro Shimoda 		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x026c, 0x180, BIT(0), 0x01);
8174285944SYoshihiro Shimoda 		if (ret)
8274285944SYoshihiro Shimoda 			return ret;
8374285944SYoshihiro Shimoda 	}
8474285944SYoshihiro Shimoda 
8574285944SYoshihiro Shimoda 	r8a779f0_eth_serdes_write32(dd->addr, 0x026c, 0x180, 0x03);
8674285944SYoshihiro Shimoda 
8774285944SYoshihiro Shimoda 	return ret;
8874285944SYoshihiro Shimoda }
8974285944SYoshihiro Shimoda 
9074285944SYoshihiro Shimoda static int
r8a779f0_eth_serdes_common_setting(struct r8a779f0_eth_serdes_channel * channel)9174285944SYoshihiro Shimoda r8a779f0_eth_serdes_common_setting(struct r8a779f0_eth_serdes_channel *channel)
9274285944SYoshihiro Shimoda {
9374285944SYoshihiro Shimoda 	struct r8a779f0_eth_serdes_drv_data *dd = channel->dd;
9474285944SYoshihiro Shimoda 
9574285944SYoshihiro Shimoda 	switch (channel->phy_interface) {
9674285944SYoshihiro Shimoda 	case PHY_INTERFACE_MODE_SGMII:
9774285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(dd->addr, 0x0244, 0x180, 0x0097);
9874285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(dd->addr, 0x01d0, 0x180, 0x0060);
9974285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(dd->addr, 0x01d8, 0x180, 0x2200);
10074285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(dd->addr, 0x01d4, 0x180, 0x0000);
10174285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(dd->addr, 0x01e0, 0x180, 0x003d);
10274285944SYoshihiro Shimoda 		return 0;
10374285944SYoshihiro Shimoda 	default:
10474285944SYoshihiro Shimoda 		return -EOPNOTSUPP;
10574285944SYoshihiro Shimoda 	}
10674285944SYoshihiro Shimoda }
10774285944SYoshihiro Shimoda 
10874285944SYoshihiro Shimoda static int
r8a779f0_eth_serdes_chan_setting(struct r8a779f0_eth_serdes_channel * channel)10974285944SYoshihiro Shimoda r8a779f0_eth_serdes_chan_setting(struct r8a779f0_eth_serdes_channel *channel)
11074285944SYoshihiro Shimoda {
11174285944SYoshihiro Shimoda 	int ret;
11274285944SYoshihiro Shimoda 
11374285944SYoshihiro Shimoda 	switch (channel->phy_interface) {
11474285944SYoshihiro Shimoda 	case PHY_INTERFACE_MODE_SGMII:
11574285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2000);
11674285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x01c0, 0x180, 0x0011);
11774285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0248, 0x180, 0x0540);
11874285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0258, 0x180, 0x0015);
11974285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0100);
12074285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x01a0, 0x180, 0x0000);
12174285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x00d0, 0x180, 0x0002);
12274285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0150, 0x180, 0x0003);
12374285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0100);
12474285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0100);
12574285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0174, 0x180, 0x0000);
12674285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0160, 0x180, 0x0007);
12774285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x01ac, 0x180, 0x0000);
12874285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x0310);
129ec4a1d93SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x00c8, 0x180, 0x0101);
13074285944SYoshihiro Shimoda 		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x00c8, 0x0180, BIT(0), 0);
13174285944SYoshihiro Shimoda 		if (ret)
13274285944SYoshihiro Shimoda 			return ret;
13374285944SYoshihiro Shimoda 
13474285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0148, 0x180, 0x0101);
13574285944SYoshihiro Shimoda 		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0148, 0x0180, BIT(0), 0);
13674285944SYoshihiro Shimoda 		if (ret)
13774285944SYoshihiro Shimoda 			return ret;
13874285944SYoshihiro Shimoda 
13974285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x00c4, 0x180, 0x1310);
14074285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x00d8, 0x180, 0x1800);
14174285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x00dc, 0x180, 0x0000);
14274285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x001c, 0x300, 0x0001);
14374285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x380, 0x2100);
14474285944SYoshihiro Shimoda 		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0000, 0x0380, BIT(8), 0);
14574285944SYoshihiro Shimoda 		if (ret)
14674285944SYoshihiro Shimoda 			return ret;
14774285944SYoshihiro Shimoda 
14874285944SYoshihiro Shimoda 		if (channel->speed == 1000)
14974285944SYoshihiro Shimoda 			r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x0140);
15074285944SYoshihiro Shimoda 		else if (channel->speed == 100)
15174285944SYoshihiro Shimoda 			r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x2100);
15274285944SYoshihiro Shimoda 
15374285944SYoshihiro Shimoda 		/* For AN_ON */
15474285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0004, 0x1f80, 0x0005);
15574285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0028, 0x1f80, 0x07a1);
15674285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f80, 0x0208);
15774285944SYoshihiro Shimoda 		break;
15874285944SYoshihiro Shimoda 	default:
15974285944SYoshihiro Shimoda 		return -EOPNOTSUPP;
16074285944SYoshihiro Shimoda 	}
16174285944SYoshihiro Shimoda 
16274285944SYoshihiro Shimoda 	return 0;
16374285944SYoshihiro Shimoda }
16474285944SYoshihiro Shimoda 
16574285944SYoshihiro Shimoda static int
r8a779f0_eth_serdes_chan_speed(struct r8a779f0_eth_serdes_channel * channel)16674285944SYoshihiro Shimoda r8a779f0_eth_serdes_chan_speed(struct r8a779f0_eth_serdes_channel *channel)
16774285944SYoshihiro Shimoda {
16874285944SYoshihiro Shimoda 	int ret;
16974285944SYoshihiro Shimoda 
17074285944SYoshihiro Shimoda 	switch (channel->phy_interface) {
17174285944SYoshihiro Shimoda 	case PHY_INTERFACE_MODE_SGMII:
17274285944SYoshihiro Shimoda 		/* For AN_ON */
17374285944SYoshihiro Shimoda 		if (channel->speed == 1000)
17474285944SYoshihiro Shimoda 			r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x1140);
17574285944SYoshihiro Shimoda 		else if (channel->speed == 100)
17674285944SYoshihiro Shimoda 			r8a779f0_eth_serdes_write32(channel->addr, 0x0000, 0x1f00, 0x3100);
17774285944SYoshihiro Shimoda 		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0008, 0x1f80, BIT(0), 1);
17874285944SYoshihiro Shimoda 		if (ret)
17974285944SYoshihiro Shimoda 			return ret;
18074285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0008, 0x1f80, 0x0000);
18174285944SYoshihiro Shimoda 		break;
18274285944SYoshihiro Shimoda 	default:
18374285944SYoshihiro Shimoda 		return -EOPNOTSUPP;
18474285944SYoshihiro Shimoda 	}
18574285944SYoshihiro Shimoda 
18674285944SYoshihiro Shimoda 	return 0;
18774285944SYoshihiro Shimoda }
18874285944SYoshihiro Shimoda 
18974285944SYoshihiro Shimoda 
r8a779f0_eth_serdes_monitor_linkup(struct r8a779f0_eth_serdes_channel * channel)19074285944SYoshihiro Shimoda static int r8a779f0_eth_serdes_monitor_linkup(struct r8a779f0_eth_serdes_channel *channel)
19174285944SYoshihiro Shimoda {
19274285944SYoshihiro Shimoda 	int i, ret;
19374285944SYoshihiro Shimoda 
19474285944SYoshihiro Shimoda 	for (i = 0; i < R8A779F0_ETH_SERDES_NUM_RETRY_LINKUP; i++) {
19574285944SYoshihiro Shimoda 		ret = r8a779f0_eth_serdes_reg_wait(channel, 0x0004, 0x300,
19674285944SYoshihiro Shimoda 						   BIT(2), BIT(2));
19774285944SYoshihiro Shimoda 		if (!ret)
19874285944SYoshihiro Shimoda 			break;
19974285944SYoshihiro Shimoda 
20074285944SYoshihiro Shimoda 		/* restart */
20174285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0100);
20274285944SYoshihiro Shimoda 		udelay(1);
20374285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(channel->addr, 0x0144, 0x180, 0x0000);
20474285944SYoshihiro Shimoda 	}
20574285944SYoshihiro Shimoda 
20674285944SYoshihiro Shimoda 	return ret;
20774285944SYoshihiro Shimoda }
20874285944SYoshihiro Shimoda 
r8a779f0_eth_serdes_hw_init(struct r8a779f0_eth_serdes_channel * channel)20974285944SYoshihiro Shimoda static int r8a779f0_eth_serdes_hw_init(struct r8a779f0_eth_serdes_channel *channel)
21074285944SYoshihiro Shimoda {
21174285944SYoshihiro Shimoda 	struct r8a779f0_eth_serdes_drv_data *dd = channel->dd;
21274285944SYoshihiro Shimoda 	int i, ret;
21374285944SYoshihiro Shimoda 
21474285944SYoshihiro Shimoda 	if (dd->initialized)
21574285944SYoshihiro Shimoda 		return 0;
21674285944SYoshihiro Shimoda 
21774285944SYoshihiro Shimoda 	ret = r8a779f0_eth_serdes_common_init_ram(dd);
21874285944SYoshihiro Shimoda 	if (ret)
21974285944SYoshihiro Shimoda 		return ret;
22074285944SYoshihiro Shimoda 
22174285944SYoshihiro Shimoda 	for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
22274285944SYoshihiro Shimoda 		ret = r8a779f0_eth_serdes_reg_wait(&dd->channel[i], 0x0000,
22374285944SYoshihiro Shimoda 						   0x300, BIT(15), 0);
22474285944SYoshihiro Shimoda 		if (ret)
22574285944SYoshihiro Shimoda 			return ret;
22674285944SYoshihiro Shimoda 	}
22774285944SYoshihiro Shimoda 
22874285944SYoshihiro Shimoda 	for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++)
22974285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03d4, 0x380, 0x0443);
23074285944SYoshihiro Shimoda 
23174285944SYoshihiro Shimoda 	ret = r8a779f0_eth_serdes_common_setting(channel);
23274285944SYoshihiro Shimoda 	if (ret)
23374285944SYoshihiro Shimoda 		return ret;
23474285944SYoshihiro Shimoda 
23574285944SYoshihiro Shimoda 	for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++)
23674285944SYoshihiro Shimoda 		r8a779f0_eth_serdes_write32(dd->channel[i].addr, 0x03d0, 0x380, 0x0001);
23774285944SYoshihiro Shimoda 
23874285944SYoshihiro Shimoda 
23974285944SYoshihiro Shimoda 	r8a779f0_eth_serdes_write32(dd->addr, 0x0000, 0x380, 0x8000);
24074285944SYoshihiro Shimoda 
24174285944SYoshihiro Shimoda 	ret = r8a779f0_eth_serdes_common_init_ram(dd);
24274285944SYoshihiro Shimoda 	if (ret)
24374285944SYoshihiro Shimoda 		return ret;
24474285944SYoshihiro Shimoda 
245d2aa66a9SYoshihiro Shimoda 	return r8a779f0_eth_serdes_reg_wait(&dd->channel[0], 0x0000, 0x380, BIT(15), 0);
24674285944SYoshihiro Shimoda }
24774285944SYoshihiro Shimoda 
r8a779f0_eth_serdes_init(struct phy * p)24874285944SYoshihiro Shimoda static int r8a779f0_eth_serdes_init(struct phy *p)
24974285944SYoshihiro Shimoda {
25074285944SYoshihiro Shimoda 	struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
25150133cd3SYoshihiro Shimoda 	int ret;
25274285944SYoshihiro Shimoda 
25374285944SYoshihiro Shimoda 	ret = r8a779f0_eth_serdes_hw_init(channel);
25450133cd3SYoshihiro Shimoda 	if (!ret)
25574285944SYoshihiro Shimoda 		channel->dd->initialized = true;
25674285944SYoshihiro Shimoda 
25774285944SYoshihiro Shimoda 	return ret;
25874285944SYoshihiro Shimoda }
25974285944SYoshihiro Shimoda 
r8a779f0_eth_serdes_hw_init_late(struct r8a779f0_eth_serdes_channel * channel)260d2aa66a9SYoshihiro Shimoda static int r8a779f0_eth_serdes_hw_init_late(struct r8a779f0_eth_serdes_channel
261d2aa66a9SYoshihiro Shimoda *channel)
262d2aa66a9SYoshihiro Shimoda {
263d2aa66a9SYoshihiro Shimoda 	int ret;
264d2aa66a9SYoshihiro Shimoda 
265d2aa66a9SYoshihiro Shimoda 	ret = r8a779f0_eth_serdes_chan_setting(channel);
266d2aa66a9SYoshihiro Shimoda 	if (ret)
267d2aa66a9SYoshihiro Shimoda 		return ret;
268d2aa66a9SYoshihiro Shimoda 
269d2aa66a9SYoshihiro Shimoda 	ret = r8a779f0_eth_serdes_chan_speed(channel);
270d2aa66a9SYoshihiro Shimoda 	if (ret)
271d2aa66a9SYoshihiro Shimoda 		return ret;
272d2aa66a9SYoshihiro Shimoda 
273d2aa66a9SYoshihiro Shimoda 	r8a779f0_eth_serdes_write32(channel->addr, 0x03c0, 0x380, 0x0000);
274d2aa66a9SYoshihiro Shimoda 
275d2aa66a9SYoshihiro Shimoda 	r8a779f0_eth_serdes_write32(channel->addr, 0x03d0, 0x380, 0x0000);
276d2aa66a9SYoshihiro Shimoda 
277d2aa66a9SYoshihiro Shimoda 	return r8a779f0_eth_serdes_monitor_linkup(channel);
278d2aa66a9SYoshihiro Shimoda }
279d2aa66a9SYoshihiro Shimoda 
r8a779f0_eth_serdes_power_on(struct phy * p)280d2aa66a9SYoshihiro Shimoda static int r8a779f0_eth_serdes_power_on(struct phy *p)
281d2aa66a9SYoshihiro Shimoda {
282d2aa66a9SYoshihiro Shimoda 	struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
283d2aa66a9SYoshihiro Shimoda 
284d2aa66a9SYoshihiro Shimoda 	return r8a779f0_eth_serdes_hw_init_late(channel);
285d2aa66a9SYoshihiro Shimoda }
286d2aa66a9SYoshihiro Shimoda 
r8a779f0_eth_serdes_set_mode(struct phy * p,enum phy_mode mode,int submode)28774285944SYoshihiro Shimoda static int r8a779f0_eth_serdes_set_mode(struct phy *p, enum phy_mode mode,
28874285944SYoshihiro Shimoda 					int submode)
28974285944SYoshihiro Shimoda {
29074285944SYoshihiro Shimoda 	struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
29174285944SYoshihiro Shimoda 
29274285944SYoshihiro Shimoda 	if (mode != PHY_MODE_ETHERNET)
29374285944SYoshihiro Shimoda 		return -EOPNOTSUPP;
29474285944SYoshihiro Shimoda 
29574285944SYoshihiro Shimoda 	switch (submode) {
29674285944SYoshihiro Shimoda 	case PHY_INTERFACE_MODE_GMII:
29774285944SYoshihiro Shimoda 	case PHY_INTERFACE_MODE_SGMII:
29874285944SYoshihiro Shimoda 	case PHY_INTERFACE_MODE_USXGMII:
29974285944SYoshihiro Shimoda 		channel->phy_interface = submode;
30074285944SYoshihiro Shimoda 		return 0;
30174285944SYoshihiro Shimoda 	default:
30274285944SYoshihiro Shimoda 		return -EOPNOTSUPP;
30374285944SYoshihiro Shimoda 	}
30474285944SYoshihiro Shimoda }
30574285944SYoshihiro Shimoda 
r8a779f0_eth_serdes_set_speed(struct phy * p,int speed)30674285944SYoshihiro Shimoda static int r8a779f0_eth_serdes_set_speed(struct phy *p, int speed)
30774285944SYoshihiro Shimoda {
30874285944SYoshihiro Shimoda 	struct r8a779f0_eth_serdes_channel *channel = phy_get_drvdata(p);
30974285944SYoshihiro Shimoda 
31074285944SYoshihiro Shimoda 	channel->speed = speed;
31174285944SYoshihiro Shimoda 
31274285944SYoshihiro Shimoda 	return 0;
31374285944SYoshihiro Shimoda }
31474285944SYoshihiro Shimoda 
31574285944SYoshihiro Shimoda static const struct phy_ops r8a779f0_eth_serdes_ops = {
31674285944SYoshihiro Shimoda 	.init		= r8a779f0_eth_serdes_init,
317d2aa66a9SYoshihiro Shimoda 	.power_on	= r8a779f0_eth_serdes_power_on,
31874285944SYoshihiro Shimoda 	.set_mode	= r8a779f0_eth_serdes_set_mode,
31974285944SYoshihiro Shimoda 	.set_speed	= r8a779f0_eth_serdes_set_speed,
32074285944SYoshihiro Shimoda };
32174285944SYoshihiro Shimoda 
r8a779f0_eth_serdes_xlate(struct device * dev,struct of_phandle_args * args)32274285944SYoshihiro Shimoda static struct phy *r8a779f0_eth_serdes_xlate(struct device *dev,
32374285944SYoshihiro Shimoda 					     struct of_phandle_args *args)
32474285944SYoshihiro Shimoda {
32574285944SYoshihiro Shimoda 	struct r8a779f0_eth_serdes_drv_data *dd = dev_get_drvdata(dev);
32674285944SYoshihiro Shimoda 
32774285944SYoshihiro Shimoda 	if (args->args[0] >= R8A779F0_ETH_SERDES_NUM)
32874285944SYoshihiro Shimoda 		return ERR_PTR(-ENODEV);
32974285944SYoshihiro Shimoda 
33074285944SYoshihiro Shimoda 	return dd->channel[args->args[0]].phy;
33174285944SYoshihiro Shimoda }
33274285944SYoshihiro Shimoda 
33374285944SYoshihiro Shimoda static const struct of_device_id r8a779f0_eth_serdes_of_table[] = {
33474285944SYoshihiro Shimoda 	{ .compatible = "renesas,r8a779f0-ether-serdes", },
33574285944SYoshihiro Shimoda 	{ }
33674285944SYoshihiro Shimoda };
33774285944SYoshihiro Shimoda MODULE_DEVICE_TABLE(of, r8a779f0_eth_serdes_of_table);
33874285944SYoshihiro Shimoda 
r8a779f0_eth_serdes_probe(struct platform_device * pdev)33974285944SYoshihiro Shimoda static int r8a779f0_eth_serdes_probe(struct platform_device *pdev)
34074285944SYoshihiro Shimoda {
34174285944SYoshihiro Shimoda 	struct r8a779f0_eth_serdes_drv_data *dd;
34274285944SYoshihiro Shimoda 	struct phy_provider *provider;
34374285944SYoshihiro Shimoda 	int i;
34474285944SYoshihiro Shimoda 
34574285944SYoshihiro Shimoda 	dd = devm_kzalloc(&pdev->dev, sizeof(*dd), GFP_KERNEL);
34674285944SYoshihiro Shimoda 	if (!dd)
34774285944SYoshihiro Shimoda 		return -ENOMEM;
34874285944SYoshihiro Shimoda 
34974285944SYoshihiro Shimoda 	platform_set_drvdata(pdev, dd);
35074285944SYoshihiro Shimoda 	dd->pdev = pdev;
351d746f127SYangtao Li 	dd->addr = devm_platform_ioremap_resource(pdev, 0);
35274285944SYoshihiro Shimoda 	if (IS_ERR(dd->addr))
35374285944SYoshihiro Shimoda 		return PTR_ERR(dd->addr);
35474285944SYoshihiro Shimoda 
35574285944SYoshihiro Shimoda 	dd->reset = devm_reset_control_get(&pdev->dev, NULL);
35674285944SYoshihiro Shimoda 	if (IS_ERR(dd->reset))
35774285944SYoshihiro Shimoda 		return PTR_ERR(dd->reset);
35874285944SYoshihiro Shimoda 
35974285944SYoshihiro Shimoda 	reset_control_reset(dd->reset);
36074285944SYoshihiro Shimoda 
36174285944SYoshihiro Shimoda 	for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) {
36274285944SYoshihiro Shimoda 		struct r8a779f0_eth_serdes_channel *channel = &dd->channel[i];
36374285944SYoshihiro Shimoda 
36474285944SYoshihiro Shimoda 		channel->phy = devm_phy_create(&pdev->dev, NULL,
36574285944SYoshihiro Shimoda 					       &r8a779f0_eth_serdes_ops);
36674285944SYoshihiro Shimoda 		if (IS_ERR(channel->phy))
36774285944SYoshihiro Shimoda 			return PTR_ERR(channel->phy);
36874285944SYoshihiro Shimoda 		channel->addr = dd->addr + R8A779F0_ETH_SERDES_OFFSET * i;
36974285944SYoshihiro Shimoda 		channel->dd = dd;
37074285944SYoshihiro Shimoda 		channel->index = i;
37174285944SYoshihiro Shimoda 		phy_set_drvdata(channel->phy, channel);
37274285944SYoshihiro Shimoda 	}
37374285944SYoshihiro Shimoda 
37474285944SYoshihiro Shimoda 	provider = devm_of_phy_provider_register(&pdev->dev,
37574285944SYoshihiro Shimoda 						 r8a779f0_eth_serdes_xlate);
37674285944SYoshihiro Shimoda 	if (IS_ERR(provider))
37774285944SYoshihiro Shimoda 		return PTR_ERR(provider);
37874285944SYoshihiro Shimoda 
37974285944SYoshihiro Shimoda 	pm_runtime_enable(&pdev->dev);
38074285944SYoshihiro Shimoda 	pm_runtime_get_sync(&pdev->dev);
38174285944SYoshihiro Shimoda 
38274285944SYoshihiro Shimoda 	return 0;
38374285944SYoshihiro Shimoda }
38474285944SYoshihiro Shimoda 
r8a779f0_eth_serdes_remove(struct platform_device * pdev)385f1c01b91SUwe Kleine-König static void r8a779f0_eth_serdes_remove(struct platform_device *pdev)
38674285944SYoshihiro Shimoda {
38774285944SYoshihiro Shimoda 	pm_runtime_put(&pdev->dev);
38874285944SYoshihiro Shimoda 	pm_runtime_disable(&pdev->dev);
38974285944SYoshihiro Shimoda 
39074285944SYoshihiro Shimoda 	platform_set_drvdata(pdev, NULL);
39174285944SYoshihiro Shimoda }
39274285944SYoshihiro Shimoda 
39374285944SYoshihiro Shimoda static struct platform_driver r8a779f0_eth_serdes_driver_platform = {
39474285944SYoshihiro Shimoda 	.probe = r8a779f0_eth_serdes_probe,
395f1c01b91SUwe Kleine-König 	.remove_new = r8a779f0_eth_serdes_remove,
39674285944SYoshihiro Shimoda 	.driver = {
39774285944SYoshihiro Shimoda 		.name = "r8a779f0_eth_serdes",
39874285944SYoshihiro Shimoda 		.of_match_table = r8a779f0_eth_serdes_of_table,
39974285944SYoshihiro Shimoda 	}
40074285944SYoshihiro Shimoda };
40174285944SYoshihiro Shimoda module_platform_driver(r8a779f0_eth_serdes_driver_platform);
40274285944SYoshihiro Shimoda MODULE_AUTHOR("Yoshihiro Shimoda");
40374285944SYoshihiro Shimoda MODULE_DESCRIPTION("Renesas Ethernet SERDES device driver");
40474285944SYoshihiro Shimoda MODULE_LICENSE("GPL");
405