aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ramips/patches-5.4/0102-staging-mt7621-pci-use-gpios-for-properly-reset.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ramips/patches-5.4/0102-staging-mt7621-pci-use-gpios-for-properly-reset.patch')
-rw-r--r--target/linux/ramips/patches-5.4/0102-staging-mt7621-pci-use-gpios-for-properly-reset.patch222
1 files changed, 222 insertions, 0 deletions
diff --git a/target/linux/ramips/patches-5.4/0102-staging-mt7621-pci-use-gpios-for-properly-reset.patch b/target/linux/ramips/patches-5.4/0102-staging-mt7621-pci-use-gpios-for-properly-reset.patch
new file mode 100644
index 0000000000..1b7828f1e6
--- /dev/null
+++ b/target/linux/ramips/patches-5.4/0102-staging-mt7621-pci-use-gpios-for-properly-reset.patch
@@ -0,0 +1,222 @@
+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, &regs);
+ 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)