--- /dev/null
+From 13f63b2dc8e04e8ff485c5880838fd41b6b9a166 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 5 Sep 2023 15:25:34 +0530
+Subject: arm64: dts: qcom: ipq6018: Fix tcsr_mutex register size
+
+From: Vignesh Viswanathan <quic_viswanat@quicinc.com>
+
+[ Upstream commit 72fc3d58b87b0d622039c6299b89024fbb7b420f ]
+
+IPQ6018's TCSR Mutex HW lock register has 32 locks of size 4KB each.
+Total size of the TCSR Mutex registers is 128KB.
+
+Fix size of the tcsr_mutex hwlock register to 0x20000.
+
+Changes in v2:
+ - Drop change to remove qcom,ipq6018-tcsr-mutex compatible string
+ - Added Fixes and stable tags
+
+Cc: stable@vger.kernel.org
+Fixes: 5bf635621245 ("arm64: dts: ipq6018: Add a few device nodes")
+Signed-off-by: Vignesh Viswanathan <quic_viswanat@quicinc.com>
+Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
+Link: https://lore.kernel.org/r/20230905095535.1263113-2-quic_viswanat@quicinc.com
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/ipq6018.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
+index a8c26aff6f376..3677209106773 100644
+--- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
+@@ -238,7 +238,7 @@
+
+ tcsr_mutex: hwlock@1905000 {
+ compatible = "qcom,ipq6018-tcsr-mutex", "qcom,tcsr-mutex";
+- reg = <0x0 0x01905000 0x0 0x1000>;
++ reg = <0x0 0x01905000 0x0 0x20000>;
+ #hwlock-cells = <1>;
+ };
+
+--
+2.42.0
+
--- /dev/null
+From c97754d8030c762ca96b032fefd2a904bd4e0243 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 9 Sep 2022 11:20:31 +0200
+Subject: arm64: dts: qcom: ipq6018: switch TCSR mutex to MMIO
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit f5e303aefc06b7508d7a490f9a2d80e4dc134c70 ]
+
+The TCSR mutex bindings allow device to be described only with address
+space (so it uses MMIO, not syscon regmap). This seems reasonable as
+TCSR mutex is actually a dedicated IO address space and it also fixes DT
+schema checks:
+
+ qcom/ipq6018-cp01-c1.dtb: hwlock: 'reg' is a required property
+ qcom/ipq6018-cp01-c1.dtb: hwlock: 'syscon' does not match any of the regexes: 'pinctrl-[0-9]+'
+
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Signed-off-by: Bjorn Andersson <andersson@kernel.org>
+Link: https://lore.kernel.org/r/20220909092035.223915-12-krzysztof.kozlowski@linaro.org
+Stable-dep-of: 72fc3d58b87b ("arm64: dts: qcom: ipq6018: Fix tcsr_mutex register size")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/boot/dts/qcom/ipq6018.dtsi | 13 ++++---------
+ 1 file changed, 4 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/qcom/ipq6018.dtsi b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
+index 201a3bb5511cd..a8c26aff6f376 100644
+--- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
++++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
+@@ -129,12 +129,6 @@
+ };
+ };
+
+- tcsr_mutex: hwlock {
+- compatible = "qcom,tcsr-mutex";
+- syscon = <&tcsr_mutex_regs 0 0x80>;
+- #hwlock-cells = <1>;
+- };
+-
+ pmuv8: pmu {
+ compatible = "arm,cortex-a53-pmu";
+ interrupts = <GIC_PPI 7 (GIC_CPU_MASK_SIMPLE(4) |
+@@ -242,9 +236,10 @@
+ #reset-cells = <1>;
+ };
+
+- tcsr_mutex_regs: syscon@1905000 {
+- compatible = "syscon";
+- reg = <0x0 0x01905000 0x0 0x8000>;
++ tcsr_mutex: hwlock@1905000 {
++ compatible = "qcom,ipq6018-tcsr-mutex", "qcom,tcsr-mutex";
++ reg = <0x0 0x01905000 0x0 0x1000>;
++ #hwlock-cells = <1>;
+ };
+
+ tcsr_q6: syscon@1945000 {
+--
+2.42.0
+
--- /dev/null
+From ad8336b7b8f27209c551c2a6904ba6f7b82dfff9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Mar 2023 19:52:02 -0500
+Subject: bluetooth: Add device 0bda:887b to device tables
+
+From: Larry Finger <Larry.Finger@lwfinger.net>
+
+[ Upstream commit 730a1d1a93a3e30c3723f87af97a8517334b2203 ]
+
+This device is part of a Realtek RTW8852BE chip.
+
+The device table entry is as follows:
+
+T: Bus=03 Lev=01 Prnt=01 Port=12 Cnt=02 Dev#= 3 Spd=12 MxCh= 0
+D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
+P: Vendor=0bda ProdID=887b Rev= 0.00
+S: Manufacturer=Realtek
+S: Product=Bluetooth Radio
+S: SerialNumber=00e04c000001
+C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
+I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
+E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+
+Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: da06ff1f585e ("Bluetooth: btusb: Add 0bda:b85b for Fn-Link RTL8852BE")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btusb.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index fffb73e6f49d4..bb1ec0cac2b29 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -418,6 +418,8 @@ static const struct usb_device_id blacklist_table[] = {
+ /* Realtek 8852BE Bluetooth devices */
+ { USB_DEVICE(0x0cb8, 0xc559), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
++ { USB_DEVICE(0x0bda, 0x887b), .driver_info = BTUSB_REALTEK |
++ BTUSB_WIDEBAND_SPEECH },
+
+ /* Realtek Bluetooth devices */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
+--
+2.42.0
+
--- /dev/null
+From baf7f4a4bb918d5e2f6d163dd791852b1de2af97 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 22 Mar 2023 19:52:03 -0500
+Subject: bluetooth: Add device 13d3:3571 to device tables
+
+From: Larry Finger <Larry.Finger@lwfinger.net>
+
+[ Upstream commit 069f534247bb6db4f8c2c2ea8e9155abf495c37e ]
+
+This device is part of a Realtek RTW8852BE chip. The device table is as follows:
+
+T: Bus=03 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
+D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
+P: Vendor=13d3 ProdID=3571 Rev= 0.00
+S: Manufacturer=Realtek
+S: Product=Bluetooth Radio
+S: SerialNumber=00e04c000001
+C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
+I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
+E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+
+Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: da06ff1f585e ("Bluetooth: btusb: Add 0bda:b85b for Fn-Link RTL8852BE")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btusb.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index bb1ec0cac2b29..6c225f48a26d4 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -420,6 +420,8 @@ static const struct usb_device_id blacklist_table[] = {
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0bda, 0x887b), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
++ { USB_DEVICE(0x13d3, 0x3571), .driver_info = BTUSB_REALTEK |
++ BTUSB_WIDEBAND_SPEECH },
+
+ /* Realtek Bluetooth devices */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
+--
+2.42.0
+
--- /dev/null
+From 3e37ba18d41eb9fa3c5f006d14447231c2fd95cf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Oct 2023 19:21:17 +0800
+Subject: Bluetooth: btusb: Add 0bda:b85b for Fn-Link RTL8852BE
+
+From: Guan Wentao <guanwentao@uniontech.com>
+
+[ Upstream commit da06ff1f585ea784c79f80e7fab0e0c4ebb49c1c ]
+
+Add PID/VID 0bda:b85b for Realtek RTL8852BE USB bluetooth part.
+The PID/VID was reported by the patch last year. [1]
+Some SBCs like rockpi 5B A8 module contains the device.
+And it`s founded in website. [2] [3]
+
+Here is the device tables in /sys/kernel/debug/usb/devices .
+
+T: Bus=07 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
+D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
+P: Vendor=0bda ProdID=b85b Rev= 0.00
+S: Manufacturer=Realtek
+S: Product=Bluetooth Radio
+S: SerialNumber=00e04c000001
+C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
+I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
+E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+
+Link: https://lore.kernel.org/all/20220420052402.19049-1-tangmeng@uniontech.com/ [1]
+Link: https://forum.radxa.com/t/bluetooth-on-ubuntu/13051/4 [2]
+Link: https://ubuntuforums.org/showthread.php?t=2489527 [3]
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Meng Tang <tangmeng@uniontech.com>
+Signed-off-by: Guan Wentao <guanwentao@uniontech.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btusb.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index f1079614bfdb3..a1a8b282b99b1 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -420,6 +420,8 @@ static const struct usb_device_id blacklist_table[] = {
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0bda, 0x887b), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
++ { USB_DEVICE(0x0bda, 0xb85b), .driver_info = BTUSB_REALTEK |
++ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x13d3, 0x3570), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x13d3, 0x3571), .driver_info = BTUSB_REALTEK |
+--
+2.42.0
+
--- /dev/null
+From 6be8ee495acc64d36028a5c831427548c30275ca Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 23 Nov 2022 11:10:05 +0300
+Subject: Bluetooth: btusb: Add Realtek RTL8852BE support ID 0x0cb8:0xc559
+
+From: Artem Lukyanov <dukzcry@ya.ru>
+
+[ Upstream commit 393b4916b7b5b94faf5c6a7c68df1c62d17e4f38 ]
+
+Add the support ID(0x0cb8, 0xc559) to usb_device_id table for
+Realtek RTL8852BE.
+
+The device info from /sys/kernel/debug/usb/devices as below.
+
+T: Bus=03 Lev=01 Prnt=01 Port=02 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
+D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
+P: Vendor=0cb8 ProdID=c559 Rev= 0.00
+S: Manufacturer=Realtek
+S: Product=Bluetooth Radio
+S: SerialNumber=00e04c000001
+C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
+I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
+E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+
+Signed-off-by: Artem Lukyanov <dukzcry@ya.ru>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: da06ff1f585e ("Bluetooth: btusb: Add 0bda:b85b for Fn-Link RTL8852BE")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btusb.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index cc210fb790d89..fffb73e6f49d4 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -415,6 +415,10 @@ static const struct usb_device_id blacklist_table[] = {
+ { USB_DEVICE(0x13d3, 0x3586), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
+
++ /* Realtek 8852BE Bluetooth devices */
++ { USB_DEVICE(0x0cb8, 0xc559), .driver_info = BTUSB_REALTEK |
++ BTUSB_WIDEBAND_SPEECH },
++
+ /* Realtek Bluetooth devices */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x0bda, 0xe0, 0x01, 0x01),
+ .driver_info = BTUSB_REALTEK },
+--
+2.42.0
+
--- /dev/null
+From d4aa3cb2c4c68f8fde58c54d631760b90a10d94c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 24 Sep 2023 16:46:55 +0530
+Subject: Bluetooth: btusb: Add RTW8852BE device 13d3:3570 to device tables
+
+From: Masum Reza <masumrezarock100@gmail.com>
+
+[ Upstream commit 02be109d3a405dbc4d53fb4b4473d7a113548088 ]
+
+This device is used in TP-Link TX20E WiFi+Bluetooth adapter.
+
+Relevant information in /sys/kernel/debug/usb/devices
+about the Bluetooth device is listed as the below.
+
+T: Bus=01 Lev=01 Prnt=01 Port=08 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
+D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
+P: Vendor=13d3 ProdID=3570 Rev= 0.00
+S: Manufacturer=Realtek
+S: Product=Bluetooth Radio
+S: SerialNumber=00e04c000001
+C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA
+I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
+E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
+I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
+I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
+I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
+I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
+I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
+I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
+
+Signed-off-by: Masum Reza <masumrezarock100@gmail.com>
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Stable-dep-of: da06ff1f585e ("Bluetooth: btusb: Add 0bda:b85b for Fn-Link RTL8852BE")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/bluetooth/btusb.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index 6c225f48a26d4..f1079614bfdb3 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -420,6 +420,8 @@ static const struct usb_device_id blacklist_table[] = {
+ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x0bda, 0x887b), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
++ { USB_DEVICE(0x13d3, 0x3570), .driver_info = BTUSB_REALTEK |
++ BTUSB_WIDEBAND_SPEECH },
+ { USB_DEVICE(0x13d3, 0x3571), .driver_info = BTUSB_REALTEK |
+ BTUSB_WIDEBAND_SPEECH },
+
+--
+2.42.0
+
--- /dev/null
+From 5c5c0250a9da09cad0e5c9cd34808b3b0d3bdf4f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 24 Oct 2023 20:30:14 +0200
+Subject: cpufreq: stats: Fix buffer overflow detection in trans_stats()
+
+From: Christian Marangi <ansuelsmth@gmail.com>
+
+[ Upstream commit ea167a7fc2426f7685c3735e104921c1a20a6d3f ]
+
+Commit 3c0897c180c6 ("cpufreq: Use scnprintf() for avoiding potential
+buffer overflow") switched from snprintf to the more secure scnprintf
+but never updated the exit condition for PAGE_SIZE.
+
+As the commit say and as scnprintf document, what scnprintf returns what
+is actually written not counting the '\0' end char. This results in the
+case of len exceeding the size, len set to PAGE_SIZE - 1, as it can be
+written at max PAGE_SIZE - 1 (as '\0' is not counted)
+
+Because of len is never set to PAGE_SIZE, the function never break early,
+never prints the warning and never return -EFBIG.
+
+Fix this by changing the condition to PAGE_SIZE - 1 to correctly trigger
+the error.
+
+Cc: 5.10+ <stable@vger.kernel.org> # 5.10+
+Fixes: 3c0897c180c6 ("cpufreq: Use scnprintf() for avoiding potential buffer overflow")
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+[ rjw: Subject and changelog edits ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/cpufreq/cpufreq_stats.c | 14 +++++++-------
+ 1 file changed, 7 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
+index 6cd5c8ab5d49f..ab856dd2d5fc0 100644
+--- a/drivers/cpufreq/cpufreq_stats.c
++++ b/drivers/cpufreq/cpufreq_stats.c
+@@ -131,25 +131,25 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
+ len += scnprintf(buf + len, PAGE_SIZE - len, " From : To\n");
+ len += scnprintf(buf + len, PAGE_SIZE - len, " : ");
+ for (i = 0; i < stats->state_num; i++) {
+- if (len >= PAGE_SIZE)
++ if (len >= PAGE_SIZE - 1)
+ break;
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ",
+ stats->freq_table[i]);
+ }
+- if (len >= PAGE_SIZE)
+- return PAGE_SIZE;
++ if (len >= PAGE_SIZE - 1)
++ return PAGE_SIZE - 1;
+
+ len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
+
+ for (i = 0; i < stats->state_num; i++) {
+- if (len >= PAGE_SIZE)
++ if (len >= PAGE_SIZE - 1)
+ break;
+
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%9u: ",
+ stats->freq_table[i]);
+
+ for (j = 0; j < stats->state_num; j++) {
+- if (len >= PAGE_SIZE)
++ if (len >= PAGE_SIZE - 1)
+ break;
+
+ if (pending)
+@@ -159,12 +159,12 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
+
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ", count);
+ }
+- if (len >= PAGE_SIZE)
++ if (len >= PAGE_SIZE - 1)
+ break;
+ len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
+ }
+
+- if (len >= PAGE_SIZE) {
++ if (len >= PAGE_SIZE - 1) {
+ pr_warn_once("cpufreq transition table exceeds PAGE_SIZE. Disabling\n");
+ return -EFBIG;
+ }
+--
+2.42.0
+
--- /dev/null
+From eb79d84adcfd4f527905aa45475665fc4d33bfbe Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Nov 2020 15:11:49 -0600
+Subject: PCI: dwc/dra7xx: Use the common MSI irq_chip
+
+From: Rob Herring <robh@kernel.org>
+
+[ Upstream commit 7f170d35f58311362e8b01b6774ca1053c0641b8 ]
+
+The dra7xx MSI irq_chip implementation is identical to the default DWC one.
+The only difference is the interrupt handler as the MSI interrupt is muxed
+with other interrupts, but that doesn't affect the irq_chip part of it.
+
+Link: https://lore.kernel.org/r/20201105211159.1814485-7-robh@kernel.org
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Kishon Vijay Abraham I <kishon@ti.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Cc: linux-omap@vger.kernel.org
+Stable-dep-of: 83a939f0fdc2 ("PCI: exynos: Don't discard .remove() callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/dwc/pci-dra7xx.c | 125 ------------------------
+ 1 file changed, 125 deletions(-)
+
+diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
+index a4aabc85dbb12..4d0c35a4aa598 100644
+--- a/drivers/pci/controller/dwc/pci-dra7xx.c
++++ b/drivers/pci/controller/dwc/pci-dra7xx.c
+@@ -377,133 +377,8 @@ static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
+ return 0;
+ }
+
+-static void dra7xx_pcie_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
+-{
+- struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+- u64 msi_target;
+-
+- msi_target = (u64)pp->msi_data;
+-
+- msg->address_lo = lower_32_bits(msi_target);
+- msg->address_hi = upper_32_bits(msi_target);
+-
+- msg->data = d->hwirq;
+-
+- dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
+- (int)d->hwirq, msg->address_hi, msg->address_lo);
+-}
+-
+-static int dra7xx_pcie_msi_set_affinity(struct irq_data *d,
+- const struct cpumask *mask,
+- bool force)
+-{
+- return -EINVAL;
+-}
+-
+-static void dra7xx_pcie_bottom_mask(struct irq_data *d)
+-{
+- struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+- unsigned int res, bit, ctrl;
+- unsigned long flags;
+-
+- raw_spin_lock_irqsave(&pp->lock, flags);
+-
+- ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
+- res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
+- bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
+-
+- pp->irq_mask[ctrl] |= BIT(bit);
+- dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res,
+- pp->irq_mask[ctrl]);
+-
+- raw_spin_unlock_irqrestore(&pp->lock, flags);
+-}
+-
+-static void dra7xx_pcie_bottom_unmask(struct irq_data *d)
+-{
+- struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+- unsigned int res, bit, ctrl;
+- unsigned long flags;
+-
+- raw_spin_lock_irqsave(&pp->lock, flags);
+-
+- ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
+- res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
+- bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
+-
+- pp->irq_mask[ctrl] &= ~BIT(bit);
+- dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res,
+- pp->irq_mask[ctrl]);
+-
+- raw_spin_unlock_irqrestore(&pp->lock, flags);
+-}
+-
+-static void dra7xx_pcie_bottom_ack(struct irq_data *d)
+-{
+- struct pcie_port *pp = irq_data_get_irq_chip_data(d);
+- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+- unsigned int res, bit, ctrl;
+-
+- ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
+- res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
+- bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
+-
+- dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_STATUS + res, BIT(bit));
+-}
+-
+-static struct irq_chip dra7xx_pci_msi_bottom_irq_chip = {
+- .name = "DRA7XX-PCI-MSI",
+- .irq_ack = dra7xx_pcie_bottom_ack,
+- .irq_compose_msi_msg = dra7xx_pcie_setup_msi_msg,
+- .irq_set_affinity = dra7xx_pcie_msi_set_affinity,
+- .irq_mask = dra7xx_pcie_bottom_mask,
+- .irq_unmask = dra7xx_pcie_bottom_unmask,
+-};
+-
+-static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
+-{
+- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+- struct device *dev = pci->dev;
+- u32 ctrl, num_ctrls;
+- int ret;
+-
+- pp->msi_irq_chip = &dra7xx_pci_msi_bottom_irq_chip;
+-
+- num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
+- /* Initialize IRQ Status array */
+- for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
+- pp->irq_mask[ctrl] = ~0;
+- dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK +
+- (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
+- pp->irq_mask[ctrl]);
+- dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE +
+- (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
+- ~0);
+- }
+-
+- ret = dw_pcie_allocate_domains(pp);
+- if (ret)
+- return ret;
+-
+- pp->msi_data = dma_map_single_attrs(dev, &pp->msi_msg,
+- sizeof(pp->msi_msg),
+- DMA_FROM_DEVICE,
+- DMA_ATTR_SKIP_CPU_SYNC);
+- ret = dma_mapping_error(dev, pp->msi_data);
+- if (ret) {
+- dev_err(dev, "Failed to map MSI data\n");
+- pp->msi_data = 0;
+- dw_pcie_free_msi(pp);
+- }
+- return ret;
+-}
+-
+ static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
+ .host_init = dra7xx_pcie_host_init,
+- .msi_host_init = dra7xx_pcie_msi_host_init,
+ };
+
+ static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
+--
+2.42.0
+
--- /dev/null
+From 2535a2b742bde8ebeb7e5852ae7ac39acd5a08a8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Nov 2020 15:11:50 -0600
+Subject: PCI: dwc: Drop the .set_num_vectors() host op
+
+From: Rob Herring <robh@kernel.org>
+
+[ Upstream commit 331e9bcead5252364e52fc95efbbe7273667b07d ]
+
+There's no reason for the .set_num_vectors() host op. Drivers needing a
+non-default value can just initialize pcie_port.num_vectors directly.
+
+Link: https://lore.kernel.org/r/20201105211159.1814485-8-robh@kernel.org
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Jingoo Han <jingoohan1@gmail.com>
+Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Cc: Thierry Reding <thierry.reding@gmail.com>
+Cc: Jonathan Hunter <jonathanh@nvidia.com>
+Cc: linux-tegra@vger.kernel.org
+Stable-dep-of: 83a939f0fdc2 ("PCI: exynos: Don't discard .remove() callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../pci/controller/dwc/pcie-designware-host.c | 19 ++++---------------
+ .../pci/controller/dwc/pcie-designware-plat.c | 7 +------
+ drivers/pci/controller/dwc/pcie-designware.h | 1 -
+ drivers/pci/controller/dwc/pcie-tegra194.c | 7 +------
+ 4 files changed, 6 insertions(+), 28 deletions(-)
+
+diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
+index d6b7eec1a25b0..32d3af7c44917 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -365,22 +365,11 @@ int dw_pcie_host_init(struct pcie_port *pp)
+ pci->link_gen = of_pci_get_max_link_speed(np);
+
+ if (pci_msi_enabled()) {
+- /*
+- * If a specific SoC driver needs to change the
+- * default number of vectors, it needs to implement
+- * the set_num_vectors callback.
+- */
+- if (!pp->ops->set_num_vectors) {
++ if (!pp->num_vectors) {
+ pp->num_vectors = MSI_DEF_NUM_VECTORS;
+- } else {
+- pp->ops->set_num_vectors(pp);
+-
+- if (pp->num_vectors > MAX_MSI_IRQS ||
+- pp->num_vectors == 0) {
+- dev_err(dev,
+- "Invalid number of vectors\n");
+- return -EINVAL;
+- }
++ } else if (pp->num_vectors > MAX_MSI_IRQS) {
++ dev_err(dev, "Invalid number of vectors\n");
++ return -EINVAL;
+ }
+
+ if (!pp->ops->msi_host_init) {
+diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
+index 562a05e07b1d5..13fede1d41572 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
++++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
+@@ -44,14 +44,8 @@ static int dw_plat_pcie_host_init(struct pcie_port *pp)
+ return 0;
+ }
+
+-static void dw_plat_set_num_vectors(struct pcie_port *pp)
+-{
+- pp->num_vectors = MAX_MSI_IRQS;
+-}
+-
+ static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
+ .host_init = dw_plat_pcie_host_init,
+- .set_num_vectors = dw_plat_set_num_vectors,
+ };
+
+ static int dw_plat_pcie_establish_link(struct dw_pcie *pci)
+@@ -128,6 +122,7 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
+ return pp->msi_irq;
+ }
+
++ pp->num_vectors = MAX_MSI_IRQS;
+ pp->ops = &dw_plat_pcie_host_ops;
+
+ ret = dw_pcie_host_init(pp);
+diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
+index 9d2f511f13faf..82c0339c283f1 100644
+--- a/drivers/pci/controller/dwc/pcie-designware.h
++++ b/drivers/pci/controller/dwc/pcie-designware.h
+@@ -174,7 +174,6 @@ enum dw_pcie_device_mode {
+
+ struct dw_pcie_host_ops {
+ int (*host_init)(struct pcie_port *pp);
+- void (*set_num_vectors)(struct pcie_port *pp);
+ int (*msi_host_init)(struct pcie_port *pp);
+ };
+
+diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
+index 825cb65945fba..a93b5dca110ec 100644
+--- a/drivers/pci/controller/dwc/pcie-tegra194.c
++++ b/drivers/pci/controller/dwc/pcie-tegra194.c
+@@ -996,11 +996,6 @@ static int tegra_pcie_dw_link_up(struct dw_pcie *pci)
+ return !!(val & PCI_EXP_LNKSTA_DLLLA);
+ }
+
+-static void tegra_pcie_set_msi_vec_num(struct pcie_port *pp)
+-{
+- pp->num_vectors = MAX_MSI_IRQS;
+-}
+-
+ static int tegra_pcie_dw_start_link(struct dw_pcie *pci)
+ {
+ struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
+@@ -1025,7 +1020,6 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = {
+
+ static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
+ .host_init = tegra_pcie_dw_host_init,
+- .set_num_vectors = tegra_pcie_set_msi_vec_num,
+ };
+
+ static void tegra_pcie_disable_phy(struct tegra_pcie_dw *pcie)
+@@ -2002,6 +1996,7 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
+ pci->n_fts[1] = FTS_VAL;
+
+ pp = &pci->pp;
++ pp->num_vectors = MAX_MSI_IRQS;
+ pcie->dev = &pdev->dev;
+ pcie->mode = (enum dw_pcie_device_mode)data->mode;
+
+--
+2.42.0
+
--- /dev/null
+From a8f5794be913c874645a36fcd07145df3ac0eac6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Nov 2020 18:01:39 +0100
+Subject: PCI: dwc: exynos: Rework the driver to support Exynos5433 variant
+
+From: Jaehoon Chung <jh80.chung@samsung.com>
+
+[ Upstream commit 778f7c194b1dac351d345ce723f8747026092949 ]
+
+Exynos5440 SoC support has been dropped since commit 8c83315da1cf ("ARM:
+dts: exynos: Remove Exynos5440"). Rework this driver to support DWC PCIe
+variant found in the Exynos5433 SoCs.
+
+The main difference in Exynos5433 variant is lack of the MSI support
+(the MSI interrupt is not even routed to the CPU).
+
+[mszyprow: reworked the driver to support only Exynos5433 variant,
+ simplified code, rebased onto current kernel code, added
+ regulator support, converted to the regular platform driver,
+ removed MSI related code, rewrote commit message, added help]
+
+Link: https://lore.kernel.org/r/20201113170139.29956-6-m.szyprowski@samsung.com
+Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com>
+Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Reviewed-by: Rob Herring <robh@kernel.org>
+Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
+Acked-by: Jingoo Han <jingoohan1@gmail.com>
+Stable-dep-of: 83a939f0fdc2 ("PCI: exynos: Don't discard .remove() callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/dwc/Kconfig | 9 +-
+ drivers/pci/controller/dwc/pci-exynos.c | 353 ++++++++++--------------
+ drivers/pci/quirks.c | 1 +
+ 3 files changed, 147 insertions(+), 216 deletions(-)
+
+diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
+index bc049865f8e05..9ee1e248e7448 100644
+--- a/drivers/pci/controller/dwc/Kconfig
++++ b/drivers/pci/controller/dwc/Kconfig
+@@ -83,10 +83,15 @@ config PCIE_DW_PLAT_EP
+ selected.
+
+ config PCI_EXYNOS
+- bool "Samsung Exynos PCIe controller"
+- depends on SOC_EXYNOS5440 || COMPILE_TEST
++ tristate "Samsung Exynos PCIe controller"
++ depends on ARCH_EXYNOS || COMPILE_TEST
+ depends on PCI_MSI_IRQ_DOMAIN
+ select PCIE_DW_HOST
++ help
++ Enables support for the PCIe controller in the Samsung Exynos SoCs
++ to work in host mode. The PCI controller is based on the DesignWare
++ hardware and therefore the driver re-uses the DesignWare core
++ functions to implement the driver.
+
+ config PCI_IMX6
+ bool "Freescale i.MX6/7/8 PCIe controller"
+diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c
+index 5c10a5432896c..c24dab383654b 100644
+--- a/drivers/pci/controller/dwc/pci-exynos.c
++++ b/drivers/pci/controller/dwc/pci-exynos.c
+@@ -2,26 +2,23 @@
+ /*
+ * PCIe host controller driver for Samsung Exynos SoCs
+ *
+- * Copyright (C) 2013 Samsung Electronics Co., Ltd.
++ * Copyright (C) 2013-2020 Samsung Electronics Co., Ltd.
+ * https://www.samsung.com
+ *
+ * Author: Jingoo Han <jg1.han@samsung.com>
++ * Jaehoon Chung <jh80.chung@samsung.com>
+ */
+
+ #include <linux/clk.h>
+ #include <linux/delay.h>
+-#include <linux/gpio.h>
+ #include <linux/interrupt.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/of_device.h>
+-#include <linux/of_gpio.h>
+ #include <linux/pci.h>
+ #include <linux/platform_device.h>
+ #include <linux/phy/phy.h>
+-#include <linux/resource.h>
+-#include <linux/signal.h>
+-#include <linux/types.h>
++#include <linux/regulator/consumer.h>
+
+ #include "pcie-designware.h"
+
+@@ -37,102 +34,43 @@
+ #define PCIE_IRQ_SPECIAL 0x008
+ #define PCIE_IRQ_EN_PULSE 0x00c
+ #define PCIE_IRQ_EN_LEVEL 0x010
+-#define IRQ_MSI_ENABLE BIT(2)
+ #define PCIE_IRQ_EN_SPECIAL 0x014
+-#define PCIE_PWR_RESET 0x018
++#define PCIE_SW_WAKE 0x018
++#define PCIE_BUS_EN BIT(1)
+ #define PCIE_CORE_RESET 0x01c
+ #define PCIE_CORE_RESET_ENABLE BIT(0)
+ #define PCIE_STICKY_RESET 0x020
+ #define PCIE_NONSTICKY_RESET 0x024
+ #define PCIE_APP_INIT_RESET 0x028
+ #define PCIE_APP_LTSSM_ENABLE 0x02c
+-#define PCIE_ELBI_RDLH_LINKUP 0x064
++#define PCIE_ELBI_RDLH_LINKUP 0x074
++#define PCIE_ELBI_XMLH_LINKUP BIT(4)
+ #define PCIE_ELBI_LTSSM_ENABLE 0x1
+ #define PCIE_ELBI_SLV_AWMISC 0x11c
+ #define PCIE_ELBI_SLV_ARMISC 0x120
+ #define PCIE_ELBI_SLV_DBI_ENABLE BIT(21)
+
+-struct exynos_pcie_mem_res {
+- void __iomem *elbi_base; /* DT 0th resource: PCIe CTRL */
+-};
+-
+-struct exynos_pcie_clk_res {
+- struct clk *clk;
+- struct clk *bus_clk;
+-};
+-
+ struct exynos_pcie {
+- struct dw_pcie *pci;
+- struct exynos_pcie_mem_res *mem_res;
+- struct exynos_pcie_clk_res *clk_res;
+- const struct exynos_pcie_ops *ops;
+- int reset_gpio;
+-
++ struct dw_pcie pci;
++ void __iomem *elbi_base;
++ struct clk *clk;
++ struct clk *bus_clk;
+ struct phy *phy;
++ struct regulator_bulk_data supplies[2];
+ };
+
+-struct exynos_pcie_ops {
+- int (*get_mem_resources)(struct platform_device *pdev,
+- struct exynos_pcie *ep);
+- int (*get_clk_resources)(struct exynos_pcie *ep);
+- int (*init_clk_resources)(struct exynos_pcie *ep);
+- void (*deinit_clk_resources)(struct exynos_pcie *ep);
+-};
+-
+-static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,
+- struct exynos_pcie *ep)
+-{
+- struct dw_pcie *pci = ep->pci;
+- struct device *dev = pci->dev;
+-
+- ep->mem_res = devm_kzalloc(dev, sizeof(*ep->mem_res), GFP_KERNEL);
+- if (!ep->mem_res)
+- return -ENOMEM;
+-
+- ep->mem_res->elbi_base = devm_platform_ioremap_resource(pdev, 0);
+- if (IS_ERR(ep->mem_res->elbi_base))
+- return PTR_ERR(ep->mem_res->elbi_base);
+-
+- return 0;
+-}
+-
+-static int exynos5440_pcie_get_clk_resources(struct exynos_pcie *ep)
++static int exynos_pcie_init_clk_resources(struct exynos_pcie *ep)
+ {
+- struct dw_pcie *pci = ep->pci;
+- struct device *dev = pci->dev;
+-
+- ep->clk_res = devm_kzalloc(dev, sizeof(*ep->clk_res), GFP_KERNEL);
+- if (!ep->clk_res)
+- return -ENOMEM;
+-
+- ep->clk_res->clk = devm_clk_get(dev, "pcie");
+- if (IS_ERR(ep->clk_res->clk)) {
+- dev_err(dev, "Failed to get pcie rc clock\n");
+- return PTR_ERR(ep->clk_res->clk);
+- }
+-
+- ep->clk_res->bus_clk = devm_clk_get(dev, "pcie_bus");
+- if (IS_ERR(ep->clk_res->bus_clk)) {
+- dev_err(dev, "Failed to get pcie bus clock\n");
+- return PTR_ERR(ep->clk_res->bus_clk);
+- }
+-
+- return 0;
+-}
+-
+-static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
+-{
+- struct dw_pcie *pci = ep->pci;
+- struct device *dev = pci->dev;
++ struct device *dev = ep->pci.dev;
+ int ret;
+
+- ret = clk_prepare_enable(ep->clk_res->clk);
++ ret = clk_prepare_enable(ep->clk);
+ if (ret) {
+ dev_err(dev, "cannot enable pcie rc clock");
+ return ret;
+ }
+
+- ret = clk_prepare_enable(ep->clk_res->bus_clk);
++ ret = clk_prepare_enable(ep->bus_clk);
+ if (ret) {
+ dev_err(dev, "cannot enable pcie bus clock");
+ goto err_bus_clk;
+@@ -141,24 +79,17 @@ static int exynos5440_pcie_init_clk_resources(struct exynos_pcie *ep)
+ return 0;
+
+ err_bus_clk:
+- clk_disable_unprepare(ep->clk_res->clk);
++ clk_disable_unprepare(ep->clk);
+
+ return ret;
+ }
+
+-static void exynos5440_pcie_deinit_clk_resources(struct exynos_pcie *ep)
++static void exynos_pcie_deinit_clk_resources(struct exynos_pcie *ep)
+ {
+- clk_disable_unprepare(ep->clk_res->bus_clk);
+- clk_disable_unprepare(ep->clk_res->clk);
++ clk_disable_unprepare(ep->bus_clk);
++ clk_disable_unprepare(ep->clk);
+ }
+
+-static const struct exynos_pcie_ops exynos5440_pcie_ops = {
+- .get_mem_resources = exynos5440_pcie_get_mem_resources,
+- .get_clk_resources = exynos5440_pcie_get_clk_resources,
+- .init_clk_resources = exynos5440_pcie_init_clk_resources,
+- .deinit_clk_resources = exynos5440_pcie_deinit_clk_resources,
+-};
+-
+ static void exynos_pcie_writel(void __iomem *base, u32 val, u32 reg)
+ {
+ writel(val, base + reg);
+@@ -173,94 +104,71 @@ static void exynos_pcie_sideband_dbi_w_mode(struct exynos_pcie *ep, bool on)
+ {
+ u32 val;
+
+- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_AWMISC);
++ val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_AWMISC);
+ if (on)
+ val |= PCIE_ELBI_SLV_DBI_ENABLE;
+ else
+ val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
+- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
++ exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_AWMISC);
+ }
+
+ static void exynos_pcie_sideband_dbi_r_mode(struct exynos_pcie *ep, bool on)
+ {
+ u32 val;
+
+- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_SLV_ARMISC);
++ val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_SLV_ARMISC);
+ if (on)
+ val |= PCIE_ELBI_SLV_DBI_ENABLE;
+ else
+ val &= ~PCIE_ELBI_SLV_DBI_ENABLE;
+- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
++ exynos_pcie_writel(ep->elbi_base, val, PCIE_ELBI_SLV_ARMISC);
+ }
+
+ static void exynos_pcie_assert_core_reset(struct exynos_pcie *ep)
+ {
+ u32 val;
+
+- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
++ val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
+ val &= ~PCIE_CORE_RESET_ENABLE;
+- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
+- exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_PWR_RESET);
+- exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_STICKY_RESET);
+- exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_NONSTICKY_RESET);
++ exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
++ exynos_pcie_writel(ep->elbi_base, 0, PCIE_STICKY_RESET);
++ exynos_pcie_writel(ep->elbi_base, 0, PCIE_NONSTICKY_RESET);
+ }
+
+ static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep)
+ {
+ u32 val;
+
+- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_CORE_RESET);
++ val = exynos_pcie_readl(ep->elbi_base, PCIE_CORE_RESET);
+ val |= PCIE_CORE_RESET_ENABLE;
+
+- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_CORE_RESET);
+- exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_STICKY_RESET);
+- exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET);
+- exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET);
+- exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET);
+-}
+-
+-static void exynos_pcie_assert_reset(struct exynos_pcie *ep)
+-{
+- struct dw_pcie *pci = ep->pci;
+- struct device *dev = pci->dev;
+-
+- if (ep->reset_gpio >= 0)
+- devm_gpio_request_one(dev, ep->reset_gpio,
+- GPIOF_OUT_INIT_HIGH, "RESET");
++ exynos_pcie_writel(ep->elbi_base, val, PCIE_CORE_RESET);
++ exynos_pcie_writel(ep->elbi_base, 1, PCIE_STICKY_RESET);
++ exynos_pcie_writel(ep->elbi_base, 1, PCIE_NONSTICKY_RESET);
++ exynos_pcie_writel(ep->elbi_base, 1, PCIE_APP_INIT_RESET);
++ exynos_pcie_writel(ep->elbi_base, 0, PCIE_APP_INIT_RESET);
+ }
+
+ static int exynos_pcie_start_link(struct dw_pcie *pci)
+ {
+ struct exynos_pcie *ep = to_exynos_pcie(pci);
++ u32 val;
++
++ val = exynos_pcie_readl(ep->elbi_base, PCIE_SW_WAKE);
++ val &= ~PCIE_BUS_EN;
++ exynos_pcie_writel(ep->elbi_base, val, PCIE_SW_WAKE);
+
+ /* assert LTSSM enable */
+- exynos_pcie_writel(ep->mem_res->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
++ exynos_pcie_writel(ep->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
+ PCIE_APP_LTSSM_ENABLE);
+-
+- /* check if the link is up or not */
+- if (!dw_pcie_wait_for_link(pci))
+- return 0;
+-
+- phy_power_off(ep->phy);
+- return -ETIMEDOUT;
++ return 0;
+ }
+
+ static void exynos_pcie_clear_irq_pulse(struct exynos_pcie *ep)
+ {
+- u32 val;
+-
+- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_PULSE);
+- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_PULSE);
+-}
+-
+-static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
+-{
+- u32 val;
++ u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_IRQ_PULSE);
+
+- /* enable INTX interrupt */
+- val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
+- IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
+- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_PULSE);
++ exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_PULSE);
+ }
+
+ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
+@@ -271,22 +179,14 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
+ return IRQ_HANDLED;
+ }
+
+-static void exynos_pcie_msi_init(struct exynos_pcie *ep)
+-{
+- u32 val;
+-
+- /* enable MSI interrupt */
+- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL);
+- val |= IRQ_MSI_ENABLE;
+- exynos_pcie_writel(ep->mem_res->elbi_base, val, PCIE_IRQ_EN_LEVEL);
+-}
+-
+-static void exynos_pcie_enable_interrupts(struct exynos_pcie *ep)
++static void exynos_pcie_enable_irq_pulse(struct exynos_pcie *ep)
+ {
+- exynos_pcie_enable_irq_pulse(ep);
++ u32 val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
++ IRQ_INTC_ASSERT | IRQ_INTD_ASSERT;
+
+- if (IS_ENABLED(CONFIG_PCI_MSI))
+- exynos_pcie_msi_init(ep);
++ exynos_pcie_writel(ep->elbi_base, val, PCIE_IRQ_EN_PULSE);
++ exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_LEVEL);
++ exynos_pcie_writel(ep->elbi_base, 0, PCIE_IRQ_EN_SPECIAL);
+ }
+
+ static u32 exynos_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
+@@ -345,13 +245,9 @@ static struct pci_ops exynos_pci_ops = {
+ static int exynos_pcie_link_up(struct dw_pcie *pci)
+ {
+ struct exynos_pcie *ep = to_exynos_pcie(pci);
+- u32 val;
++ u32 val = exynos_pcie_readl(ep->elbi_base, PCIE_ELBI_RDLH_LINKUP);
+
+- val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_ELBI_RDLH_LINKUP);
+- if (val == PCIE_ELBI_LTSSM_ENABLE)
+- return 1;
+-
+- return 0;
++ return (val & PCIE_ELBI_XMLH_LINKUP);
+ }
+
+ static int exynos_pcie_host_init(struct pcie_port *pp)
+@@ -364,17 +260,11 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
+ exynos_pcie_assert_core_reset(ep);
+
+ phy_reset(ep->phy);
+-
+- exynos_pcie_writel(ep->mem_res->elbi_base, 1,
+- PCIE_PWR_RESET);
+-
+ phy_power_on(ep->phy);
+ phy_init(ep->phy);
+
+ exynos_pcie_deassert_core_reset(ep);
+- exynos_pcie_assert_reset(ep);
+-
+- exynos_pcie_enable_interrupts(ep);
++ exynos_pcie_enable_irq_pulse(ep);
+
+ return 0;
+ }
+@@ -383,26 +273,27 @@ static const struct dw_pcie_host_ops exynos_pcie_host_ops = {
+ .host_init = exynos_pcie_host_init,
+ };
+
+-static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
++static int exynos_add_pcie_port(struct exynos_pcie *ep,
+ struct platform_device *pdev)
+ {
+- struct dw_pcie *pci = ep->pci;
++ struct dw_pcie *pci = &ep->pci;
+ struct pcie_port *pp = &pci->pp;
+ struct device *dev = &pdev->dev;
+ int ret;
+
+- pp->irq = platform_get_irq(pdev, 1);
++ pp->irq = platform_get_irq(pdev, 0);
+ if (pp->irq < 0)
+ return pp->irq;
+
+ ret = devm_request_irq(dev, pp->irq, exynos_pcie_irq_handler,
+- IRQF_SHARED, "exynos-pcie", ep);
++ IRQF_SHARED, "exynos-pcie", ep);
+ if (ret) {
+ dev_err(dev, "failed to request irq\n");
+ return ret;
+ }
+
+ pp->ops = &exynos_pcie_host_ops;
++ pp->msi_irq = -ENODEV;
+
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+@@ -420,10 +311,9 @@ static const struct dw_pcie_ops dw_pcie_ops = {
+ .start_link = exynos_pcie_start_link,
+ };
+
+-static int __init exynos_pcie_probe(struct platform_device *pdev)
++static int exynos_pcie_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+- struct dw_pcie *pci;
+ struct exynos_pcie *ep;
+ struct device_node *np = dev->of_node;
+ int ret;
+@@ -432,43 +322,45 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
+ if (!ep)
+ return -ENOMEM;
+
+- pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
+- if (!pci)
+- return -ENOMEM;
+-
+- pci->dev = dev;
+- pci->ops = &dw_pcie_ops;
+-
+- ep->pci = pci;
+- ep->ops = (const struct exynos_pcie_ops *)
+- of_device_get_match_data(dev);
+-
+- ep->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
++ ep->pci.dev = dev;
++ ep->pci.ops = &dw_pcie_ops;
+
+ ep->phy = devm_of_phy_get(dev, np, NULL);
+- if (IS_ERR(ep->phy)) {
+- if (PTR_ERR(ep->phy) != -ENODEV)
+- return PTR_ERR(ep->phy);
++ if (IS_ERR(ep->phy))
++ return PTR_ERR(ep->phy);
+
+- ep->phy = NULL;
+- }
++ /* External Local Bus interface (ELBI) registers */
++ ep->elbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi");
++ if (IS_ERR(ep->elbi_base))
++ return PTR_ERR(ep->elbi_base);
+
+- if (ep->ops && ep->ops->get_mem_resources) {
+- ret = ep->ops->get_mem_resources(pdev, ep);
+- if (ret)
+- return ret;
++ ep->clk = devm_clk_get(dev, "pcie");
++ if (IS_ERR(ep->clk)) {
++ dev_err(dev, "Failed to get pcie rc clock\n");
++ return PTR_ERR(ep->clk);
+ }
+
+- if (ep->ops && ep->ops->get_clk_resources &&
+- ep->ops->init_clk_resources) {
+- ret = ep->ops->get_clk_resources(ep);
+- if (ret)
+- return ret;
+- ret = ep->ops->init_clk_resources(ep);
+- if (ret)
+- return ret;
++ ep->bus_clk = devm_clk_get(dev, "pcie_bus");
++ if (IS_ERR(ep->bus_clk)) {
++ dev_err(dev, "Failed to get pcie bus clock\n");
++ return PTR_ERR(ep->bus_clk);
+ }
+
++ ep->supplies[0].supply = "vdd18";
++ ep->supplies[1].supply = "vdd10";
++ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ep->supplies),
++ ep->supplies);
++ if (ret)
++ return ret;
++
++ ret = exynos_pcie_init_clk_resources(ep);
++ if (ret)
++ return ret;
++
++ ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies);
++ if (ret)
++ return ret;
++
+ platform_set_drvdata(pdev, ep);
+
+ ret = exynos_add_pcie_port(ep, pdev);
+@@ -479,9 +371,9 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
+
+ fail_probe:
+ phy_exit(ep->phy);
++ exynos_pcie_deinit_clk_resources(ep);
++ regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
+
+- if (ep->ops && ep->ops->deinit_clk_resources)
+- ep->ops->deinit_clk_resources(ep);
+ return ret;
+ }
+
+@@ -489,32 +381,65 @@ static int __exit exynos_pcie_remove(struct platform_device *pdev)
+ {
+ struct exynos_pcie *ep = platform_get_drvdata(pdev);
+
+- if (ep->ops && ep->ops->deinit_clk_resources)
+- ep->ops->deinit_clk_resources(ep);
++ dw_pcie_host_deinit(&ep->pci.pp);
++ exynos_pcie_assert_core_reset(ep);
++ phy_power_off(ep->phy);
++ phy_exit(ep->phy);
++ exynos_pcie_deinit_clk_resources(ep);
++ regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
++
++ return 0;
++}
++
++static int __maybe_unused exynos_pcie_suspend_noirq(struct device *dev)
++{
++ struct exynos_pcie *ep = dev_get_drvdata(dev);
++
++ exynos_pcie_assert_core_reset(ep);
++ phy_power_off(ep->phy);
++ phy_exit(ep->phy);
++ regulator_bulk_disable(ARRAY_SIZE(ep->supplies), ep->supplies);
+
+ return 0;
+ }
+
++static int __maybe_unused exynos_pcie_resume_noirq(struct device *dev)
++{
++ struct exynos_pcie *ep = dev_get_drvdata(dev);
++ struct dw_pcie *pci = &ep->pci;
++ struct pcie_port *pp = &pci->pp;
++ int ret;
++
++ ret = regulator_bulk_enable(ARRAY_SIZE(ep->supplies), ep->supplies);
++ if (ret)
++ return ret;
++
++ /* exynos_pcie_host_init controls ep->phy */
++ exynos_pcie_host_init(pp);
++ dw_pcie_setup_rc(pp);
++ exynos_pcie_start_link(pci);
++ return dw_pcie_wait_for_link(pci);
++}
++
++static const struct dev_pm_ops exynos_pcie_pm_ops = {
++ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_pcie_suspend_noirq,
++ exynos_pcie_resume_noirq)
++};
++
+ static const struct of_device_id exynos_pcie_of_match[] = {
+- {
+- .compatible = "samsung,exynos5440-pcie",
+- .data = &exynos5440_pcie_ops
+- },
+- {},
++ { .compatible = "samsung,exynos5433-pcie", },
++ { },
+ };
+
+ static struct platform_driver exynos_pcie_driver = {
++ .probe = exynos_pcie_probe,
+ .remove = __exit_p(exynos_pcie_remove),
+ .driver = {
+ .name = "exynos-pcie",
+ .of_match_table = exynos_pcie_of_match,
++ .pm = &exynos_pcie_pm_ops,
+ },
+ };
+-
+-/* Exynos PCIe driver does not allow module unload */
+-
+-static int __init exynos_pcie_init(void)
+-{
+- return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe);
+-}
+-subsys_initcall(exynos_pcie_init);
++module_platform_driver(exynos_pcie_driver);
++MODULE_LICENSE("GPL v2");
++MODULE_DEVICE_TABLE(of, exynos_pcie_of_match);
+diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
+index 158ff4331a141..01c2b63e3b3a1 100644
+--- a/drivers/pci/quirks.c
++++ b/drivers/pci/quirks.c
+@@ -2538,6 +2538,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disab
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi);
+ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, 0x0761, quirk_disable_all_msi);
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SAMSUNG, 0xa5e3, quirk_disable_all_msi);
+
+ /* Disable MSI on chipsets that are known to not support it */
+ static void quirk_disable_msi(struct pci_dev *dev)
+--
+2.42.0
+
--- /dev/null
+From a5bb5f9005bc2bba67a3c1eee93921b864d23624 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Nov 2020 15:11:46 -0600
+Subject: PCI: dwc: Move "dbi", "dbi2", and "addr_space" resource setup into
+ common code
+
+From: Rob Herring <robh@kernel.org>
+
+[ Upstream commit a0fd361db8e508b8ce71c284b5ae3961759a0b3b ]
+
+Most DWC drivers use the common register resource names "dbi", "dbi2", and
+"addr_space", so let's move their setup into the DWC common code.
+
+This means 'dbi_base' in particular is setup later, but it looks like no
+drivers touch DBI registers before dw_pcie_host_init or dw_pcie_ep_init.
+
+Link: https://lore.kernel.org/r/20201105211159.1814485-4-robh@kernel.org
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Jingoo Han <jingoohan1@gmail.com>
+Cc: Kishon Vijay Abraham I <kishon@ti.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Cc: Murali Karicheri <m-karicheri2@ti.com>
+Cc: Minghuan Lian <minghuan.Lian@nxp.com>
+Cc: Mingkai Hu <mingkai.hu@nxp.com>
+Cc: Roy Zang <roy.zang@nxp.com>
+Cc: Jonathan Chocron <jonnyc@amazon.com>
+Cc: Jesper Nilsson <jesper.nilsson@axis.com>
+Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Xiaowei Song <songxiaowei@hisilicon.com>
+Cc: Binghui Wang <wangbinghui@hisilicon.com>
+Cc: Andy Gross <agross@kernel.org>
+Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
+Cc: Stanimir Varbanov <svarbanov@mm-sol.com>
+Cc: Pratyush Anand <pratyush.anand@gmail.com>
+Cc: Thierry Reding <thierry.reding@gmail.com>
+Cc: Jonathan Hunter <jonathanh@nvidia.com>
+Cc: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
+Cc: linux-omap@vger.kernel.org
+Cc: linuxppc-dev@lists.ozlabs.org
+Cc: linux-arm-kernel@axis.com
+Cc: linux-arm-msm@vger.kernel.org
+Cc: linux-tegra@vger.kernel.org
+Stable-dep-of: 83a939f0fdc2 ("PCI: exynos: Don't discard .remove() callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/dwc/pci-dra7xx.c | 8 ----
+ drivers/pci/controller/dwc/pci-keystone.c | 29 +-----------
+ .../pci/controller/dwc/pci-layerscape-ep.c | 37 +--------------
+ drivers/pci/controller/dwc/pcie-al.c | 9 +---
+ drivers/pci/controller/dwc/pcie-artpec6.c | 43 ++----------------
+ .../pci/controller/dwc/pcie-designware-ep.c | 29 ++++++++++--
+ .../pci/controller/dwc/pcie-designware-host.c | 7 +++
+ .../pci/controller/dwc/pcie-designware-plat.c | 45 +------------------
+ drivers/pci/controller/dwc/pcie-intel-gw.c | 4 --
+ drivers/pci/controller/dwc/pcie-kirin.c | 5 ---
+ drivers/pci/controller/dwc/pcie-qcom.c | 8 ----
+ drivers/pci/controller/dwc/pcie-spear13xx.c | 11 +----
+ drivers/pci/controller/dwc/pcie-tegra194.c | 22 ---------
+ drivers/pci/controller/dwc/pcie-uniphier-ep.c | 38 +---------------
+ drivers/pci/controller/dwc/pcie-uniphier.c | 6 ---
+ 15 files changed, 47 insertions(+), 254 deletions(-)
+
+diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
+index 6d012d2b1e90d..a4aabc85dbb12 100644
+--- a/drivers/pci/controller/dwc/pci-dra7xx.c
++++ b/drivers/pci/controller/dwc/pci-dra7xx.c
+@@ -578,7 +578,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
+ {
+ int ret;
+ struct dw_pcie_ep *ep;
+- struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct dw_pcie *pci = dra7xx->pci;
+
+@@ -594,13 +593,6 @@ static int __init dra7xx_add_pcie_ep(struct dra7xx_pcie *dra7xx,
+ if (IS_ERR(pci->dbi_base2))
+ return PTR_ERR(pci->dbi_base2);
+
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
+- if (!res)
+- return -EINVAL;
+-
+- ep->phys_base = res->start;
+- ep->addr_size = resource_size(res);
+-
+ ret = dw_pcie_ep_init(ep);
+ if (ret) {
+ dev_err(dev, "failed to initialize endpoint\n");
+diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
+index 5b722287aac92..5177f6d1ca592 100644
+--- a/drivers/pci/controller/dwc/pci-keystone.c
++++ b/drivers/pci/controller/dwc/pci-keystone.c
+@@ -978,33 +978,6 @@ static const struct dw_pcie_ep_ops ks_pcie_am654_ep_ops = {
+ .get_features = &ks_pcie_am654_get_features,
+ };
+
+-static int __init ks_pcie_add_pcie_ep(struct keystone_pcie *ks_pcie,
+- struct platform_device *pdev)
+-{
+- int ret;
+- struct dw_pcie_ep *ep;
+- struct resource *res;
+- struct device *dev = &pdev->dev;
+- struct dw_pcie *pci = ks_pcie->pci;
+-
+- ep = &pci->ep;
+-
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
+- if (!res)
+- return -EINVAL;
+-
+- ep->phys_base = res->start;
+- ep->addr_size = resource_size(res);
+-
+- ret = dw_pcie_ep_init(ep);
+- if (ret) {
+- dev_err(dev, "failed to initialize endpoint\n");
+- return ret;
+- }
+-
+- return 0;
+-}
+-
+ static void ks_pcie_disable_phy(struct keystone_pcie *ks_pcie)
+ {
+ int num_lanes = ks_pcie->num_lanes;
+@@ -1314,7 +1287,7 @@ static int ks_pcie_probe(struct platform_device *pdev)
+ }
+
+ pci->ep.ops = ep_ops;
+- ret = ks_pcie_add_pcie_ep(ks_pcie, pdev);
++ ret = dw_pcie_ep_init(&pci->ep);
+ if (ret < 0)
+ goto err_get_sync;
+ break;
+diff --git a/drivers/pci/controller/dwc/pci-layerscape-ep.c b/drivers/pci/controller/dwc/pci-layerscape-ep.c
+index 84206f265e544..4d12efdacd2f5 100644
+--- a/drivers/pci/controller/dwc/pci-layerscape-ep.c
++++ b/drivers/pci/controller/dwc/pci-layerscape-ep.c
+@@ -18,8 +18,6 @@
+
+ #include "pcie-designware.h"
+
+-#define PCIE_DBI2_OFFSET 0x1000 /* DBI2 base address*/
+-
+ #define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
+
+ struct ls_pcie_ep_drvdata {
+@@ -124,34 +122,6 @@ static const struct of_device_id ls_pcie_ep_of_match[] = {
+ { },
+ };
+
+-static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie,
+- struct platform_device *pdev)
+-{
+- struct dw_pcie *pci = pcie->pci;
+- struct device *dev = pci->dev;
+- struct dw_pcie_ep *ep;
+- struct resource *res;
+- int ret;
+-
+- ep = &pci->ep;
+- ep->ops = pcie->drvdata->ops;
+-
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
+- if (!res)
+- return -EINVAL;
+-
+- ep->phys_base = res->start;
+- ep->addr_size = resource_size(res);
+-
+- ret = dw_pcie_ep_init(ep);
+- if (ret) {
+- dev_err(dev, "failed to initialize endpoint\n");
+- return ret;
+- }
+-
+- return 0;
+-}
+-
+ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -159,7 +129,6 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
+ struct ls_pcie_ep *pcie;
+ struct pci_epc_features *ls_epc;
+ struct resource *dbi_base;
+- int ret;
+
+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie)
+@@ -188,13 +157,11 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
+ if (IS_ERR(pci->dbi_base))
+ return PTR_ERR(pci->dbi_base);
+
+- pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET;
++ pci->ep.ops = &ls_pcie_ep_ops;
+
+ platform_set_drvdata(pdev, pcie);
+
+- ret = ls_add_pcie_ep(pcie, pdev);
+-
+- return ret;
++ return dw_pcie_ep_init(&pci->ep);
+ }
+
+ static struct platform_driver ls_pcie_ep_driver = {
+diff --git a/drivers/pci/controller/dwc/pcie-al.c b/drivers/pci/controller/dwc/pcie-al.c
+index f973fbca90cf7..d06866921187b 100644
+--- a/drivers/pci/controller/dwc/pcie-al.c
++++ b/drivers/pci/controller/dwc/pcie-al.c
+@@ -347,7 +347,6 @@ static int al_pcie_probe(struct platform_device *pdev)
+ struct device *dev = &pdev->dev;
+ struct resource *controller_res;
+ struct resource *ecam_res;
+- struct resource *dbi_res;
+ struct al_pcie *al_pcie;
+ struct dw_pcie *pci;
+
+@@ -365,11 +364,6 @@ static int al_pcie_probe(struct platform_device *pdev)
+ al_pcie->pci = pci;
+ al_pcie->dev = dev;
+
+- dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+- pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res);
+- if (IS_ERR(pci->dbi_base))
+- return PTR_ERR(pci->dbi_base);
+-
+ ecam_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
+ if (!ecam_res) {
+ dev_err(dev, "couldn't find 'config' reg in DT\n");
+@@ -386,8 +380,7 @@ static int al_pcie_probe(struct platform_device *pdev)
+ return PTR_ERR(al_pcie->controller_base);
+ }
+
+- dev_dbg(dev, "From DT: dbi_base: %pR, controller_base: %pR\n",
+- dbi_res, controller_res);
++ dev_dbg(dev, "From DT: controller_base: %pR\n", controller_res);
+
+ platform_set_drvdata(pdev, al_pcie);
+
+diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c
+index 929448e9e0bc6..52ad7909cd0c0 100644
+--- a/drivers/pci/controller/dwc/pcie-artpec6.c
++++ b/drivers/pci/controller/dwc/pcie-artpec6.c
+@@ -403,38 +403,6 @@ static const struct dw_pcie_ep_ops pcie_ep_ops = {
+ .raise_irq = artpec6_pcie_raise_irq,
+ };
+
+-static int artpec6_add_pcie_ep(struct artpec6_pcie *artpec6_pcie,
+- struct platform_device *pdev)
+-{
+- int ret;
+- struct dw_pcie_ep *ep;
+- struct resource *res;
+- struct device *dev = &pdev->dev;
+- struct dw_pcie *pci = artpec6_pcie->pci;
+-
+- ep = &pci->ep;
+- ep->ops = &pcie_ep_ops;
+-
+- pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
+- if (IS_ERR(pci->dbi_base2))
+- return PTR_ERR(pci->dbi_base2);
+-
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
+- if (!res)
+- return -EINVAL;
+-
+- ep->phys_base = res->start;
+- ep->addr_size = resource_size(res);
+-
+- ret = dw_pcie_ep_init(ep);
+- if (ret) {
+- dev_err(dev, "failed to initialize endpoint\n");
+- return ret;
+- }
+-
+- return 0;
+-}
+-
+ static int artpec6_pcie_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -469,10 +437,6 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
+ artpec6_pcie->variant = variant;
+ artpec6_pcie->mode = mode;
+
+- pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
+- if (IS_ERR(pci->dbi_base))
+- return PTR_ERR(pci->dbi_base);
+-
+ artpec6_pcie->phy_base =
+ devm_platform_ioremap_resource_byname(pdev, "phy");
+ if (IS_ERR(artpec6_pcie->phy_base))
+@@ -504,9 +468,10 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
+ val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
+ val &= ~PCIECFG_DEVICE_TYPE_MASK;
+ artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
+- ret = artpec6_add_pcie_ep(artpec6_pcie, pdev);
+- if (ret < 0)
+- return ret;
++
++ pci->ep.ops = &pcie_ep_ops;
++
++ return dw_pcie_ep_init(&pci->ep);
+ break;
+ }
+ default:
+diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
+index 95ed719402d75..ea1b8893d25fe 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
++++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
+@@ -7,6 +7,7 @@
+ */
+
+ #include <linux/of.h>
++#include <linux/platform_device.h>
+
+ #include "pcie-designware.h"
+ #include <linux/pci-epc.h>
+@@ -676,20 +677,42 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
+ int ret;
+ void *addr;
+ u8 func_no;
++ struct resource *res;
+ struct pci_epc *epc;
+ struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+ struct device *dev = pci->dev;
++ struct platform_device *pdev = to_platform_device(dev);
+ struct device_node *np = dev->of_node;
+ const struct pci_epc_features *epc_features;
+ struct dw_pcie_ep_func *ep_func;
+
+ INIT_LIST_HEAD(&ep->func_list);
+
+- if (!pci->dbi_base || !pci->dbi_base2) {
+- dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
+- return -EINVAL;
++ if (!pci->dbi_base) {
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
++ pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
++ if (IS_ERR(pci->dbi_base))
++ return PTR_ERR(pci->dbi_base);
++ }
++
++ if (!pci->dbi_base2) {
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2");
++ if (!res)
++ pci->dbi_base2 = pci->dbi_base + SZ_4K;
++ else {
++ pci->dbi_base2 = devm_pci_remap_cfg_resource(dev, res);
++ if (IS_ERR(pci->dbi_base2))
++ return PTR_ERR(pci->dbi_base2);
++ }
+ }
+
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
++ if (!res)
++ return -EINVAL;
++
++ ep->phys_base = res->start;
++ ep->addr_size = resource_size(res);
++
+ ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows);
+ if (ret < 0) {
+ dev_err(dev, "Unable to read *num-ib-windows* property\n");
+diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
+index 42d8116a4a002..d6b7eec1a25b0 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -310,6 +310,13 @@ int dw_pcie_host_init(struct pcie_port *pp)
+ dev_err(dev, "Missing *config* reg space\n");
+ }
+
++ if (!pci->dbi_base) {
++ struct resource *dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
++ pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_res);
++ if (IS_ERR(pci->dbi_base))
++ return PTR_ERR(pci->dbi_base);
++ }
++
+ bridge = devm_pci_alloc_host_bridge(dev, 0);
+ if (!bridge)
+ return -ENOMEM;
+diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
+index e3e300669ed56..562a05e07b1d5 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
++++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
+@@ -139,43 +139,11 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
+ return 0;
+ }
+
+-static int dw_plat_add_pcie_ep(struct dw_plat_pcie *dw_plat_pcie,
+- struct platform_device *pdev)
+-{
+- int ret;
+- struct dw_pcie_ep *ep;
+- struct resource *res;
+- struct device *dev = &pdev->dev;
+- struct dw_pcie *pci = dw_plat_pcie->pci;
+-
+- ep = &pci->ep;
+- ep->ops = &pcie_ep_ops;
+-
+- pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
+- if (IS_ERR(pci->dbi_base2))
+- return PTR_ERR(pci->dbi_base2);
+-
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
+- if (!res)
+- return -EINVAL;
+-
+- ep->phys_base = res->start;
+- ep->addr_size = resource_size(res);
+-
+- ret = dw_pcie_ep_init(ep);
+- if (ret) {
+- dev_err(dev, "Failed to initialize endpoint\n");
+- return ret;
+- }
+- return 0;
+-}
+-
+ static int dw_plat_pcie_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+ struct dw_plat_pcie *dw_plat_pcie;
+ struct dw_pcie *pci;
+- struct resource *res; /* Resource from DT */
+ int ret;
+ const struct of_device_id *match;
+ const struct dw_plat_pcie_of_data *data;
+@@ -202,14 +170,6 @@ static int dw_plat_pcie_probe(struct platform_device *pdev)
+ dw_plat_pcie->pci = pci;
+ dw_plat_pcie->mode = mode;
+
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+- if (!res)
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-
+- pci->dbi_base = devm_ioremap_resource(dev, res);
+- if (IS_ERR(pci->dbi_base))
+- return PTR_ERR(pci->dbi_base);
+-
+ platform_set_drvdata(pdev, dw_plat_pcie);
+
+ switch (dw_plat_pcie->mode) {
+@@ -225,9 +185,8 @@ static int dw_plat_pcie_probe(struct platform_device *pdev)
+ if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP))
+ return -ENODEV;
+
+- ret = dw_plat_add_pcie_ep(dw_plat_pcie, pdev);
+- if (ret < 0)
+- return ret;
++ pci->ep.ops = &pcie_ep_ops;
++ return dw_pcie_ep_init(&pci->ep);
+ break;
+ default:
+ dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode);
+diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
+index 5e1a284fdc538..429171c35945d 100644
+--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
++++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
+@@ -236,10 +236,6 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
+ struct device *dev = pci->dev;
+ int ret;
+
+- pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "dbi");
+- if (IS_ERR(pci->dbi_base))
+- return PTR_ERR(pci->dbi_base);
+-
+ lpp->core_clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(lpp->core_clk)) {
+ ret = PTR_ERR(lpp->core_clk);
+diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
+index d0a6a2dee6f5b..3042a23cf09a4 100644
+--- a/drivers/pci/controller/dwc/pcie-kirin.c
++++ b/drivers/pci/controller/dwc/pcie-kirin.c
+@@ -157,11 +157,6 @@ static long kirin_pcie_get_resource(struct kirin_pcie *kirin_pcie,
+ if (IS_ERR(kirin_pcie->phy_base))
+ return PTR_ERR(kirin_pcie->phy_base);
+
+- kirin_pcie->pci->dbi_base =
+- devm_platform_ioremap_resource_byname(pdev, "dbi");
+- if (IS_ERR(kirin_pcie->pci->dbi_base))
+- return PTR_ERR(kirin_pcie->pci->dbi_base);
+-
+ kirin_pcie->crgctrl =
+ syscon_regmap_lookup_by_compatible("hisilicon,hi3660-crgctrl");
+ if (IS_ERR(kirin_pcie->crgctrl))
+diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
+index c68e14271c02c..150dd6fe7ba39 100644
+--- a/drivers/pci/controller/dwc/pcie-qcom.c
++++ b/drivers/pci/controller/dwc/pcie-qcom.c
+@@ -1360,7 +1360,6 @@ static const struct dw_pcie_ops dw_pcie_ops = {
+ static int qcom_pcie_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+- struct resource *res;
+ struct pcie_port *pp;
+ struct dw_pcie *pci;
+ struct qcom_pcie *pcie;
+@@ -1399,13 +1398,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
+ goto err_pm_runtime_put;
+ }
+
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+- pci->dbi_base = devm_pci_remap_cfg_resource(dev, res);
+- if (IS_ERR(pci->dbi_base)) {
+- ret = PTR_ERR(pci->dbi_base);
+- goto err_pm_runtime_put;
+- }
+-
+ pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi");
+ if (IS_ERR(pcie->elbi)) {
+ ret = PTR_ERR(pcie->elbi);
+diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c
+index e348225f651fb..1ed7e3501ff1c 100644
+--- a/drivers/pci/controller/dwc/pcie-spear13xx.c
++++ b/drivers/pci/controller/dwc/pcie-spear13xx.c
+@@ -152,6 +152,8 @@ static int spear13xx_pcie_host_init(struct pcie_port *pp)
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci);
+
++ spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
++
+ spear13xx_pcie_establish_link(spear13xx_pcie);
+ spear13xx_pcie_enable_interrupts(spear13xx_pcie);
+
+@@ -203,7 +205,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
+ struct dw_pcie *pci;
+ struct spear13xx_pcie *spear13xx_pcie;
+ struct device_node *np = dev->of_node;
+- struct resource *dbi_base;
+ int ret;
+
+ spear13xx_pcie = devm_kzalloc(dev, sizeof(*spear13xx_pcie), GFP_KERNEL);
+@@ -242,14 +243,6 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
+ return ret;
+ }
+
+- dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+- pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
+- if (IS_ERR(pci->dbi_base)) {
+- ret = PTR_ERR(pci->dbi_base);
+- goto fail_clk;
+- }
+- spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
+-
+ if (of_property_read_bool(np, "st,pcie-is-gen1"))
+ pci->link_gen = 1;
+
+diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
+index 80c2015b49d8f..825cb65945fba 100644
+--- a/drivers/pci/controller/dwc/pcie-tegra194.c
++++ b/drivers/pci/controller/dwc/pcie-tegra194.c
+@@ -1913,19 +1913,12 @@ static int tegra_pcie_config_ep(struct tegra_pcie_dw *pcie,
+ struct dw_pcie *pci = &pcie->pci;
+ struct device *dev = pcie->dev;
+ struct dw_pcie_ep *ep;
+- struct resource *res;
+ char *name;
+ int ret;
+
+ ep = &pci->ep;
+ ep->ops = &pcie_ep_ops;
+
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
+- if (!res)
+- return -EINVAL;
+-
+- ep->phys_base = res->start;
+- ep->addr_size = resource_size(res);
+ ep->page_size = SZ_64K;
+
+ ret = gpiod_set_debounce(pcie->pex_rst_gpiod, PERST_DEBOUNCE_TIME);
+@@ -1989,7 +1982,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
+ struct device *dev = &pdev->dev;
+ struct resource *atu_dma_res;
+ struct tegra_pcie_dw *pcie;
+- struct resource *dbi_res;
+ struct pcie_port *pp;
+ struct dw_pcie *pci;
+ struct phy **phys;
+@@ -2098,20 +2090,6 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
+
+ pcie->phys = phys;
+
+- dbi_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+- if (!dbi_res) {
+- dev_err(dev, "Failed to find \"dbi\" region\n");
+- return -ENODEV;
+- }
+- pcie->dbi_res = dbi_res;
+-
+- pci->dbi_base = devm_ioremap_resource(dev, dbi_res);
+- if (IS_ERR(pci->dbi_base))
+- return PTR_ERR(pci->dbi_base);
+-
+- /* Tegra HW locates DBI2 at a fixed offset from DBI */
+- pci->dbi_base2 = pci->dbi_base + 0x1000;
+-
+ atu_dma_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "atu_dma");
+ if (!atu_dma_res) {
+diff --git a/drivers/pci/controller/dwc/pcie-uniphier-ep.c b/drivers/pci/controller/dwc/pcie-uniphier-ep.c
+index 1483559600610..69810c6b0d584 100644
+--- a/drivers/pci/controller/dwc/pcie-uniphier-ep.c
++++ b/drivers/pci/controller/dwc/pcie-uniphier-ep.c
+@@ -218,35 +218,6 @@ static const struct dw_pcie_ep_ops uniphier_pcie_ep_ops = {
+ .get_features = uniphier_pcie_get_features,
+ };
+
+-static int uniphier_add_pcie_ep(struct uniphier_pcie_ep_priv *priv,
+- struct platform_device *pdev)
+-{
+- struct dw_pcie *pci = &priv->pci;
+- struct dw_pcie_ep *ep = &pci->ep;
+- struct device *dev = &pdev->dev;
+- struct resource *res;
+- int ret;
+-
+- ep->ops = &uniphier_pcie_ep_ops;
+-
+- pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
+- if (IS_ERR(pci->dbi_base2))
+- return PTR_ERR(pci->dbi_base2);
+-
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
+- if (!res)
+- return -EINVAL;
+-
+- ep->phys_base = res->start;
+- ep->addr_size = resource_size(res);
+-
+- ret = dw_pcie_ep_init(ep);
+- if (ret)
+- dev_err(dev, "Failed to initialize endpoint (%d)\n", ret);
+-
+- return ret;
+-}
+-
+ static int uniphier_pcie_ep_enable(struct uniphier_pcie_ep_priv *priv)
+ {
+ int ret;
+@@ -300,7 +271,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+ struct uniphier_pcie_ep_priv *priv;
+- struct resource *res;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+@@ -314,11 +284,6 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
+ priv->pci.dev = dev;
+ priv->pci.ops = &dw_pcie_ops;
+
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+- priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res);
+- if (IS_ERR(priv->pci.dbi_base))
+- return PTR_ERR(priv->pci.dbi_base);
+-
+ priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+@@ -352,7 +317,8 @@ static int uniphier_pcie_ep_probe(struct platform_device *pdev)
+ if (ret)
+ return ret;
+
+- return uniphier_add_pcie_ep(priv, pdev);
++ priv->pci.ep.ops = &uniphier_pcie_ep_ops;
++ return dw_pcie_ep_init(&priv->pci.ep);
+ }
+
+ static const struct pci_epc_features uniphier_pro5_data = {
+diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
+index 527ec8aeb602f..85bf170e93541 100644
+--- a/drivers/pci/controller/dwc/pcie-uniphier.c
++++ b/drivers/pci/controller/dwc/pcie-uniphier.c
+@@ -394,7 +394,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+ struct uniphier_pcie_priv *priv;
+- struct resource *res;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+@@ -404,11 +403,6 @@ static int uniphier_pcie_probe(struct platform_device *pdev)
+ priv->pci.dev = dev;
+ priv->pci.ops = &dw_pcie_ops;
+
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
+- priv->pci.dbi_base = devm_pci_remap_cfg_resource(dev, res);
+- if (IS_ERR(priv->pci.dbi_base))
+- return PTR_ERR(priv->pci.dbi_base);
+-
+ priv->base = devm_platform_ioremap_resource_byname(pdev, "link");
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+--
+2.42.0
+
--- /dev/null
+From 991c38cf974a9c07aaa5c25b35d535adee2ed41d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Nov 2020 15:11:54 -0600
+Subject: PCI: dwc: Move dw_pcie_msi_init() into core
+
+From: Rob Herring <robh@kernel.org>
+
+[ Upstream commit 59fbab1ae40eb048eb2bd2385a5b981051513458 ]
+
+The host drivers which call dw_pcie_msi_init() are all the ones using
+the built-in MSI controller, so let's move it into the common DWC code.
+
+Link: https://lore.kernel.org/r/20201105211159.1814485-12-robh@kernel.org
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Jingoo Han <jingoohan1@gmail.com>
+Cc: Kishon Vijay Abraham I <kishon@ti.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Cc: Kukjin Kim <kgene@kernel.org>
+Cc: Krzysztof Kozlowski <krzk@kernel.org>
+Cc: Richard Zhu <hongxing.zhu@nxp.com>
+Cc: Lucas Stach <l.stach@pengutronix.de>
+Cc: Shawn Guo <shawnguo@kernel.org>
+Cc: Sascha Hauer <s.hauer@pengutronix.de>
+Cc: Pengutronix Kernel Team <kernel@pengutronix.de>
+Cc: Fabio Estevam <festevam@gmail.com>
+Cc: NXP Linux Team <linux-imx@nxp.com>
+Cc: Yue Wang <yue.wang@Amlogic.com>
+Cc: Kevin Hilman <khilman@baylibre.com>
+Cc: Neil Armstrong <narmstrong@baylibre.com>
+Cc: Jerome Brunet <jbrunet@baylibre.com>
+Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Cc: Jesper Nilsson <jesper.nilsson@axis.com>
+Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Xiaowei Song <songxiaowei@hisilicon.com>
+Cc: Binghui Wang <wangbinghui@hisilicon.com>
+Cc: Stanimir Varbanov <svarbanov@mm-sol.com>
+Cc: Andy Gross <agross@kernel.org>
+Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
+Cc: Pratyush Anand <pratyush.anand@gmail.com>
+Cc: Thierry Reding <thierry.reding@gmail.com>
+Cc: Jonathan Hunter <jonathanh@nvidia.com>
+Cc: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
+Cc: linux-omap@vger.kernel.org
+Cc: linux-samsung-soc@vger.kernel.org
+Cc: linux-amlogic@lists.infradead.org
+Cc: linux-arm-kernel@axis.com
+Cc: linux-arm-msm@vger.kernel.org
+Cc: linux-tegra@vger.kernel.org
+Stable-dep-of: 83a939f0fdc2 ("PCI: exynos: Don't discard .remove() callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/dwc/pci-dra7xx.c | 2 --
+ drivers/pci/controller/dwc/pci-exynos.c | 4 ----
+ drivers/pci/controller/dwc/pci-imx6.c | 1 -
+ drivers/pci/controller/dwc/pci-meson.c | 1 -
+ drivers/pci/controller/dwc/pcie-artpec6.c | 1 -
+ drivers/pci/controller/dwc/pcie-designware-host.c | 9 +++++----
+ drivers/pci/controller/dwc/pcie-designware-plat.c | 1 -
+ drivers/pci/controller/dwc/pcie-designware.h | 10 ----------
+ drivers/pci/controller/dwc/pcie-histb.c | 2 --
+ drivers/pci/controller/dwc/pcie-kirin.c | 1 -
+ drivers/pci/controller/dwc/pcie-qcom.c | 2 --
+ drivers/pci/controller/dwc/pcie-spear13xx.c | 6 +-----
+ drivers/pci/controller/dwc/pcie-tegra194.c | 2 --
+ drivers/pci/controller/dwc/pcie-uniphier.c | 1 -
+ 14 files changed, 6 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
+index 054423d9646d6..72a5a2bf933bc 100644
+--- a/drivers/pci/controller/dwc/pci-dra7xx.c
++++ b/drivers/pci/controller/dwc/pci-dra7xx.c
+@@ -182,8 +182,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp)
+ struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
+
+ dw_pcie_setup_rc(pp);
+-
+- dw_pcie_msi_init(pp);
+ dra7xx_pcie_enable_interrupts(dra7xx);
+
+ return 0;
+diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c
+index 6498b615c834a..3939fe22e8a20 100644
+--- a/drivers/pci/controller/dwc/pci-exynos.c
++++ b/drivers/pci/controller/dwc/pci-exynos.c
+@@ -273,12 +273,8 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
+
+ static void exynos_pcie_msi_init(struct exynos_pcie *ep)
+ {
+- struct dw_pcie *pci = ep->pci;
+- struct pcie_port *pp = &pci->pp;
+ u32 val;
+
+- dw_pcie_msi_init(pp);
+-
+ /* enable MSI interrupt */
+ val = exynos_pcie_readl(ep->mem_res->elbi_base, PCIE_IRQ_EN_LEVEL);
+ val |= IRQ_MSI_ENABLE;
+diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
+index 8d1d2d79693d6..dbdf79ac48683 100644
+--- a/drivers/pci/controller/dwc/pci-imx6.c
++++ b/drivers/pci/controller/dwc/pci-imx6.c
+@@ -840,7 +840,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
+ imx6_pcie_deassert_core_reset(imx6_pcie);
+ imx6_setup_phy_mpll(imx6_pcie);
+ dw_pcie_setup_rc(pp);
+- dw_pcie_msi_init(pp);
+
+ return 0;
+ }
+diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
+index 41a3351b100b5..2df0adcf0bf22 100644
+--- a/drivers/pci/controller/dwc/pci-meson.c
++++ b/drivers/pci/controller/dwc/pci-meson.c
+@@ -381,7 +381,6 @@ static int meson_pcie_host_init(struct pcie_port *pp)
+ meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
+
+ dw_pcie_setup_rc(pp);
+- dw_pcie_msi_init(pp);
+
+ return 0;
+ }
+diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c
+index 8b3da3038ac35..7ee8f3c83f8f3 100644
+--- a/drivers/pci/controller/dwc/pcie-artpec6.c
++++ b/drivers/pci/controller/dwc/pcie-artpec6.c
+@@ -329,7 +329,6 @@ static int artpec6_pcie_host_init(struct pcie_port *pp)
+ artpec6_pcie_deassert_core_reset(artpec6_pcie);
+ artpec6_pcie_wait_for_phy(artpec6_pcie);
+ dw_pcie_setup_rc(pp);
+- dw_pcie_msi_init(pp);
+
+ return 0;
+ }
+diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
+index b242d7e64c204..e740cbeda2bbc 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -256,7 +256,7 @@ int dw_pcie_allocate_domains(struct pcie_port *pp)
+ return 0;
+ }
+
+-void dw_pcie_free_msi(struct pcie_port *pp)
++static void dw_pcie_free_msi(struct pcie_port *pp)
+ {
+ if (pp->msi_irq) {
+ irq_set_chained_handler(pp->msi_irq, NULL);
+@@ -275,19 +275,18 @@ void dw_pcie_free_msi(struct pcie_port *pp)
+ }
+ }
+
+-void dw_pcie_msi_init(struct pcie_port *pp)
++static void dw_pcie_msi_init(struct pcie_port *pp)
+ {
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ u64 msi_target = (u64)pp->msi_data;
+
+- if (!IS_ENABLED(CONFIG_PCI_MSI))
++ if (!pci_msi_enabled() || !pp->has_msi_ctrl)
+ return;
+
+ /* Program the msi_data */
+ dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target));
+ dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target));
+ }
+-EXPORT_SYMBOL_GPL(dw_pcie_msi_init);
+
+ int dw_pcie_host_init(struct pcie_port *pp)
+ {
+@@ -424,6 +423,8 @@ int dw_pcie_host_init(struct pcie_port *pp)
+ goto err_free_msi;
+ }
+
++ dw_pcie_msi_init(pp);
++
+ if (!dw_pcie_link_up(pci) && pci->ops->start_link) {
+ ret = pci->ops->start_link(pci);
+ if (ret)
+diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
+index adebcaeb1a6c0..dec24e595c3e0 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
++++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
+@@ -36,7 +36,6 @@ static const struct of_device_id dw_plat_pcie_of_match[];
+ static int dw_plat_pcie_host_init(struct pcie_port *pp)
+ {
+ dw_pcie_setup_rc(pp);
+- dw_pcie_msi_init(pp);
+
+ return 0;
+ }
+diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
+index f33dc89a93650..04c61e2e23d07 100644
+--- a/drivers/pci/controller/dwc/pcie-designware.h
++++ b/drivers/pci/controller/dwc/pcie-designware.h
+@@ -365,8 +365,6 @@ static inline void dw_pcie_dbi_ro_wr_dis(struct dw_pcie *pci)
+
+ #ifdef CONFIG_PCIE_DW_HOST
+ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp);
+-void dw_pcie_msi_init(struct pcie_port *pp);
+-void dw_pcie_free_msi(struct pcie_port *pp);
+ void dw_pcie_setup_rc(struct pcie_port *pp);
+ int dw_pcie_host_init(struct pcie_port *pp);
+ void dw_pcie_host_deinit(struct pcie_port *pp);
+@@ -379,14 +377,6 @@ static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
+ return IRQ_NONE;
+ }
+
+-static inline void dw_pcie_msi_init(struct pcie_port *pp)
+-{
+-}
+-
+-static inline void dw_pcie_free_msi(struct pcie_port *pp)
+-{
+-}
+-
+ static inline void dw_pcie_setup_rc(struct pcie_port *pp)
+ {
+ }
+diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c
+index ece544165059b..210777c793ea0 100644
+--- a/drivers/pci/controller/dwc/pcie-histb.c
++++ b/drivers/pci/controller/dwc/pcie-histb.c
+@@ -199,8 +199,6 @@ static int histb_pcie_host_init(struct pcie_port *pp)
+ /* setup root complex */
+ dw_pcie_setup_rc(pp);
+
+- dw_pcie_msi_init(pp);
+-
+ return 0;
+ }
+
+diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
+index 675b4d8392d37..f84ac1b36b2cc 100644
+--- a/drivers/pci/controller/dwc/pcie-kirin.c
++++ b/drivers/pci/controller/dwc/pcie-kirin.c
+@@ -406,7 +406,6 @@ static int kirin_pcie_host_init(struct pcie_port *pp)
+ pp->bridge->ops = &kirin_pci_ops;
+
+ dw_pcie_setup_rc(pp);
+- dw_pcie_msi_init(pp);
+
+ return 0;
+ }
+diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
+index 03251e34137f3..b482264541bc2 100644
+--- a/drivers/pci/controller/dwc/pcie-qcom.c
++++ b/drivers/pci/controller/dwc/pcie-qcom.c
+@@ -1273,8 +1273,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
+ }
+
+ dw_pcie_setup_rc(pp);
+- dw_pcie_msi_init(pp);
+-
+ qcom_ep_reset_deassert(pcie);
+
+ return 0;
+diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c
+index ebbaa06fc8ab5..31475e4493a70 100644
+--- a/drivers/pci/controller/dwc/pcie-spear13xx.c
++++ b/drivers/pci/controller/dwc/pcie-spear13xx.c
+@@ -102,16 +102,12 @@ static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)
+
+ static void spear13xx_pcie_enable_interrupts(struct spear13xx_pcie *spear13xx_pcie)
+ {
+- struct dw_pcie *pci = spear13xx_pcie->pci;
+- struct pcie_port *pp = &pci->pp;
+ struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
+
+ /* Enable MSI interrupt */
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- dw_pcie_msi_init(pp);
++ if (IS_ENABLED(CONFIG_PCI_MSI))
+ writel(readl(&app_reg->int_mask) |
+ MSI_CTRL_INT, &app_reg->int_mask);
+- }
+ }
+
+ static int spear13xx_pcie_link_up(struct dw_pcie *pci)
+diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
+index 782aa3f382829..e5cd9751e6e8c 100644
+--- a/drivers/pci/controller/dwc/pcie-tegra194.c
++++ b/drivers/pci/controller/dwc/pcie-tegra194.c
+@@ -767,8 +767,6 @@ static void tegra_pcie_enable_msi_interrupts(struct pcie_port *pp)
+ struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
+ u32 val;
+
+- dw_pcie_msi_init(pp);
+-
+ /* Enable MSI interrupt generation */
+ val = appl_readl(pcie, APPL_INTR_EN_L0_0);
+ val |= APPL_INTR_EN_L0_0_SYS_MSI_INTR_EN;
+diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
+index bd4bf2db9480e..83f545b326003 100644
+--- a/drivers/pci/controller/dwc/pcie-uniphier.c
++++ b/drivers/pci/controller/dwc/pcie-uniphier.c
+@@ -309,7 +309,6 @@ static int uniphier_pcie_host_init(struct pcie_port *pp)
+ uniphier_pcie_irq_enable(priv);
+
+ dw_pcie_setup_rc(pp);
+- dw_pcie_msi_init(pp);
+
+ return 0;
+ }
+--
+2.42.0
+
--- /dev/null
+From 84fe8050a0a03887401d8a144590419e08fd6410 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Nov 2020 15:11:55 -0600
+Subject: PCI: dwc: Move dw_pcie_setup_rc() to DWC common code
+
+From: Rob Herring <robh@kernel.org>
+
+[ Upstream commit b9ac0f9dc8ea4b91362694e82a1e66313a6c6dc6 ]
+
+All RC complex drivers must call dw_pcie_setup_rc(). The ordering of the
+call shouldn't be too important other than being after any RC resets.
+
+There's a few calls of dw_pcie_setup_rc() left as drivers implementing
+suspend/resume need it.
+
+Link: https://lore.kernel.org/r/20201105211159.1814485-13-robh@kernel.org
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Jingoo Han <jingoohan1@gmail.com>
+Cc: Kishon Vijay Abraham I <kishon@ti.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Cc: Kukjin Kim <kgene@kernel.org>
+Cc: Krzysztof Kozlowski <krzk@kernel.org>
+Cc: Richard Zhu <hongxing.zhu@nxp.com>
+Cc: Lucas Stach <l.stach@pengutronix.de>
+Cc: Shawn Guo <shawnguo@kernel.org>
+Cc: Sascha Hauer <s.hauer@pengutronix.de>
+Cc: Pengutronix Kernel Team <kernel@pengutronix.de>
+Cc: Fabio Estevam <festevam@gmail.com>
+Cc: NXP Linux Team <linux-imx@nxp.com>
+Cc: Murali Karicheri <m-karicheri2@ti.com>
+Cc: Minghuan Lian <minghuan.Lian@nxp.com>
+Cc: Mingkai Hu <mingkai.hu@nxp.com>
+Cc: Roy Zang <roy.zang@nxp.com>
+Cc: Yue Wang <yue.wang@Amlogic.com>
+Cc: Kevin Hilman <khilman@baylibre.com>
+Cc: Neil Armstrong <narmstrong@baylibre.com>
+Cc: Jerome Brunet <jbrunet@baylibre.com>
+Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
+Cc: Jesper Nilsson <jesper.nilsson@axis.com>
+Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Xiaowei Song <songxiaowei@hisilicon.com>
+Cc: Binghui Wang <wangbinghui@hisilicon.com>
+Cc: Andy Gross <agross@kernel.org>
+Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
+Cc: Stanimir Varbanov <svarbanov@mm-sol.com>
+Cc: Pratyush Anand <pratyush.anand@gmail.com>
+Cc: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
+Cc: linux-omap@vger.kernel.org
+Cc: linux-samsung-soc@vger.kernel.org
+Cc: linuxppc-dev@lists.ozlabs.org
+Cc: linux-amlogic@lists.infradead.org
+Cc: linux-arm-kernel@axis.com
+Cc: linux-arm-msm@vger.kernel.org
+Stable-dep-of: 83a939f0fdc2 ("PCI: exynos: Don't discard .remove() callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/dwc/pci-dra7xx.c | 1 -
+ drivers/pci/controller/dwc/pci-exynos.c | 1 -
+ drivers/pci/controller/dwc/pci-imx6.c | 1 -
+ drivers/pci/controller/dwc/pci-keystone.c | 2 --
+ drivers/pci/controller/dwc/pci-layerscape.c | 2 --
+ drivers/pci/controller/dwc/pci-meson.c | 2 --
+ drivers/pci/controller/dwc/pcie-armada8k.c | 2 --
+ drivers/pci/controller/dwc/pcie-artpec6.c | 1 -
+ drivers/pci/controller/dwc/pcie-designware-host.c | 1 +
+ drivers/pci/controller/dwc/pcie-designware-plat.c | 8 --------
+ drivers/pci/controller/dwc/pcie-histb.c | 3 ---
+ drivers/pci/controller/dwc/pcie-kirin.c | 2 --
+ drivers/pci/controller/dwc/pcie-qcom.c | 1 -
+ drivers/pci/controller/dwc/pcie-spear13xx.c | 2 --
+ drivers/pci/controller/dwc/pcie-uniphier.c | 2 --
+ 15 files changed, 1 insertion(+), 30 deletions(-)
+
+diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
+index 72a5a2bf933bc..b105af63854a3 100644
+--- a/drivers/pci/controller/dwc/pci-dra7xx.c
++++ b/drivers/pci/controller/dwc/pci-dra7xx.c
+@@ -181,7 +181,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp)
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
+
+- dw_pcie_setup_rc(pp);
+ dra7xx_pcie_enable_interrupts(dra7xx);
+
+ return 0;
+diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c
+index 3939fe22e8a20..5c10a5432896c 100644
+--- a/drivers/pci/controller/dwc/pci-exynos.c
++++ b/drivers/pci/controller/dwc/pci-exynos.c
+@@ -372,7 +372,6 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
+ phy_init(ep->phy);
+
+ exynos_pcie_deassert_core_reset(ep);
+- dw_pcie_setup_rc(pp);
+ exynos_pcie_assert_reset(ep);
+
+ exynos_pcie_enable_interrupts(ep);
+diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
+index dbdf79ac48683..67f06060f7a48 100644
+--- a/drivers/pci/controller/dwc/pci-imx6.c
++++ b/drivers/pci/controller/dwc/pci-imx6.c
+@@ -839,7 +839,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
+ imx6_pcie_init_phy(imx6_pcie);
+ imx6_pcie_deassert_core_reset(imx6_pcie);
+ imx6_setup_phy_mpll(imx6_pcie);
+- dw_pcie_setup_rc(pp);
+
+ return 0;
+ }
+diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
+index a5db966f6d20b..c3891a6b96123 100644
+--- a/drivers/pci/controller/dwc/pci-keystone.c
++++ b/drivers/pci/controller/dwc/pci-keystone.c
+@@ -808,8 +808,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
+ if (ret)
+ return ret;
+
+- dw_pcie_setup_rc(pp);
+-
+ ks_pcie_stop_link(pci);
+ ks_pcie_setup_rc_app_regs(ks_pcie);
+ writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
+diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
+index 4d280b940f1fe..5d325e8acb361 100644
+--- a/drivers/pci/controller/dwc/pci-layerscape.c
++++ b/drivers/pci/controller/dwc/pci-layerscape.c
+@@ -150,8 +150,6 @@ static int ls_pcie_host_init(struct pcie_port *pp)
+
+ ls_pcie_drop_msg_tlp(pcie);
+
+- dw_pcie_setup_rc(pp);
+-
+ return 0;
+ }
+
+diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
+index 2df0adcf0bf22..04589f0decb23 100644
+--- a/drivers/pci/controller/dwc/pci-meson.c
++++ b/drivers/pci/controller/dwc/pci-meson.c
+@@ -380,8 +380,6 @@ static int meson_pcie_host_init(struct pcie_port *pp)
+ meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
+ meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
+
+- dw_pcie_setup_rc(pp);
+-
+ return 0;
+ }
+
+diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c
+index dd2926bbb9017..4e2552dcf9827 100644
+--- a/drivers/pci/controller/dwc/pcie-armada8k.c
++++ b/drivers/pci/controller/dwc/pcie-armada8k.c
+@@ -171,8 +171,6 @@ static int armada8k_pcie_host_init(struct pcie_port *pp)
+ u32 reg;
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+
+- dw_pcie_setup_rc(pp);
+-
+ if (!dw_pcie_link_up(pci)) {
+ /* Disable LTSSM state machine to enable configuration */
+ reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
+diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c
+index 7ee8f3c83f8f3..fcba9915a6067 100644
+--- a/drivers/pci/controller/dwc/pcie-artpec6.c
++++ b/drivers/pci/controller/dwc/pcie-artpec6.c
+@@ -328,7 +328,6 @@ static int artpec6_pcie_host_init(struct pcie_port *pp)
+ artpec6_pcie_init_phy(artpec6_pcie);
+ artpec6_pcie_deassert_core_reset(artpec6_pcie);
+ artpec6_pcie_wait_for_phy(artpec6_pcie);
+- dw_pcie_setup_rc(pp);
+
+ return 0;
+ }
+diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
+index e740cbeda2bbc..44eccd9d956f4 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -423,6 +423,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
+ goto err_free_msi;
+ }
+
++ dw_pcie_setup_rc(pp);
+ dw_pcie_msi_init(pp);
+
+ if (!dw_pcie_link_up(pci) && pci->ops->start_link) {
+diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
+index dec24e595c3e0..9b397c807261c 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
++++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
+@@ -33,15 +33,7 @@ struct dw_plat_pcie_of_data {
+
+ static const struct of_device_id dw_plat_pcie_of_match[];
+
+-static int dw_plat_pcie_host_init(struct pcie_port *pp)
+-{
+- dw_pcie_setup_rc(pp);
+-
+- return 0;
+-}
+-
+ static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
+- .host_init = dw_plat_pcie_host_init,
+ };
+
+ static int dw_plat_pcie_establish_link(struct dw_pcie *pci)
+diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c
+index 210777c793ea0..86f9d16c50d75 100644
+--- a/drivers/pci/controller/dwc/pcie-histb.c
++++ b/drivers/pci/controller/dwc/pcie-histb.c
+@@ -196,9 +196,6 @@ static int histb_pcie_host_init(struct pcie_port *pp)
+ regval |= PCIE_WM_RC;
+ histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval);
+
+- /* setup root complex */
+- dw_pcie_setup_rc(pp);
+-
+ return 0;
+ }
+
+diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
+index f84ac1b36b2cc..ac4bbdaf53245 100644
+--- a/drivers/pci/controller/dwc/pcie-kirin.c
++++ b/drivers/pci/controller/dwc/pcie-kirin.c
+@@ -405,8 +405,6 @@ static int kirin_pcie_host_init(struct pcie_port *pp)
+ {
+ pp->bridge->ops = &kirin_pci_ops;
+
+- dw_pcie_setup_rc(pp);
+-
+ return 0;
+ }
+
+diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
+index b482264541bc2..28608f6ef9755 100644
+--- a/drivers/pci/controller/dwc/pcie-qcom.c
++++ b/drivers/pci/controller/dwc/pcie-qcom.c
+@@ -1272,7 +1272,6 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
+ goto err_disable_phy;
+ }
+
+- dw_pcie_setup_rc(pp);
+ qcom_ep_reset_deassert(pcie);
+
+ return 0;
+diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c
+index 31475e4493a70..1a9e353bef554 100644
+--- a/drivers/pci/controller/dwc/pcie-spear13xx.c
++++ b/drivers/pci/controller/dwc/pcie-spear13xx.c
+@@ -130,8 +130,6 @@ static int spear13xx_pcie_host_init(struct pcie_port *pp)
+
+ spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
+
+- dw_pcie_setup_rc(pp);
+-
+ /*
+ * this controller support only 128 bytes read size, however its
+ * default value in capability register is 512 bytes. So force
+diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
+index 83f545b326003..680950a202dd9 100644
+--- a/drivers/pci/controller/dwc/pcie-uniphier.c
++++ b/drivers/pci/controller/dwc/pcie-uniphier.c
+@@ -308,8 +308,6 @@ static int uniphier_pcie_host_init(struct pcie_port *pp)
+
+ uniphier_pcie_irq_enable(priv);
+
+- dw_pcie_setup_rc(pp);
+-
+ return 0;
+ }
+
+--
+2.42.0
+
--- /dev/null
+From 709ce1bab4115f2f008a8db0a05d14a9803e9727 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Nov 2020 15:11:53 -0600
+Subject: PCI: dwc: Move link handling into common code
+
+From: Rob Herring <robh@kernel.org>
+
+[ Upstream commit 886a9c1347558f0568e87fbbe7bcc3a76102bf0b ]
+
+All the DWC drivers do link setup and checks at roughly the same time.
+Let's use the existing .start_link() hook (currently only used in EP
+mode) and move the link handling to the core code.
+
+The behavior for a link down was inconsistent as some drivers would fail
+probe in that case while others succeed. Let's standardize this to
+succeed as there are usecases where devices (and the link) appear later
+even without hotplug. For example, a reconfigured FPGA device.
+
+Link: https://lore.kernel.org/r/20201105211159.1814485-11-robh@kernel.org
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Jingoo Han <jingoohan1@gmail.com>
+Cc: Kishon Vijay Abraham I <kishon@ti.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Cc: Kukjin Kim <kgene@kernel.org>
+Cc: Krzysztof Kozlowski <krzk@kernel.org>
+Cc: Richard Zhu <hongxing.zhu@nxp.com>
+Cc: Lucas Stach <l.stach@pengutronix.de>
+Cc: Shawn Guo <shawnguo@kernel.org>
+Cc: Sascha Hauer <s.hauer@pengutronix.de>
+Cc: Pengutronix Kernel Team <kernel@pengutronix.de>
+Cc: Fabio Estevam <festevam@gmail.com>
+Cc: NXP Linux Team <linux-imx@nxp.com>
+Cc: Murali Karicheri <m-karicheri2@ti.com>
+Cc: Yue Wang <yue.wang@Amlogic.com>
+Cc: Kevin Hilman <khilman@baylibre.com>
+Cc: Neil Armstrong <narmstrong@baylibre.com>
+Cc: Jerome Brunet <jbrunet@baylibre.com>
+Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
+Cc: Jesper Nilsson <jesper.nilsson@axis.com>
+Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Xiaowei Song <songxiaowei@hisilicon.com>
+Cc: Binghui Wang <wangbinghui@hisilicon.com>
+Cc: Andy Gross <agross@kernel.org>
+Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
+Cc: Stanimir Varbanov <svarbanov@mm-sol.com>
+Cc: Pratyush Anand <pratyush.anand@gmail.com>
+Cc: Thierry Reding <thierry.reding@gmail.com>
+Cc: Jonathan Hunter <jonathanh@nvidia.com>
+Cc: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
+Cc: linux-omap@vger.kernel.org
+Cc: linux-samsung-soc@vger.kernel.org
+Cc: linux-amlogic@lists.infradead.org
+Cc: linux-arm-kernel@axis.com
+Cc: linux-arm-msm@vger.kernel.org
+Cc: linux-tegra@vger.kernel.org
+Stable-dep-of: 83a939f0fdc2 ("PCI: exynos: Don't discard .remove() callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/dwc/pci-dra7xx.c | 2 -
+ drivers/pci/controller/dwc/pci-exynos.c | 41 +++++++----------
+ drivers/pci/controller/dwc/pci-imx6.c | 9 ++--
+ drivers/pci/controller/dwc/pci-keystone.c | 9 ----
+ drivers/pci/controller/dwc/pci-meson.c | 24 ++++------
+ drivers/pci/controller/dwc/pcie-armada8k.c | 39 +++++++---------
+ drivers/pci/controller/dwc/pcie-artpec6.c | 2 -
+ .../pci/controller/dwc/pcie-designware-host.c | 9 ++++
+ .../pci/controller/dwc/pcie-designware-plat.c | 3 --
+ drivers/pci/controller/dwc/pcie-histb.c | 34 +++++++-------
+ drivers/pci/controller/dwc/pcie-kirin.c | 23 ++--------
+ drivers/pci/controller/dwc/pcie-qcom.c | 19 ++------
+ drivers/pci/controller/dwc/pcie-spear13xx.c | 46 ++++++++-----------
+ drivers/pci/controller/dwc/pcie-tegra194.c | 1 -
+ drivers/pci/controller/dwc/pcie-uniphier.c | 13 ++----
+ 15 files changed, 103 insertions(+), 171 deletions(-)
+
+diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
+index 6b75c68dddb56..054423d9646d6 100644
+--- a/drivers/pci/controller/dwc/pci-dra7xx.c
++++ b/drivers/pci/controller/dwc/pci-dra7xx.c
+@@ -183,8 +183,6 @@ static int dra7xx_pcie_host_init(struct pcie_port *pp)
+
+ dw_pcie_setup_rc(pp);
+
+- dra7xx_pcie_establish_link(pci);
+- dw_pcie_wait_for_link(pci);
+ dw_pcie_msi_init(pp);
+ dra7xx_pcie_enable_interrupts(dra7xx);
+
+diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c
+index 7734394953e57..6498b615c834a 100644
+--- a/drivers/pci/controller/dwc/pci-exynos.c
++++ b/drivers/pci/controller/dwc/pci-exynos.c
+@@ -229,30 +229,9 @@ static void exynos_pcie_assert_reset(struct exynos_pcie *ep)
+ GPIOF_OUT_INIT_HIGH, "RESET");
+ }
+
+-static int exynos_pcie_establish_link(struct exynos_pcie *ep)
++static int exynos_pcie_start_link(struct dw_pcie *pci)
+ {
+- struct dw_pcie *pci = ep->pci;
+- struct pcie_port *pp = &pci->pp;
+- struct device *dev = pci->dev;
+-
+- if (dw_pcie_link_up(pci)) {
+- dev_err(dev, "Link already up\n");
+- return 0;
+- }
+-
+- exynos_pcie_assert_core_reset(ep);
+-
+- phy_reset(ep->phy);
+-
+- exynos_pcie_writel(ep->mem_res->elbi_base, 1,
+- PCIE_PWR_RESET);
+-
+- phy_power_on(ep->phy);
+- phy_init(ep->phy);
+-
+- exynos_pcie_deassert_core_reset(ep);
+- dw_pcie_setup_rc(pp);
+- exynos_pcie_assert_reset(ep);
++ struct exynos_pcie *ep = to_exynos_pcie(pci);
+
+ /* assert LTSSM enable */
+ exynos_pcie_writel(ep->mem_res->elbi_base, PCIE_ELBI_LTSSM_ENABLE,
+@@ -386,7 +365,20 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
+
+ pp->bridge->ops = &exynos_pci_ops;
+
+- exynos_pcie_establish_link(ep);
++ exynos_pcie_assert_core_reset(ep);
++
++ phy_reset(ep->phy);
++
++ exynos_pcie_writel(ep->mem_res->elbi_base, 1,
++ PCIE_PWR_RESET);
++
++ phy_power_on(ep->phy);
++ phy_init(ep->phy);
++
++ exynos_pcie_deassert_core_reset(ep);
++ dw_pcie_setup_rc(pp);
++ exynos_pcie_assert_reset(ep);
++
+ exynos_pcie_enable_interrupts(ep);
+
+ return 0;
+@@ -430,6 +422,7 @@ static const struct dw_pcie_ops dw_pcie_ops = {
+ .read_dbi = exynos_pcie_read_dbi,
+ .write_dbi = exynos_pcie_write_dbi,
+ .link_up = exynos_pcie_link_up,
++ .start_link = exynos_pcie_start_link,
+ };
+
+ static int __init exynos_pcie_probe(struct platform_device *pdev)
+diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
+index 104341bfde180..8d1d2d79693d6 100644
+--- a/drivers/pci/controller/dwc/pci-imx6.c
++++ b/drivers/pci/controller/dwc/pci-imx6.c
+@@ -750,9 +750,9 @@ static void imx6_pcie_ltssm_enable(struct device *dev)
+ }
+ }
+
+-static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
++static int imx6_pcie_start_link(struct dw_pcie *pci)
+ {
+- struct dw_pcie *pci = imx6_pcie->pci;
++ struct imx6_pcie *imx6_pcie = to_imx6_pcie(pci);
+ struct device *dev = pci->dev;
+ u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+ u32 tmp;
+@@ -840,7 +840,6 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
+ imx6_pcie_deassert_core_reset(imx6_pcie);
+ imx6_setup_phy_mpll(imx6_pcie);
+ dw_pcie_setup_rc(pp);
+- imx6_pcie_establish_link(imx6_pcie);
+ dw_pcie_msi_init(pp);
+
+ return 0;
+@@ -870,7 +869,7 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
+ }
+
+ static const struct dw_pcie_ops dw_pcie_ops = {
+- /* No special ops needed, but pcie-designware still expects this struct */
++ .start_link = imx6_pcie_start_link,
+ };
+
+ #ifdef CONFIG_PM_SLEEP
+@@ -979,7 +978,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
+ imx6_pcie_deassert_core_reset(imx6_pcie);
+ dw_pcie_setup_rc(pp);
+
+- ret = imx6_pcie_establish_link(imx6_pcie);
++ ret = imx6_pcie_start_link(imx6_pcie->pci);
+ if (ret < 0)
+ dev_info(dev, "pcie link is down after resume.\n");
+
+diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
+index fbd38e90bef65..a5db966f6d20b 100644
+--- a/drivers/pci/controller/dwc/pci-keystone.c
++++ b/drivers/pci/controller/dwc/pci-keystone.c
+@@ -511,14 +511,8 @@ static void ks_pcie_stop_link(struct dw_pcie *pci)
+ static int ks_pcie_start_link(struct dw_pcie *pci)
+ {
+ struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
+- struct device *dev = pci->dev;
+ u32 val;
+
+- if (dw_pcie_link_up(pci)) {
+- dev_dbg(dev, "link is already up\n");
+- return 0;
+- }
+-
+ /* Initiate Link Training */
+ val = ks_pcie_app_readl(ks_pcie, CMD_STATUS);
+ ks_pcie_app_writel(ks_pcie, CMD_STATUS, LTSSM_EN_VAL | val);
+@@ -834,9 +828,6 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
+ "Asynchronous external abort");
+ #endif
+
+- ks_pcie_start_link(pci);
+- dw_pcie_wait_for_link(pci);
+-
+ return 0;
+ }
+
+diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
+index 10d65b3093e4a..41a3351b100b5 100644
+--- a/drivers/pci/controller/dwc/pci-meson.c
++++ b/drivers/pci/controller/dwc/pci-meson.c
+@@ -231,7 +231,7 @@ static void meson_pcie_assert_reset(struct meson_pcie *mp)
+ gpiod_set_value_cansleep(mp->reset_gpio, 0);
+ }
+
+-static void meson_pcie_init_dw(struct meson_pcie *mp)
++static void meson_pcie_ltssm_enable(struct meson_pcie *mp)
+ {
+ u32 val;
+
+@@ -289,20 +289,14 @@ static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
+ dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
+ }
+
+-static int meson_pcie_establish_link(struct meson_pcie *mp)
++static int meson_pcie_start_link(struct dw_pcie *pci)
+ {
+- struct dw_pcie *pci = &mp->pci;
+- struct pcie_port *pp = &pci->pp;
+-
+- meson_pcie_init_dw(mp);
+- meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
+- meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
+-
+- dw_pcie_setup_rc(pp);
++ struct meson_pcie *mp = to_meson_pcie(pci);
+
++ meson_pcie_ltssm_enable(mp);
+ meson_pcie_assert_reset(mp);
+
+- return dw_pcie_wait_for_link(pci);
++ return 0;
+ }
+
+ static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn,
+@@ -380,14 +374,13 @@ static int meson_pcie_host_init(struct pcie_port *pp)
+ {
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct meson_pcie *mp = to_meson_pcie(pci);
+- int ret;
+
+ pp->bridge->ops = &meson_pci_ops;
+
+- ret = meson_pcie_establish_link(mp);
+- if (ret)
+- return ret;
++ meson_set_max_payload(mp, MAX_PAYLOAD_SIZE);
++ meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
+
++ dw_pcie_setup_rc(pp);
+ dw_pcie_msi_init(pp);
+
+ return 0;
+@@ -418,6 +411,7 @@ static int meson_add_pcie_port(struct meson_pcie *mp,
+
+ static const struct dw_pcie_ops dw_pcie_ops = {
+ .link_up = meson_pcie_link_up,
++ .start_link = meson_pcie_start_link,
+ };
+
+ static int meson_pcie_probe(struct platform_device *pdev)
+diff --git a/drivers/pci/controller/dwc/pcie-armada8k.c b/drivers/pci/controller/dwc/pcie-armada8k.c
+index 13901f359a415..dd2926bbb9017 100644
+--- a/drivers/pci/controller/dwc/pcie-armada8k.c
++++ b/drivers/pci/controller/dwc/pcie-armada8k.c
+@@ -154,10 +154,24 @@ static int armada8k_pcie_link_up(struct dw_pcie *pci)
+ return 0;
+ }
+
+-static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie)
++static int armada8k_pcie_start_link(struct dw_pcie *pci)
++{
++ u32 reg;
++
++ /* Start LTSSM */
++ reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
++ reg |= PCIE_APP_LTSSM_EN;
++ dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg);
++
++ return 0;
++}
++
++static int armada8k_pcie_host_init(struct pcie_port *pp)
+ {
+- struct dw_pcie *pci = pcie->pci;
+ u32 reg;
++ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
++
++ dw_pcie_setup_rc(pp);
+
+ if (!dw_pcie_link_up(pci)) {
+ /* Disable LTSSM state machine to enable configuration */
+@@ -193,26 +207,6 @@ static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie)
+ PCIE_INT_C_ASSERT_MASK | PCIE_INT_D_ASSERT_MASK;
+ dw_pcie_writel_dbi(pci, PCIE_GLOBAL_INT_MASK1_REG, reg);
+
+- if (!dw_pcie_link_up(pci)) {
+- /* Configuration done. Start LTSSM */
+- reg = dw_pcie_readl_dbi(pci, PCIE_GLOBAL_CONTROL_REG);
+- reg |= PCIE_APP_LTSSM_EN;
+- dw_pcie_writel_dbi(pci, PCIE_GLOBAL_CONTROL_REG, reg);
+- }
+-
+- /* Wait until the link becomes active again */
+- if (dw_pcie_wait_for_link(pci))
+- dev_err(pci->dev, "Link not up after reconfiguration\n");
+-}
+-
+-static int armada8k_pcie_host_init(struct pcie_port *pp)
+-{
+- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+- struct armada8k_pcie *pcie = to_armada8k_pcie(pci);
+-
+- dw_pcie_setup_rc(pp);
+- armada8k_pcie_establish_link(pcie);
+-
+ return 0;
+ }
+
+@@ -269,6 +263,7 @@ static int armada8k_add_pcie_port(struct armada8k_pcie *pcie,
+
+ static const struct dw_pcie_ops dw_pcie_ops = {
+ .link_up = armada8k_pcie_link_up,
++ .start_link = armada8k_pcie_start_link,
+ };
+
+ static int armada8k_pcie_probe(struct platform_device *pdev)
+diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c
+index a5239a58cee06..8b3da3038ac35 100644
+--- a/drivers/pci/controller/dwc/pcie-artpec6.c
++++ b/drivers/pci/controller/dwc/pcie-artpec6.c
+@@ -329,8 +329,6 @@ static int artpec6_pcie_host_init(struct pcie_port *pp)
+ artpec6_pcie_deassert_core_reset(artpec6_pcie);
+ artpec6_pcie_wait_for_phy(artpec6_pcie);
+ dw_pcie_setup_rc(pp);
+- artpec6_pcie_establish_link(pci);
+- dw_pcie_wait_for_link(pci);
+ dw_pcie_msi_init(pp);
+
+ return 0;
+diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
+index d8ffac3106d9c..b242d7e64c204 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -424,6 +424,15 @@ int dw_pcie_host_init(struct pcie_port *pp)
+ goto err_free_msi;
+ }
+
++ if (!dw_pcie_link_up(pci) && pci->ops->start_link) {
++ ret = pci->ops->start_link(pci);
++ if (ret)
++ goto err_free_msi;
++ }
++
++ /* Ignore errors, the link may come up later */
++ dw_pcie_wait_for_link(pci);
++
+ bridge->sysdata = pp;
+
+ ret = pci_host_probe(bridge);
+diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
+index 3da38ac6a87a0..adebcaeb1a6c0 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
++++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
+@@ -35,10 +35,7 @@ static const struct of_device_id dw_plat_pcie_of_match[];
+
+ static int dw_plat_pcie_host_init(struct pcie_port *pp)
+ {
+- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+-
+ dw_pcie_setup_rc(pp);
+- dw_pcie_wait_for_link(pci);
+ dw_pcie_msi_init(pp);
+
+ return 0;
+diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c
+index 777e24902afbf..ece544165059b 100644
+--- a/drivers/pci/controller/dwc/pcie-histb.c
++++ b/drivers/pci/controller/dwc/pcie-histb.c
+@@ -169,39 +169,36 @@ static int histb_pcie_link_up(struct dw_pcie *pci)
+ return 0;
+ }
+
+-static int histb_pcie_establish_link(struct pcie_port *pp)
++static int histb_pcie_start_link(struct dw_pcie *pci)
+ {
+- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct histb_pcie *hipcie = to_histb_pcie(pci);
+ u32 regval;
+
+- if (dw_pcie_link_up(pci)) {
+- dev_info(pci->dev, "Link already up\n");
+- return 0;
+- }
+-
+- /* PCIe RC work mode */
+- regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0);
+- regval &= ~PCIE_DEVICE_TYPE_MASK;
+- regval |= PCIE_WM_RC;
+- histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval);
+-
+- /* setup root complex */
+- dw_pcie_setup_rc(pp);
+-
+ /* assert LTSSM enable */
+ regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL7);
+ regval |= PCIE_APP_LTSSM_ENABLE;
+ histb_pcie_writel(hipcie, PCIE_SYS_CTRL7, regval);
+
+- return dw_pcie_wait_for_link(pci);
++ return 0;
+ }
+
+ static int histb_pcie_host_init(struct pcie_port *pp)
+ {
++ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
++ struct histb_pcie *hipcie = to_histb_pcie(pci);
++ u32 regval;
++
+ pp->bridge->ops = &histb_pci_ops;
+
+- histb_pcie_establish_link(pp);
++ /* PCIe RC work mode */
++ regval = histb_pcie_readl(hipcie, PCIE_SYS_CTRL0);
++ regval &= ~PCIE_DEVICE_TYPE_MASK;
++ regval |= PCIE_WM_RC;
++ histb_pcie_writel(hipcie, PCIE_SYS_CTRL0, regval);
++
++ /* setup root complex */
++ dw_pcie_setup_rc(pp);
++
+ dw_pcie_msi_init(pp);
+
+ return 0;
+@@ -300,6 +297,7 @@ static const struct dw_pcie_ops dw_pcie_ops = {
+ .read_dbi = histb_pcie_read_dbi,
+ .write_dbi = histb_pcie_write_dbi,
+ .link_up = histb_pcie_link_up,
++ .start_link = histb_pcie_start_link,
+ };
+
+ static int histb_pcie_probe(struct platform_device *pdev)
+diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
+index ba03dbca7885e..675b4d8392d37 100644
+--- a/drivers/pci/controller/dwc/pcie-kirin.c
++++ b/drivers/pci/controller/dwc/pcie-kirin.c
+@@ -390,32 +390,14 @@ static int kirin_pcie_link_up(struct dw_pcie *pci)
+ return 0;
+ }
+
+-static int kirin_pcie_establish_link(struct pcie_port *pp)
++static int kirin_pcie_start_link(struct dw_pcie *pci)
+ {
+- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
+- struct device *dev = kirin_pcie->pci->dev;
+- int count = 0;
+-
+- if (kirin_pcie_link_up(pci))
+- return 0;
+-
+- dw_pcie_setup_rc(pp);
+
+ /* assert LTSSM enable */
+ kirin_apb_ctrl_writel(kirin_pcie, PCIE_LTSSM_ENABLE_BIT,
+ PCIE_APP_LTSSM_ENABLE);
+
+- /* check if the link is up or not */
+- while (!kirin_pcie_link_up(pci)) {
+- usleep_range(LINK_WAIT_MIN, LINK_WAIT_MAX);
+- count++;
+- if (count == 1000) {
+- dev_err(dev, "Link Fail\n");
+- return -EINVAL;
+- }
+- }
+-
+ return 0;
+ }
+
+@@ -423,7 +405,7 @@ static int kirin_pcie_host_init(struct pcie_port *pp)
+ {
+ pp->bridge->ops = &kirin_pci_ops;
+
+- kirin_pcie_establish_link(pp);
++ dw_pcie_setup_rc(pp);
+ dw_pcie_msi_init(pp);
+
+ return 0;
+@@ -433,6 +415,7 @@ static const struct dw_pcie_ops kirin_dw_pcie_ops = {
+ .read_dbi = kirin_pcie_read_dbi,
+ .write_dbi = kirin_pcie_write_dbi,
+ .link_up = kirin_pcie_link_up,
++ .start_link = kirin_pcie_start_link,
+ };
+
+ static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
+diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
+index 4f230f01a645e..03251e34137f3 100644
+--- a/drivers/pci/controller/dwc/pcie-qcom.c
++++ b/drivers/pci/controller/dwc/pcie-qcom.c
+@@ -207,18 +207,15 @@ static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
+ usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
+ }
+
+-static int qcom_pcie_establish_link(struct qcom_pcie *pcie)
++static int qcom_pcie_start_link(struct dw_pcie *pci)
+ {
+- struct dw_pcie *pci = pcie->pci;
+-
+- if (dw_pcie_link_up(pci))
+- return 0;
++ struct qcom_pcie *pcie = to_qcom_pcie(pci);
+
+ /* Enable Link Training state machine */
+ if (pcie->ops->ltssm_enable)
+ pcie->ops->ltssm_enable(pcie);
+
+- return dw_pcie_wait_for_link(pci);
++ return 0;
+ }
+
+ static void qcom_pcie_2_1_0_ltssm_enable(struct qcom_pcie *pcie)
+@@ -1280,15 +1277,8 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
+
+ qcom_ep_reset_deassert(pcie);
+
+- ret = qcom_pcie_establish_link(pcie);
+- if (ret)
+- goto err;
+-
+ return 0;
+-err:
+- qcom_ep_reset_assert(pcie);
+- if (pcie->ops->post_deinit)
+- pcie->ops->post_deinit(pcie);
++
+ err_disable_phy:
+ phy_power_off(pcie->phy);
+ err_deinit:
+@@ -1355,6 +1345,7 @@ static const struct qcom_pcie_ops ops_2_7_0 = {
+
+ static const struct dw_pcie_ops dw_pcie_ops = {
+ .link_up = qcom_pcie_link_up,
++ .start_link = qcom_pcie_start_link,
+ };
+
+ static int qcom_pcie_probe(struct platform_device *pdev)
+diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c
+index 800c34a60a334..ebbaa06fc8ab5 100644
+--- a/drivers/pci/controller/dwc/pcie-spear13xx.c
++++ b/drivers/pci/controller/dwc/pcie-spear13xx.c
+@@ -66,32 +66,10 @@ struct pcie_app_reg {
+
+ #define to_spear13xx_pcie(x) dev_get_drvdata((x)->dev)
+
+-static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
++static int spear13xx_pcie_start_link(struct dw_pcie *pci)
+ {
+- struct dw_pcie *pci = spear13xx_pcie->pci;
+- struct pcie_port *pp = &pci->pp;
++ struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci);
+ struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
+- u32 val;
+- u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+-
+- if (dw_pcie_link_up(pci)) {
+- dev_err(pci->dev, "link already up\n");
+- return 0;
+- }
+-
+- dw_pcie_setup_rc(pp);
+-
+- /*
+- * this controller support only 128 bytes read size, however its
+- * default value in capability register is 512 bytes. So force
+- * it to 128 here.
+- */
+- val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
+- val &= ~PCI_EXP_DEVCTL_READRQ;
+- dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
+-
+- dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
+- dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
+
+ /* enable ltssm */
+ writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID)
+@@ -99,7 +77,7 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
+ | ((u32)1 << REG_TRANSLATION_ENABLE),
+ &app_reg->app_ctrl_0);
+
+- return dw_pcie_wait_for_link(pci);
++ return 0;
+ }
+
+ static irqreturn_t spear13xx_pcie_irq_handler(int irq, void *arg)
+@@ -151,10 +129,25 @@ static int spear13xx_pcie_host_init(struct pcie_port *pp)
+ {
+ struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+ struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pci);
++ u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
++ u32 val;
+
+ spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
+
+- spear13xx_pcie_establish_link(spear13xx_pcie);
++ dw_pcie_setup_rc(pp);
++
++ /*
++ * this controller support only 128 bytes read size, however its
++ * default value in capability register is 512 bytes. So force
++ * it to 128 here.
++ */
++ val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
++ val &= ~PCI_EXP_DEVCTL_READRQ;
++ dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
++
++ dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
++ dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
++
+ spear13xx_pcie_enable_interrupts(spear13xx_pcie);
+
+ return 0;
+@@ -198,6 +191,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie,
+
+ static const struct dw_pcie_ops dw_pcie_ops = {
+ .link_up = spear13xx_pcie_link_up,
++ .start_link = spear13xx_pcie_start_link,
+ };
+
+ static int spear13xx_pcie_probe(struct platform_device *pdev)
+diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
+index 8e67495be90f9..782aa3f382829 100644
+--- a/drivers/pci/controller/dwc/pcie-tegra194.c
++++ b/drivers/pci/controller/dwc/pcie-tegra194.c
+@@ -1555,7 +1555,6 @@ static int tegra_pcie_deinit_controller(struct tegra_pcie_dw *pcie)
+
+ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
+ {
+- struct pcie_port *pp = &pcie->pci.pp;
+ struct device *dev = pcie->dev;
+ char *name;
+ int ret;
+diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
+index 4620561da7a3e..bd4bf2db9480e 100644
+--- a/drivers/pci/controller/dwc/pcie-uniphier.c
++++ b/drivers/pci/controller/dwc/pcie-uniphier.c
+@@ -146,16 +146,13 @@ static int uniphier_pcie_link_up(struct dw_pcie *pci)
+ return (val & mask) == mask;
+ }
+
+-static int uniphier_pcie_establish_link(struct dw_pcie *pci)
++static int uniphier_pcie_start_link(struct dw_pcie *pci)
+ {
+ struct uniphier_pcie_priv *priv = to_uniphier_pcie(pci);
+
+- if (dw_pcie_link_up(pci))
+- return 0;
+-
+ uniphier_pcie_ltssm_enable(priv, true);
+
+- return dw_pcie_wait_for_link(pci);
++ return 0;
+ }
+
+ static void uniphier_pcie_stop_link(struct dw_pcie *pci)
+@@ -312,10 +309,6 @@ static int uniphier_pcie_host_init(struct pcie_port *pp)
+ uniphier_pcie_irq_enable(priv);
+
+ dw_pcie_setup_rc(pp);
+- ret = uniphier_pcie_establish_link(pci);
+- if (ret)
+- return ret;
+-
+ dw_pcie_msi_init(pp);
+
+ return 0;
+@@ -379,7 +372,7 @@ static int uniphier_pcie_host_enable(struct uniphier_pcie_priv *priv)
+ }
+
+ static const struct dw_pcie_ops dw_pcie_ops = {
+- .start_link = uniphier_pcie_establish_link,
++ .start_link = uniphier_pcie_start_link,
+ .stop_link = uniphier_pcie_stop_link,
+ .link_up = uniphier_pcie_link_up,
+ };
+--
+2.42.0
+
--- /dev/null
+From 7dfbd819eb0f2302460066fe9ce49e4fe8c6ce05 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Nov 2020 15:11:51 -0600
+Subject: PCI: dwc: Move MSI interrupt setup into DWC common code
+
+From: Rob Herring <robh@kernel.org>
+
+[ Upstream commit 5bcb1757e637a4f6d130f1f5106ce030516316b8 ]
+
+Platforms using the built-in DWC MSI controller all have a dedicated
+interrupt with "msi" name or at index 0, so let's move setting up the
+interrupt to the common DWC code.
+
+spear13xx and dra7xx are the 2 oddballs with muxed interrupts, so
+we need to prevent configuring the MSI interrupt by setting msi_irq
+to negative.
+
+Link: https://lore.kernel.org/r/20201105211159.1814485-9-robh@kernel.org
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Jingoo Han <jingoohan1@gmail.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Cc: Kukjin Kim <kgene@kernel.org>
+Cc: Krzysztof Kozlowski <krzk@kernel.org>
+Cc: Richard Zhu <hongxing.zhu@nxp.com>
+Cc: Lucas Stach <l.stach@pengutronix.de>
+Cc: Shawn Guo <shawnguo@kernel.org>
+Cc: Sascha Hauer <s.hauer@pengutronix.de>
+Cc: Pengutronix Kernel Team <kernel@pengutronix.de>
+Cc: Fabio Estevam <festevam@gmail.com>
+Cc: NXP Linux Team <linux-imx@nxp.com>
+Cc: Yue Wang <yue.wang@Amlogic.com>
+Cc: Kevin Hilman <khilman@baylibre.com>
+Cc: Neil Armstrong <narmstrong@baylibre.com>
+Cc: Jerome Brunet <jbrunet@baylibre.com>
+Cc: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Cc: Jesper Nilsson <jesper.nilsson@axis.com>
+Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: Xiaowei Song <songxiaowei@hisilicon.com>
+Cc: Binghui Wang <wangbinghui@hisilicon.com>
+Cc: Stanimir Varbanov <svarbanov@mm-sol.com>
+Cc: Andy Gross <agross@kernel.org>
+Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
+Cc: Pratyush Anand <pratyush.anand@gmail.com>
+Cc: Thierry Reding <thierry.reding@gmail.com>
+Cc: Jonathan Hunter <jonathanh@nvidia.com>
+Cc: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
+Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
+Cc: linux-samsung-soc@vger.kernel.org
+Cc: linux-amlogic@lists.infradead.org
+Cc: linux-arm-kernel@axis.com
+Cc: linux-arm-msm@vger.kernel.org
+Cc: linux-tegra@vger.kernel.org
+Stable-dep-of: 83a939f0fdc2 ("PCI: exynos: Don't discard .remove() callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/dwc/pci-dra7xx.c | 3 +++
+ drivers/pci/controller/dwc/pci-exynos.c | 6 -----
+ drivers/pci/controller/dwc/pci-imx6.c | 6 -----
+ drivers/pci/controller/dwc/pci-meson.c | 6 -----
+ drivers/pci/controller/dwc/pcie-artpec6.c | 6 -----
+ .../pci/controller/dwc/pcie-designware-host.c | 11 +++++++++-
+ .../pci/controller/dwc/pcie-designware-plat.c | 6 -----
+ drivers/pci/controller/dwc/pcie-histb.c | 6 -----
+ drivers/pci/controller/dwc/pcie-kirin.c | 22 -------------------
+ drivers/pci/controller/dwc/pcie-qcom.c | 8 -------
+ drivers/pci/controller/dwc/pcie-spear13xx.c | 1 +
+ drivers/pci/controller/dwc/pcie-tegra194.c | 8 -------
+ drivers/pci/controller/dwc/pcie-uniphier.c | 6 -----
+ 13 files changed, 14 insertions(+), 81 deletions(-)
+
+diff --git a/drivers/pci/controller/dwc/pci-dra7xx.c b/drivers/pci/controller/dwc/pci-dra7xx.c
+index 4d0c35a4aa598..6b75c68dddb56 100644
+--- a/drivers/pci/controller/dwc/pci-dra7xx.c
++++ b/drivers/pci/controller/dwc/pci-dra7xx.c
+@@ -489,6 +489,9 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
+ if (pp->irq < 0)
+ return pp->irq;
+
++ /* MSI IRQ is muxed */
++ pp->msi_irq = -ENODEV;
++
+ ret = dra7xx_pcie_init_irq_domain(pp);
+ if (ret < 0)
+ return ret;
+diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c
+index 242683cde04a5..7734394953e57 100644
+--- a/drivers/pci/controller/dwc/pci-exynos.c
++++ b/drivers/pci/controller/dwc/pci-exynos.c
+@@ -415,12 +415,6 @@ static int __init exynos_add_pcie_port(struct exynos_pcie *ep,
+ return ret;
+ }
+
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- pp->msi_irq = platform_get_irq(pdev, 0);
+- if (pp->msi_irq < 0)
+- return pp->msi_irq;
+- }
+-
+ pp->ops = &exynos_pcie_host_ops;
+
+ ret = dw_pcie_host_init(pp);
+diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
+index 8117f2dad86c4..104341bfde180 100644
+--- a/drivers/pci/controller/dwc/pci-imx6.c
++++ b/drivers/pci/controller/dwc/pci-imx6.c
+@@ -858,12 +858,6 @@ static int imx6_add_pcie_port(struct imx6_pcie *imx6_pcie,
+ struct device *dev = &pdev->dev;
+ int ret;
+
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- pp->msi_irq = platform_get_irq_byname(pdev, "msi");
+- if (pp->msi_irq < 0)
+- return pp->msi_irq;
+- }
+-
+ pp->ops = &imx6_pcie_host_ops;
+
+ ret = dw_pcie_host_init(pp);
+diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c
+index 1913dc2c8fa08..10d65b3093e4a 100644
+--- a/drivers/pci/controller/dwc/pci-meson.c
++++ b/drivers/pci/controller/dwc/pci-meson.c
+@@ -405,12 +405,6 @@ static int meson_add_pcie_port(struct meson_pcie *mp,
+ struct device *dev = &pdev->dev;
+ int ret;
+
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- pp->msi_irq = platform_get_irq(pdev, 0);
+- if (pp->msi_irq < 0)
+- return pp->msi_irq;
+- }
+-
+ pp->ops = &meson_pcie_host_ops;
+
+ ret = dw_pcie_host_init(pp);
+diff --git a/drivers/pci/controller/dwc/pcie-artpec6.c b/drivers/pci/controller/dwc/pcie-artpec6.c
+index 52ad7909cd0c0..a5239a58cee06 100644
+--- a/drivers/pci/controller/dwc/pcie-artpec6.c
++++ b/drivers/pci/controller/dwc/pcie-artpec6.c
+@@ -348,12 +348,6 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
+ struct device *dev = pci->dev;
+ int ret;
+
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- pp->msi_irq = platform_get_irq_byname(pdev, "msi");
+- if (pp->msi_irq < 0)
+- return pp->msi_irq;
+- }
+-
+ pp->ops = &artpec6_pcie_host_ops;
+
+ ret = dw_pcie_host_init(pp);
+diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
+index 32d3af7c44917..401890f5c8ca8 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -373,13 +373,22 @@ int dw_pcie_host_init(struct pcie_port *pp)
+ }
+
+ if (!pp->ops->msi_host_init) {
++ if (!pp->msi_irq) {
++ pp->msi_irq = platform_get_irq_byname_optional(pdev, "msi");
++ if (pp->msi_irq < 0) {
++ pp->msi_irq = platform_get_irq(pdev, 0);
++ if (pp->msi_irq < 0)
++ return pp->msi_irq;
++ }
++ }
++
+ pp->msi_irq_chip = &dw_pci_msi_bottom_irq_chip;
+
+ ret = dw_pcie_allocate_domains(pp);
+ if (ret)
+ return ret;
+
+- if (pp->msi_irq)
++ if (pp->msi_irq > 0)
+ irq_set_chained_handler_and_data(pp->msi_irq,
+ dw_chained_msi_isr,
+ pp);
+diff --git a/drivers/pci/controller/dwc/pcie-designware-plat.c b/drivers/pci/controller/dwc/pcie-designware-plat.c
+index 13fede1d41572..3da38ac6a87a0 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-plat.c
++++ b/drivers/pci/controller/dwc/pcie-designware-plat.c
+@@ -116,12 +116,6 @@ static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
+ if (pp->irq < 0)
+ return pp->irq;
+
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- pp->msi_irq = platform_get_irq(pdev, 0);
+- if (pp->msi_irq < 0)
+- return pp->msi_irq;
+- }
+-
+ pp->num_vectors = MAX_MSI_IRQS;
+ pp->ops = &dw_plat_pcie_host_ops;
+
+diff --git a/drivers/pci/controller/dwc/pcie-histb.c b/drivers/pci/controller/dwc/pcie-histb.c
+index afc1abbe49aa9..777e24902afbf 100644
+--- a/drivers/pci/controller/dwc/pcie-histb.c
++++ b/drivers/pci/controller/dwc/pcie-histb.c
+@@ -400,12 +400,6 @@ static int histb_pcie_probe(struct platform_device *pdev)
+ return PTR_ERR(hipcie->bus_reset);
+ }
+
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- pp->msi_irq = platform_get_irq_byname(pdev, "msi");
+- if (pp->msi_irq < 0)
+- return pp->msi_irq;
+- }
+-
+ hipcie->phy = devm_phy_get(dev, "phy");
+ if (IS_ERR(hipcie->phy)) {
+ dev_info(dev, "no pcie-phy found\n");
+diff --git a/drivers/pci/controller/dwc/pcie-kirin.c b/drivers/pci/controller/dwc/pcie-kirin.c
+index 3042a23cf09a4..ba03dbca7885e 100644
+--- a/drivers/pci/controller/dwc/pcie-kirin.c
++++ b/drivers/pci/controller/dwc/pcie-kirin.c
+@@ -439,31 +439,9 @@ static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
+ .host_init = kirin_pcie_host_init,
+ };
+
+-static int kirin_pcie_add_msi(struct dw_pcie *pci,
+- struct platform_device *pdev)
+-{
+- int irq;
+-
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- irq = platform_get_irq(pdev, 0);
+- if (irq < 0)
+- return irq;
+-
+- pci->pp.msi_irq = irq;
+- }
+-
+- return 0;
+-}
+-
+ static int kirin_add_pcie_port(struct dw_pcie *pci,
+ struct platform_device *pdev)
+ {
+- int ret;
+-
+- ret = kirin_pcie_add_msi(pci, pdev);
+- if (ret)
+- return ret;
+-
+ pci->pp.ops = &kirin_pcie_host_ops;
+
+ return dw_pcie_host_init(&pci->pp);
+diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
+index 150dd6fe7ba39..4f230f01a645e 100644
+--- a/drivers/pci/controller/dwc/pcie-qcom.c
++++ b/drivers/pci/controller/dwc/pcie-qcom.c
+@@ -1416,14 +1416,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
+
+ pp->ops = &qcom_pcie_dw_ops;
+
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- pp->msi_irq = platform_get_irq_byname(pdev, "msi");
+- if (pp->msi_irq < 0) {
+- ret = pp->msi_irq;
+- goto err_pm_runtime_put;
+- }
+- }
+-
+ ret = phy_init(pcie->phy);
+ if (ret)
+ goto err_pm_runtime_put;
+diff --git a/drivers/pci/controller/dwc/pcie-spear13xx.c b/drivers/pci/controller/dwc/pcie-spear13xx.c
+index 1ed7e3501ff1c..800c34a60a334 100644
+--- a/drivers/pci/controller/dwc/pcie-spear13xx.c
++++ b/drivers/pci/controller/dwc/pcie-spear13xx.c
+@@ -185,6 +185,7 @@ static int spear13xx_add_pcie_port(struct spear13xx_pcie *spear13xx_pcie,
+ }
+
+ pp->ops = &spear13xx_pcie_host_ops;
++ pp->msi_irq = -ENODEV;
+
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
+index a93b5dca110ec..8e67495be90f9 100644
+--- a/drivers/pci/controller/dwc/pcie-tegra194.c
++++ b/drivers/pci/controller/dwc/pcie-tegra194.c
+@@ -1560,14 +1560,6 @@ static int tegra_pcie_config_rp(struct tegra_pcie_dw *pcie)
+ char *name;
+ int ret;
+
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- pp->msi_irq = of_irq_get_byname(dev->of_node, "msi");
+- if (!pp->msi_irq) {
+- dev_err(dev, "Failed to get MSI interrupt\n");
+- return -ENODEV;
+- }
+- }
+-
+ pm_runtime_enable(dev);
+
+ ret = pm_runtime_get_sync(dev);
+diff --git a/drivers/pci/controller/dwc/pcie-uniphier.c b/drivers/pci/controller/dwc/pcie-uniphier.c
+index 85bf170e93541..4620561da7a3e 100644
+--- a/drivers/pci/controller/dwc/pcie-uniphier.c
++++ b/drivers/pci/controller/dwc/pcie-uniphier.c
+@@ -335,12 +335,6 @@ static int uniphier_add_pcie_port(struct uniphier_pcie_priv *priv,
+
+ pp->ops = &uniphier_pcie_host_ops;
+
+- if (IS_ENABLED(CONFIG_PCI_MSI)) {
+- pp->msi_irq = platform_get_irq_byname(pdev, "msi");
+- if (pp->msi_irq < 0)
+- return pp->msi_irq;
+- }
+-
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+ dev_err(dev, "Failed to initialize host (%d)\n", ret);
+--
+2.42.0
+
--- /dev/null
+From f014ef788425a1aeb38511ab7536facbdd3d9342 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 Nov 2020 15:11:52 -0600
+Subject: PCI: dwc: Rework MSI initialization
+
+From: Rob Herring <robh@kernel.org>
+
+[ Upstream commit f78f02638af5941eb45a402fa52c0edf4ac0f507 ]
+
+There are 3 possible MSI implementations for the DWC host. The first is
+using the built-in DWC MSI controller. The 2nd is a custom MSI
+controller as part of the PCI host (keystone only). The 3rd is an
+external MSI controller (typically GICv3 ITS). Currently, the last 2
+are distinguished with a .msi_host_init() hook with the 3rd option using
+an empty function. However we can detect the 3rd case with the presence
+of 'msi-parent' or 'msi-map' properties, so let's do that instead and
+remove the empty functions.
+
+Link: https://lore.kernel.org/r/20201105211159.1814485-10-robh@kernel.org
+Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
+Signed-off-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Acked-by: Jingoo Han <jingoohan1@gmail.com>
+Cc: Murali Karicheri <m-karicheri2@ti.com>
+Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+Cc: Bjorn Helgaas <bhelgaas@google.com>
+Cc: Minghuan Lian <minghuan.Lian@nxp.com>
+Cc: Mingkai Hu <mingkai.hu@nxp.com>
+Cc: Roy Zang <roy.zang@nxp.com>
+Cc: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+Cc: linuxppc-dev@lists.ozlabs.org
+Stable-dep-of: 83a939f0fdc2 ("PCI: exynos: Don't discard .remove() callback")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/dwc/pci-keystone.c | 9 -------
+ drivers/pci/controller/dwc/pci-layerscape.c | 25 -------------------
+ .../pci/controller/dwc/pcie-designware-host.c | 20 +++++++++------
+ drivers/pci/controller/dwc/pcie-designware.h | 1 +
+ drivers/pci/controller/dwc/pcie-intel-gw.c | 9 -------
+ 5 files changed, 13 insertions(+), 51 deletions(-)
+
+diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c
+index 5177f6d1ca592..fbd38e90bef65 100644
+--- a/drivers/pci/controller/dwc/pci-keystone.c
++++ b/drivers/pci/controller/dwc/pci-keystone.c
+@@ -272,14 +272,6 @@ static void ks_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie,
+ ks_pcie_app_writel(ks_pcie, IRQ_EOI, offset);
+ }
+
+-/*
+- * Dummy function so that DW core doesn't configure MSI
+- */
+-static int ks_pcie_am654_msi_host_init(struct pcie_port *pp)
+-{
+- return 0;
+-}
+-
+ static void ks_pcie_enable_error_irq(struct keystone_pcie *ks_pcie)
+ {
+ ks_pcie_app_writel(ks_pcie, ERR_IRQ_ENABLE_SET, ERR_IRQ_ALL);
+@@ -855,7 +847,6 @@ static const struct dw_pcie_host_ops ks_pcie_host_ops = {
+
+ static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = {
+ .host_init = ks_pcie_host_init,
+- .msi_host_init = ks_pcie_am654_msi_host_init,
+ };
+
+ static irqreturn_t ks_pcie_err_irq_handler(int irq, void *priv)
+diff --git a/drivers/pci/controller/dwc/pci-layerscape.c b/drivers/pci/controller/dwc/pci-layerscape.c
+index f24f79a70d9a8..4d280b940f1fe 100644
+--- a/drivers/pci/controller/dwc/pci-layerscape.c
++++ b/drivers/pci/controller/dwc/pci-layerscape.c
+@@ -182,37 +182,12 @@ static int ls1021_pcie_host_init(struct pcie_port *pp)
+ return ls_pcie_host_init(pp);
+ }
+
+-static int ls_pcie_msi_host_init(struct pcie_port *pp)
+-{
+- struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+- struct device *dev = pci->dev;
+- struct device_node *np = dev->of_node;
+- struct device_node *msi_node;
+-
+- /*
+- * The MSI domain is set by the generic of_msi_configure(). This
+- * .msi_host_init() function keeps us from doing the default MSI
+- * domain setup in dw_pcie_host_init() and also enforces the
+- * requirement that "msi-parent" exists.
+- */
+- msi_node = of_parse_phandle(np, "msi-parent", 0);
+- if (!msi_node) {
+- dev_err(dev, "failed to find msi-parent\n");
+- return -EINVAL;
+- }
+-
+- of_node_put(msi_node);
+- return 0;
+-}
+-
+ static const struct dw_pcie_host_ops ls1021_pcie_host_ops = {
+ .host_init = ls1021_pcie_host_init,
+- .msi_host_init = ls_pcie_msi_host_init,
+ };
+
+ static const struct dw_pcie_host_ops ls_pcie_host_ops = {
+ .host_init = ls_pcie_host_init,
+- .msi_host_init = ls_pcie_msi_host_init,
+ };
+
+ static const struct dw_pcie_ops dw_ls1021_pcie_ops = {
+diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
+index 401890f5c8ca8..d8ffac3106d9c 100644
+--- a/drivers/pci/controller/dwc/pcie-designware-host.c
++++ b/drivers/pci/controller/dwc/pcie-designware-host.c
+@@ -365,6 +365,10 @@ int dw_pcie_host_init(struct pcie_port *pp)
+ pci->link_gen = of_pci_get_max_link_speed(np);
+
+ if (pci_msi_enabled()) {
++ pp->has_msi_ctrl = !(pp->ops->msi_host_init ||
++ of_property_read_bool(np, "msi-parent") ||
++ of_property_read_bool(np, "msi-map"));
++
+ if (!pp->num_vectors) {
+ pp->num_vectors = MSI_DEF_NUM_VECTORS;
+ } else if (pp->num_vectors > MAX_MSI_IRQS) {
+@@ -372,7 +376,11 @@ int dw_pcie_host_init(struct pcie_port *pp)
+ return -EINVAL;
+ }
+
+- if (!pp->ops->msi_host_init) {
++ if (pp->ops->msi_host_init) {
++ ret = pp->ops->msi_host_init(pp);
++ if (ret < 0)
++ return ret;
++ } else if (pp->has_msi_ctrl) {
+ if (!pp->msi_irq) {
+ pp->msi_irq = platform_get_irq_byname_optional(pdev, "msi");
+ if (pp->msi_irq < 0) {
+@@ -403,10 +411,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
+ pp->msi_data = 0;
+ goto err_free_msi;
+ }
+- } else {
+- ret = pp->ops->msi_host_init(pp);
+- if (ret < 0)
+- return ret;
+ }
+ }
+
+@@ -427,7 +431,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
+ return 0;
+
+ err_free_msi:
+- if (pci_msi_enabled() && !pp->ops->msi_host_init)
++ if (pp->has_msi_ctrl)
+ dw_pcie_free_msi(pp);
+ return ret;
+ }
+@@ -437,7 +441,7 @@ void dw_pcie_host_deinit(struct pcie_port *pp)
+ {
+ pci_stop_root_bus(pp->bridge->bus);
+ pci_remove_root_bus(pp->bridge->bus);
+- if (pci_msi_enabled() && !pp->ops->msi_host_init)
++ if (pp->has_msi_ctrl)
+ dw_pcie_free_msi(pp);
+ }
+ EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);
+@@ -548,7 +552,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
+
+ dw_pcie_setup(pci);
+
+- if (pci_msi_enabled() && !pp->ops->msi_host_init) {
++ if (pp->has_msi_ctrl) {
+ num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
+
+ /* Initialize IRQ Status array */
+diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
+index 82c0339c283f1..f33dc89a93650 100644
+--- a/drivers/pci/controller/dwc/pcie-designware.h
++++ b/drivers/pci/controller/dwc/pcie-designware.h
+@@ -178,6 +178,7 @@ struct dw_pcie_host_ops {
+ };
+
+ struct pcie_port {
++ bool has_msi_ctrl:1;
+ u64 cfg0_base;
+ void __iomem *va_cfg0_base;
+ u32 cfg0_size;
+diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c
+index 429171c35945d..5ce25944cc315 100644
+--- a/drivers/pci/controller/dwc/pcie-intel-gw.c
++++ b/drivers/pci/controller/dwc/pcie-intel-gw.c
+@@ -399,14 +399,6 @@ static int intel_pcie_rc_init(struct pcie_port *pp)
+ return intel_pcie_host_setup(lpp);
+ }
+
+-/*
+- * Dummy function so that DW core doesn't configure MSI
+- */
+-static int intel_pcie_msi_init(struct pcie_port *pp)
+-{
+- return 0;
+-}
+-
+ static u64 intel_pcie_cpu_addr(struct dw_pcie *pcie, u64 cpu_addr)
+ {
+ return cpu_addr + BUS_IATU_OFFSET;
+@@ -418,7 +410,6 @@ static const struct dw_pcie_ops intel_pcie_ops = {
+
+ static const struct dw_pcie_host_ops intel_pcie_dw_ops = {
+ .host_init = intel_pcie_rc_init,
+- .msi_host_init = intel_pcie_msi_init,
+ };
+
+ static const struct intel_pcie_soc pcie_data = {
+--
+2.42.0
+
--- /dev/null
+From cfeb180401c710b50c82ea03f6a76493624afc36 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 1 Oct 2023 19:02:51 +0200
+Subject: PCI: exynos: Don't discard .remove() callback
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+
+[ Upstream commit 83a939f0fdc208ff3639dd3d42ac9b3c35607fd2 ]
+
+With CONFIG_PCI_EXYNOS=y and exynos_pcie_remove() marked with __exit, the
+function is discarded from the driver. In this case a bound device can
+still get unbound, e.g via sysfs. Then no cleanup code is run resulting in
+resource leaks or worse.
+
+The right thing to do is do always have the remove callback available.
+This fixes the following warning by modpost:
+
+ WARNING: modpost: drivers/pci/controller/dwc/pci-exynos: section mismatch in reference: exynos_pcie_driver+0x8 (section: .data) -> exynos_pcie_remove (section: .exit.text)
+
+(with ARCH=x86_64 W=1 allmodconfig).
+
+Fixes: 340cba6092c2 ("pci: Add PCIe driver for Samsung Exynos")
+Link: https://lore.kernel.org/r/20231001170254.2506508-2-u.kleine-koenig@pengutronix.de
+Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Alim Akhtar <alim.akhtar@samsung.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/pci/controller/dwc/pci-exynos.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c
+index c24dab383654b..2696a4544f102 100644
+--- a/drivers/pci/controller/dwc/pci-exynos.c
++++ b/drivers/pci/controller/dwc/pci-exynos.c
+@@ -377,7 +377,7 @@ static int exynos_pcie_probe(struct platform_device *pdev)
+ return ret;
+ }
+
+-static int __exit exynos_pcie_remove(struct platform_device *pdev)
++static int exynos_pcie_remove(struct platform_device *pdev)
+ {
+ struct exynos_pcie *ep = platform_get_drvdata(pdev);
+
+@@ -433,7 +433,7 @@ static const struct of_device_id exynos_pcie_of_match[] = {
+
+ static struct platform_driver exynos_pcie_driver = {
+ .probe = exynos_pcie_probe,
+- .remove = __exit_p(exynos_pcie_remove),
++ .remove = exynos_pcie_remove,
+ .driver = {
+ .name = "exynos-pcie",
+ .of_match_table = exynos_pcie_of_match,
+--
+2.42.0
+
--- /dev/null
+From cf31acecb91ddeab131652ce81975d8a28f641a5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 26 Apr 2021 11:11:06 +0100
+Subject: serial: meson: remove redundant initialization of variable id
+
+From: Colin Ian King <colin.king@canonical.com>
+
+[ Upstream commit 021212f5335229ed12e3d31f9b7d30bd3bb66f7d ]
+
+The variable id being initialized with a value that is never read
+and it is being updated later with a new value. The initialization is
+redundant and can be removed. Since id is just being used in a for-loop
+inside a local scope, move the declaration of id to that scope.
+
+Reviewed-by: Kevin Hilman <khilman@baylibre.com>
+Reviewed-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+Signed-off-by: Colin Ian King <colin.king@canonical.com>
+Addresses-Coverity: ("Unused value")
+Link: https://lore.kernel.org/r/20210426101106.9122-1-colin.king@canonical.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 2a1d728f20ed ("tty: serial: meson: fix hard LOCKUP on crtscts mode")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/meson_uart.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
+index 91b7359b79a2f..d06653493f0ef 100644
+--- a/drivers/tty/serial/meson_uart.c
++++ b/drivers/tty/serial/meson_uart.c
+@@ -729,12 +729,13 @@ static int meson_uart_probe(struct platform_device *pdev)
+ struct resource *res_mem, *res_irq;
+ struct uart_port *port;
+ int ret = 0;
+- int id = -1;
+
+ if (pdev->dev.of_node)
+ pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
+
+ if (pdev->id < 0) {
++ int id;
++
+ for (id = AML_UART_PORT_OFFSET; id < AML_UART_PORT_NUM; id++) {
+ if (!meson_ports[id]) {
+ pdev->id = id;
+--
+2.42.0
+
--- /dev/null
+From c81458f574f90ebc1aaaff23f62ce684bd1b7059 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Dec 2021 14:29:10 +0000
+Subject: serial: meson: Use platform_get_irq() to get the interrupt
+
+From: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+
+[ Upstream commit 5b68061983471470d4109bac776145245f06bc09 ]
+
+platform_get_resource(pdev, IORESOURCE_IRQ, ..) relies on static
+allocation of IRQ resources in DT core code, this causes an issue
+when using hierarchical interrupt domains using "interrupts" property
+in the node as this bypasses the hierarchical setup and messes up the
+irq chaining.
+
+In preparation for removal of static setup of IRQ resource from DT core
+code use platform_get_irq().
+
+Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
+Link: https://lore.kernel.org/r/20211224142917.6966-5-prabhakar.mahadev-lad.rj@bp.renesas.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 2a1d728f20ed ("tty: serial: meson: fix hard LOCKUP on crtscts mode")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/meson_uart.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
+index 78bda91a6bf15..bdc394afec5be 100644
+--- a/drivers/tty/serial/meson_uart.c
++++ b/drivers/tty/serial/meson_uart.c
+@@ -726,10 +726,11 @@ static int meson_uart_probe_clocks(struct platform_device *pdev,
+
+ static int meson_uart_probe(struct platform_device *pdev)
+ {
+- struct resource *res_mem, *res_irq;
++ struct resource *res_mem;
+ struct uart_port *port;
+ u32 fifosize = 64; /* Default is 64, 128 for EE UART_0 */
+ int ret = 0;
++ int irq;
+
+ if (pdev->dev.of_node)
+ pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
+@@ -752,9 +753,9 @@ static int meson_uart_probe(struct platform_device *pdev)
+ if (!res_mem)
+ return -ENODEV;
+
+- res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+- if (!res_irq)
+- return -ENODEV;
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0)
++ return irq;
+
+ of_property_read_u32(pdev->dev.of_node, "fifo-size", &fifosize);
+
+@@ -779,7 +780,7 @@ static int meson_uart_probe(struct platform_device *pdev)
+ port->iotype = UPIO_MEM;
+ port->mapbase = res_mem->start;
+ port->mapsize = resource_size(res_mem);
+- port->irq = res_irq->start;
++ port->irq = irq;
+ port->flags = UPF_BOOT_AUTOCONF | UPF_LOW_LATENCY;
+ port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MESON_CONSOLE);
+ port->dev = &pdev->dev;
+--
+2.42.0
+
mm-memory_hotplug-use-pfn-math-in-place-of-direct-struct-page-manipulation.patch
mtd-cfi_cmdset_0001-byte-swap-otp-info.patch
i3c-master-cdns-fix-reading-status-register.patch
+serial-meson-remove-redundant-initialization-of-vari.patch
+tty-serial-meson-retrieve-port-fifo-size-from-dt.patch
+serial-meson-use-platform_get_irq-to-get-the-interru.patch
+tty-serial-meson-fix-hard-lockup-on-crtscts-mode.patch
+cpufreq-stats-fix-buffer-overflow-detection-in-trans.patch
+bluetooth-btusb-add-realtek-rtl8852be-support-id-0x0.patch
+bluetooth-add-device-0bda-887b-to-device-tables.patch
+bluetooth-add-device-13d3-3571-to-device-tables.patch
+bluetooth-btusb-add-rtw8852be-device-13d3-3570-to-de.patch
+bluetooth-btusb-add-0bda-b85b-for-fn-link-rtl8852be.patch
+pci-dwc-move-dbi-dbi2-and-addr_space-resource-setup-.patch
+pci-dwc-dra7xx-use-the-common-msi-irq_chip.patch
+pci-dwc-drop-the-.set_num_vectors-host-op.patch
+pci-dwc-move-msi-interrupt-setup-into-dwc-common-cod.patch
+pci-dwc-rework-msi-initialization.patch
+pci-dwc-move-link-handling-into-common-code.patch
+pci-dwc-move-dw_pcie_msi_init-into-core.patch
+pci-dwc-move-dw_pcie_setup_rc-to-dwc-common-code.patch
+pci-dwc-exynos-rework-the-driver-to-support-exynos54.patch
+pci-exynos-don-t-discard-.remove-callback.patch
+arm64-dts-qcom-ipq6018-switch-tcsr-mutex-to-mmio.patch
+arm64-dts-qcom-ipq6018-fix-tcsr_mutex-register-size.patch
--- /dev/null
+From 2bcb06935a5183deb0a4f37b09f622964de14800 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 14 Oct 2023 11:39:26 +0000
+Subject: tty: serial: meson: fix hard LOCKUP on crtscts mode
+
+From: Pavel Krasavin <pkrasavin@imaqliq.com>
+
+[ Upstream commit 2a1d728f20edeee7f26dc307ed9df4e0d23947ab ]
+
+There might be hard lockup if we set crtscts mode on port without RTS/CTS configured:
+
+# stty -F /dev/ttyAML6 crtscts; echo 1 > /dev/ttyAML6; echo 2 > /dev/ttyAML6
+[ 95.890386] rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
+[ 95.890857] rcu: 3-...0: (201 ticks this GP) idle=e33c/1/0x4000000000000000 softirq=5844/5846 fqs=4984
+[ 95.900212] rcu: (detected by 2, t=21016 jiffies, g=7753, q=296 ncpus=4)
+[ 95.906972] Task dump for CPU 3:
+[ 95.910178] task:bash state:R running task stack:0 pid:205 ppid:1 flags:0x00000202
+[ 95.920059] Call trace:
+[ 95.922485] __switch_to+0xe4/0x168
+[ 95.925951] 0xffffff8003477508
+[ 95.974379] watchdog: Watchdog detected hard LOCKUP on cpu 3
+[ 95.974424] Modules linked in: 88x2cs(O) rtc_meson_vrtc
+
+Possible solution would be to not allow to setup crtscts on such port.
+
+Tested on S905X3 based board.
+
+Fixes: ff7693d079e5 ("ARM: meson: serial: add MesonX SoC on-chip uart driver")
+Cc: stable@vger.kernel.org
+Signed-off-by: Pavel Krasavin <pkrasavin@imaqliq.com>
+Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
+Reviewed-by: Dmitry Rokosov <ddrokosov@salutedevices.com>
+
+v6: stable tag added
+v5: https://lore.kernel.org/lkml/OF43DA36FF.2BD3BB21-ON00258A47.005A8125-00258A47.005A9513@gdc.ru/
+added missed Reviewed-by tags, Fixes tag added according to Dmitry and Neil notes
+v4: https://lore.kernel.org/lkml/OF55521400.7512350F-ON00258A47.003F7254-00258A47.0040E15C@gdc.ru/
+More correct patch subject according to Jiri's note
+v3: https://lore.kernel.org/lkml/OF6CF5FFA0.CCFD0E8E-ON00258A46.00549EDF-00258A46.0054BB62@gdc.ru/
+"From:" line added to the mail
+v2: https://lore.kernel.org/lkml/OF950BEF72.7F425944-ON00258A46.00488A76-00258A46.00497D44@gdc.ru/
+braces for single statement removed according to Dmitry's note
+v1: https://lore.kernel.org/lkml/OF28B2B8C9.5BC0CD28-ON00258A46.0037688F-00258A46.0039155B@gdc.ru/
+Link: https://lore.kernel.org/r/OF66360032.51C36182-ON00258A48.003F656B-00258A48.0040092C@gdc.ru
+
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/meson_uart.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
+index bdc394afec5be..bb66a3f06626c 100644
+--- a/drivers/tty/serial/meson_uart.c
++++ b/drivers/tty/serial/meson_uart.c
+@@ -370,10 +370,14 @@ static void meson_uart_set_termios(struct uart_port *port,
+ else
+ val |= AML_UART_STOP_BIT_1SB;
+
+- if (cflags & CRTSCTS)
+- val &= ~AML_UART_TWO_WIRE_EN;
+- else
++ if (cflags & CRTSCTS) {
++ if (port->flags & UPF_HARD_FLOW)
++ val &= ~AML_UART_TWO_WIRE_EN;
++ else
++ termios->c_cflag &= ~CRTSCTS;
++ } else {
+ val |= AML_UART_TWO_WIRE_EN;
++ }
+
+ writel(val, port->membase + AML_UART_CONTROL);
+
+@@ -731,6 +735,7 @@ static int meson_uart_probe(struct platform_device *pdev)
+ u32 fifosize = 64; /* Default is 64, 128 for EE UART_0 */
+ int ret = 0;
+ int irq;
++ bool has_rtscts;
+
+ if (pdev->dev.of_node)
+ pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
+@@ -758,6 +763,7 @@ static int meson_uart_probe(struct platform_device *pdev)
+ return irq;
+
+ of_property_read_u32(pdev->dev.of_node, "fifo-size", &fifosize);
++ has_rtscts = of_property_read_bool(pdev->dev.of_node, "uart-has-rtscts");
+
+ if (meson_ports[pdev->id]) {
+ dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
+@@ -782,6 +788,8 @@ static int meson_uart_probe(struct platform_device *pdev)
+ port->mapsize = resource_size(res_mem);
+ port->irq = irq;
+ port->flags = UPF_BOOT_AUTOCONF | UPF_LOW_LATENCY;
++ if (has_rtscts)
++ port->flags |= UPF_HARD_FLOW;
+ port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MESON_CONSOLE);
+ port->dev = &pdev->dev;
+ port->line = pdev->id;
+--
+2.42.0
+
--- /dev/null
+From 9d2cae48b9b4411bf46cf89fbcac9625931c327a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 May 2021 09:58:32 +0200
+Subject: tty: serial: meson: retrieve port FIFO size from DT
+
+From: Neil Armstrong <narmstrong@baylibre.com>
+
+[ Upstream commit 27d44e05d7b85d9d4cfe0a3c0663ea49752ece93 ]
+
+Now the DT bindings has a property to get the FIFO size for a particular port,
+retrieve it and use to setup the FIFO interrupts threshold.
+
+Reviewed-by: Kevin Hilman <khilman@baylibre.com>
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+Link: https://lore.kernel.org/r/20210518075833.3736038-3-narmstrong@baylibre.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Stable-dep-of: 2a1d728f20ed ("tty: serial: meson: fix hard LOCKUP on crtscts mode")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/tty/serial/meson_uart.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
+index d06653493f0ef..78bda91a6bf15 100644
+--- a/drivers/tty/serial/meson_uart.c
++++ b/drivers/tty/serial/meson_uart.c
+@@ -728,6 +728,7 @@ static int meson_uart_probe(struct platform_device *pdev)
+ {
+ struct resource *res_mem, *res_irq;
+ struct uart_port *port;
++ u32 fifosize = 64; /* Default is 64, 128 for EE UART_0 */
+ int ret = 0;
+
+ if (pdev->dev.of_node)
+@@ -755,6 +756,8 @@ static int meson_uart_probe(struct platform_device *pdev)
+ if (!res_irq)
+ return -ENODEV;
+
++ of_property_read_u32(pdev->dev.of_node, "fifo-size", &fifosize);
++
+ if (meson_ports[pdev->id]) {
+ dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
+ return -EBUSY;
+@@ -784,7 +787,7 @@ static int meson_uart_probe(struct platform_device *pdev)
+ port->type = PORT_MESON;
+ port->x_char = 0;
+ port->ops = &meson_uart_ops;
+- port->fifosize = 64;
++ port->fifosize = fifosize;
+
+ meson_ports[pdev->id] = port;
+ platform_set_drvdata(pdev, port);
+--
+2.42.0
+