summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/Kconfig24
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/designware.c16
-rw-r--r--drivers/net/designware.h1
-rw-r--r--drivers/net/fsl-mc/dpio/qbman_portal.c4
-rw-r--r--drivers/net/fsl-mc/dpni.c81
-rw-r--r--drivers/net/fsl-mc/mc.c70
-rw-r--r--drivers/net/fsl_mdio.c4
-rw-r--r--drivers/net/ldpaa_eth/ldpaa_eth.c122
-rw-r--r--drivers/net/ldpaa_eth/ldpaa_eth.h2
-rw-r--r--drivers/net/phy/cortina.c7
-rw-r--r--drivers/net/phy/micrel.c25
-rw-r--r--drivers/net/phy/phy.c102
-rw-r--r--drivers/net/phy/smsc.c10
-rw-r--r--drivers/net/phy/ti.c3
-rw-r--r--drivers/net/pic32_eth.c605
-rw-r--r--drivers/net/pic32_eth.h164
-rw-r--r--drivers/net/pic32_mdio.c121
-rw-r--r--drivers/net/tsec.c536
-rw-r--r--drivers/net/vsc9953.c354
-rw-r--r--drivers/net/xilinx_axi_emac.c280
-rw-r--r--drivers/net/xilinx_emaclite.c610
-rw-r--r--drivers/net/xilinx_ll_temac.c3
-rw-r--r--drivers/net/zynq_gem.c4
24 files changed, 2636 insertions, 513 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index de54ca8014..bc2f51d958 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
@@ -109,4 +125,12 @@ config ZYNQ_GEM
help
This MAC is present in Xilinx Zynq and ZynqMP SoCs.
+config PIC32_ETH
+ bool "Microchip PIC32 Ethernet Support"
+ depends on DM_ETH && MACH_PIC32
+ select PHYLIB
+ help
+ This driver implements 10/100 Mbps Ethernet and MAC layer for
+ Microchip PIC32 microcontrollers.
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 150470c24b..33a81ee547 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -72,3 +72,4 @@ obj-$(CONFIG_FSL_MC_ENET) += fsl-mc/
obj-$(CONFIG_FSL_MC_ENET) += ldpaa_eth/
obj-$(CONFIG_FSL_MEMAC) += fm/memac_phy.o
obj-$(CONFIG_VSC9953) += vsc9953.o
+obj-$(CONFIG_PIC32_ETH) += pic32_mdio.o pic32_eth.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 68b6548309..77b98c94c0 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -196,6 +196,8 @@ static void dw_adjust_link(struct eth_mac_regs *mac_p,
if (phydev->speed != 1000)
conf |= MII_PORTSELECT;
+ else
+ conf &= ~MII_PORTSELECT;
if (phydev->speed == 100)
conf |= FES_100;
@@ -404,7 +406,7 @@ static int _dw_free_pkt(struct dw_eth_dev *priv)
static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
{
struct phy_device *phydev;
- int mask = 0xffffffff;
+ int mask = 0xffffffff, ret;
#ifdef CONFIG_PHY_ADDR
mask = 1 << CONFIG_PHY_ADDR;
@@ -417,6 +419,11 @@ static int dw_phy_init(struct dw_eth_dev *priv, void *dev)
phy_connect_dev(phydev, dev);
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;
@@ -599,6 +606,7 @@ static int designware_eth_probe(struct udevice *dev)
priv->mac_regs_p = (struct eth_mac_regs *)iobase;
priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET);
priv->interface = pdata->phy_interface;
+ priv->max_speed = pdata->max_speed;
dw_mdio_init(dev->name, priv->mac_regs_p);
priv->bus = miiphy_get_dev_by_name(dev->name);
@@ -633,6 +641,7 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
{
struct eth_pdata *pdata = dev_get_platdata(dev);
const char *phy_mode;
+ const fdt32_t *cell;
pdata->iobase = dev_get_addr(dev);
pdata->phy_interface = -1;
@@ -644,6 +653,11 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
return -EINVAL;
}
+ pdata->max_speed = 0;
+ cell = fdt_getprop(gd->fdt_blob, dev->of_offset, "max-speed", NULL);
+ if (cell)
+ pdata->max_speed = fdt32_to_cpu(*cell);
+
return 0;
}
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index 4b9ec39cc8..ed6344cc28 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -223,6 +223,7 @@ struct dw_eth_dev {
char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
u32 interface;
+ u32 max_speed;
u32 tx_currdescnum;
u32 rx_currdescnum;
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..fdbd584186 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,18 @@ 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;
+ }
+
+ memset(&cfg, 0, sizeof(struct dprc_cfg));
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 +941,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 +1006,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 +1017,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 +1048,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 +1070,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;
}
@@ -1099,7 +1161,7 @@ int fsl_mc_ldpaa_exit(bd_t *bd)
err = dpbp_exit();
if (err < 0) {
- printf("dpni_exit() failed: %d\n", err);
+ printf("dpbp_exit() failed: %d\n", err);
goto err;
}
diff --git a/drivers/net/fsl_mdio.c b/drivers/net/fsl_mdio.c
index f48bbc3123..77b9739a24 100644
--- a/drivers/net/fsl_mdio.c
+++ b/drivers/net/fsl_mdio.c
@@ -5,6 +5,7 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
+
#include <common.h>
#include <miiphy.h>
#include <phy.h>
@@ -32,8 +33,7 @@ int tsec_local_mdio_read(struct tsec_mii_mng __iomem *phyregs, int port_addr,
int value;
int timeout = 1000000;
- /* Put the address of the phy, and the register
- * number into MIIMADD */
+ /* Put the address of the phy, and the register number into MIIMADD */
out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f));
/* Clear the command register, and wait */
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/cortina.c b/drivers/net/phy/cortina.c
index 447ecfbeb6..f975fd8209 100644
--- a/drivers/net/phy/cortina.c
+++ b/drivers/net/phy/cortina.c
@@ -257,6 +257,12 @@ int cs4340_config(struct phy_device *phydev)
return 0;
}
+int cs4340_probe(struct phy_device *phydev)
+{
+ phydev->flags = PHY_FLAG_BROKEN_RESET;
+ return 0;
+}
+
int cs4340_startup(struct phy_device *phydev)
{
phydev->link = 1;
@@ -276,6 +282,7 @@ struct phy_driver cs4340_driver = {
MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
.config = &cs4340_config,
+ .probe = &cs4340_probe,
.startup = &cs4340_startup,
.shutdown = &gen10g_shutdown,
};
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 19b6bc7472..c3da1606dc 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -27,12 +27,31 @@ static struct phy_driver KSZ804_driver = {
.shutdown = &genphy_shutdown,
};
+#define MII_KSZPHY_OMSO 0x16
+#define KSZPHY_OMSO_B_CAST_OFF (1 << 9)
+
+static int ksz_genconfig_bcastoff(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO,
+ ret | KSZPHY_OMSO_B_CAST_OFF);
+ if (ret < 0)
+ return ret;
+
+ return genphy_config(phydev);
+}
+
static struct phy_driver KSZ8031_driver = {
.name = "Micrel KSZ8021/KSZ8031",
.uid = 0x221550,
.mask = 0xfffff0,
.features = PHY_BASIC_FEATURES,
- .config = &genphy_config,
+ .config = &ksz_genconfig_bcastoff,
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
@@ -70,7 +89,7 @@ static struct phy_driver KSZ8081_driver = {
.uid = 0x221560,
.mask = 0xfffff0,
.features = PHY_BASIC_FEATURES,
- .config = &genphy_config,
+ .config = &ksz_genconfig_bcastoff,
.startup = &genphy_startup,
.shutdown = &genphy_shutdown,
};
@@ -211,7 +230,7 @@ static int ksz90x1_of_config_group(struct phy_device *phydev,
{
struct udevice *dev = phydev->dev;
struct phy_driver *drv = phydev->drv;
- const int ps_to_regval = 200;
+ const int ps_to_regval = 60;
int val[4];
int i, changed = 0, offset, max;
u16 regval = 0;
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 51b5746a5a..17866a244b 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -38,16 +38,16 @@ DECLARE_GLOBAL_DATA_PTR;
static int genphy_config_advert(struct phy_device *phydev)
{
u32 advertise;
- int oldadv, adv;
+ int oldadv, adv, bmsr;
int err, changed = 0;
- /* Only allow advertising what
- * this PHY supports */
+ /* Only allow advertising what this PHY supports */
phydev->advertising &= phydev->supported;
advertise = phydev->advertising;
/* Setup standard advertisement */
- oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+ adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+ oldadv = adv;
if (adv < 0)
return adv;
@@ -79,29 +79,40 @@ static int genphy_config_advert(struct phy_device *phydev)
changed = 1;
}
+ bmsr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+ if (bmsr < 0)
+ return bmsr;
+
+ /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
+ * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
+ * logical 1.
+ */
+ if (!(bmsr & BMSR_ESTATEN))
+ return changed;
+
/* Configure gigabit if it's supported */
- if (phydev->supported & (SUPPORTED_1000baseT_Half |
- SUPPORTED_1000baseT_Full)) {
- oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+ adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+ oldadv = adv;
+
+ if (adv < 0)
+ return adv;
- if (adv < 0)
- return adv;
+ adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
- adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+ if (phydev->supported & (SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full)) {
if (advertise & SUPPORTED_1000baseT_Half)
adv |= ADVERTISE_1000HALF;
if (advertise & SUPPORTED_1000baseT_Full)
adv |= ADVERTISE_1000FULL;
+ }
- if (adv != oldadv) {
- err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000,
- adv);
+ if (adv != oldadv)
+ changed = 1;
- if (err < 0)
- return err;
- changed = 1;
- }
- }
+ err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, adv);
+ if (err < 0)
+ return err;
return changed;
}
@@ -117,7 +128,7 @@ static int genphy_config_advert(struct phy_device *phydev)
static int genphy_setup_forced(struct phy_device *phydev)
{
int err;
- int ctl = 0;
+ int ctl = BMCR_ANRESTART;
phydev->pause = phydev->asym_pause = 0;
@@ -224,7 +235,8 @@ int genphy_update_link(struct phy_device *phydev)
if (phydev->link && mii_reg & BMSR_LSTATUS)
return 0;
- if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
+ if ((phydev->autoneg == AUTONEG_ENABLE) &&
+ !(mii_reg & BMSR_ANEGCOMPLETE)) {
int i = 0;
printf("%s Waiting for PHY auto negotiation to complete",
@@ -280,7 +292,7 @@ int genphy_parse_link(struct phy_device *phydev)
int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
/* We're using autonegotiation */
- if (phydev->supported & SUPPORTED_Autoneg) {
+ if (phydev->autoneg == AUTONEG_ENABLE) {
u32 lpa = 0;
int gblpa = 0;
u32 estatus = 0;
@@ -371,8 +383,6 @@ int genphy_config(struct phy_device *phydev)
int val;
u32 features;
- /* For now, I'll claim that the generic driver supports
- * all possible port types */
features = (SUPPORTED_TP | SUPPORTED_MII
| SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_BNC);
@@ -411,8 +421,8 @@ int genphy_config(struct phy_device *phydev)
features |= SUPPORTED_1000baseX_Half;
}
- phydev->supported = features;
- phydev->advertising = features;
+ phydev->supported &= features;
+ phydev->advertising &= features;
genphy_config_aneg(phydev);
@@ -436,7 +446,9 @@ static struct phy_driver genphy_driver = {
.uid = 0xffffffff,
.mask = 0xffffffff,
.name = "Generic PHY",
- .features = 0,
+ .features = PHY_GBIT_FEATURES | SUPPORTED_MII |
+ SUPPORTED_AUI | SUPPORTED_FIBRE |
+ SUPPORTED_BNC,
.config = genphy_config,
.startup = genphy_startup,
.shutdown = genphy_shutdown,
@@ -517,6 +529,30 @@ int phy_register(struct phy_driver *drv)
return 0;
}
+int phy_set_supported(struct phy_device *phydev, u32 max_speed)
+{
+ /* The default values for phydev->supported are provided by the PHY
+ * driver "features" member, we want to reset to sane defaults first
+ * before supporting higher speeds.
+ */
+ phydev->supported &= PHY_DEFAULT_FEATURES;
+
+ switch (max_speed) {
+ default:
+ return -ENOTSUPP;
+ case SPEED_1000:
+ phydev->supported |= PHY_1000BT_FEATURES;
+ /* fall through */
+ case SPEED_100:
+ phydev->supported |= PHY_100BT_FEATURES;
+ /* fall through */
+ case SPEED_10:
+ phydev->supported |= PHY_10BT_FEATURES;
+ }
+
+ return 0;
+}
+
static int phy_probe(struct phy_device *phydev)
{
int err = 0;
@@ -707,6 +743,9 @@ int phy_reset(struct phy_device *phydev)
int timeout = 500;
int devad = MDIO_DEVAD_NONE;
+ if (phydev->flags & PHY_FLAG_BROKEN_RESET)
+ return 0;
+
#ifdef CONFIG_PHYLIB_10G
/* If it's 10G, we need to issue reset through one of the MMDs */
if (is_10g_interface(phydev->interface)) {
@@ -717,15 +756,7 @@ int phy_reset(struct phy_device *phydev)
}
#endif
- reg = phy_read(phydev, devad, MII_BMCR);
- if (reg < 0) {
- debug("PHY status read failed\n");
- return -1;
- }
-
- reg |= BMCR_RESET;
-
- if (phy_write(phydev, devad, MII_BMCR, reg) < 0) {
+ if (phy_write(phydev, devad, MII_BMCR, BMCR_RESET) < 0) {
debug("PHY reset failed\n");
return -1;
}
@@ -738,6 +769,7 @@ int phy_reset(struct phy_device *phydev)
* auto-clearing). This should happen within 0.5 seconds per the
* IEEE spec.
*/
+ reg = phy_read(phydev, devad, MII_BMCR);
while ((reg & BMCR_RESET) && timeout--) {
reg = phy_read(phydev, devad, MII_BMCR);
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index bfd9815abf..34986a29fc 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -69,11 +69,21 @@ static struct phy_driver lan8710_driver = {
.shutdown = &genphy_shutdown,
};
+static struct phy_driver lan8740_driver = {
+ .name = "SMSC LAN8740",
+ .uid = 0x0007c110,
+ .mask = 0xffff0,
+ .features = PHY_BASIC_FEATURES,
+ .config = &genphy_config_aneg,
+ .startup = &genphy_startup,
+ .shutdown = &genphy_shutdown,
+};
int phy_smsc_init(void)
{
phy_register(&lan8710_driver);
phy_register(&lan911x_driver);
phy_register(&lan8700_driver);
+ phy_register(&lan8740_driver);
return 0;
}
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/pic32_eth.c b/drivers/net/pic32_eth.c
new file mode 100644
index 0000000000..167af8bde5
--- /dev/null
+++ b/drivers/net/pic32_eth.c
@@ -0,0 +1,605 @@
+/*
+ * (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ */
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <net.h>
+#include <miiphy.h>
+#include <console.h>
+#include <wait_bit.h>
+#include <asm/gpio.h>
+
+#include "pic32_eth.h"
+
+#define MAX_RX_BUF_SIZE 1536
+#define MAX_RX_DESCR PKTBUFSRX
+#define MAX_TX_DESCR 2
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct pic32eth_dev {
+ struct eth_dma_desc rxd_ring[MAX_RX_DESCR];
+ struct eth_dma_desc txd_ring[MAX_TX_DESCR];
+ u32 rxd_idx; /* index of RX desc to read */
+ /* regs */
+ struct pic32_ectl_regs *ectl_regs;
+ struct pic32_emac_regs *emac_regs;
+ /* Phy */
+ struct phy_device *phydev;
+ phy_interface_t phyif;
+ u32 phy_addr;
+ struct gpio_desc rst_gpio;
+};
+
+void __weak board_netphy_reset(void *dev)
+{
+ struct pic32eth_dev *priv = dev;
+
+ if (!dm_gpio_is_valid(&priv->rst_gpio))
+ return;
+
+ /* phy reset */
+ dm_gpio_set_value(&priv->rst_gpio, 0);
+ udelay(300);
+ dm_gpio_set_value(&priv->rst_gpio, 1);
+ udelay(300);
+}
+
+/* Initialize mii(MDIO) interface, discover which PHY is
+ * attached to the device, and configure it properly.
+ */
+static int pic32_mii_init(struct pic32eth_dev *priv)
+{
+ struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
+ struct pic32_emac_regs *emac_p = priv->emac_regs;
+
+ /* board phy reset */
+ board_netphy_reset(priv);
+
+ /* disable RX, TX & all transactions */
+ writel(ETHCON_ON | ETHCON_TXRTS | ETHCON_RXEN, &ectl_p->con1.clr);
+
+ /* wait till busy */
+ wait_for_bit(__func__, &ectl_p->stat.raw, ETHSTAT_BUSY, false,
+ CONFIG_SYS_HZ, false);
+
+ /* turn controller ON to access PHY over MII */
+ writel(ETHCON_ON, &ectl_p->con1.set);
+
+ mdelay(10);
+
+ /* reset MAC */
+ writel(EMAC_SOFTRESET, &emac_p->cfg1.set); /* reset assert */
+ mdelay(10);
+ writel(EMAC_SOFTRESET, &emac_p->cfg1.clr); /* reset deassert */
+
+ /* initialize MDIO/MII */
+ if (priv->phyif == PHY_INTERFACE_MODE_RMII) {
+ writel(EMAC_RMII_RESET, &emac_p->supp.set);
+ mdelay(10);
+ writel(EMAC_RMII_RESET, &emac_p->supp.clr);
+ }
+
+ return pic32_mdio_init(PIC32_MDIO_NAME, (ulong)&emac_p->mii);
+}
+
+static int pic32_phy_init(struct pic32eth_dev *priv, struct udevice *dev)
+{
+ struct mii_dev *mii;
+
+ mii = miiphy_get_dev_by_name(PIC32_MDIO_NAME);
+
+ /* find & connect PHY */
+ priv->phydev = phy_connect(mii, priv->phy_addr,
+ dev, priv->phyif);
+ if (!priv->phydev) {
+ printf("%s: %s: Error, PHY connect\n", __FILE__, __func__);
+ return 0;
+ }
+
+ /* Wait for phy to complete reset */
+ mdelay(10);
+
+ /* configure supported modes */
+ priv->phydev->supported = SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_Autoneg;
+
+ priv->phydev->advertising = ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_Autoneg;
+
+ priv->phydev->autoneg = AUTONEG_ENABLE;
+
+ return 0;
+}
+
+/* Configure MAC based on negotiated speed and duplex
+ * reported by PHY.
+ */
+static int pic32_mac_adjust_link(struct pic32eth_dev *priv)
+{
+ struct phy_device *phydev = priv->phydev;
+ struct pic32_emac_regs *emac_p = priv->emac_regs;
+
+ if (!phydev->link) {
+ printf("%s: No link.\n", phydev->dev->name);
+ return -EINVAL;
+ }
+
+ if (phydev->duplex) {
+ writel(EMAC_FULLDUP, &emac_p->cfg2.set);
+ writel(FULLDUP_GAP_TIME, &emac_p->ipgt.raw);
+ } else {
+ writel(EMAC_FULLDUP, &emac_p->cfg2.clr);
+ writel(HALFDUP_GAP_TIME, &emac_p->ipgt.raw);
+ }
+
+ switch (phydev->speed) {
+ case SPEED_100:
+ writel(EMAC_RMII_SPD100, &emac_p->supp.set);
+ break;
+ case SPEED_10:
+ writel(EMAC_RMII_SPD100, &emac_p->supp.clr);
+ break;
+ default:
+ printf("%s: Speed was bad\n", phydev->dev->name);
+ return -EINVAL;
+ }
+
+ printf("pic32eth: PHY is %s with %dbase%s, %s\n",
+ phydev->drv->name, phydev->speed,
+ (phydev->port == PORT_TP) ? "T" : "X",
+ (phydev->duplex) ? "full" : "half");
+
+ return 0;
+}
+
+static void pic32_mac_init(struct pic32eth_dev *priv, u8 *macaddr)
+{
+ struct pic32_emac_regs *emac_p = priv->emac_regs;
+ u32 stat = 0, v;
+ u64 expire;
+
+ v = EMAC_TXPAUSE | EMAC_RXPAUSE | EMAC_RXENABLE;
+ writel(v, &emac_p->cfg1.raw);
+
+ v = EMAC_EXCESS | EMAC_AUTOPAD | EMAC_PADENABLE |
+ EMAC_CRCENABLE | EMAC_LENGTHCK | EMAC_FULLDUP;
+ writel(v, &emac_p->cfg2.raw);
+
+ /* recommended back-to-back inter-packet gap for 10 Mbps half duplex */
+ writel(HALFDUP_GAP_TIME, &emac_p->ipgt.raw);
+
+ /* recommended non-back-to-back interpacket gap is 0xc12 */
+ writel(0xc12, &emac_p->ipgr.raw);
+
+ /* recommended collision window retry limit is 0x370F */
+ writel(0x370f, &emac_p->clrt.raw);
+
+ /* set maximum frame length: allow VLAN tagged frame */
+ writel(0x600, &emac_p->maxf.raw);
+
+ /* set the mac address */
+ writel(macaddr[0] | (macaddr[1] << 8), &emac_p->sa2.raw);
+ writel(macaddr[2] | (macaddr[3] << 8), &emac_p->sa1.raw);
+ writel(macaddr[4] | (macaddr[5] << 8), &emac_p->sa0.raw);
+
+ /* default, enable 10 Mbps operation */
+ writel(EMAC_RMII_SPD100, &emac_p->supp.clr);
+
+ /* wait until link status UP or deadline elapsed */
+ expire = get_ticks() + get_tbclk() * 2;
+ for (; get_ticks() < expire;) {
+ stat = phy_read(priv->phydev, priv->phy_addr, MII_BMSR);
+ if (stat & BMSR_LSTATUS)
+ break;
+ }
+
+ if (!(stat & BMSR_LSTATUS))
+ printf("MAC: Link is DOWN!\n");
+
+ /* delay to stabilize before any tx/rx */
+ mdelay(10);
+}
+
+static void pic32_mac_reset(struct pic32eth_dev *priv)
+{
+ struct pic32_emac_regs *emac_p = priv->emac_regs;
+ struct mii_dev *mii;
+
+ /* Reset MAC */
+ writel(EMAC_SOFTRESET, &emac_p->cfg1.raw);
+ mdelay(10);
+
+ /* clear reset */
+ writel(0, &emac_p->cfg1.raw);
+
+ /* Reset MII */
+ mii = priv->phydev->bus;
+ if (mii && mii->reset)
+ mii->reset(mii);
+}
+
+/* initializes the MAC and PHY, then establishes a link */
+static void pic32_ctrl_reset(struct pic32eth_dev *priv)
+{
+ struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
+ u32 v;
+
+ /* disable RX, TX & any other transactions */
+ writel(ETHCON_ON | ETHCON_TXRTS | ETHCON_RXEN, &ectl_p->con1.clr);
+
+ /* wait till busy */
+ wait_for_bit(__func__, &ectl_p->stat.raw, ETHSTAT_BUSY, false,
+ CONFIG_SYS_HZ, false);
+ /* decrement received buffcnt to zero. */
+ while (readl(&ectl_p->stat.raw) & ETHSTAT_BUFCNT)
+ writel(ETHCON_BUFCDEC, &ectl_p->con1.set);
+
+ /* clear any existing interrupt event */
+ writel(0xffffffff, &ectl_p->irq.clr);
+
+ /* clear RX/TX start address */
+ writel(0xffffffff, &ectl_p->txst.clr);
+ writel(0xffffffff, &ectl_p->rxst.clr);
+
+ /* clear the receive filters */
+ writel(0x00ff, &ectl_p->rxfc.clr);
+
+ /* set the receive filters
+ * ETH_FILT_CRC_ERR_REJECT
+ * ETH_FILT_RUNT_REJECT
+ * ETH_FILT_UCAST_ACCEPT
+ * ETH_FILT_MCAST_ACCEPT
+ * ETH_FILT_BCAST_ACCEPT
+ */
+ v = ETHRXFC_BCEN | ETHRXFC_MCEN | ETHRXFC_UCEN |
+ ETHRXFC_RUNTEN | ETHRXFC_CRCOKEN;
+ writel(v, &ectl_p->rxfc.set);
+
+ /* turn controller ON to access PHY over MII */
+ writel(ETHCON_ON, &ectl_p->con1.set);
+}
+
+static void pic32_rx_desc_init(struct pic32eth_dev *priv)
+{
+ struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
+ struct eth_dma_desc *rxd;
+ u32 idx, bufsz;
+
+ priv->rxd_idx = 0;
+ for (idx = 0; idx < MAX_RX_DESCR; idx++) {
+ rxd = &priv->rxd_ring[idx];
+
+ /* hw owned */
+ rxd->hdr = EDH_NPV | EDH_EOWN | EDH_STICKY;
+
+ /* packet buffer address */
+ rxd->data_buff = virt_to_phys(net_rx_packets[idx]);
+
+ /* link to next desc */
+ rxd->next_ed = virt_to_phys(rxd + 1);
+
+ /* reset status */
+ rxd->stat1 = 0;
+ rxd->stat2 = 0;
+
+ /* decrement bufcnt */
+ writel(ETHCON_BUFCDEC, &ectl_p->con1.set);
+ }
+
+ /* link last descr to beginning of list */
+ rxd->next_ed = virt_to_phys(&priv->rxd_ring[0]);
+
+ /* flush rx ring */
+ flush_dcache_range((ulong)priv->rxd_ring,
+ (ulong)priv->rxd_ring + sizeof(priv->rxd_ring));
+
+ /* set rx desc-ring start address */
+ writel((ulong)virt_to_phys(&priv->rxd_ring[0]), &ectl_p->rxst.raw);
+
+ /* RX Buffer size */
+ bufsz = readl(&ectl_p->con2.raw);
+ bufsz &= ~(ETHCON_RXBUFSZ << ETHCON_RXBUFSZ_SHFT);
+ bufsz |= ((MAX_RX_BUF_SIZE / 16) << ETHCON_RXBUFSZ_SHFT);
+ writel(bufsz, &ectl_p->con2.raw);
+
+ /* enable the receiver in hardware which allows hardware
+ * to DMA received pkts to the descriptor pointer address.
+ */
+ writel(ETHCON_RXEN, &ectl_p->con1.set);
+}
+
+static int pic32_eth_start(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct pic32eth_dev *priv = dev_get_priv(dev);
+
+ /* controller */
+ pic32_ctrl_reset(priv);
+
+ /* reset MAC */
+ pic32_mac_reset(priv);
+
+ /* configure PHY */
+ phy_config(priv->phydev);
+
+ /* initialize MAC */
+ pic32_mac_init(priv, &pdata->enetaddr[0]);
+
+ /* init RX descriptor; TX descriptors are handled in xmit */
+ pic32_rx_desc_init(priv);
+
+ /* Start up & update link status of PHY */
+ phy_startup(priv->phydev);
+
+ /* adjust mac with phy link status */
+ return pic32_mac_adjust_link(priv);
+}
+
+static void pic32_eth_stop(struct udevice *dev)
+{
+ struct pic32eth_dev *priv = dev_get_priv(dev);
+ struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
+ struct pic32_emac_regs *emac_p = priv->emac_regs;
+
+ /* Reset the phy if the controller is enabled */
+ if (readl(&ectl_p->con1.raw) & ETHCON_ON)
+ phy_reset(priv->phydev);
+
+ /* Shut down the PHY */
+ phy_shutdown(priv->phydev);
+
+ /* Stop rx/tx */
+ writel(ETHCON_TXRTS | ETHCON_RXEN, &ectl_p->con1.clr);
+ mdelay(10);
+
+ /* reset MAC */
+ writel(EMAC_SOFTRESET, &emac_p->cfg1.raw);
+
+ /* clear reset */
+ writel(0, &emac_p->cfg1.raw);
+ mdelay(10);
+
+ /* disable controller */
+ writel(ETHCON_ON, &ectl_p->con1.clr);
+ mdelay(10);
+
+ /* wait until everything is down */
+ wait_for_bit(__func__, &ectl_p->stat.raw, ETHSTAT_BUSY, false,
+ 2 * CONFIG_SYS_HZ, false);
+
+ /* clear any existing interrupt event */
+ writel(0xffffffff, &ectl_p->irq.clr);
+}
+
+static int pic32_eth_send(struct udevice *dev, void *packet, int length)
+{
+ struct pic32eth_dev *priv = dev_get_priv(dev);
+ struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
+ struct eth_dma_desc *txd;
+ u64 deadline;
+
+ txd = &priv->txd_ring[0];
+
+ /* set proper flags & length in descriptor header */
+ txd->hdr = EDH_SOP | EDH_EOP | EDH_EOWN | EDH_BCOUNT(length);
+
+ /* pass buffer address to hardware */
+ txd->data_buff = virt_to_phys(packet);
+
+ debug("%s: %d / .hdr %x, .data_buff %x, .stat %x, .nexted %x\n",
+ __func__, __LINE__, txd->hdr, txd->data_buff, txd->stat2,
+ txd->next_ed);
+
+ /* cache flush (packet) */
+ flush_dcache_range((ulong)packet, (ulong)packet + length);
+
+ /* cache flush (txd) */
+ flush_dcache_range((ulong)txd, (ulong)txd + sizeof(*txd));
+
+ /* pass descriptor table base to h/w */
+ writel(virt_to_phys(txd), &ectl_p->txst.raw);
+
+ /* ready to send enabled, hardware can now send the packet(s) */
+ writel(ETHCON_TXRTS | ETHCON_ON, &ectl_p->con1.set);
+
+ /* wait until tx has completed and h/w has released ownership
+ * of the tx descriptor or timeout elapsed.
+ */
+ deadline = get_ticks() + get_tbclk();
+ for (;;) {
+ /* check timeout */
+ if (get_ticks() > deadline)
+ return -ETIMEDOUT;
+
+ if (ctrlc())
+ return -EINTR;
+
+ /* tx completed ? */
+ if (readl(&ectl_p->con1.raw) & ETHCON_TXRTS) {
+ udelay(1);
+ continue;
+ }
+
+ /* h/w not released ownership yet? */
+ invalidate_dcache_range((ulong)txd, (ulong)txd + sizeof(*txd));
+ if (!(txd->hdr & EDH_EOWN))
+ break;
+ }
+
+ return 0;
+}
+
+static int pic32_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct pic32eth_dev *priv = dev_get_priv(dev);
+ struct eth_dma_desc *rxd;
+ u32 idx = priv->rxd_idx;
+ u32 rx_count;
+
+ /* find the next ready to receive */
+ rxd = &priv->rxd_ring[idx];
+
+ invalidate_dcache_range((ulong)rxd, (ulong)rxd + sizeof(*rxd));
+ /* check if owned by MAC */
+ if (rxd->hdr & EDH_EOWN)
+ return -EAGAIN;
+
+ /* Sanity check on header: SOP and EOP */
+ if ((rxd->hdr & (EDH_SOP | EDH_EOP)) != (EDH_SOP | EDH_EOP)) {
+ printf("%s: %s, rx pkt across multiple descr\n",
+ __FILE__, __func__);
+ return 0;
+ }
+
+ debug("%s: %d /idx %i, hdr=%x, data_buff %x, stat %x, nexted %x\n",
+ __func__, __LINE__, idx, rxd->hdr,
+ rxd->data_buff, rxd->stat2, rxd->next_ed);
+
+ /* Sanity check on rx_stat: OK, CRC */
+ if (!RSV_RX_OK(rxd->stat2) || RSV_CRC_ERR(rxd->stat2)) {
+ debug("%s: %s: Error, rx problem detected\n",
+ __FILE__, __func__);
+ return 0;
+ }
+
+ /* invalidate dcache */
+ rx_count = RSV_RX_COUNT(rxd->stat2);
+ invalidate_dcache_range((ulong)net_rx_packets[idx],
+ (ulong)net_rx_packets[idx] + rx_count);
+
+ /* Pass the packet to protocol layer */
+ *packetp = net_rx_packets[idx];
+
+ /* increment number of bytes rcvd (ignore CRC) */
+ return rx_count - 4;
+}
+
+static int pic32_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ struct pic32eth_dev *priv = dev_get_priv(dev);
+ struct pic32_ectl_regs *ectl_p = priv->ectl_regs;
+ struct eth_dma_desc *rxd;
+ int idx = priv->rxd_idx;
+
+ /* sanity check */
+ if (packet != net_rx_packets[idx]) {
+ printf("rxd_id %d: packet is not matched,\n", idx);
+ return -EAGAIN;
+ }
+
+ /* prepare for receive */
+ rxd = &priv->rxd_ring[idx];
+ rxd->hdr = EDH_STICKY | EDH_NPV | EDH_EOWN;
+
+ flush_dcache_range((ulong)rxd, (ulong)rxd + sizeof(*rxd));
+
+ /* decrement rx pkt count */
+ writel(ETHCON_BUFCDEC, &ectl_p->con1.set);
+
+ debug("%s: %d / idx %i, hdr %x, data_buff %x, stat %x, nexted %x\n",
+ __func__, __LINE__, idx, rxd->hdr, rxd->data_buff,
+ rxd->stat2, rxd->next_ed);
+
+ priv->rxd_idx = (priv->rxd_idx + 1) % MAX_RX_DESCR;
+
+ return 0;
+}
+
+static const struct eth_ops pic32_eth_ops = {
+ .start = pic32_eth_start,
+ .send = pic32_eth_send,
+ .recv = pic32_eth_recv,
+ .free_pkt = pic32_eth_free_pkt,
+ .stop = pic32_eth_stop,
+};
+
+static int pic32_eth_probe(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct pic32eth_dev *priv = dev_get_priv(dev);
+ const char *phy_mode;
+ void __iomem *iobase;
+ fdt_addr_t addr;
+ fdt_size_t size;
+ int offset = 0;
+ int phy_addr = -1;
+
+ addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ iobase = ioremap(addr, size);
+ pdata->iobase = (phys_addr_t)addr;
+
+ /* get phy mode */
+ pdata->phy_interface = -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;
+ }
+
+ /* get phy addr */
+ offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+ "phy-handle");
+ if (offset > 0)
+ phy_addr = fdtdec_get_int(gd->fdt_blob, offset, "reg", -1);
+
+ /* phy reset gpio */
+ gpio_request_by_name_nodev(gd->fdt_blob, dev->of_offset,
+ "reset-gpios", 0,
+ &priv->rst_gpio, GPIOD_IS_OUT);
+
+ priv->phyif = pdata->phy_interface;
+ priv->phy_addr = phy_addr;
+ priv->ectl_regs = iobase;
+ priv->emac_regs = iobase + PIC32_EMAC1CFG1;
+
+ pic32_mii_init(priv);
+
+ return pic32_phy_init(priv, dev);
+}
+
+static int pic32_eth_remove(struct udevice *dev)
+{
+ struct pic32eth_dev *priv = dev_get_priv(dev);
+ struct mii_dev *bus;
+
+ dm_gpio_free(dev, &priv->rst_gpio);
+ phy_shutdown(priv->phydev);
+ free(priv->phydev);
+ bus = miiphy_get_dev_by_name(PIC32_MDIO_NAME);
+ mdio_unregister(bus);
+ mdio_free(bus);
+ iounmap(priv->ectl_regs);
+ return 0;
+}
+
+static const struct udevice_id pic32_eth_ids[] = {
+ { .compatible = "microchip,pic32mzda-eth" },
+ { }
+};
+
+U_BOOT_DRIVER(pic32_ethernet) = {
+ .name = "pic32_ethernet",
+ .id = UCLASS_ETH,
+ .of_match = pic32_eth_ids,
+ .probe = pic32_eth_probe,
+ .remove = pic32_eth_remove,
+ .ops = &pic32_eth_ops,
+ .priv_auto_alloc_size = sizeof(struct pic32eth_dev),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
diff --git a/drivers/net/pic32_eth.h b/drivers/net/pic32_eth.h
new file mode 100644
index 0000000000..be2a1872d8
--- /dev/null
+++ b/drivers/net/pic32_eth.h
@@ -0,0 +1,164 @@
+/*
+ * (c) 2015 Purna Chandra Mandal <purna.mandal@microchip.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ */
+
+#ifndef __MICROCHIP_PIC32_ETH_H_
+#define __MICROCHIP_PIC32_ETH_H_
+
+#include <mach/pic32.h>
+
+/* Ethernet */
+struct pic32_ectl_regs {
+ struct pic32_reg_atomic con1; /* 0x00 */
+ struct pic32_reg_atomic con2; /* 0x10 */
+ struct pic32_reg_atomic txst; /* 0x20 */
+ struct pic32_reg_atomic rxst; /* 0x30 */
+ struct pic32_reg_atomic ht0; /* 0x40 */
+ struct pic32_reg_atomic ht1; /* 0x50 */
+ struct pic32_reg_atomic pmm0; /* 0x60 */
+ struct pic32_reg_atomic pmm1; /* 0x70 */
+ struct pic32_reg_atomic pmcs; /* 0x80 */
+ struct pic32_reg_atomic pmo; /* 0x90 */
+ struct pic32_reg_atomic rxfc; /* 0xa0 */
+ struct pic32_reg_atomic rxwm; /* 0xb0 */
+ struct pic32_reg_atomic ien; /* 0xc0 */
+ struct pic32_reg_atomic irq; /* 0xd0 */
+ struct pic32_reg_atomic stat; /* 0xe0 */
+};
+
+struct pic32_mii_regs {
+ struct pic32_reg_atomic mcfg; /* 0x280 */
+ struct pic32_reg_atomic mcmd; /* 0x290 */
+ struct pic32_reg_atomic madr; /* 0x2a0 */
+ struct pic32_reg_atomic mwtd; /* 0x2b0 */
+ struct pic32_reg_atomic mrdd; /* 0x2c0 */
+ struct pic32_reg_atomic mind; /* 0x2d0 */
+};
+
+struct pic32_emac_regs {
+ struct pic32_reg_atomic cfg1; /* 0x200*/
+ struct pic32_reg_atomic cfg2; /* 0x210*/
+ struct pic32_reg_atomic ipgt; /* 0x220*/
+ struct pic32_reg_atomic ipgr; /* 0x230*/
+ struct pic32_reg_atomic clrt; /* 0x240*/
+ struct pic32_reg_atomic maxf; /* 0x250*/
+ struct pic32_reg_atomic supp; /* 0x260*/
+ struct pic32_reg_atomic test; /* 0x270*/
+ struct pic32_mii_regs mii; /* 0x280 - 0x2d0 */
+ struct pic32_reg_atomic res1; /* 0x2e0 */
+ struct pic32_reg_atomic res2; /* 0x2f0 */
+ struct pic32_reg_atomic sa0; /* 0x300 */
+ struct pic32_reg_atomic sa1; /* 0x310 */
+ struct pic32_reg_atomic sa2; /* 0x320 */
+};
+
+/* ETHCON1 Reg field */
+#define ETHCON_BUFCDEC BIT(0)
+#define ETHCON_RXEN BIT(8)
+#define ETHCON_TXRTS BIT(9)
+#define ETHCON_ON BIT(15)
+
+/* ETHCON2 Reg field */
+#define ETHCON_RXBUFSZ 0x7f
+#define ETHCON_RXBUFSZ_SHFT 0x4
+
+/* ETHSTAT Reg field */
+#define ETHSTAT_BUSY BIT(7)
+#define ETHSTAT_BUFCNT 0x00ff0000
+
+/* ETHRXFC Register fields */
+#define ETHRXFC_BCEN BIT(0)
+#define ETHRXFC_MCEN BIT(1)
+#define ETHRXFC_UCEN BIT(3)
+#define ETHRXFC_RUNTEN BIT(4)
+#define ETHRXFC_CRCOKEN BIT(5)
+
+/* EMAC1CFG1 register offset */
+#define PIC32_EMAC1CFG1 0x0200
+
+/* EMAC1CFG1 register fields */
+#define EMAC_RXENABLE BIT(0)
+#define EMAC_RXPAUSE BIT(2)
+#define EMAC_TXPAUSE BIT(3)
+#define EMAC_SOFTRESET BIT(15)
+
+/* EMAC1CFG2 register fields */
+#define EMAC_FULLDUP BIT(0)
+#define EMAC_LENGTHCK BIT(1)
+#define EMAC_CRCENABLE BIT(4)
+#define EMAC_PADENABLE BIT(5)
+#define EMAC_AUTOPAD BIT(7)
+#define EMAC_EXCESS BIT(14)
+
+/* EMAC1IPGT register magic */
+#define FULLDUP_GAP_TIME 0x15
+#define HALFDUP_GAP_TIME 0x12
+
+/* EMAC1SUPP register fields */
+#define EMAC_RMII_SPD100 BIT(8)
+#define EMAC_RMII_RESET BIT(11)
+
+/* MII Management Configuration Register */
+#define MIIMCFG_RSTMGMT BIT(15)
+#define MIIMCFG_CLKSEL_DIV40 0x0020 /* 100Mhz / 40 */
+
+/* MII Management Command Register */
+#define MIIMCMD_READ BIT(0)
+#define MIIMCMD_SCAN BIT(1)
+
+/* MII Management Address Register */
+#define MIIMADD_REGADDR 0x1f
+#define MIIMADD_REGADDR_SHIFT 0
+#define MIIMADD_PHYADDR_SHIFT 8
+
+/* MII Management Indicator Register */
+#define MIIMIND_BUSY BIT(0)
+#define MIIMIND_NOTVALID BIT(2)
+#define MIIMIND_LINKFAIL BIT(3)
+
+/* Packet Descriptor */
+/* Received Packet Status */
+#define _RSV1_PKT_CSUM 0xffff
+#define _RSV2_CRC_ERR BIT(20)
+#define _RSV2_LEN_ERR BIT(21)
+#define _RSV2_RX_OK BIT(23)
+#define _RSV2_RX_COUNT 0xffff
+
+#define RSV_RX_CSUM(__rsv1) ((__rsv1) & _RSV1_PKT_CSUM)
+#define RSV_RX_COUNT(__rsv2) ((__rsv2) & _RSV2_RX_COUNT)
+#define RSV_RX_OK(__rsv2) ((__rsv2) & _RSV2_RX_OK)
+#define RSV_CRC_ERR(__rsv2) ((__rsv2) & _RSV2_CRC_ERR)
+
+/* Ethernet Hardware Descriptor Header bits */
+#define EDH_EOWN BIT(7)
+#define EDH_NPV BIT(8)
+#define EDH_STICKY BIT(9)
+#define _EDH_BCOUNT 0x07ff0000
+#define EDH_EOP BIT(30)
+#define EDH_SOP BIT(31)
+#define EDH_BCOUNT_SHIFT 16
+#define EDH_BCOUNT(len) ((len) << EDH_BCOUNT_SHIFT)
+
+/* Ethernet Hardware Descriptors
+ * ref: PIC32 Family Reference Manual Table 35-7
+ * This structure represents the layout of the DMA
+ * memory shared between the CPU and the Ethernet
+ * controller.
+ */
+/* TX/RX DMA descriptor */
+struct eth_dma_desc {
+ u32 hdr; /* header */
+ u32 data_buff; /* data buffer address */
+ u32 stat1; /* transmit/receive packet status */
+ u32 stat2; /* transmit/receive packet status */
+ u32 next_ed; /* next descriptor */
+};
+
+#define PIC32_MDIO_NAME "PIC32_EMAC"
+
+int pic32_mdio_init(const char *name, ulong ioaddr);
+
+#endif /* __MICROCHIP_PIC32_ETH_H_*/
diff --git a/drivers/net/pic32_mdio.c b/drivers/net/pic32_mdio.c
new file mode 100644
index 0000000000..578fc96905
--- /dev/null
+++ b/drivers/net/pic32_mdio.c
@@ -0,0 +1,121 @@
+/*
+ * pic32_mdio.c: PIC32 MDIO/MII driver, part of pic32_eth.c.
+ *
+ * Copyright 2015 Microchip Inc.
+ * Purna Chandra Mandal <purna.mandal@microchip.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <phy.h>
+#include <miiphy.h>
+#include <errno.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+#include "pic32_eth.h"
+
+static int pic32_mdio_write(struct mii_dev *bus,
+ int addr, int dev_addr,
+ int reg, u16 value)
+{
+ u32 v;
+ struct pic32_mii_regs *mii_regs = bus->priv;
+
+ /* Wait for the previous operation to finish */
+ wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
+ false, CONFIG_SYS_HZ, true);
+
+ /* Put phyaddr and regaddr into MIIMADD */
+ v = (addr << MIIMADD_PHYADDR_SHIFT) | (reg & MIIMADD_REGADDR);
+ writel(v, &mii_regs->madr.raw);
+
+ /* Initiate a write command */
+ writel(value, &mii_regs->mwtd.raw);
+
+ /* Wait 30 clock cycles for busy flag to be set */
+ udelay(12);
+
+ /* Wait for write to complete */
+ wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
+ false, CONFIG_SYS_HZ, true);
+
+ return 0;
+}
+
+static int pic32_mdio_read(struct mii_dev *bus, int addr, int devaddr, int reg)
+{
+ u32 v;
+ struct pic32_mii_regs *mii_regs = bus->priv;
+
+ /* Wait for the previous operation to finish */
+ wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
+ false, CONFIG_SYS_HZ, true);
+
+ /* Put phyaddr and regaddr into MIIMADD */
+ v = (addr << MIIMADD_PHYADDR_SHIFT) | (reg & MIIMADD_REGADDR);
+ writel(v, &mii_regs->madr.raw);
+
+ /* Initiate a read command */
+ writel(MIIMCMD_READ, &mii_regs->mcmd.raw);
+
+ /* Wait 30 clock cycles for busy flag to be set */
+ udelay(12);
+
+ /* Wait for read to complete */
+ wait_for_bit(__func__, &mii_regs->mind.raw,
+ MIIMIND_NOTVALID | MIIMIND_BUSY,
+ false, CONFIG_SYS_HZ, false);
+
+ /* Clear the command register */
+ writel(0, &mii_regs->mcmd.raw);
+
+ /* Grab the value read from the PHY */
+ v = readl(&mii_regs->mrdd.raw);
+ return v;
+}
+
+static int pic32_mdio_reset(struct mii_dev *bus)
+{
+ struct pic32_mii_regs *mii_regs = bus->priv;
+
+ /* Reset MII (due to new addresses) */
+ writel(MIIMCFG_RSTMGMT, &mii_regs->mcfg.raw);
+
+ /* Wait for the operation to finish */
+ wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
+ false, CONFIG_SYS_HZ, true);
+
+ /* Clear reset bit */
+ writel(0, &mii_regs->mcfg);
+
+ /* Wait for the operation to finish */
+ wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
+ false, CONFIG_SYS_HZ, true);
+
+ /* Set the MII Management Clock (MDC) - no faster than 2.5 MHz */
+ writel(MIIMCFG_CLKSEL_DIV40, &mii_regs->mcfg.raw);
+
+ /* Wait for the operation to finish */
+ wait_for_bit(__func__, &mii_regs->mind.raw, MIIMIND_BUSY,
+ false, CONFIG_SYS_HZ, true);
+ return 0;
+}
+
+int pic32_mdio_init(const char *name, ulong ioaddr)
+{
+ struct mii_dev *bus;
+
+ bus = mdio_alloc();
+ if (!bus) {
+ printf("Failed to allocate PIC32-MDIO bus\n");
+ return -ENOMEM;
+ }
+
+ bus->read = pic32_mdio_read;
+ bus->write = pic32_mdio_write;
+ bus->reset = pic32_mdio_reset;
+ strncpy(bus->name, name, sizeof(bus->name));
+ bus->priv = (void *)ioaddr;
+
+ return mdio_register(bus);
+}
diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c
index 9b09caf8c8..be0f38288f 100644
--- a/drivers/net/tsec.c
+++ b/drivers/net/tsec.c
@@ -1,18 +1,16 @@
/*
* Freescale Three Speed Ethernet Controller driver
*
- * This software may be used and distributed according to the
- * terms of the GNU Public License, Version 2, incorporated
- * herein by reference.
- *
* Copyright 2004-2011, 2013 Freescale Semiconductor, Inc.
* (C) Copyright 2003, Motorola, Inc.
* author Andy Fleming
*
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <common.h>
+#include <dm.h>
#include <malloc.h>
#include <net.h>
#include <command.h>
@@ -24,21 +22,7 @@
DECLARE_GLOBAL_DATA_PTR;
-#define TX_BUF_CNT 2
-
-static uint rx_idx; /* index of the current RX buffer */
-static uint tx_idx; /* index of the current TX buffer */
-
-#ifdef __GNUC__
-static struct txbd8 __iomem txbd[TX_BUF_CNT] __aligned(8);
-static struct rxbd8 __iomem rxbd[PKTBUFSRX] __aligned(8);
-
-#else
-#error "rtx must be 64-bit aligned"
-#endif
-
-static int tsec_send(struct eth_device *dev, void *packet, int length);
-
+#ifndef CONFIG_DM_ETH
/* Default initializations for TSEC controllers. */
static struct tsec_info_struct tsec_info[] = {
@@ -64,6 +48,7 @@ static struct tsec_info_struct tsec_info[] = {
STD_TSEC_INFO(4), /* TSEC4 */
#endif
};
+#endif /* CONFIG_DM_ETH */
#define TBIANA_SETTINGS ( \
TBIANA_ASYMMETRIC_PAUSE \
@@ -84,8 +69,10 @@ static struct tsec_info_struct tsec_info[] = {
/* Configure the TBI for SGMII operation */
static void tsec_configure_serdes(struct tsec_private *priv)
{
- /* Access TBI PHY registers at given TSEC register offset as opposed
- * to the register offset used for external PHY accesses */
+ /*
+ * Access TBI PHY registers at given TSEC register offset as opposed
+ * to the register offset used for external PHY accesses
+ */
tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
0, TBI_ANA, TBIANA_SETTINGS);
tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa),
@@ -100,7 +87,8 @@ static void tsec_configure_serdes(struct tsec_private *priv)
/* Set the appropriate hash bit for the given addr */
-/* The algorithm works like so:
+/*
+ * The algorithm works like so:
* 1) Take the Destination Address (ie the multicast address), and
* do a CRC on it (little endian), and reverse the bits of the
* result.
@@ -111,9 +99,13 @@ static void tsec_configure_serdes(struct tsec_private *priv)
* hash index which gaddr register to use, and the 5 other bits
* indicate which bit (assuming an IBM numbering scheme, which
* for PowerPC (tm) is usually the case) in the register holds
- * the entry. */
-static int
-tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
+ * the entry.
+ */
+#ifndef CONFIG_DM_ETH
+static int tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
+#else
+static int tsec_mcast_addr(struct udevice *dev, const u8 *mcast_mac, int set)
+#endif
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
@@ -135,7 +127,8 @@ tsec_mcast_addr(struct eth_device *dev, const u8 *mcast_mac, u8 set)
}
#endif /* Multicast TFTP ? */
-/* Initialized required registers to appropriate values, zeroing
+/*
+ * Initialized required registers to appropriate values, zeroing
* those we don't care about (unless zero is bad, in which case,
* choose a more appropriate value)
*/
@@ -181,7 +174,8 @@ static void init_registers(struct tsec __iomem *regs)
}
-/* Configure maccfg2 based on negotiated speed and duplex
+/*
+ * Configure maccfg2 based on negotiated speed and duplex
* reported by PHY handling code
*/
static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
@@ -212,7 +206,8 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
case 10:
maccfg2 |= MACCFG2_MII;
- /* Set R100 bit in all modes although
+ /*
+ * Set R100 bit in all modes although
* it is only used in RGMII mode
*/
if (phydev->speed == 100)
@@ -231,15 +226,174 @@ static void adjust_link(struct tsec_private *priv, struct phy_device *phydev)
(phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
}
+/*
+ * This returns the status bits of the device. The return value
+ * is never checked, and this is what the 8260 driver did, so we
+ * do the same. Presumably, this would be zero if there were no
+ * errors
+ */
+#ifndef CONFIG_DM_ETH
+static int tsec_send(struct eth_device *dev, void *packet, int length)
+#else
+static int tsec_send(struct udevice *dev, void *packet, int length)
+#endif
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+ uint16_t status;
+ int result = 0;
+ int i;
+
+ /* Find an empty buffer descriptor */
+ for (i = 0;
+ in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
+ i++) {
+ if (i >= TOUT_LOOP) {
+ debug("%s: tsec: tx buffers full\n", dev->name);
+ return result;
+ }
+ }
+
+ out_be32(&priv->txbd[priv->tx_idx].bufptr, (u32)packet);
+ out_be16(&priv->txbd[priv->tx_idx].length, length);
+ status = in_be16(&priv->txbd[priv->tx_idx].status);
+ out_be16(&priv->txbd[priv->tx_idx].status, status |
+ (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
+
+ /* Tell the DMA to go */
+ out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
+
+ /* Wait for buffer to be transmitted */
+ for (i = 0;
+ in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_READY;
+ i++) {
+ if (i >= TOUT_LOOP) {
+ debug("%s: tsec: tx error\n", dev->name);
+ return result;
+ }
+ }
+
+ priv->tx_idx = (priv->tx_idx + 1) % TX_BUF_CNT;
+ result = in_be16(&priv->txbd[priv->tx_idx].status) & TXBD_STATS;
+
+ return result;
+}
+
+#ifndef CONFIG_DM_ETH
+static int tsec_recv(struct eth_device *dev)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+
+ while (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
+ int length = in_be16(&priv->rxbd[priv->rx_idx].length);
+ uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
+ uchar *packet = net_rx_packets[priv->rx_idx];
+
+ /* Send the packet up if there were no errors */
+ if (!(status & RXBD_STATS))
+ net_process_received_packet(packet, length - 4);
+ else
+ printf("Got error %x\n", (status & RXBD_STATS));
+
+ out_be16(&priv->rxbd[priv->rx_idx].length, 0);
+
+ status = RXBD_EMPTY;
+ /* Set the wrap bit if this is the last element in the list */
+ if ((priv->rx_idx + 1) == PKTBUFSRX)
+ status |= RXBD_WRAP;
+ out_be16(&priv->rxbd[priv->rx_idx].status, status);
+
+ priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
+ }
+
+ if (in_be32(&regs->ievent) & IEVENT_BSY) {
+ out_be32(&regs->ievent, IEVENT_BSY);
+ out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+ }
+
+ return -1;
+}
+#else
+static int tsec_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+ int ret = -1;
+
+ if (!(in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY)) {
+ int length = in_be16(&priv->rxbd[priv->rx_idx].length);
+ uint16_t status = in_be16(&priv->rxbd[priv->rx_idx].status);
+ uint32_t buf;
+
+ /* Send the packet up if there were no errors */
+ if (!(status & RXBD_STATS)) {
+ buf = in_be32(&priv->rxbd[priv->rx_idx].bufptr);
+ *packetp = (uchar *)buf;
+ ret = length - 4;
+ } else {
+ printf("Got error %x\n", (status & RXBD_STATS));
+ }
+ }
+
+ if (in_be32(&regs->ievent) & IEVENT_BSY) {
+ out_be32(&regs->ievent, IEVENT_BSY);
+ out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
+ }
+
+ return ret;
+}
+
+static int tsec_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ uint16_t status;
+
+ out_be16(&priv->rxbd[priv->rx_idx].length, 0);
+
+ status = RXBD_EMPTY;
+ /* Set the wrap bit if this is the last element in the list */
+ if ((priv->rx_idx + 1) == PKTBUFSRX)
+ status |= RXBD_WRAP;
+ out_be16(&priv->rxbd[priv->rx_idx].status, status);
+
+ priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
+
+ return 0;
+}
+#endif
+
+/* Stop the interface */
+#ifndef CONFIG_DM_ETH
+static void tsec_halt(struct eth_device *dev)
+#else
+static void tsec_halt(struct udevice *dev)
+#endif
+{
+ struct tsec_private *priv = (struct tsec_private *)dev->priv;
+ struct tsec __iomem *regs = priv->regs;
+
+ clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+ setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
+
+ while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
+ != (IEVENT_GRSC | IEVENT_GTSC))
+ ;
+
+ clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
+
+ /* Shut down the PHY, as needed */
+ phy_shutdown(priv->phydev);
+}
+
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
/*
* When MACCFG1[Rx_EN] is enabled during system boot as part
* of the eTSEC port initialization sequence,
* the eTSEC Rx logic may not be properly initialized.
*/
-void redundant_init(struct eth_device *dev)
+void redundant_init(struct tsec_private *priv)
{
- struct tsec_private *priv = dev->priv;
struct tsec __iomem *regs = priv->regs;
uint t, count = 0;
int fail = 1;
@@ -274,25 +428,27 @@ void redundant_init(struct eth_device *dev)
do {
uint16_t status;
- tsec_send(dev, (void *)pkt, sizeof(pkt));
+ tsec_send(priv->dev, (void *)pkt, sizeof(pkt));
/* Wait for buffer to be received */
- for (t = 0; in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY; t++) {
+ for (t = 0;
+ in_be16(&priv->rxbd[priv->rx_idx].status) & RXBD_EMPTY;
+ t++) {
if (t >= 10 * TOUT_LOOP) {
- printf("%s: tsec: rx error\n", dev->name);
+ printf("%s: tsec: rx error\n", priv->dev->name);
break;
}
}
- if (!memcmp(pkt, (void *)net_rx_packets[rx_idx], sizeof(pkt)))
+ if (!memcmp(pkt, net_rx_packets[priv->rx_idx], sizeof(pkt)))
fail = 0;
- out_be16(&rxbd[rx_idx].length, 0);
+ out_be16(&priv->rxbd[priv->rx_idx].length, 0);
status = RXBD_EMPTY;
- if ((rx_idx + 1) == PKTBUFSRX)
+ if ((priv->rx_idx + 1) == PKTBUFSRX)
status |= RXBD_WRAP;
- out_be16(&rxbd[rx_idx].status, status);
- rx_idx = (rx_idx + 1) % PKTBUFSRX;
+ out_be16(&priv->rxbd[priv->rx_idx].status, status);
+ priv->rx_idx = (priv->rx_idx + 1) % PKTBUFSRX;
if (in_be32(&regs->ievent) & IEVENT_BSY) {
out_be32(&regs->ievent, IEVENT_BSY);
@@ -315,49 +471,49 @@ void redundant_init(struct eth_device *dev)
}
#endif
-/* Set up the buffers and their descriptors, and bring up the
+/*
+ * Set up the buffers and their descriptors, and bring up the
* interface
*/
-static void startup_tsec(struct eth_device *dev)
+static void startup_tsec(struct tsec_private *priv)
{
- struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct tsec __iomem *regs = priv->regs;
uint16_t status;
int i;
/* reset the indices to zero */
- rx_idx = 0;
- tx_idx = 0;
+ priv->rx_idx = 0;
+ priv->tx_idx = 0;
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
uint svr;
#endif
/* Point to the buffer descriptors */
- out_be32(&regs->tbase, (u32)&txbd[0]);
- out_be32(&regs->rbase, (u32)&rxbd[0]);
+ out_be32(&regs->tbase, (u32)&priv->txbd[0]);
+ out_be32(&regs->rbase, (u32)&priv->rxbd[0]);
/* Initialize the Rx Buffer descriptors */
for (i = 0; i < PKTBUFSRX; i++) {
- out_be16(&rxbd[i].status, RXBD_EMPTY);
- out_be16(&rxbd[i].length, 0);
- out_be32(&rxbd[i].bufptr, (u32)net_rx_packets[i]);
+ out_be16(&priv->rxbd[i].status, RXBD_EMPTY);
+ out_be16(&priv->rxbd[i].length, 0);
+ out_be32(&priv->rxbd[i].bufptr, (u32)net_rx_packets[i]);
}
- status = in_be16(&rxbd[PKTBUFSRX - 1].status);
- out_be16(&rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
+ status = in_be16(&priv->rxbd[PKTBUFSRX - 1].status);
+ out_be16(&priv->rxbd[PKTBUFSRX - 1].status, status | RXBD_WRAP);
/* Initialize the TX Buffer Descriptors */
for (i = 0; i < TX_BUF_CNT; i++) {
- out_be16(&txbd[i].status, 0);
- out_be16(&txbd[i].length, 0);
- out_be32(&txbd[i].bufptr, 0);
+ out_be16(&priv->txbd[i].status, 0);
+ out_be16(&priv->txbd[i].length, 0);
+ out_be32(&priv->txbd[i].bufptr, 0);
}
- status = in_be16(&txbd[TX_BUF_CNT - 1].status);
- out_be16(&txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
+ status = in_be16(&priv->txbd[TX_BUF_CNT - 1].status);
+ out_be16(&priv->txbd[TX_BUF_CNT - 1].status, status | TXBD_WRAP);
#ifdef CONFIG_SYS_FSL_ERRATUM_NMG_ETSEC129
svr = get_svr();
if ((SVR_MAJ(svr) == 1) || IS_SVR_REV(svr, 2, 0))
- redundant_init(dev);
+ redundant_init(priv);
#endif
/* Enable Transmit and Receive */
setbits_be32(&regs->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN);
@@ -369,113 +525,22 @@ static void startup_tsec(struct eth_device *dev)
clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
}
-/* This returns the status bits of the device. The return value
- * is never checked, and this is what the 8260 driver did, so we
- * do the same. Presumably, this would be zero if there were no
- * errors
- */
-static int tsec_send(struct eth_device *dev, void *packet, int length)
-{
- struct tsec_private *priv = (struct tsec_private *)dev->priv;
- struct tsec __iomem *regs = priv->regs;
- uint16_t status;
- int result = 0;
- int i;
-
- /* Find an empty buffer descriptor */
- for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
- if (i >= TOUT_LOOP) {
- debug("%s: tsec: tx buffers full\n", dev->name);
- return result;
- }
- }
-
- out_be32(&txbd[tx_idx].bufptr, (u32)packet);
- out_be16(&txbd[tx_idx].length, length);
- status = in_be16(&txbd[tx_idx].status);
- out_be16(&txbd[tx_idx].status, status |
- (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT));
-
- /* Tell the DMA to go */
- out_be32(&regs->tstat, TSTAT_CLEAR_THALT);
-
- /* Wait for buffer to be transmitted */
- for (i = 0; in_be16(&txbd[tx_idx].status) & TXBD_READY; i++) {
- if (i >= TOUT_LOOP) {
- debug("%s: tsec: tx error\n", dev->name);
- return result;
- }
- }
-
- tx_idx = (tx_idx + 1) % TX_BUF_CNT;
- result = in_be16(&txbd[tx_idx].status) & TXBD_STATS;
-
- return result;
-}
-
-static int tsec_recv(struct eth_device *dev)
-{
- struct tsec_private *priv = (struct tsec_private *)dev->priv;
- struct tsec __iomem *regs = priv->regs;
-
- while (!(in_be16(&rxbd[rx_idx].status) & RXBD_EMPTY)) {
- int length = in_be16(&rxbd[rx_idx].length);
- uint16_t status = in_be16(&rxbd[rx_idx].status);
-
- /* Send the packet up if there were no errors */
- if (!(status & RXBD_STATS))
- net_process_received_packet(net_rx_packets[rx_idx],
- length - 4);
- else
- printf("Got error %x\n", (status & RXBD_STATS));
-
- out_be16(&rxbd[rx_idx].length, 0);
-
- status = RXBD_EMPTY;
- /* Set the wrap bit if this is the last element in the list */
- if ((rx_idx + 1) == PKTBUFSRX)
- status |= RXBD_WRAP;
- out_be16(&rxbd[rx_idx].status, status);
-
- rx_idx = (rx_idx + 1) % PKTBUFSRX;
- }
-
- if (in_be32(&regs->ievent) & IEVENT_BSY) {
- out_be32(&regs->ievent, IEVENT_BSY);
- out_be32(&regs->rstat, RSTAT_CLEAR_RHALT);
- }
-
- return -1;
-
-}
-
-/* Stop the interface */
-static void tsec_halt(struct eth_device *dev)
-{
- struct tsec_private *priv = (struct tsec_private *)dev->priv;
- struct tsec __iomem *regs = priv->regs;
-
- clrbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
- setbits_be32(&regs->dmactrl, DMACTRL_GRS | DMACTRL_GTS);
-
- while ((in_be32(&regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))
- != (IEVENT_GRSC | IEVENT_GTSC))
- ;
-
- clrbits_be32(&regs->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN);
-
- /* Shut down the PHY, as needed */
- phy_shutdown(priv->phydev);
-}
-
-/* Initializes data structures and registers for the controller,
- * and brings the interface up. Returns the link status, meaning
+/*
+ * Initializes data structures and registers for the controller,
+ * and brings the interface up. Returns the link status, meaning
* that it returns success if the link is up, failure otherwise.
- * This allows u-boot to find the first active controller.
+ * This allows U-Boot to find the first active controller.
*/
+#ifndef CONFIG_DM_ETH
static int tsec_init(struct eth_device *dev, bd_t * bd)
+#else
+static int tsec_init(struct udevice *dev)
+#endif
{
struct tsec_private *priv = (struct tsec_private *)dev->priv;
+#ifdef CONFIG_DM_ETH
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+#endif
struct tsec __iomem *regs = priv->regs;
u32 tempval;
int ret;
@@ -489,17 +554,27 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
/* Init ECNTRL */
out_be32(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
- /* Copy the station address into the address registers.
+ /*
+ * Copy the station address into the address registers.
* For a station address of 0x12345678ABCD in transmission
* order (BE), MACnADDR1 is set to 0xCDAB7856 and
* MACnADDR2 is set to 0x34120000.
*/
+#ifndef CONFIG_DM_ETH
tempval = (dev->enetaddr[5] << 24) | (dev->enetaddr[4] << 16) |
(dev->enetaddr[3] << 8) | dev->enetaddr[2];
+#else
+ tempval = (pdata->enetaddr[5] << 24) | (pdata->enetaddr[4] << 16) |
+ (pdata->enetaddr[3] << 8) | pdata->enetaddr[2];
+#endif
out_be32(&regs->macstnaddr1, tempval);
+#ifndef CONFIG_DM_ETH
tempval = (dev->enetaddr[1] << 24) | (dev->enetaddr[0] << 16);
+#else
+ tempval = (pdata->enetaddr[1] << 24) | (pdata->enetaddr[0] << 16);
+#endif
out_be32(&regs->macstnaddr2, tempval);
@@ -507,7 +582,7 @@ static int tsec_init(struct eth_device *dev, bd_t * bd)
init_registers(regs);
/* Ready the device for tx/rx */
- startup_tsec(dev);
+ startup_tsec(priv);
/* Start up the PHY */
ret = phy_startup(priv->phydev);
@@ -551,8 +626,8 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
* be set by the platform code.
*/
if ((interface == PHY_INTERFACE_MODE_RGMII_ID) ||
- (interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
- (interface == PHY_INTERFACE_MODE_RGMII_RXID))
+ (interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
+ (interface == PHY_INTERFACE_MODE_RGMII_RXID))
return interface;
return PHY_INTERFACE_MODE_RGMII;
@@ -565,14 +640,13 @@ static phy_interface_t tsec_get_interface(struct tsec_private *priv)
return PHY_INTERFACE_MODE_MII;
}
-
-/* Discover which PHY is attached to the device, and configure it
+/*
+ * Discover which PHY is attached to the device, and configure it
* properly. If the PHY is not recognized, then return 0
* (failure). Otherwise, return 1
*/
-static int init_phy(struct eth_device *dev)
+static int init_phy(struct tsec_private *priv)
{
- struct tsec_private *priv = (struct tsec_private *)dev->priv;
struct phy_device *phydev;
struct tsec __iomem *regs = priv->regs;
u32 supported = (SUPPORTED_10baseT_Half |
@@ -584,14 +658,15 @@ static int init_phy(struct eth_device *dev)
supported |= SUPPORTED_1000baseT_Full;
/* Assign a Physical address to the TBI */
- out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
+ out_be32(&regs->tbipa, priv->tbiaddr);
priv->interface = tsec_get_interface(priv);
if (priv->interface == PHY_INTERFACE_MODE_SGMII)
tsec_configure_serdes(priv);
- phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
+ phydev = phy_connect(priv->bus, priv->phyaddr, priv->dev,
+ priv->interface);
if (!phydev)
return 0;
@@ -605,7 +680,9 @@ static int init_phy(struct eth_device *dev)
return 1;
}
-/* Initialize device structure. Returns success if PHY
+#ifndef CONFIG_DM_ETH
+/*
+ * Initialize device structure. Returns success if PHY
* initialization succeeded (i.e. if it recognizes the PHY)
*/
static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
@@ -630,11 +707,13 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
priv->phyregs_sgmii = tsec_info->miiregs_sgmii;
priv->phyaddr = tsec_info->phyaddr;
+ priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
priv->flags = tsec_info->flags;
strcpy(dev->name, tsec_info->devname);
priv->interface = tsec_info->interface;
priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname);
+ priv->dev = dev;
dev->iobase = 0;
dev->priv = priv;
dev->init = tsec_init;
@@ -645,7 +724,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
dev->mcast = tsec_mcast_addr;
#endif
- /* Tell u-boot to get the addr from the env */
+ /* Tell U-Boot to get the addr from the env */
for (i = 0; i < 6; i++)
dev->enetaddr[i] = 0;
@@ -657,7 +736,7 @@ static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info)
clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
/* Try to initialize PHY here, and return */
- return init_phy(dev);
+ return init_phy(priv);
}
/*
@@ -690,3 +769,118 @@ int tsec_standard_init(bd_t *bis)
return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info));
}
+#else /* CONFIG_DM_ETH */
+int tsec_probe(struct udevice *dev)
+{
+ struct tsec_private *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct fsl_pq_mdio_info mdio_info;
+ int offset = 0;
+ int reg;
+ const char *phy_mode;
+ int ret;
+
+ pdata->iobase = (phys_addr_t)dev_get_addr(dev);
+ priv->regs = (struct tsec *)pdata->iobase;
+
+ offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+ "phy-handle");
+ if (offset > 0) {
+ reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
+ priv->phyaddr = reg;
+ } else {
+ debug("phy-handle does not exist under tsec %s\n", dev->name);
+ return -ENOENT;
+ }
+
+ offset = fdt_parent_offset(gd->fdt_blob, offset);
+ if (offset > 0) {
+ reg = fdtdec_get_int(gd->fdt_blob, offset, "reg", 0);
+ priv->phyregs_sgmii = (struct tsec_mii_mng *)(reg + 0x520);
+ } else {
+ debug("No parent node for PHY?\n");
+ return -ENOENT;
+ }
+
+ offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset,
+ "tbi-handle");
+ if (offset > 0) {
+ reg = fdtdec_get_int(gd->fdt_blob, offset, "reg",
+ CONFIG_SYS_TBIPA_VALUE);
+ priv->tbiaddr = reg;
+ } else {
+ priv->tbiaddr = CONFIG_SYS_TBIPA_VALUE;
+ }
+
+ phy_mode = fdt_getprop(gd->fdt_blob, dev->of_offset,
+ "phy-connection-type", NULL);
+ if (phy_mode)
+ pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+ if (pdata->phy_interface == -1) {
+ debug("Invalid PHY interface '%s'\n", phy_mode);
+ return -EINVAL;
+ }
+ priv->interface = pdata->phy_interface;
+
+ /* Initialize flags */
+ priv->flags = TSEC_GIGABIT;
+ if (priv->interface == PHY_INTERFACE_MODE_SGMII)
+ priv->flags |= TSEC_SGMII;
+
+ mdio_info.regs = priv->phyregs_sgmii;
+ mdio_info.name = (char *)dev->name;
+ ret = fsl_pq_mdio_init(NULL, &mdio_info);
+ if (ret)
+ return ret;
+
+ /* Reset the MAC */
+ setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
+ udelay(2); /* Soft Reset must be asserted for 3 TX clocks */
+ clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET);
+
+ priv->dev = dev;
+ priv->bus = miiphy_get_dev_by_name(dev->name);
+
+ /* Try to initialize PHY here, and return */
+ return !init_phy(priv);
+}
+
+int tsec_remove(struct udevice *dev)
+{
+ struct tsec_private *priv = dev->priv;
+
+ free(priv->phydev);
+ mdio_unregister(priv->bus);
+ mdio_free(priv->bus);
+
+ return 0;
+}
+
+static const struct eth_ops tsec_ops = {
+ .start = tsec_init,
+ .send = tsec_send,
+ .recv = tsec_recv,
+ .free_pkt = tsec_free_pkt,
+ .stop = tsec_halt,
+#ifdef CONFIG_MCAST_TFTP
+ .mcast = tsec_mcast_addr,
+#endif
+};
+
+static const struct udevice_id tsec_ids[] = {
+ { .compatible = "fsl,tsec" },
+ { }
+};
+
+U_BOOT_DRIVER(eth_tsec) = {
+ .name = "tsec",
+ .id = UCLASS_ETH,
+ .of_match = tsec_ids,
+ .probe = tsec_probe,
+ .remove = tsec_remove,
+ .ops = &tsec_ops,
+ .priv_auto_alloc_size = sizeof(struct tsec_private),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
+#endif /* CONFIG_DM_ETH */
diff --git a/drivers/net/vsc9953.c b/drivers/net/vsc9953.c
index 7595db1acb..44afe14051 100644
--- a/drivers/net/vsc9953.c
+++ b/drivers/net/vsc9953.c
@@ -469,6 +469,47 @@ static void vsc9953_vlan_ingr_fltr_learn_drop(int enable)
clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK);
}
+enum aggr_code_mode {
+ AGGR_CODE_RAND = 0,
+ AGGR_CODE_ALL, /* S/D MAC, IPv4 S/D IP, IPv6 Flow Label, S/D PORT */
+};
+
+/* Set aggregation code generation mode */
+static int vsc9953_aggr_code_set(enum aggr_code_mode ac)
+{
+ int rc;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ switch (ac) {
+ case AGGR_CODE_RAND:
+ clrsetbits_le32(&l2ana_reg->common.aggr_cfg,
+ VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
+ VSC9953_AC_IP6_LBL_ENA |
+ VSC9953_AC_IP6_TCPUDP_ENA |
+ VSC9953_AC_IP4_SIPDIP_ENA |
+ VSC9953_AC_IP4_TCPUDP_ENA, VSC9953_AC_RND_ENA);
+ rc = 0;
+ break;
+ case AGGR_CODE_ALL:
+ clrsetbits_le32(&l2ana_reg->common.aggr_cfg, VSC9953_AC_RND_ENA,
+ VSC9953_AC_DMAC_ENA | VSC9953_AC_SMAC_ENA |
+ VSC9953_AC_IP6_LBL_ENA |
+ VSC9953_AC_IP6_TCPUDP_ENA |
+ VSC9953_AC_IP4_SIPDIP_ENA |
+ VSC9953_AC_IP4_TCPUDP_ENA);
+ rc = 0;
+ break;
+ default:
+ /* unknown mode for aggregation code */
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
/* Egress untag modes of a VSC9953 port */
enum egress_untag_mode {
EGRESS_UNTAG_ALL = 0,
@@ -593,6 +634,25 @@ static void vsc9953_port_all_vlan_egress_untagged_set(
vsc9953_port_vlan_egr_untag_set(i, mode);
}
+static int vsc9953_autoage_time_set(int age_period)
+{
+ u32 autoage;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ if (age_period < 0 || age_period > VSC9953_AUTOAGE_PERIOD_MASK)
+ return -EINVAL;
+
+ autoage = bitfield_replace_by_mask(in_le32(&l2ana_reg->ana.auto_age),
+ VSC9953_AUTOAGE_PERIOD_MASK,
+ age_period);
+ out_le32(&l2ana_reg->ana.auto_age, autoage);
+
+ return 0;
+}
+
#ifdef CONFIG_CMD_ETHSW
/* Enable/disable status of a VSC9953 port */
@@ -1474,6 +1534,224 @@ static int vsc9953_port_ingress_filtering_get(int port_no)
return !!(val & (1 << port_no));
}
+/* Get the aggregation group of a port */
+static int vsc9953_port_aggr_grp_get(int port_no, int *aggr_grp)
+{
+ u32 val;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ if (!VSC9953_PORT_CHECK(port_no))
+ return -EINVAL;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ val = in_le32(&l2ana_reg->port[port_no].port_cfg);
+ *aggr_grp = bitfield_extract_by_mask(val,
+ VSC9953_PORT_CFG_PORTID_MASK);
+
+ return 0;
+}
+
+static void vsc9953_aggr_grp_members_get(int aggr_grp,
+ u8 aggr_membr[VSC9953_MAX_PORTS])
+{
+ int port_no;
+ int aggr_membr_grp;
+
+ for (port_no = 0; port_no < VSC9953_MAX_PORTS; port_no++) {
+ aggr_membr[port_no] = 0;
+
+ if (vsc9953_port_aggr_grp_get(port_no, &aggr_membr_grp))
+ continue;
+
+ if (aggr_grp == aggr_membr_grp)
+ aggr_membr[port_no] = 1;
+ }
+}
+
+static void vsc9953_update_dest_members_masks(int port_no, u32 membr_bitfld_old,
+ u32 membr_bitfld_new)
+{
+ int i;
+ u32 pgid;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ /*
+ * NOTE: Only the unicast destination masks are updated, since
+ * we do not support for now Layer-2 multicast entries
+ */
+ for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+ if (i == port_no) {
+ clrsetbits_le32(&l2ana_reg->port_id_tbl.port_grp_id[i],
+ VSC9953_PGID_PORT_MASK,
+ membr_bitfld_new);
+ continue;
+ }
+
+ pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
+ if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
+ pgid &= ~((u32)(1 << port_no));
+ if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
+ pgid |= ((u32)(1 << port_no));
+
+ out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
+ }
+}
+
+static void vsc9953_update_source_members_masks(int port_no,
+ u32 membr_bitfld_old,
+ u32 membr_bitfld_new)
+{
+ int i;
+ int index;
+ u32 pgid;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ for (i = 0; i < VSC9953_MAX_PORTS + 1; i++) {
+ index = PGID_SRC_START + i;
+ pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[index]);
+ if (i == port_no) {
+ pgid = (pgid | VSC9953_PGID_PORT_MASK) &
+ ~membr_bitfld_new;
+ out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index],
+ pgid);
+ continue;
+ }
+
+ if ((u32)(1 << i) & membr_bitfld_old & VSC9953_PGID_PORT_MASK)
+ pgid |= (u32)(1 << port_no);
+
+ if ((u32)(1 << i) & membr_bitfld_new & VSC9953_PGID_PORT_MASK)
+ pgid &= ~(u32)(1 << port_no);
+ out_le32(&l2ana_reg->port_id_tbl.port_grp_id[index], pgid);
+ }
+}
+
+static u32 vsc9953_aggr_mask_get_next(u32 aggr_mask, u32 member_bitfield)
+{
+ if (!member_bitfield)
+ return 0;
+
+ if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
+ aggr_mask = 1;
+ else
+ aggr_mask <<= 1;
+
+ while (!(aggr_mask & member_bitfield)) {
+ aggr_mask <<= 1;
+ if (!(aggr_mask & VSC9953_PGID_PORT_MASK))
+ aggr_mask = 1;
+ }
+
+ return aggr_mask;
+}
+
+static void vsc9953_update_aggr_members_masks(int port_no, u32 membr_bitfld_old,
+ u32 membr_bitfld_new)
+{
+ int i;
+ u32 pgid;
+ u32 aggr_mask_old = 0;
+ u32 aggr_mask_new = 0;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ /* Update all the PGID aggregation masks */
+ for (i = PGID_AGGR_START; i < PGID_SRC_START; i++) {
+ pgid = in_le32(&l2ana_reg->port_id_tbl.port_grp_id[i]);
+
+ aggr_mask_old = vsc9953_aggr_mask_get_next(aggr_mask_old,
+ membr_bitfld_old);
+ pgid = (pgid & ~membr_bitfld_old) | aggr_mask_old;
+
+ aggr_mask_new = vsc9953_aggr_mask_get_next(aggr_mask_new,
+ membr_bitfld_new);
+ pgid = (pgid & ~membr_bitfld_new) | aggr_mask_new;
+
+ out_le32(&l2ana_reg->port_id_tbl.port_grp_id[i], pgid);
+ }
+}
+
+static u32 vsc9953_aggr_membr_bitfield_get(u8 member[VSC9953_MAX_PORTS])
+{
+ int i;
+ u32 member_bitfield = 0;
+
+ for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+ if (member[i])
+ member_bitfield |= 1 << i;
+ }
+ member_bitfield &= VSC9953_PGID_PORT_MASK;
+
+ return member_bitfield;
+}
+
+static void vsc9953_update_members_masks(int port_no,
+ u8 member_old[VSC9953_MAX_PORTS],
+ u8 member_new[VSC9953_MAX_PORTS])
+{
+ u32 membr_bitfld_old = vsc9953_aggr_membr_bitfield_get(member_old);
+ u32 membr_bitfld_new = vsc9953_aggr_membr_bitfield_get(member_new);
+
+ vsc9953_update_dest_members_masks(port_no, membr_bitfld_old,
+ membr_bitfld_new);
+ vsc9953_update_source_members_masks(port_no, membr_bitfld_old,
+ membr_bitfld_new);
+ vsc9953_update_aggr_members_masks(port_no, membr_bitfld_old,
+ membr_bitfld_new);
+}
+
+/* Set the aggregation group of a port */
+static int vsc9953_port_aggr_grp_set(int port_no, int aggr_grp)
+{
+ u8 aggr_membr_old[VSC9953_MAX_PORTS];
+ u8 aggr_membr_new[VSC9953_MAX_PORTS];
+ int rc;
+ int aggr_grp_old;
+ u32 val;
+ struct vsc9953_analyzer *l2ana_reg;
+
+ if (!VSC9953_PORT_CHECK(port_no) || !VSC9953_PORT_CHECK(aggr_grp))
+ return -EINVAL;
+
+ l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET +
+ VSC9953_ANA_OFFSET);
+
+ rc = vsc9953_port_aggr_grp_get(port_no, &aggr_grp_old);
+ if (rc)
+ return rc;
+
+ /* get all the members of the old aggregation group */
+ vsc9953_aggr_grp_members_get(aggr_grp_old, aggr_membr_old);
+
+ /* get all the members of the same aggregation group */
+ vsc9953_aggr_grp_members_get(aggr_grp, aggr_membr_new);
+
+ /* add current port as member to the new aggregation group */
+ aggr_membr_old[port_no] = 0;
+ aggr_membr_new[port_no] = 1;
+
+ /* update masks */
+ vsc9953_update_members_masks(port_no, aggr_membr_old, aggr_membr_new);
+
+ /* Change logical port number */
+ val = in_le32(&l2ana_reg->port[port_no].port_cfg);
+ val = bitfield_replace_by_mask(val,
+ VSC9953_PORT_CFG_PORTID_MASK, aggr_grp);
+ out_le32(&l2ana_reg->port[port_no].port_cfg, val);
+
+ return 0;
+}
+
static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd)
{
int i;
@@ -2064,6 +2342,72 @@ static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd)
return CMD_RET_SUCCESS;
}
+static int vsc9953_port_aggr_show_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ int i;
+ int aggr_grp;
+
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+
+ if (vsc9953_port_aggr_grp_get(parsed_cmd->port, &aggr_grp))
+ return CMD_RET_FAILURE;
+ printf("%7s %10s\n", "Port", "Aggr grp");
+ printf("%7d %10d\n", parsed_cmd->port, aggr_grp);
+ } else {
+ printf("%7s %10s\n", "Port", "Aggr grp");
+ for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+ if (vsc9953_port_aggr_grp_get(i, &aggr_grp))
+ continue;
+ printf("%7d %10d\n", i, aggr_grp);
+ }
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int vsc9953_port_aggr_set_key_func(struct ethsw_command_def *parsed_cmd)
+{
+ int i;
+
+ /* Aggregation group number should be set in parsed_cmd->aggr_grp */
+ if (parsed_cmd->aggr_grp == ETHSW_CMD_AGGR_GRP_NONE) {
+ printf("Please set an aggregation group value\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (!VSC9953_PORT_CHECK(parsed_cmd->aggr_grp)) {
+ printf("Invalid aggregation group number: %d\n",
+ parsed_cmd->aggr_grp);
+ return CMD_RET_FAILURE;
+ }
+
+ if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) {
+ if (!VSC9953_PORT_CHECK(parsed_cmd->port)) {
+ printf("Invalid port number: %d\n", parsed_cmd->port);
+ return CMD_RET_FAILURE;
+ }
+ if (vsc9953_port_aggr_grp_set(parsed_cmd->port,
+ parsed_cmd->aggr_grp)) {
+ printf("Port %d: failed to set aggr group %d\n",
+ parsed_cmd->port, parsed_cmd->aggr_grp);
+ }
+ } else {
+ for (i = 0; i < VSC9953_MAX_PORTS; i++) {
+ if (vsc9953_port_aggr_grp_set(i,
+ parsed_cmd->aggr_grp)) {
+ printf("Port %d: failed to set aggr group %d\n",
+ i, parsed_cmd->aggr_grp);
+ }
+ }
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
static struct ethsw_command_func vsc9953_cmd_func = {
.ethsw_name = "L2 Switch VSC9953",
.port_enable = &vsc9953_port_status_key_func,
@@ -2088,7 +2432,9 @@ static struct ethsw_command_func vsc9953_cmd_func = {
.vlan_learn_show = &vsc9953_vlan_learn_show_key_func,
.vlan_learn_set = &vsc9953_vlan_learn_set_key_func,
.port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func,
- .port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func
+ .port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func,
+ .port_aggr_show = &vsc9953_port_aggr_show_key_func,
+ .port_aggr_set = &vsc9953_port_aggr_set_key_func,
};
#endif /* CONFIG_CMD_ETHSW */
@@ -2107,6 +2453,10 @@ void vsc9953_default_configuration(void)
{
int i;
+ if (vsc9953_autoage_time_set(VSC9953_DEFAULT_AGE_TIME))
+ debug("VSC9953: failed to set AGE time to %d\n",
+ VSC9953_DEFAULT_AGE_TIME);
+
for (i = 0; i < VSC9953_MAX_VLAN; i++)
vsc9953_vlan_table_membership_all_set(i, 0);
vsc9953_port_all_vlan_aware_set(1);
@@ -2115,6 +2465,8 @@ void vsc9953_default_configuration(void)
vsc9953_vlan_table_membership_all_set(1, 1);
vsc9953_vlan_ingr_fltr_learn_drop(1);
vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO);
+ if (vsc9953_aggr_code_set(AGGR_CODE_ALL))
+ debug("VSC9953: failed to set default aggregation code mode\n");
}
void vsc9953_init(bd_t *bis)
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(&regs->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(&regs->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(&regs->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(&regs->uaw0, val);
- val = (dev->enetaddr[5] << 8) | dev->enetaddr[4] ;
+ val = (pdata->enetaddr[5] << 8) | pdata->enetaddr[4];
val |= in_be32(&regs->uaw1) & ~XAE_UAW1_UNICASTADDR_MASK;
out_be32(&regs->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__, &regs->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(&regs->mdioctrl);
+ out_be32(&regs->mdioaddr, XEL_MDIOADDR_OP_MASK |
+ ((phyaddress << XEL_MDIOADDR_PHYADR_SHIFT) | registernum));
+ out_be32(&regs->mdioctrl, ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK);
+
+ if (mdio_wait(regs))
+ return 1;
+
+ /* Read data */
+ *data = in_be32(&regs->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(&regs->mdioctrl);
+ out_be32(&regs->mdioaddr, ~XEL_MDIOADDR_OP_MASK &
+ ((phyaddress << XEL_MDIOADDR_PHYADR_SHIFT) | registernum));
+ out_be32(&regs->mdiowr, data);
+ out_be32(&regs->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(&regs->tx_ping_tsr, 0);
/* Copy MAC address */
- xemaclite_alignedwrite(dev->enetaddr, dev->iobase, ENET_ADDR_LENGTH);
+ xemaclite_alignedwrite(pdata->enetaddr, &regs->tx_ping,
+ ENET_ADDR_LENGTH);
/* Set the length */
- out_be32 (dev->iobase + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
+ out_be32(&regs->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(&regs->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 (&regs->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(&regs->tx_pong_tsr, 0);
+ xemaclite_alignedwrite(pdata->enetaddr, &regs->tx_pong,
+ ENET_ADDR_LENGTH);
+ out_be32(&regs->tx_pong_tplr, ENET_ADDR_LENGTH);
+ out_be32(&regs->tx_pong_tsr, XEL_TSR_PROG_MAC_ADDR);
+ while ((in_be32(&regs->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(&regs->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(&regs->rx_pong_rsr, XEL_RSR_RECV_IE_MASK);
+
+ out_be32(&regs->mdioctrl, XEL_MDIOCTRL_MDIOEN_MASK);
+ if (in_be32(&regs->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(&regs->tx_ping_tsr);
+ if (emaclite->txpp)
+ tmp |= ~in_be32(&regs->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(&regs->tx_ping_tsr, 0);
if (emaclite->txpp) {
- out_be32 (dev->iobase + XEL_TSR_OFFSET +
- XEL_BUFFER_OFFSET, 0);
+ out_be32(&regs->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(&regs->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, &regs->tx_ping, len);
+ out_be32(&regs->tx_ping_tplr, len &
+ (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO));
+ reg = in_be32(&regs->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(&regs->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(&regs->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, &regs->tx_pong, len);
+ out_be32(&regs->tx_pong_tplr, len &
+ (XEL_TPLR_LENGTH_MASK_HI |
+ XEL_TPLR_LENGTH_MASK_LO));
+ reg = in_be32(&regs->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(&regs->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(&regs->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 = &regs->rx_ping;
+ ack = &regs->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(&regs->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 = &regs->rx_pong;
+ ack = &regs->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 */