diff options
Diffstat (limited to 'drivers/ptp')
-rw-r--r-- | drivers/ptp/Kconfig | 2 | ||||
-rw-r--r-- | drivers/ptp/ptp_chardev.c | 1 | ||||
-rw-r--r-- | drivers/ptp/ptp_clock.c | 9 | ||||
-rw-r--r-- | drivers/ptp/ptp_clockmatrix.c | 94 | ||||
-rw-r--r-- | drivers/ptp/ptp_clockmatrix.h | 8 | ||||
-rw-r--r-- | drivers/ptp/ptp_idt82p33.c | 6 | ||||
-rw-r--r-- | drivers/ptp/ptp_ines.c | 12 | ||||
-rw-r--r-- | drivers/ptp/ptp_kvm.c | 2 |
8 files changed, 117 insertions, 17 deletions
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index 86400c708150..942f72d8151d 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -64,7 +64,7 @@ config DP83640_PHY depends on NETWORK_PHY_TIMESTAMPING depends on PHYLIB depends on PTP_1588_CLOCK - ---help--- + help Supports the DP83640 PHYTER with IEEE 1588 features. This driver adds support for using the DP83640 as a PTP diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index 93d574faf1fe..375cd6e4aade 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c @@ -136,6 +136,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) caps.pps = ptp->info->pps; caps.n_pins = ptp->info->n_pins; caps.cross_timestamping = ptp->info->getcrosststamp != NULL; + caps.adjust_phase = ptp->info->adjphase != NULL; if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) err = -EFAULT; break; diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index acabbe72e55e..03a246e60fd9 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -146,6 +146,15 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx) else err = ops->adjfreq(ops, ppb); ptp->dialed_frequency = tx->freq; + } else if (tx->modes & ADJ_OFFSET) { + if (ops->adjphase) { + s32 offset = tx->offset; + + if (!(tx->modes & ADJ_NANO)) + offset *= NSEC_PER_USEC; + + err = ops->adjphase(ops, offset); + } } else if (tx->modes == 0) { tx->freq = ptp->dialed_frequency; err = 0; diff --git a/drivers/ptp/ptp_clockmatrix.c b/drivers/ptp/ptp_clockmatrix.c index 032e112c3dd9..ceb6bc58f3b4 100644 --- a/drivers/ptp/ptp_clockmatrix.c +++ b/drivers/ptp/ptp_clockmatrix.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/ptp_clock_kernel.h> #include <linux/delay.h> +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/timekeeping.h> @@ -24,6 +25,16 @@ MODULE_LICENSE("GPL"); #define SETTIME_CORRECTION (0) +static long set_write_phase_ready(struct ptp_clock_info *ptp) +{ + struct idtcm_channel *channel = + container_of(ptp, struct idtcm_channel, caps); + + channel->write_phase_ready = 1; + + return 0; +} + static int char_array_to_timespec(u8 *buf, u8 count, struct timespec64 *ts) @@ -780,7 +791,7 @@ static int idtcm_load_firmware(struct idtcm *idtcm, /* Page size 128, last 4 bytes of page skipped */ if (((loaddr > 0x7b) && (loaddr <= 0x7f)) - || ((loaddr > 0xfb) && (loaddr <= 0xff))) + || loaddr > 0xfb) continue; err = idtcm_write(idtcm, regaddr, 0, &val, sizeof(val)); @@ -871,6 +882,64 @@ static int idtcm_set_pll_mode(struct idtcm_channel *channel, /* PTP Hardware Clock interface */ +/** + * @brief Maximum absolute value for write phase offset in picoseconds + * + * Destination signed register is 32-bit register in resolution of 50ps + * + * 0x7fffffff * 50 = 2147483647 * 50 = 107374182350 + */ +static int _idtcm_adjphase(struct idtcm_channel *channel, s32 delta_ns) +{ + struct idtcm *idtcm = channel->idtcm; + + int err; + u8 i; + u8 buf[4] = {0}; + s32 phase_50ps; + s64 offset_ps; + + if (channel->pll_mode != PLL_MODE_WRITE_PHASE) { + + err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_PHASE); + + if (err) + return err; + + channel->write_phase_ready = 0; + + ptp_schedule_worker(channel->ptp_clock, + msecs_to_jiffies(WR_PHASE_SETUP_MS)); + } + + if (!channel->write_phase_ready) + delta_ns = 0; + + offset_ps = (s64)delta_ns * 1000; + + /* + * Check for 32-bit signed max * 50: + * + * 0x7fffffff * 50 = 2147483647 * 50 = 107374182350 + */ + if (offset_ps > MAX_ABS_WRITE_PHASE_PICOSECONDS) + offset_ps = MAX_ABS_WRITE_PHASE_PICOSECONDS; + else if (offset_ps < -MAX_ABS_WRITE_PHASE_PICOSECONDS) + offset_ps = -MAX_ABS_WRITE_PHASE_PICOSECONDS; + + phase_50ps = DIV_ROUND_CLOSEST(div64_s64(offset_ps, 50), 1); + + for (i = 0; i < 4; i++) { + buf[i] = phase_50ps & 0xff; + phase_50ps >>= 8; + } + + err = idtcm_write(idtcm, channel->dpll_phase, DPLL_WR_PHASE, + buf, sizeof(buf)); + + return err; +} + static int idtcm_adjfreq(struct ptp_clock_info *ptp, s32 ppb) { struct idtcm_channel *channel = @@ -977,6 +1046,24 @@ static int idtcm_adjtime(struct ptp_clock_info *ptp, s64 delta) return err; } +static int idtcm_adjphase(struct ptp_clock_info *ptp, s32 delta) +{ + struct idtcm_channel *channel = + container_of(ptp, struct idtcm_channel, caps); + + struct idtcm *idtcm = channel->idtcm; + + int err; + + mutex_lock(&idtcm->reg_lock); + + err = _idtcm_adjphase(channel, delta); + + mutex_unlock(&idtcm->reg_lock); + + return err; +} + static int idtcm_enable(struct ptp_clock_info *ptp, struct ptp_clock_request *rq, int on) { @@ -1055,13 +1142,16 @@ static const struct ptp_clock_info idtcm_caps = { .owner = THIS_MODULE, .max_adj = 244000, .n_per_out = 1, + .adjphase = &idtcm_adjphase, .adjfreq = &idtcm_adjfreq, .adjtime = &idtcm_adjtime, .gettime64 = &idtcm_gettime, .settime64 = &idtcm_settime, .enable = &idtcm_enable, + .do_aux_work = &set_write_phase_ready, }; + static int idtcm_enable_channel(struct idtcm *idtcm, u32 index) { struct idtcm_channel *channel; @@ -1146,6 +1236,8 @@ static int idtcm_enable_channel(struct idtcm *idtcm, u32 index) if (!channel->ptp_clock) return -ENOTSUPP; + channel->write_phase_ready = 0; + dev_info(&idtcm->client->dev, "PLL%d registered as ptp%d\n", index, channel->ptp_clock->index); diff --git a/drivers/ptp/ptp_clockmatrix.h b/drivers/ptp/ptp_clockmatrix.h index 6c1f93ab46f3..3de0eb72889c 100644 --- a/drivers/ptp/ptp_clockmatrix.h +++ b/drivers/ptp/ptp_clockmatrix.h @@ -15,6 +15,8 @@ #define FW_FILENAME "idtcm.bin" #define MAX_PHC_PLL 4 +#define MAX_ABS_WRITE_PHASE_PICOSECONDS (107374182350LL) + #define PLL_MASK_ADDR (0xFFA5) #define DEFAULT_PLL_MASK (0x04) @@ -33,8 +35,9 @@ #define POST_SM_RESET_DELAY_MS (3000) #define PHASE_PULL_IN_THRESHOLD_NS (150000) -#define TOD_WRITE_OVERHEAD_COUNT_MAX (5) -#define TOD_BYTE_COUNT (11) +#define TOD_WRITE_OVERHEAD_COUNT_MAX (5) +#define TOD_BYTE_COUNT (11) +#define WR_PHASE_SETUP_MS (5000) /* Values of DPLL_N.DPLL_MODE.PLL_MODE */ enum pll_mode { @@ -77,6 +80,7 @@ struct idtcm_channel { u16 hw_dpll_n; enum pll_mode pll_mode; u16 output_mask; + int write_phase_ready; }; struct idtcm { diff --git a/drivers/ptp/ptp_idt82p33.c b/drivers/ptp/ptp_idt82p33.c index b63ac240308b..179f6c472e50 100644 --- a/drivers/ptp/ptp_idt82p33.c +++ b/drivers/ptp/ptp_idt82p33.c @@ -23,12 +23,12 @@ MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); /* Module Parameters */ -u32 sync_tod_timeout = SYNC_TOD_TIMEOUT_SEC; +static u32 sync_tod_timeout = SYNC_TOD_TIMEOUT_SEC; module_param(sync_tod_timeout, uint, 0); MODULE_PARM_DESC(sync_tod_timeout, "duration in second to keep SYNC_TOD on (set to 0 to keep it always on)"); -u32 phase_snap_threshold = SNAP_THRESHOLD_NS; +static u32 phase_snap_threshold = SNAP_THRESHOLD_NS; module_param(phase_snap_threshold, uint, 0); MODULE_PARM_DESC(phase_snap_threshold, "threshold (150000ns by default) below which adjtime would ignore"); @@ -881,7 +881,7 @@ static int idt82p33_load_firmware(struct idt82p33 *idt82p33) /* Page size 128, last 4 bytes of page skipped */ if (((loaddr > 0x7b) && (loaddr <= 0x7f)) - || ((loaddr > 0xfb) && (loaddr <= 0xff))) + || loaddr > 0xfb) continue; err = idt82p33_write(idt82p33, _ADDR(page, loaddr), diff --git a/drivers/ptp/ptp_ines.c b/drivers/ptp/ptp_ines.c index dfda54cbd866..7711651ff19e 100644 --- a/drivers/ptp/ptp_ines.c +++ b/drivers/ptp/ptp_ines.c @@ -400,8 +400,8 @@ static int ines_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr) ines_write32(port, ts_stat_rx, ts_stat_rx); ines_write32(port, ts_stat_tx, ts_stat_tx); - port->rxts_enabled = ts_stat_rx == TS_ENABLE ? true : false; - port->txts_enabled = ts_stat_tx == TS_ENABLE ? true : false; + port->rxts_enabled = ts_stat_rx == TS_ENABLE; + port->txts_enabled = ts_stat_tx == TS_ENABLE; spin_unlock_irqrestore(&port->lock, flags); @@ -783,16 +783,10 @@ static struct mii_timestamping_ctrl ines_ctrl = { static int ines_ptp_ctrl_probe(struct platform_device *pld) { struct ines_clock *clock; - struct resource *res; void __iomem *addr; int err = 0; - res = platform_get_resource(pld, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pld->dev, "missing memory resource\n"); - return -EINVAL; - } - addr = devm_ioremap_resource(&pld->dev, res); + addr = devm_platform_ioremap_resource(pld, 0); if (IS_ERR(addr)) { err = PTR_ERR(addr); goto out; diff --git a/drivers/ptp/ptp_kvm.c b/drivers/ptp/ptp_kvm.c index fc7d0b77e118..658d33fc3195 100644 --- a/drivers/ptp/ptp_kvm.c +++ b/drivers/ptp/ptp_kvm.c @@ -22,7 +22,7 @@ struct kvm_ptp_clock { struct ptp_clock_info caps; }; -DEFINE_SPINLOCK(kvm_ptp_lock); +static DEFINE_SPINLOCK(kvm_ptp_lock); static struct pvclock_vsyscall_time_info *hv_clock; |