diff --git a/arch/arm/dts/ipq807x-hk07.dts b/arch/arm/dts/ipq807x-hk07.dts index 19b999e747..78b4b331ed 100644 --- a/arch/arm/dts/ipq807x-hk07.dts +++ b/arch/arm/dts/ipq807x-hk07.dts @@ -27,7 +27,9 @@ ess-switch { switch_mac_mode = <0x0>; switch_mac_mode1 = <0xFF>; - switch_mac_mode2 = <0xFF>; + switch_mac_mode2 = <0x6>; + 8081_port = <5>; + napa_gpio = <44>; }; }; diff --git a/board/qca/arm/ipq807x/ipq807x.c b/board/qca/arm/ipq807x/ipq807x.c index a6e669155c..fac9bbe969 100644 --- a/board/qca/arm/ipq807x/ipq807x.c +++ b/board/qca/arm/ipq807x/ipq807x.c @@ -311,6 +311,19 @@ int get_aquantia_gpio() return aquantia_gpio; } +int get_napa_gpio() +{ + int napa_gpio = -1, node; + + node = fdt_path_offset(gd->fdt_blob, "/ess-switch"); + if (node >= 0) + napa_gpio = fdtdec_get_uint(gd->fdt_blob, node, "napa_gpio", -1); + else + return node; + + return napa_gpio; +} + void aquantia_phy_reset_init(void) { int aquantia_gpio = -1, node; @@ -330,6 +343,29 @@ void aquantia_phy_reset_init(void) } } +void napa_phy_reset_init(void) +{ + int napa_gpio = -1, node; + unsigned int *napa_gpio_base; + + napa_gpio = get_napa_gpio(); + if (napa_gpio >=0) { + napa_gpio_base = (unsigned int *)GPIO_CONFIG_ADDR(napa_gpio); + writel(0x203, napa_gpio_base); + gpio_direction_output(napa_gpio, 0x0); + } +} + +void napa_phy_reset_init_done(void) +{ + int napa_gpio; + + napa_gpio = get_napa_gpio(); + if (napa_gpio >= 0) { + gpio_set_value(napa_gpio, 0x1); + } +} + void aquantia_phy_reset_init_done(void) { int aquantia_gpio; @@ -403,9 +439,11 @@ void eth_clock_enable(void) writel(0x203, tlmm_base); writel(0, tlmm_base + 0x4); aquantia_phy_reset_init(); + napa_phy_reset_init(); mdelay(500); writel(2, tlmm_base + 0x4); aquantia_phy_reset_init_done(); + napa_phy_reset_init_done(); mdelay(500); } diff --git a/drivers/net/ipq807x/ipq807x_edma.c b/drivers/net/ipq807x/ipq807x_edma.c index 535da32892..0923809e70 100644 --- a/drivers/net/ipq807x/ipq807x_edma.c +++ b/drivers/net/ipq807x/ipq807x_edma.c @@ -61,6 +61,7 @@ extern int ipq_qca8033_phy_init(struct phy_ops **ops, u32 phy_id); extern int ipq_qca_aquantia_phy_init(struct phy_ops **ops, u32 phy_id); static int tftp_acl_our_port; +static int uniphy_phy_mode; /* * EDMA hardware instance */ @@ -914,7 +915,8 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) char *dp[] = {"Half", "Full"}; int linkup=0; int mac_speed = 0, speed_clock1 = 0, speed_clock2 = 0; - int phy_addr, port_8033 = -1, node, aquantia_port = -1; + int phy_addr, port_8033 = -1, node, aquantia_port = -1, port_8081 = -1; + int sgmii_mode = 0; node = fdt_path_offset(gd->fdt_blob, "/ess-switch"); if (node >= 0) @@ -922,6 +924,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) + port_8081 = fdtdec_get_uint(gd->fdt_blob, node, "8081_port", -1); /* * Check PHY link, speed, Duplex on all phys. * we will proceed even if single link is up @@ -943,6 +948,8 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) if (i == port_8033) phy_addr = QCA8033_PHY_ADDR; + if (i == port_8081) + phy_addr = QCA8081_PHY_ADDR; else if (i == aquantia_port) phy_addr = AQU_PHY_ADDR; else @@ -969,6 +976,8 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) printf ("eth%d PHY%d %s Speed :%d %s duplex\n", priv->mac_unit, i, lstatus[status], speed, dp[duplex]); + if (i == port_8081) + sgmii_mode = 1; break; case FAL_SPEED_100: mac_speed = 0x1; @@ -985,6 +994,8 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) printf ("eth%d PHY%d %s Speed :%d %s duplex\n", priv->mac_unit, i, lstatus[status], speed, dp[duplex]); + if (i == port_8081) + sgmii_mode = 1; break; case FAL_SPEED_1000: mac_speed = 0x2; @@ -998,6 +1009,8 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) printf ("eth%d PHY%d %s Speed :%d %s duplex\n", priv->mac_unit, i, lstatus[status], speed, dp[duplex]); + if (i == port_8081) + sgmii_mode = 1; break; case FAL_SPEED_10000: mac_speed = 0x3; @@ -1008,12 +1021,23 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) dp[duplex]); break; case FAL_SPEED_2500: - mac_speed = 0x4; - speed_clock1 = 0x107; + if (i == port_8081) + mac_speed = 0x2; + else + mac_speed = 0x4; + + if (port_8081 == 4) + speed_clock1 = 0x301; + else if (port_8081 == 5) + speed_clock1 = 0x101; + else + speed_clock1 = 0x107; speed_clock2 = 0x0; printf ("eth%d PHY%d %s Speed :%d %s duplex\n", priv->mac_unit, i, lstatus[status], speed, dp[duplex]); + if (i == port_8081) + sgmii_mode = 0; break; case FAL_SPEED_5000: mac_speed = 0x5; @@ -1027,6 +1051,20 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) printf("Unknown speed\n"); break; } + + if (i == port_8081) { + if (sgmii_mode != uniphy_phy_mode) { + uniphy_phy_mode = sgmii_mode; + if (sgmii_mode) { + ppe_port_bridge_txmac_set(i, 1); + ppe_uniphy_mode_set(0x2, PORT_WRAPPER_SGMII0_RGMII4); + + } else { + ppe_port_bridge_txmac_set(i, 1); + ppe_uniphy_mode_set(0x2, PORT_WRAPPER_SGMII_PLUS); + } + } + } ipq807x_speed_clock_set(i, speed_clock1, speed_clock2); if (i == aquantia_port) ipq807x_uxsgmii_speed_set(i, mac_speed, duplex, status); @@ -1649,7 +1687,7 @@ int ipq807x_edma_init(void *edma_board_cfg) int ret = -1; ipq807x_edma_board_cfg_t ledma_cfg, *edma_cfg; static int sw_init_done = 0; - int port_8033 = -1, node, phy_addr, aquantia_port = -1; + int port_8033 = -1, port_8081 = -1, node, phy_addr, aquantia_port = -1; int mode; node = fdt_path_offset(gd->fdt_blob, "/ess-switch"); @@ -1659,6 +1697,9 @@ int ipq807x_edma_init(void *edma_board_cfg) if (node >= 0) aquantia_port = fdtdec_get_uint(gd->fdt_blob, node, "aquantia_port", -1); + if (node >= 0) + port_8081 = fdtdec_get_uint(gd->fdt_blob, node, "8081_port", -1); + mode = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode", -1); if (mode < 0) { printf("Error: switch_mac_mode not specified in dts"); @@ -1749,6 +1790,8 @@ int ipq807x_edma_init(void *edma_board_cfg) phy_addr = QCA8033_PHY_ADDR; else if (phy_id == aquantia_port) phy_addr = AQU_PHY_ADDR; + else if (phy_id == port_8081) + phy_addr = QCA8081_PHY_ADDR; else phy_addr = phy_id; @@ -1781,6 +1824,9 @@ int ipq807x_edma_init(void *edma_board_cfg) case QCA8033_PHY: ipq_qca8033_phy_init(&ipq807x_edma_dev[i]->ops[phy_id], phy_addr); break; + case QCA8081_PHY: + ipq_qca8081_phy_init(&ipq807x_edma_dev[i]->ops[phy_id], phy_addr); + break; case AQUANTIA_PHY_107: case AQUANTIA_PHY_109: case AQUANTIA_PHY_111: diff --git a/drivers/net/ipq807x/ipq807x_ppe.c b/drivers/net/ipq807x/ipq807x_ppe.c index 5eddf2c08d..bc55ca69c0 100644 --- a/drivers/net/ipq807x/ipq807x_ppe.c +++ b/drivers/net/ipq807x/ipq807x_ppe.c @@ -1075,7 +1075,7 @@ static void ppe_port_mux_set(int port_id, int port_type) port_mux_ctrl.bf.port4_pcs_sel = PORT4_PCS_SEL_GMII_FROM_PCS0; if (port_id == PORT5) { if (port_type == PORT_GMAC_TYPE) { - port_mux_ctrl.bf.port5_pcs_sel = PORT5_PCS_SEL_GMII_FROM_PCS1; + port_mux_ctrl.bf.port5_pcs_sel = PORT5_PCS_SEL_GMII_FROM_PCS0; port_mux_ctrl.bf.port5_gmac_sel = PORT5_GMAC_SEL_GMAC; } else if (port_type == PORT_XGMAC_TYPE) { port_mux_ctrl.bf.port5_pcs_sel = PORT5_PCS_SEL_GMII_FROM_PCS1; @@ -1104,6 +1104,9 @@ static void ppe_port_mux_mac_type_set(int port_id, int mode) case PORT_WRAPPER_SGMII0_RGMII4: port_type = PORT_GMAC_TYPE; break; + case PORT_WRAPPER_SGMII_PLUS: + port_type = PORT_GMAC_TYPE; + break; case PORT_WRAPPER_USXGMII: port_type = PORT_XGMAC_TYPE; break; diff --git a/drivers/net/ipq807x/ipq807x_uniphy.c b/drivers/net/ipq807x/ipq807x_uniphy.c index 403201659d..f164270352 100644 --- a/drivers/net/ipq807x/ipq807x_uniphy.c +++ b/drivers/net/ipq807x/ipq807x_uniphy.c @@ -143,6 +143,7 @@ static void ppe_uniphy_sgmii_mode_set(uint32_t uniphy_index, uint32_t channel) else if (channel == 4) reg_value |= UNIPHY_CH4_CH1_0_SGMII; } else { + reg_value &= ~UNIPHY_SG_PLUS_MODE; reg_value |= UNIPHY_SG_MODE; } writel(reg_value, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) @@ -150,6 +151,25 @@ static void ppe_uniphy_sgmii_mode_set(uint32_t uniphy_index, uint32_t channel) ppe_gcc_uniphy_soft_reset(uniphy_index); } +static void ppe_uniphy_sgmii_plus_mode_set(uint32_t uniphy_index) +{ + uint32_t reg_value; + + writel(UNIPHY_MISC2_REG_SGMII_PLUS_MODE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_MISC2_REG_OFFSET); + writel(UNIPHY_PLL_RESET_REG_VALUE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_PLL_RESET_REG_OFFSET); + udelay(500); + writel(UNIPHY_PLL_RESET_REG_DEFAULT_VALUE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_PLL_RESET_REG_OFFSET); + ppe_gcc_uniphy_xpcs_reset(uniphy_index, true); + + writel(0x800, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_MODE_CONTROL); + ppe_gcc_uniphy_soft_reset(uniphy_index); + ppe_uniphy_calibration(uniphy_index); +} + static int ppe_uniphy_10g_r_linkup(uint32_t uniphy_index) { uint32_t reg_value = 0; @@ -219,6 +239,9 @@ void ppe_uniphy_mode_set(uint32_t uniphy_index, uint32_t mode) case PORT_WRAPPER_SGMII4_RGMII4: ppe_uniphy_sgmii_mode_set(uniphy_index, 4); break; + case PORT_WRAPPER_SGMII_PLUS: + ppe_uniphy_sgmii_plus_mode_set(uniphy_index); + break; case PORT_WRAPPER_USXGMII: ppe_uniphy_usxgmii_mode_set(uniphy_index); break; diff --git a/drivers/net/ipq807x/ipq807x_uniphy.h b/drivers/net/ipq807x/ipq807x_uniphy.h index 0efdfc8526..f0070646d0 100644 --- a/drivers/net/ipq807x/ipq807x_uniphy.h +++ b/drivers/net/ipq807x/ipq807x_uniphy.h @@ -29,7 +29,8 @@ #define PPE_UNIPHY_BASE 0X07A00000 #define PPE_UNIPHY_REG_INC 0x10000 #define PPE_UNIPHY_MODE_CONTROL 0x46C -#define UNIPHY_SG_MODE 0x400 +#define UNIPHY_SG_MODE 0x420 +#define UNIPHY_SG_PLUS_MODE 0x800 #define UNIPHY_CH0_PSGMII_QSGMII 0x200 #define UNIPHY_CH4_CH1_0_SGMII 0x4 #define UNIPHY_CH1_CH0_SGMII 0x2 @@ -37,6 +38,7 @@ #define UNIPHY_MISC2_REG_OFFSET 0x218 #define UNIPHY_MISC2_REG_SGMII_MODE 0x30 +#define UNIPHY_MISC2_REG_SGMII_PLUS_MODE 0x50 #define UNIPHY_MISC2_REG_VALUE 0x70 diff --git a/drivers/net/ipq_common/ipq_phy.h b/drivers/net/ipq_common/ipq_phy.h index e984112bcf..923a39061b 100644 --- a/drivers/net/ipq_common/ipq_phy.h +++ b/drivers/net/ipq_common/ipq_phy.h @@ -37,6 +37,8 @@ #define QCA8075_PHY_V1_1_2P 0x004DD0B2 #define QCA8033_PHY 0x004DD074 #define QCA8033_PHY_ADDR 0x6 +#define QCA8081_PHY 0x004DD100 +#define QCA8081_PHY_ADDR 0x1C #define AQUANTIA_PHY_107 0x03a1b4e2 #define AQUANTIA_PHY_109 0x03a1b502 #define AQUANTIA_PHY_111 0x03a1b610 @@ -90,6 +92,7 @@ enum port_wrapper_cfg { PORT_WRAPPER_SGMII1_RGMII4, PORT_WRAPPER_SGMII4_RGMII4, PORT_WRAPPER_QSGMII, + PORT_WRAPPER_SGMII_PLUS, };