1*d397f7c4SAlexandru Gagniuc /* 2*d397f7c4SAlexandru Gagniuc * Micrel PHY drivers 3*d397f7c4SAlexandru Gagniuc * 4*d397f7c4SAlexandru Gagniuc * SPDX-License-Identifier: GPL-2.0+ 5*d397f7c4SAlexandru Gagniuc * 6*d397f7c4SAlexandru Gagniuc * Copyright 2010-2011 Freescale Semiconductor, Inc. 7*d397f7c4SAlexandru Gagniuc * author Andy Fleming 8*d397f7c4SAlexandru Gagniuc * (C) 2012 NetModule AG, David Andrey, added KSZ9031 9*d397f7c4SAlexandru Gagniuc */ 10*d397f7c4SAlexandru Gagniuc #include <config.h> 11*d397f7c4SAlexandru Gagniuc #include <common.h> 12*d397f7c4SAlexandru Gagniuc #include <dm.h> 13*d397f7c4SAlexandru Gagniuc #include <errno.h> 14*d397f7c4SAlexandru Gagniuc #include <fdtdec.h> 15*d397f7c4SAlexandru Gagniuc #include <micrel.h> 16*d397f7c4SAlexandru Gagniuc #include <phy.h> 17*d397f7c4SAlexandru Gagniuc 18*d397f7c4SAlexandru Gagniuc DECLARE_GLOBAL_DATA_PTR; 19*d397f7c4SAlexandru Gagniuc 20*d397f7c4SAlexandru Gagniuc static struct phy_driver KSZ804_driver = { 21*d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ804", 22*d397f7c4SAlexandru Gagniuc .uid = 0x221510, 23*d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 24*d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 25*d397f7c4SAlexandru Gagniuc .config = &genphy_config, 26*d397f7c4SAlexandru Gagniuc .startup = &genphy_startup, 27*d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 28*d397f7c4SAlexandru Gagniuc }; 29*d397f7c4SAlexandru Gagniuc 30*d397f7c4SAlexandru Gagniuc #define MII_KSZPHY_OMSO 0x16 31*d397f7c4SAlexandru Gagniuc #define KSZPHY_OMSO_B_CAST_OFF (1 << 9) 32*d397f7c4SAlexandru Gagniuc 33*d397f7c4SAlexandru Gagniuc static int ksz_genconfig_bcastoff(struct phy_device *phydev) 34*d397f7c4SAlexandru Gagniuc { 35*d397f7c4SAlexandru Gagniuc int ret; 36*d397f7c4SAlexandru Gagniuc 37*d397f7c4SAlexandru Gagniuc ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO); 38*d397f7c4SAlexandru Gagniuc if (ret < 0) 39*d397f7c4SAlexandru Gagniuc return ret; 40*d397f7c4SAlexandru Gagniuc 41*d397f7c4SAlexandru Gagniuc ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO, 42*d397f7c4SAlexandru Gagniuc ret | KSZPHY_OMSO_B_CAST_OFF); 43*d397f7c4SAlexandru Gagniuc if (ret < 0) 44*d397f7c4SAlexandru Gagniuc return ret; 45*d397f7c4SAlexandru Gagniuc 46*d397f7c4SAlexandru Gagniuc return genphy_config(phydev); 47*d397f7c4SAlexandru Gagniuc } 48*d397f7c4SAlexandru Gagniuc 49*d397f7c4SAlexandru Gagniuc static struct phy_driver KSZ8031_driver = { 50*d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ8021/KSZ8031", 51*d397f7c4SAlexandru Gagniuc .uid = 0x221550, 52*d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 53*d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 54*d397f7c4SAlexandru Gagniuc .config = &ksz_genconfig_bcastoff, 55*d397f7c4SAlexandru Gagniuc .startup = &genphy_startup, 56*d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 57*d397f7c4SAlexandru Gagniuc }; 58*d397f7c4SAlexandru Gagniuc 59*d397f7c4SAlexandru Gagniuc /** 60*d397f7c4SAlexandru Gagniuc * KSZ8051 61*d397f7c4SAlexandru Gagniuc */ 62*d397f7c4SAlexandru Gagniuc #define MII_KSZ8051_PHY_OMSO 0x16 63*d397f7c4SAlexandru Gagniuc #define MII_KSZ8051_PHY_OMSO_NAND_TREE_ON (1 << 5) 64*d397f7c4SAlexandru Gagniuc 65*d397f7c4SAlexandru Gagniuc static int ksz8051_config(struct phy_device *phydev) 66*d397f7c4SAlexandru Gagniuc { 67*d397f7c4SAlexandru Gagniuc unsigned val; 68*d397f7c4SAlexandru Gagniuc 69*d397f7c4SAlexandru Gagniuc /* Disable NAND-tree */ 70*d397f7c4SAlexandru Gagniuc val = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ8051_PHY_OMSO); 71*d397f7c4SAlexandru Gagniuc val &= ~MII_KSZ8051_PHY_OMSO_NAND_TREE_ON; 72*d397f7c4SAlexandru Gagniuc phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ8051_PHY_OMSO, val); 73*d397f7c4SAlexandru Gagniuc 74*d397f7c4SAlexandru Gagniuc return genphy_config(phydev); 75*d397f7c4SAlexandru Gagniuc } 76*d397f7c4SAlexandru Gagniuc 77*d397f7c4SAlexandru Gagniuc static struct phy_driver KSZ8051_driver = { 78*d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ8051", 79*d397f7c4SAlexandru Gagniuc .uid = 0x221550, 80*d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 81*d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 82*d397f7c4SAlexandru Gagniuc .config = &ksz8051_config, 83*d397f7c4SAlexandru Gagniuc .startup = &genphy_startup, 84*d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 85*d397f7c4SAlexandru Gagniuc }; 86*d397f7c4SAlexandru Gagniuc 87*d397f7c4SAlexandru Gagniuc static struct phy_driver KSZ8081_driver = { 88*d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ8081", 89*d397f7c4SAlexandru Gagniuc .uid = 0x221560, 90*d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 91*d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 92*d397f7c4SAlexandru Gagniuc .config = &ksz_genconfig_bcastoff, 93*d397f7c4SAlexandru Gagniuc .startup = &genphy_startup, 94*d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 95*d397f7c4SAlexandru Gagniuc }; 96*d397f7c4SAlexandru Gagniuc 97*d397f7c4SAlexandru Gagniuc /** 98*d397f7c4SAlexandru Gagniuc * KSZ8895 99*d397f7c4SAlexandru Gagniuc */ 100*d397f7c4SAlexandru Gagniuc 101*d397f7c4SAlexandru Gagniuc static unsigned short smireg_to_phy(unsigned short reg) 102*d397f7c4SAlexandru Gagniuc { 103*d397f7c4SAlexandru Gagniuc return ((reg & 0xc0) >> 3) + 0x06 + ((reg & 0x20) >> 5); 104*d397f7c4SAlexandru Gagniuc } 105*d397f7c4SAlexandru Gagniuc 106*d397f7c4SAlexandru Gagniuc static unsigned short smireg_to_reg(unsigned short reg) 107*d397f7c4SAlexandru Gagniuc { 108*d397f7c4SAlexandru Gagniuc return reg & 0x1F; 109*d397f7c4SAlexandru Gagniuc } 110*d397f7c4SAlexandru Gagniuc 111*d397f7c4SAlexandru Gagniuc static void ksz8895_write_smireg(struct phy_device *phydev, int smireg, int val) 112*d397f7c4SAlexandru Gagniuc { 113*d397f7c4SAlexandru Gagniuc phydev->bus->write(phydev->bus, smireg_to_phy(smireg), MDIO_DEVAD_NONE, 114*d397f7c4SAlexandru Gagniuc smireg_to_reg(smireg), val); 115*d397f7c4SAlexandru Gagniuc } 116*d397f7c4SAlexandru Gagniuc 117*d397f7c4SAlexandru Gagniuc #if 0 118*d397f7c4SAlexandru Gagniuc static int ksz8895_read_smireg(struct phy_device *phydev, int smireg) 119*d397f7c4SAlexandru Gagniuc { 120*d397f7c4SAlexandru Gagniuc return phydev->bus->read(phydev->bus, smireg_to_phy(smireg), 121*d397f7c4SAlexandru Gagniuc MDIO_DEVAD_NONE, smireg_to_reg(smireg)); 122*d397f7c4SAlexandru Gagniuc } 123*d397f7c4SAlexandru Gagniuc #endif 124*d397f7c4SAlexandru Gagniuc 125*d397f7c4SAlexandru Gagniuc int ksz8895_config(struct phy_device *phydev) 126*d397f7c4SAlexandru Gagniuc { 127*d397f7c4SAlexandru Gagniuc /* we are connected directly to the switch without 128*d397f7c4SAlexandru Gagniuc * dedicated PHY. SCONF1 == 001 */ 129*d397f7c4SAlexandru Gagniuc phydev->link = 1; 130*d397f7c4SAlexandru Gagniuc phydev->duplex = DUPLEX_FULL; 131*d397f7c4SAlexandru Gagniuc phydev->speed = SPEED_100; 132*d397f7c4SAlexandru Gagniuc 133*d397f7c4SAlexandru Gagniuc /* Force the switch to start */ 134*d397f7c4SAlexandru Gagniuc ksz8895_write_smireg(phydev, 1, 1); 135*d397f7c4SAlexandru Gagniuc 136*d397f7c4SAlexandru Gagniuc return 0; 137*d397f7c4SAlexandru Gagniuc } 138*d397f7c4SAlexandru Gagniuc 139*d397f7c4SAlexandru Gagniuc static int ksz8895_startup(struct phy_device *phydev) 140*d397f7c4SAlexandru Gagniuc { 141*d397f7c4SAlexandru Gagniuc return 0; 142*d397f7c4SAlexandru Gagniuc } 143*d397f7c4SAlexandru Gagniuc 144*d397f7c4SAlexandru Gagniuc static struct phy_driver ksz8895_driver = { 145*d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ8895/KSZ8864", 146*d397f7c4SAlexandru Gagniuc .uid = 0x221450, 147*d397f7c4SAlexandru Gagniuc .mask = 0xffffe1, 148*d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 149*d397f7c4SAlexandru Gagniuc .config = &ksz8895_config, 150*d397f7c4SAlexandru Gagniuc .startup = &ksz8895_startup, 151*d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 152*d397f7c4SAlexandru Gagniuc }; 153*d397f7c4SAlexandru Gagniuc 154*d397f7c4SAlexandru Gagniuc #ifndef CONFIG_PHY_MICREL_KSZ9021 155*d397f7c4SAlexandru Gagniuc /* 156*d397f7c4SAlexandru Gagniuc * I can't believe Micrel used the exact same part number 157*d397f7c4SAlexandru Gagniuc * for the KSZ9021. Shame Micrel, Shame! 158*d397f7c4SAlexandru Gagniuc */ 159*d397f7c4SAlexandru Gagniuc static struct phy_driver KS8721_driver = { 160*d397f7c4SAlexandru Gagniuc .name = "Micrel KS8721BL", 161*d397f7c4SAlexandru Gagniuc .uid = 0x221610, 162*d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 163*d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 164*d397f7c4SAlexandru Gagniuc .config = &genphy_config, 165*d397f7c4SAlexandru Gagniuc .startup = &genphy_startup, 166*d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 167*d397f7c4SAlexandru Gagniuc }; 168*d397f7c4SAlexandru Gagniuc #endif 169*d397f7c4SAlexandru Gagniuc 170*d397f7c4SAlexandru Gagniuc 171*d397f7c4SAlexandru Gagniuc /* 172*d397f7c4SAlexandru Gagniuc * KSZ9021 - KSZ9031 common 173*d397f7c4SAlexandru Gagniuc */ 174*d397f7c4SAlexandru Gagniuc 175*d397f7c4SAlexandru Gagniuc #define MII_KSZ90xx_PHY_CTL 0x1f 176*d397f7c4SAlexandru Gagniuc #define MIIM_KSZ90xx_PHYCTL_1000 (1 << 6) 177*d397f7c4SAlexandru Gagniuc #define MIIM_KSZ90xx_PHYCTL_100 (1 << 5) 178*d397f7c4SAlexandru Gagniuc #define MIIM_KSZ90xx_PHYCTL_10 (1 << 4) 179*d397f7c4SAlexandru Gagniuc #define MIIM_KSZ90xx_PHYCTL_DUPLEX (1 << 3) 180*d397f7c4SAlexandru Gagniuc 181*d397f7c4SAlexandru Gagniuc static int ksz90xx_startup(struct phy_device *phydev) 182*d397f7c4SAlexandru Gagniuc { 183*d397f7c4SAlexandru Gagniuc unsigned phy_ctl; 184*d397f7c4SAlexandru Gagniuc int ret; 185*d397f7c4SAlexandru Gagniuc 186*d397f7c4SAlexandru Gagniuc ret = genphy_update_link(phydev); 187*d397f7c4SAlexandru Gagniuc if (ret) 188*d397f7c4SAlexandru Gagniuc return ret; 189*d397f7c4SAlexandru Gagniuc 190*d397f7c4SAlexandru Gagniuc phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL); 191*d397f7c4SAlexandru Gagniuc 192*d397f7c4SAlexandru Gagniuc if (phy_ctl & MIIM_KSZ90xx_PHYCTL_DUPLEX) 193*d397f7c4SAlexandru Gagniuc phydev->duplex = DUPLEX_FULL; 194*d397f7c4SAlexandru Gagniuc else 195*d397f7c4SAlexandru Gagniuc phydev->duplex = DUPLEX_HALF; 196*d397f7c4SAlexandru Gagniuc 197*d397f7c4SAlexandru Gagniuc if (phy_ctl & MIIM_KSZ90xx_PHYCTL_1000) 198*d397f7c4SAlexandru Gagniuc phydev->speed = SPEED_1000; 199*d397f7c4SAlexandru Gagniuc else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_100) 200*d397f7c4SAlexandru Gagniuc phydev->speed = SPEED_100; 201*d397f7c4SAlexandru Gagniuc else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_10) 202*d397f7c4SAlexandru Gagniuc phydev->speed = SPEED_10; 203*d397f7c4SAlexandru Gagniuc return 0; 204*d397f7c4SAlexandru Gagniuc } 205*d397f7c4SAlexandru Gagniuc 206*d397f7c4SAlexandru Gagniuc /* Common OF config bits for KSZ9021 and KSZ9031 */ 207*d397f7c4SAlexandru Gagniuc #if defined(CONFIG_PHY_MICREL_KSZ9021) || defined(CONFIG_PHY_MICREL_KSZ9031) 208*d397f7c4SAlexandru Gagniuc #ifdef CONFIG_DM_ETH 209*d397f7c4SAlexandru Gagniuc struct ksz90x1_reg_field { 210*d397f7c4SAlexandru Gagniuc const char *name; 211*d397f7c4SAlexandru Gagniuc const u8 size; /* Size of the bitfield, in bits */ 212*d397f7c4SAlexandru Gagniuc const u8 off; /* Offset from bit 0 */ 213*d397f7c4SAlexandru Gagniuc const u8 dflt; /* Default value */ 214*d397f7c4SAlexandru Gagniuc }; 215*d397f7c4SAlexandru Gagniuc 216*d397f7c4SAlexandru Gagniuc struct ksz90x1_ofcfg { 217*d397f7c4SAlexandru Gagniuc const u16 reg; 218*d397f7c4SAlexandru Gagniuc const u16 devad; 219*d397f7c4SAlexandru Gagniuc const struct ksz90x1_reg_field *grp; 220*d397f7c4SAlexandru Gagniuc const u16 grpsz; 221*d397f7c4SAlexandru Gagniuc }; 222*d397f7c4SAlexandru Gagniuc 223*d397f7c4SAlexandru Gagniuc static const struct ksz90x1_reg_field ksz90x1_rxd_grp[] = { 224*d397f7c4SAlexandru Gagniuc { "rxd0-skew-ps", 4, 0, 0x7 }, { "rxd1-skew-ps", 4, 4, 0x7 }, 225*d397f7c4SAlexandru Gagniuc { "rxd2-skew-ps", 4, 8, 0x7 }, { "rxd3-skew-ps", 4, 12, 0x7 } 226*d397f7c4SAlexandru Gagniuc }; 227*d397f7c4SAlexandru Gagniuc 228*d397f7c4SAlexandru Gagniuc static const struct ksz90x1_reg_field ksz90x1_txd_grp[] = { 229*d397f7c4SAlexandru Gagniuc { "txd0-skew-ps", 4, 0, 0x7 }, { "txd1-skew-ps", 4, 4, 0x7 }, 230*d397f7c4SAlexandru Gagniuc { "txd2-skew-ps", 4, 8, 0x7 }, { "txd3-skew-ps", 4, 12, 0x7 }, 231*d397f7c4SAlexandru Gagniuc }; 232*d397f7c4SAlexandru Gagniuc 233*d397f7c4SAlexandru Gagniuc static int ksz90x1_of_config_group(struct phy_device *phydev, 234*d397f7c4SAlexandru Gagniuc struct ksz90x1_ofcfg *ofcfg) 235*d397f7c4SAlexandru Gagniuc { 236*d397f7c4SAlexandru Gagniuc struct udevice *dev = phydev->dev; 237*d397f7c4SAlexandru Gagniuc struct phy_driver *drv = phydev->drv; 238*d397f7c4SAlexandru Gagniuc const int ps_to_regval = 60; 239*d397f7c4SAlexandru Gagniuc int val[4]; 240*d397f7c4SAlexandru Gagniuc int i, changed = 0, offset, max; 241*d397f7c4SAlexandru Gagniuc u16 regval = 0; 242*d397f7c4SAlexandru Gagniuc 243*d397f7c4SAlexandru Gagniuc if (!drv || !drv->writeext) 244*d397f7c4SAlexandru Gagniuc return -EOPNOTSUPP; 245*d397f7c4SAlexandru Gagniuc 246*d397f7c4SAlexandru Gagniuc for (i = 0; i < ofcfg->grpsz; i++) { 247*d397f7c4SAlexandru Gagniuc val[i] = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), 248*d397f7c4SAlexandru Gagniuc ofcfg->grp[i].name, -1); 249*d397f7c4SAlexandru Gagniuc offset = ofcfg->grp[i].off; 250*d397f7c4SAlexandru Gagniuc if (val[i] == -1) { 251*d397f7c4SAlexandru Gagniuc /* Default register value for KSZ9021 */ 252*d397f7c4SAlexandru Gagniuc regval |= ofcfg->grp[i].dflt << offset; 253*d397f7c4SAlexandru Gagniuc } else { 254*d397f7c4SAlexandru Gagniuc changed = 1; /* Value was changed in OF */ 255*d397f7c4SAlexandru Gagniuc /* Calculate the register value and fix corner cases */ 256*d397f7c4SAlexandru Gagniuc if (val[i] > ps_to_regval * 0xf) { 257*d397f7c4SAlexandru Gagniuc max = (1 << ofcfg->grp[i].size) - 1; 258*d397f7c4SAlexandru Gagniuc regval |= max << offset; 259*d397f7c4SAlexandru Gagniuc } else { 260*d397f7c4SAlexandru Gagniuc regval |= (val[i] / ps_to_regval) << offset; 261*d397f7c4SAlexandru Gagniuc } 262*d397f7c4SAlexandru Gagniuc } 263*d397f7c4SAlexandru Gagniuc } 264*d397f7c4SAlexandru Gagniuc 265*d397f7c4SAlexandru Gagniuc if (!changed) 266*d397f7c4SAlexandru Gagniuc return 0; 267*d397f7c4SAlexandru Gagniuc 268*d397f7c4SAlexandru Gagniuc return drv->writeext(phydev, 0, ofcfg->devad, ofcfg->reg, regval); 269*d397f7c4SAlexandru Gagniuc } 270*d397f7c4SAlexandru Gagniuc #endif 271*d397f7c4SAlexandru Gagniuc #endif 272*d397f7c4SAlexandru Gagniuc 273*d397f7c4SAlexandru Gagniuc #ifdef CONFIG_PHY_MICREL_KSZ9021 274*d397f7c4SAlexandru Gagniuc /* 275*d397f7c4SAlexandru Gagniuc * KSZ9021 276*d397f7c4SAlexandru Gagniuc */ 277*d397f7c4SAlexandru Gagniuc 278*d397f7c4SAlexandru Gagniuc /* PHY Registers */ 279*d397f7c4SAlexandru Gagniuc #define MII_KSZ9021_EXTENDED_CTRL 0x0b 280*d397f7c4SAlexandru Gagniuc #define MII_KSZ9021_EXTENDED_DATAW 0x0c 281*d397f7c4SAlexandru Gagniuc #define MII_KSZ9021_EXTENDED_DATAR 0x0d 282*d397f7c4SAlexandru Gagniuc 283*d397f7c4SAlexandru Gagniuc #define CTRL1000_PREFER_MASTER (1 << 10) 284*d397f7c4SAlexandru Gagniuc #define CTRL1000_CONFIG_MASTER (1 << 11) 285*d397f7c4SAlexandru Gagniuc #define CTRL1000_MANUAL_CONFIG (1 << 12) 286*d397f7c4SAlexandru Gagniuc 287*d397f7c4SAlexandru Gagniuc #if defined(CONFIG_DM_ETH) && (defined(CONFIG_PHY_MICREL_KSZ9021) || \ 288*d397f7c4SAlexandru Gagniuc defined(CONFIG_PHY_MICREL_KSZ9031)) 289*d397f7c4SAlexandru Gagniuc static const struct ksz90x1_reg_field ksz9021_clk_grp[] = { 290*d397f7c4SAlexandru Gagniuc { "txen-skew-ps", 4, 0, 0x7 }, { "txc-skew-ps", 4, 4, 0x7 }, 291*d397f7c4SAlexandru Gagniuc { "rxdv-skew-ps", 4, 8, 0x7 }, { "rxc-skew-ps", 4, 12, 0x7 }, 292*d397f7c4SAlexandru Gagniuc }; 293*d397f7c4SAlexandru Gagniuc 294*d397f7c4SAlexandru Gagniuc static int ksz9021_of_config(struct phy_device *phydev) 295*d397f7c4SAlexandru Gagniuc { 296*d397f7c4SAlexandru Gagniuc struct ksz90x1_ofcfg ofcfg[] = { 297*d397f7c4SAlexandru Gagniuc { MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW, 0, ksz90x1_rxd_grp, 4 }, 298*d397f7c4SAlexandru Gagniuc { MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW, 0, ksz90x1_txd_grp, 4 }, 299*d397f7c4SAlexandru Gagniuc { MII_KSZ9021_EXT_RGMII_CLOCK_SKEW, 0, ksz9021_clk_grp, 4 }, 300*d397f7c4SAlexandru Gagniuc }; 301*d397f7c4SAlexandru Gagniuc int i, ret = 0; 302*d397f7c4SAlexandru Gagniuc 303*d397f7c4SAlexandru Gagniuc for (i = 0; i < ARRAY_SIZE(ofcfg); i++) { 304*d397f7c4SAlexandru Gagniuc ret = ksz90x1_of_config_group(phydev, &(ofcfg[i])); 305*d397f7c4SAlexandru Gagniuc if (ret) 306*d397f7c4SAlexandru Gagniuc return ret; 307*d397f7c4SAlexandru Gagniuc } 308*d397f7c4SAlexandru Gagniuc 309*d397f7c4SAlexandru Gagniuc return 0; 310*d397f7c4SAlexandru Gagniuc } 311*d397f7c4SAlexandru Gagniuc #else 312*d397f7c4SAlexandru Gagniuc static int ksz9021_of_config(struct phy_device *phydev) 313*d397f7c4SAlexandru Gagniuc { 314*d397f7c4SAlexandru Gagniuc return 0; 315*d397f7c4SAlexandru Gagniuc } 316*d397f7c4SAlexandru Gagniuc #endif 317*d397f7c4SAlexandru Gagniuc 318*d397f7c4SAlexandru Gagniuc int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val) 319*d397f7c4SAlexandru Gagniuc { 320*d397f7c4SAlexandru Gagniuc /* extended registers */ 321*d397f7c4SAlexandru Gagniuc phy_write(phydev, MDIO_DEVAD_NONE, 322*d397f7c4SAlexandru Gagniuc MII_KSZ9021_EXTENDED_CTRL, regnum | 0x8000); 323*d397f7c4SAlexandru Gagniuc return phy_write(phydev, MDIO_DEVAD_NONE, 324*d397f7c4SAlexandru Gagniuc MII_KSZ9021_EXTENDED_DATAW, val); 325*d397f7c4SAlexandru Gagniuc } 326*d397f7c4SAlexandru Gagniuc 327*d397f7c4SAlexandru Gagniuc int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum) 328*d397f7c4SAlexandru Gagniuc { 329*d397f7c4SAlexandru Gagniuc /* extended registers */ 330*d397f7c4SAlexandru Gagniuc phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_CTRL, regnum); 331*d397f7c4SAlexandru Gagniuc return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_EXTENDED_DATAR); 332*d397f7c4SAlexandru Gagniuc } 333*d397f7c4SAlexandru Gagniuc 334*d397f7c4SAlexandru Gagniuc 335*d397f7c4SAlexandru Gagniuc static int ksz9021_phy_extread(struct phy_device *phydev, int addr, int devaddr, 336*d397f7c4SAlexandru Gagniuc int regnum) 337*d397f7c4SAlexandru Gagniuc { 338*d397f7c4SAlexandru Gagniuc return ksz9021_phy_extended_read(phydev, regnum); 339*d397f7c4SAlexandru Gagniuc } 340*d397f7c4SAlexandru Gagniuc 341*d397f7c4SAlexandru Gagniuc static int ksz9021_phy_extwrite(struct phy_device *phydev, int addr, 342*d397f7c4SAlexandru Gagniuc int devaddr, int regnum, u16 val) 343*d397f7c4SAlexandru Gagniuc { 344*d397f7c4SAlexandru Gagniuc return ksz9021_phy_extended_write(phydev, regnum, val); 345*d397f7c4SAlexandru Gagniuc } 346*d397f7c4SAlexandru Gagniuc 347*d397f7c4SAlexandru Gagniuc /* Micrel ksz9021 */ 348*d397f7c4SAlexandru Gagniuc static int ksz9021_config(struct phy_device *phydev) 349*d397f7c4SAlexandru Gagniuc { 350*d397f7c4SAlexandru Gagniuc unsigned ctrl1000 = 0; 351*d397f7c4SAlexandru Gagniuc const unsigned master = CTRL1000_PREFER_MASTER | 352*d397f7c4SAlexandru Gagniuc CTRL1000_CONFIG_MASTER | CTRL1000_MANUAL_CONFIG; 353*d397f7c4SAlexandru Gagniuc unsigned features = phydev->drv->features; 354*d397f7c4SAlexandru Gagniuc int ret; 355*d397f7c4SAlexandru Gagniuc 356*d397f7c4SAlexandru Gagniuc ret = ksz9021_of_config(phydev); 357*d397f7c4SAlexandru Gagniuc if (ret) 358*d397f7c4SAlexandru Gagniuc return ret; 359*d397f7c4SAlexandru Gagniuc 360*d397f7c4SAlexandru Gagniuc if (getenv("disable_giga")) 361*d397f7c4SAlexandru Gagniuc features &= ~(SUPPORTED_1000baseT_Half | 362*d397f7c4SAlexandru Gagniuc SUPPORTED_1000baseT_Full); 363*d397f7c4SAlexandru Gagniuc /* force master mode for 1000BaseT due to chip errata */ 364*d397f7c4SAlexandru Gagniuc if (features & SUPPORTED_1000baseT_Half) 365*d397f7c4SAlexandru Gagniuc ctrl1000 |= ADVERTISE_1000HALF | master; 366*d397f7c4SAlexandru Gagniuc if (features & SUPPORTED_1000baseT_Full) 367*d397f7c4SAlexandru Gagniuc ctrl1000 |= ADVERTISE_1000FULL | master; 368*d397f7c4SAlexandru Gagniuc phydev->advertising = features; 369*d397f7c4SAlexandru Gagniuc phydev->supported = features; 370*d397f7c4SAlexandru Gagniuc phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, ctrl1000); 371*d397f7c4SAlexandru Gagniuc genphy_config_aneg(phydev); 372*d397f7c4SAlexandru Gagniuc genphy_restart_aneg(phydev); 373*d397f7c4SAlexandru Gagniuc return 0; 374*d397f7c4SAlexandru Gagniuc } 375*d397f7c4SAlexandru Gagniuc 376*d397f7c4SAlexandru Gagniuc static struct phy_driver ksz9021_driver = { 377*d397f7c4SAlexandru Gagniuc .name = "Micrel ksz9021", 378*d397f7c4SAlexandru Gagniuc .uid = 0x221610, 379*d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 380*d397f7c4SAlexandru Gagniuc .features = PHY_GBIT_FEATURES, 381*d397f7c4SAlexandru Gagniuc .config = &ksz9021_config, 382*d397f7c4SAlexandru Gagniuc .startup = &ksz90xx_startup, 383*d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 384*d397f7c4SAlexandru Gagniuc .writeext = &ksz9021_phy_extwrite, 385*d397f7c4SAlexandru Gagniuc .readext = &ksz9021_phy_extread, 386*d397f7c4SAlexandru Gagniuc }; 387*d397f7c4SAlexandru Gagniuc #endif 388*d397f7c4SAlexandru Gagniuc 389*d397f7c4SAlexandru Gagniuc /** 390*d397f7c4SAlexandru Gagniuc * KSZ9031 391*d397f7c4SAlexandru Gagniuc */ 392*d397f7c4SAlexandru Gagniuc /* PHY Registers */ 393*d397f7c4SAlexandru Gagniuc #define MII_KSZ9031_MMD_ACCES_CTRL 0x0d 394*d397f7c4SAlexandru Gagniuc #define MII_KSZ9031_MMD_REG_DATA 0x0e 395*d397f7c4SAlexandru Gagniuc 396*d397f7c4SAlexandru Gagniuc #if defined(CONFIG_DM_ETH) && (defined(CONFIG_PHY_MICREL_KSZ9021) || \ 397*d397f7c4SAlexandru Gagniuc defined(CONFIG_PHY_MICREL_KSZ9031)) 398*d397f7c4SAlexandru Gagniuc static const struct ksz90x1_reg_field ksz9031_ctl_grp[] = 399*d397f7c4SAlexandru Gagniuc { { "txen-skew-ps", 4, 0, 0x7 }, { "rxdv-skew-ps", 4, 4, 0x7 } }; 400*d397f7c4SAlexandru Gagniuc static const struct ksz90x1_reg_field ksz9031_clk_grp[] = 401*d397f7c4SAlexandru Gagniuc { { "rxc-skew-ps", 5, 0, 0xf }, { "txc-skew-ps", 5, 5, 0xf } }; 402*d397f7c4SAlexandru Gagniuc 403*d397f7c4SAlexandru Gagniuc static int ksz9031_of_config(struct phy_device *phydev) 404*d397f7c4SAlexandru Gagniuc { 405*d397f7c4SAlexandru Gagniuc struct ksz90x1_ofcfg ofcfg[] = { 406*d397f7c4SAlexandru Gagniuc { MII_KSZ9031_EXT_RGMII_CTRL_SIG_SKEW, 2, ksz9031_ctl_grp, 2 }, 407*d397f7c4SAlexandru Gagniuc { MII_KSZ9031_EXT_RGMII_RX_DATA_SKEW, 2, ksz90x1_rxd_grp, 4 }, 408*d397f7c4SAlexandru Gagniuc { MII_KSZ9031_EXT_RGMII_TX_DATA_SKEW, 2, ksz90x1_txd_grp, 4 }, 409*d397f7c4SAlexandru Gagniuc { MII_KSZ9031_EXT_RGMII_CLOCK_SKEW, 2, ksz9031_clk_grp, 2 }, 410*d397f7c4SAlexandru Gagniuc }; 411*d397f7c4SAlexandru Gagniuc int i, ret = 0; 412*d397f7c4SAlexandru Gagniuc 413*d397f7c4SAlexandru Gagniuc for (i = 0; i < ARRAY_SIZE(ofcfg); i++) { 414*d397f7c4SAlexandru Gagniuc ret = ksz90x1_of_config_group(phydev, &(ofcfg[i])); 415*d397f7c4SAlexandru Gagniuc if (ret) 416*d397f7c4SAlexandru Gagniuc return ret; 417*d397f7c4SAlexandru Gagniuc } 418*d397f7c4SAlexandru Gagniuc 419*d397f7c4SAlexandru Gagniuc return 0; 420*d397f7c4SAlexandru Gagniuc } 421*d397f7c4SAlexandru Gagniuc 422*d397f7c4SAlexandru Gagniuc static int ksz9031_center_flp_timing(struct phy_device *phydev) 423*d397f7c4SAlexandru Gagniuc { 424*d397f7c4SAlexandru Gagniuc struct phy_driver *drv = phydev->drv; 425*d397f7c4SAlexandru Gagniuc int ret = 0; 426*d397f7c4SAlexandru Gagniuc 427*d397f7c4SAlexandru Gagniuc if (!drv || !drv->writeext) 428*d397f7c4SAlexandru Gagniuc return -EOPNOTSUPP; 429*d397f7c4SAlexandru Gagniuc 430*d397f7c4SAlexandru Gagniuc ret = drv->writeext(phydev, 0, 0, MII_KSZ9031_FLP_BURST_TX_LO, 0x1A80); 431*d397f7c4SAlexandru Gagniuc if (ret) 432*d397f7c4SAlexandru Gagniuc return ret; 433*d397f7c4SAlexandru Gagniuc 434*d397f7c4SAlexandru Gagniuc ret = drv->writeext(phydev, 0, 0, MII_KSZ9031_FLP_BURST_TX_HI, 0x6); 435*d397f7c4SAlexandru Gagniuc return ret; 436*d397f7c4SAlexandru Gagniuc } 437*d397f7c4SAlexandru Gagniuc #else 438*d397f7c4SAlexandru Gagniuc static int ksz9031_of_config(struct phy_device *phydev) 439*d397f7c4SAlexandru Gagniuc { 440*d397f7c4SAlexandru Gagniuc return 0; 441*d397f7c4SAlexandru Gagniuc } 442*d397f7c4SAlexandru Gagniuc static int ksz9031_center_flp_timing(struct phy_device *phydev) 443*d397f7c4SAlexandru Gagniuc { 444*d397f7c4SAlexandru Gagniuc return 0; 445*d397f7c4SAlexandru Gagniuc } 446*d397f7c4SAlexandru Gagniuc #endif 447*d397f7c4SAlexandru Gagniuc 448*d397f7c4SAlexandru Gagniuc /* Accessors to extended registers*/ 449*d397f7c4SAlexandru Gagniuc int ksz9031_phy_extended_write(struct phy_device *phydev, 450*d397f7c4SAlexandru Gagniuc int devaddr, int regnum, u16 mode, u16 val) 451*d397f7c4SAlexandru Gagniuc { 452*d397f7c4SAlexandru Gagniuc /*select register addr for mmd*/ 453*d397f7c4SAlexandru Gagniuc phy_write(phydev, MDIO_DEVAD_NONE, 454*d397f7c4SAlexandru Gagniuc MII_KSZ9031_MMD_ACCES_CTRL, devaddr); 455*d397f7c4SAlexandru Gagniuc /*select register for mmd*/ 456*d397f7c4SAlexandru Gagniuc phy_write(phydev, MDIO_DEVAD_NONE, 457*d397f7c4SAlexandru Gagniuc MII_KSZ9031_MMD_REG_DATA, regnum); 458*d397f7c4SAlexandru Gagniuc /*setup mode*/ 459*d397f7c4SAlexandru Gagniuc phy_write(phydev, MDIO_DEVAD_NONE, 460*d397f7c4SAlexandru Gagniuc MII_KSZ9031_MMD_ACCES_CTRL, (mode | devaddr)); 461*d397f7c4SAlexandru Gagniuc /*write the value*/ 462*d397f7c4SAlexandru Gagniuc return phy_write(phydev, MDIO_DEVAD_NONE, 463*d397f7c4SAlexandru Gagniuc MII_KSZ9031_MMD_REG_DATA, val); 464*d397f7c4SAlexandru Gagniuc } 465*d397f7c4SAlexandru Gagniuc 466*d397f7c4SAlexandru Gagniuc int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr, 467*d397f7c4SAlexandru Gagniuc int regnum, u16 mode) 468*d397f7c4SAlexandru Gagniuc { 469*d397f7c4SAlexandru Gagniuc phy_write(phydev, MDIO_DEVAD_NONE, 470*d397f7c4SAlexandru Gagniuc MII_KSZ9031_MMD_ACCES_CTRL, devaddr); 471*d397f7c4SAlexandru Gagniuc phy_write(phydev, MDIO_DEVAD_NONE, 472*d397f7c4SAlexandru Gagniuc MII_KSZ9031_MMD_REG_DATA, regnum); 473*d397f7c4SAlexandru Gagniuc phy_write(phydev, MDIO_DEVAD_NONE, 474*d397f7c4SAlexandru Gagniuc MII_KSZ9031_MMD_ACCES_CTRL, (devaddr | mode)); 475*d397f7c4SAlexandru Gagniuc return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA); 476*d397f7c4SAlexandru Gagniuc } 477*d397f7c4SAlexandru Gagniuc 478*d397f7c4SAlexandru Gagniuc static int ksz9031_phy_extread(struct phy_device *phydev, int addr, int devaddr, 479*d397f7c4SAlexandru Gagniuc int regnum) 480*d397f7c4SAlexandru Gagniuc { 481*d397f7c4SAlexandru Gagniuc return ksz9031_phy_extended_read(phydev, devaddr, regnum, 482*d397f7c4SAlexandru Gagniuc MII_KSZ9031_MOD_DATA_NO_POST_INC); 483*d397f7c4SAlexandru Gagniuc } 484*d397f7c4SAlexandru Gagniuc 485*d397f7c4SAlexandru Gagniuc static int ksz9031_phy_extwrite(struct phy_device *phydev, int addr, 486*d397f7c4SAlexandru Gagniuc int devaddr, int regnum, u16 val) 487*d397f7c4SAlexandru Gagniuc { 488*d397f7c4SAlexandru Gagniuc return ksz9031_phy_extended_write(phydev, devaddr, regnum, 489*d397f7c4SAlexandru Gagniuc MII_KSZ9031_MOD_DATA_POST_INC_RW, val); 490*d397f7c4SAlexandru Gagniuc } 491*d397f7c4SAlexandru Gagniuc 492*d397f7c4SAlexandru Gagniuc static int ksz9031_config(struct phy_device *phydev) 493*d397f7c4SAlexandru Gagniuc { 494*d397f7c4SAlexandru Gagniuc int ret; 495*d397f7c4SAlexandru Gagniuc ret = ksz9031_of_config(phydev); 496*d397f7c4SAlexandru Gagniuc if (ret) 497*d397f7c4SAlexandru Gagniuc return ret; 498*d397f7c4SAlexandru Gagniuc ret = ksz9031_center_flp_timing(phydev); 499*d397f7c4SAlexandru Gagniuc if (ret) 500*d397f7c4SAlexandru Gagniuc return ret; 501*d397f7c4SAlexandru Gagniuc return genphy_config(phydev); 502*d397f7c4SAlexandru Gagniuc } 503*d397f7c4SAlexandru Gagniuc 504*d397f7c4SAlexandru Gagniuc static struct phy_driver ksz9031_driver = { 505*d397f7c4SAlexandru Gagniuc .name = "Micrel ksz9031", 506*d397f7c4SAlexandru Gagniuc .uid = 0x221620, 507*d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 508*d397f7c4SAlexandru Gagniuc .features = PHY_GBIT_FEATURES, 509*d397f7c4SAlexandru Gagniuc .config = &ksz9031_config, 510*d397f7c4SAlexandru Gagniuc .startup = &ksz90xx_startup, 511*d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 512*d397f7c4SAlexandru Gagniuc .writeext = &ksz9031_phy_extwrite, 513*d397f7c4SAlexandru Gagniuc .readext = &ksz9031_phy_extread, 514*d397f7c4SAlexandru Gagniuc }; 515*d397f7c4SAlexandru Gagniuc 516*d397f7c4SAlexandru Gagniuc int ksz886x_config(struct phy_device *phydev) 517*d397f7c4SAlexandru Gagniuc { 518*d397f7c4SAlexandru Gagniuc /* we are connected directly to the switch without 519*d397f7c4SAlexandru Gagniuc * dedicated PHY. */ 520*d397f7c4SAlexandru Gagniuc phydev->link = 1; 521*d397f7c4SAlexandru Gagniuc phydev->duplex = DUPLEX_FULL; 522*d397f7c4SAlexandru Gagniuc phydev->speed = SPEED_100; 523*d397f7c4SAlexandru Gagniuc return 0; 524*d397f7c4SAlexandru Gagniuc } 525*d397f7c4SAlexandru Gagniuc 526*d397f7c4SAlexandru Gagniuc static int ksz886x_startup(struct phy_device *phydev) 527*d397f7c4SAlexandru Gagniuc { 528*d397f7c4SAlexandru Gagniuc return 0; 529*d397f7c4SAlexandru Gagniuc } 530*d397f7c4SAlexandru Gagniuc 531*d397f7c4SAlexandru Gagniuc static struct phy_driver ksz886x_driver = { 532*d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ886x Switch", 533*d397f7c4SAlexandru Gagniuc .uid = 0x00221430, 534*d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 535*d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 536*d397f7c4SAlexandru Gagniuc .config = &ksz886x_config, 537*d397f7c4SAlexandru Gagniuc .startup = &ksz886x_startup, 538*d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 539*d397f7c4SAlexandru Gagniuc }; 540*d397f7c4SAlexandru Gagniuc 541*d397f7c4SAlexandru Gagniuc int phy_micrel_ksz8xxx_init(void) 542*d397f7c4SAlexandru Gagniuc { 543*d397f7c4SAlexandru Gagniuc phy_register(&KSZ804_driver); 544*d397f7c4SAlexandru Gagniuc phy_register(&KSZ8031_driver); 545*d397f7c4SAlexandru Gagniuc phy_register(&KSZ8051_driver); 546*d397f7c4SAlexandru Gagniuc phy_register(&KSZ8081_driver); 547*d397f7c4SAlexandru Gagniuc #ifdef CONFIG_PHY_MICREL_KSZ9021 548*d397f7c4SAlexandru Gagniuc phy_register(&ksz9021_driver); 549*d397f7c4SAlexandru Gagniuc #else 550*d397f7c4SAlexandru Gagniuc phy_register(&KS8721_driver); 551*d397f7c4SAlexandru Gagniuc #endif 552*d397f7c4SAlexandru Gagniuc phy_register(&ksz9031_driver); 553*d397f7c4SAlexandru Gagniuc phy_register(&ksz8895_driver); 554*d397f7c4SAlexandru Gagniuc phy_register(&ksz886x_driver); 555*d397f7c4SAlexandru Gagniuc return 0; 556*d397f7c4SAlexandru Gagniuc } 557