1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-3-Clause) 2 /* 3 * Copyright (c) 2014-2025, Advanced Micro Devices, Inc. 4 * Copyright (c) 2014, Synopsys, Inc. 5 * All rights reserved 6 */ 7 8 #include <linux/clk.h> 9 #include <linux/clocksource.h> 10 #include <linux/ptp_clock_kernel.h> 11 #include <linux/net_tstamp.h> 12 13 #include "xgbe.h" 14 #include "xgbe-common.h" 15 16 static u64 xgbe_cc_read(const struct cyclecounter *cc) 17 { 18 struct xgbe_prv_data *pdata = container_of(cc, 19 struct xgbe_prv_data, 20 tstamp_cc); 21 u64 nsec; 22 23 nsec = pdata->hw_if.get_tstamp_time(pdata); 24 25 return nsec; 26 } 27 28 static int xgbe_adjfine(struct ptp_clock_info *info, long scaled_ppm) 29 { 30 struct xgbe_prv_data *pdata = container_of(info, 31 struct xgbe_prv_data, 32 ptp_clock_info); 33 unsigned long flags; 34 u64 addend; 35 36 addend = adjust_by_scaled_ppm(pdata->tstamp_addend, scaled_ppm); 37 38 spin_lock_irqsave(&pdata->tstamp_lock, flags); 39 40 pdata->hw_if.update_tstamp_addend(pdata, addend); 41 42 spin_unlock_irqrestore(&pdata->tstamp_lock, flags); 43 44 return 0; 45 } 46 47 static int xgbe_adjtime(struct ptp_clock_info *info, s64 delta) 48 { 49 struct xgbe_prv_data *pdata = container_of(info, 50 struct xgbe_prv_data, 51 ptp_clock_info); 52 unsigned long flags; 53 54 spin_lock_irqsave(&pdata->tstamp_lock, flags); 55 timecounter_adjtime(&pdata->tstamp_tc, delta); 56 spin_unlock_irqrestore(&pdata->tstamp_lock, flags); 57 58 return 0; 59 } 60 61 static int xgbe_gettime(struct ptp_clock_info *info, struct timespec64 *ts) 62 { 63 struct xgbe_prv_data *pdata = container_of(info, 64 struct xgbe_prv_data, 65 ptp_clock_info); 66 unsigned long flags; 67 u64 nsec; 68 69 spin_lock_irqsave(&pdata->tstamp_lock, flags); 70 71 nsec = timecounter_read(&pdata->tstamp_tc); 72 73 spin_unlock_irqrestore(&pdata->tstamp_lock, flags); 74 75 *ts = ns_to_timespec64(nsec); 76 77 return 0; 78 } 79 80 static int xgbe_settime(struct ptp_clock_info *info, 81 const struct timespec64 *ts) 82 { 83 struct xgbe_prv_data *pdata = container_of(info, 84 struct xgbe_prv_data, 85 ptp_clock_info); 86 unsigned long flags; 87 u64 nsec; 88 89 nsec = timespec64_to_ns(ts); 90 91 spin_lock_irqsave(&pdata->tstamp_lock, flags); 92 93 timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec); 94 95 spin_unlock_irqrestore(&pdata->tstamp_lock, flags); 96 97 return 0; 98 } 99 100 static int xgbe_enable(struct ptp_clock_info *info, 101 struct ptp_clock_request *request, int on) 102 { 103 return -EOPNOTSUPP; 104 } 105 106 void xgbe_ptp_register(struct xgbe_prv_data *pdata) 107 { 108 struct ptp_clock_info *info = &pdata->ptp_clock_info; 109 struct ptp_clock *clock; 110 struct cyclecounter *cc = &pdata->tstamp_cc; 111 u64 dividend; 112 113 snprintf(info->name, sizeof(info->name), "%s", 114 netdev_name(pdata->netdev)); 115 info->owner = THIS_MODULE; 116 info->max_adj = pdata->ptpclk_rate; 117 info->adjfine = xgbe_adjfine; 118 info->adjtime = xgbe_adjtime; 119 info->gettime64 = xgbe_gettime; 120 info->settime64 = xgbe_settime; 121 info->enable = xgbe_enable; 122 123 clock = ptp_clock_register(info, pdata->dev); 124 if (IS_ERR(clock)) { 125 dev_err(pdata->dev, "ptp_clock_register failed\n"); 126 return; 127 } 128 129 pdata->ptp_clock = clock; 130 131 /* Calculate the addend: 132 * addend = 2^32 / (PTP ref clock / 50Mhz) 133 * = (2^32 * 50Mhz) / PTP ref clock 134 */ 135 dividend = 50000000; 136 dividend <<= 32; 137 pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate); 138 139 /* Setup the timecounter */ 140 cc->read = xgbe_cc_read; 141 cc->mask = CLOCKSOURCE_MASK(64); 142 cc->mult = 1; 143 cc->shift = 0; 144 145 timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, 146 ktime_to_ns(ktime_get_real())); 147 148 /* Disable all timestamping to start */ 149 XGMAC_IOWRITE(pdata, MAC_TSCR, 0); 150 pdata->tstamp_config.tx_type = HWTSTAMP_TX_OFF; 151 pdata->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; 152 } 153 154 void xgbe_ptp_unregister(struct xgbe_prv_data *pdata) 155 { 156 if (pdata->ptp_clock) 157 ptp_clock_unregister(pdata->ptp_clock); 158 } 159