Skip to content

Commit

Permalink
phy: fsl: Add Lynx 10G SerDes driver
Browse files Browse the repository at this point in the history
This adds support for the Lynx 10G "SerDes" devices found on various NXP
QorIQ SoCs. There may be up to four SerDes devices on each SoC, each
supporting up to eight lanes. Protocol support for each SerDes is highly
heterogeneous, with each SoC typically having a totally different
selection of supported protocols for each lane. Additionally, the SerDes
devices on each SoC also have differing support. One SerDes will
typically support Ethernet on most lanes, while the other will typically
support PCIe on most lanes.

There is wide hardware support for this SerDes. It is present on QorIQ
T-Series and Layerscape processors. Because each SoC typically has
specific instructions and exceptions for its SerDes, I have limited the
initial scope of this module to just the LS1046A and LS1088A.
Additionally, I have only added support for Ethernet protocols. There is
not a great need for dynamic reconfiguration for other protocols (except
perhaps for M.2 cards), so support for them may never be added.

Nevertheless, I have tried to provide an obvious path for adding support
for other SoCs as well as other protocols. SATA just needs support for
configuring LNmSSCR0. PCIe may need to configure the equalization
registers. It also uses multiple lanes. I have tried to write the driver
with multi-lane support in mind, so there should not need to be any
large changes. Although there are 6 protocols supported, I have only
tested SGMII and XFI. The rest have been implemented as described in
the datasheet. Most of these protocols should work "as-is", but
10GBASE-KR will need PCS support for link training.

The PLLs are modeled as clocks proper. This lets us take advantage of
the existing clock infrastructure. I have not given the same treatment
to the per-lane clocks because they need to be programmed in-concert
with the rest of the lane settings. One tricky thing is that the VCO
(PLL) rate exceeds 2^32 (maxing out at around 5GHz). This will be a
problem on 32-bit platforms, since clock rates are stored as unsigned
longs. To work around this, the pll clock rate is generally treated in
units of kHz.

The PLLs are configured rather interestingly. Instead of the usual direct
programming of the appropriate divisors, the input and output clock rates
are selected directly. Generally, the only restriction is that the input
and output must be integer multiples of each other. This suggests some kind
of internal look-up table. The datasheets generally list out the supported
combinations explicitly, and not all input/output combinations are
documented. I'm not sure if this is due to lack of support, or due to an
oversight. If this becomes an issue, then some combinations can be
blacklisted (or whitelisted). This may also be necessary for other SoCs
which have more stringent clock requirements.

Unlike some other phys where e.g. PCIe x4 will use 4 separate phys all
configured for PCIe, this driver uses one phy configured to use 4 lanes.
This is because while the individual lanes may be configured
individually, the protocol selection acts on all lanes at once.
Additionally, the order which lanes should be configured in is specified
by the datasheet. To coordinate this, lanes are reserved in phy_init,
and released in phy_exit.

This driver was written with reference to the LS1046A reference manual.
However, it was informed by reference manuals for all processors with
mEMACs, especially the T4240 (which appears to have a "maxed-out"
configuration). The earlier P-series processors appear to be similar, but
have a different overall register layout (using "banks" instead of
separate SerDes). Perhaps this those use a "5G Lynx SerDes."

Signed-off-by: Sean Anderson <sean.anderson@seco.com>
  • Loading branch information
sean-anderson-seco authored and intel-lab-lkp committed Oct 18, 2022
1 parent ab8164a commit 6184185
Show file tree
Hide file tree
Showing 8 changed files with 1,777 additions and 0 deletions.
1 change: 1 addition & 0 deletions Documentation/driver-api/phy/index.rst
Expand Up @@ -7,6 +7,7 @@ Generic PHY Framework
.. toctree::

phy
lynx_10g
samsung-usb2

.. only:: subproject and html
Expand Down
58 changes: 58 additions & 0 deletions Documentation/driver-api/phy/lynx_10g.rst
@@ -0,0 +1,58 @@
.. SPDX-License-Identifier: GPL-2.0
===========================
Lynx 10G Phy (QorIQ SerDes)
===========================

Using this phy
--------------

:c:func:`phy_get` just gets (or creates) a new :c:type:`phy` with the lanes
described in the phandle. :c:func:`phy_init` is what actually reserves the
lanes for use. Unlike some other drivers, when the phy is created, there is no
default protocol. :c:func:`phy_set_mode <phy_set_mode_ext>` must be called in
order to set the protocol.

Supporting SoCs
---------------

Each new SoC needs a :c:type:`struct lynx_conf <lynx_conf>`, containing the
number of lanes in each device, the endianness of the device, and the helper
functions to use when selecting protocol controllers. For example, the
configuration for the LS1046A is::

