Skip to content

Commit a62a56d

Browse files
jlemondavem330
authored andcommitted
ptp: ocp: Enable 4th timestamper / PPS generator
A 4th timestamper is added which timestamps the output of the PHC. The clock nanosecond offset is not always zero, so when compared to other timestampers, this provides precise measurements. Also, the timestamper interrupt from the PHC can be used to generate a PPS signal for /dev/pps. Also allow PTP_CLK_REQ_PEROUT requests for a 1PPS output, but do not actually configure any output pins, this is done via sysfs. Signed-off-by: Jonathan Lemon <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 71d7e08 commit a62a56d

File tree

1 file changed

+74
-8
lines changed

1 file changed

+74
-8
lines changed

drivers/ptp/ptp_ocp.c

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ struct ptp_ocp_i2c_info {
191191
struct ptp_ocp_ext_info {
192192
int index;
193193
irqreturn_t (*irq_fcn)(int irq, void *priv);
194-
int (*enable)(void *priv, bool enable);
194+
int (*enable)(void *priv, u32 req, bool enable);
195195
};
196196

197197
struct ptp_ocp_ext_src {
@@ -237,10 +237,14 @@ struct ptp_ocp {
237237
int nmea_port;
238238
u8 serial[6];
239239
bool has_serial;
240+
u32 pps_req_map;
240241
int flash_start;
241242
u32 utc_tai_offset;
242243
};
243244

245+
#define OCP_REQ_TIMESTAMP BIT(0)
246+
#define OCP_REQ_PPS BIT(1)
247+
244248
struct ocp_resource {
245249
unsigned long offset;
246250
int size;
@@ -258,7 +262,7 @@ static int ptp_ocp_register_serial(struct ptp_ocp *bp, struct ocp_resource *r);
258262
static int ptp_ocp_register_ext(struct ptp_ocp *bp, struct ocp_resource *r);
259263
static int ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r);
260264
static irqreturn_t ptp_ocp_ts_irq(int irq, void *priv);
261-
static int ptp_ocp_ts_enable(void *priv, bool enable);
265+
static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);
262266

263267
#define bp_assign_entry(bp, res, val) ({ \
264268
uintptr_t addr = (uintptr_t)(bp) + (res)->bp_offset; \
@@ -284,7 +288,7 @@ static int ptp_ocp_ts_enable(void *priv, bool enable);
284288
OCP_RES_LOCATION(member), .setup = ptp_ocp_register_ext
285289

286290
/* This is the MSI vector mapping used.
287-
* 0: N/C
291+
* 0: TS3 (and PPS)
288292
* 1: TS0
289293
* 2: TS1
290294
* 3: GNSS
@@ -329,6 +333,15 @@ static struct ocp_resource ocp_fb_resource[] = {
329333
.enable = ptp_ocp_ts_enable,
330334
},
331335
},
336+
{
337+
OCP_EXT_RESOURCE(pps),
338+
.offset = 0x010C0000, .size = 0x10000, .irq_vec = 0,
339+
.extra = &(struct ptp_ocp_ext_info) {
340+
.index = 3,
341+
.irq_fcn = ptp_ocp_ts_irq,
342+
.enable = ptp_ocp_ts_enable,
343+
},
344+
},
332345
{
333346
OCP_MEM_RESOURCE(pps_to_ext),
334347
.offset = 0x01030000, .size = 0x10000,
@@ -634,10 +647,12 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
634647
{
635648
struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
636649
struct ptp_ocp_ext_src *ext = NULL;
650+
u32 req;
637651
int err;
638652

639653
switch (rq->type) {
640654
case PTP_CLK_REQ_EXTTS:
655+
req = OCP_REQ_TIMESTAMP;
641656
switch (rq->extts.index) {
642657
case 0:
643658
ext = bp->ts0;
@@ -648,18 +663,30 @@ ptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq,
648663
case 2:
649664
ext = bp->ts2;
650665
break;
666+
case 3:
667+
ext = bp->pps;
668+
break;
651669
}
652670
break;
653671
case PTP_CLK_REQ_PPS:
672+
req = OCP_REQ_PPS;
654673
ext = bp->pps;
655674
break;
675+
case PTP_CLK_REQ_PEROUT:
676+
if (on &&
677+
(rq->perout.period.sec != 1 || rq->perout.period.nsec != 0))
678+
return -EINVAL;
679+
/* This is a request for 1PPS on an output SMA.
680+
* Allow, but assume manual configuration.
681+
*/
682+
return 0;
656683
default:
657684
return -EOPNOTSUPP;
658685
}
659686

