rockchip: update motorcomm patchset

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen 2023-02-06 03:51:55 +08:00
parent 4580230440
commit 9229b66c09
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
26 changed files with 992 additions and 934 deletions

View File

@ -32,7 +32,7 @@
"ethernet-phy-ieee802.3-c22";
reg = <3>;
motorcomm,clk-out-frequency = <125000000>;
motorcomm,clk-out-frequency-hz = <125000000>;
motorcomm,keep-pll-enabled;
motorcomm,auto-sleep-disabled;

View File

@ -28,7 +28,7 @@
"ethernet-phy-ieee802.3-c22";
reg = <0>;
motorcomm,clk-out-frequency = <125000000>;
motorcomm,clk-out-frequency-hz = <125000000>;
motorcomm,keep-pll-enabled;
motorcomm,auto-sleep-disabled;

View File

@ -32,7 +32,7 @@
"ethernet-phy-ieee802.3-c22";
reg = <3>;
motorcomm,clk-out-frequency = <125000000>;
motorcomm,clk-out-frequency-hz = <125000000>;
motorcomm,keep-pll-enabled;
motorcomm,auto-sleep-disabled;

View File

@ -43,7 +43,7 @@
"ethernet-phy-ieee802.3-c22";
reg = <0>;
motorcomm,clk-out-frequency = <125000000>;
motorcomm,clk-out-frequency-hz = <125000000>;
motorcomm,keep-pll-enabled;
motorcomm,auto-sleep-disabled;

View File

