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