diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/fm/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/fm/b4860.c | 64 | ||||
-rw-r--r-- | drivers/net/fm/eth.c | 7 | ||||
-rw-r--r-- | drivers/net/fm/init.c | 2 | ||||
-rw-r--r-- | drivers/net/fm/t1024.c | 88 | ||||
-rw-r--r-- | drivers/net/fm/t1040.c | 4 | ||||
-rw-r--r-- | drivers/net/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/phy/cortina.c | 333 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 3 | ||||
-rw-r--r-- | drivers/net/phy/vitesse.c | 13 |
10 files changed, 508 insertions, 9 deletions
diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile index 5ae3b16..d052fcb 100644 --- a/drivers/net/fm/Makefile +++ b/drivers/net/fm/Makefile @@ -28,6 +28,8 @@ obj-$(CONFIG_PPC_T1040) += t1040.o obj-$(CONFIG_PPC_T1042) += t1040.o obj-$(CONFIG_PPC_T1020) += t1040.o obj-$(CONFIG_PPC_T1022) += t1040.o +obj-$(CONFIG_PPC_T1023) += t1024.o +obj-$(CONFIG_PPC_T1024) += t1024.o obj-$(CONFIG_PPC_T2080) += t2080.o obj-$(CONFIG_PPC_T2081) += t2080.o obj-$(CONFIG_PPC_T4240) += t4240.o diff --git a/drivers/net/fm/b4860.c b/drivers/net/fm/b4860.c index 373cc4f..eb058c9 100644 --- a/drivers/net/fm/b4860.c +++ b/drivers/net/fm/b4860.c @@ -10,6 +10,7 @@ #include <asm/io.h> #include <asm/immap_85xx.h> #include <asm/fsl_serdes.h> +#include <hwconfig.h> u32 port_to_devdisr[] = { [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1, @@ -46,15 +47,76 @@ void fman_enable_port(enum fm_port port) phy_interface_t fman_port_enet_if(enum fm_port port) { +#if defined(CONFIG_B4860QDS) + u32 serdes2_prtcl; + char buffer[HWCONFIG_BUFFER_SIZE]; + char *buf = NULL; + ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); +#endif + if (is_device_disabled(port)) return PHY_INTERFACE_MODE_NONE; /*B4860 has two 10Gig Mac*/ if ((port == FM1_10GEC1 || port == FM1_10GEC2) && ((is_serdes_configured(XAUI_FM1_MAC9)) || - (is_serdes_configured(XAUI_FM1_MAC10)))) + #if !defined(CONFIG_B4860QDS) + (is_serdes_configured(XFI_FM1_MAC9)) || + (is_serdes_configured(XFI_FM1_MAC10)) || + #endif + (is_serdes_configured(XAUI_FM1_MAC10)) + )) return PHY_INTERFACE_MODE_XGMII; +#if defined(CONFIG_B4860QDS) + serdes2_prtcl = in_be32(&gur->rcwsr[4]) & + FSL_CORENET2_RCWSR4_SRDS2_PRTCL; + + if (serdes2_prtcl) { + serdes2_prtcl >>= FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT; + switch (serdes2_prtcl) { + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0xb1: + case 0xb2: + /* + * Extract hwconfig from environment since environment + * is not setup yet + */ + getenv_f("hwconfig", buffer, sizeof(buffer)); + buf = buffer; + + /* check if XFI interface enable in hwconfig for 10g */ + if (hwconfig_subarg_cmp_f("fsl_b4860_serdes2", + "sfp_amc", "sfp", buf)) { + if ((port == FM1_10GEC1 || + port == FM1_10GEC2) && + ((is_serdes_configured(XFI_FM1_MAC9)) || + (is_serdes_configured(XFI_FM1_MAC10)))) + return PHY_INTERFACE_MODE_XGMII; + else if ((port == FM1_DTSEC1) || + (port == FM1_DTSEC2) || + (port == FM1_DTSEC3) || + (port == FM1_DTSEC4)) + return PHY_INTERFACE_MODE_NONE; + } + } + } +#endif + /* Fix me need to handle RGMII here first */ switch (port) { diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c index 137886c..f1e39b9 100644 --- a/drivers/net/fm/eth.c +++ b/drivers/net/fm/eth.c @@ -565,9 +565,11 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg) num = fm_eth->num; #ifdef CONFIG_SYS_FMAN_V3 +#ifndef CONFIG_FSL_FM_10GEC_REGULAR_NOTATION if (fm_eth->type == FM_ETH_10G_E) { - /* 10GEC1/10GEC2 use mEMAC9/mEMAC10 - * 10GEC3/10GEC4 use mEMAC1/mEMAC2 + /* 10GEC1/10GEC2 use mEMAC9/mEMAC10 on T2080/T4240. + * 10GEC3/10GEC4 use mEMAC1/mEMAC2 on T2080. + * 10GEC1 uses mEMAC1 on T1024. * so it needs to change the num. */ if (fm_eth->num >= 2) @@ -575,6 +577,7 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg) else num += 8; } +#endif base = ®->memac[num].fm_memac; phyregs = ®->memac[num].fm_memac_mdio; #else diff --git a/drivers/net/fm/init.c b/drivers/net/fm/init.c index 6cf21c6..5d82f29 100644 --- a/drivers/net/fm/init.c +++ b/drivers/net/fm/init.c @@ -254,8 +254,10 @@ static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop) */ if (((info->port == FM1_DTSEC9) && (PORT_IS_ENABLED(FM1_10GEC1))) || ((info->port == FM1_DTSEC10) && (PORT_IS_ENABLED(FM1_10GEC2))) || + ((info->port == FM1_DTSEC1) && (PORT_IS_ENABLED(FM1_10GEC1))) || ((info->port == FM1_DTSEC1) && (PORT_IS_ENABLED(FM1_10GEC3))) || ((info->port == FM1_DTSEC2) && (PORT_IS_ENABLED(FM1_10GEC4))) || + ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC1))) || ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC9))) || ((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC10))) || ((info->port == FM1_10GEC3) && (PORT_IS_ENABLED(FM1_DTSEC1))) || diff --git a/drivers/net/fm/t1024.c b/drivers/net/fm/t1024.c new file mode 100644 index 0000000..9b31173 --- /dev/null +++ b/drivers/net/fm/t1024.c @@ -0,0 +1,88 @@ +/* Copyright 2014 Freescale Semiconductor, Inc. + * + * Shengzhou Liu <Shengzhou.Liu@freescale.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <phy.h> +#include <fm_eth.h> +#include <asm/immap_85xx.h> +#include <asm/fsl_serdes.h> + +u32 port_to_devdisr[] = { + [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1, + [FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2, + [FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3, + [FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4, + [FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1_1, /* MAC1 */ +}; + +static int is_device_disabled(enum fm_port port) +{ + ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + u32 devdisr2 = in_be32(&gur->devdisr2); + + return port_to_devdisr[port] & devdisr2; +} + +void fman_disable_port(enum fm_port port) +{ + ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + + setbits_be32(&gur->devdisr2, port_to_devdisr[port]); +} + +phy_interface_t fman_port_enet_if(enum fm_port port) +{ + ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); + u32 rcwsr13 = in_be32(&gur->rcwsr[13]); + + if (is_device_disabled(port)) + return PHY_INTERFACE_MODE_NONE; + + if ((port == FM1_10GEC1) && (is_serdes_configured(XFI_FM1_MAC1))) + return PHY_INTERFACE_MODE_XGMII; + + if ((port == FM1_DTSEC3) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) == + FSL_CORENET_RCWSR13_EC2_RGMII) && + (!is_serdes_configured(QSGMII_FM1_A))) + return PHY_INTERFACE_MODE_RGMII; + + if ((port == FM1_DTSEC4) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) == + FSL_CORENET_RCWSR13_EC1_RGMII) && + (!is_serdes_configured(QSGMII_FM1_A))) + return PHY_INTERFACE_MODE_RGMII; + + /* handle SGMII */ + switch (port) { + case FM1_DTSEC1: + case FM1_DTSEC2: + case FM1_DTSEC3: + if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1)) + return PHY_INTERFACE_MODE_SGMII; + else if (is_serdes_configured(SGMII_2500_FM1_DTSEC1 + + port - FM1_DTSEC1)) + return PHY_INTERFACE_MODE_SGMII_2500; + break; + default: + break; + } + + /* handle QSGMII */ + switch (port) { + case FM1_DTSEC1: + case FM1_DTSEC2: + case FM1_DTSEC3: + case FM1_DTSEC4: + /* check lane A on SerDes1 */ + if (is_serdes_configured(QSGMII_FM1_A)) + return PHY_INTERFACE_MODE_QSGMII; + break; + default: + break; + } + + return PHY_INTERFACE_MODE_NONE; +} diff --git a/drivers/net/fm/t1040.c b/drivers/net/fm/t1040.c index 4cce46d..d2a097e 100644 --- a/drivers/net/fm/t1040.c +++ b/drivers/net/fm/t1040.c @@ -25,8 +25,6 @@ phy_interface_t fman_port_enet_if(enum fm_port port) else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) == FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_MII) return PHY_INTERFACE_MODE_MII; - else - return PHY_INTERFACE_MODE_NONE; } if ((port == FM1_DTSEC4) && @@ -38,8 +36,6 @@ phy_interface_t fman_port_enet_if(enum fm_port port) else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) == FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_MII) return PHY_INTERFACE_MODE_MII; - else - return PHY_INTERFACE_MODE_NONE; } if (port == FM1_DTSEC5) { diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 9556536..f46bf00 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_PHYLIB) += phy.o obj-$(CONFIG_PHYLIB_10G) += generic_10g.o obj-$(CONFIG_PHY_ATHEROS) += atheros.o obj-$(CONFIG_PHY_BROADCOM) += broadcom.o +obj-$(CONFIG_PHY_CORTINA) += cortina.o obj-$(CONFIG_PHY_DAVICOM) += davicom.o obj-$(CONFIG_PHY_ET1011C) += et1011c.o obj-$(CONFIG_PHY_LXT) += lxt.o diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c new file mode 100644 index 0000000..254f056 --- /dev/null +++ b/drivers/net/phy/cortina.c @@ -0,0 +1,333 @@ +/* + * Cortina CS4315/CS4340 10G PHY drivers + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Copyright 2014 Freescale Semiconductor, Inc. + * + */ + +#include <config.h> +#include <common.h> +#include <malloc.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/err.h> +#include <phy.h> +#include <cortina.h> +#ifdef CONFIG_SYS_CORTINA_FW_IN_NAND +#include <nand.h> +#elif defined(CONFIG_SYS_CORTINA_FW_IN_SPIFLASH) +#include <spi_flash.h> +#elif defined(CONFIG_SYS_CORTINA_FW_IN_MMC) +#include <mmc.h> +#endif + +#ifndef CONFIG_PHYLIB_10G +#error The Cortina PHY needs 10G support +#endif + +struct cortina_reg_config cortina_reg_cfg[] = { + /* CS4315_enable_sr_mode */ + {VILLA_GLOBAL_MSEQCLKCTRL, 0x8004}, + {VILLA_MSEQ_OPTIONS, 0xf}, + {VILLA_MSEQ_PC, 0x0}, + {VILLA_MSEQ_BANKSELECT, 0x4}, + {VILLA_LINE_SDS_COMMON_SRX0_RX_CPA, 0x55}, + {VILLA_LINE_SDS_COMMON_SRX0_RX_LOOP_FILTER, 0x30}, + {VILLA_DSP_SDS_SERDES_SRX_DFE0_SELECT, 0x1}, + {VILLA_DSP_SDS_DSP_COEF_DFE0_SELECT, 0x2}, + {VILLA_LINE_SDS_COMMON_SRX0_RX_CPB, 0x2003}, + {VILLA_DSP_SDS_SERDES_SRX_FFE_DELAY_CTRL, 0xF047}, + {VILLA_MSEQ_ENABLE_MSB, 0x0000}, + {VILLA_MSEQ_SPARE21_LSB, 0x6}, + {VILLA_MSEQ_RESET_COUNT_LSB, 0x0}, + {VILLA_MSEQ_SPARE12_MSB, 0x0000}, + /* + * to invert the receiver path, uncomment the next line + * write (VILLA_MSEQ_SPARE12_MSB, 0x4000) + * + * SPARE2_LSB is used to configure the device while in sr mode to + * enable power savings and to use the optical module LOS signal. + * in power savings mode, the internal prbs checker can not be used. + * if the optical module LOS signal is used as an input to the micro + * code, then the micro code will wait until the optical module + * LOS = 0 before turning on the adaptive equalizer. + * Setting SPARE2_LSB bit 0 to 1 places the devie in power savings mode + * while setting bit 0 to 0 disables power savings mode. + * Setting SPARE2_LSB bit 2 to 0 configures the device to use the + * optical module LOS signal while setting bit 2 to 1 configures the + * device so that it will ignore the optical module LOS SPARE2_LSB = 0 + */ + + /* enable power savings, ignore optical module LOS */ + {VILLA_MSEQ_SPARE2_LSB, 0x5}, + + {VILLA_MSEQ_SPARE7_LSB, 0x1e}, + {VILLA_MSEQ_BANKSELECT, 0x4}, + {VILLA_MSEQ_SPARE9_LSB, 0x2}, + {VILLA_MSEQ_SPARE3_LSB, 0x0F53}, + {VILLA_MSEQ_SPARE3_MSB, 0x2006}, + {VILLA_MSEQ_SPARE8_LSB, 0x3FF7}, + {VILLA_MSEQ_SPARE8_MSB, 0x0A46}, + {VILLA_MSEQ_COEF8_FFE0_LSB, 0xD500}, + {VILLA_MSEQ_COEF8_FFE1_LSB, 0x0200}, + {VILLA_MSEQ_COEF8_FFE2_LSB, 0xBA00}, + {VILLA_MSEQ_COEF8_FFE3_LSB, 0x0100}, + {VILLA_MSEQ_COEF8_FFE4_LSB, 0x0300}, + {VILLA_MSEQ_COEF8_FFE5_LSB, 0x0300}, + {VILLA_MSEQ_COEF8_DFE0_LSB, 0x0700}, + {VILLA_MSEQ_COEF8_DFE0N_LSB, 0x0E00}, + {VILLA_MSEQ_COEF8_DFE1_LSB, 0x0B00}, + {VILLA_DSP_SDS_DSP_COEF_LARGE_LEAK, 0x2}, + {VILLA_DSP_SDS_SERDES_SRX_DAC_ENABLEB_LSB, 0xD000}, + {VILLA_MSEQ_POWER_DOWN_LSB, 0xFFFF}, + {VILLA_MSEQ_POWER_DOWN_MSB, 0x0}, + {VILLA_MSEQ_CAL_RX_SLICER, 0x80}, + {VILLA_DSP_SDS_SERDES_SRX_DAC_BIAS_SELECT1_MSB, 0x3f}, + {VILLA_GLOBAL_MSEQCLKCTRL, 0x4}, + {VILLA_MSEQ_OPTIONS, 0x7}, + + /* set up min value for ffe1 */ + {VILLA_MSEQ_COEF_INIT_SEL, 0x2}, + {VILLA_DSP_SDS_DSP_PRECODEDINITFFE21, 0x41}, + + /* CS4315_sr_rx_pre_eq_set_4in */ + {VILLA_GLOBAL_MSEQCLKCTRL, 0x8004}, + {VILLA_MSEQ_OPTIONS, 0xf}, + {VILLA_MSEQ_BANKSELECT, 0x4}, + {VILLA_MSEQ_PC, 0x0}, + + /* for lengths from 3.5 to 4.5inches */ + {VILLA_MSEQ_SERDES_PARAM_LSB, 0x0306}, + {VILLA_MSEQ_SPARE25_LSB, 0x0306}, + {VILLA_MSEQ_SPARE21_LSB, 0x2}, + {VILLA_MSEQ_SPARE23_LSB, 0x2}, + {VILLA_MSEQ_CAL_RX_DFE_EQ, 0x0}, + + {VILLA_GLOBAL_MSEQCLKCTRL, 0x4}, + {VILLA_MSEQ_OPTIONS, 0x7}, + + /* CS4315_rx_drive_4inch */ + /* for length 4inches */ + {VILLA_GLOBAL_VILLA2_COMPATIBLE, 0x0000}, + {VILLA_HOST_SDS_COMMON_STX0_TX_OUTPUT_CTRLA, 0x3023}, + {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLB, 0xc01E}, + + /* CS4315_tx_drive_4inch */ + /* for length 4inches */ + {VILLA_GLOBAL_VILLA2_COMPATIBLE, 0x0000}, + {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLA, 0x3023}, + {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLB, 0xc01E}, +}; + +void cs4340_upload_firmware(struct phy_device *phydev) +{ + char line_temp[0x50] = {0}; + char reg_addr[0x50] = {0}; + char reg_data[0x50] = {0}; + int i, line_cnt = 0, column_cnt = 0; + struct cortina_reg_config fw_temp; + char *addr = NULL; + +#if defined(CONFIG_SYS_CORTINA_FW_IN_NOR) || \ + defined(CONFIG_SYS_CORTINA_FW_IN_REMOTE) + + addr = (char *)CONFIG_CORTINA_FW_ADDR; +#elif defined(CONFIG_SYS_CORTINA_FW_IN_NAND) + int ret; + size_t fw_length = CONFIG_CORTINA_FW_LENGTH; + + addr = malloc(CONFIG_CORTINA_FW_LENGTH); + ret = nand_read(&nand_info[0], (loff_t)CONFIG_CORTINA_FW_ADDR, + &fw_length, (u_char *)addr); + if (ret == -EUCLEAN) { + printf("NAND read of Cortina firmware at 0x%x failed %d\n", + CONFIG_CORTINA_FW_ADDR, ret); + } +#elif defined(CONFIG_SYS_CORTINA_FW_IN_SPIFLASH) + int ret; + struct spi_flash *ucode_flash; + + addr = malloc(CONFIG_CORTINA_FW_LENGTH); + ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, + CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE); + if (!ucode_flash) { + puts("SF: probe for Cortina ucode failed\n"); + } else { + ret = spi_flash_read(ucode_flash, CONFIG_CORTINA_FW_ADDR, + CONFIG_CORTINA_FW_LENGTH, addr); + if (ret) + puts("SF: read for Cortina ucode failed\n"); + spi_flash_free(ucode_flash); + } +#elif defined(CONFIG_SYS_CORTINA_FW_IN_MMC) + int dev = CONFIG_SYS_MMC_ENV_DEV; + u32 cnt = CONFIG_CORTINA_FW_LENGTH / 512; + u32 blk = CONFIG_CORTINA_FW_ADDR / 512; + struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); + + if (!mmc) { + puts("Failed to find MMC device for Cortina ucode\n"); + } else { + addr = malloc(CONFIG_CORTINA_FW_LENGTH); + printf("MMC read: dev # %u, block # %u, count %u ...\n", + dev, blk, cnt); + mmc_init(mmc); + (void)mmc->block_dev.block_read(dev, blk, cnt, addr); + /* flush cache after read */ + flush_cache((ulong)addr, cnt * 512); + } +#endif + + while (*addr != 'Q') { + i = 0; + + while (*addr != 0x0a) { + line_temp[i++] = *addr++; + if (0x50 < i) { + printf("Not found Cortina PHY ucode at 0x%x\n", + CONFIG_CORTINA_FW_ADDR); + return; + } + } + + addr++; /* skip '\n' */ + line_cnt++; + column_cnt = i; + line_temp[column_cnt] = '\0'; + + if (CONFIG_CORTINA_FW_LENGTH < line_cnt) + return; + + for (i = 0; i < column_cnt; i++) { + if (isspace(line_temp[i++])) + break; + } + + memcpy(reg_addr, line_temp, i); + memcpy(reg_data, &line_temp[i], column_cnt - i); + strim(reg_addr); + strim(reg_data); + fw_temp.reg_addr = (simple_strtoul(reg_addr, NULL, 0)) & 0xffff; + fw_temp.reg_value = (simple_strtoul(reg_data, NULL, 0)) & + 0xffff; + phy_write(phydev, 0x00, fw_temp.reg_addr, fw_temp.reg_value); + } +} + +int cs4340_phy_init(struct phy_device *phydev) +{ + int timeout = 100; /* 100ms */ + int reg_value; + + /* step1: BIST test */ + phy_write(phydev, 0x00, VILLA_GLOBAL_MSEQCLKCTRL, 0x0004); + phy_write(phydev, 0x00, VILLA_GLOBAL_LINE_SOFT_RESET, 0x0000); + phy_write(phydev, 0x00, VILLA_GLOBAL_BIST_CONTROL, 0x0001); + while (--timeout) { + reg_value = phy_read(phydev, 0x00, VILLA_GLOBAL_BIST_STATUS); + if (reg_value & mseq_edc_bist_done) { + if (0 == (reg_value & mseq_edc_bist_fail)) + break; + } + udelay(1000); + } + + if (!timeout) { + printf("%s BIST mseq_edc_bist_done timeout!\n", __func__); + return -1; + } + + /* setp2: upload ucode */ + cs4340_upload_firmware(phydev); + reg_value = phy_read(phydev, 0x00, VILLA_GLOBAL_DWNLD_CHECKSUM_STATUS); + if (reg_value) { + debug("%s checksum status failed.\n", __func__); + return -1; + } + + return 0; +} + +int cs4340_config(struct phy_device *phydev) +{ + cs4340_phy_init(phydev); + return 0; +} + +int cs4340_startup(struct phy_device *phydev) +{ + phydev->link = 1; + + /* For now just lie and say it's 10G all the time */ + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + return 0; +} + +struct phy_driver cs4340_driver = { + .name = "Cortina CS4315/CS4340", + .uid = PHY_UID_CS4340, + .mask = 0xfffffff0, + .features = PHY_10G_FEATURES, + .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS | MDIO_DEVS_AN | + MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2), + .config = &cs4340_config, + .startup = &cs4340_startup, + .shutdown = &gen10g_shutdown, +}; + +int phy_cortina_init(void) +{ + phy_register(&cs4340_driver); + return 0; +} + +int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id) +{ + int phy_reg; + bool is_cortina_phy = false; + + switch (addr) { +#ifdef CORTINA_PHY_ADDR1 + case CORTINA_PHY_ADDR1: +#endif +#ifdef CORTINA_PHY_ADDR2 + case CORTINA_PHY_ADDR2: +#endif +#ifdef CORTINA_PHY_ADDR3 + case CORTINA_PHY_ADDR3: +#endif +#ifdef CORTINA_PHY_ADDR4 + case CORTINA_PHY_ADDR4: +#endif + is_cortina_phy = true; + break; + default: + break; + } + + /* Cortina PHY has non-standard offset of PHY ID registers */ + if (is_cortina_phy) + phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_LSB); + else + phy_reg = bus->read(bus, addr, devad, MII_PHYSID1); + + if (phy_reg < 0) + return -EIO; + + *phy_id = (phy_reg & 0xffff) << 16; + if (is_cortina_phy) + phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_MSB); + else + phy_reg = bus->read(bus, addr, devad, MII_PHYSID2); + + if (phy_reg < 0) + return -EIO; + + *phy_id |= (phy_reg & 0xffff); + + return 0; +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 467c972..5b04c85 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -448,6 +448,9 @@ int phy_init(void) #ifdef CONFIG_PHY_BROADCOM phy_broadcom_init(); #endif +#ifdef CONFIG_PHY_CORTINA + phy_cortina_init(); +#endif #ifdef CONFIG_PHY_DAVICOM phy_davicom_init(); #endif diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c index 2b29cd8..20a6746 100644 --- a/drivers/net/phy/vitesse.c +++ b/drivers/net/phy/vitesse.c @@ -1,8 +1,8 @@ /* * Vitesse PHY drivers * - * Copyright 2010-2012 Freescale Semiconductor, Inc. - * Author: Andy Fleming + * Copyright 2010-2014 Freescale Semiconductor, Inc. + * Original Author: Andy Fleming * Add vsc8662 phy support - Priyanka Jain * SPDX-License-Identifier: GPL-2.0+ */ @@ -50,6 +50,7 @@ #define MIIM_VSC8574_18G_CMDSTAT 0x8000 /* Vitesse VSC8514 control register */ +#define MIIM_VSC8514_MAC_SERDES_CON 0x10 #define MIIM_VSC8514_GENERAL18 0x12 #define MIIM_VSC8514_GENERAL19 0x13 #define MIIM_VSC8514_GENERAL23 0x17 @@ -246,6 +247,14 @@ static int vsc8514_config(struct phy_device *phydev) val = (val & 0xf8ff); phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val); + /* Enable Serdes Auto-negotiation */ + phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, + PHY_EXT_PAGE_ACCESS_EXTENDED3); + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON); + val = val | MIIM_VSC8574_MAC_SERDES_ANEG; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON, val); + phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); + genphy_config_aneg(phydev); return 0; |