@ -20,7 +20,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -1098,12 +1098,21 @@ static int rockchip_usb2phy_probe(struct
@@ -1100,12 +1100,21 @@ static int rockchip_usb2phy_probe(struct
rphy->usbgrf = NULL;
}

View File

@ -33,7 +33,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
const struct rockchip_usb2phy_cfg *phy_cfg;
struct rockchip_usb2phy_port ports[USB2PHY_NUM_PORTS];
};
@@ -934,6 +936,102 @@ static irqreturn_t rockchip_usb2phy_otg_
@@ -936,6 +938,102 @@ static irqreturn_t rockchip_usb2phy_otg_
return IRQ_NONE;
}
@ -136,7 +136,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
struct rockchip_usb2phy_port *rport,
struct device_node *child_np)
@@ -947,18 +1045,9 @@ static int rockchip_usb2phy_host_port_in
@@ -949,18 +1047,9 @@ static int rockchip_usb2phy_host_port_in
mutex_init(&rport->mutex);
INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work);
@ -157,7 +157,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
return ret;
}
@@ -1007,44 +1096,10 @@ static int rockchip_usb2phy_otg_port_ini
@@ -1009,44 +1098,10 @@ static int rockchip_usb2phy_otg_port_ini
INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work);
INIT_DELAYED_WORK(&rport->otg_sm_work, rockchip_usb2phy_otg_sm_work);
@ -206,7 +206,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
if (!IS_ERR(rphy->edev)) {
rport->event_nb.notifier_call = rockchip_otg_event;
@@ -1117,6 +1172,7 @@ static int rockchip_usb2phy_probe(struct
@@ -1119,6 +1174,7 @@ static int rockchip_usb2phy_probe(struct
phy_cfgs = match->data;
rphy->chg_state = USB_CHG_STATE_UNDEFINED;
rphy->chg_type = POWER_SUPPLY_TYPE_UNKNOWN;
@ -214,7 +214,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
platform_set_drvdata(pdev, rphy);
ret = rockchip_usb2phy_extcon_register(rphy);
@@ -1196,6 +1252,20 @@ next_child:
@@ -1198,6 +1254,20 @@ next_child:
}
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);

View File

@ -17,7 +17,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -1136,12 +1136,19 @@ static int rockchip_usb2phy_probe(struct
@@ -1138,12 +1138,19 @@ static int rockchip_usb2phy_probe(struct
return -EINVAL;
}

View File

@ -16,7 +16,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -1100,6 +1100,7 @@ static int rockchip_usb2phy_otg_port_ini
@@ -1102,6 +1102,7 @@ static int rockchip_usb2phy_otg_port_ini
if (ret) {
dev_err(rphy->dev, "failed to init irq for host port\n");
goto out;
@ -24,7 +24,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
if (!IS_ERR(rphy->edev)) {
rport->event_nb.notifier_call = rockchip_otg_event;
@@ -1511,6 +1512,69 @@ static const struct rockchip_usb2phy_cfg
@@ -1513,6 +1514,69 @@ static const struct rockchip_usb2phy_cfg
{ /* sentinel */ }
};
@ -94,7 +94,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = {
{
.reg = 0x100,
@@ -1560,6 +1624,7 @@ static const struct of_device_id rockchi
@@ -1562,6 +1626,7 @@ static const struct of_device_id rockchi
{ .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs },
{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },

View File

@ -23,7 +23,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -948,8 +948,14 @@ static irqreturn_t rockchip_usb2phy_irq(
@@ -950,8 +950,14 @@ static irqreturn_t rockchip_usb2phy_irq(
if (!rport->phy)
continue;

View File

@ -17,7 +17,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -927,13 +927,11 @@ static irqreturn_t rockchip_usb2phy_bval
@@ -929,13 +929,11 @@ static irqreturn_t rockchip_usb2phy_bval
static irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data)
{

View File

@ -15,7 +15,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -913,13 +913,9 @@ static irqreturn_t rockchip_usb2phy_bval
@@ -915,13 +915,9 @@ static irqreturn_t rockchip_usb2phy_bval
if (!property_enabled(rphy->grf, &rport->port_cfg->bvalid_det_st))
return IRQ_NONE;

View File

@ -17,7 +17,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -1353,9 +1353,9 @@ static const struct rockchip_usb2phy_cfg
@@ -1355,9 +1355,9 @@ static const struct rockchip_usb2phy_cfg
.port_cfgs = {
[USB2PHY_PORT_OTG] = {
.phy_sus = { 0x0100, 8, 0, 0, 0x1d1 },
@ -30,7 +30,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
.ls_det_en = { 0x3020, 0, 0, 0, 1 },
.ls_det_st = { 0x3024, 0, 0, 0, 1 },
.ls_det_clr = { 0x3028, 0, 0, 0, 1 },
@@ -1396,9 +1396,9 @@ static const struct rockchip_usb2phy_cfg
@@ -1398,9 +1398,9 @@ static const struct rockchip_usb2phy_cfg
.port_cfgs = {
[USB2PHY_PORT_OTG] = {
.phy_sus = { 0x0100, 15, 0, 0, 0x1d1 },
@ -43,7 +43,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
.ls_det_en = { 0x0110, 0, 0, 0, 1 },
.ls_det_st = { 0x0114, 0, 0, 0, 1 },
.ls_det_clr = { 0x0118, 0, 0, 0, 1 },
@@ -1520,9 +1520,9 @@ static const struct rockchip_usb2phy_cfg
@@ -1522,9 +1522,9 @@ static const struct rockchip_usb2phy_cfg
.port_cfgs = {
[USB2PHY_PORT_OTG] = {
.phy_sus = { 0x0000, 8, 0, 0, 0x1d1 },

View File

@ -85,7 +85,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
schedule_delayed_work(&rport->otg_sm_work,
OTG_SCHEDULE_DELAY * 3);
} else {
@@ -921,11 +944,30 @@ static irqreturn_t rockchip_usb2phy_bval
@@ -923,11 +946,30 @@ static irqreturn_t rockchip_usb2phy_bval
return IRQ_HANDLED;
}
@ -116,7 +116,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
return ret;
}
@@ -1023,6 +1065,25 @@ static int rockchip_usb2phy_port_irq_ini
@@ -1025,6 +1067,25 @@ static int rockchip_usb2phy_port_irq_ini
"failed to request otg-bvalid irq handle\n");
return ret;
}
@ -142,7 +142,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
}
break;
default:
@@ -1297,10 +1358,14 @@ static const struct rockchip_usb2phy_cfg
@@ -1299,10 +1360,14 @@ static const struct rockchip_usb2phy_cfg
.bvalid_det_en = { 0x0680, 3, 3, 0, 1 },
.bvalid_det_st = { 0x0690, 3, 3, 0, 1 },
.bvalid_det_clr = { 0x06a0, 3, 3, 0, 1 },
@ -157,7 +157,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
.utmi_ls = { 0x0480, 3, 2, 0, 1 },
},
[USB2PHY_PORT_HOST] = {
@@ -1356,11 +1421,15 @@ static const struct rockchip_usb2phy_cfg
@@ -1358,11 +1423,15 @@ static const struct rockchip_usb2phy_cfg
.bvalid_det_en = { 0x3020, 3, 2, 0, 3 },
.bvalid_det_st = { 0x3024, 3, 2, 0, 3 },
.bvalid_det_clr = { 0x3028, 3, 2, 0, 3 },
@ -173,7 +173,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
.utmi_ls = { 0x0120, 5, 4, 0, 1 },
},
[USB2PHY_PORT_HOST] = {
@@ -1399,11 +1468,15 @@ static const struct rockchip_usb2phy_cfg
@@ -1401,11 +1470,15 @@ static const struct rockchip_usb2phy_cfg
.bvalid_det_en = { 0x0110, 3, 2, 0, 3 },
.bvalid_det_st = { 0x0114, 3, 2, 0, 3 },
.bvalid_det_clr = { 0x0118, 3, 2, 0, 3 },
@ -189,7 +189,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
.utmi_ls = { 0x0120, 5, 4, 0, 1 },
},
[USB2PHY_PORT_HOST] = {
@@ -1461,8 +1534,12 @@ static const struct rockchip_usb2phy_cfg
@@ -1463,8 +1536,12 @@ static const struct rockchip_usb2phy_cfg
.bvalid_det_en = { 0xe3c0, 3, 3, 0, 1 },
.bvalid_det_st = { 0xe3e0, 3, 3, 0, 1 },
.bvalid_det_clr = { 0xe3d0, 3, 3, 0, 1 },
@ -202,7 +202,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
},
[USB2PHY_PORT_HOST] = {
.phy_sus = { 0xe458, 1, 0, 0x2, 0x1 },
@@ -1496,8 +1573,12 @@ static const struct rockchip_usb2phy_cfg
@@ -1498,8 +1575,12 @@ static const struct rockchip_usb2phy_cfg
.bvalid_det_en = { 0xe3c0, 8, 8, 0, 1 },
.bvalid_det_st = { 0xe3e0, 8, 8, 0, 1 },
.bvalid_det_clr = { 0xe3d0, 8, 8, 0, 1 },
@ -215,7 +215,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
},
[USB2PHY_PORT_HOST] = {
.phy_sus = { 0xe468, 1, 0, 0x2, 0x1 },
@@ -1523,8 +1604,12 @@ static const struct rockchip_usb2phy_cfg
@@ -1525,8 +1606,12 @@ static const struct rockchip_usb2phy_cfg
.bvalid_det_en = { 0x0080, 3, 2, 0, 3 },
.bvalid_det_st = { 0x0084, 3, 2, 0, 3 },
.bvalid_det_clr = { 0x0088, 3, 2, 0, 3 },

View File

@ -23,7 +23,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -986,7 +986,9 @@ static irqreturn_t rockchip_usb2phy_irq(
@@ -988,7 +988,9 @@ static irqreturn_t rockchip_usb2phy_irq(
switch (rport->port_id) {
case USB2PHY_PORT_OTG:

View File

@ -16,7 +16,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -1293,7 +1293,7 @@ static int rockchip_usb2phy_probe(struct
@@ -1295,7 +1295,7 @@ static int rockchip_usb2phy_probe(struct
phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops);
if (IS_ERR(phy)) {

View File

@ -18,7 +18,7 @@ Signed-off-by: Vinod Koul <vkoul@kernel.org>
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -1172,6 +1172,12 @@ static int rockchip_usb2phy_otg_port_ini
@@ -1174,6 +1174,12 @@ static int rockchip_usb2phy_otg_port_ini
EXTCON_USB_HOST, &rport->event_nb);
if (ret)
dev_err(rphy->dev, "register USB HOST notifier failed\n");

View File

@ -0,0 +1,54 @@
From f340ed8664a55a467850ec1689996e63d9ee971a Mon Sep 17 00:00:00 2001
From: Peter Geis <pgwipeout@gmail.com>
Date: Fri, 2 Sep 2022 14:45:42 -0400
Subject: [PATCH] phy: rockchip-inno-usb2: Return zero after otg sync
The otg sync state patch reuses the ret variable, but fails to set it to
zero after use. This leads to a situation when the otg port is in
peripheral mode where the otg phy aborts halfway through setup. It also
fails to account for a failure to register the extcon notifier. Fix this
by using our own variable and skipping otg sync in case of failure.
Fixes: 8dc60f8da22f ("phy: rockchip-inno-usb2: Sync initial otg state")
Reported-by: Markus Reichl <m.reichl@fivetechno.de>
Reported-by: Michael Riesch <michael.riesch@wolfvision.net>
Signed-off-by: Peter Geis <pgwipeout@gmail.com>
Tested-by: Michael Riesch <michael.riesch@wolfvision.net>
Tested-by: Markus Reichl <m.reichl@fivetechno.de>
Reviewed-by: Samuel Holland <samuel@sholland.org>
Link: https://lore.kernel.org/r/20220902184543.1234835-1-pgwipeout@gmail.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
---
drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -1134,7 +1134,7 @@ static int rockchip_usb2phy_otg_port_ini
struct rockchip_usb2phy_port *rport,
struct device_node *child_np)
{
- int ret;
+ int ret, id;
rport->port_id = USB2PHY_PORT_OTG;
rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
@@ -1172,13 +1172,15 @@ static int rockchip_usb2phy_otg_port_ini
ret = devm_extcon_register_notifier(rphy->dev, rphy->edev,
EXTCON_USB_HOST, &rport->event_nb);
- if (ret)
+ if (ret) {
dev_err(rphy->dev, "register USB HOST notifier failed\n");
+ goto out;
+ }
if (!of_property_read_bool(rphy->dev->of_node, "extcon")) {
/* do initial sync of usb state */
- ret = property_enabled(rphy->grf, &rport->port_cfg->utmi_id);
- extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !ret);
+ id = property_enabled(rphy->grf, &rport->port_cfg->utmi_id);
+ extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !id);
}
}

View File

@ -0,0 +1,26 @@
From 4104a713204d62aca482eebb0c6226d82a0721eb Mon Sep 17 00:00:00 2001
From: Frank Sae <Frank.Sae@motor-comm.com>
Date: Sat, 28 Jan 2023 14:35:57 +0800
Subject: [PATCH] net: phy: fix the spelling problem of Sentinel
CHECK: 'sentinal' may be misspelled - perhaps 'sentinel'?
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20230128063558.5850-1-Frank.Sae@motor-comm.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/motorcomm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -1804,7 +1804,7 @@ static const struct mdio_device_id __may
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8511) },
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8521) },
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },
- { /* sentinal */ }
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(mdio, motorcomm_tbl);

View File

@ -0,0 +1,29 @@
From 3c1dc22162d673d595855d24f95200ed2643f88f Mon Sep 17 00:00:00 2001
From: Frank Sae <Frank.Sae@motor-comm.com>
Date: Sat, 28 Jan 2023 14:35:58 +0800
Subject: [PATCH] net: phy: motorcomm: change the phy id of yt8521 and yt8531s
to lowercase
The phy id is usually defined in lower case.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20230128063558.5850-2-Frank.Sae@motor-comm.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/motorcomm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -12,8 +12,8 @@
#include <linux/phy.h>
#define PHY_ID_YT8511 0x0000010a
-#define PHY_ID_YT8521 0x0000011A
-#define PHY_ID_YT8531S 0x4F51E91A
+#define PHY_ID_YT8521 0x0000011a
+#define PHY_ID_YT8531S 0x4f51e91a
/* YT8521/YT8531S Register Overview
* UTP Register space | FIBER Register space

View File

@ -0,0 +1,107 @@
From 4869a146cd60fc8115230f0a45e15e534c531922 Mon Sep 17 00:00:00 2001
From: Frank Sae <Frank.Sae@motor-comm.com>
Date: Thu, 2 Feb 2023 11:00:34 +0800
Subject: [PATCH] net: phy: Add BIT macro for Motorcomm yt8521/yt8531 gigabit
ethernet phy
Add BIT macro for Motorcomm yt8521/yt8531 gigabit ethernet phy.
This is a preparatory patch. Add BIT macro for 0xA012 reg, and
supplement for 0xA001 and 0xA003 reg. These will be used to support dts.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/motorcomm.c | 55 ++++++++++++++++++++++++++++++++++---
1 file changed, 51 insertions(+), 4 deletions(-)
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -161,6 +161,11 @@
#define YT8521_CHIP_CONFIG_REG 0xA001
#define YT8521_CCR_SW_RST BIT(15)
+/* 1b0 disable 1.9ns rxc clock delay *default*
+ * 1b1 enable 1.9ns rxc clock delay
+ */
+#define YT8521_CCR_RXC_DLY_EN BIT(8)
+#define YT8521_CCR_RXC_DLY_1_900_NS 1900
#define YT8521_CCR_MODE_SEL_MASK (BIT(2) | BIT(1) | BIT(0))
#define YT8521_CCR_MODE_UTP_TO_RGMII 0
@@ -178,22 +183,41 @@
#define YT8521_MODE_POLL 0x3
#define YT8521_RGMII_CONFIG1_REG 0xA003
-
+/* 1b0 use original tx_clk_rgmii *default*
+ * 1b1 use inverted tx_clk_rgmii.
+ */
+#define YT8521_RC1R_TX_CLK_SEL_INVERTED BIT(14)
/* TX Gig-E Delay is bits 3:0, default 0x1
* TX Fast-E Delay is bits 7:4, default 0xf
* RX Delay is bits 13:10, default 0x0
* Delay = 150ps * N
* On = 2250ps, off = 0ps
*/
-#define YT8521_RC1R_RX_DELAY_MASK (0xF << 10)
+#define YT8521_RC1R_RX_DELAY_MASK GENMASK(13, 10)
#define YT8521_RC1R_RX_DELAY_EN (0xF << 10)
#define YT8521_RC1R_RX_DELAY_DIS (0x0 << 10)
-#define YT8521_RC1R_FE_TX_DELAY_MASK (0xF << 4)
+#define YT8521_RC1R_FE_TX_DELAY_MASK GENMASK(7, 4)
#define YT8521_RC1R_FE_TX_DELAY_EN (0xF << 4)
#define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << 4)
-#define YT8521_RC1R_GE_TX_DELAY_MASK (0xF << 0)
+#define YT8521_RC1R_GE_TX_DELAY_MASK GENMASK(3, 0)
#define YT8521_RC1R_GE_TX_DELAY_EN (0xF << 0)
#define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << 0)
+#define YT8521_RC1R_RGMII_0_000_NS 0
+#define YT8521_RC1R_RGMII_0_150_NS 1
+#define YT8521_RC1R_RGMII_0_300_NS 2
+#define YT8521_RC1R_RGMII_0_450_NS 3
+#define YT8521_RC1R_RGMII_0_600_NS 4
+#define YT8521_RC1R_RGMII_0_750_NS 5
+#define YT8521_RC1R_RGMII_0_900_NS 6
+#define YT8521_RC1R_RGMII_1_050_NS 7
+#define YT8521_RC1R_RGMII_1_200_NS 8
+#define YT8521_RC1R_RGMII_1_350_NS 9
+#define YT8521_RC1R_RGMII_1_500_NS 10
+#define YT8521_RC1R_RGMII_1_650_NS 11
+#define YT8521_RC1R_RGMII_1_800_NS 12
+#define YT8521_RC1R_RGMII_1_950_NS 13
+#define YT8521_RC1R_RGMII_2_100_NS 14
+#define YT8521_RC1R_RGMII_2_250_NS 15
#define YTPHY_MISC_CONFIG_REG 0xA006
#define YTPHY_MCR_FIBER_SPEED_MASK BIT(0)
@@ -222,6 +246,29 @@
*/
#define YTPHY_WCR_TYPE_PULSE BIT(0)
+#define YTPHY_SYNCE_CFG_REG 0xA012
+#define YT8521_SCR_SYNCE_ENABLE BIT(5)
+/* 1b0 output 25m clock
+ * 1b1 output 125m clock *default*
+ */
+#define YT8521_SCR_CLK_FRE_SEL_125M BIT(3)
+#define YT8521_SCR_CLK_SRC_MASK GENMASK(2, 1)
+#define YT8521_SCR_CLK_SRC_PLL_125M 0
+#define YT8521_SCR_CLK_SRC_UTP_RX 1
+#define YT8521_SCR_CLK_SRC_SDS_RX 2
+#define YT8521_SCR_CLK_SRC_REF_25M 3
+#define YT8531_SCR_SYNCE_ENABLE BIT(6)
+/* 1b0 output 25m clock *default*
+ * 1b1 output 125m clock
+ */
+#define YT8531_SCR_CLK_FRE_SEL_125M BIT(4)
+#define YT8531_SCR_CLK_SRC_MASK GENMASK(3, 1)
+#define YT8531_SCR_CLK_SRC_PLL_125M 0
+#define YT8531_SCR_CLK_SRC_UTP_RX 1
+#define YT8531_SCR_CLK_SRC_SDS_RX 2
+#define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL 3
+#define YT8531_SCR_CLK_SRC_REF_25M 4
+#define YT8531_SCR_CLK_SRC_SSC_25M 5
#define YT8531S_SYNCE_CFG_REG 0xA012
#define YT8531S_SCR_SYNCE_ENABLE BIT(6)

View File

@ -0,0 +1,343 @@
From a6e68f0f8769f79c67cdcfb6302feecd36197dec Mon Sep 17 00:00:00 2001
From: Frank Sae <Frank.Sae@motor-comm.com>
Date: Thu, 2 Feb 2023 11:00:35 +0800
Subject: [PATCH] net: phy: Add dts support for Motorcomm yt8521 gigabit
ethernet phy
Add dts support for Motorcomm yt8521 gigabit ethernet phy.
Add ytphy_rgmii_clk_delay_config function to support dst config for
the delay of rgmii clk. This funciont is common for yt8521, yt8531s
and yt8531.
This patch has been verified on AM335x platform.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/motorcomm.c | 253 ++++++++++++++++++++++++++++--------
1 file changed, 199 insertions(+), 54 deletions(-)
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/phy.h>
+#include <linux/of.h>
#define PHY_ID_YT8511 0x0000010a
#define PHY_ID_YT8521 0x0000011a
@@ -187,21 +188,9 @@
* 1b1 use inverted tx_clk_rgmii.
*/
#define YT8521_RC1R_TX_CLK_SEL_INVERTED BIT(14)
-/* TX Gig-E Delay is bits 3:0, default 0x1
- * TX Fast-E Delay is bits 7:4, default 0xf
- * RX Delay is bits 13:10, default 0x0
- * Delay = 150ps * N
- * On = 2250ps, off = 0ps
- */
#define YT8521_RC1R_RX_DELAY_MASK GENMASK(13, 10)
-#define YT8521_RC1R_RX_DELAY_EN (0xF << 10)
-#define YT8521_RC1R_RX_DELAY_DIS (0x0 << 10)
#define YT8521_RC1R_FE_TX_DELAY_MASK GENMASK(7, 4)
-#define YT8521_RC1R_FE_TX_DELAY_EN (0xF << 4)
-#define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << 4)
#define YT8521_RC1R_GE_TX_DELAY_MASK GENMASK(3, 0)
-#define YT8521_RC1R_GE_TX_DELAY_EN (0xF << 0)
-#define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << 0)
#define YT8521_RC1R_RGMII_0_000_NS 0
#define YT8521_RC1R_RGMII_0_150_NS 1
#define YT8521_RC1R_RGMII_0_300_NS 2
@@ -274,6 +263,10 @@
/* Extended Register end */
+#define YTPHY_DTS_OUTPUT_CLK_DIS 0
+#define YTPHY_DTS_OUTPUT_CLK_25M 25000000
+#define YTPHY_DTS_OUTPUT_CLK_125M 125000000
+
struct yt8521_priv {
/* combo_advertising is used for case of YT8521 in combo mode,
* this means that yt8521 may work in utp or fiber mode which depends
@@ -641,6 +634,142 @@ static int yt8521_write_page(struct phy_
};
/**
+ * struct ytphy_cfg_reg_map - map a config value to a register value
+ * @cfg: value in device configuration
+ * @reg: value in the register
+ */
+struct ytphy_cfg_reg_map {
+ u32 cfg;
+ u32 reg;
+};
+
+static const struct ytphy_cfg_reg_map ytphy_rgmii_delays[] = {
+ /* for tx delay / rx delay with YT8521_CCR_RXC_DLY_EN is not set. */
+ { 0, YT8521_RC1R_RGMII_0_000_NS },
+ { 150, YT8521_RC1R_RGMII_0_150_NS },
+ { 300, YT8521_RC1R_RGMII_0_300_NS },
+ { 450, YT8521_RC1R_RGMII_0_450_NS },
+ { 600, YT8521_RC1R_RGMII_0_600_NS },
+ { 750, YT8521_RC1R_RGMII_0_750_NS },
+ { 900, YT8521_RC1R_RGMII_0_900_NS },
+ { 1050, YT8521_RC1R_RGMII_1_050_NS },
+ { 1200, YT8521_RC1R_RGMII_1_200_NS },
+ { 1350, YT8521_RC1R_RGMII_1_350_NS },
+ { 1500, YT8521_RC1R_RGMII_1_500_NS },
+ { 1650, YT8521_RC1R_RGMII_1_650_NS },
+ { 1800, YT8521_RC1R_RGMII_1_800_NS },
+ { 1950, YT8521_RC1R_RGMII_1_950_NS }, /* default tx/rx delay */
+ { 2100, YT8521_RC1R_RGMII_2_100_NS },
+ { 2250, YT8521_RC1R_RGMII_2_250_NS },
+
+ /* only for rx delay with YT8521_CCR_RXC_DLY_EN is set. */
+ { 0 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_000_NS },
+ { 150 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_150_NS },
+ { 300 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_300_NS },
+ { 450 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_450_NS },
+ { 600 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_600_NS },
+ { 750 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_750_NS },
+ { 900 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_0_900_NS },
+ { 1050 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_050_NS },
+ { 1200 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_200_NS },
+ { 1350 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_350_NS },
+ { 1500 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_500_NS },
+ { 1650 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_650_NS },
+ { 1800 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_800_NS },
+ { 1950 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_1_950_NS },
+ { 2100 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_2_100_NS },
+ { 2250 + YT8521_CCR_RXC_DLY_1_900_NS, YT8521_RC1R_RGMII_2_250_NS }
+};
+
+static u32 ytphy_get_delay_reg_value(struct phy_device *phydev,
+ const char *prop_name,
+ const struct ytphy_cfg_reg_map *tbl,
+ int tb_size,
+ u16 *rxc_dly_en,
+ u32 dflt)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ int tb_size_half = tb_size / 2;
+ u32 val;
+ int i;
+
+ if (of_property_read_u32(node, prop_name, &val))
+ goto err_dts_val;
+
+ /* when rxc_dly_en is NULL, it is get the delay for tx, only half of
+ * tb_size is valid.
+ */
+ if (!rxc_dly_en)
+ tb_size = tb_size_half;
+
+ for (i = 0; i < tb_size; i++) {
+ if (tbl[i].cfg == val) {
+ if (rxc_dly_en && i < tb_size_half)
+ *rxc_dly_en = 0;
+ return tbl[i].reg;
+ }
+ }
+
+ phydev_warn(phydev, "Unsupported value %d for %s using default (%u)\n",
+ val, prop_name, dflt);
+
+err_dts_val:
+ /* when rxc_dly_en is not NULL, it is get the delay for rx.
+ * The rx default in dts and ytphy_rgmii_clk_delay_config is 1950 ps,
+ * so YT8521_CCR_RXC_DLY_EN should not be set.
+ */
+ if (rxc_dly_en)
+ *rxc_dly_en = 0;
+
+ return dflt;
+}
+
+static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev)
+{
+ int tb_size = ARRAY_SIZE(ytphy_rgmii_delays);
+ u16 rxc_dly_en = YT8521_CCR_RXC_DLY_EN;
+ u32 rx_reg, tx_reg;
+ u16 mask, val = 0;
+ int ret;
+
+ rx_reg = ytphy_get_delay_reg_value(phydev, "rx-internal-delay-ps",
+ ytphy_rgmii_delays, tb_size,
+ &rxc_dly_en,
+ YT8521_RC1R_RGMII_1_950_NS);
+ tx_reg = ytphy_get_delay_reg_value(phydev, "tx-internal-delay-ps",
+ ytphy_rgmii_delays, tb_size, NULL,
+ YT8521_RC1R_RGMII_1_950_NS);
+
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ rxc_dly_en = 0;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ rxc_dly_en = 0;
+ val |= FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg);
+ break;
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ val |= FIELD_PREP(YT8521_RC1R_RX_DELAY_MASK, rx_reg) |
+ FIELD_PREP(YT8521_RC1R_GE_TX_DELAY_MASK, tx_reg);
+ break;
+ default: /* do not support other modes */
+ return -EOPNOTSUPP;
+ }
+
+ ret = ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG,
+ YT8521_CCR_RXC_DLY_EN, rxc_dly_en);
+ if (ret < 0)
+ return ret;
+
+ /* Generally, it is not necessary to adjust YT8521_RC1R_FE_TX_DELAY */
+ mask = YT8521_RC1R_RX_DELAY_MASK | YT8521_RC1R_GE_TX_DELAY_MASK;
+ return ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, mask, val);
+}
+
+/**
* yt8521_probe() - read chip config then set suitable polling_mode
* @phydev: a pointer to a &struct phy_device
*
@@ -648,9 +777,12 @@ static int yt8521_write_page(struct phy_
*/
static int yt8521_probe(struct phy_device *phydev)
{
+ struct device_node *node = phydev->mdio.dev.of_node;
struct device *dev = &phydev->mdio.dev;
struct yt8521_priv *priv;
int chip_config;
+ u16 mask, val;
+ u32 freq;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -695,7 +827,45 @@ static int yt8521_probe(struct phy_devic
return ret;
}
- return 0;
+ if (of_property_read_u32(node, "motorcomm,clk-out-frequency-hz-hz", &freq))
+ freq = YTPHY_DTS_OUTPUT_CLK_DIS;
+
+ if (phydev->drv->phy_id == PHY_ID_YT8521) {
+ switch (freq) {
+ case YTPHY_DTS_OUTPUT_CLK_DIS:
+ mask = YT8521_SCR_SYNCE_ENABLE;
+ val = 0;
+ break;
+ case YTPHY_DTS_OUTPUT_CLK_25M:
+ mask = YT8521_SCR_SYNCE_ENABLE |
+ YT8521_SCR_CLK_SRC_MASK |
+ YT8521_SCR_CLK_FRE_SEL_125M;
+ val = YT8521_SCR_SYNCE_ENABLE |
+ FIELD_PREP(YT8521_SCR_CLK_SRC_MASK,
+ YT8521_SCR_CLK_SRC_REF_25M);
+ break;
+ case YTPHY_DTS_OUTPUT_CLK_125M:
+ mask = YT8521_SCR_SYNCE_ENABLE |
+ YT8521_SCR_CLK_SRC_MASK |
+ YT8521_SCR_CLK_FRE_SEL_125M;
+ val = YT8521_SCR_SYNCE_ENABLE |
+ YT8521_SCR_CLK_FRE_SEL_125M |
+ FIELD_PREP(YT8521_SCR_CLK_SRC_MASK,
+ YT8521_SCR_CLK_SRC_PLL_125M);
+ break;
+ default:
+ phydev_warn(phydev, "Freq err:%u\n", freq);
+ return -EINVAL;
+ }
+ } else if (phydev->drv->phy_id == PHY_ID_YT8531S) {
+ return 0;
+ } else {
+ phydev_warn(phydev, "PHY id err\n");
+ return -EINVAL;
+ }
+
+ return ytphy_modify_ext_with_lock(phydev, YTPHY_SYNCE_CFG_REG, mask,
+ val);
}
/**
@@ -1180,61 +1350,36 @@ static int yt8521_resume(struct phy_devi
*/
static int yt8521_config_init(struct phy_device *phydev)
{
+ struct device_node *node = phydev->mdio.dev.of_node;
int old_page;
int ret = 0;
- u16 val;
old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
if (old_page < 0)
goto err_restore_page;
- switch (phydev->interface) {
- case PHY_INTERFACE_MODE_RGMII:
- val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS;
- val |= YT8521_RC1R_RX_DELAY_DIS;
- break;
- case PHY_INTERFACE_MODE_RGMII_RXID:
- val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS;
- val |= YT8521_RC1R_RX_DELAY_EN;
- break;
- case PHY_INTERFACE_MODE_RGMII_TXID:
- val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN;
- val |= YT8521_RC1R_RX_DELAY_DIS;
- break;
- case PHY_INTERFACE_MODE_RGMII_ID:
- val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN;
- val |= YT8521_RC1R_RX_DELAY_EN;
- break;
- case PHY_INTERFACE_MODE_SGMII:
- break;
- default: /* do not support other modes */
- ret = -EOPNOTSUPP;
- goto err_restore_page;
- }
-
/* set rgmii delay mode */
if (phydev->interface != PHY_INTERFACE_MODE_SGMII) {
- ret = ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG,
- (YT8521_RC1R_RX_DELAY_MASK |
- YT8521_RC1R_FE_TX_DELAY_MASK |
- YT8521_RC1R_GE_TX_DELAY_MASK),
- val);
+ ret = ytphy_rgmii_clk_delay_config(phydev);
if (ret < 0)
goto err_restore_page;
}
- /* disable auto sleep */
- ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG,
- YT8521_ESC1R_SLEEP_SW, 0);
- if (ret < 0)
- goto err_restore_page;
-
- /* enable RXC clock when no wire plug */
- ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG,
- YT8521_CGR_RX_CLK_EN, 0);
- if (ret < 0)
- goto err_restore_page;
+ if (of_property_read_bool(node, "motorcomm,auto-sleep-disabled")) {
+ /* disable auto sleep */
+ ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG,
+ YT8521_ESC1R_SLEEP_SW, 0);
+ if (ret < 0)
+ goto err_restore_page;
+ }
+ if (of_property_read_bool(node, "motorcomm,keep-pll-enabled")) {
+ /* enable RXC clock when no wire plug */
+ ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG,
+ YT8521_CGR_RX_CLK_EN, 0);
+ if (ret < 0)
+ goto err_restore_page;
+ }
err_restore_page:
return phy_restore_page(phydev, old_page, ret);
}

