Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only 2 : : /******************************************************************************* 3 : : Copyright (C) 2013 Vayavya Labs Pvt Ltd 4 : : 5 : : This implements all the API for managing HW timestamp & PTP. 6 : : 7 : : 8 : : Author: Rayagond Kokatanur <rayagond@vayavyalabs.com> 9 : : Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> 10 : : *******************************************************************************/ 11 : : 12 : : #include <linux/io.h> 13 : : #include <linux/delay.h> 14 : : #include "common.h" 15 : : #include "stmmac_ptp.h" 16 : : 17 : 0 : static void config_hw_tstamping(void __iomem *ioaddr, u32 data) 18 : : { 19 : 0 : writel(data, ioaddr + PTP_TCR); 20 : 0 : } 21 : : 22 : 0 : static void config_sub_second_increment(void __iomem *ioaddr, 23 : : u32 ptp_clock, int gmac4, u32 *ssinc) 24 : : { 25 : 0 : u32 value = readl(ioaddr + PTP_TCR); 26 : 0 : unsigned long data; 27 : 0 : u32 reg_value; 28 : : 29 : : /* For GMAC3.x, 4.x versions, convert the ptp_clock to nano second 30 : : * formula = (1/ptp_clock) * 1000000000 31 : : * where ptp_clock is 50MHz if fine method is used to update system 32 : : */ 33 [ # # ]: 0 : if (value & PTP_TCR_TSCFUPDT) 34 : : data = (1000000000ULL / 50000000); 35 : : else 36 : 0 : data = (1000000000ULL / ptp_clock); 37 : : 38 : : /* 0.465ns accuracy */ 39 [ # # ]: 0 : if (!(value & PTP_TCR_TSCTRLSSR)) 40 : 0 : data = (data * 1000) / 465; 41 : : 42 : 0 : data &= PTP_SSIR_SSINC_MASK; 43 : : 44 : 0 : reg_value = data; 45 [ # # ]: 0 : if (gmac4) 46 : 0 : reg_value <<= GMAC4_PTP_SSIR_SSINC_SHIFT; 47 : : 48 : 0 : writel(reg_value, ioaddr + PTP_SSIR); 49 : : 50 [ # # ]: 0 : if (ssinc) 51 : 0 : *ssinc = data; 52 : 0 : } 53 : : 54 : 0 : static int init_systime(void __iomem *ioaddr, u32 sec, u32 nsec) 55 : : { 56 : 0 : int limit; 57 : 0 : u32 value; 58 : : 59 : 0 : writel(sec, ioaddr + PTP_STSUR); 60 : 0 : writel(nsec, ioaddr + PTP_STNSUR); 61 : : /* issue command to initialize the system time value */ 62 : 0 : value = readl(ioaddr + PTP_TCR); 63 : 0 : value |= PTP_TCR_TSINIT; 64 : 0 : writel(value, ioaddr + PTP_TCR); 65 : : 66 : : /* wait for present system time initialize to complete */ 67 : : limit = 10; 68 [ # # ]: 0 : while (limit--) { 69 [ # # ]: 0 : if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSINIT)) 70 : : break; 71 [ # # ]: 0 : mdelay(10); 72 : : } 73 [ # # ]: 0 : if (limit < 0) 74 : 0 : return -EBUSY; 75 : : 76 : : return 0; 77 : : } 78 : : 79 : 0 : static int config_addend(void __iomem *ioaddr, u32 addend) 80 : : { 81 : 0 : u32 value; 82 : 0 : int limit; 83 : : 84 : 0 : writel(addend, ioaddr + PTP_TAR); 85 : : /* issue command to update the addend value */ 86 : 0 : value = readl(ioaddr + PTP_TCR); 87 : 0 : value |= PTP_TCR_TSADDREG; 88 : 0 : writel(value, ioaddr + PTP_TCR); 89 : : 90 : : /* wait for present addend update to complete */ 91 : 0 : limit = 10; 92 [ # # ]: 0 : while (limit--) { 93 [ # # ]: 0 : if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG)) 94 : : break; 95 [ # # ]: 0 : mdelay(10); 96 : : } 97 [ # # ]: 0 : if (limit < 0) 98 : 0 : return -EBUSY; 99 : : 100 : : return 0; 101 : : } 102 : : 103 : 0 : static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec, 104 : : int add_sub, int gmac4) 105 : : { 106 : 0 : u32 value; 107 : 0 : int limit; 108 : : 109 [ # # ]: 0 : if (add_sub) { 110 : : /* If the new sec value needs to be subtracted with 111 : : * the system time, then MAC_STSUR reg should be 112 : : * programmed with (2^32 – <new_sec_value>) 113 : : */ 114 [ # # ]: 0 : if (gmac4) 115 : 0 : sec = -sec; 116 : : 117 : 0 : value = readl(ioaddr + PTP_TCR); 118 [ # # ]: 0 : if (value & PTP_TCR_TSCTRLSSR) 119 : 0 : nsec = (PTP_DIGITAL_ROLLOVER_MODE - nsec); 120 : : else 121 : 0 : nsec = (PTP_BINARY_ROLLOVER_MODE - nsec); 122 : : } 123 : : 124 : 0 : writel(sec, ioaddr + PTP_STSUR); 125 : 0 : value = (add_sub << PTP_STNSUR_ADDSUB_SHIFT) | nsec; 126 : 0 : writel(value, ioaddr + PTP_STNSUR); 127 : : 128 : : /* issue command to initialize the system time value */ 129 : 0 : value = readl(ioaddr + PTP_TCR); 130 : 0 : value |= PTP_TCR_TSUPDT; 131 : 0 : writel(value, ioaddr + PTP_TCR); 132 : : 133 : : /* wait for present system time adjust/update to complete */ 134 : 0 : limit = 10; 135 [ # # ]: 0 : while (limit--) { 136 [ # # ]: 0 : if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT)) 137 : : break; 138 [ # # ]: 0 : mdelay(10); 139 : : } 140 [ # # ]: 0 : if (limit < 0) 141 : 0 : return -EBUSY; 142 : : 143 : : return 0; 144 : : } 145 : : 146 : 0 : static void get_systime(void __iomem *ioaddr, u64 *systime) 147 : : { 148 : 0 : u64 ns; 149 : : 150 : : /* Get the TSSS value */ 151 : 0 : ns = readl(ioaddr + PTP_STNSR); 152 : : /* Get the TSS and convert sec time value to nanosecond */ 153 : 0 : ns += readl(ioaddr + PTP_STSR) * 1000000000ULL; 154 : : 155 [ # # ]: 0 : if (systime) 156 : 0 : *systime = ns; 157 : 0 : } 158 : : 159 : : const struct stmmac_hwtimestamp stmmac_ptp = { 160 : : .config_hw_tstamping = config_hw_tstamping, 161 : : .init_systime = init_systime, 162 : : .config_sub_second_increment = config_sub_second_increment, 163 : : .config_addend = config_addend, 164 : : .adjust_systime = adjust_systime, 165 : : .get_systime = get_systime, 166 : : };