1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 2d397f7c4SAlexandru Gagniuc /* 3d397f7c4SAlexandru Gagniuc * Micrel PHY drivers 4d397f7c4SAlexandru Gagniuc * 5d397f7c4SAlexandru Gagniuc * Copyright 2010-2011 Freescale Semiconductor, Inc. 6d397f7c4SAlexandru Gagniuc * author Andy Fleming 7d397f7c4SAlexandru Gagniuc * (C) 2012 NetModule AG, David Andrey, added KSZ9031 8d397f7c4SAlexandru Gagniuc */ 9d397f7c4SAlexandru Gagniuc #include <config.h> 10d397f7c4SAlexandru Gagniuc #include <common.h> 11d397f7c4SAlexandru Gagniuc #include <dm.h> 12d397f7c4SAlexandru Gagniuc #include <errno.h> 13d397f7c4SAlexandru Gagniuc #include <fdtdec.h> 14d397f7c4SAlexandru Gagniuc #include <micrel.h> 15d397f7c4SAlexandru Gagniuc #include <phy.h> 16d397f7c4SAlexandru Gagniuc 17d397f7c4SAlexandru Gagniuc static struct phy_driver KSZ804_driver = { 18d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ804", 19d397f7c4SAlexandru Gagniuc .uid = 0x221510, 20d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 21d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 22d397f7c4SAlexandru Gagniuc .config = &genphy_config, 23d397f7c4SAlexandru Gagniuc .startup = &genphy_startup, 24d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 25d397f7c4SAlexandru Gagniuc }; 26d397f7c4SAlexandru Gagniuc 27d397f7c4SAlexandru Gagniuc #define MII_KSZPHY_OMSO 0x16 28d397f7c4SAlexandru Gagniuc #define KSZPHY_OMSO_B_CAST_OFF (1 << 9) 29d397f7c4SAlexandru Gagniuc 30d397f7c4SAlexandru Gagniuc static int ksz_genconfig_bcastoff(struct phy_device *phydev) 31d397f7c4SAlexandru Gagniuc { 32d397f7c4SAlexandru Gagniuc int ret; 33d397f7c4SAlexandru Gagniuc 34d397f7c4SAlexandru Gagniuc ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO); 35d397f7c4SAlexandru Gagniuc if (ret < 0) 36d397f7c4SAlexandru Gagniuc return ret; 37d397f7c4SAlexandru Gagniuc 38d397f7c4SAlexandru Gagniuc ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO, 39d397f7c4SAlexandru Gagniuc ret | KSZPHY_OMSO_B_CAST_OFF); 40d397f7c4SAlexandru Gagniuc if (ret < 0) 41d397f7c4SAlexandru Gagniuc return ret; 42d397f7c4SAlexandru Gagniuc 43d397f7c4SAlexandru Gagniuc return genphy_config(phydev); 44d397f7c4SAlexandru Gagniuc } 45d397f7c4SAlexandru Gagniuc 46d397f7c4SAlexandru Gagniuc static struct phy_driver KSZ8031_driver = { 47d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ8021/KSZ8031", 48d397f7c4SAlexandru Gagniuc .uid = 0x221550, 49d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 50d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 51d397f7c4SAlexandru Gagniuc .config = &ksz_genconfig_bcastoff, 52d397f7c4SAlexandru Gagniuc .startup = &genphy_startup, 53d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 54d397f7c4SAlexandru Gagniuc }; 55d397f7c4SAlexandru Gagniuc 56d397f7c4SAlexandru Gagniuc /** 57d397f7c4SAlexandru Gagniuc * KSZ8051 58d397f7c4SAlexandru Gagniuc */ 59d397f7c4SAlexandru Gagniuc #define MII_KSZ8051_PHY_OMSO 0x16 60d397f7c4SAlexandru Gagniuc #define MII_KSZ8051_PHY_OMSO_NAND_TREE_ON (1 << 5) 61d397f7c4SAlexandru Gagniuc 62d397f7c4SAlexandru Gagniuc static int ksz8051_config(struct phy_device *phydev) 63d397f7c4SAlexandru Gagniuc { 64d397f7c4SAlexandru Gagniuc unsigned val; 65d397f7c4SAlexandru Gagniuc 66d397f7c4SAlexandru Gagniuc /* Disable NAND-tree */ 67d397f7c4SAlexandru Gagniuc val = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ8051_PHY_OMSO); 68d397f7c4SAlexandru Gagniuc val &= ~MII_KSZ8051_PHY_OMSO_NAND_TREE_ON; 69d397f7c4SAlexandru Gagniuc phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZ8051_PHY_OMSO, val); 70d397f7c4SAlexandru Gagniuc 71d397f7c4SAlexandru Gagniuc return genphy_config(phydev); 72d397f7c4SAlexandru Gagniuc } 73d397f7c4SAlexandru Gagniuc 74d397f7c4SAlexandru Gagniuc static struct phy_driver KSZ8051_driver = { 75d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ8051", 76d397f7c4SAlexandru Gagniuc .uid = 0x221550, 77d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 78d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 79d397f7c4SAlexandru Gagniuc .config = &ksz8051_config, 80d397f7c4SAlexandru Gagniuc .startup = &genphy_startup, 81d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 82d397f7c4SAlexandru Gagniuc }; 83d397f7c4SAlexandru Gagniuc 84d397f7c4SAlexandru Gagniuc static struct phy_driver KSZ8081_driver = { 85d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ8081", 86d397f7c4SAlexandru Gagniuc .uid = 0x221560, 87d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 88d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 89d397f7c4SAlexandru Gagniuc .config = &ksz_genconfig_bcastoff, 90d397f7c4SAlexandru Gagniuc .startup = &genphy_startup, 91d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 92d397f7c4SAlexandru Gagniuc }; 93d397f7c4SAlexandru Gagniuc 94d397f7c4SAlexandru Gagniuc /** 95d397f7c4SAlexandru Gagniuc * KSZ8895 96d397f7c4SAlexandru Gagniuc */ 97d397f7c4SAlexandru Gagniuc 98d397f7c4SAlexandru Gagniuc static unsigned short smireg_to_phy(unsigned short reg) 99d397f7c4SAlexandru Gagniuc { 100d397f7c4SAlexandru Gagniuc return ((reg & 0xc0) >> 3) + 0x06 + ((reg & 0x20) >> 5); 101d397f7c4SAlexandru Gagniuc } 102d397f7c4SAlexandru Gagniuc 103d397f7c4SAlexandru Gagniuc static unsigned short smireg_to_reg(unsigned short reg) 104d397f7c4SAlexandru Gagniuc { 105d397f7c4SAlexandru Gagniuc return reg & 0x1F; 106d397f7c4SAlexandru Gagniuc } 107d397f7c4SAlexandru Gagniuc 108d397f7c4SAlexandru Gagniuc static void ksz8895_write_smireg(struct phy_device *phydev, int smireg, int val) 109d397f7c4SAlexandru Gagniuc { 110d397f7c4SAlexandru Gagniuc phydev->bus->write(phydev->bus, smireg_to_phy(smireg), MDIO_DEVAD_NONE, 111d397f7c4SAlexandru Gagniuc smireg_to_reg(smireg), val); 112d397f7c4SAlexandru Gagniuc } 113d397f7c4SAlexandru Gagniuc 114d397f7c4SAlexandru Gagniuc #if 0 115d397f7c4SAlexandru Gagniuc static int ksz8895_read_smireg(struct phy_device *phydev, int smireg) 116d397f7c4SAlexandru Gagniuc { 117d397f7c4SAlexandru Gagniuc return phydev->bus->read(phydev->bus, smireg_to_phy(smireg), 118d397f7c4SAlexandru Gagniuc MDIO_DEVAD_NONE, smireg_to_reg(smireg)); 119d397f7c4SAlexandru Gagniuc } 120d397f7c4SAlexandru Gagniuc #endif 121d397f7c4SAlexandru Gagniuc 122d397f7c4SAlexandru Gagniuc int ksz8895_config(struct phy_device *phydev) 123d397f7c4SAlexandru Gagniuc { 124d397f7c4SAlexandru Gagniuc /* we are connected directly to the switch without 125d397f7c4SAlexandru Gagniuc * dedicated PHY. SCONF1 == 001 */ 126d397f7c4SAlexandru Gagniuc phydev->link = 1; 127d397f7c4SAlexandru Gagniuc phydev->duplex = DUPLEX_FULL; 128d397f7c4SAlexandru Gagniuc phydev->speed = SPEED_100; 129d397f7c4SAlexandru Gagniuc 130d397f7c4SAlexandru Gagniuc /* Force the switch to start */ 131d397f7c4SAlexandru Gagniuc ksz8895_write_smireg(phydev, 1, 1); 132d397f7c4SAlexandru Gagniuc 133d397f7c4SAlexandru Gagniuc return 0; 134d397f7c4SAlexandru Gagniuc } 135d397f7c4SAlexandru Gagniuc 136d397f7c4SAlexandru Gagniuc static int ksz8895_startup(struct phy_device *phydev) 137d397f7c4SAlexandru Gagniuc { 138d397f7c4SAlexandru Gagniuc return 0; 139d397f7c4SAlexandru Gagniuc } 140d397f7c4SAlexandru Gagniuc 141d397f7c4SAlexandru Gagniuc static struct phy_driver ksz8895_driver = { 142d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ8895/KSZ8864", 143d397f7c4SAlexandru Gagniuc .uid = 0x221450, 144d397f7c4SAlexandru Gagniuc .mask = 0xffffe1, 145d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 146d397f7c4SAlexandru Gagniuc .config = &ksz8895_config, 147d397f7c4SAlexandru Gagniuc .startup = &ksz8895_startup, 148d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 149d397f7c4SAlexandru Gagniuc }; 150d397f7c4SAlexandru Gagniuc 151fbc120e6SAlexandru Gagniuc /* Micrel used the exact same part number for the KSZ9021. */ 152d397f7c4SAlexandru Gagniuc static struct phy_driver KS8721_driver = { 153d397f7c4SAlexandru Gagniuc .name = "Micrel KS8721BL", 154d397f7c4SAlexandru Gagniuc .uid = 0x221610, 155d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 156d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 157d397f7c4SAlexandru Gagniuc .config = &genphy_config, 158d397f7c4SAlexandru Gagniuc .startup = &genphy_startup, 159d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 160d397f7c4SAlexandru Gagniuc }; 161d397f7c4SAlexandru Gagniuc 162d397f7c4SAlexandru Gagniuc int ksz886x_config(struct phy_device *phydev) 163d397f7c4SAlexandru Gagniuc { 164d397f7c4SAlexandru Gagniuc /* we are connected directly to the switch without 165d397f7c4SAlexandru Gagniuc * dedicated PHY. */ 166d397f7c4SAlexandru Gagniuc phydev->link = 1; 167d397f7c4SAlexandru Gagniuc phydev->duplex = DUPLEX_FULL; 168d397f7c4SAlexandru Gagniuc phydev->speed = SPEED_100; 169d397f7c4SAlexandru Gagniuc return 0; 170d397f7c4SAlexandru Gagniuc } 171d397f7c4SAlexandru Gagniuc 172d397f7c4SAlexandru Gagniuc static int ksz886x_startup(struct phy_device *phydev) 173d397f7c4SAlexandru Gagniuc { 174d397f7c4SAlexandru Gagniuc return 0; 175d397f7c4SAlexandru Gagniuc } 176d397f7c4SAlexandru Gagniuc 177d397f7c4SAlexandru Gagniuc static struct phy_driver ksz886x_driver = { 178d397f7c4SAlexandru Gagniuc .name = "Micrel KSZ886x Switch", 179d397f7c4SAlexandru Gagniuc .uid = 0x00221430, 180d397f7c4SAlexandru Gagniuc .mask = 0xfffff0, 181d397f7c4SAlexandru Gagniuc .features = PHY_BASIC_FEATURES, 182d397f7c4SAlexandru Gagniuc .config = &ksz886x_config, 183d397f7c4SAlexandru Gagniuc .startup = &ksz886x_startup, 184d397f7c4SAlexandru Gagniuc .shutdown = &genphy_shutdown, 185d397f7c4SAlexandru Gagniuc }; 186d397f7c4SAlexandru Gagniuc 187d397f7c4SAlexandru Gagniuc int phy_micrel_ksz8xxx_init(void) 188d397f7c4SAlexandru Gagniuc { 189d397f7c4SAlexandru Gagniuc phy_register(&KSZ804_driver); 190d397f7c4SAlexandru Gagniuc phy_register(&KSZ8031_driver); 191d397f7c4SAlexandru Gagniuc phy_register(&KSZ8051_driver); 192d397f7c4SAlexandru Gagniuc phy_register(&KSZ8081_driver); 193d397f7c4SAlexandru Gagniuc phy_register(&KS8721_driver); 194d397f7c4SAlexandru Gagniuc phy_register(&ksz8895_driver); 195d397f7c4SAlexandru Gagniuc phy_register(&ksz886x_driver); 196d397f7c4SAlexandru Gagniuc return 0; 197d397f7c4SAlexandru Gagniuc } 198