Merge branch 'net-lan969x-add-rgmii-support'

Daniel Machon says:

====================
net: lan969x: add RGMII support

== Description:

This series is the fourth of a multi-part series, that prepares and adds
support for the new lan969x switch driver.

The upstreaming efforts is split into multiple series (might change a
bit as we go along):

        1) Prepare the Sparx5 driver for lan969x (merged)

        2) Add support for lan969x (same basic features as Sparx5
           provides excl. FDMA and VCAP, merged).

        3) Add lan969x VCAP functionality (merged).

    --> 4) Add RGMII support.

        5) Add FDMA support.

== RGMII support:

The lan969x switch device includes two RGMII port interfaces (port 28
and 29) supporting data speeds of 1 Gbps, 100 Mbps and 10 Mbps.

== Patch breakdown:

Patch #1 does some preparation work.

Patch #2 adds new function: is_port_rgmii() to the match data ops.

Patch #3 uses the is_port_rgmii() in a number of places.

Patch #4 makes sure that we do not configure an RGMII device as a
         low-speed device, when doing a port config.

Patch #5 makes sure we only return the PCS if the port mode requires
         it.

Patch #6 adds checks for RGMII PHY modes in sparx5_verify_speeds().

Patch #7 adds registers required to configure RGMII.

Patch #8 adds RGMII implementation.

Patch #9 documents RGMII delays in the dt-bindings.

Details are in the commit description of the individual patches

v4: https://lore.kernel.org/20241213-sparx5-lan969x-switch-driver-4-v4-0-d1a72c9c4714@microchip.com
v3: https://lore.kernel.org/20241118-sparx5-lan969x-switch-driver-4-v3-0-3cefee5e7e3a@microchip.com
v2: https://lore.kernel.org/20241113-sparx5-lan969x-switch-driver-4-v2-0-0db98ac096d1@microchip.com
v1: https://lore.kernel.org/20241106-sparx5-lan969x-switch-driver-4-v1-0-f7f7316436bd@microchip.com
====================

Link: https://patch.msgid.link/20241220-sparx5-lan969x-switch-driver-4-v5-0-fa8ba5dff732@microchip.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2024-12-23 10:58:07 -08:00
11 changed files with 484 additions and 29 deletions

View File

@@ -129,6 +129,24 @@ properties:
minimum: 0
maximum: 383
rx-internal-delay-ps:
description:
RGMII Receive Clock Delay defined in pico seconds, used to select
the DLL phase shift between 1000 ps (45 degree shift at 1Gbps) and
3300 ps (147 degree shift at 1Gbps). A value of 0 ps will disable
any delay. The Default is no delay.
enum: [0, 1000, 1700, 2000, 2500, 3000, 3300]
default: 0
tx-internal-delay-ps:
description:
RGMII Transmit Clock Delay defined in pico seconds, used to select
the DLL phase shift between 1000 ps (45 degree shift at 1Gbps) and
3300 ps (147 degree shift at 1Gbps). A value of 0 ps will disable
any delay. The Default is no delay.
enum: [0, 1000, 1700, 2000, 2500, 3000, 3300]
default: 0
required:
- reg
- phys

View File

@@ -20,7 +20,8 @@ sparx5-switch-$(CONFIG_LAN969X_SWITCH) += lan969x/lan969x_regs.o \
lan969x/lan969x.o \
lan969x/lan969x_calendar.o \
lan969x/lan969x_vcap_ag_api.o \
lan969x/lan969x_vcap_impl.o
lan969x/lan969x_vcap_impl.o \
lan969x/lan969x_rgmii.o
# Provide include files
ccflags-y += -I$(srctree)/drivers/net/ethernet/microchip/vcap

View File

