Commit 07420a02 authored by Sergio Paracuellos's avatar Sergio Paracuellos Committed by Greg Kroah-Hartman

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: bd1a05bd ("staging: mt7621-pci: use PERST_N instead of gpio control")
Signed-off-by: default avatarSergio Paracuellos <sergio.paracuellos@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent fdd228cd
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -35,6 +36,7 @@ ...@@ -35,6 +36,7 @@
/* sysctl */ /* sysctl */
#define MT7621_CHIP_REV_ID 0x0c #define MT7621_CHIP_REV_ID 0x0c
#define MT7621_GPIO_MODE 0x60
#define CHIP_REV_MT7621_E2 0x0101 #define CHIP_REV_MT7621_E2 0x0101
/* MediaTek specific configuration registers */ /* MediaTek specific configuration registers */
...@@ -81,7 +83,6 @@ ...@@ -81,7 +83,6 @@
#define PCIE_BAR_ENABLE BIT(0) #define PCIE_BAR_ENABLE BIT(0)
#define PCIE_PORT_INT_EN(x) BIT(20 + (x)) #define PCIE_PORT_INT_EN(x) BIT(20 + (x))
#define PCIE_PORT_CLK_EN(x) BIT(24 + (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_PORT_LINKUP BIT(0)
#define PCIE_CLK_GEN_EN BIT(31) #define PCIE_CLK_GEN_EN BIT(31)
...@@ -89,6 +90,9 @@ ...@@ -89,6 +90,9 @@
#define PCIE_CLK_GEN1_DIS GENMASK(30, 24) #define PCIE_CLK_GEN1_DIS GENMASK(30, 24)
#define PCIE_CLK_GEN1_EN (BIT(27) | BIT(25)) #define PCIE_CLK_GEN1_EN (BIT(27) | BIT(25))
#define MEMORY_BASE 0x0 #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 * struct mt7621_pcie_port - PCIe port information
...@@ -119,6 +123,7 @@ struct mt7621_pcie_port { ...@@ -119,6 +123,7 @@ struct mt7621_pcie_port {
* @offset: IO / Memory offset * @offset: IO / Memory offset
* @dev: Pointer to PCIe device * @dev: Pointer to PCIe device
* @ports: pointer to PCIe port information * @ports: pointer to PCIe port information
* @perst: gpio reset
* @rst: pointer to pcie reset * @rst: pointer to pcie reset
*/ */
struct mt7621_pcie { struct mt7621_pcie {
...@@ -132,6 +137,7 @@ struct mt7621_pcie { ...@@ -132,6 +137,7 @@ struct mt7621_pcie {
resource_size_t io; resource_size_t io;
} offset; } offset;
struct list_head ports; struct list_head ports;
struct gpio_desc *perst;
struct reset_control *rst; struct reset_control *rst;
}; };
...@@ -198,6 +204,23 @@ static void write_config(struct mt7621_pcie *pcie, unsigned int dev, ...@@ -198,6 +204,23 @@ static void write_config(struct mt7621_pcie *pcie, unsigned int dev,
pcie_write(pcie, val, RALINK_PCI_CONFIG_DATA); 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) static inline void mt7621_control_assert(struct mt7621_pcie_port *port)
{ {
u32 chip_rev_id = rt_sysc_r32(MT7621_CHIP_REV_ID); 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) ...@@ -344,6 +367,12 @@ static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie)
struct resource regs; struct resource regs;
int err; 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); err = of_address_to_resource(node, 0, &regs);
if (err) { if (err) {
dev_err(dev, "missing \"reg\" property\n"); dev_err(dev, "missing \"reg\" property\n");
...@@ -384,7 +413,6 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port) ...@@ -384,7 +413,6 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port)
struct mt7621_pcie *pcie = port->pcie; struct mt7621_pcie *pcie = port->pcie;
struct device *dev = pcie->dev; struct device *dev = pcie->dev;
u32 slot = port->slot; u32 slot = port->slot;
u32 val = 0;
int err; int err;
/* /*
...@@ -393,47 +421,34 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port) ...@@ -393,47 +421,34 @@ static int mt7621_pcie_init_port(struct mt7621_pcie_port *port)
*/ */
mt7621_reset_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); err = phy_init(port->phy);
if (err) { if (err) {
dev_err(dev, "failed to initialize port%d phy\n", slot); dev_err(dev, "failed to initialize port%d phy\n", slot);
goto err_phy_init; return err;
} }
err = phy_power_on(port->phy); err = phy_power_on(port->phy);
if (err) { if (err) {
dev_err(dev, "failed to power on port%d phy\n", slot); dev_err(dev, "failed to power on port%d phy\n", slot);
goto err_phy_on; return err;
}
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;
} }
port->enabled = true; port->enabled = true;
return 0; 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) static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
{ {
struct device *dev = pcie->dev; struct device *dev = pcie->dev;
struct mt7621_pcie_port *port, *tmp; struct mt7621_pcie_port *port, *tmp;
u32 val = 0;
int err; 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) { list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
u32 slot = port->slot; u32 slot = port->slot;
...@@ -441,10 +456,29 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie) ...@@ -441,10 +456,29 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
if (err) { if (err) {
dev_err(dev, "Initiating port %d failed\n", slot); dev_err(dev, "Initiating port %d failed\n", slot);
list_del(&port->list); 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); 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(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_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); 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) ...@@ -453,30 +487,12 @@ static void mt7621_pcie_init_ports(struct mt7621_pcie *pcie)
reset_control_deassert(pcie->rst); 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; struct mt7621_pcie *pcie = port->pcie;
u32 slot = port->slot; u32 slot = port->slot;
u32 offset = MT7621_PCIE_OFFSET + (slot * MT7621_NEXT_PORT); u32 offset = MT7621_PCIE_OFFSET + (slot * MT7621_NEXT_PORT);
u32 val; 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 */ /* enable pcie interrupt */
val = pcie_read(pcie, RALINK_PCI_PCIMSK_ADDR); val = pcie_read(pcie, RALINK_PCI_PCIMSK_ADDR);
...@@ -492,8 +508,6 @@ static int mt7621_pcie_enable_port(struct mt7621_pcie_port *port) ...@@ -492,8 +508,6 @@ static int mt7621_pcie_enable_port(struct mt7621_pcie_port *port)
/* configure class code and revision ID */ /* configure class code and revision ID */
pcie_write(pcie, PCIE_CLASS_CODE | PCIE_REVISION_ID, pcie_write(pcie, PCIE_CLASS_CODE | PCIE_REVISION_ID,
offset + RALINK_PCI_CLASS); offset + RALINK_PCI_CLASS);
return 0;
} }
static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie) static void mt7621_pcie_enable_ports(struct mt7621_pcie *pcie)
...@@ -506,11 +520,7 @@ 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) { list_for_each_entry(port, &pcie->ports, list) {
if (port->enabled) { if (port->enabled) {
if (mt7621_pcie_enable_port(port)) { mt7621_pcie_enable_port(port);
dev_err(dev, "de-assert port %d PERST_N\n",
port->slot);
continue;
}
dev_info(dev, "PCIE%d enabled\n", num_slots_enabled); dev_info(dev, "PCIE%d enabled\n", num_slots_enabled);
num_slots_enabled++; num_slots_enabled++;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment