Commit 7752422f authored by David S. Miller's avatar David S. Miller

Merge branch 'altera-tse-phylink'

Maxime Chevallier says:

====================
net: altera: tse: phylink conversion

This is V4 of a series converting the Altera TSE driver to phylink,
introducing a new PCS driver along the way.

The Altera TSE can be built with a SGMII/1000BaseX PCS, allowing to use
SFP ports with this MAC, which is the end goal of adding phylink support
and a proper PCS driver.

The PCS itself can either be mapped in the MAC's register space, in that
case, it's accessed through 32 bits registers, with the higher 16 bits
always 0. Alternatively, it can sit on its own register space, exposing
16 bits registers, some of which ressemble the standard PHY registers.

To tackle that rework, several things needs updating, starting by the DT
binding, since we add support for a new register range for the PCS.

Hence, the first patch of the series is a conversion to YAML of the
existing binding.

Then, patch 2 does a bit of simple cleanup to the TSE driver, using nice
reverse xmas tree definitions.

Patch 3 adds the actual PCS driver, as a standalone driver. Some future
series will then reuse that PCS driver from the dwmac-socfpga driver,
which implements support for this exact PCS too, allowing to share the
code nicely.

Patch 4 is then a phylink conversion of the altera_tse driver, to use
this new PCS driver.

Finally, patch 5 updates the newly converted DT binding to support the
pcs register range.

This series contains bits and pieces for this conversion, please tell me if
you want me to send it as individual patches.

V4 Changes:
 - Add missing MODULE_* macros to the TSE PCS driver

V3 Changes:
 - YAML binding conversion changes and PCS addition changes thanks to
   Krzysztof's reviews

