diff --git a/arch/arm/include/asm/arch-ipq5018/ipq5018_gmac.h b/arch/arm/include/asm/arch-ipq5018/ipq5018_gmac.h index 4d71b39959..b85ac1ebd8 100644 --- a/arch/arm/include/asm/arch-ipq5018/ipq5018_gmac.h +++ b/arch/arm/include/asm/arch-ipq5018/ipq5018_gmac.h @@ -266,6 +266,9 @@ struct ipq_eth_dev { uint ipq_swith; uint phy_external_link; int link_printed; + u32 sfp_mode; + u32 sfp_tx_gpio; + u32 sfp_rx_gpio; u32 padding; ipq_gmac_desc_t *desc_tx[NO_OF_TX_DESC]; ipq_gmac_desc_t *desc_rx[NO_OF_RX_DESC]; diff --git a/board/qca/arm/ipq5018/ipq5018.c b/board/qca/arm/ipq5018/ipq5018.c index e5c9e03ed5..e3db8e3cd2 100644 --- a/board/qca/arm/ipq5018/ipq5018.c +++ b/board/qca/arm/ipq5018/ipq5018.c @@ -770,6 +770,15 @@ static void set_ext_mdio_gpio(int node) } } +static void reset_sfp_gpio(int gpio) +{ + unsigned int *sfp_gpio_base; + + sfp_gpio_base = (unsigned int *)GPIO_CONFIG_ADDR(gpio); + writel(0x2c3, sfp_gpio_base); + writel(0x0, GPIO_IN_OUT_ADDR(gpio)); +} + static void reset_napa_phy_gpio(int gpio) { unsigned int *napa_gpio_base; @@ -1172,6 +1181,18 @@ int board_eth_init(bd_t *bis) gmac_cfg[loop].phy_external_link = fdtdec_get_uint(gd->fdt_blob, offset, "phy_external_link", 0); + gmac_cfg[loop].sfp_mode = fdtdec_get_uint(gd->fdt_blob, + offset, "switch_mac_mode", 0); + gmac_cfg[loop].sfp_rx_gpio + = fdtdec_get_uint(gd->fdt_blob, offset, + "sfp_rx_gpio", 0); + gmac_cfg[loop].sfp_tx_gpio + = fdtdec_get_uint(gd->fdt_blob, offset, + "sfp_tx_gpio", 0); + if (gmac_cfg[loop].sfp_tx_gpio) { + reset_sfp_gpio(gmac_cfg[loop].sfp_tx_gpio); + } + gmac_cfg[loop].phy_napa_gpio = fdtdec_get_uint(gd->fdt_blob, offset, "napa_gpio", 0); if (gmac_cfg[loop].phy_napa_gpio){ diff --git a/board/qca/arm/ipq5018/ipq5018.h b/board/qca/arm/ipq5018/ipq5018.h index ebbcbb8b69..9f2250f361 100644 --- a/board/qca/arm/ipq5018/ipq5018.h +++ b/board/qca/arm/ipq5018/ipq5018.h @@ -498,6 +498,9 @@ typedef struct { int phy_interface_mode; int phy_napa_gpio; int phy_8033_gpio; + u32 sfp_tx_gpio; + u32 sfp_rx_gpio; + u32 sfp_mode; int phy_type; u32 mac_pwr; int ipq_swith; diff --git a/drivers/net/ipq5018/ipq5018_gmac.c b/drivers/net/ipq5018/ipq5018_gmac.c index 6e8d163950..e45a680be7 100644 --- a/drivers/net/ipq5018/ipq5018_gmac.c +++ b/drivers/net/ipq5018/ipq5018_gmac.c @@ -45,7 +45,10 @@ extern int ipq_qca8081_phy_init(struct phy_ops **ops, u32 phy_id); extern int ipq_gephy_phy_init(struct phy_ops **ops, u32 phy_id); extern int ipq_sw_mdio_init(const char *); extern int ipq5018_sw_mdio_init(const char *); -extern void ppe_uniphy_mode_set(uint32_t mode); +extern void ppe_uniphy_mode_set(uint32_t mode, uint32_t phy_mode); +extern void uniphy_channel0_input_output_6_get(int mode, u32 gpio, u8 *status, + fal_port_speed_t *speed, + fal_port_duplex_t *duplex); extern int ipq_athrs17_init(ipq_gmac_board_cfg_t *gmac_cfg); static int ipq_eth_wr_macaddr(struct eth_device *dev) @@ -354,6 +357,7 @@ static int ipq5018_phy_link_update(struct eth_device *dev) char *dp[] = {"Half", "Full"}; int speed_clock1 = 0, speed_clock2 = 0; int mode = PORT_WRAPPER_SGMII0_RGMII4; + uint32_t phy_mode = 0x70; phy_get_ops = priv->ops; @@ -363,17 +367,27 @@ static int ipq5018_phy_link_update(struct eth_device *dev) status = ipq5018_s17c_Link_Update(priv); } - if (phy_get_ops != NULL && - phy_get_ops->phy_get_link_status != NULL && - phy_get_ops->phy_get_speed != NULL && - phy_get_ops->phy_get_duplex != NULL){ + if (priv->sfp_tx_gpio || phy_get_ops) { + if (phy_get_ops && + phy_get_ops->phy_get_link_status != NULL && + phy_get_ops->phy_get_speed != NULL && + phy_get_ops->phy_get_duplex != NULL){ - status = phy_get_ops->phy_get_link_status(priv->mac_unit, - priv->phy_address); - phy_get_ops->phy_get_speed(priv->mac_unit, - priv->phy_address, &speed); - phy_get_ops->phy_get_duplex(priv->mac_unit, - priv->phy_address, &duplex); + status = phy_get_ops->phy_get_link_status(priv->mac_unit, + priv->phy_address); + phy_get_ops->phy_get_speed(priv->mac_unit, + priv->phy_address, &speed); + phy_get_ops->phy_get_duplex(priv->mac_unit, + priv->phy_address, &duplex); + } + + if (priv->sfp_tx_gpio) { + mode = priv->sfp_mode; + uniphy_channel0_input_output_6_get(priv->sfp_mode, + priv->sfp_rx_gpio, + &status, + &speed, &duplex); + } switch (speed) { case FAL_SPEED_10: @@ -398,6 +412,8 @@ static int ipq5018_phy_link_update(struct eth_device *dev) priv->speed = SGMII_PORT_SELECT; speed_clock1 = 1; speed_clock2 = 0; + if (priv->sfp_tx_gpio) + phy_mode = 0x30; printf ("eth%d %s Speed :%d %s duplex\n", priv->mac_unit, lstatus[status], speed, @@ -408,6 +424,11 @@ static int ipq5018_phy_link_update(struct eth_device *dev) mode = PORT_WRAPPER_SGMII_PLUS; speed_clock1 = 1; speed_clock2 = 0; + + if (priv->sfp_tx_gpio) + phy_mode = 0x50; + else + phy_mode = 0x30; printf ("eth%d %s Speed :%d %s duplex\n", priv->mac_unit, lstatus[status], speed, @@ -427,7 +448,7 @@ static int ipq5018_phy_link_update(struct eth_device *dev) } if (priv->mac_unit){ - ppe_uniphy_mode_set(mode); + ppe_uniphy_mode_set(mode, phy_mode); } else { ipq5018_enable_gephy(); } @@ -724,7 +745,9 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg) uchar enet_addr[CONFIG_IPQ_NO_MACS * 6]; int i; uint32_t phy_chip_id, phy_chip_id1, phy_chip_id2; + uint32_t phy_mode = 0x70; int ret; + memset(enet_addr, 0, sizeof(enet_addr)); /* Mdio init */ @@ -786,6 +809,14 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg) ipq_gmac_macs[i]->interface = gmac_cfg->phy_interface_mode; ipq_gmac_macs[i]->phy_type = gmac_cfg->phy_type; ipq_gmac_macs[i]->phy_external_link = gmac_cfg->phy_external_link; + ipq_gmac_macs[i]->sfp_tx_gpio = gmac_cfg->sfp_tx_gpio; + ipq_gmac_macs[i]->sfp_rx_gpio = gmac_cfg->sfp_rx_gpio; + ipq_gmac_macs[i]->sfp_mode = gmac_cfg->sfp_mode; + + if (gmac_cfg->sfp_mode == PORT_WRAPPER_SGMII_PLUS) + phy_mode = 0x50; + else if (gmac_cfg->sfp_mode == PORT_WRAPPER_SGMII_FIBER) + phy_mode = 0x30; snprintf((char *)ipq_gmac_macs[i]->phy_name, sizeof(ipq_gmac_macs[i]->phy_name), "IPQ MDIO%d", i); @@ -847,7 +878,12 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg) } break; default: - printf("GMAC%d:Invalid PHY ID \n", i); + if (gmac_cfg->sfp_tx_gpio) { + ppe_uniphy_mode_set(gmac_cfg->sfp_mode, + phy_mode); + } else { + printf("GMAC%d:Invalid PHY ID \n", i); + } break; } /* Initialize 8337 switch */ diff --git a/drivers/net/ipq5018/ipq5018_uniphy.c b/drivers/net/ipq5018/ipq5018_uniphy.c index 7daeec098e..41ed018564 100644 --- a/drivers/net/ipq5018/ipq5018_uniphy.c +++ b/drivers/net/ipq5018/ipq5018_uniphy.c @@ -59,9 +59,74 @@ static void ppe_gcc_uniphy_soft_reset(void) writel(reg_value, GCC_UNIPHY0_MISC); } -static void ppe_uniphy_sgmii_mode_set(uint32_t mode) +void uniphy_channel0_input_output_6_get(int mode, u32 gpio, u8 *status, + fal_port_speed_t *speed, + fal_port_duplex_t *duplex) +{ + uint32_t reg_value; + int val; + + *status = 1; + *speed = FAL_SPEED_BUTT; + *duplex = FAL_DUPLEX_BUTT; + + reg_value = readl(PPE_UNIPHY_BASE + UNIPHY_DEC_CHANNEL_0_INPUT_OUTPUT_6); + + val = reg_value & CH0_LINK_MAC; + + if (val) { + switch(mode) { + case PORT_WRAPPER_SGMII_FIBER: + *status = 0; /* LINK UP */ + break; + case PORT_WRAPPER_SGMII_PLUS: + /* + * get rx_los status + * if, rx_los = 0, link up + * else, link down + */ + if (gpio && !gpio_get_value(gpio)) { + *status = 0; + *speed = FAL_SPEED_2500; + *duplex = FAL_FULL_DUPLEX; + } + return; + default: + printf("%s: Invalid mode\n", __func__); + break; + } + } + + val = (reg_value & CH0_SPEED_MODE_MAC) >> 4; + + switch(val) { + case UNIPHY_SPEED_1000M: + *speed = FAL_SPEED_1000; + break; + case UNIPHY_SPEED_100M: + *speed = FAL_SPEED_100; + break; + case UNIPHY_SPEED_10M: + *speed = FAL_SPEED_10; + break; + default: + *speed = FAL_SPEED_BUTT; + break; + + } + + val = (reg_value & CH0_DUPLEX_MODE_MAC) >> 6; + + if (val) + *duplex = FAL_FULL_DUPLEX; + else + *duplex = FAL_HALF_DUPLEX; + + return; +} + +static void ppe_uniphy_sgmii_mode_set(uint32_t mode, uint32_t phy_mode) { - uint32_t phy_mode = 0x70; writel(UNIPHY_MISC2_REG_SGMII_MODE, PPE_UNIPHY_BASE + UNIPHY_MISC2_REG_OFFSET); @@ -96,7 +161,6 @@ static void ppe_uniphy_sgmii_mode_set(uint32_t mode) case PORT_WRAPPER_SGMII_PLUS: writel((UNIPHY_SG_PLUS_MODE | UNIPHY_PSGMII_MAC_MODE), PPE_UNIPHY_BASE + PPE_UNIPHY_MODE_CONTROL); - phy_mode = 0x30; break; default: @@ -123,12 +187,12 @@ static void ppe_uniphy_sgmii_mode_set(uint32_t mode) ppe_uniphy_calibration(); } -void ppe_uniphy_mode_set(uint32_t mode) +void ppe_uniphy_mode_set(uint32_t mode, uint32_t phy_mode) { /* * SGMII and SHMII plus confugure in same function */ - ppe_uniphy_sgmii_mode_set(mode); + ppe_uniphy_sgmii_mode_set(mode, phy_mode); } void ppe_uniphy_set_forceMode(void) diff --git a/drivers/net/ipq5018/ipq5018_uniphy.h b/drivers/net/ipq5018/ipq5018_uniphy.h index da08281c29..cd47f274f1 100644 --- a/drivers/net/ipq5018/ipq5018_uniphy.h +++ b/drivers/net/ipq5018/ipq5018_uniphy.h @@ -14,6 +14,7 @@ #ifndef _IPQ5018_UNIPHY_H_ #define _IPQ5018_UNIPHY_H +#include "ipq_phy.h" #define PPE_UNIPHY_INSTANCE0 0 @@ -47,6 +48,11 @@ #define UNIPHY_DEC_CHANNEL_0_INPUT_OUTPUT_4 0x480 #define UNIPHY_FORCE_SPEED_25M (1 << 3) +#define UNIPHY_DEC_CHANNEL_0_INPUT_OUTPUT_6 0x488 +#define CH0_LINK_MAC (1 << 7) +#define CH0_DUPLEX_MODE_MAC (1 << 6) +#define CH0_SPEED_MODE_MAC (3 << 4) + #define UNIPHY_REF_CLK_CTRL_REG 0x74 #define UNIPHY_INSTANCE_LINK_DETECT 0x570 @@ -61,7 +67,14 @@ #define UNIPHY_PLL_RESET_REG_VALUE 0x02bf #define UNIPHY_PLL_RESET_REG_DEFAULT_VALUE 0x02ff -void ppe_uniphy_mode_set(uint32_t mode); +#define UNIPHY_SPEED_10M 0 +#define UNIPHY_SPEED_100M 1 +#define UNIPHY_SPEED_1000M 2 + +void ppe_uniphy_mode_set(uint32_t mode, uint32_t phy_mode); void ppe_uniphy_set_forceMode(void); void ppe_uniphy_refclk_set(void); +void uniphy_channel0_input_output_6_get(int mode, u32 gpio, u8 *status, + fal_port_speed_t *speed, + fal_port_duplex_t *duplex); #endif