From patchwork Mon Oct 23 15:46:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Parthiban Veerasooran X-Patchwork-Id: 13433072 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1DF221C291; Mon, 23 Oct 2023 15:47:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="NbEumL13" Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6961810E; Mon, 23 Oct 2023 08:47:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1698076055; x=1729612055; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=A//mX39WgKrhnFTzfWIlrGGCHGSw0jj6+bKlpduDZ94=; b=NbEumL13tGd4Y7BdEdSfmwSK1B3Emnz/upFbm2KhiXb/AVfSUFkVZAqC wyEY+u28Y0WQn+SjqV6za2/mY1iBcVdlJeq/8gWVcQgAbWp+K+tcQrK0L lxJP4lemtgGrxHvi0y0KQNHvPe2NyPs/C8R4fMWXG5ycxXmQ6iYHv3ntW EqJNIxjh9DG0zptVHSJ7ce7PCTre8xTWvwqdMcPf4kSgs9nK1f6409LSA nPF2sqBZPEM305+x2ILTFc5w1i33tbdEoxHkF3VBBEjkHLHyYwEtJMU7r 0v3PiryZ4aSHaAVjsJaOdc1s8YN8Z8WE5yTKjmokMQPBY0DqnJ8Hki0WF g==; X-CSE-ConnectionGUID: 4O8X7pv4TK2a1gqzb4d+ug== X-CSE-MsgGUID: ygJQLuoVQ7WS4Z46AWCG0Q== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.03,244,1694761200"; d="scan'208";a="10448732" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa4.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Oct 2023 08:47:34 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Mon, 23 Oct 2023 08:47:21 -0700 Received: from CHE-LT-I17164LX.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.21 via Frontend Transport; Mon, 23 Oct 2023 08:47:09 -0700 From: Parthiban Veerasooran To: , , , , , , , , , , , , CC: , , , , , , , , , Parthiban Veerasooran Subject: [PATCH net-next v2 1/9] net: ethernet: implement OPEN Alliance control transaction interface Date: Mon, 23 Oct 2023 21:16:41 +0530 Message-ID: <20231023154649.45931-2-Parthiban.Veerasooran@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> References: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org Implement register read/write interface according to the control communication specified in the OPEN Alliance 10BASE-T1x MACPHY Serial Interface document. 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 32-bit control command header followed by register 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. 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 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. The register data being read or written can be protected against simple bit errors. When enabled by setting the Protection Enable (PROTE) bit in the CONFIG0 register, protection is accomplished by duplication of each 32-bit word containing register data with its ones’ complement. Errors are detected at the receiver by performing a simple exclusive-OR (XOR) of each received 32-bit word containing register data with its received complement and detecting if there are any zeros in the result. Signed-off-by: Parthiban Veerasooran --- Documentation/networking/oa-tc6-framework.rst | 233 ++++++++++++++ MAINTAINERS | 8 + drivers/net/ethernet/Kconfig | 12 + drivers/net/ethernet/Makefile | 1 + drivers/net/ethernet/oa_tc6.c | 288 ++++++++++++++++++ include/linux/oa_tc6.h | 28 ++ 6 files changed, 570 insertions(+) create mode 100644 Documentation/networking/oa-tc6-framework.rst create mode 100644 drivers/net/ethernet/oa_tc6.c create mode 100644 include/linux/oa_tc6.h diff --git a/Documentation/networking/oa-tc6-framework.rst b/Documentation/networking/oa-tc6-framework.rst new file mode 100644 index 000000000000..5406f6f4b4f1 --- /dev/null +++ b/Documentation/networking/oa-tc6-framework.rst @@ -0,0 +1,233 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. include:: + +========================================================================= +OPEN Alliance 10BASE-T1x MAC-PHY Serial Interface (TC6) Framework Support +========================================================================= + +:Copyright: |copy| 2023 MICROCHIP + +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 the configured 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://www.opensig.org/about/specifications/ + +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 | + +----------------------+ +-----------------------------+ + | | + | | + +----------------------+ +-----------------------------+ + | PHYLIB | | SPI Subsystem | + +----------------------+ +-----------------------------+ + | + | + +----------------------------------------------------------+ + | 10BASE-T1x MAC-PHY Device | + +----------------------------------------------------------+ + +Implementation +-------------- + +MAC Driver +~~~~~~~~~~ +- Initializes and configures the OA TC6 framework for the MAC-PHY. + +- Initializes PHYLIB interface. + +- Registers and configures the network device. + +- Sends the tx ethernet frame from n/w subsystem to OA TC6 framework. + +OPEN Alliance TC6 Framework +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- Registers macphy interrupt which is used to indicate receive data + available, any communication errors and tx credit count availability in + case it was 0 already. + +- Prepares SPI chunks from the tx ethernet frame enqueued by the MAC + driver and sends to MAC-PHY. + +- Receives SPI chunks from MAC-PHY and prepares ethernet frame and sends + to n/w subsystem. + +- Prepares and performs control read/write commands. + +Data Transaction +~~~~~~~~~~~~~~~~ + +Tx ethernet frame from the n/w layer is divided into multiple chunks in +the oa_tc6_prepare_tx_chunks() function. Each tx chunk will have 4 bytes +header and 64/32 bytes chunk payload. + +.. code-block:: none + + +---------------------------------------------------+ + | Tx Chunk | + | +---------------------------+ +----------------+ | MOSI + | | 64/32 bytes chunk payload | | 4 bytes header | |------------> + | +---------------------------+ +----------------+ | + +---------------------------------------------------+ + +The number of buffers available in the MAC-PHY to store the incoming tx +chunk payloads is represented as tx credit count (txc). This txc can be +read either from the Buffer Status Register or footer (Refer below in the +rx case for the footer info) received from the MAC-PHY. The number of txc +is needed to transport the ethernet frame is calculated from the size of +the ethernet frame. The header in the each chunk is updated with the +chunk payload details like data not control, data valid, start valid, +start word offset, end byte offset, end valid and parity bit. + +Once the tx chunks are ready, oa_tc6_handler() task is triggered to +perform SPI transfer. This task checks for the txc availability in the +MAC-PHY and sends the number of chunks equal to the txc. If there is no +txc is available then the task waits for the interrupt to indicate the +txc availability. If the available txc is less than the needed txc then +the SPI transfer is performed for the available txc and the rx chunks +footer is processed for the txc availability again. For every SPI +transfer the received rx chunks will be processed for the rx ethernet +frame (if any), txc and rca. + +Rx ethernet frame from the MAC-PHY is framed from the rx chunks received +from the MAC-PHY and will be transferred to the n/w layer. Each rx chunk +will have 64/32 bytes chunk payload and 4 bytes footer. + +.. code-block:: none + + +---------------------------------------------------+ + | Rx Chunk | + | +----------------+ +---------------------------+ | MISO + | | 4 bytes footer | | 64/32 bytes chunk payload | |------------> + | +----------------+ +---------------------------+ | + +---------------------------------------------------+ + +In case of interrupt, the oa_tc6_handler() task performs an empty chunk +SPI transfer to get the reason for the interrupt in the received chunk +footer. The reason can be receive chunk available (rca) or extended block +status (exst) or txc availability. Based on this the corresponding +operation is performed. If it is for rca then the SPI transfer is +performed with the empty chunks equal to the rca to get the rx chunks. +Rx ethernet frame is framed from the rx chunks received and transferred +to n/w layer. If it is for exst then the STATUS0 register will be read +for the error detail. + +In the beginning the interrupt occurs for indicating the reset complete +from the MAC-PHY and is ready for the configuration. oa_tc6_handler() task +handles this interrupt to get and clear the reset complete status. + +Control Transaction +~~~~~~~~~~~~~~~~~~~ + +Control transactions are performed to read/write the registers in the +MAC-PHY. Each control command headers are 4 bytes length with the +necessary details to read/write the registers. + +In case of a register write command, the write command header has the +information like data not control, write not read, address increment +disable, memory map selector, address, length and parity followed by the +data to be written. If the protected mode is enabled in the CONFIG0 +register then each data to be written will be sent first followed by its +ones' complement value to ensure the error free transfer. For every write +command, both the write command header and the data will be echoed back in +the rx path to confirm the error free transaction. + +In case of a register read command, the read command is preferred with the +above mentioned details and the echoed rx data will be processed for the +register data. In case of protected mode enabled the echoed rx data +contains the ones' complemented data also for verifying the data error. + +oa_tc6_perform_ctrl() function prepares control commands based on the +read/write request, performs SPI transfer, checks for the error and +returns read register data in case of control read command. diff --git a/MAINTAINERS b/MAINTAINERS index 8985a1b0b5ee..1c165026bbd4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15971,6 +15971,14 @@ L: linux-rdma@vger.kernel.org S: Supported F: drivers/infiniband/ulp/opa_vnic +OPEN ALLIANCE 10BASE-T1S MACPHY SERIAL INTERFACE FRAMEWORK +M: Parthiban Veerasooran +L: netdev@vger.kernel.org +S: Maintained +F: Documentation/networking/oa-tc6-framework.rst +F: drivers/include/linux/oa_tc6.h +F: drivers/net/ethernet/oa_tc6.c + OPEN FIRMWARE AND FLATTENED DEVICE TREE M: Rob Herring M: Frank Rowand diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 5a274b99f299..c58c46591baf 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -160,6 +160,18 @@ config ETHOC help Say Y here if you want to use the OpenCores 10/100 Mbps Ethernet MAC. +config OA_TC6 + tristate "OPEN Alliance TC6 10BASE-T1x MAC-PHY support" + depends on SPI + select PHYLIB + help + This library implements OPEN Alliance TC6 10BASE-T1x MAC-PHY + Serial Interface protocol for supporting 10BASE-T1x MAC-PHYs. + + This option is provided for the case where no in-kernel-tree modules + require OA_TC6 functions, but a module built outside the kernel tree + does. Such modules that use library OA_TC6 functions require M here. + source "drivers/net/ethernet/packetengines/Kconfig" source "drivers/net/ethernet/pasemi/Kconfig" source "drivers/net/ethernet/pensando/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index 0d872d4efcd1..cf5487fc0761 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -104,3 +104,4 @@ obj-$(CONFIG_NET_VENDOR_XILINX) += xilinx/ obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/ obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/ obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/ +obj-$(CONFIG_OA_TC6) += oa_tc6.o diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c new file mode 100644 index 000000000000..acedc327b05e --- /dev/null +++ b/drivers/net/ethernet/oa_tc6.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface framework + * + * Author: Parthiban Veerasooran + */ + +#include +#include + +/* Opaque structure for MACPHY drivers */ +struct oa_tc6 { + struct spi_device *spi; + u8 *ctrl_tx_buf; + u8 *ctrl_rx_buf; + bool prote; +}; + +static int oa_tc6_spi_transfer(struct spi_device *spi, u8 *ptx, u8 *prx, u16 len) +{ + struct spi_transfer xfer = { + .tx_buf = ptx, + .rx_buf = prx, + .len = len, + }; + struct spi_message msg; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + return spi_sync(spi, &msg); +} + +static int oa_tc6_get_parity(u32 p) +{ + /* 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 void oa_tc6_prepare_ctrl_buf(struct oa_tc6 *tc6, u32 addr, u32 val[], + u8 len, bool wnr, u8 *buf, bool prote) +{ + u32 hdr; + + /* Prepare the control header with the required details */ + hdr = FIELD_PREP(CTRL_HDR_DNC, 0) | + FIELD_PREP(CTRL_HDR_WNR, wnr) | + FIELD_PREP(CTRL_HDR_AID, 0) | + FIELD_PREP(CTRL_HDR_MMS, addr >> 16) | + FIELD_PREP(CTRL_HDR_ADDR, addr) | + FIELD_PREP(CTRL_HDR_LEN, len - 1); + hdr |= FIELD_PREP(CTRL_HDR_P, oa_tc6_get_parity(hdr)); + *(__be32 *)buf = cpu_to_be32(hdr); + + if (wnr) { + for (u8 i = 0; i < len; i++) { + u16 pos; + + if (!prote) { + /* Send the value to be written followed by the + * header. + */ + pos = (i + 1) * TC6_HDR_SIZE; + *(__be32 *)&buf[pos] = cpu_to_be32(val[i]); + } else { + /* If protected then send complemented value + * also followed by actual value. + */ + pos = TC6_HDR_SIZE + (i * (TC6_HDR_SIZE * 2)); + *(__be32 *)&buf[pos] = cpu_to_be32(val[i]); + pos = (i + 1) * (TC6_HDR_SIZE * 2); + *(__be32 *)&buf[pos] = cpu_to_be32(~val[i]); + } + } + } +} + +static int oa_tc6_check_control(struct oa_tc6 *tc6, u8 *ptx, u8 *prx, u8 len, + bool wnr, bool prote) +{ + /* 1st 4 bytes of rx chunk data can be discarded */ + u32 rx_hdr = *(u32 *)&prx[TC6_HDR_SIZE]; + u32 tx_hdr = *(u32 *)ptx; + u32 rx_data_complement; + u32 tx_data; + u32 rx_data; + u16 pos1; + u16 pos2; + + /* If tx hdr and echoed hdr are not equal then there might be an issue + * with the connection between SPI host and MAC-PHY. Here this case is + * considered as MAC-PHY is not connected. + */ + if (tx_hdr != rx_hdr) + return -ENODEV; + + if (wnr) { + if (!prote) { + /* In case of ctrl write, both tx data & echoed + * data are compared for the error. + */ + pos1 = TC6_HDR_SIZE; + pos2 = TC6_HDR_SIZE * 2; + for (u8 i = 0; i < len; i++) { + tx_data = *(u32 *)&ptx[pos1 + (i * TC6_HDR_SIZE)]; + rx_data = *(u32 *)&prx[pos2 + (i * TC6_HDR_SIZE)]; + if (tx_data != rx_data) + return -ENODEV; + } + return 0; + } + } else { + if (!prote) + return 0; + } + + /* In case of ctrl read or ctrl write in protected mode, the rx data and + * the complement of rx data are compared for the error. + */ + pos1 = TC6_HDR_SIZE * 2; + pos2 = TC6_HDR_SIZE * 3; + for (u8 i = 0; i < len; i++) { + rx_data = *(u32 *)&prx[pos1 + (i * TC6_HDR_SIZE * 2)]; + rx_data_complement = *(u32 *)&prx[pos2 + (i * TC6_HDR_SIZE * 2)]; + if (rx_data != ~rx_data_complement) + return -ENODEV; + } + + return 0; +} + +/** + * oa_tc6_perform_ctrl - function to perform control transaction. + * @tc6: oa_tc6 struct. + * @addr: register address of the MACPHY to be written/read. + * @val: value to be written/read in the @addr register address of the MACPHY. + * @len: number of consecutive registers to be written/read from @addr. + * @wnr: operation to be performed for the register @addr (write not read). + * @prote: control data (register) read/write protection enable/disable. + * + * Returns 0 on success otherwise failed. + */ +static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len, + bool wnr, bool prote) +{ + u8 *tx_buf = tc6->ctrl_tx_buf; + u8 *rx_buf = tc6->ctrl_rx_buf; + u16 size; + u16 pos; + int ret; + + if (prote) + size = (TC6_HDR_SIZE * 2) + (len * (TC6_HDR_SIZE * 2)); + else + size = (TC6_HDR_SIZE * 2) + (len * TC6_HDR_SIZE); + + /* Prepare control command */ + oa_tc6_prepare_ctrl_buf(tc6, addr, val, len, wnr, tx_buf, prote); + + /* Perform SPI transfer */ + ret = oa_tc6_spi_transfer(tc6->spi, tx_buf, rx_buf, size); + if (ret) + return ret; + + /* Check echoed/received control reply for errors */ + ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len, wnr, prote); + if (ret) + return ret; + + if (!wnr) { + /* Copy read data from the rx data in case of ctrl read */ + for (u8 i = 0; i < len; i++) { + if (!prote) { + pos = (TC6_HDR_SIZE * 2) + (i * TC6_HDR_SIZE); + val[i] = be32_to_cpu(*(__be32 *)&rx_buf[pos]); + } else { + pos = (TC6_HDR_SIZE * 2) + + (i * (TC6_HDR_SIZE * 2)); + val[i] = be32_to_cpu(*(__be32 *)&rx_buf[pos]); + } + } + } + + return ret; +} + +/** + * oa_tc6_write_register - function for writing a MACPHY register. + * @tc6: oa_tc6 struct. + * @addr: register address of the MACPHY to be written. + * @val: value to be written in the @addr register address of the MACPHY. + * + * Returns 0 on success otherwise failed. + */ +int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 val) +{ + return oa_tc6_perform_ctrl(tc6, addr, &val, 1, true, tc6->prote); +} +EXPORT_SYMBOL_GPL(oa_tc6_write_register); + +/** + * oa_tc6_read_register - function for reading a MACPHY register. + * @tc6: oa_tc6 struct. + * @addr: register address of the MACPHY to be read. + * @val: value read from the @addr register address of the MACPHY. + * + * Returns 0 on success otherwise failed. + */ +int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 *val) +{ + return oa_tc6_perform_ctrl(tc6, addr, val, 1, false, tc6->prote); +} +EXPORT_SYMBOL_GPL(oa_tc6_read_register); + +/** + * oa_tc6_write_registers - function for writing multiple consecutive registers. + * @tc6: oa_tc6 struct. + * @addr: address of the first register to be written in the MACPHY. + * @val: values to be written from the starting register address @addr. + * @len: number of consecutive registers to be written from @addr. + * + * Maximum of 128 consecutive registers can be written starting at @addr. + * + * Returns 0 on success otherwise failed. + */ +int oa_tc6_write_registers(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len) +{ + return oa_tc6_perform_ctrl(tc6, addr, val, len, true, tc6->prote); +} +EXPORT_SYMBOL_GPL(oa_tc6_write_registers); + +/** + * oa_tc6_read_registers - function for reading multiple consecutive registers. + * @tc6: oa_tc6 struct. + * @addr: address of the first register to be read in the MACPHY. + * @val: values to be read from the starting register address @addr. + * + * Maximum of 128 consecutive registers can be read starting at @addr. + * + * Returns 0 on success otherwise failed. + */ +int oa_tc6_read_registers(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len) +{ + return oa_tc6_perform_ctrl(tc6, addr, val, len, false, tc6->prote); +} +EXPORT_SYMBOL_GPL(oa_tc6_read_registers); + +/** + * oa_tc6_init - allocates and intializes oa_tc6 structure. + * @spi: device with which data will be exchanged. + * @prote: control data (register) read/write protection enable/disable. + * + * Returns pointer reference to the oa_tc6 structure if all the memory + * allocation success otherwise NULL. + */ +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, bool prote) +{ + struct oa_tc6 *tc6; + + tc6 = devm_kzalloc(&spi->dev, sizeof(*tc6), GFP_KERNEL); + if (!tc6) + return NULL; + + tc6->ctrl_tx_buf = devm_kzalloc(&spi->dev, TC6_CTRL_BUF_SIZE, GFP_KERNEL); + if (!tc6->ctrl_tx_buf) + return NULL; + + tc6->ctrl_rx_buf = devm_kzalloc(&spi->dev, TC6_CTRL_BUF_SIZE, GFP_KERNEL); + if (!tc6->ctrl_rx_buf) + return NULL; + + tc6->spi = spi; + tc6->prote = prote; + + return tc6; +} +EXPORT_SYMBOL_GPL(oa_tc6_init); + +MODULE_DESCRIPTION("OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface Lib"); +MODULE_AUTHOR("Parthiban Veerasooran "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h new file mode 100644 index 000000000000..6284828bda42 --- /dev/null +++ b/include/linux/oa_tc6.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface framework + * + * Author: Parthiban Veerasooran + */ + +#include + +/* Control header */ +#define CTRL_HDR_DNC BIT(31) /* Data-Not-Control */ +#define CTRL_HDR_HDRB BIT(30) /* Received Header Bad */ +#define CTRL_HDR_WNR BIT(29) /* Write-Not-Read */ +#define CTRL_HDR_AID BIT(28) /* Address Increment Disable */ +#define CTRL_HDR_MMS GENMASK(27, 24) /* Memory Map Selector */ +#define CTRL_HDR_ADDR GENMASK(23, 8) /* Address */ +#define CTRL_HDR_LEN GENMASK(7, 1) /* Length */ +#define CTRL_HDR_P BIT(0) /* Parity Bit */ + +#define TC6_HDR_SIZE 4 /* Ctrl command header size as per OA */ +#define TC6_FTR_SIZE 4 /* Ctrl command footer size ss per OA */ +#define TC6_CTRL_BUF_SIZE 1032 /* Max ctrl buffer size for 128 regs */ + +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, bool prote); +int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 val); +int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 *val); +int oa_tc6_write_registers(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len); +int oa_tc6_read_registers(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len); From patchwork Mon Oct 23 15:46:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parthiban Veerasooran X-Patchwork-Id: 13433073 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 70F8D1C293; Mon, 23 Oct 2023 15:47:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="xXheGG3I" Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A8E23101; Mon, 23 Oct 2023 08:47:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1698076059; x=1729612059; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=IcLRsqXm3RrW6Za2geboSU2UmP+psDSYEwOcvrxgQTE=; b=xXheGG3IiXnnrypW4IEiTgZ57kW/rh+U/uAsXIn+VRwWBG357eo5wQyK R2XfpDhFswEroKpQKE9x7BV1WOzdIgeKiu2BXRr0XxHSODDKRZimSLwbH miCv1s3gEDNWsKMABy2DgfboTiQBfC1PpC12OTh/wup9m3c3XJU2OHhNL 7ttL9VJS6ScUG+eN00E5MUAIpAM1nJQr2esGn5k1/xkzuLNGBvOFG7a+4 YImK0bM1U6juHMs1toUpxYip01wEdLkW98yZpOlO0MJG7sR7S+hwOtk7M XNQsRLvxUrecyWAIaCDAfN2jYciNAifyy+SOEhdp1kYt0SFO+lWaN4DWr Q==; X-CSE-ConnectionGUID: 4O8X7pv4TK2a1gqzb4d+ug== X-CSE-MsgGUID: br4/HxjgT1+QYrysW4eXBQ== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.03,244,1694761200"; d="scan'208";a="10448736" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa4.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Oct 2023 08:47:35 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Mon, 23 Oct 2023 08:47:34 -0700 Received: from CHE-LT-I17164LX.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.21 via Frontend Transport; Mon, 23 Oct 2023 08:47:22 -0700 From: Parthiban Veerasooran To: , , , , , , , , , , , , CC: , , , , , , , , , Parthiban Veerasooran Subject: [PATCH net-next v2 2/9] net: ethernet: oa_tc6: implement mac-phy software reset Date: Mon, 23 Oct 2023 21:16:42 +0530 Message-ID: <20231023154649.45931-3-Parthiban.Veerasooran@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> References: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org Reset complete bit is set when the MAC-PHY reset completes and ready for configuration. When it is set, it will generate a non-maskable interrupt to alert the SPI host. 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 --- drivers/net/ethernet/oa_tc6.c | 64 ++++++++++++++++++++++++++++++++--- include/linux/oa_tc6.h | 9 +++++ 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index acedc327b05e..e4457569135f 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -6,6 +6,8 @@ */ #include +#include +#include #include /* Opaque structure for MACPHY drivers */ @@ -169,10 +171,15 @@ static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len, if (ret) return ret; - /* Check echoed/received control reply for errors */ - ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len, wnr, prote); - if (ret) - return ret; + /* In case of reset write, the echoed control command doesn't have any + * valid data. So no need to check for errors. + */ + if (addr != RESET) { + /* Check echoed/received control reply for errors */ + ret = oa_tc6_check_control(tc6, tx_buf, rx_buf, len, wnr, prote); + if (ret) + return ret; + } if (!wnr) { /* Copy read data from the rx data in case of ctrl read */ @@ -191,6 +198,49 @@ static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len, return ret; } +static int oa_tc6_sw_reset(struct oa_tc6 *tc6) +{ + u32 regval; + int ret; + + /* Perform software reset with both protected and unprotected control + * commands because the driver doesn't know the current status of the + * MAC-PHY. + */ + regval = SWRESET; + ret = oa_tc6_perform_ctrl(tc6, RESET, ®val, 1, true, true); + if (ret) + return ret; + + ret = oa_tc6_perform_ctrl(tc6, RESET, ®val, 1, true, false); + if (ret) + return ret; + + /* The chip completes a reset in 3us, we might get here earlier than + * that, as an added margin we'll conditionally sleep 5us. + */ + udelay(5); + + ret = oa_tc6_perform_ctrl(tc6, STATUS0, ®val, 1, false, false); + if (ret) + return ret; + + /* Check for reset complete interrupt status */ + if (regval & RESETC) { + regval = RESETC; + /* SPI host should write RESETC bit with one to + * clear the reset interrupt status. + */ + ret = oa_tc6_perform_ctrl(tc6, STATUS0, ®val, 1, true, false); + if (ret) + return ret; + } else { + return -ENODEV; + } + + return 0; +} + /** * oa_tc6_write_register - function for writing a MACPHY register. * @tc6: oa_tc6 struct. @@ -279,6 +329,12 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, bool prote) tc6->spi = spi; tc6->prote = prote; + /* Perform MAC-PHY software reset */ + if (oa_tc6_sw_reset(tc6)) { + dev_err(&spi->dev, "MAC-PHY software reset failed\n"); + return NULL; + } + return tc6; } EXPORT_SYMBOL_GPL(oa_tc6_init); diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h index 6284828bda42..8a838499da97 100644 --- a/include/linux/oa_tc6.h +++ b/include/linux/oa_tc6.h @@ -21,6 +21,15 @@ #define TC6_FTR_SIZE 4 /* Ctrl command footer size ss per OA */ #define TC6_CTRL_BUF_SIZE 1032 /* Max ctrl buffer size for 128 regs */ +/* Open Alliance TC6 Standard Control and Status Registers */ +/* Reset Control and Status Register */ +#define RESET 0x0003 +#define SWRESET BIT(0) /* Software Reset */ + +/* Status Register #0 */ +#define STATUS0 0x0008 +#define RESETC BIT(6) /* Reset Complete */ + struct oa_tc6 *oa_tc6_init(struct spi_device *spi, bool prote); int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 val); int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 *val); From patchwork Mon Oct 23 15:46:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parthiban Veerasooran X-Patchwork-Id: 13433074 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE9F91BDFD; Mon, 23 Oct 2023 15:48:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="XZL6pm63" Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2FD4CD78; Mon, 23 Oct 2023 08:48:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1698076084; x=1729612084; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=zMQDhCf+BgR+OEM7pXSPI1V2CELpCiJL5Et7roC/YbA=; b=XZL6pm63Wx6w2FoVwYVTvE6W4WlycBVFKKrCG1VnrL3tZOgUW0Tb7ddI fBS7iHxHTcNHR6cHznwiEFJ2DBrEzgSK18F/hJgaMqNlGG9bKCkZ0a6SF oPnzp5yg2zNvVznmtZSVBRU9pYsK9roTprRGVS0jAJIQzDXbDUSY+XlX7 m+z2wsEJeILVS/YUl3109pNboDTgIJMKjHp5dtGKW3EFgHYB0OqcyM6Kt MxCfekxYuH2yyJx784cpj79i5wzcOqAINx78bUyK7DfhNFDJeImfDDz7d YjwPMllfjxQhKNSLdGvw4G7Mw4Q0vUUSXcEEg+gdop7EVZC1p9MuOlt9B A==; X-CSE-ConnectionGUID: klqWPg5QRmSazEzEhLffbg== X-CSE-MsgGUID: uFGpmiGxSa+ChhZCPsoW3g== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.03,244,1694761200"; d="scan'208";a="241208147" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa5.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Oct 2023 08:48:03 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Mon, 23 Oct 2023 08:47:49 -0700 Received: from CHE-LT-I17164LX.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.21 via Frontend Transport; Mon, 23 Oct 2023 08:47:35 -0700 From: Parthiban Veerasooran To: , , , , , , , , , , , , CC: , , , , , , , , , Parthiban Veerasooran Subject: [PATCH net-next v2 3/9] net: ethernet: oa_tc6: implement OA TC6 configuration function Date: Mon, 23 Oct 2023 21:16:43 +0530 Message-ID: <20231023154649.45931-4-Parthiban.Veerasooran@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> References: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org Read STDCAP register for the MAC-PHY capability and check against the configuration parameters such as chunk payload, tx cut through and rx cut through to configure the MAC-PHY. It also configures the control command protected/unprotected mode. In cut through mode configuration the MAC-PHY doesn't buffer the incoming data. In tx case, it passes the data to the network if the configured cps of data available. In rx case, it passes the data to the SPI host if the configured cps of data available from the network. Also disables all the errors mask in the IMASK0 register to check for the errors. Signed-off-by: Parthiban Veerasooran --- drivers/net/ethernet/oa_tc6.c | 86 ++++++++++++++++++++++++++++++++++- include/linux/oa_tc6.h | 24 +++++++++- 2 files changed, 107 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index e4457569135f..9a98d59f286d 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -8,6 +8,7 @@ #include #include #include +#include #include /* Opaque structure for MACPHY drivers */ @@ -16,6 +17,7 @@ struct oa_tc6 { u8 *ctrl_tx_buf; u8 *ctrl_rx_buf; bool prote; + u32 cps; }; static int oa_tc6_spi_transfer(struct spi_device *spi, u8 *ptx, u8 *prx, u16 len) @@ -198,6 +200,81 @@ static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len, return ret; } +static int oa_tc6_configure(struct oa_tc6 *tc6) +{ + struct spi_device *spi = tc6->spi; + struct device_node *oa_node; + u32 regval; + u8 mincps; + bool ctc; + int ret; + + /* Read and configure the IMASK0 register for unmasking the interrupts */ + ret = oa_tc6_perform_ctrl(tc6, IMASK0, ®val, 1, false, false); + if (ret) + return ret; + + regval &= ~(TXPEM & TXBOEM & TXBUEM & RXBOEM & LOFEM & HDREM); + + ret = oa_tc6_perform_ctrl(tc6, IMASK0, ®val, 1, true, false); + if (ret) + return ret; + + /* Read STDCAP register to get the MAC-PHY standard capabilities */ + ret = oa_tc6_perform_ctrl(tc6, STDCAP, ®val, 1, false, false); + if (ret) + return ret; + + mincps = FIELD_GET(MINCPS, regval); + ctc = (regval & CTC) ? true : false; + + regval = 0; + oa_node = of_get_child_by_name(spi->dev.of_node, "oa-tc6"); + if (oa_node) { + /* Read OA parameters from DT */ + if (of_property_present(oa_node, "oa-cps")) { + ret = of_property_read_u32(oa_node, "oa-cps", &tc6->cps); + if (ret < 0) + return ret; + /* Return error if the configured cps is less than the + * minimum cps supported by the MAC-PHY. + */ + if (tc6->cps < mincps) + return -ENODEV; + } else { + tc6->cps = 64; + } + if (of_property_present(oa_node, "oa-txcte")) { + /* Return error if the tx cut through mode is configured + * but it is not supported by MAC-PHY. + */ + if (ctc) + regval |= TXCTE; + else + return -ENODEV; + } + if (of_property_present(oa_node, "oa-rxcte")) { + /* Return error if the rx cut through mode is configured + * but it is not supported by MAC-PHY. + */ + if (ctc) + regval |= RXCTE; + else + return -ENODEV; + } + if (of_property_present(oa_node, "oa-prote")) { + regval |= PROTE; + tc6->prote = true; + } + } else { + tc6->cps = 64; + } + + regval |= FIELD_PREP(CPS, ilog2(tc6->cps) / ilog2(2)) | SYNC; + + return oa_tc6_perform_ctrl(tc6, CONFIG0, ®val, 1, true, false); +} + static int oa_tc6_sw_reset(struct oa_tc6 *tc6) { u32 regval; @@ -310,7 +387,7 @@ EXPORT_SYMBOL_GPL(oa_tc6_read_registers); * Returns pointer reference to the oa_tc6 structure if all the memory * allocation success otherwise NULL. */ -struct oa_tc6 *oa_tc6_init(struct spi_device *spi, bool prote) +struct oa_tc6 *oa_tc6_init(struct spi_device *spi) { struct oa_tc6 *tc6; @@ -327,7 +404,6 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, bool prote) return NULL; tc6->spi = spi; - tc6->prote = prote; /* Perform MAC-PHY software reset */ if (oa_tc6_sw_reset(tc6)) { @@ -335,6 +411,12 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, bool prote) return NULL; } + /* Perform OA parameters and MAC-PHY configuration */ + if (oa_tc6_configure(tc6)) { + dev_err(&spi->dev, "OA and MAC-PHY configuration failed\n"); + return NULL; + } + return tc6; } EXPORT_SYMBOL_GPL(oa_tc6_init); diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h index 8a838499da97..378636fd9ca8 100644 --- a/include/linux/oa_tc6.h +++ b/include/linux/oa_tc6.h @@ -22,15 +22,37 @@ #define TC6_CTRL_BUF_SIZE 1032 /* Max ctrl buffer size for 128 regs */ /* Open Alliance TC6 Standard Control and Status Registers */ +/* Standard Capabilities Register */ +#define STDCAP 0x0002 +#define CTC BIT(7) /* Cut-Through Capability */ +#define MINCPS GENMASK(2, 0) /* Minimum supported cps */ + /* Reset Control and Status Register */ #define RESET 0x0003 #define SWRESET BIT(0) /* Software Reset */ +/* Configuration Register #0 */ +#define CONFIG0 0x0004 +#define SYNC BIT(15) /* Configuration Synchronization */ +#define TXCTE BIT(9) /* Tx cut-through enable */ +#define RXCTE BIT(8) /* Rx cut-through enable */ +#define PROTE BIT(5) /* Ctrl read/write Protection Enable */ +#define CPS GENMASK(2, 0) /* Chunk Payload Size */ + /* Status Register #0 */ #define STATUS0 0x0008 #define RESETC BIT(6) /* Reset Complete */ -struct oa_tc6 *oa_tc6_init(struct spi_device *spi, bool prote); +/* Interrupt Mask Register #0 */ +#define IMASK0 0x000C +#define HDREM BIT(5) /* Header Error Mask */ +#define LOFEM BIT(4) /* Loss of Framing Error Mask */ +#define RXBOEM BIT(3) /* Rx Buffer Overflow Error Mask */ +#define TXBUEM BIT(2) /* Tx Buffer Underflow Error Mask */ +#define TXBOEM BIT(1) /* Tx Buffer Overflow Error Mask */ +#define TXPEM BIT(0) /* Tx Protocol Error Mask */ + +struct oa_tc6 *oa_tc6_init(struct spi_device *spi); int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 val); int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 *val); int oa_tc6_write_registers(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len); From patchwork Mon Oct 23 15:46:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parthiban Veerasooran X-Patchwork-Id: 13433075 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5A9771C291; Mon, 23 Oct 2023 15:48:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="YwBQaOdE" Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D3E6AE9; Mon, 23 Oct 2023 08:48:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1698076086; x=1729612086; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=b9l7jWwFPMAuzQs/YBtDqS7+V1WAQBtPurYwM8FLNtI=; b=YwBQaOdEIDc4sz3OiL0snkWXbHAUkLmzLWdRhvVZkZwaQi8T8tDvJQEv XutM6nbjywMZR5hzNJWV4c+DB3da7qQNCZ+z2DU+v+Y10H/eCGzf/jg2x ifdZZzwriynmHE03Y9fjbYBkngttn4kIx/x+ZEIwUmUp9/nwQioA8cByr pE9QWrDO1OajBFFbOH3QK0j1w3X9yNS/551W5Md7v+wR3mkpB2zVEekh/ eWrZG6RKq5xZeTUw5r9OlnSWEVJ30JfHW5E73QoMFqPmrjKjl8dELODp4 kNuOzN+9PI1zY0QZ+4jfcFW8HFHTeO01Gbo6wTdIdoqSBltov5dJP3tK5 g==; X-CSE-ConnectionGUID: klqWPg5QRmSazEzEhLffbg== X-CSE-MsgGUID: OkqgdSelQ7et0cyfBRDkVw== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.03,244,1694761200"; d="scan'208";a="241208148" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa5.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Oct 2023 08:48:04 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Mon, 23 Oct 2023 08:48:02 -0700 Received: from CHE-LT-I17164LX.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.21 via Frontend Transport; Mon, 23 Oct 2023 08:47:50 -0700 From: Parthiban Veerasooran To: , , , , , , , , , , , , CC: , , , , , , , , , Parthiban Veerasooran Subject: [PATCH net-next v2 4/9] dt-bindings: net: add OPEN Alliance 10BASE-T1x MAC-PHY Serial Interface Date: Mon, 23 Oct 2023 21:16:44 +0530 Message-ID: <20231023154649.45931-5-Parthiban.Veerasooran@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> References: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org Add DT bindings OPEN Alliance 10BASE-T1x MACPHY Serial Interface parameters. These are generic properties that can apply to any 10BASE-T1x MAC-PHY which uses OPEN Alliance TC6 specification. Signed-off-by: Parthiban Veerasooran --- .../devicetree/bindings/net/oa-tc6.yaml | 72 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 73 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/oa-tc6.yaml diff --git a/Documentation/devicetree/bindings/net/oa-tc6.yaml b/Documentation/devicetree/bindings/net/oa-tc6.yaml new file mode 100644 index 000000000000..9f442fa6cace --- /dev/null +++ b/Documentation/devicetree/bindings/net/oa-tc6.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/oa-tc6.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OPEN Alliance 10BASE-T1x MAC-PHY Specification Common Properties + +maintainers: + - Parthiban Veerasooran + +description: + These are generic properties that can apply to any 10BASE-T1x MAC-PHY + which uses OPEN Alliance TC6 specification. + + 10BASE-T1x MAC-PHY Serial Interface Specification can be found at: + https://opensig.org/about/specifications/ + +properties: + $nodename: + pattern: "^oa-tc6(@.*)?" + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + oa-cps: + maxItems: 1 + description: + Chunk Payload Size. Configures the data chunk payload size to 2^N, + where N is the value of this bitfield. The minimum possible data + chunk payload size is 8 bytes or N = 3. The default data chunk + payload size is 64 bytes, or N = 6. The minimum supported data chunk + payload size for this MAC-PHY device is indicated in the CPSMIN + field of the CAPABILITY register. Valid values for this parameter + are 8, 16, 32 and 64. All other values are reserved. + + oa-txcte: + maxItems: 1 + description: + Transmit Cut-Through Enable. When supported by this MAC-PHY device, + this bit enables the cut-through mode of frame transfer through the + MAC-PHY device from the SPI host to the network. + + oa-rxcte: + maxItems: 1 + description: + Receive Cut-Through Enable. When supported by this MAC-PHY device, + this bit enables the cut-through mode of frame transfer through the + MAC-PHY device from the network to the SPI host. + + oa-prote: + maxItems: 1 + description: + Control data read/write Protection Enable. When set, all control + data written to and read from the MAC-PHY will be transferred with + its complement for detection of bit errors. + +additionalProperties: true + +examples: + - | + oa-tc6 { + #address-cells = <1>; + #size-cells = <0>; + oa-cps = <64>; + oa-txcte; + oa-rxcte; + oa-prote; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 1c165026bbd4..9580be91f5e9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15975,6 +15975,7 @@ OPEN ALLIANCE 10BASE-T1S MACPHY SERIAL INTERFACE FRAMEWORK M: Parthiban Veerasooran L: netdev@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/net/oa-tc6.yaml F: Documentation/networking/oa-tc6-framework.rst F: drivers/include/linux/oa_tc6.h F: drivers/net/ethernet/oa_tc6.c From patchwork Mon Oct 23 15:46:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Parthiban Veerasooran X-Patchwork-Id: 13433076 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2156C1BDFD; Mon, 23 Oct 2023 15:48:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="vPtHXHgO" Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7E35510C1; Mon, 23 Oct 2023 08:48:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1698076101; x=1729612101; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=aKOyYh8+vIo+d2j/qQ/62TebL7XNgXjBI6Y8djFnusY=; b=vPtHXHgO5nsRTM1sYqUpNKW4ZKQTgosm4NsNPsA28urqsxRo5ZT+MwBW biNNUMIkUB9WR1CurTZObrj4uzFBQHGR1sMf6rbTkVvuQwkYbo0A37sg4 2d6r2FZ3oXDVibWvxqfz3PBJ8jpb8mq9s+kH55L85EiDdT+AnjdjkluSx NGXb91bgvGOSE36aXXp6vRtIKRGU8LNSdN23asG/TLA3cARCcsHGMuDAL SWsrSa5dnEeSokS2nRGWt6ixB0ah2oKFXdjGL1/5HmWHDpOyFOqaBwEIG KxWuNGBHgb3GduiInzX6/6goHnLK+3KIcJa2R4MLTU2RfFx+izqGTebDr Q==; X-CSE-ConnectionGUID: 5dJfxnw6T/GgyIcRbipreg== X-CSE-MsgGUID: Saz8qzNpQNGuhgULQlpWSw== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.03,244,1694761200"; d="scan'208";a="177613862" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa6.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Oct 2023 08:48:20 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Mon, 23 Oct 2023 08:48:16 -0700 Received: from CHE-LT-I17164LX.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.21 via Frontend Transport; Mon, 23 Oct 2023 08:48:03 -0700 From: Parthiban Veerasooran To: , , , , , , , , , , , , CC: , , , , , , , , , Parthiban Veerasooran Subject: [PATCH net-next v2 5/9] net: ethernet: oa_tc6: implement internal PHY initialization Date: Mon, 23 Oct 2023 21:16:45 +0530 Message-ID: <20231023154649.45931-6-Parthiban.Veerasooran@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> References: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org 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. Signed-off-by: Parthiban Veerasooran --- drivers/net/ethernet/oa_tc6.c | 157 ++++++++++++++++++++++++++++++++-- include/linux/oa_tc6.h | 65 +++++++------- 2 files changed, 187 insertions(+), 35 deletions(-) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index 9a98d59f286d..a4532c83e909 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -6,16 +6,23 @@ */ #include -#include #include +#include +#include #include #include /* Opaque structure for MACPHY drivers */ struct oa_tc6 { + struct net_device *netdev; + struct phy_device *phydev; + struct mii_bus *mdiobus; struct spi_device *spi; + struct device *dev; u8 *ctrl_tx_buf; u8 *ctrl_rx_buf; + bool dprac; + bool iprac; bool prote; u32 cps; }; @@ -204,6 +211,8 @@ static int oa_tc6_configure(struct oa_tc6 *tc6) { struct spi_device *spi = tc6->spi; struct device_node *oa_node; + bool dprac; + bool iprac; u32 regval; u8 mincps; bool ctc; @@ -225,8 +234,14 @@ static int oa_tc6_configure(struct oa_tc6 *tc6) if (ret) return ret; + /* Minimum supported Chunk Payload Size */ mincps = FIELD_GET(MINCPS, regval); + /* Cut-Through Capability */ ctc = (regval & CTC) ? true : false; + /* Direct PHY Register Access Capability */ + dprac = (regval & DPRAC) ? true : false; + /* Indirect PHY Register access Capability */ + iprac = (regval & IPRAC) ? true : false; regval = 0; oa_node = of_get_child_by_name(spi->dev.of_node, "oa-tc6"); @@ -242,7 +257,7 @@ static int oa_tc6_configure(struct oa_tc6 *tc6) if (tc6->cps < mincps) return -ENODEV; } else { - tc6->cps = 64; + tc6->cps = OA_TC6_MAX_CPS; } if (of_property_present(oa_node, "oa-txcte")) { /* Return error if the tx cut through mode is configured @@ -266,8 +281,26 @@ static int oa_tc6_configure(struct oa_tc6 *tc6) regval |= PROTE; tc6->prote = true; } + if (of_property_present(oa_node, "oa-dprac")) { + /* Return error if the direct phy register access mode + * is configured but it is not supported by MAC-PHY. + */ + if (dprac) + tc6->dprac = true; + else + return -ENODEV; + } + if (of_property_present(oa_node, "oa-iprac")) { + /* Return error if the indirect phy register access mode + * is configured but it is not supported by MAC-PHY. + */ + if (iprac) + tc6->iprac = true; + else + return -ENODEV; + } } else { - tc6->cps = 64; + tc6->cps = OA_TC6_MAX_CPS; } regval |= FIELD_PREP(CPS, ilog2(tc6->cps) / ilog2(2)) | SYNC; @@ -379,15 +412,108 @@ int oa_tc6_read_registers(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len) } EXPORT_SYMBOL_GPL(oa_tc6_read_registers); +static void oa_tc6_handle_link_change(struct net_device *netdev) +{ + phy_print_status(netdev->phydev); +} + +static int oa_tc6_mdiobus_read(struct mii_bus *bus, int phy_id, int idx) +{ + struct oa_tc6 *tc6 = bus->priv; + u32 regval; + bool ret; + + ret = oa_tc6_read_register(tc6, 0xFF00 | (idx & 0xFF), ®val); + if (ret) + return -ENODEV; + + return regval; +} + +static int oa_tc6_mdiobus_write(struct mii_bus *bus, int phy_id, int idx, + u16 val) +{ + struct oa_tc6 *tc6 = bus->priv; + + return oa_tc6_write_register(tc6, 0xFF00 | (idx & 0xFF), val); +} + +static int oa_tc6_phy_init(struct oa_tc6 *tc6) +{ + int ret; + + if (tc6->dprac) { + tc6->mdiobus = mdiobus_alloc(); + if (!tc6->mdiobus) { + netdev_err(tc6->netdev, "MDIO bus alloc failed\n"); + return -ENODEV; + } + + tc6->mdiobus->phy_mask = ~(u32)BIT(1); + tc6->mdiobus->priv = tc6; + tc6->mdiobus->read = oa_tc6_mdiobus_read; + tc6->mdiobus->write = oa_tc6_mdiobus_write; + 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); + return ret; + } + + tc6->phydev = phy_find_first(tc6->mdiobus); + if (!tc6->phydev) { + netdev_err(tc6->netdev, "No PHY found\n"); + mdiobus_unregister(tc6->mdiobus); + mdiobus_free(tc6->mdiobus); + 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); + mdiobus_unregister(tc6->mdiobus); + mdiobus_free(tc6->mdiobus); + return ret; + } + + phy_attached_info(tc6->netdev->phydev); + + return ret; + } else if (tc6->iprac) { + // To be implemented. Currently returns -ENODEV. + return -ENODEV; + } else { + return -ENODEV; + } + return 0; +} + +static void oa_tc6_phy_exit(struct oa_tc6 *tc6) +{ + phy_disconnect(tc6->phydev); + mdiobus_unregister(tc6->mdiobus); + mdiobus_free(tc6->mdiobus); +} + /** * oa_tc6_init - allocates and intializes oa_tc6 structure. * @spi: device with which data will be exchanged. - * @prote: control data (register) read/write protection enable/disable. + * @netdev: network device to use. * * Returns pointer reference to the oa_tc6 structure if all the memory * allocation success otherwise NULL. */ -struct oa_tc6 *oa_tc6_init(struct spi_device *spi) +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev) { struct oa_tc6 *tc6; @@ -395,15 +521,19 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi) if (!tc6) return NULL; + /* Allocate memory for the control tx buffer used for SPI transfer. */ tc6->ctrl_tx_buf = devm_kzalloc(&spi->dev, TC6_CTRL_BUF_SIZE, GFP_KERNEL); if (!tc6->ctrl_tx_buf) return NULL; + /* Allocate memory for the control rx buffer used for SPI transfer. */ tc6->ctrl_rx_buf = devm_kzalloc(&spi->dev, TC6_CTRL_BUF_SIZE, GFP_KERNEL); if (!tc6->ctrl_rx_buf) return NULL; tc6->spi = spi; + tc6->netdev = netdev; + SET_NETDEV_DEV(netdev, &spi->dev); /* Perform MAC-PHY software reset */ if (oa_tc6_sw_reset(tc6)) { @@ -417,10 +547,27 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi) return NULL; } + /* Initialize PHY */ + if (oa_tc6_phy_init(tc6)) { + dev_err(&spi->dev, "PHY initialization failed\n"); + return NULL; + } + return tc6; } EXPORT_SYMBOL_GPL(oa_tc6_init); +/** + * oa_tc6_exit - exit function. + * @tc6: oa_tc6 struct. + * + */ +void oa_tc6_exit(struct oa_tc6 *tc6) +{ + oa_tc6_phy_exit(tc6); +} +EXPORT_SYMBOL_GPL(oa_tc6_exit); + MODULE_DESCRIPTION("OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface Lib"); MODULE_AUTHOR("Parthiban Veerasooran "); MODULE_LICENSE("GPL"); diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h index 378636fd9ca8..36b729c384ac 100644 --- a/include/linux/oa_tc6.h +++ b/include/linux/oa_tc6.h @@ -5,54 +5,59 @@ * Author: Parthiban Veerasooran */ +#include #include /* Control header */ -#define CTRL_HDR_DNC BIT(31) /* Data-Not-Control */ -#define CTRL_HDR_HDRB BIT(30) /* Received Header Bad */ -#define CTRL_HDR_WNR BIT(29) /* Write-Not-Read */ -#define CTRL_HDR_AID BIT(28) /* Address Increment Disable */ -#define CTRL_HDR_MMS GENMASK(27, 24) /* Memory Map Selector */ -#define CTRL_HDR_ADDR GENMASK(23, 8) /* Address */ -#define CTRL_HDR_LEN GENMASK(7, 1) /* Length */ -#define CTRL_HDR_P BIT(0) /* Parity Bit */ +#define CTRL_HDR_DNC BIT(31) /* Data-Not-Control */ +#define CTRL_HDR_HDRB BIT(30) /* Received Header Bad */ +#define CTRL_HDR_WNR BIT(29) /* Write-Not-Read */ +#define CTRL_HDR_AID BIT(28) /* Address Increment Disable */ +#define CTRL_HDR_MMS GENMASK(27, 24) /* Memory Map Selector */ +#define CTRL_HDR_ADDR GENMASK(23, 8) /* Address */ +#define CTRL_HDR_LEN GENMASK(7, 1) /* Length */ +#define CTRL_HDR_P BIT(0) /* Parity Bit */ #define TC6_HDR_SIZE 4 /* Ctrl command header size as per OA */ #define TC6_FTR_SIZE 4 /* Ctrl command footer size ss per OA */ #define TC6_CTRL_BUF_SIZE 1032 /* Max ctrl buffer size for 128 regs */ +#define OA_TC6_MAX_CPS 64 /* Open Alliance TC6 Standard Control and Status Registers */ /* Standard Capabilities Register */ -#define STDCAP 0x0002 -#define CTC BIT(7) /* Cut-Through Capability */ -#define MINCPS GENMASK(2, 0) /* Minimum supported cps */ +#define STDCAP 0x0002 +#define IPRAC BIT(9) /* Indirect PHY Reg access Capability */ +#define DPRAC BIT(8) /* Direct PHY Reg Access Capability */ +#define CTC BIT(7) /* Cut-Through Capability */ +#define MINCPS GENMASK(2, 0) /* Minimum supported cps */ /* Reset Control and Status Register */ -#define RESET 0x0003 -#define SWRESET BIT(0) /* Software Reset */ +#define RESET 0x0003 +#define SWRESET BIT(0) /* Software Reset */ /* Configuration Register #0 */ -#define CONFIG0 0x0004 -#define SYNC BIT(15) /* Configuration Synchronization */ -#define TXCTE BIT(9) /* Tx cut-through enable */ -#define RXCTE BIT(8) /* Rx cut-through enable */ -#define PROTE BIT(5) /* Ctrl read/write Protection Enable */ -#define CPS GENMASK(2, 0) /* Chunk Payload Size */ +#define CONFIG0 0x0004 +#define SYNC BIT(15) /* Configuration Synchronization */ +#define TXCTE BIT(9) /* Tx cut-through enable */ +#define RXCTE BIT(8) /* Rx cut-through enable */ +#define PROTE BIT(5) /* Ctrl read/write Protection Enable */ +#define CPS GENMASK(2, 0) /* Chunk Payload Size */ /* Status Register #0 */ -#define STATUS0 0x0008 -#define RESETC BIT(6) /* Reset Complete */ +#define STATUS0 0x0008 +#define RESETC BIT(6) /* Reset Complete */ /* Interrupt Mask Register #0 */ -#define IMASK0 0x000C -#define HDREM BIT(5) /* Header Error Mask */ -#define LOFEM BIT(4) /* Loss of Framing Error Mask */ -#define RXBOEM BIT(3) /* Rx Buffer Overflow Error Mask */ -#define TXBUEM BIT(2) /* Tx Buffer Underflow Error Mask */ -#define TXBOEM BIT(1) /* Tx Buffer Overflow Error Mask */ -#define TXPEM BIT(0) /* Tx Protocol Error Mask */ - -struct oa_tc6 *oa_tc6_init(struct spi_device *spi); +#define IMASK0 0x000C +#define HDREM BIT(5) /* Header Error Mask */ +#define LOFEM BIT(4) /* Loss of Framing Error Mask */ +#define RXBOEM BIT(3) /* Rx Buffer Overflow Error Mask */ +#define TXBUEM BIT(2) /* Tx Buffer Underflow Error Mask */ +#define TXBOEM BIT(1) /* Tx Buffer Overflow Error Mask */ +#define TXPEM BIT(0) /* Tx Protocol Error Mask */ + +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev); +void oa_tc6_exit(struct oa_tc6 *tc6); int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 val); int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 *val); int oa_tc6_write_registers(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len); From patchwork Mon Oct 23 15:46:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parthiban Veerasooran X-Patchwork-Id: 13433077 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EE614291E; Mon, 23 Oct 2023 15:48:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="XcEQeZtA" Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 514E2D78; Mon, 23 Oct 2023 08:48:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1698076124; x=1729612124; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=319+vSZztvLLamoEF3n0o2ZCH6mocDPpJVQBgHHyFrE=; b=XcEQeZtA4ReGOaXZ7E4oPLMHZPutMmkwZVYpV1G1lYL+nftrxQNuCDVG OmAXV4a3aCqvPEPwiymz2eanSDPemCrOk0ePd2r4+OJ7IM7hsf3l3PGqL GkJIDjbpjJIskGkNZtNEGJXZsGYODLjqsz661AvzS05S3SqPcRIVmpOMl A5A703lMD1ha+SzWwgbWSUtgws93jVf0i8pHMUuNez0qVinamm/bt0Gbw +BOVgDWkrNUiHLaThllVhqQ8+mXw8uOg+/wCJSHmMqAIHVppzAJS/OB7n nnj+cgDLB2lnoMp3VZiGPoeG1mQTEAEhVBQjFR5N/FECy1zmHWYVnZuMa g==; X-CSE-ConnectionGUID: 3fgSQoFlQtGqppEDCSfPXA== X-CSE-MsgGUID: 9FbTWUEDSxOq5imcHkIxXQ== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.03,244,1694761200"; d="scan'208";a="241208203" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa5.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Oct 2023 08:48:44 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Mon, 23 Oct 2023 08:48:30 -0700 Received: from CHE-LT-I17164LX.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.21 via Frontend Transport; Mon, 23 Oct 2023 08:48:17 -0700 From: Parthiban Veerasooran To: , , , , , , , , , , , , CC: , , , , , , , , , Parthiban Veerasooran Subject: [PATCH net-next v2 6/9] dt-bindings: net: oa-tc6: add PHY register access capability Date: Mon, 23 Oct 2023 21:16:46 +0530 Message-ID: <20231023154649.45931-7-Parthiban.Veerasooran@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> References: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org 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. Signed-off-by: Parthiban Veerasooran --- Documentation/devicetree/bindings/net/oa-tc6.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/net/oa-tc6.yaml b/Documentation/devicetree/bindings/net/oa-tc6.yaml index 9f442fa6cace..09f1c11c68b9 100644 --- a/Documentation/devicetree/bindings/net/oa-tc6.yaml +++ b/Documentation/devicetree/bindings/net/oa-tc6.yaml @@ -58,6 +58,18 @@ properties: data written to and read from the MAC-PHY will be transferred with its complement for detection of bit errors. + oa-dprac: + maxItems: 1 + description: + Direct PHY Register Access Capability. Indicates if PHY registers + are directly accessible within the SPI register memory space. + + oa-dprac: + maxItems: 1 + description: + Indirect PHY Register Access Capability. Indicates if PHY registers + are indirectly accessible through the MDIO/MDC registers MDIOACCn. + additionalProperties: true examples: @@ -69,4 +81,6 @@ examples: oa-txcte; oa-rxcte; oa-prote; + oa-dprac; + oa-iprac; }; From patchwork Mon Oct 23 15:46:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Parthiban Veerasooran X-Patchwork-Id: 13433080 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 27B451CA9C; Mon, 23 Oct 2023 15:49:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="y+FtTpZ7" Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.153.233]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3809710E2; Mon, 23 Oct 2023 08:49:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1698076181; x=1729612181; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=n/izdiZhTIAFpixIdmHImp1j/dWWgoDq11M5yXTYGQk=; b=y+FtTpZ7aeV7zD5ssUNDxtEK/ilsnrF4QlG0xUxmAs7jzGeDaBl+V564 E2qip0F1SVdBdk8Bt8/JhZYtfjuoLYNiP2V4l+Wl5LlXUYylWz6JwXazT rD4g4zTTTsb8fQk/jyHKbMOqcq3+5uON1luQ3n/g/WT90rekB5luvdgrW iiFS4dwW87AM/3IkTQXuuSVuAbnHc18Z8q4i65H8Hi71A2uySU3A31NQl 8hPiBkObxUV5vZ8+cW2/YVzhNVjLNJE8wcE+lyVS9k9fwpcWCZm1/Cpcf yMW3faBAuIVfygl4yE9t58/VEgvi5VcIcPZEuEGwS/0eMf/LvFXXWAKLU g==; X-CSE-ConnectionGUID: QHZHViV/SCKDGxPPfhUelg== X-CSE-MsgGUID: Jfx4f8Y7TT2VvZGTiS4uyQ== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.03,244,1694761200"; d="scan'208";a="241208245" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa5.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Oct 2023 08:49:40 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Mon, 23 Oct 2023 08:48:44 -0700 Received: from CHE-LT-I17164LX.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.21 via Frontend Transport; Mon, 23 Oct 2023 08:48:30 -0700 From: Parthiban Veerasooran To: , , , , , , , , , , , , CC: , , , , , , , , , Parthiban Veerasooran Subject: [PATCH net-next v2 7/9] net: ethernet: oa_tc6: implement data transaction interface Date: Mon, 23 Oct 2023 21:16:47 +0530 Message-ID: <20231023154649.45931-8-Parthiban.Veerasooran@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> References: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org The ethernet frame to be sent to MAC-PHY is converted into multiple transmit data chunks. A transmit data chunk consists of a 4-byte data header followed by the transmit data chunk payload. The received ethernet frame from the network is converted into multiple receive data chunks by the MAC-PHY and a receive data chunk consists of the receive data chunk payload followed by a 4-byte data footer at the end. The MAC-PHY shall support a default data chunk payload size of 64 bytes. Data chunk payload sizes of 32, 16, or 8 bytes may also be supported. The data chunk payload is always a multiple of 4 bytes. The 4-byte data header occurs at the beginning of each transmit data chunk on MOSI and the 4-byte data footer occurs at the end of each receive data chunk on MISO. The data header and footer contain the information needed to determine the validity and location of the transmit and receive frame data within the data chunk payload. Ethernet frames shall be aligned to a 32-bit boundary within the data chunk payload. Signed-off-by: Parthiban Veerasooran --- drivers/net/ethernet/oa_tc6.c | 546 +++++++++++++++++++++++++++++++++- include/linux/oa_tc6.h | 47 ++- 2 files changed, 591 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index a4532c83e909..1306ca0b0884 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -14,17 +14,36 @@ /* Opaque structure for MACPHY drivers */ struct oa_tc6 { + int (*config_cps_buf)(void *tc6, u32 cps); + struct work_struct tx_work; struct net_device *netdev; struct phy_device *phydev; struct mii_bus *mdiobus; struct spi_device *spi; + struct sk_buff *tx_skb; + bool rx_eth_started; struct device *dev; + /* Protects oa_tc6_perform_spi_xfer function elements between MAC-PHY + * interrupt handler and the tx work handler. + */ + struct mutex lock; u8 *ctrl_tx_buf; u8 *ctrl_rx_buf; + u8 *spi_tx_buf; + u8 *spi_rx_buf; + u8 *eth_tx_buf; + u8 *eth_rx_buf; + u16 rxd_bytes; + u8 txc_needed; + bool int_flag; + bool tx_flag; bool dprac; bool iprac; bool prote; + u16 tx_pos; u32 cps; + u8 txc; + u8 rca; }; static int oa_tc6_spi_transfer(struct spi_device *spi, u8 *ptx, u8 *prx, u16 len) @@ -55,6 +74,24 @@ static int oa_tc6_get_parity(u32 p) return !((p >> 28) & 1); } +static u16 oa_tc6_prepare_empty_chunk(struct oa_tc6 *tc6, u8 *buf, u8 cp_count) +{ + u32 hdr; + + /* Prepare empty chunks used for getting interrupt information or if + * receive data available. + */ + for (u8 i = 0; i < cp_count; i++) { + hdr = FIELD_PREP(DATA_HDR_DNC, 1); + hdr |= FIELD_PREP(DATA_HDR_P, oa_tc6_get_parity(hdr)); + *(__be32 *)&buf[i * (tc6->cps + TC6_HDR_SIZE)] = cpu_to_be32(hdr); + memset(&buf[TC6_HDR_SIZE + (i * (tc6->cps + TC6_HDR_SIZE))], 0, + tc6->cps); + } + + return cp_count * (tc6->cps + TC6_HDR_SIZE); +} + static void oa_tc6_prepare_ctrl_buf(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len, bool wnr, u8 *buf, bool prote) { @@ -218,6 +255,14 @@ static int oa_tc6_configure(struct oa_tc6 *tc6) bool ctc; int ret; + /* Read BUFSTS register to get the current txc and rca. */ + ret = oa_tc6_read_register(tc6, OA_TC6_BUFSTS, ®val); + if (ret) + return ret; + + tc6->txc = FIELD_GET(TXC, regval); + tc6->rca = FIELD_GET(RCA, regval); + /* Read and configure the IMASK0 register for unmasking the interrupts */ ret = oa_tc6_perform_ctrl(tc6, IMASK0, ®val, 1, false, false); if (ret) @@ -259,6 +304,12 @@ static int oa_tc6_configure(struct oa_tc6 *tc6) } else { tc6->cps = OA_TC6_MAX_CPS; } + /* Call queue buffer size config function if defined by MAC */ + if (tc6->config_cps_buf) { + ret = tc6->config_cps_buf(tc6, tc6->cps); + if (ret) + return ret; + } if (of_property_present(oa_node, "oa-txcte")) { /* Return error if the tx cut through mode is configured * but it is not supported by MAC-PHY. @@ -498,6 +549,240 @@ static int oa_tc6_phy_init(struct oa_tc6 *tc6) return 0; } +static int oa_tc6_process_exst(struct oa_tc6 *tc6) +{ + u32 regval; + int ret; + + ret = oa_tc6_read_register(tc6, STATUS0, ®val); + if (ret) + return ret; + + if (regval & TXPE) + net_err_ratelimited("%s: Transmit protocol error\n", + tc6->netdev->name); + + if (regval & TXBOE) + net_err_ratelimited("%s: Transmit buffer overflow\n", + tc6->netdev->name); + + if (regval & TXBUE) + net_err_ratelimited("%s: Transmit buffer underflow\n", + tc6->netdev->name); + + if (regval & RXBOE) + net_err_ratelimited("%s: Receive buffer overflow\n", + tc6->netdev->name); + + if (regval & LOFE) + net_err_ratelimited("%s: Loss of frame\n", tc6->netdev->name); + + if (regval & HDRE) + net_err_ratelimited("%s: Header error\n", tc6->netdev->name); + + if (regval & TXFCSE) + net_err_ratelimited("%s: Tx Frame Check Seq Error\n", + tc6->netdev->name); + + return oa_tc6_write_register(tc6, STATUS0, regval); +} + +static void oa_tc6_rx_eth_ready(struct oa_tc6 *tc6) +{ + struct sk_buff *skb; + + /* Send the received ethernet packet to network layer */ + skb = netdev_alloc_skb(tc6->netdev, tc6->rxd_bytes + NET_IP_ALIGN); + if (!skb) { + tc6->netdev->stats.rx_dropped++; + netdev_dbg(tc6->netdev, "Out of memory for rx'd frame"); + } else { + skb_reserve(skb, NET_IP_ALIGN); + memcpy(skb_put(skb, tc6->rxd_bytes), &tc6->eth_rx_buf[0], + tc6->rxd_bytes); + skb->protocol = eth_type_trans(skb, tc6->netdev); + tc6->netdev->stats.rx_packets++; + tc6->netdev->stats.rx_bytes += tc6->rxd_bytes; + /* 0 for NET_RX_SUCCESS and 1 for NET_RX_DROP */ + if (netif_rx(skb)) + tc6->netdev->stats.rx_dropped++; + } +} + +static void oa_tc6_rx_eth_complete2(struct oa_tc6 *tc6, u8 *payload, u32 ftr) +{ + u16 ebo; + + if (FIELD_GET(DATA_FTR_EV, ftr)) + ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1; + else + ebo = tc6->cps; + + memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes], &payload[0], ebo); + tc6->rxd_bytes += ebo; + if (FIELD_GET(DATA_FTR_EV, ftr)) { + /* If EV set then send the received ethernet frame to n/w */ + oa_tc6_rx_eth_ready(tc6); + tc6->rxd_bytes = 0; + tc6->rx_eth_started = false; + } +} + +static void oa_tc6_rx_eth_complete1(struct oa_tc6 *tc6, u8 *payload, u32 ftr) +{ + u16 ebo; + u16 sbo; + + sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4; + ebo = FIELD_GET(DATA_FTR_EBO, ftr) + 1; + + if (ebo <= sbo) { + memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes], &payload[0], ebo); + tc6->rxd_bytes += ebo; + oa_tc6_rx_eth_ready(tc6); + tc6->rxd_bytes = 0; + memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes], &payload[sbo], + tc6->cps - sbo); + tc6->rxd_bytes += (tc6->cps - sbo); + } else { + memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes], &payload[sbo], + ebo - sbo); + tc6->rxd_bytes += (ebo - sbo); + oa_tc6_rx_eth_ready(tc6); + tc6->rxd_bytes = 0; + } +} + +static void oa_tc6_start_rx_eth(struct oa_tc6 *tc6, u8 *payload, u32 ftr) +{ + u16 sbo; + + tc6->rxd_bytes = 0; + tc6->rx_eth_started = true; + sbo = FIELD_GET(DATA_FTR_SWO, ftr) * 4; + memcpy(&tc6->eth_rx_buf[tc6->rxd_bytes], &payload[sbo], tc6->cps - sbo); + tc6->rxd_bytes += (tc6->cps - sbo); +} + +static u32 oa_tc6_get_footer(struct oa_tc6 *tc6, u8 *buf, u8 cp_num) +{ + __be32 ftr; + + ftr = *(__be32 *)&buf[tc6->cps + (cp_num * (tc6->cps + TC6_FTR_SIZE))]; + + return be32_to_cpu(ftr); +} + +static void oa_tc6_update_txc_rca(struct oa_tc6 *tc6, u32 ftr) +{ + tc6->txc = FIELD_GET(DATA_FTR_TXC, ftr); + tc6->rca = FIELD_GET(DATA_FTR_RCA, ftr); +} + +static int oa_tc6_check_ftr_errors(struct oa_tc6 *tc6, u32 ftr) +{ + /* Check for footer parity error */ + if (oa_tc6_get_parity(ftr)) { + net_err_ratelimited("%s: Footer parity error\n", + tc6->netdev->name); + return FTR_ERR; + } + /* If EXST set in the footer then read STS0 register to get the + * status information. + */ + if (FIELD_GET(DATA_FTR_EXST, ftr)) { + if (oa_tc6_process_exst(tc6)) + net_err_ratelimited("%s: Failed to process EXST\n", + tc6->netdev->name); + return FTR_ERR; + } + if (FIELD_GET(DATA_FTR_HDRB, ftr)) { + net_err_ratelimited("%s: Footer eeceived header bad\n", + tc6->netdev->name); + return FTR_ERR; + } + if (!FIELD_GET(DATA_FTR_SYNC, ftr)) { + net_err_ratelimited("%s: Footer configuration unsync\n", + tc6->netdev->name); + return FTR_ERR; + } + return FTR_OK; +} + +static void oa_tc6_drop_rx_eth(struct oa_tc6 *tc6) +{ + tc6->rxd_bytes = 0; + tc6->rx_eth_started = false; + tc6->netdev->stats.rx_dropped++; + net_err_ratelimited("%s: Footer frame drop\n", + tc6->netdev->name); +} + +static int oa_tc6_process_rx_chunks(struct oa_tc6 *tc6, u8 *buf, u16 len) +{ + u8 cp_count; + u8 *payload; + u32 ftr; + int ret; + + /* Calculate the number of chunks received */ + cp_count = len / (tc6->cps + TC6_FTR_SIZE); + + for (u8 i = 0; i < cp_count; i++) { + /* Get the footer and payload */ + ftr = oa_tc6_get_footer(tc6, buf, i); + payload = &buf[(i * (tc6->cps + TC6_FTR_SIZE))]; + /* Check for footer errors */ + ret = oa_tc6_check_ftr_errors(tc6, ftr); + if (ret) { + if (tc6->rx_eth_started) + oa_tc6_drop_rx_eth(tc6); + return ret; + } + /* If Frame Drop is set, indicates that the MAC has detected a + * condition for which the SPI host should drop the received + * ethernet frame. + */ + if (FIELD_GET(DATA_FTR_FD, ftr) && FIELD_GET(DATA_FTR_EV, ftr)) { + if (tc6->rx_eth_started) + oa_tc6_drop_rx_eth(tc6); + + if (FIELD_GET(DATA_FTR_SV, ftr)) { + oa_tc6_start_rx_eth(tc6, payload, ftr); + oa_tc6_update_txc_rca(tc6, ftr); + } + continue; + } + /* Check for data valid */ + if (FIELD_GET(DATA_FTR_DV, ftr)) { + /* Check whether both start valid and end valid are in a + * single chunk payload means a single chunk payload may + * contain an entire ethernet frame. + */ + if (FIELD_GET(DATA_FTR_SV, ftr) && + FIELD_GET(DATA_FTR_EV, ftr)) { + oa_tc6_rx_eth_complete1(tc6, payload, ftr); + oa_tc6_update_txc_rca(tc6, ftr); + continue; + } + /* Check for start valid to start capturing the incoming + * ethernet frame. + */ + if (FIELD_GET(DATA_FTR_SV, ftr) && !tc6->rx_eth_started) { + oa_tc6_start_rx_eth(tc6, payload, ftr); + oa_tc6_update_txc_rca(tc6, ftr); + continue; + } + + /* Check for end valid and calculate the copy length */ + if (tc6->rx_eth_started) + oa_tc6_rx_eth_complete2(tc6, payload, ftr); + } + oa_tc6_update_txc_rca(tc6, ftr); + } + return FTR_OK; +} + static void oa_tc6_phy_exit(struct oa_tc6 *tc6) { phy_disconnect(tc6->phydev); @@ -505,17 +790,237 @@ static void oa_tc6_phy_exit(struct oa_tc6 *tc6) mdiobus_free(tc6->mdiobus); } +static void oa_tc6_prepare_tx_chunks(struct oa_tc6 *tc6, u8 *buf, + struct sk_buff *skb) +{ + bool frame_started = false; + u16 copied_bytes = 0; + u16 copy_len; + u32 hdr; + + /* Calculate the number tx credit counts needed to transport the tx + * ethernet frame. + */ + tc6->txc_needed = (skb->len / tc6->cps) + ((skb->len % tc6->cps) ? 1 : 0); + + for (u8 i = 0; i < tc6->txc_needed; i++) { + /* Prepare the header for each chunks to be transmitted */ + hdr = FIELD_PREP(DATA_HDR_DNC, 1) | + FIELD_PREP(DATA_HDR_DV, 1); + if (!frame_started) { + hdr |= FIELD_PREP(DATA_HDR_SV, 1) | + FIELD_PREP(DATA_HDR_SWO, 0); + frame_started = true; + } + if ((tc6->cps + copied_bytes) >= skb->len) { + copy_len = skb->len - copied_bytes; + hdr |= FIELD_PREP(DATA_HDR_EBO, copy_len - 1) | + FIELD_PREP(DATA_HDR_EV, 1); + } else { + copy_len = tc6->cps; + } + copied_bytes += copy_len; + hdr |= FIELD_PREP(DATA_HDR_P, oa_tc6_get_parity(hdr)); + *(__be32 *)&buf[i * (tc6->cps + TC6_HDR_SIZE)] = cpu_to_be32(hdr); + /* Copy the ethernet frame in the chunk payload section */ + memcpy(&buf[TC6_HDR_SIZE + (i * (tc6->cps + TC6_HDR_SIZE))], + &skb->data[copied_bytes - copy_len], copy_len); + } +} + +static u16 oa_tc6_calculate_tx_len(struct oa_tc6 *tc6) +{ + /* If the available txc is greater than the txc needed (calculated from + * the tx ethernet frame then the tx length can be txc needed. Else the + * tx length can be available txc and the remaining needed txc will be + * updated either in the footer of the current transfer or through the + * interrupt. + */ + if (tc6->txc >= tc6->txc_needed) + return tc6->txc_needed * (tc6->cps + TC6_HDR_SIZE); + else + return tc6->txc * (tc6->cps + TC6_HDR_SIZE); +} + +static u16 oa_tc6_calculate_rca_len(struct oa_tc6 *tc6, u16 tx_len) +{ + u16 rca_needed = 0; + u16 tx_txc; + + /* If tx eth frame and rca are available at the same time then check + * whether the rca is less than the needed txc for the tx eth frame. If + * not then add additional empty chunks along with the tx chunks to get + * all the rca. + */ + if (tc6->tx_flag && tc6->txc) { + tx_txc = tc6->txc_needed - (tx_len / (tc6->cps + TC6_HDR_SIZE)); + if (tx_txc < tc6->rca) + rca_needed = tc6->rca - tx_txc; + } else { + /* Add only empty chunks for rca if there is no tx chunks + * available to transmit. + */ + rca_needed = tc6->rca; + } + return oa_tc6_prepare_empty_chunk(tc6, &tc6->spi_tx_buf[tx_len], + rca_needed); +} + +static void oa_tc6_tx_eth_complete(struct oa_tc6 *tc6) +{ + tc6->netdev->stats.tx_packets++; + tc6->netdev->stats.tx_bytes += tc6->tx_skb->len; + dev_kfree_skb(tc6->tx_skb); + tc6->tx_pos = 0; + tc6->tx_skb = NULL; + tc6->tx_flag = false; + if (netif_queue_stopped(tc6->netdev)) + netif_wake_queue(tc6->netdev); +} + +static int oa_tc6_perform_spi_xfer(struct oa_tc6 *tc6) +{ + bool do_tx_again; + u16 total_len; + u16 rca_len; + u16 tx_len; + int ret; + + do { + do_tx_again = false; + rca_len = 0; + tx_len = 0; + + /* In case of an interrupt, perform an empty chunk transfer to + * know the purpose of the interrupt. Interrupt may occur in + * case of RCA (Receive Chunk Available) and TXC (Transmit + * Credit Count). Both will occur if they are not indicated + * through the previous footer. + */ + if (tc6->int_flag) { + tc6->int_flag = false; + total_len = oa_tc6_prepare_empty_chunk(tc6, + tc6->spi_tx_buf, + 1); + } else { + /* Calculate the transfer length */ + if (tc6->tx_flag && tc6->txc) { + tx_len = oa_tc6_calculate_tx_len(tc6); + memcpy(&tc6->spi_tx_buf[0], + &tc6->eth_tx_buf[tc6->tx_pos], tx_len); + } + + if (tc6->rca) + rca_len = oa_tc6_calculate_rca_len(tc6, tx_len); + + total_len = tx_len + rca_len; + } + ret = oa_tc6_spi_transfer(tc6->spi, tc6->spi_tx_buf, + tc6->spi_rx_buf, total_len); + if (ret) + return ret; + /* Process the rxd chunks to get the ethernet frame or status */ + ret = oa_tc6_process_rx_chunks(tc6, tc6->spi_rx_buf, total_len); + if (ret) + return ret; + if (tc6->tx_flag) { + tc6->tx_pos += tx_len; + tc6->txc_needed = tc6->txc_needed - + (tx_len / (tc6->cps + TC6_HDR_SIZE)); + /* If the complete ethernet frame is transmitted then + * return the skb and update the details to n/w layer. + */ + if (!tc6->txc_needed) + oa_tc6_tx_eth_complete(tc6); + else if (tc6->txc) + /* If txc is available again and updated from + * the previous footer then perform tx again. + */ + do_tx_again = true; + } + + /* If rca is updated from the previous footer then perform empty + * tx to receive ethernet frame. + */ + if (tc6->rca) + do_tx_again = true; + } while (do_tx_again); + + return 0; +} + +/* MAC-PHY interrupt handler */ +static irqreturn_t macphy_irq_handler(int irq, void *dev_id) +{ + struct oa_tc6 *tc6 = dev_id; + + tc6->int_flag = true; + mutex_lock(&tc6->lock); + if (oa_tc6_perform_spi_xfer(tc6)) + net_err_ratelimited("%s: SPI transfer failed\n", + tc6->netdev->name); + mutex_unlock(&tc6->lock); + + return IRQ_HANDLED; +} + +/* Workqueue to perform SPI transfer */ +static void tc6_tx_work_handler(struct work_struct *work) +{ + struct oa_tc6 *tc6 = container_of(work, struct oa_tc6, tx_work); + + mutex_lock(&tc6->lock); + if (oa_tc6_perform_spi_xfer(tc6)) + net_err_ratelimited("%s: SPI transfer failed\n", + tc6->netdev->name); + mutex_unlock(&tc6->lock); +} + +/** + * oa_tc6_send_eth_pkt - function for sending the tx ethernet frame. + * @tc6: oa_tc6 struct. + * @skb: socket buffer in which the ethernet frame is stored. + * + * As this is called from atomic context, work queue is used here because the + * spi_sync will block for the transfer completion. + * + * Returns NETDEV_TX_OK if the tx work is scheduled or NETDEV_TX_BUSY if the + * previous enqueued tx skb is in progress. + */ +netdev_tx_t oa_tc6_send_eth_pkt(struct oa_tc6 *tc6, struct sk_buff *skb) +{ + if (tc6->tx_flag) { + netif_stop_queue(tc6->netdev); + return NETDEV_TX_BUSY; + } + + tc6->tx_skb = skb; + /* Prepare tx chunks using the tx ethernet frame */ + oa_tc6_prepare_tx_chunks(tc6, tc6->eth_tx_buf, skb); + + tc6->tx_flag = true; + schedule_work(&tc6->tx_work); + + return NETDEV_TX_OK; +} +EXPORT_SYMBOL_GPL(oa_tc6_send_eth_pkt); + /** * oa_tc6_init - allocates and intializes oa_tc6 structure. * @spi: device with which data will be exchanged. * @netdev: network device to use. + * @config_cps_buf: function pointer passed by MAC driver to be called for + * configuring cps buffer size. Queue buffer size in the MAC has to be configured + * according to the cps. * * Returns pointer reference to the oa_tc6 structure if all the memory * allocation success otherwise NULL. */ -struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev) +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev, + int (*config_cps_buf)(void *tc6, u32 cps)) { struct oa_tc6 *tc6; + int ret; tc6 = devm_kzalloc(&spi->dev, sizeof(*tc6), GFP_KERNEL); if (!tc6) @@ -531,9 +1036,37 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev) if (!tc6->ctrl_rx_buf) return NULL; + /* Allocate memory for the tx buffer used for SPI transfer. */ + tc6->spi_tx_buf = devm_kzalloc(&spi->dev, ETH_LEN + (OA_TC6_MAX_CPS * TC6_HDR_SIZE), + GFP_KERNEL); + if (!tc6->spi_tx_buf) + return NULL; + + /* Allocate memory for the rx buffer used for SPI transfer. */ + tc6->spi_rx_buf = devm_kzalloc(&spi->dev, ETH_LEN + (OA_TC6_MAX_CPS * TC6_FTR_SIZE), + GFP_KERNEL); + if (!tc6->spi_rx_buf) + return NULL; + + /* Allocate memory for the tx ethernet chunks to transfer on SPI. */ + tc6->eth_tx_buf = devm_kzalloc(&spi->dev, ETH_LEN + (OA_TC6_MAX_CPS * TC6_HDR_SIZE), + GFP_KERNEL); + if (!tc6->eth_tx_buf) + return NULL; + + /* Allocate memory for the rx ethernet packet. */ + tc6->eth_rx_buf = devm_kzalloc(&spi->dev, ETH_LEN + (OA_TC6_MAX_CPS * TC6_FTR_SIZE), + GFP_KERNEL); + if (!tc6->eth_rx_buf) + return NULL; + tc6->spi = spi; tc6->netdev = netdev; SET_NETDEV_DEV(netdev, &spi->dev); + tc6->config_cps_buf = config_cps_buf; + /* Set the SPI controller to pump at realtime priority */ + spi->rt = true; + spi_setup(spi); /* Perform MAC-PHY software reset */ if (oa_tc6_sw_reset(tc6)) { @@ -552,6 +1085,16 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev) dev_err(&spi->dev, "PHY initialization failed\n"); return NULL; } + mutex_init(&tc6->lock); + INIT_WORK(&tc6->tx_work, tc6_tx_work_handler); + /* Register MAC-PHY interrupt service routine */ + ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, + macphy_irq_handler, IRQF_ONESHOT, + "macphy int", tc6); + if (ret) { + dev_err(&spi->dev, "Error attaching macphy irq %d\n", ret); + return NULL; + } return tc6; } @@ -564,6 +1107,7 @@ EXPORT_SYMBOL_GPL(oa_tc6_init); */ void oa_tc6_exit(struct oa_tc6 *tc6) { + devm_free_irq(&tc6->spi->dev, tc6->spi->irq, tc6); oa_tc6_phy_exit(tc6); } EXPORT_SYMBOL_GPL(oa_tc6_exit); diff --git a/include/linux/oa_tc6.h b/include/linux/oa_tc6.h index 36b729c384ac..58d1143f15ba 100644 --- a/include/linux/oa_tc6.h +++ b/include/linux/oa_tc6.h @@ -18,9 +18,39 @@ #define CTRL_HDR_LEN GENMASK(7, 1) /* Length */ #define CTRL_HDR_P BIT(0) /* Parity Bit */ +/* Data header */ +#define DATA_HDR_DNC BIT(31) /* Data-Not-Control */ +#define DATA_HDR_SEQ BIT(30) /* Data Chunk Sequence */ +#define DATA_HDR_NORX BIT(29) /* No Receive */ +#define DATA_HDR_DV BIT(21) /* Data Valid */ +#define DATA_HDR_SV BIT(20) /* Start Valid */ +#define DATA_HDR_SWO GENMASK(19, 16) /* Start Word Offset */ +#define DATA_HDR_EV BIT(14) /* End Valid */ +#define DATA_HDR_EBO GENMASK(13, 8) /* End Byte Offset */ +#define DATA_HDR_P BIT(0) /* Header Parity Bit */ + +/* Data footer */ +#define DATA_FTR_EXST BIT(31) /* Extended Status */ +#define DATA_FTR_HDRB BIT(30) /* Received Header Bad */ +#define DATA_FTR_SYNC BIT(29) /* Configuration Synchronized */ +#define DATA_FTR_RCA GENMASK(28, 24) /* Receive Chunks Available */ +#define DATA_FTR_DV BIT(21) /* Data Valid */ +#define DATA_FTR_SV BIT(20) /* Start Valid */ +#define DATA_FTR_SWO GENMASK(19, 16) /* Start Word Offset */ +#define DATA_FTR_FD BIT(15) /* Frame Drop */ +#define DATA_FTR_EV BIT(14) /* End Valid */ +#define DATA_FTR_EBO GENMASK(13, 8) /* End Byte Offset */ +#define DATA_FTR_TXC GENMASK(5, 1) /* Transmit Credits */ +#define DATA_FTR_P BIT(0) /* Footer Parity Bit */ + #define TC6_HDR_SIZE 4 /* Ctrl command header size as per OA */ #define TC6_FTR_SIZE 4 /* Ctrl command footer size ss per OA */ #define TC6_CTRL_BUF_SIZE 1032 /* Max ctrl buffer size for 128 regs */ + +#define FTR_OK 0 +#define FTR_ERR 1 + +#define ETH_LEN (ETH_DATA_LEN + ETH_HLEN + ETH_FCS_LEN) #define OA_TC6_MAX_CPS 64 /* Open Alliance TC6 Standard Control and Status Registers */ @@ -45,7 +75,20 @@ /* Status Register #0 */ #define STATUS0 0x0008 +#define CDPE BIT(12) /* Control Data Protection Error */ +#define TXFCSE BIT(11) /* Transmit Frame Check Sequence Error */ #define RESETC BIT(6) /* Reset Complete */ +#define HDRE BIT(5) /* Header Error */ +#define LOFE BIT(4) /* Loss of Framing Error */ +#define RXBOE BIT(3) /* Receive Buffer Overflow Error */ +#define TXBUE BIT(2) /* Transmit Buffer Underflow Error */ +#define TXBOE BIT(1) /* Transmit Buffer Overflow Error */ +#define TXPE BIT(0) /* Transmit Protocol Error */ + +/* Buffer Status Register */ +#define OA_TC6_BUFSTS 0x000B +#define TXC GENMASK(15, 8) /* Transmit Credits Available */ +#define RCA GENMASK(7, 0) /* Receive Chunks Available */ /* Interrupt Mask Register #0 */ #define IMASK0 0x000C @@ -56,9 +99,11 @@ #define TXBOEM BIT(1) /* Tx Buffer Overflow Error Mask */ #define TXPEM BIT(0) /* Tx Protocol Error Mask */ -struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev); +struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev, + int (*config_cps_buf)(void *tc6, u32 cps)); void oa_tc6_exit(struct oa_tc6 *tc6); int oa_tc6_write_register(struct oa_tc6 *tc6, u32 addr, u32 val); int oa_tc6_read_register(struct oa_tc6 *tc6, u32 addr, u32 *val); int oa_tc6_write_registers(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len); int oa_tc6_read_registers(struct oa_tc6 *tc6, u32 addr, u32 val[], u8 len); +netdev_tx_t oa_tc6_send_eth_pkt(struct oa_tc6 *tc6, struct sk_buff *skb); From patchwork Mon Oct 23 15:46:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Parthiban Veerasooran X-Patchwork-Id: 13433079 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 460821C2A0; Mon, 23 Oct 2023 15:49:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="oR60E7nj" Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A925CBC; Mon, 23 Oct 2023 08:49:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1698076168; x=1729612168; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=EIAWZnz+aluTlA+jsc27kElv023QDhk3i4+lvfGU06U=; b=oR60E7njDXyiXiUIlAn9gYGJe11y4BDMAtLvYM+Xkr83DI2EKjPrcm/2 cGey8Wsgr2rCJ0WmVvxWZEY3H0p005Qkk7u9ms9FXngWLQvG2DUi2a0yy Kzt2RfG7rBLY8TGQ8rrkpo0dKao+jI+weVJJjm7JijQRA+AgVB3c7AsxL R3m+kxfEFj3DvjRbYqTQF53HV0YyUqTYTFQYJx27C9s3WxVdAGJILbPHn BJyl1T6/mYOlfVggsGBQNkQdC5LJ2pAoi7R2Oqj2m5WzpSBA5ZOxwBPRw 8kmgg8xO/EFXOPNyZvtDnAUMQ3FfOUPbdMtM23INO++zeVUh2JJTE8qQ0 w==; X-CSE-ConnectionGUID: R4tFaVLSQ02v5bYQOZNT7Q== X-CSE-MsgGUID: 6LR9DXzTRyiGay5Whjwrxg== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.03,244,1694761200"; d="scan'208";a="177613922" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa6.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Oct 2023 08:49:27 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Mon, 23 Oct 2023 08:48:57 -0700 Received: from CHE-LT-I17164LX.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.21 via Frontend Transport; Mon, 23 Oct 2023 08:48:45 -0700 From: Parthiban Veerasooran To: , , , , , , , , , , , , CC: , , , , , , , , , Parthiban Veerasooran Subject: [PATCH net-next v2 8/9] microchip: lan865x: add driver support for Microchip's LAN865X MACPHY Date: Mon, 23 Oct 2023 21:16:48 +0530 Message-ID: <20231023154649.45931-9-Parthiban.Veerasooran@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> References: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org 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. A smaller payload data size of 32 bytes is also supported and may be configured in the Chunk Payload Size (CPS) field of the Configuration 0 (OA_CONFIG0) register. Changing the chunk payload size requires the LAN8650/1 be reset and shall not be done during normal operation. 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 into the LAN8650/1. The PHY and MAC are connected via an internal Media Independent Interface (MII). Signed-off-by: Parthiban Veerasooran --- MAINTAINERS | 6 + drivers/net/ethernet/microchip/Kconfig | 11 + drivers/net/ethernet/microchip/Makefile | 2 + drivers/net/ethernet/microchip/lan865x.c | 415 +++++++++++++++++++++++ 4 files changed, 434 insertions(+) create mode 100644 drivers/net/ethernet/microchip/lan865x.c diff --git a/MAINTAINERS b/MAINTAINERS index 9580be91f5e9..1b1bd3218a2d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14001,6 +14001,12 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/microchip/lan743x_* +MICROCHIP LAN8650/1 10BASE-T1S MACPHY ETHERNET DRIVER +M: Parthiban Veerasooran +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/ethernet/microchip/lan865x.c + MICROCHIP LAN87xx/LAN937x T1 PHY DRIVER M: Arun Ramadoss R: UNGLinuxDriver@microchip.com diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig index 329e374b9539..596caf59dea6 100644 --- a/drivers/net/ethernet/microchip/Kconfig +++ b/drivers/net/ethernet/microchip/Kconfig @@ -59,4 +59,15 @@ source "drivers/net/ethernet/microchip/lan966x/Kconfig" source "drivers/net/ethernet/microchip/sparx5/Kconfig" source "drivers/net/ethernet/microchip/vcap/Kconfig" +config LAN865X + tristate "LAN865x support" + depends on SPI + depends on OA_TC6 + help + Support for the Microchip LAN8650/1 Rev.B0 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 diff --git a/drivers/net/ethernet/microchip/Makefile b/drivers/net/ethernet/microchip/Makefile index bbd349264e6f..1fa4e15a067d 100644 --- a/drivers/net/ethernet/microchip/Makefile +++ b/drivers/net/ethernet/microchip/Makefile @@ -12,3 +12,5 @@ lan743x-objs := lan743x_main.o lan743x_ethtool.o lan743x_ptp.o obj-$(CONFIG_LAN966X_SWITCH) += lan966x/ obj-$(CONFIG_SPARX5_SWITCH) += sparx5/ obj-$(CONFIG_VCAP) += vcap/ + +obj-$(CONFIG_LAN865X) += lan865x.o diff --git a/drivers/net/ethernet/microchip/lan865x.c b/drivers/net/ethernet/microchip/lan865x.c new file mode 100644 index 000000000000..3ac6a0a31b37 --- /dev/null +++ b/drivers/net/ethernet/microchip/lan865x.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Microchip's LAN865x 10BASE-T1S MAC-PHY driver + * + * Author: Parthiban Veerasooran + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "lan865x" + +/* MAC Network Control Register */ +#define LAN865X_MAC_NCR 0x00010000 +#define LAN865X_TXEN BIT(3) /* Transmit Enable */ +#define LAN865X_RXEN BIT(2) /* Receive Enable */ +#define LAN865X_MAC_NCFGR 0x00010001 /* MAC Network Configuration Register */ +#define LAN865X_MAC_HRB 0x00010020 /* MAC Hash Register Bottom */ +#define LAN865X_MAC_HRT 0x00010021 /* MAC Hash Register Top */ +#define LAN865X_MAC_SAB1 0x00010022 /* MAC Specific Address 1 Bottom Register */ +#define LAN865X_MAC_SAT1 0x00010023 /* MAC Specific Address 1 Top Register */ +/* Queue Transmit Configuration */ +#define LAN865X_QTXCFG 0x000A0081 +/* Queue Receive Configuration */ +#define LAN865X_QRXCFG 0x000A0082 +#define LAN865X_BUFSZ GENMASK(22, 20) /* Buffer Size */ + +#define MAC_PROMISCUOUS_MODE BIT(4) +#define MAC_MULTICAST_MODE BIT(6) +#define MAC_UNICAST_MODE BIT(7) + +#define TX_TIMEOUT (4 * HZ) +#define LAN865X_MSG_DEFAULT \ + (NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN | NETIF_MSG_LINK) + +struct lan865x_priv { + struct net_device *netdev; + struct spi_device *spi; + struct oa_tc6 *tc6; + u32 msg_enable; + bool protected; + bool txcte; + bool rxcte; + u32 cps; +}; + +static int lan865x_set_hw_macaddr(struct net_device *netdev) +{ + u32 regval; + bool ret; + struct lan865x_priv *priv = netdev_priv(netdev); + const u8 *mac = netdev->dev_addr; + + ret = oa_tc6_read_register(priv->tc6, LAN865X_MAC_NCR, ®val); + if (ret) + goto error_mac; + if ((regval & LAN865X_TXEN) | (regval & LAN865X_RXEN)) { + if (netif_msg_drv(priv)) + netdev_warn(netdev, "Hardware must be disabled for MAC setting\n"); + return -EBUSY; + } + /* MAC address setting */ + regval = (mac[3] << 24) | (mac[2] << 16) | (mac[1] << 8) | mac[0]; + ret = oa_tc6_write_register(priv->tc6, LAN865X_MAC_SAB1, regval); + if (ret) + goto error_mac; + + regval = (mac[5] << 8) | mac[4]; + ret = oa_tc6_write_register(priv->tc6, LAN865X_MAC_SAT1, regval); + if (ret) + goto error_mac; + + return 0; + +error_mac: + return -ENODEV; +} + +static void lan865x_set_msglevel(struct net_device *netdev, u32 val) +{ + struct lan865x_priv *priv = netdev_priv(netdev); + + priv->msg_enable = val; +} + +static u32 lan865x_get_msglevel(struct net_device *netdev) +{ + struct lan865x_priv *priv = netdev_priv(netdev); + + return priv->msg_enable; +} + +static void +lan865x_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) +{ + strscpy(info->driver, DRV_NAME, sizeof(info->driver)); + strscpy(info->bus_info, dev_name(netdev->dev.parent), + sizeof(info->bus_info)); +} + +static const struct ethtool_ops lan865x_ethtool_ops = { + .get_drvinfo = lan865x_get_drvinfo, + .get_msglevel = lan865x_get_msglevel, + .set_msglevel = lan865x_set_msglevel, + .get_link_ksettings = phy_ethtool_get_link_ksettings, + .set_link_ksettings = phy_ethtool_set_link_ksettings, +}; + +static void lan865x_tx_timeout(struct net_device *netdev, unsigned int txqueue) +{ + netdev->stats.tx_errors++; +} + +static int lan865x_set_mac_address(struct net_device *netdev, void *addr) +{ + struct sockaddr *address = addr; + + if (netif_running(netdev)) + return -EBUSY; + + eth_hw_addr_set(netdev, address->sa_data); + + return lan865x_set_hw_macaddr(netdev); +} + +static u32 lan865x_hash(u8 addr[ETH_ALEN]) +{ + return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; +} + +static void lan865x_set_multicast_list(struct net_device *netdev) +{ + struct lan865x_priv *priv = netdev_priv(netdev); + u32 regval = 0; + + if (netdev->flags & IFF_PROMISC) { + /* Enabling promiscuous mode */ + regval |= MAC_PROMISCUOUS_MODE; + regval &= (~MAC_MULTICAST_MODE); + regval &= (~MAC_UNICAST_MODE); + } else if (netdev->flags & IFF_ALLMULTI) { + /* Enabling all multicast mode */ + regval &= (~MAC_PROMISCUOUS_MODE); + regval |= MAC_MULTICAST_MODE; + regval &= (~MAC_UNICAST_MODE); + } else if (!netdev_mc_empty(netdev)) { + /* Enabling specific multicast addresses */ + struct netdev_hw_addr *ha; + u32 hash_lo = 0; + u32 hash_hi = 0; + + netdev_for_each_mc_addr(ha, netdev) { + u32 bit_num = lan865x_hash(ha->addr); + u32 mask = 1 << (bit_num & 0x1f); + + if (bit_num & 0x20) + hash_hi |= mask; + else + hash_lo |= mask; + } + if (oa_tc6_write_register(priv->tc6, LAN865X_MAC_HRT, hash_hi)) { + if (netif_msg_timer(priv)) + netdev_err(netdev, "Failed to write reg_hashh"); + return; + } + if (oa_tc6_write_register(priv->tc6, LAN865X_MAC_HRB, hash_lo)) { + if (netif_msg_timer(priv)) + netdev_err(netdev, "Failed to write reg_hashl"); + return; + } + regval &= (~MAC_PROMISCUOUS_MODE); + regval &= (~MAC_MULTICAST_MODE); + regval |= MAC_UNICAST_MODE; + } else { + /* enabling local mac address only */ + if (oa_tc6_write_register(priv->tc6, LAN865X_MAC_HRT, regval)) { + if (netif_msg_timer(priv)) + netdev_err(netdev, "Failed to write reg_hashh"); + return; + } + if (oa_tc6_write_register(priv->tc6, LAN865X_MAC_HRB, regval)) { + if (netif_msg_timer(priv)) + netdev_err(netdev, "Failed to write reg_hashl"); + return; + } + } + if (oa_tc6_write_register(priv->tc6, LAN865X_MAC_NCFGR, regval)) { + if (netif_msg_timer(priv)) + netdev_err(netdev, "Failed to enable promiscuous mode"); + } +} + +static netdev_tx_t lan865x_send_packet(struct sk_buff *skb, + struct net_device *netdev) +{ + struct lan865x_priv *priv = netdev_priv(netdev); + + return oa_tc6_send_eth_pkt(priv->tc6, skb); +} + +static int lan865x_hw_disable(struct lan865x_priv *priv) +{ + u32 regval; + + if (oa_tc6_read_register(priv->tc6, LAN865X_MAC_NCR, ®val)) + return -ENODEV; + + regval &= ~(LAN865X_TXEN | LAN865X_RXEN); + + if (oa_tc6_write_register(priv->tc6, LAN865X_MAC_NCR, regval)) + return -ENODEV; + + return 0; +} + +static int lan865x_net_close(struct net_device *netdev) +{ + struct lan865x_priv *priv = netdev_priv(netdev); + int ret; + + netif_stop_queue(netdev); + if (netdev->phydev) + phy_stop(netdev->phydev); + ret = lan865x_hw_disable(priv); + if (ret) { + if (netif_msg_ifup(priv)) + netdev_err(netdev, "Failed to disable the hardware\n"); + return ret; + } + + return 0; +} + +static int lan865x_hw_enable(struct lan865x_priv *priv) +{ + u32 regval; + + if (oa_tc6_read_register(priv->tc6, LAN865X_MAC_NCR, ®val)) + return -ENODEV; + + regval |= LAN865X_TXEN | LAN865X_RXEN; + + if (oa_tc6_write_register(priv->tc6, LAN865X_MAC_NCR, regval)) + return -ENODEV; + + return 0; +} + +static int lan865x_net_open(struct net_device *netdev) +{ + struct lan865x_priv *priv = netdev_priv(netdev); + + if (lan865x_hw_enable(priv) != 0) { + if (netif_msg_ifup(priv)) + netdev_err(netdev, "Failed to enable hardware\n"); + return -ENODEV; + } + phy_start(netdev->phydev); + netif_start_queue(netdev); + + return 0; +} + +static const struct net_device_ops lan865x_netdev_ops = { + .ndo_open = lan865x_net_open, + .ndo_stop = lan865x_net_close, + .ndo_start_xmit = lan865x_send_packet, + .ndo_set_rx_mode = lan865x_set_multicast_list, + .ndo_set_mac_address = lan865x_set_mac_address, + .ndo_tx_timeout = lan865x_tx_timeout, + .ndo_validate_addr = eth_validate_addr, +}; + +/* Configures the number of bytes allocated to each buffer in the + * transmit/receive queue. LAN865x supports only 64 and 32 bytes cps and also 64 + * is the default value. So it is enough to configure the queue buffer size only + * for 32 bytes. Generally cps can't be changed during run time and also it is + * configured in the device tree. The values for the Tx/Rx queue buffer size are + * taken from the LAN865x datasheet. + */ +static int lan865x_config_cps_buf(void *tc6, u32 cps) +{ + u32 regval; + int ret; + + if (cps == 32) { + ret = oa_tc6_read_register(tc6, LAN865X_QTXCFG, ®val); + if (ret) + return ret; + + regval &= ~LAN865X_BUFSZ; + regval |= FIELD_PREP(LAN865X_BUFSZ, 0x0); + + ret = oa_tc6_write_register(tc6, LAN865X_QTXCFG, regval); + if (ret) + return ret; + + ret = oa_tc6_read_register(tc6, LAN865X_QRXCFG, ®val); + if (ret) + return ret; + + regval &= ~LAN865X_BUFSZ; + regval |= FIELD_PREP(LAN865X_BUFSZ, 0x0); + + ret = oa_tc6_write_register(tc6, LAN865X_QRXCFG, regval); + if (ret) + return ret; + } + + return 0; +} + +static int lan865x_probe(struct spi_device *spi) +{ + struct net_device *netdev; + struct lan865x_priv *priv; + int ret; + + netdev = alloc_etherdev(sizeof(struct lan865x_priv)); + if (!netdev) + return -ENOMEM; + + priv = netdev_priv(netdev); + priv->netdev = netdev; + priv->spi = spi; + priv->msg_enable = 0; + spi_set_drvdata(spi, priv); + + priv->tc6 = oa_tc6_init(spi, netdev, lan865x_config_cps_buf); + if (!priv->tc6) { + ret = -ENODEV; + goto err_oa_tc6_init; + } + if (device_get_ethdev_address(&spi->dev, netdev)) + eth_hw_addr_random(netdev); + + ret = lan865x_set_hw_macaddr(netdev); + if (ret) { + if (netif_msg_probe(priv)) + dev_err(&spi->dev, "Failed to configure MAC"); + goto err_config; + } + + netdev->if_port = IF_PORT_10BASET; + netdev->irq = spi->irq; + netdev->netdev_ops = &lan865x_netdev_ops; + netdev->watchdog_timeo = TX_TIMEOUT; + netdev->ethtool_ops = &lan865x_ethtool_ops; + ret = register_netdev(netdev); + if (ret) { + if (netif_msg_probe(priv)) + dev_err(&spi->dev, "Register netdev failed (ret = %d)", + ret); + goto err_config; + } + + return 0; + +err_config: + oa_tc6_exit(priv->tc6); +err_oa_tc6_init: + free_netdev(priv->netdev); + return ret; +} + +static void lan865x_remove(struct spi_device *spi) +{ + struct lan865x_priv *priv = spi_get_drvdata(spi); + + oa_tc6_exit(priv->tc6); + unregister_netdev(priv->netdev); + free_netdev(priv->netdev); +} + +#ifdef CONFIG_OF +static const struct of_device_id lan865x_dt_ids[] = { + { .compatible = "microchip,lan865x" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, lan865x_dt_ids); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id lan865x_acpi_ids[] = { + { .id = "LAN865X", + }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, lan865x_acpi_ids); +#endif + +static struct spi_driver lan865x_driver = { + .driver = { + .name = DRV_NAME, +#ifdef CONFIG_OF + .of_match_table = lan865x_dt_ids, +#endif +#ifdef CONFIG_ACPI + .acpi_match_table = ACPI_PTR(lan865x_acpi_ids), +#endif + }, + .probe = lan865x_probe, + .remove = lan865x_remove, +}; +module_spi_driver(lan865x_driver); + +MODULE_DESCRIPTION(DRV_NAME " 10Base-T1S MACPHY Ethernet Driver"); +MODULE_AUTHOR("Parthiban Veerasooran "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:" DRV_NAME); From patchwork Mon Oct 23 15:46:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Parthiban Veerasooran X-Patchwork-Id: 13433078 X-Patchwork-Delegate: kuba@kernel.org Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net [23.128.96.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4604C1C29D; Mon, 23 Oct 2023 15:49:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=microchip.com header.i=@microchip.com header.b="WWNyD9nE" Received: from esa.microchip.iphmx.com (esa.microchip.iphmx.com [68.232.154.123]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 09B0310A; Mon, 23 Oct 2023 08:49:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1698076170; x=1729612170; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=q4Pt0gwBLyBOMj0Wnjreub+jmFGjoXYgtnrkexWrKuQ=; b=WWNyD9nEl7TtbCz9BEaY2DrVpnbdtPDJbjx2WQ5JaO24PyuymYRq/CJZ 0zcNvf8nIoMENwmcgo5LdmiuYEkjSdAjALxCquamSSYs5JZIkCiDB08TL 4waZgWhxDDPBpM73lNvRsDihwosQtLDdWjOb4716UH3ljPMKxvxgi7eZD jpVdV3Ya/3V46Ng0ZzLin71tHInCgchlBfRUaPvNlOSe3lgdKdvY64G/d SPHrXIIHab930TR6UExWe1j4C7q75RmHwLWiYSj1UBsjjt7r1PgVV6h5+ 1nXWd4p32ag6B44BukvRSJlYIMbEgnibzZ7h8n1E0LznniUUJIsDbfopQ g==; X-CSE-ConnectionGUID: R4tFaVLSQ02v5bYQOZNT7Q== X-CSE-MsgGUID: i+IzyY15S9G3s11hpzaXEw== X-ThreatScanner-Verdict: Negative X-IronPort-AV: E=Sophos;i="6.03,244,1694761200"; d="scan'208";a="177613932" X-Amp-Result: SKIPPED(no attachment in message) Received: from unknown (HELO email.microchip.com) ([170.129.1.10]) by esa6.microchip.iphmx.com with ESMTP/TLS/ECDHE-RSA-AES128-GCM-SHA256; 23 Oct 2023 08:49:29 -0700 Received: from chn-vm-ex03.mchp-main.com (10.10.85.151) by chn-vm-ex02.mchp-main.com (10.10.85.144) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Mon, 23 Oct 2023 08:49:12 -0700 Received: from CHE-LT-I17164LX.microchip.com (10.10.85.11) by chn-vm-ex03.mchp-main.com (10.10.85.151) with Microsoft SMTP Server id 15.1.2507.21 via Frontend Transport; Mon, 23 Oct 2023 08:48:58 -0700 From: Parthiban Veerasooran To: , , , , , , , , , , , , CC: , , , , , , , , , Parthiban Veerasooran Subject: [PATCH net-next v2 9/9] dt-bindings: net: add Microchip's LAN865X 10BASE-T1S MACPHY Date: Mon, 23 Oct 2023 21:16:49 +0530 Message-ID: <20231023154649.45931-10-Parthiban.Veerasooran@microchip.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> References: <20231023154649.45931-1-Parthiban.Veerasooran@microchip.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org Add DT bindings for Microchip's LAN865X 10BASE-T1S MACPHY. 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). Signed-off-by: Parthiban Veerasooran --- .../bindings/net/microchip,lan865x.yaml | 101 ++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 102 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/microchip,lan865x.yaml diff --git a/Documentation/devicetree/bindings/net/microchip,lan865x.yaml b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml new file mode 100644 index 000000000000..974622dd6846 --- /dev/null +++ b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/microchip,lan865x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip LAN8650/1 10BASE-T1S MACPHY Ethernet Controllers + +maintainers: + - Parthiban Veerasooran + +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). + + Specifications about the LAN8650/1 can be found at: + https://www.microchip.com/en-us/product/lan8650 + +allOf: + - $ref: ethernet-controller.yaml# + +properties: + compatible: + const: microchip,lan865x + + 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 + + local-mac-address: + description: + Specifies the MAC address assigned to the network device. + $ref: /schemas/types.yaml#/definitions/uint8-array + minItems: 6 + maxItems: 6 + + spi-max-frequency: + minimum: 15000000 + maximum: 25000000 + + oa-tc6: + $ref: oa-tc6.yaml# + unevaluatedProperties: true + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +required: + - compatible + - reg + - pinctrl-names + - pinctrl-0 + - interrupts + - interrupt-parent + - local-mac-address + - spi-max-frequency + - oa-tc6 + +additionalProperties: false + +examples: + - | + spi { + #address-cells = <1>; + #size-cells = <0>; + + ethernet@0 { + compatible = "microchip,lan865x"; + 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>; + status = "okay"; + oa-tc6 { + #address-cells = <1>; + #size-cells = <0>; + oa-cps = <64>; + oa-txcte; + oa_rxcte; + oa-prote; + oa-dprac; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 1b1bd3218a2d..d2b3c0e8d97e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14005,6 +14005,7 @@ MICROCHIP LAN8650/1 10BASE-T1S MACPHY ETHERNET DRIVER M: Parthiban Veerasooran L: netdev@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/net/microchip,lan865x.yaml F: drivers/net/ethernet/microchip/lan865x.c MICROCHIP LAN87xx/LAN937x T1 PHY DRIVER