| @@ -1,17 +1,9 @@ |
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
| 1 | 2 | /* |
| 2 | 3 | * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name> |
| 3 | 4 | * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org> |
| 4 | 5 | * Copyright (c) 2015, The Linux Foundation. All rights reserved. |
| 5 | 6 | * Copyright (c) 2016 John Crispin <john@phrozen.org> |
| 6 | | − * |
| 7 | | − * This program is free software; you can redistribute it and/or modify |
| 8 | | − * it under the terms of the GNU General Public License version 2 and |
| 9 | | − * only version 2 as published by the Free Software Foundation. |
| 10 | | − * |
| 11 | | − * This program is distributed in the hope that it will be useful, |
| 12 | | − * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | | − * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | | − * GNU General Public License for more details. |
| 15 | 7 | */ |
| 16 | 8 | |
| 17 | 9 | #include <linux/module.h> |
| @@ -473,10 +465,10 @@ qca8k_set_pad_ctrl(struct qca8k_priv *priv, int port, int mode) · 455 unmodified lines |
| 473 | 465 | static void |
| 474 | 466 | qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable) |
| 475 | 467 | { |
| 476 | | − u32 mask = QCA8K_PORT_STATUS_TXMAC; |
| 468 | + u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; |
| 477 | 469 | |
| 478 | 470 | /* Port 0 and 6 have no internal PHY */ |
| 479 | | − if ((port > 0) && (port < 6)) |
| 471 | + if (port > 0 && port < 6) |
| 480 | 472 | mask |= QCA8K_PORT_STATUS_LINK_AUTO; |
| 481 | 473 | |
| 482 | 474 | if (enable) |
| @@ -490,6 +482,7 @@ qca8k_setup(struct dsa_switch *ds) · 7 unmodified lines |
| 490 | 482 | { |
| 491 | 483 | struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; |
| 492 | 484 | int ret, i, phy_mode = -1; |
| 485 | + u32 mask; |
| 493 | 486 | |
| 494 | 487 | /* Make sure that port 0 is the cpu port */ |
| 495 | 488 | if (!dsa_is_cpu_port(ds, 0)) { |
| @@ -515,7 +508,10 @@ qca8k_setup(struct dsa_switch *ds) · 19 unmodified lines |
| 515 | 508 | if (ret < 0) |
| 516 | 509 | return ret; |
| 517 | 510 | |
| 518 | | − /* Enable CPU Port */ |
| 511 | + /* Enable CPU Port, force it to maximum bandwidth and full-duplex */ |
| 512 | + mask = QCA8K_PORT_STATUS_SPEED_1000 | QCA8K_PORT_STATUS_TXFLOW | |
| 513 | + QCA8K_PORT_STATUS_RXFLOW | QCA8K_PORT_STATUS_DUPLEX; |
| 514 | + qca8k_write(priv, QCA8K_REG_PORT_STATUS(QCA8K_CPU_PORT), mask); |
| 519 | 515 | qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0, |
| 520 | 516 | QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); |
| 521 | 517 | qca8k_port_set_status(priv, QCA8K_CPU_PORT, 1); |
| @@ -583,6 +579,47 @@ qca8k_setup(struct dsa_switch *ds) · 61 unmodified lines |
| 583 | 579 | return 0; |
| 584 | 580 | } |
| 585 | 581 | |
| 582 | +static void |
| 583 | +qca8k_adjust_link(struct dsa_switch *ds, int port, struct phy_device *phy) |
| 584 | +{ |
| 585 | + struct qca8k_priv *priv = ds->priv; |
| 586 | + u32 reg; |
| 587 | + |
| 588 | + /* Force fixed-link setting for CPU port, skip others. */ |
| 589 | + if (!phy_is_pseudo_fixed_link(phy)) |
| 590 | + return; |
| 591 | + |
| 592 | + /* Set port speed */ |
| 593 | + switch (phy->speed) { |
| 594 | + case 10: |
| 595 | + reg = QCA8K_PORT_STATUS_SPEED_10; |
| 596 | + break; |
| 597 | + case 100: |
| 598 | + reg = QCA8K_PORT_STATUS_SPEED_100; |
| 599 | + break; |
| 600 | + case 1000: |
| 601 | + reg = QCA8K_PORT_STATUS_SPEED_1000; |
| 602 | + break; |
| 603 | + default: |
| 604 | + dev_dbg(priv->dev, "port%d link speed %dMbps not supported.\n", |
| 605 | + port, phy->speed); |
| 606 | + return; |
| 607 | + } |
| 608 | + |
| 609 | + /* Set duplex mode */ |
| 610 | + if (phy->duplex == DUPLEX_FULL) |
| 611 | + reg |= QCA8K_PORT_STATUS_DUPLEX; |
| 612 | + |
| 613 | + /* Force flow control */ |
| 614 | + if (dsa_is_cpu_port(ds, port)) |
| 615 | + reg |= QCA8K_PORT_STATUS_RXFLOW | QCA8K_PORT_STATUS_TXFLOW; |
| 616 | + |
| 617 | + /* Force link down before changing MAC options */ |
| 618 | + qca8k_port_set_status(priv, port, 0); |
| 619 | + qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); |
| 620 | + qca8k_port_set_status(priv, port, 1); |
| 621 | +} |
| 622 | + |
| 586 | 623 | static int |
| 587 | 624 | qca8k_phy_read(struct dsa_switch *ds, int phy, int regnum) |
| 588 | 625 | { |
| @@ -837,6 +874,7 @@ qca8k_get_tag_protocol(struct dsa_switch *ds, int port) · 248 unmodified lines |
| 837 | 874 | static const struct dsa_switch_ops qca8k_switch_ops = { |
| 838 | 875 | .get_tag_protocol = qca8k_get_tag_protocol, |
| 839 | 876 | .setup = qca8k_setup, |
| 877 | + .adjust_link = qca8k_adjust_link, |
| 840 | 878 | .get_strings = qca8k_get_strings, |
| 841 | 879 | .phy_read = qca8k_phy_read, |
| 842 | 880 | .phy_write = qca8k_phy_write, |
| @@ -868,6 +906,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev) · 25 unmodified lines |
| 868 | 906 | return -ENOMEM; |
| 869 | 907 | |
| 870 | 908 | priv->bus = mdiodev->bus; |
| 909 | + priv->dev = &mdiodev->dev; |
| 871 | 910 | |
| 872 | 911 | /* read the switches ID register */ |
| 873 | 912 | id = qca8k_read(priv, QCA8K_REG_MASK_CTRL); |
| @@ -939,6 +978,7 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, · 65 unmodified lines |
| 939 | 978 | qca8k_suspend, qca8k_resume); |
| 940 | 979 | |
| 941 | 980 | static const struct of_device_id qca8k_of_match[] = { |
| 981 | + { .compatible = "qca,qca8334" }, |
| 942 | 982 | { .compatible = "qca,qca8337" }, |
| 943 | 983 | { /* sentinel */ }, |
| 944 | 984 | }; |