diff options
Diffstat (limited to 'drivers/net/niu.c')
-rw-r--r-- | drivers/net/niu.c | 293 |
1 files changed, 283 insertions, 10 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 2c3bb36cda17..5ddca4e3d27b 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c | |||
@@ -33,8 +33,8 @@ | |||
33 | 33 | ||
34 | #define DRV_MODULE_NAME "niu" | 34 | #define DRV_MODULE_NAME "niu" |
35 | #define PFX DRV_MODULE_NAME ": " | 35 | #define PFX DRV_MODULE_NAME ": " |
36 | #define DRV_MODULE_VERSION "0.9" | 36 | #define DRV_MODULE_VERSION "1.0" |
37 | #define DRV_MODULE_RELDATE "May 4, 2008" | 37 | #define DRV_MODULE_RELDATE "Nov 14, 2008" |
38 | 38 | ||
39 | static char version[] __devinitdata = | 39 | static char version[] __devinitdata = |
40 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; | 40 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; |
@@ -51,8 +51,7 @@ MODULE_VERSION(DRV_MODULE_VERSION); | |||
51 | #ifndef readq | 51 | #ifndef readq |
52 | static u64 readq(void __iomem *reg) | 52 | static u64 readq(void __iomem *reg) |
53 | { | 53 | { |
54 | return (((u64)readl(reg + 0x4UL) << 32) | | 54 | return ((u64) readl(reg)) | (((u64) readl(reg + 4UL)) << 32); |
55 | (u64)readl(reg)); | ||
56 | } | 55 | } |
57 | 56 | ||
58 | static void writeq(u64 val, void __iomem *reg) | 57 | static void writeq(u64 val, void __iomem *reg) |
@@ -407,7 +406,7 @@ static int esr2_set_rx_cfg(struct niu *np, unsigned long channel, u32 val) | |||
407 | } | 406 | } |
408 | 407 | ||
409 | /* Mode is always 10G fiber. */ | 408 | /* Mode is always 10G fiber. */ |
410 | static int serdes_init_niu(struct niu *np) | 409 | static int serdes_init_niu_10g_fiber(struct niu *np) |
411 | { | 410 | { |
412 | struct niu_link_config *lp = &np->link_config; | 411 | struct niu_link_config *lp = &np->link_config; |
413 | u32 tx_cfg, rx_cfg; | 412 | u32 tx_cfg, rx_cfg; |
@@ -444,6 +443,223 @@ static int serdes_init_niu(struct niu *np) | |||
444 | return 0; | 443 | return 0; |
445 | } | 444 | } |
446 | 445 | ||
446 | static int serdes_init_niu_1g_serdes(struct niu *np) | ||
447 | { | ||
448 | struct niu_link_config *lp = &np->link_config; | ||
449 | u16 pll_cfg, pll_sts; | ||
450 | int max_retry = 100; | ||
451 | u64 sig, mask, val; | ||
452 | u32 tx_cfg, rx_cfg; | ||
453 | unsigned long i; | ||
454 | int err; | ||
455 | |||
456 | tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV | | ||
457 | PLL_TX_CFG_RATE_HALF); | ||
458 | rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT | | ||
459 | PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH | | ||
460 | PLL_RX_CFG_RATE_HALF); | ||
461 | |||
462 | if (np->port == 0) | ||
463 | rx_cfg |= PLL_RX_CFG_EQ_LP_ADAPTIVE; | ||
464 | |||
465 | if (lp->loopback_mode == LOOPBACK_PHY) { | ||
466 | u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS; | ||
467 | |||
468 | mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, | ||
469 | ESR2_TI_PLL_TEST_CFG_L, test_cfg); | ||
470 | |||
471 | tx_cfg |= PLL_TX_CFG_ENTEST; | ||
472 | rx_cfg |= PLL_RX_CFG_ENTEST; | ||
473 | } | ||
474 | |||
475 | /* Initialize PLL for 1G */ | ||
476 | pll_cfg = (PLL_CFG_ENPLL | PLL_CFG_MPY_8X); | ||
477 | |||
478 | err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, | ||
479 | ESR2_TI_PLL_CFG_L, pll_cfg); | ||
480 | if (err) { | ||
481 | dev_err(np->device, PFX "NIU Port %d " | ||
482 | "serdes_init_niu_1g_serdes: " | ||
483 | "mdio write to ESR2_TI_PLL_CFG_L failed", np->port); | ||
484 | return err; | ||
485 | } | ||
486 | |||
487 | pll_sts = PLL_CFG_ENPLL; | ||
488 | |||
489 | err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, | ||
490 | ESR2_TI_PLL_STS_L, pll_sts); | ||
491 | if (err) { | ||
492 | dev_err(np->device, PFX "NIU Port %d " | ||
493 | "serdes_init_niu_1g_serdes: " | ||
494 | "mdio write to ESR2_TI_PLL_STS_L failed", np->port); | ||
495 | return err; | ||
496 | } | ||
497 | |||
498 | udelay(200); | ||
499 | |||
500 | /* Initialize all 4 lanes of the SERDES. */ | ||
501 | for (i = 0; i < 4; i++) { | ||
502 | err = esr2_set_tx_cfg(np, i, tx_cfg); | ||
503 | if (err) | ||
504 | return err; | ||
505 | } | ||
506 | |||
507 | for (i = 0; i < 4; i++) { | ||
508 | err = esr2_set_rx_cfg(np, i, rx_cfg); | ||
509 | if (err) | ||
510 | return err; | ||
511 | } | ||
512 | |||
513 | switch (np->port) { | ||
514 | case 0: | ||
515 | val = (ESR_INT_SRDY0_P0 | ESR_INT_DET0_P0); | ||
516 | mask = val; | ||
517 | break; | ||
518 | |||
519 | case 1: | ||
520 | val = (ESR_INT_SRDY0_P1 | ESR_INT_DET0_P1); | ||
521 | mask = val; | ||
522 | break; | ||
523 | |||
524 | default: | ||
525 | return -EINVAL; | ||
526 | } | ||
527 | |||
528 | while (max_retry--) { | ||
529 | sig = nr64(ESR_INT_SIGNALS); | ||
530 | if ((sig & mask) == val) | ||
531 | break; | ||
532 | |||
533 | mdelay(500); | ||
534 | } | ||
535 | |||
536 | if ((sig & mask) != val) { | ||
537 | dev_err(np->device, PFX "Port %u signal bits [%08x] are not " | ||
538 | "[%08x]\n", np->port, (int) (sig & mask), (int) val); | ||
539 | return -ENODEV; | ||
540 | } | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static int serdes_init_niu_10g_serdes(struct niu *np) | ||
546 | { | ||
547 | struct niu_link_config *lp = &np->link_config; | ||
548 | u32 tx_cfg, rx_cfg, pll_cfg, pll_sts; | ||
549 | int max_retry = 100; | ||
550 | u64 sig, mask, val; | ||
551 | unsigned long i; | ||
552 | int err; | ||
553 | |||
554 | tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV); | ||
555 | rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT | | ||
556 | PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH | | ||
557 | PLL_RX_CFG_EQ_LP_ADAPTIVE); | ||
558 | |||
559 | if (lp->loopback_mode == LOOPBACK_PHY) { | ||
560 | u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS; | ||
561 | |||
562 | mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, | ||
563 | ESR2_TI_PLL_TEST_CFG_L, test_cfg); | ||
564 | |||
565 | tx_cfg |= PLL_TX_CFG_ENTEST; | ||
566 | rx_cfg |= PLL_RX_CFG_ENTEST; | ||
567 | } | ||
568 | |||
569 | /* Initialize PLL for 10G */ | ||
570 | pll_cfg = (PLL_CFG_ENPLL | PLL_CFG_MPY_10X); | ||
571 | |||
572 | err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, | ||
573 | ESR2_TI_PLL_CFG_L, pll_cfg & 0xffff); | ||
574 | if (err) { | ||
575 | dev_err(np->device, PFX "NIU Port %d " | ||
576 | "serdes_init_niu_10g_serdes: " | ||
577 | "mdio write to ESR2_TI_PLL_CFG_L failed", np->port); | ||
578 | return err; | ||
579 | } | ||
580 | |||
581 | pll_sts = PLL_CFG_ENPLL; | ||
582 | |||
583 | err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR, | ||
584 | ESR2_TI_PLL_STS_L, pll_sts & 0xffff); | ||
585 | if (err) { | ||
586 | dev_err(np->device, PFX "NIU Port %d " | ||
587 | "serdes_init_niu_10g_serdes: " | ||
588 | "mdio write to ESR2_TI_PLL_STS_L failed", np->port); | ||
589 | return err; | ||
590 | } | ||
591 | |||
592 | udelay(200); | ||
593 | |||
594 | /* Initialize all 4 lanes of the SERDES. */ | ||
595 | for (i = 0; i < 4; i++) { | ||
596 | err = esr2_set_tx_cfg(np, i, tx_cfg); | ||
597 | if (err) | ||
598 | return err; | ||
599 | } | ||
600 | |||
601 | for (i = 0; i < 4; i++) { | ||
602 | err = esr2_set_rx_cfg(np, i, rx_cfg); | ||
603 | if (err) | ||
604 | return err; | ||
605 | } | ||
606 | |||
607 | /* check if serdes is ready */ | ||
608 | |||
609 | switch (np->port) { | ||
610 | case 0: | ||
611 | mask = ESR_INT_SIGNALS_P0_BITS; | ||
612 | val = (ESR_INT_SRDY0_P0 | | ||
613 | ESR_INT_DET0_P0 | | ||
614 | ESR_INT_XSRDY_P0 | | ||
615 | ESR_INT_XDP_P0_CH3 | | ||
616 | ESR_INT_XDP_P0_CH2 | | ||
617 | ESR_INT_XDP_P0_CH1 | | ||
618 | ESR_INT_XDP_P0_CH0); | ||
619 | break; | ||
620 | |||
621 | case 1: | ||
622 | mask = ESR_INT_SIGNALS_P1_BITS; | ||
623 | val = (ESR_INT_SRDY0_P1 | | ||
624 | ESR_INT_DET0_P1 | | ||
625 | ESR_INT_XSRDY_P1 | | ||
626 | ESR_INT_XDP_P1_CH3 | | ||
627 | ESR_INT_XDP_P1_CH2 | | ||
628 | ESR_INT_XDP_P1_CH1 | | ||
629 | ESR_INT_XDP_P1_CH0); | ||
630 | break; | ||
631 | |||
632 | default: | ||
633 | return -EINVAL; | ||
634 | } | ||
635 | |||
636 | while (max_retry--) { | ||
637 | sig = nr64(ESR_INT_SIGNALS); | ||
638 | if ((sig & mask) == val) | ||
639 | break; | ||
640 | |||
641 | mdelay(500); | ||
642 | } | ||
643 | |||
644 | if ((sig & mask) != val) { | ||
645 | pr_info(PFX "NIU Port %u signal bits [%08x] are not " | ||
646 | "[%08x] for 10G...trying 1G\n", | ||
647 | np->port, (int) (sig & mask), (int) val); | ||
648 | |||
649 | /* 10G failed, try initializing at 1G */ | ||
650 | err = serdes_init_niu_1g_serdes(np); | ||
651 | if (!err) { | ||
652 | np->flags &= ~NIU_FLAGS_10G; | ||
653 | np->mac_xcvr = MAC_XCVR_PCS; | ||
654 | } else { | ||
655 | dev_err(np->device, PFX "Port %u 10G/1G SERDES " | ||
656 | "Link Failed \n", np->port); | ||
657 | return -ENODEV; | ||
658 | } | ||
659 | } | ||
660 | return 0; | ||
661 | } | ||
662 | |||
447 | static int esr_read_rxtx_ctrl(struct niu *np, unsigned long chan, u32 *val) | 663 | static int esr_read_rxtx_ctrl(struct niu *np, unsigned long chan, u32 *val) |
448 | { | 664 | { |
449 | int err; | 665 | int err; |
@@ -1955,13 +2171,23 @@ static const struct niu_phy_ops phy_ops_10g_serdes = { | |||
1955 | .link_status = link_status_10g_serdes, | 2171 | .link_status = link_status_10g_serdes, |
1956 | }; | 2172 | }; |
1957 | 2173 | ||
2174 | static const struct niu_phy_ops phy_ops_10g_serdes_niu = { | ||
2175 | .serdes_init = serdes_init_niu_10g_serdes, | ||
2176 | .link_status = link_status_10g_serdes, | ||
2177 | }; | ||
2178 | |||
2179 | static const struct niu_phy_ops phy_ops_1g_serdes_niu = { | ||
2180 | .serdes_init = serdes_init_niu_1g_serdes, | ||
2181 | .link_status = link_status_1g_serdes, | ||
2182 | }; | ||
2183 | |||
1958 | static const struct niu_phy_ops phy_ops_1g_rgmii = { | 2184 | static const struct niu_phy_ops phy_ops_1g_rgmii = { |
1959 | .xcvr_init = xcvr_init_1g_rgmii, | 2185 | .xcvr_init = xcvr_init_1g_rgmii, |
1960 | .link_status = link_status_1g_rgmii, | 2186 | .link_status = link_status_1g_rgmii, |
1961 | }; | 2187 | }; |
1962 | 2188 | ||
1963 | static const struct niu_phy_ops phy_ops_10g_fiber_niu = { | 2189 | static const struct niu_phy_ops phy_ops_10g_fiber_niu = { |
1964 | .serdes_init = serdes_init_niu, | 2190 | .serdes_init = serdes_init_niu_10g_fiber, |
1965 | .xcvr_init = xcvr_init_10g, | 2191 | .xcvr_init = xcvr_init_10g, |
1966 | .link_status = link_status_10g, | 2192 | .link_status = link_status_10g, |
1967 | }; | 2193 | }; |
@@ -1999,11 +2225,21 @@ struct niu_phy_template { | |||
1999 | u32 phy_addr_base; | 2225 | u32 phy_addr_base; |
2000 | }; | 2226 | }; |
2001 | 2227 | ||
2002 | static const struct niu_phy_template phy_template_niu = { | 2228 | static const struct niu_phy_template phy_template_niu_10g_fiber = { |
2003 | .ops = &phy_ops_10g_fiber_niu, | 2229 | .ops = &phy_ops_10g_fiber_niu, |
2004 | .phy_addr_base = 16, | 2230 | .phy_addr_base = 16, |
2005 | }; | 2231 | }; |
2006 | 2232 | ||
2233 | static const struct niu_phy_template phy_template_niu_10g_serdes = { | ||
2234 | .ops = &phy_ops_10g_serdes_niu, | ||
2235 | .phy_addr_base = 0, | ||
2236 | }; | ||
2237 | |||
2238 | static const struct niu_phy_template phy_template_niu_1g_serdes = { | ||
2239 | .ops = &phy_ops_1g_serdes_niu, | ||
2240 | .phy_addr_base = 0, | ||
2241 | }; | ||
2242 | |||
2007 | static const struct niu_phy_template phy_template_10g_fiber = { | 2243 | static const struct niu_phy_template phy_template_10g_fiber = { |
2008 | .ops = &phy_ops_10g_fiber, | 2244 | .ops = &phy_ops_10g_fiber, |
2009 | .phy_addr_base = 8, | 2245 | .phy_addr_base = 8, |
@@ -2183,8 +2419,25 @@ static int niu_determine_phy_disposition(struct niu *np) | |||
2183 | u32 phy_addr_off = 0; | 2419 | u32 phy_addr_off = 0; |
2184 | 2420 | ||
2185 | if (plat_type == PLAT_TYPE_NIU) { | 2421 | if (plat_type == PLAT_TYPE_NIU) { |
2186 | tp = &phy_template_niu; | 2422 | switch (np->flags & |
2187 | phy_addr_off += np->port; | 2423 | (NIU_FLAGS_10G | |
2424 | NIU_FLAGS_FIBER | | ||
2425 | NIU_FLAGS_XCVR_SERDES)) { | ||
2426 | case NIU_FLAGS_10G | NIU_FLAGS_XCVR_SERDES: | ||
2427 | /* 10G Serdes */ | ||
2428 | tp = &phy_template_niu_10g_serdes; | ||
2429 | break; | ||
2430 | case NIU_FLAGS_XCVR_SERDES: | ||
2431 | /* 1G Serdes */ | ||
2432 | tp = &phy_template_niu_1g_serdes; | ||
2433 | break; | ||
2434 | case NIU_FLAGS_10G | NIU_FLAGS_FIBER: | ||
2435 | /* 10G Fiber */ | ||
2436 | default: | ||
2437 | tp = &phy_template_niu_10g_fiber; | ||
2438 | phy_addr_off += np->port; | ||
2439 | break; | ||
2440 | } | ||
2188 | } else { | 2441 | } else { |
2189 | switch (np->flags & | 2442 | switch (np->flags & |
2190 | (NIU_FLAGS_10G | | 2443 | (NIU_FLAGS_10G | |
@@ -7212,6 +7465,12 @@ static int __devinit niu_phy_type_prop_decode(struct niu *np, | |||
7212 | np->flags |= NIU_FLAGS_10G; | 7465 | np->flags |= NIU_FLAGS_10G; |
7213 | np->flags &= ~NIU_FLAGS_FIBER; | 7466 | np->flags &= ~NIU_FLAGS_FIBER; |
7214 | np->mac_xcvr = MAC_XCVR_XPCS; | 7467 | np->mac_xcvr = MAC_XCVR_XPCS; |
7468 | } else if (!strcmp(phy_prop, "xgsd") || !strcmp(phy_prop, "gsd")) { | ||
7469 | /* 10G Serdes or 1G Serdes, default to 10G */ | ||
7470 | np->flags |= NIU_FLAGS_10G; | ||
7471 | np->flags &= ~NIU_FLAGS_FIBER; | ||
7472 | np->flags |= NIU_FLAGS_XCVR_SERDES; | ||
7473 | np->mac_xcvr = MAC_XCVR_XPCS; | ||
7215 | } else { | 7474 | } else { |
7216 | return -EINVAL; | 7475 | return -EINVAL; |
7217 | } | 7476 | } |
@@ -7740,6 +7999,8 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent) | |||
7740 | u32 val; | 7999 | u32 val; |
7741 | int err; | 8000 | int err; |
7742 | 8001 | ||
8002 | num_10g = num_1g = 0; | ||
8003 | |||
7743 | if (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR) || | 8004 | if (!strcmp(np->vpd.model, NIU_ALONSO_MDL_STR) || |
7744 | !strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) { | 8005 | !strcmp(np->vpd.model, NIU_KIMI_MDL_STR)) { |
7745 | num_10g = 0; | 8006 | num_10g = 0; |
@@ -7756,6 +8017,16 @@ static int __devinit walk_phys(struct niu *np, struct niu_parent *parent) | |||
7756 | parent->num_ports = 2; | 8017 | parent->num_ports = 2; |
7757 | val = (phy_encode(PORT_TYPE_10G, 0) | | 8018 | val = (phy_encode(PORT_TYPE_10G, 0) | |
7758 | phy_encode(PORT_TYPE_10G, 1)); | 8019 | phy_encode(PORT_TYPE_10G, 1)); |
8020 | } else if ((np->flags & NIU_FLAGS_XCVR_SERDES) && | ||
8021 | (parent->plat_type == PLAT_TYPE_NIU)) { | ||
8022 | /* this is the Monza case */ | ||
8023 | if (np->flags & NIU_FLAGS_10G) { | ||
8024 | val = (phy_encode(PORT_TYPE_10G, 0) | | ||
8025 | phy_encode(PORT_TYPE_10G, 1)); | ||
8026 | } else { | ||
8027 | val = (phy_encode(PORT_TYPE_1G, 0) | | ||
8028 | phy_encode(PORT_TYPE_1G, 1)); | ||
8029 | } | ||
7759 | } else { | 8030 | } else { |
7760 | err = fill_phy_probe_info(np, parent, info); | 8031 | err = fill_phy_probe_info(np, parent, info); |
7761 | if (err) | 8032 | if (err) |
@@ -8653,7 +8924,9 @@ static void __devinit niu_device_announce(struct niu *np) | |||
8653 | dev->name, | 8924 | dev->name, |
8654 | (np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"), | 8925 | (np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"), |
8655 | (np->flags & NIU_FLAGS_10G ? "10G" : "1G"), | 8926 | (np->flags & NIU_FLAGS_10G ? "10G" : "1G"), |
8656 | (np->flags & NIU_FLAGS_FIBER ? "FIBER" : "COPPER"), | 8927 | (np->flags & NIU_FLAGS_FIBER ? "FIBER" : |
8928 | (np->flags & NIU_FLAGS_XCVR_SERDES ? "SERDES" : | ||
8929 | "COPPER")), | ||
8657 | (np->mac_xcvr == MAC_XCVR_MII ? "MII" : | 8930 | (np->mac_xcvr == MAC_XCVR_MII ? "MII" : |
8658 | (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")), | 8931 | (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")), |
8659 | np->vpd.phy_type); | 8932 | np->vpd.phy_type); |