Merge branch 'add-support-for-open-alliance-10base-t1x-macphy-serial-interface'

Parthiban Veerasooran says:

====================
Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface

This patch series contain the below updates,

- Adds support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface
  in the net/ethernet/oa_tc6.c.

  Link to the spec:
  -----------------
  https://opensig.org/download/document/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf

- Adds driver support for Microchip LAN8650/1 Rev.B1 10BASE-T1S MACPHY
  Ethernet driver in the net/ethernet/microchip/lan865x/lan865x.c.

  Link to the product:
  --------------------
  https://www.microchip.com/en-us/product/lan8650

Testing Details:
----------------
The driver performance was tested using iperf3 in the below two setups
separately.

Setup 1:
--------
Node 0 - Raspberry Pi 4 with LAN8650 MAC-PHY
Node 1 - Raspberry Pi 4 with EVB-LAN8670-USB USB Stick

Setup 2:
--------
Node 0 - SAMA7G54-EK with LAN8650 MAC-PHY
Node 1 - Raspberry Pi 4 with EVB-LAN8670-USB USB Stick

Achieved maximum of 9.4 Mbps.

Some systems like Raspberry Pi 4 need performance mode enabled to get the
proper clock speed for SPI. Refer below link for more details.

https://github.com/raspberrypi/linux/issues/3381#issuecomment-1144723750
====================

Link: https://patch.msgid.link/20240909082514.262942-1-Parthiban.Veerasooran@microchip.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-09-11 20:54:36 -07:00
commit 3cfb5aa10c
15 changed files with 2471 additions and 0 deletions

View File

@ -0,0 +1,74 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/microchip,lan8650.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip LAN8650/1 10BASE-T1S MACPHY Ethernet Controllers
maintainers:
- Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
description:
The LAN8650/1 combines a Media Access Controller (MAC) and an Ethernet
PHY to enable 10BASET1S networks. The Ethernet Media Access Controller
(MAC) module implements a 10 Mbps half duplex Ethernet MAC, compatible
with the IEEE 802.3 standard and a 10BASE-T1S physical layer transceiver
integrated into the LAN8650/1. The communication between the Host and
the MAC-PHY is specified in the OPEN Alliance 10BASE-T1x MACPHY Serial
Interface (TC6).
allOf:
- $ref: /schemas/net/ethernet-controller.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
oneOf:
- const: microchip,lan8650
- items:
- const: microchip,lan8651
- const: microchip,lan8650
reg:
maxItems: 1
interrupts:
description:
Interrupt from MAC-PHY asserted in the event of Receive Chunks
Available, Transmit Chunk Credits Available and Extended Status
Event.
maxItems: 1
spi-max-frequency:
minimum: 15000000
maximum: 25000000
required:
- compatible
- reg
- interrupts
- spi-max-frequency
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
ethernet@0 {
compatible = "microchip,lan8651", "microchip,lan8650";
reg = <0>;
pinctrl-names = "default";
pinctrl-0 = <&eth0_pins>;
interrupt-parent = <&gpio>;
interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
local-mac-address = [04 05 06 01 02 03];
spi-max-frequency = <15000000>;
};
};

View File

@ -88,6 +88,7 @@ Contents:
nexthop-group-resilient
nf_conntrack-sysctl
nf_flowtable
oa-tc6-framework
openvswitch
operstates
packet_mmap

View File

@ -0,0 +1,497 @@
.. SPDX-License-Identifier: GPL-2.0+
=========================================================================
OPEN Alliance 10BASE-T1x MAC-PHY Serial Interface (TC6) Framework Support
=========================================================================
Introduction
------------
The IEEE 802.3cg project defines two 10 Mbit/s PHYs operating over a
single pair of conductors. The 10BASE-T1L (Clause 146) is a long reach
PHY supporting full duplex point-to-point operation over 1 km of single
balanced pair of conductors. The 10BASE-T1S (Clause 147) is a short reach
PHY supporting full / half duplex point-to-point operation over 15 m of
single balanced pair of conductors, or half duplex multidrop bus
operation over 25 m of single balanced pair of conductors.
Furthermore, the IEEE 802.3cg project defines the new Physical Layer
Collision Avoidance (PLCA) Reconciliation Sublayer (Clause 148) meant to
provide improved determinism to the CSMA/CD media access method. PLCA
works in conjunction with the 10BASE-T1S PHY operating in multidrop mode.
The aforementioned PHYs are intended to cover the low-speed / low-cost
applications in industrial and automotive environment. The large number
of pins (16) required by the MII interface, which is specified by the
IEEE 802.3 in Clause 22, is one of the major cost factors that need to be
addressed to fulfil this objective.
The MAC-PHY solution integrates an IEEE Clause 4 MAC and a 10BASE-T1x PHY
exposing a low pin count Serial Peripheral Interface (SPI) to the host
microcontroller. This also enables the addition of Ethernet functionality
to existing low-end microcontrollers which do not integrate a MAC
controller.
Overview
--------
The MAC-PHY is specified to carry both data (Ethernet frames) and control
(register access) transactions over a single full-duplex serial peripheral
interface.
Protocol Overview
-----------------
Two types of transactions are defined in the protocol: data transactions
for Ethernet frame transfers and control transactions for register
read/write transfers. A chunk is the basic element of data transactions
and is composed of 4 bytes of overhead plus 64 bytes of payload size for
each chunk. Ethernet frames are transferred over one or more data chunks.
Control transactions consist of one or more register read/write control
commands.
SPI transactions are initiated by the SPI host with the assertion of CSn
low to the MAC-PHY and ends with the deassertion of CSn high. In between
each SPI transaction, the SPI host may need time for additional
processing and to setup the next SPI data or control transaction.
SPI data transactions consist of an equal number of transmit (TX) and
receive (RX) chunks. Chunks in both transmit and receive directions may
or may not contain valid frame data independent from each other, allowing
for the simultaneous transmission and reception of different length
frames.
Each transmit data chunk begins with a 32-bit data header followed by a
data chunk payload on MOSI. The data header indicates whether transmit
frame data is present and provides the information to determine which
bytes of the payload contain valid frame data.
In parallel, receive data chunks are received on MISO. Each receive data
chunk consists of a data chunk payload ending with a 32-bit data footer.
The data footer indicates if there is receive frame data present within
the payload or not and provides the information to determine which bytes
of the payload contain valid frame data.
Reference
---------
10BASE-T1x MAC-PHY Serial Interface Specification,
Link: https://opensig.org/download/document/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf
Hardware Architecture
---------------------
.. code-block:: none
+----------+ +-------------------------------------+
| | | MAC-PHY |
| |<---->| +-----------+ +-------+ +-------+ |
| SPI Host | | | SPI Slave | | MAC | | PHY | |
| | | +-----------+ +-------+ +-------+ |
+----------+ +-------------------------------------+
Software Architecture
---------------------
.. code-block:: none
+----------------------------------------------------------+
| Networking Subsystem |
+----------------------------------------------------------+
/ \ / \
| |
| |
\ / |
+----------------------+ +-----------------------------+
| MAC Driver |<--->| OPEN Alliance TC6 Framework |
+----------------------+ +-----------------------------+
/ \ / \
| |
| |
| \ /
+----------------------------------------------------------+
| SPI Subsystem |
+----------------------------------------------------------+
/ \
|
|
\ /
+----------------------------------------------------------+
| 10BASE-T1x MAC-PHY Device |
+----------------------------------------------------------+
Implementation
--------------
MAC Driver
~~~~~~~~~~
- Probed by SPI subsystem.
- Initializes OA TC6 framework for the MAC-PHY.
- Registers and configures the network device.
- Sends the tx ethernet frames from n/w subsystem to OA TC6 framework.
OPEN Alliance TC6 Framework
~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Initializes PHYLIB interface.
- Registers mac-phy interrupt.
- Performs mac-phy register read/write operation using the control
transaction protocol specified in the OPEN Alliance 10BASE-T1x MAC-PHY
Serial Interface specification.
- Performs Ethernet frames transaction using the data transaction protocol
for Ethernet frames specified in the OPEN Alliance 10BASE-T1x MAC-PHY
Serial Interface specification.
- Forwards the received Ethernet frame from 10Base-T1x MAC-PHY to n/w
subsystem.
Data Transaction
~~~~~~~~~~~~~~~~
The Ethernet frames that are typically transferred from the SPI host to
the MAC-PHY will be converted into multiple transmit data chunks. Each
transmit data chunk will have a 4 bytes header which contains the
information needed to determine the validity and the location of the
transmit frame data within the 64 bytes data chunk payload.
.. code-block:: none
+---------------------------------------------------+
| Tx Chunk |
| +---------------------------+ +----------------+ | MOSI
| | 64 bytes chunk payload | | 4 bytes header | |------------>
| +---------------------------+ +----------------+ |
+---------------------------------------------------+
4 bytes header contains the below fields,
DNC (Bit 31) - Data-Not-Control flag. This flag specifies the type of SPI
transaction. For TX data chunks, this bit shall be 1.
0 - Control command
1 - Data chunk
SEQ (Bit 30) - Data Chunk Sequence. This bit is used to indicate an
even/odd transmit data chunk sequence to the MAC-PHY.
NORX (Bit 29) - No Receive flag. The SPI host may set this bit to prevent
the MAC-PHY from conveying RX data on the MISO for the
current chunk (DV = 0 in the footer), indicating that the
host would not process it. Typically, the SPI host should
set NORX = 0 indicating that it will accept and process
any receive frame data within the current chunk.
RSVD (Bit 28..24) - Reserved: All reserved bits shall be 0.
VS (Bit 23..22) - Vendor Specific. These bits are implementation specific.
If the MAC-PHY does not implement these bits, the host
shall set them to 0.
DV (Bit 21) - Data Valid flag. The SPI host uses this bit to indicate
whether the current chunk contains valid transmit frame data
(DV = 1) or not (DV = 0). When 0, the MAC-PHY ignores the
chunk payload. Note that the receive path is unaffected by
the setting of the DV bit in the data header.
SV (Bit 20) - Start Valid flag. The SPI host shall set this bit when the
beginning of an Ethernet frame is present in the current
transmit data chunk payload. Otherwise, this bit shall be
zero. This bit is not to be confused with the Start-of-Frame
Delimiter (SFD) byte described in IEEE 802.3 [2].
SWO (Bit 19..16) - Start Word Offset. When SV = 1, this field shall
contain the 32-bit word offset into the transmit data
chunk payload that points to the start of a new
Ethernet frame to be transmitted. The host shall write
this field as zero when SV = 0.
RSVD (Bit 15) - Reserved: All reserved bits shall be 0.
EV (Bit 14) - End Valid flag. The SPI host shall set this bit when the end
of an Ethernet frame is present in the current transmit data
chunk payload. Otherwise, this bit shall be zero.
EBO (Bit 13..8) - End Byte Offset. When EV = 1, this field shall contain
the byte offset into the transmit data chunk payload
that points to the last byte of the Ethernet frame to
transmit. This field shall be zero when EV = 0.
TSC (Bit 7..6) - Timestamp Capture. Request a timestamp capture when the
frame is transmitted onto the network.
00 - Do not capture a timestamp
01 - Capture timestamp into timestamp capture register A
10 - Capture timestamp into timestamp capture register B
11 - Capture timestamp into timestamp capture register C
RSVD (Bit 5..1) - Reserved: All reserved bits shall be 0.
P (Bit 0) - Parity. Parity bit calculated over the transmit data header.
Method used is odd parity.
The number of buffers available in the MAC-PHY to store the incoming
transmit data chunk payloads is represented as transmit credits. The
available transmit credits in the MAC-PHY can be read either from the
Buffer Status Register or footer (Refer below for the footer info)
received from the MAC-PHY. The SPI host should not write more data chunks
than the available transmit credits as this will lead to transmit buffer
overflow error.
In case the previous data footer had no transmit credits available and
once the transmit credits become available for transmitting transmit data
chunks, the MAC-PHY interrupt is asserted to SPI host. On reception of the
first data header this interrupt will be deasserted and the received
footer for the first data chunk will have the transmit credits available
information.
The Ethernet frames that are typically transferred from MAC-PHY to SPI
host will be sent as multiple receive data chunks. Each receive data
chunk will have 64 bytes of data chunk payload followed by 4 bytes footer
which contains the information needed to determine the validity and the
location of the receive frame data within the 64 bytes data chunk payload.
.. code-block:: none
+---------------------------------------------------+
| Rx Chunk |
| +----------------+ +---------------------------+ | MISO
| | 4 bytes footer | | 64 bytes chunk payload | |------------>
| +----------------+ +---------------------------+ |
+---------------------------------------------------+
4 bytes footer contains the below fields,
EXST (Bit 31) - Extended Status. This bit is set when any bit in the
STATUS0 or STATUS1 registers are set and not masked.
HDRB (Bit 30) - Received Header Bad. When set, indicates that the MAC-PHY
received a control or data header with a parity error.
SYNC (Bit 29) - Configuration Synchronized flag. This bit reflects the
state of the SYNC bit in the CONFIG0 configuration
register (see Table 12). A zero indicates that the MAC-PHY
configuration may not be as expected by the SPI host.
Following configuration, the SPI host sets the
corresponding bitin the configuration register which is
reflected in this field.
RCA (Bit 28..24) - Receive Chunks Available. The RCA field indicates to
the SPI host the minimum number of additional receive
data chunks of frame data that are available for
reading beyond the current receive data chunk. This
field is zero when there is no receive frame data
pending in the MAC-PHYs buffer for reading.
VS (Bit 23..22) - Vendor Specific. These bits are implementation specific.
If not implemented, the MAC-PHY shall set these bits to
0.
DV (Bit 21) - Data Valid flag. The MAC-PHY uses this bit to indicate
whether the current receive data chunk contains valid
receive frame data (DV = 1) or not (DV = 0). When 0, the
SPI host shall ignore the chunk payload.
SV (Bit 20) - Start Valid flag. The MAC-PHY sets this bit when the current
chunk payload contains the start of an Ethernet frame.
Otherwise, this bit is zero. The SV bit is not to be
confused with the Start-of-Frame Delimiter (SFD) byte
described in IEEE 802.3 [2].
SWO (Bit 19..16) - Start Word Offset. When SV = 1, this field contains the
32-bit word offset into the receive data chunk payload
containing the first byte of a new received Ethernet
frame. When a receive timestamp has been added to the
beginning of the received Ethernet frame (RTSA = 1)
then SWO points to the most significant byte of the
timestamp. This field will be zero when SV = 0.
FD (Bit 15) - Frame Drop. When set, this bit indicates that the MAC has
detected a condition for which the SPI host should drop the
received Ethernet frame. This bit is only valid at the end
of a received Ethernet frame (EV = 1) and shall be zero at
all other times.
EV (Bit 14) - End Valid flag. The MAC-PHY sets this bit when the end of a
received Ethernet frame is present in this receive data
chunk payload.
EBO (Bit 13..8) - End Byte Offset: When EV = 1, this field contains the
byte offset into the receive data chunk payload that
locates the last byte of the received Ethernet frame.
This field is zero when EV = 0.
RTSA (Bit 7) - Receive Timestamp Added. This bit is set when a 32-bit or
64-bit timestamp has been added to the beginning of the
received Ethernet frame. The MAC-PHY shall set this bit to
zero when SV = 0.
RTSP (Bit 6) - Receive Timestamp Parity. Parity bit calculated over the
32-bit/64-bit timestamp added to the beginning of the
received Ethernet frame. Method used is odd parity. The
MAC-PHY shall set this bit to zero when RTSA = 0.
TXC (Bit 5..1) - Transmit Credits. This field contains the minimum number
of transmit data chunks of frame data that the SPI host
can write in a single transaction without incurring a
transmit buffer overflow error.
P (Bit 0) - Parity. Parity bit calculated over the receive data footer.
Method used is odd parity.
SPI host will initiate the data receive transaction based on the receive
chunks available in the MAC-PHY which is provided in the receive chunk
footer (RCA - Receive Chunks Available). SPI host will create data invalid
transmit data chunks (empty chunks) or data valid transmit data chunks in
case there are valid Ethernet frames to transmit to the MAC-PHY. The
receive chunks available in MAC-PHY can be read either from the Buffer
Status Register or footer.
In case the previous data footer had no receive data chunks available and
once the receive data chunks become available again for reading, the
MAC-PHY interrupt is asserted to SPI host. On reception of the first data
header this interrupt will be deasserted and the received footer for the
first data chunk will have the receive chunks available information.
MAC-PHY Interrupt
~~~~~~~~~~~~~~~~~
The MAC-PHY interrupt is asserted when the following conditions are met.
Receive chunks available - This interrupt is asserted when the previous
data footer had no receive data chunks available and once the receive
data chunks become available for reading. On reception of the first data
header this interrupt will be deasserted.
Transmit chunk credits available - This interrupt is asserted when the
previous data footer indicated no transmit credits available and once the
transmit credits become available for transmitting transmit data chunks.
On reception of the first data header this interrupt will be deasserted.
Extended status event - This interrupt is asserted when the previous data
footer indicated no extended status and once the extended event become
available. In this case the host should read status #0 register to know
the corresponding error/event. On reception of the first data header this
interrupt will be deasserted.
Control Transaction
~~~~~~~~~~~~~~~~~~~
4 bytes control header contains the below fields,
DNC (Bit 31) - Data-Not-Control flag. This flag specifies the type of SPI
transaction. For control commands, this bit shall be 0.
0 - Control command
1 - Data chunk
HDRB (Bit 30) - Received Header Bad. When set by the MAC-PHY, indicates
that a header was received with a parity error. The SPI
host should always clear this bit. The MAC-PHY ignores the
HDRB value sent by the SPI host on MOSI.
WNR (Bit 29) - Write-Not-Read. This bit indicates if data is to be written
to registers (when set) or read from registers
(when clear).
AID (Bit 28) - Address Increment Disable. When clear, the address will be
automatically post-incremented by one following each
register read or write. When set, address auto increment is
disabled allowing successive reads and writes to occur at
the same register address.
MMS (Bit 27..24) - Memory Map Selector. This field selects the specific
register memory map to access.
ADDR (Bit 23..8) - Address. Address of the first register within the
selected memory map to access.
LEN (Bit 7..1) - Length. Specifies the number of registers to read/write.
This field is interpreted as the number of registers
minus 1 allowing for up to 128 consecutive registers read
or written starting at the address specified in ADDR. A
length of zero shall read or write a single register.
P (Bit 0) - Parity. Parity bit calculated over the control command header.
Method used is odd parity.
Control transactions consist of one or more control commands. Control
commands are used by the SPI host to read and write registers within the
MAC-PHY. Each control commands are composed of a 4 bytes control command
header followed by register write data in case of control write command.
The MAC-PHY ignores the final 4 bytes of data from the SPI host at the end
of the control write command. The control write command is also echoed
from the MAC-PHY back to the SPI host to identify which register write
failed in case of any bus errors. The echoed Control write command will
have the first 4 bytes unused value to be ignored by the SPI host
followed by 4 bytes echoed control header followed by echoed register
write data. Control write commands can write either a single register or
multiple consecutive registers. When multiple consecutive registers are
written, the address is automatically post-incremented by the MAC-PHY.
Writing to any unimplemented or undefined registers shall be ignored and
yield no effect.
The MAC-PHY ignores all data from the SPI host following the control
header for the remainder of the control read command. The control read
command is also echoed from the MAC-PHY back to the SPI host to identify
which register read is failed in case of any bus errors. The echoed
Control read command will have the first 4 bytes of unused value to be
ignored by the SPI host followed by 4 bytes echoed control header followed
by register read data. Control read commands can read either a single
register or multiple consecutive registers. When multiple consecutive
registers are read, the address is automatically post-incremented by the
MAC-PHY. Reading any unimplemented or undefined registers shall return
zero.
Device drivers API
==================
The include/linux/oa_tc6.h defines the following functions:
.. c:function:: struct oa_tc6 *oa_tc6_init(struct spi_device *spi, \
struct net_device *netdev)
Initialize OA TC6 lib.
.. c:function:: void oa_tc6_exit(struct oa_tc6 *tc6)
Free allocated OA TC6 lib.
.. c:function:: int oa_tc6_write_register(struct oa_tc6 *tc6, u32 address, \
u32 value)
Write a single register in the MAC-PHY.
.. c:function:: int oa_tc6_write_registers(struct oa_tc6 *tc6, u32 address, \
u32 value[], u8 length)
Writing multiple consecutive registers starting from @address in the MAC-PHY.
Maximum of 128 consecutive registers can be written starting at @address.
.. c:function:: int oa_tc6_read_register(struct oa_tc6 *tc6, u32 address, \
u32 *value)
Read a single register in the MAC-PHY.
.. c:function:: int oa_tc6_read_registers(struct oa_tc6 *tc6, u32 address, \
u32 value[], u8 length)
Reading multiple consecutive registers starting from @address in the MAC-PHY.
Maximum of 128 consecutive registers can be read starting at @address.
.. c:function:: netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, \
struct sk_buff *skb);
The transmit Ethernet frame in the skb is or going to be transmitted through
the MAC-PHY.
.. c:function:: int oa_tc6_zero_align_receive_frame_enable(struct oa_tc6 *tc6);
Zero align receive frame feature can be enabled to align all receive ethernet
frames data to start at the beginning of any receive data chunk payload with a
start word offset (SWO) of zero.

View File

@ -14980,6 +14980,13 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/microchip/lan743x_*
MICROCHIP LAN8650/1 10BASE-T1S MACPHY ETHERNET DRIVER
M: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/microchip,lan8650.yaml
F: drivers/net/ethernet/microchip/lan865x/lan865x.c
MICROCHIP LAN87xx/LAN937x T1 PHY DRIVER
M: Arun Ramadoss <arun.ramadoss@microchip.com>
R: UNGLinuxDriver@microchip.com
@ -17113,6 +17120,14 @@ L: linux-rdma@vger.kernel.org
S: Supported
F: drivers/infiniband/ulp/opa_vnic
OPEN ALLIANCE 10BASE-T1S MACPHY SERIAL INTERFACE FRAMEWORK
M: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/networking/oa-tc6-framework.rst
F: drivers/include/linux/oa_tc6.h
F: drivers/net/ethernet/oa_tc6.c
OPEN FIRMWARE AND FLATTENED DEVICE TREE
M: Rob Herring <robh@kernel.org>
M: Saravana Kannan <saravanak@google.com>

View File

@ -158,6 +158,17 @@ config ETHOC
help
Say Y here if you want to use the OpenCores 10/100 Mbps Ethernet MAC.
config OA_TC6
tristate "OPEN Alliance TC6 10BASE-T1x MAC-PHY support"
depends on SPI
select PHYLIB
help
This library implements OPEN Alliance TC6 10BASE-T1x MAC-PHY
Serial Interface protocol for supporting 10BASE-T1x MAC-PHYs.
To know the implementation details, refer documentation in
<file:Documentation/networking/oa-tc6-framework.rst>.
source "drivers/net/ethernet/packetengines/Kconfig"
source "drivers/net/ethernet/pasemi/Kconfig"
source "drivers/net/ethernet/pensando/Kconfig"

View File

@ -105,3 +105,4 @@ obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/
obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/
obj-$(CONFIG_OA_TC6) += oa_tc6.o

View File

@ -57,6 +57,7 @@ config LAN743X
To compile this driver as a module, choose M here. The module will be
called lan743x.
source "drivers/net/ethernet/microchip/lan865x/Kconfig"
source "drivers/net/ethernet/microchip/lan966x/Kconfig"
source "drivers/net/ethernet/microchip/sparx5/Kconfig"
source "drivers/net/ethernet/microchip/vcap/Kconfig"

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_LAN743X) += lan743x.o
lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o
obj-$(CONFIG_LAN865X) += lan865x/
obj-$(CONFIG_LAN966X_SWITCH) += lan966x/
obj-$(CONFIG_SPARX5_SWITCH) += sparx5/
obj-$(CONFIG_VCAP) += vcap/

View File

@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Microchip LAN865x Driver Support
#
if NET_VENDOR_MICROCHIP
config LAN865X
tristate "LAN865x support"
depends on SPI
select OA_TC6
help
Support for the Microchip LAN8650/1 Rev.B0/B1 MACPHY Ethernet chip. It
uses OPEN Alliance 10BASE-T1x Serial Interface specification.
To compile this driver as a module, choose M here. The module will be
called lan865x.
endif # NET_VENDOR_MICROCHIP

View File

@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the Microchip LAN865x Driver
#
obj-$(CONFIG_LAN865X) += lan865x.o

View File

@ -0,0 +1,429 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Microchip's LAN865x 10BASE-T1S MAC-PHY driver
*
* Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/phy.h>
#include <linux/oa_tc6.h>
#define DRV_NAME "lan8650"
/* MAC Network Control Register */
#define LAN865X_REG_MAC_NET_CTL 0x00010000
#define MAC_NET_CTL_TXEN BIT(3) /* Transmit Enable */
#define MAC_NET_CTL_RXEN BIT(2) /* Receive Enable */
/* MAC Network Configuration Reg */
#define LAN865X_REG_MAC_NET_CFG 0x00010001
#define MAC_NET_CFG_PROMISCUOUS_MODE BIT(4)
#define MAC_NET_CFG_MULTICAST_MODE BIT(6)
#define MAC_NET_CFG_UNICAST_MODE BIT(7)
/* MAC Hash Register Bottom */
#define LAN865X_REG_MAC_L_HASH 0x00010020
/* MAC Hash Register Top */
#define LAN865X_REG_MAC_H_HASH 0x00010021
/* MAC Specific Addr 1 Bottom Reg */
#define LAN865X_REG_MAC_L_SADDR1 0x00010022
/* MAC Specific Addr 1 Top Reg */
#define LAN865X_REG_MAC_H_SADDR1 0x00010023
struct lan865x_priv {
struct work_struct multicast_work;
struct net_device *netdev;
struct spi_device *spi;
struct oa_tc6 *tc6;
};
static int lan865x_set_hw_macaddr_low_bytes(struct oa_tc6 *tc6, const u8 *mac)
{
u32 regval;
regval = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0];
return oa_tc6_write_register(tc6, LAN865X_REG_MAC_L_SADDR1, regval);
}
static int lan865x_set_hw_macaddr(struct lan865x_priv *priv, const u8 *mac)
{
int restore_ret;
u32 regval;
int ret;
/* Configure MAC address low bytes */
ret = lan865x_set_hw_macaddr_low_bytes(priv->tc6, mac);
if (ret)
return ret;
/* Prepare and configure MAC address high bytes */
regval = (mac[5] << 8) | mac[4];
ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_H_SADDR1,
regval);
if (!ret)
return 0;
/* Restore the old MAC address low bytes from netdev if the new MAC
* address high bytes setting failed.
*/
restore_ret = lan865x_set_hw_macaddr_low_bytes(priv->tc6,
priv->netdev->dev_addr);
if (restore_ret)
return restore_ret;
return ret;
}
static const struct ethtool_ops lan865x_ethtool_ops = {
.get_link_ksettings = phy_ethtool_get_link_ksettings,
.set_link_ksettings = phy_ethtool_set_link_ksettings,
};
static int lan865x_set_mac_address(struct net_device *netdev, void *addr)
{
struct lan865x_priv *priv = netdev_priv(netdev);
struct sockaddr *address = addr;
int ret;
ret = eth_prepare_mac_addr_change(netdev, addr);
if (ret < 0)
return ret;
if (ether_addr_equal(address->sa_data, netdev->dev_addr))
return 0;
ret = lan865x_set_hw_macaddr(priv, address->sa_data);
if (ret)
return ret;
eth_commit_mac_addr_change(netdev, addr);
return 0;
}
static u32 get_address_bit(u8 addr[ETH_ALEN], u32 bit)
{
return ((addr[bit / 8]) >> (bit % 8)) & 1;
}
static u32 lan865x_hash(u8 addr[ETH_ALEN])
{
u32 hash_index = 0;
for (int i = 0; i < 6; i++) {
u32 hash = 0;
for (int j = 0; j < 8; j++)
hash ^= get_address_bit(addr, (j * 6) + i);
hash_index |= (hash << i);
}
return hash_index;
}
static int lan865x_set_specific_multicast_addr(struct lan865x_priv *priv)
{
struct netdev_hw_addr *ha;
u32 hash_lo = 0;
u32 hash_hi = 0;
int ret;
netdev_for_each_mc_addr(ha, priv->netdev) {
u32 bit_num = lan865x_hash(ha->addr);
if (bit_num >= BIT(5))
hash_hi |= (1 << (bit_num - BIT(5)));
else
hash_lo |= (1 << bit_num);
}
/* Enabling specific multicast addresses */
ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_H_HASH, hash_hi);
if (ret) {
netdev_err(priv->netdev, "Failed to write reg_hashh: %d\n",
ret);
return ret;
}
ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_L_HASH, hash_lo);
if (ret)
netdev_err(priv->netdev, "Failed to write reg_hashl: %d\n",
ret);
return ret;
}
static int lan865x_set_all_multicast_addr(struct lan865x_priv *priv)
{
int ret;
/* Enabling all multicast addresses */
ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_H_HASH,
0xffffffff);
if (ret) {
netdev_err(priv->netdev, "Failed to write reg_hashh: %d\n",
ret);
return ret;
}
ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_L_HASH,
0xffffffff);
if (ret)
netdev_err(priv->netdev, "Failed to write reg_hashl: %d\n",
ret);
return ret;
}
static int lan865x_clear_all_multicast_addr(struct lan865x_priv *priv)
{
int ret;
ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_H_HASH, 0);
if (ret) {
netdev_err(priv->netdev, "Failed to write reg_hashh: %d\n",
ret);
return ret;
}
ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_L_HASH, 0);
if (ret)
netdev_err(priv->netdev, "Failed to write reg_hashl: %d\n",
ret);
return ret;
}
static void lan865x_multicast_work_handler(struct work_struct *work)
{
struct lan865x_priv *priv = container_of(work, struct lan865x_priv,
multicast_work);
u32 regval = 0;
int ret;
if (priv->netdev->flags & IFF_PROMISC) {
/* Enabling promiscuous mode */
regval |= MAC_NET_CFG_PROMISCUOUS_MODE;
regval &= (~MAC_NET_CFG_MULTICAST_MODE);
regval &= (~MAC_NET_CFG_UNICAST_MODE);
} else if (priv->netdev->flags & IFF_ALLMULTI) {
/* Enabling all multicast mode */
if (lan865x_set_all_multicast_addr(priv))
return;
regval &= (~MAC_NET_CFG_PROMISCUOUS_MODE);
regval |= MAC_NET_CFG_MULTICAST_MODE;
regval &= (~MAC_NET_CFG_UNICAST_MODE);
} else if (!netdev_mc_empty(priv->netdev)) {
/* Enabling specific multicast mode */
if (lan865x_set_specific_multicast_addr(priv))
return;
regval &= (~MAC_NET_CFG_PROMISCUOUS_MODE);
regval |= MAC_NET_CFG_MULTICAST_MODE;
regval &= (~MAC_NET_CFG_UNICAST_MODE);
} else {
/* Enabling local mac address only */
if (lan865x_clear_all_multicast_addr(priv))
return;
}
ret = oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_NET_CFG, regval);
if (ret)
netdev_err(priv->netdev, "Failed to enable promiscuous/multicast/normal mode: %d\n",
ret);
}
static void lan865x_set_multicast_list(struct net_device *netdev)
{
struct lan865x_priv *priv = netdev_priv(netdev);
schedule_work(&priv->multicast_work);
}
static netdev_tx_t lan865x_send_packet(struct sk_buff *skb,
struct net_device *netdev)
{
struct lan865x_priv *priv = netdev_priv(netdev);
return oa_tc6_start_xmit(priv->tc6, skb);
}
static int lan865x_hw_disable(struct lan865x_priv *priv)
{
u32 regval;
if (oa_tc6_read_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, &regval))
return -ENODEV;
regval &= ~(MAC_NET_CTL_TXEN | MAC_NET_CTL_RXEN);
if (oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, regval))
return -ENODEV;
return 0;
}
static int lan865x_net_close(struct net_device *netdev)
{
struct lan865x_priv *priv = netdev_priv(netdev);
int ret;
netif_stop_queue(netdev);
phy_stop(netdev->phydev);
ret = lan865x_hw_disable(priv);
if (ret) {
netdev_err(netdev, "Failed to disable the hardware: %d\n", ret);
return ret;
}
return 0;
}
static int lan865x_hw_enable(struct lan865x_priv *priv)
{
u32 regval;
if (oa_tc6_read_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, &regval))
return -ENODEV;
regval |= MAC_NET_CTL_TXEN | MAC_NET_CTL_RXEN;
if (oa_tc6_write_register(priv->tc6, LAN865X_REG_MAC_NET_CTL, regval))
return -ENODEV;
return 0;
}
static int lan865x_net_open(struct net_device *netdev)
{
struct lan865x_priv *priv = netdev_priv(netdev);
int ret;
ret = lan865x_hw_enable(priv);
if (ret) {
netdev_err(netdev, "Failed to enable hardware: %d\n", ret);
return ret;
}
phy_start(netdev->phydev);
return 0;
}
static const struct net_device_ops lan865x_netdev_ops = {
.ndo_open = lan865x_net_open,
.ndo_stop = lan865x_net_close,
.ndo_start_xmit = lan865x_send_packet,
.ndo_set_rx_mode = lan865x_set_multicast_list,
.ndo_set_mac_address = lan865x_set_mac_address,
};
static int lan865x_probe(struct spi_device *spi)
{
struct net_device *netdev;
struct lan865x_priv *priv;
int ret;
netdev = alloc_etherdev(sizeof(struct lan865x_priv));
if (!netdev)
return -ENOMEM;
priv = netdev_priv(netdev);
priv->netdev = netdev;
priv->spi = spi;
spi_set_drvdata(spi, priv);
INIT_WORK(&priv->multicast_work, lan865x_multicast_work_handler);
priv->tc6 = oa_tc6_init(spi, netdev);
if (!priv->tc6) {
ret = -ENODEV;
goto free_netdev;
}
/* As per the point s3 in the below errata, SPI receive Ethernet frame
* transfer may halt when starting the next frame in the same data block
* (chunk) as the end of a previous frame. The RFA field should be
* configured to 01b or 10b for proper operation. In these modes, only
* one receive Ethernet frame will be placed in a single data block.
* When the RFA field is written to 01b, received frames will be forced
* to only start in the first word of the data block payload (SWO=0). As
* recommended, enable zero align receive frame feature for proper
* operation.
*
* https://ww1.microchip.com/downloads/aemDocuments/documents/AIS/ProductDocuments/Errata/LAN8650-1-Errata-80001075.pdf
*/
ret = oa_tc6_zero_align_receive_frame_enable(priv->tc6);
if (ret) {
dev_err(&spi->dev, "Failed to set ZARFE: %d\n", ret);
goto oa_tc6_exit;
}
/* Get the MAC address from the SPI device tree node */
if (device_get_ethdev_address(&spi->dev, netdev))
eth_hw_addr_random(netdev);
ret = lan865x_set_hw_macaddr(priv, netdev->dev_addr);
if (ret) {
dev_err(&spi->dev, "Failed to configure MAC: %d\n", ret);
goto oa_tc6_exit;
}
netdev->if_port = IF_PORT_10BASET;
netdev->irq = spi->irq;
netdev->netdev_ops = &lan865x_netdev_ops;
netdev->ethtool_ops = &lan865x_ethtool_ops;
ret = register_netdev(netdev);
if (ret) {
dev_err(&spi->dev, "Register netdev failed (ret = %d)", ret);
goto oa_tc6_exit;
}
return 0;
oa_tc6_exit:
oa_tc6_exit(priv->tc6);
free_netdev:
free_netdev(priv->netdev);
return ret;
}
static void lan865x_remove(struct spi_device *spi)
{
struct lan865x_priv *priv = spi_get_drvdata(spi);
cancel_work_sync(&priv->multicast_work);
unregister_netdev(priv->netdev);
oa_tc6_exit(priv->tc6);
free_netdev(priv->netdev);
}
static const struct spi_device_id spidev_spi_ids[] = {
{ .name = "lan8650" },
{},
};
static const struct of_device_id lan865x_dt_ids[] = {
{ .compatible = "microchip,lan8650" },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, lan865x_dt_ids);
static struct spi_driver lan865x_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = lan865x_dt_ids,
},
.probe = lan865x_probe,
.remove = lan865x_remove,
.id_table = spidev_spi_ids,
};
module_spi_driver(lan865x_driver);
MODULE_DESCRIPTION(DRV_NAME " 10Base-T1S MACPHY Ethernet Driver");
MODULE_AUTHOR("Parthiban Veerasooran <parthiban.veerasooran@microchip.com>");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@ -268,6 +268,34 @@ static int lan86xx_read_status(struct phy_device *phydev)
return 0;
}
/* OPEN Alliance 10BASE-T1x compliance MAC-PHYs will have both C22 and
* C45 registers space. If the PHY is discovered via C22 bus protocol it assumes
* it uses C22 protocol and always uses C22 registers indirect access to access
* C45 registers. This is because, we don't have a clean separation between
* C22/C45 register space and C22/C45 MDIO bus protocols. Resulting, PHY C45
* registers direct access can't be used which can save multiple SPI bus access.
* To support this feature, set .read_mmd/.write_mmd in the PHY driver to call
* .read_c45/.write_c45 in the OPEN Alliance framework
* drivers/net/ethernet/oa_tc6.c
*/
static int lan865x_phy_read_mmd(struct phy_device *phydev, int devnum,
u16 regnum)
{
struct mii_bus *bus = phydev->mdio.bus;
int addr = phydev->mdio.addr;
return __mdiobus_c45_read(bus, addr, devnum, regnum);
}
static int lan865x_phy_write_mmd(struct phy_device *phydev, int devnum,
u16 regnum, u16 val)
{
struct mii_bus *bus = phydev->mdio.bus;
int addr = phydev->mdio.addr;
return __mdiobus_c45_write(bus, addr, devnum, regnum, val);
}
static struct phy_driver microchip_t1s_driver[] = {
{
PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1),
@ -285,6 +313,8 @@ static struct phy_driver microchip_t1s_driver[] = {
.features = PHY_BASIC_T1S_P2MP_FEATURES,
.config_init = lan865x_revb0_config_init,
.read_status = lan86xx_read_status,
.read_mmd = lan865x_phy_read_mmd,
.write_mmd = lan865x_phy_write_mmd,
.get_plca_cfg = genphy_c45_plca_get_cfg,
.set_plca_cfg = genphy_c45_plca_set_cfg,
.get_plca_status = genphy_c45_plca_get_status,

24
include/linux/oa_tc6.h Normal file
View File

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* OPEN Alliance 10BASET1x MACPHY Serial Interface framework
*
* Link: https://opensig.org/download/document/OPEN_Alliance_10BASET1x_MAC-PHY_Serial_Interface_V1.1.pdf
*
* Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
*/
#include <linux/etherdevice.h>
#include <linux/spi/spi.h>
struct oa_tc6;
struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev);
void oa_tc6_exit(struct oa_tc6 *tc6);
int oa_tc6_write_register(struct oa_tc6 *tc6, u32 address, u32 value);
int oa_tc6_write_registers(struct oa_tc6 *tc6, u32 address, u32 value[],
u8 length);
int oa_tc6_read_register(struct oa_tc6 *tc6, u32 address, u32 *value);
int oa_tc6_read_registers(struct oa_tc6 *tc6, u32 address, u32 value[],
u8 length);
netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb);
int oa_tc6_zero_align_receive_frame_enable(struct oa_tc6 *tc6);

View File

@ -23,6 +23,7 @@
#define MDIO_MMD_DTEXS 5 /* DTE Extender Sublayer */
#define MDIO_MMD_TC 6 /* Transmission Convergence */
#define MDIO_MMD_AN 7 /* Auto-Negotiation */
#define MDIO_MMD_POWER_UNIT 13 /* PHY Power Unit */
#define MDIO_MMD_C22EXT 29 /* Clause 22 extension */
#define MDIO_MMD_VEND1 30 /* Vendor specific 1 */
#define MDIO_MMD_VEND2 31 /* Vendor specific 2 */