diff options
author | David S. Miller <davem@davemloft.net> | 2014-10-14 14:45:17 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-10-14 14:45:17 -0400 |
commit | f787d6c8dd52ded9874cbbc447a32515c80fa2bf (patch) | |
tree | 57cb9578e7e20ab6700a715e67834d08b399a11a | |
parent | 02ea80741a25435123e8a5ca40cac6a0bcf0c9f1 (diff) | |
parent | 278d24047891a1bf4a98128eaa8ecafd019e58c2 (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.h | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fec_ptp.c | 272 |
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 | ||
489 | void fec_ptp_init(struct platform_device *pdev); | 498 | void fec_ptp_init(struct platform_device *pdev); |
490 | void fec_ptp_start_cyclecounter(struct net_device *ndev); | 499 | void fec_ptp_start_cyclecounter(struct net_device *ndev); |
491 | int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr); | 500 | int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr); |
492 | int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr); | 501 | int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr); |
502 | uint 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 | */ | ||
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 | |||
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 | */ |
144 | static int fec_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) | 299 | static 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, | |||
272 | static int fec_ptp_enable(struct ptp_clock_info *ptp, | 467 | static 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 | */ | ||
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 | } | ||