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