diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c index d7498132064e..3c96dd4581cf 100644 --- a/drivers/net/dsa/microchip/ksz8.c +++ b/drivers/net/dsa/microchip/ksz8.c @@ -2589,6 +2589,7 @@ static int ksz8463_setup(struct dsa_switch *ds) if (ret) goto free_girq; + ksz8463_ptp_set_caps(ds); ret = ksz_ptp_clock_register(ds); if (ret) { dev_err(dev->dev, "Failed to register PTP clock: %d\n", @@ -2898,6 +2899,7 @@ static int ksz8_setup(struct dsa_switch *ds) } if (dev->info->ptp_capable) { + ksz_ptp_set_caps(ds); ret = ksz_ptp_clock_register(ds); if (ret) { dev_err(dev->dev, "Failed to register PTP clock: %d\n", diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index 3ee995545c57..72528a53b67d 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -1781,6 +1781,7 @@ static int ksz9477_setup(struct dsa_switch *ds) } if (dev->info->ptp_capable) { + ksz_ptp_set_caps(ds); ret = ksz_ptp_clock_register(ds); if (ret) { dev_err(dev->dev, "Failed to register PTP clock: %d\n", diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index f1b53439ff58..767c8fe8e819 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1175,6 +1175,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .supports_mii = {false, false, true}, .supports_rmii = {false, false, true}, .internal_phy = {true, true, false}, + .n_pins = 12, + .n_per_out = 12, }, [KSZ8563] = { @@ -1208,6 +1210,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .ptp_capable = true, .wr_table = &ksz8563_register_set, .rd_table = &ksz8563_register_set, + .n_pins = 2, + .n_per_out = 3, }, [KSZ8795] = { @@ -1443,6 +1447,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .sgmii_port = 7, .wr_table = &ksz9477_register_set, .rd_table = &ksz9477_register_set, + .n_pins = 2, + .n_per_out = 3, }, [KSZ9896] = { @@ -1608,6 +1614,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .internal_phy = {true, true, false}, .gbit_capable = {true, true, true}, .ptp_capable = true, + .n_pins = 2, + .n_per_out = 3, }, [KSZ8567] = { @@ -1645,6 +1653,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .gbit_capable = {false, false, false, false, false, true, true}, .ptp_capable = true, + .n_pins = 2, + .n_per_out = 3, }, [KSZ9567] = { @@ -1679,6 +1689,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { true, false, false}, .gbit_capable = {true, true, true, true, true, true, true}, .ptp_capable = true, + .n_pins = 2, + .n_per_out = 3, }, [LAN9370] = { @@ -1710,6 +1722,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .supports_rgmii = {false, false, false, false, true}, .internal_phy = {true, true, true, true, false}, .ptp_capable = true, + .n_pins = 2, + .n_per_out = 3, }, [LAN9371] = { @@ -1741,6 +1755,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .supports_rgmii = {false, false, false, false, true, true}, .internal_phy = {true, true, true, true, false, false}, .ptp_capable = true, + .n_pins = 2, + .n_per_out = 3, }, [LAN9372] = { @@ -1776,6 +1792,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .internal_phy = {true, true, true, true, false, false, true, true}, .ptp_capable = true, + .n_pins = 2, + .n_per_out = 3, }, [LAN9373] = { @@ -1811,6 +1829,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .internal_phy = {true, true, true, false, false, false, true, true}, .ptp_capable = true, + .n_pins = 2, + .n_per_out = 3, }, [LAN9374] = { @@ -1846,6 +1866,8 @@ const struct ksz_chip_data ksz_switch_chips[] = { .internal_phy = {true, true, true, true, false, false, true, true}, .ptp_capable = true, + .n_pins = 2, + .n_per_out = 3, }, [LAN9646] = { diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 091cfbdc486f..f1c0e89e13c1 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -139,6 +139,8 @@ struct ksz_chip_data { u8 sgmii_port; const struct regmap_access_table *wr_table; const struct regmap_access_table *rd_table; + const u8 n_pins; + const u8 n_per_out; }; struct ksz_irq { diff --git a/drivers/net/dsa/microchip/ksz_ptp.c b/drivers/net/dsa/microchip/ksz_ptp.c index 39cc70d65900..1c59428b159b 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.c +++ b/drivers/net/dsa/microchip/ksz_ptp.c @@ -26,6 +26,7 @@ */ #define KSZ_MAX_DRIFT_CORR 6249999 #define KSZ_MAX_PULSE_WIDTH 125000000LL +#define KSZ8463_MAX_PULSE_WIDTH 500000LL #define KSZ_PTP_INC_NS 40ULL /* HW clock is incremented every 40 ns (by 40) */ #define KSZ_PTP_SUBNS_BITS 32 @@ -63,6 +64,17 @@ static int ksz_ptp_tou_gpio(struct ksz_device *dev) LED_SRC_PTP_GPIO_1 | LED_SRC_PTP_GPIO_2); } +static int ksz8463_ptp_tou_reset(struct ksz_device *dev, u8 unit) +{ + int ret; + + ret = ksz_rmw16(dev, KSZ8463_TOU_SW_RST, BIT(unit), BIT(unit)); + if (ret) + return ret; + + return ksz_rmw16(dev, KSZ8463_TOU_SW_RST, BIT(unit), 0); +} + static int ksz_ptp_tou_reset(struct ksz_device *dev, u8 unit) { u32 data; @@ -86,7 +98,7 @@ static int ksz_ptp_tou_reset(struct ksz_device *dev, u8 unit) 0); } -static int ksz_ptp_tou_pulse_verify(u64 pulse_ns) +static int ksz_ptp_tou_pulse_verify(u64 pulse_ns, u32 mask) { u32 data; @@ -94,7 +106,7 @@ static int ksz_ptp_tou_pulse_verify(u64 pulse_ns) return -EINVAL; data = (pulse_ns / 8); - if (!FIELD_FIT(TRIG_PULSE_WIDTH_M, data)) + if ((mask & data) != data) return -ERANGE; return 0; @@ -120,6 +132,28 @@ static int ksz_ptp_tou_target_time_set(struct ksz_device *dev, return 0; } +static int ksz8463_ptp_tou_start(struct ksz_device *dev, u8 unit) +{ + u16 data; + int ret; + + ret = ksz_rmw16(dev, KSZ8463_TOU_EN, BIT(unit), BIT(unit)); + if (ret) + return ret; + + ret = ksz_read16(dev, KSZ8463_TOU_ACTIVE, &data); + if (ret) + return ret; + + if (!(data & BIT(unit))) { + dev_err(dev->dev, "%s: Trigger unit%d error!\n", __func__, + unit); + return -EIO; + } + + return 0; +} + static int ksz_ptp_tou_start(struct ksz_device *dev, u8 unit) { u32 data; @@ -147,6 +181,56 @@ static int ksz_ptp_tou_start(struct ksz_device *dev, u8 unit) return 0; } +static int ksz8463_ptp_configure_perout(struct ksz_device *dev, + struct ptp_perout_request const *request, + u32 cycle_width_ns, u32 pulse_width_ns, + u8 index) +{ + struct ptp_pin_desc *pin = &dev->ptp_data.pin_config[index]; + u16 cfg_base = KSZ8463_TRIG1_CFG + KSZ8463_TRIGN_CFG_SIZE * pin->chan; + u16 data; + int ret; + + /* Hardware has only 32 bit for the second field */ + if ((request->start.sec & 0xffffffff) != request->start.sec) + return -EINVAL; + + data = KSZ8463_NOTIFY_BIT | + FIELD_PREP(KSZ8463_PATTERN_M, TRIG_POS_PERIOD) | + pin->index; + ret = ksz_write16(dev, cfg_base + KSZ8463_PATTERN_OFF, data); + if (ret) + return ret; + + ret = ksz_write32(dev, cfg_base + KSZ8463_CYCLE_WIDTH_OFF, + cycle_width_ns); + if (ret) + return ret; + + /* Set cycle count 0 - Infinite */ + ret = ksz_write16(dev, cfg_base + KSZ8463_CYCLE_CNT_OFF, 0); + if (ret) + return ret; + + /* KSZ8463 uses a 8 ns unit value to compute the pulse width */ + data = (pulse_width_ns / 8); + ret = ksz_write16(dev, cfg_base + KSZ8463_PULSE_WIDTH_OFF, data); + if (ret) + return ret; + + ret = ksz_write32(dev, cfg_base + KSZ8463_TARGET_NSEC, + request->start.nsec); + if (ret) + return ret; + + ret = ksz_write32(dev, cfg_base + KSZ8463_TARGET_SEC, + request->start.sec); + if (ret) + return ret; + + return 0; +} + static int ksz_ptp_configure_perout(struct ksz_device *dev, u32 cycle_width_ns, u32 pulse_width_ns, struct timespec64 const *target_time, @@ -183,17 +267,11 @@ static int ksz_ptp_configure_perout(struct ksz_device *dev, return 0; } -static int ksz_ptp_enable_perout(struct ksz_device *dev, - struct ptp_perout_request const *request, - int on) +static int ksz_ptp_get_pin(struct ksz_device *dev, + struct ptp_perout_request const *request) { struct ksz_ptp_data *ptp_data = &dev->ptp_data; - u64 req_pulse_width_ns; - u64 cycle_width_ns; - u64 pulse_width_ns; - int pin = 0; - u32 data32; - int ret; + int pin; if (request->flags & ~PTP_PEROUT_DUTY_CYCLE) return -EOPNOTSUPP; @@ -206,6 +284,119 @@ static int ksz_ptp_enable_perout(struct ksz_device *dev, if (pin < 0) return -EINVAL; + return pin; +} + +static int ksz_ptp_compute_perout_cycle(struct ksz_device *dev, + struct ptp_perout_request const *request, + u64 max_pulse_width, + u64 *cycle_width_ns, + u64 *pulse_width_ns) +{ + struct timespec64 tmp; + + if (request->period.sec < 0) + return -EINVAL; + + if (!request->period.sec && !request->period.nsec) + return -EINVAL; + + tmp.tv_sec = request->period.sec; + tmp.tv_nsec = request->period.nsec; + *cycle_width_ns = timespec64_to_ns(&tmp); + if ((*cycle_width_ns & TRIG_CYCLE_WIDTH_M) != *cycle_width_ns) { + *cycle_width_ns = 0; + *pulse_width_ns = 0; + return -EINVAL; + } + + if (request->flags & PTP_PEROUT_DUTY_CYCLE) { + *pulse_width_ns = request->on.sec * NSEC_PER_SEC + + request->on.nsec; + return 0; + } + + /* Use a duty cycle of 50%. Maximum pulse width supported by the + * hardware is a little bit more than 125 ms. + */ + *pulse_width_ns = (request->period.sec * NSEC_PER_SEC + + request->period.nsec) / 2; + *pulse_width_ns = min_t(u64, *pulse_width_ns, max_pulse_width); + + return 0; +} + +static int ksz8463_ptp_enable_perout(struct ksz_device *dev, + struct ptp_perout_request const *request, + int on) +{ + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + u64 cycle_width_ns; + u64 pulse_width_ns; + int pin; + int ret; + + pin = ksz_ptp_get_pin(dev, request); + if (pin < 0) + return pin; + + ret = ksz8463_ptp_tou_reset(dev, request->index); + if (ret) + return ret; + + if (!on) { + ptp_data->tou_mode = KSZ_PTP_TOU_IDLE; + return 0; + } + + ret = ksz_ptp_compute_perout_cycle(dev, request, + KSZ8463_MAX_PULSE_WIDTH, + &cycle_width_ns, &pulse_width_ns); + if (ret) + return ret; + + ret = ksz_ptp_tou_pulse_verify(pulse_width_ns, + KSZ8463_TRIG_PULSE_WIDTH_M); + if (ret) + return ret; + + ret = ksz8463_ptp_configure_perout(dev, request, + cycle_width_ns, pulse_width_ns, + pin); + if (ret) + return ret; + + ret = ksz_ptp_tou_gpio(dev); + if (ret) + return ret; + + ret = ksz8463_ptp_tou_start(dev, request->index); + if (ret) + return ret; + + memcpy(&ptp_data->perout_request, request, + sizeof(struct ptp_perout_request)); + ptp_data->tou_mode = KSZ_PTP_TOU_PEROUT; + + return 0; +} + +static int ksz_ptp_enable_perout(struct ksz_device *dev, + struct ptp_perout_request const *request, + int on) +{ + struct ksz_ptp_data *ptp_data = &dev->ptp_data; + struct timespec64 tmp; + u64 cycle_width_ns; + u64 pulse_width_ns; + int pin = 0; + u32 data32; + int ret; + + pin = ksz_ptp_get_pin(dev, request); + if (pin < 0) + return pin; + data32 = FIELD_PREP(PTP_GPIO_INDEX, pin) | FIELD_PREP(PTP_TOU_INDEX, request->index); ret = ksz_rmw32(dev, REG_PTP_UNIT_INDEX__4, @@ -222,36 +413,19 @@ static int ksz_ptp_enable_perout(struct ksz_device *dev, return 0; } - ptp_data->perout_target_time_first.tv_sec = request->start.sec; - ptp_data->perout_target_time_first.tv_nsec = request->start.nsec; - - ptp_data->perout_period.tv_sec = request->period.sec; - ptp_data->perout_period.tv_nsec = request->period.nsec; - - cycle_width_ns = timespec64_to_ns(&ptp_data->perout_period); - if ((cycle_width_ns & TRIG_CYCLE_WIDTH_M) != cycle_width_ns) - return -EINVAL; - - if (request->flags & PTP_PEROUT_DUTY_CYCLE) { - pulse_width_ns = request->on.sec * NSEC_PER_SEC + - request->on.nsec; - } else { - /* Use a duty cycle of 50%. Maximum pulse width supported by the - * hardware is a little bit more than 125 ms. - */ - req_pulse_width_ns = (request->period.sec * NSEC_PER_SEC + - request->period.nsec) / 2; - pulse_width_ns = min_t(u64, req_pulse_width_ns, - KSZ_MAX_PULSE_WIDTH); - } - - ret = ksz_ptp_tou_pulse_verify(pulse_width_ns); + ret = ksz_ptp_compute_perout_cycle(dev, request, KSZ_MAX_PULSE_WIDTH, + &cycle_width_ns, &pulse_width_ns); if (ret) return ret; + ret = ksz_ptp_tou_pulse_verify(pulse_width_ns, TRIG_PULSE_WIDTH_M); + if (ret) + return ret; + + tmp.tv_sec = request->start.sec; + tmp.tv_nsec = request->start.nsec; ret = ksz_ptp_configure_perout(dev, cycle_width_ns, pulse_width_ns, - &ptp_data->perout_target_time_first, - pin); + &tmp, pin); if (ret) return ret; @@ -263,6 +437,8 @@ static int ksz_ptp_enable_perout(struct ksz_device *dev, if (ret) return ret; + memcpy(&ptp_data->perout_request, request, + sizeof(struct ptp_perout_request)); ptp_data->tou_mode = KSZ_PTP_TOU_PEROUT; return 0; @@ -756,13 +932,14 @@ static int ksz_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) return ret; } -static int ksz_ptp_restart_perout(struct ksz_device *dev) +static int ksz_ptp_prepare_restart_perout(struct ksz_device *dev, + struct ptp_perout_request *request) { struct ksz_ptp_data *ptp_data = &dev->ptp_data; s64 now_ns, first_ns, period_ns, next_ns; - struct ptp_perout_request request; struct timespec64 next; struct timespec64 now; + struct timespec64 tmp; unsigned int count; int ret; @@ -773,10 +950,14 @@ static int ksz_ptp_restart_perout(struct ksz_device *dev) return ret; now_ns = timespec64_to_ns(&now); - first_ns = timespec64_to_ns(&ptp_data->perout_target_time_first); + tmp.tv_sec = ptp_data->perout_request.start.sec; + tmp.tv_nsec = ptp_data->perout_request.start.nsec; + first_ns = timespec64_to_ns(&tmp); /* Calculate next perout event based on start time and period */ - period_ns = timespec64_to_ns(&ptp_data->perout_period); + tmp.tv_sec = ptp_data->perout_request.period.sec; + tmp.tv_nsec = ptp_data->perout_request.period.nsec; + period_ns = timespec64_to_ns(&tmp); if (first_ns < now_ns) { count = div_u64(now_ns - first_ns, period_ns); @@ -791,40 +972,109 @@ static int ksz_ptp_restart_perout(struct ksz_device *dev) /* Restart periodic output signal */ next = ns_to_timespec64(next_ns); - request.start.sec = next.tv_sec; - request.start.nsec = next.tv_nsec; - request.period.sec = ptp_data->perout_period.tv_sec; - request.period.nsec = ptp_data->perout_period.tv_nsec; - request.index = 0; - request.flags = 0; + memcpy(request, &ptp_data->perout_request, + sizeof(struct ptp_perout_request)); + request->start.sec = next.tv_sec; + request->start.nsec = next.tv_nsec; + + return 0; +} + +static int ksz_ptp_restart_perout(struct ksz_device *dev) +{ + struct ptp_perout_request request; + int ret; + + ret = ksz_ptp_prepare_restart_perout(dev, &request); + if (ret) + return ret; return ksz_ptp_enable_perout(dev, &request, 1); } +static int ksz8463_ptp_restart_perout(struct ksz_device *dev) +{ + struct ptp_perout_request request; + int ret; + + ret = ksz_ptp_prepare_restart_perout(dev, &request); + if (ret) + return ret; + + return ksz8463_ptp_enable_perout(dev, &request, 1); +} + +static int __ksz_ptp_settime(struct ksz_device *dev, + const struct timespec64 *ts) +{ + const u16 *regs = dev->info->regs; + int ret; + + /* Write to shadow registers and Load PTP clock */ + ret = ksz_write16(dev, regs[PTP_RTC_SUB_NANOSEC], PTP_RTC_0NS); + if (ret) + return ret; + + ret = ksz_write32(dev, regs[PTP_RTC_NANOSEC], ts->tv_nsec); + if (ret) + return ret; + + ret = ksz_write32(dev, regs[PTP_RTC_SEC], ts->tv_sec); + if (ret) + return ret; + + ret = ksz_rmw16(dev, regs[PTP_CLK_CTRL], PTP_LOAD_TIME, PTP_LOAD_TIME); + if (ret) + return ret; + + return 0; +} + +static int ksz8463_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); + int ret; + + mutex_lock(&ptp_data->lock); + + ret = __ksz_ptp_settime(dev, ts); + if (ret) + goto unlock; + + switch (ptp_data->tou_mode) { + case KSZ_PTP_TOU_IDLE: + break; + + case KSZ_PTP_TOU_PEROUT: + ret = ksz8463_ptp_restart_perout(dev); + if (ret) + goto unlock; + + break; + } + + spin_lock_bh(&ptp_data->clock_lock); + ptp_data->clock_time = *ts; + spin_unlock_bh(&ptp_data->clock_lock); + +unlock: + mutex_unlock(&ptp_data->lock); + + return ret; +} + static int ksz_ptp_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) { struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); - const u16 *regs = dev->info->regs; int ret; mutex_lock(&ptp_data->lock); - /* Write to shadow registers and Load PTP clock */ - ret = ksz_write16(dev, regs[PTP_RTC_SUB_NANOSEC], PTP_RTC_0NS); - if (ret) - goto unlock; - - ret = ksz_write32(dev, regs[PTP_RTC_NANOSEC], ts->tv_nsec); - if (ret) - goto unlock; - - ret = ksz_write32(dev, regs[PTP_RTC_SEC], ts->tv_sec); - if (ret) - goto unlock; - - ret = ksz_rmw16(dev, regs[PTP_CLK_CTRL], PTP_LOAD_TIME, PTP_LOAD_TIME); + ret = __ksz_ptp_settime(dev, ts); if (ret) goto unlock; @@ -890,18 +1140,13 @@ static int ksz_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) return ret; } -static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +static int __ksz_ptp_adjtime(struct ksz_device *dev, s64 delta) { - struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); - struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); - struct timespec64 delta64 = ns_to_timespec64(delta); const u16 *regs = dev->info->regs; s32 sec, nsec; u16 data16; int ret; - mutex_lock(&ptp_data->lock); - /* do not use ns_to_timespec64(), * both sec and nsec are subtracted by hw */ @@ -909,15 +1154,15 @@ static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) ret = ksz_write32(dev, regs[PTP_RTC_NANOSEC], abs(nsec)); if (ret) - goto unlock; + return ret; ret = ksz_write32(dev, regs[PTP_RTC_SEC], abs(sec)); if (ret) - goto unlock; + return ret; ret = ksz_read16(dev, regs[PTP_CLK_CTRL], &data16); if (ret) - goto unlock; + return ret; data16 |= PTP_STEP_ADJ; @@ -928,6 +1173,56 @@ static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) data16 |= PTP_STEP_DIR; ret = ksz_write16(dev, regs[PTP_CLK_CTRL], data16); + if (ret) + return ret; + + return 0; +} + +static int ksz8463_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); + struct timespec64 delta64 = ns_to_timespec64(delta); + int ret; + + mutex_lock(&ptp_data->lock); + + ret = __ksz_ptp_adjtime(dev, delta); + if (ret) + goto unlock; + + switch (ptp_data->tou_mode) { + case KSZ_PTP_TOU_IDLE: + break; + + case KSZ_PTP_TOU_PEROUT: + ret = ksz8463_ptp_restart_perout(dev); + if (ret) + goto unlock; + + break; + } + + spin_lock_bh(&ptp_data->clock_lock); + ptp_data->clock_time = timespec64_add(ptp_data->clock_time, delta64); + spin_unlock_bh(&ptp_data->clock_lock); + +unlock: + mutex_unlock(&ptp_data->lock); + return ret; +} + +static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); + struct timespec64 delta64 = ns_to_timespec64(delta); + int ret; + + mutex_lock(&ptp_data->lock); + + ret = __ksz_ptp_adjtime(dev, delta); if (ret) goto unlock; @@ -952,6 +1247,26 @@ static int ksz_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) return ret; } +static int ksz8463_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *req, int on) +{ + struct ksz_ptp_data *ptp_data = ptp_caps_to_data(ptp); + struct ksz_device *dev = ptp_data_to_ksz_dev(ptp_data); + int ret; + + switch (req->type) { + case PTP_CLK_REQ_PEROUT: + mutex_lock(&ptp_data->lock); + ret = ksz8463_ptp_enable_perout(dev, &req->perout, on); + mutex_unlock(&ptp_data->lock); + break; + default: + return -EOPNOTSUPP; + } + + return ret; +} + static int ksz_ptp_enable(struct ptp_clock_info *ptp, struct ptp_clock_request *req, int on) { @@ -1028,6 +1343,48 @@ static int ksz_ptp_start_clock(struct ksz_device *dev) return 0; } +void ksz8463_ptp_set_caps(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + struct ksz_ptp_data *ptp_data; + + ptp_data = &dev->ptp_data; + + ptp_data->caps.owner = THIS_MODULE; + snprintf(ptp_data->caps.name, 16, "Microchip Clock"); + ptp_data->caps.max_adj = KSZ_MAX_DRIFT_CORR; + ptp_data->caps.gettime64 = ksz_ptp_gettime; + ptp_data->caps.settime64 = ksz8463_ptp_settime; + ptp_data->caps.adjfine = ksz_ptp_adjfine; + ptp_data->caps.adjtime = ksz8463_ptp_adjtime; + ptp_data->caps.do_aux_work = ksz_ptp_do_aux_work; + ptp_data->caps.enable = ksz8463_ptp_enable; + ptp_data->caps.verify = ksz_ptp_verify_pin; + ptp_data->caps.n_pins = dev->info->n_pins; + ptp_data->caps.n_per_out = dev->info->n_per_out; +} + +void ksz_ptp_set_caps(struct dsa_switch *ds) +{ + struct ksz_device *dev = ds->priv; + struct ksz_ptp_data *ptp_data; + + ptp_data = &dev->ptp_data; + + ptp_data->caps.owner = THIS_MODULE; + snprintf(ptp_data->caps.name, 16, "Microchip Clock"); + ptp_data->caps.max_adj = KSZ_MAX_DRIFT_CORR; + ptp_data->caps.gettime64 = ksz_ptp_gettime; + ptp_data->caps.settime64 = ksz_ptp_settime; + ptp_data->caps.adjfine = ksz_ptp_adjfine; + ptp_data->caps.adjtime = ksz_ptp_adjtime; + ptp_data->caps.do_aux_work = ksz_ptp_do_aux_work; + ptp_data->caps.enable = ksz_ptp_enable; + ptp_data->caps.verify = ksz_ptp_verify_pin; + ptp_data->caps.n_pins = dev->info->n_pins; + ptp_data->caps.n_per_out = dev->info->n_per_out; +} + int ksz_ptp_clock_register(struct dsa_switch *ds) { struct ksz_device *dev = ds->priv; @@ -1040,24 +1397,11 @@ int ksz_ptp_clock_register(struct dsa_switch *ds) mutex_init(&ptp_data->lock); spin_lock_init(&ptp_data->clock_lock); - ptp_data->caps.owner = THIS_MODULE; - snprintf(ptp_data->caps.name, 16, "Microchip Clock"); - ptp_data->caps.max_adj = KSZ_MAX_DRIFT_CORR; - ptp_data->caps.gettime64 = ksz_ptp_gettime; - ptp_data->caps.settime64 = ksz_ptp_settime; - ptp_data->caps.adjfine = ksz_ptp_adjfine; - ptp_data->caps.adjtime = ksz_ptp_adjtime; - ptp_data->caps.do_aux_work = ksz_ptp_do_aux_work; - ptp_data->caps.enable = ksz_ptp_enable; - ptp_data->caps.verify = ksz_ptp_verify_pin; - ptp_data->caps.n_pins = KSZ_PTP_N_GPIO; - ptp_data->caps.n_per_out = 3; - ret = ksz_ptp_start_clock(dev); if (ret) return ret; - for (i = 0; i < KSZ_PTP_N_GPIO; i++) { + for (i = 0; i < dev->info->n_pins; i++) { struct ptp_pin_desc *ptp_pin = &ptp_data->pin_config[i]; snprintf(ptp_pin->name, diff --git a/drivers/net/dsa/microchip/ksz_ptp.h b/drivers/net/dsa/microchip/ksz_ptp.h index 7067ec9bd1e6..22898a22723c 100644 --- a/drivers/net/dsa/microchip/ksz_ptp.h +++ b/drivers/net/dsa/microchip/ksz_ptp.h @@ -12,7 +12,7 @@ #include -#define KSZ_PTP_N_GPIO 2 +#define KSZ_PTP_N_GPIO 12 enum ksz_ptp_tou_mode { KSZ_PTP_TOU_IDLE, @@ -29,10 +29,11 @@ struct ksz_ptp_data { spinlock_t clock_lock; struct timespec64 clock_time; enum ksz_ptp_tou_mode tou_mode; - struct timespec64 perout_target_time_first; /* start of first pulse */ - struct timespec64 perout_period; + struct ptp_perout_request perout_request; }; +void ksz_ptp_set_caps(struct dsa_switch *ds); +void ksz8463_ptp_set_caps(struct dsa_switch *ds); int ksz_ptp_clock_register(struct dsa_switch *ds); void ksz_ptp_clock_unregister(struct dsa_switch *ds); @@ -65,6 +66,8 @@ struct ksz_ptp_data { struct mutex lock; }; +static inline void ksz_ptp_set_caps(struct dsa_switch *ds) { } +static inline void ksz8463_ptp_set_caps(struct dsa_switch *ds) { } static inline int ksz_ptp_clock_register(struct dsa_switch *ds) { return 0; diff --git a/drivers/net/dsa/microchip/ksz_ptp_reg.h b/drivers/net/dsa/microchip/ksz_ptp_reg.h index 65ea8577af75..16f117fa5d49 100644 --- a/drivers/net/dsa/microchip/ksz_ptp_reg.h +++ b/drivers/net/dsa/microchip/ksz_ptp_reg.h @@ -51,6 +51,22 @@ #define REG_PTP_UNIT_INDEX__4 0x0520 +#define KSZ8463_TOU_ACTIVE 0x202 +#define KSZ8463_TOU_EN 0x206 +#define KSZ8463_TOU_SW_RST 0x208 + +#define KSZ8463_TRIGN_CFG_SIZE 0x20 +#define KSZ8463_TRIG1_CFG 0x220 +#define KSZ8463_TARGET_NSEC 0x000 +#define KSZ8463_TARGET_SEC 0x004 +#define KSZ8463_PATTERN_OFF 0x008 +#define KSZ8463_NOTIFY_BIT BIT(8) +#define KSZ8463_PATTERN_M GENMASK(6, 4) +#define KSZ8463_PULSE_WIDTH_OFF 0x00A +#define KSZ8463_TRIG_PULSE_WIDTH_M GENMASK(15, 0) +#define KSZ8463_CYCLE_WIDTH_OFF 0x00C +#define KSZ8463_CYCLE_CNT_OFF 0x010 + #define PTP_GPIO_INDEX GENMASK(19, 16) #define PTP_TSI_INDEX BIT(8) #define PTP_TOU_INDEX GENMASK(1, 0) diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index 86ce3a86705f..3a209122fc7d 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -867,6 +867,7 @@ static int lan937x_setup(struct dsa_switch *ds) } } + ksz_ptp_set_caps(ds); ret = ksz_ptp_clock_register(ds); if (ret) { dev_err(dev->dev, "Failed to register PTP clock: %d\n",