Merge branch 'sja1105-next'
Vladimir Oltean says: ==================== New RGMII delay DT bindings for the SJA1105 DSA driver During recent reviews I've been telling people that new MAC drivers should adopt a certain DT binding format for RGMII delays in order to avoid conflicting interpretations. Some suggestions were better received than others, and it appears we are still far from a consensus. Part of the problem seems to be that there are still drivers that apply RGMII delays based on an incorrect interpretation of the device tree, and these serve as a bad example for others. I happen to maintain one of those drivers and I am able to test it, so I figure that one of the ways in which I can make a change is to stop providing a bad example. Therefore, this series adds support for the "rx-internal-delay-ps" and "tx-internal-delay-ps" properties inside sja1105 switch port DT nodes, and if these are present, they will decide what RGMII delays will the driver apply. The in-tree device trees are also updated to follow the new format, as well as the schema validator. I assume it's okay to get all changes merged in through the same tree (net-next). Although the DTS changes could be split, if needed - the driver works with or without them. There is one more DTS which should be changed, which is in Shawn's tree but not in net-next: https://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux.git/tree/arch/arm64/boot/dts/freescale/fsl-lx2160a-bluebox3.dts?h=for-next For that, I'd have to send a separate patch. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
4d8e5035fa
Documentation/devicetree/bindings/net/dsa
drivers/net/dsa/sja1105
@ -46,6 +46,9 @@ patternProperties:
|
||||
type: object
|
||||
description: Ethernet switch ports
|
||||
|
||||
allOf:
|
||||
- $ref: "http://devicetree.org/schemas/net/ethernet-controller.yaml#"
|
||||
|
||||
properties:
|
||||
reg:
|
||||
description: Port number
|
||||
@ -94,6 +97,10 @@ patternProperties:
|
||||
|
||||
managed: true
|
||||
|
||||
rx-internal-delay-ps: true
|
||||
|
||||
tx-internal-delay-ps: true
|
||||
|
||||
required:
|
||||
- reg
|
||||
|
||||
|
@ -74,10 +74,42 @@ properties:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
patternProperties:
|
||||
"^(ethernet-)?ports$":
|
||||
patternProperties:
|
||||
"^(ethernet-)?port@[0-9]+$":
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
phy-mode:
|
||||
contains:
|
||||
enum:
|
||||
- rgmii
|
||||
- rgmii-rxid
|
||||
- rgmii-txid
|
||||
- rgmii-id
|
||||
then:
|
||||
properties:
|
||||
rx-internal-delay-ps:
|
||||
$ref: "#/$defs/internal-delay-ps"
|
||||
tx-internal-delay-ps:
|
||||
$ref: "#/$defs/internal-delay-ps"
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
$defs:
|
||||
internal-delay-ps:
|
||||
description:
|
||||
Disable tunable delay lines using 0 ps, or enable them and select
|
||||
the phase between 1640 ps (73.8 degree shift at 1Gbps) and 2260 ps
|
||||
(101.7 degree shift) in increments of 0.9 degrees (20 ps).
|
||||
enum:
|
||||
[0, 1640, 1660, 1680, 1700, 1720, 1740, 1760, 1780, 1800, 1820, 1840,
|
||||
1860, 1880, 1900, 1920, 1940, 1960, 1980, 2000, 2020, 2040, 2060, 2080,
|
||||
2100, 2120, 2140, 2160, 2180, 2200, 2220, 2240, 2260]
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
@ -97,29 +129,40 @@ examples:
|
||||
port@0 {
|
||||
phy-handle = <&rgmii_phy6>;
|
||||
phy-mode = "rgmii-id";
|
||||
rx-internal-delay-ps = <0>;
|
||||
tx-internal-delay-ps = <0>;
|
||||
reg = <0>;
|
||||
};
|
||||
|
||||
port@1 {
|
||||
phy-handle = <&rgmii_phy3>;
|
||||
phy-mode = "rgmii-id";
|
||||
rx-internal-delay-ps = <0>;
|
||||
tx-internal-delay-ps = <0>;
|
||||
reg = <1>;
|
||||
};
|
||||
|
||||
port@2 {
|
||||
phy-handle = <&rgmii_phy4>;
|
||||
phy-mode = "rgmii-id";
|
||||
rx-internal-delay-ps = <0>;
|
||||
tx-internal-delay-ps = <0>;
|
||||
reg = <2>;
|
||||
};
|
||||
|
||||
port@3 {
|
||||
phy-handle = <&rgmii_phy4>;
|
||||
phy-mode = "rgmii-id";
|
||||
rx-internal-delay-ps = <0>;
|
||||
tx-internal-delay-ps = <0>;
|
||||
reg = <3>;
|
||||
};
|
||||
|
||||
port@4 {
|
||||
ethernet = <&enet2>;
|
||||
phy-mode = "rgmii";
|
||||
rx-internal-delay-ps = <0>;
|
||||
tx-internal-delay-ps = <0>;
|
||||
reg = <4>;
|
||||
|
||||
fixed-link {
|
||||
|
@ -20,6 +20,27 @@
|
||||
#define SJA1105_AGEING_TIME_MS(ms) ((ms) / 10)
|
||||
#define SJA1105_NUM_L2_POLICERS SJA1110_MAX_L2_POLICING_COUNT
|
||||
|
||||
/* Calculated assuming 1Gbps, where the clock has 125 MHz (8 ns period)
|
||||
* To avoid floating point operations, we'll multiply the degrees by 10
|
||||
* to get a "phase" and get 1 decimal point precision.
|
||||
*/
|
||||
#define SJA1105_RGMII_DELAY_PS_TO_PHASE(ps) \
|
||||
(((ps) * 360) / 800)
|
||||
#define SJA1105_RGMII_DELAY_PHASE_TO_PS(phase) \
|
||||
((800 * (phase)) / 360)
|
||||
#define SJA1105_RGMII_DELAY_PHASE_TO_HW(phase) \
|
||||
(((phase) - 738) / 9)
|
||||
#define SJA1105_RGMII_DELAY_PS_TO_HW(ps) \
|
||||
SJA1105_RGMII_DELAY_PHASE_TO_HW(SJA1105_RGMII_DELAY_PS_TO_PHASE(ps))
|
||||
|
||||
/* Valid range in degrees is a value between 73.8 and 101.7
|
||||
* in 0.9 degree increments
|
||||
*/
|
||||
#define SJA1105_RGMII_DELAY_MIN_PS \
|
||||
SJA1105_RGMII_DELAY_PHASE_TO_PS(738)
|
||||
#define SJA1105_RGMII_DELAY_MAX_PS \
|
||||
SJA1105_RGMII_DELAY_PHASE_TO_PS(1017)
|
||||
|
||||
typedef enum {
|
||||
SPI_READ = 0,
|
||||
SPI_WRITE = 1,
|
||||
@ -222,8 +243,8 @@ struct sja1105_flow_block {
|
||||
|
||||
struct sja1105_private {
|
||||
struct sja1105_static_config static_config;
|
||||
bool rgmii_rx_delay[SJA1105_MAX_NUM_PORTS];
|
||||
bool rgmii_tx_delay[SJA1105_MAX_NUM_PORTS];
|
||||
int rgmii_rx_delay_ps[SJA1105_MAX_NUM_PORTS];
|
||||
int rgmii_tx_delay_ps[SJA1105_MAX_NUM_PORTS];
|
||||
phy_interface_t phy_mode[SJA1105_MAX_NUM_PORTS];
|
||||
bool fixed_link[SJA1105_MAX_NUM_PORTS];
|
||||
unsigned long ucast_egress_floods;
|
||||
|
@ -498,17 +498,6 @@ sja1110_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
|
||||
sja1105_packing(buf, &cmd->txc_pd, 0, 0, size, op);
|
||||
}
|
||||
|
||||
/* Valid range in degrees is an integer between 73.8 and 101.7 */
|
||||
static u64 sja1105_rgmii_delay(u64 phase)
|
||||
{
|
||||
/* UM11040.pdf: The delay in degree phase is 73.8 + delay_tune * 0.9.
|
||||
* To avoid floating point operations we'll multiply by 10
|
||||
* and get 1 decimal point precision.
|
||||
*/
|
||||
phase *= 10;
|
||||
return (phase - 738) / 9;
|
||||
}
|
||||
|
||||
/* The RGMII delay setup procedure is 2-step and gets called upon each
|
||||
* .phylink_mac_config. Both are strategic.
|
||||
* The reason is that the RX Tunable Delay Line of the SJA1105 MAC has issues
|
||||
@ -521,13 +510,15 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
|
||||
const struct sja1105_private *priv = ctx;
|
||||
const struct sja1105_regs *regs = priv->info->regs;
|
||||
struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
|
||||
int rx_delay = priv->rgmii_rx_delay_ps[port];
|
||||
int tx_delay = priv->rgmii_tx_delay_ps[port];
|
||||
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
|
||||
int rc;
|
||||
|
||||
if (priv->rgmii_rx_delay[port])
|
||||
pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
|
||||
if (priv->rgmii_tx_delay[port])
|
||||
pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
|
||||
if (rx_delay)
|
||||
pad_mii_id.rxc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(rx_delay);
|
||||
if (tx_delay)
|
||||
pad_mii_id.txc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(tx_delay);
|
||||
|
||||
/* Stage 1: Turn the RGMII delay lines off. */
|
||||
pad_mii_id.rxc_bypass = 1;
|
||||
@ -542,11 +533,11 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
|
||||
return rc;
|
||||
|
||||
/* Stage 2: Turn the RGMII delay lines on. */
|
||||
if (priv->rgmii_rx_delay[port]) {
|
||||
if (rx_delay) {
|
||||
pad_mii_id.rxc_bypass = 0;
|
||||
pad_mii_id.rxc_pd = 0;
|
||||
}
|
||||
if (priv->rgmii_tx_delay[port]) {
|
||||
if (tx_delay) {
|
||||
pad_mii_id.txc_bypass = 0;
|
||||
pad_mii_id.txc_pd = 0;
|
||||
}
|
||||
@ -561,20 +552,22 @@ int sja1110_setup_rgmii_delay(const void *ctx, int port)
|
||||
const struct sja1105_private *priv = ctx;
|
||||
const struct sja1105_regs *regs = priv->info->regs;
|
||||
struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
|
||||
int rx_delay = priv->rgmii_rx_delay_ps[port];
|
||||
int tx_delay = priv->rgmii_tx_delay_ps[port];
|
||||
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
|
||||
|
||||
pad_mii_id.rxc_pd = 1;
|
||||
pad_mii_id.txc_pd = 1;
|
||||
|
||||
if (priv->rgmii_rx_delay[port]) {
|
||||
pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
|
||||
if (rx_delay) {
|
||||
pad_mii_id.rxc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(rx_delay);
|
||||
/* The "BYPASS" bit in SJA1110 is actually a "don't bypass" */
|
||||
pad_mii_id.rxc_bypass = 1;
|
||||
pad_mii_id.rxc_pd = 0;
|
||||
}
|
||||
|
||||
if (priv->rgmii_tx_delay[port]) {
|
||||
pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
|
||||
if (tx_delay) {
|
||||
pad_mii_id.txc_delay = SJA1105_RGMII_DELAY_PS_TO_HW(tx_delay);
|
||||
pad_mii_id.txc_bypass = 1;
|
||||
pad_mii_id.txc_pd = 0;
|
||||
}
|
||||
|
@ -1109,27 +1109,78 @@ static int sja1105_static_config_load(struct sja1105_private *priv)
|
||||
return sja1105_static_config_upload(priv);
|
||||
}
|
||||
|
||||
static int sja1105_parse_rgmii_delays(struct sja1105_private *priv)
|
||||
/* This is the "new way" for a MAC driver to configure its RGMII delay lines,
|
||||
* based on the explicit "rx-internal-delay-ps" and "tx-internal-delay-ps"
|
||||
* properties. It has the advantage of working with fixed links and with PHYs
|
||||
* that apply RGMII delays too, and the MAC driver needs not perform any
|
||||
* special checks.
|
||||
*
|
||||
* Previously we were acting upon the "phy-mode" property when we were
|
||||
* operating in fixed-link, basically acting as a PHY, but with a reversed
|
||||
* interpretation: PHY_INTERFACE_MODE_RGMII_TXID means that the MAC should
|
||||
* behave as if it is connected to a PHY which has applied RGMII delays in the
|
||||
* TX direction. So if anything, RX delays should have been added by the MAC,
|
||||
* but we were adding TX delays.
|
||||
*
|
||||
* If the "{rx,tx}-internal-delay-ps" properties are not specified, we fall
|
||||
* back to the legacy behavior and apply delays on fixed-link ports based on
|
||||
* the reverse interpretation of the phy-mode. This is a deviation from the
|
||||
* expected default behavior which is to simply apply no delays. To achieve
|
||||
* that behavior with the new bindings, it is mandatory to specify
|
||||
* "{rx,tx}-internal-delay-ps" with a value of 0.
|
||||
*/
|
||||
static int sja1105_parse_rgmii_delays(struct sja1105_private *priv, int port,
|
||||
struct device_node *port_dn)
|
||||
{
|
||||
struct dsa_switch *ds = priv->ds;
|
||||
int port;
|
||||
phy_interface_t phy_mode = priv->phy_mode[port];
|
||||
struct device *dev = &priv->spidev->dev;
|
||||
int rx_delay = -1, tx_delay = -1;
|
||||
|
||||
for (port = 0; port < ds->num_ports; port++) {
|
||||
if (!priv->fixed_link[port])
|
||||
continue;
|
||||
if (!phy_interface_mode_is_rgmii(phy_mode))
|
||||
return 0;
|
||||
|
||||
if (priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_RXID ||
|
||||
priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_ID)
|
||||
priv->rgmii_rx_delay[port] = true;
|
||||
of_property_read_u32(port_dn, "rx-internal-delay-ps", &rx_delay);
|
||||
of_property_read_u32(port_dn, "tx-internal-delay-ps", &tx_delay);
|
||||
|
||||
if (priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_TXID ||
|
||||
priv->phy_mode[port] == PHY_INTERFACE_MODE_RGMII_ID)
|
||||
priv->rgmii_tx_delay[port] = true;
|
||||
if (rx_delay == -1 && tx_delay == -1 && priv->fixed_link[port]) {
|
||||
dev_warn(dev,
|
||||
"Port %d interpreting RGMII delay settings based on \"phy-mode\" property, "
|
||||
"please update device tree to specify \"rx-internal-delay-ps\" and "
|
||||
"\"tx-internal-delay-ps\"",
|
||||
port);
|
||||
|
||||
if ((priv->rgmii_rx_delay[port] || priv->rgmii_tx_delay[port]) &&
|
||||
!priv->info->setup_rgmii_delay)
|
||||
return -EINVAL;
|
||||
if (phy_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
|
||||
phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
|
||||
rx_delay = 2000;
|
||||
|
||||
if (phy_mode == PHY_INTERFACE_MODE_RGMII_TXID ||
|
||||
phy_mode == PHY_INTERFACE_MODE_RGMII_ID)
|
||||
tx_delay = 2000;
|
||||
}
|
||||
|
||||
if (rx_delay < 0)
|
||||
rx_delay = 0;
|
||||
if (tx_delay < 0)
|
||||
tx_delay = 0;
|
||||
|
||||
if ((rx_delay || tx_delay) && !priv->info->setup_rgmii_delay) {
|
||||
dev_err(dev, "Chip cannot apply RGMII delays\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((rx_delay && rx_delay < SJA1105_RGMII_DELAY_MIN_PS) ||
|
||||
(tx_delay && tx_delay < SJA1105_RGMII_DELAY_MIN_PS) ||
|
||||
(rx_delay > SJA1105_RGMII_DELAY_MAX_PS) ||
|
||||
(tx_delay > SJA1105_RGMII_DELAY_MAX_PS)) {
|
||||
dev_err(dev,
|
||||
"port %d RGMII delay values out of range, must be between %d and %d ps\n",
|
||||
port, SJA1105_RGMII_DELAY_MIN_PS, SJA1105_RGMII_DELAY_MAX_PS);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
priv->rgmii_rx_delay_ps[port] = rx_delay;
|
||||
priv->rgmii_tx_delay_ps[port] = tx_delay;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1180,6 +1231,10 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
|
||||
}
|
||||
|
||||
priv->phy_mode[index] = phy_mode;
|
||||
|
||||
err = sja1105_parse_rgmii_delays(priv, index, child);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -3317,15 +3372,6 @@ static int sja1105_probe(struct spi_device *spi)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Error out early if internal delays are required through DT
|
||||
* and we can't apply them.
|
||||
*/
|
||||
rc = sja1105_parse_rgmii_delays(priv);
|
||||
if (rc < 0) {
|
||||
dev_err(ds->dev, "RGMII delay not supported\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_NET_SCH_CBS)) {
|
||||
priv->cbs = devm_kcalloc(dev, priv->info->num_cbs_shapers,
|
||||
sizeof(struct sja1105_cbs_entry),
|
||||
|
Loading…
x
Reference in New Issue
Block a user