drivers/net/dsa/b53/b53_serdes.c

Source file repositories/reference/linux-study-clean/drivers/net/dsa/b53/b53_serdes.c

File Facts

System
Linux kernel
Corpus path
drivers/net/dsa/b53/b53_serdes.c
Extension
.c
Size
6573 bytes
Lines
250
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 OR BSD-3-Clause
/*
 * Northstar Plus switch SerDes/SGMII PHY main logic
 *
 * Copyright (C) 2018 Florian Fainelli <f.fainelli@gmail.com>
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/phy.h>
#include <linux/phylink.h>
#include <net/dsa.h>

#include "b53_priv.h"
#include "b53_serdes.h"
#include "b53_regs.h"

static inline struct b53_pcs *pcs_to_b53_pcs(struct phylink_pcs *pcs)
{
	return container_of(pcs, struct b53_pcs, pcs);
}

static void b53_serdes_write_blk(struct b53_device *dev, u8 offset, u16 block,
				 u16 value)
{
	b53_write16(dev, B53_SERDES_PAGE, B53_SERDES_BLKADDR, block);
	b53_write16(dev, B53_SERDES_PAGE, offset, value);
}

static u16 b53_serdes_read_blk(struct b53_device *dev, u8 offset, u16 block)
{
	u16 value;

	b53_write16(dev, B53_SERDES_PAGE, B53_SERDES_BLKADDR, block);
	b53_read16(dev, B53_SERDES_PAGE, offset, &value);

	return value;
}

static void b53_serdes_set_lane(struct b53_device *dev, u8 lane)
{
	if (dev->serdes_lane == lane)
		return;

	WARN_ON(lane > 1);

	b53_serdes_write_blk(dev, B53_SERDES_LANE,
			     SERDES_XGXSBLK0_BLOCKADDRESS, lane);
	dev->serdes_lane = lane;
}

static void b53_serdes_write(struct b53_device *dev, u8 lane,
			     u8 offset, u16 block, u16 value)
{
	b53_serdes_set_lane(dev, lane);
	b53_serdes_write_blk(dev, offset, block, value);
}

static u16 b53_serdes_read(struct b53_device *dev, u8 lane,
			   u8 offset, u16 block)
{
	b53_serdes_set_lane(dev, lane);
	return b53_serdes_read_blk(dev, offset, block);
}

static int b53_serdes_config(struct phylink_pcs *pcs, unsigned int neg_mode,
			     phy_interface_t interface,
			     const unsigned long *advertising,
			     bool permit_pause_to_mac)
{
	struct b53_device *dev = pcs_to_b53_pcs(pcs)->dev;
	u8 lane = pcs_to_b53_pcs(pcs)->lane;
	u16 reg;

	reg = b53_serdes_read(dev, lane, B53_SERDES_DIGITAL_CONTROL(1),
			      SERDES_DIGITAL_BLK);
	if (interface == PHY_INTERFACE_MODE_1000BASEX)
		reg |= FIBER_MODE_1000X;
	else
		reg &= ~FIBER_MODE_1000X;
	b53_serdes_write(dev, lane, B53_SERDES_DIGITAL_CONTROL(1),
			 SERDES_DIGITAL_BLK, reg);

	return 0;
}

static void b53_serdes_an_restart(struct phylink_pcs *pcs)
{

Annotation

Implementation Notes