diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/net/dsa/qca8k.c | 156 | ||||
| -rw-r--r-- | drivers/net/dsa/qca8k.h | 13 |
2 files changed, 168 insertions, 1 deletions
diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 14ad78225f07..c4fa400efdcc 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c | |||
| @@ -481,6 +481,155 @@ qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) | |||
| 481 | qca8k_reg_clear(priv, QCA8K_REG_PORT_STATUS(port), mask); | 481 | qca8k_reg_clear(priv, QCA8K_REG_PORT_STATUS(port), mask); |
| 482 | } | 482 | } |
| 483 | 483 | ||
| 484 | static u32 | ||
| 485 | qca8k_port_to_phy(int port) | ||
| 486 | { | ||
| 487 | /* From Andrew Lunn: | ||
| 488 | * Port 0 has no internal phy. | ||
| 489 | * Port 1 has an internal PHY at MDIO address 0. | ||
| 490 | * Port 2 has an internal PHY at MDIO address 1. | ||
| 491 | * ... | ||
| 492 | * Port 5 has an internal PHY at MDIO address 4. | ||
| 493 | * Port 6 has no internal PHY. | ||
| 494 | */ | ||
| 495 | |||
| 496 | return port - 1; | ||
| 497 | } | ||
| 498 | |||
| 499 | static int | ||
| 500 | qca8k_mdio_write(struct qca8k_priv *priv, int port, u32 regnum, u16 data) | ||
| 501 | { | ||
| 502 | u32 phy, val; | ||
| 503 | |||
| 504 | if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) | ||
| 505 | return -EINVAL; | ||
| 506 | |||
| 507 | /* callee is responsible for not passing bad ports, | ||
| 508 | * but we still would like to make spills impossible. | ||
| 509 | */ | ||
| 510 | phy = qca8k_port_to_phy(port) % PHY_MAX_ADDR; | ||
| 511 | val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | | ||
| 512 | QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | | ||
| 513 | QCA8K_MDIO_MASTER_REG_ADDR(regnum) | | ||
| 514 | QCA8K_MDIO_MASTER_DATA(data); | ||
| 515 | |||
| 516 | qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val); | ||
| 517 | |||
| 518 | return qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL, | ||
| 519 | QCA8K_MDIO_MASTER_BUSY); | ||
| 520 | } | ||
| 521 | |||
| 522 | static int | ||
| 523 | qca8k_mdio_read(struct qca8k_priv *priv, int port, u32 regnum) | ||
| 524 | { | ||
| 525 | u32 phy, val; | ||
| 526 | |||
| 527 | if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) | ||
| 528 | return -EINVAL; | ||
| 529 | |||
| 530 | /* callee is responsible for not passing bad ports, | ||
| 531 | * but we still would like to make spills impossible. | ||
| 532 | */ | ||
| 533 | phy = qca8k_port_to_phy(port) % PHY_MAX_ADDR; | ||
| 534 | val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | | ||
| 535 | QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | | ||
| 536 | QCA8K_MDIO_MASTER_REG_ADDR(regnum); | ||
| 537 | |||
| 538 | qca8k_write(priv, QCA8K_MDIO_MASTER_CTRL, val); | ||
| 539 | |||
| 540 | if (qca8k_busy_wait(priv, QCA8K_MDIO_MASTER_CTRL, | ||
| 541 | QCA8K_MDIO_MASTER_BUSY)) | ||
| 542 | return -ETIMEDOUT; | ||
| 543 | |||
| 544 | val = (qca8k_read(priv, QCA8K_MDIO_MASTER_CTRL) & | ||
| 545 | QCA8K_MDIO_MASTER_DATA_MASK); | ||
| 546 | |||
| 547 | return val; | ||
| 548 | } | ||
| 549 | |||
| 550 | static int | ||
| 551 | qca8k_phy_write(struct dsa_switch *ds, int port, int regnum, u16 data) | ||
| 552 | { | ||
| 553 | struct qca8k_priv *priv = ds->priv; | ||
| 554 | |||
| 555 | return qca8k_mdio_write(priv, port, regnum, data); | ||
| 556 | } | ||
| 557 | |||
| 558 | static int | ||
| 559 | qca8k_phy_read(struct dsa_switch *ds, int port, int regnum) | ||
| 560 | { | ||
| 561 | struct qca8k_priv *priv = ds->priv; | ||
| 562 | int ret; | ||
| 563 | |||
| 564 | ret = qca8k_mdio_read(priv, port, regnum); | ||
| 565 | |||
| 566 | if (ret < 0) | ||
| 567 | return 0xffff; | ||
| 568 | |||
| 569 | return ret; | ||
| 570 | } | ||
| 571 | |||
| 572 | static int | ||
| 573 | qca8k_setup_mdio_bus(struct qca8k_priv *priv) | ||
| 574 | { | ||
| 575 | u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; | ||
| 576 | struct device_node *ports, *port; | ||
| 577 | int err; | ||
| 578 | |||
| 579 | ports = of_get_child_by_name(priv->dev->of_node, "ports"); | ||
| 580 | if (!ports) | ||
| 581 | return -EINVAL; | ||
| 582 | |||
| 583 | for_each_available_child_of_node(ports, port) { | ||
| 584 | err = of_property_read_u32(port, "reg", ®); | ||
| 585 | if (err) | ||
| 586 | return err; | ||
| 587 | |||
| 588 | if (!dsa_is_user_port(priv->ds, reg)) | ||
| 589 | continue; | ||
| 590 | |||
| 591 | if (of_property_read_bool(port, "phy-handle")) | ||
| 592 | external_mdio_mask |= BIT(reg); | ||
| 593 | else | ||
| 594 | internal_mdio_mask |= BIT(reg); | ||
| 595 | } | ||
| 596 | |||
| 597 | if (!external_mdio_mask && !internal_mdio_mask) { | ||
| 598 | dev_err(priv->dev, "no PHYs are defined.\n"); | ||
| 599 | return -EINVAL; | ||
| 600 | } | ||
| 601 | |||
| 602 | /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through | ||
| 603 | * the MDIO_MASTER register also _disconnects_ the external MDC | ||
| 604 | * passthrough to the internal PHYs. It's not possible to use both | ||
| 605 | * configurations at the same time! | ||
| 606 | * | ||
| 607 | * Because this came up during the review process: | ||
| 608 | * If the external mdio-bus driver is capable magically disabling | ||
| 609 | * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's | ||
| 610 | * accessors for the time being, it would be possible to pull this | ||
| 611 | * off. | ||
| 612 | */ | ||
| 613 | if (!!external_mdio_mask && !!internal_mdio_mask) { | ||
| 614 | dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); | ||
| 615 | return -EINVAL; | ||
| 616 | } | ||
| 617 | |||
| 618 | if (external_mdio_mask) { | ||
| 619 | /* Make sure to disable the internal mdio bus in cases | ||
| 620 | * a dt-overlay and driver reload changed the configuration | ||
| 621 | */ | ||
| 622 | |||
| 623 | qca8k_reg_clear(priv, QCA8K_MDIO_MASTER_CTRL, | ||
| 624 | QCA8K_MDIO_MASTER_EN); | ||
| 625 | return 0; | ||
| 626 | } | ||
| 627 | |||
| 628 | priv->ops.phy_read = qca8k_phy_read; | ||
| 629 | priv->ops.phy_write = qca8k_phy_write; | ||
| 630 | return 0; | ||
| 631 | } | ||
| 632 | |||
| 484 | static int | 633 | static int |
| 485 | qca8k_setup(struct dsa_switch *ds) | 634 | qca8k_setup(struct dsa_switch *ds) |
| 486 | { | 635 | { |
| @@ -502,6 +651,10 @@ qca8k_setup(struct dsa_switch *ds) | |||
| 502 | if (IS_ERR(priv->regmap)) | 651 | if (IS_ERR(priv->regmap)) |
| 503 | pr_warn("regmap initialization failed"); | 652 | pr_warn("regmap initialization failed"); |
| 504 | 653 | ||
| 654 | ret = qca8k_setup_mdio_bus(priv); | ||
| 655 | if (ret) | ||
| 656 | return ret; | ||
| 657 | |||
| 505 | /* Initialize CPU port pad mode (xMII type, delays...) */ | 658 | /* Initialize CPU port pad mode (xMII type, delays...) */ |
| 506 | phy_mode = of_get_phy_mode(ds->ports[QCA8K_CPU_PORT].dn); | 659 | phy_mode = of_get_phy_mode(ds->ports[QCA8K_CPU_PORT].dn); |
| 507 | if (phy_mode < 0) { | 660 | if (phy_mode < 0) { |
| @@ -905,7 +1058,8 @@ qca8k_sw_probe(struct mdio_device *mdiodev) | |||
| 905 | return -ENOMEM; | 1058 | return -ENOMEM; |
| 906 | 1059 | ||
| 907 | priv->ds->priv = priv; | 1060 | priv->ds->priv = priv; |
| 908 | priv->ds->ops = &qca8k_switch_ops; | 1061 | priv->ops = qca8k_switch_ops; |
| 1062 | priv->ds->ops = &priv->ops; | ||
| 909 | mutex_init(&priv->reg_mutex); | 1063 | mutex_init(&priv->reg_mutex); |
| 910 | dev_set_drvdata(&mdiodev->dev, priv); | 1064 | dev_set_drvdata(&mdiodev->dev, priv); |
| 911 | 1065 | ||
diff --git a/drivers/net/dsa/qca8k.h b/drivers/net/dsa/qca8k.h index d146e54c8a6c..249fd62268e5 100644 --- a/drivers/net/dsa/qca8k.h +++ b/drivers/net/dsa/qca8k.h | |||
| @@ -49,6 +49,18 @@ | |||
| 49 | #define QCA8K_MIB_FLUSH BIT(24) | 49 | #define QCA8K_MIB_FLUSH BIT(24) |
| 50 | #define QCA8K_MIB_CPU_KEEP BIT(20) | 50 | #define QCA8K_MIB_CPU_KEEP BIT(20) |
| 51 | #define QCA8K_MIB_BUSY BIT(17) | 51 | #define QCA8K_MIB_BUSY BIT(17) |
| 52 | #define QCA8K_MDIO_MASTER_CTRL 0x3c | ||
| 53 | #define QCA8K_MDIO_MASTER_BUSY BIT(31) | ||
| 54 | #define QCA8K_MDIO_MASTER_EN BIT(30) | ||
| 55 | #define QCA8K_MDIO_MASTER_READ BIT(27) | ||
| 56 | #define QCA8K_MDIO_MASTER_WRITE 0 | ||
| 57 | #define QCA8K_MDIO_MASTER_SUP_PRE BIT(26) | ||
| 58 | #define QCA8K_MDIO_MASTER_PHY_ADDR(x) ((x) << 21) | ||
| 59 | #define QCA8K_MDIO_MASTER_REG_ADDR(x) ((x) << 16) | ||
| 60 | #define QCA8K_MDIO_MASTER_DATA(x) (x) | ||
| 61 | #define QCA8K_MDIO_MASTER_DATA_MASK GENMASK(15, 0) | ||
| 62 | #define QCA8K_MDIO_MASTER_MAX_PORTS 5 | ||
| 63 | #define QCA8K_MDIO_MASTER_MAX_REG 32 | ||
| 52 | #define QCA8K_GOL_MAC_ADDR0 0x60 | 64 | #define QCA8K_GOL_MAC_ADDR0 0x60 |
| 53 | #define QCA8K_GOL_MAC_ADDR1 0x64 | 65 | #define QCA8K_GOL_MAC_ADDR1 0x64 |
| 54 | #define QCA8K_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) | 66 | #define QCA8K_REG_PORT_STATUS(_i) (0x07c + (_i) * 4) |
| @@ -169,6 +181,7 @@ struct qca8k_priv { | |||
| 169 | struct dsa_switch *ds; | 181 | struct dsa_switch *ds; |
| 170 | struct mutex reg_mutex; | 182 | struct mutex reg_mutex; |
| 171 | struct device *dev; | 183 | struct device *dev; |
| 184 | struct dsa_switch_ops ops; | ||
| 172 | }; | 185 | }; |
| 173 | 186 | ||
| 174 | struct qca8k_mib_desc { | 187 | struct qca8k_mib_desc { |
