aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/mt7621-pci/pci-mt7621.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/mt7621-pci/pci-mt7621.c')
-rw-r--r--drivers/staging/mt7621-pci/pci-mt7621.c120
1 files changed, 69 insertions, 51 deletions
diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c
index 03d919a94552..89fa813142ab 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,14 +36,16 @@
/* sysctl */
#define MT7621_CHIP_REV_ID 0x0c
+#define MT7621_GPIO_MODE 0x60
#define CHIP_REV_MT7621_E2 0x0101
/* MediaTek specific configuration registers */
#define PCIE_FTS_NUM 0x70c
#define PCIE_FTS_NUM_MASK GENMASK(15, 8)
-#define PCIE_FTS_NUM_L0(x) ((x) & 0xff << 8)
+#define PCIE_FTS_NUM_L0(x) (((x) & 0xff) << 8)
/* rt_sysc_membase relative registers */
+#define RALINK_CLKCFG1 0x30
#define RALINK_PCIE_CLK_GEN 0x7c
#define RALINK_PCIE_CLK_GEN1 0x80
@@ -81,7 +84,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 +91,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 +124,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 +138,7 @@ struct mt7621_pcie {
resource_size_t io;
} offset;
struct list_head ports;
+ struct gpio_desc *perst;
struct reset_control *rst;
};
@@ -198,6 +205,28 @@ 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_pcie_port_clk_disable(struct mt7621_pcie_port *port)
+{
+ rt_sysc_m32(PCIE_PORT_CLK_EN(port->slot), 0, RALINK_CLKCFG1);
+}
+
static inline void mt7621_control_assert(struct mt7621_pcie_port *port)
{
u32 chip_rev_id = rt_sysc_r32(MT7621_CHIP_REV_ID);
@@ -344,6 +373,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 +419,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 +427,35 @@ 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", (unsigned int)val, slot);
-
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;
+ phy_exit(port->phy);
+ 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 +463,30 @@ 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);
+ mt7621_pcie_port_clk_disable(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 +495,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 +516,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,12 +528,8 @@ 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;
- }
- dev_info(dev, "PCIE%d enabled\n", slot);
+ mt7621_pcie_enable_port(port);
+ dev_info(dev, "PCIE%d enabled\n", num_slots_enabled);
num_slots_enabled++;
}
}
@@ -709,4 +727,4 @@ static int __init mt7621_pci_init(void)
return platform_driver_register(&mt7621_pci_driver);
}
-arch_initcall(mt7621_pci_init);
+module_init(mt7621_pci_init);