Skip to content

Commit 7f9d82a

Browse files
committed
Merge branch 'fix-missing-phy-to-mac-rx-clock'
Romain Gantois says: ==================== Fix missing PHY-to-MAC RX clock There is an issue with some stmmac/PHY combinations that has been reported some time ago in a couple of different series: Clark Wang's report: https://lore.kernel.org/all/[email protected]/ Clément Léger's report: https://lore.kernel.org/linux-arm-kernel/[email protected]/ Stmmac controllers require an RX clock signal from the MII bus to perform their hardware initialization successfully. This causes issues with some PHY/PCS devices. If these devices do not bring the clock signal up before the MAC driver initializes its hardware, then said initialization will fail. This can happen at probe time or when the system wakes up from a suspended state. This series introduces new flags for phy_device and phylink_pcs. These flags allow MAC drivers to signal to PHY/PCS drivers that the RX clock signal should be enabled as soon as possible, and that it should always stay enabled. I have included specific uses of these flags that fix the RZN1 GMAC1 stmmac driver that I am currently working on and that is not yet upstream. I have also included changes to the at803x PHY driver that should fix the issue that Clark Wang was having. ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents af352c3 + 0f671b3 commit 7f9d82a

File tree

8 files changed

+111
-13
lines changed

8 files changed

+111
-13
lines changed

drivers/net/ethernet/stmicro/stmmac/common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ struct mac_device_info {
593593
const struct stmmac_mmc_ops *mmc;
594594
const struct stmmac_est_ops *est;
595595
struct dw_xpcs *xpcs;
596-
struct phylink_pcs *lynx_pcs; /* Lynx external PCS */
596+
struct phylink_pcs *phylink_pcs;
597597
struct mii_regs mii; /* MII register Addresses */
598598
struct mac_link link;
599599
void __iomem *pcsr; /* vpointer to device CSRs */

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -479,9 +479,9 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
479479
goto err_dvr_remove;
480480
}
481481

