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