19b18e519SShengzhou Liu /* 29b18e519SShengzhou Liu * Cortina CS4315/CS4340 10G PHY drivers 39b18e519SShengzhou Liu * 49b18e519SShengzhou Liu * SPDX-License-Identifier: GPL-2.0+ 59b18e519SShengzhou Liu * 69b18e519SShengzhou Liu * Copyright 2014 Freescale Semiconductor, Inc. 79b18e519SShengzhou Liu * 89b18e519SShengzhou Liu */ 99b18e519SShengzhou Liu 109b18e519SShengzhou Liu #include <config.h> 119b18e519SShengzhou Liu #include <common.h> 129b18e519SShengzhou Liu #include <malloc.h> 139b18e519SShengzhou Liu #include <linux/ctype.h> 149b18e519SShengzhou Liu #include <linux/string.h> 159b18e519SShengzhou Liu #include <linux/err.h> 169b18e519SShengzhou Liu #include <phy.h> 179b18e519SShengzhou Liu #include <cortina.h> 189b18e519SShengzhou Liu #ifdef CONFIG_SYS_CORTINA_FW_IN_NAND 199b18e519SShengzhou Liu #include <nand.h> 209b18e519SShengzhou Liu #elif defined(CONFIG_SYS_CORTINA_FW_IN_SPIFLASH) 219b18e519SShengzhou Liu #include <spi_flash.h> 229b18e519SShengzhou Liu #elif defined(CONFIG_SYS_CORTINA_FW_IN_MMC) 239b18e519SShengzhou Liu #include <mmc.h> 249b18e519SShengzhou Liu #endif 259b18e519SShengzhou Liu 269b18e519SShengzhou Liu #ifndef CONFIG_PHYLIB_10G 279b18e519SShengzhou Liu #error The Cortina PHY needs 10G support 289b18e519SShengzhou Liu #endif 299b18e519SShengzhou Liu 309b18e519SShengzhou Liu struct cortina_reg_config cortina_reg_cfg[] = { 319b18e519SShengzhou Liu /* CS4315_enable_sr_mode */ 329b18e519SShengzhou Liu {VILLA_GLOBAL_MSEQCLKCTRL, 0x8004}, 339b18e519SShengzhou Liu {VILLA_MSEQ_OPTIONS, 0xf}, 349b18e519SShengzhou Liu {VILLA_MSEQ_PC, 0x0}, 359b18e519SShengzhou Liu {VILLA_MSEQ_BANKSELECT, 0x4}, 369b18e519SShengzhou Liu {VILLA_LINE_SDS_COMMON_SRX0_RX_CPA, 0x55}, 379b18e519SShengzhou Liu {VILLA_LINE_SDS_COMMON_SRX0_RX_LOOP_FILTER, 0x30}, 389b18e519SShengzhou Liu {VILLA_DSP_SDS_SERDES_SRX_DFE0_SELECT, 0x1}, 399b18e519SShengzhou Liu {VILLA_DSP_SDS_DSP_COEF_DFE0_SELECT, 0x2}, 409b18e519SShengzhou Liu {VILLA_LINE_SDS_COMMON_SRX0_RX_CPB, 0x2003}, 419b18e519SShengzhou Liu {VILLA_DSP_SDS_SERDES_SRX_FFE_DELAY_CTRL, 0xF047}, 429b18e519SShengzhou Liu {VILLA_MSEQ_ENABLE_MSB, 0x0000}, 439b18e519SShengzhou Liu {VILLA_MSEQ_SPARE21_LSB, 0x6}, 449b18e519SShengzhou Liu {VILLA_MSEQ_RESET_COUNT_LSB, 0x0}, 459b18e519SShengzhou Liu {VILLA_MSEQ_SPARE12_MSB, 0x0000}, 469b18e519SShengzhou Liu /* 479b18e519SShengzhou Liu * to invert the receiver path, uncomment the next line 489b18e519SShengzhou Liu * write (VILLA_MSEQ_SPARE12_MSB, 0x4000) 499b18e519SShengzhou Liu * 509b18e519SShengzhou Liu * SPARE2_LSB is used to configure the device while in sr mode to 519b18e519SShengzhou Liu * enable power savings and to use the optical module LOS signal. 529b18e519SShengzhou Liu * in power savings mode, the internal prbs checker can not be used. 539b18e519SShengzhou Liu * if the optical module LOS signal is used as an input to the micro 549b18e519SShengzhou Liu * code, then the micro code will wait until the optical module 559b18e519SShengzhou Liu * LOS = 0 before turning on the adaptive equalizer. 569b18e519SShengzhou Liu * Setting SPARE2_LSB bit 0 to 1 places the devie in power savings mode 579b18e519SShengzhou Liu * while setting bit 0 to 0 disables power savings mode. 589b18e519SShengzhou Liu * Setting SPARE2_LSB bit 2 to 0 configures the device to use the 599b18e519SShengzhou Liu * optical module LOS signal while setting bit 2 to 1 configures the 609b18e519SShengzhou Liu * device so that it will ignore the optical module LOS SPARE2_LSB = 0 619b18e519SShengzhou Liu */ 629b18e519SShengzhou Liu 639b18e519SShengzhou Liu /* enable power savings, ignore optical module LOS */ 649b18e519SShengzhou Liu {VILLA_MSEQ_SPARE2_LSB, 0x5}, 659b18e519SShengzhou Liu 669b18e519SShengzhou Liu {VILLA_MSEQ_SPARE7_LSB, 0x1e}, 679b18e519SShengzhou Liu {VILLA_MSEQ_BANKSELECT, 0x4}, 689b18e519SShengzhou Liu {VILLA_MSEQ_SPARE9_LSB, 0x2}, 699b18e519SShengzhou Liu {VILLA_MSEQ_SPARE3_LSB, 0x0F53}, 709b18e519SShengzhou Liu {VILLA_MSEQ_SPARE3_MSB, 0x2006}, 719b18e519SShengzhou Liu {VILLA_MSEQ_SPARE8_LSB, 0x3FF7}, 729b18e519SShengzhou Liu {VILLA_MSEQ_SPARE8_MSB, 0x0A46}, 739b18e519SShengzhou Liu {VILLA_MSEQ_COEF8_FFE0_LSB, 0xD500}, 749b18e519SShengzhou Liu {VILLA_MSEQ_COEF8_FFE1_LSB, 0x0200}, 759b18e519SShengzhou Liu {VILLA_MSEQ_COEF8_FFE2_LSB, 0xBA00}, 769b18e519SShengzhou Liu {VILLA_MSEQ_COEF8_FFE3_LSB, 0x0100}, 779b18e519SShengzhou Liu {VILLA_MSEQ_COEF8_FFE4_LSB, 0x0300}, 789b18e519SShengzhou Liu {VILLA_MSEQ_COEF8_FFE5_LSB, 0x0300}, 799b18e519SShengzhou Liu {VILLA_MSEQ_COEF8_DFE0_LSB, 0x0700}, 809b18e519SShengzhou Liu {VILLA_MSEQ_COEF8_DFE0N_LSB, 0x0E00}, 819b18e519SShengzhou Liu {VILLA_MSEQ_COEF8_DFE1_LSB, 0x0B00}, 829b18e519SShengzhou Liu {VILLA_DSP_SDS_DSP_COEF_LARGE_LEAK, 0x2}, 839b18e519SShengzhou Liu {VILLA_DSP_SDS_SERDES_SRX_DAC_ENABLEB_LSB, 0xD000}, 849b18e519SShengzhou Liu {VILLA_MSEQ_POWER_DOWN_LSB, 0xFFFF}, 859b18e519SShengzhou Liu {VILLA_MSEQ_POWER_DOWN_MSB, 0x0}, 869b18e519SShengzhou Liu {VILLA_MSEQ_CAL_RX_SLICER, 0x80}, 879b18e519SShengzhou Liu {VILLA_DSP_SDS_SERDES_SRX_DAC_BIAS_SELECT1_MSB, 0x3f}, 889b18e519SShengzhou Liu {VILLA_GLOBAL_MSEQCLKCTRL, 0x4}, 899b18e519SShengzhou Liu {VILLA_MSEQ_OPTIONS, 0x7}, 909b18e519SShengzhou Liu 919b18e519SShengzhou Liu /* set up min value for ffe1 */ 929b18e519SShengzhou Liu {VILLA_MSEQ_COEF_INIT_SEL, 0x2}, 939b18e519SShengzhou Liu {VILLA_DSP_SDS_DSP_PRECODEDINITFFE21, 0x41}, 949b18e519SShengzhou Liu 959b18e519SShengzhou Liu /* CS4315_sr_rx_pre_eq_set_4in */ 969b18e519SShengzhou Liu {VILLA_GLOBAL_MSEQCLKCTRL, 0x8004}, 979b18e519SShengzhou Liu {VILLA_MSEQ_OPTIONS, 0xf}, 989b18e519SShengzhou Liu {VILLA_MSEQ_BANKSELECT, 0x4}, 999b18e519SShengzhou Liu {VILLA_MSEQ_PC, 0x0}, 1009b18e519SShengzhou Liu 1019b18e519SShengzhou Liu /* for lengths from 3.5 to 4.5inches */ 1029b18e519SShengzhou Liu {VILLA_MSEQ_SERDES_PARAM_LSB, 0x0306}, 1039b18e519SShengzhou Liu {VILLA_MSEQ_SPARE25_LSB, 0x0306}, 1049b18e519SShengzhou Liu {VILLA_MSEQ_SPARE21_LSB, 0x2}, 1059b18e519SShengzhou Liu {VILLA_MSEQ_SPARE23_LSB, 0x2}, 1069b18e519SShengzhou Liu {VILLA_MSEQ_CAL_RX_DFE_EQ, 0x0}, 1079b18e519SShengzhou Liu 1089b18e519SShengzhou Liu {VILLA_GLOBAL_MSEQCLKCTRL, 0x4}, 1099b18e519SShengzhou Liu {VILLA_MSEQ_OPTIONS, 0x7}, 1109b18e519SShengzhou Liu 1119b18e519SShengzhou Liu /* CS4315_rx_drive_4inch */ 1129b18e519SShengzhou Liu /* for length 4inches */ 1139b18e519SShengzhou Liu {VILLA_GLOBAL_VILLA2_COMPATIBLE, 0x0000}, 1149b18e519SShengzhou Liu {VILLA_HOST_SDS_COMMON_STX0_TX_OUTPUT_CTRLA, 0x3023}, 1159b18e519SShengzhou Liu {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLB, 0xc01E}, 1169b18e519SShengzhou Liu 1179b18e519SShengzhou Liu /* CS4315_tx_drive_4inch */ 1189b18e519SShengzhou Liu /* for length 4inches */ 1199b18e519SShengzhou Liu {VILLA_GLOBAL_VILLA2_COMPATIBLE, 0x0000}, 1209b18e519SShengzhou Liu {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLA, 0x3023}, 1219b18e519SShengzhou Liu {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLB, 0xc01E}, 1229b18e519SShengzhou Liu }; 1239b18e519SShengzhou Liu 1249b18e519SShengzhou Liu void cs4340_upload_firmware(struct phy_device *phydev) 1259b18e519SShengzhou Liu { 1269b18e519SShengzhou Liu char line_temp[0x50] = {0}; 1279b18e519SShengzhou Liu char reg_addr[0x50] = {0}; 1289b18e519SShengzhou Liu char reg_data[0x50] = {0}; 1299b18e519SShengzhou Liu int i, line_cnt = 0, column_cnt = 0; 1309b18e519SShengzhou Liu struct cortina_reg_config fw_temp; 1319b18e519SShengzhou Liu char *addr = NULL; 1329b18e519SShengzhou Liu 1339b18e519SShengzhou Liu #if defined(CONFIG_SYS_CORTINA_FW_IN_NOR) || \ 1349b18e519SShengzhou Liu defined(CONFIG_SYS_CORTINA_FW_IN_REMOTE) 1359b18e519SShengzhou Liu 1369b18e519SShengzhou Liu addr = (char *)CONFIG_CORTINA_FW_ADDR; 1379b18e519SShengzhou Liu #elif defined(CONFIG_SYS_CORTINA_FW_IN_NAND) 1389b18e519SShengzhou Liu int ret; 1399b18e519SShengzhou Liu size_t fw_length = CONFIG_CORTINA_FW_LENGTH; 1409b18e519SShengzhou Liu 1419b18e519SShengzhou Liu addr = malloc(CONFIG_CORTINA_FW_LENGTH); 1429b18e519SShengzhou Liu ret = nand_read(&nand_info[0], (loff_t)CONFIG_CORTINA_FW_ADDR, 1439b18e519SShengzhou Liu &fw_length, (u_char *)addr); 1449b18e519SShengzhou Liu if (ret == -EUCLEAN) { 1459b18e519SShengzhou Liu printf("NAND read of Cortina firmware at 0x%x failed %d\n", 1469b18e519SShengzhou Liu CONFIG_CORTINA_FW_ADDR, ret); 1479b18e519SShengzhou Liu } 1489b18e519SShengzhou Liu #elif defined(CONFIG_SYS_CORTINA_FW_IN_SPIFLASH) 1499b18e519SShengzhou Liu int ret; 1509b18e519SShengzhou Liu struct spi_flash *ucode_flash; 1519b18e519SShengzhou Liu 1529b18e519SShengzhou Liu addr = malloc(CONFIG_CORTINA_FW_LENGTH); 1539b18e519SShengzhou Liu ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, 1549b18e519SShengzhou Liu CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE); 1559b18e519SShengzhou Liu if (!ucode_flash) { 1569b18e519SShengzhou Liu puts("SF: probe for Cortina ucode failed\n"); 1579b18e519SShengzhou Liu } else { 1589b18e519SShengzhou Liu ret = spi_flash_read(ucode_flash, CONFIG_CORTINA_FW_ADDR, 1599b18e519SShengzhou Liu CONFIG_CORTINA_FW_LENGTH, addr); 1609b18e519SShengzhou Liu if (ret) 1619b18e519SShengzhou Liu puts("SF: read for Cortina ucode failed\n"); 1629b18e519SShengzhou Liu spi_flash_free(ucode_flash); 1639b18e519SShengzhou Liu } 1649b18e519SShengzhou Liu #elif defined(CONFIG_SYS_CORTINA_FW_IN_MMC) 1659b18e519SShengzhou Liu int dev = CONFIG_SYS_MMC_ENV_DEV; 1669b18e519SShengzhou Liu u32 cnt = CONFIG_CORTINA_FW_LENGTH / 512; 1679b18e519SShengzhou Liu u32 blk = CONFIG_CORTINA_FW_ADDR / 512; 1689b18e519SShengzhou Liu struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV); 1699b18e519SShengzhou Liu 1709b18e519SShengzhou Liu if (!mmc) { 1719b18e519SShengzhou Liu puts("Failed to find MMC device for Cortina ucode\n"); 1729b18e519SShengzhou Liu } else { 1739b18e519SShengzhou Liu addr = malloc(CONFIG_CORTINA_FW_LENGTH); 1749b18e519SShengzhou Liu printf("MMC read: dev # %u, block # %u, count %u ...\n", 1759b18e519SShengzhou Liu dev, blk, cnt); 1769b18e519SShengzhou Liu mmc_init(mmc); 177*7c4213f6SStephen Warren (void)mmc->block_dev.block_read(&mmc->block_dev, blk, cnt, 178*7c4213f6SStephen Warren addr); 1799b18e519SShengzhou Liu /* flush cache after read */ 1809b18e519SShengzhou Liu flush_cache((ulong)addr, cnt * 512); 1819b18e519SShengzhou Liu } 1829b18e519SShengzhou Liu #endif 1839b18e519SShengzhou Liu 1849b18e519SShengzhou Liu while (*addr != 'Q') { 1859b18e519SShengzhou Liu i = 0; 1869b18e519SShengzhou Liu 1879b18e519SShengzhou Liu while (*addr != 0x0a) { 1889b18e519SShengzhou Liu line_temp[i++] = *addr++; 1899b18e519SShengzhou Liu if (0x50 < i) { 1908bb06563Spankaj chauhan printf("Not found Cortina PHY ucode at 0x%p\n", 1918bb06563Spankaj chauhan (char *)CONFIG_CORTINA_FW_ADDR); 1929b18e519SShengzhou Liu return; 1939b18e519SShengzhou Liu } 1949b18e519SShengzhou Liu } 1959b18e519SShengzhou Liu 1969b18e519SShengzhou Liu addr++; /* skip '\n' */ 1979b18e519SShengzhou Liu line_cnt++; 1989b18e519SShengzhou Liu column_cnt = i; 1999b18e519SShengzhou Liu line_temp[column_cnt] = '\0'; 2009b18e519SShengzhou Liu 2019b18e519SShengzhou Liu if (CONFIG_CORTINA_FW_LENGTH < line_cnt) 2029b18e519SShengzhou Liu return; 2039b18e519SShengzhou Liu 2049b18e519SShengzhou Liu for (i = 0; i < column_cnt; i++) { 2059b18e519SShengzhou Liu if (isspace(line_temp[i++])) 2069b18e519SShengzhou Liu break; 2079b18e519SShengzhou Liu } 2089b18e519SShengzhou Liu 2099b18e519SShengzhou Liu memcpy(reg_addr, line_temp, i); 2109b18e519SShengzhou Liu memcpy(reg_data, &line_temp[i], column_cnt - i); 2119b18e519SShengzhou Liu strim(reg_addr); 2129b18e519SShengzhou Liu strim(reg_data); 2139b18e519SShengzhou Liu fw_temp.reg_addr = (simple_strtoul(reg_addr, NULL, 0)) & 0xffff; 2149b18e519SShengzhou Liu fw_temp.reg_value = (simple_strtoul(reg_data, NULL, 0)) & 2159b18e519SShengzhou Liu 0xffff; 2169b18e519SShengzhou Liu phy_write(phydev, 0x00, fw_temp.reg_addr, fw_temp.reg_value); 2179b18e519SShengzhou Liu } 2189b18e519SShengzhou Liu } 2199b18e519SShengzhou Liu 2209b18e519SShengzhou Liu int cs4340_phy_init(struct phy_device *phydev) 2219b18e519SShengzhou Liu { 2229b18e519SShengzhou Liu int timeout = 100; /* 100ms */ 2239b18e519SShengzhou Liu int reg_value; 2249b18e519SShengzhou Liu 2259b18e519SShengzhou Liu /* step1: BIST test */ 2269b18e519SShengzhou Liu phy_write(phydev, 0x00, VILLA_GLOBAL_MSEQCLKCTRL, 0x0004); 2279b18e519SShengzhou Liu phy_write(phydev, 0x00, VILLA_GLOBAL_LINE_SOFT_RESET, 0x0000); 2289b18e519SShengzhou Liu phy_write(phydev, 0x00, VILLA_GLOBAL_BIST_CONTROL, 0x0001); 2299b18e519SShengzhou Liu while (--timeout) { 2309b18e519SShengzhou Liu reg_value = phy_read(phydev, 0x00, VILLA_GLOBAL_BIST_STATUS); 2319b18e519SShengzhou Liu if (reg_value & mseq_edc_bist_done) { 2329b18e519SShengzhou Liu if (0 == (reg_value & mseq_edc_bist_fail)) 2339b18e519SShengzhou Liu break; 2349b18e519SShengzhou Liu } 2359b18e519SShengzhou Liu udelay(1000); 2369b18e519SShengzhou Liu } 2379b18e519SShengzhou Liu 2389b18e519SShengzhou Liu if (!timeout) { 2399b18e519SShengzhou Liu printf("%s BIST mseq_edc_bist_done timeout!\n", __func__); 2409b18e519SShengzhou Liu return -1; 2419b18e519SShengzhou Liu } 2429b18e519SShengzhou Liu 2439b18e519SShengzhou Liu /* setp2: upload ucode */ 2449b18e519SShengzhou Liu cs4340_upload_firmware(phydev); 2459b18e519SShengzhou Liu reg_value = phy_read(phydev, 0x00, VILLA_GLOBAL_DWNLD_CHECKSUM_STATUS); 2469b18e519SShengzhou Liu if (reg_value) { 2479b18e519SShengzhou Liu debug("%s checksum status failed.\n", __func__); 2489b18e519SShengzhou Liu return -1; 2499b18e519SShengzhou Liu } 2509b18e519SShengzhou Liu 2519b18e519SShengzhou Liu return 0; 2529b18e519SShengzhou Liu } 2539b18e519SShengzhou Liu 2549b18e519SShengzhou Liu int cs4340_config(struct phy_device *phydev) 2559b18e519SShengzhou Liu { 2569b18e519SShengzhou Liu cs4340_phy_init(phydev); 2579b18e519SShengzhou Liu return 0; 2589b18e519SShengzhou Liu } 2599b18e519SShengzhou Liu 2609b18e519SShengzhou Liu int cs4340_startup(struct phy_device *phydev) 2619b18e519SShengzhou Liu { 2629b18e519SShengzhou Liu phydev->link = 1; 2639b18e519SShengzhou Liu 2649b18e519SShengzhou Liu /* For now just lie and say it's 10G all the time */ 2659b18e519SShengzhou Liu phydev->speed = SPEED_10000; 2669b18e519SShengzhou Liu phydev->duplex = DUPLEX_FULL; 2679b18e519SShengzhou Liu return 0; 2689b18e519SShengzhou Liu } 2699b18e519SShengzhou Liu 2709b18e519SShengzhou Liu struct phy_driver cs4340_driver = { 2719b18e519SShengzhou Liu .name = "Cortina CS4315/CS4340", 2729b18e519SShengzhou Liu .uid = PHY_UID_CS4340, 2739b18e519SShengzhou Liu .mask = 0xfffffff0, 2749b18e519SShengzhou Liu .features = PHY_10G_FEATURES, 2759b18e519SShengzhou Liu .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | 2769b18e519SShengzhou Liu MDIO_DEVS_PHYXS | MDIO_DEVS_AN | 2779b18e519SShengzhou Liu MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2), 2789b18e519SShengzhou Liu .config = &cs4340_config, 2799b18e519SShengzhou Liu .startup = &cs4340_startup, 2809b18e519SShengzhou Liu .shutdown = &gen10g_shutdown, 2819b18e519SShengzhou Liu }; 2829b18e519SShengzhou Liu 2839b18e519SShengzhou Liu int phy_cortina_init(void) 2849b18e519SShengzhou Liu { 2859b18e519SShengzhou Liu phy_register(&cs4340_driver); 2869b18e519SShengzhou Liu return 0; 2879b18e519SShengzhou Liu } 2889b18e519SShengzhou Liu 2899b18e519SShengzhou Liu int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id) 2909b18e519SShengzhou Liu { 2919b18e519SShengzhou Liu int phy_reg; 2929b18e519SShengzhou Liu bool is_cortina_phy = false; 2939b18e519SShengzhou Liu 2949b18e519SShengzhou Liu switch (addr) { 2959b18e519SShengzhou Liu #ifdef CORTINA_PHY_ADDR1 2969b18e519SShengzhou Liu case CORTINA_PHY_ADDR1: 2979b18e519SShengzhou Liu #endif 2989b18e519SShengzhou Liu #ifdef CORTINA_PHY_ADDR2 2999b18e519SShengzhou Liu case CORTINA_PHY_ADDR2: 3009b18e519SShengzhou Liu #endif 3019b18e519SShengzhou Liu #ifdef CORTINA_PHY_ADDR3 3029b18e519SShengzhou Liu case CORTINA_PHY_ADDR3: 3039b18e519SShengzhou Liu #endif 3049b18e519SShengzhou Liu #ifdef CORTINA_PHY_ADDR4 3059b18e519SShengzhou Liu case CORTINA_PHY_ADDR4: 3069b18e519SShengzhou Liu #endif 3079b18e519SShengzhou Liu is_cortina_phy = true; 3089b18e519SShengzhou Liu break; 3099b18e519SShengzhou Liu default: 3109b18e519SShengzhou Liu break; 3119b18e519SShengzhou Liu } 3129b18e519SShengzhou Liu 3139b18e519SShengzhou Liu /* Cortina PHY has non-standard offset of PHY ID registers */ 3149b18e519SShengzhou Liu if (is_cortina_phy) 3159b18e519SShengzhou Liu phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_LSB); 3169b18e519SShengzhou Liu else 3179b18e519SShengzhou Liu phy_reg = bus->read(bus, addr, devad, MII_PHYSID1); 3189b18e519SShengzhou Liu 3199b18e519SShengzhou Liu if (phy_reg < 0) 3209b18e519SShengzhou Liu return -EIO; 3219b18e519SShengzhou Liu 3229b18e519SShengzhou Liu *phy_id = (phy_reg & 0xffff) << 16; 3239b18e519SShengzhou Liu if (is_cortina_phy) 3249b18e519SShengzhou Liu phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_MSB); 3259b18e519SShengzhou Liu else 3269b18e519SShengzhou Liu phy_reg = bus->read(bus, addr, devad, MII_PHYSID2); 3279b18e519SShengzhou Liu 3289b18e519SShengzhou Liu if (phy_reg < 0) 3299b18e519SShengzhou Liu return -EIO; 3309b18e519SShengzhou Liu 3319b18e519SShengzhou Liu *phy_id |= (phy_reg & 0xffff); 3329b18e519SShengzhou Liu 3339b18e519SShengzhou Liu return 0; 3349b18e519SShengzhou Liu } 335