Skip to content

Commit

Permalink
ramips: ethernet: ralink: rewrite esw_rt3050 to support link states
Browse files Browse the repository at this point in the history
Ensure the esw is initialized before the ethernet device is sending
packets. Further implement carrier detection similar to mt7620.
If any port has a link, the ethernet device will detect a carrier.

Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
  • Loading branch information
lynxis committed Jun 25, 2021
1 parent 74c58c9 commit 8569bc5
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 45 deletions.
142 changes: 97 additions & 45 deletions target/linux/ramips/files/drivers/net/ethernet/ralink/esw_rt3050.c
Expand Up @@ -24,6 +24,7 @@
#include <linux/reset.h>

#include "mtk_eth_soc.h"
#include "esw_rt3050.h"

/* HW limitations for this switch:
* - No large frame support (PKT_MAX_LEN at most 1536)
Expand Down Expand Up @@ -216,6 +217,7 @@ struct rt305x_esw {
struct device *dev;
void __iomem *base;
int irq;
struct fe_priv *priv;

/* Protects against concurrent register r/w operations. */
spinlock_t reg_rw_lock;
Expand Down Expand Up @@ -736,19 +738,44 @@ static void esw_hw_init(struct rt305x_esw *esw)
esw_w32(esw, ~RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_IMR);
}


int rt3050_esw_has_carrier(struct fe_priv *priv)
{
struct rt305x_esw *esw = priv->soc->swpriv;
u32 link;
int i;
bool cpuport;

link = esw_r32(esw, RT305X_ESW_REG_POA);
link >>= RT305X_ESW_POA_LINK_SHIFT;
cpuport = link & BIT(RT305X_ESW_PORT6);
link &= RT305X_ESW_POA_LINK_MASK;
for (i = 0; i <= RT305X_ESW_PORT5; i++) {
if (priv->link[i] != (link & BIT(i)))
dev_info(esw->dev, "port %d link %s\n", i, link & BIT(i) ? "up" : "down");
priv->link[i] = link & BIT(i);
}

return !!link && cpuport;
}

static irqreturn_t esw_interrupt(int irq, void *_esw)
{
struct rt305x_esw *esw = (struct rt305x_esw *)_esw;
struct rt305x_esw *esw = (struct rt305x_esw *) _esw;
u32 status;
int i;

status = esw_r32(esw, RT305X_ESW_REG_ISR);
if (status & RT305X_ESW_PORT_ST_CHG) {
u32 link = esw_r32(esw, RT305X_ESW_REG_POA);

link >>= RT305X_ESW_POA_LINK_SHIFT;
link &= RT305X_ESW_POA_LINK_MASK;
dev_info(esw->dev, "link changed 0x%02X\n", link);
if (!esw->priv)
goto out;
if (rt3050_esw_has_carrier(esw->priv))
netif_carrier_on(esw->priv->netdev);
else
netif_carrier_off(esw->priv->netdev);
}

out:
esw_w32(esw, status, RT305X_ESW_REG_ISR);

return IRQ_HANDLED;
Expand Down Expand Up @@ -1376,9 +1403,7 @@ static int esw_probe(struct platform_device *pdev)
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct device_node *np = pdev->dev.of_node;
const __be32 *port_map, *port_disable, *reg_init;
struct switch_dev *swdev;
struct rt305x_esw *esw;
int ret;

esw = devm_kzalloc(&pdev->dev, sizeof(*esw), GFP_KERNEL);
if (!esw)
Expand Down Expand Up @@ -1417,6 +1442,67 @@ static int esw_probe(struct platform_device *pdev)
if (IS_ERR(esw->rst_ephy))
esw->rst_ephy = NULL;

spin_lock_init(&esw->reg_rw_lock);
platform_set_drvdata(pdev, esw);

return 0;
}

static int esw_remove(struct platform_device *pdev)
{
struct rt305x_esw *esw = platform_get_drvdata(pdev);

if (esw) {
esw_w32(esw, ~0, RT305X_ESW_REG_IMR);
platform_set_drvdata(pdev, NULL);
}

return 0;
}

static const struct of_device_id ralink_esw_match[] = {
{ .compatible = "ralink,rt3050-esw" },
{},
};
MODULE_DEVICE_TABLE(of, ralink_esw_match);

