drivers/net/phy/bcm84881.c

Source file repositories/reference/linux-study-clean/drivers/net/phy/bcm84881.c

File Facts

System
Linux kernel
Corpus path
drivers/net/phy/bcm84881.c
Extension
.c
Size
13333 bytes
Lines
475
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
// Broadcom BCM84881 NBASE-T PHY driver, as found on a SFP+ module.
// Copyright (C) 2019 Russell King, Deep Blue Solutions Ltd.
//
// Like the Marvell 88x3310, the Broadcom 84881 changes its host-side
// interface according to the operating speed between 10GBASE-R,
// 2500BASE-X and SGMII (but unlike the 88x3310, without the control
// word).
//
// This driver only supports those aspects of the PHY that I'm able to
// observe and test with the SFP+ module, which is an incomplete subset
// of what this PHY is able to support. For example, I only assume it
// supports a single lane Serdes connection, but it may be that the PHY
// is able to support more than that.
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/phy.h>

enum {
	MDIO_AN_C22 = 0xffe0,
};

/* BCM8489x LED controller (BCM84891L datasheet 2.4.1.58). Each pin has
 * CTL bits in 0xA83B (stride 3: 2-bit CTL + 1-bit OE_N) plus MASK_LOW/
 * MASK_EXT source selects. LED4 is firmware-controlled; always RMW.
 */
#define BCM8489X_LED_CTL		0xa83b
#define BCM8489X_LED_CTL_ON(i)		(0x2 << ((i) * 3))
#define BCM8489X_LED_CTL_MASK(i)	(0x3 << ((i) * 3))

#define BCM8489X_LED_SRC_RX		BIT(1)
#define BCM8489X_LED_SRC_TX		BIT(2)
#define BCM8489X_LED_SRC_1000		BIT(3)	/* high only at 1000 */
#define BCM8489X_LED_SRC_100_1000	BIT(4)	/* high at 100 and 1000 */
#define BCM8489X_LED_SRC_FORCE		BIT(5)	/* always-1 source */
#define BCM8489X_LED_SRC_10G		BIT(7)
#define BCM8489X_LED_SRCX_2500		BIT(2)
#define BCM8489X_LED_SRCX_5000		BIT(3)

#define BCM8489X_MAX_LEDS		2

static const struct {
	u16 mask_low;
	u16 mask_ext;
} bcm8489x_led_regs[BCM8489X_MAX_LEDS] = {
	{ 0xa82c, 0xa8ef },	/* LED1 */
	{ 0xa82f, 0xa8f0 },	/* LED2 */
};

static int bcm84881_wait_init(struct phy_device *phydev)
{
	int val;

	return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
					 val, !(val & MDIO_CTRL1_RESET),
					 100000, 2000000, false);
}

static void bcm84881_fill_possible_interfaces(struct phy_device *phydev)
{
	unsigned long *possible = phydev->possible_interfaces;

	__set_bit(PHY_INTERFACE_MODE_SGMII, possible);
	__set_bit(PHY_INTERFACE_MODE_2500BASEX, possible);
	__set_bit(PHY_INTERFACE_MODE_10GBASER, possible);
}

static int bcm84881_config_init(struct phy_device *phydev)
{
	bcm84881_fill_possible_interfaces(phydev);

	switch (phydev->interface) {
	case PHY_INTERFACE_MODE_SGMII:
	case PHY_INTERFACE_MODE_2500BASEX:
	case PHY_INTERFACE_MODE_10GBASER:
		break;
	default:
		return -ENODEV;
	}

	return 0;
}

static int bcm8489x_config_init(struct phy_device *phydev)
{
	__set_bit(PHY_INTERFACE_MODE_USXGMII, phydev->possible_interfaces);

	if (phydev->interface != PHY_INTERFACE_MODE_USXGMII)
		return -ENODEV;

Annotation

Implementation Notes