staging: mt7621-pci: use gpio perst instead of builtin behaviour [Linux 5.3]

This Linux kernel change "staging: mt7621-pci: use gpio perst instead of builtin behaviour" is included in the Linux 5.3 release. This change is authored by Sergio Paracuellos <sergio.paracuellos [at] gmail.com> on Wed Jun 19 09:44:56 2019 +0200. The commit for this change in Linux stable tree is 07420a0 (patch).

staging: mt7621-pci: use gpio perst instead of builtin behaviour

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>

There are 106 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/staging/mt7621-pci/pci-mt7621.c | 106 +++++++++++++++++---------------
 1 file changed, 58 insertions(+), 48 deletions(-)

diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c
index 7ba6ec9..de09bda 100644
--- a/drivers/staging/mt7621-pci/pci-mt7621.c
+++ b/drivers/staging/mt7621-pci/pci-mt7621.c
@@ -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++;
        }

Leave a Reply

Your email address will not be published. Required fields are marked *