// SPDX-License-Identifier: GPL-2.0+
/*
* OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface framework
*
* Author: Parthiban Veerasooran <parthiban.veerasooran@microchip.com>
*/
#include <linux/bitfield.h>
#include <linux/iopoll.h>
#include <linux/mdio.h>
#include <linux/phy.h>
#include <linux/oa_tc6.h>
/* OPEN Alliance TC6 registers */
/* Standard Capabilities Register */
#define OA_TC6_REG_STDCAP 0x0002
#define STDCAP_DIRECT_PHY_REG_ACCESS BIT(8)
/* Reset Control and Status Register */
#define OA_TC6_REG_RESET 0x0003
#define RESET_SWRESET BIT(0) /* Software Reset */
/* Configuration Register #0 */
#define OA_TC6_REG_CONFIG0 0x0004
#define CONFIG0_SYNC BIT(15)
#define CONFIG0_ZARFE_ENABLE BIT(12)
/* Status Register #0 */
#define OA_TC6_REG_STATUS0 0x0008
#define STATUS0_RESETC BIT(6) /* Reset Complete */
#define STATUS0_HEADER_ERROR BIT(5)
#define STATUS0_LOSS_OF_FRAME_ERROR BIT(4)
#define STATUS0_RX_BUFFER_OVERFLOW_ERROR BIT(3)
#define STATUS0_TX_PROTOCOL_ERROR BIT(0)
/* Buffer Status Register */
#define OA_TC6_REG_BUFFER_STATUS 0x000B
#define BUFFER_STATUS_TX_CREDITS_AVAILABLE GENMASK(15, 8)
#define BUFFER_STATUS_RX_CHUNKS_AVAILABLE GENMASK(7, 0)
/* Interrupt Mask Register #0 */
#define OA_TC6_REG_INT_MASK0 0x000C
#define INT_MASK0_HEADER_ERR_MASK BIT(5)
#define INT_MASK0_LOSS_OF_FRAME_ERR_MASK BIT(4)
#define INT_MASK0_RX_BUFFER_OVERFLOW_ERR_MASK BIT(3)
#define INT_MASK0_TX_PROTOCOL_ERR_MASK BIT(0)
/* PHY Clause 22 registers base address and mask */
#define OA_TC6_PHY_STD_REG_ADDR_BASE 0xFF00
#define OA_TC6_PHY_STD_REG_ADDR_MASK 0x1F
/* Control command header */
#define OA_TC6_CTRL_HEADER_DATA_NOT_CTRL BIT(31)
#define OA_TC6_CTRL_HEADER_WRITE_NOT_READ BIT(29)
#define OA_TC6_CTRL_HEADER_MEM_MAP_SELECTOR GENMASK(27, 24)
#define OA_TC6_CTRL_HEADER_ADDR GENMASK(23, 8)
#define OA_TC6_CTRL_HEADER_LENGTH GENMASK(7, 1)
#define OA_TC6_CTRL_HEADER_PARITY BIT(0)
/* Data header */
#define OA_TC6_DATA_HEADER_DATA_NOT_CTRL BIT(31)
#define OA_TC6_DATA_HEADER_DATA_VALID BIT(21)
#define OA_TC6_DATA_HEADER_START_VALID BIT(20)
#define OA_TC6_DATA_HEADER_START_WORD_OFFSET GENMASK(19, 16)
#define OA_TC6_DATA_HEADER_END_VALID BIT(14)
#define OA_TC6_DATA_HEADER_END_BYTE_OFFSET GENMASK(13, 8)
#define OA_TC6_DATA_HEADER_PARITY BIT(0)
/* Data footer */
#define OA_TC6_DATA_FOOTER_EXTENDED_STS BIT(31)
#define OA_TC6_DATA_FOOTER_RXD_HEADER_BAD BIT(30)
#define OA_TC6_DATA_FOOTER_CONFIG_SYNC BIT(29)
#define OA_TC6_DATA_FOOTER_RX_CHUNKS GENMASK(28, 24)
#define OA_TC6_DATA_FOOTER_DATA_VALID BIT(21)
#define OA_TC6_DATA_FOOTER_START_VALID BIT(20)
#define OA_TC6_DATA_FOOTER_START_WORD_OFFSET GENMASK(19, 16)
#define OA_TC6_DATA_FOOTER_END_VALID BIT(14)
#define OA_TC6_DATA_FOOTER_END_BYTE_OFFSET GENMASK(13, 8)
#define OA_TC6_DATA_FOOTER_TX_CREDITS GENMASK(5, 1)
/* PHY – Clause 45 registers memory map selector (MMS) as per table 6 in the
* OPEN Alliance specification.
*/
#define OA_TC6_PHY_C45_PCS_MMS2 2 /* MMD 3 */
#define OA_TC6_PHY_C45_PMA_PMD_MMS3 3 /* MMD 1 */
#define OA_TC6_PHY_C45_VS_PLCA_MMS4 4 /* MMD 31 */
#define OA_TC6_PHY_C45_AUTO_NEG_MMS5 5 /* MMD 7 */
#define OA_TC6_PHY_C45_POWER_UNIT_MMS6 6 /* MMD 13 */
#define OA_TC6_CTRL_HEADER_SIZE 4
#define OA_TC6_CTRL_REG_VALUE_SIZE 4
#define OA_TC6_CTRL_IGNORED_SIZE 4
#define OA_TC6_CTRL_MAX_REGISTERS 128
#define OA_TC6_CTRL_SPI_BUF_SIZE (OA_TC6_CTRL_HEADER_SIZE +\
(OA_TC6_CTRL_MAX_REGISTERS *\
OA_TC6_CTRL_REG_VALUE_SIZE) +\
OA_TC6_CTRL_IGNORED_SIZE)
#define OA_TC6_CHUNK_PAYLOAD_SIZE 64
#define OA_TC6_DATA_HEADER_SIZE 4
#define OA_TC6_CHUNK_SIZE (OA_TC6_DATA_HEADER_SIZE +\
OA_TC6_CHUNK_PAYLOAD_SIZE)
#define OA_TC6_MAX_TX_CHUNKS 48
#define OA_TC6_SPI_DATA_BUF_SIZE (OA_TC6_MAX_TX_CHUNKS *\
OA_TC6_CHUNK_SIZE)
#define STATUS0_RESETC_POLL_DELAY 1000
#define STATUS0_RESETC_POLL_TIMEOUT 1000000
/* Internal structure for MAC-PHY drivers */
struct oa_tc6 {
struct device *dev;
struct net_device *netdev;
struct phy_device *phydev;
struct mii_bus *mdiobus;
struct spi_device *spi;
struct mutex spi_ctrl_lock; /* Protects spi control transfer */
void *spi_ctrl_tx_buf;
void *spi_ctrl_rx_buf;
void *spi_data_tx_buf;
void *spi_data_rx_buf;
struct sk_buff *ongoing_tx_skb;
struct sk_buff *waiting_tx_skb;
struct sk_buff *rx_skb;
struct task_struct *spi_thread;
wait_queue_head_t spi_wq;
u16 tx_skb_offset;
u16 spi_data_tx_buf_offset;
u16 tx_credits;
u8 rx_chunks_available;
bool rx_buf_overflow;
bool int_flag;
};
enum oa_tc6_header_type {
OA_TC6_CTRL_HEADER,
OA_TC6_DATA_HEADER