View File

@ -0,0 +1,100 @@
From 36152f87dda4af221b16258751451d9cd3d0fb0b Mon Sep 17 00:00:00 2001
From: Frank Sae <Frank.Sae@motor-comm.com>
Date: Thu, 2 Feb 2023 11:00:36 +0800
Subject: [PATCH] net: phy: Add dts support for Motorcomm yt8531s gigabit
ethernet phy
Add dts support for Motorcomm yt8531s gigabit ethernet phy.
Change yt8521_probe to support clk config of yt8531s. Becase
yt8521_probe does the things which yt8531s is needed, so
removed yt8531s function.
This patch has been verified on AM335x platform with yt8531s board.
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/motorcomm.c | 51 ++++++++++++++++++++-----------------
1 file changed, 27 insertions(+), 24 deletions(-)
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -258,8 +258,6 @@
#define YT8531_SCR_CLK_SRC_CLOCK_FROM_DIGITAL 3
#define YT8531_SCR_CLK_SRC_REF_25M 4
#define YT8531_SCR_CLK_SRC_SSC_25M 5
-#define YT8531S_SYNCE_CFG_REG 0xA012
-#define YT8531S_SCR_SYNCE_ENABLE BIT(6)
/* Extended Register end */
@@ -858,7 +856,32 @@ static int yt8521_probe(struct phy_devic
return -EINVAL;
}
} else if (phydev->drv->phy_id == PHY_ID_YT8531S) {
- return 0;
+ switch (freq) {
+ case YTPHY_DTS_OUTPUT_CLK_DIS:
+ mask = YT8531_SCR_SYNCE_ENABLE;
+ val = 0;
+ break;
+ case YTPHY_DTS_OUTPUT_CLK_25M:
+ mask = YT8531_SCR_SYNCE_ENABLE |
+ YT8531_SCR_CLK_SRC_MASK |
+ YT8531_SCR_CLK_FRE_SEL_125M;
+ val = YT8531_SCR_SYNCE_ENABLE |
+ FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
+ YT8531_SCR_CLK_SRC_REF_25M);
+ break;
+ case YTPHY_DTS_OUTPUT_CLK_125M:
+ mask = YT8531_SCR_SYNCE_ENABLE |
+ YT8531_SCR_CLK_SRC_MASK |
+ YT8531_SCR_CLK_FRE_SEL_125M;
+ val = YT8531_SCR_SYNCE_ENABLE |
+ YT8531_SCR_CLK_FRE_SEL_125M |
+ FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
+ YT8531_SCR_CLK_SRC_PLL_125M);
+ break;
+ default:
+ phydev_warn(phydev, "Freq err:%u\n", freq);
+ return -EINVAL;
+ }
} else {
phydev_warn(phydev, "PHY id err\n");
return -EINVAL;
@@ -869,26 +892,6 @@ static int yt8521_probe(struct phy_devic
}
/**
- * yt8531s_probe() - read chip config then set suitable polling_mode
- * @phydev: a pointer to a &struct phy_device
- *
- * returns 0 or negative errno code
- */
-static int yt8531s_probe(struct phy_device *phydev)
-{
- int ret;
-
- /* Disable SyncE clock output by default */
- ret = ytphy_modify_ext_with_lock(phydev, YT8531S_SYNCE_CFG_REG,
- YT8531S_SCR_SYNCE_ENABLE, 0);
- if (ret < 0)
- return ret;
-
- /* same as yt8521_probe */
- return yt8521_probe(phydev);
-}
-
-/**
* ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp
* @phydev: a pointer to a &struct phy_device
*
@@ -1970,7 +1973,7 @@ static struct phy_driver motorcomm_phy_d
PHY_ID_MATCH_EXACT(PHY_ID_YT8531S),
.name = "YT8531S Gigabit Ethernet",
.get_features = yt8521_get_features,
- .probe = yt8531s_probe,
+ .probe = yt8521_probe,
.read_page = yt8521_read_page,
.write_page = yt8521_write_page,
.get_wol = ytphy_get_wol,

View File

@ -0,0 +1,302 @@
From 4ac94f728a588e7096dd5010cd7141a309ea7805 Mon Sep 17 00:00:00 2001
From: Frank Sae <Frank.Sae@motor-comm.com>
Date: Thu, 2 Feb 2023 11:00:37 +0800
Subject: [PATCH] net: phy: Add driver for Motorcomm yt8531 gigabit ethernet
phy
Add a driver for the motorcomm yt8531 gigabit ethernet phy. We have
verified the driver on AM335x platform with yt8531 board. On the
board, yt8531 gigabit ethernet phy works in utp mode, RGMII
interface, supports 1000M/100M/10M speeds, and wol(magic package).
Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/Kconfig | 2 +-
drivers/net/phy/motorcomm.c | 208 +++++++++++++++++++++++++++++++++++-
2 files changed, 207 insertions(+), 3 deletions(-)
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -319,7 +319,7 @@ config MOTORCOMM_PHY
tristate "Motorcomm PHYs"
help
Enables support for Motorcomm network PHYs.
- Currently supports the YT8511, YT8521, YT8531S Gigabit Ethernet PHYs.
+ Currently supports YT85xx Gigabit Ethernet PHYs.
config NATIONAL_PHY
tristate "National Semiconductor PHYs"
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Motorcomm 8511/8521/8531S PHY driver.
+ * Motorcomm 8511/8521/8531/8531S PHY driver.
*
* Author: Peter Geis <pgwipeout@gmail.com>
* Author: Frank <Frank.Sae@motor-comm.com>
@@ -14,6 +14,7 @@
#define PHY_ID_YT8511 0x0000010a
#define PHY_ID_YT8521 0x0000011a
+#define PHY_ID_YT8531 0x4f51e91b
#define PHY_ID_YT8531S 0x4f51e91a
/* YT8521/YT8531S Register Overview
@@ -517,6 +518,61 @@ err_restore_page:
return phy_restore_page(phydev, old_page, ret);
}
+static int yt8531_set_wol(struct phy_device *phydev,
+ struct ethtool_wolinfo *wol)
+{
+ const u16 mac_addr_reg[] = {
+ YTPHY_WOL_MACADDR2_REG,
+ YTPHY_WOL_MACADDR1_REG,
+ YTPHY_WOL_MACADDR0_REG,
+ };
+ const u8 *mac_addr;
+ u16 mask, val;
+ int ret;
+ u8 i;
+
+ if (wol->wolopts & WAKE_MAGIC) {
+ mac_addr = phydev->attached_dev->dev_addr;
+
+ /* Store the device address for the magic packet */
+ for (i = 0; i < 3; i++) {
+ ret = ytphy_write_ext_with_lock(phydev, mac_addr_reg[i],
+ ((mac_addr[i * 2] << 8)) |
+ (mac_addr[i * 2 + 1]));
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Enable WOL feature */
+ mask = YTPHY_WCR_PULSE_WIDTH_MASK | YTPHY_WCR_INTR_SEL;
+ val = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;
+ val |= YTPHY_WCR_TYPE_PULSE | YTPHY_WCR_PULSE_WIDTH_672MS;
+ ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG,
+ mask, val);
+ if (ret < 0)
+ return ret;
+
+ /* Enable WOL interrupt */
+ ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, 0,
+ YTPHY_IER_WOL);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* Disable WOL feature */
+ mask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;
+ ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG,
+ mask, 0);
+
+ /* Disable WOL interrupt */
+ ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG,
+ YTPHY_IER_WOL, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int yt8511_read_page(struct phy_device *phydev)
{
return __phy_read(phydev, YT8511_PAGE_SELECT);
@@ -767,6 +823,17 @@ static int ytphy_rgmii_clk_delay_config(
return ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, mask, val);
}
+static int ytphy_rgmii_clk_delay_config_with_lock(struct phy_device *phydev)
+{
+ int ret;
+
+ phy_lock_mdio_bus(phydev);
+ ret = ytphy_rgmii_clk_delay_config(phydev);
+ phy_unlock_mdio_bus(phydev);
+
+ return ret;
+}
+
/**
* yt8521_probe() - read chip config then set suitable polling_mode
* @phydev: a pointer to a &struct phy_device
@@ -891,6 +958,43 @@ static int yt8521_probe(struct phy_devic
val);
}
+static int yt8531_probe(struct phy_device *phydev)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ u16 mask, val;
+ u32 freq;
+
+ if (of_property_read_u32(node, "motorcomm,clk-out-frequency-hz-hz", &freq))
+ freq = YTPHY_DTS_OUTPUT_CLK_DIS;
+
+ switch (freq) {
+ case YTPHY_DTS_OUTPUT_CLK_DIS:
+ mask = YT8531_SCR_SYNCE_ENABLE;
+ val = 0;
+ break;
+ case YTPHY_DTS_OUTPUT_CLK_25M:
+ mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK |
+ YT8531_SCR_CLK_FRE_SEL_125M;
+ val = YT8531_SCR_SYNCE_ENABLE |
+ FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
+ YT8531_SCR_CLK_SRC_REF_25M);
+ break;
+ case YTPHY_DTS_OUTPUT_CLK_125M:
+ mask = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_SRC_MASK |
+ YT8531_SCR_CLK_FRE_SEL_125M;
+ val = YT8531_SCR_SYNCE_ENABLE | YT8531_SCR_CLK_FRE_SEL_125M |
+ FIELD_PREP(YT8531_SCR_CLK_SRC_MASK,
+ YT8531_SCR_CLK_SRC_PLL_125M);
+ break;
+ default:
+ phydev_warn(phydev, "Freq err:%u\n", freq);
+ return -EINVAL;
+ }
+
+ return ytphy_modify_ext_with_lock(phydev, YTPHY_SYNCE_CFG_REG, mask,
+ val);
+}
+
/**
* ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp
* @phydev: a pointer to a &struct phy_device
@@ -1387,6 +1491,94 @@ err_restore_page:
return phy_restore_page(phydev, old_page, ret);
}
+static int yt8531_config_init(struct phy_device *phydev)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ int ret;
+
+ ret = ytphy_rgmii_clk_delay_config_with_lock(phydev);
+ if (ret < 0)
+ return ret;
+
+ if (of_property_read_bool(node, "motorcomm,auto-sleep-disabled")) {
+ /* disable auto sleep */
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8521_EXTREG_SLEEP_CONTROL1_REG,
+ YT8521_ESC1R_SLEEP_SW, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (of_property_read_bool(node, "motorcomm,keep-pll-enabled")) {
+ /* enable RXC clock when no wire plug */
+ ret = ytphy_modify_ext_with_lock(phydev,
+ YT8521_CLOCK_GATING_REG,
+ YT8521_CGR_RX_CLK_EN, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * yt8531_link_change_notify() - Adjust the tx clock direction according to
+ * the current speed and dts config.
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * NOTE: This function is only used to adapt to VF2 with JH7110 SoC. Please
+ * keep "motorcomm,tx-clk-adj-enabled" not exist in dts when the soc is not
+ * JH7110.
+ */
+static void yt8531_link_change_notify(struct phy_device *phydev)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ bool tx_clk_adj_enabled = false;
+ bool tx_clk_1000_inverted;
+ bool tx_clk_100_inverted;
+ bool tx_clk_10_inverted;
+ u16 val = 0;
+ int ret;
+
+ if (of_property_read_bool(node, "motorcomm,tx-clk-adj-enabled"))
+ tx_clk_adj_enabled = true;
+
+ if (!tx_clk_adj_enabled)
+ return;
+
+ if (of_property_read_bool(node, "motorcomm,tx-clk-10-inverted"))
+ tx_clk_10_inverted = true;
+ if (of_property_read_bool(node, "motorcomm,tx-clk-100-inverted"))
+ tx_clk_100_inverted = true;
+ if (of_property_read_bool(node, "motorcomm,tx-clk-1000-inverted"))
+ tx_clk_1000_inverted = true;
+
+ if (phydev->speed < 0)
+ return;
+
+ switch (phydev->speed) {
+ case SPEED_1000:
+ if (tx_clk_1000_inverted)
+ val = YT8521_RC1R_TX_CLK_SEL_INVERTED;
+ break;
+ case SPEED_100:
+ if (tx_clk_100_inverted)
+ val = YT8521_RC1R_TX_CLK_SEL_INVERTED;
+ break;
+ case SPEED_10:
+ if (tx_clk_10_inverted)
+ val = YT8521_RC1R_TX_CLK_SEL_INVERTED;
+ break;
+ default:
+ return;
+ }
+
+ ret = ytphy_modify_ext_with_lock(phydev, YT8521_RGMII_CONFIG1_REG,
+ YT8521_RC1R_TX_CLK_SEL_INVERTED, val);
+ if (ret < 0)
+ phydev_warn(phydev, "Modify TX_CLK_SEL err:%d\n", ret);
+}
+
/**
* yt8521_prepare_fiber_features() - A small helper function that setup
* fiber's features.
@@ -1970,6 +2162,17 @@ static struct phy_driver motorcomm_phy_d
.resume = yt8521_resume,
},
{
+ PHY_ID_MATCH_EXACT(PHY_ID_YT8531),
+ .name = "YT8531 Gigabit Ethernet",
+ .probe = yt8531_probe,
+ .config_init = yt8531_config_init,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .get_wol = ytphy_get_wol,
+ .set_wol = yt8531_set_wol,
+ .link_change_notify = yt8531_link_change_notify,
+ },
+ {
PHY_ID_MATCH_EXACT(PHY_ID_YT8531S),
.name = "YT8531S Gigabit Ethernet",
.get_features = yt8521_get_features,
@@ -1990,7 +2193,7 @@ static struct phy_driver motorcomm_phy_d
module_phy_driver(motorcomm_phy_drvs);
-MODULE_DESCRIPTION("Motorcomm 8511/8521/8531S PHY driver");
+MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S PHY driver");
MODULE_AUTHOR("Peter Geis");
MODULE_AUTHOR("Frank");
MODULE_LICENSE("GPL");
@@ -1998,6 +2201,7 @@ MODULE_LICENSE("GPL");
static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8511) },
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8521) },
+ { PHY_ID_MATCH_EXACT(PHY_ID_YT8531) },
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },
{ /* sentinel */ }
};