482-
stpriv->hw->lynx_pcs = lynx_pcs_create_mdiodev(pcs_bus, 0);
483-
if (IS_ERR(stpriv->hw->lynx_pcs)) {
484-
ret = PTR_ERR(stpriv->hw->lynx_pcs);
482+
stpriv->hw->phylink_pcs = lynx_pcs_create_mdiodev(pcs_bus, 0);
483+
if (IS_ERR(stpriv->hw->phylink_pcs)) {
484+
ret = PTR_ERR(stpriv->hw->phylink_pcs);
485485
goto err_dvr_remove;
486486
}
487487
}
@@ -498,7 +498,7 @@ static void socfpga_dwmac_remove(struct platform_device *pdev)
498498
{
499499
struct net_device *ndev = platform_get_drvdata(pdev);
500500
struct stmmac_priv *priv = netdev_priv(ndev);
501-
struct phylink_pcs *pcs = priv->hw->lynx_pcs;
501+
struct phylink_pcs *pcs = priv->hw->phylink_pcs;
502502

503503
stmmac_pltfr_remove(pdev);
504504

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -944,10 +944,7 @@ static struct phylink_pcs *stmmac_mac_select_pcs(struct phylink_config *config,
944944
if (priv->hw->xpcs)
945945
return &priv->hw->xpcs->pcs;
946946

947-
if (priv->hw->lynx_pcs)
948-
return priv->hw->lynx_pcs;
949-
950-
return NULL;
947+
return priv->hw->phylink_pcs;
951948
}
952949

953950
static void stmmac_mac_config(struct phylink_config *config, unsigned int mode,
@@ -1221,6 +1218,9 @@ static int stmmac_phy_setup(struct stmmac_priv *priv)
12211218
priv->phylink_config.type = PHYLINK_NETDEV;
12221219
priv->phylink_config.mac_managed_pm = true;
12231220

1221+
/* Stmmac always requires an RX clock for hardware initialization */
1222+
priv->phylink_config.mac_requires_rxc = true;
1223+
12241224
mdio_bus_data = priv->plat->mdio_bus_data;
12251225
if (mdio_bus_data)
12261226
priv->phylink_config.ovr_an_inband =
@@ -3411,6 +3411,10 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)
34113411
u32 chan;
34123412
int ret;
34133413

3414+
/* Make sure RX clock is enabled */
3415+
if (priv->hw->phylink_pcs)
3416+
phylink_pcs_pre_init(priv->phylink, priv->hw->phylink_pcs);
3417+
34143418
/* DMA initialization and SW reset */
34153419
ret = stmmac_init_dma_engine(priv);
34163420
if (ret < 0) {
@@ -3960,8 +3964,7 @@ static int __stmmac_open(struct net_device *dev,
39603964
if (priv->hw->pcs != STMMAC_PCS_TBI &&
39613965
priv->hw->pcs != STMMAC_PCS_RTBI &&
39623966
(!priv->hw->xpcs ||
3963-
xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73) &&
3964-
!priv->hw->lynx_pcs) {
3967+
xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73)) {
39653968
ret = stmmac_init_phy(dev);
39663969
if (ret) {
39673970
netdev_err(priv->dev,

drivers/net/pcs/pcs-rzn1-miic.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,10 +279,38 @@ static int miic_validate(struct phylink_pcs *pcs, unsigned long *supported,
279279
return -EINVAL;
280280
}
281281

282+
static int miic_pre_init(struct phylink_pcs *pcs)
283+
{
284+
struct miic_port *miic_port = phylink_pcs_to_miic_port(pcs);
285+
struct miic *miic = miic_port->miic;
286+
u32 val, mask;
287+
288+
/* Start RX clock if required */
289+
if (pcs->rxc_always_on) {
290+
/* In MII through mode, the clock signals will be driven by the
291+
* external PHY, which might not be initialized yet. Set RMII
292+
* as default mode to ensure that a reference clock signal is
293+
* generated.
294+
*/
295+
miic_port->interface = PHY_INTERFACE_MODE_RMII;
296+
297+
val = FIELD_PREP(MIIC_CONVCTRL_CONV_MODE, CONV_MODE_RMII) |
298+
FIELD_PREP(MIIC_CONVCTRL_CONV_SPEED, CONV_MODE_100MBPS);
299+
mask = MIIC_CONVCTRL_CONV_MODE | MIIC_CONVCTRL_CONV_SPEED;
300+
301+
miic_reg_rmw(miic, MIIC_CONVCTRL(miic_port->port), mask, val);
302+
303+
miic_converter_enable(miic, miic_port->port, 1);
304+
}
305+
306+
return 0;
307+
}
308+
282309
static const struct phylink_pcs_ops miic_phylink_ops = {
283310
.pcs_validate = miic_validate,
284311
.pcs_config = miic_config,
285312
.pcs_link_up = miic_link_up,
313+
.pcs_pre_init = miic_pre_init,
286314
};
287315

288316
struct phylink_pcs *miic_create(struct device *dev, struct device_node *np)

drivers/net/phy/phylink.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,21 @@ static void phylink_pcs_poll_start(struct phylink *pl)
10421042
mod_timer(&pl->link_poll, jiffies + HZ);
10431043
}
10441044

1045+
int phylink_pcs_pre_init(struct phylink *pl, struct phylink_pcs *pcs)
1046+
{
1047+
int ret = 0;
1048+
1049+
/* Signal to PCS driver that MAC requires RX clock for init */
1050+
if (pl->config->mac_requires_rxc)
1051+
pcs->rxc_always_on = true;
1052+
1053+
if (pcs->ops->pcs_pre_init)
1054+
ret = pcs->ops->pcs_pre_init(pcs);
1055+
1056+
return ret;
1057+
}
1058+
EXPORT_SYMBOL_GPL(phylink_pcs_pre_init);
1059+
10451060
static void phylink_mac_config(struct phylink *pl,
10461061
const struct phylink_link_state *state)
10471062
{
@@ -1923,6 +1938,8 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
19231938
static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy,
19241939
phy_interface_t interface)
19251940
{
1941+
u32 flags = 0;
1942+
19261943
if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED ||
19271944
(pl->cfg_link_an_mode == MLO_AN_INBAND &&
19281945
phy_interface_mode_is_8023z(interface) && !pl->sfp_bus)))
@@ -1931,7 +1948,10 @@ static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy,
19311948
if (pl->phydev)
19321949
return -EBUSY;
19331950

1934-
return phy_attach_direct(pl->netdev, phy, 0, interface);
1951+
if (pl->config->mac_requires_rxc)
1952+
flags |= PHY_F_RXC_ALWAYS_ON;
1953+
1954+
return phy_attach_direct(pl->netdev, phy, flags, interface);
19351955
}
19361956

19371957
/**
@@ -2034,6 +2054,9 @@ int phylink_fwnode_phy_connect(struct phylink *pl,
20342054
pl->link_config.interface = pl->link_interface;
20352055
}
20362056

2057+
if (pl->config->mac_requires_rxc)
2058+
flags |= PHY_F_RXC_ALWAYS_ON;
2059+
20372060
ret = phy_attach_direct(pl->netdev, phy_dev, flags,
20382061
pl->link_interface);
20392062
phy_device_free(phy_dev);

drivers/net/phy/qcom/at803x.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,8 @@ static int at803x_hibernation_mode_config(struct phy_device *phydev)
426426
/* The default after hardware reset is hibernation mode enabled. After
427427
* software reset, the value is retained.
428428
*/
429-
if (!(priv->flags & AT803X_DISABLE_HIBERNATION_MODE))
429+
if (!(priv->flags & AT803X_DISABLE_HIBERNATION_MODE) &&
430+
!(phydev->dev_flags & PHY_F_RXC_ALWAYS_ON))
430431
return 0;
431432

432433
return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,

include/linux/phy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,7 @@ struct phy_device {
778778

779779
/* Generic phy_device::dev_flags */
780780
#define PHY_F_NO_IRQ 0x80000000
781+
#define PHY_F_RXC_ALWAYS_ON 0x40000000
781782

782783
static inline struct phy_device *to_phy_device(const struct device *dev)
783784
{

include/linux/phylink.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ enum phylink_op_type {
138138
* @poll_fixed_state: if true, starts link_poll,
139139
* if MAC link is at %MLO_AN_FIXED mode.
140140
* @mac_managed_pm: if true, indicate the MAC driver is responsible for PHY PM.
141+
* @mac_requires_rxc: if true, the MAC always requires a receive clock from PHY.
142+
* The PHY driver should start the clock signal as soon as
143+
* possible and avoid stopping it during suspend events.
141144
* @ovr_an_inband: if true, override PCS to MLO_AN_INBAND
142145
* @get_fixed_state: callback to execute to determine the fixed link state,
143146
* if MAC link is at %MLO_AN_FIXED mode.
@@ -150,6 +153,7 @@ struct phylink_config {
150153
enum phylink_op_type type;
151154
bool poll_fixed_state;
152155
bool mac_managed_pm;
156+
bool mac_requires_rxc;
153157
bool ovr_an_inband;
154158
void (*get_fixed_state)(struct phylink_config *config,
155159
struct phylink_link_state *state);
@@ -392,6 +396,10 @@ struct phylink_pcs_ops;
392396
* @phylink: pointer to &struct phylink_config
393397
* @neg_mode: provide PCS neg mode via "mode" argument
394398
* @poll: poll the PCS for link changes
399+
* @rxc_always_on: The MAC driver requires the reference clock
400+
* to always be on. Standalone PCS drivers which
401+
* do not have access to a PHY device can check
402+
* this instead of PHY_F_RXC_ALWAYS_ON.
395403
*
396404
* This structure is designed to be embedded within the PCS private data,
397405
* and will be passed between phylink and the PCS.
@@ -404,6 +412,7 @@ struct phylink_pcs {
404412
struct phylink *phylink;
405413
bool neg_mode;
406414
bool poll;
415+
bool rxc_always_on;
407416
};
408417

409418
/**
@@ -418,6 +427,8 @@ struct phylink_pcs {
418427
* @pcs_an_restart: restart 802.3z BaseX autonegotiation.
419428
* @pcs_link_up: program the PCS for the resolved link configuration
420429
* (where necessary).
430+
* @pcs_pre_init: configure PCS components necessary for MAC hardware
431+
* initialization e.g. RX clock for stmmac.
421432
*/
422433
struct phylink_pcs_ops {
423434
int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
@@ -437,6 +448,7 @@ struct phylink_pcs_ops {
437448
void (*pcs_an_restart)(struct phylink_pcs *pcs);
438449
void (*pcs_link_up)(struct phylink_pcs *pcs, unsigned int neg_mode,
439450
phy_interface_t interface, int speed, int duplex);
451+
int (*pcs_pre_init)(struct phylink_pcs *pcs);
440452
};
441453

442454
#if 0 /* For kernel-doc purposes only. */
@@ -542,6 +554,34 @@ void pcs_an_restart(struct phylink_pcs *pcs);
542554
*/
543555
void pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
544556
phy_interface_t interface, int speed, int duplex);
557+
558+
/**
559+
* pcs_pre_init() - Configure PCS components necessary for MAC initialization
560+
* @pcs: a pointer to a &struct phylink_pcs.
561+
*
562+
* This function can be called by MAC drivers through the
563+
* phylink_pcs_pre_init() wrapper, before their hardware is initialized. It
564+
* should not be called after the link is brought up, as reconfiguring the PCS
565+
* at this point could break the link.
566+
*
567+
* Some MAC devices require specific hardware initialization to be performed by
568+
* their associated PCS device before they can properly initialize their own
569+
* hardware. An example of this is the initialization of stmmac controllers,
570+
* which requires an active REF_CLK signal to be provided by the PHY/PCS.
571+
*
572+
* By calling phylink_pcs_pre_init(), MAC drivers can ensure that the PCS is
573+
* setup in a way that allows for successful hardware initialization.
574+
*
575+
* The specific configuration performed by pcs_pre_init() is dependent on the
576+
* model of PCS and the requirements of the MAC device attached to it. PCS
577+
* driver authors should consider whether their target device is to be used in
578+
* conjunction with a MAC device whose driver calls phylink_pcs_pre_init(). MAC
579+
* driver authors should document their requirements for the PCS
580+
* pre-initialization.
581+
*
582+
*/
583+
int pcs_pre_init(struct phylink_pcs *pcs);
584+
545585
#endif
546586

547587
struct phylink *phylink_create(struct phylink_config *,
@@ -561,6 +601,8 @@ void phylink_disconnect_phy(struct phylink *);
561601
void phylink_mac_change(struct phylink *, bool up);
562602
void phylink_pcs_change(struct phylink_pcs *, bool up);
563603

604+
int phylink_pcs_pre_init(struct phylink *pl, struct phylink_pcs *pcs);
605+
564606
void phylink_start(struct phylink *);
565607
void phylink_stop(struct phylink *);
566608

0 commit comments

Comments
 (0)