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