You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
7.0 KiB
Diff
223 lines
7.0 KiB
Diff
4 years ago
|
From 227a8bf421ff8b085444e51e471ef06a87228cfd Mon Sep 17 00:00:00 2001
|
||
|
From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
|
||
|
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 <sergio.paracuellos@gmail.com>
|
||
|
Link: https://lore.kernel.org/r/20200313200913.24321-2-sergio.paracuellos@gmail.com
|
||
|
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||
|
---
|
||
|
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)
|