uboot/drivers/net/phy/xilinx_phy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Xilinx PCS/PMA Core phy driver
   4 *
   5 * Copyright (C) 2015 - 2016 Xilinx, Inc.
   6 */
   7
   8#include <config.h>
   9#include <common.h>
  10#include <phy.h>
  11#include <dm.h>
  12
  13#define MII_PHY_STATUS_SPD_MASK         0x0C00
  14#define MII_PHY_STATUS_FULLDUPLEX       0x1000
  15#define MII_PHY_STATUS_1000             0x0800
  16#define MII_PHY_STATUS_100              0x0400
  17#define XPCSPMA_PHY_CTRL_ISOLATE_DISABLE 0xFBFF
  18
  19/* Mask used for ID comparisons */
  20#define XILINX_PHY_ID_MASK              0xfffffff0
  21
  22/* Known PHY IDs */
  23#define XILINX_PHY_ID                   0x01740c00
  24
  25/* struct phy_device dev_flags definitions */
  26#define XAE_PHY_TYPE_MII                0
  27#define XAE_PHY_TYPE_GMII               1
  28#define XAE_PHY_TYPE_RGMII_1_3          2
  29#define XAE_PHY_TYPE_RGMII_2_0          3
  30#define XAE_PHY_TYPE_SGMII              4
  31#define XAE_PHY_TYPE_1000BASE_X         5
  32
  33static int xilinxphy_startup(struct phy_device *phydev)
  34{
  35        int err;
  36        int status = 0;
  37
  38        debug("%s\n", __func__);
  39        /* Update the link, but return if there
  40         * was an error
  41         */
  42        err = genphy_update_link(phydev);
  43        if (err)
  44                return err;
  45
  46        if (AUTONEG_ENABLE == phydev->autoneg) {
  47                status = phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
  48                status = status & MII_PHY_STATUS_SPD_MASK;
  49
  50                if (status & MII_PHY_STATUS_FULLDUPLEX)
  51                        phydev->duplex = DUPLEX_FULL;
  52                else
  53                        phydev->duplex = DUPLEX_HALF;
  54
  55                switch (status) {
  56                case MII_PHY_STATUS_1000:
  57                        phydev->speed = SPEED_1000;
  58                        break;
  59
  60                case MII_PHY_STATUS_100:
  61                        phydev->speed = SPEED_100;
  62                        break;
  63
  64                default:
  65                        phydev->speed = SPEED_10;
  66                        break;
  67                }
  68        } else {
  69                int bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
  70
  71                if (bmcr < 0)
  72                        return bmcr;
  73
  74                if (bmcr & BMCR_FULLDPLX)
  75                        phydev->duplex = DUPLEX_FULL;
  76                else
  77                        phydev->duplex = DUPLEX_HALF;
  78
  79                if (bmcr & BMCR_SPEED1000)
  80                        phydev->speed = SPEED_1000;
  81                else if (bmcr & BMCR_SPEED100)
  82                        phydev->speed = SPEED_100;
  83                else
  84                        phydev->speed = SPEED_10;
  85        }
  86
  87        /*
  88         * For 1000BASE-X Phy Mode the speed/duplex will always be
  89         * 1000Mbps/fullduplex
  90         */
  91        if (phydev->flags == XAE_PHY_TYPE_1000BASE_X) {
  92                phydev->duplex = DUPLEX_FULL;
  93                phydev->speed = SPEED_1000;
  94        }
  95
  96        return 0;
  97}
  98
  99static int xilinxphy_of_init(struct phy_device *phydev)
 100{
 101        u32 phytype;
 102        ofnode node;
 103
 104        debug("%s\n", __func__);
 105        node = phy_get_ofnode(phydev);
 106        if (!ofnode_valid(node))
 107                return -EINVAL;
 108
 109        phytype = ofnode_read_u32_default(node, "xlnx,phy-type", -1);
 110        if (phytype == XAE_PHY_TYPE_1000BASE_X)
 111                phydev->flags |= XAE_PHY_TYPE_1000BASE_X;
 112
 113        return 0;
 114}
 115
 116static int xilinxphy_config(struct phy_device *phydev)
 117{
 118        int temp;
 119
 120        debug("%s\n", __func__);
 121        xilinxphy_of_init(phydev);
 122        temp = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
 123        temp &= XPCSPMA_PHY_CTRL_ISOLATE_DISABLE;
 124        phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, temp);
 125
 126        return 0;
 127}
 128
 129static struct phy_driver xilinxphy_driver = {
 130        .uid = XILINX_PHY_ID,
 131        .mask = XILINX_PHY_ID_MASK,
 132        .name = "Xilinx PCS/PMA PHY",
 133        .features = PHY_GBIT_FEATURES,
 134        .config = &xilinxphy_config,
 135        .startup = &xilinxphy_startup,
 136        .shutdown = &genphy_shutdown,
 137};
 138
 139int phy_xilinx_init(void)
 140{
 141        debug("%s\n", __func__);
 142        phy_register(&xilinxphy_driver);
 143
 144        return 0;
 145}
 146