Skip to content

Commit de94fc1

Browse files
xdarklightkuba-moo
authored andcommitted
net: stmmac: dwmac-meson8b: add support for the RGMII RX delay on G12A
Amlogic Meson G12A (and newer: G12B, SM1) SoCs have a more advanced RX delay logic. Instead of fine-tuning the delay in the nanoseconds range it now allows tuning in 200 picosecond steps. This support comes with new bits in the PRG_ETH1[19:16] register. Add support for validating the RGMII RX delay as well as configuring the register accordingly on these platforms. Reviewed-by: Andrew Lunn <andrew@lunn.ch> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 7985244 commit de94fc1

File tree

1 file changed

+48
-13
lines changed

1 file changed

+48
-13
lines changed

drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,21 @@
6868
*/
6969
#define PRG_ETH0_ADJ_SKEW GENMASK(24, 20)
7070

71+
#define PRG_ETH1 0x4
72+
73+
/* Defined for adding a delay to the input RX_CLK for better timing.
74+
* Each step is 200ps. These bits are used with external RGMII PHYs
75+
* because RGMII RX only has the small window. cfg_rxclk_dly can
76+
* adjust the window between RX_CLK and RX_DATA and improve the stability
77+
* of "rx data valid".
78+
*/
79+
#define PRG_ETH1_CFG_RXCLK_DLY GENMASK(19, 16)
80+
7181
struct meson8b_dwmac;
7282

7383
struct meson8b_dwmac_data {
7484
int (*set_phy_mode)(struct meson8b_dwmac *dwmac);
85+
bool has_prg_eth1_rgmii_rx_delay;
7586
};
7687

7788
struct meson8b_dwmac {
@@ -270,30 +281,35 @@ static int meson8b_devm_clk_prepare_enable(struct meson8b_dwmac *dwmac,
270281

271282
static int meson8b_init_rgmii_delays(struct meson8b_dwmac *dwmac)
272283
{
273-
u32 tx_dly_config, rx_dly_config, delay_config;
284+
u32 tx_dly_config, rx_adj_config, cfg_rxclk_dly, delay_config;
274285
int ret;
275286

287+
rx_adj_config = 0;
288+
cfg_rxclk_dly = 0;
276289
tx_dly_config = FIELD_PREP(PRG_ETH0_TXDLY_MASK,
277290
dwmac->tx_delay_ns >> 1);
278291

279-
if (dwmac->rx_delay_ps == 2000)
280-
rx_dly_config = PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP;
281-
else
282-
rx_dly_config = 0;
292+
if (dwmac->data->has_prg_eth1_rgmii_rx_delay)
293+
cfg_rxclk_dly = FIELD_PREP(PRG_ETH1_CFG_RXCLK_DLY,
294+
dwmac->rx_delay_ps / 200);
295+
else if (dwmac->rx_delay_ps == 2000)
296+
rx_adj_config = PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP;
283297

284298
switch (dwmac->phy_mode) {
285299
case PHY_INTERFACE_MODE_RGMII:
286-
delay_config = tx_dly_config | rx_dly_config;
300+
delay_config = tx_dly_config | rx_adj_config;
287301
break;
288302
case PHY_INTERFACE_MODE_RGMII_RXID:
289303
delay_config = tx_dly_config;
304+
cfg_rxclk_dly = 0;
290305
break;
291306
case PHY_INTERFACE_MODE_RGMII_TXID:
292-
delay_config = rx_dly_config;
307+
delay_config = rx_adj_config;
293308
break;
294309
case PHY_INTERFACE_MODE_RGMII_ID:
295310
case PHY_INTERFACE_MODE_RMII:
296311
delay_config = 0;
312+
cfg_rxclk_dly = 0;
297313
break;
298314
default:
299315
dev_err(dwmac->dev, "unsupported phy-mode %s\n",
@@ -323,6 +339,9 @@ static int meson8b_init_rgmii_delays(struct meson8b_dwmac *dwmac)
323339
PRG_ETH0_ADJ_DELAY | PRG_ETH0_ADJ_SKEW,
324340
delay_config);
325341

342+
meson8b_dwmac_mask_bits(dwmac, PRG_ETH1, PRG_ETH1_CFG_RXCLK_DLY,
343+
cfg_rxclk_dly);
344+
326345
return 0;
327346
}
328347

@@ -423,11 +442,20 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
423442
dwmac->rx_delay_ps *= 1000;
424443
}
425444

426-
if (dwmac->rx_delay_ps != 0 && dwmac->rx_delay_ps != 2000) {
427-
dev_err(&pdev->dev,
428-
"The only allowed RX delays values are: 0ps, 2000ps");
429-
ret = -EINVAL;
430-
goto err_remove_config_dt;
445+
if (dwmac->data->has_prg_eth1_rgmii_rx_delay) {
446+
if (dwmac->rx_delay_ps != 0 && dwmac->rx_delay_ps != 2000) {
447+
dev_err(dwmac->dev,
448+
"The only allowed RGMII RX delays values are: 0ps, 2000ps");
449+
ret = -EINVAL;
450+
goto err_remove_config_dt;
451+
}
452+
} else {
453+
if (dwmac->rx_delay_ps > 3000 || dwmac->rx_delay_ps % 200) {
454+
dev_err(dwmac->dev,
455+
"The RGMII RX delay range is 0..3000ps in 200ps steps");
456+
ret = -EINVAL;
457+
goto err_remove_config_dt;
458+
}
431459
}
432460

433461
dwmac->timing_adj_clk = devm_clk_get_optional(dwmac->dev,
@@ -469,10 +497,17 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
469497

470498
static const struct meson8b_dwmac_data meson8b_dwmac_data = {
471499
.set_phy_mode = meson8b_set_phy_mode,
500+
.has_prg_eth1_rgmii_rx_delay = false,
472501
};
473502

474503
static const struct meson8b_dwmac_data meson_axg_dwmac_data = {
475504
.set_phy_mode = meson_axg_set_phy_mode,
505+
.has_prg_eth1_rgmii_rx_delay = false,
506+
};
507+
508+
static const struct meson8b_dwmac_data meson_g12a_dwmac_data = {
509+
.set_phy_mode = meson_axg_set_phy_mode,
510+
.has_prg_eth1_rgmii_rx_delay = true,
476511
};
477512

478513
static const struct of_device_id meson8b_dwmac_match[] = {
@@ -494,7 +529,7 @@ static const struct of_device_id meson8b_dwmac_match[] = {
494529
},
495530
{
496531
.compatible = "amlogic,meson-g12a-dwmac",
497-
.data = &meson_axg_dwmac_data,
532+
.data = &meson_g12a_dwmac_data,
498533
},
499534
{ }
500535
};

0 commit comments

Comments
 (0)