V2 Changes :
 - Fixed the binding after the YAML conversion
 - Added a pcs_validate() callback
 - Introduced a comment to justify a soft reset for the PCS
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9837ec95 565f02fc
* Altera Triple-Speed Ethernet MAC driver (TSE)
Required properties:
- compatible: Should be "altr,tse-1.0" for legacy SGDMA based TSE, and should
be "altr,tse-msgdma-1.0" for the preferred MSGDMA based TSE.
ALTR is supported for legacy device trees, but is deprecated.
altr should be used for all new designs.
- reg: Address and length of the register set for the device. It contains
the information of registers in the same order as described by reg-names
- reg-names: Should contain the reg names
"control_port": MAC configuration space region
"tx_csr": xDMA Tx dispatcher control and status space region
"tx_desc": MSGDMA Tx dispatcher descriptor space region
"rx_csr" : xDMA Rx dispatcher control and status space region
"rx_desc": MSGDMA Rx dispatcher descriptor space region
"rx_resp": MSGDMA Rx dispatcher response space region
"s1": SGDMA descriptor memory
- interrupts: Should contain the TSE interrupts and its mode.
- interrupt-names: Should contain the interrupt names
"rx_irq": xDMA Rx dispatcher interrupt
"tx_irq": xDMA Tx dispatcher interrupt
- rx-fifo-depth: MAC receive FIFO buffer depth in bytes
- tx-fifo-depth: MAC transmit FIFO buffer depth in bytes
- phy-mode: See ethernet.txt in the same directory.
- phy-handle: See ethernet.txt in the same directory.
- phy-addr: See ethernet.txt in the same directory. A configuration should
include phy-handle or phy-addr.
- altr,has-supplementary-unicast:
If present, TSE supports additional unicast addresses.
Otherwise additional unicast addresses are not supported.
- altr,has-hash-multicast-filter:
If present, TSE supports a hash based multicast filter.
Otherwise, hash-based multicast filtering is not supported.
- mdio device tree subnode: When the TSE has a phy connected to its local
mdio, there must be device tree subnode with the following
required properties:
- compatible: Must be "altr,tse-mdio".
- #address-cells: Must be <1>.
- #size-cells: Must be <0>.
For each phy on the mdio bus, there must be a node with the following
fields:
- reg: phy id used to communicate to phy.
- device_type: Must be "ethernet-phy".
The MAC address will be determined using the optional properties defined in
ethernet.txt.
Example:
tse_sub_0_eth_tse_0: ethernet@1,00000000 {
compatible = "altr,tse-msgdma-1.0";
reg = <0x00000001 0x00000000 0x00000400>,
<0x00000001 0x00000460 0x00000020>,
<0x00000001 0x00000480 0x00000020>,
<0x00000001 0x000004A0 0x00000008>,
<0x00000001 0x00000400 0x00000020>,
<0x00000001 0x00000420 0x00000020>;
reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc";
interrupt-parent = <&hps_0_arm_gic_0>;
interrupts = <0 41 4>, <0 40 4>;
interrupt-names = "rx_irq", "tx_irq";
rx-fifo-depth = <2048>;
tx-fifo-depth = <2048>;
address-bits = <48>;
max-frame-size = <1500>;
local-mac-address = [ 00 00 00 00 00 00 ];
phy-mode = "gmii";
altr,has-supplementary-unicast;
altr,has-hash-multicast-filter;
phy-handle = <&phy0>;
mdio {
compatible = "altr,tse-mdio";
#address-cells = <1>;
#size-cells = <0>;
phy0: ethernet-phy@0 {
reg = <0x0>;
device_type = "ethernet-phy";
};
phy1: ethernet-phy@1 {
reg = <0x1>;
device_type = "ethernet-phy";
};
};
};
tse_sub_1_eth_tse_0: ethernet@1,00001000 {
compatible = "altr,tse-msgdma-1.0";
reg = <0x00000001 0x00001000 0x00000400>,
<0x00000001 0x00001460 0x00000020>,
<0x00000001 0x00001480 0x00000020>,
<0x00000001 0x000014A0 0x00000008>,
<0x00000001 0x00001400 0x00000020>,
<0x00000001 0x00001420 0x00000020>;
reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc";
interrupt-parent = <&hps_0_arm_gic_0>;
interrupts = <0 43 4>, <0 42 4>;
interrupt-names = "rx_irq", "tx_irq";
rx-fifo-depth = <2048>;
tx-fifo-depth = <2048>;
address-bits = <48>;
max-frame-size = <1500>;
local-mac-address = [ 00 00 00 00 00 00 ];
phy-mode = "gmii";
altr,has-supplementary-unicast;
altr,has-hash-multicast-filter;
phy-handle = <&phy1>;
};
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/altr,tse.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Altera Triple Speed Ethernet MAC driver (TSE)
maintainers:
- Maxime Chevallier <maxime.chevallier@bootlin.com>
properties:
compatible:
oneOf:
- const: altr,tse-1.0
- const: ALTR,tse-1.0
deprecated: true
- const: altr,tse-msgdma-1.0
interrupts:
minItems: 2
interrupt-names:
items:
- const: rx_irq
- const: tx_irq
rx-fifo-depth:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Depth in bytes of the RX FIFO
tx-fifo-depth:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Depth in bytes of the TX FIFO
altr,has-supplementary-unicast:
type: boolean
description:
If present, TSE supports additional unicast addresses.
altr,has-hash-multicast-filter:
type: boolean
description:
If present, TSE supports hash based multicast filter.
mdio:
$ref: mdio.yaml#
unevaluatedProperties: false
description:
Creates and registers an MDIO bus.
properties:
compatible:
const: altr,tse-mdio
required:
- compatible
required:
- compatible
- reg
- interrupts
- rx-fifo-depth
- tx-fifo-depth
allOf:
- $ref: "ethernet-controller.yaml#"
- if:
properties:
compatible:
contains:
enum:
- const: altr,tse-1.0
- const: ALTR,tse-1.0
then:
properties:
reg:
minItems: 4
reg-names:
items:
- const: control_port
- const: rx_csr
- const: tx_csr
- const: s1
- if:
properties:
compatible:
contains:
enum:
- altr,tse-msgdma-1.0
then:
properties:
reg:
minItems: 6
maxItems: 7
reg-names:
minItems: 6
items:
- const: control_port
- const: rx_csr
- const: rx_desc
- const: rx_resp
- const: tx_csr
- const: tx_desc
- const: pcs
unevaluatedProperties: false
examples:
- |
tse_sub_0: ethernet@c0100000 {
compatible = "altr,tse-msgdma-1.0";
reg = <0xc0100000 0x00000400>,
<0xc0101000 0x00000020>,
<0xc0102000 0x00000020>,
<0xc0103000 0x00000008>,
<0xc0104000 0x00000020>,
<0xc0105000 0x00000020>,
<0xc0106000 0x00000100>;
reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc", "pcs";
interrupt-parent = <&intc>;
interrupts = <0 44 4>,<0 45 4>;
interrupt-names = "rx_irq","tx_irq";
rx-fifo-depth = <2048>;
tx-fifo-depth = <2048>;
max-frame-size = <1500>;
local-mac-address = [ 00 00 00 00 00 00 ];
altr,has-supplementary-unicast;
altr,has-hash-multicast-filter;
sfp = <&sfp0>;
phy-mode = "sgmii";
managed = "in-band-status";
};
- |
tse_sub_1_eth_tse_0: ethernet@1,00001000 {
compatible = "altr,tse-msgdma-1.0";
reg = <0x00001000 0x00000400>,
<0x00001460 0x00000020>,
<0x00001480 0x00000020>,
<0x000014A0 0x00000008>,
<0x00001400 0x00000020>,
<0x00001420 0x00000020>;
reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc";
interrupt-parent = <&hps_0_arm_gic_0>;
interrupts = <0 43 4>, <0 42 4>;
interrupt-names = "rx_irq", "tx_irq";
rx-fifo-depth = <2048>;
tx-fifo-depth = <2048>;
max-frame-size = <1500>;
local-mac-address = [ 00 00 00 00 00 00 ];
phy-mode = "gmii";
altr,has-supplementary-unicast;
altr,has-hash-multicast-filter;
phy-handle = <&phy1>;
mdio {
compatible = "altr,tse-mdio";
#address-cells = <1>;
#size-cells = <0>;
phy1: ethernet-phy@1 {
reg = <0x1>;
};
};
};
...
......@@ -878,6 +878,13 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/altera/
ALTERA TSE PCS
M: Maxime Chevallier <maxime.chevallier@bootlin.com>
L: netdev@vger.kernel.org
S: Supported
F: drivers/net/pcs/pcs-altera-tse.c
F: include/linux/pcs-altera-tse.h
ALTERA UART/JTAG UART SERIAL DRIVERS
M: Tobias Klauser <tklauser@distanz.ch>
L: linux-serial@vger.kernel.org
......
......@@ -3,6 +3,8 @@ config ALTERA_TSE
tristate "Altera Triple-Speed Ethernet MAC support"
depends on HAS_DMA
select PHYLIB
select PHYLINK
select PCS_ALTERA_TSE
help
This driver supports the Altera Triple-Speed (TSE) Ethernet MAC.
......
......@@ -27,6 +27,7 @@
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/phylink.h>
#define ALTERA_TSE_SW_RESET_WATCHDOG_CNTR 10000
#define ALTERA_TSE_MAC_FIFO_WIDTH 4 /* TX/RX FIFO width in
......@@ -109,17 +110,6 @@
#define MAC_CMDCFG_DISABLE_READ_TIMEOUT_GET(v) GET_BIT_VALUE(v, 27)
#define MAC_CMDCFG_CNT_RESET_GET(v) GET_BIT_VALUE(v, 31)
/* SGMII PCS register addresses
*/
#define SGMII_PCS_SCRATCH 0x10
#define SGMII_PCS_REV 0x11
#define SGMII_PCS_LINK_TIMER_0 0x12
#define SGMII_PCS_LINK_TIMER_1 0x13
#define SGMII_PCS_IF_MODE 0x14
#define SGMII_PCS_DIS_READ_TO 0x15
#define SGMII_PCS_READ_TO 0x16
#define SGMII_PCS_SW_RESET_TIMEOUT 100 /* usecs */
/* MDIO registers within MAC register Space
*/
struct altera_tse_mdio {
......@@ -423,6 +413,9 @@ struct altera_tse_private {
void __iomem *tx_dma_csr;
void __iomem *tx_dma_desc;
/* SGMII PCS address space */
void __iomem *pcs_base;
/* Rx buffers queue */
struct tse_buffer *rx_ring;
u32 rx_cons;
......@@ -480,6 +473,10 @@ struct altera_tse_private {
u32 msg_enable;
struct altera_dmaops *dmaops;
struct phylink *phylink;
struct phylink_config phylink_config;
struct phylink_pcs *pcs;
};
/* Function prototypes
......
......@@ -199,9 +199,9 @@ static int tse_reglen(struct net_device *dev)
static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *regbuf)
{
int i;
struct altera_tse_private *priv = netdev_priv(dev);
u32 *buf = regbuf;
int i;
/* Set version to a known value, so ethtool knows
* how to do any special formatting of this data.
......@@ -221,6 +221,22 @@ static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs,
buf[i] = csrrd32(priv->mac_dev, i * 4);
}
static int tse_ethtool_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *cmd)
{
struct altera_tse_private *priv = netdev_priv(dev);
return phylink_ethtool_ksettings_set(priv->phylink, cmd);
}
static int tse_ethtool_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
struct altera_tse_private *priv = netdev_priv(dev);
return phylink_ethtool_ksettings_get(priv->phylink, cmd);
}
static const struct ethtool_ops tse_ethtool_ops = {
.get_drvinfo = tse_get_drvinfo,
.get_regs_len = tse_reglen,
......@@ -231,8 +247,8 @@ static const struct ethtool_ops tse_ethtool_ops = {
.get_ethtool_stats = tse_fill_stats,
.get_msglevel = tse_get_msglevel,
.set_msglevel = tse_set_msglevel,
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
.get_link_ksettings = tse_ethtool_get_link_ksettings,
.set_link_ksettings = tse_ethtool_set_link_ksettings,
.get_ts_info = ethtool_op_get_ts_info,
};
......
......@@ -26,4 +26,10 @@ config PCS_RZN1_MIIC
on RZ/N1 SoCs. This PCS converts MII to RMII/RGMII or can be set in
pass-through mode for MII.
config PCS_ALTERA_TSE
tristate
help
This module provides helper functions for the Altera Triple Speed
Ethernet SGMII PCS, that can be found on the Intel Socfpga family.
endmenu
......@@ -6,3 +6,4 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o
obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o
obj-$(CONFIG_PCS_ALTERA_TSE) += pcs-altera-tse.o
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2022 Bootlin
*
* Maxime Chevallier <maxime.chevallier@bootlin.com>
*/
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/phylink.h>
#include <linux/pcs-altera-tse.h>
/* SGMII PCS register addresses
*/
#define SGMII_PCS_SCRATCH 0x10
#define SGMII_PCS_REV 0x11
#define SGMII_PCS_LINK_TIMER_0 0x12
#define SGMII_PCS_LINK_TIMER_REG(x) (0x12 + (x))
#define SGMII_PCS_LINK_TIMER_1 0x13
#define SGMII_PCS_IF_MODE 0x14
#define PCS_IF_MODE_SGMII_ENA BIT(0)
#define PCS_IF_MODE_USE_SGMII_AN BIT(1)
#define PCS_IF_MODE_SGMI_SPEED_MASK GENMASK(3, 2)
#define PCS_IF_MODE_SGMI_SPEED_10 (0 << 2)
#define PCS_IF_MODE_SGMI_SPEED_100 (1 << 2)
#define PCS_IF_MODE_SGMI_SPEED_1000 (2 << 2)
#define PCS_IF_MODE_SGMI_HALF_DUPLEX BIT(4)
#define PCS_IF_MODE_SGMI_PHY_AN BIT(5)
#define SGMII_PCS_DIS_READ_TO 0x15
#define SGMII_PCS_READ_TO 0x16
#define SGMII_PCS_SW_RESET_TIMEOUT 100 /* usecs */
struct altera_tse_pcs {
struct phylink_pcs pcs;
void __iomem *base;
int reg_width;
};
static struct altera_tse_pcs *phylink_pcs_to_tse_pcs(struct phylink_pcs *pcs)
{
return container_of(pcs, struct altera_tse_pcs, pcs);
}
static u16 tse_pcs_read(struct altera_tse_pcs *tse_pcs, int regnum)
{
if (tse_pcs->reg_width == 4)
return readl(tse_pcs->base + regnum * 4);
else
return readw(tse_pcs->base + regnum * 2);
}
static void tse_pcs_write(struct altera_tse_pcs *tse_pcs, int regnum,
u16 value)
{
if (tse_pcs->reg_width == 4)
writel(value, tse_pcs->base + regnum * 4);
else
writew(value, tse_pcs->base + regnum * 2);
}
static int tse_pcs_reset(struct altera_tse_pcs *tse_pcs)
{
int i = 0;
u16 bmcr;
/* Reset PCS block */
bmcr = tse_pcs_read(tse_pcs, MII_BMCR);
bmcr |= BMCR_RESET;
tse_pcs_write(tse_pcs, MII_BMCR, bmcr);
for (i = 0; i < SGMII_PCS_SW_RESET_TIMEOUT; i++) {
if (!(tse_pcs_read(tse_pcs, MII_BMCR) & BMCR_RESET))
return 0;
udelay(1);
}
return -ETIMEDOUT;
}
static int alt_tse_pcs_validate(struct phylink_pcs *pcs,
unsigned long *supported,
const struct phylink_link_state *state)
{
if (state->interface == PHY_INTERFACE_MODE_SGMII ||
state->interface == PHY_INTERFACE_MODE_1000BASEX)
return 1;
return -EINVAL;
}
static int alt_tse_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertising,
bool permit_pause_to_mac)
{
struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs);
u32 ctrl, if_mode;
ctrl = tse_pcs_read(tse_pcs, MII_BMCR);
if_mode = tse_pcs_read(tse_pcs, SGMII_PCS_IF_MODE);
/* Set link timer to 1.6ms, as per the MegaCore Function User Guide */
tse_pcs_write(tse_pcs, SGMII_PCS_LINK_TIMER_0, 0x0D40);
tse_pcs_write(tse_pcs, SGMII_PCS_LINK_TIMER_1, 0x03);
if (interface == PHY_INTERFACE_MODE_SGMII) {
if_mode |= PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA;
} else if (interface == PHY_INTERFACE_MODE_1000BASEX) {
if_mode &= ~(PCS_IF_MODE_USE_SGMII_AN | PCS_IF_MODE_SGMII_ENA);
if_mode |= PCS_IF_MODE_SGMI_SPEED_1000;
}
ctrl |= (BMCR_SPEED1000 | BMCR_FULLDPLX | BMCR_ANENABLE);
tse_pcs_write(tse_pcs, MII_BMCR, ctrl);
tse_pcs_write(tse_pcs, SGMII_PCS_IF_MODE, if_mode);
return tse_pcs_reset(tse_pcs);
}
static void alt_tse_pcs_get_state(struct phylink_pcs *pcs,
struct phylink_link_state *state)
{
struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs);
u16 bmsr, lpa;
bmsr = tse_pcs_read(tse_pcs, MII_BMSR);
lpa = tse_pcs_read(tse_pcs, MII_LPA);
phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
}
static void alt_tse_pcs_an_restart(struct phylink_pcs *pcs)
{
struct altera_tse_pcs *tse_pcs = phylink_pcs_to_tse_pcs(pcs);
u16 bmcr;
bmcr = tse_pcs_read(tse_pcs, MII_BMCR);
bmcr |= BMCR_ANRESTART;
tse_pcs_write(tse_pcs, MII_BMCR, bmcr);
/* This PCS seems to require a soft reset to re-sync the AN logic */
tse_pcs_reset(tse_pcs);
}
static const struct phylink_pcs_ops alt_tse_pcs_ops = {
.pcs_validate = alt_tse_pcs_validate,
.pcs_get_state = alt_tse_pcs_get_state,
.pcs_config = alt_tse_pcs_config,
.pcs_an_restart = alt_tse_pcs_an_restart,
};
struct phylink_pcs *alt_tse_pcs_create(struct net_device *ndev,
void __iomem *pcs_base, int reg_width)
{
struct altera_tse_pcs *tse_pcs;
if (reg_width != 4 && reg_width != 2)
return ERR_PTR(-EINVAL);
tse_pcs = devm_kzalloc(&ndev->dev, sizeof(*tse_pcs), GFP_KERNEL);
if (!tse_pcs)
return ERR_PTR(-ENOMEM);
tse_pcs->pcs.ops = &alt_tse_pcs_ops;
tse_pcs->base = pcs_base;
tse_pcs->reg_width = reg_width;
return &tse_pcs->pcs;
}
EXPORT_SYMBOL_GPL(alt_tse_pcs_create);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Altera TSE PCS driver");
MODULE_AUTHOR("Maxime Chevallier <maxime.chevallier@bootlin.com>");
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2022 Bootlin
*
* Maxime Chevallier <maxime.chevallier@bootlin.com>
*/
#ifndef __LINUX_PCS_ALTERA_TSE_H
#define __LINUX_PCS_ALTERA_TSE_H
struct phylink_pcs;
struct net_device;
struct phylink_pcs *alt_tse_pcs_create(struct net_device *ndev,
void __iomem *pcs_base, int reg_width);
#endif /* __LINUX_PCS_ALTERA_TSE_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment