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
Changes:
v2:
- Removed RFC tag.
- OA TC6 framework configured in the Kconfig and Makefile to compile as a
module.
- Kerneldoc headers added for all the API methods exposed to MAC driver.
- Odd parity calculation logic updated from the below link,
https://elixir.bootlin.com/linux/latest/source/lib/bch.c#L348
- Control buffer memory allocation moved to the initial function.
- struct oa_tc6 implemented as an obaque structure.
- Removed kthread for handling mac-phy interrupt instead threaded irq is
used.
- Removed interrupt implementation for soft reset handling instead of
that polling has been implemented.
- Registers name in the defines changed according to the specification
document.
- Registers defines are arranged in the order of offset and followed by
register fields.
- oa_tc6_write_register() implemented for writing a single register and
oa_tc6_write_registers() implemented for writing multiple registers.
- oa_tc6_read_register() implemented for reading a single register and
oa_tc6_read_registers() implemented for reading multiple registers.
- Removed DRV_VERSION macro as git hash provided by ethtool.
- Moved MDIO bus registration and PHY initialization to the OA TC6 lib.
- Replaced lan865x_set/get_link_ksettings() functions with
phy_ethtool_ksettings_set/get() functions.
- MAC-PHY's standard capability register values checked against the
user configured values.
- Removed unnecessary parameters validity check in various places.
- Removed MAC address configuration in the lan865x_net_open() function as
it is done in the lan865x_probe() function already.
- Moved standard registers and proprietary vendor registers to the
respective files.
- Added proper subject prefixes for the DT bindings.
- Moved OA specific properties to a separate DT bindings and corrected the
types & mistakes in the DT bindings.
- Inherited OA specific DT bindings to the LAN865x specific DT bindings.
- Removed sparse warnings in all the places.
- Used net_err_ratelimited() for printing the error messages.
- oa_tc6_process_rx_chunks() function and the content of oa_tc6_handler()
function are split into small functions.
- Used proper macros provided by network layer for calculating the
MAX_ETH_LEN.
- Return value of netif_rx() function handled properly.
- Removed unnecessary NULL initialization of skb in the
oa_tc6_rx_eth_ready() function removed.
- Local variables declaration ordered in reverse xmas tree notation.
v3:
- Completely redesigned all the patches.
- Control and data interface patches are divided into multiple small
patches.
- Device driver APIs added in the oa-tc6-framework.rst file.
- Code readability improved in all the patches.
- Defined macros wherever is possible.
- Changed RESETC to STATUS0_RESETC for improving the readability.
- Removed OA specific DT bindings.
- Used default configurations defined in the OA spec.
- All variables are named properly as per OA spec for more redability.
- Bigger functions are split into multiple smaller functions.
- DT binding check is done.
- Phy mask is removed in phy scanning.
- Used NET_RX_DROP to compare the rx packet submission status.
- Indentation in the Kconfig file corrected.
- Removed CONFIG_OF and CONFIG_ACPI ifdefs.
- Removed MODULE_ALIAS().
v4:
- Fixed indentation in oa-tc6-framework.rst file.
- Replaced ENODEV error code with EPROTO in the
oa_tc6_check_ctrl_write_reply and oa_tc6_check_ctrl_read_reply()
functions.
- Renamed oa_tc6_read_sw_reset_status() function as
oa_tc6_read_status0().
- Changed software reset polling delay as 1ms and polling timeout as 1s.
- Implemented clause 45 registers direct access.
- Replaced ENODEV error code with ENOMEM in the
oa_tc6_mdiobus_register() function.
- Changed transmit skbs queue size as 2.
- Added skb_linearize() function to convert contiguous packet data.
- Checked kthread_should_stop() in the oa_tc6_spi_thread_handler()
function before proceeding for the oa_tc6_try_spi_transfer().
- Removed netdev_err() print in the oa_tc6_allocate_rx_skb() function.
- Added spi-peripheral-props reference in the dt-bindings.
- Changed the fallback order in the dt-bindings.
- Replaced netif_start_queue() with netif_wake_queue().
- Empty data transfer performed in the oa_tc6_init() function to clear
the reset complete interrupt.
- ZARFE bit in the CONFIG0 register is set to 1 to avoid lan865x halt
based on the recommendation in the lan865x errata.
v5:
- Added base commit info in the cover letter.
- Fixed all the warnings reported in the oa-tc6-framework.rst file.
- Fixed kernel-doc reported warnings.
- Fixed reverse christmas tree notation.
- Printed error code in case STATUS0 register read is failed.
- Removed C29 support in the PHY initialization.
- Returned the same error code from the function instead of replacing
with another error code.
- Used netdev_alloc_skb_ip_align() to allocate receive skb buffer.
- Enabling zero align receive frame feature moved to OA TC6 framework
as a helper function for vendor specific drivers.
- Replaced eth_hw_addr_set() with eth_commit_mac_addr_change() as it is
a better pair for eth_prepare_mac_addr_change().
- Fixed device tree binding issues in the driver and documentation.
- Fixed multicast addresses hash value calculation.
Parthiban Veerasooran (14):
Documentation: networking: add OPEN Alliance 10BASE-T1x MAC-PHY serial
interface
net: ethernet: oa_tc6: implement register write operation
net: ethernet: oa_tc6: implement register read operation
net: ethernet: oa_tc6: implement software reset
net: ethernet: oa_tc6: implement error interrupts unmasking
net: ethernet: oa_tc6: implement internal PHY initialization
net: phy: microchip_t1s: add c45 direct access in LAN865x internal PHY
net: ethernet: oa_tc6: enable open alliance tc6 data communication
net: ethernet: oa_tc6: implement transmit path to transfer tx ethernet
frames
net: ethernet: oa_tc6: implement receive path to receive rx ethernet
frames
net: ethernet: oa_tc6: implement mac-phy interrupt
net: ethernet: oa_tc6: add helper function to enable zero align rx
frame
microchip: lan865x: add driver support for Microchip's LAN865X MAC-PHY
dt-bindings: net: add Microchip's LAN865X 10BASE-T1S MACPHY
.../bindings/net/microchip,lan8650.yaml | 80 +
Documentation/networking/index.rst | 1 +
Documentation/networking/oa-tc6-framework.rst | 497 ++++++
MAINTAINERS | 15 +
drivers/net/ethernet/Kconfig | 11 +
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/microchip/Kconfig | 1 +
drivers/net/ethernet/microchip/Makefile | 1 +
.../net/ethernet/microchip/lan865x/Kconfig | 19 +
.../net/ethernet/microchip/lan865x/Makefile | 6 +
.../net/ethernet/microchip/lan865x/lan865x.c | 391 +++++
drivers/net/ethernet/oa_tc6.c | 1363 +++++++++++++++++
drivers/net/phy/microchip_t1s.c | 30 +
include/linux/oa_tc6.h | 24 +
include/uapi/linux/mdio.h | 1 +
15 files changed, 2441 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/microchip,lan8650.yaml
create mode 100644 Documentation/networking/oa-tc6-framework.rst
create mode 100644 drivers/net/ethernet/microchip/lan865x/Kconfig
create mode 100644 drivers/net/ethernet/microchip/lan865x/Makefile
create mode 100644 drivers/net/ethernet/microchip/lan865x/lan865x.c
create mode 100644 drivers/net/ethernet/oa_tc6.c
create mode 100644 include/linux/oa_tc6.h
base-commit: 1722389b0d863056d78287a120a1d6cadb8d4f7b
--
2.34.1
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.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
Documentation/networking/index.rst | 1 +
Documentation/networking/oa-tc6-framework.rst | 497 ++++++++++++++++++
MAINTAINERS | 6 +
3 files changed, 504 insertions(+)
create mode 100644 Documentation/networking/oa-tc6-framework.rst
@@ -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-PHY’s 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.
Implement register write operation according to the control communication
specified in the OPEN Alliance 10BASE-T1x MACPHY Serial Interface
document. Control write commands are used by the SPI host to write
registers within the MAC-PHY. Each control write commands are composed of
a 32 bits control command header followed by register write data.
The MAC-PHY ignores the final 32 bits of data from the SPI host at the
end of the control write command. The write command and data is also
echoed from the MAC-PHY back to the SPI host to enable the SPI host to
identify which register write failed in the case of any bus errors.
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.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
MAINTAINERS | 2 +
drivers/net/ethernet/Kconfig | 11 ++
drivers/net/ethernet/Makefile | 1 +
drivers/net/ethernet/oa_tc6.c | 242 ++++++++++++++++++++++++++++++++++
include/linux/oa_tc6.h | 17 +++
5 files changed, 273 insertions(+)
create mode 100644 drivers/net/ethernet/oa_tc6.c
create mode 100644 include/linux/oa_tc6.h
@@ -0,0 +1,242 @@+// SPDX-License-Identifier: GPL-2.0++/*+*OPENAlliance10BASE‑T1xMAC‑PHYSerialInterfaceframework+*+*Author:ParthibanVeerasooran<parthiban.veerasooran@microchip.com>+*/++#include<linux/bitfield.h>+#include<linux/oa_tc6.h>++/* Control command header */+#define OA_TC6_CTRL_HEADER_DATA_NOT_CTRL BIT(31)+#define OA_TC6_CTRL_HEADER_WRITE_NOT_READ BIT(29)+#define OA_TC6_CTRL_HEADER_MEM_MAP_SELECTOR GENMASK(27, 24)+#define OA_TC6_CTRL_HEADER_ADDR GENMASK(23, 8)+#define OA_TC6_CTRL_HEADER_LENGTH GENMASK(7, 1)+#define OA_TC6_CTRL_HEADER_PARITY BIT(0)++#define OA_TC6_CTRL_HEADER_SIZE 4+#define OA_TC6_CTRL_REG_VALUE_SIZE 4+#define OA_TC6_CTRL_IGNORED_SIZE 4+#define OA_TC6_CTRL_MAX_REGISTERS 128+#define OA_TC6_CTRL_SPI_BUF_SIZE (OA_TC6_CTRL_HEADER_SIZE +\+(OA_TC6_CTRL_MAX_REGISTERS*\+OA_TC6_CTRL_REG_VALUE_SIZE)+\+OA_TC6_CTRL_IGNORED_SIZE)++/* Internal structure for MAC-PHY drivers */+structoa_tc6{+structspi_device*spi;+structmutexspi_ctrl_lock;/* Protects spi control transfer */+void*spi_ctrl_tx_buf;+void*spi_ctrl_rx_buf;+};++enumoa_tc6_header_type{+OA_TC6_CTRL_HEADER,+};++enumoa_tc6_register_op{+OA_TC6_CTRL_REG_WRITE=1,+};++staticintoa_tc6_spi_transfer(structoa_tc6*tc6,+enumoa_tc6_header_typeheader_type,u16length)+{+structspi_transferxfer={0};+structspi_messagemsg;++xfer.tx_buf=tc6->spi_ctrl_tx_buf;+xfer.rx_buf=tc6->spi_ctrl_rx_buf;+xfer.len=length;++spi_message_init(&msg);+spi_message_add_tail(&xfer,&msg);++returnspi_sync(tc6->spi,&msg);+}++staticintoa_tc6_get_parity(u32p)+{+/* Public domain code snippet, lifted from+*http://www-graphics.stanford.edu/~seander/bithacks.html+*/+p^=p>>1;+p^=p>>2;+p=(p&0x11111111U)*0x11111111U;++/* Odd parity is used here */+return!((p>>28)&1);+}++static__be32oa_tc6_prepare_ctrl_header(u32addr,u8length,+enumoa_tc6_register_opreg_op)+{+u32header;++header=FIELD_PREP(OA_TC6_CTRL_HEADER_DATA_NOT_CTRL,+OA_TC6_CTRL_HEADER)|+FIELD_PREP(OA_TC6_CTRL_HEADER_WRITE_NOT_READ,reg_op)|+FIELD_PREP(OA_TC6_CTRL_HEADER_MEM_MAP_SELECTOR,addr>>16)|+FIELD_PREP(OA_TC6_CTRL_HEADER_ADDR,addr)|+FIELD_PREP(OA_TC6_CTRL_HEADER_LENGTH,length-1);+header|=FIELD_PREP(OA_TC6_CTRL_HEADER_PARITY,+oa_tc6_get_parity(header));++returncpu_to_be32(header);+}++staticvoidoa_tc6_update_ctrl_write_data(structoa_tc6*tc6,u32value[],+u8length)+{+__be32*tx_buf=tc6->spi_ctrl_tx_buf+OA_TC6_CTRL_HEADER_SIZE;++for(inti=0;i<length;i++)+*tx_buf++=cpu_to_be32(value[i]);+}++staticu16oa_tc6_calculate_ctrl_buf_size(u8length)+{+/* Control command consists 4 bytes header + 4 bytes register value for+*eachregister+4bytesignoredvalue.+*/+returnOA_TC6_CTRL_HEADER_SIZE+OA_TC6_CTRL_REG_VALUE_SIZE*length++OA_TC6_CTRL_IGNORED_SIZE;+}++staticvoidoa_tc6_prepare_ctrl_spi_buf(structoa_tc6*tc6,u32address,+u32value[],u8length,+enumoa_tc6_register_opreg_op)+{+__be32*tx_buf=tc6->spi_ctrl_tx_buf;++*tx_buf=oa_tc6_prepare_ctrl_header(address,length,reg_op);++oa_tc6_update_ctrl_write_data(tc6,value,length);+}++staticintoa_tc6_check_ctrl_write_reply(structoa_tc6*tc6,u8size)+{+u8*tx_buf=tc6->spi_ctrl_tx_buf;+u8*rx_buf=tc6->spi_ctrl_rx_buf;++rx_buf+=OA_TC6_CTRL_IGNORED_SIZE;++/* The echoed control write must match with the one that was+*transmitted.+*/+if(memcmp(tx_buf,rx_buf,size-OA_TC6_CTRL_IGNORED_SIZE))+return-EPROTO;++return0;+}++staticintoa_tc6_perform_ctrl(structoa_tc6*tc6,u32address,u32value[],+u8length,enumoa_tc6_register_opreg_op)+{+u16size;+intret;++/* Prepare control command and copy to SPI control buffer */+oa_tc6_prepare_ctrl_spi_buf(tc6,address,value,length,reg_op);++size=oa_tc6_calculate_ctrl_buf_size(length);++/* Perform SPI transfer */+ret=oa_tc6_spi_transfer(tc6,OA_TC6_CTRL_HEADER,size);+if(ret){+dev_err(&tc6->spi->dev,"SPI transfer failed for control: %d\n",+ret);+returnret;+}++/* Check echoed/received control write command reply for errors */+returnoa_tc6_check_ctrl_write_reply(tc6,size);+}++/**+*oa_tc6_write_registers-functionforwritingmultipleconsecutiveregisters.+*@tc6:oa_tc6struct.+*@address:addressofthefirstregistertobewrittenintheMAC-PHY.+*@value:valuestobewrittenfromthestartingregisteraddress@address.+*@length:numberofconsecutiveregisterstobewrittenfrom@address.+*+*Maximumof128consecutiveregisterscanbewrittenstartingat@address.+*+*Return:0onsuccessotherwisefailed.+*/+intoa_tc6_write_registers(structoa_tc6*tc6,u32address,u32value[],+u8length)+{+intret;++if(!length||length>OA_TC6_CTRL_MAX_REGISTERS){+dev_err(&tc6->spi->dev,"Invalid register length parameter\n");+return-EINVAL;+}++mutex_lock(&tc6->spi_ctrl_lock);+ret=oa_tc6_perform_ctrl(tc6,address,value,length,+OA_TC6_CTRL_REG_WRITE);+mutex_unlock(&tc6->spi_ctrl_lock);++returnret;+}+EXPORT_SYMBOL_GPL(oa_tc6_write_registers);++/**+*oa_tc6_write_register-functionforwritingaMAC-PHYregister.+*@tc6:oa_tc6struct.+*@address:registeraddressoftheMAC-PHYtobewritten.+*@value:valuetobewritteninthe@addressregisteraddressoftheMAC-PHY.+*+*Return:0onsuccessotherwisefailed.+*/+intoa_tc6_write_register(structoa_tc6*tc6,u32address,u32value)+{+returnoa_tc6_write_registers(tc6,address,&value,1);+}+EXPORT_SYMBOL_GPL(oa_tc6_write_register);++/**+*oa_tc6_init-allocatesandinitializesoa_tc6structure.+*@spi:devicewithwhichdatawillbeexchanged.+*+*Return:pointerreferencetotheoa_tc6structureiftheMAC-PHY+*initializationissuccessfulotherwiseNULL.+*/+structoa_tc6*oa_tc6_init(structspi_device*spi)+{+structoa_tc6*tc6;++tc6=devm_kzalloc(&spi->dev,sizeof(*tc6),GFP_KERNEL);+if(!tc6)+returnNULL;++tc6->spi=spi;+mutex_init(&tc6->spi_ctrl_lock);++/* Set the SPI controller to pump at realtime priority */+tc6->spi->rt=true;+spi_setup(tc6->spi);++tc6->spi_ctrl_tx_buf=devm_kzalloc(&tc6->spi->dev,+OA_TC6_CTRL_SPI_BUF_SIZE,+GFP_KERNEL);+if(!tc6->spi_ctrl_tx_buf)+returnNULL;++tc6->spi_ctrl_rx_buf=devm_kzalloc(&tc6->spi->dev,+OA_TC6_CTRL_SPI_BUF_SIZE,+GFP_KERNEL);+if(!tc6->spi_ctrl_rx_buf)+returnNULL;++returntc6;+}+EXPORT_SYMBOL_GPL(oa_tc6_init);++MODULE_DESCRIPTION("OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface Lib");+MODULE_AUTHOR("Parthiban Veerasooran <parthiban.veerasooran@microchip.com>");+MODULE_LICENSE("GPL");
Implement register read operation according to the control communication
specified in the OPEN Alliance 10BASE-T1x MACPHY Serial Interface
document. Control read commands are used by the SPI host to read
registers within the MAC-PHY. Each control read commands are composed of
a 32 bits control command header.
The MAC-PHY ignores all data from the SPI host following the control
header for the remainder of the control read command. 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.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
drivers/net/ethernet/oa_tc6.c | 84 ++++++++++++++++++++++++++++++++++-
include/linux/oa_tc6.h | 3 ++
2 files changed, 85 insertions(+), 2 deletions(-)
@@ -132,6 +134,30 @@ static int oa_tc6_check_ctrl_write_reply(struct oa_tc6 *tc6, u8 size)return0;}+staticintoa_tc6_check_ctrl_read_reply(structoa_tc6*tc6,u8size)+{+u32*rx_buf=tc6->spi_ctrl_rx_buf+OA_TC6_CTRL_IGNORED_SIZE;+u32*tx_buf=tc6->spi_ctrl_tx_buf;++/* The echoed control read header must match with the one that was+*transmitted.+*/+if(*tx_buf!=*rx_buf)+return-EPROTO;++return0;+}++staticvoidoa_tc6_copy_ctrl_read_data(structoa_tc6*tc6,u32value[],+u8length)+{+__be32*rx_buf=tc6->spi_ctrl_rx_buf+OA_TC6_CTRL_IGNORED_SIZE++OA_TC6_CTRL_HEADER_SIZE;++for(inti=0;i<length;i++)+value[i]=be32_to_cpu(*rx_buf++);+}+staticintoa_tc6_perform_ctrl(structoa_tc6*tc6,u32address,u32value[],u8length,enumoa_tc6_register_opreg_op){
@@ -152,8 +178,62 @@ static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 address, u32 value[],}/* Check echoed/received control write command reply for errors */-returnoa_tc6_check_ctrl_write_reply(tc6,size);+if(reg_op==OA_TC6_CTRL_REG_WRITE)+returnoa_tc6_check_ctrl_write_reply(tc6,size);++/* Check echoed/received control read command reply for errors */+ret=oa_tc6_check_ctrl_read_reply(tc6,size);+if(ret)+returnret;++oa_tc6_copy_ctrl_read_data(tc6,value,length);++return0;+}++/**+*oa_tc6_read_registers-functionforreadingmultipleconsecutiveregisters.+*@tc6:oa_tc6struct.+*@address:addressofthefirstregistertobereadintheMAC-PHY.+*@value:valuestobereadfromthestartingregisteraddress@address.+*@length:numberofconsecutiveregisterstobereadfrom@address.+*+*Maximumof128consecutiveregisterscanbereadstartingat@address.+*+*Return:0onsuccessotherwisefailed.+*/+intoa_tc6_read_registers(structoa_tc6*tc6,u32address,u32value[],+u8length)+{+intret;++if(!length||length>OA_TC6_CTRL_MAX_REGISTERS){+dev_err(&tc6->spi->dev,"Invalid register length parameter\n");+return-EINVAL;+}++mutex_lock(&tc6->spi_ctrl_lock);+ret=oa_tc6_perform_ctrl(tc6,address,value,length,+OA_TC6_CTRL_REG_READ);+mutex_unlock(&tc6->spi_ctrl_lock);++returnret;+}+EXPORT_SYMBOL_GPL(oa_tc6_read_registers);++/**+*oa_tc6_read_register-functionforreadingaMAC-PHYregister.+*@tc6:oa_tc6struct.+*@address:registeraddressoftheMAC-PHYtoberead.+*@value:valuereadfromthe@addressregisteraddressoftheMAC-PHY.+*+*Return:0onsuccessotherwisefailed.+*/+intoa_tc6_read_register(structoa_tc6*tc6,u32address,u32*value)+{+returnoa_tc6_read_registers(tc6,address,value,1);}+EXPORT_SYMBOL_GPL(oa_tc6_read_register);/***oa_tc6_write_registers-functionforwritingmultipleconsecutiveregisters.
This will unmask the following error interrupts from the MAC-PHY.
tx protocol error
rx buffer overflow error
loss of framing error
header error
The MAC-PHY will signal an error by setting the EXST bit in the receive
data footer which will then allow the host to read the STATUS0 register
to find the source of the error.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
drivers/net/ethernet/oa_tc6.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
Reset complete bit is set when the MAC-PHY reset completes and ready for
configuration. Additionally reset complete bit in the STS0 register has
to be written by one upon reset complete to clear the interrupt.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
drivers/net/ethernet/oa_tc6.c | 56 +++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
@@ -279,6 +291,42 @@ int oa_tc6_write_register(struct oa_tc6 *tc6, u32 address, u32 value)}EXPORT_SYMBOL_GPL(oa_tc6_write_register);+staticintoa_tc6_read_status0(structoa_tc6*tc6)+{+u32regval;+intret;++ret=oa_tc6_read_register(tc6,OA_TC6_REG_STATUS0,®val);+if(ret){+dev_err(&tc6->spi->dev,"STATUS0 register read failed: %d\n",+ret);+return0;+}++returnregval;+}++staticintoa_tc6_sw_reset_macphy(structoa_tc6*tc6)+{+u32regval=RESET_SWRESET;+intret;++ret=oa_tc6_write_register(tc6,OA_TC6_REG_RESET,regval);+if(ret)+returnret;++/* Poll for soft reset complete for every 1ms until 1s timeout */+ret=readx_poll_timeout(oa_tc6_read_status0,tc6,regval,+regval&STATUS0_RESETC,+STATUS0_RESETC_POLL_DELAY,+STATUS0_RESETC_POLL_TIMEOUT);+if(ret)+return-ENODEV;++/* Clear the reset complete status */+returnoa_tc6_write_register(tc6,OA_TC6_REG_STATUS0,regval);+}+/***oa_tc6_init-allocatesandinitializesoa_tc6structure.*@spi:devicewithwhichdatawillbeexchanged.
Internal PHY is initialized as per the PHY register capability supported
by the MAC-PHY. Direct PHY Register Access Capability indicates if PHY
registers are directly accessible within the SPI register memory space.
Indirect PHY Register Access Capability indicates if PHY registers are
indirectly accessible through the MDIO/MDC registers MDIOACCn defined in
OPEN Alliance specification. Currently the direct register access is only
supported.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
drivers/net/ethernet/oa_tc6.c | 230 +++++++++++++++++++++++++++++++++-
include/linux/oa_tc6.h | 4 +-
include/uapi/linux/mdio.h | 1 +
3 files changed, 233 insertions(+), 2 deletions(-)
@@ -46,6 +65,10 @@/* Internal structure for MAC-PHY drivers */structoa_tc6{+structdevice*dev;+structnet_device*netdev;+structphy_device*phydev;+structmii_bus*mdiobus;structspi_device*spi;structmutexspi_ctrl_lock;/* Protects spi control transfer */void*spi_ctrl_tx_buf;
@@ -298,6 +321,191 @@ int oa_tc6_write_register(struct oa_tc6 *tc6, u32 address, u32 value)}EXPORT_SYMBOL_GPL(oa_tc6_write_register);+staticintoa_tc6_check_phy_reg_direct_access_capability(structoa_tc6*tc6)+{+u32regval;+intret;++ret=oa_tc6_read_register(tc6,OA_TC6_REG_STDCAP,®val);+if(ret)+returnret;++if(!(regval&STDCAP_DIRECT_PHY_REG_ACCESS))+return-ENODEV;++return0;+}++staticvoidoa_tc6_handle_link_change(structnet_device*netdev)+{+phy_print_status(netdev->phydev);+}++staticintoa_tc6_mdiobus_read(structmii_bus*bus,intaddr,intregnum)+{+structoa_tc6*tc6=bus->priv;+u32regval;+boolret;++ret=oa_tc6_read_register(tc6,OA_TC6_PHY_STD_REG_ADDR_BASE|+(regnum&OA_TC6_PHY_STD_REG_ADDR_MASK),+®val);+if(ret)+returnret;++returnregval;+}++staticintoa_tc6_mdiobus_write(structmii_bus*bus,intaddr,intregnum,+u16val)+{+structoa_tc6*tc6=bus->priv;++returnoa_tc6_write_register(tc6,OA_TC6_PHY_STD_REG_ADDR_BASE|+(regnum&OA_TC6_PHY_STD_REG_ADDR_MASK),+val);+}++staticintoa_tc6_get_phy_c45_mms(intdevnum)+{+switch(devnum){+caseMDIO_MMD_PCS:+returnOA_TC6_PHY_C45_PCS_MMS2;+caseMDIO_MMD_PMAPMD:+returnOA_TC6_PHY_C45_PMA_PMD_MMS3;+caseMDIO_MMD_VEND2:+returnOA_TC6_PHY_C45_VS_PLCA_MMS4;+caseMDIO_MMD_AN:+returnOA_TC6_PHY_C45_AUTO_NEG_MMS5;+caseMDIO_MMD_POWER_UNIT:+returnOA_TC6_PHY_C45_POWER_UNIT_MMS6;+default:+return-EOPNOTSUPP;+}+}++staticintoa_tc6_mdiobus_read_c45(structmii_bus*bus,intaddr,intdevnum,+intregnum)+{+structoa_tc6*tc6=bus->priv;+u32regval;+intret;++ret=oa_tc6_get_phy_c45_mms(devnum);+if(ret<0)+returnret;++ret=oa_tc6_read_register(tc6,(ret<<16)|regnum,®val);+if(ret)+returnret;++returnregval;+}++staticintoa_tc6_mdiobus_write_c45(structmii_bus*bus,intaddr,intdevnum,+intregnum,u16val)+{+structoa_tc6*tc6=bus->priv;+intret;++ret=oa_tc6_get_phy_c45_mms(devnum);+if(ret<0)+returnret;++returnoa_tc6_write_register(tc6,(ret<<16)|regnum,val);+}++staticintoa_tc6_mdiobus_register(structoa_tc6*tc6)+{+intret;++tc6->mdiobus=mdiobus_alloc();+if(!tc6->mdiobus){+netdev_err(tc6->netdev,"MDIO bus alloc failed\n");+return-ENOMEM;+}++tc6->mdiobus->priv=tc6;+tc6->mdiobus->read=oa_tc6_mdiobus_read;+tc6->mdiobus->write=oa_tc6_mdiobus_write;+/* OPEN Alliance 10BASE-T1x compliance MAC-PHYs will have both C22 and+*C45registersspace.IfthePHYisdiscoveredviaC22busprotocolit+*assumesitusesC22protocolandalwaysusesC22registersindirect+*accesstoaccessC45registers.Thisisbecause,wedon'thavea+*cleanseparationbetweenC22/C45registerspaceandC22/C45MDIObus+*protocols.Resulting,PHYC45registersdirectaccesscan'tbeused+*whichcansavemultipleSPIbusaccess.Tosupportthisfeature,PHY+*driverscanset.read_mmd/.write_mmdinthePHYdrivertocall+*.read_c45/.write_c45.Ex:drivers/net/phy/microchip_t1s.c+*/+tc6->mdiobus->read_c45=oa_tc6_mdiobus_read_c45;+tc6->mdiobus->write_c45=oa_tc6_mdiobus_write_c45;+tc6->mdiobus->name="oa-tc6-mdiobus";+tc6->mdiobus->parent=tc6->dev;++snprintf(tc6->mdiobus->id,ARRAY_SIZE(tc6->mdiobus->id),"%s",+dev_name(&tc6->spi->dev));++ret=mdiobus_register(tc6->mdiobus);+if(ret){+netdev_err(tc6->netdev,"Could not register MDIO bus\n");+mdiobus_free(tc6->mdiobus);+returnret;+}++return0;+}++staticvoidoa_tc6_mdiobus_unregister(structoa_tc6*tc6)+{+mdiobus_unregister(tc6->mdiobus);+mdiobus_free(tc6->mdiobus);+}++staticintoa_tc6_phy_init(structoa_tc6*tc6)+{+intret;++ret=oa_tc6_check_phy_reg_direct_access_capability(tc6);+if(ret){+netdev_err(tc6->netdev,+"Direct PHY register access is not supported by the MAC-PHY\n");+returnret;+}++ret=oa_tc6_mdiobus_register(tc6);+if(ret)+returnret;++tc6->phydev=phy_find_first(tc6->mdiobus);+if(!tc6->phydev){+netdev_err(tc6->netdev,"No PHY found\n");+oa_tc6_mdiobus_unregister(tc6);+return-ENODEV;+}++tc6->phydev->is_internal=true;+ret=phy_connect_direct(tc6->netdev,tc6->phydev,+&oa_tc6_handle_link_change,+PHY_INTERFACE_MODE_INTERNAL);+if(ret){+netdev_err(tc6->netdev,"Can't attach PHY to %s\n",+tc6->mdiobus->id);+oa_tc6_mdiobus_unregister(tc6);+returnret;+}++phy_attached_info(tc6->netdev->phydev);++return0;+}++staticvoidoa_tc6_phy_exit(structoa_tc6*tc6)+{+phy_disconnect(tc6->phydev);+oa_tc6_mdiobus_unregister(tc6);+}+staticintoa_tc6_read_status0(structoa_tc6*tc6){u32regval;
@@ -354,11 +562,12 @@ static int oa_tc6_unmask_macphy_error_interrupts(struct oa_tc6 *tc6)/***oa_tc6_init-allocatesandinitializesoa_tc6structure.*@spi:devicewithwhichdatawillbeexchanged.+*@netdev:networkdeviceinterfacestructure.**Return:pointerreferencetotheoa_tc6structureiftheMAC-PHY*initializationissuccessfulotherwiseNULL.*/-structoa_tc6*oa_tc6_init(structspi_device*spi)+structoa_tc6*oa_tc6_init(structspi_device*spi,structnet_device*netdev){structoa_tc6*tc6;intret;
@@ -368,6 +577,8 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi)returnNULL;tc6->spi=spi;+tc6->netdev=netdev;+SET_NETDEV_DEV(netdev,&spi->dev);mutex_init(&tc6->spi_ctrl_lock);/* Set the SPI controller to pump at realtime priority */
This patch adds c45 registers direct access support in Microchip's
LAN865x internal PHY.
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
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
drivers/net/phy/microchip_t1s.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
@@ -268,6 +268,34 @@ static int lan86xx_read_status(struct phy_device *phydev)return0;}+/* OPEN Alliance 10BASE-T1x compliance MAC-PHYs will have both C22 and+*C45registersspace.IfthePHYisdiscoveredviaC22busprotocolitassumes+*itusesC22protocolandalwaysusesC22registersindirectaccesstoaccess+*C45registers.Thisisbecause,wedon'thaveacleanseparationbetween+*C22/C45registerspaceandC22/C45MDIObusprotocols.Resulting,PHYC45+*registersdirectaccesscan'tbeusedwhichcansavemultipleSPIbusaccess.+*Tosupportthisfeature,set.read_mmd/.write_mmdinthePHYdrivertocall+*.read_c45/.write_c45intheOPENAllianceframework+*drivers/net/ethernet/oa_tc6.c+*/+staticintlan865x_phy_read_mmd(structphy_device*phydev,intdevnum,+u16regnum)+{+structmii_bus*bus=phydev->mdio.bus;+intaddr=phydev->mdio.addr;++return__mdiobus_c45_read(bus,addr,devnum,regnum);+}++staticintlan865x_phy_write_mmd(structphy_device*phydev,intdevnum,+u16regnum,u16val)+{+structmii_bus*bus=phydev->mdio.bus;+intaddr=phydev->mdio.addr;++return__mdiobus_c45_write(bus,addr,devnum,regnum,val);+}+staticstructphy_drivermicrochip_t1s_driver[]={{PHY_ID_MATCH_EXACT(PHY_ID_LAN867X_REVB1),
Enabling Configuration Synchronization bit (SYNC) in the Configuration
Register #0 enables data communication in the MAC-PHY. The state of this
bit is reflected in the data footer SYNC bit.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
drivers/net/ethernet/oa_tc6.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
@@ -559,6 +563,21 @@ static int oa_tc6_unmask_macphy_error_interrupts(struct oa_tc6 *tc6)returnoa_tc6_write_register(tc6,OA_TC6_REG_INT_MASK0,regval);}+staticintoa_tc6_enable_data_transfer(structoa_tc6*tc6)+{+u32value;+intret;++ret=oa_tc6_read_register(tc6,OA_TC6_REG_CONFIG0,&value);+if(ret)+returnret;++/* Enable configuration synchronization for data transfer */+value|=CONFIG0_SYNC;++returnoa_tc6_write_register(tc6,OA_TC6_REG_CONFIG0,value);+}+/***oa_tc6_init-allocatesandinitializesoa_tc6structure.*@spi:devicewithwhichdatawillbeexchanged.
@@ -618,7 +637,18 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)returnNULL;}+ret=oa_tc6_enable_data_transfer(tc6);+if(ret){+dev_err(&tc6->spi->dev,"Failed to enable data transfer: %d\n",+ret);+gotophy_exit;+}+returntc6;++phy_exit:+oa_tc6_phy_exit(tc6);+returnNULL;}EXPORT_SYMBOL_GPL(oa_tc6_init);
SPI rx data buffer can contain one or more receive data chunks. A receive
data chunk consists a 64 bytes receive data chunk payload followed a
4 bytes data footer at the end. The data footer contains the information
needed to determine the validity and location of the receive frame data
within the receive data chunk payload and the host can use these
information to generate ethernet frame. Initially the receive chunks
available will be updated from the buffer status register and then it
will be updated from the footer received on each spi data transfer. Tx
data valid or empty chunks equal to the number receive chunks available
will be transmitted in the MOSI to receive all the rx chunks.
Additionally the receive data footer contains the below information as
well. The received footer will be examined for the receive errors if any.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
drivers/net/ethernet/oa_tc6.c | 242 ++++++++++++++++++++++++++++++++--
1 file changed, 234 insertions(+), 8 deletions(-)
@@ -691,8 +718,11 @@ static int oa_tc6_process_rx_chunk_footer(struct oa_tc6 *tc6, u32 footer)/* Process rx chunk footer for the following,*1.txcredits*2.errorsifanyfromMAC-PHY+*3.receivechunksavailable*/tc6->tx_credits=FIELD_GET(OA_TC6_DATA_FOOTER_TX_CREDITS,footer);+tc6->rx_chunks_available=FIELD_GET(OA_TC6_DATA_FOOTER_RX_CHUNKS,+footer);if(FIELD_GET(OA_TC6_DATA_FOOTER_EXTENDED_STS,footer)){intret=oa_tc6_process_extended_status(tc6);
@@ -718,6 +748,142 @@ static int oa_tc6_process_rx_chunk_footer(struct oa_tc6 *tc6, u32 footer)return0;}+staticvoidoa_tc6_submit_rx_skb(structoa_tc6*tc6)+{+tc6->rx_skb->protocol=eth_type_trans(tc6->rx_skb,tc6->netdev);+tc6->netdev->stats.rx_packets++;+tc6->netdev->stats.rx_bytes+=tc6->rx_skb->len;++if(netif_rx(tc6->rx_skb)==NET_RX_DROP)+tc6->netdev->stats.rx_dropped++;++tc6->rx_skb=NULL;+}++staticvoidoa_tc6_update_rx_skb(structoa_tc6*tc6,u8*payload,u8length)+{+memcpy(skb_put(tc6->rx_skb,length),payload,length);+}++staticintoa_tc6_allocate_rx_skb(structoa_tc6*tc6)+{+tc6->rx_skb=netdev_alloc_skb_ip_align(tc6->netdev,tc6->netdev->mtu++ETH_HLEN+ETH_FCS_LEN);+if(!tc6->rx_skb){+tc6->netdev->stats.rx_dropped++;+return-ENOMEM;+}++return0;+}++staticintoa_tc6_prcs_complete_rx_frame(structoa_tc6*tc6,u8*payload,+u16size)+{+intret;++ret=oa_tc6_allocate_rx_skb(tc6);+if(ret)+returnret;++oa_tc6_update_rx_skb(tc6,payload,size);++oa_tc6_submit_rx_skb(tc6);++return0;+}++staticintoa_tc6_prcs_rx_frame_start(structoa_tc6*tc6,u8*payload,u16size)+{+intret;++ret=oa_tc6_allocate_rx_skb(tc6);+if(ret)+returnret;++oa_tc6_update_rx_skb(tc6,payload,size);++return0;+}++staticvoidoa_tc6_prcs_rx_frame_end(structoa_tc6*tc6,u8*payload,u16size)+{+oa_tc6_update_rx_skb(tc6,payload,size);++oa_tc6_submit_rx_skb(tc6);+}++staticvoidoa_tc6_prcs_ongoing_rx_frame(structoa_tc6*tc6,u8*payload,+u32footer)+{+oa_tc6_update_rx_skb(tc6,payload,OA_TC6_CHUNK_PAYLOAD_SIZE);+}++staticintoa_tc6_prcs_rx_chunk_payload(structoa_tc6*tc6,u8*data,+u32footer)+{+u8start_byte_offset=FIELD_GET(OA_TC6_DATA_FOOTER_START_WORD_OFFSET,+footer)*sizeof(u32);+u8end_byte_offset=FIELD_GET(OA_TC6_DATA_FOOTER_END_BYTE_OFFSET,+footer);+boolstart_valid=FIELD_GET(OA_TC6_DATA_FOOTER_START_VALID,footer);+boolend_valid=FIELD_GET(OA_TC6_DATA_FOOTER_END_VALID,footer);+u16size;++/* Restart the new rx frame after receiving rx buffer overflow error */+if(start_valid&&tc6->rx_buf_overflow)+tc6->rx_buf_overflow=false;++if(tc6->rx_buf_overflow)+return0;++/* Process the chunk with complete rx frame */+if(start_valid&&end_valid&&start_byte_offset<end_byte_offset){+size=end_byte_offset+1-start_byte_offset;+returnoa_tc6_prcs_complete_rx_frame(tc6,+&data[start_byte_offset],+size);+}++/* Process the chunk with only rx frame start */+if(start_valid&&!end_valid){+size=OA_TC6_CHUNK_PAYLOAD_SIZE-start_byte_offset;+returnoa_tc6_prcs_rx_frame_start(tc6,+&data[start_byte_offset],+size);+}++/* Process the chunk with only rx frame end */+if(end_valid&&!start_valid){+size=end_byte_offset+1;+oa_tc6_prcs_rx_frame_end(tc6,data,size);+return0;+}++/* Process the chunk with previous rx frame end and next rx frame+*start.+*/+if(start_valid&&end_valid&&start_byte_offset>end_byte_offset){+/* After rx buffer overflow error received, there might be a+*possibilityofgettinganendvalidofapreviously+*incompleterxframealongwiththenewrxframestartvalid.+*/+if(tc6->rx_skb){+size=end_byte_offset+1;+oa_tc6_prcs_rx_frame_end(tc6,data,size);+}+size=OA_TC6_CHUNK_PAYLOAD_SIZE-start_byte_offset;+returnoa_tc6_prcs_rx_frame_start(tc6,+&data[start_byte_offset],+size);+}++/* Process the chunk with ongoing rx frame data */+oa_tc6_prcs_ongoing_rx_frame(tc6,data,footer);++return0;+}+staticu32oa_tc6_get_rx_chunk_footer(structoa_tc6*tc6,u16footer_offset){u8*rx_buf=tc6->spi_data_rx_buf;
@@ -743,6 +909,20 @@ static int oa_tc6_process_spi_data_rx_buf(struct oa_tc6 *tc6, u16 length)ret=oa_tc6_process_rx_chunk_footer(tc6,footer);if(ret)returnret;++/* If there is a data valid chunks then process it for the+*informationneededtodeterminethevalidityandthelocation+*ofthereceiveframedata.+*/+if(FIELD_GET(OA_TC6_DATA_FOOTER_DATA_VALID,footer)){+u8*payload=tc6->spi_data_rx_buf+i*+OA_TC6_CHUNK_SIZE;++ret=oa_tc6_prcs_rx_chunk_payload(tc6,payload,+footer);+if(ret)+returnret;+}}return0;
@@ -833,31 +1013,74 @@ static u16 oa_tc6_prepare_spi_tx_buf_for_tx_skbs(struct oa_tc6 *tc6)returnused_tx_credits*OA_TC6_CHUNK_SIZE;}+staticvoidoa_tc6_add_empty_chunks_to_spi_buf(structoa_tc6*tc6,+u16needed_empty_chunks)+{+__be32header;++header=oa_tc6_prepare_data_header(OA_TC6_DATA_INVALID,+OA_TC6_DATA_START_INVALID,+OA_TC6_DATA_END_INVALID,0);++while(needed_empty_chunks--){+__be32*tx_buf=tc6->spi_data_tx_buf++tc6->spi_data_tx_buf_offset;++*tx_buf=header;+tc6->spi_data_tx_buf_offset+=OA_TC6_CHUNK_SIZE;+}+}++staticu16oa_tc6_prepare_spi_tx_buf_for_rx_chunks(structoa_tc6*tc6,u16len)+{+u16tx_chunks=len/OA_TC6_CHUNK_SIZE;+u16needed_empty_chunks;++/* If there are more chunks to receive than to transmit, we need to add+*enoughemptytxchunkstoallowthereceptionoftheexcessrx+*chunks.+*/+if(tx_chunks>=tc6->rx_chunks_available)+returnlen;++needed_empty_chunks=tc6->rx_chunks_available-tx_chunks;++oa_tc6_add_empty_chunks_to_spi_buf(tc6,needed_empty_chunks);++returnneeded_empty_chunks*OA_TC6_CHUNK_SIZE+len;+}+staticintoa_tc6_try_spi_transfer(structoa_tc6*tc6){intret;while(true){-u16spi_length=0;+u16spi_len=0;tc6->spi_data_tx_buf_offset=0;if(tc6->tx_skb||!skb_queue_empty(&tc6->tx_skb_q))-spi_length=oa_tc6_prepare_spi_tx_buf_for_tx_skbs(tc6);+spi_len=oa_tc6_prepare_spi_tx_buf_for_tx_skbs(tc6);-if(spi_length==0)+spi_len=oa_tc6_prepare_spi_tx_buf_for_rx_chunks(tc6,spi_len);++if(spi_len==0)break;-ret=oa_tc6_spi_transfer(tc6,OA_TC6_DATA_HEADER,spi_length);+ret=oa_tc6_spi_transfer(tc6,OA_TC6_DATA_HEADER,spi_len);if(ret){netdev_err(tc6->netdev,"SPI data transfer failed: %d\n",ret);returnret;}-ret=oa_tc6_process_spi_data_rx_buf(tc6,spi_length);+ret=oa_tc6_process_spi_data_rx_buf(tc6,spi_len);if(ret){+if(ret==-EAGAIN)+continue;+oa_tc6_cleanup_ongoing_tx_skb(tc6);+oa_tc6_cleanup_ongoing_rx_skb(tc6);netdev_err(tc6->netdev,"Device error: %d\n",ret);returnret;}
@@ -897,15 +1120,17 @@ static int oa_tc6_update_buffer_status_from_register(struct oa_tc6 *tc6)u32value;intret;-/* Initially tx credits to be updated from the register as there is no-*datatransferperformedyet.Lateritwillbeupdatedfromtherx-*footer.+/* Initially tx credits and rx chunks available to be updated from the+*registerasthereisnodatatransferperformedyet.Latertheywill+*beupdatedfromtherxfooter.*/ret=oa_tc6_read_register(tc6,OA_TC6_REG_BUFFER_STATUS,&value);if(ret)returnret;tc6->tx_credits=FIELD_GET(BUFFER_STATUS_TX_CREDITS_AVAILABLE,value);+tc6->rx_chunks_available=FIELD_GET(BUFFER_STATUS_RX_CHUNKS_AVAILABLE,+value);return0;}
The transmit ethernet frame will be converted into multiple transmit data
chunks. Each transmit data chunk consists of a 4 bytes header followed by
a 64 bytes transmit data chunk payload. The 4 bytes data header occurs at
the beginning of each transmit data chunk on MOSI. The data header
contains the information needed to determine the validity and location of
the transmit frame data within the data chunk payload. The number of
transmit data chunks transmitted to mac-phy is limited to the number
transmit credits available in the mac-phy. Initially the transmit credits
will be updated from the buffer status register and then it will be
updated from the footer received on each spi data transfer. The received
footer will be examined for the transmit errors if any.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
drivers/net/ethernet/oa_tc6.c | 401 +++++++++++++++++++++++++++++++++-
include/linux/oa_tc6.h | 1 +
2 files changed, 400 insertions(+), 2 deletions(-)
@@ -578,6 +638,309 @@ static int oa_tc6_enable_data_transfer(struct oa_tc6 *tc6)returnoa_tc6_write_register(tc6,OA_TC6_REG_CONFIG0,value);}+staticvoidoa_tc6_cleanup_ongoing_tx_skb(structoa_tc6*tc6)+{+if(tc6->tx_skb){+tc6->netdev->stats.tx_dropped++;+kfree_skb(tc6->tx_skb);+tc6->tx_skb=NULL;+}+}++staticintoa_tc6_process_extended_status(structoa_tc6*tc6)+{+u32value;+intret;++ret=oa_tc6_read_register(tc6,OA_TC6_REG_STATUS0,&value);+if(ret){+netdev_err(tc6->netdev,"STATUS0 register read failed: %d\n",+ret);+returnret;+}++/* Clear the error interrupts status */+ret=oa_tc6_write_register(tc6,OA_TC6_REG_STATUS0,value);+if(ret){+netdev_err(tc6->netdev,"STATUS0 register write failed: %d\n",+ret);+returnret;+}++if(FIELD_GET(STATUS0_TX_PROTOCOL_ERROR,value)){+netdev_err(tc6->netdev,"Transmit protocol error\n");+return-ENODEV;+}+/* TODO: Currently loss of frame and header errors are treated as+*non-recoverableerrors.Theywillbehandledinthenextversion.+*/+if(FIELD_GET(STATUS0_LOSS_OF_FRAME_ERROR,value)){+netdev_err(tc6->netdev,"Loss of frame error\n");+return-ENODEV;+}+if(FIELD_GET(STATUS0_HEADER_ERROR,value)){+netdev_err(tc6->netdev,"Header error\n");+return-ENODEV;+}++return0;+}++staticintoa_tc6_process_rx_chunk_footer(structoa_tc6*tc6,u32footer)+{+/* Process rx chunk footer for the following,+*1.txcredits+*2.errorsifanyfromMAC-PHY+*/+tc6->tx_credits=FIELD_GET(OA_TC6_DATA_FOOTER_TX_CREDITS,footer);++if(FIELD_GET(OA_TC6_DATA_FOOTER_EXTENDED_STS,footer)){+intret=oa_tc6_process_extended_status(tc6);++if(ret)+returnret;+}++/* TODO: Currently received header bad and configuration unsync errors+*aretreatedasnon-recoverableerrors.Theywillbehandledinthe+*nextversion.+*/+if(FIELD_GET(OA_TC6_DATA_FOOTER_RXD_HEADER_BAD,footer)){+netdev_err(tc6->netdev,"Rxd header bad error\n");+return-ENODEV;+}++if(!FIELD_GET(OA_TC6_DATA_FOOTER_CONFIG_SYNC,footer)){+netdev_err(tc6->netdev,"Config unsync error\n");+return-ENODEV;+}++return0;+}++staticu32oa_tc6_get_rx_chunk_footer(structoa_tc6*tc6,u16footer_offset)+{+u8*rx_buf=tc6->spi_data_rx_buf;+__be32footer;++footer=*((__be32*)&rx_buf[footer_offset]);++returnbe32_to_cpu(footer);+}++staticintoa_tc6_process_spi_data_rx_buf(structoa_tc6*tc6,u16length)+{+u16no_of_rx_chunks=length/OA_TC6_CHUNK_SIZE;+u32footer;+intret;++/* All the rx chunks in the receive SPI data buffer are examined here */+for(inti=0;i<no_of_rx_chunks;i++){+/* Last 4 bytes in each received chunk consist footer info */+footer=oa_tc6_get_rx_chunk_footer(tc6,i*OA_TC6_CHUNK_SIZE++OA_TC6_CHUNK_PAYLOAD_SIZE);++ret=oa_tc6_process_rx_chunk_footer(tc6,footer);+if(ret)+returnret;+}++return0;+}++static__be32oa_tc6_prepare_data_header(booldata_valid,boolstart_valid,+boolend_valid,u8end_byte_offset)+{+u32header=FIELD_PREP(OA_TC6_DATA_HEADER_DATA_NOT_CTRL,+OA_TC6_DATA_HEADER)|+FIELD_PREP(OA_TC6_DATA_HEADER_DATA_VALID,data_valid)|+FIELD_PREP(OA_TC6_DATA_HEADER_START_VALID,start_valid)|+FIELD_PREP(OA_TC6_DATA_HEADER_END_VALID,end_valid)|+FIELD_PREP(OA_TC6_DATA_HEADER_END_BYTE_OFFSET,+end_byte_offset);++header|=FIELD_PREP(OA_TC6_DATA_HEADER_PARITY,+oa_tc6_get_parity(header));++returncpu_to_be32(header);+}++staticvoidoa_tc6_add_tx_skb_to_spi_buf(structoa_tc6*tc6)+{+enumoa_tc6_data_end_valid_infoend_valid=OA_TC6_DATA_END_INVALID;+__be32*tx_buf=tc6->spi_data_tx_buf+tc6->spi_data_tx_buf_offset;+u16remaining_len=tc6->tx_skb->len-tc6->tx_skb_offset;+u8*tx_skb_data=tc6->tx_skb->data+tc6->tx_skb_offset;+enumoa_tc6_data_start_valid_infostart_valid;+u8end_byte_offset=0;+u16length_to_copy;++/* Initial value is assigned here to avoid more than 80 characters in+*thedeclarationplace.+*/+start_valid=OA_TC6_DATA_START_INVALID;++/* Set start valid if the current tx chunk contains the start of the tx+*ethernetframe.+*/+if(!tc6->tx_skb_offset)+start_valid=OA_TC6_DATA_START_VALID;++/* If the remaining tx skb length is more than the chunk payload size of+*64bytesthencopyonly64bytesandleavetheongoingtxskbfor+*nexttxchunk.+*/+length_to_copy=min_t(u16,remaining_len,OA_TC6_CHUNK_PAYLOAD_SIZE);++/* Copy the tx skb data to the tx chunk payload buffer */+memcpy(tx_buf+1,tx_skb_data,length_to_copy);+tc6->tx_skb_offset+=length_to_copy;++/* Set end valid if the current tx chunk contains the end of the tx+*ethernetframe.+*/+if(tc6->tx_skb->len==tc6->tx_skb_offset){+end_valid=OA_TC6_DATA_END_VALID;+end_byte_offset=length_to_copy-1;+tc6->tx_skb_offset=0;+tc6->netdev->stats.tx_bytes+=tc6->tx_skb->len;+tc6->netdev->stats.tx_packets++;+kfree_skb(tc6->tx_skb);+tc6->tx_skb=NULL;+}++*tx_buf=oa_tc6_prepare_data_header(OA_TC6_DATA_VALID,start_valid,+end_valid,end_byte_offset);+tc6->spi_data_tx_buf_offset+=OA_TC6_CHUNK_SIZE;+}++staticu16oa_tc6_prepare_spi_tx_buf_for_tx_skbs(structoa_tc6*tc6)+{+u16used_tx_credits;++/* Get tx skbs and convert them into tx chunks based on the tx credits+*available.+*/+for(used_tx_credits=0;used_tx_credits<tc6->tx_credits;+used_tx_credits++){+if(!tc6->tx_skb)+tc6->tx_skb=skb_dequeue(&tc6->tx_skb_q);+if(!tc6->tx_skb)+break;+oa_tc6_add_tx_skb_to_spi_buf(tc6);+}++returnused_tx_credits*OA_TC6_CHUNK_SIZE;+}++staticintoa_tc6_try_spi_transfer(structoa_tc6*tc6)+{+intret;++while(true){+u16spi_length=0;++tc6->spi_data_tx_buf_offset=0;++if(tc6->tx_skb||!skb_queue_empty(&tc6->tx_skb_q))+spi_length=oa_tc6_prepare_spi_tx_buf_for_tx_skbs(tc6);++if(spi_length==0)+break;++ret=oa_tc6_spi_transfer(tc6,OA_TC6_DATA_HEADER,spi_length);+if(ret){+netdev_err(tc6->netdev,"SPI data transfer failed: %d\n",+ret);+returnret;+}++ret=oa_tc6_process_spi_data_rx_buf(tc6,spi_length);+if(ret){+oa_tc6_cleanup_ongoing_tx_skb(tc6);+netdev_err(tc6->netdev,"Device error: %d\n",ret);+returnret;+}++if(skb_queue_len(&tc6->tx_skb_q)<OA_TC6_TX_SKB_QUEUE_SIZE&&+netif_queue_stopped(tc6->netdev))+netif_wake_queue(tc6->netdev);+}++return0;+}++staticintoa_tc6_spi_thread_handler(void*data)+{+structoa_tc6*tc6=data;+intret;++while(likely(!kthread_should_stop())){+/* This kthread will be waken up if there is a tx skb */+wait_event_interruptible(tc6->spi_wq,+!skb_queue_empty(&tc6->tx_skb_q)||+kthread_should_stop());++if(kthread_should_stop())+break;++ret=oa_tc6_try_spi_transfer(tc6);+if(ret)+returnret;+}++return0;+}++staticintoa_tc6_update_buffer_status_from_register(structoa_tc6*tc6)+{+u32value;+intret;++/* Initially tx credits to be updated from the register as there is no+*datatransferperformedyet.Lateritwillbeupdatedfromtherx+*footer.+*/+ret=oa_tc6_read_register(tc6,OA_TC6_REG_BUFFER_STATUS,&value);+if(ret)+returnret;++tc6->tx_credits=FIELD_GET(BUFFER_STATUS_TX_CREDITS_AVAILABLE,value);++return0;+}++/**+*oa_tc6_start_xmit-functionforsendingthetxskbwhichconsistsethernet+*frame.+*@tc6:oa_tc6struct.+*@skb:socketbufferinwhichtheethernetframeisstored.+*+*Return:NETDEV_TX_OKifthetransmitethernetframeskbaddedinthetx_skb_q+*otherwisereturnsNETDEV_TX_BUSY.+*/+netdev_tx_toa_tc6_start_xmit(structoa_tc6*tc6,structsk_buff*skb)+{+if(skb_queue_len(&tc6->tx_skb_q)>OA_TC6_TX_SKB_QUEUE_SIZE){+netif_stop_queue(tc6->netdev);+returnNETDEV_TX_BUSY;+}++if(skb_linearize(skb)){+dev_kfree_skb_any(skb);+tc6->netdev->stats.tx_dropped++;+returnNETDEV_TX_OK;+}++skb_queue_tail(&tc6->tx_skb_q,skb);++/* Wake spi kthread to perform spi transfer */+wake_up_interruptible(&tc6->spi_wq);++returnNETDEV_TX_OK;+}+EXPORT_SYMBOL_GPL(oa_tc6_start_xmit);+/***oa_tc6_init-allocatesandinitializesoa_tc6structure.*@spi:devicewithwhichdatawillbeexchanged.
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.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
drivers/net/ethernet/oa_tc6.c | 53 +++++++++++++++++++++++++++++++++--
1 file changed, 51 insertions(+), 2 deletions(-)
@@ -1064,6 +1065,14 @@ static int oa_tc6_try_spi_transfer(struct oa_tc6 *tc6)spi_len=oa_tc6_prepare_spi_tx_buf_for_rx_chunks(tc6,spi_len);+if(tc6->int_flag){+tc6->int_flag=false;+if(spi_len==0){+oa_tc6_add_empty_chunks_to_spi_buf(tc6,1);+spi_len=OA_TC6_CHUNK_SIZE;+}+}+if(spi_len==0)break;
@@ -1099,8 +1108,10 @@ static int oa_tc6_spi_thread_handler(void *data)intret;while(likely(!kthread_should_stop())){-/* This kthread will be waken up if there is a tx skb */-wait_event_interruptible(tc6->spi_wq,+/* This kthread will be waken up if there is a tx skb or mac-phy+*interrupttoperformspitransferwithtxchunks.+*/+wait_event_interruptible(tc6->spi_wq,tc6->int_flag||!skb_queue_empty(&tc6->tx_skb_q)||kthread_should_stop());
@@ -1135,6 +1146,24 @@ static int oa_tc6_update_buffer_status_from_register(struct oa_tc6 *tc6)return0;}+staticirqreturn_toa_tc6_macphy_isr(intirq,void*data)+{+structoa_tc6*tc6=data;++/* MAC-PHY interrupt can occur for the following reasons.+*-availabilityoftxcreditsifitwas0beforeandnotreportedin+*thepreviousrxfooter.+*-availabilityofrxchunksifitwas0beforeandnotreportedin+*thepreviousrxfooter.+*-extendedstatuseventnotreportedinthepreviousrxfooter.+*/+tc6->int_flag=true;+/* Wake spi kthread to perform spi transfer */+wake_up_interruptible(&tc6->spi_wq);++returnIRQ_HANDLED;+}+/***oa_tc6_start_xmit-functionforsendingthetxskbwhichconsistsethernet*frame.
@@ -1263,8 +1292,28 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)sched_set_fifo(tc6->spi_thread);+ret=devm_request_irq(&tc6->spi->dev,tc6->spi->irq,oa_tc6_macphy_isr,+IRQF_TRIGGER_FALLING,dev_name(&tc6->spi->dev),+tc6);+if(ret){+dev_err(&tc6->spi->dev,"Failed to request macphy isr %d\n",+ret);+gotokthread_stop;+}++/* oa_tc6_sw_reset_macphy() function resets and clears the MAC-PHY reset+*completestatus.IRQisalsoassertedonresetcompletionanditis+*remainasserteduntilMAC-PHYreceivesadatachunk.Soperformingan+*emptydatachunktransmissionwilldeasserttheIRQ.Refersection+*7.7and9.2.8.8intheOPENAlliancespecificationformoredetails.+*/+tc6->int_flag=true;+wake_up_interruptible(&tc6->spi_wq);+returntc6;+kthread_stop:+kthread_stop(tc6->spi_thread);phy_exit:oa_tc6_phy_exit(tc6);returnNULL;
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. Receive frames may begin
anywhere within the receive data chunk payload when this feature is not
enabled.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
drivers/net/ethernet/oa_tc6.c | 24 ++++++++++++++++++++++++
include/linux/oa_tc6.h | 1 +
2 files changed, 25 insertions(+)
The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE-T1x
MAC-PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
MAC integration provides the low pin count standard SPI interface to any
microcontroller therefore providing Ethernet functionality without
requiring MAC integration within the microcontroller. The LAN8650/1
operates as an SPI client supporting SCLK clock rates up to a maximum of
25 MHz. This SPI interface supports the transfer of both data (Ethernet
frames) and control (register access).
By default, the chunk data payload is 64 bytes in size. The Ethernet
Media Access Controller (MAC) module implements a 10 Mbps half duplex
Ethernet MAC, compatible with the IEEE 802.3 standard. 10BASE-T1S
physical layer transceiver integrated is into the LAN8650/1. The PHY and
MAC are connected via an internal Media Independent Interface (MII).
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
MAINTAINERS | 6 +
drivers/net/ethernet/microchip/Kconfig | 1 +
drivers/net/ethernet/microchip/Makefile | 1 +
.../net/ethernet/microchip/lan865x/Kconfig | 19 +
.../net/ethernet/microchip/lan865x/Makefile | 6 +
.../net/ethernet/microchip/lan865x/lan865x.c | 391 ++++++++++++++++++
6 files changed, 424 insertions(+)
create mode 100644 drivers/net/ethernet/microchip/lan865x/Kconfig
create mode 100644 drivers/net/ethernet/microchip/lan865x/Makefile
create mode 100644 drivers/net/ethernet/microchip/lan865x/lan865x.c
@@ -0,0 +1,391 @@+// SPDX-License-Identifier: GPL-2.0++/*+*Microchip'sLAN865x10BASE-T1SMAC-PHYdriver+*+*Author:ParthibanVeerasooran<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++structlan865x_priv{+structwork_structmulticast_work;+structnet_device*netdev;+structspi_device*spi;+structoa_tc6*tc6;+};++staticintlan865x_set_hw_macaddr_low_bytes(structoa_tc6*tc6,constu8*mac)+{+u32regval;++regval=(mac[3]<<24)|(mac[2]<<16)|(mac[1]<<8)|mac[0];++returnoa_tc6_write_register(tc6,LAN865X_REG_MAC_L_SADDR1,regval);+}++staticintlan865x_set_hw_macaddr(structlan865x_priv*priv,constu8*mac)+{+intrestore_ret;+u32regval;+intret;++/* Configure MAC address low bytes */+ret=lan865x_set_hw_macaddr_low_bytes(priv->tc6,mac);+if(ret)+returnret;++/* 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)+return0;++/* Restore the old MAC address low bytes from netdev if the new MAC+*addresshighbytessettingfailed.+*/+restore_ret=lan865x_set_hw_macaddr_low_bytes(priv->tc6,+priv->netdev->dev_addr);+if(restore_ret)+returnrestore_ret;++returnret;+}++staticvoid+lan865x_get_drvinfo(structnet_device*netdev,structethtool_drvinfo*info)+{+strscpy(info->driver,DRV_NAME,sizeof(info->driver));+strscpy(info->bus_info,dev_name(netdev->dev.parent),+sizeof(info->bus_info));+}++staticconststructethtool_opslan865x_ethtool_ops={+.get_drvinfo=lan865x_get_drvinfo,+.get_link_ksettings=phy_ethtool_get_link_ksettings,+.set_link_ksettings=phy_ethtool_set_link_ksettings,+};++staticintlan865x_set_mac_address(structnet_device*netdev,void*addr)+{+structlan865x_priv*priv=netdev_priv(netdev);+structsockaddr*address=addr;+intret;++ret=eth_prepare_mac_addr_change(netdev,addr);+if(ret<0)+returnret;++if(ether_addr_equal(address->sa_data,netdev->dev_addr))+return0;++ret=lan865x_set_hw_macaddr(priv,address->sa_data);+if(ret)+returnret;++eth_commit_mac_addr_change(netdev,address->sa_data);++return0;+}++staticu32get_address_bit(u8addr[ETH_ALEN],u32bit)+{+return((addr[bit/8])>>(bit%8))&1;+}++staticu32lan865x_hash(u8addr[ETH_ALEN])+{+u32hash_index=0;++for(inti=0;i<6;i++){+u32hash=0;++for(intj=0;j<8;j++)+hash^=get_address_bit(addr,(j*6)+i);++hash_index|=(hash<<i);+}++returnhash_index;+}++staticvoidlan865x_set_specific_multicast_addr(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);+structnetdev_hw_addr*ha;+u32hash_lo=0;+u32hash_hi=0;++netdev_for_each_mc_addr(ha,netdev){+u32bit_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 */+if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_H_HASH,hash_hi)){+netdev_err(netdev,"Failed to write reg_hashh");+return;+}++if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_L_HASH,hash_lo))+netdev_err(netdev,"Failed to write reg_hashl");+}++staticvoidlan865x_multicast_work_handler(structwork_struct*work)+{+structlan865x_priv*priv=container_of(work,structlan865x_priv,+multicast_work);+u32regval=0;++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);+}elseif(priv->netdev->flags&IFF_ALLMULTI){+/* Enabling all multicast mode */+regval&=(~MAC_NET_CFG_PROMISCUOUS_MODE);+regval|=MAC_NET_CFG_MULTICAST_MODE;+regval&=(~MAC_NET_CFG_UNICAST_MODE);+}elseif(!netdev_mc_empty(priv->netdev)){+lan865x_set_specific_multicast_addr(priv->netdev);+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(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_H_HASH,+0)){+netdev_err(priv->netdev,"Failed to write reg_hashh");+return;+}+if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_L_HASH,+0)){+netdev_err(priv->netdev,"Failed to write reg_hashl");+return;+}+}+if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_NET_CFG,regval))+netdev_err(priv->netdev,+"Failed to enable promiscuous/multicast/normal mode");+}++staticvoidlan865x_set_multicast_list(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);++schedule_work(&priv->multicast_work);+}++staticnetdev_tx_tlan865x_send_packet(structsk_buff*skb,+structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);++returnoa_tc6_start_xmit(priv->tc6,skb);+}++staticintlan865x_hw_disable(structlan865x_priv*priv)+{+u32regval;++if(oa_tc6_read_register(priv->tc6,LAN865X_REG_MAC_NET_CTL,®val))+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;++return0;+}++staticintlan865x_net_close(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);+intret;++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);+returnret;+}++return0;+}++staticintlan865x_hw_enable(structlan865x_priv*priv)+{+u32regval;++if(oa_tc6_read_register(priv->tc6,LAN865X_REG_MAC_NET_CTL,®val))+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;++return0;+}++staticintlan865x_net_open(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);+intret;++ret=lan865x_hw_enable(priv);+if(ret){+netdev_err(netdev,"Failed to enable hardware: %d\n",ret);+returnret;+}++phy_start(netdev->phydev);++return0;+}++staticconststructnet_device_opslan865x_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,+};++staticintlan865x_probe(structspi_device*spi)+{+structnet_device*netdev;+structlan865x_priv*priv;+intret;++netdev=alloc_etherdev(sizeof(structlan865x_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;+gotofree_netdev;+}++/* As per the point s3 in the below errata, SPI receive Ethernet frame+*transfermayhaltwhenstartingthenextframeinthesamedatablock+*(chunk)astheendofapreviousframe.TheRFAfieldshouldbe+*configuredto01bor10bforproperoperation.Inthesemodes,only+*onereceiveEthernetframewillbeplacedinasingledatablock.+*WhentheRFAfieldiswrittento01b,receivedframeswillbeforced+*toonlystartinthefirstwordofthedatablockpayload(SWO=0).As+*recommended,enablezeroalignreceiveframefeatureforproper+*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);+gotooa_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);+gotooa_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);+gotooa_tc6_exit;+}++return0;++oa_tc6_exit:+oa_tc6_exit(priv->tc6);+free_netdev:+free_netdev(priv->netdev);+returnret;+}++staticvoidlan865x_remove(structspi_device*spi)+{+structlan865x_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);+}++staticconststructspi_device_idspidev_spi_ids[]={+{.name="lan8650"},+{},+};++staticconststructof_device_idlan865x_dt_ids[]={+{.compatible="microchip,lan8650"},+{/* Sentinel */}+};+MODULE_DEVICE_TABLE(of,lan865x_dt_ids);++staticstructspi_driverlan865x_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");
The LAN8650/1 combines a Media Access Controller (MAC) and an Ethernet
PHY to enable 10BASE-T1S 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).
Reviewed-by: Conor Dooley<conor.dooley@microchip.com>
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
.../bindings/net/microchip,lan8650.yaml | 80 +++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 81 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/microchip,lan8650.yaml
@@ -0,0 +1,80 @@+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)+%YAML1.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 10BASE‑T1S 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++"#address-cells":+const:1++"#size-cells":+const:0++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 = <ð0_pins>;+interrupt-parent = <&gpio>;+interrupts = <6 IRQ_TYPE_EDGE_FALLING>;+local-mac-address = [04 05 06 01 02 03];+spi-max-frequency = <15000000>;+};+};
From: Randy Dunlap <hidden> Date: 2024-07-30 04:15:18
On 7/29/24 9:09 PM, Parthiban Veerasooran wrote:
The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE-T1x
MAC-PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
MAC integration provides the low pin count standard SPI interface to any
microcontroller therefore providing Ethernet functionality without
requiring MAC integration within the microcontroller. The LAN8650/1
operates as an SPI client supporting SCLK clock rates up to a maximum of
25 MHz. This SPI interface supports the transfer of both data (Ethernet
frames) and control (register access).
By default, the chunk data payload is 64 bytes in size. The Ethernet
Media Access Controller (MAC) module implements a 10 Mbps half duplex
Ethernet MAC, compatible with the IEEE 802.3 standard. 10BASE-T1S
physical layer transceiver integrated is into the LAN8650/1. The PHY and
MAC are connected via an internal Media Independent Interface (MII).
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
MAINTAINERS | 6 +
drivers/net/ethernet/microchip/Kconfig | 1 +
drivers/net/ethernet/microchip/Makefile | 1 +
.../net/ethernet/microchip/lan865x/Kconfig | 19 +
.../net/ethernet/microchip/lan865x/Makefile | 6 +
.../net/ethernet/microchip/lan865x/lan865x.c | 391 ++++++++++++++++++
6 files changed, 424 insertions(+)
create mode 100644 drivers/net/ethernet/microchip/lan865x/Kconfig
create mode 100644 drivers/net/ethernet/microchip/lan865x/Makefile
create mode 100644 drivers/net/ethernet/microchip/lan865x/lan865x.c
Since OA_TC6 is described as a library, it would make sense to select OA_TC6 here instead
of depending on it.
OTOH, that might cause some Kconfig dependency issues... I haven't looked into that.
+ help
+ Support for the Microchip LAN8650/1 Rev.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
From: Stefan Bigler <hidden> Date: 2024-07-30 06:16:13
Hi Parthiban
Thanks for v5. I tested and after some fixes it works (I'm still on 6.6.y but it was easy to apply the patches).
I found the following issues:
1) set of Mac-Addr is not working correctly
be ware to the fact that eth_commit_mac_addr_change() takes the pointer to the sockaddr and not to the sa_data
drivers/net/ethernet/microchip/lan865x/lan865x.c
@@ -278,7 +278,7 @@ static int lan865x_set_mac_address(struct net_device *netdev, void *addr) if (ret) return ret;- eth_commit_mac_addr_change(netdev, address->sa_data);+ eth_commit_mac_addr_change(netdev, address);
2) Missing symbol export
drivers/net/ethernet/oa_tc6.c
3) My patch for Multicast support was incomplete
Sorry for this. I did forgott to write that the MAC_NET_CFG_MULTICAST_MODE must be set.
I addition I also added the correct implemenation for IFF_ALLMULTI
drivers/net/ethernet/microchip/lan865x/lan865x.c
Thanks for your work.
Best Regards
Stefan
Am 2024-07-30T06:09:05.000+02:00 hat Parthiban Veerasooran [off-list ref] geschrieben:
quoted hunk
The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE-T1x
MAC-PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
MAC integration provides the low pin count standard SPI interface to any
microcontroller therefore providing Ethernet functionality without
requiring MAC integration within the microcontroller. The LAN8650/1
operates as an SPI client supporting SCLK clock rates up to a maximum of
25 MHz. This SPI interface supports the transfer of both data (Ethernet
frames) and control (register access).
By default, the chunk data payload is 64 bytes in size. The Ethernet
Media Access Controller (MAC) module implements a 10 Mbps half duplex
Ethernet MAC, compatible with the IEEE 802.3 standard. 10BASE-T1S
physical layer transceiver integrated is into the LAN8650/1. The PHY and
MAC are connected via an internal Media Independent Interface (MII).
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
MAINTAINERS | 6 +
drivers/net/ethernet/microchip/Kconfig | 1 +
drivers/net/ethernet/microchip/Makefile | 1 +
.../net/ethernet/microchip/lan865x/Kconfig | 19 +
.../net/ethernet/microchip/lan865x/Makefile | 6 +
.../net/ethernet/microchip/lan865x/lan865x.c | 391 ++++++++++++++++++
6 files changed, 424 insertions(+)
create mode 100644 drivers/net/ethernet/microchip/lan865x/Kconfig
create mode 100644 drivers/net/ethernet/microchip/lan865x/Makefile
create mode 100644 drivers/net/ethernet/microchip/lan865x/lan865x.c
@@ -0,0 +1,391 @@+// SPDX-License-Identifier: GPL-2.0++/*+*Microchip'sLAN865x10BASE-T1SMAC-PHYdriver+*+*Author:ParthibanVeerasooran<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++structlan865x_priv{+structwork_structmulticast_work;+structnet_device*netdev;+structspi_device*spi;+structoa_tc6*tc6;+};++staticintlan865x_set_hw_macaddr_low_bytes(structoa_tc6*tc6,constu8*mac)+{+u32regval;++regval=(mac[3]<<24)|(mac[2]<<16)|(mac[1]<<8)|mac[0];++returnoa_tc6_write_register(tc6,LAN865X_REG_MAC_L_SADDR1,regval);+}++staticintlan865x_set_hw_macaddr(structlan865x_priv*priv,constu8*mac)+{+intrestore_ret;+u32regval;+intret;++/* Configure MAC address low bytes */+ret=lan865x_set_hw_macaddr_low_bytes(priv->tc6,mac);+if(ret)+returnret;++/* 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)+return0;++/* Restore the old MAC address low bytes from netdev if the new MAC+*addresshighbytessettingfailed.+*/+restore_ret=lan865x_set_hw_macaddr_low_bytes(priv->tc6,+priv->netdev->dev_addr);+if(restore_ret)+returnrestore_ret;++returnret;+}++staticvoid+lan865x_get_drvinfo(structnet_device*netdev,structethtool_drvinfo*info)+{+strscpy(info->driver,DRV_NAME,sizeof(info->driver));+strscpy(info->bus_info,dev_name(netdev->dev.parent),+sizeof(info->bus_info));+}++staticconststructethtool_opslan865x_ethtool_ops={+.get_drvinfo=lan865x_get_drvinfo,+.get_link_ksettings=phy_ethtool_get_link_ksettings,+.set_link_ksettings=phy_ethtool_set_link_ksettings,+};++staticintlan865x_set_mac_address(structnet_device*netdev,void*addr)+{+structlan865x_priv*priv=netdev_priv(netdev);+structsockaddr*address=addr;+intret;++ret=eth_prepare_mac_addr_change(netdev,addr);+if(ret<0)+returnret;++if(ether_addr_equal(address->sa_data,netdev->dev_addr))+return0;++ret=lan865x_set_hw_macaddr(priv,address->sa_data);+if(ret)+returnret;++eth_commit_mac_addr_change(netdev,address->sa_data);++return0;+}++staticu32get_address_bit(u8addr[ETH_ALEN],u32bit)+{+return((addr[bit/8])>>(bit%8))&1;+}++staticu32lan865x_hash(u8addr[ETH_ALEN])+{+u32hash_index=0;++for(inti=0;i<6;i++){+u32hash=0;++for(intj=0;j<8;j++)+hash^=get_address_bit(addr,(j*6)+i);++hash_index|=(hash<<i);+}++returnhash_index;+}++staticvoidlan865x_set_specific_multicast_addr(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);+structnetdev_hw_addr*ha;+u32hash_lo=0;+u32hash_hi=0;++netdev_for_each_mc_addr(ha,netdev){+u32bit_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 */+if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_H_HASH,hash_hi)){+netdev_err(netdev,"Failed to write reg_hashh");+return;+}++if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_L_HASH,hash_lo))+netdev_err(netdev,"Failed to write reg_hashl");+}++staticvoidlan865x_multicast_work_handler(structwork_struct*work)+{+structlan865x_priv*priv=container_of(work,structlan865x_priv,+multicast_work);+u32regval=0;++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);+}elseif(priv->netdev->flags&IFF_ALLMULTI){+/* Enabling all multicast mode */+regval&=(~MAC_NET_CFG_PROMISCUOUS_MODE);+regval|=MAC_NET_CFG_MULTICAST_MODE;+regval&=(~MAC_NET_CFG_UNICAST_MODE);+}elseif(!netdev_mc_empty(priv->netdev)){+lan865x_set_specific_multicast_addr(priv->netdev);+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(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_H_HASH,+0)){+netdev_err(priv->netdev,"Failed to write reg_hashh");+return;+}+if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_L_HASH,+0)){+netdev_err(priv->netdev,"Failed to write reg_hashl");+return;+}+}+if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_NET_CFG,regval))+netdev_err(priv->netdev,+"Failed to enable promiscuous/multicast/normal mode");+}++staticvoidlan865x_set_multicast_list(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);++schedule_work(&priv->multicast_work);+}++staticnetdev_tx_tlan865x_send_packet(structsk_buff*skb,+structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);++returnoa_tc6_start_xmit(priv->tc6,skb);+}++staticintlan865x_hw_disable(structlan865x_priv*priv)+{+u32regval;++if(oa_tc6_read_register(priv->tc6,LAN865X_REG_MAC_NET_CTL,®val))+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;++return0;+}++staticintlan865x_net_close(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);+intret;++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);+returnret;+}++return0;+}++staticintlan865x_hw_enable(structlan865x_priv*priv)+{+u32regval;++if(oa_tc6_read_register(priv->tc6,LAN865X_REG_MAC_NET_CTL,®val))+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;++return0;+}++staticintlan865x_net_open(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);+intret;++ret=lan865x_hw_enable(priv);+if(ret){+netdev_err(netdev,"Failed to enable hardware: %d\n",ret);+returnret;+}++phy_start(netdev->phydev);++return0;+}++staticconststructnet_device_opslan865x_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,+};++staticintlan865x_probe(structspi_device*spi)+{+structnet_device*netdev;+structlan865x_priv*priv;+intret;++netdev=alloc_etherdev(sizeof(structlan865x_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;+gotofree_netdev;+}++/* As per the point s3 in the below errata, SPI receive Ethernet frame+*transfermayhaltwhenstartingthenextframeinthesamedatablock+*(chunk)astheendofapreviousframe.TheRFAfieldshouldbe+*configuredto01bor10bforproperoperation.Inthesemodes,only+*onereceiveEthernetframewillbeplacedinasingledatablock.+*WhentheRFAfieldiswrittento01b,receivedframeswillbeforced+*toonlystartinthefirstwordofthedatablockpayload(SWO=0).As+*recommended,enablezeroalignreceiveframefeatureforproper+*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);+gotooa_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);+gotooa_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);+gotooa_tc6_exit;+}++return0;++oa_tc6_exit:+oa_tc6_exit(priv->tc6);+free_netdev:+free_netdev(priv->netdev);+returnret;+}++staticvoidlan865x_remove(structspi_device*spi)+{+structlan865x_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);+}++staticconststructspi_device_idspidev_spi_ids[]={+{.name="lan8650"},+{},+};++staticconststructof_device_idlan865x_dt_ids[]={+{.compatible="microchip,lan8650"},+{/* Sentinel */}+};+MODULE_DEVICE_TABLE(of,lan865x_dt_ids);++staticstructspi_driverlan865x_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");
From: Rob Herring <robh@kernel.org> Date: 2024-07-30 15:17:11
On Tue, Jul 30, 2024 at 09:39:06AM +0530, Parthiban Veerasooran wrote:
The LAN8650/1 combines a Media Access Controller (MAC) and an Ethernet
PHY to enable 10BASE-T1S 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).
Reviewed-by: Conor Dooley<conor.dooley@microchip.com>
FYI: This is on my RADAR, but low priority, probably not until i get
back from vacation. Given the very long timer between revisions, i
don't see this delay being a problem.
Andrew
FYI: This is on my RADAR, but low priority, probably not until i get
back from vacation. Given the very long timer between revisions, i
don't see this delay being a problem.
SG, thanks for the heads up, let me mark it as deferred, you should
be able to bring it back to life with a pw-bot command.. or ask for
a repost.
--
pw-bot: defer
Hi Rob Herring,
On 30/07/24 8:47 pm, Rob Herring wrote:
EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
On Tue, Jul 30, 2024 at 09:39:06AM +0530, Parthiban Veerasooran wrote:
quoted
The LAN8650/1 combines a Media Access Controller (MAC) and an Ethernet
PHY to enable 10BASE-T1S 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).
Reviewed-by: Conor Dooley<conor.dooley@microchip.com>
missing space ^
Ah ok. Thanks for letting me know. Will correct it in the next version.
Best regards,
Parthiban V
Hi Andrew,
On 31/07/24 1:59 am, Andrew Lunn wrote:
EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
On Tue, Jul 30, 2024 at 09:38:52AM +0530, Parthiban Veerasooran wrote:
FYI: This is on my RADAR, but low priority, probably not until i get
back from vacation. Given the very long timer between revisions, i
don't see this delay being a problem.
Thanks for the info. There was a confusion between patches, created this
much delay in posting the next version. Surely next time will take care
of the timeline. Sorry for the inconvenience. Eagerly waiting for your
review feedback. We really appreciate your support on this.
Best regards,
Parthiban V
Hi Randy,
On 30/07/24 9:45 am, Randy Dunlap wrote:
EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
On 7/29/24 9:09 PM, Parthiban Veerasooran wrote:
quoted
The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE-T1x
MAC-PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
MAC integration provides the low pin count standard SPI interface to any
microcontroller therefore providing Ethernet functionality without
requiring MAC integration within the microcontroller. The LAN8650/1
operates as an SPI client supporting SCLK clock rates up to a maximum of
25 MHz. This SPI interface supports the transfer of both data (Ethernet
frames) and control (register access).
By default, the chunk data payload is 64 bytes in size. The Ethernet
Media Access Controller (MAC) module implements a 10 Mbps half duplex
Ethernet MAC, compatible with the IEEE 802.3 standard. 10BASE-T1S
physical layer transceiver integrated is into the LAN8650/1. The PHY and
MAC are connected via an internal Media Independent Interface (MII).
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
MAINTAINERS | 6 +
drivers/net/ethernet/microchip/Kconfig | 1 +
drivers/net/ethernet/microchip/Makefile | 1 +
.../net/ethernet/microchip/lan865x/Kconfig | 19 +
.../net/ethernet/microchip/lan865x/Makefile | 6 +
.../net/ethernet/microchip/lan865x/lan865x.c | 391 ++++++++++++++++++
6 files changed, 424 insertions(+)
create mode 100644 drivers/net/ethernet/microchip/lan865x/Kconfig
create mode 100644 drivers/net/ethernet/microchip/lan865x/Makefile
create mode 100644 drivers/net/ethernet/microchip/lan865x/lan865x.c
Since OA_TC6 is described as a library, it would make sense to select OA_TC6 here instead
of depending on it.
OTOH, that might cause some Kconfig dependency issues... I haven't looked into that.Yes that makes sense. I will change it in the next version.
Best regards,
Parthiban V
quoted
+ help
+ Support for the Microchip LAN8650/1 Rev.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
Hi Stefan,
On 30/07/24 11:46 am, Stefan Bigler wrote:
quoted hunk
EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
Hi Parthiban
Thanks for v5. I tested and after some fixes it works (I'm still on 6.6.y but it was easy to apply the patches).
I found the following issues:
1) set of Mac-Addr is not working correctly
be ware to the fact that eth_commit_mac_addr_change() takes the pointer to the sockaddr and not to the sa_data
drivers/net/ethernet/microchip/lan865x/lan865x.c
@@ -278,7 +278,7 @@ static int lan865x_set_mac_address(struct net_device *netdev, void *addr) if (ret) return ret;- eth_commit_mac_addr_change(netdev, address->sa_data);+ eth_commit_mac_addr_change(netdev, address);
Ah ok, sorry for the wrong one. Sure will correct it in the next version.
quoted hunk
2) Missing symbol export
drivers/net/ethernet/oa_tc6.c
Yes, I already changed it in the reposted v5 due to net-next window was
closed previously.
quoted hunk
3) My patch for Multicast support was incomplete
Sorry for this. I did forgott to write that the MAC_NET_CFG_MULTICAST_MODE must be set.
I addition I also added the correct implemenation for IFF_ALLMULTI
drivers/net/ethernet/microchip/lan865x/lan865x.c
Sure, I will consider this in the next version. Thanks a lot for your
support on this.
Best regards,
Parthiban V
Thanks for your work.
Best Regards
Stefan
Am 2024-07-30T06:09:05.000+02:00 hat Parthiban Veerasooran [off-list ref] geschrieben:
quoted
The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE-T1x
MAC-PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
MAC integration provides the low pin count standard SPI interface to any
microcontroller therefore providing Ethernet functionality without
requiring MAC integration within the microcontroller. The LAN8650/1
operates as an SPI client supporting SCLK clock rates up to a maximum of
25 MHz. This SPI interface supports the transfer of both data (Ethernet
frames) and control (register access).
By default, the chunk data payload is 64 bytes in size. The Ethernet
Media Access Controller (MAC) module implements a 10 Mbps half duplex
Ethernet MAC, compatible with the IEEE 802.3 standard. 10BASE-T1S
physical layer transceiver integrated is into the LAN8650/1. The PHY and
MAC are connected via an internal Media Independent Interface (MII).
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
---
MAINTAINERS | 6 +
drivers/net/ethernet/microchip/Kconfig | 1 +
drivers/net/ethernet/microchip/Makefile | 1 +
.../net/ethernet/microchip/lan865x/Kconfig | 19 +
.../net/ethernet/microchip/lan865x/Makefile | 6 +
.../net/ethernet/microchip/lan865x/lan865x.c | 391 ++++++++++++++++++
6 files changed, 424 insertions(+)
create mode 100644 drivers/net/ethernet/microchip/lan865x/Kconfig
create mode 100644 drivers/net/ethernet/microchip/lan865x/Makefile
create mode 100644 drivers/net/ethernet/microchip/lan865x/lan865x.c
@@ -0,0 +1,391 @@+// SPDX-License-Identifier: GPL-2.0++/*+*Microchip'sLAN865x10BASE-T1SMAC-PHYdriver+*+*Author:ParthibanVeerasooran<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++structlan865x_priv{+structwork_structmulticast_work;+structnet_device*netdev;+structspi_device*spi;+structoa_tc6*tc6;+};++staticintlan865x_set_hw_macaddr_low_bytes(structoa_tc6*tc6,constu8*mac)+{+u32regval;++regval=(mac[3]<<24)|(mac[2]<<16)|(mac[1]<<8)|mac[0];++returnoa_tc6_write_register(tc6,LAN865X_REG_MAC_L_SADDR1,regval);+}++staticintlan865x_set_hw_macaddr(structlan865x_priv*priv,constu8*mac)+{+intrestore_ret;+u32regval;+intret;++/* Configure MAC address low bytes */+ret=lan865x_set_hw_macaddr_low_bytes(priv->tc6,mac);+if(ret)+returnret;++/* 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)+return0;++/* Restore the old MAC address low bytes from netdev if the new MAC+*addresshighbytessettingfailed.+*/+restore_ret=lan865x_set_hw_macaddr_low_bytes(priv->tc6,+priv->netdev->dev_addr);+if(restore_ret)+returnrestore_ret;++returnret;+}++staticvoid+lan865x_get_drvinfo(structnet_device*netdev,structethtool_drvinfo*info)+{+strscpy(info->driver,DRV_NAME,sizeof(info->driver));+strscpy(info->bus_info,dev_name(netdev->dev.parent),+sizeof(info->bus_info));+}++staticconststructethtool_opslan865x_ethtool_ops={+.get_drvinfo=lan865x_get_drvinfo,+.get_link_ksettings=phy_ethtool_get_link_ksettings,+.set_link_ksettings=phy_ethtool_set_link_ksettings,+};++staticintlan865x_set_mac_address(structnet_device*netdev,void*addr)+{+structlan865x_priv*priv=netdev_priv(netdev);+structsockaddr*address=addr;+intret;++ret=eth_prepare_mac_addr_change(netdev,addr);+if(ret<0)+returnret;++if(ether_addr_equal(address->sa_data,netdev->dev_addr))+return0;++ret=lan865x_set_hw_macaddr(priv,address->sa_data);+if(ret)+returnret;++eth_commit_mac_addr_change(netdev,address->sa_data);++return0;+}++staticu32get_address_bit(u8addr[ETH_ALEN],u32bit)+{+return((addr[bit/8])>>(bit%8))&1;+}++staticu32lan865x_hash(u8addr[ETH_ALEN])+{+u32hash_index=0;++for(inti=0;i<6;i++){+u32hash=0;++for(intj=0;j<8;j++)+hash^=get_address_bit(addr,(j*6)+i);++hash_index|=(hash<<i);+}++returnhash_index;+}++staticvoidlan865x_set_specific_multicast_addr(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);+structnetdev_hw_addr*ha;+u32hash_lo=0;+u32hash_hi=0;++netdev_for_each_mc_addr(ha,netdev){+u32bit_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 */+if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_H_HASH,hash_hi)){+netdev_err(netdev,"Failed to write reg_hashh");+return;+}++if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_L_HASH,hash_lo))+netdev_err(netdev,"Failed to write reg_hashl");+}++staticvoidlan865x_multicast_work_handler(structwork_struct*work)+{+structlan865x_priv*priv=container_of(work,structlan865x_priv,+multicast_work);+u32regval=0;++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);+}elseif(priv->netdev->flags&IFF_ALLMULTI){+/* Enabling all multicast mode */+regval&=(~MAC_NET_CFG_PROMISCUOUS_MODE);+regval|=MAC_NET_CFG_MULTICAST_MODE;+regval&=(~MAC_NET_CFG_UNICAST_MODE);+}elseif(!netdev_mc_empty(priv->netdev)){+lan865x_set_specific_multicast_addr(priv->netdev);+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(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_H_HASH,+0)){+netdev_err(priv->netdev,"Failed to write reg_hashh");+return;+}+if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_L_HASH,+0)){+netdev_err(priv->netdev,"Failed to write reg_hashl");+return;+}+}+if(oa_tc6_write_register(priv->tc6,LAN865X_REG_MAC_NET_CFG,regval))+netdev_err(priv->netdev,+"Failed to enable promiscuous/multicast/normal mode");+}++staticvoidlan865x_set_multicast_list(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);++schedule_work(&priv->multicast_work);+}++staticnetdev_tx_tlan865x_send_packet(structsk_buff*skb,+structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);++returnoa_tc6_start_xmit(priv->tc6,skb);+}++staticintlan865x_hw_disable(structlan865x_priv*priv)+{+u32regval;++if(oa_tc6_read_register(priv->tc6,LAN865X_REG_MAC_NET_CTL,®val))+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;++return0;+}++staticintlan865x_net_close(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);+intret;++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);+returnret;+}++return0;+}++staticintlan865x_hw_enable(structlan865x_priv*priv)+{+u32regval;++if(oa_tc6_read_register(priv->tc6,LAN865X_REG_MAC_NET_CTL,®val))+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;++return0;+}++staticintlan865x_net_open(structnet_device*netdev)+{+structlan865x_priv*priv=netdev_priv(netdev);+intret;++ret=lan865x_hw_enable(priv);+if(ret){+netdev_err(netdev,"Failed to enable hardware: %d\n",ret);+returnret;+}++phy_start(netdev->phydev);++return0;+}++staticconststructnet_device_opslan865x_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,+};++staticintlan865x_probe(structspi_device*spi)+{+structnet_device*netdev;+structlan865x_priv*priv;+intret;++netdev=alloc_etherdev(sizeof(structlan865x_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;+gotofree_netdev;+}++/* As per the point s3 in the below errata, SPI receive Ethernet frame+*transfermayhaltwhenstartingthenextframeinthesamedatablock+*(chunk)astheendofapreviousframe.TheRFAfieldshouldbe+*configuredto01bor10bforproperoperation.Inthesemodes,only+*onereceiveEthernetframewillbeplacedinasingledatablock.+*WhentheRFAfieldiswrittento01b,receivedframeswillbeforced+*toonlystartinthefirstwordofthedatablockpayload(SWO=0).As+*recommended,enablezeroalignreceiveframefeatureforproper+*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);+gotooa_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);+gotooa_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);+gotooa_tc6_exit;+}++return0;++oa_tc6_exit:+oa_tc6_exit(priv->tc6);+free_netdev:+free_netdev(priv->netdev);+returnret;+}++staticvoidlan865x_remove(structspi_device*spi)+{+structlan865x_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);+}++staticconststructspi_device_idspidev_spi_ids[]={+{.name="lan8650"},+{},+};++staticconststructof_device_idlan865x_dt_ids[]={+{.compatible="microchip,lan8650"},+{/* Sentinel */}+};+MODULE_DEVICE_TABLE(of,lan865x_dt_ids);++staticstructspi_driverlan865x_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");--
From: Andrew Lunn <andrew@lunn.ch> Date: 2024-08-11 15:35:43
On Tue, Jul 30, 2024 at 09:38:53AM +0530, Parthiban Veerasooran wrote:
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.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
From: Andrew Lunn <andrew@lunn.ch> Date: 2024-08-11 15:37:56
On Tue, Jul 30, 2024 at 09:38:55AM +0530, Parthiban Veerasooran wrote:
Implement register read operation according to the control communication
specified in the OPEN Alliance 10BASE-T1x MACPHY Serial Interface
document. Control read commands are used by the SPI host to read
registers within the MAC-PHY. Each control read commands are composed of
a 32 bits control command header.
The MAC-PHY ignores all data from the SPI host following the control
header for the remainder of the control read command. 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.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
From: Andrew Lunn <andrew@lunn.ch> Date: 2024-08-11 15:39:38
On Tue, Jul 30, 2024 at 09:38:56AM +0530, Parthiban Veerasooran wrote:
Reset complete bit is set when the MAC-PHY reset completes and ready for
configuration. Additionally reset complete bit in the STS0 register has
to be written by one upon reset complete to clear the interrupt.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
From: Andrew Lunn <andrew@lunn.ch> Date: 2024-08-11 15:47:48
On Tue, Jul 30, 2024 at 09:38:58AM +0530, Parthiban Veerasooran wrote:
Internal PHY is initialized as per the PHY register capability supported
by the MAC-PHY. Direct PHY Register Access Capability indicates if PHY
registers are directly accessible within the SPI register memory space.
Indirect PHY Register Access Capability indicates if PHY registers are
indirectly accessible through the MDIO/MDC registers MDIOACCn defined in
OPEN Alliance specification. Currently the direct register access is only
supported.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
From: Andrew Lunn <andrew@lunn.ch> Date: 2024-08-11 15:48:39
On Tue, Jul 30, 2024 at 09:38:59AM +0530, Parthiban Veerasooran wrote:
This patch adds c45 registers direct access support in Microchip's
LAN865x internal PHY.
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
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
From: Andrew Lunn <andrew@lunn.ch> Date: 2024-08-11 15:54:15
On Tue, Jul 30, 2024 at 09:39:01AM +0530, Parthiban Veerasooran wrote:
The transmit ethernet frame will be converted into multiple transmit data
chunks. Each transmit data chunk consists of a 4 bytes header followed by
a 64 bytes transmit data chunk payload. The 4 bytes data header occurs at
the beginning of each transmit data chunk on MOSI. The data header
contains the information needed to determine the validity and location of
the transmit frame data within the data chunk payload. The number of
transmit data chunks transmitted to mac-phy is limited to the number
transmit credits available in the mac-phy. Initially the transmit credits
will be updated from the buffer status register and then it will be
updated from the footer received on each spi data transfer. The received
footer will be examined for the transmit errors if any.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
From: Andrew Lunn <andrew@lunn.ch> Date: 2024-08-11 15:56:23
On Tue, Jul 30, 2024 at 09:39:02AM +0530, Parthiban Veerasooran wrote:
SPI rx data buffer can contain one or more receive data chunks. A receive
data chunk consists a 64 bytes receive data chunk payload followed a
4 bytes data footer at the end. The data footer contains the information
needed to determine the validity and location of the receive frame data
within the receive data chunk payload and the host can use these
information to generate ethernet frame. Initially the receive chunks
available will be updated from the buffer status register and then it
will be updated from the footer received on each spi data transfer. Tx
data valid or empty chunks equal to the number receive chunks available
will be transmitted in the MOSI to receive all the rx chunks.
Additionally the receive data footer contains the below information as
well. The received footer will be examined for the receive errors if any.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
From: Andrew Lunn <andrew@lunn.ch> Date: 2024-08-11 15:57:36
On Tue, Jul 30, 2024 at 09:39:04AM +0530, Parthiban Veerasooran wrote:
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. Receive frames may begin
anywhere within the receive data chunk payload when this feature is not
enabled.
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
From: Andrew Lunn <andrew@lunn.ch> Date: 2024-08-11 15:59:13
On Tue, Jul 30, 2024 at 09:39:06AM +0530, Parthiban Veerasooran wrote:
The LAN8650/1 combines a Media Access Controller (MAC) and an Ethernet
PHY to enable 10BASE-T1S 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).
Reviewed-by: Conor Dooley<conor.dooley@microchip.com>
Signed-off-by: Parthiban Veerasooran <Parthiban.Veerasooran@microchip.com>
From: Andrew Lunn <andrew@lunn.ch> Date: 2024-08-11 16:09:18
On Tue, Jul 30, 2024 at 09:39:05AM +0530, Parthiban Veerasooran wrote:
The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE-T1x
MAC-PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
MAC integration provides the low pin count standard SPI interface to any
microcontroller therefore providing Ethernet functionality without
requiring MAC integration within the microcontroller. The LAN8650/1
operates as an SPI client supporting SCLK clock rates up to a maximum of
25 MHz. This SPI interface supports the transfer of both data (Ethernet
frames) and control (register access).
By default, the chunk data payload is 64 bytes in size. The Ethernet
Media Access Controller (MAC) module implements a 10 Mbps half duplex
Ethernet MAC, compatible with the IEEE 802.3 standard. 10BASE-T1S
physical layer transceiver integrated is into the LAN8650/1. The PHY and
MAC are connected via an internal Media Independent Interface (MII).
I see there are some fixes needed for Multicast, but otherwise this
looks O.K.
Please send a new version with the fixes, and then i think we are
ready for this to be merged.
Andrew
Hi Andrew,
On 11/08/24 9:39 pm, Andrew Lunn wrote:
EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
On Tue, Jul 30, 2024 at 09:39:05AM +0530, Parthiban Veerasooran wrote:
quoted
The LAN8650/1 is designed to conform to the OPEN Alliance 10BASE-T1x
MAC-PHY Serial Interface specification, Version 1.1. The IEEE Clause 4
MAC integration provides the low pin count standard SPI interface to any
microcontroller therefore providing Ethernet functionality without
requiring MAC integration within the microcontroller. The LAN8650/1
operates as an SPI client supporting SCLK clock rates up to a maximum of
25 MHz. This SPI interface supports the transfer of both data (Ethernet
frames) and control (register access).
By default, the chunk data payload is 64 bytes in size. The Ethernet
Media Access Controller (MAC) module implements a 10 Mbps half duplex
Ethernet MAC, compatible with the IEEE 802.3 standard. 10BASE-T1S
physical layer transceiver integrated is into the LAN8650/1. The PHY and
MAC are connected via an internal Media Independent Interface (MII).
I see there are some fixes needed for Multicast, but otherwise this
looks O.K.
Sure, will fix them.
Please send a new version with the fixes, and then i think we are
ready for this to be merged.
O.K. Thanks a lot Andrew for reviewing all the patches. I will fix the
above patch and send v6 patch series now.
Best regards,
Parthiban V