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