xref: /openbmc/linux/drivers/net/dsa/mv88e6xxx/ptp.c (revision 2fa8d3af4badc40a39092140a01101119988faf6)
1*2fa8d3afSBrandon Streiff /*
2*2fa8d3afSBrandon Streiff  * Marvell 88E6xxx Switch PTP support
3*2fa8d3afSBrandon Streiff  *
4*2fa8d3afSBrandon Streiff  * Copyright (c) 2008 Marvell Semiconductor
5*2fa8d3afSBrandon Streiff  *
6*2fa8d3afSBrandon Streiff  * Copyright (c) 2017 National Instruments
7*2fa8d3afSBrandon Streiff  *      Erik Hons <erik.hons@ni.com>
8*2fa8d3afSBrandon Streiff  *      Brandon Streiff <brandon.streiff@ni.com>
9*2fa8d3afSBrandon Streiff  *      Dane Wagner <dane.wagner@ni.com>
10*2fa8d3afSBrandon Streiff  *
11*2fa8d3afSBrandon Streiff  * This program is free software; you can redistribute it and/or modify
12*2fa8d3afSBrandon Streiff  * it under the terms of the GNU General Public License as published by
13*2fa8d3afSBrandon Streiff  * the Free Software Foundation; either version 2 of the License, or
14*2fa8d3afSBrandon Streiff  * (at your option) any later version.
15*2fa8d3afSBrandon Streiff  */
16*2fa8d3afSBrandon Streiff 
17*2fa8d3afSBrandon Streiff #include "chip.h"
18*2fa8d3afSBrandon Streiff #include "global2.h"
19*2fa8d3afSBrandon Streiff #include "ptp.h"
20*2fa8d3afSBrandon Streiff 
21*2fa8d3afSBrandon Streiff /* Raw timestamps are in units of 8-ns clock periods. */
22*2fa8d3afSBrandon Streiff #define CC_SHIFT	28
23*2fa8d3afSBrandon Streiff #define CC_MULT		(8 << CC_SHIFT)
24*2fa8d3afSBrandon Streiff #define CC_MULT_NUM	(1 << 9)
25*2fa8d3afSBrandon Streiff #define CC_MULT_DEM	15625ULL
26*2fa8d3afSBrandon Streiff 
27*2fa8d3afSBrandon Streiff #define TAI_EVENT_WORK_INTERVAL msecs_to_jiffies(100)
28*2fa8d3afSBrandon Streiff 
29*2fa8d3afSBrandon Streiff #define cc_to_chip(cc) container_of(cc, struct mv88e6xxx_chip, tstamp_cc)
30*2fa8d3afSBrandon Streiff #define ptp_to_chip(ptp) container_of(ptp, struct mv88e6xxx_chip, \
31*2fa8d3afSBrandon Streiff 				      ptp_clock_info)
32*2fa8d3afSBrandon Streiff #define dw_overflow_to_chip(dw) container_of(dw, struct mv88e6xxx_chip, \
33*2fa8d3afSBrandon Streiff 					     overflow_work)
34*2fa8d3afSBrandon Streiff 
35*2fa8d3afSBrandon Streiff static int mv88e6xxx_tai_read(struct mv88e6xxx_chip *chip, int addr,
36*2fa8d3afSBrandon Streiff 			      u16 *data, int len)
37*2fa8d3afSBrandon Streiff {
38*2fa8d3afSBrandon Streiff 	if (!chip->info->ops->avb_ops->tai_read)
39*2fa8d3afSBrandon Streiff 		return -EOPNOTSUPP;
40*2fa8d3afSBrandon Streiff 
41*2fa8d3afSBrandon Streiff 	return chip->info->ops->avb_ops->tai_read(chip, addr, data, len);
42*2fa8d3afSBrandon Streiff }
43*2fa8d3afSBrandon Streiff 
44*2fa8d3afSBrandon Streiff static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
45*2fa8d3afSBrandon Streiff {
46*2fa8d3afSBrandon Streiff 	struct mv88e6xxx_chip *chip = cc_to_chip(cc);
47*2fa8d3afSBrandon Streiff 	u16 phc_time[2];
48*2fa8d3afSBrandon Streiff 	int err;
49*2fa8d3afSBrandon Streiff 
50*2fa8d3afSBrandon Streiff 	err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_TIME_LO, phc_time,
51*2fa8d3afSBrandon Streiff 				 ARRAY_SIZE(phc_time));
52*2fa8d3afSBrandon Streiff 	if (err)
53*2fa8d3afSBrandon Streiff 		return 0;
54*2fa8d3afSBrandon Streiff 	else
55*2fa8d3afSBrandon Streiff 		return ((u32)phc_time[1] << 16) | phc_time[0];
56*2fa8d3afSBrandon Streiff }
57*2fa8d3afSBrandon Streiff 
58*2fa8d3afSBrandon Streiff static int mv88e6xxx_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
59*2fa8d3afSBrandon Streiff {
60*2fa8d3afSBrandon Streiff 	struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
61*2fa8d3afSBrandon Streiff 	int neg_adj = 0;
62*2fa8d3afSBrandon Streiff 	u32 diff, mult;
63*2fa8d3afSBrandon Streiff 	u64 adj;
64*2fa8d3afSBrandon Streiff 
65*2fa8d3afSBrandon Streiff 	if (scaled_ppm < 0) {
66*2fa8d3afSBrandon Streiff 		neg_adj = 1;
67*2fa8d3afSBrandon Streiff 		scaled_ppm = -scaled_ppm;
68*2fa8d3afSBrandon Streiff 	}
69*2fa8d3afSBrandon Streiff 	mult = CC_MULT;
70*2fa8d3afSBrandon Streiff 	adj = CC_MULT_NUM;
71*2fa8d3afSBrandon Streiff 	adj *= scaled_ppm;
72*2fa8d3afSBrandon Streiff 	diff = div_u64(adj, CC_MULT_DEM);
73*2fa8d3afSBrandon Streiff 
74*2fa8d3afSBrandon Streiff 	mutex_lock(&chip->reg_lock);
75*2fa8d3afSBrandon Streiff 
76*2fa8d3afSBrandon Streiff 	timecounter_read(&chip->tstamp_tc);
77*2fa8d3afSBrandon Streiff 	chip->tstamp_cc.mult = neg_adj ? mult - diff : mult + diff;
78*2fa8d3afSBrandon Streiff 
79*2fa8d3afSBrandon Streiff 	mutex_unlock(&chip->reg_lock);
80*2fa8d3afSBrandon Streiff 
81*2fa8d3afSBrandon Streiff 	return 0;
82*2fa8d3afSBrandon Streiff }
83*2fa8d3afSBrandon Streiff 
84*2fa8d3afSBrandon Streiff static int mv88e6xxx_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
85*2fa8d3afSBrandon Streiff {
86*2fa8d3afSBrandon Streiff 	struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
87*2fa8d3afSBrandon Streiff 
88*2fa8d3afSBrandon Streiff 	mutex_lock(&chip->reg_lock);
89*2fa8d3afSBrandon Streiff 	timecounter_adjtime(&chip->tstamp_tc, delta);
90*2fa8d3afSBrandon Streiff 	mutex_unlock(&chip->reg_lock);
91*2fa8d3afSBrandon Streiff 
92*2fa8d3afSBrandon Streiff 	return 0;
93*2fa8d3afSBrandon Streiff }
94*2fa8d3afSBrandon Streiff 
95*2fa8d3afSBrandon Streiff static int mv88e6xxx_ptp_gettime(struct ptp_clock_info *ptp,
96*2fa8d3afSBrandon Streiff 				 struct timespec64 *ts)
97*2fa8d3afSBrandon Streiff {
98*2fa8d3afSBrandon Streiff 	struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
99*2fa8d3afSBrandon Streiff 	u64 ns;
100*2fa8d3afSBrandon Streiff 
101*2fa8d3afSBrandon Streiff 	mutex_lock(&chip->reg_lock);
102*2fa8d3afSBrandon Streiff 	ns = timecounter_read(&chip->tstamp_tc);
103*2fa8d3afSBrandon Streiff 	mutex_unlock(&chip->reg_lock);
104*2fa8d3afSBrandon Streiff 
105*2fa8d3afSBrandon Streiff 	*ts = ns_to_timespec64(ns);
106*2fa8d3afSBrandon Streiff 
107*2fa8d3afSBrandon Streiff 	return 0;
108*2fa8d3afSBrandon Streiff }
109*2fa8d3afSBrandon Streiff 
110*2fa8d3afSBrandon Streiff static int mv88e6xxx_ptp_settime(struct ptp_clock_info *ptp,
111*2fa8d3afSBrandon Streiff 				 const struct timespec64 *ts)
112*2fa8d3afSBrandon Streiff {
113*2fa8d3afSBrandon Streiff 	struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
114*2fa8d3afSBrandon Streiff 	u64 ns;
115*2fa8d3afSBrandon Streiff 
116*2fa8d3afSBrandon Streiff 	ns = timespec64_to_ns(ts);
117*2fa8d3afSBrandon Streiff 
118*2fa8d3afSBrandon Streiff 	mutex_lock(&chip->reg_lock);
119*2fa8d3afSBrandon Streiff 	timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc, ns);
120*2fa8d3afSBrandon Streiff 	mutex_unlock(&chip->reg_lock);
121*2fa8d3afSBrandon Streiff 
122*2fa8d3afSBrandon Streiff 	return 0;
123*2fa8d3afSBrandon Streiff }
124*2fa8d3afSBrandon Streiff 
125*2fa8d3afSBrandon Streiff static int mv88e6xxx_ptp_enable(struct ptp_clock_info *ptp,
126*2fa8d3afSBrandon Streiff 				struct ptp_clock_request *rq, int on)
127*2fa8d3afSBrandon Streiff {
128*2fa8d3afSBrandon Streiff 	return -EOPNOTSUPP;
129*2fa8d3afSBrandon Streiff }
130*2fa8d3afSBrandon Streiff 
131*2fa8d3afSBrandon Streiff static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
132*2fa8d3afSBrandon Streiff 				enum ptp_pin_function func, unsigned int chan)
133*2fa8d3afSBrandon Streiff {
134*2fa8d3afSBrandon Streiff 	return -EOPNOTSUPP;
135*2fa8d3afSBrandon Streiff }
136*2fa8d3afSBrandon Streiff 
137*2fa8d3afSBrandon Streiff /* With a 125MHz input clock, the 32-bit timestamp counter overflows in ~34.3
138*2fa8d3afSBrandon Streiff  * seconds; this task forces periodic reads so that we don't miss any.
139*2fa8d3afSBrandon Streiff  */
140*2fa8d3afSBrandon Streiff #define MV88E6XXX_TAI_OVERFLOW_PERIOD (HZ * 16)
141*2fa8d3afSBrandon Streiff static void mv88e6xxx_ptp_overflow_check(struct work_struct *work)
142*2fa8d3afSBrandon Streiff {
143*2fa8d3afSBrandon Streiff 	struct delayed_work *dw = to_delayed_work(work);
144*2fa8d3afSBrandon Streiff 	struct mv88e6xxx_chip *chip = dw_overflow_to_chip(dw);
145*2fa8d3afSBrandon Streiff 	struct timespec64 ts;
146*2fa8d3afSBrandon Streiff 
147*2fa8d3afSBrandon Streiff 	mv88e6xxx_ptp_gettime(&chip->ptp_clock_info, &ts);
148*2fa8d3afSBrandon Streiff 
149*2fa8d3afSBrandon Streiff 	schedule_delayed_work(&chip->overflow_work,
150*2fa8d3afSBrandon Streiff 			      MV88E6XXX_TAI_OVERFLOW_PERIOD);
151*2fa8d3afSBrandon Streiff }
152*2fa8d3afSBrandon Streiff 
153*2fa8d3afSBrandon Streiff int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
154*2fa8d3afSBrandon Streiff {
155*2fa8d3afSBrandon Streiff 	/* Set up the cycle counter */
156*2fa8d3afSBrandon Streiff 	memset(&chip->tstamp_cc, 0, sizeof(chip->tstamp_cc));
157*2fa8d3afSBrandon Streiff 	chip->tstamp_cc.read	= mv88e6xxx_ptp_clock_read;
158*2fa8d3afSBrandon Streiff 	chip->tstamp_cc.mask	= CYCLECOUNTER_MASK(32);
159*2fa8d3afSBrandon Streiff 	chip->tstamp_cc.mult	= CC_MULT;
160*2fa8d3afSBrandon Streiff 	chip->tstamp_cc.shift	= CC_SHIFT;
161*2fa8d3afSBrandon Streiff 
162*2fa8d3afSBrandon Streiff 	timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc,
163*2fa8d3afSBrandon Streiff 			 ktime_to_ns(ktime_get_real()));
164*2fa8d3afSBrandon Streiff 
165*2fa8d3afSBrandon Streiff 	INIT_DELAYED_WORK(&chip->overflow_work, mv88e6xxx_ptp_overflow_check);
166*2fa8d3afSBrandon Streiff 
167*2fa8d3afSBrandon Streiff 	chip->ptp_clock_info.owner = THIS_MODULE;
168*2fa8d3afSBrandon Streiff 	snprintf(chip->ptp_clock_info.name, sizeof(chip->ptp_clock_info.name),
169*2fa8d3afSBrandon Streiff 		 dev_name(chip->dev));
170*2fa8d3afSBrandon Streiff 	chip->ptp_clock_info.max_adj	= 1000000;
171*2fa8d3afSBrandon Streiff 
172*2fa8d3afSBrandon Streiff 	chip->ptp_clock_info.adjfine	= mv88e6xxx_ptp_adjfine;
173*2fa8d3afSBrandon Streiff 	chip->ptp_clock_info.adjtime	= mv88e6xxx_ptp_adjtime;
174*2fa8d3afSBrandon Streiff 	chip->ptp_clock_info.gettime64	= mv88e6xxx_ptp_gettime;
175*2fa8d3afSBrandon Streiff 	chip->ptp_clock_info.settime64	= mv88e6xxx_ptp_settime;
176*2fa8d3afSBrandon Streiff 	chip->ptp_clock_info.enable	= mv88e6xxx_ptp_enable;
177*2fa8d3afSBrandon Streiff 	chip->ptp_clock_info.verify	= mv88e6xxx_ptp_verify;
178*2fa8d3afSBrandon Streiff 
179*2fa8d3afSBrandon Streiff 	chip->ptp_clock = ptp_clock_register(&chip->ptp_clock_info, chip->dev);
180*2fa8d3afSBrandon Streiff 	if (IS_ERR(chip->ptp_clock))
181*2fa8d3afSBrandon Streiff 		return PTR_ERR(chip->ptp_clock);
182*2fa8d3afSBrandon Streiff 
183*2fa8d3afSBrandon Streiff 	schedule_delayed_work(&chip->overflow_work,
184*2fa8d3afSBrandon Streiff 			      MV88E6XXX_TAI_OVERFLOW_PERIOD);
185*2fa8d3afSBrandon Streiff 
186*2fa8d3afSBrandon Streiff 	return 0;
187*2fa8d3afSBrandon Streiff }
188*2fa8d3afSBrandon Streiff 
189*2fa8d3afSBrandon Streiff void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
190*2fa8d3afSBrandon Streiff {
191*2fa8d3afSBrandon Streiff 	if (chip->ptp_clock) {
192*2fa8d3afSBrandon Streiff 		cancel_delayed_work_sync(&chip->overflow_work);
193*2fa8d3afSBrandon Streiff 
194*2fa8d3afSBrandon Streiff 		ptp_clock_unregister(chip->ptp_clock);
195*2fa8d3afSBrandon Streiff 		chip->ptp_clock = NULL;
196*2fa8d3afSBrandon Streiff 	}
197*2fa8d3afSBrandon Streiff }
198