| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- From ba751e28d44255744a30190faad0ca09b455c44d Mon Sep 17 00:00:00 2001
- From: DENG Qingfang <[email protected]>
- Date: Wed, 19 May 2021 11:32:00 +0800
- Subject: [PATCH] net: dsa: mt7530: add interrupt support
- Add support for MT7530 interrupt controller to handle internal PHYs.
- In order to assign an IRQ number to each PHY, the registration of MDIO bus
- is also done in this driver.
- Signed-off-by: DENG Qingfang <[email protected]>
- Reviewed-by: Andrew Lunn <[email protected]>
- Reviewed-by: Florian Fainelli <[email protected]>
- Reviewed-by: Vladimir Oltean <[email protected]>
- Signed-off-by: David S. Miller <[email protected]>
- ---
- drivers/net/dsa/mt7530.c | 264 +++++++++++++++++++++++++++++++++++----
- drivers/net/dsa/mt7530.h | 20 ++-
- 2 files changed, 256 insertions(+), 28 deletions(-)
- --- a/drivers/net/dsa/mt7530.c
- +++ b/drivers/net/dsa/mt7530.c
- @@ -10,6 +10,7 @@
- #include <linux/mfd/syscon.h>
- #include <linux/module.h>
- #include <linux/netdevice.h>
- +#include <linux/of_irq.h>
- #include <linux/of_mdio.h>
- #include <linux/of_net.h>
- #include <linux/of_platform.h>
- @@ -603,18 +604,14 @@ mt7530_mib_reset(struct dsa_switch *ds)
- mt7530_write(priv, MT7530_MIB_CCR, CCR_MIB_ACTIVATE);
- }
-
- -static int mt7530_phy_read(struct dsa_switch *ds, int port, int regnum)
- +static int mt7530_phy_read(struct mt7530_priv *priv, int port, int regnum)
- {
- - struct mt7530_priv *priv = ds->priv;
- -
- return mdiobus_read_nested(priv->bus, port, regnum);
- }
-
- -static int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum,
- +static int mt7530_phy_write(struct mt7530_priv *priv, int port, int regnum,
- u16 val)
- {
- - struct mt7530_priv *priv = ds->priv;
- -
- return mdiobus_write_nested(priv->bus, port, regnum, val);
- }
-
- @@ -792,9 +789,8 @@ out:
- }
-
- static int
- -mt7531_ind_phy_read(struct dsa_switch *ds, int port, int regnum)
- +mt7531_ind_phy_read(struct mt7530_priv *priv, int port, int regnum)
- {
- - struct mt7530_priv *priv = ds->priv;
- int devad;
- int ret;
-
- @@ -810,10 +806,9 @@ mt7531_ind_phy_read(struct dsa_switch *d
- }
-
- static int
- -mt7531_ind_phy_write(struct dsa_switch *ds, int port, int regnum,
- +mt7531_ind_phy_write(struct mt7530_priv *priv, int port, int regnum,
- u16 data)
- {
- - struct mt7530_priv *priv = ds->priv;
- int devad;
- int ret;
-
- @@ -829,6 +824,22 @@ mt7531_ind_phy_write(struct dsa_switch *
- return ret;
- }
-
- +static int
- +mt753x_phy_read(struct mii_bus *bus, int port, int regnum)
- +{
- + struct mt7530_priv *priv = bus->priv;
- +
- + return priv->info->phy_read(priv, port, regnum);
- +}
- +
- +static int
- +mt753x_phy_write(struct mii_bus *bus, int port, int regnum, u16 val)
- +{
- + struct mt7530_priv *priv = bus->priv;
- +
- + return priv->info->phy_write(priv, port, regnum, val);
- +}
- +
- static void
- mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
- uint8_t *data)
- @@ -1796,6 +1807,210 @@ mt7530_setup_gpio(struct mt7530_priv *pr
- return devm_gpiochip_add_data(dev, gc, priv);
- }
-
- +static irqreturn_t
- +mt7530_irq_thread_fn(int irq, void *dev_id)
- +{
- + struct mt7530_priv *priv = dev_id;
- + bool handled = false;
- + u32 val;
- + int p;
- +
- + mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
- + val = mt7530_mii_read(priv, MT7530_SYS_INT_STS);
- + mt7530_mii_write(priv, MT7530_SYS_INT_STS, val);
- + mutex_unlock(&priv->bus->mdio_lock);
- +
- + for (p = 0; p < MT7530_NUM_PHYS; p++) {
- + if (BIT(p) & val) {
- + unsigned int irq;
- +
- + irq = irq_find_mapping(priv->irq_domain, p);
- + handle_nested_irq(irq);
- + handled = true;
- + }
- + }
- +
- + return IRQ_RETVAL(handled);
- +}
- +
- +static void
- +mt7530_irq_mask(struct irq_data *d)
- +{
- + struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
- +
- + priv->irq_enable &= ~BIT(d->hwirq);
- +}
- +
- +static void
- +mt7530_irq_unmask(struct irq_data *d)
- +{
- + struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
- +
- + priv->irq_enable |= BIT(d->hwirq);
- +}
- +
- +static void
- +mt7530_irq_bus_lock(struct irq_data *d)
- +{
- + struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
- +
- + mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
- +}
- +
- +static void
- +mt7530_irq_bus_sync_unlock(struct irq_data *d)
- +{
- + struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
- +
- + mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable);
- + mutex_unlock(&priv->bus->mdio_lock);
- +}
- +
- +static struct irq_chip mt7530_irq_chip = {
- + .name = KBUILD_MODNAME,
- + .irq_mask = mt7530_irq_mask,
- + .irq_unmask = mt7530_irq_unmask,
- + .irq_bus_lock = mt7530_irq_bus_lock,
- + .irq_bus_sync_unlock = mt7530_irq_bus_sync_unlock,
- +};
- +
- +static int
- +mt7530_irq_map(struct irq_domain *domain, unsigned int irq,
- + irq_hw_number_t hwirq)
- +{
- + irq_set_chip_data(irq, domain->host_data);
- + irq_set_chip_and_handler(irq, &mt7530_irq_chip, handle_simple_irq);
- + irq_set_nested_thread(irq, true);
- + irq_set_noprobe(irq);
- +
- + return 0;
- +}
- +
- +static const struct irq_domain_ops mt7530_irq_domain_ops = {
- + .map = mt7530_irq_map,
- + .xlate = irq_domain_xlate_onecell,
- +};
- +
- +static void
- +mt7530_setup_mdio_irq(struct mt7530_priv *priv)
- +{
- + struct dsa_switch *ds = priv->ds;
- + int p;
- +
- + for (p = 0; p < MT7530_NUM_PHYS; p++) {
- + if (BIT(p) & ds->phys_mii_mask) {
- + unsigned int irq;
- +
- + irq = irq_create_mapping(priv->irq_domain, p);
- + ds->slave_mii_bus->irq[p] = irq;
- + }
- + }
- +}
- +
- +static int
- +mt7530_setup_irq(struct mt7530_priv *priv)
- +{
- + struct device *dev = priv->dev;
- + struct device_node *np = dev->of_node;
- + int ret;
- +
- + if (!of_property_read_bool(np, "interrupt-controller")) {
- + dev_info(dev, "no interrupt support\n");
- + return 0;
- + }
- +
- + priv->irq = of_irq_get(np, 0);
- + if (priv->irq <= 0) {
- + dev_err(dev, "failed to get parent IRQ: %d\n", priv->irq);
- + return priv->irq ? : -EINVAL;
- + }
- +
- + priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
- + &mt7530_irq_domain_ops, priv);
- + if (!priv->irq_domain) {
- + dev_err(dev, "failed to create IRQ domain\n");
- + return -ENOMEM;
- + }
- +
- + /* This register must be set for MT7530 to properly fire interrupts */
- + if (priv->id != ID_MT7531)
- + mt7530_set(priv, MT7530_TOP_SIG_CTRL, TOP_SIG_CTRL_NORMAL);
- +
- + ret = request_threaded_irq(priv->irq, NULL, mt7530_irq_thread_fn,
- + IRQF_ONESHOT, KBUILD_MODNAME, priv);
- + if (ret) {
- + irq_domain_remove(priv->irq_domain);
- + dev_err(dev, "failed to request IRQ: %d\n", ret);
- + return ret;
- + }
- +
- + return 0;
- +}
- +
- +static void
- +mt7530_free_mdio_irq(struct mt7530_priv *priv)
- +{
- + int p;
- +
- + for (p = 0; p < MT7530_NUM_PHYS; p++) {
- + if (BIT(p) & priv->ds->phys_mii_mask) {
- + unsigned int irq;
- +
- + irq = irq_find_mapping(priv->irq_domain, p);
- + irq_dispose_mapping(irq);
- + }
- + }
- +}
- +
- +static void
- +mt7530_free_irq_common(struct mt7530_priv *priv)
- +{
- + free_irq(priv->irq, priv);
- + irq_domain_remove(priv->irq_domain);
- +}
- +
- +static void
- +mt7530_free_irq(struct mt7530_priv *priv)
- +{
- + mt7530_free_mdio_irq(priv);
- + mt7530_free_irq_common(priv);
- +}
- +
- +static int
- +mt7530_setup_mdio(struct mt7530_priv *priv)
- +{
- + struct dsa_switch *ds = priv->ds;
- + struct device *dev = priv->dev;
- + struct mii_bus *bus;
- + static int idx;
- + int ret;
- +
- + bus = devm_mdiobus_alloc(dev);
- + if (!bus)
- + return -ENOMEM;
- +
- + ds->slave_mii_bus = bus;
- + bus->priv = priv;
- + bus->name = KBUILD_MODNAME "-mii";
- + snprintf(bus->id, MII_BUS_ID_SIZE, KBUILD_MODNAME "-%d", idx++);
- + bus->read = mt753x_phy_read;
- + bus->write = mt753x_phy_write;
- + bus->parent = dev;
- + bus->phy_mask = ~ds->phys_mii_mask;
- +
- + if (priv->irq)
- + mt7530_setup_mdio_irq(priv);
- +
- + ret = devm_mdiobus_register(dev, bus);
- + if (ret) {
- + dev_err(dev, "failed to register MDIO bus: %d\n", ret);
- + if (priv->irq)
- + mt7530_free_mdio_irq(priv);
- + }
- +
- + return ret;
- +}
- +
- static int
- mt7530_setup(struct dsa_switch *ds)
- {
- @@ -2747,24 +2962,20 @@ static int
- mt753x_setup(struct dsa_switch *ds)
- {
- struct mt7530_priv *priv = ds->priv;
- + int ret = priv->info->sw_setup(ds);
-
- - return priv->info->sw_setup(ds);
- -}
- -
- -static int
- -mt753x_phy_read(struct dsa_switch *ds, int port, int regnum)
- -{
- - struct mt7530_priv *priv = ds->priv;
- + if (ret)
- + return ret;
-
- - return priv->info->phy_read(ds, port, regnum);
- -}
- + ret = mt7530_setup_irq(priv);
- + if (ret)
- + return ret;
-
- -static int
- -mt753x_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
- -{
- - struct mt7530_priv *priv = ds->priv;
- + ret = mt7530_setup_mdio(priv);
- + if (ret && priv->irq)
- + mt7530_free_irq_common(priv);
-
- - return priv->info->phy_write(ds, port, regnum, val);
- + return ret;
- }
-
- static int mt753x_get_mac_eee(struct dsa_switch *ds, int port,
- @@ -2801,8 +3012,6 @@ static const struct dsa_switch_ops mt753
- .get_tag_protocol = mtk_get_tag_protocol,
- .setup = mt753x_setup,
- .get_strings = mt7530_get_strings,
- - .phy_read = mt753x_phy_read,
- - .phy_write = mt753x_phy_write,
- .get_ethtool_stats = mt7530_get_ethtool_stats,
- .get_sset_count = mt7530_get_sset_count,
- .set_ageing_time = mt7530_set_ageing_time,
- @@ -2985,6 +3194,9 @@ mt7530_remove(struct mdio_device *mdiode
- dev_err(priv->dev, "Failed to disable io pwr: %d\n",
- ret);
-
- + if (priv->irq)
- + mt7530_free_irq(priv);
- +
- dsa_unregister_switch(priv->ds);
- mutex_destroy(&priv->reg_mutex);
- }
- --- a/drivers/net/dsa/mt7530.h
- +++ b/drivers/net/dsa/mt7530.h
- @@ -7,6 +7,7 @@
- #define __MT7530_H
-
- #define MT7530_NUM_PORTS 7
- +#define MT7530_NUM_PHYS 5
- #define MT7530_CPU_PORT 6
- #define MT7530_NUM_FDB_RECORDS 2048
- #define MT7530_ALL_MEMBERS 0xff
- @@ -392,6 +393,12 @@ enum mt7531_sgmii_force_duplex {
- #define SYS_CTRL_SW_RST BIT(1)
- #define SYS_CTRL_REG_RST BIT(0)
-
- +/* Register for system interrupt */
- +#define MT7530_SYS_INT_EN 0x7008
- +
- +/* Register for system interrupt status */
- +#define MT7530_SYS_INT_STS 0x700c
- +
- /* Register for PHY Indirect Access Control */
- #define MT7531_PHY_IAC 0x701C
- #define MT7531_PHY_ACS_ST BIT(31)
- @@ -713,6 +720,8 @@ static const char *p5_intf_modes(unsigne
- }
- }
-
- +struct mt7530_priv;
- +
- /* struct mt753x_info - This is the main data structure for holding the specific
- * part for each supported device
- * @sw_setup: Holding the handler to a device initialization
- @@ -737,8 +746,8 @@ struct mt753x_info {
- enum mt753x_id id;
-
- int (*sw_setup)(struct dsa_switch *ds);
- - int (*phy_read)(struct dsa_switch *ds, int port, int regnum);
- - int (*phy_write)(struct dsa_switch *ds, int port, int regnum, u16 val);
- + int (*phy_read)(struct mt7530_priv *priv, int port, int regnum);
- + int (*phy_write)(struct mt7530_priv *priv, int port, int regnum, u16 val);
- int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface);
- int (*cpu_port_config)(struct dsa_switch *ds, int port);
- bool (*phy_mode_supported)(struct dsa_switch *ds, int port,
- @@ -772,6 +781,10 @@ struct mt753x_info {
- * registers
- * @p6_interface Holding the current port 6 interface
- * @p5_intf_sel: Holding the current port 5 interface select
- + *
- + * @irq: IRQ number of the switch
- + * @irq_domain: IRQ domain of the switch irq_chip
- + * @irq_enable: IRQ enable bits, synced to SYS_INT_EN
- */
- struct mt7530_priv {
- struct device *dev;
- @@ -793,6 +806,9 @@ struct mt7530_priv {
- struct mt7530_port ports[MT7530_NUM_PORTS];
- /* protect among processes for registers access*/
- struct mutex reg_mutex;
- + int irq;
- + struct irq_domain *irq_domain;
- + u32 irq_enable;
- };
-
- struct mt7530_hw_vlan_entry {
|