View File

@ -1,664 +0,0 @@
From: Frank <Frank.Sae@motor-comm.com>
To: Peter Geis <pgwipeout@gmail.com>, Andrew Lunn <andrew@lunn.ch>,
Heiner Kallweit <hkallweit1@gmail.com>,
Russell King <linux@armlinux.org.uk>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Rob Herring <robh+dt@kernel.org>,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>
Cc: xiaogang.fan@motor-comm.com, fei.zhang@motor-comm.com,
hua.sun@motor-comm.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, Frank <Frank.Sae@motor-comm.com>,
devicetree@vger.kernel.org
Subject: [PATCH net-next v1 2/3] net: phy: Add dts support for Motorcomm yt8521/yt8531s gigabit ethernet phy
Date: Thu, 5 Jan 2023 15:30:23 +0800 [thread overview]
Message-ID: <20230105073024.8390-3-Frank.Sae@motor-comm.com> (raw)
In-Reply-To: <20230105073024.8390-1-Frank.Sae@motor-comm.com>
Add dts support for yt8521 and yt8531s. This patch has
been tested on AM335x platform which has one YT8531S interface
card and passed all test cases.
Signed-off-by: Frank <Frank.Sae@motor-comm.com>
---
drivers/net/phy/motorcomm.c | 517 ++++++++++++++++++++++++++++++------
1 file changed, 434 insertions(+), 83 deletions(-)
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -10,10 +10,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/phy.h>
+#include <linux/of.h>
#define PHY_ID_YT8511 0x0000010a
-#define PHY_ID_YT8521 0x0000011A
-#define PHY_ID_YT8531S 0x4F51E91A
+#define PHY_ID_YT8521 0x0000011a
+#define PHY_ID_YT8531S 0x4f51e91a
/* YT8521/YT8531S Register Overview
* UTP Register space | FIBER Register space
@@ -144,6 +145,16 @@
#define YT8521_ESC1R_SLEEP_SW BIT(15)
#define YT8521_ESC1R_PLLON_SLP BIT(14)
+/* Phy Serdes analog cfg2 Register */
+#define YTPHY_SERDES_ANALOG_CFG2_REG 0xA1
+#define YTPHY_SAC2R_TX_AMPLITUDE_MASK ((0x7 << 13) | (0x7 << 1))
+#define YT8521_SAC2R_TX_AMPLITUDE_LOW ((0x7 << 13) | (0x0 << 1))
+#define YT8521_SAC2R_TX_AMPLITUDE_MIDDLE ((0x5 << 13) | (0x5 << 1))
+#define YT8521_SAC2R_TX_AMPLITUDE_HIGH ((0x3 << 13) | (0x6 << 1))
+#define YT8531S_SAC2R_TX_AMPLITUDE_LOW ((0x0 << 13) | (0x0 << 1))
+#define YT8531S_SAC2R_TX_AMPLITUDE_MIDDLE ((0x0 << 13) | (0x1 << 1))
+#define YT8531S_SAC2R_TX_AMPLITUDE_HIGH ((0x0 << 13) | (0x2 << 1))
+
/* Phy fiber Link timer cfg2 Register */
#define YT8521_LINK_TIMER_CFG2_REG 0xA5
#define YT8521_LTCR_EN_AUTOSEN BIT(15)
@@ -161,6 +172,7 @@
#define YT8521_CHIP_CONFIG_REG 0xA001
#define YT8521_CCR_SW_RST BIT(15)
+#define YT8521_CCR_RXC_DLY_EN BIT(8)
#define YT8521_CCR_MODE_SEL_MASK (BIT(2) | BIT(1) | BIT(0))
#define YT8521_CCR_MODE_UTP_TO_RGMII 0
@@ -178,22 +190,27 @@
#define YT8521_MODE_POLL 0x3
#define YT8521_RGMII_CONFIG1_REG 0xA003
-
+#define YT8521_RC1R_TX_CLK_SEL_MASK BIT(14)
+#define YT8521_RC1R_TX_CLK_SEL_ORIGINAL (0x0 << 14)
+#define YT8521_RC1R_TX_CLK_SEL_INVERTED (0x1 << 14)
/* TX Gig-E Delay is bits 3:0, default 0x1
* TX Fast-E Delay is bits 7:4, default 0xf
* RX Delay is bits 13:10, default 0x0
* Delay = 150ps * N
* On = 2250ps, off = 0ps
*/
-#define YT8521_RC1R_RX_DELAY_MASK (0xF << 10)
-#define YT8521_RC1R_RX_DELAY_EN (0xF << 10)
-#define YT8521_RC1R_RX_DELAY_DIS (0x0 << 10)
-#define YT8521_RC1R_FE_TX_DELAY_MASK (0xF << 4)
-#define YT8521_RC1R_FE_TX_DELAY_EN (0xF << 4)
-#define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << 4)
-#define YT8521_RC1R_GE_TX_DELAY_MASK (0xF << 0)
-#define YT8521_RC1R_GE_TX_DELAY_EN (0xF << 0)
-#define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << 0)
+#define YT8521_RC1R_GE_TX_DELAY_BIT (0)
+#define YT8521_RC1R_FE_TX_DELAY_BIT (4)
+#define YT8521_RC1R_RX_DELAY_BIT (10)
+#define YT8521_RC1R_RX_DELAY_MASK (0xF << YT8521_RC1R_RX_DELAY_BIT)
+#define YT8521_RC1R_RX_DELAY_EN (0xF << YT8521_RC1R_RX_DELAY_BIT)
+#define YT8521_RC1R_RX_DELAY_DIS (0x0 << YT8521_RC1R_RX_DELAY_BIT)
+#define YT8521_RC1R_FE_TX_DELAY_MASK (0xF << YT8521_RC1R_FE_TX_DELAY_BIT)
+#define YT8521_RC1R_FE_TX_DELAY_EN (0xF << YT8521_RC1R_FE_TX_DELAY_BIT)
+#define YT8521_RC1R_FE_TX_DELAY_DIS (0x0 << YT8521_RC1R_FE_TX_DELAY_BIT)
+#define YT8521_RC1R_GE_TX_DELAY_MASK (0xF << YT8521_RC1R_GE_TX_DELAY_BIT)
+#define YT8521_RC1R_GE_TX_DELAY_EN (0xF << YT8521_RC1R_GE_TX_DELAY_BIT)
+#define YT8521_RC1R_GE_TX_DELAY_DIS (0x0 << YT8521_RC1R_GE_TX_DELAY_BIT)
#define YTPHY_MISC_CONFIG_REG 0xA006
#define YTPHY_MCR_FIBER_SPEED_MASK BIT(0)
@@ -222,11 +239,33 @@
*/
#define YTPHY_WCR_TYPE_PULSE BIT(0)
-#define YT8531S_SYNCE_CFG_REG 0xA012
-#define YT8531S_SCR_SYNCE_ENABLE BIT(6)
+#define YTPHY_SYNCE_CFG_REG 0xA012
+#define YT8521_SCR_CLK_SRC_MASK (BIT(2) | BIT(1))
+#define YT8521_SCR_CLK_SRC_PLL_125M (0x0 << 1)
+#define YT8521_SCR_CLK_SRC_REF_25M (0x3 << 1)
+#define YT8521_SCR_SYNCE_ENABLE BIT(5)
+#define YT8521_SCR_CLK_FRE_SEL_MASK BIT(3)
+#define YT8521_SCR_CLK_FRE_SEL_125M (0x1 << 3)
+#define YT8521_SCR_CLK_FRE_SEL_25M (0x0 << 3)
+#define YT8531_SCR_CLK_SRC_MASK (BIT(3) | BIT(2) | BIT(1))
+#define YT8531_SCR_CLK_SRC_PLL_125M (0x0 << 1)
+#define YT8531_SCR_CLK_SRC_REF_25M (0x4 << 1)
+#define YT8531_SCR_SYNCE_ENABLE BIT(6)
+#define YT8531_SCR_CLK_FRE_SEL_MASK BIT(4)
+#define YT8531_SCR_CLK_FRE_SEL_125M (0x1 << 4)
+#define YT8531_SCR_CLK_FRE_SEL_25M (0x0 << 4)
/* Extended Register end */
+#define YTPHY_DTS_MAX_TX_AMPLITUDE 0x2
+#define YTPHY_DTS_MAX_DELAY_VAL 2250
+#define YTPHY_DTS_STEP_DELAY_VAL 150
+#define YTPHY_DTS_INVAL_VAL 0xFF
+
+#define YTPHY_DTS_OUTPUT_CLK_DIS 0
+#define YTPHY_DTS_OUTPUT_CLK_25M 25000000
+#define YTPHY_DTS_OUTPUT_CLK_125M 125000000
+
struct yt8521_priv {
/* combo_advertising is used for case of YT8521 in combo mode,
* this means that yt8521 may work in utp or fiber mode which depends
@@ -243,6 +282,30 @@ struct yt8521_priv {
* YT8521_RSSR_TO_BE_ARBITRATED
*/
u8 reg_page;
+
+ /* The following parameters are from dts */
+ /* rx delay = rx_delay_basic + rx_delay_additional
+ * basic delay is ~2ns, 0 = off, 1 = on
+ * rx_delay_additional,delay time = 150ps * val
+ */
+ u8 rx_delay_basic;
+ u8 rx_delay_additional;
+
+ /* tx_delay_ge is tx_delay for 1000Mbps
+ * tx_delay_fe is tx_delay for 100Mbps or 10Mbps
+ * delay time = 150ps * val
+ */
+ u8 tx_delay_ge;
+ u8 tx_delay_fe;
+ u8 sds_tx_amplitude;
+ bool keep_pll_enabled;
+ bool auto_sleep_disabled;
+ bool clock_ouput; /* output clock ctl: 0=off, 1=on */
+ bool clock_freq_125M; /* output clock freq selcect: 0=25M, 1=125M */
+ bool tx_clk_adj_enabled;/* tx clk adj ctl: 0=off, 1=on */
+ bool tx_clk_10_inverted;
+ bool tx_clk_100_inverted;
+ bool tx_clk_1000_inverted;
};
/**
@@ -593,6 +656,325 @@ static int yt8521_write_page(struct phy_
return ytphy_modify_ext(phydev, YT8521_REG_SPACE_SELECT_REG, mask, set);
};
+static int ytphy_parse_dt(struct phy_device *phydev)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ struct yt8521_priv *priv = phydev->priv;
+ u32 freq, val;
+ int ret;
+
+ priv->rx_delay_additional = YTPHY_DTS_INVAL_VAL;
+ priv->sds_tx_amplitude = YTPHY_DTS_INVAL_VAL;
+ priv->rx_delay_basic = YTPHY_DTS_INVAL_VAL;
+ priv->tx_delay_ge = YTPHY_DTS_INVAL_VAL;
+ priv->tx_delay_fe = YTPHY_DTS_INVAL_VAL;
+
+ if (!IS_ENABLED(CONFIG_OF_MDIO)) {
+ priv->auto_sleep_disabled = true;
+ priv->keep_pll_enabled = true;
+ return 0;
+ }
+
+ ret = of_property_read_u32(node, "motorcomm,clk-out-frequency", &freq);
+ if (ret < 0)
+ freq = YTPHY_DTS_OUTPUT_CLK_DIS;/* default value as dts*/
+
+ switch (freq) {
+ case YTPHY_DTS_OUTPUT_CLK_DIS:
+ priv->clock_ouput = false;
+ break;
+ case YTPHY_DTS_OUTPUT_CLK_25M:
+ priv->clock_freq_125M = false;
+ priv->clock_ouput = true;
+ break;
+ case YTPHY_DTS_OUTPUT_CLK_125M:
+ priv->clock_freq_125M = true;
+ priv->clock_ouput = true;
+ break;
+ default:
+ phydev_err(phydev, "invalid motorcomm,clk-out-frequency\n");
+ return -EINVAL;
+ }
+
+ if (!of_property_read_u32(node, "motorcomm,rx-delay-basic", &val)) {
+ if (val > 1) {
+ phydev_err(phydev,
+ "invalid motorcomm,rx-delay-basic\n");
+ return -EINVAL;
+ }
+ priv->rx_delay_basic = val;
+ }
+
+ if (!of_property_read_u32(node, "motorcomm,rx-delay-additional-ps", &val)) {
+ if (val > YTPHY_DTS_MAX_DELAY_VAL) {
+ phydev_err(phydev, "invalid motorcomm,rx-delay-additional-ps\n");
+ return -EINVAL;
+ }
+ if (val)
+ val /= YTPHY_DTS_STEP_DELAY_VAL;
+ priv->rx_delay_additional = val;
+ }
+
+ if (!of_property_read_u32(node, "motorcomm,tx-delay-fe-ps", &val)) {
+ if (val > YTPHY_DTS_MAX_DELAY_VAL) {
+ phydev_err(phydev,
+ "invalid motorcomm,tx-delay-fe-ps\n");
+ return -EINVAL;
+ }
+ if (val)
+ val /= YTPHY_DTS_STEP_DELAY_VAL;
+ priv->tx_delay_fe = val;
+ }
+
+ if (!of_property_read_u32(node, "motorcomm,tx-delay-ge-ps", &val)) {
+ if (val > YTPHY_DTS_MAX_DELAY_VAL) {
+ phydev_err(phydev,
+ "invalid motorcomm,tx-delay-ge-ps\n");
+ return -EINVAL;
+ }
+ if (val)
+ val /= YTPHY_DTS_STEP_DELAY_VAL;
+ priv->tx_delay_ge = val;
+ }
+
+ if (of_property_read_bool(node, "motorcomm,keep-pll-enabled"))
+ priv->keep_pll_enabled = true;
+
+ if (of_property_read_bool(node, "motorcomm,auto-sleep-disabled"))
+ priv->auto_sleep_disabled = true;
+
+ if (of_property_read_bool(node, "motorcomm,tx-clk-adj-enabled"))
+ priv->tx_clk_adj_enabled = true;
+ if (priv->tx_clk_adj_enabled) {
+ if (of_property_read_bool(node, "motorcomm,tx-clk-10-inverted"))
+ priv->tx_clk_10_inverted = true;
+ if (of_property_read_bool(node, "motorcomm,tx-clk-100-inverted"))
+ priv->tx_clk_100_inverted = true;
+ if (of_property_read_bool(node, "motorcomm,tx-clk-1000-inverted"))
+ priv->tx_clk_1000_inverted = true;
+ }
+
+ if (!of_property_read_u32(node, "motorcomm,sds-tx-amplitude", &val)) {
+ if (val > YTPHY_DTS_MAX_TX_AMPLITUDE) {
+ phydev_err(phydev,
+ "invalid motorcomm,sds-tx-amplitude\n");
+ return -EINVAL;
+ }
+ priv->sds_tx_amplitude = val;
+ }
+
+ return 0;
+}
+
+static int ytphy_clk_out_config(struct phy_device *phydev)
+{
+ struct yt8521_priv *priv = phydev->priv;
+ u16 set = 0;
+ u16 mask;
+
+ switch (phydev->drv->phy_id) {
+ case PHY_ID_YT8511:
+ /* YT8511 will be supported later */
+ return -EOPNOTSUPP;
+ case PHY_ID_YT8521:
+ mask = YT8521_SCR_SYNCE_ENABLE;
+ if (priv->clock_ouput) {
+ mask |= YT8521_SCR_CLK_SRC_MASK;
+ mask |= YT8521_SCR_CLK_FRE_SEL_MASK;
+ set |= YT8521_SCR_SYNCE_ENABLE;
+ if (priv->clock_freq_125M) {
+ set |= YT8521_SCR_CLK_FRE_SEL_125M;
+ set |= YT8521_SCR_CLK_SRC_PLL_125M;
+ } else {
+ set |= YT8521_SCR_CLK_FRE_SEL_25M;
+ set |= YT8521_SCR_CLK_SRC_REF_25M;
+ }
+ }
+ break;
+ case PHY_ID_YT8531:
+ case PHY_ID_YT8531S:
+ mask = YT8531_SCR_SYNCE_ENABLE;
+ if (priv->clock_ouput) {
+ mask |= YT8531_SCR_CLK_SRC_MASK;
+ mask |= YT8531_SCR_CLK_FRE_SEL_MASK;
+ set |= YT8531_SCR_SYNCE_ENABLE;
+ if (priv->clock_freq_125M) {
+ set |= YT8531_SCR_CLK_FRE_SEL_125M;
+ set |= YT8531_SCR_CLK_SRC_PLL_125M;
+ } else {
+ set |= YT8531_SCR_CLK_FRE_SEL_25M;
+ set |= YT8531_SCR_CLK_SRC_REF_25M;
+ }
+ }
+ break;
+ default:
+ phydev_err(phydev, "invalid phy id\n");
+ return -EINVAL;
+ }
+
+ return ytphy_modify_ext(phydev, YTPHY_SYNCE_CFG_REG, mask, set);
+}
+
+static int ytphy_serdes_tx_amplitude_config(struct phy_device *phydev)
+{
+ u16 yt8531s_tx_amplitude[] = { YT8531S_SAC2R_TX_AMPLITUDE_LOW,
+ YT8531S_SAC2R_TX_AMPLITUDE_MIDDLE,
+ YT8531S_SAC2R_TX_AMPLITUDE_HIGH };
+ u16 yt8521_tx_amplitude[] = { YT8521_SAC2R_TX_AMPLITUDE_LOW,
+ YT8521_SAC2R_TX_AMPLITUDE_MIDDLE,
+ YT8521_SAC2R_TX_AMPLITUDE_HIGH };
+ struct yt8521_priv *priv = phydev->priv;
+ u16 tx_amplitude;
+
+ if (priv->sds_tx_amplitude == YTPHY_DTS_INVAL_VAL)
+ /* don't config Serdes tx amplitude.*/
+ return 0;
+
+ switch (phydev->drv->phy_id) {
+ case PHY_ID_YT8511:
+ case PHY_ID_YT8531:
+ /* YT8511 and YT8531 not support this function.*/
+ return -EOPNOTSUPP;
+ case PHY_ID_YT8521:
+ tx_amplitude = yt8521_tx_amplitude[priv->sds_tx_amplitude];
+ break;
+ case PHY_ID_YT8531S:
+ tx_amplitude = yt8531s_tx_amplitude[priv->sds_tx_amplitude];
+ break;
+ default:
+ phydev_err(phydev, "invalid phy id\n");
+ return -EINVAL;
+ }
+
+ return ytphy_modify_ext(phydev, YTPHY_SERDES_ANALOG_CFG2_REG,
+ YTPHY_SAC2R_TX_AMPLITUDE_MASK, tx_amplitude);
+}
+
+static int ytphy_rgmii_clk_delay_config(struct phy_device *phydev)
+{
+ struct yt8521_priv *priv = phydev->priv;
+ u16 mask = 0;
+ u16 val = 0;
+ int ret;
+
+ /* rx delay basic controlled by dts.*/
+ if (priv->rx_delay_basic != YTPHY_DTS_INVAL_VAL) {
+ if (priv->rx_delay_basic)
+ val = YT8521_CCR_RXC_DLY_EN;
+ ret = ytphy_modify_ext(phydev, YT8521_CHIP_CONFIG_REG,
+ YT8521_CCR_RXC_DLY_EN, val);
+ if (ret < 0)
+ return ret;
+ }
+
+ val = 0;
+ /* If rx_delay_additional and tx_delay_* are all not be seted in dts,
+ * then used the fixed *_DELAY_DIS or *_DELAY_EN. Otherwise, use the
+ * value set by rx_delay_additional, tx_delay_ge and tx_delay_fe.
+ */
+ if ((priv->rx_delay_additional & priv->tx_delay_ge & priv->tx_delay_fe)
+ == YTPHY_DTS_INVAL_VAL) {
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ val |= YT8521_RC1R_GE_TX_DELAY_DIS;
+ val |= YT8521_RC1R_FE_TX_DELAY_DIS;
+ val |= YT8521_RC1R_RX_DELAY_DIS;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ val |= YT8521_RC1R_GE_TX_DELAY_DIS;
+ val |= YT8521_RC1R_FE_TX_DELAY_DIS;
+ val |= YT8521_RC1R_RX_DELAY_EN;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ val |= YT8521_RC1R_GE_TX_DELAY_EN;
+ val |= YT8521_RC1R_FE_TX_DELAY_EN;
+ val |= YT8521_RC1R_RX_DELAY_DIS;
+ break;
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ val |= YT8521_RC1R_GE_TX_DELAY_EN;
+ val |= YT8521_RC1R_FE_TX_DELAY_EN;
+ val |= YT8521_RC1R_RX_DELAY_EN;
+ break;
+ default: /* do not support other modes */
+ return -EOPNOTSUPP;
+ }
+ mask = YT8521_RC1R_RX_DELAY_MASK | YT8521_RC1R_FE_TX_DELAY_MASK
+ | YT8521_RC1R_GE_TX_DELAY_MASK;
+ } else {
+ switch (phydev->interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ if (priv->rx_delay_additional != YTPHY_DTS_INVAL_VAL) {
+ mask |= YT8521_RC1R_RX_DELAY_MASK;
+ val |= (priv->rx_delay_additional) << YT8521_RC1R_RX_DELAY_BIT;
+ }
+ if (priv->tx_delay_fe != YTPHY_DTS_INVAL_VAL) {
+ mask |= YT8521_RC1R_FE_TX_DELAY_MASK;
+ val |= (priv->tx_delay_fe) << YT8521_RC1R_FE_TX_DELAY_BIT;
+ }
+ if (priv->tx_delay_ge != YTPHY_DTS_INVAL_VAL) {
+ mask |= YT8521_RC1R_GE_TX_DELAY_MASK;
+ val |= (priv->tx_delay_ge) << YT8521_RC1R_GE_TX_DELAY_BIT;
+ }
+ break;
+ default: /* do not support other modes */
+ return -EOPNOTSUPP;
+ }
+ }
+
+ return ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG, mask, val);
+}
+
+static int ytphy_clk_delay_config(struct phy_device *phydev)
+{
+ switch (phydev->drv->phy_id) {
+ case PHY_ID_YT8511:
+ /* YT8511 will be supported later */
+ return -EOPNOTSUPP;
+ case PHY_ID_YT8521:
+ case PHY_ID_YT8531S:
+ /* YT8521 and YT8531S support SGMII mode, but don't need
+ * delay.
+ */
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII)
+ return 0;
+
+ return ytphy_rgmii_clk_delay_config(phydev);
+ case PHY_ID_YT8531:
+ /* YT8531 don't support SGMII mode. */
+ return ytphy_rgmii_clk_delay_config(phydev);
+ default:
+ phydev_err(phydev, "invalid phy id\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ytphy_probe_helper(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct yt8521_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ phydev->priv = priv;
+
+ ret = ytphy_parse_dt(phydev);
+ if (ret < 0)
+ return ret;
+
+ phy_lock_mdio_bus(phydev);
+ ret = ytphy_clk_out_config(phydev);
+ phy_unlock_mdio_bus(phydev);
+ return ret;
+}
+
/**
* yt8521_probe() - read chip config then set suitable polling_mode
* @phydev: a pointer to a &struct phy_device
@@ -601,16 +983,15 @@ static int yt8521_write_page(struct phy_
*/
static int yt8521_probe(struct phy_device *phydev)
{
- struct device *dev = &phydev->mdio.dev;
struct yt8521_priv *priv;
int chip_config;
int ret;
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
+ ret = ytphy_probe_helper(phydev);
+ if (ret < 0)
+ return ret;
- phydev->priv = priv;
+ priv = phydev->priv;
chip_config = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG);
if (chip_config < 0)
@@ -652,26 +1033,6 @@ static int yt8521_probe(struct phy_devic
}
/**
- * yt8531s_probe() - read chip config then set suitable polling_mode
- * @phydev: a pointer to a &struct phy_device
- *
- * returns 0 or negative errno code
- */
-static int yt8531s_probe(struct phy_device *phydev)
-{
- int ret;
-
- /* Disable SyncE clock output by default */
- ret = ytphy_modify_ext_with_lock(phydev, YT8531S_SYNCE_CFG_REG,
- YT8531S_SCR_SYNCE_ENABLE, 0);
- if (ret < 0)
- return ret;
-
- /* same as yt8521_probe */
- return yt8521_probe(phydev);
-}
-
-/**
* ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp
* @phydev: a pointer to a &struct phy_device
*
@@ -1125,6 +1486,34 @@ static int yt8521_resume(struct phy_devi
return yt8521_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0);
}
+static int ytphy_config_init_helper(struct phy_device *phydev)
+{
+ struct yt8521_priv *priv = phydev->priv;
+ int ret;
+
+ ret = ytphy_clk_delay_config(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* disable auto sleep */
+ if (priv->auto_sleep_disabled) {
+ ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG,
+ YT8521_ESC1R_SLEEP_SW, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* enable RXC clock when no wire plug */
+ if (priv->keep_pll_enabled) {
+ ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG,
+ YT8521_CGR_RX_CLK_EN, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
/**
* yt8521_config_init() - called to initialize the PHY
* @phydev: a pointer to a &struct phy_device
@@ -1135,59 +1524,21 @@ static int yt8521_config_init(struct phy
{
int old_page;
int ret = 0;
- u16 val;
old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
if (old_page < 0)
goto err_restore_page;
- switch (phydev->interface) {
- case PHY_INTERFACE_MODE_RGMII:
- val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS;
- val |= YT8521_RC1R_RX_DELAY_DIS;
- break;
- case PHY_INTERFACE_MODE_RGMII_RXID:
- val = YT8521_RC1R_GE_TX_DELAY_DIS | YT8521_RC1R_FE_TX_DELAY_DIS;
- val |= YT8521_RC1R_RX_DELAY_EN;
- break;
- case PHY_INTERFACE_MODE_RGMII_TXID:
- val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN;
- val |= YT8521_RC1R_RX_DELAY_DIS;
- break;
- case PHY_INTERFACE_MODE_RGMII_ID:
- val = YT8521_RC1R_GE_TX_DELAY_EN | YT8521_RC1R_FE_TX_DELAY_EN;
- val |= YT8521_RC1R_RX_DELAY_EN;
- break;
- case PHY_INTERFACE_MODE_SGMII:
- break;
- default: /* do not support other modes */
- ret = -EOPNOTSUPP;
- goto err_restore_page;
- }
-
- /* set rgmii delay mode */
- if (phydev->interface != PHY_INTERFACE_MODE_SGMII) {
- ret = ytphy_modify_ext(phydev, YT8521_RGMII_CONFIG1_REG,
- (YT8521_RC1R_RX_DELAY_MASK |
- YT8521_RC1R_FE_TX_DELAY_MASK |
- YT8521_RC1R_GE_TX_DELAY_MASK),
- val);
- if (ret < 0)
- goto err_restore_page;
- }
-
- /* disable auto sleep */
- ret = ytphy_modify_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1_REG,
- YT8521_ESC1R_SLEEP_SW, 0);
+ ret = ytphy_config_init_helper(phydev);
if (ret < 0)
goto err_restore_page;
- /* enable RXC clock when no wire plug */
- ret = ytphy_modify_ext(phydev, YT8521_CLOCK_GATING_REG,
- YT8521_CGR_RX_CLK_EN, 0);
+ ret = yt8521_write_page(phydev, YT8521_RSSR_FIBER_SPACE);
if (ret < 0)
goto err_restore_page;
+ ret = ytphy_serdes_tx_amplitude_config(phydev);
+
err_restore_page:
return phy_restore_page(phydev, old_page, ret);
}
@@ -1778,7 +2129,7 @@ static struct phy_driver motorcomm_phy_d
PHY_ID_MATCH_EXACT(PHY_ID_YT8531S),
.name = "YT8531S Gigabit Ethernet",
.get_features = yt8521_get_features,
- .probe = yt8531s_probe,
+ .probe = yt8521_probe,
.read_page = yt8521_read_page,
.write_page = yt8521_write_page,
.get_wol = ytphy_get_wol,
@@ -1804,7 +2155,7 @@ static const struct mdio_device_id __may
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8511) },
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8521) },
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },
- { /* sentinal */ }
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(mdio, motorcomm_tbl);

