1 // SPDX-License-Identifier: GPL-2.0-only
2 /*******************************************************************************
3 Copyright (C) 2013 Vayavya Labs Pvt Ltd
5 This implements all the API for managing HW timestamp & PTP.
8 Author: Rayagond Kokatanur <rayagond@vayavyalabs.com>
9 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
10 *******************************************************************************/
13 #include <linux/iopoll.h>
14 #include <linux/delay.h>
16 #include "stmmac_ptp.h"
18 static void config_hw_tstamping(void __iomem
*ioaddr
, u32 data
)
20 writel(data
, ioaddr
+ PTP_TCR
);
23 static void config_sub_second_increment(void __iomem
*ioaddr
,
24 u32 ptp_clock
, int gmac4
, u32
*ssinc
)
26 u32 value
= readl(ioaddr
+ PTP_TCR
);
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.
38 if (value
& PTP_TCR_TSCFUPDT
)
39 data
= (2000000000ULL / ptp_clock
);
41 data
= (1000000000ULL / ptp_clock
);
43 /* 0.465ns accuracy */
44 if (!(value
& PTP_TCR_TSCTRLSSR
))
45 data
= (data
* 1000) / 465;
47 data
&= PTP_SSIR_SSINC_MASK
;
51 reg_value
<<= GMAC4_PTP_SSIR_SSINC_SHIFT
;
53 writel(reg_value
, ioaddr
+ PTP_SSIR
);
59 static int init_systime(void __iomem
*ioaddr
, u32 sec
, u32 nsec
)
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
);
70 /* wait for present system time initialize to complete */
71 return readl_poll_timeout(ioaddr
+ PTP_TCR
, value
,
72 !(value
& PTP_TCR_TSINIT
),
76 static int config_addend(void __iomem
*ioaddr
, u32 addend
)
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
);
87 /* wait for present addend update to complete */
90 if (!(readl(ioaddr
+ PTP_TCR
) & PTP_TCR_TSADDREG
))
100 static int adjust_systime(void __iomem
*ioaddr
, u32 sec
, u32 nsec
,
101 int add_sub
, int gmac4
)
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>)
114 value
= readl(ioaddr
+ PTP_TCR
);
115 if (value
& PTP_TCR_TSCTRLSSR
)
116 nsec
= (PTP_DIGITAL_ROLLOVER_MODE
- nsec
);
118 nsec
= (PTP_BINARY_ROLLOVER_MODE
- nsec
);
121 writel(sec
, ioaddr
+ PTP_STSUR
);
122 value
= (add_sub
<< PTP_STNSUR_ADDSUB_SHIFT
) | nsec
;
123 writel(value
, ioaddr
+ PTP_STNSUR
);
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
);
130 /* wait for present system time adjust/update to complete */
133 if (!(readl(ioaddr
+ PTP_TCR
) & PTP_TCR_TSUPDT
))
143 static void get_systime(void __iomem
*ioaddr
, u64
*systime
)
147 /* Get the TSSS value */
148 ns
= readl(ioaddr
+ PTP_STNSR
);
149 /* Get the TSS and convert sec time value to nanosecond */
150 ns
+= readl(ioaddr
+ PTP_STSR
) * 1000000000ULL;
156 const struct stmmac_hwtimestamp stmmac_ptp
= {
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
,