[PATCH v14 00/15] phy: Add support for Lynx 10G SerDes

Vladimir Oltean vladimir.oltean at nxp.com
Mon Jun 12 09:33:53 PDT 2023


On Mon, Jun 12, 2023 at 10:35:21AM -0400, Sean Anderson wrote:
> > And if SERDES protocol switching was not physically possible, would this
> > patch set still have value?
> 
> Yes. To e.g. set up SGMII25 or to fix the clocking situation.

Let me analyze the reasons one by one.

The clocking situation only exists due to a hope that protocol changing
would be possible. If you were sure it wasn't possible, your board would
have had refclks set up for protocol 3333 via the supported PLL mapping 2222.
In essence, I consider this almost a non-argument, as it fixes a
self-inflicted problem.

Have you actually tested changing individual lanes from SGMII to SGMII 2.5?
I know it works on LS1028A, but I don't know if that's also true on LS1046A.
Your comments do say "LYNX_PROTO_SGMII25, /* Not tested */".

Assuming a start from SERDES protocol 3333 with PLL mapping 2222,
this protocol change implies powering on PLL 1 (reset state machine
wants it to be disabled) and moving those lanes from PLL 2 to PLL 1.

At first sight you might appear to have a point related to the fact that
PLL register writes are necessary, and thus this whole shebang is necessary.
But this can all be done using PBI commands, with the added benefit that
U-Boot can also use those SERDES networking ports, and not just Linux.
You can use the RCW+PBL specific to your board to inform the SoC that
your platform's refclk 1 is 156 MHz (something which the reset state
machine seems unable to learn, with protocol 0x3333). You don't have to
put that in the device tree. You don't have to push code to any open
source project to expose your platform specific details. Then, just like
in the case of the Lynx 28G driver on LX2160, the SERDES driver could
just treat the PLL configuration as read-only, which would greatly
simplify things and eliminate the need for a clk driver.

Here is an illustrative example (sorry, I don't have a board with the
right refclk on that PLL, to verify all the way):

Add this to ./serdes_10g.rcw in the root of the qoriq-rcw repository:

/*
 * Registers for the Lynx 10G SERDES block.
 *
 * Must be included by an SoC-specific header that defines the
 * SRDS_BASE value.
 */

