6161#define FEC_T_INC_CORR_MASK 0x00007f00
6262#define FEC_T_INC_CORR_OFFSET 8
6363
64+ #define FEC_T_CTRL_PINPER 0x00000080
65+ #define FEC_T_TF0_MASK 0x00000001
66+ #define FEC_T_TF0_OFFSET 0
67+ #define FEC_T_TF1_MASK 0x00000002
68+ #define FEC_T_TF1_OFFSET 1
69+ #define FEC_T_TF2_MASK 0x00000004
70+ #define FEC_T_TF2_OFFSET 2
71+ #define FEC_T_TF3_MASK 0x00000008
72+ #define FEC_T_TF3_OFFSET 3
73+ #define FEC_T_TDRE_MASK 0x00000001
74+ #define FEC_T_TDRE_OFFSET 0
75+ #define FEC_T_TMODE_MASK 0x0000003C
76+ #define FEC_T_TMODE_OFFSET 2
77+ #define FEC_T_TIE_MASK 0x00000040
78+ #define FEC_T_TIE_OFFSET 6
79+ #define FEC_T_TF_MASK 0x00000080
80+ #define FEC_T_TF_OFFSET 7
81+
6482#define FEC_ATIME_CTRL 0x400
6583#define FEC_ATIME 0x404
6684#define FEC_ATIME_EVT_OFFSET 0x408
6987#define FEC_ATIME_INC 0x414
7088#define FEC_TS_TIMESTAMP 0x418
7189
90+ #define FEC_TGSR 0x604
91+ #define FEC_TCSR (n ) (0x608 + n * 0x08)
92+ #define FEC_TCCR (n ) (0x60C + n * 0x08)
93+ #define MAX_TIMER_CHANNEL 3
94+ #define FEC_TMODE_TOGGLE 0x05
95+ #define FEC_HIGH_PULSE 0x0F
96+
7297#define FEC_CC_MULT (1 << 31)
7398#define FEC_COUNTER_PERIOD (1 << 31)
99+ #define PPS_OUPUT_RELOAD_PERIOD NSEC_PER_SEC
100+ #define FEC_CHANNLE_0 0
101+ #define DEFAULT_PPS_CHANNEL FEC_CHANNLE_0
102+
103+ /**
104+ * fec_ptp_enable_pps
105+ * @fep: the fec_enet_private structure handle
106+ * @enable: enable the channel pps output
107+ *
108+ * This function enble the PPS ouput on the timer channel.
109+ */
110+ static int fec_ptp_enable_pps (struct fec_enet_private * fep , uint enable )
111+ {
112+ unsigned long flags ;
113+ u32 val , tempval ;
114+ int inc ;
115+ struct timespec ts ;
116+ u64 ns ;
117+ u32 remainder ;
118+ val = 0 ;
119+
120+ if (!(fep -> hwts_tx_en || fep -> hwts_rx_en )) {
121+ dev_err (& fep -> pdev -> dev , "No ptp stack is running\n" );
122+ return - EINVAL ;
123+ }
124+
125+ if (fep -> pps_enable == enable )
126+ return 0 ;
127+
128+ fep -> pps_channel = DEFAULT_PPS_CHANNEL ;
129+ fep -> reload_period = PPS_OUPUT_RELOAD_PERIOD ;
130+ inc = fep -> ptp_inc ;
131+
132+ spin_lock_irqsave (& fep -> tmreg_lock , flags );
133+
134+ if (enable ) {
135+ /* clear capture or output compare interrupt status if have.
136+ */
137+ writel (FEC_T_TF_MASK , fep -> hwp + FEC_TCSR (fep -> pps_channel ));
138+
139+ /* It is recommended to doulbe check the TMODE field in the
140+ * TCSR register to be cleared before the first compare counter
141+ * is written into TCCR register. Just add a double check.
142+ */
143+ val = readl (fep -> hwp + FEC_TCSR (fep -> pps_channel ));
144+ do {
145+ val &= ~(FEC_T_TMODE_MASK );
146+ writel (val , fep -> hwp + FEC_TCSR (fep -> pps_channel ));
147+ val = readl (fep -> hwp + FEC_TCSR (fep -> pps_channel ));
148+ } while (val & FEC_T_TMODE_MASK );
149+
150+ /* Dummy read counter to update the counter */
151+ timecounter_read (& fep -> tc );
152+ /* We want to find the first compare event in the next
153+ * second point. So we need to know what the ptp time
154+ * is now and how many nanoseconds is ahead to get next second.
155+ * The remaining nanosecond ahead before the next second would be
156+ * NSEC_PER_SEC - ts.tv_nsec. Add the remaining nanoseconds
157+ * to current timer would be next second.
158+ */
159+ tempval = readl (fep -> hwp + FEC_ATIME_CTRL );
160+ tempval |= FEC_T_CTRL_CAPTURE ;
161+ writel (tempval , fep -> hwp + FEC_ATIME_CTRL );
162+
163+ tempval = readl (fep -> hwp + FEC_ATIME );
164+ /* Convert the ptp local counter to 1588 timestamp */
165+ ns = timecounter_cyc2time (& fep -> tc , tempval );
166+ ts .tv_sec = div_u64_rem (ns , 1000000000ULL , & remainder );
167+ ts .tv_nsec = remainder ;
168+
169+ /* The tempval is less than 3 seconds, and so val is less than
170+ * 4 seconds. No overflow for 32bit calculation.
171+ */
172+ val = NSEC_PER_SEC - (u32 )ts .tv_nsec + tempval ;
173+
174+ /* Need to consider the situation that the current time is
175+ * very close to the second point, which means NSEC_PER_SEC
176+ * - ts.tv_nsec is close to be zero(For example 20ns); Since the timer
177+ * is still running when we calculate the first compare event, it is
178+ * possible that the remaining nanoseonds run out before the compare
179+ * counter is calculated and written into TCCR register. To avoid
180+ * this possibility, we will set the compare event to be the next
181+ * of next second. The current setting is 31-bit timer and wrap
182+ * around over 2 seconds. So it is okay to set the next of next
183+ * seond for the timer.
184+ */
185+ val += NSEC_PER_SEC ;
186+
187+ /* We add (2 * NSEC_PER_SEC - (u32)ts.tv_nsec) to current
188+ * ptp counter, which maybe cause 32-bit wrap. Since the
189+ * (NSEC_PER_SEC - (u32)ts.tv_nsec) is less than 2 second.
190+ * We can ensure the wrap will not cause issue. If the offset
191+ * is bigger than fep->cc.mask would be a error.
192+ */
193+ val &= fep -> cc .mask ;
194+ writel (val , fep -> hwp + FEC_TCCR (fep -> pps_channel ));
195+
196+ /* Calculate the second the compare event timestamp */
197+ fep -> next_counter = (val + fep -> reload_period ) & fep -> cc .mask ;
198+
199+ /* * Enable compare event when overflow */
200+ val = readl (fep -> hwp + FEC_ATIME_CTRL );
201+ val |= FEC_T_CTRL_PINPER ;
202+ writel (val , fep -> hwp + FEC_ATIME_CTRL );
203+
204+ /* Compare channel setting. */
205+ val = readl (fep -> hwp + FEC_TCSR (fep -> pps_channel ));
206+ val |= (1 << FEC_T_TF_OFFSET | 1 << FEC_T_TIE_OFFSET );
207+ val &= ~(1 << FEC_T_TDRE_OFFSET );
208+ val &= ~(FEC_T_TMODE_MASK );
209+ val |= (FEC_HIGH_PULSE << FEC_T_TMODE_OFFSET );
210+ writel (val , fep -> hwp + FEC_TCSR (fep -> pps_channel ));
211+
212+ /* Write the second compare event timestamp and calculate
213+ * the third timestamp. Refer the TCCR register detail in the spec.
214+ */
215+ writel (fep -> next_counter , fep -> hwp + FEC_TCCR (fep -> pps_channel ));
216+ fep -> next_counter = (fep -> next_counter + fep -> reload_period ) & fep -> cc .mask ;
217+ } else {
218+ writel (0 , fep -> hwp + FEC_TCSR (fep -> pps_channel ));
219+ }
220+
221+ fep -> pps_enable = enable ;
222+ spin_unlock_irqrestore (& fep -> tmreg_lock , flags );
223+
224+ return 0 ;
225+ }
226+
74227/**
75228 * fec_ptp_read - read raw cycle counter (to be used by time counter)
76229 * @cc: the cyclecounter structure
@@ -314,6 +467,15 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
314467static int fec_ptp_enable (struct ptp_clock_info * ptp ,
315468 struct ptp_clock_request * rq , int on )
316469{
470+ struct fec_enet_private * fep =
471+ container_of (ptp , struct fec_enet_private , ptp_caps );
472+ int ret = 0 ;
473+
474+ if (rq -> type == PTP_CLK_REQ_PPS ) {
475+ ret = fec_ptp_enable_pps (fep , on );
476+
477+ return ret ;
478+ }
317479 return - EOPNOTSUPP ;
318480}
319481
@@ -428,7 +590,7 @@ void fec_ptp_init(struct platform_device *pdev)
428590 fep -> ptp_caps .n_ext_ts = 0 ;
429591 fep -> ptp_caps .n_per_out = 0 ;
430592 fep -> ptp_caps .n_pins = 0 ;
431- fep -> ptp_caps .pps = 0 ;
593+ fep -> ptp_caps .pps = 1 ;
432594 fep -> ptp_caps .adjfreq = fec_ptp_adjfreq ;
433595 fep -> ptp_caps .adjtime = fec_ptp_adjtime ;
434596 fep -> ptp_caps .gettime = fec_ptp_gettime ;
@@ -452,3 +614,36 @@ void fec_ptp_init(struct platform_device *pdev)
452614
453615 schedule_delayed_work (& fep -> time_keep , HZ );
454616}
617+
618+ /**
619+ * fec_ptp_check_pps_event
620+ * @fep: the fec_enet_private structure handle
621+ *
622+ * This function check the pps event and reload the timer compare counter.
623+ */
624+ uint fec_ptp_check_pps_event (struct fec_enet_private * fep )
625+ {
626+ u32 val ;
627+ u8 channel = fep -> pps_channel ;
628+ struct ptp_clock_event event ;
629+
630+ val = readl (fep -> hwp + FEC_TCSR (channel ));
631+ if (val & FEC_T_TF_MASK ) {
632+ /* Write the next next compare(not the next according the spec)
633+ * value to the register
634+ */
635+ writel (fep -> next_counter , fep -> hwp + FEC_TCCR (channel ));
636+ do {
637+ writel (val , fep -> hwp + FEC_TCSR (channel ));
638+ } while (readl (fep -> hwp + FEC_TCSR (channel )) & FEC_T_TF_MASK );
639+
640+ /* Update the counter; */
641+ fep -> next_counter = (fep -> next_counter + fep -> reload_period ) & fep -> cc .mask ;
642+
643+ event .type = PTP_CLOCK_PPS ;
644+ ptp_clock_event (fep -> ptp_clock , & event );
645+ return 1 ;
646+ }
647+
648+ return 0 ;
649+ }
0 commit comments