From 227a8bf421ff8b085444e51e471ef06a87228cfd Mon Sep 17 00:00:00 2001 From: Sergio Paracuellos Date: Fri, 13 Mar 2020 21:09:08 +0100 Subject: [PATCH] staging: mt7621-pci: use gpios for properly reset Original driver code was using three gpio's for reset asserts and deasserts the pcis. Instead of using that a general reset control with a perst gpio was introduced and it seems it is partially working but sometimes there are some unexpected hangs on boot. This commit make use of the three original gpios using 'reset-gpios' property of the device tree and removes the reset line and perst gpio. According to the mediatek aplication note v0.1 there are three gpios used for pcie ports reset control: gpio#19, gpio#8 and gpio#7 for slots 0, 1 and 2 respectively. This schema can be used separately for mt7621A but in some boards due to pin share issue, if the PCM and I2S function are enable at the same time, there are no enough GPIO to control per-port PCIe reset. In those cases gpio#19 is enought for reset the three ports together. Because of this we just try to get the three gpios but if some of them fail we are not failing in boot process, just prints a kernel notice and take after into account if the descriptor is or not valid in order to use it. All of them are set as GPIO output low configuration. The gpio descriptor's API takes device tree property into account and invert value if the pin is configured as active low. So we also have to properly request pins from device tree and set values correct in assert and deassert functions. After this changes the order to make all assert and deassert in the 'probe' process makes more sense: * Parse device tree. * make assert of the RC's and EP's before doing anything else. * make deassert of the RC's before initializing the phy. * Init the phy. * make deassert of the EP's before initialize pci ports. * Normal PCI initialization. Signed-off-by: Sergio Paracuellos Link: https://lore.kernel.org/r/20200313200913.24321-2-sergio.paracuellos@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/mt7621-pci/pci-mt7621.c | 84 ++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 33 deletions(-) --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -95,6 +95,7 @@ * @pcie: pointer to PCIe host info * @phy: pointer to PHY control block * @pcie_rst: pointer to port reset control + * @gpio_rst: gpio reset * @slot: port slot * @enabled: indicates if port is enabled */ @@ -104,6 +105,7 @@ struct mt7621_pcie_port { struct mt7621_pcie *pcie; struct phy *phy; struct reset_control *pcie_rst; + struct gpio_desc *gpio_rst; u32 slot; bool enabled; }; @@ -117,8 +119,6 @@ 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 * @resets_inverted: depends on chip revision * reset lines are inverted. */ @@ -133,8 +133,6 @@ struct mt7621_pcie { resource_size_t io; } offset; struct list_head ports; - struct gpio_desc *perst; - struct reset_control *rst; bool resets_inverted; }; @@ -210,16 +208,16 @@ static void write_config(struct mt7621_p pcie_write(pcie, val, RALINK_PCI_CONFIG_DATA); } -static inline void mt7621_perst_gpio_pcie_assert(struct mt7621_pcie *pcie) +static inline void mt7621_rst_gpio_pcie_assert(struct mt7621_pcie_port *port) { - gpiod_set_value(pcie->perst, 0); - mdelay(PERST_DELAY_US); + if (port->gpio_rst) + gpiod_set_value(port->gpio_rst, 1); } -static inline void mt7621_perst_gpio_pcie_deassert(struct mt7621_pcie *pcie) +static inline void mt7621_rst_gpio_pcie_deassert(struct mt7621_pcie_port *port) { - gpiod_set_value(pcie->perst, 1); - mdelay(PERST_DELAY_US); + if (port->gpio_rst) + gpiod_set_value(port->gpio_rst, 0); } static inline bool mt7621_pcie_port_is_linkup(struct mt7621_pcie_port *port) @@ -367,6 +365,13 @@ static int mt7621_pcie_parse_port(struct if (IS_ERR(port->phy)) return PTR_ERR(port->phy); + port->gpio_rst = devm_gpiod_get_index_optional(dev, "reset", slot, + GPIOD_OUT_LOW); + if (IS_ERR(port->gpio_rst)) { + dev_err(dev, "Failed to get GPIO for PCIe%d\n", slot); + return PTR_ERR(port->gpio_rst); + } + port->slot = slot; port->pcie = pcie; @@ -383,12 +388,6 @@ static int mt7621_pcie_parse_dt(struct m 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"); @@ -399,12 +398,6 @@ static int mt7621_pcie_parse_dt(struct m if (IS_ERR(pcie->base)) return PTR_ERR(pcie->base); - pcie->rst = devm_reset_control_get_exclusive(dev, "pcie"); - if (PTR_ERR(pcie->rst) == -EPROBE_DEFER) { - dev_err(dev, "failed to get pcie reset control\n"); - return PTR_ERR(pcie->rst); - } - for_each_available_child_of_node(node, child) { int slot; @@ -458,16 +451,49 @@ static int mt7621_pcie_init_port(struct return 0; } +static void mt7621_pcie_reset_assert(struct mt7621_pcie *pcie) +{ + struct mt7621_pcie_port *port; + + list_for_each_entry(port, &pcie->ports, list) { + /* PCIe RC reset assert */ + mt7621_control_assert(port); + + /* PCIe EP reset assert */ + mt7621_rst_gpio_pcie_assert(port); + } + + mdelay(PERST_DELAY_US); +} + +static void mt7621_pcie_reset_rc_deassert(struct mt7621_pcie *pcie) +{ + struct mt7621_pcie_port *port; + + list_for_each_entry(port, &pcie->ports, list) + mt7621_control_deassert(port); +} + +static void mt7621_pcie_reset_ep_deassert(struct mt7621_pcie *pcie) +{ + struct mt7621_pcie_port *port; + + list_for_each_entry(port, &pcie->ports, list) + mt7621_rst_gpio_pcie_deassert(port); + + mdelay(PERST_DELAY_US); +} + 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); + mt7621_pcie_reset_assert(pcie); + mt7621_pcie_reset_rc_deassert(pcie); list_for_each_entry_safe(port, tmp, &pcie->ports, list) { u32 slot = port->slot; @@ -476,16 +502,10 @@ static void mt7621_pcie_init_ports(struc 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); + mt7621_pcie_reset_ep_deassert(pcie); list_for_each_entry(port, &pcie->ports, list) { u32 slot = port->slot; @@ -499,8 +519,6 @@ static void mt7621_pcie_init_ports(struc port->enabled = false; } } - - reset_control_deassert(pcie->rst); } static void mt7621_pcie_enable_port(struct mt7621_pcie_port *port)