#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)
struct device *dev;
void __iomem *base;
int irq;
+ struct fe_priv *priv;
/* Protects against concurrent register r/w operations. */
spinlock_t reg_rw_lock;
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;
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)
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";
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,