mirror of
https://github.com/torvalds/linux.git
synced 2024-12-05 10:32:35 +00:00
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: bd1a05bd87
("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>
This commit is contained in:
parent
fdd228cd6d
commit
07420a02b0
@ -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, ®s);
|
||||
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++;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user