staging: mt7621-pci: use gpio perst instead of builtin behaviour
authorSergio Paracuellos <sergio.paracuellos@gmail.com>
Wed, 19 Jun 2019 07:44:56 +0000 (09:44 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 20 Jun 2019 12:45:49 +0000 (14:45 +0200)
Some boards seems to ignore the PERST builtin behaviour to properly
perform a pcie line reset. Use gpio PERST behaviour instead which
seems to be more common.

Fixes: bd1a05bd87ad ("staging: mt7621-pci: use PERST_N instead of gpio control")
Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/mt7621-pci/pci-mt7621.c

index 7ba6ec93ac0f1e786a0dfad0536f10c0ac9cd135..de09bda0b4cd4302d838707fb0af41a5a4649852 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/gpio/consumer.h>
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -35,6 +36,7 @@
 
 /* sysctl */
 #define MT7621_CHIP_REV_ID             0x0c
+#define MT7621_GPIO_MODE               0x60
 #define CHIP_REV_MT7621_E2             0x0101
 
 /* MediaTek specific configuration registers */
@@ -81,7 +83,6 @@
 #define PCIE_BAR_ENABLE                        BIT(0)
 #define PCIE_PORT_INT_EN(x)            BIT(20 + (x))
 #define PCIE_PORT_CLK_EN(x)            BIT(24 + (x))
-#define PCIE_PORT_PERST(x)             BIT(1 + (x))
 #define PCIE_PORT_LINKUP               BIT(0)
 
 #define PCIE_CLK_GEN_EN                        BIT(31)
@@ -89,6 +90,9 @@
 #define PCIE_CLK_GEN1_DIS              GENMASK(30, 24)
 #define PCIE_CLK_GEN1_EN               (BIT(27) | BIT(25))
 #define MEMORY_BASE                    0x0
+#define PERST_MODE_MASK                        GENMASK(11, 10)
+#define PERST_MODE_GPIO                        BIT(10)
+#define PERST_DELAY_US                 1000
 
 /**
  * struct mt7621_pcie_port - PCIe port information
@@ -119,6 +123,7 @@ struct mt7621_pcie_port {
  * @offset: IO / Memory offset
  * @dev: Pointer to PCIe device
  * @ports: pointer to PCIe port information
+ * @perst: gpio reset
  * @rst: pointer to pcie reset
  */
 struct mt7621_pcie {
@@ -132,6 +137,7 @@ struct mt7621_pcie {
                resource_size_t io;
        } offset;
        struct list_head ports;
+       struct gpio_desc *perst;
        struct reset_control *rst;
 };
 
@@ -198,6 +204,23 @@ static void write_config(struct mt7621_pcie *pcie, unsigned int dev,
        pcie_write(pcie, val, RALINK_PCI_CONFIG_DATA);
 }
 
+static inline void mt7621_perst_gpio_pcie_assert(struct mt7621_pcie *pcie)
+{
+       gpiod_set_value(pcie->perst, 0);
+       mdelay(PERST_DELAY_US);
+}
+
+static inline void mt7621_perst_gpio_pcie_deassert(struct mt7621_pcie *pcie)
+{
+       gpiod_set_value(pcie->perst, 1);
+       mdelay(PERST_DELAY_US);
+}
+
+static inline bool mt7621_pcie_port_is_linkup(struct mt7621_pcie_port *port)
+{
+       return (pcie_port_read(port, RALINK_PCI_STATUS) & PCIE_PORT_LINKUP) != 0;
+}
+
 static inline void mt7621_control_assert(struct mt7621_pcie_port *port)
 {
        u32 chip_rev_id = rt_sysc_r32(MT7621_CHIP_REV_ID);
@@ -344,6 +367,12 @@ static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie)
        struct resource regs;
        int err;
 
+       pcie->perst = devm_gpiod_get(dev, "perst", GPIOD_OUT_HIGH);
+       if (IS_ERR(pcie->perst)) {
+               dev_err(dev, "failed to get gpio perst\n");
+               return PTR_ERR(pcie->perst);
+       }
+
        err = of_address_to_resource(node, 0, &regs);
        if (err) {
                dev_err(dev, "missing \"reg\" property\n");
@@ -384,7 +413,6 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port)
        struct mt7621_pcie *pcie = port->pcie;
        struct device *dev = pcie->dev;
        u32 slot = port->slot;
-       u32 val = 0;
        int err;
 
        /*
@@ -393,47 +421,34 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port)
         */
        mt7621_reset_port(port);
 
-       val = read_config(pcie, slot, PCIE_FTS_NUM);
-       dev_info(dev, "Port %d N_FTS = %x\n", slot, (unsigned int)val);
-
        err = phy_init(port->phy);
        if (err) {
                dev_err(dev, "failed to initialize port%d phy\n", slot);
-               goto err_phy_init;
+               return err;
        }
 
        err = phy_power_on(port->phy);
        if (err) {
                dev_err(dev, "failed to power on port%d phy\n", slot);
-               goto err_phy_on;
-       }
-
-       if ((pcie_port_read(port, RALINK_PCI_STATUS) & PCIE_PORT_LINKUP) == 0) {
-               dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n", slot);
-               mt7621_control_assert(port);
-               port->enabled = false;
-               err = -ENODEV;
-               goto err_no_link_up;
+               return err;
        }
 
        port->enabled = true;
 
        return 0;
-
-err_no_link_up:
-       phy_power_off(port->phy);
-err_phy_on:
-       phy_exit(port->phy);
-err_phy_init:
-       return err;
 }
 
 static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
 {
        struct device *dev = pcie->dev;
        struct mt7621_pcie_port *port, *tmp;
+       u32 val = 0;
        int err;
 
+       rt_sysc_m32(PERST_MODE_MASK, PERST_MODE_GPIO, MT7621_GPIO_MODE);
+
+       mt7621_perst_gpio_pcie_assert(pcie);
+
        list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
                u32 slot = port->slot;
 
@@ -441,10 +456,29 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
                if (err) {
                        dev_err(dev, "Initiating port %d failed\n", slot);
                        list_del(&port->list);
+               } else {
+                       val = read_config(pcie, slot, PCIE_FTS_NUM);
+                       dev_info(dev, "Port %d N_FTS = %x\n", slot,
+                                (unsigned int)val);
                }
        }
 
        reset_control_assert(pcie->rst);
