Commit 6566cd36 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'RGMII-delays-for-SJA1105-DSA-driver'

Vladimir Oltean says:

====================
RGMII delays for SJA1105 DSA driver

This patchset configures the Tunable Delay Lines of the SJA1105 P/Q/R/S
switches. These add a programmable phase offset on the RGMII RX and TX
clock signals and get used by the driver for fixed-link interfaces that
use the rgmii-id, rgmii-txid or rgmii-rxid phy-modes.

Tested on a board where RGMII delays were already set up, by adding
MAC-side delays on the RGMII interface towards a BCM5464R PHY and
noticing that the MAC now reports SFD, preamble, FCS etc. errors.

Conflicts trivially in drivers/net/dsa/sja1105/sja1105_spi.c with
https://patchwork.ozlabs.org/project/netdev/list/?series=112614&state=*


which must be applied first.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 283da99a c05ec3d4
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -35,8 +35,8 @@ struct sja1105_regs {
	u64 ptptsclk;
	u64 ptpegr_ts[SJA1105_NUM_PORTS];
	u64 pad_mii_tx[SJA1105_NUM_PORTS];
	u64 pad_mii_id[SJA1105_NUM_PORTS];
	u64 cgu_idiv[SJA1105_NUM_PORTS];
	u64 rgmii_pad_mii_tx[SJA1105_NUM_PORTS];
	u64 mii_tx_clk[SJA1105_NUM_PORTS];
	u64 mii_rx_clk[SJA1105_NUM_PORTS];
	u64 mii_ext_tx_clk[SJA1105_NUM_PORTS];
@@ -161,6 +161,7 @@ typedef enum {
	SJA1105_SPEED_AUTO	= 0,
} sja1105_speed_t;

int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port);
int sja1105_clocking_setup_port(struct sja1105_private *priv, int port);
int sja1105_clocking_setup(struct sja1105_private *priv);

+97 −3
Original line number Diff line number Diff line
@@ -19,6 +19,17 @@ struct sja1105_cfg_pad_mii_tx {
	u64 clk_ipud;
};

struct sja1105_cfg_pad_mii_id {
	u64 rxc_stable_ovr;
	u64 rxc_delay;
	u64 rxc_bypass;
	u64 rxc_pd;
	u64 txc_stable_ovr;
	u64 txc_delay;
	u64 txc_bypass;
	u64 txc_pd;
};

/* UM10944 Table 82.
 * IDIV_0_C to IDIV_4_C control registers
 * (addr. 10000Bh to 10000Fh)
@@ -373,11 +384,88 @@ static int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv,
	sja1105_cfg_pad_mii_tx_packing(packed_buf, &pad_mii_tx, PACK);

	return sja1105_spi_send_packed_buf(priv, SPI_WRITE,
					   regs->rgmii_pad_mii_tx[port],
					   regs->pad_mii_tx[port],
					   packed_buf, SJA1105_SIZE_CGU_CMD);
}

static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port)
static void
sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
			       enum packing_op op)
{
	const int size = SJA1105_SIZE_CGU_CMD;

	sja1105_packing(buf, &cmd->rxc_stable_ovr, 15, 15, size, op);
	sja1105_packing(buf, &cmd->rxc_delay,      14, 10, size, op);
	sja1105_packing(buf, &cmd->rxc_bypass,      9,  9, size, op);
	sja1105_packing(buf, &cmd->rxc_pd,          8,  8, size, op);
	sja1105_packing(buf, &cmd->txc_stable_ovr,  7,  7, size, op);
	sja1105_packing(buf, &cmd->txc_delay,       6,  2, size, op);
	sja1105_packing(buf, &cmd->txc_bypass,      1,  1, size, op);
	sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
}

/* Valid range in degrees is an integer between 73.8 and 101.7 */
static inline 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
 * with recovering from a frequency change of the link partner's RGMII clock.
 * The easiest way to recover from this is to temporarily power down the TDL,
 * as it will re-lock at the new frequency afterwards.
 */
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};
	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);

	/* Stage 1: Turn the RGMII delay lines off. */
	pad_mii_id.rxc_bypass = 1;
	pad_mii_id.rxc_pd = 1;
	pad_mii_id.txc_bypass = 1;
	pad_mii_id.txc_pd = 1;
	sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);

	rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE,
					 regs->pad_mii_id[port],
					 packed_buf, SJA1105_SIZE_CGU_CMD);
	if (rc < 0)
		return rc;

	/* Stage 2: Turn the RGMII delay lines on. */
	if (priv->rgmii_rx_delay[port]) {
		pad_mii_id.rxc_bypass = 0;
		pad_mii_id.rxc_pd = 0;
	}
	if (priv->rgmii_tx_delay[port]) {
		pad_mii_id.txc_bypass = 0;
		pad_mii_id.txc_pd = 0;
	}
	sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);

	return sja1105_spi_send_packed_buf(priv, SPI_WRITE,
					   regs->pad_mii_id[port],
					   packed_buf, SJA1105_SIZE_CGU_CMD);
}

