static u64 sparx5_ptp_get_1ppm(struct sparx5 *sparx5)
{ /* Represents 1ppm adjustment in 2^59 format with 1.59687500000(625) *1.99609375000(500),3.99218750000(250)asreference *Thevalueiscalculatedasfollowing: *(1/1000000)/((2^-59)/X)
*/
u64 res = 0;
switch (sparx5->coreclock) { case SPX5_CORE_CLOCK_250MHZ:
res = 2301339409586; break; case SPX5_CORE_CLOCK_328MHZ:
res = 1756832768924; break; case SPX5_CORE_CLOCK_500MHZ:
res = 1150669704793; break; case SPX5_CORE_CLOCK_625MHZ:
res = 920535763834; break; default:
WARN(1, "Invalid core clock"); break;
}
return res;
}
static u64 sparx5_ptp_get_nominal_value(struct sparx5 *sparx5)
{
u64 res = 0;
switch (sparx5->coreclock) { case SPX5_CORE_CLOCK_250MHZ:
res = 0x1FF0000000000000; break; case SPX5_CORE_CLOCK_328MHZ:
res = 0x18604697DD0F9B5B; break; case SPX5_CORE_CLOCK_500MHZ:
res = 0x0FF8000000000000; break; case SPX5_CORE_CLOCK_625MHZ:
res = 0x0CC6666666666666; break; default:
WARN(1, "Invalid core clock"); break;
}
/* For now don't allow to run ptp on ports that are part of a bridge, *becauseincaseoftransparentclocktheHWwillstillforwardthe *frames,sotherewouldbeduplicateframes
*/
if (test_bit(port->portno, sparx5->bridge_mask)) return -EINVAL;
switch (cfg->tx_type) { case HWTSTAMP_TX_ON:
port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; break; case HWTSTAMP_TX_ONESTEP_SYNC:
port->ptp_cmd = IFH_REW_OP_ONE_STEP_PTP; break; case HWTSTAMP_TX_OFF:
port->ptp_cmd = IFH_REW_OP_NOOP; break; default: return -ERANGE;
}
switch (cfg->rx_filter) { case HWTSTAMP_FILTER_NONE: break; case HWTSTAMP_FILTER_ALL: case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: case HWTSTAMP_FILTER_NTP_ALL:
cfg->rx_filter = HWTSTAMP_FILTER_ALL; break; default: return -ERANGE;
}
/* Commit back the result & save it */
mutex_lock(&sparx5->ptp_lock);
phc = &sparx5->phc[SPARX5_PHC_PORT];
phc->hwtstamp_config = *cfg;
mutex_unlock(&sparx5->ptp_lock);
*pdu_w16_offset = 7; if (type & PTP_CLASS_L2)
*pdu_type = IFH_PDU_TYPE_PTP; if (type & PTP_CLASS_IPV4)
*pdu_type = IFH_PDU_TYPE_IPV4_UDP_PTP; if (type & PTP_CLASS_IPV6)
*pdu_type = IFH_PDU_TYPE_IPV6_UDP_PTP;
if (port->ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
*rew_op = IFH_REW_OP_TWO_STEP_PTP; return;
}
/* If it is sync and run 1 step then set the correct operation, *otherwiserunas2step
*/
msgtype = ptp_get_msgtype(header, type); if ((msgtype & 0xf) == 0) {
*rew_op = IFH_REW_OP_ONE_STEP_PTP; return;
}
/* Get next timestamp from fifo, which needs to be the *rxtimestampwhichrepresentstheidoftheframe
*/
spx5_rmw(REW_PTP_TWOSTEP_CTRL_PTP_NXT_SET(1),
REW_PTP_TWOSTEP_CTRL_PTP_NXT,
sparx5, REW_PTP_TWOSTEP_CTRL);
val = spx5_rd(sparx5, REW_PTP_TWOSTEP_CTRL);
/* Check if a timestamp can be retried */ if (!(val & REW_PTP_TWOSTEP_CTRL_PTP_VLD)) break;
/* Read RX timestamping to get the ID */
id = spx5_rd(sparx5, REW_PTP_TWOSTEP_STAMP);
id <<= 8;
id |= spx5_rd(sparx5, REW_PTP_TWOSTEP_STAMP_SUBNS);
/* Must be in IDLE mode before the time can be loaded */
spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_IDLE) |
PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
PTP_PTP_PIN_CFG_PTP_PIN_DOM |
PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
sparx5, PTP_PTP_PIN_CFG(consts->tod_pin));
/* Set new value */
spx5_wr(PTP_PTP_TOD_SEC_MSB_PTP_TOD_SEC_MSB_SET(upper_32_bits(ts->tv_sec)),
sparx5, PTP_PTP_TOD_SEC_MSB(consts->tod_pin));
spx5_wr(lower_32_bits(ts->tv_sec),
sparx5, PTP_PTP_TOD_SEC_LSB(consts->tod_pin));
spx5_wr(ts->tv_nsec, sparx5, PTP_PTP_TOD_NSEC(consts->tod_pin));
/* Must be in IDLE mode before the time can be loaded */
spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_IDLE) |
PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
PTP_PTP_PIN_CFG_PTP_PIN_DOM |
PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
sparx5, PTP_PTP_PIN_CFG(consts->tod_pin));
/* Adjust time with the value of PTP_TOD_NSEC */
spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_DELTA) |
PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) |
PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0),
PTP_PTP_PIN_CFG_PTP_PIN_ACTION |
PTP_PTP_PIN_CFG_PTP_PIN_DOM |
PTP_PTP_PIN_CFG_PTP_PIN_SYNC,
sparx5, PTP_PTP_PIN_CFG(consts->tod_pin));
spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags);
} else { /* Fall back using sparx5_ptp_settime64 which is not exact */ struct timespec64 ts;
u64 now;
sparx5_ptp_gettime64(ptp, &ts);
now = ktime_to_ns(timespec64_to_ktime(ts));
ts = ns_to_timespec64(now + delta);
/* Configure the nominal TOD increment per clock cycle */
spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(0x7),
PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS,
sparx5, PTP_PTP_DOM_CFG);
for (i = 0; i < SPARX5_PHC_COUNT; ++i) {
spx5_wr((u32)tod_adj & 0xFFFFFFFF, sparx5,
PTP_CLK_PER_CFG(i, 0));
spx5_wr((u32)(tod_adj >> 32), sparx5,
PTP_CLK_PER_CFG(i, 1));
}
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.