diff --git a/arch/arm/dts/ipq807x-hk01-c2.dts b/arch/arm/dts/ipq807x-hk01-c2.dts index 00f0fc786f..d24dd60080 100644 --- a/arch/arm/dts/ipq807x-hk01-c2.dts +++ b/arch/arm/dts/ipq807x-hk01-c2.dts @@ -30,8 +30,9 @@ }; ess-switch { switch_mac_mode = <0x5>; - switch_mac_mode1 = <0xFF>; + switch_mac_mode1 = <0x7>; switch_mac_mode2 = <0x2>; + sfp_port = <4>; aquantia_port = <5>; aquantia_gpio = <44>; }; diff --git a/drivers/net/ipq807x/ipq807x_edma.c b/drivers/net/ipq807x/ipq807x_edma.c index 28eb48aa37..c64465c07f 100755 --- a/drivers/net/ipq807x/ipq807x_edma.c +++ b/drivers/net/ipq807x/ipq807x_edma.c @@ -892,6 +892,7 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) int linkup=0; int mac_speed = 0, speed_clock1 = 0, speed_clock2 = 0; int phy_addr, port_8033 = -1, node, aquantia_port = -1; + int sfp_port = -1; int phy_node = -1; int ret_sgmii_mode; @@ -902,6 +903,9 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) if (node >= 0) aquantia_port = fdtdec_get_uint(gd->fdt_blob, node, "aquantia_port", -1); + if (node >= 0) + sfp_port = fdtdec_get_uint(gd->fdt_blob, node, "sfp_port", -1); + phy_node = fdt_path_offset(gd->fdt_blob, "/ess-switch/port_phyinfo"); /* * Check PHY link, speed, Duplex on all phys. @@ -909,35 +913,44 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) * else we will return with -1; */ for (i = 0; i < PHY_MAX; i++) { - if (!priv->ops[i]) { - printf ("Phy ops not mapped\n"); - continue; - } - phy_get_ops = priv->ops[i]; - if (!phy_get_ops->phy_get_link_status || - !phy_get_ops->phy_get_speed || - !phy_get_ops->phy_get_duplex) { - printf ("Link status/Get speed/Get duplex not mapped\n"); - return -1; - } - - if (phy_node >= 0) { - phy_addr = phy_info[i]->phy_address; + if (i == sfp_port) { + status = phy_status_get_from_ppe(i); + speed = FAL_SPEED_10000; + duplex = FAL_FULL_DUPLEX; } else { + if (!priv->ops[i]) { + printf ("Phy ops not mapped\n"); + continue; + } + phy_get_ops = priv->ops[i]; - if (i == port_8033) - phy_addr = QCA8033_PHY_ADDR; - else if (i == aquantia_port) - phy_addr = AQU_PHY_ADDR; - else - phy_addr = i; + if (!phy_get_ops->phy_get_link_status || + !phy_get_ops->phy_get_speed || + !phy_get_ops->phy_get_duplex) { + printf ("Link status/Get speed/Get duplex not mapped\n"); + return -1; + } + + if (phy_node >= 0) { + phy_addr = phy_info[i]->phy_address; + } else { + + if (i == port_8033) + phy_addr = QCA8033_PHY_ADDR; + else if (i == aquantia_port) + phy_addr = AQU_PHY_ADDR; + else + phy_addr = i; + } + status = phy_get_ops->phy_get_link_status(priv->mac_unit, phy_addr); + phy_get_ops->phy_get_speed(priv->mac_unit, phy_addr, &speed); + phy_get_ops->phy_get_duplex(priv->mac_unit, phy_addr, &duplex); } - status = phy_get_ops->phy_get_link_status(priv->mac_unit, phy_addr); + if (status == 0) linkup++; - phy_get_ops->phy_get_speed(priv->mac_unit, phy_addr, &speed); - phy_get_ops->phy_get_duplex(priv->mac_unit, phy_addr, &duplex); + switch (speed) { case FAL_SPEED_10: if (i == aquantia_port) { @@ -1001,7 +1014,10 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) break; case FAL_SPEED_10000: mac_speed = 0x3; - speed_clock1 = 0x101; + if (i == 4) + speed_clock1 = 0x301; + else + speed_clock1 = 0x101; speed_clock2 = 0x0; printf ("eth%d PHY%d %s Speed :%d %s duplex\n", priv->mac_unit, i, lstatus[status], speed, @@ -1077,6 +1093,8 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) ipq807x_speed_clock_set(i, speed_clock1, speed_clock2); if (i == aquantia_port) ipq807x_uxsgmii_speed_set(i, mac_speed, duplex, status); + else if (i == sfp_port) + ipq807x_10g_r_speed_set(i, status); else ipq807x_pqsgmii_speed_set(i, mac_speed, status); } diff --git a/drivers/net/ipq807x/ipq807x_edma.h b/drivers/net/ipq807x/ipq807x_edma.h index eaf78f3025..b236951f83 100644 --- a/drivers/net/ipq807x/ipq807x_edma.h +++ b/drivers/net/ipq807x/ipq807x_edma.h @@ -319,5 +319,7 @@ extern void ipq807x_speed_clock_set(int port, int speed_clock1, int speed_clock2 extern void ipq807x_pqsgmii_speed_set(int port, int speed, int status); extern void ipq807x_uxsgmii_speed_set(int port, int speed, int duplex, int status); extern void ppe_port_bridge_txmac_sett(int port, int status); +extern void ipq807x_10g_r_speed_set(int port, int status); +extern int phy_status_get_from_ppe(int port_id); #endif /* ___IPQ807X_EDMA__ */ diff --git a/drivers/net/ipq807x/ipq807x_ppe.c b/drivers/net/ipq807x/ipq807x_ppe.c index 34a413194f..1d2bc57a0c 100644 --- a/drivers/net/ipq807x/ipq807x_ppe.c +++ b/drivers/net/ipq807x/ipq807x_ppe.c @@ -191,6 +191,19 @@ void ipq807x_speed_clock_set(int port, int speed_clock1, int speed_clock2) } } +int phy_status_get_from_ppe(int port_id) +{ + uint32_t reg_field = 0; + + ipq807x_ppe_reg_read(PORT_PHY_STATUS_ADDRESS, ®_field); + if (port_id == (PORT5 - PPE_UNIPHY_INSTANCE1)) + reg_field >>= PORT_PHY_STATUS_PORT5_1_OFFSET; + else + reg_field >>= PORT_PHY_STATUS_PORT6_OFFSET; + + return ((reg_field >> 7) & 0x1) ? 0 : 1; +} + void ppe_port_bridge_txmac_set(int port_id, int status) { uint32_t reg_value = 0; @@ -249,7 +262,18 @@ void ppe_xgmac_speed_set(uint32_t uniphy_index, int speed) } +void ppe_xgmac_10g_r_speed_set(uint32_t uniphy_index) +{ + uint32_t reg_value = 0; + ipq807x_ppe_reg_read(PPE_SWITCH_NSS_SWITCH_XGMAC0 + + (uniphy_index * NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION), ®_value); + + reg_value |=JD; + ipq807x_ppe_reg_write(PPE_SWITCH_NSS_SWITCH_XGMAC0 + + (uniphy_index * NSS_SWITCH_XGMAC_MAC_TX_CONFIGURATION), reg_value); + +} void ppe_port_txmac_status_set(uint32_t uniphy_index) { @@ -289,6 +313,25 @@ void ppe_mac_packet_filter_set(uint32_t uniphy_index) (uniphy_index * MAC_PACKET_FILTER_INC), 0x81); } +void ipq807x_10g_r_speed_set(int port, int status) +{ + uint32_t uniphy_index; + + /* Setting the speed only for PORT5 and PORT6 */ + if (port == (PORT5 - PPE_UNIPHY_INSTANCE1)) + uniphy_index = PPE_UNIPHY_INSTANCE1; + else if (port == (PORT6 - PPE_UNIPHY_INSTANCE1)) + uniphy_index = PPE_UNIPHY_INSTANCE2; + else + return; + + ppe_xgmac_10g_r_speed_set(uniphy_index - 1); + ppe_port_bridge_txmac_set(port + 1, status); + ppe_port_txmac_status_set(uniphy_index - 1); + ppe_port_rxmac_status_set(uniphy_index - 1); + ppe_mac_packet_filter_set(uniphy_index - 1); +} + void ipq807x_uxsgmii_speed_set(int port, int speed, int duplex, int status) { @@ -1113,6 +1156,9 @@ static void ppe_port_mux_mac_type_set(int port_id, int mode) case PORT_WRAPPER_USXGMII: port_type = PORT_XGMAC_TYPE; break; + case PORT_WRAPPER_10GBASE_R: + port_type = PORT_XGMAC_TYPE; + break; default: return; } diff --git a/drivers/net/ipq807x/ipq807x_ppe.h b/drivers/net/ipq807x/ipq807x_ppe.h index f9bed8892c..c5febe46cd 100644 --- a/drivers/net/ipq807x/ipq807x_ppe.h +++ b/drivers/net/ipq807x/ipq807x_ppe.h @@ -117,6 +117,10 @@ union ipo_action_u { #define PORT6_GMAC_SEL_GMAC 1 #define PORT6_GMAC_SEL_XGMAC 0 +#define PORT_PHY_STATUS_ADDRESS 0x44 +#define PORT_PHY_STATUS_PORT5_1_OFFSET 8 +#define PORT_PHY_STATUS_PORT6_OFFSET 16 + #define IPQ807X_PPE_IPE_L3_BASE_ADDR 0x200000 #define IPQ807X_PPE_L3_VP_PORT_TBL_ADDR (IPQ807X_PPE_IPE_L3_BASE_ADDR + 0x1000) #define IPQ807X_PPE_L3_VP_PORT_TBL_INC 0x10 diff --git a/drivers/net/ipq807x/ipq807x_uniphy.c b/drivers/net/ipq807x/ipq807x_uniphy.c index 94ac9ac91b..62ae9e727d 100644 --- a/drivers/net/ipq807x/ipq807x_uniphy.c +++ b/drivers/net/ipq807x/ipq807x_uniphy.c @@ -194,6 +194,21 @@ static int ppe_uniphy_10g_r_linkup(uint32_t uniphy_index) return 0; } +static void ppe_uniphy_10g_r_mode_set(uint32_t uniphy_index) +{ + uint32_t reg_value = 0; + + ppe_gcc_uniphy_xpcs_reset(uniphy_index, true); + writel(0x1021, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_MODE_CONTROL); + writel(0x1C0, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + UNIPHY_INSTANCE_LINK_DETECT); + ppe_gcc_uniphy_soft_reset(uniphy_index); + ppe_uniphy_calibration(uniphy_index); + ppe_gcc_uniphy_xpcs_reset(uniphy_index, false); +} + + static void ppe_uniphy_usxgmii_mode_set(uint32_t uniphy_index) { uint32_t reg_value = 0; @@ -253,6 +268,9 @@ void ppe_uniphy_mode_set(uint32_t uniphy_index, uint32_t mode) case PORT_WRAPPER_USXGMII: ppe_uniphy_usxgmii_mode_set(uniphy_index); break; + case PORT_WRAPPER_10GBASE_R: + ppe_uniphy_10g_r_mode_set(uniphy_index); + break; default: break; } diff --git a/drivers/net/ipq807x/ipq807x_uniphy.h b/drivers/net/ipq807x/ipq807x_uniphy.h index 410667eec5..4d8bac9495 100644 --- a/drivers/net/ipq807x/ipq807x_uniphy.h +++ b/drivers/net/ipq807x/ipq807x_uniphy.h @@ -38,6 +38,8 @@ #define UNIPHY_CH1_CH0_SGMII (1 << 1) #define UNIPHY_CH0_ATHR_CSCO_MODE_25M (1 << 0) +#define UNIPHY_INSTANCE_LINK_DETECT 0x570 + #define UNIPHY_MISC2_REG_OFFSET 0x218 #define UNIPHY_MISC2_REG_SGMII_MODE 0x30 #define UNIPHY_MISC2_REG_SGMII_PLUS_MODE 0x50 diff --git a/drivers/net/ipq_common/ipq_phy.h b/drivers/net/ipq_common/ipq_phy.h index 4a3c00fec1..61a3026139 100755 --- a/drivers/net/ipq_common/ipq_phy.h +++ b/drivers/net/ipq_common/ipq_phy.h @@ -93,6 +93,7 @@ enum port_wrapper_cfg { PORT_WRAPPER_SGMII4_RGMII4, PORT_WRAPPER_QSGMII, PORT_WRAPPER_SGMII_PLUS, + PORT_WRAPPER_10GBASE_R, }; enum phy_mode {