Skip to content

Commit 6c5af96

Browse files
committed
Merge branch 'ptp-Add-adjust-phase-to-support-phase-offset'
Vincent Cheng says: ==================== ptp: Add adjust phase to support phase offset. This series adds adjust phase to the PTP Hardware Clock device interface. Some PTP hardware clocks have a write phase mode that has a built-in hardware filtering capability. The write phase mode utilizes a phase offset control word instead of a frequency offset control word. Add adjust phase function to take advantage of this capability. Changes since v1: - As suggested by Richard Cochran: 1. ops->adjphase is new so need to check for non-null function pointer. 2. Kernel coding style uses lower_case_underscores. 3. Use existing PTP clock API for delayed worker. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 115506f + 425d2b1 commit 6c5af96

File tree

7 files changed

+114
-6
lines changed

7 files changed

+114
-6
lines changed

drivers/ptp/ptp_chardev.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
136136
caps.pps = ptp->info->pps;
137137
caps.n_pins = ptp->info->n_pins;
138138
caps.cross_timestamping = ptp->info->getcrosststamp != NULL;
139+
caps.adjust_phase = ptp->info->adjphase != NULL;
139140
if (copy_to_user((void __user *)arg, &caps, sizeof(caps)))
140141
err = -EFAULT;
141142
break;

