diff options
Diffstat (limited to 'drivers/net/dsa/mv88e6xxx/ptp.c')
| -rw-r--r-- | drivers/net/dsa/mv88e6xxx/ptp.c | 195 |
1 files changed, 98 insertions, 97 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c index 56391e09b325..f7603573d3a9 100644 --- a/drivers/net/dsa/mv88e6xxx/ptp.c +++ b/drivers/net/dsa/mv88e6xxx/ptp.c @@ -18,6 +18,13 @@ #define MV88E6XXX_MAX_ADJ_PPB 1000000 +struct mv88e6xxx_cc_coeffs { + u32 cc_shift; + u32 cc_mult; + u32 cc_mult_num; + u32 cc_mult_dem; +}; + /* Family MV88E6250: * Raw timestamps are in units of 10-ns clock periods. * @@ -25,22 +32,43 @@ * simplifies to * clkadj = scaled_ppm * 2^7 / 5^5 */ -#define MV88E6250_CC_SHIFT 28 -#define MV88E6250_CC_MULT (10 << MV88E6250_CC_SHIFT) -#define MV88E6250_CC_MULT_NUM (1 << 7) -#define MV88E6250_CC_MULT_DEM 3125ULL +#define MV88E6XXX_CC_10NS_SHIFT 28 +static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_10ns_coeffs = { + .cc_shift = MV88E6XXX_CC_10NS_SHIFT, + .cc_mult = 10 << MV88E6XXX_CC_10NS_SHIFT, + .cc_mult_num = 1 << 7, + .cc_mult_dem = 3125ULL, +}; -/* Other families: +/* Other families except MV88E6393X in internal clock mode: * Raw timestamps are in units of 8-ns clock periods. * * clkadj = scaled_ppm * 8*2^28 / (10^6 * 2^16) * simplifies to * clkadj = scaled_ppm * 2^9 / 5^6 */ -#define MV88E6XXX_CC_SHIFT 28 -#define MV88E6XXX_CC_MULT (8 << MV88E6XXX_CC_SHIFT) -#define MV88E6XXX_CC_MULT_NUM (1 << 9) -#define MV88E6XXX_CC_MULT_DEM 15625ULL +#define MV88E6XXX_CC_8NS_SHIFT 28 +static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_8ns_coeffs = { + .cc_shift = MV88E6XXX_CC_8NS_SHIFT, + .cc_mult = 8 << MV88E6XXX_CC_8NS_SHIFT, + .cc_mult_num = 1 << 9, + .cc_mult_dem = 15625ULL +}; + +/* Family MV88E6393X using internal clock: + * Raw timestamps are in units of 4-ns clock periods. + * + * clkadj = scaled_ppm * 4*2^28 / (10^6 * 2^16) + * simplifies to + * clkadj = scaled_ppm * 2^8 / 5^6 + */ +#define MV88E6XXX_CC_4NS_SHIFT 28 +static const struct mv88e6xxx_cc_coeffs mv88e6xxx_cc_4ns_coeffs = { + .cc_shift = MV88E6XXX_CC_4NS_SHIFT, + .cc_mult = 4 << MV88E6XXX_CC_4NS_SHIFT, + .cc_mult_num = 1 << 8, + .cc_mult_dem = 15625ULL +}; #define TAI_EVENT_WORK_INTERVAL msecs_to_jiffies(100) @@ -83,13 +111,40 @@ static int mv88e6352_set_gpio_func(struct mv88e6xxx_chip *chip, int pin, return chip->info->ops->gpio_ops->set_pctl(chip, pin, func); } -static u64 mv88e6352_ptp_clock_read(const struct cyclecounter *cc) +static const struct mv88e6xxx_cc_coeffs * +mv88e6xxx_cc_coeff_get(struct mv88e6xxx_chip *chip) +{ + u16 period_ps; + int err; + + err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_CLOCK_PERIOD, &period_ps, 1); + if (err) { + dev_err(chip->dev, "failed to read cycle counter period: %d\n", + err); + return ERR_PTR(err); + } + + switch (period_ps) { + case 4000: + return &mv88e6xxx_cc_4ns_coeffs; + case 8000: + return &mv88e6xxx_cc_8ns_coeffs; + case 10000: + return &mv88e6xxx_cc_10ns_coeffs; + default: + dev_err(chip->dev, "unexpected cycle counter period of %u ps\n", + period_ps); + return ERR_PTR(-ENODEV); + } +} + +static u64 mv88e6352_ptp_clock_read(struct cyclecounter *cc) { struct mv88e6xxx_chip *chip = cc_to_chip(cc); u16 phc_time[2]; int err; - err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_TIME_LO, phc_time, + err = mv88e6xxx_tai_read(chip, MV88E6352_TAI_TIME_LO, phc_time, ARRAY_SIZE(phc_time)); if (err) return 0; @@ -97,13 +152,13 @@ static u64 mv88e6352_ptp_clock_read(const struct cyclecounter *cc) return ((u32)phc_time[1] << 16) | phc_time[0]; } -static u64 mv88e6165_ptp_clock_read(const struct cyclecounter *cc) +static u64 mv88e6165_ptp_clock_read(struct cyclecounter *cc) { struct mv88e6xxx_chip *chip = cc_to_chip(cc); u16 phc_time[2]; int err; - err = mv88e6xxx_tai_read(chip, MV88E6XXX_PTP_GC_TIME_LO, phc_time, + err = mv88e6xxx_tai_read(chip, MV88E6165_PTP_GC_TIME_LO, phc_time, ARRAY_SIZE(phc_time)); if (err) return 0; @@ -112,42 +167,26 @@ static u64 mv88e6165_ptp_clock_read(const struct cyclecounter *cc) } /* mv88e6352_config_eventcap - configure TAI event capture - * @event: PTP_CLOCK_PPS (internal) or PTP_CLOCK_EXTTS (external) * @rising: zero for falling-edge trigger, else rising-edge trigger * * This will also reset the capture sequence counter. */ -static int mv88e6352_config_eventcap(struct mv88e6xxx_chip *chip, int event, - int rising) +static int mv88e6352_config_eventcap(struct mv88e6xxx_chip *chip, int rising) { - u16 global_config; - u16 cap_config; + u16 evcap_config; int err; - chip->evcap_config = MV88E6XXX_TAI_CFG_CAP_OVERWRITE | - MV88E6XXX_TAI_CFG_CAP_CTR_START; + evcap_config = MV88E6352_TAI_CFG_CAP_OVERWRITE | + MV88E6352_TAI_CFG_CAP_CTR_START; if (!rising) - chip->evcap_config |= MV88E6XXX_TAI_CFG_EVREQ_FALLING; + evcap_config |= MV88E6352_TAI_CFG_EVREQ_FALLING; - global_config = (chip->evcap_config | chip->trig_config); - err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_CFG, global_config); + err = mv88e6xxx_tai_write(chip, MV88E6352_TAI_CFG, evcap_config); if (err) return err; - if (event == PTP_CLOCK_PPS) { - cap_config = MV88E6XXX_TAI_EVENT_STATUS_CAP_TRIG; - } else if (event == PTP_CLOCK_EXTTS) { - /* if STATUS_CAP_TRIG is unset we capture PTP_EVREQ events */ - cap_config = 0; - } else { - return -EINVAL; - } - /* Write the capture config; this also clears the capture counter */ - err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_EVENT_STATUS, - cap_config); - - return err; + return mv88e6xxx_tai_write(chip, MV88E6352_TAI_EVENT_STATUS, 0); } static void mv88e6352_tai_event_work(struct work_struct *ugly) @@ -160,7 +199,7 @@ static void mv88e6352_tai_event_work(struct work_struct *ugly) int err; mv88e6xxx_reg_lock(chip); - err = mv88e6xxx_tai_read(chip, MV88E6XXX_TAI_EVENT_STATUS, + err = mv88e6xxx_tai_read(chip, MV88E6352_TAI_EVENT_STATUS, status, ARRAY_SIZE(status)); mv88e6xxx_reg_unlock(chip); @@ -168,19 +207,19 @@ static void mv88e6352_tai_event_work(struct work_struct *ugly) dev_err(chip->dev, "failed to read TAI status register\n"); return; } - if (status[0] & MV88E6XXX_TAI_EVENT_STATUS_ERROR) { + if (status[0] & MV88E6352_TAI_EVENT_STATUS_ERROR) { dev_warn(chip->dev, "missed event capture\n"); return; } - if (!(status[0] & MV88E6XXX_TAI_EVENT_STATUS_VALID)) + if (!(status[0] & MV88E6352_TAI_EVENT_STATUS_VALID)) goto out; raw_ts = ((u32)status[2] << 16) | status[1]; /* Clear the valid bit so the next timestamp can come in */ - status[0] &= ~MV88E6XXX_TAI_EVENT_STATUS_VALID; + status[0] &= ~MV88E6352_TAI_EVENT_STATUS_VALID; mv88e6xxx_reg_lock(chip); - err = mv88e6xxx_tai_write(chip, MV88E6XXX_TAI_EVENT_STATUS, status[0]); + err = mv88e6xxx_tai_write(chip, MV88E6352_TAI_EVENT_STATUS, status[0]); mv88e6xxx_reg_unlock(chip); if (err) { dev_err(chip->dev, "failed to write TAI status register\n"); @@ -204,7 +243,6 @@ out: static int mv88e6xxx_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct mv88e6xxx_chip *chip = ptp_to_chip(ptp); - const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops; int neg_adj = 0; u32 diff, mult; u64 adj; @@ -214,10 +252,10 @@ static int mv88e6xxx_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) scaled_ppm = -scaled_ppm; } - mult = ptp_ops->cc_mult; - adj = ptp_ops->cc_mult_num; + mult = chip->cc_coeffs->cc_mult; + adj = chip->cc_coeffs->cc_mult_num; adj *= scaled_ppm; - diff = div_u64(adj, ptp_ops->cc_mult_dem); + diff = div_u64(adj, chip->cc_coeffs->cc_mult_dem); mv88e6xxx_reg_lock(chip); @@ -278,13 +316,6 @@ static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip, int pin; int err; - /* Reject requests with unsupported flags */ - if (rq->extts.flags & ~(PTP_ENABLE_FEATURE | - PTP_RISING_EDGE | - PTP_FALLING_EDGE | - PTP_STRICT_FLAGS)) - return -EOPNOTSUPP; - /* Reject requests to enable time stamping on both edges. */ if ((rq->extts.flags & PTP_STRICT_FLAGS) && (rq->extts.flags & PTP_ENABLE_FEATURE) && @@ -308,7 +339,7 @@ static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip, schedule_delayed_work(&chip->tai_event_work, TAI_EVENT_WORK_INTERVAL); - err = mv88e6352_config_eventcap(chip, PTP_CLOCK_EXTTS, rising); + err = mv88e6352_config_eventcap(chip, rising); } else { func = MV88E6352_G2_SCRATCH_GPIO_PCTL_GPIO; @@ -364,37 +395,6 @@ const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = { (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ), - .cc_shift = MV88E6XXX_CC_SHIFT, - .cc_mult = MV88E6XXX_CC_MULT, - .cc_mult_num = MV88E6XXX_CC_MULT_NUM, - .cc_mult_dem = MV88E6XXX_CC_MULT_DEM, -}; - -const struct mv88e6xxx_ptp_ops mv88e6250_ptp_ops = { - .clock_read = mv88e6352_ptp_clock_read, - .ptp_enable = mv88e6352_ptp_enable, - .ptp_verify = mv88e6352_ptp_verify, - .event_work = mv88e6352_tai_event_work, - .port_enable = mv88e6352_hwtstamp_port_enable, - .port_disable = mv88e6352_hwtstamp_port_disable, - .n_ext_ts = 1, - .arr0_sts_reg = MV88E6XXX_PORT_PTP_ARR0_STS, - .arr1_sts_reg = MV88E6XXX_PORT_PTP_ARR1_STS, - .dep_sts_reg = MV88E6XXX_PORT_PTP_DEP_STS, - .rx_filters = (1 << HWTSTAMP_FILTER_NONE) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ), - .cc_shift = MV88E6250_CC_SHIFT, - .cc_mult = MV88E6250_CC_MULT, - .cc_mult_num = MV88E6250_CC_MULT_NUM, - .cc_mult_dem = MV88E6250_CC_MULT_DEM, }; const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = { @@ -418,10 +418,6 @@ const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = { (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ), - .cc_shift = MV88E6XXX_CC_SHIFT, - .cc_mult = MV88E6XXX_CC_MULT, - .cc_mult_num = MV88E6XXX_CC_MULT_NUM, - .cc_mult_dem = MV88E6XXX_CC_MULT_DEM, }; const struct mv88e6xxx_ptp_ops mv88e6390_ptp_ops = { @@ -446,13 +442,9 @@ const struct mv88e6xxx_ptp_ops mv88e6390_ptp_ops = { (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ), - .cc_shift = MV88E6XXX_CC_SHIFT, - .cc_mult = MV88E6XXX_CC_MULT, - .cc_mult_num = MV88E6XXX_CC_MULT_NUM, - .cc_mult_dem = MV88E6XXX_CC_MULT_DEM, }; -static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc) +static u64 mv88e6xxx_ptp_clock_read(struct cyclecounter *cc) { struct mv88e6xxx_chip *chip = cc_to_chip(cc); @@ -462,10 +454,10 @@ static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc) return 0; } -/* With a 125MHz input clock, the 32-bit timestamp counter overflows in ~34.3 +/* With a 250MHz input clock, the 32-bit timestamp counter overflows in ~17.2 * seconds; this task forces periodic reads so that we don't miss any. */ -#define MV88E6XXX_TAI_OVERFLOW_PERIOD (HZ * 16) +#define MV88E6XXX_TAI_OVERFLOW_PERIOD (HZ * 8) static void mv88e6xxx_ptp_overflow_check(struct work_struct *work) { struct delayed_work *dw = to_delayed_work(work); @@ -484,11 +476,15 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip) int i; /* Set up the cycle counter */ + chip->cc_coeffs = mv88e6xxx_cc_coeff_get(chip); + if (IS_ERR(chip->cc_coeffs)) + return PTR_ERR(chip->cc_coeffs); + memset(&chip->tstamp_cc, 0, sizeof(chip->tstamp_cc)); chip->tstamp_cc.read = mv88e6xxx_ptp_clock_read; chip->tstamp_cc.mask = CYCLECOUNTER_MASK(32); - chip->tstamp_cc.mult = ptp_ops->cc_mult; - chip->tstamp_cc.shift = ptp_ops->cc_shift; + chip->tstamp_cc.mult = chip->cc_coeffs->cc_mult; + chip->tstamp_cc.shift = chip->cc_coeffs->cc_shift; timecounter_init(&chip->tstamp_tc, &chip->tstamp_cc, ktime_to_ns(ktime_get_real())); @@ -524,6 +520,10 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip) chip->ptp_clock_info.verify = ptp_ops->ptp_verify; chip->ptp_clock_info.do_aux_work = mv88e6xxx_hwtstamp_work; + chip->ptp_clock_info.supported_extts_flags = PTP_RISING_EDGE | + PTP_FALLING_EDGE | + PTP_STRICT_FLAGS; + if (ptp_ops->set_ptp_cpu_port) { struct dsa_port *dp; int upstream = 0; @@ -551,6 +551,7 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip) return 0; } +/* This must never be called holding the register lock */ void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip) { if (chip->ptp_clock) { |