static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
					sja1105_mii_role_t role)
{
	struct device *dev = priv->ds->dev;
	struct sja1105_mac_config_entry *mac;
@@ -429,6 +517,12 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port)
	}
	if (!priv->info->setup_rgmii_delay)
		return 0;
	/* The role has no hardware effect for RGMII. However we use it as
	 * a proxy for this interface being a MAC-to-MAC connection, with
	 * the RGMII internal delays needing to be applied by us.
	 */
	if (role == XMII_MAC)
		return 0;

	return priv->info->setup_rgmii_delay(priv, port);
}
@@ -575,7 +669,7 @@ int sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
		rc = sja1105_rmii_clocking_setup(priv, port, role);
		break;
	case XMII_MODE_RGMII:
		rc = sja1105_rgmii_clocking_setup(priv, port);
		rc = sja1105_rgmii_clocking_setup(priv, port, role);
		break;
	default:
		dev_err(dev, "Invalid interface mode specified: %d\n",
+7 −4
Original line number Diff line number Diff line
@@ -500,11 +500,10 @@ static struct sja1105_regs sja1105et_regs = {
	.port_control = 0x11,
	.config = 0x020000,
	.rgu = 0x100440,
	/* UM10944.pdf, Table 86, ACU Register overview */
	.pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
	.rmii_pll1 = 0x10000A,
	.cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
	/* UM10944.pdf, Table 86, ACU Register overview */
	.rgmii_pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
	.mac = {0x200, 0x202, 0x204, 0x206, 0x208},
	.mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440},
	.mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640},
@@ -530,11 +529,11 @@ static struct sja1105_regs sja1105pqrs_regs = {
	.port_control = 0x12,
	.config = 0x020000,
	.rgu = 0x100440,
	/* UM10944.pdf, Table 86, ACU Register overview */
	.pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
	.pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814},
	.rmii_pll1 = 0x10000A,
	.cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
	/* UM10944.pdf, Table 86, ACU Register overview */
	.rgmii_pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
	.mac = {0x200, 0x202, 0x204, 0x206, 0x208},
	.mac_hl1 = {0x400, 0x410, 0x420, 0x430, 0x440},
	.mac_hl2 = {0x600, 0x610, 0x620, 0x630, 0x640},
@@ -589,6 +588,7 @@ struct sja1105_info sja1105p_info = {
	.dyn_ops		= sja1105pqrs_dyn_ops,
	.ptp_ts_bits		= 32,
	.ptpegr_ts_bytes	= 8,
	.setup_rgmii_delay	= sja1105pqrs_setup_rgmii_delay,
	.reset_cmd		= sja1105pqrs_reset_cmd,
	.fdb_add_cmd		= sja1105pqrs_fdb_add,
	.fdb_del_cmd		= sja1105pqrs_fdb_del,
@@ -603,6 +603,7 @@ struct sja1105_info sja1105q_info = {
	.dyn_ops		= sja1105pqrs_dyn_ops,
	.ptp_ts_bits		= 32,
	.ptpegr_ts_bytes	= 8,
	.setup_rgmii_delay	= sja1105pqrs_setup_rgmii_delay,
	.reset_cmd		= sja1105pqrs_reset_cmd,
	.fdb_add_cmd		= sja1105pqrs_fdb_add,
	.fdb_del_cmd		= sja1105pqrs_fdb_del,
@@ -617,6 +618,7 @@ struct sja1105_info sja1105r_info = {
	.dyn_ops		= sja1105pqrs_dyn_ops,
	.ptp_ts_bits		= 32,
	.ptpegr_ts_bytes	= 8,
	.setup_rgmii_delay	= sja1105pqrs_setup_rgmii_delay,
	.reset_cmd		= sja1105pqrs_reset_cmd,
	.fdb_add_cmd		= sja1105pqrs_fdb_add,
	.fdb_del_cmd		= sja1105pqrs_fdb_del,
@@ -632,6 +634,7 @@ struct sja1105_info sja1105s_info = {
	.regs			= &sja1105pqrs_regs,
	.ptp_ts_bits		= 32,
	.ptpegr_ts_bytes	= 8,
	.setup_rgmii_delay	= sja1105pqrs_setup_rgmii_delay,
	.reset_cmd		= sja1105pqrs_reset_cmd,
	.fdb_add_cmd		= sja1105pqrs_fdb_add,
	.fdb_del_cmd		= sja1105pqrs_fdb_del,