From 3e1848778c068bddd442855792d478eb2f038665 Mon Sep 17 00:00:00 2001 From: Hou Zhiqiang Date: Sat, 12 Jun 2021 21:15:41 +0300 Subject: [PATCH 01/10] Fix a memory leak issue in the RX port initialization. Signed-off-by: Hou Zhiqiang Reviewed-by: Ramon Fried --- drivers/net/fm/eth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c index 0e89e663f71..7c23ccc1f0e 100644 --- a/drivers/net/fm/eth.c +++ b/drivers/net/fm/eth.c @@ -288,8 +288,10 @@ static int fm_eth_rx_port_parameter_init(struct fm_eth *fm_eth) /* alloc Rx buffer from main memory */ rx_buf_pool = malloc(MAX_RXBUF_LEN * RX_BD_RING_SIZE); - if (!rx_buf_pool) + if (!rx_buf_pool) { + free(rx_bd_ring_base); return -ENOMEM; + } memset(rx_buf_pool, 0, MAX_RXBUF_LEN * RX_BD_RING_SIZE); debug("%s: rx_buf_pool = %p\n", __func__, rx_buf_pool); From 70018635969987c1224b27f62c851ac70264f272 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 16 Apr 2021 13:25:09 -0700 Subject: [PATCH 02/10] net: e1000: do not attempt to set hwaddr for i210 without FLASH commit f1bcad22dd19 ("net: e1000: add support for writing to EEPROM") adds support for storing hwaddr in EEPROM however i210 devices do not support this and thus results in errors such as: Warning: e1000#0 failed to set MAC address' Check if a flash device is present and if not return -ENOSYS indicating this is not supported. Signed-off-by: Tim Harvey Reviewed-by: Ramon Fried --- drivers/net/e1000.c | 4 ++++ drivers/net/e1000.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 694114eca79..60613b7df07 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -5673,6 +5673,10 @@ static int e1000_write_hwaddr(struct eth_device *dev) DEBUGOUT("%s: mac=%pM\n", __func__, mac); + if ((hw->eeprom.type == e1000_eeprom_invm) && + !(E1000_READ_REG(hw, EECD) & E1000_EECD_FLASH_DETECTED_I210)) + return -ENOSYS; + memset(current_mac, 0, 6); /* Read from EEPROM, not from registers, to make sure diff --git a/drivers/net/e1000.h b/drivers/net/e1000.h index 072851ba31c..082154a997e 100644 --- a/drivers/net/e1000.h +++ b/drivers/net/e1000.h @@ -1245,6 +1245,7 @@ struct e1000_hw { #define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ #define E1000_EECD_FLUPD_I210 0x00800000 /* Update FLASH */ #define E1000_EECD_FLUDONE_I210 0x04000000 /* Update FLASH done*/ +#define E1000_EECD_FLASH_DETECTED_I210 0x00080000 /* FLASH detected */ #define E1000_FLUDONE_ATTEMPTS 20000 #define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ #define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ From 07292f8e51dfc9a8f4065e08144955eebff88944 Mon Sep 17 00:00:00 2001 From: Daniil Stas Date: Sun, 23 May 2021 22:24:48 +0000 Subject: [PATCH 03/10] net: dwc_eth_qos: Fix needless phy auto-negotiation restarts Disabling clk_ck clock leads to link up status loss in phy, which leads to auto-negotiation restart before each network command execution. This issue is especially big for PXE boot protocol because of auto-negotiation restarts before each configuration filename trial. To avoid this issue don't disable clk_ck clock after it was enabled. Signed-off-by: Daniil Stas Cc: Ramon Fried Cc: Joe Hershberger Cc: Patrick Delaunay Cc: Patrice Chotard Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index e8242ca4e1b..2f088c758f0 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -321,6 +321,7 @@ struct eqos_priv { void *rx_pkt; bool started; bool reg_access_ok; + bool clk_ck_enabled; }; /* @@ -591,12 +592,13 @@ static int eqos_start_clks_stm32(struct udevice *dev) goto err_disable_clk_rx; } - if (clk_valid(&eqos->clk_ck)) { + if (clk_valid(&eqos->clk_ck) && !eqos->clk_ck_enabled) { ret = clk_enable(&eqos->clk_ck); if (ret < 0) { pr_err("clk_enable(clk_ck) failed: %d", ret); goto err_disable_clk_tx; } + eqos->clk_ck_enabled = true; } #endif @@ -648,8 +650,6 @@ static void eqos_stop_clks_stm32(struct udevice *dev) clk_disable(&eqos->clk_tx); clk_disable(&eqos->clk_rx); clk_disable(&eqos->clk_master_bus); - if (clk_valid(&eqos->clk_ck)) - clk_disable(&eqos->clk_ck); #endif debug("%s: OK\n", __func__); From f024e0b208dd81db03522930b70c875370a86aae Mon Sep 17 00:00:00 2001 From: Daniil Stas Date: Sun, 30 May 2021 13:34:09 +0000 Subject: [PATCH 04/10] net: dwc_eth_qos: Revert some changes of commit 3a97da12ee7b Revert some changes of commit 3a97da12ee7b ("net: dwc_eth_qos: add dwc eqos for imx support") that were probably added by mistake. One of these changes can lead to received data corruption (enabling FUP and FEP bits). Another causes invalid register rxq_ctrl0 settings for some platforms. And another makes some writes at unknown memory location. Fixes: 3a97da12ee7b ("net: dwc_eth_qos: add dwc eqos for imx support") Signed-off-by: Daniil Stas Cc: Ye Li Cc: Fugang Duan Cc: Peng Fan Cc: Ramon Fried Cc: Joe Hershberger Cc: Patrice Chotard Cc: Patrick Delaunay Reviewed-by: Ramon Fried --- drivers/net/dwc_eth_qos.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 2f088c758f0..b012bed517d 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -172,8 +172,6 @@ struct eqos_mtl_regs { #define EQOS_MTL_RXQ0_OPERATION_MODE_RFA_MASK 0x3f #define EQOS_MTL_RXQ0_OPERATION_MODE_EHFC BIT(7) #define EQOS_MTL_RXQ0_OPERATION_MODE_RSF BIT(5) -#define EQOS_MTL_RXQ0_OPERATION_MODE_FEP BIT(4) -#define EQOS_MTL_RXQ0_OPERATION_MODE_FUP BIT(3) #define EQOS_MTL_RXQ0_DEBUG_PRXQ_SHIFT 16 #define EQOS_MTL_RXQ0_DEBUG_PRXQ_MASK 0x7fff @@ -1222,7 +1220,6 @@ static int eqos_start(struct udevice *dev) } /* Configure MTL */ - writel(0x60, &eqos->mtl_regs->txq0_quantum_weight - 0x100); /* Enable Store and Forward mode for TX */ /* Program Tx operating mode */ @@ -1236,9 +1233,7 @@ static int eqos_start(struct udevice *dev) /* Enable Store and Forward mode for RX, since no jumbo frame */ setbits_le32(&eqos->mtl_regs->rxq0_operation_mode, - EQOS_MTL_RXQ0_OPERATION_MODE_RSF | - EQOS_MTL_RXQ0_OPERATION_MODE_FEP | - EQOS_MTL_RXQ0_OPERATION_MODE_FUP); + EQOS_MTL_RXQ0_OPERATION_MODE_RSF); /* Transmit/Receive queue fifo size; use all RAM for 1 queue */ val = readl(&eqos->mac_regs->hw_feature1); @@ -1314,12 +1309,6 @@ static int eqos_start(struct udevice *dev) eqos->config->config_mac << EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT); - clrsetbits_le32(&eqos->mac_regs->rxq_ctrl0, - EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK << - EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT, - 0x2 << - EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT); - /* Multicast and Broadcast Queue Enable */ setbits_le32(&eqos->mac_regs->unused_0a4, 0x00100000); From eab447b2b5d3d357f07a28150b13862b1c26b2e2 Mon Sep 17 00:00:00 2001 From: Jassi Brar Date: Fri, 4 Jun 2021 18:44:38 +0900 Subject: [PATCH 05/10] net: synquacer: Add netsec driver Add SynQuacer's NETSEC GbE controller driver. Since this driver will load the firmware from SPI NOR flash, this depends on CONFIG_SYNQUACER_SPI=y. Signed-off-by: Jassi Brar Reviewed-by: Ramon Fried --- drivers/net/Kconfig | 8 + drivers/net/Makefile | 1 + drivers/net/sni_netsec.c | 1134 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 1143 insertions(+) create mode 100644 drivers/net/sni_netsec.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 382639044bf..9fc28b149d0 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -673,6 +673,14 @@ config SNI_AVE This driver implements support for the Socionext AVE Ethernet controller, as found on the Socionext UniPhier family. +config SNI_NETSEC + bool "Socionext NETSEC Ethernet support" + depends on DM_ETH && SYNQUACER_SPI + select PHYLIB + help + This driver implements support for the Socionext SynQuacer NETSEC + ethernet controller, as found on the Socionext SynQuacer family. + source "drivers/net/mscc_eswitch/Kconfig" config ETHER_ON_FEC1 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index a44a7d3f56a..d56baa65b2f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -89,6 +89,7 @@ obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o obj-$(CONFIG_FSL_PFE) += pfe_eth/ obj-y += qe/ obj-$(CONFIG_SNI_AVE) += sni_ave.o +obj-$(CONFIG_SNI_NETSEC) += sni_netsec.o obj-y += ti/ obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o obj-y += mscc_eswitch/ diff --git a/drivers/net/sni_netsec.c b/drivers/net/sni_netsec.c new file mode 100644 index 00000000000..a9ebf6af9c5 --- /dev/null +++ b/drivers/net/sni_netsec.c @@ -0,0 +1,1134 @@ +// SPDX-License-Identifier: GPL-2.0+ +/** + * netsec.c - Socionext Synquacer Netsec driver + * Copyright 2021 Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NETSEC_REG_SOFT_RST 0x104 +#define NETSEC_REG_COM_INIT 0x120 + +#define NETSEC_REG_TOP_STATUS 0x200 +#define NETSEC_IRQ_RX BIT(1) +#define NETSEC_IRQ_TX BIT(0) + +#define NETSEC_REG_TOP_INTEN 0x204 +#define NETSEC_REG_INTEN_SET 0x234 +#define NETSEC_REG_INTEN_CLR 0x238 + +#define NETSEC_REG_NRM_TX_STATUS 0x400 +#define NETSEC_REG_NRM_TX_INTEN 0x404 +#define NETSEC_REG_NRM_TX_INTEN_SET 0x428 +#define NETSEC_REG_NRM_TX_INTEN_CLR 0x42c +#define NRM_TX_ST_NTOWNR BIT(17) +#define NRM_TX_ST_TR_ERR BIT(16) +#define NRM_TX_ST_TXDONE BIT(15) +#define NRM_TX_ST_TMREXP BIT(14) + +#define NETSEC_REG_NRM_RX_STATUS 0x440 +#define NETSEC_REG_NRM_RX_INTEN 0x444 +#define NETSEC_REG_NRM_RX_INTEN_SET 0x468 +#define NETSEC_REG_NRM_RX_INTEN_CLR 0x46c +#define NRM_RX_ST_RC_ERR BIT(16) +#define NRM_RX_ST_PKTCNT BIT(15) +#define NRM_RX_ST_TMREXP BIT(14) + +#define NETSEC_REG_PKT_CMD_BUF 0xd0 + +#define NETSEC_REG_CLK_EN 0x100 + +#define NETSEC_REG_PKT_CTRL 0x140 + +#define NETSEC_REG_DMA_TMR_CTRL 0x20c +#define NETSEC_REG_F_TAIKI_MC_VER 0x22c +#define NETSEC_REG_F_TAIKI_VER 0x230 +#define NETSEC_REG_DMA_HM_CTRL 0x214 +#define NETSEC_REG_DMA_MH_CTRL 0x220 +#define NETSEC_REG_ADDR_DIS_CORE 0x218 +#define NETSEC_REG_DMAC_HM_CMD_BUF 0x210 +#define NETSEC_REG_DMAC_MH_CMD_BUF 0x21c + +#define NETSEC_REG_NRM_TX_PKTCNT 0x410 + +#define NETSEC_REG_NRM_TX_DONE_PKTCNT 0x414 +#define NETSEC_REG_NRM_TX_DONE_TXINT_PKTCNT 0x418 + +#define NETSEC_REG_NRM_TX_TMR 0x41c + +#define NETSEC_REG_NRM_RX_PKTCNT 0x454 +#define NETSEC_REG_NRM_RX_RXINT_PKTCNT 0x458 +#define NETSEC_REG_NRM_TX_TXINT_TMR 0x420 +#define NETSEC_REG_NRM_RX_RXINT_TMR 0x460 + +#define NETSEC_REG_NRM_RX_TMR 0x45c + +#define NETSEC_REG_NRM_TX_DESC_START_UP 0x434 +#define NETSEC_REG_NRM_TX_DESC_START_LW 0x408 +#define NETSEC_REG_NRM_RX_DESC_START_UP 0x474 +#define NETSEC_REG_NRM_RX_DESC_START_LW 0x448 + +#define NETSEC_REG_NRM_TX_CONFIG 0x430 +#define NETSEC_REG_NRM_RX_CONFIG 0x470 + +#define MAC_REG_STATUS 0x1024 +#define MAC_REG_DATA 0x11c0 +#define MAC_REG_CMD 0x11c4 +#define MAC_REG_FLOW_TH 0x11cc +#define MAC_REG_INTF_SEL 0x11d4 +#define MAC_REG_DESC_INIT 0x11fc +#define MAC_REG_DESC_SOFT_RST 0x1204 +#define NETSEC_REG_MODE_TRANS_COMP_STATUS 0x500 + +#define GMAC_REG_MCR 0x0000 +#define GMAC_REG_MFFR 0x0004 +#define GMAC_REG_GAR 0x0010 +#define GMAC_REG_GDR 0x0014 +#define GMAC_REG_FCR 0x0018 +#define GMAC_REG_BMR 0x1000 +#define GMAC_REG_RDLAR 0x100c +#define GMAC_REG_TDLAR 0x1010 +#define GMAC_REG_OMR 0x1018 + +#define MHZ(n) ((n) * 1000 * 1000) + +#define NETSEC_TX_SHIFT_OWN_FIELD 31 +#define NETSEC_TX_SHIFT_LD_FIELD 30 +#define NETSEC_TX_SHIFT_DRID_FIELD 24 +#define NETSEC_TX_SHIFT_PT_FIELD 21 +#define NETSEC_TX_SHIFT_TDRID_FIELD 16 +#define NETSEC_TX_SHIFT_CC_FIELD 15 +#define NETSEC_TX_SHIFT_FS_FIELD 9 +#define NETSEC_TX_LAST 8 +#define NETSEC_TX_SHIFT_CO 7 +#define NETSEC_TX_SHIFT_SO 6 +#define NETSEC_TX_SHIFT_TRS_FIELD 4 + +#define NETSEC_RX_PKT_OWN_FIELD 31 +#define NETSEC_RX_PKT_LD_FIELD 30 +#define NETSEC_RX_PKT_SDRID_FIELD 24 +#define NETSEC_RX_PKT_FR_FIELD 23 +#define NETSEC_RX_PKT_ER_FIELD 21 +#define NETSEC_RX_PKT_ERR_FIELD 16 +#define NETSEC_RX_PKT_TDRID_FIELD 12 +#define NETSEC_RX_PKT_FS_FIELD 9 +#define NETSEC_RX_PKT_LS_FIELD 8 +#define NETSEC_RX_PKT_CO_FIELD 6 + +#define NETSEC_RX_PKT_ERR_MASK 3 + +#define NETSEC_MAX_TX_PKT_LEN 1518 +#define NETSEC_MAX_TX_JUMBO_PKT_LEN 9018 + +#define NETSEC_RING_GMAC 15 +#define NETSEC_RING_MAX 2 + +#define NETSEC_TCP_SEG_LEN_MAX 1460 +#define NETSEC_TCP_JUMBO_SEG_LEN_MAX 8960 + +#define NETSEC_RX_CKSUM_NOTAVAIL 0 +#define NETSEC_RX_CKSUM_OK 1 +#define NETSEC_RX_CKSUM_NG 2 + +#define NETSEC_TOP_IRQ_REG_ME_START BIT(20) +#define NETSEC_IRQ_TRANSITION_COMPLETE BIT(4) + +#define NETSEC_MODE_TRANS_COMP_IRQ_N2T BIT(20) +#define NETSEC_MODE_TRANS_COMP_IRQ_T2N BIT(19) + +#define NETSEC_INT_PKTCNT_MAX 2047 + +#define NETSEC_FLOW_START_TH_MAX 95 +#define NETSEC_FLOW_STOP_TH_MAX 95 +#define NETSEC_FLOW_PAUSE_TIME_MIN 5 + +#define NETSEC_CLK_EN_REG_DOM_ALL 0x3f + +#define NETSEC_PKT_CTRL_REG_MODE_NRM BIT(28) +#define NETSEC_PKT_CTRL_REG_EN_JUMBO BIT(27) +#define NETSEC_PKT_CTRL_REG_LOG_CHKSUM_ER BIT(3) +#define NETSEC_PKT_CTRL_REG_LOG_HD_INCOMPLETE BIT(2) +#define NETSEC_PKT_CTRL_REG_LOG_HD_ER BIT(1) +#define NETSEC_PKT_CTRL_REG_DRP_NO_MATCH BIT(0) + +#define NETSEC_CLK_EN_REG_DOM_G BIT(5) +#define NETSEC_CLK_EN_REG_DOM_C BIT(1) +#define NETSEC_CLK_EN_REG_DOM_D BIT(0) + +#define NETSEC_COM_INIT_REG_DB BIT(2) +#define NETSEC_COM_INIT_REG_CLS BIT(1) +#define NETSEC_COM_INIT_REG_ALL (NETSEC_COM_INIT_REG_CLS | \ + NETSEC_COM_INIT_REG_DB) + +#define NETSEC_SOFT_RST_REG_RESET 0 +#define NETSEC_SOFT_RST_REG_RUN BIT(31) + +#define NETSEC_DMA_CTRL_REG_STOP 1 +#define MH_CTRL__MODE_TRANS BIT(20) + +#define NETSEC_GMAC_CMD_ST_READ 0 +#define NETSEC_GMAC_CMD_ST_WRITE BIT(28) +#define NETSEC_GMAC_CMD_ST_BUSY BIT(31) + +#define NETSEC_GMAC_BMR_REG_COMMON 0x00412080 +#define NETSEC_GMAC_BMR_REG_RESET 0x00020181 +#define NETSEC_GMAC_BMR_REG_SWR 0x00000001 + +#define NETSEC_GMAC_OMR_REG_ST BIT(13) +#define NETSEC_GMAC_OMR_REG_SR BIT(1) + +#define NETSEC_GMAC_MCR_REG_IBN BIT(30) +#define NETSEC_GMAC_MCR_REG_CST BIT(25) +#define NETSEC_GMAC_MCR_REG_JE BIT(20) +#define NETSEC_MCR_PS BIT(15) +#define NETSEC_GMAC_MCR_REG_FES BIT(14) +#define NETSEC_GMAC_MCR_REG_FULL_DUPLEX_COMMON 0x0000280c +#define NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON 0x0001a00c + +#define NETSEC_FCR_RFE BIT(2) +#define NETSEC_FCR_TFE BIT(1) + +#define NETSEC_GMAC_GAR_REG_GW BIT(1) +#define NETSEC_GMAC_GAR_REG_GB BIT(0) + +#define NETSEC_GMAC_GAR_REG_SHIFT_PA 11 +#define NETSEC_GMAC_GAR_REG_SHIFT_GR 6 +#define GMAC_REG_SHIFT_CR_GAR 2 + +#define NETSEC_GMAC_GAR_REG_CR_25_35_MHZ 2 +#define NETSEC_GMAC_GAR_REG_CR_35_60_MHZ 3 +#define NETSEC_GMAC_GAR_REG_CR_60_100_MHZ 0 +#define NETSEC_GMAC_GAR_REG_CR_100_150_MHZ 1 +#define NETSEC_GMAC_GAR_REG_CR_150_250_MHZ 4 +#define NETSEC_GMAC_GAR_REG_CR_250_300_MHZ 5 + +#define NETSEC_GMAC_RDLAR_REG_COMMON 0x18000 +#define NETSEC_GMAC_TDLAR_REG_COMMON 0x1c000 + +#define NETSEC_REG_NETSEC_VER_F_TAIKI 0x50000 + +#define NETSEC_REG_DESC_RING_CONFIG_CFG_UP BIT(31) +#define NETSEC_REG_DESC_RING_CONFIG_CH_RST BIT(30) +#define NETSEC_REG_DESC_TMR_MODE 4 +#define NETSEC_REG_DESC_ENDIAN 0 + +#define NETSEC_MAC_DESC_SOFT_RST_SOFT_RST 1 +#define NETSEC_MAC_DESC_INIT_REG_INIT 1 + +#define NETSEC_EEPROM_MAC_ADDRESS 0x00 +#define NETSEC_EEPROM_HM_ME_ADDRESS_H 0x08 +#define NETSEC_EEPROM_HM_ME_ADDRESS_L 0x0C +#define NETSEC_EEPROM_HM_ME_SIZE 0x10 +#define NETSEC_EEPROM_MH_ME_ADDRESS_H 0x14 +#define NETSEC_EEPROM_MH_ME_ADDRESS_L 0x18 +#define NETSEC_EEPROM_MH_ME_SIZE 0x1C +#define NETSEC_EEPROM_PKT_ME_ADDRESS 0x20 +#define NETSEC_EEPROM_PKT_ME_SIZE 0x24 + +#define DESC_SZ sizeof(struct netsec_de) + +#define NETSEC_F_NETSEC_VER_MAJOR_NUM(x) ((x) & 0xffff0000) + +#define EERPROM_MAP_OFFSET 0x8000000 +#define NOR_BLOCK 1024 + +struct netsec_de { /* Netsec Descriptor layout */ + u32 attr; + u32 data_buf_addr_up; + u32 data_buf_addr_lw; + u32 buf_len_info; +}; + +struct netsec_priv { + struct netsec_de rxde[PKTBUFSRX]; + struct netsec_de txde[1]; + u16 rxat; + + phys_addr_t eeprom_base; + phys_addr_t ioaddr; + + struct mii_dev *bus; + struct phy_device *phydev; + u32 phy_addr, freq; + int phy_mode; + int max_speed; +}; + +struct netsec_tx_pkt_ctrl { + u16 tcp_seg_len; + bool tcp_seg_offload_flag; + bool cksum_offload_flag; +}; + +struct netsec_rx_pkt_info { + int rx_cksum_result; + int err_code; + bool err_flag; +}; + +static void netsec_write_reg(struct netsec_priv *priv, u32 reg_addr, u32 val) +{ + writel(val, priv->ioaddr + reg_addr); +} + +static u32 netsec_read_reg(struct netsec_priv *priv, u32 reg_addr) +{ + return readl(priv->ioaddr + reg_addr); +} + +/************* MDIO BUS OPS FOLLOW *************/ + +#define TIMEOUT_SPINS_MAC 1000 +#define TIMEOUT_SECONDARY_MS_MAC 100 + +static u32 netsec_clk_type(u32 freq) +{ + if (freq < MHZ(35)) + return NETSEC_GMAC_GAR_REG_CR_25_35_MHZ; + if (freq < MHZ(60)) + return NETSEC_GMAC_GAR_REG_CR_35_60_MHZ; + if (freq < MHZ(100)) + return NETSEC_GMAC_GAR_REG_CR_60_100_MHZ; + if (freq < MHZ(150)) + return NETSEC_GMAC_GAR_REG_CR_100_150_MHZ; + if (freq < MHZ(250)) + return NETSEC_GMAC_GAR_REG_CR_150_250_MHZ; + + return NETSEC_GMAC_GAR_REG_CR_250_300_MHZ; +} + +static int netsec_wait_while_busy(struct netsec_priv *priv, u32 addr, u32 mask) +{ + u32 timeout = TIMEOUT_SPINS_MAC; + + while (--timeout && netsec_read_reg(priv, addr) & mask) + cpu_relax(); + if (timeout) + return 0; + + timeout = TIMEOUT_SECONDARY_MS_MAC; + while (--timeout && netsec_read_reg(priv, addr) & mask) + udelay(2000); + + if (timeout) + return 0; + + pr_err("%s: timeout\n", __func__); + + return -ETIMEDOUT; +} + +static int netsec_set_mac_reg(struct netsec_priv *priv, u32 addr, u32 value) +{ + netsec_write_reg(priv, MAC_REG_DATA, value); + netsec_write_reg(priv, MAC_REG_CMD, addr | NETSEC_GMAC_CMD_ST_WRITE); + return netsec_wait_while_busy(priv, + MAC_REG_CMD, NETSEC_GMAC_CMD_ST_BUSY); +} + +static int netsec_get_mac_reg(struct netsec_priv *priv, u32 addr, u32 *read) +{ + int ret; + + netsec_write_reg(priv, MAC_REG_CMD, addr | NETSEC_GMAC_CMD_ST_READ); + ret = netsec_wait_while_busy(priv, + MAC_REG_CMD, NETSEC_GMAC_CMD_ST_BUSY); + if (ret) + return ret; + + *read = netsec_read_reg(priv, MAC_REG_DATA); + + return 0; +} + +static int netsec_mac_wait_while_busy(struct netsec_priv *priv, + u32 addr, u32 mask) +{ + u32 timeout = TIMEOUT_SPINS_MAC; + u32 data; + int ret; + + do { + ret = netsec_get_mac_reg(priv, addr, &data); + if (ret) + break; + udelay(1); + } while (--timeout && (data & mask)); + + if (timeout) + return 0; + + timeout = TIMEOUT_SECONDARY_MS_MAC; + do { + udelay(2000); + + ret = netsec_get_mac_reg(priv, addr, &data); + if (ret) + break; + cpu_relax(); + } while (--timeout && (data & mask)); + + if (timeout && !ret) + return 0; + + return -ETIMEDOUT; +} + +static void netsec_cache_invalidate(uintptr_t vaddr, int len) +{ + invalidate_dcache_range(rounddown(vaddr, ARCH_DMA_MINALIGN), + roundup(vaddr + len, ARCH_DMA_MINALIGN)); +} + +static void netsec_cache_flush(uintptr_t vaddr, int len) +{ + flush_dcache_range(rounddown(vaddr, ARCH_DMA_MINALIGN), + roundup(vaddr + len, ARCH_DMA_MINALIGN)); +} + +static void netsec_set_rx_de(struct netsec_priv *priv, u16 idx, void *addr) +{ + struct netsec_de *de = &priv->rxde[idx]; + u32 attr = (1 << NETSEC_RX_PKT_OWN_FIELD) | + (1 << NETSEC_RX_PKT_FS_FIELD) | + (1 << NETSEC_RX_PKT_LS_FIELD); + + if (idx == PKTBUFSRX - 1) + attr |= (1 << NETSEC_RX_PKT_LD_FIELD); + + de->data_buf_addr_up = upper_32_bits((dma_addr_t)addr); + de->data_buf_addr_lw = lower_32_bits((dma_addr_t)addr); + de->buf_len_info = PKTSIZE; + de->attr = attr; + dmb(); + netsec_cache_flush((uintptr_t)de, sizeof(*de)); +} + +static void netsec_set_tx_de(struct netsec_priv *priv, void *addr, int len) +{ + struct netsec_de *de = &priv->txde[0]; + u32 attr; + + attr = (1 << NETSEC_TX_SHIFT_OWN_FIELD) | + (1 << NETSEC_TX_SHIFT_PT_FIELD) | + (NETSEC_RING_GMAC << NETSEC_TX_SHIFT_TDRID_FIELD) | + (1 << NETSEC_TX_SHIFT_FS_FIELD) | + (1 << NETSEC_TX_LAST) | + (1 << NETSEC_TX_SHIFT_TRS_FIELD) | + (1 << NETSEC_TX_SHIFT_LD_FIELD); + + de->data_buf_addr_up = upper_32_bits((dma_addr_t)addr); + de->data_buf_addr_lw = lower_32_bits((dma_addr_t)addr); + de->buf_len_info = len; + de->attr = attr; + dmb(); + netsec_cache_flush((uintptr_t)de, sizeof(*de)); +} + +static int netsec_get_phy_reg(struct netsec_priv *priv, + int phy_addr, int reg_addr) +{ + u32 data; + int ret; + + if (phy_addr != 7) + return -EINVAL; + + if (netsec_set_mac_reg(priv, GMAC_REG_GAR, NETSEC_GMAC_GAR_REG_GB | + phy_addr << NETSEC_GMAC_GAR_REG_SHIFT_PA | + reg_addr << NETSEC_GMAC_GAR_REG_SHIFT_GR | + (netsec_clk_type(priv->freq) << + GMAC_REG_SHIFT_CR_GAR))) + return -ETIMEDOUT; + + ret = netsec_mac_wait_while_busy(priv, GMAC_REG_GAR, + NETSEC_GMAC_GAR_REG_GB); + if (ret) + return ret; + + ret = netsec_get_mac_reg(priv, GMAC_REG_GDR, &data); + if (ret) + return ret; + + return data; +} + +static int netsec_set_phy_reg(struct netsec_priv *priv, + int phy_addr, int reg_addr, u16 val) +{ + int ret; + + if (phy_addr != 7) + return -EINVAL; + if (netsec_set_mac_reg(priv, GMAC_REG_GDR, val)) + return -ETIMEDOUT; + + if (netsec_set_mac_reg(priv, GMAC_REG_GAR, + phy_addr << NETSEC_GMAC_GAR_REG_SHIFT_PA | + reg_addr << NETSEC_GMAC_GAR_REG_SHIFT_GR | + NETSEC_GMAC_GAR_REG_GW | NETSEC_GMAC_GAR_REG_GB | + (netsec_clk_type(priv->freq) << + GMAC_REG_SHIFT_CR_GAR))) + return -ETIMEDOUT; + + ret = netsec_mac_wait_while_busy(priv, GMAC_REG_GAR, + NETSEC_GMAC_GAR_REG_GB); + + /* Developerbox implements RTL8211E PHY and there is + * a compatibility problem with F_GMAC4. + * RTL8211E expects MDC clock must be kept toggling for several + * clock cycle with MDIO high before entering the IDLE state. + * To meet this requirement, netsec driver needs to issue dummy + * read(e.g. read PHYID1(offset 0x2) register) right after write. + */ + netsec_get_phy_reg(priv, phy_addr, MII_PHYSID1); + + return ret; +} + +static int netsec_mac_update_to_phy_state(struct netsec_priv *priv) +{ + struct phy_device *phydev = priv->phydev; + u32 value = 0; + + value = phydev->duplex ? NETSEC_GMAC_MCR_REG_FULL_DUPLEX_COMMON : + NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON; + + if (phydev->speed != SPEED_1000) + value |= NETSEC_MCR_PS; + + if (phydev->interface != PHY_INTERFACE_MODE_GMII && + phydev->speed == SPEED_100) + value |= NETSEC_GMAC_MCR_REG_FES; + + value |= NETSEC_GMAC_MCR_REG_CST | NETSEC_GMAC_MCR_REG_JE; + + if (phy_interface_is_rgmii(phydev)) + value |= NETSEC_GMAC_MCR_REG_IBN; + + if (netsec_set_mac_reg(priv, GMAC_REG_MCR, value)) + return -ETIMEDOUT; + + return 0; +} + +static int netsec_start_gmac(struct netsec_priv *priv) +{ + u32 value = 0; + int ret; + + if (priv->max_speed != SPEED_1000) + value = (NETSEC_GMAC_MCR_REG_CST | + NETSEC_GMAC_MCR_REG_HALF_DUPLEX_COMMON); + + if (netsec_set_mac_reg(priv, GMAC_REG_MCR, value)) + return -ETIMEDOUT; + + if (netsec_set_mac_reg(priv, GMAC_REG_BMR, + NETSEC_GMAC_BMR_REG_RESET)) + return -ETIMEDOUT; + + /* Wait soft reset */ + mdelay(5); + + ret = netsec_get_mac_reg(priv, GMAC_REG_BMR, &value); + if (ret) + return ret; + + if (value & NETSEC_GMAC_BMR_REG_SWR) + return -EAGAIN; + + netsec_write_reg(priv, MAC_REG_DESC_SOFT_RST, 1); + if (netsec_wait_while_busy(priv, MAC_REG_DESC_SOFT_RST, 1)) + return -ETIMEDOUT; + + netsec_write_reg(priv, MAC_REG_DESC_INIT, 1); + if (netsec_wait_while_busy(priv, MAC_REG_DESC_INIT, 1)) + return -ETIMEDOUT; + + if (netsec_set_mac_reg(priv, GMAC_REG_BMR, + NETSEC_GMAC_BMR_REG_COMMON)) + return -ETIMEDOUT; + + if (netsec_set_mac_reg(priv, GMAC_REG_RDLAR, + NETSEC_GMAC_RDLAR_REG_COMMON)) + return -ETIMEDOUT; + + if (netsec_set_mac_reg(priv, GMAC_REG_TDLAR, + NETSEC_GMAC_TDLAR_REG_COMMON)) + return -ETIMEDOUT; + + if (netsec_set_mac_reg(priv, GMAC_REG_MFFR, 0x80000001)) + return -ETIMEDOUT; + + ret = netsec_mac_update_to_phy_state(priv); + if (ret) + return ret; + + ret = netsec_get_mac_reg(priv, GMAC_REG_OMR, &value); + if (ret) + return ret; + + value |= NETSEC_GMAC_OMR_REG_SR; + value |= NETSEC_GMAC_OMR_REG_ST; + + netsec_write_reg(priv, NETSEC_REG_NRM_RX_INTEN_CLR, ~0); + netsec_write_reg(priv, NETSEC_REG_NRM_TX_INTEN_CLR, ~0); + + if (netsec_set_mac_reg(priv, GMAC_REG_OMR, value)) + return -ETIMEDOUT; + + return 0; +} + +static int netsec_stop_gmac(struct netsec_priv *priv) +{ + u32 value; + int ret; + + ret = netsec_get_mac_reg(priv, GMAC_REG_OMR, &value); + if (ret) + return ret; + value &= ~NETSEC_GMAC_OMR_REG_SR; + value &= ~NETSEC_GMAC_OMR_REG_ST; + + /* disable all interrupts */ + netsec_write_reg(priv, NETSEC_REG_NRM_RX_INTEN_CLR, ~0); + netsec_write_reg(priv, NETSEC_REG_NRM_TX_INTEN_CLR, ~0); + + return netsec_set_mac_reg(priv, GMAC_REG_OMR, value); +} + +static void netsec_spi_read(char *buf, loff_t len, loff_t offset) +{ + struct udevice *new; + struct spi_flash *flash; + + spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, + CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE, &new); + flash = dev_get_uclass_priv(new); + + spi_flash_read(flash, offset, len, buf); +} + +static int netsec_read_rom_hwaddr(struct udevice *dev) +{ + struct netsec_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + char macp[NOR_BLOCK]; + + netsec_spi_read(macp, sizeof(macp), priv->eeprom_base); + + pdata->enetaddr[0] = readb(macp + 3); + pdata->enetaddr[1] = readb(macp + 2); + pdata->enetaddr[2] = readb(macp + 1); + pdata->enetaddr[3] = readb(macp + 0); + pdata->enetaddr[4] = readb(macp + 7); + pdata->enetaddr[5] = readb(macp + 6); + return 0; +} + +static int netsec_send(struct udevice *dev, void *packet, int length) +{ + struct netsec_priv *priv = dev_get_priv(dev); + u32 val, tout; + + val = netsec_read_reg(priv, NETSEC_REG_NRM_TX_STATUS); + netsec_cache_flush((uintptr_t)packet, length); + netsec_set_tx_de(priv, packet, length); + netsec_write_reg(priv, NETSEC_REG_NRM_TX_PKTCNT, 1); /* submit another tx */ + + val = netsec_read_reg(priv, NETSEC_REG_NRM_TX_PKTCNT); + + tout = 10000; + do { + val = netsec_read_reg(priv, NETSEC_REG_NRM_TX_DONE_PKTCNT); + udelay(2); + } while (--tout && !val); + + if (!tout) { + val = netsec_read_reg(priv, NETSEC_REG_NRM_TX_PKTCNT); + pr_err("%s: ETIMEDOUT: %dpackets\n", __func__, val); + return -ETIMEDOUT; + } + + return 0; +} + +static int netsec_free_packet(struct udevice *dev, uchar *packet, int length) +{ + struct netsec_priv *priv = dev_get_priv(dev); + + netsec_set_rx_de(priv, priv->rxat, net_rx_packets[priv->rxat]); + + priv->rxat++; + if (priv->rxat == PKTBUFSRX) + priv->rxat = 0; + + return 0; +} + +static int netsec_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct netsec_priv *priv = dev_get_priv(dev); + int idx = priv->rxat; + uchar *ptr = net_rx_packets[idx]; + struct netsec_de *de = &priv->rxde[idx]; + int length = 0; + + netsec_cache_invalidate((uintptr_t)de, sizeof(*de)); + + if (de->attr & (1U << NETSEC_RX_PKT_OWN_FIELD)) + return -EAGAIN; + + length = de->buf_len_info >> 16; + + /* invalidate after DMA is done */ + netsec_cache_invalidate((uintptr_t)ptr, length); + *packetp = ptr; + + return length; +} + +static int _netsec_get_phy_reg(struct mii_dev *bus, + int phy_addr, int devad, int reg_addr) +{ + return netsec_get_phy_reg(bus->priv, phy_addr, reg_addr); +} + +static int _netsec_set_phy_reg(struct mii_dev *bus, + int phy_addr, int devad, int reg_addr, u16 val) +{ + return netsec_set_phy_reg(bus->priv, phy_addr, reg_addr, val); +} + +static int netsec_mdiobus_init(struct netsec_priv *priv, const char *name) +{ + struct mii_dev *bus = mdio_alloc(); + + if (!bus) + return -ENOMEM; + + bus->read = _netsec_get_phy_reg; + bus->write = _netsec_set_phy_reg; + snprintf(bus->name, sizeof(bus->name), "%s", name); + bus->priv = priv; + + return mdio_register(bus); +} + +static int netsec_phy_init(struct netsec_priv *priv, void *dev) +{ + struct phy_device *phydev; + int ret; + + phydev = phy_connect(priv->bus, priv->phy_addr, dev, priv->phy_mode); + + phydev->supported &= PHY_GBIT_FEATURES; + if (priv->max_speed) { + ret = phy_set_supported(phydev, priv->max_speed); + if (ret) + return ret; + } + phydev->advertising = phydev->supported; + + priv->phydev = phydev; + phy_config(phydev); + + return 0; +} + +static int netsec_netdev_load_ucode_region(struct netsec_priv *priv, u32 reg, + u32 addr_h, u32 addr_l, u32 size) +{ + u64 base = ((u64)addr_h << 32 | addr_l) - EERPROM_MAP_OFFSET; + + while (size > 0) { + char buf[NOR_BLOCK]; + u32 *ucode = (u32 *)buf; + u64 off; + int i; + + off = base % NOR_BLOCK; + base -= off; + netsec_spi_read(buf, sizeof(buf), base); + + for (i = off / 4; i < sizeof(buf) / 4 && size > 0; i++, size--) + netsec_write_reg(priv, reg, ucode[i]); + base += NOR_BLOCK; + } + + return 0; +} + +static int netsec_netdev_load_microcode(struct netsec_priv *priv) +{ + u32 addr_h, addr_l, size; + char buf[NOR_BLOCK]; + u32 *ucinfo = (u32 *)buf; + int err; + + netsec_spi_read(buf, sizeof(buf), priv->eeprom_base); + + addr_h = ucinfo[NETSEC_EEPROM_HM_ME_ADDRESS_H >> 2]; + addr_l = ucinfo[NETSEC_EEPROM_HM_ME_ADDRESS_L >> 2]; + size = ucinfo[NETSEC_EEPROM_HM_ME_SIZE >> 2]; + + err = netsec_netdev_load_ucode_region(priv, NETSEC_REG_DMAC_HM_CMD_BUF, + addr_h, addr_l, size); + if (err) + return err; + + addr_h = ucinfo[NETSEC_EEPROM_MH_ME_ADDRESS_H >> 2]; + addr_l = ucinfo[NETSEC_EEPROM_MH_ME_ADDRESS_L >> 2]; + size = ucinfo[NETSEC_EEPROM_MH_ME_SIZE >> 2]; + + err = netsec_netdev_load_ucode_region(priv, NETSEC_REG_DMAC_MH_CMD_BUF, + addr_h, addr_l, size); + if (err) + return err; + + addr_h = 0; + addr_l = ucinfo[NETSEC_EEPROM_PKT_ME_ADDRESS >> 2]; + size = ucinfo[NETSEC_EEPROM_PKT_ME_SIZE >> 2]; + + err = netsec_netdev_load_ucode_region(priv, NETSEC_REG_PKT_CMD_BUF, + addr_h, addr_l, size); + if (err) + return err; + + return 0; +} + +void netsec_pre_init_microengine(struct netsec_priv *priv) +{ + u32 data; + + /* Remove dormant settings */ + data = netsec_get_phy_reg(priv, priv->phy_addr, MII_BMCR); + data &= ~BMCR_PDOWN; + data |= BMCR_ISOLATE; + netsec_set_phy_reg(priv, priv->phy_addr, MII_BMCR, data); + mdelay(100); + + /* Put phy in loopback mode to guarantee RXCLK input */ + data |= BMCR_LOOPBACK; + netsec_set_phy_reg(priv, priv->phy_addr, MII_BMCR, data); + mdelay(100); +} + +void netsec_post_init_microengine(struct netsec_priv *priv) +{ + u32 data; + + /* Get phy back to normal operation */ + data = netsec_get_phy_reg(priv, priv->phy_addr, MII_BMCR); + data &= ~BMCR_LOOPBACK; + netsec_set_phy_reg(priv, priv->phy_addr, MII_BMCR, data); + mdelay(100); + + /* Apply software reset */ + data |= BMCR_RESET; + netsec_set_phy_reg(priv, priv->phy_addr, MII_BMCR, data); + mdelay(100); +} + +static int netsec_reset_hardware(struct netsec_priv *priv, bool load_ucode) +{ + u32 value; + int err; + + netsec_write_reg(priv, NETSEC_REG_CLK_EN, 0x24); + + /* stop DMA engines */ + if (!netsec_read_reg(priv, NETSEC_REG_ADDR_DIS_CORE)) { + netsec_write_reg(priv, NETSEC_REG_DMA_HM_CTRL, + NETSEC_DMA_CTRL_REG_STOP); + netsec_write_reg(priv, NETSEC_REG_DMA_MH_CTRL, + NETSEC_DMA_CTRL_REG_STOP); + + value = 100; + while (netsec_read_reg(priv, NETSEC_REG_DMA_HM_CTRL) & + NETSEC_DMA_CTRL_REG_STOP) { + udelay(1000); + if (--value == 0) { + pr_err("%s:%d timeout!\n", __func__, __LINE__); + break; + } + } + + value = 100; + while (netsec_read_reg(priv, NETSEC_REG_DMA_MH_CTRL) & + NETSEC_DMA_CTRL_REG_STOP) { + udelay(1000); + if (--value == 0) { + pr_err("%s:%d timeout!\n", __func__, __LINE__); + break; + } + } + } + + netsec_set_mac_reg(priv, GMAC_REG_BMR, NETSEC_GMAC_BMR_REG_RESET); + + netsec_write_reg(priv, NETSEC_REG_SOFT_RST, NETSEC_SOFT_RST_REG_RESET); + netsec_write_reg(priv, NETSEC_REG_SOFT_RST, NETSEC_SOFT_RST_REG_RUN); + netsec_write_reg(priv, NETSEC_REG_COM_INIT, NETSEC_COM_INIT_REG_ALL); + + value = 100; + while (netsec_read_reg(priv, NETSEC_REG_COM_INIT) != 0) { + udelay(1000); + if (--value == 0) { + pr_err("%s:%d COM_INIT timeout!\n", __func__, __LINE__); + break; + } + } + + /* MAC desc init */ + netsec_write_reg(priv, MAC_REG_DESC_INIT, 1); + netsec_wait_while_busy(priv, MAC_REG_DESC_INIT, 1); + /* set MAC_INTF_SEL */ + netsec_write_reg(priv, MAC_REG_INTF_SEL, 1); + + netsec_write_reg(priv, NETSEC_REG_CLK_EN, 1 << 5); + + /* set desc_start addr */ + netsec_write_reg(priv, NETSEC_REG_NRM_RX_DESC_START_UP, + upper_32_bits((dma_addr_t)priv->rxde)); + netsec_write_reg(priv, NETSEC_REG_NRM_RX_DESC_START_LW, + lower_32_bits((dma_addr_t)priv->rxde)); + + netsec_write_reg(priv, NETSEC_REG_NRM_TX_DESC_START_UP, + upper_32_bits((dma_addr_t)priv->txde)); + netsec_write_reg(priv, NETSEC_REG_NRM_TX_DESC_START_LW, + lower_32_bits((dma_addr_t)priv->txde)); + + /* set normal tx dring ring config */ + netsec_write_reg(priv, NETSEC_REG_NRM_TX_CONFIG, + 1 << NETSEC_REG_DESC_ENDIAN); + netsec_write_reg(priv, NETSEC_REG_NRM_RX_CONFIG, + 1 << NETSEC_REG_DESC_ENDIAN); + + if (load_ucode) { + err = netsec_netdev_load_microcode(priv); + if (err) { + pr_err("%s: failed to load microcode (%d)\n", + __func__, err); + return err; + } + } + + /* set desc_start addr */ + netsec_write_reg(priv, NETSEC_REG_NRM_RX_DESC_START_UP, + upper_32_bits((dma_addr_t)priv->rxde)); + netsec_write_reg(priv, NETSEC_REG_NRM_RX_DESC_START_LW, + lower_32_bits((dma_addr_t)priv->rxde)); + + netsec_write_reg(priv, NETSEC_REG_NRM_TX_DESC_START_UP, + upper_32_bits((dma_addr_t)priv->txde)); + netsec_write_reg(priv, NETSEC_REG_NRM_TX_DESC_START_LW, + lower_32_bits((dma_addr_t)priv->txde)); + + netsec_write_reg(priv, NETSEC_REG_CLK_EN, 1 << 5); + + /* start DMA engines */ + netsec_write_reg(priv, NETSEC_REG_DMA_TMR_CTRL, priv->freq / 1000000 - 1); + + netsec_pre_init_microengine(priv); + + netsec_write_reg(priv, NETSEC_REG_ADDR_DIS_CORE, 0); + + mdelay(100); + + if (!(netsec_read_reg(priv, NETSEC_REG_TOP_STATUS) & + NETSEC_TOP_IRQ_REG_ME_START)) { + pr_err("microengine start failed\n"); + return -ENXIO; + } + + netsec_post_init_microengine(priv); + + /* clear microcode load end status */ + netsec_write_reg(priv, NETSEC_REG_TOP_STATUS, + NETSEC_TOP_IRQ_REG_ME_START); + + netsec_write_reg(priv, NETSEC_REG_CLK_EN, 1 << 5); + + value = netsec_read_reg(priv, NETSEC_REG_PKT_CTRL); + value |= NETSEC_PKT_CTRL_REG_MODE_NRM; + /* change to normal mode */ + netsec_write_reg(priv, NETSEC_REG_DMA_MH_CTRL, MH_CTRL__MODE_TRANS); + netsec_write_reg(priv, NETSEC_REG_PKT_CTRL, value); + + value = 100; + while ((netsec_read_reg(priv, NETSEC_REG_MODE_TRANS_COMP_STATUS) & + NETSEC_MODE_TRANS_COMP_IRQ_T2N) == 0) { + udelay(1000); + if (--value == 0) { + value = netsec_read_reg(priv, NETSEC_REG_MODE_TRANS_COMP_STATUS); + pr_err("%s:%d timeout! val=%x\n", __func__, __LINE__, value); + break; + } + } + + /* clear any pending EMPTY/ERR irq status */ + netsec_write_reg(priv, NETSEC_REG_NRM_TX_STATUS, ~0); + + /* Disable TX & RX intr */ + netsec_write_reg(priv, NETSEC_REG_INTEN_CLR, ~0); + + return 0; +} + +static void netsec_stop(struct udevice *dev) +{ + struct netsec_priv *priv = dev_get_priv(dev); + + netsec_write_reg(priv, NETSEC_REG_ADDR_DIS_CORE, 7); + netsec_stop_gmac(priv); + phy_shutdown(priv->phydev); + netsec_reset_hardware(priv, false); +} + +static int netsec_start(struct udevice *dev) +{ + struct netsec_priv *priv = dev_get_priv(dev); + int i; + + phy_startup(priv->phydev); + netsec_start_gmac(priv); + + priv->rxat = 0; + for (i = 0; i < PKTBUFSRX; i++) + netsec_set_rx_de(priv, i, net_rx_packets[i]); + + return 0; +} + +static int netsec_of_to_plat(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct netsec_priv *priv = dev_get_priv(dev); + struct ofnode_phandle_args phandle_args; + const char *phy_mode; + + pdata->iobase = dev_read_addr_index(dev, 0); + priv->eeprom_base = dev_read_addr_index(dev, 1) - EERPROM_MAP_OFFSET; + + pdata->phy_interface = -1; + phy_mode = dev_read_prop(dev, "phy-mode", NULL); + if (phy_mode) + pdata->phy_interface = phy_get_interface_by_name(phy_mode); + if (pdata->phy_interface == -1) { + pr_err("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); + return -EINVAL; + } + + if (!dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, + &phandle_args)) + priv->phy_addr = ofnode_read_u32_default(phandle_args.node, "reg", 7); + else + priv->phy_addr = 7; + + pdata->max_speed = dev_read_u32_default(dev, "max-speed", SPEED_1000); + + priv->ioaddr = pdata->iobase; + priv->phy_mode = pdata->phy_interface; + priv->max_speed = pdata->max_speed; + priv->freq = 250000000UL; + + return 0; +} + +#define SMMU_SCR0_SHCFG_INNER (0x2 << 22) +#define SMMU_SCR0_MTCFG (0x1 << 20) +#define SMMU_SCR0_MEMATTR_INNER_OUTER_WB (0xf << 16) + +static int netsec_probe(struct udevice *dev) +{ + struct netsec_priv *priv = dev_get_priv(dev); + int ret; + + writel(SMMU_SCR0_SHCFG_INNER | SMMU_SCR0_MTCFG | SMMU_SCR0_MEMATTR_INNER_OUTER_WB, + (phys_addr_t)0x52E00000); + + netsec_reset_hardware(priv, true); + + ret = netsec_mdiobus_init(priv, dev->name); + if (ret) { + pr_err("Failed to initialize mdiobus: %d\n", ret); + return ret; + } + + priv->bus = miiphy_get_dev_by_name(dev->name); + + ret = netsec_phy_init(priv, dev); + if (ret) { + pr_err("Failed to initialize phy: %d\n", ret); + goto out_mdiobus_release; + } + + return 0; +out_mdiobus_release: + mdio_unregister(priv->bus); + mdio_free(priv->bus); + return ret; +} + +static int netsec_remove(struct udevice *dev) +{ + struct netsec_priv *priv = dev_get_priv(dev); + + free(priv->phydev); + mdio_unregister(priv->bus); + mdio_free(priv->bus); + + return 0; +} + +static const struct eth_ops netsec_ops = { + .start = netsec_start, + .stop = netsec_stop, + .send = netsec_send, + .recv = netsec_recv, + .free_pkt = netsec_free_packet, + .read_rom_hwaddr = netsec_read_rom_hwaddr, +}; + +static const struct udevice_id netsec_ids[] = { + { + .compatible = "socionext,synquacer-netsec", + }, + {} +}; + +U_BOOT_DRIVER(ave) = { + .name = "synquacer_netsec", + .id = UCLASS_ETH, + .of_match = netsec_ids, + .probe = netsec_probe, + .remove = netsec_remove, + .of_to_plat = netsec_of_to_plat, + .ops = &netsec_ops, + .priv_auto = sizeof(struct netsec_priv), + .plat_auto = sizeof(struct eth_pdata), +}; From 02036d90ec10510c8218aad463a332a50c3528c4 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 3 Jun 2021 07:52:41 +0000 Subject: [PATCH 06/10] net: sun8i-emac: fix MDIO frequency Commit 4f0278dac56a ("net: sun8i-emac: Lower MDIO frequency") leads to network failure on the OrangePi PC. => dhcp sun8i_emac_eth_start: Timeout According to the commit message the change of the MDIO frequency is only required for external PHYs. Fixes: 4f0278dac56a ("net: sun8i-emac: Lower MDIO frequency") Signed-off-by: Heinrich Schuchardt --- drivers/net/sun8i_emac.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index 5a1b38bf80f..d7553fe1634 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -211,7 +211,9 @@ static int sun8i_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) * The EMAC clock is either 200 or 300 MHz, so we need a divider * of 128 to get the MDIO frequency below the required 2.5 MHz. */ - mii_cmd |= MDIO_CMD_MII_CLK_CSR_DIV_128 << MDIO_CMD_MII_CLK_CSR_SHIFT; + if (!priv->use_internal_phy) + mii_cmd |= MDIO_CMD_MII_CLK_CSR_DIV_128 << + MDIO_CMD_MII_CLK_CSR_SHIFT; mii_cmd |= MDIO_CMD_MII_BUSY; @@ -242,7 +244,9 @@ static int sun8i_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, * The EMAC clock is either 200 or 300 MHz, so we need a divider * of 128 to get the MDIO frequency below the required 2.5 MHz. */ - mii_cmd |= MDIO_CMD_MII_CLK_CSR_DIV_128 << MDIO_CMD_MII_CLK_CSR_SHIFT; + if (!priv->use_internal_phy) + mii_cmd |= MDIO_CMD_MII_CLK_CSR_DIV_128 << + MDIO_CMD_MII_CLK_CSR_SHIFT; mii_cmd |= MDIO_CMD_MII_WRITE; mii_cmd |= MDIO_CMD_MII_BUSY; From 6e424b4acac0dba486a97ecd80a78aa0fea43683 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 24 Feb 2021 17:30:44 +0100 Subject: [PATCH 07/10] net: use a more deterministic approach to get the active ethernet device If the environment variable "ethact" is not set, the first device in the uclass is returned. This depends on the probing order of the ethernet devices. Moreover it is not not configurable at all. Try to return the ethernet device with sequence id 0 first which then can be configured by the aliases in a device tree. Fall back to the old mechanism in case of an error. Signed-off-by: Michael Walle Reviewed-by: Ramon Fried --- net/eth-uclass.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/net/eth-uclass.c b/net/eth-uclass.c index 34ca731d1e3..0b4260dc5be 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -69,8 +69,11 @@ void eth_set_current_to_next(void) /* * Typically this will simply return the active device. * In the case where the most recent active device was unset, this will attempt - * to return the first device. If that device doesn't exist or fails to probe, - * this function will return NULL. + * to return the device with sequence id 0 (which can be configured by the + * device tree). If this fails, fall back to just getting the first device. + * The latter is non-deterministic and depends on the order of the probing. + * If that device doesn't exist or fails to probe, this function will return + * NULL. */ struct udevice *eth_get_dev(void) { @@ -80,9 +83,13 @@ struct udevice *eth_get_dev(void) if (!uc_priv) return NULL; - if (!uc_priv->current) - eth_errno = uclass_first_device(UCLASS_ETH, - &uc_priv->current); + if (!uc_priv->current) { + eth_errno = uclass_get_device_by_seq(UCLASS_ETH, 0, + &uc_priv->current); + if (eth_errno) + eth_errno = uclass_first_device(UCLASS_ETH, + &uc_priv->current); + } return uc_priv->current; } From 82a3c9ef20d43d97416589854b4bbcb4c2450c24 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Thu, 25 Feb 2021 16:51:11 +0100 Subject: [PATCH 08/10] net: use the same alias stem for ethernet as linux Linux uses the prefix "ethernet" whereas u-boot uses "eth". This is from the linux tree: $ grep "eth[0-9].*=.*&" arch/**/*dts{,i}|wc -l 0 $ grep "ethernet[0-9].*=.*&" arch/**/*dts{,i}|wc -l 633 In u-boot device trees both prefixes are used. Until recently the only user of the ethernet alias was the sandbox test device tree. This changed with commit fc054d563bfb ("net: Introduce DSA class for Ethernet switches"). There, the MAC addresses are inherited based on the devices sequence IDs which is in turn given by the device tree. Before there are more users in u-boot and both worlds will differ even more, rename the alias prefix to "ethernet" to match the linux ones. Also adapt the test cases and rename any old aliases in the u-boot device trees. Cc: David Wu Signed-off-by: Michael Walle Reviewed-by: Fabio Estevam Reviewed-by: Simon Glass --- arch/arm/dts/fsl-ls1028a-rdb.dts | 12 ++++++------ arch/sandbox/dts/test.dts | 10 +++++----- net/eth-uclass.c | 4 ++-- test/dm/ofnode.c | 2 +- test/dm/test-fdt.c | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/arch/arm/dts/fsl-ls1028a-rdb.dts b/arch/arm/dts/fsl-ls1028a-rdb.dts index 3432fca3526..82a8c0a0cde 100644 --- a/arch/arm/dts/fsl-ls1028a-rdb.dts +++ b/arch/arm/dts/fsl-ls1028a-rdb.dts @@ -15,12 +15,12 @@ compatible = "fsl,ls1028a-rdb", "fsl,ls1028a"; aliases { spi0 = &fspi; - eth0 = &enetc0; - eth1 = &enetc2; - eth2 = &mscc_felix_port0; - eth3 = &mscc_felix_port1; - eth4 = &mscc_felix_port2; - eth5 = &mscc_felix_port3; + ethernet0 = &enetc0; + ethernet1 = &enetc2; + ethernet2 = &mscc_felix_port0; + ethernet3 = &mscc_felix_port1; + ethernet4 = &mscc_felix_port2; + ethernet5 = &mscc_felix_port3; }; }; diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 5ca3bc502a4..8e7eaf2d150 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -14,11 +14,11 @@ aliases { console = &uart0; - eth0 = "/eth@10002000"; - eth2 = &swp_0; - eth3 = ð_3; - eth4 = &dsa_eth0; - eth5 = ð_5; + ethernet0 = "/eth@10002000"; + ethernet2 = &swp_0; + ethernet3 = ð_3; + ethernet4 = &dsa_eth0; + ethernet5 = ð_5; gpio1 = &gpio_a; gpio2 = &gpio_b; gpio3 = &gpio_c; diff --git a/net/eth-uclass.c b/net/eth-uclass.c index 0b4260dc5be..5146bd6666c 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -605,8 +605,8 @@ static int eth_pre_remove(struct udevice *dev) return 0; } -UCLASS_DRIVER(eth) = { - .name = "eth", +UCLASS_DRIVER(ethernet) = { + .name = "ethernet", .id = UCLASS_ETH, .post_bind = eth_post_bind, .pre_unbind = eth_pre_unbind, diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index e0b525eeb18..de895773b55 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -213,7 +213,7 @@ static int dm_test_ofnode_read_aliases(struct unit_test_state *uts) ofnode node; int size; - node = ofnode_get_aliases_node("eth3"); + node = ofnode_get_aliases_node("ethernet3"); ut_assert(ofnode_valid(node)); ut_asserteq_str("sbe5", ofnode_get_name(node)); diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c index d273e218530..8866d4d959d 100644 --- a/test/dm/test-fdt.c +++ b/test/dm/test-fdt.c @@ -183,7 +183,7 @@ static int dm_test_alias_highest_id(struct unit_test_state *uts) { int ret; - ret = dev_read_alias_highest_id("eth"); + ret = dev_read_alias_highest_id("ethernet"); ut_asserteq(5, ret); ret = dev_read_alias_highest_id("gpio"); From 75efe7dc996ddb9835590b1a8970f19b5c4b1ade Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Wed, 21 Apr 2021 12:42:01 +0100 Subject: [PATCH 09/10] cmd: pxe_utils: sysboot: fix crash if either board or soc are not set. If the environment does not have "soc" or "board" set, and fdtdir option is specified in extlinux.conf, the bootloader will crash whilst dereferencing a null pointer. Add a guard against null soc or board. Fixes a crash of qemu-riscv64_smode configuration, which does not have CONFIG_SYS_SOC defined. Signed-off-by: Dimitri John Ledkov Reviewed-by: Ramon Fried --- cmd/pxe_utils.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmd/pxe_utils.c b/cmd/pxe_utils.c index 71c5af4c25d..9a30629e26e 100644 --- a/cmd/pxe_utils.c +++ b/cmd/pxe_utils.c @@ -587,6 +587,14 @@ static int label_boot(struct cmd_tbl *cmdtp, struct pxe_label *label) f2 = "-"; f3 = env_get("board"); f4 = ".dtb"; + if (!f1) { + f1 = ""; + f2 = ""; + } + if (!f3) { + f2 = ""; + f3 = ""; + } } len = strlen(label->fdtdir); From 54c321f9deeba309989f0828e4d0427cbfbefcd3 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Thu, 17 Jun 2021 16:08:54 -0700 Subject: [PATCH 10/10] net: octeontx: smi: use dt live tree API clean up octeontx_smi_probe by using the live-tree API. Signed-off-by: Tim Harvey Reviewed-by: Stefan Roese Reviewed-by: Ramon Fried --- drivers/net/octeontx/smi.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/net/octeontx/smi.c b/drivers/net/octeontx/smi.c index 27f4423c6ac..d70fa820c7b 100644 --- a/drivers/net/octeontx/smi.c +++ b/drivers/net/octeontx/smi.c @@ -314,10 +314,12 @@ int rxaui_phy_xs_init(struct mii_dev *bus, int phy_addr) int octeontx_smi_probe(struct udevice *dev) { - int ret, subnode, cnt = 0, node = dev_ofnode(dev).of_offset; - struct mii_dev *bus; - struct octeontx_smi_priv *priv; pci_dev_t bdf = dm_pci_get_bdf(dev); + struct octeontx_smi_priv *priv; + struct mii_dev *bus; + int ret, cnt = 0; + ofnode subnode; + u64 baseaddr; debug("SMI PCI device: %x\n", bdf); if (!dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM)) { @@ -325,14 +327,12 @@ int octeontx_smi_probe(struct udevice *dev) return -1; } - node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, - "cavium,thunder-8890-mdio-nexus"); - fdt_for_each_subnode(subnode, gd->fdt_blob, node) { - ret = fdt_node_check_compatible(gd->fdt_blob, subnode, - "cavium,thunder-8890-mdio"); - if (ret) + dev_for_each_subnode(subnode, dev) { + if (!ofnode_device_is_compatible(subnode, + "cavium,thunder-8890-mdio")) + continue; + if (ofnode_read_u64(subnode, "reg", &baseaddr)) continue; - bus = mdio_alloc(); priv = malloc(sizeof(*priv)); if (!bus || !priv) { @@ -347,9 +347,7 @@ int octeontx_smi_probe(struct udevice *dev) bus->priv = priv; priv->mode = CLAUSE22; - priv->baseaddr = (void __iomem *)fdtdec_get_addr(gd->fdt_blob, - subnode, - "reg"); + priv->baseaddr = (void __iomem *)baseaddr; debug("mdio base addr %p\n", priv->baseaddr); /* use given name or generate its own unique name */