File Index
Files and directories
Sign in
FILE

bcm54140.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/phy/bcm54140.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/* Broadcom BCM54140 Quad SGMII/QSGMII Copper/Fiber Gigabit PHY
  3 *
  4 * Copyright (c) 2020 Michael Walle <michael@walle.cc>
  5 */
  6
  7#include <linux/bitfield.h>
  8#include <linux/brcmphy.h>
  9#include <linux/hwmon.h>
 10#include <linux/module.h>
 11#include <linux/phy.h>
 12
 13#include "phylib.h"
 14#include "bcm-phy-lib.h"
 15
 16/* RDB per-port registers
 17 */
 18#define BCM54140_RDB_ISR		0x00a	/* interrupt status */
 19#define BCM54140_RDB_IMR		0x00b	/* interrupt mask */
 20#define  BCM54140_RDB_INT_LINK		BIT(1)	/* link status changed */
 21#define  BCM54140_RDB_INT_SPEED		BIT(2)	/* link speed change */
 22#define  BCM54140_RDB_INT_DUPLEX	BIT(3)	/* duplex mode changed */
 23#define BCM54140_RDB_SPARE1		0x012	/* spare control 1 */
 24#define  BCM54140_RDB_SPARE1_LSLM	BIT(2)	/* link speed LED mode */
 25#define BCM54140_RDB_SPARE2		0x014	/* spare control 2 */
 26#define  BCM54140_RDB_SPARE2_WS_RTRY_DIS BIT(8) /* wirespeed retry disable */
 27#define  BCM54140_RDB_SPARE2_WS_RTRY_LIMIT GENMASK(4, 2) /* retry limit */
 28#define BCM54140_RDB_SPARE3		0x015	/* spare control 3 */
 29#define  BCM54140_RDB_SPARE3_BIT0	BIT(0)
 30#define BCM54140_RDB_LED_CTRL		0x019	/* LED control */
 31#define  BCM54140_RDB_LED_CTRL_ACTLINK0	BIT(4)
 32#define  BCM54140_RDB_LED_CTRL_ACTLINK1	BIT(8)
 33#define BCM54140_RDB_C_APWR		0x01a	/* auto power down control */
 34#define  BCM54140_RDB_C_APWR_SINGLE_PULSE	BIT(8)	/* single pulse */
 35#define  BCM54140_RDB_C_APWR_APD_MODE_DIS	0 /* ADP disable */
 36#define  BCM54140_RDB_C_APWR_APD_MODE_EN	1 /* ADP enable */
 37#define  BCM54140_RDB_C_APWR_APD_MODE_DIS2	2 /* ADP disable */
 38#define  BCM54140_RDB_C_APWR_APD_MODE_EN_ANEG	3 /* ADP enable w/ aneg */
 39#define  BCM54140_RDB_C_APWR_APD_MODE_MASK	GENMASK(6, 5)
 40#define  BCM54140_RDB_C_APWR_SLP_TIM_MASK BIT(4)/* sleep timer */
 41#define  BCM54140_RDB_C_APWR_SLP_TIM_2_7 0	/* 2.7s */
 42#define  BCM54140_RDB_C_APWR_SLP_TIM_5_4 1	/* 5.4s */
 43#define BCM54140_RDB_C_PWR		0x02a	/* copper power control */
 44#define  BCM54140_RDB_C_PWR_ISOLATE	BIT(5)	/* super isolate mode */
 45#define BCM54140_RDB_C_MISC_CTRL	0x02f	/* misc copper control */
 46#define  BCM54140_RDB_C_MISC_CTRL_WS_EN BIT(4)	/* wirespeed enable */
 47
 48/* RDB global registers
 49 */
 50#define BCM54140_RDB_TOP_IMR		0x82d	/* interrupt mask */
 51#define  BCM54140_RDB_TOP_IMR_PORT0	BIT(4)
 52#define  BCM54140_RDB_TOP_IMR_PORT1	BIT(5)
 53#define  BCM54140_RDB_TOP_IMR_PORT2	BIT(6)
 54#define  BCM54140_RDB_TOP_IMR_PORT3	BIT(7)
 55#define BCM54140_RDB_MON_CTRL		0x831	/* monitor control */
 56#define  BCM54140_RDB_MON_CTRL_V_MODE	BIT(3)	/* voltage mode */
 57#define  BCM54140_RDB_MON_CTRL_SEL_MASK	GENMASK(2, 1)
 58#define  BCM54140_RDB_MON_CTRL_SEL_TEMP	0	/* meassure temperature */
 59#define  BCM54140_RDB_MON_CTRL_SEL_1V0	1	/* meassure AVDDL 1.0V */
 60#define  BCM54140_RDB_MON_CTRL_SEL_3V3	2	/* meassure AVDDH 3.3V */
 61#define  BCM54140_RDB_MON_CTRL_SEL_RR	3	/* meassure all round-robin */
 62#define  BCM54140_RDB_MON_CTRL_PWR_DOWN	BIT(0)	/* power-down monitor */
 63#define BCM54140_RDB_MON_TEMP_VAL	0x832	/* temperature value */
 64#define BCM54140_RDB_MON_TEMP_MAX	0x833	/* temperature high thresh */
 65#define BCM54140_RDB_MON_TEMP_MIN	0x834	/* temperature low thresh */
 66#define  BCM54140_RDB_MON_TEMP_DATA_MASK GENMASK(9, 0)
 67#define BCM54140_RDB_MON_1V0_VAL	0x835	/* AVDDL 1.0V value */
 68#define BCM54140_RDB_MON_1V0_MAX	0x836	/* AVDDL 1.0V high thresh */
 69#define BCM54140_RDB_MON_1V0_MIN	0x837	/* AVDDL 1.0V low thresh */
 70#define  BCM54140_RDB_MON_1V0_DATA_MASK	GENMASK(10, 0)
 71#define BCM54140_RDB_MON_3V3_VAL	0x838	/* AVDDH 3.3V value */
 72#define BCM54140_RDB_MON_3V3_MAX	0x839	/* AVDDH 3.3V high thresh */
 73#define BCM54140_RDB_MON_3V3_MIN	0x83a	/* AVDDH 3.3V low thresh */
 74#define  BCM54140_RDB_MON_3V3_DATA_MASK	GENMASK(11, 0)
 75#define BCM54140_RDB_MON_ISR		0x83b	/* interrupt status */
 76#define  BCM54140_RDB_MON_ISR_3V3	BIT(2)	/* AVDDH 3.3V alarm */
 77#define  BCM54140_RDB_MON_ISR_1V0	BIT(1)	/* AVDDL 1.0V alarm */
 78#define  BCM54140_RDB_MON_ISR_TEMP	BIT(0)	/* temperature alarm */
 79
 80/* According to the datasheet the formula is:
 81 *   T = 413.35 - (0.49055 * bits[9:0])
 82 */
 83#define BCM54140_HWMON_TO_TEMP(v) (413350L - (v) * 491)
 84#define BCM54140_HWMON_FROM_TEMP(v) DIV_ROUND_CLOSEST_ULL(413350L - (v), 491)
 85
 86/* According to the datasheet the formula is:
 87 *   U = bits[11:0] / 1024 * 220 / 0.2
 88 *
 89 * Normalized:
 90 *   U = bits[11:0] / 4096 * 2514
 91 */
 92#define BCM54140_HWMON_TO_IN_1V0(v) ((v) * 2514 >> 11)
 93#define BCM54140_HWMON_FROM_IN_1V0(v) DIV_ROUND_CLOSEST_ULL(((v) << 11), 2514)
 94
 95/* According to the datasheet the formula is:
 96 *   U = bits[10:0] / 1024 * 880 / 0.7
 97 *
 98 * Normalized:
 99 *   U = bits[10:0] / 2048 * 4400
100 */
101#define BCM54140_HWMON_TO_IN_3V3(v) ((v) * 4400 >> 12)
102#define BCM54140_HWMON_FROM_IN_3V3(v) DIV_ROUND_CLOSEST_ULL(((v) << 12), 4400)
103
104#define BCM54140_HWMON_TO_IN(ch, v) ((ch) ? BCM54140_HWMON_TO_IN_3V3(v) \
105					  : BCM54140_HWMON_TO_IN_1V0(v))
106#define BCM54140_HWMON_FROM_IN(ch, v) ((ch) ? BCM54140_HWMON_FROM_IN_3V3(v) \
107					    : BCM54140_HWMON_FROM_IN_1V0(v))
108#define BCM54140_HWMON_IN_MASK(ch) ((ch) ? BCM54140_RDB_MON_3V3_DATA_MASK \
109					 : BCM54140_RDB_MON_1V0_DATA_MASK)
110#define BCM54140_HWMON_IN_VAL_REG(ch) ((ch) ? BCM54140_RDB_MON_3V3_VAL \
111					    : BCM54140_RDB_MON_1V0_VAL)
112#define BCM54140_HWMON_IN_MIN_REG(ch) ((ch) ? BCM54140_RDB_MON_3V3_MIN \
113					    : BCM54140_RDB_MON_1V0_MIN)
114#define BCM54140_HWMON_IN_MAX_REG(ch) ((ch) ? BCM54140_RDB_MON_3V3_MAX \
115					    : BCM54140_RDB_MON_1V0_MAX)
116#define BCM54140_HWMON_IN_ALARM_BIT(ch) ((ch) ? BCM54140_RDB_MON_ISR_3V3 \
117					      : BCM54140_RDB_MON_ISR_1V0)
118
119/* This PHY has two different PHY IDs depening on its MODE_SEL pin. This
120 * pin choses between 4x SGMII and QSGMII mode:
121 *   AE02_5009 4x SGMII
122 *   AE02_5019 QSGMII
123 */
124#define BCM54140_PHY_ID_MASK	0xffffffe8
125
126#define BCM54140_PHY_ID_REV(phy_id)	((phy_id) & 0x7)
127#define BCM54140_REV_B0			1
128
129#define BCM54140_DEFAULT_DOWNSHIFT 5
130#define BCM54140_MAX_DOWNSHIFT 9
131
132enum bcm54140_global_phy {
133	BCM54140_BASE_ADDR = 0,
134};
135
136struct bcm54140_priv {
137	int port;
138	int base_addr;
139#if IS_ENABLED(CONFIG_HWMON)
140	/* protect the alarm bits */
141	struct mutex alarm_lock;
142	u16 alarm;
143#endif
144};
145
146#if IS_ENABLED(CONFIG_HWMON)
147static umode_t bcm54140_hwmon_is_visible(const void *data,
148					 enum hwmon_sensor_types type,
149					 u32 attr, int channel)
150{
151	switch (type) {
152	case hwmon_in:
153		switch (attr) {
154		case hwmon_in_min:
155		case hwmon_in_max:
156			return 0644;
157		case hwmon_in_label:
158		case hwmon_in_input:
159		case hwmon_in_alarm:
160			return 0444;
161		default:
162			return 0;
163		}
164	case hwmon_temp:
165		switch (attr) {
166		case hwmon_temp_min:
167		case hwmon_temp_max:
168			return 0644;
169		case hwmon_temp_input:
170		case hwmon_temp_alarm:
171			return 0444;
172		default:
173			return 0;
174		}
175	default:
176		return 0;
177	}
178}
179
180static int bcm54140_hwmon_read_alarm(struct device *dev, unsigned int bit,
181				     long *val)
182{
183	struct phy_device *phydev = dev_get_drvdata(dev);
184	struct bcm54140_priv *priv = phydev->priv;
185	int tmp, ret = 0;
186
187	mutex_lock(&priv->alarm_lock);
188
189	/* latch any alarm bits */
190	tmp = bcm_phy_read_rdb(phydev, BCM54140_RDB_MON_ISR);
191	if (tmp < 0) {
192		ret = tmp;
193		goto out;
194	}
195	priv->alarm |= tmp;
196
197	*val = !!(priv->alarm & bit);
198	priv->alarm &= ~bit;
199
200out:
201	mutex_unlock(&priv->alarm_lock);
202	return ret;
203}
204
205static int bcm54140_hwmon_read_temp(struct device *dev, u32 attr, long *val)
206{
207	struct phy_device *phydev = dev_get_drvdata(dev);
208	u16 reg;
209	int tmp;
210
211	switch (attr) {
212	case hwmon_temp_input:
213		reg = BCM54140_RDB_MON_TEMP_VAL;
214		break;
215	case hwmon_temp_min:
216		reg = BCM54140_RDB_MON_TEMP_MIN;
217		break;
218	case hwmon_temp_max:
219		reg = BCM54140_RDB_MON_TEMP_MAX;
220		break;
221	case hwmon_temp_alarm:
222		return bcm54140_hwmon_read_alarm(dev,
223						 BCM54140_RDB_MON_ISR_TEMP,
224						 val);
225	default:
226		return -EOPNOTSUPP;
227	}
228
229	tmp = bcm_phy_read_rdb(phydev, reg);
230	if (tmp < 0)
231		return tmp;
232
233	*val = BCM54140_HWMON_TO_TEMP(tmp & BCM54140_RDB_MON_TEMP_DATA_MASK);
234
235	return 0;
236}
237
238static int bcm54140_hwmon_read_in(struct device *dev, u32 attr,
239				  int channel, long *val)
240{
241	struct phy_device *phydev = dev_get_drvdata(dev);
242	u16 bit, reg;
243	int tmp;
244
245	switch (attr) {
246	case hwmon_in_input:
247		reg = BCM54140_HWMON_IN_VAL_REG(channel);
248		break;
249	case hwmon_in_min:
250		reg = BCM54140_HWMON_IN_MIN_REG(channel);
251		break;
252	case hwmon_in_max:
253		reg = BCM54140_HWMON_IN_MAX_REG(channel);
254		break;
255	case hwmon_in_alarm:
256		bit = BCM54140_HWMON_IN_ALARM_BIT(channel);
257		return bcm54140_hwmon_read_alarm(dev, bit, val);
258	default:
259		return -EOPNOTSUPP;
260	}
261
262	tmp = bcm_phy_read_rdb(phydev, reg);
263	if (tmp < 0)
264		return tmp;
265
266	tmp &= BCM54140_HWMON_IN_MASK(channel);
267	*val = BCM54140_HWMON_TO_IN(channel, tmp);
268
269	return 0;
270}
271
272static int bcm54140_hwmon_read(struct device *dev,
273			       enum hwmon_sensor_types type, u32 attr,
274			       int channel, long *val)
275{
276	switch (type) {
277	case hwmon_temp:
278		return bcm54140_hwmon_read_temp(dev, attr, val);
279	case hwmon_in:
280		return bcm54140_hwmon_read_in(dev, attr, channel, val);
281	default:
282		return -EOPNOTSUPP;
283	}
284}
285
286static const char *const bcm54140_hwmon_in_labels[] = {
287	"AVDDL",
288	"AVDDH",
289};
290
291static int bcm54140_hwmon_read_string(struct device *dev,
292				      enum hwmon_sensor_types type, u32 attr,
293				      int channel, const char **str)
294{
295	switch (type) {
296	case hwmon_in:
297		switch (attr) {
298		case hwmon_in_label:
299			*str = bcm54140_hwmon_in_labels[channel];
300			return 0;
301		default:
302			return -EOPNOTSUPP;
303		}
304	default:
305		return -EOPNOTSUPP;
306	}
307}
308
309static int bcm54140_hwmon_write_temp(struct device *dev, u32 attr,
310				     int channel, long val)
311{
312	struct phy_device *phydev = dev_get_drvdata(dev);
313	u16 mask = BCM54140_RDB_MON_TEMP_DATA_MASK;
314	u16 reg;
315
316	val = clamp_val(val, BCM54140_HWMON_TO_TEMP(mask),
317			BCM54140_HWMON_TO_TEMP(0));
318
319	switch (attr) {
320	case hwmon_temp_min:
321		reg = BCM54140_RDB_MON_TEMP_MIN;
322		break;
323	case hwmon_temp_max:
324		reg = BCM54140_RDB_MON_TEMP_MAX;
325		break;
326	default:
327		return -EOPNOTSUPP;
328	}
329
330	return bcm_phy_modify_rdb(phydev, reg, mask,
331				  BCM54140_HWMON_FROM_TEMP(val));
332}
333
334static int bcm54140_hwmon_write_in(struct device *dev, u32 attr,
335				   int channel, long val)
336{
337	struct phy_device *phydev = dev_get_drvdata(dev);
338	u16 mask = BCM54140_HWMON_IN_MASK(channel);
339	u16 reg;
340
341	val = clamp_val(val, 0, BCM54140_HWMON_TO_IN(channel, mask));
342
343	switch (attr) {
344	case hwmon_in_min:
345		reg = BCM54140_HWMON_IN_MIN_REG(channel);
346		break;
347	case hwmon_in_max:
348		reg = BCM54140_HWMON_IN_MAX_REG(channel);
349		break;
350	default:
351		return -EOPNOTSUPP;
352	}
353
354	return bcm_phy_modify_rdb(phydev, reg, mask,
355				  BCM54140_HWMON_FROM_IN(channel, val));
356}
357
358static int bcm54140_hwmon_write(struct device *dev,
359				enum hwmon_sensor_types type, u32 attr,
360				int channel, long val)
361{
362	switch (type) {
363	case hwmon_temp:
364		return bcm54140_hwmon_write_temp(dev, attr, channel, val);
365	case hwmon_in:
366		return bcm54140_hwmon_write_in(dev, attr, channel, val);
367	default:
368		return -EOPNOTSUPP;
369	}
370}
371
372static const struct hwmon_channel_info * const bcm54140_hwmon_info[] = {
373	HWMON_CHANNEL_INFO(temp,
374			   HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
375			   HWMON_T_ALARM),
376	HWMON_CHANNEL_INFO(in,
377			   HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
378			   HWMON_I_ALARM | HWMON_I_LABEL,
379			   HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX |
380			   HWMON_I_ALARM | HWMON_I_LABEL),
381	NULL
382};
383
384static const struct hwmon_ops bcm54140_hwmon_ops = {
385	.is_visible = bcm54140_hwmon_is_visible,
386	.read = bcm54140_hwmon_read,
387	.read_string = bcm54140_hwmon_read_string,
388	.write = bcm54140_hwmon_write,
389};
390
391static const struct hwmon_chip_info bcm54140_chip_info = {
392	.ops = &bcm54140_hwmon_ops,
393	.info = bcm54140_hwmon_info,
394};
395
396static int bcm54140_enable_monitoring(struct phy_device *phydev)
397{
398	u16 mask, set;
399
400	/* 3.3V voltage mode */
401	set = BCM54140_RDB_MON_CTRL_V_MODE;
402
403	/* select round-robin */
404	mask = BCM54140_RDB_MON_CTRL_SEL_MASK;
405	set |= FIELD_PREP(BCM54140_RDB_MON_CTRL_SEL_MASK,
406			  BCM54140_RDB_MON_CTRL_SEL_RR);
407
408	/* remove power-down bit */
409	mask |= BCM54140_RDB_MON_CTRL_PWR_DOWN;
410
411	return bcm_phy_modify_rdb(phydev, BCM54140_RDB_MON_CTRL, mask, set);
412}
413
414static int bcm54140_probe_once(struct phy_device *phydev)
415{
416	struct device *hwmon;
417	int ret;
418
419	/* enable hardware monitoring */
420	ret = bcm54140_enable_monitoring(phydev);
421	if (ret)
422		return ret;
423
424	hwmon = devm_hwmon_device_register_with_info(&phydev->mdio.dev,
425						     "BCM54140", phydev,
426						     &bcm54140_chip_info,
427						     NULL);
428	return PTR_ERR_OR_ZERO(hwmon);
429}
430#endif
431
432static int bcm54140_base_read_rdb(struct phy_device *phydev, u16 rdb)
433{
434	int ret;
435
436	phy_lock_mdio_bus(phydev);
437	ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
438				  MII_BCM54XX_RDB_ADDR, rdb);
439	if (ret < 0)
440		goto out;
441
442	ret = __phy_package_read(phydev, BCM54140_BASE_ADDR,
443				 MII_BCM54XX_RDB_DATA);
444
445out:
446	phy_unlock_mdio_bus(phydev);
447	return ret;
448}
449
450static int bcm54140_base_write_rdb(struct phy_device *phydev,
451				   u16 rdb, u16 val)
452{
453	int ret;
454
455	phy_lock_mdio_bus(phydev);
456	ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
457				  MII_BCM54XX_RDB_ADDR, rdb);
458	if (ret < 0)
459		goto out;
460
461	ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
462				  MII_BCM54XX_RDB_DATA, val);
463
464out:
465	phy_unlock_mdio_bus(phydev);
466	return ret;
467}
468
469/* Under some circumstances a core PLL may not lock, this will then prevent
470 * a successful link establishment. Restart the PLL after the voltages are
471 * stable to workaround this issue.
472 */
473static int bcm54140_b0_workaround(struct phy_device *phydev)
474{
475	int spare3;
476	int ret;
477
478	spare3 = bcm_phy_read_rdb(phydev, BCM54140_RDB_SPARE3);
479	if (spare3 < 0)
480		return spare3;
481
482	spare3 &= ~BCM54140_RDB_SPARE3_BIT0;
483
484	ret = bcm_phy_write_rdb(phydev, BCM54140_RDB_SPARE3, spare3);
485	if (ret)
486		return ret;
487
488	ret = phy_modify(phydev, MII_BMCR, 0, BMCR_PDOWN);
489	if (ret)
490		return ret;
491
492	ret = phy_modify(phydev, MII_BMCR, BMCR_PDOWN, 0);
493	if (ret)
494		return ret;
495
496	spare3 |= BCM54140_RDB_SPARE3_BIT0;
497
498	return bcm_phy_write_rdb(phydev, BCM54140_RDB_SPARE3, spare3);
499}
500
501/* The BCM54140 is a quad PHY where only the first port has access to the
502 * global register. Thus we need to find out its PHY address.
503 *
504 */
505static int bcm54140_get_base_addr_and_port(struct phy_device *phydev)
506{
507	struct bcm54140_priv *priv = phydev->priv;
508	struct mii_bus *bus = phydev->mdio.bus;
509	int addr, min_addr, max_addr;
510	int step = 1;
511	u32 phy_id;
512	int tmp;
513
514	min_addr = phydev->mdio.addr;
515	max_addr = phydev->mdio.addr;
516	addr = phydev->mdio.addr;
517
518	/* We scan forward and backwards and look for PHYs which have the
519	 * same phy_id like we do. Step 1 will scan forward, step 2
520	 * backwards. Once we are finished, we have a min_addr and
521	 * max_addr which resembles the range of PHY addresses of the same
522	 * type of PHY. There is one caveat; there may be many PHYs of
523	 * the same type, but we know that each PHY takes exactly 4
524	 * consecutive addresses. Therefore we can deduce our offset
525	 * to the base address of this quad PHY.
526	 */
527
528	while (1) {
529		if (step == 3) {
530			break;
531		} else if (step == 1) {
532			max_addr = addr;
533			addr++;
534		} else {
535			min_addr = addr;
536			addr--;
537		}
538
539		if (addr < 0 || addr >= PHY_MAX_ADDR) {
540			addr = phydev->mdio.addr;
541			step++;
542			continue;
543		}
544
545		/* read the PHY id */
546		tmp = mdiobus_read(bus, addr, MII_PHYSID1);
547		if (tmp < 0)
548			return tmp;
549		phy_id = tmp << 16;
550		tmp = mdiobus_read(bus, addr, MII_PHYSID2);
551		if (tmp < 0)
552			return tmp;
553		phy_id |= tmp;
554
555		/* see if it is still the same PHY */
556		if ((phy_id & phydev->drv->phy_id_mask) !=
557		    (phydev->drv->phy_id & phydev->drv->phy_id_mask)) {
558			addr = phydev->mdio.addr;
559			step++;
560		}
561	}
562
563	/* The range we get should be a multiple of four. Please note that both
564	 * the min_addr and max_addr are inclusive. So we have to add one if we
565	 * subtract them.
566	 */
567	if ((max_addr - min_addr + 1) % 4) {
568		dev_err(&phydev->mdio.dev,
569			"Detected Quad PHY IDs %d..%d doesn't make sense.\n",
570			min_addr, max_addr);
571		return -EINVAL;
572	}
573
574	priv->port = (phydev->mdio.addr - min_addr) % 4;
575	priv->base_addr = phydev->mdio.addr - priv->port;
576
577	return 0;
578}
579
580static int bcm54140_probe(struct phy_device *phydev)
581{
582	struct bcm54140_priv *priv;
583	int ret;
584
585	priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
586	if (!priv)
587		return -ENOMEM;
588
589	phydev->priv = priv;
590
591	ret = bcm54140_get_base_addr_and_port(phydev);
592	if (ret)
593		return ret;
594
595	devm_phy_package_join(&phydev->mdio.dev, phydev, priv->base_addr, 0);
596
597#if IS_ENABLED(CONFIG_HWMON)
598	mutex_init(&priv->alarm_lock);
599
600	if (phy_package_init_once(phydev)) {
601		ret = bcm54140_probe_once(phydev);
602		if (ret)
603			return ret;
604	}
605#endif
606
607	phydev_dbg(phydev, "probed (port %d, base PHY address %d)\n",
608		   priv->port, priv->base_addr);
609
610	return 0;
611}
612
613static int bcm54140_config_init(struct phy_device *phydev)
614{
615	u16 reg = 0xffff;
616	int ret;
617
618	/* Apply hardware errata */
619	if (BCM54140_PHY_ID_REV(phydev->phy_id) == BCM54140_REV_B0) {
620		ret = bcm54140_b0_workaround(phydev);
621		if (ret)
622			return ret;
623	}
624
625	/* Unmask events we are interested in. */
626	reg &= ~(BCM54140_RDB_INT_DUPLEX |
627		 BCM54140_RDB_INT_SPEED |
628		 BCM54140_RDB_INT_LINK);
629	ret = bcm_phy_write_rdb(phydev, BCM54140_RDB_IMR, reg);
630	if (ret)
631		return ret;
632
633	/* LED1=LINKSPD[1], LED2=LINKSPD[2], LED3=LINK/ACTIVITY */
634	ret = bcm_phy_modify_rdb(phydev, BCM54140_RDB_SPARE1,
635				 0, BCM54140_RDB_SPARE1_LSLM);
636	if (ret)
637		return ret;
638
639	ret = bcm_phy_modify_rdb(phydev, BCM54140_RDB_LED_CTRL,
640				 0, BCM54140_RDB_LED_CTRL_ACTLINK0);
641	if (ret)
642		return ret;
643
644	/* disable super isolate mode */
645	return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_PWR,
646				  BCM54140_RDB_C_PWR_ISOLATE, 0);
647}
648
649static irqreturn_t bcm54140_handle_interrupt(struct phy_device *phydev)
650{
651	int irq_status, irq_mask;
652
653	irq_status = bcm_phy_read_rdb(phydev, BCM54140_RDB_ISR);
654	if (irq_status < 0) {
655		phy_error(phydev);
656		return IRQ_NONE;
657	}
658
659	irq_mask = bcm_phy_read_rdb(phydev, BCM54140_RDB_IMR);
660	if (irq_mask < 0) {
661		phy_error(phydev);
662		return IRQ_NONE;
663	}
664	irq_mask = ~irq_mask;
665
666	if (!(irq_status & irq_mask))
667		return IRQ_NONE;
668
669	phy_trigger_machine(phydev);
670
671	return IRQ_HANDLED;
672}
673
674static int bcm54140_ack_intr(struct phy_device *phydev)
675{
676	int reg;
677
678	/* clear pending interrupts */
679	reg = bcm_phy_read_rdb(phydev, BCM54140_RDB_ISR);
680	if (reg < 0)
681		return reg;
682
683	return 0;
684}
685
686static int bcm54140_config_intr(struct phy_device *phydev)
687{
688	struct bcm54140_priv *priv = phydev->priv;
689	static const u16 port_to_imr_bit[] = {
690		BCM54140_RDB_TOP_IMR_PORT0, BCM54140_RDB_TOP_IMR_PORT1,
691		BCM54140_RDB_TOP_IMR_PORT2, BCM54140_RDB_TOP_IMR_PORT3,
692	};
693	int reg, err;
694
695	if (priv->port >= ARRAY_SIZE(port_to_imr_bit))
696		return -EINVAL;
697
698	reg = bcm54140_base_read_rdb(phydev, BCM54140_RDB_TOP_IMR);
699	if (reg < 0)
700		return reg;
701
702	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
703		err = bcm54140_ack_intr(phydev);
704		if (err)
705			return err;
706
707		reg &= ~port_to_imr_bit[priv->port];
708		err = bcm54140_base_write_rdb(phydev, BCM54140_RDB_TOP_IMR, reg);
709	} else {
710		reg |= port_to_imr_bit[priv->port];
711		err = bcm54140_base_write_rdb(phydev, BCM54140_RDB_TOP_IMR, reg);
712		if (err)
713			return err;
714
715		err = bcm54140_ack_intr(phydev);
716	}
717
718	return err;
719}
720
721static int bcm54140_get_downshift(struct phy_device *phydev, u8 *data)
722{
723	int val;
724
725	val = bcm_phy_read_rdb(phydev, BCM54140_RDB_C_MISC_CTRL);
726	if (val < 0)
727		return val;
728
729	if (!(val & BCM54140_RDB_C_MISC_CTRL_WS_EN)) {
730		*data = DOWNSHIFT_DEV_DISABLE;
731		return 0;
732	}
733
734	val = bcm_phy_read_rdb(phydev, BCM54140_RDB_SPARE2);
735	if (val < 0)
736		return val;
737
738	if (val & BCM54140_RDB_SPARE2_WS_RTRY_DIS)
739		*data = 1;
740	else
741		*data = FIELD_GET(BCM54140_RDB_SPARE2_WS_RTRY_LIMIT, val) + 2;
742
743	return 0;
744}
745
746static int bcm54140_set_downshift(struct phy_device *phydev, u8 cnt)
747{
748	u16 mask, set;
749	int ret;
750
751	if (cnt > BCM54140_MAX_DOWNSHIFT && cnt != DOWNSHIFT_DEV_DEFAULT_COUNT)
752		return -EINVAL;
753
754	if (!cnt)
755		return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_MISC_CTRL,
756					  BCM54140_RDB_C_MISC_CTRL_WS_EN, 0);
757
758	if (cnt == DOWNSHIFT_DEV_DEFAULT_COUNT)
759		cnt = BCM54140_DEFAULT_DOWNSHIFT;
760
761	if (cnt == 1) {
762		mask = 0;
763		set = BCM54140_RDB_SPARE2_WS_RTRY_DIS;
764	} else {
765		mask = BCM54140_RDB_SPARE2_WS_RTRY_DIS;
766		mask |= BCM54140_RDB_SPARE2_WS_RTRY_LIMIT;
767		set = FIELD_PREP(BCM54140_RDB_SPARE2_WS_RTRY_LIMIT, cnt - 2);
768	}
769	ret = bcm_phy_modify_rdb(phydev, BCM54140_RDB_SPARE2,
770				 mask, set);
771	if (ret)
772		return ret;
773
774	return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_MISC_CTRL,
775				  0, BCM54140_RDB_C_MISC_CTRL_WS_EN);
776}
777
778static int bcm54140_get_edpd(struct phy_device *phydev, u16 *tx_interval)
779{
780	int val;
781
782	val = bcm_phy_read_rdb(phydev, BCM54140_RDB_C_APWR);
783	if (val < 0)
784		return val;
785
786	switch (FIELD_GET(BCM54140_RDB_C_APWR_APD_MODE_MASK, val)) {
787	case BCM54140_RDB_C_APWR_APD_MODE_DIS:
788	case BCM54140_RDB_C_APWR_APD_MODE_DIS2:
789		*tx_interval = ETHTOOL_PHY_EDPD_DISABLE;
790		break;
791	case BCM54140_RDB_C_APWR_APD_MODE_EN:
792	case BCM54140_RDB_C_APWR_APD_MODE_EN_ANEG:
793		switch (FIELD_GET(BCM54140_RDB_C_APWR_SLP_TIM_MASK, val)) {
794		case BCM54140_RDB_C_APWR_SLP_TIM_2_7:
795			*tx_interval = 2700;
796			break;
797		case BCM54140_RDB_C_APWR_SLP_TIM_5_4:
798			*tx_interval = 5400;
799			break;
800		}
801	}
802
803	return 0;
804}
805
806static int bcm54140_set_edpd(struct phy_device *phydev, u16 tx_interval)
807{
808	u16 mask, set;
809
810	mask = BCM54140_RDB_C_APWR_APD_MODE_MASK;
811	if (tx_interval == ETHTOOL_PHY_EDPD_DISABLE)
812		set = FIELD_PREP(BCM54140_RDB_C_APWR_APD_MODE_MASK,
813				 BCM54140_RDB_C_APWR_APD_MODE_DIS);
814	else
815		set = FIELD_PREP(BCM54140_RDB_C_APWR_APD_MODE_MASK,
816				 BCM54140_RDB_C_APWR_APD_MODE_EN_ANEG);
817
818	/* enable single pulse mode */
819	set |= BCM54140_RDB_C_APWR_SINGLE_PULSE;
820
821	/* set sleep timer */
822	mask |= BCM54140_RDB_C_APWR_SLP_TIM_MASK;
823	switch (tx_interval) {
824	case ETHTOOL_PHY_EDPD_DFLT_TX_MSECS:
825	case ETHTOOL_PHY_EDPD_DISABLE:
826	case 2700:
827		set |= BCM54140_RDB_C_APWR_SLP_TIM_2_7;
828		break;
829	case 5400:
830		set |= BCM54140_RDB_C_APWR_SLP_TIM_5_4;
831		break;
832	default:
833		return -EINVAL;
834	}
835
836	return bcm_phy_modify_rdb(phydev, BCM54140_RDB_C_APWR, mask, set);
837}
838
839static int bcm54140_get_tunable(struct phy_device *phydev,
840				struct ethtool_tunable *tuna, void *data)
841{
842	switch (tuna->id) {
843	case ETHTOOL_PHY_DOWNSHIFT:
844		return bcm54140_get_downshift(phydev, data);
845	case ETHTOOL_PHY_EDPD:
846		return bcm54140_get_edpd(phydev, data);
847	default:
848		return -EOPNOTSUPP;
849	}
850}
851
852static int bcm54140_set_tunable(struct phy_device *phydev,
853				struct ethtool_tunable *tuna, const void *data)
854{
855	switch (tuna->id) {
856	case ETHTOOL_PHY_DOWNSHIFT:
857		return bcm54140_set_downshift(phydev, *(const u8 *)data);
858	case ETHTOOL_PHY_EDPD:
859		return bcm54140_set_edpd(phydev, *(const u16 *)data);
860	default:
861		return -EOPNOTSUPP;
862	}
863}
864
865static struct phy_driver bcm54140_drivers[] = {
866	{
867		.phy_id         = PHY_ID_BCM54140,
868		.phy_id_mask    = BCM54140_PHY_ID_MASK,
869		.name           = "Broadcom BCM54140",
870		.flags		= PHY_POLL_CABLE_TEST,
871		.features       = PHY_GBIT_FEATURES,
872		.config_init    = bcm54140_config_init,
873		.handle_interrupt = bcm54140_handle_interrupt,
874		.config_intr    = bcm54140_config_intr,
875		.probe		= bcm54140_probe,
876		.suspend	= genphy_suspend,
877		.resume		= genphy_resume,
878		.soft_reset	= genphy_soft_reset,
879		.get_tunable	= bcm54140_get_tunable,
880		.set_tunable	= bcm54140_set_tunable,
881		.cable_test_start = bcm_phy_cable_test_start_rdb,
882		.cable_test_get_status = bcm_phy_cable_test_get_status_rdb,
883	},
884};
885module_phy_driver(bcm54140_drivers);
886
887static const struct mdio_device_id __maybe_unused bcm54140_tbl[] = {
888	{ PHY_ID_BCM54140, BCM54140_PHY_ID_MASK },
889	{ }
890};
891
892MODULE_AUTHOR("Michael Walle");
893MODULE_DESCRIPTION("Broadcom BCM54140 PHY driver");
894MODULE_DEVICE_TABLE(mdio, bcm54140_tbl);
895MODULE_LICENSE("GPL");
~/ Read-only file preview.