+
+       mt7621_perst_gpio_pcie_deassert(pcie);
+
+       list_for_each_entry(port, &pcie->ports, list) {
+               u32 slot = port->slot;
+
+               if (!mt7621_pcie_port_is_linkup(port)) {
+                       dev_err(dev, "pcie%d no card, disable it (RST & CLK)\n",
+                               slot);
+                       phy_power_off(port->phy);
+                       mt7621_control_assert(port);
+                       port->enabled = false;
+               }
+       }
+
        rt_sysc_m32(0x30, 2 << 4, SYSC_REG_SYSTEM_CONFIG1);
        rt_sysc_m32(PCIE_CLK_GEN_EN, PCIE_CLK_GEN_DIS, RALINK_PCIE_CLK_GEN);
        rt_sysc_m32(PCIE_CLK_GEN1_DIS, PCIE_CLK_GEN1_EN, RALINK_PCIE_CLK_GEN1);
@@ -453,30 +487,12 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
        reset_control_deassert(pcie->rst);
 }
 
-static int mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
+static void mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
 {
        struct mt7621_pcie *pcie = port->pcie;
        u32 slot = port->slot;
        u32 offset = MT7621_PCIE_OFFSET + (slot * MT7621_NEXT_PORT);
        u32 val;
-       int err;
-
-       /* assert port PERST_N */
-       val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
-       val |= PCIE_PORT_PERST(slot);
-       pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
-
-       /* de-assert port PERST_N */
-       val = pcie_read(pcie, RALINK_PCI_PCICFG_ADDR);
-       val &= ~PCIE_PORT_PERST(slot);
-       pcie_write(pcie, val, RALINK_PCI_PCICFG_ADDR);
-
-       /* 100ms timeout value should be enough for Gen1 training */
-       err = readl_poll_timeout(port->base + RALINK_PCI_STATUS,
-                                val, !!(val & PCIE_PORT_LINKUP),
-                                20, 100 * USEC_PER_MSEC);
-       if (err)
-               return -ETIMEDOUT;
 
        /* enable pcie interrupt */
        val = pcie_read(pcie, RALINK_PCI_PCIMSK_ADDR);
@@ -492,8 +508,6 @@ static int mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
        /* configure class code and revision ID */
        pcie_write(pcie, PCIE_CLASS_CODE | PCIE_REVISION_ID,
                   offset + RALINK_PCI_CLASS);
-
-       return 0;
 }
 
 static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie)
@@ -506,11 +520,7 @@ static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie)
 
        list_for_each_entry(port, &pcie->ports, list) {
                if (port->enabled) {
-                       if (mt7621_pcie_enable_port(port)) {
-                               dev_err(dev, "de-assert port %d PERST_N\n",
-                                       port->slot);
-                               continue;
-                       }
+                       mt7621_pcie_enable_port(port);
                        dev_info(dev, "PCIE%d enabled\n", num_slots_enabled);
                        num_slots_enabled++;
                }