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 <Parthiban.Veerasooran@xxxxxxxxxxxxx> --- 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 <linux/bitfield.h> #include <linux/interrupt.h> #include <linux/delay.h> +#include <linux/of.h> #include <linux/oa_tc6.h> /* 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); -- 2.34.1