162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* $Date: 2005/10/24 23:18:13 $ $RCSfile: mv88e1xxx.c,v $ $Revision: 1.49 $ */ 362306a36Sopenharmony_ci#include "common.h" 462306a36Sopenharmony_ci#include "mv88e1xxx.h" 562306a36Sopenharmony_ci#include "cphy.h" 662306a36Sopenharmony_ci#include "elmer0.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* MV88E1XXX MDI crossover register values */ 962306a36Sopenharmony_ci#define CROSSOVER_MDI 0 1062306a36Sopenharmony_ci#define CROSSOVER_MDIX 1 1162306a36Sopenharmony_ci#define CROSSOVER_AUTO 3 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define INTR_ENABLE_MASK 0x6CA0 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * Set the bits given by 'bitval' in PHY register 'reg'. 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_cistatic void mdio_set_bit(struct cphy *cphy, int reg, u32 bitval) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci u32 val; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci (void) simple_mdio_read(cphy, reg, &val); 2362306a36Sopenharmony_ci (void) simple_mdio_write(cphy, reg, val | bitval); 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * Clear the bits given by 'bitval' in PHY register 'reg'. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_cistatic void mdio_clear_bit(struct cphy *cphy, int reg, u32 bitval) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci u32 val; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci (void) simple_mdio_read(cphy, reg, &val); 3462306a36Sopenharmony_ci (void) simple_mdio_write(cphy, reg, val & ~bitval); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * NAME: phy_reset 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * DESC: Reset the given PHY's port. NOTE: This is not a global 4162306a36Sopenharmony_ci * chip reset. 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * PARAMS: cphy - Pointer to PHY instance data. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * RETURN: 0 - Successful reset. 4662306a36Sopenharmony_ci * -1 - Timeout. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_cistatic int mv88e1xxx_reset(struct cphy *cphy, int wait) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci u32 ctl; 5162306a36Sopenharmony_ci int time_out = 1000; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci mdio_set_bit(cphy, MII_BMCR, BMCR_RESET); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci do { 5662306a36Sopenharmony_ci (void) simple_mdio_read(cphy, MII_BMCR, &ctl); 5762306a36Sopenharmony_ci ctl &= BMCR_RESET; 5862306a36Sopenharmony_ci if (ctl) 5962306a36Sopenharmony_ci udelay(1); 6062306a36Sopenharmony_ci } while (ctl && --time_out); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci return ctl ? -1 : 0; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic int mv88e1xxx_interrupt_enable(struct cphy *cphy) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci /* Enable PHY interrupts. */ 6862306a36Sopenharmony_ci (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, 6962306a36Sopenharmony_ci INTR_ENABLE_MASK); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* Enable Marvell interrupts through Elmer0. */ 7262306a36Sopenharmony_ci if (t1_is_asic(cphy->adapter)) { 7362306a36Sopenharmony_ci u32 elmer; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); 7662306a36Sopenharmony_ci elmer |= ELMER0_GP_BIT1; 7762306a36Sopenharmony_ci if (is_T2(cphy->adapter)) 7862306a36Sopenharmony_ci elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4; 7962306a36Sopenharmony_ci t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic int mv88e1xxx_interrupt_disable(struct cphy *cphy) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci /* Disable all phy interrupts. */ 8762306a36Sopenharmony_ci (void) simple_mdio_write(cphy, MV88E1XXX_INTERRUPT_ENABLE_REGISTER, 0); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* Disable Marvell interrupts through Elmer0. */ 9062306a36Sopenharmony_ci if (t1_is_asic(cphy->adapter)) { 9162306a36Sopenharmony_ci u32 elmer; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); 9462306a36Sopenharmony_ci elmer &= ~ELMER0_GP_BIT1; 9562306a36Sopenharmony_ci if (is_T2(cphy->adapter)) 9662306a36Sopenharmony_ci elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4); 9762306a36Sopenharmony_ci t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic int mv88e1xxx_interrupt_clear(struct cphy *cphy) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci u32 elmer; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* Clear PHY interrupts by reading the register. */ 10762306a36Sopenharmony_ci (void) simple_mdio_read(cphy, 10862306a36Sopenharmony_ci MV88E1XXX_INTERRUPT_STATUS_REGISTER, &elmer); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Clear Marvell interrupts through Elmer0. */ 11162306a36Sopenharmony_ci if (t1_is_asic(cphy->adapter)) { 11262306a36Sopenharmony_ci t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); 11362306a36Sopenharmony_ci elmer |= ELMER0_GP_BIT1; 11462306a36Sopenharmony_ci if (is_T2(cphy->adapter)) 11562306a36Sopenharmony_ci elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; 11662306a36Sopenharmony_ci t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * Set the PHY speed and duplex. This also disables auto-negotiation, except 12362306a36Sopenharmony_ci * for 1Gb/s, where auto-negotiation is mandatory. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_cistatic int mv88e1xxx_set_speed_duplex(struct cphy *phy, int speed, int duplex) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci u32 ctl; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci (void) simple_mdio_read(phy, MII_BMCR, &ctl); 13062306a36Sopenharmony_ci if (speed >= 0) { 13162306a36Sopenharmony_ci ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); 13262306a36Sopenharmony_ci if (speed == SPEED_100) 13362306a36Sopenharmony_ci ctl |= BMCR_SPEED100; 13462306a36Sopenharmony_ci else if (speed == SPEED_1000) 13562306a36Sopenharmony_ci ctl |= BMCR_SPEED1000; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci if (duplex >= 0) { 13862306a36Sopenharmony_ci ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); 13962306a36Sopenharmony_ci if (duplex == DUPLEX_FULL) 14062306a36Sopenharmony_ci ctl |= BMCR_FULLDPLX; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */ 14362306a36Sopenharmony_ci ctl |= BMCR_ANENABLE; 14462306a36Sopenharmony_ci (void) simple_mdio_write(phy, MII_BMCR, ctl); 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int mv88e1xxx_crossover_set(struct cphy *cphy, int crossover) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci u32 data32; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci (void) simple_mdio_read(cphy, 15362306a36Sopenharmony_ci MV88E1XXX_SPECIFIC_CNTRL_REGISTER, &data32); 15462306a36Sopenharmony_ci data32 &= ~V_PSCR_MDI_XOVER_MODE(M_PSCR_MDI_XOVER_MODE); 15562306a36Sopenharmony_ci data32 |= V_PSCR_MDI_XOVER_MODE(crossover); 15662306a36Sopenharmony_ci (void) simple_mdio_write(cphy, 15762306a36Sopenharmony_ci MV88E1XXX_SPECIFIC_CNTRL_REGISTER, data32); 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic int mv88e1xxx_autoneg_enable(struct cphy *cphy) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci u32 ctl; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_AUTO); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci (void) simple_mdio_read(cphy, MII_BMCR, &ctl); 16862306a36Sopenharmony_ci /* restart autoneg for change to take effect */ 16962306a36Sopenharmony_ci ctl |= BMCR_ANENABLE | BMCR_ANRESTART; 17062306a36Sopenharmony_ci (void) simple_mdio_write(cphy, MII_BMCR, ctl); 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int mv88e1xxx_autoneg_disable(struct cphy *cphy) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci u32 ctl; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * Crossover *must* be set to manual in order to disable auto-neg. 18062306a36Sopenharmony_ci * The Alaska FAQs document highlights this point. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci (void) mv88e1xxx_crossover_set(cphy, CROSSOVER_MDI); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci /* 18562306a36Sopenharmony_ci * Must include autoneg reset when disabling auto-neg. This 18662306a36Sopenharmony_ci * is described in the Alaska FAQ document. 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_ci (void) simple_mdio_read(cphy, MII_BMCR, &ctl); 18962306a36Sopenharmony_ci ctl &= ~BMCR_ANENABLE; 19062306a36Sopenharmony_ci (void) simple_mdio_write(cphy, MII_BMCR, ctl | BMCR_ANRESTART); 19162306a36Sopenharmony_ci return 0; 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int mv88e1xxx_autoneg_restart(struct cphy *cphy) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci mdio_set_bit(cphy, MII_BMCR, BMCR_ANRESTART); 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int mv88e1xxx_advertise(struct cphy *phy, unsigned int advertise_map) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci u32 val = 0; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (advertise_map & 20562306a36Sopenharmony_ci (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) { 20662306a36Sopenharmony_ci (void) simple_mdio_read(phy, MII_GBCR, &val); 20762306a36Sopenharmony_ci val &= ~(GBCR_ADV_1000HALF | GBCR_ADV_1000FULL); 20862306a36Sopenharmony_ci if (advertise_map & ADVERTISED_1000baseT_Half) 20962306a36Sopenharmony_ci val |= GBCR_ADV_1000HALF; 21062306a36Sopenharmony_ci if (advertise_map & ADVERTISED_1000baseT_Full) 21162306a36Sopenharmony_ci val |= GBCR_ADV_1000FULL; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci (void) simple_mdio_write(phy, MII_GBCR, val); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci val = 1; 21662306a36Sopenharmony_ci if (advertise_map & ADVERTISED_10baseT_Half) 21762306a36Sopenharmony_ci val |= ADVERTISE_10HALF; 21862306a36Sopenharmony_ci if (advertise_map & ADVERTISED_10baseT_Full) 21962306a36Sopenharmony_ci val |= ADVERTISE_10FULL; 22062306a36Sopenharmony_ci if (advertise_map & ADVERTISED_100baseT_Half) 22162306a36Sopenharmony_ci val |= ADVERTISE_100HALF; 22262306a36Sopenharmony_ci if (advertise_map & ADVERTISED_100baseT_Full) 22362306a36Sopenharmony_ci val |= ADVERTISE_100FULL; 22462306a36Sopenharmony_ci if (advertise_map & ADVERTISED_PAUSE) 22562306a36Sopenharmony_ci val |= ADVERTISE_PAUSE; 22662306a36Sopenharmony_ci if (advertise_map & ADVERTISED_ASYM_PAUSE) 22762306a36Sopenharmony_ci val |= ADVERTISE_PAUSE_ASYM; 22862306a36Sopenharmony_ci (void) simple_mdio_write(phy, MII_ADVERTISE, val); 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int mv88e1xxx_set_loopback(struct cphy *cphy, int on) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci if (on) 23562306a36Sopenharmony_ci mdio_set_bit(cphy, MII_BMCR, BMCR_LOOPBACK); 23662306a36Sopenharmony_ci else 23762306a36Sopenharmony_ci mdio_clear_bit(cphy, MII_BMCR, BMCR_LOOPBACK); 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int mv88e1xxx_get_link_status(struct cphy *cphy, int *link_ok, 24262306a36Sopenharmony_ci int *speed, int *duplex, int *fc) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci u32 status; 24562306a36Sopenharmony_ci int sp = -1, dplx = -1, pause = 0; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci (void) simple_mdio_read(cphy, 24862306a36Sopenharmony_ci MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status); 24962306a36Sopenharmony_ci if ((status & V_PSSR_STATUS_RESOLVED) != 0) { 25062306a36Sopenharmony_ci if (status & V_PSSR_RX_PAUSE) 25162306a36Sopenharmony_ci pause |= PAUSE_RX; 25262306a36Sopenharmony_ci if (status & V_PSSR_TX_PAUSE) 25362306a36Sopenharmony_ci pause |= PAUSE_TX; 25462306a36Sopenharmony_ci dplx = (status & V_PSSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; 25562306a36Sopenharmony_ci sp = G_PSSR_SPEED(status); 25662306a36Sopenharmony_ci if (sp == 0) 25762306a36Sopenharmony_ci sp = SPEED_10; 25862306a36Sopenharmony_ci else if (sp == 1) 25962306a36Sopenharmony_ci sp = SPEED_100; 26062306a36Sopenharmony_ci else 26162306a36Sopenharmony_ci sp = SPEED_1000; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci if (link_ok) 26462306a36Sopenharmony_ci *link_ok = (status & V_PSSR_LINK) != 0; 26562306a36Sopenharmony_ci if (speed) 26662306a36Sopenharmony_ci *speed = sp; 26762306a36Sopenharmony_ci if (duplex) 26862306a36Sopenharmony_ci *duplex = dplx; 26962306a36Sopenharmony_ci if (fc) 27062306a36Sopenharmony_ci *fc = pause; 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int mv88e1xxx_downshift_set(struct cphy *cphy, int downshift_enable) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci u32 val; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci (void) simple_mdio_read(cphy, 27962306a36Sopenharmony_ci MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, &val); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* 28262306a36Sopenharmony_ci * Set the downshift counter to 2 so we try to establish Gb link 28362306a36Sopenharmony_ci * twice before downshifting. 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci val &= ~(V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(M_DOWNSHIFT_CNT)); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (downshift_enable) 28862306a36Sopenharmony_ci val |= V_DOWNSHIFT_ENABLE | V_DOWNSHIFT_CNT(2); 28962306a36Sopenharmony_ci (void) simple_mdio_write(cphy, 29062306a36Sopenharmony_ci MV88E1XXX_EXT_PHY_SPECIFIC_CNTRL_REGISTER, val); 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic int mv88e1xxx_interrupt_handler(struct cphy *cphy) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci int cphy_cause = 0; 29762306a36Sopenharmony_ci u32 status; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* 30062306a36Sopenharmony_ci * Loop until cause reads zero. Need to handle bouncing interrupts. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci while (1) { 30362306a36Sopenharmony_ci u32 cause; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci (void) simple_mdio_read(cphy, 30662306a36Sopenharmony_ci MV88E1XXX_INTERRUPT_STATUS_REGISTER, 30762306a36Sopenharmony_ci &cause); 30862306a36Sopenharmony_ci cause &= INTR_ENABLE_MASK; 30962306a36Sopenharmony_ci if (!cause) 31062306a36Sopenharmony_ci break; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (cause & MV88E1XXX_INTR_LINK_CHNG) { 31362306a36Sopenharmony_ci (void) simple_mdio_read(cphy, 31462306a36Sopenharmony_ci MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (status & MV88E1XXX_INTR_LINK_CHNG) 31762306a36Sopenharmony_ci cphy->state |= PHY_LINK_UP; 31862306a36Sopenharmony_ci else { 31962306a36Sopenharmony_ci cphy->state &= ~PHY_LINK_UP; 32062306a36Sopenharmony_ci if (cphy->state & PHY_AUTONEG_EN) 32162306a36Sopenharmony_ci cphy->state &= ~PHY_AUTONEG_RDY; 32262306a36Sopenharmony_ci cphy_cause |= cphy_cause_link_change; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (cause & MV88E1XXX_INTR_AUTONEG_DONE) 32762306a36Sopenharmony_ci cphy->state |= PHY_AUTONEG_RDY; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if ((cphy->state & (PHY_LINK_UP | PHY_AUTONEG_RDY)) == 33062306a36Sopenharmony_ci (PHY_LINK_UP | PHY_AUTONEG_RDY)) 33162306a36Sopenharmony_ci cphy_cause |= cphy_cause_link_change; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci return cphy_cause; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void mv88e1xxx_destroy(struct cphy *cphy) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci kfree(cphy); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic const struct cphy_ops mv88e1xxx_ops = { 34262306a36Sopenharmony_ci .destroy = mv88e1xxx_destroy, 34362306a36Sopenharmony_ci .reset = mv88e1xxx_reset, 34462306a36Sopenharmony_ci .interrupt_enable = mv88e1xxx_interrupt_enable, 34562306a36Sopenharmony_ci .interrupt_disable = mv88e1xxx_interrupt_disable, 34662306a36Sopenharmony_ci .interrupt_clear = mv88e1xxx_interrupt_clear, 34762306a36Sopenharmony_ci .interrupt_handler = mv88e1xxx_interrupt_handler, 34862306a36Sopenharmony_ci .autoneg_enable = mv88e1xxx_autoneg_enable, 34962306a36Sopenharmony_ci .autoneg_disable = mv88e1xxx_autoneg_disable, 35062306a36Sopenharmony_ci .autoneg_restart = mv88e1xxx_autoneg_restart, 35162306a36Sopenharmony_ci .advertise = mv88e1xxx_advertise, 35262306a36Sopenharmony_ci .set_loopback = mv88e1xxx_set_loopback, 35362306a36Sopenharmony_ci .set_speed_duplex = mv88e1xxx_set_speed_duplex, 35462306a36Sopenharmony_ci .get_link_status = mv88e1xxx_get_link_status, 35562306a36Sopenharmony_ci}; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic struct cphy *mv88e1xxx_phy_create(struct net_device *dev, int phy_addr, 35862306a36Sopenharmony_ci const struct mdio_ops *mdio_ops) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct adapter *adapter = netdev_priv(dev); 36162306a36Sopenharmony_ci struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (!cphy) 36462306a36Sopenharmony_ci return NULL; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci cphy_init(cphy, dev, phy_addr, &mv88e1xxx_ops, mdio_ops); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* Configure particular PHY's to run in a different mode. */ 36962306a36Sopenharmony_ci if ((board_info(adapter)->caps & SUPPORTED_TP) && 37062306a36Sopenharmony_ci board_info(adapter)->chip_phy == CHBT_PHY_88E1111) { 37162306a36Sopenharmony_ci /* 37262306a36Sopenharmony_ci * Configure the PHY transmitter as class A to reduce EMI. 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_ci (void) simple_mdio_write(cphy, 37562306a36Sopenharmony_ci MV88E1XXX_EXTENDED_ADDR_REGISTER, 0xB); 37662306a36Sopenharmony_ci (void) simple_mdio_write(cphy, 37762306a36Sopenharmony_ci MV88E1XXX_EXTENDED_REGISTER, 0x8004); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci (void) mv88e1xxx_downshift_set(cphy, 1); /* Enable downshift */ 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* LED */ 38262306a36Sopenharmony_ci if (is_T2(adapter)) { 38362306a36Sopenharmony_ci (void) simple_mdio_write(cphy, 38462306a36Sopenharmony_ci MV88E1XXX_LED_CONTROL_REGISTER, 0x1); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci return cphy; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic int mv88e1xxx_phy_reset(adapter_t* adapter) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci return 0; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ciconst struct gphy t1_mv88e1xxx_ops = { 39662306a36Sopenharmony_ci .create = mv88e1xxx_phy_create, 39762306a36Sopenharmony_ci .reset = mv88e1xxx_phy_reset 39862306a36Sopenharmony_ci}; 399