Skip to content

Commit cc2d87b

Browse files
yangbolu1991davem330
authored andcommitted
net: mscc: ocelot: support 4 PTP programmable pins
Support 4 PTP programmable pins with only PTP_PF_PEROUT function for now. The PTP_PF_EXTTS function will be supported in the future, and it should be implemented separately for Felix and Ocelot, because of different hardware interrupt implementation in them. Since the hardware is not able to support absolute start time, the periodic clock request only allows start time 0 0. But nsec could be accepted for PPS case for phase adjustment. Signed-off-by: Yangbo Lu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 94aca08 commit cc2d87b

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed

drivers/net/ethernet/mscc/ocelot_ptp.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,132 @@ int ocelot_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
165165
}
166166
EXPORT_SYMBOL(ocelot_ptp_adjfine);
167167

168+
int ocelot_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
169+
enum ptp_pin_function func, unsigned int chan)
170+
{
171+
switch (func) {
172+
case PTP_PF_NONE:
173+
case PTP_PF_PEROUT:
174+
break;
175+
case PTP_PF_EXTTS:
176+
case PTP_PF_PHYSYNC:
177+
return -1;
178+
}
179+
return 0;
180+
}
181+
EXPORT_SYMBOL(ocelot_ptp_verify);
182+
183+
int ocelot_ptp_enable(struct ptp_clock_info *ptp,
184+
struct ptp_clock_request *rq, int on)
185+
{
186+
struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
187+
struct timespec64 ts_start, ts_period;
188+
enum ocelot_ptp_pins ptp_pin;
189+
unsigned long flags;
190+
bool pps = false;
191+
int pin = -1;
192+
u32 val;
193+
s64 ns;
194+
195+
switch (rq->type) {
196+
case PTP_CLK_REQ_PEROUT:
197+
/* Reject requests with unsupported flags */
198+
if (rq->perout.flags)
199+
return -EOPNOTSUPP;
200+
201+
pin = ptp_find_pin(ocelot->ptp_clock, PTP_PF_PEROUT,
202+
rq->perout.index);
203+
if (pin == 0)
204+
ptp_pin = PTP_PIN_0;
205+
else if (pin == 1)
206+
ptp_pin = PTP_PIN_1;
207+
else if (pin == 2)
208+
ptp_pin = PTP_PIN_2;
209+
else if (pin == 3)
210+
ptp_pin = PTP_PIN_3;
211+
else
212+
return -EBUSY;
213+
214+
ts_start.tv_sec = rq->perout.start.sec;
215+
ts_start.tv_nsec = rq->perout.start.nsec;
216+
ts_period.tv_sec = rq->perout.period.sec;
217+
ts_period.tv_nsec = rq->perout.period.nsec;
218+
219+
if (ts_period.tv_sec == 1 && ts_period.tv_nsec == 0)
220+
pps = true;
221+
222+
if (ts_start.tv_sec || (ts_start.tv_nsec && !pps)) {
223+
dev_warn(ocelot->dev,
224+
"Absolute start time not supported!\n");
225+
dev_warn(ocelot->dev,
226+
"Accept nsec for PPS phase adjustment, otherwise start time should be 0 0.\n");
227+
return -EINVAL;
228+
}
229+
230+
/* Handle turning off */
231+
if (!on) {
232+
spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
233+
val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
234+
ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
235+
spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
236+
break;
237+
}
238+
239+
/* Handle PPS request */
240+
if (pps) {
241+
spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
242+
/* Pulse generated perout.start.nsec after TOD has
243+
* increased seconds.
244+
* Pulse width is set to 1us.
245+
*/
246+
ocelot_write_rix(ocelot, ts_start.tv_nsec,
247+
PTP_PIN_WF_LOW_PERIOD, ptp_pin);
248+
ocelot_write_rix(ocelot, 1000,
249+
PTP_PIN_WF_HIGH_PERIOD, ptp_pin);
250+
val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_CLOCK);
251+
val |= PTP_PIN_CFG_SYNC;
252+
ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
253+
spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
254+
break;
255+
}
256+
257+
/* Handle periodic clock */
258+
ns = timespec64_to_ns(&ts_period);
259+
ns = ns >> 1;
260+
if (ns > 0x3fffffff || ns <= 0x6)
261+
return -EINVAL;
262+
263+
spin_lock_irqsave(&ocelot->ptp_clock_lock, flags);
264+
ocelot_write_rix(ocelot, ns, PTP_PIN_WF_LOW_PERIOD, ptp_pin);
265+
ocelot_write_rix(ocelot, ns, PTP_PIN_WF_HIGH_PERIOD, ptp_pin);
266+
val = PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_CLOCK);
267+
ocelot_write_rix(ocelot, val, PTP_PIN_CFG, ptp_pin);
268+
spin_unlock_irqrestore(&ocelot->ptp_clock_lock, flags);
269+
break;
270+
default:
271+
return -EOPNOTSUPP;
272+
}
273+
return 0;
274+
}
275+
EXPORT_SYMBOL(ocelot_ptp_enable);
276+
168277
int ocelot_init_timestamp(struct ocelot *ocelot, struct ptp_clock_info *info)
169278
{
170279
struct ptp_clock *ptp_clock;
280+
int i;
171281

172282
ocelot->ptp_info = *info;
283+
284+
for (i = 0; i < OCELOT_PTP_PINS_NUM; i++) {
285+
struct ptp_pin_desc *p = &ocelot->ptp_pins[i];
286+
287+
snprintf(p->name, sizeof(p->name), "switch_1588_dat%d", i);
288+
p->index = i;
289+
p->func = PTP_PF_NONE;
290+
}
291+
292+
ocelot->ptp_info.pin_config = &ocelot->ptp_pins[0];
293+
173294
ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev);
174295
if (IS_ERR(ptp_clock))
175296
return PTR_ERR(ptp_clock);

include/soc/mscc/ocelot.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@
9292
#define OCELOT_SPEED_100 2
9393
#define OCELOT_SPEED_10 3
9494

95+
#define OCELOT_PTP_PINS_NUM 4
96+
9597
#define TARGET_OFFSET 24
9698
#define REG_MASK GENMASK(TARGET_OFFSET - 1, 0)
9799
#define REG(reg, offset) [reg & REG_MASK] = offset
@@ -552,6 +554,7 @@ struct ocelot {
552554
struct mutex ptp_lock;
553555
/* Protects the PTP clock */
554556
spinlock_t ptp_clock_lock;
557+
struct ptp_pin_desc ptp_pins[OCELOT_PTP_PINS_NUM];
555558
};
556559

557560
struct ocelot_policer {

include/soc/mscc/ocelot_ptp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ int ocelot_ptp_settime64(struct ptp_clock_info *ptp,
4949
const struct timespec64 *ts);
5050
int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta);
5151
int ocelot_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm);
52+
int ocelot_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
53+
enum ptp_pin_function func, unsigned int chan);
54+
int ocelot_ptp_enable(struct ptp_clock_info *ptp,
55+
struct ptp_clock_request *rq, int on);
5256
int ocelot_init_timestamp(struct ocelot *ocelot, struct ptp_clock_info *info);
5357
int ocelot_deinit_timestamp(struct ocelot *ocelot);
5458
#endif

0 commit comments

Comments
 (0)