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