/* Read and discard fractional part */
readl_relaxed(base + 20);
readl_relaxed(base + 24);
}
staticvoid mvpp2_tai_write_tlv(conststruct 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);
}
staticvoid mvpp2_tai_op(u32 op, void __iomem *base)
{ /* Trigger the operation. Note that an external unmaskable *eventonPTP_EVENT_REQwillalsotriggerthisaction.
*/
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 *of2^-32ns. * *units(s)=1/(2^32*10^9) *fractional=abs_scaled_ppm/(2^16*10^6) * *Whatwewanttoachieve: *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,wearedealingwithperiods,so: *period_adjusted=period_nominal/(1+fractional) *period_delta=period_nominal-period_adjusted=>positive=faster *period_delta=period_nominal*fractional/(1+fractional) * *Hence: *period_delta=period_nominal*abs_scaled_ppm/ *(2^16*10^6+abs_scaled_ppm) * *Toavoidoverflow,wereducebothsidesofthedivideoperationbyafactor *of16.
*/ static u64 mvpp22_calc_frac_ppm(struct mvpp2_tai *tai, long abs_scaled_ppm)
{
u64 val = tai->period * abs_scaled_ppm >> 4;
neg_adj = scaled_ppm < 0; if (neg_adj)
scaled_ppm = -scaled_ppm;
val = mvpp22_calc_frac_ppm(tai, scaled_ppm);
/* Convert to a signed 32-bit adjustment */ if (neg_adj) { /* -S32_MIN warns, -val < S32_MIN fails, so go for the easy *solution.
*/ if (val > 0x80000000) return -ERANGE;
base = tai->base;
spin_lock_irqsave(&tai->lock, flags); /* XXX: the only way to read the PTP time is for the CPU to trigger *anevent.However,thereisnowaytodistinguishbetweentheCPU *triggeredevent,andanexternaleventonPTP_EVENT_REQ.Sothis *isincompatiblewithexternaluseofPTP_EVENT_REQ.
*/
ptp_read_system_prets(sts);
mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0,
TCFCR0_TCF_MASK | TCFCR0_TCF_TRIGGER,
TCFCR0_TCF_CAPTURE | TCFCR0_TCF_TRIGGER);
ptp_read_system_postts(sts);
mvpp2_tai_modify(base + MVPP22_TAI_TCFCR0, TCFCR0_TCF_MASK,
TCFCR0_TCF_NOP);
tcsr = readl(base + MVPP22_TAI_TCSR); if (tcsr & TCSR_CAPTURE_1_VALID) {
mvpp22_tai_read_ts(ts, base + MVPP22_TAI_TCV1_SEC_HIGH);
ret = 0;
} elseif (tcsr & TCSR_CAPTURE_0_VALID) {
mvpp22_tai_read_ts(ts, base + MVPP22_TAI_TCV0_SEC_HIGH);
ret = 0;
} else { /* We don't seem to have a reading... */
ret = -EBUSY;
}
spin_unlock_irqrestore(&tai->lock, flags);
/* As the fractional nanosecond is a signed offset, if the MSB (sign) *bitisset,wehavetoincrementthewholenanoseconds.
*/ if (frac >= 0x80000000)
nano += 1;
mvpp2_tai_write(nano, base + MVPP22_TAI_TOD_STEP_NANO_CR);
mvpp2_tai_write(frac >> 16, base + MVPP22_TAI_TOD_STEP_FRAC_HIGH);
mvpp2_tai_write(frac, base + MVPP22_TAI_TOD_STEP_FRAC_LOW);
}
/* The tstamp consists of 2 bits of seconds and 30 bits of nanoseconds. *Weuseourstoredtimestamp(tai->stamp)toformafulltimestamp, *andwemustreadthesecondsexactlyonce.
*/
ts.tv_sec = READ_ONCE(tai->stamp.tv_sec);
ts.tv_nsec = tstamp & 0x3fffffff;
/* Calculate the delta in seconds between our stored timestamp and *thevaluereadfromthequeue.Allowtimestampsonesecondinthe *past,otherwiseconsiderthemtobeinthefuture.
*/
delta = ((tstamp >> 30) - (ts.tv_sec & 3)) & 3; if (delta == 3)
delta -= 4;
ts.tv_sec += delta;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.