diff --git a/arch/arm/dts/ipq9574-al02-c10.dts b/arch/arm/dts/ipq9574-al02-c10.dts index 46dfb661ef..b3f17fce8d 100644 --- a/arch/arm/dts/ipq9574-al02-c10.dts +++ b/arch/arm/dts/ipq9574-al02-c10.dts @@ -18,4 +18,45 @@ machid = <0x8050901>; config_name = "config@al02-c10"; + ess-switch { + /* Overriding config to support QCA8084 Switch instead of + * QCA8084 PHY + */ + qca8084_switch_enable = <1>; + switch_mac_mode0 = ; + + qca8084_swt_info { + switch_mac_mode0 = ; + switch_mac_mode1 = ; + + port@0 { + phy_address = <0xff>; + phy_type = ; + forced-speed = <2500>; + forced-duplex = <1>; + }; + port@1 { + phy_address = <1>; + phy_type = ; + }; + port@2 { + phy_address = <2>; + phy_type = ; + }; + port@3 { + phy_address = <3>; + phy_type = ; + }; + port@4 { + phy_address = <0x4>; + phy_type = ; + }; + port@5 { + phy_address = <0xff>; + phy_type = ; + forced-speed = <2500>; + forced-duplex = <1>; + }; + }; + }; }; diff --git a/drivers/net/ipq9574/ipq9574_edma.c b/drivers/net/ipq9574/ipq9574_edma.c index 341d69409b..1a5f1d6d30 100644 --- a/drivers/net/ipq9574/ipq9574_edma.c +++ b/drivers/net/ipq9574/ipq9574_edma.c @@ -46,6 +46,7 @@ static struct ipq9574_eth_dev *ipq9574_edma_dev[IPQ9574_EDMA_DEV]; uchar ipq9574_def_enetaddr[6] = {0x00, 0x03, 0x7F, 0xBA, 0xDB, 0xAD}; phy_info_t *phy_info[IPQ9574_PHY_MAX] = {0}; +phy_info_t *swt_info[QCA8084_MAX_PORTS] = {0}; int sgmii_mode[2] = {0}; extern void ipq_phy_addr_fixup(void); @@ -62,8 +63,12 @@ extern int ipq_board_fw_download(unsigned int phy_addr); extern void ipq_qca8084_phy_hw_init(struct phy_ops **ops, u32 phy_addr); extern void qca8084_phy_uqxgmii_speed_fixup(uint32_t phy_addr, uint32_t qca8084_port_id, uint32_t status, fal_port_speed_t new_speed); +extern int ipq_qca8084_hw_init(phy_info_t * phy_info[], int node); +extern void ipq_qca8084_link_update(u32 port_id); +extern void ipq_qca8084_switch_hw_reset(int gpio); static int tftp_acl_our_port; +static int qca8084_swt_enb = 0; /* * EDMA hardware instance @@ -1022,6 +1027,13 @@ static int ipq9574_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], curr_speed[i], dp[duplex]); + + if ((phy_info[i]->phy_type == QCA8084_PHY_TYPE) && qca8084_swt_enb) { + if (old_speed[i] != curr_speed[i]) { + old_speed[i] = curr_speed[i]; + ipq_qca8084_link_update(phy_addr); + } + } continue; } @@ -1257,17 +1269,22 @@ static int ipq9574_eth_init(struct eth_device *eth_dev, bd_t *this) } } - ipq9574_speed_clock_set(i, clk); + if (!qca8084_swt_enb || (i != PORT0)) + ipq9574_speed_clock_set(i, clk); - if (phy_info[i]->phy_type == QCA8084_PHY_TYPE) - qca8084_phy_uqxgmii_speed_fixup(phy_info[i]->phy_address, i + 1, - status, curr_speed[i]); + if (!qca8084_swt_enb && (phy_info[i]->phy_type == QCA8084_PHY_TYPE)) + qca8084_phy_uqxgmii_speed_fixup(phy_info[i]->phy_address, + i + 1, status, curr_speed[i]); - ipq9574_port_mac_clock_reset(i); + if (!qca8084_swt_enb || (i != PORT0)) + ipq9574_port_mac_clock_reset(i); if (i == aquantia_port[0] || i == aquantia_port[1] || - phy_info[i]->phy_type == QCA8084_PHY_TYPE) + ((phy_info[i]->phy_type == QCA8084_PHY_TYPE) && (!qca8084_swt_enb))) { ipq9574_uxsgmii_speed_set(i, mac_speed, duplex, status); + } + else if (qca8084_swt_enb && (phy_info[i]->phy_type == QCA8084_PHY_TYPE)) + ipq_qca8084_link_update(phy_addr); else if ((i == sfp_port[0] || i == sfp_port[1]) && sgmii_fiber == 0) ipq9574_10g_r_speed_set(i, status); else @@ -1831,10 +1848,11 @@ int ipq9574_edma_hw_init(struct ipq9574_edma_hw *ehw) return 0; } -void get_phy_address(int offset) +void get_phy_address(int offset, phy_info_t * phy_info[]) { int phy_type; int phy_address; + int forced_speed, forced_duplex; int i; for (i = 0; i < IPQ9574_PHY_MAX; i++) @@ -1846,7 +1864,13 @@ void get_phy_address(int offset) offset, "phy_address", 0); phy_type = fdtdec_get_uint(gd->fdt_blob, offset, "phy_type", 0); + forced_speed = fdtdec_get_uint(gd->fdt_blob, + offset, "forced-speed", 0); + forced_duplex = fdtdec_get_uint(gd->fdt_blob, + offset, "forced-duplex", 0); phy_info[i]->phy_address = phy_address; + phy_info[i]->forced_speed = forced_speed; + phy_info[i]->forced_duplex = forced_duplex; phy_info[i++]->phy_type = phy_type; } } @@ -1870,6 +1894,7 @@ int ipq9574_edma_init(void *edma_board_cfg) #ifdef CONFIG_QCA8084_PHY static int qca8084_init_done = 0; int phy_type; + int qca8084_gpio, swt_node = -1, clk[4] = {0}; #endif int node, phy_addr, mode, phy_node = -1, res = -1; int aquantia_port[2] = {-1, -1}, aquantia_port_cnt = -1; @@ -1892,9 +1917,22 @@ int ipq9574_edma_init(void *edma_board_cfg) } } +#ifdef CONFIG_QCA8084_PHY + qca8084_swt_enb = fdtdec_get_uint(gd->fdt_blob, node, "qca8084_switch_enable", 0); + qca8084_gpio = fdtdec_get_uint(gd->fdt_blob, node, "qca808x_gpio", 0); + if (qca8084_swt_enb) { + if (qca8084_gpio) + ipq_qca8084_switch_hw_reset(qca8084_gpio); + } + + swt_node = fdt_path_offset(gd->fdt_blob, "/ess-switch/qca8084_swt_info"); + if (swt_node >= 0) + get_phy_address(swt_node, swt_info); +#endif + phy_node = fdt_path_offset(gd->fdt_blob, "/ess-switch/port_phyinfo"); if (phy_node >= 0) - get_phy_address(phy_node); + get_phy_address(phy_node, phy_info); mode = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode0", -1); if (mode < 0) { @@ -2084,6 +2122,37 @@ int ipq9574_edma_init(void *edma_board_cfg) if (ret) goto init_failed; + /** QCA8084 switch specific configurations */ + if (qca8084_swt_enb) { + /** Force speed alder 1st port for QCA8084 switch mode */ + switch (swt_info[0]->forced_speed) { + case FAL_SPEED_1000: + case FAL_SPEED_2500: + clk[0] = 0x201; + clk[1] = 0x0; + clk[2] = 0x301; + clk[3] = 0x0; + + pr_debug("Force speed Alder 1st PORT for QCA8084 switch mode \n"); + ipq9574_speed_clock_set(PORT0, clk); + + /** Force Link-speed: 1000M + * Force Link-status: enable */ + ipq9574_pqsgmii_speed_set(PORT0, 0x2, 0x0); + break; + + default: + printf("Error: Unsupported speed configuraiton for QCA8084 switch \n"); + break; + } + + ret = ipq_qca8084_hw_init(swt_info, swt_node); + if (ret < 0) { + printf("Error: ipq_qca8084_hw_init failed \n"); + goto init_failed; + } + } + eth_register(dev[i]); } diff --git a/drivers/net/ipq9574/ipq9574_ppe.c b/drivers/net/ipq9574/ipq9574_ppe.c index 7e3ed7debd..af723af99f 100644 --- a/drivers/net/ipq9574/ipq9574_ppe.c +++ b/drivers/net/ipq9574/ipq9574_ppe.c @@ -831,6 +831,7 @@ void ppe_port_mux_mac_type_set(int port_id, int mode) case EPORT_WRAPPER_SGMII0_RGMII4: case EPORT_WRAPPER_SGMII_PLUS: case EPORT_WRAPPER_SGMII_FIBER: + case EPORT_WRAPPER_SGMII_CHANNEL0: port_type = PORT_GMAC_TYPE; break; case EPORT_WRAPPER_USXGMII: diff --git a/drivers/net/ipq9574/ipq9574_uniphy.c b/drivers/net/ipq9574/ipq9574_uniphy.c index f5e0a628d7..66bf499bad 100644 --- a/drivers/net/ipq9574/ipq9574_uniphy.c +++ b/drivers/net/ipq9574/ipq9574_uniphy.c @@ -235,10 +235,30 @@ static void ppe_uniphy_qsgmii_mode_set(uint32_t uniphy_index) mdelay(100); } +void ppe_uniphy_set_forceMode(void) +{ + uint32_t reg_value; + + reg_value = readl(PPE_UNIPHY_BASE + UNIPHY_DEC_CHANNEL_0_INPUT_OUTPUT_4); + reg_value |= UNIPHY_FORCE_SPEED_25M; + + writel(reg_value, PPE_UNIPHY_BASE + UNIPHY_DEC_CHANNEL_0_INPUT_OUTPUT_4); +} + static void ppe_uniphy_sgmii_mode_set(uint32_t uniphy_index, uint32_t mode) { - writel(UNIPHY_MISC2_REG_SGMII_MODE, PPE_UNIPHY_BASE + - (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_MISC2_REG_OFFSET); + if (uniphy_index == 0) { + writel(UNIPHY_MISC_SRC_PHY_MODE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_MISC_SOURCE_SELECTION_REG_OFFSET); + + ppe_uniphy_set_forceMode(); + + writel(UNIPHY_MISC2_REG_SGMII_PLUS_MODE, PPE_UNIPHY_BASE + + (uniphy_index * PPE_UNIPHY_REG_INC) + UNIPHY_MISC2_REG_OFFSET); + } else { + writel(UNIPHY_MISC2_REG_SGMII_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); @@ -254,7 +274,12 @@ static void ppe_uniphy_sgmii_mode_set(uint32_t uniphy_index, uint32_t mode) ppe_uniphy_reset(UNIPHY2_XPCS_RESET, true); mdelay(100); - if (uniphy_index == 1) { + if (uniphy_index == 0) { + writel(0x0, NSS_CC_UNIPHY_PORT1_RX_CBCR); + writel(0x0, NSS_CC_UNIPHY_PORT1_RX_CBCR + 0x4); + writel(0x0, NSS_CC_PORT1_RX_CBCR); + writel(0x0, NSS_CC_PORT1_RX_CBCR + 0x4); + } else if (uniphy_index == 1) { writel(0x0, NSS_CC_UNIPHY_PORT1_RX_CBCR + (PORT5 - 1) * 0x8); writel(0x0, NSS_CC_UNIPHY_PORT1_RX_CBCR + 0x4 + (PORT5 - 1) * 0x8); writel(0x0, NSS_CC_PORT1_RX_CBCR + (PORT5 - 1) * 0x8); @@ -280,7 +305,11 @@ static void ppe_uniphy_sgmii_mode_set(uint32_t uniphy_index, uint32_t mode) break; case EPORT_WRAPPER_SGMII_PLUS: - writel(0x820, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + if (uniphy_index == 0) + writel(0x20, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + + PPE_UNIPHY_MODE_CONTROL); + else + writel(0x820, PPE_UNIPHY_BASE + (uniphy_index * PPE_UNIPHY_REG_INC) + PPE_UNIPHY_MODE_CONTROL); break; @@ -304,7 +333,12 @@ static void ppe_uniphy_sgmii_mode_set(uint32_t uniphy_index, uint32_t mode) } mdelay(100); - if (uniphy_index == 1) { + if (uniphy_index == 0) { + writel(0x1, NSS_CC_UNIPHY_PORT1_RX_CBCR); + writel(0x1, NSS_CC_UNIPHY_PORT1_RX_CBCR + 0x4); + writel(0x1, NSS_CC_PORT1_RX_CBCR); + writel(0x1, NSS_CC_PORT1_RX_CBCR + 0x4); + } else if (uniphy_index == 1) { writel(0x1, NSS_CC_UNIPHY_PORT1_RX_CBCR + (PORT5 - 1) * 0x8); writel(0x1, NSS_CC_UNIPHY_PORT1_RX_CBCR + 0x4 + (PORT5 - 1) * 0x8); writel(0x1, NSS_CC_PORT1_RX_CBCR + (PORT5 - 1) * 0x8); diff --git a/drivers/net/ipq9574/ipq9574_uniphy.h b/drivers/net/ipq9574/ipq9574_uniphy.h index 8b1dacdbcc..4f88580001 100644 --- a/drivers/net/ipq9574/ipq9574_uniphy.h +++ b/drivers/net/ipq9574/ipq9574_uniphy.h @@ -41,6 +41,12 @@ #define UNIPHY_MISC2_REG_VALUE 0x70 +#define UNIPHY_MISC_SOURCE_SELECTION_REG_OFFSET 0x21c +#define UNIPHY_MISC_SRC_PHY_MODE 0xa882 + +#define UNIPHY_DEC_CHANNEL_0_INPUT_OUTPUT_4 0x480 +#define UNIPHY_FORCE_SPEED_25M (1 << 3) + #define UNIPHY_PLL_RESET_REG_OFFSET 0x780 #define UNIPHY_PLL_RESET_REG_VALUE 0x02bf #define UNIPHY_PLL_RESET_REG_DEFAULT_VALUE 0x02ff