diff options
Diffstat (limited to 'drivers/net/dsa/qca8k.c')
| -rw-r--r-- | drivers/net/dsa/qca8k.c | 74 | 
1 files changed, 60 insertions, 14 deletions
diff --git a/drivers/net/dsa/qca8k.c b/drivers/net/dsa/qca8k.c index 600d5ad1fbde..cdcde7f8e0b2 100644 --- a/drivers/net/dsa/qca8k.c +++ b/drivers/net/dsa/qca8k.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>   * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>   * Copyright (c) 2015, The Linux Foundation. All rights reserved.   * Copyright (c) 2016 John Crispin <john@phrozen.org> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details.   */  #include <linux/module.h> @@ -473,10 +465,10 @@ qca8k_set_pad_ctrl(struct qca8k_priv *priv, int port, int mode)  static void  qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)  { -	u32 mask = QCA8K_PORT_STATUS_TXMAC; +	u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;  	/* Port 0 and 6 have no internal PHY */ -	if ((port > 0) && (port < 6)) +	if (port > 0 && port < 6)  		mask |= QCA8K_PORT_STATUS_LINK_AUTO;  	if (enable) @@ -490,6 +482,7 @@ qca8k_setup(struct dsa_switch *ds)  {  	struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;  	int ret, i, phy_mode = -1; +	u32 mask;  	/* Make sure that port 0 is the cpu port */  	if (!dsa_is_cpu_port(ds, 0)) { @@ -515,7 +508,10 @@ qca8k_setup(struct dsa_switch *ds)  	if (ret < 0)  		return ret; -	/* Enable CPU Port */ +	/* Enable CPU Port, force it to maximum bandwidth and full-duplex */ +	mask = QCA8K_PORT_STATUS_SPEED_1000 | QCA8K_PORT_STATUS_TXFLOW | +	       QCA8K_PORT_STATUS_RXFLOW | QCA8K_PORT_STATUS_DUPLEX; +	qca8k_write(priv, QCA8K_REG_PORT_STATUS(QCA8K_CPU_PORT), mask);  	qca8k_reg_set(priv, QCA8K_REG_GLOBAL_FW_CTRL0,  		      QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN);  	qca8k_port_set_status(priv, QCA8K_CPU_PORT, 1); @@ -583,6 +579,47 @@ qca8k_setup(struct dsa_switch *ds)  	return 0;  } +static void +qca8k_adjust_link(struct dsa_switch *ds, int port, struct phy_device *phy) +{ +	struct qca8k_priv *priv = ds->priv; +	u32 reg; + +	/* Force fixed-link setting for CPU port, skip others. */ +	if (!phy_is_pseudo_fixed_link(phy)) +		return; + +	/* Set port speed */ +	switch (phy->speed) { +	case 10: +		reg = QCA8K_PORT_STATUS_SPEED_10; +		break; +	case 100: +		reg = QCA8K_PORT_STATUS_SPEED_100; +		break; +	case 1000: +		reg = QCA8K_PORT_STATUS_SPEED_1000; +		break; +	default: +		dev_dbg(priv->dev, "port%d link speed %dMbps not supported.\n", +			port, phy->speed); +		return; +	} + +	/* Set duplex mode */ +	if (phy->duplex == DUPLEX_FULL) +		reg |= QCA8K_PORT_STATUS_DUPLEX; + +	/* Force flow control */ +	if (dsa_is_cpu_port(ds, port)) +		reg |= QCA8K_PORT_STATUS_RXFLOW | QCA8K_PORT_STATUS_TXFLOW; + +	/* Force link down before changing MAC options */ +	qca8k_port_set_status(priv, port, 0); +	qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); +	qca8k_port_set_status(priv, port, 1); +} +  static int  qca8k_phy_read(struct dsa_switch *ds, int phy, int regnum)  { @@ -600,10 +637,13 @@ qca8k_phy_write(struct dsa_switch *ds, int phy, int regnum, u16 val)  }  static void -qca8k_get_strings(struct dsa_switch *ds, int port, uint8_t *data) +qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset, uint8_t *data)  {  	int i; +	if (stringset != ETH_SS_STATS) +		return; +  	for (i = 0; i < ARRAY_SIZE(ar8327_mib); i++)  		strncpy(data + i * ETH_GSTRING_LEN, ar8327_mib[i].name,  			ETH_GSTRING_LEN); @@ -631,8 +671,11 @@ qca8k_get_ethtool_stats(struct dsa_switch *ds, int port,  }  static int -qca8k_get_sset_count(struct dsa_switch *ds, int port) +qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset)  { +	if (sset != ETH_SS_STATS) +		return 0; +  	return ARRAY_SIZE(ar8327_mib);  } @@ -831,6 +874,7 @@ qca8k_get_tag_protocol(struct dsa_switch *ds, int port)  static const struct dsa_switch_ops qca8k_switch_ops = {  	.get_tag_protocol	= qca8k_get_tag_protocol,  	.setup			= qca8k_setup, +	.adjust_link            = qca8k_adjust_link,  	.get_strings		= qca8k_get_strings,  	.phy_read		= qca8k_phy_read,  	.phy_write		= qca8k_phy_write, @@ -862,6 +906,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev)  		return -ENOMEM;  	priv->bus = mdiodev->bus; +	priv->dev = &mdiodev->dev;  	/* read the switches ID register */  	id = qca8k_read(priv, QCA8K_REG_MASK_CTRL); @@ -933,6 +978,7 @@ static SIMPLE_DEV_PM_OPS(qca8k_pm_ops,  			 qca8k_suspend, qca8k_resume);  static const struct of_device_id qca8k_of_match[] = { +	{ .compatible = "qca,qca8334" },  	{ .compatible = "qca,qca8337" },  	{ /* sentinel */ },  };  | 
