zephyr/drivers/ethernet/oa_tc6.h
Lukasz Majewski 953c5f2d32 drivers: net: lan865x: Always read at least one chunk on IRQ received
According to the OPEN Alliance 10Base-T1x standard (point 7.7), it is
mandatory to read at least single data chunk (no matter if received data
is valid or not) to deassert the interrupt in the LAN865x (then the tc6
structure fields are also updated from the footer).

Current approach with reading OA_BUFSTS register was providing the
required information (RCA and TXC), but could cause transmission "stalls"
as this operation (i.e. control, not data transmission) is not causing
deassertion of the interrupt IRQ_N line from OA TC6 compliant device.

With this patch - the transmission is always performed at least once, so
interrupt is always deasserted.

As the functionality of oa_tc6_update_buf_info() - i.e reading value of
RCA and TXC - has been replaced with extracting data from footer, this
function can be safely removed.

Signed-off-by: Lukasz Majewski <lukma@denx.de>
2023-12-01 10:54:27 +00:00

253 lines
6.8 KiB
C

/*
* Copyright (c) 2023 DENX Software Engineering GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef OA_TC6_CFG_H__
#define OA_TC6_CFG_H__
#include <stdint.h>
#include <stdbool.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/net/net_pkt.h>
#define MMS_REG(m, r) ((((m) & GENMASK(3, 0)) << 16) | ((r) & GENMASK(15, 0)))
/* Memory Map Sector (MMS) 0 */
#define OA_ID MMS_REG(0x0, 0x000) /* expect 0x11 */
#define OA_PHYID MMS_REG(0x0, 0x001)
#define OA_RESET MMS_REG(0x0, 0x003)
#define OA_RESET_SWRESET BIT(0)
#define OA_CONFIG0 MMS_REG(0x0, 0x004)
#define OA_CONFIG0_SYNC BIT(15)
#define OA_CONFIG0_RFA_ZARFE BIT(12)
#define OA_CONFIG0_PROTE BIT(5)
#define OA_STATUS0 MMS_REG(0x0, 0x008)
#define OA_STATUS0_RESETC BIT(6)
#define OA_STATUS1 MMS_REG(0x0, 0x009)
#define OA_BUFSTS MMS_REG(0x0, 0x00B)
#define OA_BUFSTS_TXC GENMASK(15, 8)
#define OA_BUFSTS_RCA GENMASK(7, 0)
#define OA_IMASK0 MMS_REG(0x0, 0x00C)
#define OA_IMASK0_TXPEM BIT(0)
#define OA_IMASK0_TXBOEM BIT(1)
#define OA_IMASK0_TXBUEM BIT(2)
#define OA_IMASK0_RXBOEM BIT(3)
#define OA_IMASK0_LOFEM BIT(4)
#define OA_IMASK0_HDREM BIT(5)
#define OA_IMASK1 MMS_REG(0x0, 0x00D)
#define OA_IMASK0_UV18M BIT(19)
/* OA Control header */
#define OA_CTRL_HDR_DNC BIT(31)
#define OA_CTRL_HDR_HDRB BIT(30)
#define OA_CTRL_HDR_WNR BIT(29)
#define OA_CTRL_HDR_AID BIT(28)
#define OA_CTRL_HDR_MMS GENMASK(27, 24)
#define OA_CTRL_HDR_ADDR GENMASK(23, 8)
#define OA_CTRL_HDR_LEN GENMASK(7, 1)
#define OA_CTRL_HDR_P BIT(0)
/* OA Data header */
#define OA_DATA_HDR_DNC BIT(31)
#define OA_DATA_HDR_SEQ BIT(30)
#define OA_DATA_HDR_NORX BIT(29)
#define OA_DATA_HDR_DV BIT(21)
#define OA_DATA_HDR_SV BIT(20)
#define OA_DATA_HDR_SWO GENMASK(19, 16)
#define OA_DATA_HDR_EV BIT(14)
#define OA_DATA_HDR_EBO GENMASK(13, 8)
#define OA_DATA_HDR_P BIT(0)
/* OA Data footer */
#define OA_DATA_FTR_EXST BIT(31)
#define OA_DATA_FTR_HDRB BIT(30)
#define OA_DATA_FTR_SYNC BIT(29)
#define OA_DATA_FTR_RCA GENMASK(28, 24)
#define OA_DATA_FTR_DV BIT(21)
#define OA_DATA_FTR_SV BIT(20)
#define OA_DATA_FTR_SWO GENMASK(19, 16)
#define OA_DATA_FTR_FD BIT(15)
#define OA_DATA_FTR_EV BIT(14)
#define OA_DATA_FTR_EBO GENMASK(13, 8)
#define OA_DATA_FTR_TXC GENMASK(5, 1)
#define OA_DATA_FTR_P BIT(0)
#define OA_TC6_HDR_SIZE 4
#define OA_TC6_FTR_SIZE 4
#define OA_TC6_BUF_ALLOC_TIMEOUT K_MSEC(10)
#define OA_TC6_FTR_RCA_MAX GENMASK(4, 0)
#define OA_TC6_FTR_TXC_MAX GENMASK(4, 0)
/**
* @brief OA TC6 data.
*/
struct oa_tc6 {
/** Pointer to SPI device */
const struct spi_dt_spec *spi;
/** OA data payload (chunk) size */
uint8_t cps;
/**
* Number of available chunks buffers in OA TC6 device to store
* data for transmission
*/
uint8_t txc;
/** Number of available chunks to read from OA TC6 device */
uint8_t rca;
/** Indication of pending interrupt in OA TC6 device */
bool exst;
/** Indication of OA TC6 device being ready for transmission */
bool sync;
/** Indication of protected control transmission mode */
bool protected;
/** Pointer to network buffer concatenated from received chunk */
struct net_buf *concat_buf;
};
typedef struct {
uint32_t address;
uint32_t value;
} oa_mem_map_t;
/**
* @brief Calculate parity bit from data
*
* @param x data to calculate parity
*
* @return 0 if number of ones is odd, 1 otherwise.
*/
static inline bool oa_tc6_get_parity(const uint32_t x)
{
uint32_t y;
y = x ^ (x >> 1);
y = y ^ (y >> 2);
y = y ^ (y >> 4);
y = y ^ (y >> 8);
y = y ^ (y >> 16);
return !(y & 1);
}
/**
* @brief Read OA TC6 compliant device single register
*
* @param tc6 OA TC6 specific data
*
* @param reg register to read
* @param val pointer to variable to store read value
*
* @return 0 if read was successful, <0 otherwise.
*/
int oa_tc6_reg_read(struct oa_tc6 *tc6, const uint32_t reg, uint32_t *val);
/**
* @brief Write to OA TC6 compliant device a single register
*
* @param tc6 OA TC6 specific data
*
* @param reg register to read
* @param val data to send to device
*
* @return 0 if write was successful, <0 otherwise.
*/
int oa_tc6_reg_write(struct oa_tc6 *tc6, const uint32_t reg, uint32_t val);
/**
* @brief Enable or disable the protected mode for control transactions
*
* @param tc6 OA TC6 specific data
*
* @param prote enable or disable protected control transactions
*
* @return 0 if operation was successful, <0 otherwise.
*/
int oa_tc6_set_protected_ctrl(struct oa_tc6 *tc6, bool prote);
/**
* @brief Send OA TC6 data chunks to the device
*
* @param tc6 OA TC6 specific data
*
* @param pkt network packet to be send
*
* @return 0 if data send was successful, <0 otherwise.
*/
int oa_tc6_send_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt);
/**
* @brief Read data chunks from OA TC6 device
*
* @param tc6 OA TC6 specific data
*
* @param pkt network packet to store received data
*
* @return 0 if read was successful, <0 otherwise.
*/
int oa_tc6_read_chunks(struct oa_tc6 *tc6, struct net_pkt *pkt);
/**
* @brief Perform SPI transfer of single chunk from/to OA TC6 device
*
* @param tc6 OA TC6 specific data
*
* @param buf_rx buffer to store read data
*
* @param buf_tx buffer with data to send
*
* @param hdr OA TC6 data transmission header value
*
* @param ftr poniter to OA TC6 data received footer
*
* @return 0 if transmission was successful, <0 otherwise.
*/
int oa_tc6_chunk_spi_transfer(struct oa_tc6 *tc6, uint8_t *buf_rx, uint8_t *buf_tx,
uint32_t hdr, uint32_t *ftr);
/**
* @brief Read status from OA TC6 device
*
* @param tc6 OA TC6 specific data
*
* @param ftr poniter to OA TC6 data received footer
*
* @return 0 if successful, <0 otherwise.
*/
int oa_tc6_read_status(struct oa_tc6 *tc6, uint32_t *ftr);
/**
* @brief Read, modify and write control register from OA TC6 device
*
* @param tc6 OA TC6 specific data
*
* @param reg register to modify
*
* @param mask bit mask for modified register
*
* @param value to be stored in the register
*
* @return 0 if successful, <0 otherwise.
*/
int oa_tc6_reg_rmw(struct oa_tc6 *tc6, const uint32_t reg,
uint32_t mask, uint32_t val);
/**
* @brief Check the status of OA TC6 device
*
* @param tc6 OA TC6 specific data
*
* @return 0 if successful, <0 otherwise.
*/
int oa_tc6_check_status(struct oa_tc6 *tc6);
#endif /* OA_TC6_CFG_H__ */