drivers/net/ethernet/marvell/mvpp2/mvpp2_tai.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/marvell/mvpp2/mvpp2_tai.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/marvell/mvpp2/mvpp2_tai.c
Extension
.c
Size
13167 bytes
Lines
458
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

struct mvpp2_tai {
	struct ptp_clock_info caps;
	struct ptp_clock *ptp_clock;
	void __iomem *base;
	spinlock_t lock;
	u64 period;		// nanosecond period in 32.32 fixed point
	/* This timestamp is updated every two seconds */
	struct timespec64 stamp;
};

static void mvpp2_tai_modify(void __iomem *reg, u32 mask, u32 set)
{
	u32 val;

	val = readl_relaxed(reg) & ~mask;
	val |= set & mask;
	writel(val, reg);
}

static void mvpp2_tai_write(u32 val, void __iomem *reg)
{
	writel_relaxed(val & 0xffff, reg);
}

static u32 mvpp2_tai_read(void __iomem *reg)
{
	return readl_relaxed(reg) & 0xffff;
}

static struct mvpp2_tai *ptp_to_tai(struct ptp_clock_info *ptp)
{
	return container_of(ptp, struct mvpp2_tai, caps);
}

static void mvpp22_tai_read_ts(struct timespec64 *ts, void __iomem *base)
{
	ts->tv_sec = (u64)mvpp2_tai_read(base + 0) << 32 |
		     mvpp2_tai_read(base + 4) << 16 |
		     mvpp2_tai_read(base + 8);

	ts->tv_nsec = mvpp2_tai_read(base + 12) << 16 |
		      mvpp2_tai_read(base + 16);

	/* Read and discard fractional part */
	readl_relaxed(base + 20);
	readl_relaxed(base + 24);
}

static void mvpp2_tai_write_tlv(const struct timespec64 *ts, u32 frac,
			        void __iomem *base)
{
	mvpp2_tai_write(ts->tv_sec >> 32, base + MVPP22_TAI_TLV_SEC_HIGH);
	mvpp2_tai_write(ts->tv_sec >> 16, base + MVPP22_TAI_TLV_SEC_MED);
	mvpp2_tai_write(ts->tv_sec, base + MVPP22_TAI_TLV_SEC_LOW);
	mvpp2_tai_write(ts->tv_nsec >> 16, base + MVPP22_TAI_TLV_NANO_HIGH);
	mvpp2_tai_write(ts->tv_nsec, base + MVPP22_TAI_TLV_NANO_LOW);
	mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TLV_FRAC_HIGH);
	mvpp2_tai_write(frac, base + MVPP22_TAI_TLV_FRAC_LOW);
}

static void mvpp2_tai_op(u32 op, void __iomem *base)
{
	/* Trigger the operation. Note that an external unmaskable
	 * event on PTP_EVENT_REQ will also trigger this action.
	 */
	mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
			 TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
			 op | TCFCR0_TCF_TRIGGER);
	mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
			 TCFCR0_TCF_NOP);
}

/* The adjustment has a range of +0.5ns to -0.5ns in 2^32 steps, so has units
 * of 2^-32 ns.
 *
 * units(s) = 1 / (2^32 * 10^9)
 * fractional = abs_scaled_ppm / (2^16 * 10^6)
 *
 * What we want to achieve:
 *  freq_adjusted = freq_nominal * (1 + fractional)
 *  freq_delta = freq_adjusted - freq_nominal => positive = faster
 *  freq_delta = freq_nominal * (1 + fractional) - freq_nominal
 * So: freq_delta = freq_nominal * fractional
 *
 * However, we are dealing with periods, so:
 *  period_adjusted = period_nominal / (1 + fractional)
 *  period_delta = period_nominal - period_adjusted => positive = faster
 *  period_delta = period_nominal * fractional / (1 + fractional)
 *
 * Hence:

Annotation

Implementation Notes