From 2de09dcab6dfde7afa5d8d09fb2d0947de157877 Mon Sep 17 00:00:00 2001 From: Sham Muthayyan Date: Mon, 9 Jul 2018 19:04:36 +0530 Subject: [PATCH] ipq807x: Multiple napa port support Change-Id: I31d9ecf57e892bae31b044edb9d4ffbac2c17215 Signed-off-by: Sham Muthayyan --- arch/arm/dts/ipq807x-hk07.dts | 28 +++++- arch/arm/dts/ipq807x-hk09.dts | 32 +++++- board/qca/arm/ipq807x/ipq807x.c | 45 +++++---- drivers/net/ipq807x/ipq807x_edma.c | 150 +++++++++++++++++++---------- drivers/net/ipq807x/ipq807x_ppe.c | 9 +- drivers/net/ipq_common/ipq_phy.h | 10 +- 6 files changed, 200 insertions(+), 74 deletions(-) diff --git a/arch/arm/dts/ipq807x-hk07.dts b/arch/arm/dts/ipq807x-hk07.dts index 78b4b331ed..cdba42bd99 100644 --- a/arch/arm/dts/ipq807x-hk07.dts +++ b/arch/arm/dts/ipq807x-hk07.dts @@ -28,8 +28,34 @@ switch_mac_mode = <0x0>; switch_mac_mode1 = <0xFF>; switch_mac_mode2 = <0x6>; - 8081_port = <5>; napa_gpio = <44>; + napa_gpio_cnt = <1>; + port_phyinfo { + port@0 { + phy_address = <0>; + phy_type = <1>; + }; + port@1 { + phy_address = <1>; + phy_type = <1>; + }; + port@2 { + phy_address = <2>; + phy_type = <1>; + }; + port@3 { + phy_address = <3>; + phy_type = <1>; + }; + port@4 { + phy_address = <4>; + phy_type = <1>; + }; + port@5 { + phy_address = <28>; + phy_type = <2>; + }; + }; }; }; diff --git a/arch/arm/dts/ipq807x-hk09.dts b/arch/arm/dts/ipq807x-hk09.dts index 63f5ef3857..d5287f3697 100644 --- a/arch/arm/dts/ipq807x-hk09.dts +++ b/arch/arm/dts/ipq807x-hk09.dts @@ -27,8 +27,36 @@ }; ess-switch { switch_mac_mode = <0x0>; - switch_mac_mode1 = <0xFF>; - switch_mac_mode2 = <0xFF>; + switch_mac_mode1 = <0x6>; + switch_mac_mode2 = <0x6>; + napa_gpio = <25 44>; + napa_gpio_cnt = <2>; + port_phyinfo { + port@0 { + phy_address = <0>; + phy_type = <1>; + }; + port@1 { + phy_address = <1>; + phy_type = <1>; + }; + port@2 { + phy_address = <2>; + phy_type = <1>; + }; + port@3 { + phy_address = <3>; + phy_type = <1>; + }; + port@4 { + phy_address = <24>; + phy_type = <2>; + }; + port@5 { + phy_address = <28>; + phy_type = <2>; + }; + }; }; }; diff --git a/board/qca/arm/ipq807x/ipq807x.c b/board/qca/arm/ipq807x/ipq807x.c index 240bb34299..d6b80fdc46 100644 --- a/board/qca/arm/ipq807x/ipq807x.c +++ b/board/qca/arm/ipq807x/ipq807x.c @@ -311,17 +311,23 @@ int get_aquantia_gpio() return aquantia_gpio; } -int get_napa_gpio() +int get_napa_gpio(int napa_gpio[2]) { - int napa_gpio = -1, node; + int napa_gpio_cnt = -1, node; + int res = -1; 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; + if (node >= 0) { + napa_gpio_cnt = fdtdec_get_uint(gd->fdt_blob, node, "napa_gpio_cnt", -1); + if (napa_gpio_cnt >= 1) { + res = fdtdec_get_int_array(gd->fdt_blob, node, "napa_gpio", + napa_gpio, napa_gpio_cnt); + if (res >= 0) + return napa_gpio_cnt; + } + } - return napa_gpio; + return res; } void aquantia_phy_reset_init(void) @@ -345,24 +351,29 @@ void aquantia_phy_reset_init(void) void napa_phy_reset_init(void) { - int napa_gpio = -1, node; + int napa_gpio[2] = {0}, node, napa_gpio_cnt, i; 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); + napa_gpio_cnt = get_napa_gpio(napa_gpio); + if (napa_gpio_cnt >= 1) { + for (i = 0; i < napa_gpio_cnt; i++) { + if (napa_gpio[i] >=0) { + napa_gpio_base = (unsigned int *)GPIO_CONFIG_ADDR(napa_gpio[i]); + writel(0x203, napa_gpio_base); + gpio_direction_output(napa_gpio[i], 0x0); + } + } } } void napa_phy_reset_init_done(void) { - int napa_gpio; + int napa_gpio[2] = {0}, node, napa_gpio_cnt, i; - napa_gpio = get_napa_gpio(); - if (napa_gpio >= 0) { - gpio_set_value(napa_gpio, 0x1); + napa_gpio_cnt = get_napa_gpio(napa_gpio); + if (napa_gpio_cnt >= 1) { + for (i = 0; i < napa_gpio_cnt; i++) + gpio_set_value(napa_gpio[i], 0x1); } } diff --git a/drivers/net/ipq807x/ipq807x_edma.c b/drivers/net/ipq807x/ipq807x_edma.c index 3148947dc9..3256068ffa 100644 --- a/drivers/net/ipq807x/ipq807x_edma.c +++ b/drivers/net/ipq807x/ipq807x_edma.c @@ -45,6 +45,8 @@ DECLARE_GLOBAL_DATA_PTR; static struct ipq807x_eth_dev *ipq807x_edma_dev[IPQ807X_EDMA_DEV]; uchar ipq807x_def_enetaddr[6] = {0x00, 0x03, 0x7F, 0xBA, 0xDB, 0xAD}; +phy_info_t *phy_info[PHY_MAX] = {0}; +int sgmii_mode[2] = {0}; extern void qca8075_ess_reset(void); extern void psgmii_self_test(void); @@ -856,6 +858,22 @@ static void ipq807x_edma_disable_intr(struct ipq807x_edma_hw *ehw) IPQ807X_EDMA_MASK_INT_DISABLE); } +int set_sgmii_mode(int port_id, int sg_mode) +{ + if (port_id == 4) + sgmii_mode[0] = sg_mode; + else if (port_id == 5) + sgmii_mode[1] = sg_mode; +} + +int get_sgmii_mode(int port_id) +{ + if (port_id == 4) + return sgmii_mode[0]; + else if (port_id == 5) + return sgmii_mode[1]; +} + static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) { struct ipq807x_eth_dev *priv = eth_dev->priv; @@ -871,8 +889,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, port_8081 = -1; - int sgmii_mode = 0; + int phy_addr, port_8033 = -1, node, aquantia_port = -1; + int phy_node = -1; node = fdt_path_offset(gd->fdt_blob, "/ess-switch"); if (node >= 0) @@ -881,8 +899,7 @@ 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); + phy_node = fdt_path_offset(gd->fdt_blob, "/ess-switch/port_phyinfo"); /* * Check PHY link, speed, Duplex on all phys. * we will proceed even if single link is up @@ -902,15 +919,17 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) return -1; } - if (i == port_8033) - phy_addr = QCA8033_PHY_ADDR; - else if (i == port_8081) - phy_addr = QCA8081_PHY_ADDR; - else if (i == aquantia_port) - phy_addr = AQU_PHY_ADDR; - else - phy_addr = i; + 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); if (status == 0) linkup++; @@ -932,8 +951,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; + if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) + set_sgmii_mode(i, 1); break; case FAL_SPEED_100: mac_speed = 0x1; @@ -950,8 +969,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; + if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) + set_sgmii_mode(i, 1); break; case FAL_SPEED_1000: mac_speed = 0x2; @@ -959,14 +978,16 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) speed_clock1 = 0x104; else if (i == port_8033) speed_clock1 = 0x301; + else if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) + 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, dp[duplex]); - if (i == port_8081) - sgmii_mode = 1; + if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) + set_sgmii_mode(i, 1); break; case FAL_SPEED_10000: mac_speed = 0x3; @@ -977,23 +998,22 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) dp[duplex]); break; case FAL_SPEED_2500: - if (i == port_8081) + if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) { mac_speed = 0x2; - else - mac_speed = 0x4; - - if (port_8081 == 4) - speed_clock1 = 0x301; - else if (port_8081 == 5) - speed_clock1 = 0x101; - else + if (i == 4) + speed_clock1 = 0x301; + else if (i == 5) + speed_clock1 = 0x101; + } else { speed_clock1 = 0x107; + mac_speed = 0x4; + } 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; + if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) + set_sgmii_mode(i, 0); break; case FAL_SPEED_5000: mac_speed = 0x5; @@ -1008,19 +1028,23 @@ static int ipq807x_eth_init(struct eth_device *eth_dev, bd_t *this) 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); + if (phy_info[i]->phy_type == QCA8081_PHY_TYPE) { + if (get_sgmii_mode(i)) { + ppe_port_bridge_txmac_set(i + 1, 1); + if (i == 4) + ppe_uniphy_mode_set(0x1, PORT_WRAPPER_SGMII0_RGMII4); + else if (i == 5) + 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); + ppe_port_bridge_txmac_set(i + 1, 1); + if (i == 4) + ppe_uniphy_mode_set(0x1, PORT_WRAPPER_SGMII_PLUS); + else if (i == 5) + 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); @@ -1629,6 +1653,27 @@ int ipq807x_edma_hw_init(struct ipq807x_edma_hw *ehw) return 0; } +void get_phy_address(int offset) +{ + int phy_type; + int phy_address; + int i; + + for (i = 0; i < PHY_MAX; i++) + phy_info[i] = ipq807x_alloc_mem(sizeof(phy_info_t)); + i = 0; + for (offset = fdt_first_subnode(gd->fdt_blob, offset); offset > 0; + offset = fdt_next_subnode(gd->fdt_blob, offset)) { + + phy_address = fdtdec_get_uint(gd->fdt_blob, + offset, "phy_address", 0); + phy_type = fdtdec_get_uint(gd->fdt_blob, + offset, "phy_type", 0); + phy_info[i]->phy_address = phy_address; + phy_info[i++]->phy_type = phy_type; + } +} + int ipq807x_edma_init(void *edma_board_cfg) { struct eth_device *dev[IPQ807X_EDMA_DEV]; @@ -1640,8 +1685,10 @@ 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, port_8081 = -1, node, phy_addr, aquantia_port = -1; - int mode; + int port_8033 = -1, node, phy_addr, aquantia_port = -1; + int mode, phy_node = -1; + int napa_port_len = 0 , len; + unsigned int phy_array[6] = {0}; node = fdt_path_offset(gd->fdt_blob, "/ess-switch"); if (node >= 0) @@ -1650,8 +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); + phy_node = fdt_path_offset(gd->fdt_blob, "/ess-switch/port_phyinfo"); + if (phy_node >= 0) + get_phy_address(phy_node); mode = fdtdec_get_uint(gd->fdt_blob, node, "switch_mac_mode", -1); if (mode < 0) { @@ -1739,14 +1787,16 @@ int ipq807x_edma_init(void *edma_board_cfg) goto init_failed; for (phy_id = 0; phy_id < PHY_MAX; phy_id++) { - if (phy_id == port_8033) - 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; + if (phy_node >= 0) { + phy_addr = phy_info[phy_id]->phy_address; + } else { + if (phy_id == port_8033) + phy_addr = QCA8033_PHY_ADDR; + else if (phy_id == aquantia_port) + phy_addr = AQU_PHY_ADDR; + else + phy_addr = phy_id; + } phy_chip_id1 = ipq_mdio_read(phy_addr, QCA_PHY_ID1, NULL); phy_chip_id2 = ipq_mdio_read(phy_addr, QCA_PHY_ID2, NULL); diff --git a/drivers/net/ipq807x/ipq807x_ppe.c b/drivers/net/ipq807x/ipq807x_ppe.c index bc55ca69c0..a2ee92204a 100644 --- a/drivers/net/ipq807x/ipq807x_ppe.c +++ b/drivers/net/ipq807x/ipq807x_ppe.c @@ -1067,7 +1067,7 @@ static void ipq807x_ppe_e_sp_cfg_tbl_drr_id_set(int id) ipq807x_ppe_reg_write(IPQ807X_PPE_L1_E_SP_CFG_TBL + (id * 0x80), id * 2 + 1); } -static void ppe_port_mux_set(int port_id, int port_type) +static void ppe_port_mux_set(int port_id, int port_type, int mode) { union port_mux_ctrl_u port_mux_ctrl; @@ -1075,7 +1075,10 @@ 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_PCS0; + if (mode == PORT_WRAPPER_SGMII_PLUS) + port_mux_ctrl.bf.port5_pcs_sel = PORT5_PCS_SEL_GMII_FROM_PCS1; + else + 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; @@ -1113,7 +1116,7 @@ static void ppe_port_mux_mac_type_set(int port_id, int mode) default: return; } - ppe_port_mux_set(port_id, port_type); + ppe_port_mux_set(port_id, port_type, mode); } diff --git a/drivers/net/ipq_common/ipq_phy.h b/drivers/net/ipq_common/ipq_phy.h index 923a39061b..05c1df77c3 100644 --- a/drivers/net/ipq_common/ipq_phy.h +++ b/drivers/net/ipq_common/ipq_phy.h @@ -38,7 +38,6 @@ #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 @@ -95,6 +94,15 @@ enum port_wrapper_cfg { PORT_WRAPPER_SGMII_PLUS, }; +enum phy_mode { + MALIBU_PHY_TYPE = 1, + QCA8081_PHY_TYPE = 2, +}; + +typedef struct { + u32 phy_address; + u32 phy_type; +}phy_info_t; struct phy_ops { u8 (*phy_get_link_status) (u32 dev_id, u32 phy_id);