@@ -90,9 +90,12 @@ static const struct sparx5_main_io_resource lan969x_main_iomap[] = {
{ TARGET_DEV2G5 + 27, 0x30d8000, 1 }, /* 0xe30d8000 */
{ TARGET_DEV10G + 9, 0x30dc000, 1 }, /* 0xe30dc000 */
{ TARGET_PCS10G_BR + 9, 0x30e0000, 1 }, /* 0xe30e0000 */
{ TARGET_DEVRGMII, 0x30e4000, 1 }, /* 0xe30e4000 */
{ TARGET_DEVRGMII + 1, 0x30e8000, 1 }, /* 0xe30e8000 */
{ TARGET_DSM, 0x30ec000, 1 }, /* 0xe30ec000 */
{ TARGET_PORT_CONF, 0x30f0000, 1 }, /* 0xe30f0000 */
{ TARGET_ASM, 0x3200000, 1 }, /* 0xe3200000 */
{ TARGET_HSIO_WRAP, 0x3408000, 1 }, /* 0xe3408000 */
};
static struct sparx5_sdlb_group lan969x_sdlb_groups[LAN969X_SDLB_GRP_CNT] = {
@@ -329,6 +332,7 @@ static const struct sparx5_ops lan969x_ops = {
.is_port_5g = &lan969x_port_is_5g,
.is_port_10g = &lan969x_port_is_10g,
.is_port_25g = &lan969x_port_is_25g,
.is_port_rgmii = &lan969x_port_is_rgmii,
.get_port_dev_index = &lan969x_port_dev_mapping,
.get_port_dev_bit = &lan969x_get_dev_mode_bit,
.get_hsch_max_group_rate = &lan969x_get_hsch_max_group_rate,
@@ -336,6 +340,7 @@ static const struct sparx5_ops lan969x_ops = {
.set_port_mux = &lan969x_port_mux_set,
.ptp_irq_handler = &lan969x_ptp_irq_handler,
.dsm_calendar_calc = &lan969x_dsm_calendar_calc,
.port_config_rgmii = &lan969x_port_config_rgmii,
};
const struct sparx5_match_data lan969x_desc = {

View File

@@ -59,7 +59,17 @@ static inline bool lan969x_port_is_25g(int portno)
return false;
}
static inline bool lan969x_port_is_rgmii(int portno)
{
return portno == 28 || portno == 29;
}
/* lan969x_calendar.c */
int lan969x_dsm_calendar_calc(struct sparx5 *sparx5, u32 taxi,
struct sparx5_calendar_data *data);
/* lan969x_rgmii.c */
int lan969x_port_config_rgmii(struct sparx5_port *port,
struct sparx5_port_config *conf);
#endif

View File

@@ -0,0 +1,224 @@
// SPDX-License-Identifier: GPL-2.0+
/* Microchip lan969x Switch driver
*
* Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.
*/
#include "lan969x.h"
/* Tx clock selectors */
#define LAN969X_RGMII_TX_CLK_SEL_125MHZ 1 /* 1000Mbps */
#define LAN969X_RGMII_TX_CLK_SEL_25MHZ 2 /* 100Mbps */
#define LAN969X_RGMII_TX_CLK_SEL_2M5MHZ 3 /* 10Mbps */
/* Port speed selectors */
#define LAN969X_RGMII_SPEED_SEL_10 0 /* Select 10Mbps speed */
#define LAN969X_RGMII_SPEED_SEL_100 1 /* Select 100Mbps speed */
#define LAN969X_RGMII_SPEED_SEL_1000 2 /* Select 1000Mbps speed */
/* Clock delay selectors */
#define LAN969X_RGMII_CLK_DELAY_SEL_1_0_NS 2 /* Phase shift 45deg */
#define LAN969X_RGMII_CLK_DELAY_SEL_1_7_NS 3 /* Phase shift 77deg */
#define LAN969X_RGMII_CLK_DELAY_SEL_2_0_NS 4 /* Phase shift 90deg */
#define LAN969X_RGMII_CLK_DELAY_SEL_2_5_NS 5 /* Phase shift 112deg */
#define LAN969X_RGMII_CLK_DELAY_SEL_3_0_NS 6 /* Phase shift 135deg */
#define LAN969X_RGMII_CLK_DELAY_SEL_3_3_NS 7 /* Phase shift 147deg */
#define LAN969X_RGMII_PORT_START_IDX 28 /* Index of the first RGMII port */
#define LAN969X_RGMII_IFG_TX 4 /* TX Inter Frame Gap value */
#define LAN969X_RGMII_IFG_RX1 5 /* RX1 Inter Frame Gap value */
#define LAN969X_RGMII_IFG_RX2 1 /* RX2 Inter Frame Gap value */
#define RGMII_PORT_IDX(port) ((port)->portno - LAN969X_RGMII_PORT_START_IDX)
/* Get the tx clock selector based on the port speed. */
static int lan969x_rgmii_get_clk_sel(int speed)
{
return (speed == SPEED_10 ? LAN969X_RGMII_TX_CLK_SEL_2M5MHZ :
speed == SPEED_100 ? LAN969X_RGMII_TX_CLK_SEL_25MHZ :
LAN969X_RGMII_TX_CLK_SEL_125MHZ);
}
/* Get the port speed selector based on the port speed. */
static int lan969x_rgmii_get_speed_sel(int speed)
{
return (speed == SPEED_10 ? LAN969X_RGMII_SPEED_SEL_10 :
speed == SPEED_100 ? LAN969X_RGMII_SPEED_SEL_100 :
LAN969X_RGMII_SPEED_SEL_1000);
}
/* Get the clock delay selector based on the clock delay in picoseconds. */
static int lan969x_rgmii_get_clk_delay_sel(struct sparx5_port *port,
u32 delay_ps, u32 *clk_delay_sel)
{
switch (delay_ps) {
case 0:
/* Hardware default selector. */
*clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_2_5_NS;
break;
case 1000:
*clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_1_0_NS;
break;
case 1700:
*clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_1_7_NS;
break;
case 2000:
*clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_2_0_NS;
break;
case 2500:
*clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_2_5_NS;
break;
case 3000:
*clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_3_0_NS;
break;
case 3300:
*clk_delay_sel = LAN969X_RGMII_CLK_DELAY_SEL_3_3_NS;
break;
default:
dev_err(port->sparx5->dev, "Invalid RGMII delay: %u", delay_ps);
return -EINVAL;
}
return 0;
}
/* Configure the RGMII tx clock frequency. */
static void lan969x_rgmii_tx_clk_config(struct sparx5_port *port,
struct sparx5_port_config *conf)
{
u32 clk_sel = lan969x_rgmii_get_clk_sel(conf->speed);
u32 idx = RGMII_PORT_IDX(port);
/* Take the RGMII clock domain out of reset and set tx clock
* frequency.
*/
spx5_rmw(HSIO_WRAP_RGMII_CFG_TX_CLK_CFG_SET(clk_sel) |
HSIO_WRAP_RGMII_CFG_RGMII_TX_RST_SET(0) |
HSIO_WRAP_RGMII_CFG_RGMII_RX_RST_SET(0),
HSIO_WRAP_RGMII_CFG_TX_CLK_CFG |
HSIO_WRAP_RGMII_CFG_RGMII_TX_RST |
HSIO_WRAP_RGMII_CFG_RGMII_RX_RST,
port->sparx5, HSIO_WRAP_RGMII_CFG(idx));
}
/* Configure the RGMII port device. */
static void lan969x_rgmii_port_device_config(struct sparx5_port *port,
struct sparx5_port_config *conf)
{
u32 dtag, dotag, etype, speed_sel, idx = RGMII_PORT_IDX(port);
speed_sel = lan969x_rgmii_get_speed_sel(conf->speed);
etype = (port->vlan_type == SPX5_VLAN_PORT_TYPE_S_CUSTOM ?
port->custom_etype :
port->vlan_type == SPX5_VLAN_PORT_TYPE_C ?
ETH_P_8021Q : ETH_P_8021AD);
dtag = port->max_vlan_tags == SPX5_PORT_MAX_TAGS_TWO;
dotag = port->max_vlan_tags != SPX5_PORT_MAX_TAGS_NONE;
/* Enable the MAC. */
spx5_wr(DEVRGMII_MAC_ENA_CFG_RX_ENA_SET(1) |
DEVRGMII_MAC_ENA_CFG_TX_ENA_SET(1),
port->sparx5, DEVRGMII_MAC_ENA_CFG(idx));
/* Configure the Inter Frame Gap. */
spx5_wr(DEVRGMII_MAC_IFG_CFG_TX_IFG_SET(LAN969X_RGMII_IFG_TX) |
DEVRGMII_MAC_IFG_CFG_RX_IFG1_SET(LAN969X_RGMII_IFG_RX1) |
DEVRGMII_MAC_IFG_CFG_RX_IFG2_SET(LAN969X_RGMII_IFG_RX2),
port->sparx5, DEVRGMII_MAC_IFG_CFG(idx));
/* Configure port data rate. */
spx5_wr(DEVRGMII_DEV_RST_CTRL_SPEED_SEL_SET(speed_sel),
port->sparx5, DEVRGMII_DEV_RST_CTRL(idx));
/* Configure VLAN awareness. */
spx5_wr(DEVRGMII_MAC_TAGS_CFG_TAG_ID_SET(etype) |
DEVRGMII_MAC_TAGS_CFG_PB_ENA_SET(dtag) |
DEVRGMII_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(dotag) |
DEVRGMII_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_SET(dotag),
port->sparx5,
DEVRGMII_MAC_TAGS_CFG(idx));
}
/* Configure the RGMII delay lines in the MAC.
*
* We use the rx-internal-delay-ps" and "tx-internal-delay-ps" properties to
* configure the rx and tx delays for the MAC. If these properties are missing
* or set to zero, the MAC will not apply any delay.
*
* The PHY side delays are determined by the PHY mode
* (e.g. PHY_INTERFACE_MODE_RGMII_{ID, RXID, TXID}), and ignored by the MAC side
* entirely.
*/
static int lan969x_rgmii_delay_config(struct sparx5_port *port,
struct sparx5_port_config *conf)
{
u32 tx_clk_sel, rx_clk_sel, tx_delay_ps = 0, rx_delay_ps = 0;
u32 idx = RGMII_PORT_IDX(port);
int err;
of_property_read_u32(port->of_node, "rx-internal-delay-ps",
&rx_delay_ps);
of_property_read_u32(port->of_node, "tx-internal-delay-ps",
&tx_delay_ps);
err = lan969x_rgmii_get_clk_delay_sel(port, rx_delay_ps, &rx_clk_sel);
if (err)
return err;
err = lan969x_rgmii_get_clk_delay_sel(port, tx_delay_ps, &tx_clk_sel);
if (err)
return err;
/* Configure rx delay. */
spx5_rmw(HSIO_WRAP_DLL_CFG_DLL_RST_SET(0) |
HSIO_WRAP_DLL_CFG_DLL_ENA_SET(1) |
HSIO_WRAP_DLL_CFG_DLL_CLK_ENA_SET(!!rx_delay_ps) |
HSIO_WRAP_DLL_CFG_DLL_CLK_SEL_SET(rx_clk_sel),
HSIO_WRAP_DLL_CFG_DLL_RST |
HSIO_WRAP_DLL_CFG_DLL_ENA |
HSIO_WRAP_DLL_CFG_DLL_CLK_ENA |
HSIO_WRAP_DLL_CFG_DLL_CLK_SEL,
port->sparx5, HSIO_WRAP_DLL_CFG(idx, 0));
/* Configure tx delay. */
spx5_rmw(HSIO_WRAP_DLL_CFG_DLL_RST_SET(0) |
HSIO_WRAP_DLL_CFG_DLL_ENA_SET(1) |
HSIO_WRAP_DLL_CFG_DLL_CLK_ENA_SET(!!tx_delay_ps) |
HSIO_WRAP_DLL_CFG_DLL_CLK_SEL_SET(tx_clk_sel),
HSIO_WRAP_DLL_CFG_DLL_RST |
HSIO_WRAP_DLL_CFG_DLL_ENA |
HSIO_WRAP_DLL_CFG_DLL_CLK_ENA |
HSIO_WRAP_DLL_CFG_DLL_CLK_SEL,
port->sparx5, HSIO_WRAP_DLL_CFG(idx, 1));
return 0;
}
/* Configure GPIO's to be used as RGMII interface. */
static void lan969x_rgmii_gpio_config(struct sparx5_port *port)
{
u32 idx = RGMII_PORT_IDX(port);
/* Enable the RGMII on the GPIOs. */
spx5_wr(HSIO_WRAP_XMII_CFG_GPIO_XMII_CFG_SET(1), port->sparx5,
HSIO_WRAP_XMII_CFG(!idx));
}
int lan969x_port_config_rgmii(struct sparx5_port *port,
struct sparx5_port_config *conf)
{
int err;
err = lan969x_rgmii_delay_config(port, conf);
if (err)
return err;
lan969x_rgmii_tx_clk_config(port, conf);
lan969x_rgmii_gpio_config(port);
lan969x_rgmii_port_device_config(port, conf);
return 0;
}

View File

@@ -313,10 +313,13 @@ static int sparx5_create_port(struct sparx5 *sparx5,
struct initial_port_config *config)
{
struct sparx5_port *spx5_port;
const struct sparx5_ops *ops;
struct net_device *ndev;
struct phylink *phylink;
int err;
ops = sparx5->data->ops;
ndev = sparx5_create_netdev(sparx5, config->portno);
if (IS_ERR(ndev)) {
dev_err(sparx5->dev, "Could not create net device: %02u\n",
@@ -357,6 +360,9 @@ static int sparx5_create_port(struct sparx5 *sparx5,
MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD |
MAC_2500FD | MAC_5000FD | MAC_10000FD | MAC_25000FD;
if (ops->is_port_rgmii(spx5_port->portno))
phy_interface_set_rgmii(spx5_port->phylink_config.supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_SGMII,
spx5_port->phylink_config.supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_QSGMII,
@@ -830,6 +836,7 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
struct initial_port_config *configs, *config;
struct device_node *np = pdev->dev.of_node;
struct device_node *ports, *portnp;
const struct sparx5_ops *ops;
struct reset_control *reset;
struct sparx5 *sparx5;
int idx = 0, err = 0;
@@ -851,6 +858,7 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
return -EINVAL;
regs = sparx5->data->regs;
ops = sparx5->data->ops;
/* Do switch core reset if available */
reset = devm_reset_control_get_optional_shared(&pdev->dev, "switch");
@@ -880,7 +888,7 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
for_each_available_child_of_node(ports, portnp) {
struct sparx5_port_config *conf;
struct phy *serdes;
struct phy *serdes = NULL;
u32 portno;
err = of_property_read_u32(portnp, "reg", &portno);
@@ -910,13 +918,17 @@ static int mchp_sparx5_probe(struct platform_device *pdev)
conf->sd_sgpio = ~0;
else
sparx5->sd_sgpio_remapping = true;
serdes = devm_of_phy_get(sparx5->dev, portnp, NULL);
if (IS_ERR(serdes)) {
err = dev_err_probe(sparx5->dev, PTR_ERR(serdes),
"port %u: missing serdes\n",
portno);
of_node_put(portnp);
goto cleanup_config;
/* There is no SerDes node for RGMII ports. */
if (!ops->is_port_rgmii(portno)) {
serdes = devm_of_phy_get(sparx5->dev, portnp, NULL);
if (IS_ERR(serdes)) {
err = dev_err_probe(sparx5->dev,
PTR_ERR(serdes),
"port %u: missing serdes\n",
portno);
of_node_put(portnp);
goto cleanup_config;
}
}
config->portno = portno;
config->node = portnp;
@@ -1072,6 +1084,7 @@ static const struct sparx5_ops sparx5_ops = {
.is_port_5g = &sparx5_port_is_5g,
.is_port_10g = &sparx5_port_is_10g,
.is_port_25g = &sparx5_port_is_25g,
.is_port_rgmii = &sparx5_port_is_rgmii,
.get_port_dev_index = &sparx5_port_dev_mapping,
.get_port_dev_bit = &sparx5_port_dev_mapping,
.get_hsch_max_group_rate = &sparx5_get_hsch_max_group_rate,

View File

@@ -313,6 +313,7 @@ struct sparx5_ops {
bool (*is_port_5g)(int portno);
bool (*is_port_10g)(int portno);
bool (*is_port_25g)(int portno);
bool (*is_port_rgmii)(int portno);
u32 (*get_port_dev_index)(struct sparx5 *sparx5, int port);
u32 (*get_port_dev_bit)(struct sparx5 *sparx5, int port);
u32 (*get_hsch_max_group_rate)(int grp);
@@ -323,6 +324,8 @@ struct sparx5_ops {
irqreturn_t (*ptp_irq_handler)(int irq, void *args);
int (*dsm_calendar_calc)(struct sparx5 *sparx5, u32 taxi,
struct sparx5_calendar_data *data);
int (*port_config_rgmii)(struct sparx5_port *port,
struct sparx5_port_config *conf);
};
struct sparx5_main_io_resource {

View File

@@ -37,6 +37,7 @@ enum sparx5_target {
TARGET_FDMA = 117,
TARGET_GCB = 118,
TARGET_HSCH = 119,
TARGET_HSIO_WRAP = 120,
TARGET_LRN = 122,
TARGET_PCEP = 129,
TARGET_PCS10G_BR = 132,
@@ -54,6 +55,7 @@ enum sparx5_target {
TARGET_VCAP_SUPER = 326,
TARGET_VOP = 327,
TARGET_XQS = 331,
TARGET_DEVRGMII = 392,
NUM_TARGETS = 517
};
@@ -5367,6 +5369,69 @@ extern const struct sparx5_regs *regs;
#define HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY_GET(x)\
FIELD_GET(HSCH_TAS_STATEMACHINE_CFG_REVISIT_DLY, x)
/* LAN969X ONLY */
/* HSIOWRAP:XMII_CFG:XMII_CFG */
#define HSIO_WRAP_XMII_CFG(g) \
__REG(TARGET_HSIO_WRAP, 0, 1, 116, g, 2, 20, 0, 0, 1, 4)
#define HSIO_WRAP_XMII_CFG_GPIO_XMII_CFG GENMASK(2, 1)
#define HSIO_WRAP_XMII_CFG_GPIO_XMII_CFG_SET(x)\
FIELD_PREP(HSIO_WRAP_XMII_CFG_GPIO_XMII_CFG, x)
#define HSIO_WRAP_XMII_CFG_GPIO_XMII_CFG_GET(x)\
FIELD_GET(HSIO_WRAP_XMII_CFG_GPIO_XMII_CFG, x)
/* LAN969X ONLY */
/* HSIOWRAP:XMII_CFG:RGMII_CFG */
#define HSIO_WRAP_RGMII_CFG(g) \
__REG(TARGET_HSIO_WRAP, 0, 1, 116, g, 2, 20, 4, 0, 1, 4)
#define HSIO_WRAP_RGMII_CFG_TX_CLK_CFG GENMASK(4, 2)
#define HSIO_WRAP_RGMII_CFG_TX_CLK_CFG_SET(x)\
FIELD_PREP(HSIO_WRAP_RGMII_CFG_TX_CLK_CFG, x)
#define HSIO_WRAP_RGMII_CFG_TX_CLK_CFG_GET(x)\
FIELD_GET(HSIO_WRAP_RGMII_CFG_TX_CLK_CFG, x)
#define HSIO_WRAP_RGMII_CFG_RGMII_TX_RST BIT(1)
#define HSIO_WRAP_RGMII_CFG_RGMII_TX_RST_SET(x)\
FIELD_PREP(HSIO_WRAP_RGMII_CFG_RGMII_TX_RST, x)
#define HSIO_WRAP_RGMII_CFG_RGMII_TX_RST_GET(x)\
FIELD_GET(HSIO_WRAP_RGMII_CFG_RGMII_TX_RST, x)
#define HSIO_WRAP_RGMII_CFG_RGMII_RX_RST BIT(0)
#define HSIO_WRAP_RGMII_CFG_RGMII_RX_RST_SET(x)\
FIELD_PREP(HSIO_WRAP_RGMII_CFG_RGMII_RX_RST, x)
#define HSIO_WRAP_RGMII_CFG_RGMII_RX_RST_GET(x)\
FIELD_GET(HSIO_WRAP_RGMII_CFG_RGMII_RX_RST, x)
/* LAN969X ONLY */
/* HSIOWRAP:XMII_CFG:DLL_CFG */
#define HSIO_WRAP_DLL_CFG(g, r) \
__REG(TARGET_HSIO_WRAP, 0, 1, 116, g, 2, 20, 12, r, 2, 4)
#define HSIO_WRAP_DLL_CFG_DLL_ENA BIT(19)
#define HSIO_WRAP_DLL_CFG_DLL_ENA_SET(x)\
FIELD_PREP(HSIO_WRAP_DLL_CFG_DLL_ENA, x)
#define HSIO_WRAP_DLL_CFG_DLL_ENA_GET(x)\
FIELD_GET(HSIO_WRAP_DLL_CFG_DLL_ENA, x)
#define HSIO_WRAP_DLL_CFG_DLL_CLK_ENA BIT(18)
#define HSIO_WRAP_DLL_CFG_DLL_CLK_ENA_SET(x)\
FIELD_PREP(HSIO_WRAP_DLL_CFG_DLL_CLK_ENA, x)
#define HSIO_WRAP_DLL_CFG_DLL_CLK_ENA_GET(x)\
FIELD_GET(HSIO_WRAP_DLL_CFG_DLL_CLK_ENA, x)
#define HSIO_WRAP_DLL_CFG_DLL_CLK_SEL GENMASK(17, 15)
#define HSIO_WRAP_DLL_CFG_DLL_CLK_SEL_SET(x)\
FIELD_PREP(HSIO_WRAP_DLL_CFG_DLL_CLK_SEL, x)
#define HSIO_WRAP_DLL_CFG_DLL_CLK_SEL_GET(x)\
FIELD_GET(HSIO_WRAP_DLL_CFG_DLL_CLK_SEL, x)
#define HSIO_WRAP_DLL_CFG_DLL_RST BIT(0)
#define HSIO_WRAP_DLL_CFG_DLL_RST_SET(x)\
FIELD_PREP(HSIO_WRAP_DLL_CFG_DLL_RST, x)
#define HSIO_WRAP_DLL_CFG_DLL_RST_GET(x)\
FIELD_GET(HSIO_WRAP_DLL_CFG_DLL_RST, x)
/* LRN:COMMON:COMMON_ACCESS_CTRL */
#define LRN_COMMON_ACCESS_CTRL \
__REG(TARGET_LRN, 0, 1, 0, 0, 1, 72, 0, 0, 1, 4)
@@ -8110,4 +8175,84 @@ extern const struct sparx5_regs *regs;
#define XQS_CNT(g) \
__REG(TARGET_XQS, 0, 1, 0, g, 1024, 4, 0, 0, 1, 4)
/* LAN969X ONLY */
/* DEV1G:DEV_CFG_STATUS:DEV_RST_CTRL */
#define DEVRGMII_DEV_RST_CTRL(t) \
__REG(TARGET_DEVRGMII, t, 2, 0, 0, 1, 36, 0, 0, 1, 4)
#define DEVRGMII_DEV_RST_CTRL_SPEED_SEL GENMASK(22, 20)
#define DEVRGMII_DEV_RST_CTRL_SPEED_SEL_SET(x)\
FIELD_PREP(DEVRGMII_DEV_RST_CTRL_SPEED_SEL, x)
#define DEVRGMII_DEV_RST_CTRL_SPEED_SEL_GET(x)\
FIELD_GET(DEVRGMII_DEV_RST_CTRL_SPEED_SEL, x)
/* LAN969X ONLY */
/* DEV1G:MAC_CFG_STATUS:MAC_ENA_CFG */
#define DEVRGMII_MAC_ENA_CFG(t) \
__REG(TARGET_DEVRGMII, t, 2, 36, 0, 1, 36, 0, 0, 1, 4)
#define DEVRGMII_MAC_ENA_CFG_RX_ENA BIT(4)
#define DEVRGMII_MAC_ENA_CFG_RX_ENA_SET(x)\
FIELD_PREP(DEVRGMII_MAC_ENA_CFG_RX_ENA, x)
#define DEVRGMII_MAC_ENA_CFG_RX_ENA_GET(x)\
FIELD_GET(DEVRGMII_MAC_ENA_CFG_RX_ENA, x)
#define DEVRGMII_MAC_ENA_CFG_TX_ENA BIT(0)
#define DEVRGMII_MAC_ENA_CFG_TX_ENA_SET(x)\
FIELD_PREP(DEVRGMII_MAC_ENA_CFG_TX_ENA, x)
#define DEVRGMII_MAC_ENA_CFG_TX_ENA_GET(x)\
FIELD_GET(DEVRGMII_MAC_ENA_CFG_TX_ENA, x)
/* LAN969X ONLY */
/* DEV1G:MAC_CFG_STATUS:MAC_TAGS_CFG */
#define DEVRGMII_MAC_TAGS_CFG(t) \
__REG(TARGET_DEVRGMII, t, 2, 36, 0, 1, 36, 12, 0, 1, 4)
#define DEVRGMII_MAC_TAGS_CFG_TAG_ID GENMASK(31, 16)
#define DEVRGMII_MAC_TAGS_CFG_TAG_ID_SET(x)\
FIELD_PREP(DEVRGMII_MAC_TAGS_CFG_TAG_ID, x)
#define DEVRGMII_MAC_TAGS_CFG_TAG_ID_GET(x)\
FIELD_GET(DEVRGMII_MAC_TAGS_CFG_TAG_ID, x)
#define DEVRGMII_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA BIT(3)
#define DEVRGMII_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_SET(x)\
FIELD_PREP(DEVRGMII_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, x)
#define DEVRGMII_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_GET(x)\
FIELD_GET(DEVRGMII_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, x)
#define DEVRGMII_MAC_TAGS_CFG_PB_ENA GENMASK(2, 1)
#define DEVRGMII_MAC_TAGS_CFG_PB_ENA_SET(x)\
FIELD_PREP(DEVRGMII_MAC_TAGS_CFG_PB_ENA, x)
#define DEVRGMII_MAC_TAGS_CFG_PB_ENA_GET(x)\
FIELD_GET(DEVRGMII_MAC_TAGS_CFG_PB_ENA, x)
#define DEVRGMII_MAC_TAGS_CFG_VLAN_AWR_ENA BIT(0)
#define DEVRGMII_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(x)\
FIELD_PREP(DEVRGMII_MAC_TAGS_CFG_VLAN_AWR_ENA, x)
#define DEVRGMII_MAC_TAGS_CFG_VLAN_AWR_ENA_GET(x)\
FIELD_GET(DEVRGMII_MAC_TAGS_CFG_VLAN_AWR_ENA, x)
/* LAN969X ONLY */
/* DEV1G:MAC_CFG_STATUS:MAC_IFG_CFG */
#define DEVRGMII_MAC_IFG_CFG(t) \
__REG(TARGET_DEVRGMII, t, 2, 36, 0, 1, 36, 24, 0, 1, 4)
#define DEVRGMII_MAC_IFG_CFG_TX_IFG GENMASK(12, 8)
#define DEVRGMII_MAC_IFG_CFG_TX_IFG_SET(x)\
FIELD_PREP(DEVRGMII_MAC_IFG_CFG_TX_IFG, x)
#define DEVRGMII_MAC_IFG_CFG_TX_IFG_GET(x)\
FIELD_GET(DEVRGMII_MAC_IFG_CFG_TX_IFG, x)
#define DEVRGMII_MAC_IFG_CFG_RX_IFG2 GENMASK(7, 4)
#define DEVRGMII_MAC_IFG_CFG_RX_IFG2_SET(x)\
FIELD_PREP(DEVRGMII_MAC_IFG_CFG_RX_IFG2, x)
#define DEVRGMII_MAC_IFG_CFG_RX_IFG2_GET(x)\
FIELD_GET(DEVRGMII_MAC_IFG_CFG_RX_IFG2, x)
#define DEVRGMII_MAC_IFG_CFG_RX_IFG1 GENMASK(3, 0)
#define DEVRGMII_MAC_IFG_CFG_RX_IFG1_SET(x)\
FIELD_PREP(DEVRGMII_MAC_IFG_CFG_RX_IFG1, x)
#define DEVRGMII_MAC_IFG_CFG_RX_IFG1_GET(x)\
FIELD_GET(DEVRGMII_MAC_IFG_CFG_RX_IFG1, x)
#endif /* _SPARX5_MAIN_REGS_H_ */

View File

@@ -32,7 +32,19 @@ sparx5_phylink_mac_select_pcs(struct phylink_config *config,
{
struct sparx5_port *port = netdev_priv(to_net_dev(config->dev));
return &port->phylink_pcs;
/* Return the PCS for all the modes that require it. */
switch (interface) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_QSGMII:
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_2500BASEX:
case PHY_INTERFACE_MODE_5GBASER:
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_25GBASER:
return &port->phylink_pcs;
default:
return NULL;
}
}
static void sparx5_phylink_mac_config(struct phylink_config *config,

View File

@@ -257,6 +257,15 @@ static int sparx5_port_verify_speed(struct sparx5 *sparx5,
conf->speed != SPEED_25000))
return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_TXID:
case PHY_INTERFACE_MODE_RGMII_RXID:
if (conf->speed != SPEED_1000 &&
conf->speed != SPEED_100 &&
conf->speed != SPEED_10)
return sparx5_port_error(port, conf, SPX5_PERR_SPEED);
break;
default:
return sparx5_port_error(port, conf, SPX5_PERR_IFTYPE);
}
@@ -994,6 +1003,7 @@ int sparx5_port_config(struct sparx5 *sparx5,
struct sparx5_port *port,
struct sparx5_port_config *conf)
{
bool rgmii = phy_interface_mode_is_rgmii(conf->phy_mode);
bool high_speed_dev = sparx5_is_baser(conf->portmode);
const struct sparx5_ops *ops = sparx5->data->ops;
int err, urgency, stop_wm;
@@ -1002,8 +1012,14 @@ int sparx5_port_config(struct sparx5 *sparx5,
if (err)
return err;
if (rgmii) {
err = ops->port_config_rgmii(port, conf);
if (err)
return err;
}
/* high speed device is already configured */
if (!high_speed_dev)
if (!rgmii && !high_speed_dev)
sparx5_port_config_low_set(sparx5, port, conf);
/* Configure flow control */
@@ -1067,24 +1083,6 @@ int sparx5_port_init(struct sparx5 *sparx5,
if (err)
return err;
/* Configure MAC vlan awareness */
err = sparx5_port_max_tags_set(sparx5, port);
if (err)
return err;
/* Set Max Length */
spx5_rmw(DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_SET(ETH_MAXLEN),
DEV2G5_MAC_MAXLEN_CFG_MAX_LEN,
sparx5,
DEV2G5_MAC_MAXLEN_CFG(port->portno));
/* 1G/2G5: Signal Detect configuration */
spx5_wr(DEV2G5_PCS1G_SD_CFG_SD_POL_SET(sd_pol) |
DEV2G5_PCS1G_SD_CFG_SD_SEL_SET(sd_sel) |
DEV2G5_PCS1G_SD_CFG_SD_ENA_SET(sd_ena),
sparx5,
DEV2G5_PCS1G_SD_CFG(port->portno));
/* Set Pause WM hysteresis */
spx5_rmw(QSYS_PAUSE_CFG_PAUSE_START_SET(pause_start) |
QSYS_PAUSE_CFG_PAUSE_STOP_SET(pause_stop) |
@@ -1108,6 +1106,27 @@ int sparx5_port_init(struct sparx5 *sparx5,
ANA_CL_FILTER_CTRL_FILTER_SMAC_MC_DIS,
sparx5, ANA_CL_FILTER_CTRL(port->portno));
if (ops->is_port_rgmii(port->portno))
return 0; /* RGMII device - nothing more to configure */
/* Configure MAC vlan awareness */
err = sparx5_port_max_tags_set(sparx5, port);
if (err)
return err;
/* Set Max Length */
spx5_rmw(DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_SET(ETH_MAXLEN),
DEV2G5_MAC_MAXLEN_CFG_MAX_LEN,
sparx5,
DEV2G5_MAC_MAXLEN_CFG(port->portno));
/* 1G/2G5: Signal Detect configuration */
spx5_wr(DEV2G5_PCS1G_SD_CFG_SD_POL_SET(sd_pol) |
DEV2G5_PCS1G_SD_CFG_SD_SEL_SET(sd_sel) |
DEV2G5_PCS1G_SD_CFG_SD_ENA_SET(sd_ena),
sparx5,
DEV2G5_PCS1G_SD_CFG(port->portno));
if (conf->portmode == PHY_INTERFACE_MODE_QSGMII ||
conf->portmode == PHY_INTERFACE_MODE_SGMII) {
err = sparx5_serdes_set(sparx5, port, conf);

View File

@@ -40,6 +40,11 @@ static inline bool sparx5_port_is_25g(int portno)
return portno >= 56 && portno <= 63;
}
static inline bool sparx5_port_is_rgmii(int portno)
{
return false;
}
static inline u32 sparx5_to_high_dev(struct sparx5 *sparx5, int port)
{
const struct sparx5_ops *ops = sparx5->data->ops;