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