View File

@ -1,223 +0,0 @@
From: Frank <Frank.Sae@motor-comm.com>
To: Peter Geis <pgwipeout@gmail.com>, Andrew Lunn <andrew@lunn.ch>,
Heiner Kallweit <hkallweit1@gmail.com>,
Russell King <linux@armlinux.org.uk>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Rob Herring <robh+dt@kernel.org>,
Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>
Cc: xiaogang.fan@motor-comm.com, fei.zhang@motor-comm.com,
hua.sun@motor-comm.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, Frank <Frank.Sae@motor-comm.com>,
devicetree@vger.kernel.org
Subject: [PATCH net-next v1 3/3] net: phy: Add driver for Motorcomm yt8531 gigabit ethernet phy
Date: Thu, 5 Jan 2023 15:30:24 +0800 [thread overview]
Message-ID: <20230105073024.8390-4-Frank.Sae@motor-comm.com> (raw)
In-Reply-To: <20230105073024.8390-1-Frank.Sae@motor-comm.com>
Add driver for Motorcomm yt8531 gigabit ethernet phy. This patch has
been tested on AM335x platform which has one YT8531 interface
card and passed all test cases.
Signed-off-by: Frank <Frank.Sae@motor-comm.com>
---
drivers/net/phy/Kconfig | 2 +-
drivers/net/phy/motorcomm.c | 127 +++++++++++++++++++++++++++++++++++-
2 files changed, 126 insertions(+), 3 deletions(-)
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -319,7 +319,7 @@ config MOTORCOMM_PHY
tristate "Motorcomm PHYs"
help
Enables support for Motorcomm network PHYs.
- Currently supports the YT8511, YT8521, YT8531S Gigabit Ethernet PHYs.
+ Currently supports the YT8511, YT8521, YT8531, YT8531S Gigabit Ethernet PHYs.
config NATIONAL_PHY
tristate "National Semiconductor PHYs"
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Motorcomm 8511/8521/8531S PHY driver.
+ * Motorcomm 8511/8521/8531/8531S PHY driver.
*
* Author: Peter Geis <pgwipeout@gmail.com>
* Author: Frank <Frank.Sae@motor-comm.com>
@@ -14,6 +14,7 @@
#define PHY_ID_YT8511 0x0000010a
#define PHY_ID_YT8521 0x0000011a
+#define PHY_ID_YT8531 0x4f51e91b
#define PHY_ID_YT8531S 0x4f51e91a
/* YT8521/YT8531S Register Overview
@@ -542,6 +543,69 @@ err_restore_page:
return phy_restore_page(phydev, old_page, ret);
}
+static int yt8531_set_wol(struct phy_device *phydev,
+ struct ethtool_wolinfo *wol)
+{
+ struct net_device *p_attached_dev;
+ const u16 mac_addr_reg[] = {
+ YTPHY_WOL_MACADDR2_REG,
+ YTPHY_WOL_MACADDR1_REG,
+ YTPHY_WOL_MACADDR0_REG,
+ };
+ const u8 *mac_addr;
+ u16 mask;
+ u16 val;
+ int ret;
+ u8 i;
+
+ if (wol->wolopts & WAKE_MAGIC) {
+ p_attached_dev = phydev->attached_dev;
+ if (!p_attached_dev)
+ return -ENODEV;
+
+ mac_addr = (const u8 *)p_attached_dev->dev_addr;
+ if (!is_valid_ether_addr(mac_addr))
+ return -EINVAL;
+
+ /* Store the device address for the magic packet */
+ for (i = 0; i < 3; i++) {
+ ret = ytphy_write_ext_with_lock(phydev, mac_addr_reg[i],
+ ((mac_addr[i * 2] << 8)) |
+ (mac_addr[i * 2 + 1]));
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Enable WOL feature */
+ mask = YTPHY_WCR_PULSE_WIDTH_MASK | YTPHY_WCR_INTR_SEL;
+ val = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;
+ val |= YTPHY_WCR_TYPE_PULSE | YTPHY_WCR_PULSE_WIDTH_672MS;
+ ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG,
+ mask, val);
+ if (ret < 0)
+ return ret;
+
+ /* Enable WOL interrupt */
+ ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG, 0,
+ YTPHY_IER_WOL);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* Disable WOL feature */
+ mask = YTPHY_WCR_ENABLE | YTPHY_WCR_INTR_SEL;
+ ret = ytphy_modify_ext_with_lock(phydev, YTPHY_WOL_CONFIG_REG,
+ mask, 0);
+
+ /* Disable WOL interrupt */
+ ret = phy_modify(phydev, YTPHY_INTERRUPT_ENABLE_REG,
+ YTPHY_IER_WOL, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int yt8511_read_page(struct phy_device *phydev)
{
return __phy_read(phydev, YT8511_PAGE_SELECT);
@@ -1032,6 +1096,11 @@ static int yt8521_probe(struct phy_devic
return 0;
}
+static int yt8531_probe(struct phy_device *phydev)
+{
+ return ytphy_probe_helper(phydev);
+}
+
/**
* ytphy_utp_read_lpa() - read LPA then setup lp_advertising for utp
* @phydev: a pointer to a &struct phy_device
@@ -1543,6 +1612,48 @@ err_restore_page:
return phy_restore_page(phydev, old_page, ret);
}
+static int yt8531_config_init(struct phy_device *phydev)
+{
+ int ret;
+
+ phy_lock_mdio_bus(phydev);
+ ret = ytphy_config_init_helper(phydev);
+ phy_unlock_mdio_bus(phydev);
+
+ return ret;
+}
+
+static void yt8531_link_change_notify(struct phy_device *phydev)
+{
+ struct yt8521_priv *priv = phydev->priv;
+ u16 val = 0;
+
+ if (!(priv->tx_clk_adj_enabled))
+ return;
+
+ if (phydev->speed < 0)
+ return;
+
+ switch (phydev->speed) {
+ case SPEED_1000:
+ if (priv->tx_clk_1000_inverted)
+ val = YT8521_RC1R_TX_CLK_SEL_INVERTED;
+ break;
+ case SPEED_100:
+ if (priv->tx_clk_100_inverted)
+ val = YT8521_RC1R_TX_CLK_SEL_INVERTED;
+ break;
+ case SPEED_10:
+ if (priv->tx_clk_10_inverted)
+ val = YT8521_RC1R_TX_CLK_SEL_INVERTED;
+ break;
+ default:
+ return;
+ }
+ ytphy_modify_ext_with_lock(phydev, YT8521_RGMII_CONFIG1_REG,
+ YT8521_RC1R_TX_CLK_SEL_MASK, val);
+}
+
/**
* yt8521_prepare_fiber_features() - A small helper function that setup
* fiber's features.
@@ -2126,6 +2237,17 @@ static struct phy_driver motorcomm_phy_d
.resume = yt8521_resume,
},
{
+ PHY_ID_MATCH_EXACT(PHY_ID_YT8531),
+ .name = "YT8531 Gigabit Ethernet",
+ .probe = yt8531_probe,
+ .config_init = yt8531_config_init,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .get_wol = ytphy_get_wol,
+ .set_wol = yt8531_set_wol,
+ .link_change_notify = yt8531_link_change_notify,
+ },
+ {
PHY_ID_MATCH_EXACT(PHY_ID_YT8531S),
.name = "YT8531S Gigabit Ethernet",
.get_features = yt8521_get_features,
@@ -2146,7 +2268,7 @@ static struct phy_driver motorcomm_phy_d
module_phy_driver(motorcomm_phy_drvs);
-MODULE_DESCRIPTION("Motorcomm 8511/8521/8531S PHY driver");
+MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S PHY driver");
MODULE_AUTHOR("Peter Geis");
MODULE_AUTHOR("Frank");
MODULE_LICENSE("GPL");
@@ -2154,6 +2276,7 @@ MODULE_LICENSE("GPL");
static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8511) },
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8521) },
+ { PHY_ID_MATCH_EXACT(PHY_ID_YT8531) },
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },
{ /* sentinel */ }
};

View File

@ -90,19 +90,3 @@ Change-Id: I6624b6af2ede3c2fca61c0f753a08a33ce69a6d2
}
static const struct rockchip_p3phy_ops rk3568_ops = {
@@ -132,13 +157,14 @@ static int rockchip_p3phy_rk3588_init(st
{
u32 reg = 0;
u8 mode = 0;
+ int i;
int ret;
/* Deassert PCIe PMA output clamp mode */
regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, BIT(8) | BIT(24));
/* Set bifurcation if needed */
- for (int i = 0; i < priv->num_lanes; i++) {
+ for (i = 0; i < priv->num_lanes; i++) {
if (!priv->lanes[i])
mode |= (BIT(i) << 3);