diff options
Diffstat (limited to 'drivers/staging/mt7621-pci')
-rw-r--r-- | drivers/staging/mt7621-pci/Kconfig | 1 | ||||
-rw-r--r-- | drivers/staging/mt7621-pci/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt | 2 | ||||
-rw-r--r-- | drivers/staging/mt7621-pci/pci-mt7621.c | 122 |
4 files changed, 74 insertions, 52 deletions
diff --git a/drivers/staging/mt7621-pci/Kconfig b/drivers/staging/mt7621-pci/Kconfig index c8fa17cfa807..af928b75a940 100644 --- a/drivers/staging/mt7621-pci/Kconfig +++ b/drivers/staging/mt7621-pci/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 config PCI_MT7621 tristate "MediaTek MT7621 PCI Controller" depends on RALINK diff --git a/drivers/staging/mt7621-pci/Makefile b/drivers/staging/mt7621-pci/Makefile index d4655a726b61..f4e651cf7ce3 100644 --- a/drivers/staging/mt7621-pci/Makefile +++ b/drivers/staging/mt7621-pci/Makefile @@ -1 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_PCI_MT7621) += pci-mt7621.o diff --git a/drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt b/drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt index 5a6ee4103cd5..604ec813bd45 100644 --- a/drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt +++ b/drivers/staging/mt7621-pci/mediatek,mt7621-pci.txt @@ -6,6 +6,7 @@ Required properties: - reg: Base addresses and lengths of the PCIe subsys and root ports. - bus-range: Range of bus numbers associated with this controller. - #address-cells: Address representation for root ports (must be 3) +- perst-gpio: PCIe reset signal line. - pinctrl-names : The pin control state names. - pinctrl-0: The "default" pinctrl state. - #size-cells: Size representation for root ports (must be 2) @@ -48,6 +49,7 @@ Example for MT7621: #address-cells = <3>; #size-cells = <2>; + perst-gpio = <&gpio 19 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&pcie_pins>; diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index 379ae780c691..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); @@ -275,7 +304,7 @@ static int mt7621_pci_parse_request_of_pci_ranges(struct mt7621_pcie *pcie) break; } - if (res != NULL) + if (res) of_pci_range_to_resource(&range, node, res); } @@ -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, ®s); 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); |