Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <yangbo.lu@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Yangbo Lu and committed by
David S. Miller
cc2d87bb 94aca082

+128
+121
drivers/net/ethernet/mscc/ocelot_ptp.c
··· 165 165 } 166 166 EXPORT_SYMBOL(ocelot_ptp_adjfine); 167 167 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 + 168 277 int ocelot_init_timestamp(struct ocelot *ocelot, struct ptp_clock_info *info) 169 278 { 170 279 struct ptp_clock *ptp_clock; 280 + int i; 171 281 172 282 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 + 173 294 ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev); 174 295 if (IS_ERR(ptp_clock)) 175 296 return PTR_ERR(ptp_clock);
+3
include/soc/mscc/ocelot.h
··· 92 92 #define OCELOT_SPEED_100 2 93 93 #define OCELOT_SPEED_10 3 94 94 95 + #define OCELOT_PTP_PINS_NUM 4 96 + 95 97 #define TARGET_OFFSET 24 96 98 #define REG_MASK GENMASK(TARGET_OFFSET - 1, 0) 97 99 #define REG(reg, offset) [reg & REG_MASK] = offset ··· 554 552 struct mutex ptp_lock; 555 553 /* Protects the PTP clock */ 556 554 spinlock_t ptp_clock_lock; 555 + struct ptp_pin_desc ptp_pins[OCELOT_PTP_PINS_NUM]; 557 556 }; 558 557 559 558 struct ocelot_policer {
+4
include/soc/mscc/ocelot_ptp.h
··· 49 49 const struct timespec64 *ts); 50 50 int ocelot_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta); 51 51 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); 52 56 int ocelot_init_timestamp(struct ocelot *ocelot, struct ptp_clock_info *info); 53 57 int ocelot_deinit_timestamp(struct ocelot *ocelot); 54 58 #endif