static const struct lynx_cfg ls1046a_cfg = {
.lanes = 4,
.endian = REGMAP_ENDIAN_BIG,
.mode_conflict = lynx_ls_mode_conflict,
.mode_apply = lynx_ls_mode_apply,
.mode_init = lynx_ls_mode_init,
};

The ``mode_`` functions will generally be common to all SoCs in a series (e.g.
all Layerscape SoCs or all T-series SoCs).

In addition, you will need to add a device node as documented in
``Documentation/devicetree/bindings/phy/fsl,lynx-10g.yaml``. This lets the
driver know which lanes are available to configure.

Supporting Protocols
--------------------

Each protocol is a combination of values which must be programmed into the lane
registers. To add a new protocol, first add it to :c:type:`enum lynx_protocol
<lynx_protocol>`. Add a new entry to `lynx_proto_params`, and populate the
appropriate fields. Modify `lynx_lookup_proto` to map the :c:type:`enum
phy_mode <phy_mode>` to :c:type:`enum lynx_protocol <lynx_protocol>`. Update
the ``mode_conflict``, ``mode_apply``, and ``mode_init`` helpers are updated to
support your protocol.

You may need to modify :c:func:`lynx_set_mode` in order to support your
protocol. This can happen when you have added members to :c:type:`struct
lynx_proto_params <lynx_proto_params>`. It can also happen if you have specific
clocking requirements, or protocol-specific registers to program.

Internal API Reference
----------------------

.. kernel-doc:: drivers/phy/freescale/phy-fsl-lynx-10g.c
7 changes: 7 additions & 0 deletions MAINTAINERS
Expand Up @@ -12083,6 +12083,13 @@ S: Maintained
W: http://linux-test-project.github.io/
T: git git://github.com/linux-test-project/ltp.git

LYNX 10G SERDES DRIVER
M: Sean Anderson <sean.anderson@seco.com>
S: Maintained
F: Documentation/driver-api/phy/lynx_10g.rst
F: drivers/phy/freescale/*lynx-10g*
F: include/dt-bindings/clock/fsl,lynx-10g.h

LYNX 28G SERDES PHY DRIVER
M: Ioana Ciornei <ioana.ciornei@nxp.com>
L: netdev@vger.kernel.org
Expand Down
22 changes: 22 additions & 0 deletions drivers/phy/freescale/Kconfig
Expand Up @@ -47,3 +47,25 @@ config PHY_FSL_LYNX_28G
found on NXP's Layerscape platforms such as LX2160A.
Used to change the protocol running on SerDes lanes at runtime.
Only useful for a restricted set of Ethernet protocols.

config PHY_FSL_LYNX_10G
tristate "Freescale QorIQ Lynx 10G SerDes support"
depends on COMMON_CLK
depends on ARCH_LAYERSCAPE || PPC || COMPILE_TEST
select GENERIC_PHY
select REGMAP_MMIO
help
This adds support for the Lynx "SerDes" devices found on various QorIQ
SoCs. There may be up to four SerDes devices on each SoC, and each
device supports up to eight lanes. The SerDes is configured by
default by the RCW, but this module is necessary in order to support
some modes (such as 2.5G SGMII or 1000BASE-KX), or clock setups (as
only as subset of clock configurations are supported by the RCW).
The hardware supports a variety of protocols, including Ethernet,
SATA, PCIe, and more exotic links such as Interlaken and Aurora. This
driver only supports Ethernet, but it will try not to touch lanes
configured for other protocols.

If you have a QorIQ processor and want to dynamically reconfigure your
SerDes, say Y. If this driver is compiled as a module, it will be
named phy-fsl-lynx-10g-drv.
3 changes: 3 additions & 0 deletions drivers/phy/freescale/Makefile
Expand Up @@ -3,4 +3,7 @@ obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o
obj-$(CONFIG_PHY_MIXEL_LVDS_PHY) += phy-fsl-imx8qm-lvds-phy.o
obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o
obj-$(CONFIG_PHY_FSL_IMX8M_PCIE) += phy-fsl-imx8m-pcie.o
phy-fsl-lynx-10g-drv-y += phy-fsl-lynx-10g.o
phy-fsl-lynx-10g-drv-y += phy-fsl-lynx-10g-clk.o
obj-$(CONFIG_PHY_FSL_LYNX_10G) += phy-fsl-lynx-10g-drv.o
obj-$(CONFIG_PHY_FSL_LYNX_28G) += phy-fsl-lynx-28g.o
16 changes: 16 additions & 0 deletions drivers/phy/freescale/lynx-10g.h
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2022 Sean Anderson <sean.anderson@seco.com>
*/

#ifndef LYNX_10G
#define LYNX_10G

struct clk;
struct device;
struct regmap;

int lynx_clks_init(struct device *dev, struct regmap *regmap,
struct clk *plls[2], struct clk *ex_dlys[2]);

#endif /* LYNX 10G */

0 comments on commit 6184185

Please sign in to comment.