10933bd04SHoratiu Vultur // SPDX-License-Identifier: GPL-2.0+ 20933bd04SHoratiu Vultur /* Microchip Sparx5 Switch driver 30933bd04SHoratiu Vultur * 40933bd04SHoratiu Vultur * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries. 50933bd04SHoratiu Vultur * 60933bd04SHoratiu Vultur * The Sparx5 Chip Register Model can be browsed at this location: 70933bd04SHoratiu Vultur * https://github.com/microchip-ung/sparx-5_reginfo 80933bd04SHoratiu Vultur */ 90933bd04SHoratiu Vultur #include <linux/ptp_classify.h> 100933bd04SHoratiu Vultur 110933bd04SHoratiu Vultur #include "sparx5_main_regs.h" 120933bd04SHoratiu Vultur #include "sparx5_main.h" 130933bd04SHoratiu Vultur 140933bd04SHoratiu Vultur #define SPARX5_MAX_PTP_ID 512 150933bd04SHoratiu Vultur 160933bd04SHoratiu Vultur #define TOD_ACC_PIN 0x4 170933bd04SHoratiu Vultur 180933bd04SHoratiu Vultur enum { 190933bd04SHoratiu Vultur PTP_PIN_ACTION_IDLE = 0, 200933bd04SHoratiu Vultur PTP_PIN_ACTION_LOAD, 210933bd04SHoratiu Vultur PTP_PIN_ACTION_SAVE, 220933bd04SHoratiu Vultur PTP_PIN_ACTION_CLOCK, 230933bd04SHoratiu Vultur PTP_PIN_ACTION_DELTA, 240933bd04SHoratiu Vultur PTP_PIN_ACTION_TOD 250933bd04SHoratiu Vultur }; 260933bd04SHoratiu Vultur 270933bd04SHoratiu Vultur static u64 sparx5_ptp_get_1ppm(struct sparx5 *sparx5) 280933bd04SHoratiu Vultur { 290933bd04SHoratiu Vultur /* Represents 1ppm adjustment in 2^59 format with 1.59687500000(625) 300933bd04SHoratiu Vultur * 1.99609375000(500), 3.99218750000(250) as reference 310933bd04SHoratiu Vultur * The value is calculated as following: 320933bd04SHoratiu Vultur * (1/1000000)/((2^-59)/X) 330933bd04SHoratiu Vultur */ 340933bd04SHoratiu Vultur 350933bd04SHoratiu Vultur u64 res; 360933bd04SHoratiu Vultur 370933bd04SHoratiu Vultur switch (sparx5->coreclock) { 380933bd04SHoratiu Vultur case SPX5_CORE_CLOCK_250MHZ: 390933bd04SHoratiu Vultur res = 2301339409586; 400933bd04SHoratiu Vultur break; 410933bd04SHoratiu Vultur case SPX5_CORE_CLOCK_500MHZ: 420933bd04SHoratiu Vultur res = 1150669704793; 430933bd04SHoratiu Vultur break; 440933bd04SHoratiu Vultur case SPX5_CORE_CLOCK_625MHZ: 450933bd04SHoratiu Vultur res = 920535763834; 460933bd04SHoratiu Vultur break; 470933bd04SHoratiu Vultur default: 480933bd04SHoratiu Vultur WARN_ON("Invalid core clock"); 490933bd04SHoratiu Vultur break; 500933bd04SHoratiu Vultur } 510933bd04SHoratiu Vultur 520933bd04SHoratiu Vultur return res; 530933bd04SHoratiu Vultur } 540933bd04SHoratiu Vultur 550933bd04SHoratiu Vultur static u64 sparx5_ptp_get_nominal_value(struct sparx5 *sparx5) 560933bd04SHoratiu Vultur { 570933bd04SHoratiu Vultur u64 res; 580933bd04SHoratiu Vultur 590933bd04SHoratiu Vultur switch (sparx5->coreclock) { 600933bd04SHoratiu Vultur case SPX5_CORE_CLOCK_250MHZ: 610933bd04SHoratiu Vultur res = 0x1FF0000000000000; 620933bd04SHoratiu Vultur break; 630933bd04SHoratiu Vultur case SPX5_CORE_CLOCK_500MHZ: 640933bd04SHoratiu Vultur res = 0x0FF8000000000000; 650933bd04SHoratiu Vultur break; 660933bd04SHoratiu Vultur case SPX5_CORE_CLOCK_625MHZ: 670933bd04SHoratiu Vultur res = 0x0CC6666666666666; 680933bd04SHoratiu Vultur break; 690933bd04SHoratiu Vultur default: 700933bd04SHoratiu Vultur WARN_ON("Invalid core clock"); 710933bd04SHoratiu Vultur break; 720933bd04SHoratiu Vultur } 730933bd04SHoratiu Vultur 740933bd04SHoratiu Vultur return res; 750933bd04SHoratiu Vultur } 760933bd04SHoratiu Vultur 77*589a07b8SHoratiu Vultur int sparx5_ptp_hwtstamp_set(struct sparx5_port *port, struct ifreq *ifr) 78*589a07b8SHoratiu Vultur { 79*589a07b8SHoratiu Vultur struct sparx5 *sparx5 = port->sparx5; 80*589a07b8SHoratiu Vultur struct hwtstamp_config cfg; 81*589a07b8SHoratiu Vultur struct sparx5_phc *phc; 82*589a07b8SHoratiu Vultur 83*589a07b8SHoratiu Vultur /* For now don't allow to run ptp on ports that are part of a bridge, 84*589a07b8SHoratiu Vultur * because in case of transparent clock the HW will still forward the 85*589a07b8SHoratiu Vultur * frames, so there would be duplicate frames 86*589a07b8SHoratiu Vultur */ 87*589a07b8SHoratiu Vultur 88*589a07b8SHoratiu Vultur if (test_bit(port->portno, sparx5->bridge_mask)) 89*589a07b8SHoratiu Vultur return -EINVAL; 90*589a07b8SHoratiu Vultur 91*589a07b8SHoratiu Vultur if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) 92*589a07b8SHoratiu Vultur return -EFAULT; 93*589a07b8SHoratiu Vultur 94*589a07b8SHoratiu Vultur switch (cfg.tx_type) { 95*589a07b8SHoratiu Vultur case HWTSTAMP_TX_ON: 96*589a07b8SHoratiu Vultur port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; 97*589a07b8SHoratiu Vultur break; 98*589a07b8SHoratiu Vultur case HWTSTAMP_TX_ONESTEP_SYNC: 99*589a07b8SHoratiu Vultur port->ptp_cmd = IFH_REW_OP_ONE_STEP_PTP; 100*589a07b8SHoratiu Vultur break; 101*589a07b8SHoratiu Vultur case HWTSTAMP_TX_OFF: 102*589a07b8SHoratiu Vultur port->ptp_cmd = IFH_REW_OP_NOOP; 103*589a07b8SHoratiu Vultur break; 104*589a07b8SHoratiu Vultur default: 105*589a07b8SHoratiu Vultur return -ERANGE; 106*589a07b8SHoratiu Vultur } 107*589a07b8SHoratiu Vultur 108*589a07b8SHoratiu Vultur switch (cfg.rx_filter) { 109*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_NONE: 110*589a07b8SHoratiu Vultur break; 111*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_ALL: 112*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 113*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 114*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 115*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 116*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 117*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 118*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 119*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 120*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 121*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V2_EVENT: 122*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V2_SYNC: 123*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 124*589a07b8SHoratiu Vultur case HWTSTAMP_FILTER_NTP_ALL: 125*589a07b8SHoratiu Vultur cfg.rx_filter = HWTSTAMP_FILTER_ALL; 126*589a07b8SHoratiu Vultur break; 127*589a07b8SHoratiu Vultur default: 128*589a07b8SHoratiu Vultur return -ERANGE; 129*589a07b8SHoratiu Vultur } 130*589a07b8SHoratiu Vultur 131*589a07b8SHoratiu Vultur /* Commit back the result & save it */ 132*589a07b8SHoratiu Vultur mutex_lock(&sparx5->ptp_lock); 133*589a07b8SHoratiu Vultur phc = &sparx5->phc[SPARX5_PHC_PORT]; 134*589a07b8SHoratiu Vultur memcpy(&phc->hwtstamp_config, &cfg, sizeof(cfg)); 135*589a07b8SHoratiu Vultur mutex_unlock(&sparx5->ptp_lock); 136*589a07b8SHoratiu Vultur 137*589a07b8SHoratiu Vultur return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; 138*589a07b8SHoratiu Vultur } 139*589a07b8SHoratiu Vultur 140*589a07b8SHoratiu Vultur int sparx5_ptp_hwtstamp_get(struct sparx5_port *port, struct ifreq *ifr) 141*589a07b8SHoratiu Vultur { 142*589a07b8SHoratiu Vultur struct sparx5 *sparx5 = port->sparx5; 143*589a07b8SHoratiu Vultur struct sparx5_phc *phc; 144*589a07b8SHoratiu Vultur 145*589a07b8SHoratiu Vultur phc = &sparx5->phc[SPARX5_PHC_PORT]; 146*589a07b8SHoratiu Vultur return copy_to_user(ifr->ifr_data, &phc->hwtstamp_config, 147*589a07b8SHoratiu Vultur sizeof(phc->hwtstamp_config)) ? -EFAULT : 0; 148*589a07b8SHoratiu Vultur } 149*589a07b8SHoratiu Vultur 1500933bd04SHoratiu Vultur static int sparx5_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) 1510933bd04SHoratiu Vultur { 1520933bd04SHoratiu Vultur struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info); 1530933bd04SHoratiu Vultur struct sparx5 *sparx5 = phc->sparx5; 1540933bd04SHoratiu Vultur unsigned long flags; 1550933bd04SHoratiu Vultur bool neg_adj = 0; 1560933bd04SHoratiu Vultur u64 tod_inc; 1570933bd04SHoratiu Vultur u64 ref; 1580933bd04SHoratiu Vultur 1590933bd04SHoratiu Vultur if (!scaled_ppm) 1600933bd04SHoratiu Vultur return 0; 1610933bd04SHoratiu Vultur 1620933bd04SHoratiu Vultur if (scaled_ppm < 0) { 1630933bd04SHoratiu Vultur neg_adj = 1; 1640933bd04SHoratiu Vultur scaled_ppm = -scaled_ppm; 1650933bd04SHoratiu Vultur } 1660933bd04SHoratiu Vultur 1670933bd04SHoratiu Vultur tod_inc = sparx5_ptp_get_nominal_value(sparx5); 1680933bd04SHoratiu Vultur 1690933bd04SHoratiu Vultur /* The multiplication is split in 2 separate additions because of 1700933bd04SHoratiu Vultur * overflow issues. If scaled_ppm with 16bit fractional part was bigger 1710933bd04SHoratiu Vultur * than 20ppm then we got overflow. 1720933bd04SHoratiu Vultur */ 1730933bd04SHoratiu Vultur ref = sparx5_ptp_get_1ppm(sparx5) * (scaled_ppm >> 16); 1740933bd04SHoratiu Vultur ref += (sparx5_ptp_get_1ppm(sparx5) * (0xffff & scaled_ppm)) >> 16; 1750933bd04SHoratiu Vultur tod_inc = neg_adj ? tod_inc - ref : tod_inc + ref; 1760933bd04SHoratiu Vultur 1770933bd04SHoratiu Vultur spin_lock_irqsave(&sparx5->ptp_clock_lock, flags); 1780933bd04SHoratiu Vultur 1790933bd04SHoratiu Vultur spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(1 << BIT(phc->index)), 1800933bd04SHoratiu Vultur PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS, 1810933bd04SHoratiu Vultur sparx5, PTP_PTP_DOM_CFG); 1820933bd04SHoratiu Vultur 1830933bd04SHoratiu Vultur spx5_wr((u32)tod_inc & 0xFFFFFFFF, sparx5, 1840933bd04SHoratiu Vultur PTP_CLK_PER_CFG(phc->index, 0)); 1850933bd04SHoratiu Vultur spx5_wr((u32)(tod_inc >> 32), sparx5, 1860933bd04SHoratiu Vultur PTP_CLK_PER_CFG(phc->index, 1)); 1870933bd04SHoratiu Vultur 1880933bd04SHoratiu Vultur spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(0), 1890933bd04SHoratiu Vultur PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS, sparx5, 1900933bd04SHoratiu Vultur PTP_PTP_DOM_CFG); 1910933bd04SHoratiu Vultur 1920933bd04SHoratiu Vultur spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); 1930933bd04SHoratiu Vultur 1940933bd04SHoratiu Vultur return 0; 1950933bd04SHoratiu Vultur } 1960933bd04SHoratiu Vultur 1970933bd04SHoratiu Vultur static int sparx5_ptp_settime64(struct ptp_clock_info *ptp, 1980933bd04SHoratiu Vultur const struct timespec64 *ts) 1990933bd04SHoratiu Vultur { 2000933bd04SHoratiu Vultur struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info); 2010933bd04SHoratiu Vultur struct sparx5 *sparx5 = phc->sparx5; 2020933bd04SHoratiu Vultur unsigned long flags; 2030933bd04SHoratiu Vultur 2040933bd04SHoratiu Vultur spin_lock_irqsave(&sparx5->ptp_clock_lock, flags); 2050933bd04SHoratiu Vultur 2060933bd04SHoratiu Vultur /* Must be in IDLE mode before the time can be loaded */ 2070933bd04SHoratiu Vultur spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_IDLE) | 2080933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) | 2090933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0), 2100933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_ACTION | 2110933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_DOM | 2120933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_SYNC, 2130933bd04SHoratiu Vultur sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); 2140933bd04SHoratiu Vultur 2150933bd04SHoratiu Vultur /* Set new value */ 2160933bd04SHoratiu Vultur spx5_wr(PTP_PTP_TOD_SEC_MSB_PTP_TOD_SEC_MSB_SET(upper_32_bits(ts->tv_sec)), 2170933bd04SHoratiu Vultur sparx5, PTP_PTP_TOD_SEC_MSB(TOD_ACC_PIN)); 2180933bd04SHoratiu Vultur spx5_wr(lower_32_bits(ts->tv_sec), 2190933bd04SHoratiu Vultur sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN)); 2200933bd04SHoratiu Vultur spx5_wr(ts->tv_nsec, sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN)); 2210933bd04SHoratiu Vultur 2220933bd04SHoratiu Vultur /* Apply new values */ 2230933bd04SHoratiu Vultur spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_LOAD) | 2240933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) | 2250933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0), 2260933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_ACTION | 2270933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_DOM | 2280933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_SYNC, 2290933bd04SHoratiu Vultur sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); 2300933bd04SHoratiu Vultur 2310933bd04SHoratiu Vultur spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); 2320933bd04SHoratiu Vultur 2330933bd04SHoratiu Vultur return 0; 2340933bd04SHoratiu Vultur } 2350933bd04SHoratiu Vultur 2360933bd04SHoratiu Vultur static int sparx5_ptp_gettime64(struct ptp_clock_info *ptp, 2370933bd04SHoratiu Vultur struct timespec64 *ts) 2380933bd04SHoratiu Vultur { 2390933bd04SHoratiu Vultur struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info); 2400933bd04SHoratiu Vultur struct sparx5 *sparx5 = phc->sparx5; 2410933bd04SHoratiu Vultur unsigned long flags; 2420933bd04SHoratiu Vultur time64_t s; 2430933bd04SHoratiu Vultur s64 ns; 2440933bd04SHoratiu Vultur 2450933bd04SHoratiu Vultur spin_lock_irqsave(&sparx5->ptp_clock_lock, flags); 2460933bd04SHoratiu Vultur 2470933bd04SHoratiu Vultur spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_SAVE) | 2480933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) | 2490933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0), 2500933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_ACTION | 2510933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_DOM | 2520933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_SYNC, 2530933bd04SHoratiu Vultur sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); 2540933bd04SHoratiu Vultur 2550933bd04SHoratiu Vultur s = spx5_rd(sparx5, PTP_PTP_TOD_SEC_MSB(TOD_ACC_PIN)); 2560933bd04SHoratiu Vultur s <<= 32; 2570933bd04SHoratiu Vultur s |= spx5_rd(sparx5, PTP_PTP_TOD_SEC_LSB(TOD_ACC_PIN)); 2580933bd04SHoratiu Vultur ns = spx5_rd(sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN)); 2590933bd04SHoratiu Vultur ns &= PTP_PTP_TOD_NSEC_PTP_TOD_NSEC; 2600933bd04SHoratiu Vultur 2610933bd04SHoratiu Vultur spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); 2620933bd04SHoratiu Vultur 2630933bd04SHoratiu Vultur /* Deal with negative values */ 2640933bd04SHoratiu Vultur if ((ns & 0xFFFFFFF0) == 0x3FFFFFF0) { 2650933bd04SHoratiu Vultur s--; 2660933bd04SHoratiu Vultur ns &= 0xf; 2670933bd04SHoratiu Vultur ns += 999999984; 2680933bd04SHoratiu Vultur } 2690933bd04SHoratiu Vultur 2700933bd04SHoratiu Vultur set_normalized_timespec64(ts, s, ns); 2710933bd04SHoratiu Vultur return 0; 2720933bd04SHoratiu Vultur } 2730933bd04SHoratiu Vultur 2740933bd04SHoratiu Vultur static int sparx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) 2750933bd04SHoratiu Vultur { 2760933bd04SHoratiu Vultur struct sparx5_phc *phc = container_of(ptp, struct sparx5_phc, info); 2770933bd04SHoratiu Vultur struct sparx5 *sparx5 = phc->sparx5; 2780933bd04SHoratiu Vultur 2790933bd04SHoratiu Vultur if (delta > -(NSEC_PER_SEC / 2) && delta < (NSEC_PER_SEC / 2)) { 2800933bd04SHoratiu Vultur unsigned long flags; 2810933bd04SHoratiu Vultur 2820933bd04SHoratiu Vultur spin_lock_irqsave(&sparx5->ptp_clock_lock, flags); 2830933bd04SHoratiu Vultur 2840933bd04SHoratiu Vultur /* Must be in IDLE mode before the time can be loaded */ 2850933bd04SHoratiu Vultur spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_IDLE) | 2860933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) | 2870933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0), 2880933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_ACTION | 2890933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_DOM | 2900933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_SYNC, 2910933bd04SHoratiu Vultur sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); 2920933bd04SHoratiu Vultur 2930933bd04SHoratiu Vultur spx5_wr(PTP_PTP_TOD_NSEC_PTP_TOD_NSEC_SET(delta), 2940933bd04SHoratiu Vultur sparx5, PTP_PTP_TOD_NSEC(TOD_ACC_PIN)); 2950933bd04SHoratiu Vultur 2960933bd04SHoratiu Vultur /* Adjust time with the value of PTP_TOD_NSEC */ 2970933bd04SHoratiu Vultur spx5_rmw(PTP_PTP_PIN_CFG_PTP_PIN_ACTION_SET(PTP_PIN_ACTION_DELTA) | 2980933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_DOM_SET(phc->index) | 2990933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_SYNC_SET(0), 3000933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_ACTION | 3010933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_DOM | 3020933bd04SHoratiu Vultur PTP_PTP_PIN_CFG_PTP_PIN_SYNC, 3030933bd04SHoratiu Vultur sparx5, PTP_PTP_PIN_CFG(TOD_ACC_PIN)); 3040933bd04SHoratiu Vultur 3050933bd04SHoratiu Vultur spin_unlock_irqrestore(&sparx5->ptp_clock_lock, flags); 3060933bd04SHoratiu Vultur } else { 3070933bd04SHoratiu Vultur /* Fall back using sparx5_ptp_settime64 which is not exact */ 3080933bd04SHoratiu Vultur struct timespec64 ts; 3090933bd04SHoratiu Vultur u64 now; 3100933bd04SHoratiu Vultur 3110933bd04SHoratiu Vultur sparx5_ptp_gettime64(ptp, &ts); 3120933bd04SHoratiu Vultur 3130933bd04SHoratiu Vultur now = ktime_to_ns(timespec64_to_ktime(ts)); 3140933bd04SHoratiu Vultur ts = ns_to_timespec64(now + delta); 3150933bd04SHoratiu Vultur 3160933bd04SHoratiu Vultur sparx5_ptp_settime64(ptp, &ts); 3170933bd04SHoratiu Vultur } 3180933bd04SHoratiu Vultur 3190933bd04SHoratiu Vultur return 0; 3200933bd04SHoratiu Vultur } 3210933bd04SHoratiu Vultur 3220933bd04SHoratiu Vultur static struct ptp_clock_info sparx5_ptp_clock_info = { 3230933bd04SHoratiu Vultur .owner = THIS_MODULE, 3240933bd04SHoratiu Vultur .name = "sparx5 ptp", 3250933bd04SHoratiu Vultur .max_adj = 200000, 3260933bd04SHoratiu Vultur .gettime64 = sparx5_ptp_gettime64, 3270933bd04SHoratiu Vultur .settime64 = sparx5_ptp_settime64, 3280933bd04SHoratiu Vultur .adjtime = sparx5_ptp_adjtime, 3290933bd04SHoratiu Vultur .adjfine = sparx5_ptp_adjfine, 3300933bd04SHoratiu Vultur }; 3310933bd04SHoratiu Vultur 3320933bd04SHoratiu Vultur static int sparx5_ptp_phc_init(struct sparx5 *sparx5, 3330933bd04SHoratiu Vultur int index, 3340933bd04SHoratiu Vultur struct ptp_clock_info *clock_info) 3350933bd04SHoratiu Vultur { 3360933bd04SHoratiu Vultur struct sparx5_phc *phc = &sparx5->phc[index]; 3370933bd04SHoratiu Vultur 3380933bd04SHoratiu Vultur phc->info = *clock_info; 3390933bd04SHoratiu Vultur phc->clock = ptp_clock_register(&phc->info, sparx5->dev); 3400933bd04SHoratiu Vultur if (IS_ERR(phc->clock)) 3410933bd04SHoratiu Vultur return PTR_ERR(phc->clock); 3420933bd04SHoratiu Vultur 3430933bd04SHoratiu Vultur phc->index = index; 3440933bd04SHoratiu Vultur phc->sparx5 = sparx5; 3450933bd04SHoratiu Vultur 3460933bd04SHoratiu Vultur /* PTP Rx stamping is always enabled. */ 3470933bd04SHoratiu Vultur phc->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; 3480933bd04SHoratiu Vultur 3490933bd04SHoratiu Vultur return 0; 3500933bd04SHoratiu Vultur } 3510933bd04SHoratiu Vultur 3520933bd04SHoratiu Vultur int sparx5_ptp_init(struct sparx5 *sparx5) 3530933bd04SHoratiu Vultur { 3540933bd04SHoratiu Vultur u64 tod_adj = sparx5_ptp_get_nominal_value(sparx5); 3550933bd04SHoratiu Vultur int err, i; 3560933bd04SHoratiu Vultur 3570933bd04SHoratiu Vultur if (!sparx5->ptp) 3580933bd04SHoratiu Vultur return 0; 3590933bd04SHoratiu Vultur 3600933bd04SHoratiu Vultur for (i = 0; i < SPARX5_PHC_COUNT; ++i) { 3610933bd04SHoratiu Vultur err = sparx5_ptp_phc_init(sparx5, i, &sparx5_ptp_clock_info); 3620933bd04SHoratiu Vultur if (err) 3630933bd04SHoratiu Vultur return err; 3640933bd04SHoratiu Vultur } 3650933bd04SHoratiu Vultur 3660933bd04SHoratiu Vultur spin_lock_init(&sparx5->ptp_clock_lock); 367*589a07b8SHoratiu Vultur mutex_init(&sparx5->ptp_lock); 3680933bd04SHoratiu Vultur 3690933bd04SHoratiu Vultur /* Disable master counters */ 3700933bd04SHoratiu Vultur spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0), sparx5, PTP_PTP_DOM_CFG); 3710933bd04SHoratiu Vultur 3720933bd04SHoratiu Vultur /* Configure the nominal TOD increment per clock cycle */ 3730933bd04SHoratiu Vultur spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(0x7), 3740933bd04SHoratiu Vultur PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS, 3750933bd04SHoratiu Vultur sparx5, PTP_PTP_DOM_CFG); 3760933bd04SHoratiu Vultur 3770933bd04SHoratiu Vultur for (i = 0; i < SPARX5_PHC_COUNT; ++i) { 3780933bd04SHoratiu Vultur spx5_wr((u32)tod_adj & 0xFFFFFFFF, sparx5, 3790933bd04SHoratiu Vultur PTP_CLK_PER_CFG(i, 0)); 3800933bd04SHoratiu Vultur spx5_wr((u32)(tod_adj >> 32), sparx5, 3810933bd04SHoratiu Vultur PTP_CLK_PER_CFG(i, 1)); 3820933bd04SHoratiu Vultur } 3830933bd04SHoratiu Vultur 3840933bd04SHoratiu Vultur spx5_rmw(PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS_SET(0), 3850933bd04SHoratiu Vultur PTP_PTP_DOM_CFG_PTP_CLKCFG_DIS, 3860933bd04SHoratiu Vultur sparx5, PTP_PTP_DOM_CFG); 3870933bd04SHoratiu Vultur 3880933bd04SHoratiu Vultur /* Enable master counters */ 3890933bd04SHoratiu Vultur spx5_wr(PTP_PTP_DOM_CFG_PTP_ENA_SET(0x7), sparx5, PTP_PTP_DOM_CFG); 3900933bd04SHoratiu Vultur 3910933bd04SHoratiu Vultur return 0; 3920933bd04SHoratiu Vultur } 3930933bd04SHoratiu Vultur 3940933bd04SHoratiu Vultur void sparx5_ptp_deinit(struct sparx5 *sparx5) 3950933bd04SHoratiu Vultur { 3960933bd04SHoratiu Vultur int i; 3970933bd04SHoratiu Vultur 3980933bd04SHoratiu Vultur for (i = 0; i < SPARX5_PHC_COUNT; ++i) 3990933bd04SHoratiu Vultur ptp_clock_unregister(sparx5->phc[i].clock); 4000933bd04SHoratiu Vultur } 401