|
@@ -191,11 +191,16 @@ DECLARE_GLOBAL_DATA_PTR;
|
|
|
#define MVNETA_GMAC_AUTONEG_CONFIG 0x2c0c
|
|
|
#define MVNETA_GMAC_FORCE_LINK_DOWN BIT(0)
|
|
|
#define MVNETA_GMAC_FORCE_LINK_PASS BIT(1)
|
|
|
+#define MVNETA_GMAC_FORCE_LINK_UP (BIT(0) | BIT(1))
|
|
|
+#define MVNETA_GMAC_IB_BYPASS_AN_EN BIT(3)
|
|
|
#define MVNETA_GMAC_CONFIG_MII_SPEED BIT(5)
|
|
|
#define MVNETA_GMAC_CONFIG_GMII_SPEED BIT(6)
|
|
|
#define MVNETA_GMAC_AN_SPEED_EN BIT(7)
|
|
|
+#define MVNETA_GMAC_SET_FC_EN BIT(8)
|
|
|
+#define MVNETA_GMAC_ADVERT_FC_EN BIT(9)
|
|
|
#define MVNETA_GMAC_CONFIG_FULL_DUPLEX BIT(12)
|
|
|
#define MVNETA_GMAC_AN_DUPLEX_EN BIT(13)
|
|
|
+#define MVNETA_GMAC_SAMPLE_TX_CFG_EN BIT(15)
|
|
|
#define MVNETA_MIB_COUNTERS_BASE 0x3080
|
|
|
#define MVNETA_MIB_LATE_COLLISION 0x7c
|
|
|
#define MVNETA_DA_FILT_SPEC_MCAST 0x3400
|
|
@@ -566,6 +571,13 @@ static void mvneta_rxq_buf_size_set(struct mvneta_port *pp,
|
|
|
mvreg_write(pp, MVNETA_RXQ_SIZE_REG(rxq->id), val);
|
|
|
}
|
|
|
|
|
|
+static int mvneta_port_is_fixed_link(struct mvneta_port *pp)
|
|
|
+{
|
|
|
+ /* phy_addr is set to invalid value for fixed link */
|
|
|
+ return pp->phyaddr > PHY_MAX_ADDR;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/* Start the Ethernet port RX and TX activity */
|
|
|
static void mvneta_port_up(struct mvneta_port *pp)
|
|
|
{
|
|
@@ -816,10 +828,12 @@ static void mvneta_defaults_set(struct mvneta_port *pp)
|
|
|
/* Assign port SDMA configuration */
|
|
|
mvreg_write(pp, MVNETA_SDMA_CONFIG, val);
|
|
|
|
|
|
- /* Enable PHY polling in hardware for U-Boot */
|
|
|
- val = mvreg_read(pp, MVNETA_UNIT_CONTROL);
|
|
|
- val |= MVNETA_PHY_POLLING_ENABLE;
|
|
|
- mvreg_write(pp, MVNETA_UNIT_CONTROL, val);
|
|
|
+ /* Enable PHY polling in hardware if not in fixed-link mode */
|
|
|
+ if (!mvneta_port_is_fixed_link(pp)) {
|
|
|
+ val = mvreg_read(pp, MVNETA_UNIT_CONTROL);
|
|
|
+ val |= MVNETA_PHY_POLLING_ENABLE;
|
|
|
+ mvreg_write(pp, MVNETA_UNIT_CONTROL, val);
|
|
|
+ }
|
|
|
|
|
|
mvneta_set_ucast_table(pp, -1);
|
|
|
mvneta_set_special_mcast_table(pp, -1);
|
|
@@ -1137,6 +1151,11 @@ static void mvneta_adjust_link(struct udevice *dev)
|
|
|
struct phy_device *phydev = pp->phydev;
|
|
|
int status_change = 0;
|
|
|
|
|
|
+ if (mvneta_port_is_fixed_link(pp)) {
|
|
|
+ debug("Using fixed link, skip link adjust\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
if (phydev->link) {
|
|
|
if ((pp->speed != phydev->speed) ||
|
|
|
(pp->duplex != phydev->duplex)) {
|
|
@@ -1507,28 +1526,54 @@ static int mvneta_start(struct udevice *dev)
|
|
|
mvneta_port_power_up(pp, pp->phy_interface);
|
|
|
|
|
|
if (!pp->init || pp->link == 0) {
|
|
|
- /* Set phy address of the port */
|
|
|
- mvreg_write(pp, MVNETA_PHY_ADDR, pp->phyaddr);
|
|
|
- phydev = phy_connect(pp->bus, pp->phyaddr, dev,
|
|
|
- pp->phy_interface);
|
|
|
-
|
|
|
- pp->phydev = phydev;
|
|
|
- phy_config(phydev);
|
|
|
- phy_startup(phydev);
|
|
|
- if (!phydev->link) {
|
|
|
- printf("%s: No link.\n", phydev->dev->name);
|
|
|
- return -1;
|
|
|
- }
|
|
|
+ if (mvneta_port_is_fixed_link(pp)) {
|
|
|
+ u32 val;
|
|
|
|
|
|
- /* Full init on first call */
|
|
|
- mvneta_init(dev);
|
|
|
- pp->init = 1;
|
|
|
- } else {
|
|
|
- /* Upon all following calls, this is enough */
|
|
|
- mvneta_port_up(pp);
|
|
|
- mvneta_port_enable(pp);
|
|
|
+ pp->init = 1;
|
|
|
+ pp->link = 1;
|
|
|
+ mvneta_init(dev);
|
|
|
+
|
|
|
+ val = MVNETA_GMAC_FORCE_LINK_UP |
|
|
|
+ MVNETA_GMAC_IB_BYPASS_AN_EN |
|
|
|
+ MVNETA_GMAC_SET_FC_EN |
|
|
|
+ MVNETA_GMAC_ADVERT_FC_EN |
|
|
|
+ MVNETA_GMAC_SAMPLE_TX_CFG_EN;
|
|
|
+
|
|
|
+ if (pp->duplex)
|
|
|
+ val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX;
|
|
|
+
|
|
|
+ if (pp->speed == SPEED_1000)
|
|
|
+ val |= MVNETA_GMAC_CONFIG_GMII_SPEED;
|
|
|
+ else if (pp->speed == SPEED_100)
|
|
|
+ val |= MVNETA_GMAC_CONFIG_MII_SPEED;
|
|
|
+
|
|
|
+ mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
|
|
|
+ } else {
|
|
|
+ /* Set phy address of the port */
|
|
|
+ mvreg_write(pp, MVNETA_PHY_ADDR, pp->phyaddr);
|
|
|
+
|
|
|
+ phydev = phy_connect(pp->bus, pp->phyaddr, dev,
|
|
|
+ pp->phy_interface);
|
|
|
+
|
|
|
+ pp->phydev = phydev;
|
|
|
+ phy_config(phydev);
|
|
|
+ phy_startup(phydev);
|
|
|
+ if (!phydev->link) {
|
|
|
+ printf("%s: No link.\n", phydev->dev->name);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Full init on first call */
|
|
|
+ mvneta_init(dev);
|
|
|
+ pp->init = 1;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ /* Upon all following calls, this is enough */
|
|
|
+ mvneta_port_up(pp);
|
|
|
+ mvneta_port_enable(pp);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1625,6 +1670,7 @@ static int mvneta_probe(struct udevice *dev)
|
|
|
unsigned long addr;
|
|
|
void *bd_space;
|
|
|
int ret;
|
|
|
+ int fl_node;
|
|
|
|
|
|
/*
|
|
|
* Allocate buffer area for descs and rx_buffers. This is only
|
|
@@ -1657,10 +1703,19 @@ static int mvneta_probe(struct udevice *dev)
|
|
|
/* PHY interface is already decoded in mvneta_ofdata_to_platdata() */
|
|
|
pp->phy_interface = pdata->phy_interface;
|
|
|
|
|
|
- /* Now read phyaddr from DT */
|
|
|
- addr = fdtdec_get_int(blob, node, "phy", 0);
|
|
|
- addr = fdt_node_offset_by_phandle(blob, addr);
|
|
|
- pp->phyaddr = fdtdec_get_int(blob, addr, "reg", 0);
|
|
|
+ /* fetch 'fixed-link' property from 'neta' node */
|
|
|
+ fl_node = fdt_subnode_offset(blob, node, "fixed-link");
|
|
|
+ if (fl_node != -FDT_ERR_NOTFOUND) {
|
|
|
+ /* set phy_addr to invalid value for fixed link */
|
|
|
+ pp->phyaddr = PHY_MAX_ADDR + 1;
|
|
|
+ pp->duplex = fdtdec_get_bool(blob, fl_node, "full-duplex");
|
|
|
+ pp->speed = fdtdec_get_int(blob, fl_node, "speed", 0);
|
|
|
+ } else {
|
|
|
+ /* Now read phyaddr from DT */
|
|
|
+ addr = fdtdec_get_int(blob, node, "phy", 0);
|
|
|
+ addr = fdt_node_offset_by_phandle(blob, addr);
|
|
|
+ pp->phyaddr = fdtdec_get_int(blob, addr, "reg", 0);
|
|
|
+ }
|
|
|
|
|
|
bus = mdio_alloc();
|
|
|
if (!bus) {
|