1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Xilinx GMII2RGMII phy driver 4 * 5 * Copyright (C) 2018 Xilinx, Inc. 6 */ 7 8#include <common.h> 9#include <dm.h> 10#include <log.h> 11#include <phy.h> 12#include <asm/global_data.h> 13 14DECLARE_GLOBAL_DATA_PTR; 15 16#define ZYNQ_GMII2RGMII_REG 0x10 17#define ZYNQ_GMII2RGMII_SPEED_MASK (BMCR_SPEED1000 | BMCR_SPEED100) 18 19static int xilinxgmiitorgmii_config(struct phy_device *phydev) 20{ 21 ofnode node = phy_get_ofnode(phydev); 22 struct phy_device *ext_phydev; 23 struct ofnode_phandle_args phandle; 24 int ext_phyaddr = -1; 25 int ret; 26 27 debug("%s\n", __func__); 28 29 if (phydev->interface != PHY_INTERFACE_MODE_GMII) { 30 printf("Incorrect interface type\n"); 31 return -EINVAL; 32 } 33 34 if (!ofnode_valid(node)) 35 return -EINVAL; 36 37 phydev->addr = ofnode_read_u32_default(node, "reg", -1); 38 ret = ofnode_parse_phandle_with_args(node, "phy-handle", 39 NULL, 0, 0, &phandle); 40 if (ret) 41 return ret; 42 43 ext_phyaddr = ofnode_read_u32_default(phandle.node, "reg", -1); 44 ext_phydev = phy_find_by_mask(phydev->bus, 45 1 << ext_phyaddr); 46 if (!ext_phydev) { 47 printf("%s, No external phy device found\n", __func__); 48 return -EINVAL; 49 } 50 51 ext_phydev->interface = ofnode_read_phy_mode(node); 52 if (ext_phydev->interface == PHY_INTERFACE_MODE_NA) { 53 ext_phydev->interface = PHY_INTERFACE_MODE_RGMII; 54 } else if (!phy_interface_is_rgmii(ext_phydev)) { 55 printf("Incorrect external interface type\n"); 56 return -EINVAL; 57 } 58 59 ext_phydev->node = phandle.node; 60 phydev->priv = ext_phydev; 61 62 debug("%s, gmii2rgmmi:0x%x, extphy:0x%x\n", __func__, phydev->addr, 63 ext_phyaddr); 64 65 if (ext_phydev->drv->config) 66 ext_phydev->drv->config(ext_phydev); 67 68 return 0; 69} 70 71static int xilinxgmiitorgmii_extread(struct phy_device *phydev, int addr, 72 int devaddr, int regnum) 73{ 74 struct phy_device *ext_phydev = phydev->priv; 75 76 debug("%s\n", __func__); 77 if (ext_phydev->drv->readext) 78 ext_phydev->drv->readext(ext_phydev, addr, devaddr, regnum); 79 80 return 0; 81} 82 83static int xilinxgmiitorgmii_extwrite(struct phy_device *phydev, int addr, 84 int devaddr, int regnum, u16 val) 85 86{ 87 struct phy_device *ext_phydev = phydev->priv; 88 89 debug("%s\n", __func__); 90 if (ext_phydev->drv->writeext) 91 ext_phydev->drv->writeext(ext_phydev, addr, devaddr, regnum, 92 val); 93 94 return 0; 95} 96 97static int xilinxgmiitorgmii_startup(struct phy_device *phydev) 98{ 99 u16 val = 0; 100 struct phy_device *ext_phydev = phydev->priv; 101 102 debug("%s\n", __func__); 103 ext_phydev->dev = phydev->dev; 104 if (ext_phydev->drv->startup) 105 ext_phydev->drv->startup(ext_phydev); 106 107 val = phy_read(phydev, phydev->addr, ZYNQ_GMII2RGMII_REG); 108 val &= ~ZYNQ_GMII2RGMII_SPEED_MASK; 109 110 if (ext_phydev->speed == SPEED_1000) 111 val |= BMCR_SPEED1000; 112 else if (ext_phydev->speed == SPEED_100) 113 val |= BMCR_SPEED100; 114 115 phy_write(phydev, phydev->addr, ZYNQ_GMII2RGMII_REG, val | 116 BMCR_FULLDPLX); 117 118 phydev->duplex = ext_phydev->duplex; 119 phydev->speed = ext_phydev->speed; 120 phydev->link = ext_phydev->link; 121 122 return 0; 123} 124 125static int xilinxgmiitorgmii_probe(struct phy_device *phydev) 126{ 127 debug("%s\n", __func__); 128 129 phydev->flags |= PHY_FLAG_BROKEN_RESET; 130 131 return 0; 132} 133 134U_BOOT_PHY_DRIVER(gmii2rgmii) = { 135 .name = "XILINX GMII2RGMII", 136 .uid = PHY_GMII2RGMII_ID, 137 .mask = 0xffffffff, 138 .features = PHY_GBIT_FEATURES, 139 .probe = xilinxgmiitorgmii_probe, 140 .config = xilinxgmiitorgmii_config, 141 .startup = xilinxgmiitorgmii_startup, 142 .writeext = xilinxgmiitorgmii_extwrite, 143 .readext = xilinxgmiitorgmii_extread, 144}; 145