#define PLLnRSTCTL(n)		(SRDS_BASE + (0x20 * (n)))
#define PLLnCR0(n)		(SRDS_BASE + (0x20 * (n)) + 0x0004)
#define  POFF(x)		(((x) << 31) & 0x80000000)
#define  REFCLK_SEL(x)		(((x) << 28) & 0x70000000)
#define  REFCLK_EN(x)		(((x) << 27) & 0x08000000)
#define  FRATE_SEL(x)		(((x) << 16) & 0x000f0000)
#define  DLYDIV_SEL(x)		((x) & 0x00000003)
#define PCCR8			(SRDS_BASE + 0x0220)
#define  SGMIIA_KX(x)		(((x) << 31) & 0x80000000)
#define  SGMIIA_CFG(x)		(((x) << 28) & 0x70000000)
#define  SGMIIB_KX(x)		(((x) << 27) & 0x08000000)
#define  SGMIIB_CFG(x)		(((x) << 24) & 0x07000000)
#define  SGMIIC_KX(x)		(((x) << 23) & 0x00800000)
#define  SGMIIC_CFG(x)		(((x) << 20) & 0x00700000)
#define  SGMIID_KX(x)		(((x) << 19) & 0x00080000)
#define  SGMIID_CFG(x)		(((x) << 16) & 0x00070000)
#define  SGMIIE_KX(x)		(((x) << 15) & 0x00008000)
#define  SGMIIE_CFG(x)		(((x) << 12) & 0x00007000)
#define  SGMIIF_KX(x)		(((x) << 11) & 0x00000800)
#define  SGMIIF_CFG(x)		(((x) << 8) & 0x00000700)
#define  SGMIIG_KX(x)		(((x) << 7) & 0x00000080)
#define  SGMIIG_CFG(x)		(((x) << 4) & 0x00000070)
#define  SGMIIH_KX(x)		(((x) << 3) & 0x00000008)
#define  SGMIIH_CFG(x)		((x) & 0x00000007)
#define PCCRB			(SRDS_BASE + 0x022c)
#define  XFIA_CFG(x)		(((x) << 28) & 0x70000000)
#define  XFIB_CFG(x)		(((x) << 24) & 0x07000000)
#define  XFIC_CFG(x)		(((x) << 20) & 0x00700000)
#define  XFID_CFG(x)		(((x) << 16) & 0x00070000)
#define  XFIE_CFG(x)		(((x) << 12) & 0x00007000)
#define  XFIF_CFG(x)		(((x) << 8) & 0x00000700)
#define  XFIG_CFG(x)		(((x) << 4) & 0x00000070)
#define  XFIH_CFG(x)		((x) & 0x00000007)
#define LNmGCR0(m)		(SRDS_BASE + (0x40 * (m)) + 0x0800)
#define  RPLL_LES(x)		(((x) << 31) & 0x80000000)
#define  RRAT_SEL(x)		(((x) << 28) & 0x30000000)
#define  TPLL_LES(x)		(((x) << 27) & 0x08000000)
#define  TRAT_SEL(x)		(((x) << 24) & 0x03000000)
#define  RRST_B(x)		(((x) << 22) & 0x00400000)
#define  TRST_B(x)		(((x) << 21) & 0x00200000)
#define  RX_PD(x)		(((x) << 20) & 0x00100000)
#define  TX_PD(x)		(((x) << 19) & 0x00080000)
#define  IF20BIT_EN(x)		(((x) << 18) & 0x00040000)
#define  FIRST_LANE(x)		(((x) << 16) & 0x00010000)
#define  GCR0_RSV		0x1000
#define  PROTS(x)		(((x) << 7) & 0x00000f80)
#define LNmGCR1(m)		(SRDS_BASE + (0x40 * (m)) + 0x0804)
#define  RDAT_INV(x)		(((x) << 31) & 0x80000000)
#define  TDAT_INV(x)		(((x) << 30) & 0x40000000)
#define  OPAD_CTL(x)		(((x) << 26) & 0x04000000)
#define  REIDL_TH(x)		(((x) << 20) & 0x00700000)
#define  REIDL_EX_SEL(x)	(((x) << 18) & 0x000C0000)
#define  REIDL_ET_SEL(x)	(((x) << 16) & 0x00030000)
#define  REIDL_EX_MSB(x)	(((x) << 15) & 0x00008000)
#define  REIDL_ET_MSB(x)	(((x) << 14) & 0x00004000)
#define  REQ_CTL_SNP(x)		(((x) << 13) & 0x00002000)
#define  REQ_CDR_SNP(x)		(((x) << 12) & 0x00001000)
#define  TRSTDIR(x)		(((x) << 7) & 0x00000080)
#define  REQ_BIN_SNP(x)		(((x) << 6) & 0x00000040)
#define  ISLEW_RCTL(x)		(((x) << 4) & 0x00000030)
#define  GCR1_RSV		0x8
#define  OSLEW_RCTL(x)		((x) & 0x3)
#define LNmRECR0(m)		(SRDS_BASE + (0x40 * (m)) + 0x0810)
#define  RXEQ_BST(x)		(((x) << 28) & 0x10000000)
#define  GK2OVD(x)		(((x) << 24) & 0x0f000000)
#define  GK3OVD(x)		(((x) << 16) & 0x000f0000)
#define  GK2OVD_EN(x)		(((x) << 15) & 0x00008000)
#define  GK3OVD_EN(x)		(((x) << 14) & 0x00004000)
#define  OSETOVD_EN(x)		(((x) << 13) & 0x00002000)
#define  BASE_WAND(x)		(((x) << 10) & 0x00000c00)
#define  OSETOVD(x)		((x) & 0x0000007F)
#define LNmTECR0(m)		(SRDS_BASE + (0x40 * (m)) + 0x0818)
#define  TEQ_TYPE(x)		(((x) << 28) & 0x30000000)
#define  SGN_PREQ(x)		(((x) << 26) & 0x04000000)
#define  RATIO_PREQ(x)		(((x) << 22) & 0x03C00000)
#define  SGN_POST1Q(x)		(((x) << 21) & 0x00200000)
#define  RATIO_PST1Q(x)		(((x) << 16) & 0x001F0000)
#define  ADPT_EQ(x)		(((x) << 8) & 0x00003F00)
#define  AMP_RED(x)		((x) & 0x0000003f)
#define LNmTTLCR0(m)		(SRDS_BASE + (0x40 * (m)) + 0x0820)
#define LNmTCSR0(m)		(SRDS_BASE + (0x40 * (m)) + 0x0830)
#define LNmTCSR1(m)		(SRDS_BASE + (0x40 * (m)) + 0x0834)
#define LNmTCSR2(m)		(SRDS_BASE + (0x40 * (m)) + 0x0838)
#define LNmTCSR3(m)		(SRDS_BASE + (0x40 * (m)) + 0x083c)
#define SGMIIaCR1(a)		(SRDS_BASE + (0x10 * (a)) + 0x1804)
#define  SGMII_MDEV_PORT(x)	(((x) << 27) & 0xf8000000)
#define  SGPCS_EN(x)		(((x) << 11) & 0x00000800)
#define XFIaCR1(a)		(SRDS_BASE + (0x10 * (a)) + 0x1984)
#define  XFI_MDEV_PORT(x)	(((x) << 27) & 0xf8000000)

Add this to ./ls1046ardb/serdes_pll1_power_on.rcw in the same repo
(and finish the writes):

/*
 * Assuming that the SoC starts from SERDES1 protocol 0x3333, power on PLL 1,
 * which is required by the reset state machine to be disabled.
 */

#define SRDS_BASE		0xea0000 /* SERDES 1 */
#include <../serdes_10g.rcw>

.pbi

write PLLnCR0(0), POFF(0) | REFCLK_SEL(2) | REFCLK_EN(0)
wait 2500

write PLLnRSTCTL(0), ...

.end

Add this at the end of your board RCW:

#include <../ls1046ardb/serdes_pll1_power_on.rcw>


In short, I believe the reasons you have cited do not justify the
complexity of the solution that you propose.



More information about the linux-arm-kernel mailing list