linux/drivers/net/phy/xilinx_phy.c
<<
>>
Prefs
   1/* Xilinx PCS/PMA Core phy driver
   2 *
   3 * Copyright (C) 2015 Xilinx, Inc.
   4 *
   5 * Description:
   6 * This driver is developed for PCS/PMA Core.
   7 *
   8 * This program is free software: you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation, either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 */
  18
  19#include <linux/kernel.h>
  20#include <linux/module.h>
  21#include <linux/mii.h>
  22#include <linux/phy.h>
  23#include <linux/of.h>
  24#include <linux/xilinx_phy.h>
  25
  26#define MII_PHY_STATUS_SPD_MASK         0x0C00
  27#define MII_PHY_STATUS_FULLDUPLEX       0x1000
  28#define MII_PHY_STATUS_1000             0x0800
  29#define MII_PHY_STATUS_100              0x0400
  30#define XPCSPMA_PHY_CTRL_ISOLATE_DISABLE 0xFBFF
  31
  32static int xilinxphy_read_status(struct phy_device *phydev)
  33{
  34        int err;
  35        int status = 0;
  36
  37        /* Update the link, but return if there
  38         * was an error
  39         */
  40        err = genphy_update_link(phydev);
  41        if (err)
  42                return err;
  43
  44        if (phydev->autoneg == AUTONEG_ENABLE) {
  45                status = phy_read(phydev, MII_LPA);
  46
  47                if (status & MII_PHY_STATUS_FULLDUPLEX)
  48                        phydev->duplex = DUPLEX_FULL;
  49                else
  50                        phydev->duplex = DUPLEX_HALF;
  51
  52                switch (status & MII_PHY_STATUS_SPD_MASK) {
  53                case MII_PHY_STATUS_1000:
  54                        phydev->speed = SPEED_1000;
  55                        break;
  56
  57                case MII_PHY_STATUS_100:
  58                        phydev->speed = SPEED_100;
  59                        break;
  60
  61                default:
  62                        phydev->speed = SPEED_10;
  63                        break;
  64                }
  65        } else {
  66                int bmcr = phy_read(phydev, MII_BMCR);
  67
  68                if (bmcr < 0)
  69                        return bmcr;
  70
  71                if (bmcr & BMCR_FULLDPLX)
  72                        phydev->duplex = DUPLEX_FULL;
  73                else
  74                        phydev->duplex = DUPLEX_HALF;
  75
  76                if (bmcr & BMCR_SPEED1000)
  77                        phydev->speed = SPEED_1000;
  78                else if (bmcr & BMCR_SPEED100)
  79                        phydev->speed = SPEED_100;
  80                else
  81                        phydev->speed = SPEED_10;
  82        }
  83
  84        /* For 1000BASE-X Phy Mode the speed/duplex will always be
  85         * 1000Mbps/fullduplex
  86         */
  87        if (phydev->dev_flags == XAE_PHY_TYPE_1000BASE_X) {
  88                phydev->duplex = DUPLEX_FULL;
  89                phydev->speed = SPEED_1000;
  90        }
  91
  92        /* For 2500BASE-X Phy Mode the speed/duplex will always be
  93         * 2500Mbps/fullduplex
  94         */
  95        if (phydev->dev_flags == XAE_PHY_TYPE_2500) {
  96                phydev->duplex = DUPLEX_FULL;
  97                phydev->speed = SPEED_2500;
  98        }
  99
 100        return 0;
 101}
 102
 103static int xilinxphy_of_init(struct phy_device *phydev)
 104{
 105        struct device *dev = &phydev->mdio.dev;
 106        struct device_node *of_node = dev->of_node;
 107        u32 phytype;
 108
 109        if (!IS_ENABLED(CONFIG_OF_MDIO))
 110                return 0;
 111
 112        if (!of_node)
 113                return -ENODEV;
 114
 115        if (!of_property_read_u32(of_node, "xlnx,phy-type", &phytype)) {
 116                if (phytype == XAE_PHY_TYPE_1000BASE_X)
 117                        phydev->dev_flags |= XAE_PHY_TYPE_1000BASE_X;
 118                if (phytype == XAE_PHY_TYPE_2500)
 119                        phydev->dev_flags |= XAE_PHY_TYPE_2500;
 120        }
 121
 122        return 0;
 123}
 124
 125static int xilinxphy_config_init(struct phy_device *phydev)
 126{
 127        int temp;
 128
 129        xilinxphy_of_init(phydev);
 130        temp = phy_read(phydev, MII_BMCR);
 131        temp &= XPCSPMA_PHY_CTRL_ISOLATE_DISABLE;
 132        phy_write(phydev, MII_BMCR, temp);
 133
 134        return 0;
 135}
 136
 137static struct phy_driver xilinx_drivers[] = {
 138        {
 139                .phy_id = XILINX_PHY_ID,
 140                .phy_id_mask = XILINX_PHY_ID_MASK,
 141                .name = "Xilinx PCS/PMA PHY",
 142                .features = PHY_GBIT_FEATURES,
 143                .config_init = &xilinxphy_config_init,
 144                .config_aneg = &genphy_config_aneg,
 145                .read_status = &xilinxphy_read_status,
 146                .resume = &genphy_resume,
 147                .suspend = &genphy_suspend,
 148        },
 149};
 150
 151module_phy_driver(xilinx_drivers);
 152
 153static struct mdio_device_id __maybe_unused xilinx_tbl[] = {
 154        { XILINX_PHY_ID, XILINX_PHY_ID_MASK },
 155        { }
 156};
 157
 158MODULE_DEVICE_TABLE(mdio, xilinx_tbl);
 159MODULE_DESCRIPTION("Xilinx PCS/PMA PHY driver");
 160MODULE_LICENSE("GPL");
 161