Merge git://git.denx.de/u-boot-dm
[oweals/u-boot.git] / drivers / net / phy / xilinx_phy.c
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
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
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
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
139 int phy_xilinx_init(void)
140 {
141         debug("%s\n", __func__);
142         phy_register(&xilinxphy_driver);
143
144         return 0;
145 }