drivers: ethernet: adin2111: add Open Alliance SPI support

Add Open Alliance spi protocol support.

Open Alliance is a chunk-based SPI protocol, based on sending
over SPI an ethernet frame divided in smaller chunks, using a
specific 32-bit header for each chunk transferred. All chunks
can be sent or received by a single dma transfer.

Default mode is set to Open Alliance SPI without protection,
since the adin2111 dev. board comes shipped this way.

Tested:
- Open Alliance SPI, no protection (default board shipped)
- Open Alliance SPI, protection
- Generic SPI, no crc
- Generic SPI, with crc8

Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
This commit is contained in:
Angelo Dureghello 2024-02-07 15:20:02 +01:00 committed by Carles Cufí
commit 0ca8b0756b
7 changed files with 488 additions and 45 deletions

View file

@ -5,9 +5,11 @@
if BOARD_ADI_EVAL_ADIN1110EBZ
config SPI_STM32_INTERRUPT
config BOARD
default "adi_eval_adin1110ebz"
config SPI_STM32_DMA
default y
depends on SPI
config MDIO_INIT_PRIORITY
default 81

View file

@ -197,6 +197,11 @@
pinctrl-0 = <&spi2_sck_pb13 &spi2_miso_pb14 &spi2_mosi_pb15>;
pinctrl-names = "default";
cs-gpios = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
dmas = <&dmamux1 2 13 (STM32_DMA_MEMORY_TO_PERIPH | STM32_DMA_MEM_INC |
STM32_DMA_MEM_8BITS | STM32_DMA_PERIPH_8BITS)>,
<&dmamux1 3 12 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_MEM_INC |
STM32_DMA_MEM_8BITS | STM32_DMA_PERIPH_8BITS)>;
dma-names = "tx", "rx";
status = "okay";
adin1110: adin1110@0 {
@ -205,6 +210,9 @@
spi-max-frequency = <25000000>;
int-gpios = <&gpiob 11 GPIO_ACTIVE_LOW>;
reset-gpios = <&gpioc 7 GPIO_ACTIVE_LOW>;
status = "okay";
spi-oa;
spi-oa-protection;
port1 {
local-mac-address = [ 00 E0 22 FE DA C8 ];

View file

@ -5,9 +5,8 @@
if BOARD_ADI_EVAL_ADIN2111EBZ
config SPI_STM32_INTERRUPT
default y
depends on SPI
config BOARD
default "adi_eval_adin2111ebz"
config MDIO_INIT_PRIORITY
default 81
@ -17,6 +16,9 @@ config PHY_INIT_PRIORITY
default 82
depends on NET_L2_ETHERNET && ETH_DRIVER
config SPI_STM32_DMA
default y
if NETWORKING
config NET_L2_ETHERNET

View file

@ -162,6 +162,11 @@
pinctrl-names = "default";
cs-gpios = <&gpiob 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
status = "okay";
dmas = <&dmamux1 2 13 (STM32_DMA_MEMORY_TO_PERIPH | STM32_DMA_MEM_INC |
STM32_DMA_MEM_8BITS | STM32_DMA_PERIPH_8BITS)>,
<&dmamux1 3 12 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_MEM_INC |
STM32_DMA_MEM_8BITS | STM32_DMA_PERIPH_8BITS)>;
dma-names = "tx", "rx";
adin2111: adin2111@0 {
compatible = "adi,adin2111";
@ -169,6 +174,8 @@
spi-max-frequency = <25000000>;
int-gpios = <&gpioa 12 GPIO_ACTIVE_LOW>;
status = "okay";
spi-oa;
spi-oa-protection;
port1 {
local-mac-address = [ 00 E0 22 FE DA C9 ];

View file

@ -25,6 +25,8 @@ LOG_MODULE_REGISTER(eth_adin2111, CONFIG_ETHERNET_LOG_LEVEL);
#include "phy/phy_adin2111_priv.h"
#include "eth_adin2111_priv.h"
#define DT_DRV_COMPAT adi_adin2111
/* SPI Communication check retry delay */
#define ADIN2111_DEV_AWAIT_DELAY_POLL_US 100U
/* Number of retries SPI Communication check */
@ -46,6 +48,10 @@ LOG_MODULE_REGISTER(eth_adin2111, CONFIG_ETHERNET_LOG_LEVEL);
#define ADIN2111_UNICAST_P1_ADDR_SLOT 2U
/* MAC Address Rule and DA Filter Port 2 slot/idx */
#define ADIN2111_UNICAST_P2_ADDR_SLOT 3U
/* As per RM rev. A table 3, t3 >= 50ms, delay for SPI interface to be ready */
#define ADIN2111_SPI_ACTIVE_DELAY_MS 50U
/* As per RM rev. A page 20: approximately 10 ms (maximum) for internal logic to be ready */
#define ADIN2111_SW_RESET_DELAY_MS 10U
int eth_adin2111_lock(const struct device *dev, k_timeout_t timeout)
{
@ -61,42 +67,287 @@ int eth_adin2111_unlock(const struct device *dev)
return k_mutex_unlock(&ctx->lock);
}
int eth_adin2111_reg_write(const struct device *dev, const uint16_t reg,
const uint32_t val)
static inline bool eth_adin2111_oa_get_parity(const uint32_t x)
{
const struct adin2111_config *cfg = dev->config;
size_t header_size = ADIN2111_WRITE_HEADER_SIZE;
size_t data_size = sizeof(uint32_t);
#if CONFIG_ETH_ADIN2111_SPI_CFG0
uint8_t buf[ADIN2111_REG_WRITE_BUF_SIZE_CRC] = { 0 };
#else
uint8_t buf[ADIN2111_REG_WRITE_BUF_SIZE] = { 0 };
#endif /* CONFIG_ETH_ADIN2111_SPI_CFG0 */
uint32_t y;
/* spi header */
*(uint16_t *)buf = htons((ADIN2111_WRITE_TXN_CTRL | reg));
#if CONFIG_ETH_ADIN2111_SPI_CFG0
buf[2] = crc8_ccitt(0, buf, header_size);
++header_size;
#endif /* CONFIG_ETH_ADIN2111_SPI_CFG0 */
y = x ^ (x >> 1);
y = y ^ (y >> 2);
y = y ^ (y >> 4);
y = y ^ (y >> 8);
y = y ^ (y >> 16);
/* reg */
*(uint32_t *)(buf + header_size) = htonl(val);
#if CONFIG_ETH_ADIN2111_SPI_CFG0
buf[header_size + data_size] = crc8_ccitt(0, &buf[header_size], data_size);
++data_size;
#endif /* CONFIG_ETH_ADIN2111_SPI_CFG0 */
const struct spi_buf spi_tx_buf = {
.buf = buf,
.len = header_size + data_size
};
const struct spi_buf_set tx = { .buffers = &spi_tx_buf, .count = 1U };
return spi_write_dt(&cfg->spi, &tx);
return !(y & 1);
}
int eth_adin2111_reg_read(const struct device *dev, const uint16_t reg,
int eth_adin2111_oa_spi_xfer(const struct device *dev, uint8_t *buf_rx, uint8_t *buf_tx, int len)
{
const struct adin2111_config *cfg = dev->config;
struct spi_buf tx_buf[1];
struct spi_buf rx_buf[1];
struct spi_buf_set tx;
struct spi_buf_set rx;
int ret;
tx_buf[0].buf = buf_tx;
tx_buf[0].len = len;
rx_buf[0].buf = buf_rx;
rx_buf[0].len = len;
rx.buffers = rx_buf;
rx.count = 1;
tx.buffers = tx_buf;
tx.count = 1;
ret = spi_transceive_dt(&cfg->spi, &tx, &rx);
if (ret < 0) {
LOG_ERR("ERRR dma!\n");
return ret;
}
return 0;
}
static int eth_adin2111_reg_read_oa(const struct device *dev, const uint16_t reg,
uint32_t *val)
{
struct adin2111_data *ctx = dev->data;
uint32_t pval;
uint32_t *hdr = (uint32_t *)ctx->oa_tx_buf;
int len;
int ret;
*hdr = reg << 8;
if (reg >= 0x30) {
*hdr |= ADIN2111_OA_CTL_MMS;
}
*hdr |= eth_adin2111_oa_get_parity(*hdr);
*hdr = sys_cpu_to_be32(*hdr);
len = (ctx->oa_prot) ? ADIN2111_OA_CTL_LEN_PROT : ADIN2111_OA_CTL_LEN;
ret = eth_adin2111_oa_spi_xfer(dev, ctx->oa_rx_buf, ctx->oa_tx_buf, len);
if (ret < 0) {
return ret;
}
*val = sys_be32_to_cpu(*(uint32_t *)&ctx->oa_rx_buf[8]);
/* In protected mode read data is followed by its compliment value */
if (ctx->oa_prot) {
pval = sys_be32_to_cpu(*(uint32_t *)&ctx->oa_rx_buf[12]);
if (*val != ~pval) {
LOG_ERR("OA protected mode rx error !");
return -1;
}
}
return 0;
}
static int eth_adin2111_reg_write_oa(const struct device *dev, const uint16_t reg,
uint32_t val)
{
struct adin2111_data *ctx = dev->data;
uint32_t pval;
uint32_t *hdr = (uint32_t *)ctx->oa_tx_buf;
int len;
int ret;
*hdr = reg << 8 | ADIN2111_OA_CTL_WNR;
if (reg >= 0x30) {
*hdr |= ADIN2111_OA_CTL_MMS;
}
*hdr |= eth_adin2111_oa_get_parity(*hdr);
*hdr = sys_cpu_to_be32(*hdr);
len = (ctx->oa_prot) ? ADIN2111_OA_CTL_LEN_PROT : ADIN2111_OA_CTL_LEN;
*(uint32_t *)&ctx->oa_tx_buf[4] = sys_cpu_to_be32(val);
if (ctx->oa_prot) {
*(uint32_t *)&ctx->oa_tx_buf[8] = sys_cpu_to_be32(~val);
}
ret = eth_adin2111_oa_spi_xfer(dev, ctx->oa_rx_buf, ctx->oa_tx_buf, len);
if (ret < 0) {
return ret;
}
if (ctx->oa_prot) {
pval = sys_be32_to_cpu(*(uint32_t *)&ctx->oa_rx_buf[12]);
if (val != ~pval) {
LOG_ERR("OA protected mode tx error !");
return -1;
}
}
return 0;
}
int eth_adin2111_oa_data_read(const struct device *dev, int port)
{
struct adin2111_data *ctx = dev->data;
struct net_if *iface = ((struct adin2111_port_data *)ctx->port[port]->data)->iface;
struct net_pkt *pkt;
uint32_t hdr, ftr;
int i, len, rx_pos, ret, rca, swo;
ret = eth_adin2111_reg_read(dev, ADIN2111_BUFSTS, &rca);
if (ret < 0) {
LOG_ERR("can't read BUFSTS");
return -EIO;
}
rca &= ADIN2111_BUFSTS_RCA_MASK;
/* Preare all tx headers */
for (i = 0, len = 0; i < rca; ++i) {
hdr = ADIN2111_OA_DATA_HDR_DNC;
hdr |= eth_adin2111_oa_get_parity(hdr);
*(uint32_t *)&ctx->oa_tx_buf[len] = sys_cpu_to_be32(hdr);
len += sizeof(uint32_t) + ctx->oa_cps;
}
ret = eth_adin2111_oa_spi_xfer(dev, ctx->oa_rx_buf, ctx->oa_tx_buf, len);
if (ret < 0) {
LOG_ERR("SPI xfer failed");
return ret;
}
for (i = 0, rx_pos = 0; i < rca; ++i) {
ftr = sys_be32_to_cpu(*(uint32_t *)&ctx->oa_rx_buf[rx_pos + ctx->oa_cps]);
if (eth_adin2111_oa_get_parity(ftr)) {
LOG_ERR("OA RX: Footer parity error !");
return -EIO;
}
if (!(ftr & ADIN2111_OA_DATA_FTR_SYNC)) {
LOG_ERR("OA RX: Configuration not in sync !");
return -EIO;
}
if (!(ftr & ADIN2111_OA_DATA_FTR_DV)) {
LOG_DBG("OA RX: Data chunk not valid, skip !");
goto update_pos;
}
if (ftr & ADIN2111_OA_DATA_FTR_SV) {
swo = (ftr & ADIN2111_OA_DATA_FTR_SWO_MSK) >> ADIN2111_OA_DATA_FTR_SWO;
if (swo != 0) {
LOG_ERR("OA RX: Misalignbed start of frame !");
return -EIO;
}
/* Reset store cursor */
ctx->scur = 0;
}
len = (ftr & ADIN2111_OA_DATA_FTR_EV) ?
((ftr & ADIN2111_OA_DATA_FTR_EBO_MSK) >> ADIN2111_OA_DATA_FTR_EBO) + 1 :
ctx->oa_cps;
memcpy(&ctx->buf[ctx->scur], &ctx->oa_rx_buf[rx_pos], len);
ctx->scur += len;
if (ftr & ADIN2111_OA_DATA_FTR_EV) {
pkt = net_pkt_rx_alloc_with_buffer(iface, CONFIG_ETH_ADIN2111_BUFFER_SIZE,
AF_UNSPEC, 0,
K_MSEC(CONFIG_ETH_ADIN2111_TIMEOUT));
if (!pkt) {
LOG_ERR("OA RX: cannot allcate packet space, skipping.");
return -EIO;
}
/* Skipping CRC32 */
ret = net_pkt_write(pkt, ctx->buf, ctx->scur - sizeof(uint32_t));
if (ret < 0) {
net_pkt_unref(pkt);
LOG_ERR("Failed to write pkt, scur %d, err %d", ctx->scur, ret);
return ret;
}
ret = net_recv_data(iface, pkt);
if (ret < 0) {
net_pkt_unref(pkt);
LOG_ERR("Port %u failed to enqueue frame to RX queue, %d",
port, ret);
return ret;
}
}
update_pos:
rx_pos += ctx->oa_cps + sizeof(uint32_t);
}
return ret;
}
/*
* Setting up for a single dma transfer.
*/
static int eth_adin2111_send_oa_frame(const struct device *dev, struct net_pkt *pkt, int port)
{
struct adin2111_data *ctx = dev->data;
uint16_t clen, len = net_pkt_get_len(pkt);
uint32_t hdr;
uint8_t chunks, i;
int ret, txc, cur;
chunks = len / ctx->oa_cps;
if (len % ctx->oa_cps) {
chunks++;
}
ret = eth_adin2111_reg_read(dev, ADIN2111_BUFSTS, &txc);
if (ret < 0) {
LOG_ERR("Cannot read txc");
return -EIO;
}
txc = (txc & ADIN2111_BUFSTS_TXC_MASK) >> ADIN2111_BUFSTS_TXC;
if (txc < chunks) {
return -EIO;
}
/* Prepare for single dma transfer */
for (i = 1, cur = 0; i <= chunks; i++) {
hdr = ADIN2111_OA_DATA_HDR_DNC | ADIN2111_OA_DATA_HDR_DV |
ADIN2111_OA_DATA_HDR_NORX;
hdr |= (!!port << ADIN2111_OA_DATA_HDR_VS);
if (i == 1) {
hdr |= ADIN2111_OA_DATA_HDR_SV;
}
if (i == chunks) {
hdr |= ADIN2111_OA_DATA_HDR_EV;
hdr |= (ctx->oa_cps - 1) << ADIN2111_OA_DATA_HDR_EBO;
}
hdr |= eth_adin2111_oa_get_parity(hdr);
*(uint32_t *)&ctx->oa_tx_buf[cur] = sys_cpu_to_be32(hdr);
cur += sizeof(uint32_t);
clen = len > ctx->oa_cps ? ctx->oa_cps : len;
ret = net_pkt_read(pkt, &ctx->oa_tx_buf[cur], clen);
if (ret < 0) {
LOG_ERR("Cannot read from tx packet");
return ret;
}
cur += ctx->oa_cps;
len -= clen;
}
ret = eth_adin2111_oa_spi_xfer(dev, ctx->oa_rx_buf, ctx->oa_tx_buf, cur);
if (ret < 0) {
LOG_ERR("Error on SPI xfer");
return ret;
}
return 0;
}
static int eth_adin2111_reg_read_generic(const struct device *dev,
const uint16_t reg,
uint32_t *val)
{
const struct adin2111_config *cfg = dev->config;
@ -149,6 +400,72 @@ int eth_adin2111_reg_read(const struct device *dev, const uint16_t reg,
return ret;
}
static int eth_adin2111_reg_write_generic(const struct device *dev,
const uint16_t reg,
const uint32_t val)
{
const struct adin2111_config *cfg = dev->config;
size_t header_size = ADIN2111_WRITE_HEADER_SIZE;
size_t data_size = sizeof(uint32_t);
#if CONFIG_ETH_ADIN2111_SPI_CFG0
uint8_t buf[ADIN2111_REG_WRITE_BUF_SIZE_CRC] = { 0 };
#else
uint8_t buf[ADIN2111_REG_WRITE_BUF_SIZE] = { 0 };
#endif /* CONFIG_ETH_ADIN2111_SPI_CFG0 */
/* spi header */
*(uint16_t *)buf = htons((ADIN2111_WRITE_TXN_CTRL | reg));
#if CONFIG_ETH_ADIN2111_SPI_CFG0
buf[2] = crc8_ccitt(0, buf, header_size);
++header_size;
#endif /* CONFIG_ETH_ADIN2111_SPI_CFG0 */
/* reg */
*(uint32_t *)(buf + header_size) = htonl(val);
#if CONFIG_ETH_ADIN2111_SPI_CFG0
buf[header_size + data_size] = crc8_ccitt(0, &buf[header_size], data_size);
++data_size;
#endif /* CONFIG_ETH_ADIN2111_SPI_CFG0 */
const struct spi_buf spi_tx_buf = {
.buf = buf,
.len = header_size + data_size
};
const struct spi_buf_set tx = { .buffers = &spi_tx_buf, .count = 1U };
return spi_write_dt(&cfg->spi, &tx);
}
int eth_adin2111_reg_read(const struct device *dev, const uint16_t reg,
uint32_t *val)
{
struct adin2111_data *ctx = dev->data;
int rval;
if (ctx->oa) {
rval = eth_adin2111_reg_read_oa(dev, reg, val);
} else {
rval = eth_adin2111_reg_read_generic(dev, reg, val);
}
return rval;
}
int eth_adin2111_reg_write(const struct device *dev, const uint16_t reg,
const uint32_t val)
{
struct adin2111_data *ctx = dev->data;
int rval;
if (ctx->oa) {
rval = eth_adin2111_reg_write_oa(dev, reg, val);
} else {
rval = eth_adin2111_reg_write_generic(dev, reg, val);
}
return rval;
}
static int adin2111_read_fifo(const struct device *dev, const uint8_t port)
{
const struct adin2111_config *cfg = dev->config;
@ -302,11 +619,13 @@ static void adin2111_offload_thread(void *p1, void *p2, void *p3)
goto continue_unlock;
}
if (!ctx->oa) {
#if CONFIG_ETH_ADIN2111_SPI_CFG0
if (status0 & ADIN2111_STATUS1_SPI_ERR) {
LOG_WRN("Detected TX SPI CRC error");
}
#endif /* CONFIG_ETH_ADIN2111_SPI_CFG0 */
#endif
}
/* handle port 1 phy interrupts */
if (status0 & ADIN2111_STATUS0_PHYINT) {
@ -318,6 +637,22 @@ static void adin2111_offload_thread(void *p1, void *p2, void *p3)
adin2111_port_on_phyint(ctx->port[1]);
}
if (ctx->oa) {
if (status1 & ADIN2111_STATUS1_P1_RX_RDY) {
ret = eth_adin2111_oa_data_read(dev, 0);
if (ret < 0) {
break;
}
}
if (status1 & ADIN2111_STATUS1_P2_RX_RDY) {
ret = eth_adin2111_oa_data_read(dev, 1);
if (ret < 0) {
break;
}
}
goto continue_unlock;
}
/* handle port 1 rx */
if (status1 & ADIN2111_STATUS1_P1_RX_RDY) {
do {
@ -368,7 +703,7 @@ continue_unlock:
LOG_ERR("Failed to write IMASK1, %d", ret);
}
eth_adin2111_unlock(dev);
};
}
}
static void adin2111_int_callback(const struct device *dev,
@ -416,6 +751,31 @@ static int adin2111_port_send(const struct device *dev, struct net_pkt *pkt)
eth_adin2111_lock(adin, K_FOREVER);
if (ctx->oa) {
uint32_t val, rca = 0;
/*
* By high-traffic zperf test, noted that ADIN2111 does not like we send
* if there is something to be received. It stops to issue rx interrupts
* and zperf transfer hangs. Forcing a receive for this case.
*/
ret = eth_adin2111_reg_read(adin, ADIN2111_BUFSTS, &val);
if (ret < 0) {
return ret;
}
rca = val & ADIN2111_BUFSTS_RCA_MASK;
if (rca > 0) {
eth_adin2111_unlock(adin);
k_sem_give(&ctx->offload_sem);
k_yield();
eth_adin2111_lock(adin, K_FOREVER);
}
ret = eth_adin2111_send_oa_frame(cfg->adin, pkt, htons(cfg->port_idx));
goto end_check;
}
/* query remaining tx fifo space */
ret = adin2111_read_tx_space(adin, &tx_space);
if (ret < 0) {
@ -497,6 +857,7 @@ static int adin2111_port_send(const struct device *dev, struct net_pkt *pkt)
ret = spi_write_dt(&((const struct adin2111_config *) adin->config)->spi,
&tx);
end_check:
if (ret < 0) {
eth_stats_update_errors_tx(data->iface);
LOG_ERR("Port %u frame SPI write failed, %d", cfg->port_idx, ret);
@ -670,7 +1031,7 @@ static void adin2111_port_iface_init(struct net_if *iface)
/* all ifaces are done, start INT processing */
k_thread_create(&ctx->rx_thread, ctx->rx_thread_stack,
CONFIG_ETH_ADIN2111_IRQ_THREAD_STACK_SIZE,
K_KERNEL_STACK_SIZEOF(ctx->rx_thread_stack),
adin2111_offload_thread,
(void *)adin, NULL, NULL,
CONFIG_ETH_ADIN2111_IRQ_THREAD_PRIO,
@ -839,6 +1200,8 @@ static int adin2111_init(const struct device *dev)
return ret;
}
k_msleep(ADIN2111_SPI_ACTIVE_DELAY_MS);
ret = adin2111_check_spi(dev);
if (ret < 0) {
LOG_ERR("Failed to communicate over SPI, %d", ret);
@ -852,6 +1215,8 @@ static int adin2111_init(const struct device *dev)
return ret;
}
k_msleep(ADIN2111_SW_RESET_DELAY_MS);
ret = adin2111_await_device(dev);
if (ret < 0) {
LOG_ERR("ADIN did't come out of the reset, %d", ret);
@ -871,6 +1236,10 @@ static int adin2111_init(const struct device *dev)
val &= ~ADIN2111_CONFIG0_RXCTE;
val &= ~(ADIN2111_CONFIG0_TXCTE | ADIN2111_CONFIG0_TXFCSVE);
if (ctx->oa) {
val |= ADIN2111_CONFIG0_ZARFE;
}
ret = eth_adin2111_reg_write(dev, ADIN2111_CONFIG0, val);
if (ret < 0) {
LOG_ERR("Failed to write CONFIG0, %d", ret);
@ -966,12 +1335,11 @@ static const struct ethernet_api adin2111_port_api = {
NET_L2_GET_CTX_TYPE(ETHERNET_L2), NET_ETH_MTU);
#define ADIN2111_SPI_OPERATION ((uint16_t)(SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8)))
#define ADIN2111_MAC_INITIALIZE(inst, dev_id, ifaces, name) \
static uint8_t __aligned(4) name##_buffer_##inst[CONFIG_ETH_ADIN2111_BUFFER_SIZE]; \
static const struct adin2111_config name##_config_##inst = { \
.id = dev_id, \
.spi = SPI_DT_SPEC_INST_GET(inst, ADIN2111_SPI_OPERATION, 1), \
.spi = SPI_DT_SPEC_INST_GET(inst, ADIN2111_SPI_OPERATION, 0), \
.interrupt = GPIO_DT_SPEC_INST_GET(inst, int_gpios), \
.reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, { 0 }), \
}; \
@ -981,6 +1349,9 @@ static const struct ethernet_api adin2111_port_api = {
.offload_sem = Z_SEM_INITIALIZER(name##_data_##inst.offload_sem, 0, 1), \
.lock = Z_MUTEX_INITIALIZER(name##_data_##inst.lock), \
.buf = name##_buffer_##inst, \
.oa = DT_INST_PROP(inst, spi_oa), \
.oa_prot = DT_INST_PROP(inst, spi_oa_protection), \
.oa_cps = 64, \
}; \
/* adin */ \
DEVICE_DT_DEFINE(DT_DRV_INST(inst), adin2111_init, NULL, \

View file

@ -33,6 +33,10 @@
#define ADIN2111_CONFIG0_SYNC BIT(15)
/* Transmit Frame Check Sequence Validation Enable */
#define ADIN2111_CONFIG0_TXFCSVE BIT(14)
/* Zero Align Receive Frame Enable */
#define ADIN2111_CONFIG0_ZARFE BIT(12)
/* New packet received only after a new CS assertion */
#define ADIN2111_CONFIG0_CSARFE BIT(13)
/* Transmit Cut Through Enable */
#define ADIN2111_CONFIG0_TXCTE BIT(9)
/* Receive Cut Through Enable. Must be 0 for Generic SPI */
@ -72,9 +76,18 @@
#define ADIN2111_STATUS1_SPI_ERR BIT(10)
/* Port 1 RX FIFO Contains Data */
#define ADIN2111_STATUS1_P1_RX_RDY BIT(4)
/* Frame transmitted */
#define ADIN2111_STATUS1_TX_RDY BIT(3)
/* Value to completely clear status register 1 */
#define ADIN2111_STATUS1_CLEAR 0xFFF01F08U
/* Buffer Status Register */
#define ADIN2111_BUFSTS 0x0BU
/* Rx chunks available */
#define ADIN2111_BUFSTS_RCA_MASK GENMASK(7, 0)
/* Tx credits */
#define ADIN2111_BUFSTS_TXC 8U
#define ADIN2111_BUFSTS_TXC_MASK GENMASK(15, 8)
/* Interrupt Mask Register 0 */
#define ADIN2111_IMASK0 0x0CU
@ -161,6 +174,34 @@
/* Manufacturer unique ID */
#define ADIN2111_PHYID_OUI 0xa0ef
/* Open Alliance definitions */
#define ADIN2111_OA_ALLOC_TIMEOUT K_MSEC(10)
/* Max setting to a max RCA of 255 68-bytes ckunks */
#define ADIN2111_OA_BUF_SZ (255U * 64U)
#define ADIN2111_OA_CTL_LEN_PROT 16U
#define ADIN2111_OA_CTL_LEN 12U
#define ADIN2111_OA_CTL_MMS BIT(24)
#define ADIN2111_OA_CTL_WNR BIT(29)
#define ADIN2111_OA_DATA_HDR_DNC BIT(31)
#define ADIN2111_OA_DATA_HDR_NORX BIT(29)
#define ADIN2111_OA_DATA_HDR_VS 22U
#define ADIN2111_OA_DATA_HDR_DV BIT(21)
#define ADIN2111_OA_DATA_HDR_SV BIT(20)
#define ADIN2111_OA_DATA_HDR_EV BIT(14)
#define ADIN2111_OA_DATA_HDR_EBO 8U
#define ADIN2111_OA_DATA_FTR_SYNC BIT(29)
#define ADIN2111_OA_DATA_FTR_EBO 8U
#define ADIN2111_OA_DATA_FTR_DV BIT(21)
#define ADIN2111_OA_DATA_FTR_SV BIT(20)
#define ADIN2111_OA_DATA_FTR_EV BIT(14)
#define ADIN2111_OA_DATA_FTR_SWO 16U
#define ADIN2111_OA_DATA_FTR_SWO_MSK GENMASK(19, 16)
#define ADIN2111_OA_DATA_FTR_EBO 8U
#define ADIN2111_OA_DATA_FTR_EBO_MSK GENMASK(13, 8)
enum adin2111_chips_id {
ADIN2111_MAC = 0,
ADIN1110_MAC,
@ -183,6 +224,12 @@ struct adin2111_data {
uint32_t imask1;
uint16_t ifaces_left_to_init;
uint8_t *buf;
uint16_t scur;
bool oa;
bool oa_prot;
uint8_t oa_cps;
uint8_t oa_tx_buf[ADIN2111_OA_BUF_SZ];
uint8_t oa_rx_buf[ADIN2111_OA_BUF_SZ];
K_KERNEL_STACK_MEMBER(rx_thread_stack, CONFIG_ETH_ADIN2111_IRQ_THREAD_STACK_SIZE);
struct k_thread rx_thread;

View file

@ -53,6 +53,12 @@ properties:
reset-gpios:
type: phandle-array
description: The reset pin of ADIN2111.
spi-oa:
type: boolean
description: Enables Open Alliance SPI protocol.
spi-oa-protection:
type: boolean
description: Enables Open Alliance SPI protocol protection.
child-binding:
description: Port properties