diff options
author | Fugang Duan <B38611@freescale.com> | 2014-02-27 02:29:09 -0500 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:57:50 -0400 |
commit | f9f3fc39c0238ec761cd951fe3afcb5b97a40628 (patch) | |
tree | e82da1b014cf0bc7bf23924785c544d383bfb96d | |
parent | 450e9b8883469a675b90fb2fa655ee23e852aedd (diff) |
ENGR00301115 net: fec_ptp: fix convergence issue to support IXXAT and LinuxPTP stack
IEEE 1588 module has one hw issue in capturing the ATVR register. According
to the user manual it is:
ENET0->ATCR |= ENET_ATCR_CAPTURE_MASK;
while(ENET0->ATCR & ENET_ATCR_CAPTURE_MASK);
ts_counter_ns = ENET0->ATVR;
Incorrect behavior for ENET_ATCR[Capture and Restart Bits]. These bits will always
read a value zero. According to SPEC, when these bits are set to 1'b1, these should
hold value 1'b1 until the counter value is capture in the register clock domain.
Unfortunately there is a bug with the way the bit "ENET_ATCR_CAPTURE" clears.
So need something like:
ENET0->ATCR |= ENET_ATCR_CAPTURE_MASK;
wait();
ts_counter_ns = ENET0->ATVR;
The wait-time to be at least 6 clock cycle of the slower clock between the register
clock and the 1588 clock. The 1588 ts_clk is 25Mhz, register clock is 66Mhz, so the
wait-time must be greater than 240ns (40ns * 6). The workaround is that adding 1us
delay before read ATVR.
Signed-off-by: Fugang Duan <B38611@freescale.com>
-rw-r--r-- | drivers/net/ethernet/freescale/fec.h | 61 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 56 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fec_ptp.c | 12 |
3 files changed, 71 insertions, 58 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index a8816cbf40c5..12c8352900b2 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h | |||
@@ -390,6 +390,67 @@ struct bufdesc_ex { | |||
390 | #define FEC_PTP_TIMEOUT_TS 10 | 390 | #define FEC_PTP_TIMEOUT_TS 10 |
391 | #define FEC_PTP_TIMEOUT_EVENT 1000 | 391 | #define FEC_PTP_TIMEOUT_EVENT 1000 |
392 | 392 | ||
393 | /* Controller is ENET-MAC */ | ||
394 | #define FEC_QUIRK_ENET_MAC (1 << 0) | ||
395 | /* Controller needs driver to swap frame */ | ||
396 | #define FEC_QUIRK_SWAP_FRAME (1 << 1) | ||
397 | /* Controller uses gasket */ | ||
398 | #define FEC_QUIRK_USE_GASKET (1 << 2) | ||
399 | /* Controller has GBIT support */ | ||
400 | #define FEC_QUIRK_HAS_GBIT (1 << 3) | ||
401 | /* Controller has extend desc buffer */ | ||
402 | #define FEC_QUIRK_HAS_BUFDESC_EX (1 << 4) | ||
403 | /* Controller has hardware checksum support */ | ||
404 | #define FEC_QUIRK_HAS_CSUM (1 << 5) | ||
405 | /* Controller has hardware vlan support */ | ||
406 | #define FEC_QUIRK_HAS_VLAN (1 << 6) | ||
407 | /* Controller is FEC-MAC */ | ||
408 | #define FEC_QUIRK_FEC_MAC (1 << 7) | ||
409 | /* ENET IP errata ERR006358 | ||
410 | * | ||
411 | * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously | ||
412 | * detected as not set during a prior frame transmission, then the | ||
413 | * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs | ||
414 | * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in | ||
415 | * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously | ||
416 | * detected as not set during a prior frame transmission, then the | ||
417 | * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs | ||
418 | * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in | ||
419 | * frames not being transmitted until there is a 0-to-1 transition on | ||
420 | * ENET_TDAR[TDAR]. | ||
421 | */ | ||
422 | #define FEC_QUIRK_ERR006358 (1 << 8) | ||
423 | /* | ||
424 | * i.MX6Q/DL ENET cannot wake up system in wait mode because ENET tx & rx | ||
425 | * interrupt signal don't connect to GPC. So use pm qos to avoid cpu enter | ||
426 | * to wait mode. | ||
427 | */ | ||
428 | #define FEC_QUIRK_BUG_WAITMODE (1 << 9) | ||
429 | /* | ||
430 | * i.MX6SX ENET IP add Audio Video Bridging (AVB) feature support. | ||
431 | * ENET IP hw AVB main function: | ||
432 | * - Two class indicators on receive with configurable priority | ||
433 | * - Two class indicators and line speed timer on transmit allowing | ||
434 | * implementation class credit based shapers externally | ||
435 | * - Additional DMA registers provisioned to allow managing up to 3 | ||
436 | * independent rings | ||
437 | */ | ||
438 | #define FEC_QUIRK_HAS_AVB (1 << 10) | ||
439 | /* | ||
440 | * There is a TDAR race condition for mutliQ when the software sets TDAR | ||
441 | * and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles). | ||
442 | * This will cause the udma_tx and udma_tx_arbiter state machines to hang. | ||
443 | * The issue exist at i.MX6SX enet IP. | ||
444 | */ | ||
445 | #define FEC_QUIRK_TKT210582 (1 << 11) | ||
446 | /* | ||
447 | * Incorrect behavior for ENET_ATCR[Capture and Restart Bits]. | ||
448 | * These bits will always read a value zero. According to SPEC, when these | ||
449 | * bits are set to 1'b1, these should hold value 1'b1 until the counter value | ||
450 | * is capture in the register clock domain. | ||
451 | */ | ||
452 | #define FEC_QUIRK_TKT210590 (1 << 12) | ||
453 | |||
393 | /* PTP standard time representation structure */ | 454 | /* PTP standard time representation structure */ |
394 | struct ptp_time{ | 455 | struct ptp_time{ |
395 | u64 sec; /* seconds */ | 456 | u64 sec; /* seconds */ |
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index f5e88a25ed1d..e3ffd7aee02f 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c | |||
@@ -93,60 +93,6 @@ static const u16 fec_enet_vlan_pri_to_queue[8] = {1, 1, 1, 1, 2, 2, 2, 2}; | |||
93 | #define FEC_ENET_RAFL_V 0x8 | 93 | #define FEC_ENET_RAFL_V 0x8 |
94 | #define FEC_ENET_OPD_V 0xFFF0 | 94 | #define FEC_ENET_OPD_V 0xFFF0 |
95 | 95 | ||
96 | /* Controller is ENET-MAC */ | ||
97 | #define FEC_QUIRK_ENET_MAC (1 << 0) | ||
98 | /* Controller needs driver to swap frame */ | ||
99 | #define FEC_QUIRK_SWAP_FRAME (1 << 1) | ||
100 | /* Controller uses gasket */ | ||
101 | #define FEC_QUIRK_USE_GASKET (1 << 2) | ||
102 | /* Controller has GBIT support */ | ||
103 | #define FEC_QUIRK_HAS_GBIT (1 << 3) | ||
104 | /* Controller has extend desc buffer */ | ||
105 | #define FEC_QUIRK_HAS_BUFDESC_EX (1 << 4) | ||
106 | /* Controller has hardware checksum support */ | ||
107 | #define FEC_QUIRK_HAS_CSUM (1 << 5) | ||
108 | /* Controller has hardware vlan support */ | ||
109 | #define FEC_QUIRK_HAS_VLAN (1 << 6) | ||
110 | /* Controller is FEC-MAC */ | ||
111 | #define FEC_QUIRK_FEC_MAC (1 << 7) | ||
112 | /* ENET IP errata ERR006358 | ||
113 | * | ||
114 | * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously | ||
115 | * detected as not set during a prior frame transmission, then the | ||
116 | * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs | ||
117 | * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in | ||
118 | * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously | ||
119 | * detected as not set during a prior frame transmission, then the | ||
120 | * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs | ||
121 | * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in | ||
122 | * frames not being transmitted until there is a 0-to-1 transition on | ||
123 | * ENET_TDAR[TDAR]. | ||
124 | */ | ||
125 | #define FEC_QUIRK_ERR006358 (1 << 8) | ||
126 | /* | ||
127 | * i.MX6Q/DL ENET cannot wake up system in wait mode because ENET tx & rx | ||
128 | * interrupt signal don't connect to GPC. So use pm qos to avoid cpu enter | ||
129 | * to wait mode. | ||
130 | */ | ||
131 | #define FEC_QUIRK_BUG_WAITMODE (1 << 9) | ||
132 | /* | ||
133 | * i.MX6SX ENET IP add Audio Video Bridging (AVB) feature support. | ||
134 | * ENET IP hw AVB main function: | ||
135 | * - Two class indicators on receive with configurable priority | ||
136 | * - Two class indicators and line speed timer on transmit allowing | ||
137 | * implementation class credit based shapers externally | ||
138 | * - Additional DMA registers provisioned to allow managing up to 3 | ||
139 | * independent rings | ||
140 | */ | ||
141 | #define FEC_QUIRK_HAS_AVB (1 << 10) | ||
142 | /* | ||
143 | * There is a TDAR race condition for mutliQ when the software sets TDAR | ||
144 | * and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles). | ||
145 | * This will cause the udma_tx and udma_tx_arbiter state machines to hang. | ||
146 | * The issue exist at i.MX6SX enet IP. | ||
147 | */ | ||
148 | #define FEC_QUIRK_TKT210582 (1 << 11) | ||
149 | |||
150 | static struct platform_device_id fec_devtype[] = { | 96 | static struct platform_device_id fec_devtype[] = { |
151 | { | 97 | { |
152 | /* keep it for coldfire */ | 98 | /* keep it for coldfire */ |
@@ -175,7 +121,7 @@ static struct platform_device_id fec_devtype[] = { | |||
175 | .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | | 121 | .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | |
176 | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | | 122 | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | |
177 | FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB | | 123 | FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB | |
178 | FEC_QUIRK_TKT210582, | 124 | FEC_QUIRK_TKT210582 | FEC_QUIRK_TKT210590, |
179 | }, { | 125 | }, { |
180 | /* sentinel */ | 126 | /* sentinel */ |
181 | } | 127 | } |
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index eaf0169dff90..03e10de40e94 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c | |||
@@ -229,6 +229,8 @@ static void fec_get_curr_cnt(struct fec_enet_private *priv, | |||
229 | { | 229 | { |
230 | u32 tempval, old_sec; | 230 | u32 tempval, old_sec; |
231 | u32 timeout_event, timeout_ts = 0; | 231 | u32 timeout_event, timeout_ts = 0; |
232 | const struct platform_device_id *id_entry = | ||
233 | platform_get_device_id(priv->pdev); | ||
232 | 234 | ||
233 | do { | 235 | do { |
234 | old_sec = priv->prtc; | 236 | old_sec = priv->prtc; |
@@ -237,7 +239,8 @@ static void fec_get_curr_cnt(struct fec_enet_private *priv, | |||
237 | tempval = readl(priv->hwp + FEC_ATIME_CTRL); | 239 | tempval = readl(priv->hwp + FEC_ATIME_CTRL); |
238 | tempval |= FEC_T_CTRL_CAPTURE; | 240 | tempval |= FEC_T_CTRL_CAPTURE; |
239 | writel(tempval, priv->hwp + FEC_ATIME_CTRL); | 241 | writel(tempval, priv->hwp + FEC_ATIME_CTRL); |
240 | 242 | if (id_entry->driver_data & FEC_QUIRK_TKT210590) | |
243 | udelay(1); | ||
241 | curr_time->rtc_time.nsec = readl(priv->hwp + FEC_ATIME); | 244 | curr_time->rtc_time.nsec = readl(priv->hwp + FEC_ATIME); |
242 | 245 | ||
243 | while (readl(priv->hwp + FEC_IEVENT) & FEC_ENET_TS_TIMER) { | 246 | while (readl(priv->hwp + FEC_IEVENT) & FEC_ENET_TS_TIMER) { |
@@ -520,7 +523,7 @@ static void fec_handle_ptpdrift(struct fec_enet_private *priv, | |||
520 | } | 523 | } |
521 | 524 | ||
522 | static void fec_set_drift(struct fec_enet_private *priv, | 525 | static void fec_set_drift(struct fec_enet_private *priv, |
523 | struct ptp_set_comp *comp) | 526 | struct ptp_set_comp *comp) |
524 | { | 527 | { |
525 | struct ptp_time_correct tc; | 528 | struct ptp_time_correct tc; |
526 | u32 tmp, corr_ns; | 529 | u32 tmp, corr_ns; |
@@ -555,12 +558,15 @@ static cycle_t fec_ptp_read(const struct cyclecounter *cc) | |||
555 | { | 558 | { |
556 | struct fec_enet_private *fep = | 559 | struct fec_enet_private *fep = |
557 | container_of(cc, struct fec_enet_private, cc); | 560 | container_of(cc, struct fec_enet_private, cc); |
561 | const struct platform_device_id *id_entry = | ||
562 | platform_get_device_id(fep->pdev); | ||
558 | u32 tempval; | 563 | u32 tempval; |
559 | 564 | ||
560 | tempval = readl(fep->hwp + FEC_ATIME_CTRL); | 565 | tempval = readl(fep->hwp + FEC_ATIME_CTRL); |
561 | tempval |= FEC_T_CTRL_CAPTURE; | 566 | tempval |= FEC_T_CTRL_CAPTURE; |
562 | writel(tempval, fep->hwp + FEC_ATIME_CTRL); | 567 | writel(tempval, fep->hwp + FEC_ATIME_CTRL); |
563 | 568 | if (id_entry->driver_data & FEC_QUIRK_TKT210590) | |
569 | udelay(1); | ||
564 | return readl(fep->hwp + FEC_ATIME); | 570 | return readl(fep->hwp + FEC_ATIME); |
565 | } | 571 | } |
566 | 572 | ||