diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Kconfig | 16 | ||||
-rw-r--r-- | drivers/net/fsl-mc/dpio/qbman_portal.c | 4 | ||||
-rw-r--r-- | drivers/net/fsl-mc/dpni.c | 81 | ||||
-rw-r--r-- | drivers/net/fsl-mc/mc.c | 67 | ||||
-rw-r--r-- | drivers/net/ldpaa_eth/ldpaa_eth.c | 122 | ||||
-rw-r--r-- | drivers/net/ldpaa_eth/ldpaa_eth.h | 2 | ||||
-rw-r--r-- | drivers/net/phy/ti.c | 3 | ||||
-rw-r--r-- | drivers/net/xilinx_axi_emac.c | 280 | ||||
-rw-r--r-- | drivers/net/xilinx_emaclite.c | 610 | ||||
-rw-r--r-- | drivers/net/xilinx_ll_temac.c | 3 | ||||
-rw-r--r-- | drivers/net/zynq_gem.c | 4 |
11 files changed, 893 insertions, 299 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index de54ca8014..218e1fee22 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -102,6 +102,22 @@ config PCH_GBE This MAC is present in Intel Platform Controller Hub EG20T. It supports 10/100/1000 Mbps operation. +config XILINX_AXIEMAC + depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP) + select PHYLIB + select MII + bool "Xilinx AXI Ethernet" + help + This MAC is present in Xilinx Microblaze, Zynq and ZynqMP SoCs. + +config XILINX_EMACLITE + depends on DM_ETH && (MICROBLAZE || ARCH_ZYNQ || ARCH_ZYNQMP) + select PHYLIB + select MII + bool "Xilinx Ethernetlite" + help + This MAC is present in Xilinx Microblaze, Zynq and ZynqMP SoCs. + config ZYNQ_GEM depends on DM_ETH && (ARCH_ZYNQ || ARCH_ZYNQMP) select PHYLIB diff --git a/drivers/net/fsl-mc/dpio/qbman_portal.c b/drivers/net/fsl-mc/dpio/qbman_portal.c index 449ff8a8ba..4b64c8ae73 100644 --- a/drivers/net/fsl-mc/dpio/qbman_portal.c +++ b/drivers/net/fsl-mc/dpio/qbman_portal.c @@ -102,12 +102,14 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) void *qbman_swp_mc_start(struct qbman_swp *p) { void *ret; + int *return_val; #ifdef QBMAN_CHECKING BUG_ON(p->mc.check != swp_mc_can_start); #endif ret = qbman_cena_write_start(&p->sys, QBMAN_CENA_SWP_CR); #ifdef QBMAN_CHECKING - if (!ret) + return_val = (int *)ret; + if (!(*return_val)) p->mc.check = swp_mc_can_submit; #endif return ret; diff --git a/drivers/net/fsl-mc/dpni.c b/drivers/net/fsl-mc/dpni.c index eacb3c8bb2..41bf56abf5 100644 --- a/drivers/net/fsl-mc/dpni.c +++ b/drivers/net/fsl-mc/dpni.c @@ -8,6 +8,26 @@ #include <fsl-mc/fsl_mc_cmd.h> #include <fsl-mc/fsl_dpni.h> +int dpni_prepare_extended_cfg(const struct dpni_extended_cfg *cfg, + uint8_t *ext_cfg_buf) +{ + uint64_t *ext_params = (uint64_t *)ext_cfg_buf; + + DPNI_PREP_EXTENDED_CFG(ext_params, cfg); + + return 0; +} + +int dpni_extract_extended_cfg(struct dpni_extended_cfg *cfg, + const uint8_t *ext_cfg_buf) +{ + uint64_t *ext_params = (uint64_t *)ext_cfg_buf; + + DPNI_EXT_EXTENDED_CFG(ext_params, cfg); + + return 0; +} + int dpni_open(struct fsl_mc_io *mc_io, uint32_t cmd_flags, int dpni_id, @@ -162,6 +182,7 @@ int dpni_get_attributes(struct fsl_mc_io *mc_io, cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_ATTR, cmd_flags, token); + DPNI_CMD_GET_ATTR(cmd, attr); /* send command to mc*/ err = mc_send_command(mc_io, &cmd); @@ -174,6 +195,23 @@ int dpni_get_attributes(struct fsl_mc_io *mc_io, return 0; } +int dpni_set_errors_behavior(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + struct dpni_error_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_ERRORS_BEHAVIOR, + cmd_flags, + token); + DPNI_CMD_SET_ERRORS_BEHAVIOR(cmd, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + int dpni_get_rx_buffer_layout(struct fsl_mc_io *mc_io, uint32_t cmd_flags, uint16_t token, @@ -602,3 +640,46 @@ int dpni_get_rx_flow(struct fsl_mc_io *mc_io, return 0; } + +int dpni_set_tx_conf(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + const struct dpni_tx_conf_cfg *cfg) +{ + struct mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_CONF, + cmd_flags, + token); + DPNI_CMD_SET_TX_CONF(cmd, flow_id, cfg); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} + +int dpni_get_tx_conf(struct fsl_mc_io *mc_io, + uint32_t cmd_flags, + uint16_t token, + uint16_t flow_id, + struct dpni_tx_conf_attr *attr) +{ + struct mc_command cmd = { 0 }; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_CONF, + cmd_flags, + token); + DPNI_CMD_GET_TX_CONF(cmd, flow_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + DPNI_RSP_GET_TX_CONF(cmd, attr); + + return 0; +} diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c index 4b9b3720f7..d38e98a2fb 100644 --- a/drivers/net/fsl-mc/mc.c +++ b/drivers/net/fsl-mc/mc.c @@ -656,6 +656,26 @@ int fsl_mc_ldpaa_init(bd_t *bis) return 0; } +static int dprc_version_check(struct fsl_mc_io *mc_io, uint16_t handle) +{ + struct dprc_attributes attr; + int error; + + memset(&attr, 0, sizeof(struct dprc_attributes)); + error = dprc_get_attributes(mc_io, MC_CMD_NO_FLAGS, handle, &attr); + if (error == 0) { + if ((attr.version.major != DPRC_VER_MAJOR) || + (attr.version.minor != DPRC_VER_MINOR)) { + printf("DPRC version mismatch found %u.%u,", + attr.version.major, + attr.version.minor); + printf("supported version is %u.%u\n", + DPRC_VER_MAJOR, DPRC_VER_MINOR); + } + } + return error; +} + static int dpio_init(void) { struct qbman_swp_desc p_des; @@ -689,11 +709,18 @@ static int dpio_init(void) goto err_get_attr; } + if ((attr.version.major != DPIO_VER_MAJOR) || + (attr.version.minor != DPIO_VER_MINOR)) { + printf("DPIO version mismatch found %u.%u,", + attr.version.major, attr.version.minor); + printf("supported version is %u.%u\n", + DPIO_VER_MAJOR, DPIO_VER_MINOR); + } + dflt_dpio->dpio_id = attr.id; #ifdef DEBUG printf("Init: DPIO id=0x%d\n", dflt_dpio->dpio_id); #endif - err = dpio_enable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpio->dpio_handle); if (err < 0) { printf("dpio_enable() failed %d\n", err); @@ -785,11 +812,17 @@ static int dprc_init(void) goto err_root_open; } + err = dprc_version_check(root_mc_io, root_dprc_handle); + if (err < 0) { + printf("dprc_version_check() failed: %d\n", err); + goto err_root_open; + } + cfg.options = DPRC_CFG_OPT_TOPOLOGY_CHANGES_ALLOWED | DPRC_CFG_OPT_OBJ_CREATE_ALLOWED | DPRC_CFG_OPT_ALLOC_ALLOWED; cfg.icid = DPRC_GET_ICID_FROM_POOL; - cfg.portal_id = 250; + cfg.portal_id = DPRC_GET_PORTAL_ID_FROM_POOL; err = dprc_create_container(root_mc_io, MC_CMD_NO_FLAGS, root_dprc_handle, &cfg, @@ -907,6 +940,14 @@ static int dpbp_init(void) goto err_get_attr; } + if ((dpbp_attr.version.major != DPBP_VER_MAJOR) || + (dpbp_attr.version.minor != DPBP_VER_MINOR)) { + printf("DPBP version mismatch found %u.%u,", + dpbp_attr.version.major, dpbp_attr.version.minor); + printf("supported version is %u.%u\n", + DPBP_VER_MAJOR, DPBP_VER_MINOR); + } + dflt_dpbp->dpbp_attr.id = dpbp_attr.id; #ifdef DEBUG printf("Init: DPBP id=0x%d\n", dflt_dpbp->dpbp_attr.id); @@ -964,6 +1005,8 @@ static int dpni_init(void) { int err; struct dpni_attr dpni_attr; + uint8_t ext_cfg_buf[256] = {0}; + struct dpni_extended_cfg dpni_extended_cfg; struct dpni_cfg dpni_cfg; dflt_dpni = (struct fsl_dpni_obj *)malloc(sizeof(struct fsl_dpni_obj)); @@ -973,10 +1016,19 @@ static int dpni_init(void) goto err_malloc; } + memset(&dpni_extended_cfg, 0, sizeof(dpni_extended_cfg)); + err = dpni_prepare_extended_cfg(&dpni_extended_cfg, &ext_cfg_buf[0]); + if (err < 0) { + err = -ENODEV; + printf("dpni_prepare_extended_cfg() failed: %d\n", err); + goto err_prepare_extended_cfg; + } + memset(&dpni_cfg, 0, sizeof(dpni_cfg)); dpni_cfg.adv.options = DPNI_OPT_UNICAST_FILTER | DPNI_OPT_MULTICAST_FILTER; + dpni_cfg.adv.ext_cfg_iova = (uint64_t)&ext_cfg_buf[0]; err = dpni_create(dflt_mc_io, MC_CMD_NO_FLAGS, &dpni_cfg, &dflt_dpni->dpni_handle); @@ -995,6 +1047,14 @@ static int dpni_init(void) goto err_get_attr; } + if ((dpni_attr.version.major != DPNI_VER_MAJOR) || + (dpni_attr.version.minor != DPNI_VER_MINOR)) { + printf("DPNI version mismatch found %u.%u,", + dpni_attr.version.major, dpni_attr.version.minor); + printf("supported version is %u.%u\n", + DPNI_VER_MAJOR, DPNI_VER_MINOR); + } + dflt_dpni->dpni_id = dpni_attr.id; #ifdef DEBUG printf("Init: DPNI id=0x%d\n", dflt_dpni->dpni_id); @@ -1009,11 +1069,12 @@ static int dpni_init(void) return 0; err_close: - free(dflt_dpni); err_get_attr: dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); dpni_destroy(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); err_create: +err_prepare_extended_cfg: + free(dflt_dpni); err_malloc: return err; } diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c index 3857122bd0..7f96883d34 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.c +++ b/drivers/net/ldpaa_eth/ldpaa_eth.c @@ -100,6 +100,83 @@ static void ldpaa_eth_get_dpni_counter(void) } printf("DPNI_CNT_EGR_FRAME_DISCARD =%lld\n", value); } + +static void ldpaa_eth_get_dpmac_counter(struct eth_device *net_dev) +{ + struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; + int err = 0; + u64 value; + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_ING_BYTE, + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_ING_BYTE failed\n"); + return; + } + printf("DPMAC_CNT_ING_BYTE=%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_ING_FRAME_DISCARD, + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_ING_FRAME_DISCARD failed\n"); + return; + } + printf("DPMAC_CNT_ING_FRAME_DISCARD=%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_ING_ALIGN_ERR, + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_ING_ALIGN_ERR failed\n"); + return; + } + printf("DPMAC_CNT_ING_ALIGN_ERR =%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_ING_BYTE, + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_ING_BYTE failed\n"); + return; + } + printf("DPMAC_CNT_ING_BYTE=%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_ING_ERR_FRAME, + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_ING_ERR_FRAME failed\n"); + return; + } + printf("DPMAC_CNT_ING_ERR_FRAME=%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_EGR_BYTE , + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_EGR_BYTE failed\n"); + return; + } + printf("DPMAC_CNT_EGR_BYTE =%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_EGR_ERR_FRAME , + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_EGR_ERR_FRAME failed\n"); + return; + } + printf("DPMAC_CNT_EGR_ERR_FRAME =%lld\n", value); +} #endif static void ldpaa_eth_rx(struct ldpaa_eth_priv *priv, @@ -436,6 +513,7 @@ static void ldpaa_eth_stop(struct eth_device *net_dev) #ifdef DEBUG ldpaa_eth_get_dpni_counter(); + ldpaa_eth_get_dpmac_counter(net_dev); #endif err = dprc_disconnect(dflt_mc_io, MC_CMD_NO_FLAGS, @@ -599,6 +677,29 @@ static void ldpaa_dpbp_free(void) dpbp_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle); } +static int ldpaa_dpmac_version_check(struct fsl_mc_io *mc_io, + struct ldpaa_eth_priv *priv) +{ + struct dpmac_attr attr; + int error; + + memset(&attr, 0, sizeof(struct dpmac_attr)); + error = dpmac_get_attributes(mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + &attr); + if (error == 0) { + if ((attr.version.major != DPMAC_VER_MAJOR) || + (attr.version.minor != DPMAC_VER_MINOR)) { + printf("DPMAC version mismatch found %u.%u,", + attr.version.major, attr.version.minor); + printf("supported version is %u.%u\n", + DPMAC_VER_MAJOR, DPMAC_VER_MINOR); + } + } + + return error; +} + static int ldpaa_dpmac_setup(struct ldpaa_eth_priv *priv) { int err = 0; @@ -609,6 +710,11 @@ static int ldpaa_dpmac_setup(struct ldpaa_eth_priv *priv) &priv->dpmac_handle); if (err) printf("dpmac_create() failed\n"); + + err = ldpaa_dpmac_version_check(dflt_mc_io, priv); + if (err < 0) + printf("ldpaa_dpmac_version_check() failed: %d\n", err); + return err; } @@ -755,6 +861,7 @@ static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv) { struct dpni_pools_cfg pools_params; struct dpni_tx_flow_cfg dflt_tx_flow; + struct dpni_tx_conf_cfg tx_conf_cfg; int err = 0; pools_params.num_dpbp = 1; @@ -770,9 +877,7 @@ static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv) priv->tx_flow_id = DPNI_NEW_FLOW_ID; memset(&dflt_tx_flow, 0, sizeof(dflt_tx_flow)); - dflt_tx_flow.options = DPNI_TX_FLOW_OPT_ONLY_TX_ERROR; - dflt_tx_flow.conf_err_cfg.use_default_queue = 0; - dflt_tx_flow.conf_err_cfg.errors_only = 1; + dflt_tx_flow.use_common_tx_conf_queue = 0; err = dpni_set_tx_flow(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle, &priv->tx_flow_id, &dflt_tx_flow); @@ -781,6 +886,17 @@ static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv) return err; } + memset(&tx_conf_cfg, 0, sizeof(struct dpni_tx_conf_cfg)); + tx_conf_cfg.errors_only = true; + /*Set tx-conf and error configuration*/ + err = dpni_set_tx_conf(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, + priv->tx_flow_id, &tx_conf_cfg); + if (err) { + printf("dpni_set_tx_conf() failed\n"); + return err; + } + return 0; } diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.h b/drivers/net/ldpaa_eth/ldpaa_eth.h index af41b27844..3b16150735 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.h +++ b/drivers/net/ldpaa_eth/ldpaa_eth.h @@ -24,7 +24,7 @@ enum ldpaa_eth_type { }; /* Arbitrary values for now, but we'll need to tune */ -#define LDPAA_ETH_NUM_BUFS (2 * 7) +#define LDPAA_ETH_NUM_BUFS (7 * 7) #define LDPAA_ETH_REFILL_THRESH (LDPAA_ETH_NUM_BUFS/2) #define LDPAA_ETH_RX_BUFFER_SIZE 2048 diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c index 541a57f980..c3912d52f3 100644 --- a/drivers/net/phy/ti.c +++ b/drivers/net/phy/ti.c @@ -41,6 +41,8 @@ /* PHY CTRL bits */ #define DP83867_PHYCR_FIFO_DEPTH_SHIFT 14 +#define DP83867_MDI_CROSSOVER 5 +#define DP83867_MDI_CROSSOVER_AUTO 2 /* RGMIIDCTL bits */ #define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4 @@ -149,6 +151,7 @@ static int dp83867_config(struct phy_device *phydev) if (phy_interface_is_rgmii(phydev)) { ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_DP83867_PHYCTRL, + (DP83867_MDI_CROSSOVER_AUTO << DP83867_MDI_CROSSOVER) | (FIFO_DEPTH << DP83867_PHYCR_FIFO_DEPTH_SHIFT)); if (ret) return ret; diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index df053feee8..81274ee13b 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -8,15 +8,14 @@ #include <config.h> #include <common.h> +#include <dm.h> #include <net.h> #include <malloc.h> #include <asm/io.h> #include <phy.h> #include <miiphy.h> -#if !defined(CONFIG_PHYLIB) -# error AXI_ETHERNET requires PHYLIB -#endif +DECLARE_GLOBAL_DATA_PTR; /* Link setup */ #define XAE_EMMC_LINKSPEED_MASK 0xC0000000 /* Link speed */ @@ -86,7 +85,8 @@ struct axidma_priv { struct axidma_reg *dmatx; struct axidma_reg *dmarx; int phyaddr; - + struct axi_regs *iobase; + phy_interface_t interface; struct phy_device *phydev; struct mii_dev *bus; }; @@ -147,9 +147,8 @@ struct axi_regs { */ #define PHY_DETECT_MASK 0x1808 -static inline int mdio_wait(struct eth_device *dev) +static inline int mdio_wait(struct axi_regs *regs) { - struct axi_regs *regs = (struct axi_regs *)dev->iobase; u32 timeout = 200; /* Wait till MDIO interface is ready to accept a new transaction. */ @@ -165,13 +164,13 @@ static inline int mdio_wait(struct eth_device *dev) return 0; } -static u32 phyread(struct eth_device *dev, u32 phyaddress, u32 registernum, - u16 *val) +static u32 phyread(struct axidma_priv *priv, u32 phyaddress, u32 registernum, + u16 *val) { - struct axi_regs *regs = (struct axi_regs *)dev->iobase; + struct axi_regs *regs = priv->iobase; u32 mdioctrlreg = 0; - if (mdio_wait(dev)) + if (mdio_wait(regs)) return 1; mdioctrlreg = ((phyaddress << XAE_MDIO_MCR_PHYAD_SHIFT) & @@ -183,7 +182,7 @@ static u32 phyread(struct eth_device *dev, u32 phyaddress, u32 registernum, out_be32(®s->mdio_mcr, mdioctrlreg); - if (mdio_wait(dev)) + if (mdio_wait(regs)) return 1; /* Read data */ @@ -191,13 +190,13 @@ static u32 phyread(struct eth_device *dev, u32 phyaddress, u32 registernum, return 0; } -static u32 phywrite(struct eth_device *dev, u32 phyaddress, u32 registernum, - u32 data) +static u32 phywrite(struct axidma_priv *priv, u32 phyaddress, u32 registernum, + u32 data) { - struct axi_regs *regs = (struct axi_regs *)dev->iobase; + struct axi_regs *regs = priv->iobase; u32 mdioctrlreg = 0; - if (mdio_wait(dev)) + if (mdio_wait(regs)) return 1; mdioctrlreg = ((phyaddress << XAE_MDIO_MCR_PHYAD_SHIFT) & @@ -212,19 +211,18 @@ static u32 phywrite(struct eth_device *dev, u32 phyaddress, u32 registernum, out_be32(®s->mdio_mcr, mdioctrlreg); - if (mdio_wait(dev)) + if (mdio_wait(regs)) return 1; return 0; } -/* Setting axi emac and phy to proper setting */ -static int setup_phy(struct eth_device *dev) +static int axiemac_phy_init(struct udevice *dev) { u16 phyreg; - u32 i, speed, emmc_reg, ret; - struct axidma_priv *priv = dev->priv; - struct axi_regs *regs = (struct axi_regs *)dev->iobase; + u32 i, ret; + struct axidma_priv *priv = dev_get_priv(dev); + struct axi_regs *regs = priv->iobase; struct phy_device *phydev; u32 supported = SUPPORTED_10baseT_Half | @@ -234,16 +232,19 @@ static int setup_phy(struct eth_device *dev) SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; + /* Set default MDIO divisor */ + out_be32(®s->mdio_mc, XAE_MDIO_DIV_DFT | XAE_MDIO_MC_MDIOEN_MASK); + if (priv->phyaddr == -1) { /* Detect the PHY address */ for (i = 31; i >= 0; i--) { - ret = phyread(dev, i, PHY_DETECT_REG, &phyreg); + ret = phyread(priv, i, PHY_DETECT_REG, &phyreg); if (!ret && (phyreg != 0xFFFF) && ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { /* Found a valid PHY address */ priv->phyaddr = i; debug("axiemac: Found valid phy address, %x\n", - phyreg); + i); break; } } @@ -256,6 +257,18 @@ static int setup_phy(struct eth_device *dev) phydev->advertising = phydev->supported; priv->phydev = phydev; phy_config(phydev); + + return 0; +} + +/* Setting axi emac and phy to proper setting */ +static int setup_phy(struct udevice *dev) +{ + u32 speed, emmc_reg; + struct axidma_priv *priv = dev_get_priv(dev); + struct axi_regs *regs = priv->iobase; + struct phy_device *phydev = priv->phydev; + if (phy_startup(phydev)) { printf("axiemac: could not initialize PHY %s\n", phydev->dev->name); @@ -299,9 +312,9 @@ static int setup_phy(struct eth_device *dev) } /* STOP DMA transfers */ -static void axiemac_halt(struct eth_device *dev) +static void axiemac_stop(struct udevice *dev) { - struct axidma_priv *priv = dev->priv; + struct axidma_priv *priv = dev_get_priv(dev); u32 temp; /* Stop the hardware */ @@ -316,9 +329,9 @@ static void axiemac_halt(struct eth_device *dev) debug("axiemac: Halted\n"); } -static int axi_ethernet_init(struct eth_device *dev) +static int axi_ethernet_init(struct axidma_priv *priv) { - struct axi_regs *regs = (struct axi_regs *)dev->iobase; + struct axi_regs *regs = priv->iobase; u32 timeout = 200; /* @@ -359,25 +372,26 @@ static int axi_ethernet_init(struct eth_device *dev) return 0; } -static int axiemac_setup_mac(struct eth_device *dev) +static int axiemac_write_hwaddr(struct udevice *dev) { - struct axi_regs *regs = (struct axi_regs *)dev->iobase; + struct eth_pdata *pdata = dev_get_platdata(dev); + struct axidma_priv *priv = dev_get_priv(dev); + struct axi_regs *regs = priv->iobase; /* Set the MAC address */ - int val = ((dev->enetaddr[3] << 24) | (dev->enetaddr[2] << 16) | - (dev->enetaddr[1] << 8) | (dev->enetaddr[0])); + int val = ((pdata->enetaddr[3] << 24) | (pdata->enetaddr[2] << 16) | + (pdata->enetaddr[1] << 8) | (pdata->enetaddr[0])); out_be32(®s->uaw0, val); - val = (dev->enetaddr[5] << 8) | dev->enetaddr[4] ; + val = (pdata->enetaddr[5] << 8) | pdata->enetaddr[4]; val |= in_be32(®s->uaw1) & ~XAE_UAW1_UNICASTADDR_MASK; out_be32(®s->uaw1, val); return 0; } /* Reset DMA engine */ -static void axi_dma_init(struct eth_device *dev) +static void axi_dma_init(struct axidma_priv *priv) { - struct axidma_priv *priv = dev->priv; u32 timeout = 500; /* Reset the engine so the hardware starts from a known state */ @@ -388,9 +402,9 @@ static void axi_dma_init(struct eth_device *dev) while (timeout--) { /* Check transmit/receive channel */ /* Reset is done when the reset bit is low */ - if (!(in_be32(&priv->dmatx->control) | + if (!((in_be32(&priv->dmatx->control) | in_be32(&priv->dmarx->control)) - & XAXIDMA_CR_RESET_MASK) { + & XAXIDMA_CR_RESET_MASK)) { break; } } @@ -398,10 +412,10 @@ static void axi_dma_init(struct eth_device *dev) printf("%s: Timeout\n", __func__); } -static int axiemac_init(struct eth_device *dev, bd_t * bis) +static int axiemac_start(struct udevice *dev) { - struct axidma_priv *priv = dev->priv; - struct axi_regs *regs = (struct axi_regs *)dev->iobase; + struct axidma_priv *priv = dev_get_priv(dev); + struct axi_regs *regs = priv->iobase; u32 temp; debug("axiemac: Init started\n"); @@ -411,10 +425,10 @@ static int axiemac_init(struct eth_device *dev, bd_t * bis) * reset, and since AXIDMA reset line is connected to AxiEthernet, this * would ensure a reset of AxiEthernet. */ - axi_dma_init(dev); + axi_dma_init(priv); /* Initialize AxiEthernet hardware. */ - if (axi_ethernet_init(dev)) + if (axi_ethernet_init(priv)) return -1; /* Disable all RX interrupts before RxBD space setup */ @@ -452,7 +466,7 @@ static int axiemac_init(struct eth_device *dev, bd_t * bis) /* PHY setup */ if (!setup_phy(dev)) { - axiemac_halt(dev); + axiemac_stop(dev); return -1; } @@ -460,9 +474,9 @@ static int axiemac_init(struct eth_device *dev, bd_t * bis) return 0; } -static int axiemac_send(struct eth_device *dev, void *ptr, int len) +static int axiemac_send(struct udevice *dev, void *ptr, int len) { - struct axidma_priv *priv = dev->priv; + struct axidma_priv *priv = dev_get_priv(dev); u32 timeout; if (len > PKTSIZE_ALIGN) @@ -498,8 +512,8 @@ static int axiemac_send(struct eth_device *dev, void *ptr, int len) /* Wait for transmission to complete */ debug("axiemac: Waiting for tx to be done\n"); timeout = 200; - while (timeout && (!in_be32(&priv->dmatx->status) & - (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { + while (timeout && (!(in_be32(&priv->dmatx->status) & + (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK)))) { timeout--; udelay(1); } @@ -512,10 +526,9 @@ static int axiemac_send(struct eth_device *dev, void *ptr, int len) return 0; } -static int isrxready(struct eth_device *dev) +static int isrxready(struct axidma_priv *priv) { u32 status; - struct axidma_priv *priv = dev->priv; /* Read pending interrupts */ status = in_be32(&priv->dmarx->status); @@ -533,15 +546,15 @@ static int isrxready(struct eth_device *dev) return 0; } -static int axiemac_recv(struct eth_device *dev) +static int axiemac_recv(struct udevice *dev, int flags, uchar **packetp) { u32 length; - struct axidma_priv *priv = dev->priv; + struct axidma_priv *priv = dev_get_priv(dev); u32 temp; /* Wait for an incoming packet */ - if (!isrxready(dev)) - return 0; + if (!isrxready(priv)) + return -1; debug("axiemac: RX data ready\n"); @@ -554,9 +567,14 @@ static int axiemac_recv(struct eth_device *dev) #ifdef DEBUG print_buffer(&rxframe, &rxframe[0], 1, length, 16); #endif - /* Pass the received frame up for processing */ - if (length) - net_process_received_packet(rxframe, length); + + *packetp = rxframe; + return length; +} + +static int axiemac_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct axidma_priv *priv = dev_get_priv(dev); #ifdef DEBUG /* It is useful to clear buffer to be sure that it is consistent */ @@ -581,76 +599,128 @@ static int axiemac_recv(struct eth_device *dev) debug("axiemac: RX completed, framelength = %d\n", length); - return length; + return 0; } -static int axiemac_miiphy_read(const char *devname, uchar addr, - uchar reg, ushort *val) +static int axiemac_miiphy_read(struct mii_dev *bus, int addr, + int devad, int reg) { - struct eth_device *dev = eth_get_dev(); - u32 ret; + int ret; + u16 value; - ret = phyread(dev, addr, reg, val); - debug("axiemac: Read MII 0x%x, 0x%x, 0x%x\n", addr, reg, *val); - return ret; + ret = phyread(bus->priv, addr, reg, &value); + debug("axiemac: Read MII 0x%x, 0x%x, 0x%x, %d\n", addr, reg, + value, ret); + return value; } -static int axiemac_miiphy_write(const char *devname, uchar addr, - uchar reg, ushort val) +static int axiemac_miiphy_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 value) { - struct eth_device *dev = eth_get_dev(); - - debug("axiemac: Write MII 0x%x, 0x%x, 0x%x\n", addr, reg, val); - return phywrite(dev, addr, reg, val); + debug("axiemac: Write MII 0x%x, 0x%x, 0x%x\n", addr, reg, value); + return phywrite(bus->priv, addr, reg, value); } -static int axiemac_bus_reset(struct mii_dev *bus) +static int axi_emac_probe(struct udevice *dev) { - debug("axiemac: Bus reset\n"); + struct axidma_priv *priv = dev_get_priv(dev); + int ret; + + priv->bus = mdio_alloc(); + priv->bus->read = axiemac_miiphy_read; + priv->bus->write = axiemac_miiphy_write; + priv->bus->priv = priv; + strcpy(priv->bus->name, "axi_emac"); + + ret = mdio_register(priv->bus); + if (ret) + return ret; + + axiemac_phy_init(dev); + return 0; } -int xilinx_axiemac_initialize(bd_t *bis, unsigned long base_addr, - unsigned long dma_addr) +static int axi_emac_remove(struct udevice *dev) { - struct eth_device *dev; - struct axidma_priv *priv; + struct axidma_priv *priv = dev_get_priv(dev); - dev = calloc(1, sizeof(struct eth_device)); - if (dev == NULL) - return -1; + free(priv->phydev); + mdio_unregister(priv->bus); + mdio_free(priv->bus); - dev->priv = calloc(1, sizeof(struct axidma_priv)); - if (dev->priv == NULL) { - free(dev); - return -1; - } - priv = dev->priv; + return 0; +} - sprintf(dev->name, "aximac.%lx", base_addr); +static const struct eth_ops axi_emac_ops = { + .start = axiemac_start, + .send = axiemac_send, + .recv = axiemac_recv, + .free_pkt = axiemac_free_pkt, + .stop = axiemac_stop, + .write_hwaddr = axiemac_write_hwaddr, +}; - dev->iobase = base_addr; - priv->dmatx = (struct axidma_reg *)dma_addr; +static int axi_emac_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct axidma_priv *priv = dev_get_priv(dev); + int offset = 0; + const char *phy_mode; + + pdata->iobase = (phys_addr_t)dev_get_addr(dev); + priv->iobase = (struct axi_regs *)pdata->iobase; + + offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset, + "axistream-connected"); + if (offset <= 0) { + printf("%s: axistream is not found\n", __func__); + return -EINVAL; + } + priv->dmatx = (struct axidma_reg *)fdtdec_get_int(gd->fdt_blob, + offset, "reg", 0); + if (!priv->dmatx) { + printf("%s: axi_dma register space not found\n", __func__); + return -EINVAL; + } /* RX channel offset is 0x30 */ - priv->dmarx = (struct axidma_reg *)(dma_addr + 0x30); - dev->init = axiemac_init; - dev->halt = axiemac_halt; - dev->send = axiemac_send; - dev->recv = axiemac_recv; - dev->write_hwaddr = axiemac_setup_mac; - -#ifdef CONFIG_PHY_ADDR - priv->phyaddr = CONFIG_PHY_ADDR; -#else + priv->dmarx = (struct axidma_reg *)((u32)priv->dmatx + 0x30); + priv->phyaddr = -1; -#endif - eth_register(dev); + offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset, + "phy-handle"); + if (offset > 0) + priv->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1); + + phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset, "phy-mode", NULL); + if (phy_mode) + pdata->phy_interface = phy_get_interface_by_name(phy_mode); + if (pdata->phy_interface == -1) { + debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); + return -EINVAL; + } + priv->interface = pdata->phy_interface; + + printf("AXI EMAC: %lx, phyaddr %d, interface %s\n", (ulong)priv->iobase, + priv->phyaddr, phy_string_for_interface(priv->interface)); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) - miiphy_register(dev->name, axiemac_miiphy_read, axiemac_miiphy_write); - priv->bus = miiphy_get_dev_by_name(dev->name); - priv->bus->reset = axiemac_bus_reset; -#endif - return 1; + return 0; } + +static const struct udevice_id axi_emac_ids[] = { + { .compatible = "xlnx,axi-ethernet-1.00.a" }, + { } +}; + +U_BOOT_DRIVER(axi_emac) = { + .name = "axi_emac", + .id = UCLASS_ETH, + .of_match = axi_emac_ids, + .ofdata_to_platdata = axi_emac_ofdata_to_platdata, + .probe = axi_emac_probe, + .remove = axi_emac_remove, + .ops = &axi_emac_ops, + .priv_auto_alloc_size = sizeof(struct axidma_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index 564205df83..5862bf0a7e 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -10,27 +10,25 @@ #include <common.h> #include <net.h> #include <config.h> +#include <dm.h> +#include <console.h> #include <malloc.h> #include <asm/io.h> +#include <phy.h> +#include <miiphy.h> #include <fdtdec.h> +#include <asm-generic/errno.h> +#include <linux/kernel.h> -#undef DEBUG +DECLARE_GLOBAL_DATA_PTR; #define ENET_ADDR_LENGTH 6 - -/* EmacLite constants */ -#define XEL_BUFFER_OFFSET 0x0800 /* Next buffer's offset */ -#define XEL_TPLR_OFFSET 0x07F4 /* Tx packet length */ -#define XEL_TSR_OFFSET 0x07FC /* Tx status */ -#define XEL_RSR_OFFSET 0x17FC /* Rx status */ -#define XEL_RXBUFF_OFFSET 0x1000 /* Receive Buffer */ +#define ETH_FCS_LEN 4 /* Octets in the FCS */ /* Xmit complete */ #define XEL_TSR_XMIT_BUSY_MASK 0x00000001UL /* Xmit interrupt enable bit */ #define XEL_TSR_XMIT_IE_MASK 0x00000008UL -/* Buffer is active, SW bit only */ -#define XEL_TSR_XMIT_ACTIVE_MASK 0x80000000UL /* Program the MAC address */ #define XEL_TSR_PROGRAM_MASK 0x00000002UL /* define for programming the MAC address into the EMAC Lite */ @@ -46,14 +44,56 @@ /* Recv interrupt enable bit */ #define XEL_RSR_RECV_IE_MASK 0x00000008UL +/* MDIO Address Register Bit Masks */ +#define XEL_MDIOADDR_REGADR_MASK 0x0000001F /* Register Address */ +#define XEL_MDIOADDR_PHYADR_MASK 0x000003E0 /* PHY Address */ +#define XEL_MDIOADDR_PHYADR_SHIFT 5 +#define XEL_MDIOADDR_OP_MASK 0x00000400 /* RD/WR Operation */ + +/* MDIO Write Data Register Bit Masks */ +#define XEL_MDIOWR_WRDATA_MASK 0x0000FFFF /* Data to be Written */ + +/* MDIO Read Data Register Bit Masks */ +#define XEL_MDIORD_RDDATA_MASK 0x0000FFFF /* Data to be Read */ + +/* MDIO Control Register Bit Masks */ +#define XEL_MDIOCTRL_MDIOSTS_MASK 0x00000001 /* MDIO Status Mask */ +#define XEL_MDIOCTRL_MDIOEN_MASK 0x00000008 /* MDIO Enable */ + +struct emaclite_regs { + u32 tx_ping; /* 0x0 - TX Ping buffer */ + u32 reserved1[504]; + u32 mdioaddr; /* 0x7e4 - MDIO Address Register */ + u32 mdiowr; /* 0x7e8 - MDIO Write Data Register */ + u32 mdiord;/* 0x7ec - MDIO Read Data Register */ + u32 mdioctrl; /* 0x7f0 - MDIO Control Register */ + u32 tx_ping_tplr; /* 0x7f4 - Tx packet length */ + u32 global_interrupt; /* 0x7f8 - Global interrupt enable */ + u32 tx_ping_tsr; /* 0x7fc - Tx status */ + u32 tx_pong; /* 0x800 - TX Pong buffer */ + u32 reserved2[508]; + u32 tx_pong_tplr; /* 0xff4 - Tx packet length */ + u32 reserved3; /* 0xff8 */ + u32 tx_pong_tsr; /* 0xffc - Tx status */ + u32 rx_ping; /* 0x1000 - Receive Buffer */ + u32 reserved4[510]; + u32 rx_ping_rsr; /* 0x17fc - Rx status */ + u32 rx_pong; /* 0x1800 - Receive Buffer */ + u32 reserved5[510]; + u32 rx_pong_rsr; /* 0x1ffc - Rx status */ +}; + struct xemaclite { - u32 nexttxbuffertouse; /* Next TX buffer to write to */ - u32 nextrxbuffertouse; /* Next RX buffer to read from */ + bool use_rx_pong_buffer_next; /* Next RX buffer to read from */ u32 txpp; /* TX ping pong buffer */ u32 rxpp; /* RX ping pong buffer */ + int phyaddr; + struct emaclite_regs *regs; + struct phy_device *phydev; + struct mii_dev *bus; }; -static u32 etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */ +static uchar etherrxbuff[PKTSIZE_ALIGN]; /* Receive buffer */ static void xemaclite_alignedread(u32 *srcptr, void *destptr, u32 bytecount) { @@ -81,7 +121,7 @@ static void xemaclite_alignedread(u32 *srcptr, void *destptr, u32 bytecount) *to8ptr++ = *from8ptr++; } -static void xemaclite_alignedwrite(void *srcptr, u32 destptr, u32 bytecount) +static void xemaclite_alignedwrite(void *srcptr, u32 *destptr, u32 bytecount) { u32 i; u32 alignbuffer; @@ -107,42 +147,206 @@ static void xemaclite_alignedwrite(void *srcptr, u32 destptr, u32 bytecount) *to32ptr++ = alignbuffer; } -static void emaclite_halt(struct eth_device *dev) +static int wait_for_bit(const char *func, u32 *reg, const u32 mask, + bool set, unsigned int timeout) +{ + u32 val; + unsigned long start = get_timer(0); + + while (1) { + val = readl(reg); + + if (!set) + val = ~val; + + if ((val & mask) == mask) + return 0; + + if (get_timer(start) > timeout) + break; + + if (ctrlc()) { + puts("Abort\n"); + return -EINTR; + } + + udelay(1); + } + + debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n", + func, reg, mask, set); + + return -ETIMEDOUT; +} + +static int mdio_wait(struct emaclite_regs *regs) { - debug("eth_halt\n"); + return wait_for_bit(__func__, ®s->mdioctrl, + XEL_MDIOCTRL_MDIOSTS_MASK, false, 2000); } -static int emaclite_init(struct eth_device *dev, bd_t *bis) +static u32 phyread(struct xemaclite *emaclite, u32 phyaddress, u32 registernum, + u16 *data) { - struct xemaclite *emaclite = dev->priv; + struct emaclite_regs *regs = emaclite->regs; + + if (mdio_wait(regs)) + return 1; + + u32 ctrl_reg = in_be32(®s->mdioctrl); + out_be32(®s->mdioaddr, XEL_MDIOADDR_OP_MASK | + ((phyaddress << XEL_MDIOADDR_PHYADR_SHIFT) | registernum)); + out_be32(®s->mdioctrl, ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK); + + if (mdio_wait(regs)) + return 1; + + /* Read data */ + *data = in_be32(®s->mdiord); + return 0; +} + +static u32 phywrite(struct xemaclite *emaclite, u32 phyaddress, u32 registernum, + u16 data) +{ + struct emaclite_regs *regs = emaclite->regs; + + if (mdio_wait(regs)) + return 1; + + /* + * Write the PHY address, register number and clear the OP bit in the + * MDIO Address register and then write the value into the MDIO Write + * Data register. Finally, set the Status bit in the MDIO Control + * register to start a MDIO write transaction. + */ + u32 ctrl_reg = in_be32(®s->mdioctrl); + out_be32(®s->mdioaddr, ~XEL_MDIOADDR_OP_MASK & + ((phyaddress << XEL_MDIOADDR_PHYADR_SHIFT) | registernum)); + out_be32(®s->mdiowr, data); + out_be32(®s->mdioctrl, ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK); + + if (mdio_wait(regs)) + return 1; + + return 0; +} + +static void emaclite_stop(struct udevice *dev) +{ + debug("eth_stop\n"); +} + +/* Use MII register 1 (MII status register) to detect PHY */ +#define PHY_DETECT_REG 1 + +/* Mask used to verify certain PHY features (or register contents) + * in the register above: + * 0x1000: 10Mbps full duplex support + * 0x0800: 10Mbps half duplex support + * 0x0008: Auto-negotiation support + */ +#define PHY_DETECT_MASK 0x1808 + +static int setup_phy(struct udevice *dev) +{ + int i; + u16 phyreg; + struct xemaclite *emaclite = dev_get_priv(dev); + struct phy_device *phydev; + + u32 supported = SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full; + + if (emaclite->phyaddr != -1) { + phyread(emaclite, emaclite->phyaddr, PHY_DETECT_REG, &phyreg); + if ((phyreg != 0xFFFF) && + ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + debug("Default phy address %d is valid\n", + emaclite->phyaddr); + } else { + debug("PHY address is not setup correctly %d\n", + emaclite->phyaddr); + emaclite->phyaddr = -1; + } + } + + if (emaclite->phyaddr == -1) { + /* detect the PHY address */ + for (i = 31; i >= 0; i--) { + phyread(emaclite, i, PHY_DETECT_REG, &phyreg); + if ((phyreg != 0xFFFF) && + ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + emaclite->phyaddr = i; + debug("emaclite: Found valid phy address, %d\n", + i); + break; + } + } + } + + /* interface - look at tsec */ + phydev = phy_connect(emaclite->bus, emaclite->phyaddr, dev, + PHY_INTERFACE_MODE_MII); + /* + * Phy can support 1000baseT but device NOT that's why phydev->supported + * must be setup for 1000baseT. phydev->advertising setups what speeds + * will be used for autonegotiation where 1000baseT must be disabled. + */ + phydev->supported = supported | SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full; + phydev->advertising = supported; + emaclite->phydev = phydev; + phy_config(phydev); + phy_startup(phydev); + + if (!phydev->link) { + printf("%s: No link.\n", phydev->dev->name); + return 0; + } + + /* Do not setup anything */ + return 1; +} + +static int emaclite_start(struct udevice *dev) +{ + struct xemaclite *emaclite = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + struct emaclite_regs *regs = emaclite->regs; + debug("EmacLite Initialization Started\n"); /* * TX - TX_PING & TX_PONG initialization */ /* Restart PING TX */ - out_be32 (dev->iobase + XEL_TSR_OFFSET, 0); + out_be32(®s->tx_ping_tsr, 0); /* Copy MAC address */ - xemaclite_alignedwrite(dev->enetaddr, dev->iobase, ENET_ADDR_LENGTH); + xemaclite_alignedwrite(pdata->enetaddr, ®s->tx_ping, + ENET_ADDR_LENGTH); /* Set the length */ - out_be32 (dev->iobase + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH); + out_be32(®s->tx_ping_tplr, ENET_ADDR_LENGTH); /* Update the MAC address in the EMAC Lite */ - out_be32 (dev->iobase + XEL_TSR_OFFSET, XEL_TSR_PROG_MAC_ADDR); + out_be32(®s->tx_ping_tsr, XEL_TSR_PROG_MAC_ADDR); /* Wait for EMAC Lite to finish with the MAC address update */ - while ((in_be32 (dev->iobase + XEL_TSR_OFFSET) & + while ((in_be32 (®s->tx_ping_tsr) & XEL_TSR_PROG_MAC_ADDR) != 0) ; if (emaclite->txpp) { /* The same operation with PONG TX */ - out_be32 (dev->iobase + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, 0); - xemaclite_alignedwrite(dev->enetaddr, dev->iobase + - XEL_BUFFER_OFFSET, ENET_ADDR_LENGTH); - out_be32 (dev->iobase + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH); - out_be32 (dev->iobase + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, - XEL_TSR_PROG_MAC_ADDR); - while ((in_be32 (dev->iobase + XEL_TSR_OFFSET + - XEL_BUFFER_OFFSET) & XEL_TSR_PROG_MAC_ADDR) != 0) + out_be32(®s->tx_pong_tsr, 0); + xemaclite_alignedwrite(pdata->enetaddr, ®s->tx_pong, + ENET_ADDR_LENGTH); + out_be32(®s->tx_pong_tplr, ENET_ADDR_LENGTH); + out_be32(®s->tx_pong_tsr, XEL_TSR_PROG_MAC_ADDR); + while ((in_be32(®s->tx_pong_tsr) & + XEL_TSR_PROG_MAC_ADDR) != 0) ; } @@ -150,52 +354,48 @@ static int emaclite_init(struct eth_device *dev, bd_t *bis) * RX - RX_PING & RX_PONG initialization */ /* Write out the value to flush the RX buffer */ - out_be32 (dev->iobase + XEL_RSR_OFFSET, XEL_RSR_RECV_IE_MASK); + out_be32(®s->rx_ping_rsr, XEL_RSR_RECV_IE_MASK); if (emaclite->rxpp) - out_be32 (dev->iobase + XEL_RSR_OFFSET + XEL_BUFFER_OFFSET, - XEL_RSR_RECV_IE_MASK); + out_be32(®s->rx_pong_rsr, XEL_RSR_RECV_IE_MASK); + + out_be32(®s->mdioctrl, XEL_MDIOCTRL_MDIOEN_MASK); + if (in_be32(®s->mdioctrl) & XEL_MDIOCTRL_MDIOEN_MASK) + if (!setup_phy(dev)) + return -1; debug("EmacLite Initialization complete\n"); return 0; } -static int xemaclite_txbufferavailable(struct eth_device *dev) +static int xemaclite_txbufferavailable(struct xemaclite *emaclite) { - u32 reg; - u32 txpingbusy; - u32 txpongbusy; - struct xemaclite *emaclite = dev->priv; + u32 tmp; + struct emaclite_regs *regs = emaclite->regs; /* * Read the other buffer register * and determine if the other buffer is available */ - reg = in_be32 (dev->iobase + - emaclite->nexttxbuffertouse + 0); - txpingbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) == - XEL_TSR_XMIT_BUSY_MASK); - - reg = in_be32 (dev->iobase + - (emaclite->nexttxbuffertouse ^ XEL_TSR_OFFSET) + 0); - txpongbusy = ((reg & XEL_TSR_XMIT_BUSY_MASK) == - XEL_TSR_XMIT_BUSY_MASK); + tmp = ~in_be32(®s->tx_ping_tsr); + if (emaclite->txpp) + tmp |= ~in_be32(®s->tx_pong_tsr); - return !(txpingbusy && txpongbusy); + return !(tmp & XEL_TSR_XMIT_BUSY_MASK); } -static int emaclite_send(struct eth_device *dev, void *ptr, int len) +static int emaclite_send(struct udevice *dev, void *ptr, int len) { u32 reg; - u32 baseaddress; - struct xemaclite *emaclite = dev->priv; + struct xemaclite *emaclite = dev_get_priv(dev); + struct emaclite_regs *regs = emaclite->regs; u32 maxtry = 1000; if (len > PKTSIZE) len = PKTSIZE; - while (!xemaclite_txbufferavailable(dev) && maxtry) { + while (xemaclite_txbufferavailable(emaclite) && maxtry) { udelay(10); maxtry--; } @@ -203,58 +403,40 @@ static int emaclite_send(struct eth_device *dev, void *ptr, int len) if (!maxtry) { printf("Error: Timeout waiting for ethernet TX buffer\n"); /* Restart PING TX */ - out_be32 (dev->iobase + XEL_TSR_OFFSET, 0); + out_be32(®s->tx_ping_tsr, 0); if (emaclite->txpp) { - out_be32 (dev->iobase + XEL_TSR_OFFSET + - XEL_BUFFER_OFFSET, 0); + out_be32(®s->tx_pong_tsr, 0); } return -1; } - /* Determine the expected TX buffer address */ - baseaddress = (dev->iobase + emaclite->nexttxbuffertouse); - /* Determine if the expected buffer address is empty */ - reg = in_be32 (baseaddress + XEL_TSR_OFFSET); - if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0) - && ((in_be32 ((baseaddress) + XEL_TSR_OFFSET) - & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) { - - if (emaclite->txpp) - emaclite->nexttxbuffertouse ^= XEL_BUFFER_OFFSET; - - debug("Send packet from 0x%x\n", baseaddress); + reg = in_be32(®s->tx_ping_tsr); + if ((reg & XEL_TSR_XMIT_BUSY_MASK) == 0) { + debug("Send packet from tx_ping buffer\n"); /* Write the frame to the buffer */ - xemaclite_alignedwrite(ptr, baseaddress, len); - out_be32 (baseaddress + XEL_TPLR_OFFSET,(len & - (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO))); - reg = in_be32 (baseaddress + XEL_TSR_OFFSET); + xemaclite_alignedwrite(ptr, ®s->tx_ping, len); + out_be32(®s->tx_ping_tplr, len & + (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO)); + reg = in_be32(®s->tx_ping_tsr); reg |= XEL_TSR_XMIT_BUSY_MASK; - if ((reg & XEL_TSR_XMIT_IE_MASK) != 0) - reg |= XEL_TSR_XMIT_ACTIVE_MASK; - out_be32 (baseaddress + XEL_TSR_OFFSET, reg); + out_be32(®s->tx_ping_tsr, reg); return 0; } if (emaclite->txpp) { - /* Switch to second buffer */ - baseaddress ^= XEL_BUFFER_OFFSET; /* Determine if the expected buffer address is empty */ - reg = in_be32 (baseaddress + XEL_TSR_OFFSET); - if (((reg & XEL_TSR_XMIT_BUSY_MASK) == 0) - && ((in_be32 ((baseaddress) + XEL_TSR_OFFSET) - & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) { - debug("Send packet from 0x%x\n", baseaddress); + reg = in_be32(®s->tx_pong_tsr); + if ((reg & XEL_TSR_XMIT_BUSY_MASK) == 0) { + debug("Send packet from tx_pong buffer\n"); /* Write the frame to the buffer */ - xemaclite_alignedwrite(ptr, baseaddress, len); - out_be32 (baseaddress + XEL_TPLR_OFFSET, (len & - (XEL_TPLR_LENGTH_MASK_HI | - XEL_TPLR_LENGTH_MASK_LO))); - reg = in_be32 (baseaddress + XEL_TSR_OFFSET); + xemaclite_alignedwrite(ptr, ®s->tx_pong, len); + out_be32(®s->tx_pong_tplr, len & + (XEL_TPLR_LENGTH_MASK_HI | + XEL_TPLR_LENGTH_MASK_LO)); + reg = in_be32(®s->tx_pong_tsr); reg |= XEL_TSR_XMIT_BUSY_MASK; - if ((reg & XEL_TSR_XMIT_IE_MASK) != 0) - reg |= XEL_TSR_XMIT_ACTIVE_MASK; - out_be32 (baseaddress + XEL_TSR_OFFSET, reg); + out_be32(®s->tx_pong_tsr, reg); return 0; } } @@ -263,130 +445,188 @@ static int emaclite_send(struct eth_device *dev, void *ptr, int len) return -1; } -static int emaclite_recv(struct eth_device *dev) +static int emaclite_recv(struct udevice *dev, int flags, uchar **packetp) { - u32 length; - u32 reg; - u32 baseaddress; + u32 length, first_read, reg, attempt = 0; + void *addr, *ack; struct xemaclite *emaclite = dev->priv; + struct emaclite_regs *regs = emaclite->regs; + struct ethernet_hdr *eth; + struct ip_udp_hdr *ip; + +try_again: + if (!emaclite->use_rx_pong_buffer_next) { + reg = in_be32(®s->rx_ping_rsr); + debug("Testing data at rx_ping\n"); + if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { + debug("Data found in rx_ping buffer\n"); + addr = ®s->rx_ping; + ack = ®s->rx_ping_rsr; + } else { + debug("Data not found in rx_ping buffer\n"); + /* Pong buffer is not available - return immediately */ + if (!emaclite->rxpp) + return -1; - baseaddress = dev->iobase + emaclite->nextrxbuffertouse; - reg = in_be32 (baseaddress + XEL_RSR_OFFSET); - debug("Testing data at address 0x%x\n", baseaddress); - if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { - if (emaclite->rxpp) - emaclite->nextrxbuffertouse ^= XEL_BUFFER_OFFSET; + /* Try pong buffer if this is first attempt */ + if (attempt++) + return -1; + emaclite->use_rx_pong_buffer_next = + !emaclite->use_rx_pong_buffer_next; + goto try_again; + } } else { - - if (!emaclite->rxpp) { - debug("No data was available - address 0x%x\n", - baseaddress); - return 0; + reg = in_be32(®s->rx_pong_rsr); + debug("Testing data at rx_pong\n"); + if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { + debug("Data found in rx_pong buffer\n"); + addr = ®s->rx_pong; + ack = ®s->rx_pong_rsr; } else { - baseaddress ^= XEL_BUFFER_OFFSET; - reg = in_be32 (baseaddress + XEL_RSR_OFFSET); - if ((reg & XEL_RSR_RECV_DONE_MASK) != - XEL_RSR_RECV_DONE_MASK) { - debug("No data was available - address 0x%x\n", - baseaddress); - return 0; - } + debug("Data not found in rx_pong buffer\n"); + /* Try ping buffer if this is first attempt */ + if (attempt++) + return -1; + emaclite->use_rx_pong_buffer_next = + !emaclite->use_rx_pong_buffer_next; + goto try_again; } } - /* Get the length of the frame that arrived */ - switch(((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET + 0xC))) & - 0xFFFF0000 ) >> 16) { - case 0x806: - length = 42 + 20; /* FIXME size of ARP */ - debug("ARP Packet\n"); - break; - case 0x800: - length = 14 + 14 + - (((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET + - 0x10))) & 0xFFFF0000) >> 16); - /* FIXME size of IP packet */ - debug ("IP Packet\n"); - break; - default: - debug("Other Packet\n"); - length = PKTSIZE; - break; + + /* Read all bytes for ARP packet with 32bit alignment - 48bytes */ + first_read = ALIGN(ETHER_HDR_SIZE + ARP_HDR_SIZE + ETH_FCS_LEN, 4); + xemaclite_alignedread(addr, etherrxbuff, first_read); + + /* Detect real packet size */ + eth = (struct ethernet_hdr *)etherrxbuff; + switch (ntohs(eth->et_protlen)) { + case PROT_ARP: + length = first_read; + debug("ARP Packet %x\n", length); + break; + case PROT_IP: + ip = (struct ip_udp_hdr *)(etherrxbuff + ETHER_HDR_SIZE); + length = ntohs(ip->ip_len); + length += ETHER_HDR_SIZE + ETH_FCS_LEN; + debug("IP Packet %x\n", length); + break; + default: + debug("Other Packet\n"); + length = PKTSIZE; + break; } - xemaclite_alignedread((u32 *) (baseaddress + XEL_RXBUFF_OFFSET), - etherrxbuff, length); + /* Read the rest of the packet which is longer then first read */ + if (length != first_read) + xemaclite_alignedread(addr + first_read, + etherrxbuff + first_read, + length - first_read); /* Acknowledge the frame */ - reg = in_be32 (baseaddress + XEL_RSR_OFFSET); + reg = in_be32(ack); reg &= ~XEL_RSR_RECV_DONE_MASK; - out_be32 (baseaddress + XEL_RSR_OFFSET, reg); + out_be32(ack, reg); - debug("Packet receive from 0x%x, length %dB\n", baseaddress, length); - net_process_received_packet((uchar *)etherrxbuff, length); + debug("Packet receive from 0x%p, length %dB\n", addr, length); + *packetp = etherrxbuff; return length; - } -int xilinx_emaclite_initialize(bd_t *bis, unsigned long base_addr, - int txpp, int rxpp) +static int emaclite_miiphy_read(struct mii_dev *bus, int addr, + int devad, int reg) { - struct eth_device *dev; - struct xemaclite *emaclite; + u32 ret; + u16 val = 0; - dev = calloc(1, sizeof(*dev)); - if (dev == NULL) - return -1; + ret = phyread(bus->priv, addr, reg, &val); + debug("emaclite: Read MII 0x%x, 0x%x, 0x%x, %d\n", addr, reg, val, ret); + return val; +} - emaclite = calloc(1, sizeof(struct xemaclite)); - if (emaclite == NULL) { - free(dev); - return -1; - } +static int emaclite_miiphy_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 value) +{ + debug("emaclite: Write MII 0x%x, 0x%x, 0x%x\n", addr, reg, value); + return phywrite(bus->priv, addr, reg, value); +} + +static int emaclite_probe(struct udevice *dev) +{ + struct xemaclite *emaclite = dev_get_priv(dev); + int ret; - dev->priv = emaclite; + emaclite->bus = mdio_alloc(); + emaclite->bus->read = emaclite_miiphy_read; + emaclite->bus->write = emaclite_miiphy_write; + emaclite->bus->priv = emaclite; + strcpy(emaclite->bus->name, "emaclite"); - emaclite->txpp = txpp; - emaclite->rxpp = rxpp; + ret = mdio_register(emaclite->bus); + if (ret) + return ret; - sprintf(dev->name, "Xelite.%lx", base_addr); + return 0; +} - dev->iobase = base_addr; - dev->init = emaclite_init; - dev->halt = emaclite_halt; - dev->send = emaclite_send; - dev->recv = emaclite_recv; +static int emaclite_remove(struct udevice *dev) +{ + struct xemaclite *emaclite = dev_get_priv(dev); - eth_register(dev); + free(emaclite->phydev); + mdio_unregister(emaclite->bus); + mdio_free(emaclite->bus); - return 1; + return 0; } -#if CONFIG_IS_ENABLED(OF_CONTROL) -int xilinx_emaclite_of_init(const void *blob) +static const struct eth_ops emaclite_ops = { + .start = emaclite_start, + .send = emaclite_send, + .recv = emaclite_recv, + .stop = emaclite_stop, +}; + +static int emaclite_ofdata_to_platdata(struct udevice *dev) { + struct eth_pdata *pdata = dev_get_platdata(dev); + struct xemaclite *emaclite = dev_get_priv(dev); int offset = 0; - u32 ret = 0; - u32 reg; - do { - offset = fdt_node_offset_by_compatible(blob, offset, - "xlnx,xps-ethernetlite-1.00.a"); - if (offset != -1) { - reg = fdtdec_get_addr(blob, offset, "reg"); - if (reg != FDT_ADDR_T_NONE) { - u32 rxpp = fdtdec_get_int(blob, offset, - "xlnx,rx-ping-pong", 0); - u32 txpp = fdtdec_get_int(blob, offset, - "xlnx,tx-ping-pong", 0); - ret |= xilinx_emaclite_initialize(NULL, reg, - txpp, rxpp); - } else { - debug("EMACLITE: Can't get base address\n"); - return -1; - } - } - } while (offset != -1); + pdata->iobase = (phys_addr_t)dev_get_addr(dev); + emaclite->regs = (struct emaclite_regs *)pdata->iobase; + + emaclite->phyaddr = -1; + + offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset, + "phy-handle"); + if (offset > 0) + emaclite->phyaddr = fdtdec_get_int(gd->fdt_blob, offset, + "reg", -1); + + emaclite->txpp = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "xlnx,tx-ping-pong", 0); + emaclite->rxpp = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "xlnx,rx-ping-pong", 0); - return ret; + printf("EMACLITE: %lx, phyaddr %d, %d/%d\n", (ulong)emaclite->regs, + emaclite->phyaddr, emaclite->txpp, emaclite->rxpp); + + return 0; } -#endif + +static const struct udevice_id emaclite_ids[] = { + { .compatible = "xlnx,xps-ethernetlite-1.00.a" }, + { } +}; + +U_BOOT_DRIVER(emaclite) = { + .name = "emaclite", + .id = UCLASS_ETH, + .of_match = emaclite_ids, + .ofdata_to_platdata = emaclite_ofdata_to_platdata, + .probe = emaclite_probe, + .remove = emaclite_remove, + .ops = &emaclite_ops, + .priv_auto_alloc_size = sizeof(struct xemaclite), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; diff --git a/drivers/net/xilinx_ll_temac.c b/drivers/net/xilinx_ll_temac.c index 7cc86571e4..ca09546ab5 100644 --- a/drivers/net/xilinx_ll_temac.c +++ b/drivers/net/xilinx_ll_temac.c @@ -303,7 +303,8 @@ int xilinx_ll_temac_initialize(bd_t *bis, struct ll_temac_info *devinf) if (devinf->devname) { strncpy(dev->name, devinf->devname, sizeof(dev->name)); } else { - snprintf(dev->name, sizeof(dev->name), "lltemac.%lx", devinf->base_addr); + snprintf(dev->name, sizeof(dev->name), "ll_tem.%lx", + devinf->base_addr); devinf->devname = dev->name; } diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 97e30f3be0..b3821c31a9 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -57,7 +57,11 @@ DECLARE_GLOBAL_DATA_PTR; #define ZYNQ_GEM_NWCFG_SPEED1000 0x000000400 /* 1Gbps operation */ #define ZYNQ_GEM_NWCFG_FDEN 0x000000002 /* Full Duplex mode */ #define ZYNQ_GEM_NWCFG_FSREM 0x000020000 /* FCS removal */ +#ifdef CONFIG_ARM64 +#define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x000100000 /* Div pclk by 64, max 160MHz */ +#else #define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x0000c0000 /* Div pclk by 48, max 120MHz */ +#endif #ifdef CONFIG_ARM64 # define ZYNQ_GEM_DBUS_WIDTH (1 << 21) /* 64 bit bus */ |