660687
err = -ENXIO;
661688
if (ext)
662-
err = ext->info->enable(ext, on);
689+
err = ext->info->enable(ext, req, on);
663690

664691
return err;
665692
}
@@ -675,7 +702,8 @@ static const struct ptp_clock_info ptp_ocp_clock_info = {
675702
.adjphase = ptp_ocp_adjphase,
676703
.enable = ptp_ocp_enable,
677704
.pps = true,
678-
.n_ext_ts = 3,
705+
.n_ext_ts = 4,
706+
.n_per_out = 1,
679707
};
680708

681709
static void
@@ -1163,6 +1191,16 @@ ptp_ocp_ts_irq(int irq, void *priv)
11631191
struct ptp_clock_event ev;
11641192
u32 sec, nsec;
11651193

1194+
if (ext == ext->bp->pps) {
1195+
if (ext->bp->pps_req_map & OCP_REQ_PPS) {
1196+
ev.type = PTP_CLOCK_PPS;
1197+
ptp_clock_event(ext->bp->ptp, &ev);
1198+
}
1199+
1200+
if ((ext->bp->pps_req_map & ~OCP_REQ_PPS) == 0)
1201+
goto out;
1202+
}
1203+
11661204
/* XXX should fix API - this converts s/ns -> ts -> s/ns */
11671205
sec = ioread32(&reg->time_sec);
11681206
nsec = ioread32(&reg->time_ns);
@@ -1173,16 +1211,31 @@ ptp_ocp_ts_irq(int irq, void *priv)
11731211

11741212
ptp_clock_event(ext->bp->ptp, &ev);
11751213

1214+
out:
11761215
iowrite32(1, &reg->intr); /* write 1 to ack */
11771216

11781217
return IRQ_HANDLED;
11791218
}
11801219

11811220
static int
1182-
ptp_ocp_ts_enable(void *priv, bool enable)
1221+
ptp_ocp_ts_enable(void *priv, u32 req, bool enable)
11831222
{
11841223
struct ptp_ocp_ext_src *ext = priv;
11851224
struct ts_reg __iomem *reg = ext->mem;
1225+
struct ptp_ocp *bp = ext->bp;
1226+
1227+
if (ext == bp->pps) {
1228+
u32 old_map = bp->pps_req_map;
1229+
1230+
if (enable)
1231+
bp->pps_req_map |= req;
1232+
else
1233+
bp->pps_req_map &= ~req;
1234+
1235+
/* if no state change, just return */
1236+
if ((!!old_map ^ !!bp->pps_req_map) == 0)
1237+
return 0;
1238+
}
11861239

11871240
if (enable) {
11881241
iowrite32(1, &reg->enable);
@@ -1199,7 +1252,7 @@ ptp_ocp_ts_enable(void *priv, bool enable)
11991252
static void
12001253
ptp_ocp_unregister_ext(struct ptp_ocp_ext_src *ext)
12011254
{
1202-
ext->info->enable(ext, false);
1255+
ext->info->enable(ext, ~0, false);
12031256
pci_free_irq(ext->bp->pdev, ext->irq_vec, ext);
12041257
kfree(ext);
12051258
}
@@ -1889,8 +1942,8 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
18891942
struct timespec64 ts;
18901943
struct ptp_ocp *bp;
18911944
const char *src;
1945+
bool on, map;
18921946
char *buf;
1893-
bool on;
18941947

18951948
buf = (char *)__get_free_page(GFP_KERNEL);
18961949
if (!buf)
@@ -1938,6 +1991,19 @@ ptp_ocp_summary_show(struct seq_file *s, void *data)
19381991
on ? " ON" : "OFF", src);
19391992
}
19401993

1994+
if (bp->pps) {
1995+
ts_reg = bp->pps->mem;
1996+
src = "PHC";
1997+
on = ioread32(&ts_reg->enable);
1998+
map = !!(bp->pps_req_map & OCP_REQ_TIMESTAMP);
1999+
seq_printf(s, "%7s: %s, src: %s\n", "TS3",
2000+
on & map ? " ON" : "OFF", src);
2001+
2002+
map = !!(bp->pps_req_map & OCP_REQ_PPS);
2003+
seq_printf(s, "%7s: %s, src: %s\n", "PPS",
2004+
on & map ? " ON" : "OFF", src);
2005+
}
2006+
19412007
if (bp->irig_out) {
19422008
ctrl = ioread32(&bp->irig_out->ctrl);
19432009
on = ctrl & IRIG_M_CTRL_ENABLE;

0 commit comments

Comments
 (0)