From: Jean-Marie Verdun <ver...@hpe.com> Add support for the Wiznet W5500 spi to ethernet controller
Signed-off-by: Jean-Marie Verdun <ver...@hpe.com> --- drivers/net/Kconfig | 54 ++--- drivers/net/Makefile | 7 +- drivers/net/w5500.c | 508 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/w5500.h | 135 ++++++++++++ 4 files changed, 662 insertions(+), 42 deletions(-) create mode 100644 drivers/net/w5500.c create mode 100644 drivers/net/w5500.h diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index a0a7890bd26..41ecc8e05dc 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -19,6 +19,15 @@ config SPL_DM_ETH depends on SPL_NET def_bool y +config W5500 + bool "W5500 device driver" + depends on SPI + help + Enable w5500 driver + + Adds support for Wiznet W5500 device. The device must be attached + to a SPI bus. + config DM_MDIO bool "Enable Driver Model for MDIO devices" depends on PHYLIB @@ -122,14 +131,6 @@ config AG7XXX This driver supports the Atheros AG7xxx Ethernet MAC. This MAC is present in the Atheros AR7xxx, AR9xxx and QCA9xxx MIPS chips. -config AIROHA_ETH - bool "Airoha Ethernet QDMA Driver" - depends on ARCH_AIROHA - select PHYLIB - select DM_RESET - help - This Driver support Airoha Ethernet QDMA Driver - Say Y to enable support for the Airoha Ethernet QDMA. config ALTERA_TSE bool "Altera Triple-Speed Ethernet MAC support" @@ -245,13 +246,6 @@ config DWC_ETH_QOS Of Service) IP block. The IP supports many options for bus type, clocking/reset structure, and feature list. -config DWC_ETH_QOS_ADI - bool "Synopsys DWC Ethernet QOS device support for ADI SC59x-64 parts" - depends on DWC_ETH_QOS - help - The Synopsis Designware Ethernet QoS IP block with the specific - configuration used in the ADI ADSP-SC59X 64 bit SoCs - config DWC_ETH_QOS_IMX bool "Synopsys DWC Ethernet QOS device support for IMX" depends on DWC_ETH_QOS @@ -867,7 +861,6 @@ config RENESAS_ETHER_SWITCH config RENESAS_RAVB bool "Renesas Ethernet AVB MAC" depends on RCAR_64 - select BITBANGMII select PHYLIB select PHY_ETHERNET_ID help @@ -982,7 +975,14 @@ config TSEC_ENET This driver implements support for the (Enhanced) Three-Speed Ethernet Controller found on Freescale SoCs. -source "drivers/net/mtk_eth/Kconfig" +config MEDIATEK_ETH + bool "MediaTek Ethernet GMAC Driver" + select PHYLIB + select DM_GPIO + select DM_RESET + help + This Driver support MediaTek Ethernet GMAC + Say Y to enable support for the MediaTek Ethernet GMAC. config HIFEMAC_ETH bool "HiSilicon Fast Ethernet Controller" @@ -1016,26 +1016,6 @@ config FSL_ENETC This driver supports the NXP ENETC Ethernet controller found on some of the NXP SoCs. -config FSL_ENETC_NETC_BLK_CTRL - bool "NXP ENETC NETC blocks control driver" - depends on FSL_ENETC && IMX95 - default y if IMX95 - help - This driver configures Integrated Endpoint Register Block (IERB) and - Privileged Register Block (PRB) of NETC. For i.MX platforms, it also - includes the configuration of NETCMIX block. - The IERB contains registers that are used for pre-boot initialization, - debug, and non-customer configuration. The PRB controls global reset - and global error handling for NETC. The NETCMIX block is mainly used - to set MII protocol and PCS protocol of the links, it also contains - settings for some other functions. - -config MDIO_GPIO_BITBANG - bool "GPIO bitbanging MDIO driver" - depends on DM_MDIO && DM_GPIO - help - Driver for bitbanging MDIO - config MDIO_MUX_I2CREG bool "MDIO MUX accessed as a register over I2C" depends on DM_MDIO_MUX && DM_I2C diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3244d39036d..28578efb92f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_AG7XXX) += ag7xxx.o -obj-$(CONFIG_AIROHA_ETH) += airoha_eth.o obj-$(CONFIG_ALTERA_TSE) += altera_tse.o obj-$(CONFIG_ASPEED_MDIO) += aspeed_mdio.o obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o @@ -20,7 +19,6 @@ obj-$(CONFIG_DM_ETH_PHY) += eth-phy-uclass.o obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o obj-$(CONFIG_DSA_SANDBOX) += dsa_sandbox.o obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o -obj-$(CONFIG_DWC_ETH_QOS_ADI) += dwc_eth_qos_adi.o obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o obj-$(CONFIG_DWC_ETH_QOS_INTEL) += dwc_eth_qos_intel.o obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o @@ -46,7 +44,6 @@ obj-$(CONFIG_FEC_MXC) += fec_mxc.o obj-$(CONFIG_FMAN_ENET) += fm/ obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o -obj-$(CONFIG_FSL_ENETC_NETC_BLK_CTRL) += fsl_enetc_netc_blk_ctrl.o obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o obj-$(CONFIG_FSL_MC_ENET) += fsl-mc/ obj-$(CONFIG_FSL_MC_ENET) += ldpaa_eth/ @@ -64,14 +61,13 @@ obj-$(CONFIG_LITEETH) += liteeth.o obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o -obj-$(CONFIG_MDIO_GPIO_BITBANG) += mdio_gpio.o obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o obj-$(CONFIG_MDIO_MUX_MESON_G12A) += mdio_mux_meson_g12a.o obj-$(CONFIG_MDIO_MUX_MESON_GXL) += mdio_mux_meson_gxl.o obj-$(CONFIG_MDIO_MUX_MMIOREG) += mdio_mux_mmioreg.o obj-$(CONFIG_MDIO_MUX_SANDBOX) += mdio_mux_sandbox.o obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o -obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth/ +obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o obj-$(CONFIG_MT7620_ETH) += mt7620-eth.o obj-$(CONFIG_MT7628_ETH) += mt7628-eth.o @@ -103,6 +99,7 @@ obj-$(CONFIG_SUN4I_EMAC) += sunxi_emac.o obj-$(CONFIG_SUN8I_EMAC) += sun8i_emac.o obj-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o obj-$(CONFIG_TULIP) += dc2114x.o +obj-$(CONFIG_W5500) += w5500.o obj-$(CONFIG_VSC7385_ENET) += vsc7385.o obj-$(CONFIG_XILINX_AXIEMAC) += xilinx_axi_emac.o obj-$(CONFIG_XILINX_AXIMRMAC) += xilinx_axi_mrmac.o diff --git a/drivers/net/w5500.c b/drivers/net/w5500.c new file mode 100644 index 00000000000..45494c78933 --- /dev/null +++ b/drivers/net/w5500.c @@ -0,0 +1,508 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright Hewlett Packard Enterprise Development LP. + * + * Jean-Marie Verdun <ver...@hpe.com> + * + * inspired from the linux kernel driver from + * Copyright (C) 2006-2008 WIZnet Co.,Ltd. + * Copyright (C) 2012 Mike Sinkovsky <ms...@permonline.ru> + * + * available at + * + * https://github.com/torvalds/linux/blob/master/drivers/net/ethernet/wiznet/w5100.c + * + * Datasheet: + * http://www.wiznet.co.kr/wp-content/uploads/wiznethome/Chip/W5100/Document/W5100_Datasheet_v1.2.6.pdf + * http://wiznethome.cafe24.com/wp-content/uploads/wiznethome/Chip/W5200/Documents/W5200_DS_V140E.pdf + * http://wizwiki.net/wiki/lib/exe/fetch.php?media=products:w5500:w5500_ds_v106e_141230.pdf + * + */ + +#include <dm.h> +#include <log.h> +#include <malloc.h> +#include <spi.h> +#include <net.h> +#include "w5500.h" +#include <asm/global_data.h> +#include <linux/delay.h> + +DECLARE_GLOBAL_DATA_PTR; +static int w5500_command(struct udevice *dev, u8 cmd) +{ + struct eth_w5500_priv *priv = dev_get_priv(dev); + u16 counter = 0; + + w5500_spi_write(dev, W5100_S0_CR(priv), cmd); + while (w5500_spi_read(dev, W5100_S0_CR(priv)) != 0) { + counter++; + if (counter == 500) + return -EIO; + udelay(10); + } + return 0; +} + +/* + * Set priv ptr + * + * priv - priv void ptr to store in the device + */ +void w5500_eth_set_priv(int index, void *priv) +{ + struct udevice *dev; + struct eth_w5500_priv *dev_priv; + int ret; + + ret = uclass_get_device(UCLASS_ETH, index, &dev); + if (ret) + return; + + dev_priv = dev_get_priv(dev); + + dev_priv->priv = priv; +} + +static int w5500_eth_start(struct udevice *dev) +{ + struct eth_w5500_priv *priv = dev_get_priv(dev); + + debug("eth_w5500: Start\n"); + + u8 mode = S0_MR_MACRAW; + + if (!priv->promisc) + mode |= W5500_S0_MR_MF; + + w5500_spi_write(dev, W5100_S0_MR(priv), mode); + w5500_command(dev, S0_CR_OPEN); + priv->offset = 0; + return 0; +} + +static int w5500_eth_send(struct udevice *dev, void *packet, int length) +{ + struct eth_w5500_priv *priv = dev_get_priv(dev); + u16 offset; + + if (priv->disabled) + return 0; + + offset = w5500_spi_read16(dev, W5100_S0_TX_WR(priv)); + w5500_writebuf(dev, offset, packet, length); + w5500_spi_write16(dev, W5100_S0_TX_WR(priv), offset + length); + w5500_command(dev, S0_CR_SEND); + return 0; +} + +static int w5500_eth_recv(struct udevice *dev, int flags, u8 **packetp) +{ + struct eth_w5500_priv *priv = dev_get_priv(dev); + u16 rx_len; + u16 offset; + u8 data[9000]; + u16 tmp; + + u16 rx_buf_len = w5500_spi_read16(dev, W5100_S0_RX_RSR(priv)); + + while ((tmp = + w5500_spi_read16(dev, W5100_S0_RX_RSR(priv))) != rx_buf_len) + rx_buf_len = tmp; + + if (rx_buf_len == 0) + return 0; + + offset = w5500_spi_read16(dev, W5100_S0_RX_RD(priv)); + rx_len = rx_buf_len - 2; + w5500_readbuf(dev, offset + 2, data, rx_len); + w5500_spi_write16(dev, W5100_S0_RX_RD(priv), offset + 2 + rx_len); + w5500_command(dev, S0_CR_RECV); + *packetp = data; + + priv->offset += rx_buf_len; + return rx_len; +} + +static int w5500_eth_free_pkt(struct udevice *dev, u8 *packet, int length) +{ + struct eth_w5500_priv *priv = dev_get_priv(dev); + int i; + + if (!priv->recv_packets) + return 0; + + --priv->recv_packets; + for (i = 0; i < priv->recv_packets; i++) { + priv->recv_packet_length[i] = priv->recv_packet_length[i + 1]; + memcpy(priv->recv_packet_buffer[i], + priv->recv_packet_buffer[i + 1], + priv->recv_packet_length[i + 1]); + } + priv->recv_packet_length[priv->recv_packets] = 0; + + return 0; +} + +static void w5500_eth_stop(struct udevice *dev) +{ + debug("eth_w5500: Stop\n"); +} + +static int xfer(struct udevice *dev, void *dout, unsigned int bout, void *din, + unsigned int bin) +{ + /* Ok the xfer function in uboot is symmetrical + * (write and read operation happens at the same time) + * w5500 requires bytes send followed by receive operation on the MISO line + * So we need to create a buffer which contain bout+bin bytes and pass the various + * pointer to the xfer function + */ + + struct udevice *bus = dev_get_parent(dev); + u8 buffin[BUFFER_SZ]; + u8 buffout[BUFFER_SZ]; + + if ((bout + bin) < BUFFER_SZ) { + for (int i = 0; i < bout; i++) { + buffout[i] = ((u8 *)(dout))[i]; + buffin[i] = 0; + } + for (int i = bout; i < (bin + bout); i++) { + buffin[i] = 0; + buffout[i] = 0; + } + if (bus) { + dm_spi_xfer(dev, 8 * (bout + bin), buffout, buffin, + SPI_XFER_BEGIN | SPI_XFER_END); + for (int i = bout; i < (bin + bout); i++) + ((u8 *)(din))[bin + bout - i - 1] = buffin[i]; + } else { + return -1; + } + } + return 0; +} + +static int w5500_spi_write(struct udevice *dev, u32 addr, u8 data) +{ + u8 bank; + u8 din = 0; + u8 cmd[4]; + + bank = (addr >> 16); + + if (bank > 0) + bank = bank << 3; + + cmd[0] = (addr >> 8) & 0xff; + cmd[1] = addr & 0xff; + cmd[2] = bank | 0x4; + cmd[3] = data; + + return xfer(dev, cmd, sizeof(cmd), &din, 0); +} + +static int w5500_spi_read(struct udevice *dev, u32 addr) +{ + u8 bank; + u8 cmd[3]; + u8 data; + int ret; + + bank = (addr >> 16); + + if (bank > 0) + bank = bank << 3; + + cmd[0] = addr >> 8; + cmd[1] = addr & 0xff; + cmd[2] = bank; + + ret = xfer(dev, cmd, sizeof(cmd), &data, 1); + + return data; +} + +static int w5500_spi_read16(struct udevice *dev, u32 addr) +{ + u16 data; + int ret; + u8 bank; + u8 cmd[3]; + + bank = (addr >> 16); + + if (bank > 0) + bank = bank << 3; + + cmd[0] = addr >> 8; + cmd[1] = addr & 0xff; + cmd[2] = bank; + + ret = xfer(dev, cmd, sizeof(cmd), &data, 2); + + return data; +} + +static int w5500_spi_write16(struct udevice *dev, u32 addr, u16 data) +{ + int ret; + u8 buf[2]; + + buf[0] = data >> 8; + buf[1] = data & 0xff; + + ret = w5500_writebulk(dev, addr, &buf[0], 2); + + return ret; +} + +static int w5500_readbulk(struct udevice *dev, u32 addr, u8 *buf, int len) +{ + int i; + u8 data[9000]; + u8 bank; + u8 cmd[3]; + int ret; + + bank = (addr >> 16); + + if (bank > 0) + bank = bank << 3; + + cmd[0] = addr >> 8; + cmd[1] = addr & 0xff; + cmd[2] = bank; + + ret = xfer(dev, cmd, sizeof(cmd), &data, len); + + for (i = 0; i < len; i++) + buf[(len - 1) - i] = data[i]; + + return 0; +} + +static int w5500_writebulk(struct udevice *dev, u32 addr, const u8 *buf, + int len) +{ + int i; + u8 bank; + u8 cmd[9000]; + u8 din = 0; + + bank = (addr >> 16); + if (bank > 0) + bank = bank << 3; + + cmd[0] = (addr >> 8) & 0xff; + cmd[1] = addr & 0xff; + cmd[2] = bank | 0x4; + + for (i = 0; i < len; i++) + cmd[i + 3] = buf[i]; + + return xfer(dev, cmd, len + 3, &din, 0); +} + +static int w5500_writebuf(struct udevice *dev, u16 offset, const u8 *buf, + int len) +{ + u32 addr; + int ret; + int remain = 0; + struct eth_w5500_priv *priv = dev_get_priv(dev); + const u32 mem_start = priv->s0_tx_buf; + const u16 mem_size = priv->s0_tx_buf_size; + + offset %= mem_size; + addr = mem_start + offset; + + if (offset + len > mem_size) { + remain = (offset + len) % mem_size; + len = mem_size - offset; + } + + ret = w5500_writebulk(dev, addr, buf, len); + + if (ret || !remain) + return ret; + + return w5500_writebulk(dev, mem_start, buf + len, remain); +} + +static int w5500_readbuf(struct udevice *dev, u16 offset, u8 *buf, int len) +{ + u32 addr; + int remain = 0; + int ret; + struct eth_w5500_priv *priv = dev_get_priv(dev); + const u32 mem_start = priv->s0_rx_buf; + const u16 mem_size = priv->s0_rx_buf_size; + + offset %= mem_size; + addr = mem_start + offset; + + if (offset + len > mem_size) { + remain = (offset + len) % mem_size; + len = mem_size - offset; + } + + ret = w5500_readbulk(dev, addr, buf, len); + if (ret || !remain) + return ret; + + return w5500_readbulk(dev, mem_start, buf + len, remain); +} + +static int w5500_eth_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct eth_w5500_priv *priv = dev_get_priv(dev); + u8 eth[6]; + u8 mode; + + if (memcmp(priv->host_hwaddr, pdata->enetaddr, ARP_HLEN) != 0) { + memcpy(priv->host_hwaddr, pdata->enetaddr, ARP_HLEN); + w5500_writebulk(dev, W5100_SHAR, priv->host_hwaddr, ARP_HLEN); + } + + w5500_readbulk(dev, W5100_SHAR, eth, 6); + + mode = 0x84; + w5500_spi_write(dev, W5100_S0_MR(priv), mode); + w5500_command(dev, S0_CR_OPEN); + w5500_enable_intr(dev); + + return 0; +} + +static const struct eth_ops w5500_eth_ops = { + .start = w5500_eth_start, + .send = w5500_eth_send, + .recv = w5500_eth_recv, + .free_pkt = w5500_eth_free_pkt, + .stop = w5500_eth_stop, + .write_hwaddr = w5500_eth_write_hwaddr, +}; + +static int w5500_eth_remove(struct udevice *dev) +{ + return 0; +} + +int w5500_eth_of_to_plat(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct eth_w5500_priv *priv = dev_get_priv(dev); + u8 mac[8]; + u32 ret; + ofnode remote; + const void *ptr; + int size; + + size = 0; + ptr = ofnode_read_prop(remote, "local-mac-address", &size); + if (size == 6) { + mac[0] = ((u8 *)ptr)[0]; + mac[1] = ((u8 *)ptr)[1]; + mac[2] = ((u8 *)ptr)[2]; + mac[3] = ((u8 *)ptr)[4]; + mac[4] = ((u8 *)ptr)[5]; + mac[5] = ((u8 *)ptr)[5]; + } else { + return ret; + } + + memcpy(pdata->enetaddr, (void *)mac, ARP_HLEN); + + priv->disabled = false; + + return 0; +} + +static void w5500_socket_intr_mask(struct udevice *dev, u8 mask) +{ + u32 imr; + + imr = W5500_SIMR; + + w5500_spi_write(dev, imr, mask); +} + +static void w5500_disable_intr(struct udevice *dev) +{ + w5500_socket_intr_mask(dev, 0); +} + +static void w5500_enable_intr(struct udevice *dev) +{ + w5500_socket_intr_mask(dev, IR_S0); +} + +int w5500_eth_probe(struct udevice *dev) +{ + struct eth_w5500_priv *priv = dev_get_priv(dev); + int i; + u16 rtr; + u8 cmd[3]; + + if (device_get_uclass_id(dev->parent) != UCLASS_SPI) { + debug("Error device not attached to a SPI controlled\n"); + return -ENODEV; + } + + cmd[0] = 0x00; + cmd[1] = 0x19; + cmd[2] = 0; + + w5500_spi_write(dev, W5100_MR, MR_RST); + w5500_spi_write(dev, W5100_MR, MR_PB); + + rtr = W5500_RTR; + if (w5500_spi_read16(dev, rtr) != RTR_DEFAULT) { + debug("RTR issue in probe .... %x\n", + w5500_spi_read16(dev, rtr)); + return -ENODEV; + } + + w5500_disable_intr(dev); + + /* Configure internal RX memory as 16K RX buffer and + * internal TX memory as 16K TX buffer + */ + + w5500_spi_write(dev, W5500_Sn_RXMEM_SIZE(0), 0x10); + w5500_spi_write(dev, W5500_Sn_TXMEM_SIZE(0), 0x10); + + for (i = 1; i < 8; i++) { + w5500_spi_write(dev, W5500_Sn_RXMEM_SIZE(i), 0); + w5500_spi_write(dev, W5500_Sn_TXMEM_SIZE(i), 0); + } + + priv->s0_regs = W5500_S0_REGS; + priv->s0_tx_buf = W5500_TX_MEM_START; + priv->s0_tx_buf_size = W5500_TX_MEM_SIZE; + priv->s0_rx_buf = W5500_RX_MEM_START; + priv->s0_rx_buf_size = W5500_RX_MEM_SIZE; + + priv->offset = 0; + return 0; +} + +static const struct udevice_id w5500_eth_ids[] = { + {.compatible = "wiznet,w5500" }, + { } +}; + +U_BOOT_DRIVER(eth_w5500) = { + .name = "eth_w5500", + .id = UCLASS_ETH, + .of_match = w5500_eth_ids, + .of_to_plat = w5500_eth_of_to_plat, + .probe = w5500_eth_probe, + .remove = w5500_eth_remove, + .ops = &w5500_eth_ops, + .priv_auto = sizeof(struct eth_w5500_priv), + .plat_auto = sizeof(struct eth_pdata), +}; diff --git a/drivers/net/w5500.h b/drivers/net/w5500.h new file mode 100644 index 00000000000..8a18312050b --- /dev/null +++ b/drivers/net/w5500.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2025 Hewlett Packard Enterprise LLC + * + * Jean-Marie Verdun <ver...@hpe.com> + */ + +#ifndef __ETH_H +#define __ETH_H + +#include <net.h> + +#define BUFFER_SZ 16384 +#define W5100_SPI_WRITE_OPCODE 0xf0 +#define W5100_SPI_READ_OPCODE 0x0f +#define W5100_SHAR 0x0009 /* Source MAC address */ +#define W5500_S0_REGS 0x10000 +#define S0_REGS(priv) ((priv)->s0_regs) +#define W5100_MR 0x0000 /* Mode Register */ +#define MR_RST 0x80 /* S/W reset */ +#define MR_PB 0x10 /* Ping block */ + +#define W5100_Sn_MR 0x0000 /* Sn Mode Register */ +#define W5100_Sn_CR 0x0001 /* Sn Command Register */ +#define W5100_Sn_IR 0x0002 /* Sn Interrupt Register */ +#define W5100_Sn_SR 0x0003 /* Sn Status Register */ +#define W5100_Sn_TX_FSR 0x0020 /* Sn Transmit free memory size */ +#define W5100_Sn_TX_RD 0x0022 /* Sn Transmit memory read pointer */ +#define W5100_Sn_TX_WR 0x0024 /* Sn Transmit memory write pointer */ +#define W5100_Sn_RX_RSR 0x0026 /* Sn Receive free memory size */ +#define W5100_Sn_RX_RD 0x0028 /* Sn Receive memory read pointer */ + +#define W5100_S0_MR(priv) (S0_REGS(priv) + W5100_Sn_MR) + +#define S0_MR_MACRAW 0x04 /* MAC RAW mode */ +#define S0_MR_MF 0x40 /* MAC Filter for W5100 and W5200 */ +#define W5500_S0_MR_MF 0x80 /* MAC Filter for W5500 */ +#define W5100_S0_MR(priv) (S0_REGS(priv) + W5100_Sn_MR) + +#define S0_MR_MACRAW 0x04 /* MAC RAW mode */ +#define S0_MR_MF 0x40 /* MAC Filter for W5100 and W5200 */ +#define W5500_S0_MR_MF 0x80 /* MAC Filter for W5500 */ + +/* + * W5100 and W5200 common registers about the same with the W5500 + */ +#define W5100_IMR 0x0016 /* Interrupt Mask Register */ +#define IR_S0 0x01 /* S0 interrupt */ +#define W5100_RTR 0x0017 /* Retry Time-value Register */ +#define RTR_DEFAULT 2000 /* =0x07d0 (2000) */ +#define W5500_SIMR 0x0018 /* Socket Interrupt Mask Register */ +#define W5500_RTR 0x0019 /* Retry Time-value Register */ + +#define W5100_S0_CR(priv) (S0_REGS(priv) + W5100_Sn_CR) +#define S0_CR_OPEN 0x01 /* OPEN command */ +#define S0_CR_CLOSE 0x10 /* CLOSE command */ +#define S0_CR_SEND 0x20 /* SEND command */ +#define S0_CR_RECV 0x40 /* RECV command */ +#define W5100_S0_IR(priv) (S0_REGS(priv) + W5100_Sn_IR) +#define S0_IR_SENDOK 0x10 /* complete sending */ +#define S0_IR_RECV 0x04 /* receiving data */ +#define W5100_S0_SR(priv) (S0_REGS(priv) + W5100_Sn_SR) +#define S0_SR_MACRAW 0x42 /* mac raw mode */ +#define W5100_S0_TX_FSR(priv) (S0_REGS(priv) + W5100_Sn_TX_FSR) +#define W5100_S0_TX_RD(priv) (S0_REGS(priv) + W5100_Sn_TX_RD) +#define W5100_S0_TX_WR(priv) (S0_REGS(priv) + W5100_Sn_TX_WR) +#define W5100_S0_RX_RSR(priv) (S0_REGS(priv) + W5100_Sn_RX_RSR) +#define W5100_S0_RX_RD(priv) (S0_REGS(priv) + W5100_Sn_RX_RD) + +#define W5500_TX_MEM_START 0x20000 +#define W5500_TX_MEM_SIZE 0x04000 +#define W5500_RX_MEM_START 0x30000 +#define W5500_RX_MEM_SIZE 0x04000 + +#define W5500_Sn_RXMEM_SIZE(n) \ + (0x1001e + (n) * 0x40000) /* Sn RX Memory Size */ +#define W5500_Sn_TXMEM_SIZE(n) \ + (0x1001f + (n) * 0x40000) /* Sn TX Memory Size */ + +/** + * A packet handler + * + * dev - device pointer + * pkt - pointer to the "sent" packet + * len - packet length + */ +typedef int w5500_eth_tx_hand_f(struct udevice *dev, void *pkt, + unsigned int len); + +/** + * struct eth_w5500_priv - memory for w5500 driver + * + * host_hwaddr - MAC address of mocked machine + * disabled - Will not respond + * recv_packet_buffer - buffers of the packet returned as received + * recv_packet_length - lengths of the packet returned as received + * recv_packets - number of packets returned + * tx_handler - function to generate responses to sent packets + * priv - a pointer to some structure a test may want to keep track of + */ +struct eth_w5500_priv { + uchar host_hwaddr[ARP_HLEN]; + bool disabled; + uchar *recv_packet_buffer[PKTBUFSRX]; + int recv_packet_length[PKTBUFSRX]; + int recv_packets; + w5500_eth_tx_hand_f *tx_handler; + const struct dm_spi_ops *spi_ops; + struct udevice **spi_dev; + /* Socket 0 register offset address */ + u32 s0_regs; + /* Socket 0 TX buffer offset address and size */ + u32 s0_tx_buf; + u16 s0_tx_buf_size; + /* Socket 0 RX buffer offset address and size */ + u32 s0_rx_buf; + u16 s0_rx_buf_size; + bool promisc; + u32 msg_enable; + u16 offset; + void *priv; +}; + +static int w5500_spi_write(struct udevice *dev, u32 addr, u8 data); +static int w5500_spi_read(struct udevice *dev, u32 addr); +static void w5500_enable_intr(struct udevice *dev); +static int w5500_spi_read16(struct udevice *dev, u32 addr); +static int w5500_spi_write16(struct udevice *dev, u32 addr, u16 data); +static int w5500_writebuf(struct udevice *dev, u16 offset, const u8 *buf, + int len); +static int w5500_readbuf(struct udevice *dev, u16 offset, u8 *buf, int len); +static int w5500_writebulk(struct udevice *dev, u32 addr, const u8 *buf, + int len); + +#endif /* __ETH_H */ -- 2.43.0