/* called by the ethernet driver to bound with the switch driver */
int rt3050_esw_init(struct fe_priv *priv)
{
struct device_node *np = priv->switch_np;
struct platform_device *pdev = of_find_device_by_node(np);
struct switch_dev *swdev;
struct rt305x_esw *esw;
const __be32 *rgmii;
int ret;

if (!pdev)
return -ENODEV;

if (!of_device_is_compatible(np, ralink_esw_match->compatible))
return -EINVAL;

esw = platform_get_drvdata(pdev);
if (!esw)
return -EPROBE_DEFER;

priv->soc->swpriv = esw;
esw->priv = priv;

esw_hw_init(esw);

rgmii = of_get_property(np, "ralink,rgmii", NULL);
if (rgmii && be32_to_cpu(*rgmii) == 1) {
/*
* External switch connected to RGMII interface.
* Unregister the switch device after initialization.
*/
dev_err(&pdev->dev, "RGMII mode, not exporting switch device.\n");
unregister_switch(&esw->swdev);
platform_set_drvdata(pdev, NULL);
return -ENODEV;
}

swdev = &esw->swdev;
swdev->of_node = pdev->dev.of_node;
swdev->name = "rt305x-esw";
Expand All @@ -1432,53 +1518,19 @@ static int esw_probe(struct platform_device *pdev)
return ret;
}

platform_set_drvdata(pdev, esw);

spin_lock_init(&esw->reg_rw_lock);

esw_hw_init(esw);

reg_init = of_get_property(np, "ralink,rgmii", NULL);
if (reg_init && be32_to_cpu(*reg_init) == 1) {
/*
* External switch connected to RGMII interface.
* Unregister the switch device after initialization.
*/
dev_err(&pdev->dev, "RGMII mode, not exporting switch device.\n");
unregister_switch(&esw->swdev);
platform_set_drvdata(pdev, NULL);
return -ENODEV;
}

ret = devm_request_irq(&pdev->dev, esw->irq, esw_interrupt, 0, "esw",
esw);

esw);
if (!ret) {
esw_w32(esw, RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_ISR);
esw_w32(esw, ~RT305X_ESW_PORT_ST_CHG, RT305X_ESW_REG_IMR);
}

return ret;
}

static int esw_remove(struct platform_device *pdev)
{
struct rt305x_esw *esw = platform_get_drvdata(pdev);

if (esw) {
esw_w32(esw, ~0, RT305X_ESW_REG_IMR);
platform_set_drvdata(pdev, NULL);
}
dev_info(&pdev->dev, "mediatek esw at 0x%08lx, irq %d initialized\n",
esw->base, esw->irq);

return 0;
}

static const struct of_device_id ralink_esw_match[] = {
{ .compatible = "ralink,rt3050-esw" },
{},
};
MODULE_DEVICE_TABLE(of, ralink_esw_match);

static struct platform_driver esw_driver = {
.probe = esw_probe,
.remove = esw_remove,
Expand Down
Expand Up @@ -26,4 +26,7 @@ static inline int __init mtk_switch_init(void) { return 0; }
static inline void mtk_switch_exit(void) { }

#endif

int rt3050_esw_init(struct fe_priv *priv);
int rt3050_esw_has_carrier(struct fe_priv *priv);
#endif
Expand Up @@ -17,6 +17,7 @@
#include <asm/mach-ralink/ralink_regs.h>

#include "mtk_eth_soc.h"
#include "esw_rt3050.h"
#include "mdio_rt2880.h"

static const u16 rt5350_reg_table[FE_REG_COUNT] = {
Expand Down Expand Up @@ -115,6 +116,7 @@ static void rt5350_tx_dma(struct fe_tx_dma *txd)
static struct fe_soc_data rt3050_data = {
.init_data = rt305x_init_data,
.fwd_config = rt3050_fwd_config,
.switch_init = rt3050_esw_init,
.pdma_glo_cfg = FE_PDMA_SIZE_8DWORDS,
.checksum_bit = RX_DMA_L4VALID,
.rx_int = FE_RX_DONE_INT,
Expand All @@ -127,6 +129,7 @@ static struct fe_soc_data rt5350_data = {
.reg_table = rt5350_reg_table,
.set_mac = rt5350_set_mac,
.fwd_config = rt5350_fwd_config,
.switch_init = rt3050_esw_init,
.tx_dma = rt5350_tx_dma,
.pdma_glo_cfg = FE_PDMA_SIZE_8DWORDS,
.checksum_bit = RX_DMA_L4VALID,
Expand Down

0 comments on commit 8569bc5

Please sign in to comment.