xref: /openbmc/u-boot/drivers/net/phy/xilinx_phy.c (revision ae485b54)
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