drivers/ptp/ptp_clock.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx)
146146
else
147147
err = ops->adjfreq(ops, ppb);
148148
ptp->dialed_frequency = tx->freq;
149+
} else if (tx->modes & ADJ_OFFSET) {
150+
if (ops->adjphase)
151+
err = ops->adjphase(ops, tx->offset);
149152
} else if (tx->modes == 0) {
150153
tx->freq = ptp->dialed_frequency;
151154
err = 0;

drivers/ptp/ptp_clockmatrix.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/module.h>
1111
#include <linux/ptp_clock_kernel.h>
1212
#include <linux/delay.h>
13+
#include <linux/jiffies.h>
1314
#include <linux/kernel.h>
1415
#include <linux/timekeeping.h>
1516

@@ -24,6 +25,16 @@ MODULE_LICENSE("GPL");
2425

2526
#define SETTIME_CORRECTION (0)
2627

28+
static long set_write_phase_ready(struct ptp_clock_info *ptp)
29+
{
30+
struct idtcm_channel *channel =
31+
container_of(ptp, struct idtcm_channel, caps);
32+
33+
channel->write_phase_ready = 1;
34+
35+
return 0;
36+
}
37+
2738
static int char_array_to_timespec(u8 *buf,
2839
u8 count,
2940
struct timespec64 *ts)
@@ -871,6 +882,64 @@ static int idtcm_set_pll_mode(struct idtcm_channel *channel,
871882

872883
/* PTP Hardware Clock interface */
873884

885+
/**
886+
* @brief Maximum absolute value for write phase offset in picoseconds
887+
*
888+
* Destination signed register is 32-bit register in resolution of 50ps
889+
*
890+
* 0x7fffffff * 50 = 2147483647 * 50 = 107374182350
891+
*/
892+
static int _idtcm_adjphase(struct idtcm_channel *channel, s32 delta_ns)
893+
{
894+
struct idtcm *idtcm = channel->idtcm;
895+
896+
int err;
897+
u8 i;
898+
u8 buf[4] = {0};
899+
s32 phase_50ps;
900+
s64 offset_ps;
901+
902+
if (channel->pll_mode != PLL_MODE_WRITE_PHASE) {
903+
904+
err = idtcm_set_pll_mode(channel, PLL_MODE_WRITE_PHASE);
905+
906+
if (err)
907+
return err;
908+
909+
channel->write_phase_ready = 0;
910+
911+
ptp_schedule_worker(channel->ptp_clock,
912+
msecs_to_jiffies(WR_PHASE_SETUP_MS));
913+
}
914+
915+
if (!channel->write_phase_ready)
916+
delta_ns = 0;
917+
918+
offset_ps = (s64)delta_ns * 1000;
919+
920+
/*
921+
* Check for 32-bit signed max * 50:
922+
*
923+
* 0x7fffffff * 50 = 2147483647 * 50 = 107374182350
924+
*/
925+
if (offset_ps > MAX_ABS_WRITE_PHASE_PICOSECONDS)
926+
offset_ps = MAX_ABS_WRITE_PHASE_PICOSECONDS;
927+
else if (offset_ps < -MAX_ABS_WRITE_PHASE_PICOSECONDS)
928+
offset_ps = -MAX_ABS_WRITE_PHASE_PICOSECONDS;
929+
930+
phase_50ps = DIV_ROUND_CLOSEST(div64_s64(offset_ps, 50), 1);
931+
932+
for (i = 0; i < 4; i++) {
933+
buf[i] = phase_50ps & 0xff;
934+
phase_50ps >>= 8;
935+
}
936+
937+
err = idtcm_write(idtcm, channel->dpll_phase, DPLL_WR_PHASE,
938+
buf, sizeof(buf));
939+
940+
return err;
941+
}
942+
874943
static int idtcm_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
875944
{
876945
struct idtcm_channel *channel =
@@ -977,6 +1046,24 @@ static int idtcm_adjtime(struct ptp_clock_info *ptp, s64 delta)
9771046
return err;
9781047
}
9791048

1049+
static int idtcm_adjphase(struct ptp_clock_info *ptp, s32 delta)
1050+
{
1051+
struct idtcm_channel *channel =
1052+
container_of(ptp, struct idtcm_channel, caps);
1053+
1054+
struct idtcm *idtcm = channel->idtcm;
1055+
1056+
int err;
1057+
1058+
mutex_lock(&idtcm->reg_lock);
1059+
1060+
err = _idtcm_adjphase(channel, delta);
1061+
1062+
mutex_unlock(&idtcm->reg_lock);
1063+
1064+
return err;
1065+
}
1066+
9801067
static int idtcm_enable(struct ptp_clock_info *ptp,
9811068
struct ptp_clock_request *rq, int on)
9821069
{
@@ -1055,13 +1142,16 @@ static const struct ptp_clock_info idtcm_caps = {
10551142
.owner = THIS_MODULE,
10561143
.max_adj = 244000,
10571144
.n_per_out = 1,
1145+
.adjphase = &idtcm_adjphase,
10581146
.adjfreq = &idtcm_adjfreq,
10591147
.adjtime = &idtcm_adjtime,
10601148
.gettime64 = &idtcm_gettime,
10611149
.settime64 = &idtcm_settime,
10621150
.enable = &idtcm_enable,
1151+
.do_aux_work = &set_write_phase_ready,
10631152
};
10641153

1154+
10651155
static int idtcm_enable_channel(struct idtcm *idtcm, u32 index)
10661156
{
10671157
struct idtcm_channel *channel;
@@ -1146,6 +1236,8 @@ static int idtcm_enable_channel(struct idtcm *idtcm, u32 index)
11461236
if (!channel->ptp_clock)
11471237
return -ENOTSUPP;
11481238

1239+
channel->write_phase_ready = 0;
1240+
11491241
dev_info(&idtcm->client->dev, "PLL%d registered as ptp%d\n",
11501242
index, channel->ptp_clock->index);
11511243

drivers/ptp/ptp_clockmatrix.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#define FW_FILENAME "idtcm.bin"
1616
#define MAX_PHC_PLL 4
1717

18+
#define MAX_ABS_WRITE_PHASE_PICOSECONDS (107374182350LL)
19+
1820
#define PLL_MASK_ADDR (0xFFA5)
1921
#define DEFAULT_PLL_MASK (0x04)
2022

@@ -33,8 +35,9 @@
3335

3436
#define POST_SM_RESET_DELAY_MS (3000)
3537
#define PHASE_PULL_IN_THRESHOLD_NS (150000)
36-
#define TOD_WRITE_OVERHEAD_COUNT_MAX (5)
37-
#define TOD_BYTE_COUNT (11)
38+
#define TOD_WRITE_OVERHEAD_COUNT_MAX (5)
39+
#define TOD_BYTE_COUNT (11)
40+
#define WR_PHASE_SETUP_MS (5000)
3841

3942
/* Values of DPLL_N.DPLL_MODE.PLL_MODE */
4043
enum pll_mode {
@@ -77,6 +80,7 @@ struct idtcm_channel {
7780
u16 hw_dpll_n;
7881
enum pll_mode pll_mode;
7982
u16 output_mask;
83+
int write_phase_ready;
8084
};
8185

8286
struct idtcm {

include/linux/ptp_clock_kernel.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct ptp_system_timestamp {
3636
};
3737

3838
/**
39-
* struct ptp_clock_info - decribes a PTP hardware clock
39+
* struct ptp_clock_info - describes a PTP hardware clock
4040
*
4141
* @owner: The clock driver should set to THIS_MODULE.
4242
* @name: A short "friendly name" to identify the clock and to
@@ -65,6 +65,9 @@ struct ptp_system_timestamp {
6565
* parameter delta: Desired frequency offset from nominal frequency
6666
* in parts per billion
6767
*
68+
* @adjphase: Adjusts the phase offset of the hardware clock.
69+
* parameter delta: Desired change in nanoseconds.
70+
*
6871
* @adjtime: Shifts the time of the hardware clock.
6972
* parameter delta: Desired change in nanoseconds.
7073
*
@@ -128,6 +131,7 @@ struct ptp_clock_info {
128131
struct ptp_pin_desc *pin_config;
129132
int (*adjfine)(struct ptp_clock_info *ptp, long scaled_ppm);
130133
int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta);
134+
int (*adjphase)(struct ptp_clock_info *ptp, s32 phase);
131135
int (*adjtime)(struct ptp_clock_info *ptp, s64 delta);
132136
int (*gettime64)(struct ptp_clock_info *ptp, struct timespec64 *ts);
133137
int (*gettimex64)(struct ptp_clock_info *ptp, struct timespec64 *ts,

include/uapi/linux/ptp_clock.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ struct ptp_clock_caps {
8989
int n_pins; /* Number of input/output pins. */
9090
/* Whether the clock supports precise system-device cross timestamps */
9191
int cross_timestamping;
92-
int rsv[13]; /* Reserved for future use. */
92+
/* Whether the clock supports adjust phase */
93+
int adjust_phase;
94+
int rsv[12]; /* Reserved for future use. */
9395
};
9496

9597
struct ptp_extts_request {

tools/testing/selftests/ptp/testptp.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,14 +269,16 @@ int main(int argc, char *argv[])
269269
" %d programmable periodic signals\n"
270270
" %d pulse per second\n"
271271
" %d programmable pins\n"
272-
" %d cross timestamping\n",
272+
" %d cross timestamping\n"
273+
" %d adjust_phase\n",
273274
caps.max_adj,
274275
caps.n_alarm,
275276
caps.n_ext_ts,
276277
caps.n_per_out,
277278
caps.pps,
278279
caps.n_pins,
279-
caps.cross_timestamping);
280+
caps.cross_timestamping,
281+
caps.adjust_phase);
280282
}
281283
}
282284

0 commit comments

Comments
 (0)