GNU Linux-libre 4.14.266-gnu1
[releases.git] / drivers / net / phy / phy-core.c
1 /*
2  * Core PHY library, taken from phy.c
3  *
4  * This program is free software; you can redistribute  it and/or modify it
5  * under  the terms of  the GNU General  Public License as published by the
6  * Free Software Foundation;  either version 2 of the  License, or (at your
7  * option) any later version.
8  */
9 #include <linux/export.h>
10 #include <linux/phy.h>
11
12 const char *phy_speed_to_str(int speed)
13 {
14         switch (speed) {
15         case SPEED_10:
16                 return "10Mbps";
17         case SPEED_100:
18                 return "100Mbps";
19         case SPEED_1000:
20                 return "1Gbps";
21         case SPEED_2500:
22                 return "2.5Gbps";
23         case SPEED_5000:
24                 return "5Gbps";
25         case SPEED_10000:
26                 return "10Gbps";
27         case SPEED_14000:
28                 return "14Gbps";
29         case SPEED_20000:
30                 return "20Gbps";
31         case SPEED_25000:
32                 return "25Gbps";
33         case SPEED_40000:
34                 return "40Gbps";
35         case SPEED_50000:
36                 return "50Gbps";
37         case SPEED_56000:
38                 return "56Gbps";
39         case SPEED_100000:
40                 return "100Gbps";
41         case SPEED_UNKNOWN:
42                 return "Unknown";
43         default:
44                 return "Unsupported (update phy-core.c)";
45         }
46 }
47 EXPORT_SYMBOL_GPL(phy_speed_to_str);
48
49 const char *phy_duplex_to_str(unsigned int duplex)
50 {
51         if (duplex == DUPLEX_HALF)
52                 return "Half";
53         if (duplex == DUPLEX_FULL)
54                 return "Full";
55         if (duplex == DUPLEX_UNKNOWN)
56                 return "Unknown";
57         return "Unsupported (update phy-core.c)";
58 }
59 EXPORT_SYMBOL_GPL(phy_duplex_to_str);
60
61 /* A mapping of all SUPPORTED settings to speed/duplex.  This table
62  * must be grouped by speed and sorted in descending match priority
63  * - iow, descending speed. */
64 static const struct phy_setting settings[] = {
65         {
66                 .speed = SPEED_10000,
67                 .duplex = DUPLEX_FULL,
68                 .bit = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
69         },
70         {
71                 .speed = SPEED_10000,
72                 .duplex = DUPLEX_FULL,
73                 .bit = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
74         },
75         {
76                 .speed = SPEED_10000,
77                 .duplex = DUPLEX_FULL,
78                 .bit = ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
79         },
80         {
81                 .speed = SPEED_2500,
82                 .duplex = DUPLEX_FULL,
83                 .bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
84         },
85         {
86                 .speed = SPEED_1000,
87                 .duplex = DUPLEX_FULL,
88                 .bit = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
89         },
90         {
91                 .speed = SPEED_1000,
92                 .duplex = DUPLEX_FULL,
93                 .bit = ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
94         },
95         {
96                 .speed = SPEED_1000,
97                 .duplex = DUPLEX_FULL,
98                 .bit = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
99         },
100         {
101                 .speed = SPEED_1000,
102                 .duplex = DUPLEX_HALF,
103                 .bit = ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
104         },
105         {
106                 .speed = SPEED_100,
107                 .duplex = DUPLEX_FULL,
108                 .bit = ETHTOOL_LINK_MODE_100baseT_Full_BIT,
109         },
110         {
111                 .speed = SPEED_100,
112                 .duplex = DUPLEX_HALF,
113                 .bit = ETHTOOL_LINK_MODE_100baseT_Half_BIT,
114         },
115         {
116                 .speed = SPEED_10,
117                 .duplex = DUPLEX_FULL,
118                 .bit = ETHTOOL_LINK_MODE_10baseT_Full_BIT,
119         },
120         {
121                 .speed = SPEED_10,
122                 .duplex = DUPLEX_HALF,
123                 .bit = ETHTOOL_LINK_MODE_10baseT_Half_BIT,
124         },
125 };
126
127 /**
128  * phy_lookup_setting - lookup a PHY setting
129  * @speed: speed to match
130  * @duplex: duplex to match
131  * @mask: allowed link modes
132  * @maxbit: bit size of link modes
133  * @exact: an exact match is required
134  *
135  * Search the settings array for a setting that matches the speed and
136  * duplex, and which is supported.
137  *
138  * If @exact is unset, either an exact match or %NULL for no match will
139  * be returned.
140  *
141  * If @exact is set, an exact match, the fastest supported setting at
142  * or below the specified speed, the slowest supported setting, or if
143  * they all fail, %NULL will be returned.
144  */
145 const struct phy_setting *
146 phy_lookup_setting(int speed, int duplex, const unsigned long *mask,
147                    size_t maxbit, bool exact)
148 {
149         const struct phy_setting *p, *match = NULL, *last = NULL;
150         int i;
151
152         for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
153                 if (p->bit < maxbit && test_bit(p->bit, mask)) {
154                         last = p;
155                         if (p->speed == speed && p->duplex == duplex) {
156                                 /* Exact match for speed and duplex */
157                                 match = p;
158                                 break;
159                         } else if (!exact) {
160                                 if (!match && p->speed <= speed)
161                                         /* Candidate */
162                                         match = p;
163
164                                 if (p->speed < speed)
165                                         break;
166                         }
167                 }
168         }
169
170         if (!match && !exact)
171                 match = last;
172
173         return match;
174 }
175 EXPORT_SYMBOL_GPL(phy_lookup_setting);
176
177 size_t phy_speeds(unsigned int *speeds, size_t size,
178                   unsigned long *mask, size_t maxbit)
179 {
180         size_t count;
181         int i;
182
183         for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++)
184                 if (settings[i].bit < maxbit &&
185                     test_bit(settings[i].bit, mask) &&
186                     (count == 0 || speeds[count - 1] != settings[i].speed))
187                         speeds[count++] = settings[i].speed;
188
189         return count;
190 }
191
192 static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
193                              u16 regnum)
194 {
195         /* Write the desired MMD Devad */
196         bus->write(bus, phy_addr, MII_MMD_CTRL, devad);
197
198         /* Write the desired MMD register address */
199         bus->write(bus, phy_addr, MII_MMD_DATA, regnum);
200
201         /* Select the Function : DATA with no post increment */
202         bus->write(bus, phy_addr, MII_MMD_CTRL, devad | MII_MMD_CTRL_NOINCR);
203 }
204
205 /**
206  * phy_read_mmd - Convenience function for reading a register
207  * from an MMD on a given PHY.
208  * @phydev: The phy_device struct
209  * @devad: The MMD to read from (0..31)
210  * @regnum: The register on the MMD to read (0..65535)
211  *
212  * Same rules as for phy_read();
213  */
214 int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
215 {
216         int val;
217
218         if (regnum > (u16)~0 || devad > 32)
219                 return -EINVAL;
220
221         if (phydev->drv->read_mmd) {
222                 val = phydev->drv->read_mmd(phydev, devad, regnum);
223         } else if (phydev->is_c45) {
224                 u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
225
226                 val = mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, addr);
227         } else {
228                 struct mii_bus *bus = phydev->mdio.bus;
229                 int phy_addr = phydev->mdio.addr;
230
231                 mutex_lock(&bus->mdio_lock);
232                 mmd_phy_indirect(bus, phy_addr, devad, regnum);
233
234                 /* Read the content of the MMD's selected register */
235                 val = bus->read(bus, phy_addr, MII_MMD_DATA);
236                 mutex_unlock(&bus->mdio_lock);
237         }
238         return val;
239 }
240 EXPORT_SYMBOL(phy_read_mmd);
241
242 /**
243  * phy_write_mmd - Convenience function for writing a register
244  * on an MMD on a given PHY.
245  * @phydev: The phy_device struct
246  * @devad: The MMD to read from
247  * @regnum: The register on the MMD to read
248  * @val: value to write to @regnum
249  *
250  * Same rules as for phy_write();
251  */
252 int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
253 {
254         int ret;
255
256         if (regnum > (u16)~0 || devad > 32)
257                 return -EINVAL;
258
259         if (phydev->drv->write_mmd) {
260                 ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
261         } else if (phydev->is_c45) {
262                 u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
263
264                 ret = mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
265                                     addr, val);
266         } else {
267                 struct mii_bus *bus = phydev->mdio.bus;
268                 int phy_addr = phydev->mdio.addr;
269
270                 mutex_lock(&bus->mdio_lock);
271                 mmd_phy_indirect(bus, phy_addr, devad, regnum);
272
273                 /* Write the data into MMD's selected register */
274                 bus->write(bus, phy_addr, MII_MMD_DATA, val);
275                 mutex_unlock(&bus->mdio_lock);
276
277                 ret = 0;
278         }
279         return ret;
280 }
281 EXPORT_SYMBOL(phy_write_mmd);