aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-10-14 14:45:17 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-14 14:45:17 -0400
commitf787d6c8dd52ded9874cbbc447a32515c80fa2bf (patch)
tree57cb9578e7e20ab6700a715e67834d08b399a11a
parent02ea80741a25435123e8a5ca40cac6a0bcf0c9f1 (diff)
parent278d24047891a1bf4a98128eaa8ecafd019e58c2 (diff)
Merge branch 'fec-ptp'
Luwei Zhou says: ==================== Enable FEC pps feather Change from v2 to v3: -Using the default channel 0 to be PPS channel not PTP_PIN_SET/GETFUNC interface. -Using the linux definition of NSEC_PER_SEC. Change from v1 to v2: - Fix the potential 32-bit multiplication overflow issue. - Optimize the hareware adjustment code to improve efficiency as Richard suggested - Use ptp PTP_PIN_SET/GETFUNC interface to set PPS channel not device tree and add PTP_PF_PPS enumeration - Modify comments style ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/freescale/fec.h10
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c2
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c272
3 files changed, 267 insertions, 17 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 1d5e1822bb2c..1e65917a9381 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -484,12 +484,22 @@ struct fec_enet_private {
484 unsigned int itr_clk_rate; 484 unsigned int itr_clk_rate;
485 485
486 u32 rx_copybreak; 486 u32 rx_copybreak;
487
488 /* ptp clock period in ns*/
489 unsigned int ptp_inc;
490
491 /* pps */
492 int pps_channel;
493 unsigned int reload_period;
494 int pps_enable;
495 unsigned int next_counter;
487}; 496};
488 497
489void fec_ptp_init(struct platform_device *pdev); 498void fec_ptp_init(struct platform_device *pdev);
490void fec_ptp_start_cyclecounter(struct net_device *ndev); 499void fec_ptp_start_cyclecounter(struct net_device *ndev);
491int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr); 500int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
492int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr); 501int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
502uint fec_ptp_check_pps_event(struct fec_enet_private *fep);
493 503
494/****************************************************************************/ 504/****************************************************************************/
495#endif /* FEC_H */ 505#endif /* FEC_H */
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 7a8209e73199..e364d1fc7bdc 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -1622,6 +1622,8 @@ fec_enet_interrupt(int irq, void *dev_id)
1622 complete(&fep->mdio_done); 1622 complete(&fep->mdio_done);
1623 } 1623 }
1624 1624
1625 fec_ptp_check_pps_event(fep);
1626
1625 return ret; 1627 return ret;
1626} 1628}
1627 1629
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index cca3617a2321..0fdcdc9ea028 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -61,6 +61,24 @@
61#define FEC_T_INC_CORR_MASK 0x00007f00 61#define FEC_T_INC_CORR_MASK 0x00007f00
62#define FEC_T_INC_CORR_OFFSET 8 62#define FEC_T_INC_CORR_OFFSET 8
63 63
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
64#define FEC_ATIME_CTRL 0x400 82#define FEC_ATIME_CTRL 0x400
65#define FEC_ATIME 0x404 83#define FEC_ATIME 0x404
66#define FEC_ATIME_EVT_OFFSET 0x408 84#define FEC_ATIME_EVT_OFFSET 0x408
@@ -69,7 +87,143 @@
69#define FEC_ATIME_INC 0x414 87#define FEC_ATIME_INC 0x414
70#define FEC_TS_TIMESTAMP 0x418 88#define FEC_TS_TIMESTAMP 0x418
71 89
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
72#define FEC_CC_MULT (1 << 31) 97#define FEC_CC_MULT (1 << 31)
98#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 */
110static 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
73/** 227/**
74 * fec_ptp_read - read raw cycle counter (to be used by time counter) 228 * fec_ptp_read - read raw cycle counter (to be used by time counter)
75 * @cc: the cyclecounter structure 229 * @cc: the cyclecounter structure
@@ -113,14 +267,15 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev)
113 /* 1ns counter */ 267 /* 1ns counter */
114 writel(inc << FEC_T_INC_OFFSET, fep->hwp + FEC_ATIME_INC); 268 writel(inc << FEC_T_INC_OFFSET, fep->hwp + FEC_ATIME_INC);
115 269
116 /* use free running count */ 270 /* use 31-bit timer counter */
117 writel(0, fep->hwp + FEC_ATIME_EVT_PERIOD); 271 writel(FEC_COUNTER_PERIOD, fep->hwp + FEC_ATIME_EVT_PERIOD);
118 272
119 writel(FEC_T_CTRL_ENABLE, fep->hwp + FEC_ATIME_CTRL); 273 writel(FEC_T_CTRL_ENABLE | FEC_T_CTRL_PERIOD_RST,
274 fep->hwp + FEC_ATIME_CTRL);
120 275
121 memset(&fep->cc, 0, sizeof(fep->cc)); 276 memset(&fep->cc, 0, sizeof(fep->cc));
122 fep->cc.read = fec_ptp_read; 277 fep->cc.read = fec_ptp_read;
123 fep->cc.mask = CLOCKSOURCE_MASK(32); 278 fep->cc.mask = CLOCKSOURCE_MASK(31);
124 fep->cc.shift = 31; 279 fep->cc.shift = 31;
125 fep->cc.mult = FEC_CC_MULT; 280 fep->cc.mult = FEC_CC_MULT;
126 281
@@ -143,32 +298,59 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev)
143 */ 298 */
144static int fec_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) 299static int fec_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
145{ 300{
146 u64 diff;
147 unsigned long flags; 301 unsigned long flags;
148 int neg_adj = 0; 302 int neg_adj = 0;
149 u32 mult = FEC_CC_MULT; 303 u32 i, tmp;
304 u32 corr_inc, corr_period;
305 u32 corr_ns;
306 u64 lhs, rhs;
150 307
151 struct fec_enet_private *fep = 308 struct fec_enet_private *fep =
152 container_of(ptp, struct fec_enet_private, ptp_caps); 309 container_of(ptp, struct fec_enet_private, ptp_caps);
153 310
311 if (ppb == 0)
312 return 0;
313
154 if (ppb < 0) { 314 if (ppb < 0) {
155 ppb = -ppb; 315 ppb = -ppb;
156 neg_adj = 1; 316 neg_adj = 1;
157 } 317 }
158 318
159 diff = mult; 319 /* In theory, corr_inc/corr_period = ppb/NSEC_PER_SEC;
160 diff *= ppb; 320 * Try to find the corr_inc between 1 to fep->ptp_inc to
161 diff = div_u64(diff, 1000000000ULL); 321 * meet adjustment requirement.
322 */
323 lhs = NSEC_PER_SEC;
324 rhs = (u64)ppb * (u64)fep->ptp_inc;
325 for (i = 1; i <= fep->ptp_inc; i++) {
326 if (lhs >= rhs) {
327 corr_inc = i;
328 corr_period = div_u64(lhs, rhs);
329 break;
330 }
331 lhs += NSEC_PER_SEC;
332 }
333 /* Not found? Set it to high value - double speed
334 * correct in every clock step.
335 */
336 if (i > fep->ptp_inc) {
337 corr_inc = fep->ptp_inc;
338 corr_period = 1;
339 }
340
341 if (neg_adj)
342 corr_ns = fep->ptp_inc - corr_inc;
343 else
344 corr_ns = fep->ptp_inc + corr_inc;
162 345
163 spin_lock_irqsave(&fep->tmreg_lock, flags); 346 spin_lock_irqsave(&fep->tmreg_lock, flags);
164 /*
165 * dummy read to set cycle_last in tc to now.
166 * So use adjusted mult to calculate when next call
167 * timercounter_read.
168 */
169 timecounter_read(&fep->tc);
170 347
171 fep->cc.mult = neg_adj ? mult - diff : mult + diff; 348 tmp = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK;
349 tmp |= corr_ns << FEC_T_INC_CORR_OFFSET;
350 writel(tmp, fep->hwp + FEC_ATIME_INC);
351 writel(corr_period, fep->hwp + FEC_ATIME_CORR);
352 /* dummy read to update the timer. */
353 timecounter_read(&fep->tc);
172 354
173 spin_unlock_irqrestore(&fep->tmreg_lock, flags); 355 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
174 356
@@ -188,12 +370,19 @@ static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
188 container_of(ptp, struct fec_enet_private, ptp_caps); 370 container_of(ptp, struct fec_enet_private, ptp_caps);
189 unsigned long flags; 371 unsigned long flags;
190 u64 now; 372 u64 now;
373 u32 counter;
191 374
192 spin_lock_irqsave(&fep->tmreg_lock, flags); 375 spin_lock_irqsave(&fep->tmreg_lock, flags);
193 376
194 now = timecounter_read(&fep->tc); 377 now = timecounter_read(&fep->tc);
195 now += delta; 378 now += delta;
196 379
380 /* Get the timer value based on adjusted timestamp.
381 * Update the counter with the masked value.
382 */
383 counter = now & fep->cc.mask;
384 writel(counter, fep->hwp + FEC_ATIME);
385
197 /* reset the timecounter */ 386 /* reset the timecounter */
198 timecounter_init(&fep->tc, &fep->cc, now); 387 timecounter_init(&fep->tc, &fep->cc, now);
199 388
@@ -244,6 +433,7 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
244 433
245 u64 ns; 434 u64 ns;
246 unsigned long flags; 435 unsigned long flags;
436 u32 counter;
247 437
248 mutex_lock(&fep->ptp_clk_mutex); 438 mutex_lock(&fep->ptp_clk_mutex);
249 /* Check the ptp clock */ 439 /* Check the ptp clock */
@@ -254,8 +444,13 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
254 444
255 ns = ts->tv_sec * 1000000000ULL; 445 ns = ts->tv_sec * 1000000000ULL;
256 ns += ts->tv_nsec; 446 ns += ts->tv_nsec;
447 /* Get the timer value based on timestamp.
448 * Update the counter with the masked value.
449 */
450 counter = ns & fep->cc.mask;
257 451
258 spin_lock_irqsave(&fep->tmreg_lock, flags); 452 spin_lock_irqsave(&fep->tmreg_lock, flags);
453 writel(counter, fep->hwp + FEC_ATIME);
259 timecounter_init(&fep->tc, &fep->cc, ns); 454 timecounter_init(&fep->tc, &fep->cc, ns);
260 spin_unlock_irqrestore(&fep->tmreg_lock, flags); 455 spin_unlock_irqrestore(&fep->tmreg_lock, flags);
261 mutex_unlock(&fep->ptp_clk_mutex); 456 mutex_unlock(&fep->ptp_clk_mutex);
@@ -272,6 +467,15 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
272static int fec_ptp_enable(struct ptp_clock_info *ptp, 467static int fec_ptp_enable(struct ptp_clock_info *ptp,
273 struct ptp_clock_request *rq, int on) 468 struct ptp_clock_request *rq, int on)
274{ 469{
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 }
275 return -EOPNOTSUPP; 479 return -EOPNOTSUPP;
276} 480}
277 481
@@ -386,7 +590,7 @@ void fec_ptp_init(struct platform_device *pdev)
386 fep->ptp_caps.n_ext_ts = 0; 590 fep->ptp_caps.n_ext_ts = 0;
387 fep->ptp_caps.n_per_out = 0; 591 fep->ptp_caps.n_per_out = 0;
388 fep->ptp_caps.n_pins = 0; 592 fep->ptp_caps.n_pins = 0;
389 fep->ptp_caps.pps = 0; 593 fep->ptp_caps.pps = 1;
390 fep->ptp_caps.adjfreq = fec_ptp_adjfreq; 594 fep->ptp_caps.adjfreq = fec_ptp_adjfreq;
391 fep->ptp_caps.adjtime = fec_ptp_adjtime; 595 fep->ptp_caps.adjtime = fec_ptp_adjtime;
392 fep->ptp_caps.gettime = fec_ptp_gettime; 596 fep->ptp_caps.gettime = fec_ptp_gettime;
@@ -394,6 +598,7 @@ void fec_ptp_init(struct platform_device *pdev)
394 fep->ptp_caps.enable = fec_ptp_enable; 598 fep->ptp_caps.enable = fec_ptp_enable;
395 599
396 fep->cycle_speed = clk_get_rate(fep->clk_ptp); 600 fep->cycle_speed = clk_get_rate(fep->clk_ptp);
601 fep->ptp_inc = NSEC_PER_SEC / fep->cycle_speed;
397 602
398 spin_lock_init(&fep->tmreg_lock); 603 spin_lock_init(&fep->tmreg_lock);
399 604
@@ -409,3 +614,36 @@ void fec_ptp_init(struct platform_device *pdev)
409 614
410 schedule_delayed_work(&fep->time_keep, HZ); 615 schedule_delayed_work(&fep->time_keep, HZ);
411} 616}
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 */
624uint 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}