From: Álvaro Fernández Rojas Date: Tue, 31 Mar 2020 07:26:30 +0000 (+0200) Subject: bcm27xx: update 5.4 patches from RPi foundation X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=49109cedab88d95596e3a3c04ef9e6d30fb4bcb3;p=openwrt%2Fstaging%2Frmilecki.git bcm27xx: update 5.4 patches from RPi foundation Signed-off-by: Álvaro Fernández Rojas --- diff --git a/target/linux/bcm27xx/bcm2708/config-5.4 b/target/linux/bcm27xx/bcm2708/config-5.4 index 6e7d91e3f41..1f12a36ee72 100644 --- a/target/linux/bcm27xx/bcm2708/config-5.4 +++ b/target/linux/bcm27xx/bcm2708/config-5.4 @@ -243,6 +243,8 @@ CONFIG_HAVE_SYSCALL_TRACEPOINTS=y CONFIG_HAVE_UID16=y CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HW_CONSOLE=y +CONFIG_HZ=100 +CONFIG_HZ_100=y CONFIG_HZ_FIXED=0 CONFIG_I2C=y # CONFIG_I2C_BCM2708 is not set diff --git a/target/linux/bcm27xx/bcm2709/config-5.4 b/target/linux/bcm27xx/bcm2709/config-5.4 index e6ce625d1be..c1630c599d8 100644 --- a/target/linux/bcm27xx/bcm2709/config-5.4 +++ b/target/linux/bcm27xx/bcm2709/config-5.4 @@ -311,6 +311,8 @@ CONFIG_HIGHMEM=y CONFIG_HIGHPTE=y CONFIG_HOTPLUG_CPU=y CONFIG_HW_CONSOLE=y +CONFIG_HZ=100 +CONFIG_HZ_100=y CONFIG_HZ_FIXED=0 CONFIG_I2C=y # CONFIG_I2C_BCM2708 is not set diff --git a/target/linux/bcm27xx/bcm2710/config-5.4 b/target/linux/bcm27xx/bcm2710/config-5.4 index a04d519b137..4a5b491b0fc 100644 --- a/target/linux/bcm27xx/bcm2710/config-5.4 +++ b/target/linux/bcm27xx/bcm2710/config-5.4 @@ -367,6 +367,8 @@ CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HOLES_IN_ZONE=y CONFIG_HOTPLUG_CPU=y CONFIG_HW_CONSOLE=y +CONFIG_HZ=250 +CONFIG_HZ_250=y CONFIG_I2C=y # CONFIG_I2C_BCM2708 is not set CONFIG_I2C_BOARDINFO=y diff --git a/target/linux/bcm27xx/bcm2711/config-5.4 b/target/linux/bcm27xx/bcm2711/config-5.4 index 0b0e49ad62d..abf6e8844a1 100644 --- a/target/linux/bcm27xx/bcm2711/config-5.4 +++ b/target/linux/bcm27xx/bcm2711/config-5.4 @@ -373,6 +373,8 @@ CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HOLES_IN_ZONE=y CONFIG_HOTPLUG_CPU=y CONFIG_HW_CONSOLE=y +CONFIG_HZ=250 +CONFIG_HZ_250=y CONFIG_I2C=y # CONFIG_I2C_BCM2708 is not set CONFIG_I2C_BOARDINFO=y diff --git a/target/linux/bcm27xx/patches-5.4/950-0435-ARM-dts-overlays-Create-custom-clocks-in.patch b/target/linux/bcm27xx/patches-5.4/950-0435-ARM-dts-overlays-Create-custom-clocks-in.patch new file mode 100644 index 00000000000..ac50884bcea --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0435-ARM-dts-overlays-Create-custom-clocks-in.patch @@ -0,0 +1,79 @@ +From c182949e33dc3ac4d718386f97c75583bae0e46b Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 28 Feb 2020 11:22:40 +0000 +Subject: [PATCH] ARM: dts: overlays: Create custom clocks in / + +Change [1] removes the simple-bus compatible string from the "/clocks" +node, preventing any custom clocks placed there from being initialised. +Rather than reinstate the compatible string and trigger DT warnings at +kernel build time, change the overlays to instantiate those clocks under +the root node ("/"). + +See: https://github.com/raspberrypi/linux/issues/3481 + +Signed-off-by: Phil Elwell + +[1] 4b2d24662126 ("ARM: dts: bcm283x: Remove simple-bus from fixed clocks") +--- + .../boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +- + arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts | 2 +- + 5 files changed, 5 insertions(+), 5 deletions(-) + +--- a/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts ++++ b/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts +@@ -9,7 +9,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target-path = "/clocks"; ++ target-path = "/"; + __overlay__ { + boss_osc: boss_osc { + compatible = "allo,dac-clk"; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target-path = "/clocks"; ++ target-path = "/"; + __overlay__ { + dacpro_osc: dacpro_osc { + compatible = "hifiberry,dacpro-clk"; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target-path = "/clocks"; ++ target-path = "/"; + __overlay__ { + dacpro_osc: dacpro_osc { + compatible = "hifiberry,dacpro-clk"; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts +@@ -6,7 +6,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target-path = "/clocks"; ++ target-path = "/"; + __overlay__ { + dacpro_osc: dacpro_osc { + compatible = "hifiberry,dacpro-clk"; +--- a/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts ++++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts +@@ -8,7 +8,7 @@ + compatible = "brcm,bcm2835"; + + fragment@0 { +- target-path = "/clocks"; ++ target-path = "/"; + __overlay__ { + dachd_osc: pll_dachd_osc { + compatible = "hifiberry,dachd-clk"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0436-ARM-dts-overlays-Create-custom-clocks-in.patch b/target/linux/bcm27xx/patches-5.4/950-0436-ARM-dts-overlays-Create-custom-clocks-in.patch deleted file mode 100644 index ac50884bcea..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0436-ARM-dts-overlays-Create-custom-clocks-in.patch +++ /dev/null @@ -1,79 +0,0 @@ -From c182949e33dc3ac4d718386f97c75583bae0e46b Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 28 Feb 2020 11:22:40 +0000 -Subject: [PATCH] ARM: dts: overlays: Create custom clocks in / - -Change [1] removes the simple-bus compatible string from the "/clocks" -node, preventing any custom clocks placed there from being initialised. -Rather than reinstate the compatible string and trigger DT warnings at -kernel build time, change the overlays to instantiate those clocks under -the root node ("/"). - -See: https://github.com/raspberrypi/linux/issues/3481 - -Signed-off-by: Phil Elwell - -[1] 4b2d24662126 ("ARM: dts: bcm283x: Remove simple-bus from fixed clocks") ---- - .../boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts | 2 +- - arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts | 2 +- - arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts | 2 +- - arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts | 2 +- - arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts | 2 +- - 5 files changed, 5 insertions(+), 5 deletions(-) - ---- a/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts -+++ b/arch/arm/boot/dts/overlays/allo-boss-dac-pcm512x-audio-overlay.dts -@@ -9,7 +9,7 @@ - compatible = "brcm,bcm2835"; - - fragment@0 { -- target-path = "/clocks"; -+ target-path = "/"; - __overlay__ { - boss_osc: boss_osc { - compatible = "allo,dac-clk"; ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplus-overlay.dts -@@ -6,7 +6,7 @@ - compatible = "brcm,bcm2835"; - - fragment@0 { -- target-path = "/clocks"; -+ target-path = "/"; - __overlay__ { - dacpro_osc: dacpro_osc { - compatible = "hifiberry,dacpro-clk"; ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadc-overlay.dts -@@ -6,7 +6,7 @@ - compatible = "brcm,bcm2835"; - - fragment@0 { -- target-path = "/clocks"; -+ target-path = "/"; - __overlay__ { - dacpro_osc: dacpro_osc { - compatible = "hifiberry,dacpro-clk"; ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplusadcpro-overlay.dts -@@ -6,7 +6,7 @@ - compatible = "brcm,bcm2835"; - - fragment@0 { -- target-path = "/clocks"; -+ target-path = "/"; - __overlay__ { - dacpro_osc: dacpro_osc { - compatible = "hifiberry,dacpro-clk"; ---- a/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts -+++ b/arch/arm/boot/dts/overlays/hifiberry-dacplushd-overlay.dts -@@ -8,7 +8,7 @@ - compatible = "brcm,bcm2835"; - - fragment@0 { -- target-path = "/clocks"; -+ target-path = "/"; - __overlay__ { - dachd_osc: pll_dachd_osc { - compatible = "hifiberry,dachd-clk"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0436-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch b/target/linux/bcm27xx/patches-5.4/950-0436-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch new file mode 100644 index 00000000000..4774fd23261 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0436-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch @@ -0,0 +1,26 @@ +From 38e906c77467bf83ec130bea6859b46ea1e0d4b8 Mon Sep 17 00:00:00 2001 +From: Naushir Patuck +Date: Thu, 30 Jan 2020 12:35:44 +0000 +Subject: [PATCH] staging: vc04_services: Fix vcsm overflow bug when + counting transactions + +The response block and local state were using u16 and u32 respectively +to represent transaction id. When the former would wrap, there is a +mismatch and subsequent transactions will be marked as failures. + +Signed-off-by: Naushir Patuck +--- + drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c ++++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c +@@ -34,7 +34,7 @@ struct sm_cmd_rsp_blk { + /* To be signaled when the response is there */ + struct completion cmplt; + +- u16 id; ++ u32 id; + u16 length; + + u8 msg[VC_SM_MAX_MSG_LEN]; diff --git a/target/linux/bcm27xx/patches-5.4/950-0437-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch b/target/linux/bcm27xx/patches-5.4/950-0437-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch new file mode 100644 index 00000000000..213e8b8d9d7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0437-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch @@ -0,0 +1,34 @@ +From 04f569021b0d24ec9f5c3671447b77157c859d16 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Fri, 7 Feb 2020 09:51:31 +0000 +Subject: [PATCH] overlays: Add timeout_ms parameter to gpio-poweroff + +The timeout_ms parameter specifies in milliseconds how long the kernel +waits for power-down before issuing a WARN. The default value is 3000 ms. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/README | 2 ++ + arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts | 1 + + 2 files changed, 3 insertions(+) + +--- a/arch/arm/boot/dts/overlays/README ++++ b/arch/arm/boot/dts/overlays/README +@@ -821,6 +821,8 @@ Params: gpiopin GPIO for + input Set if the gpio pin should be configured as + an input. + export Set to export the configured pin to sysfs ++ timeout_ms Specify (in ms) how long the kernel waits for ++ power-down before issuing a WARN (default 3000). + + + Name: gpio-shutdown +--- a/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts ++++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts +@@ -32,5 +32,6 @@ + active_low = <&power_ctrl>,"gpios:8"; + input = <&power_ctrl>,"input?"; + export = <&power_ctrl>,"export?"; ++ timeout_ms = <&power_ctrl>,"timeout-ms:0"; + }; + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0437-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch b/target/linux/bcm27xx/patches-5.4/950-0437-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch deleted file mode 100644 index 4774fd23261..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0437-staging-vc04_services-Fix-vcsm-overflow-bug-when-cou.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 38e906c77467bf83ec130bea6859b46ea1e0d4b8 Mon Sep 17 00:00:00 2001 -From: Naushir Patuck -Date: Thu, 30 Jan 2020 12:35:44 +0000 -Subject: [PATCH] staging: vc04_services: Fix vcsm overflow bug when - counting transactions - -The response block and local state were using u16 and u32 respectively -to represent transaction id. When the former would wrap, there is a -mismatch and subsequent transactions will be marked as failures. - -Signed-off-by: Naushir Patuck ---- - drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c -+++ b/drivers/staging/vc04_services/vc-sm-cma/vc_sm_cma_vchi.c -@@ -34,7 +34,7 @@ struct sm_cmd_rsp_blk { - /* To be signaled when the response is there */ - struct completion cmplt; - -- u16 id; -+ u32 id; - u16 length; - - u8 msg[VC_SM_MAX_MSG_LEN]; diff --git a/target/linux/bcm27xx/patches-5.4/950-0438-of-overlay-Correct-symbol-path-fixups.patch b/target/linux/bcm27xx/patches-5.4/950-0438-of-overlay-Correct-symbol-path-fixups.patch new file mode 100644 index 00000000000..4b005876de1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0438-of-overlay-Correct-symbol-path-fixups.patch @@ -0,0 +1,37 @@ +From 8f22c4228bbb91697ab3510f5a6176e530c0d639 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Thu, 6 Feb 2020 12:23:15 +0000 +Subject: [PATCH] of: overlay: Correct symbol path fixups + +When symbols from overlays are added to the live tree their paths must +be rebased. The translated symbol is normally the result of joining +the fragment-relative path (with a leading "/") to the target path +(either copied directly from the "target-path" property or resolved +from the phandle). This translation fails when the target is the root +node (a common case for Raspberry Pi overlays) because the resulting +path starts with a double slash. For example, if target-path is "/" and +the fragment adds a node called "newnode", the label associated with +that node will be assigned the path "//newnode", which can't be found +in the tree. + +Fix the failure case by explicitly replacing a target path of "/" with +an empty string. + +Fixes: d1651b03c2df ("of: overlay: add overlay symbols to live device tree") + +Signed-off-by: Phil Elwell +--- + drivers/of/overlay.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/of/overlay.c ++++ b/drivers/of/overlay.c +@@ -245,6 +245,8 @@ static struct property *dup_and_fixup_sy + if (!target_path) + return NULL; + target_path_len = strlen(target_path); ++ if (!strcmp(target_path, "/")) ++ target_path_len = 0; + + new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); + if (!new_prop) diff --git a/target/linux/bcm27xx/patches-5.4/950-0438-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch b/target/linux/bcm27xx/patches-5.4/950-0438-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch deleted file mode 100644 index 213e8b8d9d7..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0438-overlays-Add-timeout_ms-parameter-to-gpio-poweroff.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 04f569021b0d24ec9f5c3671447b77157c859d16 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Fri, 7 Feb 2020 09:51:31 +0000 -Subject: [PATCH] overlays: Add timeout_ms parameter to gpio-poweroff - -The timeout_ms parameter specifies in milliseconds how long the kernel -waits for power-down before issuing a WARN. The default value is 3000 ms. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/overlays/README | 2 ++ - arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts | 1 + - 2 files changed, 3 insertions(+) - ---- a/arch/arm/boot/dts/overlays/README -+++ b/arch/arm/boot/dts/overlays/README -@@ -821,6 +821,8 @@ Params: gpiopin GPIO for - input Set if the gpio pin should be configured as - an input. - export Set to export the configured pin to sysfs -+ timeout_ms Specify (in ms) how long the kernel waits for -+ power-down before issuing a WARN (default 3000). - - - Name: gpio-shutdown ---- a/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts -+++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts -@@ -32,5 +32,6 @@ - active_low = <&power_ctrl>,"gpios:8"; - input = <&power_ctrl>,"input?"; - export = <&power_ctrl>,"export?"; -+ timeout_ms = <&power_ctrl>,"timeout-ms:0"; - }; - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0439-of-overlay-Correct-symbol-path-fixups.patch b/target/linux/bcm27xx/patches-5.4/950-0439-of-overlay-Correct-symbol-path-fixups.patch deleted file mode 100644 index 4b005876de1..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0439-of-overlay-Correct-symbol-path-fixups.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 8f22c4228bbb91697ab3510f5a6176e530c0d639 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Thu, 6 Feb 2020 12:23:15 +0000 -Subject: [PATCH] of: overlay: Correct symbol path fixups - -When symbols from overlays are added to the live tree their paths must -be rebased. The translated symbol is normally the result of joining -the fragment-relative path (with a leading "/") to the target path -(either copied directly from the "target-path" property or resolved -from the phandle). This translation fails when the target is the root -node (a common case for Raspberry Pi overlays) because the resulting -path starts with a double slash. For example, if target-path is "/" and -the fragment adds a node called "newnode", the label associated with -that node will be assigned the path "//newnode", which can't be found -in the tree. - -Fix the failure case by explicitly replacing a target path of "/" with -an empty string. - -Fixes: d1651b03c2df ("of: overlay: add overlay symbols to live device tree") - -Signed-off-by: Phil Elwell ---- - drivers/of/overlay.c | 2 ++ - 1 file changed, 2 insertions(+) - ---- a/drivers/of/overlay.c -+++ b/drivers/of/overlay.c -@@ -245,6 +245,8 @@ static struct property *dup_and_fixup_sy - if (!target_path) - return NULL; - target_path_len = strlen(target_path); -+ if (!strcmp(target_path, "/")) -+ target_path_len = 0; - - new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); - if (!new_prop) diff --git a/target/linux/bcm27xx/patches-5.4/950-0439-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch b/target/linux/bcm27xx/patches-5.4/950-0439-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch new file mode 100644 index 00000000000..636ad26a917 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0439-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch @@ -0,0 +1,25 @@ +From 65318cd76f4523acf8ffe8fe7448fb7d913f8c66 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Tue, 3 Mar 2020 09:43:41 +0000 +Subject: [PATCH] overlays: sc16ic750-i2c: Fix xtal parameter + +The xtal parameter is targetting the wrong node - fix it. + +See: https://github.com/raspberrypi/linux/issues/3156 + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts ++++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts +@@ -32,7 +32,7 @@ + __overrides__ { + int_pin = <&sc16is750>,"interrupts:0"; + addr = <&sc16is750>,"reg:0",<&sc16is750_clk>,"name"; +- xtal = <&sc16is750>,"clock-frequency:0"; ++ xtal = <&sc16is750_clk>,"clock-frequency:0"; + }; + + }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0440-of-address-Introduce-of_get_next_dma_parent-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0440-of-address-Introduce-of_get_next_dma_parent-helper.patch new file mode 100644 index 00000000000..1056cfc60dc --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0440-of-address-Introduce-of_get_next_dma_parent-helper.patch @@ -0,0 +1,39 @@ +From 25ab98ceb9844642c994b5766de1033552d1aef2 Mon Sep 17 00:00:00 2001 +From: Robin Murphy +Date: Wed, 3 Jul 2019 18:23:01 +0100 +Subject: [PATCH] of/address: Introduce of_get_next_dma_parent() helper + +commit 862ab5578f754117742c8b8c8e5ddf98bdb190ba upstream. + +Add of_get_next_dma_parent() helper which is similar to +__of_get_dma_parent(), but can be used in iterators and decrements the +ref count on the prior parent. + +Signed-off-by: Robin Murphy +Reviewed-by: Geert Uytterhoeven +Tested-by: Nicolas Saenz Julienne +Reviewed-by: Nicolas Saenz Julienne +Signed-off-by: Rob Herring +--- + drivers/of/address.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -695,6 +695,16 @@ static struct device_node *__of_get_dma_ + return of_node_get(args.np); + } + ++static struct device_node *of_get_next_dma_parent(struct device_node *np) ++{ ++ struct device_node *parent; ++ ++ parent = __of_get_dma_parent(np); ++ of_node_put(np); ++ ++ return parent; ++} ++ + u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) + { + struct device_node *host; diff --git a/target/linux/bcm27xx/patches-5.4/950-0440-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch b/target/linux/bcm27xx/patches-5.4/950-0440-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch deleted file mode 100644 index 636ad26a917..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0440-overlays-sc16ic750-i2c-Fix-xtal-parameter.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 65318cd76f4523acf8ffe8fe7448fb7d913f8c66 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Tue, 3 Mar 2020 09:43:41 +0000 -Subject: [PATCH] overlays: sc16ic750-i2c: Fix xtal parameter - -The xtal parameter is targetting the wrong node - fix it. - -See: https://github.com/raspberrypi/linux/issues/3156 - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts -+++ b/arch/arm/boot/dts/overlays/sc16is750-i2c-overlay.dts -@@ -32,7 +32,7 @@ - __overrides__ { - int_pin = <&sc16is750>,"interrupts:0"; - addr = <&sc16is750>,"reg:0",<&sc16is750_clk>,"name"; -- xtal = <&sc16is750>,"clock-frequency:0"; -+ xtal = <&sc16is750_clk>,"clock-frequency:0"; - }; - - }; diff --git a/target/linux/bcm27xx/patches-5.4/950-0441-of-address-Follow-DMA-parent-for-dma-coherent.patch b/target/linux/bcm27xx/patches-5.4/950-0441-of-address-Follow-DMA-parent-for-dma-coherent.patch new file mode 100644 index 00000000000..dbfb1025cd3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0441-of-address-Follow-DMA-parent-for-dma-coherent.patch @@ -0,0 +1,30 @@ +From e4a649779ff6857240fe691cdf147a3b4896e71b Mon Sep 17 00:00:00 2001 +From: Robin Murphy +Date: Wed, 3 Jul 2019 14:47:31 +0100 +Subject: [PATCH] of: address: Follow DMA parent for "dma-coherent" + +commit c60bf3eb888a362100aa1bdbea351dab681e262a upstream. + +Much like for address translation, when checking for DMA coherence we +should be sure to walk up the DMA hierarchy, rather than the MMIO one, +now that we can accommodate them being different. + +Signed-off-by: Robin Murphy +Tested-by: Nicolas Saenz Julienne +Reviewed-by: Nicolas Saenz Julienne +Signed-off-by: Rob Herring +--- + drivers/of/address.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -1023,7 +1023,7 @@ bool of_dma_is_coherent(struct device_no + of_node_put(node); + return true; + } +- node = of_get_next_parent(node); ++ node = of_get_next_dma_parent(node); + } + of_node_put(node); + return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0441-of-address-Introduce-of_get_next_dma_parent-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0441-of-address-Introduce-of_get_next_dma_parent-helper.patch deleted file mode 100644 index 1056cfc60dc..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0441-of-address-Introduce-of_get_next_dma_parent-helper.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 25ab98ceb9844642c994b5766de1033552d1aef2 Mon Sep 17 00:00:00 2001 -From: Robin Murphy -Date: Wed, 3 Jul 2019 18:23:01 +0100 -Subject: [PATCH] of/address: Introduce of_get_next_dma_parent() helper - -commit 862ab5578f754117742c8b8c8e5ddf98bdb190ba upstream. - -Add of_get_next_dma_parent() helper which is similar to -__of_get_dma_parent(), but can be used in iterators and decrements the -ref count on the prior parent. - -Signed-off-by: Robin Murphy -Reviewed-by: Geert Uytterhoeven -Tested-by: Nicolas Saenz Julienne -Reviewed-by: Nicolas Saenz Julienne -Signed-off-by: Rob Herring ---- - drivers/of/address.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - ---- a/drivers/of/address.c -+++ b/drivers/of/address.c -@@ -695,6 +695,16 @@ static struct device_node *__of_get_dma_ - return of_node_get(args.np); - } - -+static struct device_node *of_get_next_dma_parent(struct device_node *np) -+{ -+ struct device_node *parent; -+ -+ parent = __of_get_dma_parent(np); -+ of_node_put(np); -+ -+ return parent; -+} -+ - u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr) - { - struct device_node *host; diff --git a/target/linux/bcm27xx/patches-5.4/950-0442-of-Factor-out-addr-size-cells-parsing.patch b/target/linux/bcm27xx/patches-5.4/950-0442-of-Factor-out-addr-size-cells-parsing.patch new file mode 100644 index 00000000000..045ee9827fa --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0442-of-Factor-out-addr-size-cells-parsing.patch @@ -0,0 +1,117 @@ +From 839aeedc908eb729b9014e7d1d38e109778a52d2 Mon Sep 17 00:00:00 2001 +From: Robin Murphy +Date: Tue, 2 Jul 2019 18:42:39 +0100 +Subject: [PATCH] of: Factor out #{addr,size}-cells parsing + +In some cases such as PCI host controllers, we may have a "parent bus" +which is an OF leaf node, but still need to correctly parse ranges from +the point of view of that bus. For that, factor out variants of the +"#addr-cells" and "#size-cells" parsers which do not assume they have a +device node and thus immediately traverse upwards before reading the +relevant property. + +Signed-off-by: Robin Murphy +[robh: don't make of_bus_n_{addr,size}_cells() public] +Reviewed-by: Geert Uytterhoeven +Tested-by: Nicolas Saenz Julienne +Reviewed-by: Nicolas Saenz Julienne +Signed-off-by: Rob Herring + +(cherry picked from commit b68ac8dc22ebbf003e26e44bf4dd3030c076df5a) +--- + drivers/of/address.c | 2 ++ + drivers/of/base.c | 32 ++++++++++++++++++++++---------- + drivers/of/of_private.h | 14 ++++++++++++++ + 3 files changed, 38 insertions(+), 10 deletions(-) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -14,6 +14,8 @@ + #include + #include + ++#include "of_private.h" ++ + /* Max address size we deal with */ + #define OF_MAX_ADDR_CELLS 4 + #define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS) +--- a/drivers/of/base.c ++++ b/drivers/of/base.c +@@ -86,34 +86,46 @@ static bool __of_node_is_type(const stru + return np && match && type && !strcmp(match, type); + } + +-int of_n_addr_cells(struct device_node *np) ++int of_bus_n_addr_cells(struct device_node *np) + { + u32 cells; + +- do { +- if (np->parent) +- np = np->parent; ++ for (; np; np = np->parent) + if (!of_property_read_u32(np, "#address-cells", &cells)) + return cells; +- } while (np->parent); ++ + /* No #address-cells property for the root node */ + return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; + } ++ ++int of_n_addr_cells(struct device_node *np) ++{ ++ if (np->parent) ++ np = np->parent; ++ ++ return of_bus_n_addr_cells(np); ++} + EXPORT_SYMBOL(of_n_addr_cells); + +-int of_n_size_cells(struct device_node *np) ++int of_bus_n_size_cells(struct device_node *np) + { + u32 cells; + +- do { +- if (np->parent) +- np = np->parent; ++ for (; np; np = np->parent) + if (!of_property_read_u32(np, "#size-cells", &cells)) + return cells; +- } while (np->parent); ++ + /* No #size-cells property for the root node */ + return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; + } ++ ++int of_n_size_cells(struct device_node *np) ++{ ++ if (np->parent) ++ np = np->parent; ++ ++ return of_bus_n_size_cells(np); ++} + EXPORT_SYMBOL(of_n_size_cells); + + #ifdef CONFIG_NUMA +--- a/drivers/of/of_private.h ++++ b/drivers/of/of_private.h +@@ -158,4 +158,18 @@ extern void __of_sysfs_remove_bin_file(s + #define for_each_transaction_entry_reverse(_oft, _te) \ + list_for_each_entry_reverse(_te, &(_oft)->te_list, node) + ++extern int of_bus_n_addr_cells(struct device_node *np); ++extern int of_bus_n_size_cells(struct device_node *np); ++ ++#ifdef CONFIG_OF_ADDRESS ++extern int of_dma_get_range(struct device_node *np, u64 *dma_addr, ++ u64 *paddr, u64 *size); ++#else ++static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr, ++ u64 *paddr, u64 *size) ++{ ++ return -ENODEV; ++} ++#endif ++ + #endif /* _LINUX_OF_PRIVATE_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0442-of-address-Follow-DMA-parent-for-dma-coherent.patch b/target/linux/bcm27xx/patches-5.4/950-0442-of-address-Follow-DMA-parent-for-dma-coherent.patch deleted file mode 100644 index dbfb1025cd3..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0442-of-address-Follow-DMA-parent-for-dma-coherent.patch +++ /dev/null @@ -1,30 +0,0 @@ -From e4a649779ff6857240fe691cdf147a3b4896e71b Mon Sep 17 00:00:00 2001 -From: Robin Murphy -Date: Wed, 3 Jul 2019 14:47:31 +0100 -Subject: [PATCH] of: address: Follow DMA parent for "dma-coherent" - -commit c60bf3eb888a362100aa1bdbea351dab681e262a upstream. - -Much like for address translation, when checking for DMA coherence we -should be sure to walk up the DMA hierarchy, rather than the MMIO one, -now that we can accommodate them being different. - -Signed-off-by: Robin Murphy -Tested-by: Nicolas Saenz Julienne -Reviewed-by: Nicolas Saenz Julienne -Signed-off-by: Rob Herring ---- - drivers/of/address.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/of/address.c -+++ b/drivers/of/address.c -@@ -1023,7 +1023,7 @@ bool of_dma_is_coherent(struct device_no - of_node_put(node); - return true; - } -- node = of_get_next_parent(node); -+ node = of_get_next_dma_parent(node); - } - of_node_put(node); - return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0443-of-Factor-out-addr-size-cells-parsing.patch b/target/linux/bcm27xx/patches-5.4/950-0443-of-Factor-out-addr-size-cells-parsing.patch deleted file mode 100644 index 045ee9827fa..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0443-of-Factor-out-addr-size-cells-parsing.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 839aeedc908eb729b9014e7d1d38e109778a52d2 Mon Sep 17 00:00:00 2001 -From: Robin Murphy -Date: Tue, 2 Jul 2019 18:42:39 +0100 -Subject: [PATCH] of: Factor out #{addr,size}-cells parsing - -In some cases such as PCI host controllers, we may have a "parent bus" -which is an OF leaf node, but still need to correctly parse ranges from -the point of view of that bus. For that, factor out variants of the -"#addr-cells" and "#size-cells" parsers which do not assume they have a -device node and thus immediately traverse upwards before reading the -relevant property. - -Signed-off-by: Robin Murphy -[robh: don't make of_bus_n_{addr,size}_cells() public] -Reviewed-by: Geert Uytterhoeven -Tested-by: Nicolas Saenz Julienne -Reviewed-by: Nicolas Saenz Julienne -Signed-off-by: Rob Herring - -(cherry picked from commit b68ac8dc22ebbf003e26e44bf4dd3030c076df5a) ---- - drivers/of/address.c | 2 ++ - drivers/of/base.c | 32 ++++++++++++++++++++++---------- - drivers/of/of_private.h | 14 ++++++++++++++ - 3 files changed, 38 insertions(+), 10 deletions(-) - ---- a/drivers/of/address.c -+++ b/drivers/of/address.c -@@ -14,6 +14,8 @@ - #include - #include - -+#include "of_private.h" -+ - /* Max address size we deal with */ - #define OF_MAX_ADDR_CELLS 4 - #define OF_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS) ---- a/drivers/of/base.c -+++ b/drivers/of/base.c -@@ -86,34 +86,46 @@ static bool __of_node_is_type(const stru - return np && match && type && !strcmp(match, type); - } - --int of_n_addr_cells(struct device_node *np) -+int of_bus_n_addr_cells(struct device_node *np) - { - u32 cells; - -- do { -- if (np->parent) -- np = np->parent; -+ for (; np; np = np->parent) - if (!of_property_read_u32(np, "#address-cells", &cells)) - return cells; -- } while (np->parent); -+ - /* No #address-cells property for the root node */ - return OF_ROOT_NODE_ADDR_CELLS_DEFAULT; - } -+ -+int of_n_addr_cells(struct device_node *np) -+{ -+ if (np->parent) -+ np = np->parent; -+ -+ return of_bus_n_addr_cells(np); -+} - EXPORT_SYMBOL(of_n_addr_cells); - --int of_n_size_cells(struct device_node *np) -+int of_bus_n_size_cells(struct device_node *np) - { - u32 cells; - -- do { -- if (np->parent) -- np = np->parent; -+ for (; np; np = np->parent) - if (!of_property_read_u32(np, "#size-cells", &cells)) - return cells; -- } while (np->parent); -+ - /* No #size-cells property for the root node */ - return OF_ROOT_NODE_SIZE_CELLS_DEFAULT; - } -+ -+int of_n_size_cells(struct device_node *np) -+{ -+ if (np->parent) -+ np = np->parent; -+ -+ return of_bus_n_size_cells(np); -+} - EXPORT_SYMBOL(of_n_size_cells); - - #ifdef CONFIG_NUMA ---- a/drivers/of/of_private.h -+++ b/drivers/of/of_private.h -@@ -158,4 +158,18 @@ extern void __of_sysfs_remove_bin_file(s - #define for_each_transaction_entry_reverse(_oft, _te) \ - list_for_each_entry_reverse(_te, &(_oft)->te_list, node) - -+extern int of_bus_n_addr_cells(struct device_node *np); -+extern int of_bus_n_size_cells(struct device_node *np); -+ -+#ifdef CONFIG_OF_ADDRESS -+extern int of_dma_get_range(struct device_node *np, u64 *dma_addr, -+ u64 *paddr, u64 *size); -+#else -+static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr, -+ u64 *paddr, u64 *size) -+{ -+ return -ENODEV; -+} -+#endif -+ - #endif /* _LINUX_OF_PRIVATE_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0443-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch b/target/linux/bcm27xx/patches-5.4/950-0443-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch new file mode 100644 index 00000000000..28d1987a9c7 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0443-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch @@ -0,0 +1,40 @@ +From 39f5d9e883393e32938eac45b564f74afde8a942 Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Wed, 4 Sep 2019 11:43:30 +0100 +Subject: [PATCH] of/address: Translate 'dma-ranges' for parent nodes + missing 'dma-ranges' + +commit 81db12ee15cb83926e290a8a3654a2dfebc80935 upstream. + +'dma-ranges' frequently exists without parent nodes having 'dma-ranges'. +While this is an error for 'ranges', this is fine because DMA capable +devices always have a translatable DMA address. Also, with no +'dma-ranges' at all, the assumption is that DMA addresses are 1:1 with +no restrictions unless perhaps the device itself has implicit +restrictions. + +Cc: Robin Murphy +Tested-by: Nicolas Saenz Julienne +Reviewed-by: Nicolas Saenz Julienne +Signed-off-by: Rob Herring +--- + drivers/of/address.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -519,9 +519,13 @@ static int of_translate_one(struct devic + * + * As far as we know, this damage only exists on Apple machines, so + * This code is only enabled on powerpc. --gcl ++ * ++ * This quirk also applies for 'dma-ranges' which frequently exist in ++ * child nodes without 'dma-ranges' in the parent nodes. --RobH + */ + ranges = of_get_property(parent, rprop, &rlen); +- if (ranges == NULL && !of_empty_ranges_quirk(parent)) { ++ if (ranges == NULL && !of_empty_ranges_quirk(parent) && ++ strcmp(rprop, "dma-ranges")) { + pr_debug("no ranges; cannot translate\n"); + return 1; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0444-of-Make-of_dma_get_range-work-on-bus-nodes.patch b/target/linux/bcm27xx/patches-5.4/950-0444-of-Make-of_dma_get_range-work-on-bus-nodes.patch new file mode 100644 index 00000000000..1cac2dfcd8a --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0444-of-Make-of_dma_get_range-work-on-bus-nodes.patch @@ -0,0 +1,107 @@ +From 7631cb95056f03136c9e0a35484e8bebe7b52650 Mon Sep 17 00:00:00 2001 +From: Robin Murphy +Date: Wed, 3 Jul 2019 18:42:20 +0100 +Subject: [PATCH] of: Make of_dma_get_range() work on bus nodes + +commit 951d48855d86e72e0d6de73440fe09d363168064 upstream. + +Since the "dma-ranges" property is only valid for a node representing a +bus, of_dma_get_range() currently assumes the node passed in is a leaf +representing a device, and starts the walk from its parent. In cases +like PCI host controllers on typical FDT systems, however, where the PCI +endpoints are probed dynamically the initial leaf node represents the +'bus' itself, and this logic means we fail to consider any "dma-ranges" +describing the host bridge itself. Rework the logic such that +of_dma_get_range() also works correctly starting from a bus node +containing "dma-ranges". + +While this does mean "dma-ranges" could incorrectly be in a device leaf +node, there isn't really any way in this function to ensure that a leaf +node is or isn't a bus node. + +Signed-off-by: Robin Murphy +[robh: Allow for the bus child node to still be passed in] +Signed-off-by: Rob Herring +Reviewed-by: Robin Murphy +Reviewed-by: Nicolas Saenz Julienne +Tested-by: Nicolas Saenz Julienne +--- + drivers/of/address.c | 44 ++++++++++++++++++-------------------------- + 1 file changed, 18 insertions(+), 26 deletions(-) + +--- a/drivers/of/address.c ++++ b/drivers/of/address.c +@@ -940,47 +940,39 @@ int of_dma_get_range(struct device_node + const __be32 *ranges = NULL; + int len, naddr, nsize, pna; + int ret = 0; ++ bool found_dma_ranges = false; + u64 dmaaddr; + +- if (!node) +- return -EINVAL; +- +- while (1) { +- struct device_node *parent; +- +- naddr = of_n_addr_cells(node); +- nsize = of_n_size_cells(node); +- +- parent = __of_get_dma_parent(node); +- of_node_put(node); +- +- node = parent; +- if (!node) +- break; +- ++ while (node) { + ranges = of_get_property(node, "dma-ranges", &len); + + /* Ignore empty ranges, they imply no translation required */ + if (ranges && len > 0) + break; + +- /* +- * At least empty ranges has to be defined for parent node if +- * DMA is supported +- */ +- if (!ranges) +- break; ++ /* Once we find 'dma-ranges', then a missing one is an error */ ++ if (found_dma_ranges && !ranges) { ++ ret = -ENODEV; ++ goto out; ++ } ++ found_dma_ranges = true; ++ ++ node = of_get_next_dma_parent(node); + } + +- if (!ranges) { ++ if (!node || !ranges) { + pr_debug("no dma-ranges found for node(%pOF)\n", np); + ret = -ENODEV; + goto out; + } + +- len /= sizeof(u32); +- ++ naddr = of_bus_n_addr_cells(node); ++ nsize = of_bus_n_size_cells(node); + pna = of_n_addr_cells(node); ++ if ((len / sizeof(__be32)) % (pna + naddr + nsize)) { ++ ret = -EINVAL; ++ goto out; ++ } + + /* dma-ranges format: + * DMA addr : naddr cells +@@ -988,7 +980,7 @@ int of_dma_get_range(struct device_node + * size : nsize cells + */ + dmaaddr = of_read_number(ranges, naddr); +- *paddr = of_translate_dma_address(np, ranges); ++ *paddr = of_translate_dma_address(node, ranges + naddr); + if (*paddr == OF_BAD_ADDR) { + pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n", + dma_addr, np); diff --git a/target/linux/bcm27xx/patches-5.4/950-0444-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch b/target/linux/bcm27xx/patches-5.4/950-0444-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch deleted file mode 100644 index 28d1987a9c7..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0444-of-address-Translate-dma-ranges-for-parent-nodes-mis.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 39f5d9e883393e32938eac45b564f74afde8a942 Mon Sep 17 00:00:00 2001 -From: Rob Herring -Date: Wed, 4 Sep 2019 11:43:30 +0100 -Subject: [PATCH] of/address: Translate 'dma-ranges' for parent nodes - missing 'dma-ranges' - -commit 81db12ee15cb83926e290a8a3654a2dfebc80935 upstream. - -'dma-ranges' frequently exists without parent nodes having 'dma-ranges'. -While this is an error for 'ranges', this is fine because DMA capable -devices always have a translatable DMA address. Also, with no -'dma-ranges' at all, the assumption is that DMA addresses are 1:1 with -no restrictions unless perhaps the device itself has implicit -restrictions. - -Cc: Robin Murphy -Tested-by: Nicolas Saenz Julienne -Reviewed-by: Nicolas Saenz Julienne -Signed-off-by: Rob Herring ---- - drivers/of/address.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - ---- a/drivers/of/address.c -+++ b/drivers/of/address.c -@@ -519,9 +519,13 @@ static int of_translate_one(struct devic - * - * As far as we know, this damage only exists on Apple machines, so - * This code is only enabled on powerpc. --gcl -+ * -+ * This quirk also applies for 'dma-ranges' which frequently exist in -+ * child nodes without 'dma-ranges' in the parent nodes. --RobH - */ - ranges = of_get_property(parent, rprop, &rlen); -- if (ranges == NULL && !of_empty_ranges_quirk(parent)) { -+ if (ranges == NULL && !of_empty_ranges_quirk(parent) && -+ strcmp(rprop, "dma-ranges")) { - pr_debug("no ranges; cannot translate\n"); - return 1; - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0445-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch b/target/linux/bcm27xx/patches-5.4/950-0445-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch new file mode 100644 index 00000000000..a90e7f8587c --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0445-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch @@ -0,0 +1,30 @@ +From c17f622cbb33332a305ef383506740d3d01aa831 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Wed, 11 Sep 2019 20:25:43 +0200 +Subject: [PATCH] arm64: mm: use arm64_dma_phys_limit instead of + calling max_zone_dma_phys() + +commit ae970dc096b2d39f65f2e18d142e3978dc9ee1c7 upstream. + +By the time we call zones_sizes_init() arm64_dma_phys_limit already +contains the result of max_zone_dma_phys(). We use the variable instead +of calling the function directly to save some precious cpu time. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Catalin Marinas +Signed-off-by: Catalin Marinas +--- + arch/arm64/mm/init.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/arch/arm64/mm/init.c ++++ b/arch/arm64/mm/init.c +@@ -187,7 +187,7 @@ static void __init zone_sizes_init(unsig + unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; + + #ifdef CONFIG_ZONE_DMA32 +- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(max_zone_dma_phys()); ++ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit); + #endif + max_zone_pfns[ZONE_NORMAL] = max; + diff --git a/target/linux/bcm27xx/patches-5.4/950-0445-of-Make-of_dma_get_range-work-on-bus-nodes.patch b/target/linux/bcm27xx/patches-5.4/950-0445-of-Make-of_dma_get_range-work-on-bus-nodes.patch deleted file mode 100644 index 1cac2dfcd8a..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0445-of-Make-of_dma_get_range-work-on-bus-nodes.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 7631cb95056f03136c9e0a35484e8bebe7b52650 Mon Sep 17 00:00:00 2001 -From: Robin Murphy -Date: Wed, 3 Jul 2019 18:42:20 +0100 -Subject: [PATCH] of: Make of_dma_get_range() work on bus nodes - -commit 951d48855d86e72e0d6de73440fe09d363168064 upstream. - -Since the "dma-ranges" property is only valid for a node representing a -bus, of_dma_get_range() currently assumes the node passed in is a leaf -representing a device, and starts the walk from its parent. In cases -like PCI host controllers on typical FDT systems, however, where the PCI -endpoints are probed dynamically the initial leaf node represents the -'bus' itself, and this logic means we fail to consider any "dma-ranges" -describing the host bridge itself. Rework the logic such that -of_dma_get_range() also works correctly starting from a bus node -containing "dma-ranges". - -While this does mean "dma-ranges" could incorrectly be in a device leaf -node, there isn't really any way in this function to ensure that a leaf -node is or isn't a bus node. - -Signed-off-by: Robin Murphy -[robh: Allow for the bus child node to still be passed in] -Signed-off-by: Rob Herring -Reviewed-by: Robin Murphy -Reviewed-by: Nicolas Saenz Julienne -Tested-by: Nicolas Saenz Julienne ---- - drivers/of/address.c | 44 ++++++++++++++++++-------------------------- - 1 file changed, 18 insertions(+), 26 deletions(-) - ---- a/drivers/of/address.c -+++ b/drivers/of/address.c -@@ -940,47 +940,39 @@ int of_dma_get_range(struct device_node - const __be32 *ranges = NULL; - int len, naddr, nsize, pna; - int ret = 0; -+ bool found_dma_ranges = false; - u64 dmaaddr; - -- if (!node) -- return -EINVAL; -- -- while (1) { -- struct device_node *parent; -- -- naddr = of_n_addr_cells(node); -- nsize = of_n_size_cells(node); -- -- parent = __of_get_dma_parent(node); -- of_node_put(node); -- -- node = parent; -- if (!node) -- break; -- -+ while (node) { - ranges = of_get_property(node, "dma-ranges", &len); - - /* Ignore empty ranges, they imply no translation required */ - if (ranges && len > 0) - break; - -- /* -- * At least empty ranges has to be defined for parent node if -- * DMA is supported -- */ -- if (!ranges) -- break; -+ /* Once we find 'dma-ranges', then a missing one is an error */ -+ if (found_dma_ranges && !ranges) { -+ ret = -ENODEV; -+ goto out; -+ } -+ found_dma_ranges = true; -+ -+ node = of_get_next_dma_parent(node); - } - -- if (!ranges) { -+ if (!node || !ranges) { - pr_debug("no dma-ranges found for node(%pOF)\n", np); - ret = -ENODEV; - goto out; - } - -- len /= sizeof(u32); -- -+ naddr = of_bus_n_addr_cells(node); -+ nsize = of_bus_n_size_cells(node); - pna = of_n_addr_cells(node); -+ if ((len / sizeof(__be32)) % (pna + naddr + nsize)) { -+ ret = -EINVAL; -+ goto out; -+ } - - /* dma-ranges format: - * DMA addr : naddr cells -@@ -988,7 +980,7 @@ int of_dma_get_range(struct device_node - * size : nsize cells - */ - dmaaddr = of_read_number(ranges, naddr); -- *paddr = of_translate_dma_address(np, ranges); -+ *paddr = of_translate_dma_address(node, ranges + naddr); - if (*paddr == OF_BAD_ADDR) { - pr_err("translation of DMA address(%pad) to CPU address failed node(%pOF)\n", - dma_addr, np); diff --git a/target/linux/bcm27xx/patches-5.4/950-0446-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch b/target/linux/bcm27xx/patches-5.4/950-0446-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch deleted file mode 100644 index a90e7f8587c..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0446-arm64-mm-use-arm64_dma_phys_limit-instead-of-calling.patch +++ /dev/null @@ -1,30 +0,0 @@ -From c17f622cbb33332a305ef383506740d3d01aa831 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Wed, 11 Sep 2019 20:25:43 +0200 -Subject: [PATCH] arm64: mm: use arm64_dma_phys_limit instead of - calling max_zone_dma_phys() - -commit ae970dc096b2d39f65f2e18d142e3978dc9ee1c7 upstream. - -By the time we call zones_sizes_init() arm64_dma_phys_limit already -contains the result of max_zone_dma_phys(). We use the variable instead -of calling the function directly to save some precious cpu time. - -Signed-off-by: Nicolas Saenz Julienne -Reviewed-by: Catalin Marinas -Signed-off-by: Catalin Marinas ---- - arch/arm64/mm/init.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/arm64/mm/init.c -+++ b/arch/arm64/mm/init.c -@@ -187,7 +187,7 @@ static void __init zone_sizes_init(unsig - unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; - - #ifdef CONFIG_ZONE_DMA32 -- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(max_zone_dma_phys()); -+ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit); - #endif - max_zone_pfns[ZONE_NORMAL] = max; - diff --git a/target/linux/bcm27xx/patches-5.4/950-0446-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch b/target/linux/bcm27xx/patches-5.4/950-0446-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch new file mode 100644 index 00000000000..3039bfe822e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0446-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch @@ -0,0 +1,117 @@ +From 4d2bd7f66bac81b042afc2a6e742bd776a5a3938 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Wed, 11 Sep 2019 20:25:44 +0200 +Subject: [PATCH] arm64: rename variables used to calculate + ZONE_DMA32's size + +commit a573cdd7973dedd87e62196c400332896bb236c8 upstream. + +Let the name indicate that they are used to calculate ZONE_DMA32's size +as opposed to ZONE_DMA. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Catalin Marinas +Signed-off-by: Catalin Marinas +--- + arch/arm64/mm/init.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +--- a/arch/arm64/mm/init.c ++++ b/arch/arm64/mm/init.c +@@ -56,7 +56,7 @@ EXPORT_SYMBOL(physvirt_offset); + struct page *vmemmap __ro_after_init; + EXPORT_SYMBOL(vmemmap); + +-phys_addr_t arm64_dma_phys_limit __ro_after_init; ++phys_addr_t arm64_dma32_phys_limit __ro_after_init; + + #ifdef CONFIG_KEXEC_CORE + /* +@@ -174,7 +174,7 @@ static void __init reserve_elfcorehdr(vo + * currently assumes that for memory starting above 4G, 32-bit devices will + * use a DMA offset. + */ +-static phys_addr_t __init max_zone_dma_phys(void) ++static phys_addr_t __init max_zone_dma32_phys(void) + { + phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32); + return min(offset + (1ULL << 32), memblock_end_of_DRAM()); +@@ -187,7 +187,7 @@ static void __init zone_sizes_init(unsig + unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; + + #ifdef CONFIG_ZONE_DMA32 +- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit); ++ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit); + #endif + max_zone_pfns[ZONE_NORMAL] = max; + +@@ -200,16 +200,16 @@ static void __init zone_sizes_init(unsig + { + struct memblock_region *reg; + unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; +- unsigned long max_dma = min; ++ unsigned long max_dma32 = min; + + memset(zone_size, 0, sizeof(zone_size)); + + /* 4GB maximum for 32-bit only capable devices */ + #ifdef CONFIG_ZONE_DMA32 +- max_dma = PFN_DOWN(arm64_dma_phys_limit); +- zone_size[ZONE_DMA32] = max_dma - min; ++ max_dma32 = PFN_DOWN(arm64_dma32_phys_limit); ++ zone_size[ZONE_DMA32] = max_dma32 - min; + #endif +- zone_size[ZONE_NORMAL] = max - max_dma; ++ zone_size[ZONE_NORMAL] = max - max_dma32; + + memcpy(zhole_size, zone_size, sizeof(zhole_size)); + +@@ -221,14 +221,14 @@ static void __init zone_sizes_init(unsig + continue; + + #ifdef CONFIG_ZONE_DMA32 +- if (start < max_dma) { +- unsigned long dma_end = min(end, max_dma); ++ if (start < max_dma32) { ++ unsigned long dma_end = min(end, max_dma32); + zhole_size[ZONE_DMA32] -= dma_end - start; + } + #endif +- if (end > max_dma) { ++ if (end > max_dma32) { + unsigned long normal_end = min(end, max); +- unsigned long normal_start = max(start, max_dma); ++ unsigned long normal_start = max(start, max_dma32); + zhole_size[ZONE_NORMAL] -= normal_end - normal_start; + } + } +@@ -420,9 +420,9 @@ void __init arm64_memblock_init(void) + + /* 4GB maximum for 32-bit only capable devices */ + if (IS_ENABLED(CONFIG_ZONE_DMA32)) +- arm64_dma_phys_limit = max_zone_dma_phys(); ++ arm64_dma32_phys_limit = max_zone_dma32_phys(); + else +- arm64_dma_phys_limit = PHYS_MASK + 1; ++ arm64_dma32_phys_limit = PHYS_MASK + 1; + + reserve_crashkernel(); + +@@ -430,7 +430,7 @@ void __init arm64_memblock_init(void) + + high_memory = __va(memblock_end_of_DRAM() - 1) + 1; + +- dma_contiguous_reserve(arm64_dma_phys_limit); ++ dma_contiguous_reserve(arm64_dma32_phys_limit); + } + + void __init bootmem_init(void) +@@ -534,7 +534,7 @@ static void __init free_unused_memmap(vo + void __init mem_init(void) + { + if (swiotlb_force == SWIOTLB_FORCE || +- max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT)) ++ max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT)) + swiotlb_init(1); + else + swiotlb_force = SWIOTLB_NO_FORCE; diff --git a/target/linux/bcm27xx/patches-5.4/950-0447-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch b/target/linux/bcm27xx/patches-5.4/950-0447-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch deleted file mode 100644 index 3039bfe822e..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0447-arm64-rename-variables-used-to-calculate-ZONE_DMA32-.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 4d2bd7f66bac81b042afc2a6e742bd776a5a3938 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Wed, 11 Sep 2019 20:25:44 +0200 -Subject: [PATCH] arm64: rename variables used to calculate - ZONE_DMA32's size - -commit a573cdd7973dedd87e62196c400332896bb236c8 upstream. - -Let the name indicate that they are used to calculate ZONE_DMA32's size -as opposed to ZONE_DMA. - -Signed-off-by: Nicolas Saenz Julienne -Reviewed-by: Catalin Marinas -Signed-off-by: Catalin Marinas ---- - arch/arm64/mm/init.c | 30 +++++++++++++++--------------- - 1 file changed, 15 insertions(+), 15 deletions(-) - ---- a/arch/arm64/mm/init.c -+++ b/arch/arm64/mm/init.c -@@ -56,7 +56,7 @@ EXPORT_SYMBOL(physvirt_offset); - struct page *vmemmap __ro_after_init; - EXPORT_SYMBOL(vmemmap); - --phys_addr_t arm64_dma_phys_limit __ro_after_init; -+phys_addr_t arm64_dma32_phys_limit __ro_after_init; - - #ifdef CONFIG_KEXEC_CORE - /* -@@ -174,7 +174,7 @@ static void __init reserve_elfcorehdr(vo - * currently assumes that for memory starting above 4G, 32-bit devices will - * use a DMA offset. - */ --static phys_addr_t __init max_zone_dma_phys(void) -+static phys_addr_t __init max_zone_dma32_phys(void) - { - phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32); - return min(offset + (1ULL << 32), memblock_end_of_DRAM()); -@@ -187,7 +187,7 @@ static void __init zone_sizes_init(unsig - unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; - - #ifdef CONFIG_ZONE_DMA32 -- max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma_phys_limit); -+ max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit); - #endif - max_zone_pfns[ZONE_NORMAL] = max; - -@@ -200,16 +200,16 @@ static void __init zone_sizes_init(unsig - { - struct memblock_region *reg; - unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; -- unsigned long max_dma = min; -+ unsigned long max_dma32 = min; - - memset(zone_size, 0, sizeof(zone_size)); - - /* 4GB maximum for 32-bit only capable devices */ - #ifdef CONFIG_ZONE_DMA32 -- max_dma = PFN_DOWN(arm64_dma_phys_limit); -- zone_size[ZONE_DMA32] = max_dma - min; -+ max_dma32 = PFN_DOWN(arm64_dma32_phys_limit); -+ zone_size[ZONE_DMA32] = max_dma32 - min; - #endif -- zone_size[ZONE_NORMAL] = max - max_dma; -+ zone_size[ZONE_NORMAL] = max - max_dma32; - - memcpy(zhole_size, zone_size, sizeof(zhole_size)); - -@@ -221,14 +221,14 @@ static void __init zone_sizes_init(unsig - continue; - - #ifdef CONFIG_ZONE_DMA32 -- if (start < max_dma) { -- unsigned long dma_end = min(end, max_dma); -+ if (start < max_dma32) { -+ unsigned long dma_end = min(end, max_dma32); - zhole_size[ZONE_DMA32] -= dma_end - start; - } - #endif -- if (end > max_dma) { -+ if (end > max_dma32) { - unsigned long normal_end = min(end, max); -- unsigned long normal_start = max(start, max_dma); -+ unsigned long normal_start = max(start, max_dma32); - zhole_size[ZONE_NORMAL] -= normal_end - normal_start; - } - } -@@ -420,9 +420,9 @@ void __init arm64_memblock_init(void) - - /* 4GB maximum for 32-bit only capable devices */ - if (IS_ENABLED(CONFIG_ZONE_DMA32)) -- arm64_dma_phys_limit = max_zone_dma_phys(); -+ arm64_dma32_phys_limit = max_zone_dma32_phys(); - else -- arm64_dma_phys_limit = PHYS_MASK + 1; -+ arm64_dma32_phys_limit = PHYS_MASK + 1; - - reserve_crashkernel(); - -@@ -430,7 +430,7 @@ void __init arm64_memblock_init(void) - - high_memory = __va(memblock_end_of_DRAM() - 1) + 1; - -- dma_contiguous_reserve(arm64_dma_phys_limit); -+ dma_contiguous_reserve(arm64_dma32_phys_limit); - } - - void __init bootmem_init(void) -@@ -534,7 +534,7 @@ static void __init free_unused_memmap(vo - void __init mem_init(void) - { - if (swiotlb_force == SWIOTLB_FORCE || -- max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT)) -+ max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT)) - swiotlb_init(1); - else - swiotlb_force = SWIOTLB_NO_FORCE; diff --git a/target/linux/bcm27xx/patches-5.4/950-0447-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch b/target/linux/bcm27xx/patches-5.4/950-0447-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch new file mode 100644 index 00000000000..2397c71af7e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0447-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch @@ -0,0 +1,174 @@ +From 1fb65f4bc30fbadd0c89521985ff8142693c9631 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Wed, 11 Sep 2019 20:25:45 +0200 +Subject: [PATCH] arm64: use both ZONE_DMA and ZONE_DMA32 + +commit 1a8e1cef7603e218339ac63cb3178b25554524e5 upstream. + +So far all arm64 devices have supported 32 bit DMA masks for their +peripherals. This is not true anymore for the Raspberry Pi 4 as most of +it's peripherals can only address the first GB of memory on a total of +up to 4 GB. + +This goes against ZONE_DMA32's intent, as it's expected for ZONE_DMA32 +to be addressable with a 32 bit mask. So it was decided to re-introduce +ZONE_DMA in arm64. + +ZONE_DMA will contain the lower 1G of memory, which is currently the +memory area addressable by any peripheral on an arm64 device. +ZONE_DMA32 will contain the rest of the 32 bit addressable memory. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Catalin Marinas +Signed-off-by: Catalin Marinas +--- + arch/arm64/Kconfig | 4 +++ + arch/arm64/include/asm/page.h | 2 ++ + arch/arm64/mm/init.c | 54 +++++++++++++++++++++++++---------- + 3 files changed, 45 insertions(+), 15 deletions(-) + +--- a/arch/arm64/Kconfig ++++ b/arch/arm64/Kconfig +@@ -267,6 +267,10 @@ config GENERIC_CSUM + config GENERIC_CALIBRATE_DELAY + def_bool y + ++config ZONE_DMA ++ bool "Support DMA zone" if EXPERT ++ default y ++ + config ZONE_DMA32 + bool "Support DMA32 zone" if EXPERT + default y +--- a/arch/arm64/include/asm/page.h ++++ b/arch/arm64/include/asm/page.h +@@ -38,4 +38,6 @@ extern int pfn_valid(unsigned long); + + #include + ++#define ARCH_ZONE_DMA_BITS 30 ++ + #endif +--- a/arch/arm64/mm/init.c ++++ b/arch/arm64/mm/init.c +@@ -56,6 +56,13 @@ EXPORT_SYMBOL(physvirt_offset); + struct page *vmemmap __ro_after_init; + EXPORT_SYMBOL(vmemmap); + ++/* ++ * We create both ZONE_DMA and ZONE_DMA32. ZONE_DMA covers the first 1G of ++ * memory as some devices, namely the Raspberry Pi 4, have peripherals with ++ * this limited view of the memory. ZONE_DMA32 will cover the rest of the 32 ++ * bit addressable memory area. ++ */ ++phys_addr_t arm64_dma_phys_limit __ro_after_init; + phys_addr_t arm64_dma32_phys_limit __ro_after_init; + + #ifdef CONFIG_KEXEC_CORE +@@ -169,15 +176,16 @@ static void __init reserve_elfcorehdr(vo + { + } + #endif /* CONFIG_CRASH_DUMP */ ++ + /* +- * Return the maximum physical address for ZONE_DMA32 (DMA_BIT_MASK(32)). It +- * currently assumes that for memory starting above 4G, 32-bit devices will +- * use a DMA offset. ++ * Return the maximum physical address for a zone with a given address size ++ * limit. It currently assumes that for memory starting above 4G, 32-bit ++ * devices will use a DMA offset. + */ +-static phys_addr_t __init max_zone_dma32_phys(void) ++static phys_addr_t __init max_zone_phys(unsigned int zone_bits) + { +- phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32); +- return min(offset + (1ULL << 32), memblock_end_of_DRAM()); ++ phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, zone_bits); ++ return min(offset + (1ULL << zone_bits), memblock_end_of_DRAM()); + } + + #ifdef CONFIG_NUMA +@@ -186,6 +194,9 @@ static void __init zone_sizes_init(unsig + { + unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; + ++#ifdef CONFIG_ZONE_DMA ++ max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit); ++#endif + #ifdef CONFIG_ZONE_DMA32 + max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit); + #endif +@@ -201,13 +212,18 @@ static void __init zone_sizes_init(unsig + struct memblock_region *reg; + unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; + unsigned long max_dma32 = min; ++ unsigned long max_dma = min; + + memset(zone_size, 0, sizeof(zone_size)); + +- /* 4GB maximum for 32-bit only capable devices */ ++#ifdef CONFIG_ZONE_DMA ++ max_dma = PFN_DOWN(arm64_dma_phys_limit); ++ zone_size[ZONE_DMA] = max_dma - min; ++ max_dma32 = max_dma; ++#endif + #ifdef CONFIG_ZONE_DMA32 + max_dma32 = PFN_DOWN(arm64_dma32_phys_limit); +- zone_size[ZONE_DMA32] = max_dma32 - min; ++ zone_size[ZONE_DMA32] = max_dma32 - max_dma; + #endif + zone_size[ZONE_NORMAL] = max - max_dma32; + +@@ -219,11 +235,17 @@ static void __init zone_sizes_init(unsig + + if (start >= max) + continue; +- ++#ifdef CONFIG_ZONE_DMA ++ if (start < max_dma) { ++ unsigned long dma_end = min_not_zero(end, max_dma); ++ zhole_size[ZONE_DMA] -= dma_end - start; ++ } ++#endif + #ifdef CONFIG_ZONE_DMA32 + if (start < max_dma32) { +- unsigned long dma_end = min(end, max_dma32); +- zhole_size[ZONE_DMA32] -= dma_end - start; ++ unsigned long dma32_end = min(end, max_dma32); ++ unsigned long dma32_start = max(start, max_dma); ++ zhole_size[ZONE_DMA32] -= dma32_end - dma32_start; + } + #endif + if (end > max_dma32) { +@@ -418,9 +440,11 @@ void __init arm64_memblock_init(void) + + early_init_fdt_scan_reserved_mem(); + +- /* 4GB maximum for 32-bit only capable devices */ ++ if (IS_ENABLED(CONFIG_ZONE_DMA)) ++ arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS); ++ + if (IS_ENABLED(CONFIG_ZONE_DMA32)) +- arm64_dma32_phys_limit = max_zone_dma32_phys(); ++ arm64_dma32_phys_limit = max_zone_phys(32); + else + arm64_dma32_phys_limit = PHYS_MASK + 1; + +@@ -430,7 +454,7 @@ void __init arm64_memblock_init(void) + + high_memory = __va(memblock_end_of_DRAM() - 1) + 1; + +- dma_contiguous_reserve(arm64_dma32_phys_limit); ++ dma_contiguous_reserve(arm64_dma_phys_limit ? : arm64_dma32_phys_limit); + } + + void __init bootmem_init(void) +@@ -534,7 +558,7 @@ static void __init free_unused_memmap(vo + void __init mem_init(void) + { + if (swiotlb_force == SWIOTLB_FORCE || +- max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT)) ++ max_pfn > PFN_DOWN(arm64_dma_phys_limit ? : arm64_dma32_phys_limit)) + swiotlb_init(1); + else + swiotlb_force = SWIOTLB_NO_FORCE; diff --git a/target/linux/bcm27xx/patches-5.4/950-0448-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch b/target/linux/bcm27xx/patches-5.4/950-0448-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch deleted file mode 100644 index 2397c71af7e..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0448-arm64-use-both-ZONE_DMA-and-ZONE_DMA32.patch +++ /dev/null @@ -1,174 +0,0 @@ -From 1fb65f4bc30fbadd0c89521985ff8142693c9631 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Wed, 11 Sep 2019 20:25:45 +0200 -Subject: [PATCH] arm64: use both ZONE_DMA and ZONE_DMA32 - -commit 1a8e1cef7603e218339ac63cb3178b25554524e5 upstream. - -So far all arm64 devices have supported 32 bit DMA masks for their -peripherals. This is not true anymore for the Raspberry Pi 4 as most of -it's peripherals can only address the first GB of memory on a total of -up to 4 GB. - -This goes against ZONE_DMA32's intent, as it's expected for ZONE_DMA32 -to be addressable with a 32 bit mask. So it was decided to re-introduce -ZONE_DMA in arm64. - -ZONE_DMA will contain the lower 1G of memory, which is currently the -memory area addressable by any peripheral on an arm64 device. -ZONE_DMA32 will contain the rest of the 32 bit addressable memory. - -Signed-off-by: Nicolas Saenz Julienne -Reviewed-by: Catalin Marinas -Signed-off-by: Catalin Marinas ---- - arch/arm64/Kconfig | 4 +++ - arch/arm64/include/asm/page.h | 2 ++ - arch/arm64/mm/init.c | 54 +++++++++++++++++++++++++---------- - 3 files changed, 45 insertions(+), 15 deletions(-) - ---- a/arch/arm64/Kconfig -+++ b/arch/arm64/Kconfig -@@ -267,6 +267,10 @@ config GENERIC_CSUM - config GENERIC_CALIBRATE_DELAY - def_bool y - -+config ZONE_DMA -+ bool "Support DMA zone" if EXPERT -+ default y -+ - config ZONE_DMA32 - bool "Support DMA32 zone" if EXPERT - default y ---- a/arch/arm64/include/asm/page.h -+++ b/arch/arm64/include/asm/page.h -@@ -38,4 +38,6 @@ extern int pfn_valid(unsigned long); - - #include - -+#define ARCH_ZONE_DMA_BITS 30 -+ - #endif ---- a/arch/arm64/mm/init.c -+++ b/arch/arm64/mm/init.c -@@ -56,6 +56,13 @@ EXPORT_SYMBOL(physvirt_offset); - struct page *vmemmap __ro_after_init; - EXPORT_SYMBOL(vmemmap); - -+/* -+ * We create both ZONE_DMA and ZONE_DMA32. ZONE_DMA covers the first 1G of -+ * memory as some devices, namely the Raspberry Pi 4, have peripherals with -+ * this limited view of the memory. ZONE_DMA32 will cover the rest of the 32 -+ * bit addressable memory area. -+ */ -+phys_addr_t arm64_dma_phys_limit __ro_after_init; - phys_addr_t arm64_dma32_phys_limit __ro_after_init; - - #ifdef CONFIG_KEXEC_CORE -@@ -169,15 +176,16 @@ static void __init reserve_elfcorehdr(vo - { - } - #endif /* CONFIG_CRASH_DUMP */ -+ - /* -- * Return the maximum physical address for ZONE_DMA32 (DMA_BIT_MASK(32)). It -- * currently assumes that for memory starting above 4G, 32-bit devices will -- * use a DMA offset. -+ * Return the maximum physical address for a zone with a given address size -+ * limit. It currently assumes that for memory starting above 4G, 32-bit -+ * devices will use a DMA offset. - */ --static phys_addr_t __init max_zone_dma32_phys(void) -+static phys_addr_t __init max_zone_phys(unsigned int zone_bits) - { -- phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32); -- return min(offset + (1ULL << 32), memblock_end_of_DRAM()); -+ phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, zone_bits); -+ return min(offset + (1ULL << zone_bits), memblock_end_of_DRAM()); - } - - #ifdef CONFIG_NUMA -@@ -186,6 +194,9 @@ static void __init zone_sizes_init(unsig - { - unsigned long max_zone_pfns[MAX_NR_ZONES] = {0}; - -+#ifdef CONFIG_ZONE_DMA -+ max_zone_pfns[ZONE_DMA] = PFN_DOWN(arm64_dma_phys_limit); -+#endif - #ifdef CONFIG_ZONE_DMA32 - max_zone_pfns[ZONE_DMA32] = PFN_DOWN(arm64_dma32_phys_limit); - #endif -@@ -201,13 +212,18 @@ static void __init zone_sizes_init(unsig - struct memblock_region *reg; - unsigned long zone_size[MAX_NR_ZONES], zhole_size[MAX_NR_ZONES]; - unsigned long max_dma32 = min; -+ unsigned long max_dma = min; - - memset(zone_size, 0, sizeof(zone_size)); - -- /* 4GB maximum for 32-bit only capable devices */ -+#ifdef CONFIG_ZONE_DMA -+ max_dma = PFN_DOWN(arm64_dma_phys_limit); -+ zone_size[ZONE_DMA] = max_dma - min; -+ max_dma32 = max_dma; -+#endif - #ifdef CONFIG_ZONE_DMA32 - max_dma32 = PFN_DOWN(arm64_dma32_phys_limit); -- zone_size[ZONE_DMA32] = max_dma32 - min; -+ zone_size[ZONE_DMA32] = max_dma32 - max_dma; - #endif - zone_size[ZONE_NORMAL] = max - max_dma32; - -@@ -219,11 +235,17 @@ static void __init zone_sizes_init(unsig - - if (start >= max) - continue; -- -+#ifdef CONFIG_ZONE_DMA -+ if (start < max_dma) { -+ unsigned long dma_end = min_not_zero(end, max_dma); -+ zhole_size[ZONE_DMA] -= dma_end - start; -+ } -+#endif - #ifdef CONFIG_ZONE_DMA32 - if (start < max_dma32) { -- unsigned long dma_end = min(end, max_dma32); -- zhole_size[ZONE_DMA32] -= dma_end - start; -+ unsigned long dma32_end = min(end, max_dma32); -+ unsigned long dma32_start = max(start, max_dma); -+ zhole_size[ZONE_DMA32] -= dma32_end - dma32_start; - } - #endif - if (end > max_dma32) { -@@ -418,9 +440,11 @@ void __init arm64_memblock_init(void) - - early_init_fdt_scan_reserved_mem(); - -- /* 4GB maximum for 32-bit only capable devices */ -+ if (IS_ENABLED(CONFIG_ZONE_DMA)) -+ arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS); -+ - if (IS_ENABLED(CONFIG_ZONE_DMA32)) -- arm64_dma32_phys_limit = max_zone_dma32_phys(); -+ arm64_dma32_phys_limit = max_zone_phys(32); - else - arm64_dma32_phys_limit = PHYS_MASK + 1; - -@@ -430,7 +454,7 @@ void __init arm64_memblock_init(void) - - high_memory = __va(memblock_end_of_DRAM() - 1) + 1; - -- dma_contiguous_reserve(arm64_dma32_phys_limit); -+ dma_contiguous_reserve(arm64_dma_phys_limit ? : arm64_dma32_phys_limit); - } - - void __init bootmem_init(void) -@@ -534,7 +558,7 @@ static void __init free_unused_memmap(vo - void __init mem_init(void) - { - if (swiotlb_force == SWIOTLB_FORCE || -- max_pfn > (arm64_dma32_phys_limit >> PAGE_SHIFT)) -+ max_pfn > PFN_DOWN(arm64_dma_phys_limit ? : arm64_dma32_phys_limit)) - swiotlb_init(1); - else - swiotlb_force = SWIOTLB_NO_FORCE; diff --git a/target/linux/bcm27xx/patches-5.4/950-0448-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch b/target/linux/bcm27xx/patches-5.4/950-0448-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch new file mode 100644 index 00000000000..23811e0b6e9 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0448-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch @@ -0,0 +1,84 @@ +From 1c108eaeae73a504ac1b2d882bc1fefb91eecf17 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Wed, 11 Sep 2019 20:25:46 +0200 +Subject: [PATCH] mm: refresh ZONE_DMA and ZONE_DMA32 comments in 'enum + zone_type' + +commit 734f9246e791d8da278957b2c326d7709b2a97c0 upstream. + +These zones usage has evolved with time and the comments were outdated. +This joins both ZONE_DMA and ZONE_DMA32 explanation and gives up to date +examples on how they are used on different architectures. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Christoph Hellwig +Reviewed-by: Catalin Marinas +Signed-off-by: Catalin Marinas +--- + include/linux/mmzone.h | 45 ++++++++++++++++++++++++------------------ + 1 file changed, 26 insertions(+), 19 deletions(-) + +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -358,33 +358,40 @@ struct per_cpu_nodestat { + #endif /* !__GENERATING_BOUNDS.H */ + + enum zone_type { +-#ifdef CONFIG_ZONE_DMA + /* +- * ZONE_DMA is used when there are devices that are not able +- * to do DMA to all of addressable memory (ZONE_NORMAL). Then we +- * carve out the portion of memory that is needed for these devices. +- * The range is arch specific. +- * +- * Some examples +- * +- * Architecture Limit +- * --------------------------- +- * parisc, ia64, sparc <4G +- * s390, powerpc <2G +- * arm Various +- * alpha Unlimited or 0-16MB. ++ * ZONE_DMA and ZONE_DMA32 are used when there are peripherals not able ++ * to DMA to all of the addressable memory (ZONE_NORMAL). ++ * On architectures where this area covers the whole 32 bit address ++ * space ZONE_DMA32 is used. ZONE_DMA is left for the ones with smaller ++ * DMA addressing constraints. This distinction is important as a 32bit ++ * DMA mask is assumed when ZONE_DMA32 is defined. Some 64-bit ++ * platforms may need both zones as they support peripherals with ++ * different DMA addressing limitations. ++ * ++ * Some examples: ++ * ++ * - i386 and x86_64 have a fixed 16M ZONE_DMA and ZONE_DMA32 for the ++ * rest of the lower 4G. ++ * ++ * - arm only uses ZONE_DMA, the size, up to 4G, may vary depending on ++ * the specific device. ++ * ++ * - arm64 has a fixed 1G ZONE_DMA and ZONE_DMA32 for the rest of the ++ * lower 4G. ++ * ++ * - powerpc only uses ZONE_DMA, the size, up to 2G, may vary ++ * depending on the specific device. + * +- * i386, x86_64 and multiple other arches +- * <16M. ++ * - s390 uses ZONE_DMA fixed to the lower 2G. ++ * ++ * - ia64 and riscv only use ZONE_DMA32. ++ * ++ * - parisc uses neither. + */ ++#ifdef CONFIG_ZONE_DMA + ZONE_DMA, + #endif + #ifdef CONFIG_ZONE_DMA32 +- /* +- * x86_64 needs two ZONE_DMAs because it supports devices that are +- * only able to do DMA to the lower 16M but also 32 bit devices that +- * can only do DMA areas below 4G. +- */ + ZONE_DMA32, + #endif + /* diff --git a/target/linux/bcm27xx/patches-5.4/950-0449-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch b/target/linux/bcm27xx/patches-5.4/950-0449-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch deleted file mode 100644 index 23811e0b6e9..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0449-mm-refresh-ZONE_DMA-and-ZONE_DMA32-comments-in-enum-.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 1c108eaeae73a504ac1b2d882bc1fefb91eecf17 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Wed, 11 Sep 2019 20:25:46 +0200 -Subject: [PATCH] mm: refresh ZONE_DMA and ZONE_DMA32 comments in 'enum - zone_type' - -commit 734f9246e791d8da278957b2c326d7709b2a97c0 upstream. - -These zones usage has evolved with time and the comments were outdated. -This joins both ZONE_DMA and ZONE_DMA32 explanation and gives up to date -examples on how they are used on different architectures. - -Signed-off-by: Nicolas Saenz Julienne -Reviewed-by: Christoph Hellwig -Reviewed-by: Catalin Marinas -Signed-off-by: Catalin Marinas ---- - include/linux/mmzone.h | 45 ++++++++++++++++++++++++------------------ - 1 file changed, 26 insertions(+), 19 deletions(-) - ---- a/include/linux/mmzone.h -+++ b/include/linux/mmzone.h -@@ -358,33 +358,40 @@ struct per_cpu_nodestat { - #endif /* !__GENERATING_BOUNDS.H */ - - enum zone_type { --#ifdef CONFIG_ZONE_DMA - /* -- * ZONE_DMA is used when there are devices that are not able -- * to do DMA to all of addressable memory (ZONE_NORMAL). Then we -- * carve out the portion of memory that is needed for these devices. -- * The range is arch specific. -- * -- * Some examples -- * -- * Architecture Limit -- * --------------------------- -- * parisc, ia64, sparc <4G -- * s390, powerpc <2G -- * arm Various -- * alpha Unlimited or 0-16MB. -+ * ZONE_DMA and ZONE_DMA32 are used when there are peripherals not able -+ * to DMA to all of the addressable memory (ZONE_NORMAL). -+ * On architectures where this area covers the whole 32 bit address -+ * space ZONE_DMA32 is used. ZONE_DMA is left for the ones with smaller -+ * DMA addressing constraints. This distinction is important as a 32bit -+ * DMA mask is assumed when ZONE_DMA32 is defined. Some 64-bit -+ * platforms may need both zones as they support peripherals with -+ * different DMA addressing limitations. -+ * -+ * Some examples: -+ * -+ * - i386 and x86_64 have a fixed 16M ZONE_DMA and ZONE_DMA32 for the -+ * rest of the lower 4G. -+ * -+ * - arm only uses ZONE_DMA, the size, up to 4G, may vary depending on -+ * the specific device. -+ * -+ * - arm64 has a fixed 1G ZONE_DMA and ZONE_DMA32 for the rest of the -+ * lower 4G. -+ * -+ * - powerpc only uses ZONE_DMA, the size, up to 2G, may vary -+ * depending on the specific device. - * -- * i386, x86_64 and multiple other arches -- * <16M. -+ * - s390 uses ZONE_DMA fixed to the lower 2G. -+ * -+ * - ia64 and riscv only use ZONE_DMA32. -+ * -+ * - parisc uses neither. - */ -+#ifdef CONFIG_ZONE_DMA - ZONE_DMA, - #endif - #ifdef CONFIG_ZONE_DMA32 -- /* -- * x86_64 needs two ZONE_DMAs because it supports devices that are -- * only able to do DMA to the lower 16M but also 32 bit devices that -- * can only do DMA areas below 4G. -- */ - ZONE_DMA32, - #endif - /* diff --git a/target/linux/bcm27xx/patches-5.4/950-0449-resource-Add-a-resource_list_first_type-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0449-resource-Add-a-resource_list_first_type-helper.patch new file mode 100644 index 00000000000..c2c959a3c12 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0449-resource-Add-a-resource_list_first_type-helper.patch @@ -0,0 +1,36 @@ +From dacb1a46835914b8c3862db15726bcc0a68af8f5 Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Mon, 28 Oct 2019 11:32:32 -0500 +Subject: [PATCH] resource: Add a resource_list_first_type helper + +commit 494f8b10d832456a96be4ee7317425f6936cabc8 upstream. + +A common pattern is looping over a resource_list just to get a matching +entry with a specific type. Add resource_list_first_type() helper which +implements this. + +Signed-off-by: Rob Herring +Signed-off-by: Lorenzo Pieralisi +--- + include/linux/resource_ext.h | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +--- a/include/linux/resource_ext.h ++++ b/include/linux/resource_ext.h +@@ -66,4 +66,16 @@ resource_list_destroy_entry(struct resou + #define resource_list_for_each_entry_safe(entry, tmp, list) \ + list_for_each_entry_safe((entry), (tmp), (list), node) + ++static inline struct resource_entry * ++resource_list_first_type(struct list_head *list, unsigned long type) ++{ ++ struct resource_entry *entry; ++ ++ resource_list_for_each_entry(entry, list) { ++ if (resource_type(entry->res) == type) ++ return entry; ++ } ++ return NULL; ++} ++ + #endif /* _LINUX_RESOURCE_EXT_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0450-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch b/target/linux/bcm27xx/patches-5.4/950-0450-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch new file mode 100644 index 00000000000..5de73d37f7d --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0450-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch @@ -0,0 +1,195 @@ +From 78b03f0aef9f67c4db700ba5dc56e2c8f562d181 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Mon, 14 Oct 2019 20:31:03 +0200 +Subject: [PATCH] dma/direct: turn ARCH_ZONE_DMA_BITS into a variable + +commit 8b5369ea580964dbc982781bfb9fb93459fc5e8d upstream. + +Some architectures, notably ARM, are interested in tweaking this +depending on their runtime DMA addressing limitations. + +Acked-by: Christoph Hellwig +Signed-off-by: Nicolas Saenz Julienne +Signed-off-by: Catalin Marinas +--- + arch/arm64/include/asm/page.h | 2 -- + arch/arm64/mm/init.c | 9 +++++++-- + arch/powerpc/include/asm/page.h | 9 --------- + arch/powerpc/mm/mem.c | 20 +++++++++++++++----- + arch/s390/include/asm/page.h | 2 -- + arch/s390/mm/init.c | 1 + + include/linux/dma-direct.h | 2 ++ + kernel/dma/direct.c | 13 ++++++------- + 8 files changed, 31 insertions(+), 27 deletions(-) + +--- a/arch/arm64/include/asm/page.h ++++ b/arch/arm64/include/asm/page.h +@@ -38,6 +38,4 @@ extern int pfn_valid(unsigned long); + + #include + +-#define ARCH_ZONE_DMA_BITS 30 +- + #endif +--- a/arch/arm64/mm/init.c ++++ b/arch/arm64/mm/init.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -41,6 +42,8 @@ + #include + #include + ++#define ARM64_ZONE_DMA_BITS 30 ++ + /* + * We need to be able to catch inadvertent references to memstart_addr + * that occur (potentially in generic code) before arm64_memblock_init() +@@ -440,8 +443,10 @@ void __init arm64_memblock_init(void) + + early_init_fdt_scan_reserved_mem(); + +- if (IS_ENABLED(CONFIG_ZONE_DMA)) +- arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS); ++ if (IS_ENABLED(CONFIG_ZONE_DMA)) { ++ zone_dma_bits = ARM64_ZONE_DMA_BITS; ++ arm64_dma_phys_limit = max_zone_phys(ARM64_ZONE_DMA_BITS); ++ } + + if (IS_ENABLED(CONFIG_ZONE_DMA32)) + arm64_dma32_phys_limit = max_zone_phys(32); +--- a/arch/powerpc/include/asm/page.h ++++ b/arch/powerpc/include/asm/page.h +@@ -334,13 +334,4 @@ struct vm_area_struct; + #endif /* __ASSEMBLY__ */ + #include + +-/* +- * Allow 30-bit DMA for very limited Broadcom wifi chips on many powerbooks. +- */ +-#ifdef CONFIG_PPC32 +-#define ARCH_ZONE_DMA_BITS 30 +-#else +-#define ARCH_ZONE_DMA_BITS 31 +-#endif +- + #endif /* _ASM_POWERPC_PAGE_H */ +--- a/arch/powerpc/mm/mem.c ++++ b/arch/powerpc/mm/mem.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -223,10 +224,10 @@ static int __init mark_nonram_nosave(voi + * everything else. GFP_DMA32 page allocations automatically fall back to + * ZONE_DMA. + * +- * By using 31-bit unconditionally, we can exploit ARCH_ZONE_DMA_BITS to +- * inform the generic DMA mapping code. 32-bit only devices (if not handled +- * by an IOMMU anyway) will take a first dip into ZONE_NORMAL and get +- * otherwise served by ZONE_DMA. ++ * By using 31-bit unconditionally, we can exploit zone_dma_bits to inform the ++ * generic DMA mapping code. 32-bit only devices (if not handled by an IOMMU ++ * anyway) will take a first dip into ZONE_NORMAL and get otherwise served by ++ * ZONE_DMA. + */ + static unsigned long max_zone_pfns[MAX_NR_ZONES]; + +@@ -259,9 +260,18 @@ void __init paging_init(void) + printk(KERN_DEBUG "Memory hole size: %ldMB\n", + (long int)((top_of_ram - total_ram) >> 20)); + ++ /* ++ * Allow 30-bit DMA for very limited Broadcom wifi chips on many ++ * powerbooks. ++ */ ++ if (IS_ENABLED(CONFIG_PPC32)) ++ zone_dma_bits = 30; ++ else ++ zone_dma_bits = 31; ++ + #ifdef CONFIG_ZONE_DMA + max_zone_pfns[ZONE_DMA] = min(max_low_pfn, +- 1UL << (ARCH_ZONE_DMA_BITS - PAGE_SHIFT)); ++ 1UL << (zone_dma_bits - PAGE_SHIFT)); + #endif + max_zone_pfns[ZONE_NORMAL] = max_low_pfn; + #ifdef CONFIG_HIGHMEM +--- a/arch/s390/include/asm/page.h ++++ b/arch/s390/include/asm/page.h +@@ -179,8 +179,6 @@ static inline int devmem_is_allowed(unsi + #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +-#define ARCH_ZONE_DMA_BITS 31 +- + #include + #include + +--- a/arch/s390/mm/init.c ++++ b/arch/s390/mm/init.c +@@ -118,6 +118,7 @@ void __init paging_init(void) + + sparse_memory_present_with_active_regions(MAX_NUMNODES); + sparse_init(); ++ zone_dma_bits = 31; + memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); + max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS); + max_zone_pfns[ZONE_NORMAL] = max_low_pfn; +--- a/include/linux/dma-direct.h ++++ b/include/linux/dma-direct.h +@@ -8,6 +8,8 @@ + + static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); + ++extern unsigned int zone_dma_bits; ++ + #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA + #include + #else +--- a/kernel/dma/direct.c ++++ b/kernel/dma/direct.c +@@ -16,12 +16,11 @@ + #include + + /* +- * Most architectures use ZONE_DMA for the first 16 Megabytes, but +- * some use it for entirely different regions: ++ * Most architectures use ZONE_DMA for the first 16 Megabytes, but some use it ++ * it for entirely different regions. In that case the arch code needs to ++ * override the variable below for dma-direct to work properly. + */ +-#ifndef ARCH_ZONE_DMA_BITS +-#define ARCH_ZONE_DMA_BITS 24 +-#endif ++unsigned int zone_dma_bits __ro_after_init = 24; + + static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size) + { +@@ -69,7 +68,7 @@ static gfp_t __dma_direct_optimal_gfp_ma + * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding + * zones. + */ +- if (*phys_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS)) ++ if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits)) + return GFP_DMA; + if (*phys_mask <= DMA_BIT_MASK(32)) + return GFP_DMA32; +@@ -395,7 +394,7 @@ int dma_direct_supported(struct device * + u64 min_mask; + + if (IS_ENABLED(CONFIG_ZONE_DMA)) +- min_mask = DMA_BIT_MASK(ARCH_ZONE_DMA_BITS); ++ min_mask = DMA_BIT_MASK(zone_dma_bits); + else + min_mask = DMA_BIT_MASK(30); + diff --git a/target/linux/bcm27xx/patches-5.4/950-0450-resource-Add-a-resource_list_first_type-helper.patch b/target/linux/bcm27xx/patches-5.4/950-0450-resource-Add-a-resource_list_first_type-helper.patch deleted file mode 100644 index c2c959a3c12..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0450-resource-Add-a-resource_list_first_type-helper.patch +++ /dev/null @@ -1,36 +0,0 @@ -From dacb1a46835914b8c3862db15726bcc0a68af8f5 Mon Sep 17 00:00:00 2001 -From: Rob Herring -Date: Mon, 28 Oct 2019 11:32:32 -0500 -Subject: [PATCH] resource: Add a resource_list_first_type helper - -commit 494f8b10d832456a96be4ee7317425f6936cabc8 upstream. - -A common pattern is looping over a resource_list just to get a matching -entry with a specific type. Add resource_list_first_type() helper which -implements this. - -Signed-off-by: Rob Herring -Signed-off-by: Lorenzo Pieralisi ---- - include/linux/resource_ext.h | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - ---- a/include/linux/resource_ext.h -+++ b/include/linux/resource_ext.h -@@ -66,4 +66,16 @@ resource_list_destroy_entry(struct resou - #define resource_list_for_each_entry_safe(entry, tmp, list) \ - list_for_each_entry_safe((entry), (tmp), (list), node) - -+static inline struct resource_entry * -+resource_list_first_type(struct list_head *list, unsigned long type) -+{ -+ struct resource_entry *entry; -+ -+ resource_list_for_each_entry(entry, list) { -+ if (resource_type(entry->res) == type) -+ return entry; -+ } -+ return NULL; -+} -+ - #endif /* _LINUX_RESOURCE_EXT_H */ diff --git a/target/linux/bcm27xx/patches-5.4/950-0451-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch b/target/linux/bcm27xx/patches-5.4/950-0451-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch deleted file mode 100644 index 5de73d37f7d..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0451-dma-direct-turn-ARCH_ZONE_DMA_BITS-into-a-variable.patch +++ /dev/null @@ -1,195 +0,0 @@ -From 78b03f0aef9f67c4db700ba5dc56e2c8f562d181 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Mon, 14 Oct 2019 20:31:03 +0200 -Subject: [PATCH] dma/direct: turn ARCH_ZONE_DMA_BITS into a variable - -commit 8b5369ea580964dbc982781bfb9fb93459fc5e8d upstream. - -Some architectures, notably ARM, are interested in tweaking this -depending on their runtime DMA addressing limitations. - -Acked-by: Christoph Hellwig -Signed-off-by: Nicolas Saenz Julienne -Signed-off-by: Catalin Marinas ---- - arch/arm64/include/asm/page.h | 2 -- - arch/arm64/mm/init.c | 9 +++++++-- - arch/powerpc/include/asm/page.h | 9 --------- - arch/powerpc/mm/mem.c | 20 +++++++++++++++----- - arch/s390/include/asm/page.h | 2 -- - arch/s390/mm/init.c | 1 + - include/linux/dma-direct.h | 2 ++ - kernel/dma/direct.c | 13 ++++++------- - 8 files changed, 31 insertions(+), 27 deletions(-) - ---- a/arch/arm64/include/asm/page.h -+++ b/arch/arm64/include/asm/page.h -@@ -38,6 +38,4 @@ extern int pfn_valid(unsigned long); - - #include - --#define ARCH_ZONE_DMA_BITS 30 -- - #endif ---- a/arch/arm64/mm/init.c -+++ b/arch/arm64/mm/init.c -@@ -20,6 +20,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -41,6 +42,8 @@ - #include - #include - -+#define ARM64_ZONE_DMA_BITS 30 -+ - /* - * We need to be able to catch inadvertent references to memstart_addr - * that occur (potentially in generic code) before arm64_memblock_init() -@@ -440,8 +443,10 @@ void __init arm64_memblock_init(void) - - early_init_fdt_scan_reserved_mem(); - -- if (IS_ENABLED(CONFIG_ZONE_DMA)) -- arm64_dma_phys_limit = max_zone_phys(ARCH_ZONE_DMA_BITS); -+ if (IS_ENABLED(CONFIG_ZONE_DMA)) { -+ zone_dma_bits = ARM64_ZONE_DMA_BITS; -+ arm64_dma_phys_limit = max_zone_phys(ARM64_ZONE_DMA_BITS); -+ } - - if (IS_ENABLED(CONFIG_ZONE_DMA32)) - arm64_dma32_phys_limit = max_zone_phys(32); ---- a/arch/powerpc/include/asm/page.h -+++ b/arch/powerpc/include/asm/page.h -@@ -334,13 +334,4 @@ struct vm_area_struct; - #endif /* __ASSEMBLY__ */ - #include - --/* -- * Allow 30-bit DMA for very limited Broadcom wifi chips on many powerbooks. -- */ --#ifdef CONFIG_PPC32 --#define ARCH_ZONE_DMA_BITS 30 --#else --#define ARCH_ZONE_DMA_BITS 31 --#endif -- - #endif /* _ASM_POWERPC_PAGE_H */ ---- a/arch/powerpc/mm/mem.c -+++ b/arch/powerpc/mm/mem.c -@@ -31,6 +31,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -223,10 +224,10 @@ static int __init mark_nonram_nosave(voi - * everything else. GFP_DMA32 page allocations automatically fall back to - * ZONE_DMA. - * -- * By using 31-bit unconditionally, we can exploit ARCH_ZONE_DMA_BITS to -- * inform the generic DMA mapping code. 32-bit only devices (if not handled -- * by an IOMMU anyway) will take a first dip into ZONE_NORMAL and get -- * otherwise served by ZONE_DMA. -+ * By using 31-bit unconditionally, we can exploit zone_dma_bits to inform the -+ * generic DMA mapping code. 32-bit only devices (if not handled by an IOMMU -+ * anyway) will take a first dip into ZONE_NORMAL and get otherwise served by -+ * ZONE_DMA. - */ - static unsigned long max_zone_pfns[MAX_NR_ZONES]; - -@@ -259,9 +260,18 @@ void __init paging_init(void) - printk(KERN_DEBUG "Memory hole size: %ldMB\n", - (long int)((top_of_ram - total_ram) >> 20)); - -+ /* -+ * Allow 30-bit DMA for very limited Broadcom wifi chips on many -+ * powerbooks. -+ */ -+ if (IS_ENABLED(CONFIG_PPC32)) -+ zone_dma_bits = 30; -+ else -+ zone_dma_bits = 31; -+ - #ifdef CONFIG_ZONE_DMA - max_zone_pfns[ZONE_DMA] = min(max_low_pfn, -- 1UL << (ARCH_ZONE_DMA_BITS - PAGE_SHIFT)); -+ 1UL << (zone_dma_bits - PAGE_SHIFT)); - #endif - max_zone_pfns[ZONE_NORMAL] = max_low_pfn; - #ifdef CONFIG_HIGHMEM ---- a/arch/s390/include/asm/page.h -+++ b/arch/s390/include/asm/page.h -@@ -179,8 +179,6 @@ static inline int devmem_is_allowed(unsi - #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) - --#define ARCH_ZONE_DMA_BITS 31 -- - #include - #include - ---- a/arch/s390/mm/init.c -+++ b/arch/s390/mm/init.c -@@ -118,6 +118,7 @@ void __init paging_init(void) - - sparse_memory_present_with_active_regions(MAX_NUMNODES); - sparse_init(); -+ zone_dma_bits = 31; - memset(max_zone_pfns, 0, sizeof(max_zone_pfns)); - max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS); - max_zone_pfns[ZONE_NORMAL] = max_low_pfn; ---- a/include/linux/dma-direct.h -+++ b/include/linux/dma-direct.h -@@ -8,6 +8,8 @@ - - static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); - -+extern unsigned int zone_dma_bits; -+ - #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA - #include - #else ---- a/kernel/dma/direct.c -+++ b/kernel/dma/direct.c -@@ -16,12 +16,11 @@ - #include - - /* -- * Most architectures use ZONE_DMA for the first 16 Megabytes, but -- * some use it for entirely different regions: -+ * Most architectures use ZONE_DMA for the first 16 Megabytes, but some use it -+ * it for entirely different regions. In that case the arch code needs to -+ * override the variable below for dma-direct to work properly. - */ --#ifndef ARCH_ZONE_DMA_BITS --#define ARCH_ZONE_DMA_BITS 24 --#endif -+unsigned int zone_dma_bits __ro_after_init = 24; - - static void report_addr(struct device *dev, dma_addr_t dma_addr, size_t size) - { -@@ -69,7 +68,7 @@ static gfp_t __dma_direct_optimal_gfp_ma - * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding - * zones. - */ -- if (*phys_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS)) -+ if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits)) - return GFP_DMA; - if (*phys_mask <= DMA_BIT_MASK(32)) - return GFP_DMA32; -@@ -395,7 +394,7 @@ int dma_direct_supported(struct device * - u64 min_mask; - - if (IS_ENABLED(CONFIG_ZONE_DMA)) -- min_mask = DMA_BIT_MASK(ARCH_ZONE_DMA_BITS); -+ min_mask = DMA_BIT_MASK(zone_dma_bits); - else - min_mask = DMA_BIT_MASK(30); - diff --git a/target/linux/bcm27xx/patches-5.4/950-0451-x86-PCI-sta2x11-use-default-DMA-address-translation.patch b/target/linux/bcm27xx/patches-5.4/950-0451-x86-PCI-sta2x11-use-default-DMA-address-translation.patch new file mode 100644 index 00000000000..51fd4be35e1 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0451-x86-PCI-sta2x11-use-default-DMA-address-translation.patch @@ -0,0 +1,259 @@ +From 97a48106d1698038720495fdd49c491b283bf110 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Thu, 7 Nov 2019 16:06:45 +0100 +Subject: [PATCH] x86/PCI: sta2x11: use default DMA address translation + +commit e380a0394c36a3a878c858418d5dd7f5f195b6fc upstream. + +The devices found behind this PCIe chip have unusual DMA mapping +constraints as there is an AMBA interconnect placed in between them and +the different PCI endpoints. The offset between physical memory +addresses and AMBA's view is provided by reading a PCI config register, +which is saved and used whenever DMA mapping is needed. + +It turns out that this DMA setup can be represented by properly setting +'dma_pfn_offset', 'dma_bus_mask' and 'dma_mask' during the PCI device +enable fixup. And ultimately allows us to get rid of this device's +custom DMA functions. + +Aside from the code deletion and DMA setup, sta2x11_pdev_to_mapping() is +moved to avoid warnings whenever CONFIG_PM is not enabled. + +Signed-off-by: Nicolas Saenz Julienne +Signed-off-by: Christoph Hellwig +--- + arch/x86/Kconfig | 1 - + arch/x86/include/asm/device.h | 3 - + arch/x86/include/asm/dma-direct.h | 9 -- + arch/x86/pci/sta2x11-fixup.c | 135 ++++++------------------------ + 4 files changed, 26 insertions(+), 122 deletions(-) + delete mode 100644 arch/x86/include/asm/dma-direct.h + +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -708,7 +708,6 @@ config X86_SUPPORTS_MEMORY_FAILURE + config STA2X11 + bool "STA2X11 Companion Chip Support" + depends on X86_32_NON_STANDARD && PCI +- select ARCH_HAS_PHYS_TO_DMA + select SWIOTLB + select MFD_STA2X11 + select GPIOLIB +--- a/arch/x86/include/asm/device.h ++++ b/arch/x86/include/asm/device.h +@@ -6,9 +6,6 @@ struct dev_archdata { + #if defined(CONFIG_INTEL_IOMMU) || defined(CONFIG_AMD_IOMMU) + void *iommu; /* hook for IOMMU specific extension */ + #endif +-#ifdef CONFIG_STA2X11 +- bool is_sta2x11; +-#endif + }; + + #if defined(CONFIG_X86_DEV_DMA_OPS) && defined(CONFIG_PCI_DOMAINS) +--- a/arch/x86/include/asm/dma-direct.h ++++ /dev/null +@@ -1,9 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 */ +-#ifndef ASM_X86_DMA_DIRECT_H +-#define ASM_X86_DMA_DIRECT_H 1 +- +-bool dma_capable(struct device *dev, dma_addr_t addr, size_t size); +-dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr); +-phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr); +- +-#endif /* ASM_X86_DMA_DIRECT_H */ +--- a/arch/x86/pci/sta2x11-fixup.c ++++ b/arch/x86/pci/sta2x11-fixup.c +@@ -30,7 +30,6 @@ struct sta2x11_ahb_regs { /* saved durin + }; + + struct sta2x11_mapping { +- u32 amba_base; + int is_suspended; + struct sta2x11_ahb_regs regs[STA2X11_NR_FUNCS]; + }; +@@ -92,18 +91,6 @@ static int sta2x11_pdev_to_ep(struct pci + return pdev->bus->number - instance->bus0; + } + +-static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev) +-{ +- struct sta2x11_instance *instance; +- int ep; +- +- instance = sta2x11_pdev_to_instance(pdev); +- if (!instance) +- return NULL; +- ep = sta2x11_pdev_to_ep(pdev); +- return instance->map + ep; +-} +- + /* This is exported, as some devices need to access the MFD registers */ + struct sta2x11_instance *sta2x11_get_instance(struct pci_dev *pdev) + { +@@ -111,39 +98,6 @@ struct sta2x11_instance *sta2x11_get_ins + } + EXPORT_SYMBOL(sta2x11_get_instance); + +- +-/** +- * p2a - Translate physical address to STA2x11 AMBA address, +- * used for DMA transfers to STA2x11 +- * @p: Physical address +- * @pdev: PCI device (must be hosted within the connext) +- */ +-static dma_addr_t p2a(dma_addr_t p, struct pci_dev *pdev) +-{ +- struct sta2x11_mapping *map; +- dma_addr_t a; +- +- map = sta2x11_pdev_to_mapping(pdev); +- a = p + map->amba_base; +- return a; +-} +- +-/** +- * a2p - Translate STA2x11 AMBA address to physical address +- * used for DMA transfers from STA2x11 +- * @a: STA2x11 AMBA address +- * @pdev: PCI device (must be hosted within the connext) +- */ +-static dma_addr_t a2p(dma_addr_t a, struct pci_dev *pdev) +-{ +- struct sta2x11_mapping *map; +- dma_addr_t p; +- +- map = sta2x11_pdev_to_mapping(pdev); +- p = a - map->amba_base; +- return p; +-} +- + /* At setup time, we use our own ops if the device is a ConneXt one */ + static void sta2x11_setup_pdev(struct pci_dev *pdev) + { +@@ -151,9 +105,6 @@ static void sta2x11_setup_pdev(struct pc + + if (!instance) /* either a sta2x11 bridge or another ST device */ + return; +- pci_set_consistent_dma_mask(pdev, STA2X11_AMBA_SIZE - 1); +- pci_set_dma_mask(pdev, STA2X11_AMBA_SIZE - 1); +- pdev->dev.archdata.is_sta2x11 = true; + + /* We must enable all devices as master, for audio DMA to work */ + pci_set_master(pdev); +@@ -161,61 +112,6 @@ static void sta2x11_setup_pdev(struct pc + DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_setup_pdev); + + /* +- * The following three functions are exported (used in swiotlb: FIXME) +- */ +-/** +- * dma_capable - Check if device can manage DMA transfers (FIXME: kill it) +- * @dev: device for a PCI device +- * @addr: DMA address +- * @size: DMA size +- */ +-bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +-{ +- struct sta2x11_mapping *map; +- +- if (!dev->archdata.is_sta2x11) { +- if (!dev->dma_mask) +- return false; +- return addr + size - 1 <= *dev->dma_mask; +- } +- +- map = sta2x11_pdev_to_mapping(to_pci_dev(dev)); +- +- if (!map || (addr < map->amba_base)) +- return false; +- if (addr + size >= map->amba_base + STA2X11_AMBA_SIZE) { +- return false; +- } +- +- return true; +-} +- +-/** +- * __phys_to_dma - Return the DMA AMBA address used for this STA2x11 device +- * @dev: device for a PCI device +- * @paddr: Physical address +- */ +-dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) +-{ +- if (!dev->archdata.is_sta2x11) +- return paddr; +- return p2a(paddr, to_pci_dev(dev)); +-} +- +-/** +- * dma_to_phys - Return the physical address used for this STA2x11 DMA address +- * @dev: device for a PCI device +- * @daddr: STA2x11 AMBA DMA address +- */ +-phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr) +-{ +- if (!dev->archdata.is_sta2x11) +- return daddr; +- return a2p(daddr, to_pci_dev(dev)); +-} +- +- +-/* + * At boot we must set up the mappings for the pcie-to-amba bridge. + * It involves device access, and the same happens at suspend/resume time + */ +@@ -234,12 +130,22 @@ phys_addr_t __dma_to_phys(struct device + /* At probe time, enable mapping for each endpoint, using the pdev */ + static void sta2x11_map_ep(struct pci_dev *pdev) + { +- struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev); ++ struct sta2x11_instance *instance = sta2x11_pdev_to_instance(pdev); ++ struct device *dev = &pdev->dev; ++ u32 amba_base, max_amba_addr; + int i; + +- if (!map) ++ if (!instance) + return; +- pci_read_config_dword(pdev, AHB_BASE(0), &map->amba_base); ++ ++ pci_read_config_dword(pdev, AHB_BASE(0), &amba_base); ++ max_amba_addr = amba_base + STA2X11_AMBA_SIZE - 1; ++ ++ dev->dma_pfn_offset = PFN_DOWN(-amba_base); ++ ++ dev->bus_dma_mask = max_amba_addr; ++ pci_set_consistent_dma_mask(pdev, max_amba_addr); ++ pci_set_dma_mask(pdev, max_amba_addr); + + /* Configure AHB mapping */ + pci_write_config_dword(pdev, AHB_PEXLBASE(0), 0); +@@ -253,13 +159,24 @@ static void sta2x11_map_ep(struct pci_de + + dev_info(&pdev->dev, + "sta2x11: Map EP %i: AMBA address %#8x-%#8x\n", +- sta2x11_pdev_to_ep(pdev), map->amba_base, +- map->amba_base + STA2X11_AMBA_SIZE - 1); ++ sta2x11_pdev_to_ep(pdev), amba_base, max_amba_addr); + } + DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_map_ep); + + #ifdef CONFIG_PM /* Some register values must be saved and restored */ + ++static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev) ++{ ++ struct sta2x11_instance *instance; ++ int ep; ++ ++ instance = sta2x11_pdev_to_instance(pdev); ++ if (!instance) ++ return NULL; ++ ep = sta2x11_pdev_to_ep(pdev); ++ return instance->map + ep; ++} ++ + static void suspend_mapping(struct pci_dev *pdev) + { + struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0452-PCI-of-Add-inbound-resource-parsing-to-helpers.patch b/target/linux/bcm27xx/patches-5.4/950-0452-PCI-of-Add-inbound-resource-parsing-to-helpers.patch new file mode 100644 index 00000000000..0d74bc57ad5 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0452-PCI-of-Add-inbound-resource-parsing-to-helpers.patch @@ -0,0 +1,427 @@ +From 125a18144253e3a3f4bcad24484ee9b590dc47c6 Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Wed, 30 Oct 2019 17:30:57 -0500 +Subject: [PATCH] PCI: of: Add inbound resource parsing to helpers + +Extend devm_of_pci_get_host_bridge_resources() and +pci_parse_request_of_pci_ranges() helpers to also parse the inbound +addresses from DT 'dma-ranges' and populate a resource list with the +translated addresses. This will help ensure 'dma-ranges' is always +parsed in a consistent way. + +Tested-by: Srinath Mannam +Tested-by: Thomas Petazzoni # for AArdvark +Signed-off-by: Rob Herring +Signed-off-by: Lorenzo Pieralisi +Reviewed-by: Srinath Mannam +Reviewed-by: Andrew Murray +Acked-by: Gustavo Pimentel +Cc: Jingoo Han +Cc: Gustavo Pimentel +Cc: Lorenzo Pieralisi +Cc: Bjorn Helgaas +Cc: Thomas Petazzoni +Cc: Will Deacon +Cc: Linus Walleij +Cc: Toan Le +Cc: Ley Foon Tan +Cc: Tom Joseph +Cc: Ray Jui +Cc: Scott Branden +Cc: bcm-kernel-feedback-list@broadcom.com +Cc: Ryder Lee +Cc: Karthikeyan Mitran +Cc: Hou Zhiqiang +Cc: Simon Horman +Cc: Shawn Lin +Cc: Heiko Stuebner +Cc: Michal Simek +Cc: rfi@lists.rocketboards.org +Cc: linux-mediatek@lists.infradead.org +Cc: linux-renesas-soc@vger.kernel.org +Cc: linux-rockchip@lists.infradead.org +(cherry picked from commit 331f63457165a30c708280de2c77f1742c6351dc) +--- + .../pci/controller/dwc/pcie-designware-host.c | 8 +-- + drivers/pci/controller/pci-aardvark.c | 3 +- + drivers/pci/controller/pci-ftpci100.c | 4 +- + drivers/pci/controller/pci-host-common.c | 2 +- + drivers/pci/controller/pci-v3-semi.c | 8 +-- + drivers/pci/controller/pci-versatile.c | 3 +- + drivers/pci/controller/pci-xgene.c | 4 +- + drivers/pci/controller/pcie-altera.c | 5 +- + drivers/pci/controller/pcie-cadence-host.c | 2 +- + drivers/pci/controller/pcie-iproc-platform.c | 4 +- + drivers/pci/controller/pcie-mediatek.c | 4 +- + drivers/pci/controller/pcie-mobiveil.c | 4 +- + drivers/pci/controller/pcie-rcar.c | 3 +- + drivers/pci/controller/pcie-rockchip-host.c | 4 +- + drivers/pci/controller/pcie-xilinx-nwl.c | 4 +- + drivers/pci/controller/pcie-xilinx.c | 4 +- + drivers/pci/of.c | 61 ++++++++++++++++--- + drivers/pci/pci.h | 8 ++- + include/linux/pci.h | 9 ++- + 19 files changed, 96 insertions(+), 48 deletions(-) + +--- a/drivers/pci/controller/dwc/pcie-designware-host.c ++++ b/drivers/pci/controller/dwc/pcie-designware-host.c +@@ -343,12 +343,8 @@ int dw_pcie_host_init(struct pcie_port * + if (!bridge) + return -ENOMEM; + +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, +- &bridge->windows, &pp->io_base); +- if (ret) +- return ret; +- +- ret = devm_request_pci_bus_resources(dev, &bridge->windows); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (ret) + return ret; + +--- a/drivers/pci/controller/pci-aardvark.c ++++ b/drivers/pci/controller/pci-aardvark.c +@@ -1023,7 +1023,8 @@ static int advk_pcie_probe(struct platfo + return ret; + } + +- ret = advk_pcie_parse_request_of_pci_ranges(pcie); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, &bus); + if (ret) { + dev_err(dev, "Failed to parse resources\n"); + return ret; +--- a/drivers/pci/controller/pci-ftpci100.c ++++ b/drivers/pci/controller/pci-ftpci100.c +@@ -480,8 +480,8 @@ static int faraday_pci_probe(struct plat + if (IS_ERR(p->base)) + return PTR_ERR(p->base); + +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, +- &res, &io_base); ++ ret = pci_parse_request_of_pci_ranges(dev, &host->windows, ++ &host->dma_ranges, NULL); + if (ret) + return ret; + +--- a/drivers/pci/controller/pci-host-common.c ++++ b/drivers/pci/controller/pci-host-common.c +@@ -27,7 +27,7 @@ static struct pci_config_window *gen_pci + struct pci_config_window *cfg; + + /* Parse our PCI ranges and request their resources */ +- err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); ++ err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range); + if (err) + return ERR_PTR(err); + +--- a/drivers/pci/controller/pci-v3-semi.c ++++ b/drivers/pci/controller/pci-v3-semi.c +@@ -793,12 +793,8 @@ static int v3_pci_probe(struct platform_ + if (IS_ERR(v3->config_base)) + return PTR_ERR(v3->config_base); + +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, +- &io_base); +- if (ret) +- return ret; +- +- ret = devm_request_pci_bus_resources(dev, &res); ++ ret = pci_parse_request_of_pci_ranges(dev, &host->windows, ++ &host->dma_ranges, NULL); + if (ret) + return ret; + +--- a/drivers/pci/controller/pci-versatile.c ++++ b/drivers/pci/controller/pci-versatile.c +@@ -141,7 +141,8 @@ static int versatile_pci_probe(struct pl + if (IS_ERR(versatile_cfg_base[1])) + return PTR_ERR(versatile_cfg_base[1]); + +- ret = versatile_pci_parse_request_of_pci_ranges(dev, &pci_res); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ NULL, NULL); + if (ret) + return ret; + +--- a/drivers/pci/controller/pci-xgene.c ++++ b/drivers/pci/controller/pci-xgene.c +@@ -634,8 +634,8 @@ static int xgene_pcie_probe(struct platf + if (ret) + return ret; + +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, +- &iobase); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (ret) + return ret; + +--- a/drivers/pci/controller/pcie-altera.c ++++ b/drivers/pci/controller/pcie-altera.c +@@ -833,9 +833,8 @@ static int altera_pcie_probe(struct plat + return ret; + } + +- INIT_LIST_HEAD(&pcie->resources); +- +- ret = altera_pcie_parse_request_of_pci_ranges(pcie); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (ret) { + dev_err(dev, "Failed add resources\n"); + return ret; +--- a/drivers/pci/controller/pcie-cadence-host.c ++++ b/drivers/pci/controller/pcie-cadence-host.c +@@ -211,7 +211,7 @@ static int cdns_pcie_host_init(struct de + int err; + + /* Parse our PCI ranges and request their resources */ +- err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); ++ err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range); + if (err) + return err; + +--- a/drivers/pci/controller/pcie-iproc-platform.c ++++ b/drivers/pci/controller/pcie-iproc-platform.c +@@ -97,8 +97,8 @@ static int iproc_pcie_pltfm_probe(struct + if (IS_ERR(pcie->phy)) + return PTR_ERR(pcie->phy); + +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &resources, +- &iobase); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (ret) { + dev_err(dev, "unable to get PCI host bridge resources\n"); + return ret; +--- a/drivers/pci/controller/pcie-mediatek.c ++++ b/drivers/pci/controller/pcie-mediatek.c +@@ -1027,8 +1027,8 @@ static int mtk_pcie_setup(struct mtk_pci + resource_size_t io_base; + int err; + +- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, +- windows, &io_base); ++ err = pci_parse_request_of_pci_ranges(dev, windows, ++ &host->dma_ranges, &bus); + if (err) + return err; + +--- a/drivers/pci/controller/pcie-mobiveil.c ++++ b/drivers/pci/controller/pcie-mobiveil.c +@@ -883,8 +883,8 @@ static int mobiveil_pcie_probe(struct pl + INIT_LIST_HEAD(&pcie->resources); + + /* parse the host bridge base addresses from the device tree file */ +- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, +- &pcie->resources, &iobase); ++ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (ret) { + dev_err(dev, "Getting bridge resources failed\n"); + return ret; +--- a/drivers/pci/controller/pcie-rcar.c ++++ b/drivers/pci/controller/pcie-rcar.c +@@ -1143,7 +1143,8 @@ static int rcar_pcie_probe(struct platfo + pcie->dev = dev; + platform_set_drvdata(pdev, pcie); + +- err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL); ++ err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, ++ &bridge->dma_ranges, NULL); + if (err) + goto err_free_bridge; + +--- a/drivers/pci/controller/pcie-rockchip-host.c ++++ b/drivers/pci/controller/pcie-rockchip-host.c +@@ -995,8 +995,8 @@ static int rockchip_pcie_probe(struct pl + if (err < 0) + goto err_deinit_port; + +- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, +- &res, &io_base); ++ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, &bus_res); + if (err) + goto err_remove_irq_domain; + +--- a/drivers/pci/controller/pcie-xilinx-nwl.c ++++ b/drivers/pci/controller/pcie-xilinx-nwl.c +@@ -845,8 +845,8 @@ static int nwl_pcie_probe(struct platfor + return err; + } + +- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, +- &iobase); ++ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (err) { + dev_err(dev, "Getting bridge resources failed\n"); + return err; +--- a/drivers/pci/controller/pcie-xilinx.c ++++ b/drivers/pci/controller/pcie-xilinx.c +@@ -647,8 +647,8 @@ static int xilinx_pcie_probe(struct plat + return err; + } + +- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, +- &iobase); ++ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); + if (err) { + dev_err(dev, "Getting bridge resources failed\n"); + return err; +--- a/drivers/pci/of.c ++++ b/drivers/pci/of.c +@@ -257,14 +257,16 @@ EXPORT_SYMBOL_GPL(of_pci_check_probe_onl + */ + int devm_of_pci_get_host_bridge_resources(struct device *dev, + unsigned char busno, unsigned char bus_max, +- struct list_head *resources, resource_size_t *io_base) ++ struct list_head *resources, ++ struct list_head *ib_resources, ++ resource_size_t *io_base) + { + struct device_node *dev_node = dev->of_node; + struct resource *res, tmp_res; + struct resource *bus_range; + struct of_pci_range range; + struct of_pci_range_parser parser; +- char range_type[4]; ++ const char *range_type; + int err; + + if (io_base) +@@ -298,12 +300,12 @@ int devm_of_pci_get_host_bridge_resource + for_each_of_pci_range(&parser, &range) { + /* Read next ranges element */ + if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) +- snprintf(range_type, 4, " IO"); ++ range_type = "IO"; + else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) +- snprintf(range_type, 4, "MEM"); ++ range_type = "MEM"; + else +- snprintf(range_type, 4, "err"); +- dev_info(dev, " %s %#010llx..%#010llx -> %#010llx\n", ++ range_type = "err"; ++ dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n", + range_type, range.cpu_addr, + range.cpu_addr + range.size - 1, range.pci_addr); + +@@ -340,6 +342,48 @@ int devm_of_pci_get_host_bridge_resource + pci_add_resource_offset(resources, res, res->start - range.pci_addr); + } + ++ /* Check for dma-ranges property */ ++ if (!ib_resources) ++ return 0; ++ err = of_pci_dma_range_parser_init(&parser, dev_node); ++ if (err) ++ return 0; ++ ++ dev_dbg(dev, "Parsing dma-ranges property...\n"); ++ for_each_of_pci_range(&parser, &range) { ++ struct resource_entry *entry; ++ /* ++ * If we failed translation or got a zero-sized region ++ * then skip this range ++ */ ++ if (((range.flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) || ++ range.cpu_addr == OF_BAD_ADDR || range.size == 0) ++ continue; ++ ++ dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n", ++ "IB MEM", range.cpu_addr, ++ range.cpu_addr + range.size - 1, range.pci_addr); ++ ++ ++ err = of_pci_range_to_resource(&range, dev_node, &tmp_res); ++ if (err) ++ continue; ++ ++ res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL); ++ if (!res) { ++ err = -ENOMEM; ++ goto failed; ++ } ++ ++ /* Keep the resource list sorted */ ++ resource_list_for_each_entry(entry, ib_resources) ++ if (entry->res->start > res->start) ++ break; ++ ++ pci_add_resource_offset(&entry->node, res, ++ res->start - range.pci_addr); ++ } ++ + return 0; + + failed: +@@ -482,6 +526,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_and_map_p + + int pci_parse_request_of_pci_ranges(struct device *dev, + struct list_head *resources, ++ struct list_head *ib_resources, + struct resource **bus_range) + { + int err, res_valid = 0; +@@ -489,8 +534,10 @@ int pci_parse_request_of_pci_ranges(stru + struct resource_entry *win, *tmp; + + INIT_LIST_HEAD(resources); ++ if (ib_resources) ++ INIT_LIST_HEAD(ib_resources); + err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, resources, +- &iobase); ++ ib_resources, &iobase); + if (err) + return err; + +--- a/drivers/pci/pci.h ++++ b/drivers/pci/pci.h +@@ -636,11 +636,15 @@ static inline void pci_release_bus_of_no + #if defined(CONFIG_OF_ADDRESS) + int devm_of_pci_get_host_bridge_resources(struct device *dev, + unsigned char busno, unsigned char bus_max, +- struct list_head *resources, resource_size_t *io_base); ++ struct list_head *resources, ++ struct list_head *ib_resources, ++ resource_size_t *io_base); + #else + static inline int devm_of_pci_get_host_bridge_resources(struct device *dev, + unsigned char busno, unsigned char bus_max, +- struct list_head *resources, resource_size_t *io_base) ++ struct list_head *resources, ++ struct list_head *ib_resources, ++ resource_size_t *io_base) + { + return -EINVAL; + } +--- a/include/linux/pci.h ++++ b/include/linux/pci.h +@@ -2278,6 +2278,7 @@ struct irq_domain; + struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus); + int pci_parse_request_of_pci_ranges(struct device *dev, + struct list_head *resources, ++ struct list_head *ib_resources, + struct resource **bus_range); + + /* Arch may override this (weak) */ +@@ -2286,9 +2287,11 @@ struct device_node *pcibios_get_phb_of_n + #else /* CONFIG_OF */ + static inline struct irq_domain * + pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; } +-static inline int pci_parse_request_of_pci_ranges(struct device *dev, +- struct list_head *resources, +- struct resource **bus_range) ++static inline int ++pci_parse_request_of_pci_ranges(struct device *dev, ++ struct list_head *resources, ++ struct list_head *ib_resources, ++ struct resource **bus_range) + { + return -EINVAL; + } diff --git a/target/linux/bcm27xx/patches-5.4/950-0452-x86-PCI-sta2x11-use-default-DMA-address-translation.patch b/target/linux/bcm27xx/patches-5.4/950-0452-x86-PCI-sta2x11-use-default-DMA-address-translation.patch deleted file mode 100644 index 51fd4be35e1..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0452-x86-PCI-sta2x11-use-default-DMA-address-translation.patch +++ /dev/null @@ -1,259 +0,0 @@ -From 97a48106d1698038720495fdd49c491b283bf110 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Thu, 7 Nov 2019 16:06:45 +0100 -Subject: [PATCH] x86/PCI: sta2x11: use default DMA address translation - -commit e380a0394c36a3a878c858418d5dd7f5f195b6fc upstream. - -The devices found behind this PCIe chip have unusual DMA mapping -constraints as there is an AMBA interconnect placed in between them and -the different PCI endpoints. The offset between physical memory -addresses and AMBA's view is provided by reading a PCI config register, -which is saved and used whenever DMA mapping is needed. - -It turns out that this DMA setup can be represented by properly setting -'dma_pfn_offset', 'dma_bus_mask' and 'dma_mask' during the PCI device -enable fixup. And ultimately allows us to get rid of this device's -custom DMA functions. - -Aside from the code deletion and DMA setup, sta2x11_pdev_to_mapping() is -moved to avoid warnings whenever CONFIG_PM is not enabled. - -Signed-off-by: Nicolas Saenz Julienne -Signed-off-by: Christoph Hellwig ---- - arch/x86/Kconfig | 1 - - arch/x86/include/asm/device.h | 3 - - arch/x86/include/asm/dma-direct.h | 9 -- - arch/x86/pci/sta2x11-fixup.c | 135 ++++++------------------------ - 4 files changed, 26 insertions(+), 122 deletions(-) - delete mode 100644 arch/x86/include/asm/dma-direct.h - ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -708,7 +708,6 @@ config X86_SUPPORTS_MEMORY_FAILURE - config STA2X11 - bool "STA2X11 Companion Chip Support" - depends on X86_32_NON_STANDARD && PCI -- select ARCH_HAS_PHYS_TO_DMA - select SWIOTLB - select MFD_STA2X11 - select GPIOLIB ---- a/arch/x86/include/asm/device.h -+++ b/arch/x86/include/asm/device.h -@@ -6,9 +6,6 @@ struct dev_archdata { - #if defined(CONFIG_INTEL_IOMMU) || defined(CONFIG_AMD_IOMMU) - void *iommu; /* hook for IOMMU specific extension */ - #endif --#ifdef CONFIG_STA2X11 -- bool is_sta2x11; --#endif - }; - - #if defined(CONFIG_X86_DEV_DMA_OPS) && defined(CONFIG_PCI_DOMAINS) ---- a/arch/x86/include/asm/dma-direct.h -+++ /dev/null -@@ -1,9 +0,0 @@ --/* SPDX-License-Identifier: GPL-2.0 */ --#ifndef ASM_X86_DMA_DIRECT_H --#define ASM_X86_DMA_DIRECT_H 1 -- --bool dma_capable(struct device *dev, dma_addr_t addr, size_t size); --dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr); --phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr); -- --#endif /* ASM_X86_DMA_DIRECT_H */ ---- a/arch/x86/pci/sta2x11-fixup.c -+++ b/arch/x86/pci/sta2x11-fixup.c -@@ -30,7 +30,6 @@ struct sta2x11_ahb_regs { /* saved durin - }; - - struct sta2x11_mapping { -- u32 amba_base; - int is_suspended; - struct sta2x11_ahb_regs regs[STA2X11_NR_FUNCS]; - }; -@@ -92,18 +91,6 @@ static int sta2x11_pdev_to_ep(struct pci - return pdev->bus->number - instance->bus0; - } - --static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev) --{ -- struct sta2x11_instance *instance; -- int ep; -- -- instance = sta2x11_pdev_to_instance(pdev); -- if (!instance) -- return NULL; -- ep = sta2x11_pdev_to_ep(pdev); -- return instance->map + ep; --} -- - /* This is exported, as some devices need to access the MFD registers */ - struct sta2x11_instance *sta2x11_get_instance(struct pci_dev *pdev) - { -@@ -111,39 +98,6 @@ struct sta2x11_instance *sta2x11_get_ins - } - EXPORT_SYMBOL(sta2x11_get_instance); - -- --/** -- * p2a - Translate physical address to STA2x11 AMBA address, -- * used for DMA transfers to STA2x11 -- * @p: Physical address -- * @pdev: PCI device (must be hosted within the connext) -- */ --static dma_addr_t p2a(dma_addr_t p, struct pci_dev *pdev) --{ -- struct sta2x11_mapping *map; -- dma_addr_t a; -- -- map = sta2x11_pdev_to_mapping(pdev); -- a = p + map->amba_base; -- return a; --} -- --/** -- * a2p - Translate STA2x11 AMBA address to physical address -- * used for DMA transfers from STA2x11 -- * @a: STA2x11 AMBA address -- * @pdev: PCI device (must be hosted within the connext) -- */ --static dma_addr_t a2p(dma_addr_t a, struct pci_dev *pdev) --{ -- struct sta2x11_mapping *map; -- dma_addr_t p; -- -- map = sta2x11_pdev_to_mapping(pdev); -- p = a - map->amba_base; -- return p; --} -- - /* At setup time, we use our own ops if the device is a ConneXt one */ - static void sta2x11_setup_pdev(struct pci_dev *pdev) - { -@@ -151,9 +105,6 @@ static void sta2x11_setup_pdev(struct pc - - if (!instance) /* either a sta2x11 bridge or another ST device */ - return; -- pci_set_consistent_dma_mask(pdev, STA2X11_AMBA_SIZE - 1); -- pci_set_dma_mask(pdev, STA2X11_AMBA_SIZE - 1); -- pdev->dev.archdata.is_sta2x11 = true; - - /* We must enable all devices as master, for audio DMA to work */ - pci_set_master(pdev); -@@ -161,61 +112,6 @@ static void sta2x11_setup_pdev(struct pc - DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_setup_pdev); - - /* -- * The following three functions are exported (used in swiotlb: FIXME) -- */ --/** -- * dma_capable - Check if device can manage DMA transfers (FIXME: kill it) -- * @dev: device for a PCI device -- * @addr: DMA address -- * @size: DMA size -- */ --bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) --{ -- struct sta2x11_mapping *map; -- -- if (!dev->archdata.is_sta2x11) { -- if (!dev->dma_mask) -- return false; -- return addr + size - 1 <= *dev->dma_mask; -- } -- -- map = sta2x11_pdev_to_mapping(to_pci_dev(dev)); -- -- if (!map || (addr < map->amba_base)) -- return false; -- if (addr + size >= map->amba_base + STA2X11_AMBA_SIZE) { -- return false; -- } -- -- return true; --} -- --/** -- * __phys_to_dma - Return the DMA AMBA address used for this STA2x11 device -- * @dev: device for a PCI device -- * @paddr: Physical address -- */ --dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) --{ -- if (!dev->archdata.is_sta2x11) -- return paddr; -- return p2a(paddr, to_pci_dev(dev)); --} -- --/** -- * dma_to_phys - Return the physical address used for this STA2x11 DMA address -- * @dev: device for a PCI device -- * @daddr: STA2x11 AMBA DMA address -- */ --phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr) --{ -- if (!dev->archdata.is_sta2x11) -- return daddr; -- return a2p(daddr, to_pci_dev(dev)); --} -- -- --/* - * At boot we must set up the mappings for the pcie-to-amba bridge. - * It involves device access, and the same happens at suspend/resume time - */ -@@ -234,12 +130,22 @@ phys_addr_t __dma_to_phys(struct device - /* At probe time, enable mapping for each endpoint, using the pdev */ - static void sta2x11_map_ep(struct pci_dev *pdev) - { -- struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev); -+ struct sta2x11_instance *instance = sta2x11_pdev_to_instance(pdev); -+ struct device *dev = &pdev->dev; -+ u32 amba_base, max_amba_addr; - int i; - -- if (!map) -+ if (!instance) - return; -- pci_read_config_dword(pdev, AHB_BASE(0), &map->amba_base); -+ -+ pci_read_config_dword(pdev, AHB_BASE(0), &amba_base); -+ max_amba_addr = amba_base + STA2X11_AMBA_SIZE - 1; -+ -+ dev->dma_pfn_offset = PFN_DOWN(-amba_base); -+ -+ dev->bus_dma_mask = max_amba_addr; -+ pci_set_consistent_dma_mask(pdev, max_amba_addr); -+ pci_set_dma_mask(pdev, max_amba_addr); - - /* Configure AHB mapping */ - pci_write_config_dword(pdev, AHB_PEXLBASE(0), 0); -@@ -253,13 +159,24 @@ static void sta2x11_map_ep(struct pci_de - - dev_info(&pdev->dev, - "sta2x11: Map EP %i: AMBA address %#8x-%#8x\n", -- sta2x11_pdev_to_ep(pdev), map->amba_base, -- map->amba_base + STA2X11_AMBA_SIZE - 1); -+ sta2x11_pdev_to_ep(pdev), amba_base, max_amba_addr); - } - DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_map_ep); - - #ifdef CONFIG_PM /* Some register values must be saved and restored */ - -+static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev) -+{ -+ struct sta2x11_instance *instance; -+ int ep; -+ -+ instance = sta2x11_pdev_to_instance(pdev); -+ if (!instance) -+ return NULL; -+ ep = sta2x11_pdev_to_ep(pdev); -+ return instance->map + ep; -+} -+ - static void suspend_mapping(struct pci_dev *pdev) - { - struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0453-PCI-of-Add-inbound-resource-parsing-to-helpers.patch b/target/linux/bcm27xx/patches-5.4/950-0453-PCI-of-Add-inbound-resource-parsing-to-helpers.patch deleted file mode 100644 index 0d74bc57ad5..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0453-PCI-of-Add-inbound-resource-parsing-to-helpers.patch +++ /dev/null @@ -1,427 +0,0 @@ -From 125a18144253e3a3f4bcad24484ee9b590dc47c6 Mon Sep 17 00:00:00 2001 -From: Rob Herring -Date: Wed, 30 Oct 2019 17:30:57 -0500 -Subject: [PATCH] PCI: of: Add inbound resource parsing to helpers - -Extend devm_of_pci_get_host_bridge_resources() and -pci_parse_request_of_pci_ranges() helpers to also parse the inbound -addresses from DT 'dma-ranges' and populate a resource list with the -translated addresses. This will help ensure 'dma-ranges' is always -parsed in a consistent way. - -Tested-by: Srinath Mannam -Tested-by: Thomas Petazzoni # for AArdvark -Signed-off-by: Rob Herring -Signed-off-by: Lorenzo Pieralisi -Reviewed-by: Srinath Mannam -Reviewed-by: Andrew Murray -Acked-by: Gustavo Pimentel -Cc: Jingoo Han -Cc: Gustavo Pimentel -Cc: Lorenzo Pieralisi -Cc: Bjorn Helgaas -Cc: Thomas Petazzoni -Cc: Will Deacon -Cc: Linus Walleij -Cc: Toan Le -Cc: Ley Foon Tan -Cc: Tom Joseph -Cc: Ray Jui -Cc: Scott Branden -Cc: bcm-kernel-feedback-list@broadcom.com -Cc: Ryder Lee -Cc: Karthikeyan Mitran -Cc: Hou Zhiqiang -Cc: Simon Horman -Cc: Shawn Lin -Cc: Heiko Stuebner -Cc: Michal Simek -Cc: rfi@lists.rocketboards.org -Cc: linux-mediatek@lists.infradead.org -Cc: linux-renesas-soc@vger.kernel.org -Cc: linux-rockchip@lists.infradead.org -(cherry picked from commit 331f63457165a30c708280de2c77f1742c6351dc) ---- - .../pci/controller/dwc/pcie-designware-host.c | 8 +-- - drivers/pci/controller/pci-aardvark.c | 3 +- - drivers/pci/controller/pci-ftpci100.c | 4 +- - drivers/pci/controller/pci-host-common.c | 2 +- - drivers/pci/controller/pci-v3-semi.c | 8 +-- - drivers/pci/controller/pci-versatile.c | 3 +- - drivers/pci/controller/pci-xgene.c | 4 +- - drivers/pci/controller/pcie-altera.c | 5 +- - drivers/pci/controller/pcie-cadence-host.c | 2 +- - drivers/pci/controller/pcie-iproc-platform.c | 4 +- - drivers/pci/controller/pcie-mediatek.c | 4 +- - drivers/pci/controller/pcie-mobiveil.c | 4 +- - drivers/pci/controller/pcie-rcar.c | 3 +- - drivers/pci/controller/pcie-rockchip-host.c | 4 +- - drivers/pci/controller/pcie-xilinx-nwl.c | 4 +- - drivers/pci/controller/pcie-xilinx.c | 4 +- - drivers/pci/of.c | 61 ++++++++++++++++--- - drivers/pci/pci.h | 8 ++- - include/linux/pci.h | 9 ++- - 19 files changed, 96 insertions(+), 48 deletions(-) - ---- a/drivers/pci/controller/dwc/pcie-designware-host.c -+++ b/drivers/pci/controller/dwc/pcie-designware-host.c -@@ -343,12 +343,8 @@ int dw_pcie_host_init(struct pcie_port * - if (!bridge) - return -ENOMEM; - -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, -- &bridge->windows, &pp->io_base); -- if (ret) -- return ret; -- -- ret = devm_request_pci_bus_resources(dev, &bridge->windows); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (ret) - return ret; - ---- a/drivers/pci/controller/pci-aardvark.c -+++ b/drivers/pci/controller/pci-aardvark.c -@@ -1023,7 +1023,8 @@ static int advk_pcie_probe(struct platfo - return ret; - } - -- ret = advk_pcie_parse_request_of_pci_ranges(pcie); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, &bus); - if (ret) { - dev_err(dev, "Failed to parse resources\n"); - return ret; ---- a/drivers/pci/controller/pci-ftpci100.c -+++ b/drivers/pci/controller/pci-ftpci100.c -@@ -480,8 +480,8 @@ static int faraday_pci_probe(struct plat - if (IS_ERR(p->base)) - return PTR_ERR(p->base); - -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, -- &res, &io_base); -+ ret = pci_parse_request_of_pci_ranges(dev, &host->windows, -+ &host->dma_ranges, NULL); - if (ret) - return ret; - ---- a/drivers/pci/controller/pci-host-common.c -+++ b/drivers/pci/controller/pci-host-common.c -@@ -27,7 +27,7 @@ static struct pci_config_window *gen_pci - struct pci_config_window *cfg; - - /* Parse our PCI ranges and request their resources */ -- err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); -+ err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range); - if (err) - return ERR_PTR(err); - ---- a/drivers/pci/controller/pci-v3-semi.c -+++ b/drivers/pci/controller/pci-v3-semi.c -@@ -793,12 +793,8 @@ static int v3_pci_probe(struct platform_ - if (IS_ERR(v3->config_base)) - return PTR_ERR(v3->config_base); - -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, -- &io_base); -- if (ret) -- return ret; -- -- ret = devm_request_pci_bus_resources(dev, &res); -+ ret = pci_parse_request_of_pci_ranges(dev, &host->windows, -+ &host->dma_ranges, NULL); - if (ret) - return ret; - ---- a/drivers/pci/controller/pci-versatile.c -+++ b/drivers/pci/controller/pci-versatile.c -@@ -141,7 +141,8 @@ static int versatile_pci_probe(struct pl - if (IS_ERR(versatile_cfg_base[1])) - return PTR_ERR(versatile_cfg_base[1]); - -- ret = versatile_pci_parse_request_of_pci_ranges(dev, &pci_res); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ NULL, NULL); - if (ret) - return ret; - ---- a/drivers/pci/controller/pci-xgene.c -+++ b/drivers/pci/controller/pci-xgene.c -@@ -634,8 +634,8 @@ static int xgene_pcie_probe(struct platf - if (ret) - return ret; - -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, -- &iobase); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (ret) - return ret; - ---- a/drivers/pci/controller/pcie-altera.c -+++ b/drivers/pci/controller/pcie-altera.c -@@ -833,9 +833,8 @@ static int altera_pcie_probe(struct plat - return ret; - } - -- INIT_LIST_HEAD(&pcie->resources); -- -- ret = altera_pcie_parse_request_of_pci_ranges(pcie); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (ret) { - dev_err(dev, "Failed add resources\n"); - return ret; ---- a/drivers/pci/controller/pcie-cadence-host.c -+++ b/drivers/pci/controller/pcie-cadence-host.c -@@ -211,7 +211,7 @@ static int cdns_pcie_host_init(struct de - int err; - - /* Parse our PCI ranges and request their resources */ -- err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range); -+ err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range); - if (err) - return err; - ---- a/drivers/pci/controller/pcie-iproc-platform.c -+++ b/drivers/pci/controller/pcie-iproc-platform.c -@@ -97,8 +97,8 @@ static int iproc_pcie_pltfm_probe(struct - if (IS_ERR(pcie->phy)) - return PTR_ERR(pcie->phy); - -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &resources, -- &iobase); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (ret) { - dev_err(dev, "unable to get PCI host bridge resources\n"); - return ret; ---- a/drivers/pci/controller/pcie-mediatek.c -+++ b/drivers/pci/controller/pcie-mediatek.c -@@ -1027,8 +1027,8 @@ static int mtk_pcie_setup(struct mtk_pci - resource_size_t io_base; - int err; - -- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, -- windows, &io_base); -+ err = pci_parse_request_of_pci_ranges(dev, windows, -+ &host->dma_ranges, &bus); - if (err) - return err; - ---- a/drivers/pci/controller/pcie-mobiveil.c -+++ b/drivers/pci/controller/pcie-mobiveil.c -@@ -883,8 +883,8 @@ static int mobiveil_pcie_probe(struct pl - INIT_LIST_HEAD(&pcie->resources); - - /* parse the host bridge base addresses from the device tree file */ -- ret = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, -- &pcie->resources, &iobase); -+ ret = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (ret) { - dev_err(dev, "Getting bridge resources failed\n"); - return ret; ---- a/drivers/pci/controller/pcie-rcar.c -+++ b/drivers/pci/controller/pcie-rcar.c -@@ -1143,7 +1143,8 @@ static int rcar_pcie_probe(struct platfo - pcie->dev = dev; - platform_set_drvdata(pdev, pcie); - -- err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, NULL); -+ err = pci_parse_request_of_pci_ranges(dev, &pcie->resources, -+ &bridge->dma_ranges, NULL); - if (err) - goto err_free_bridge; - ---- a/drivers/pci/controller/pcie-rockchip-host.c -+++ b/drivers/pci/controller/pcie-rockchip-host.c -@@ -995,8 +995,8 @@ static int rockchip_pcie_probe(struct pl - if (err < 0) - goto err_deinit_port; - -- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, -- &res, &io_base); -+ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, &bus_res); - if (err) - goto err_remove_irq_domain; - ---- a/drivers/pci/controller/pcie-xilinx-nwl.c -+++ b/drivers/pci/controller/pcie-xilinx-nwl.c -@@ -845,8 +845,8 @@ static int nwl_pcie_probe(struct platfor - return err; - } - -- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, -- &iobase); -+ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (err) { - dev_err(dev, "Getting bridge resources failed\n"); - return err; ---- a/drivers/pci/controller/pcie-xilinx.c -+++ b/drivers/pci/controller/pcie-xilinx.c -@@ -647,8 +647,8 @@ static int xilinx_pcie_probe(struct plat - return err; - } - -- err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, &res, -- &iobase); -+ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); - if (err) { - dev_err(dev, "Getting bridge resources failed\n"); - return err; ---- a/drivers/pci/of.c -+++ b/drivers/pci/of.c -@@ -257,14 +257,16 @@ EXPORT_SYMBOL_GPL(of_pci_check_probe_onl - */ - int devm_of_pci_get_host_bridge_resources(struct device *dev, - unsigned char busno, unsigned char bus_max, -- struct list_head *resources, resource_size_t *io_base) -+ struct list_head *resources, -+ struct list_head *ib_resources, -+ resource_size_t *io_base) - { - struct device_node *dev_node = dev->of_node; - struct resource *res, tmp_res; - struct resource *bus_range; - struct of_pci_range range; - struct of_pci_range_parser parser; -- char range_type[4]; -+ const char *range_type; - int err; - - if (io_base) -@@ -298,12 +300,12 @@ int devm_of_pci_get_host_bridge_resource - for_each_of_pci_range(&parser, &range) { - /* Read next ranges element */ - if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO) -- snprintf(range_type, 4, " IO"); -+ range_type = "IO"; - else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM) -- snprintf(range_type, 4, "MEM"); -+ range_type = "MEM"; - else -- snprintf(range_type, 4, "err"); -- dev_info(dev, " %s %#010llx..%#010llx -> %#010llx\n", -+ range_type = "err"; -+ dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n", - range_type, range.cpu_addr, - range.cpu_addr + range.size - 1, range.pci_addr); - -@@ -340,6 +342,48 @@ int devm_of_pci_get_host_bridge_resource - pci_add_resource_offset(resources, res, res->start - range.pci_addr); - } - -+ /* Check for dma-ranges property */ -+ if (!ib_resources) -+ return 0; -+ err = of_pci_dma_range_parser_init(&parser, dev_node); -+ if (err) -+ return 0; -+ -+ dev_dbg(dev, "Parsing dma-ranges property...\n"); -+ for_each_of_pci_range(&parser, &range) { -+ struct resource_entry *entry; -+ /* -+ * If we failed translation or got a zero-sized region -+ * then skip this range -+ */ -+ if (((range.flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM) || -+ range.cpu_addr == OF_BAD_ADDR || range.size == 0) -+ continue; -+ -+ dev_info(dev, " %6s %#012llx..%#012llx -> %#012llx\n", -+ "IB MEM", range.cpu_addr, -+ range.cpu_addr + range.size - 1, range.pci_addr); -+ -+ -+ err = of_pci_range_to_resource(&range, dev_node, &tmp_res); -+ if (err) -+ continue; -+ -+ res = devm_kmemdup(dev, &tmp_res, sizeof(tmp_res), GFP_KERNEL); -+ if (!res) { -+ err = -ENOMEM; -+ goto failed; -+ } -+ -+ /* Keep the resource list sorted */ -+ resource_list_for_each_entry(entry, ib_resources) -+ if (entry->res->start > res->start) -+ break; -+ -+ pci_add_resource_offset(&entry->node, res, -+ res->start - range.pci_addr); -+ } -+ - return 0; - - failed: -@@ -482,6 +526,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_and_map_p - - int pci_parse_request_of_pci_ranges(struct device *dev, - struct list_head *resources, -+ struct list_head *ib_resources, - struct resource **bus_range) - { - int err, res_valid = 0; -@@ -489,8 +534,10 @@ int pci_parse_request_of_pci_ranges(stru - struct resource_entry *win, *tmp; - - INIT_LIST_HEAD(resources); -+ if (ib_resources) -+ INIT_LIST_HEAD(ib_resources); - err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, resources, -- &iobase); -+ ib_resources, &iobase); - if (err) - return err; - ---- a/drivers/pci/pci.h -+++ b/drivers/pci/pci.h -@@ -636,11 +636,15 @@ static inline void pci_release_bus_of_no - #if defined(CONFIG_OF_ADDRESS) - int devm_of_pci_get_host_bridge_resources(struct device *dev, - unsigned char busno, unsigned char bus_max, -- struct list_head *resources, resource_size_t *io_base); -+ struct list_head *resources, -+ struct list_head *ib_resources, -+ resource_size_t *io_base); - #else - static inline int devm_of_pci_get_host_bridge_resources(struct device *dev, - unsigned char busno, unsigned char bus_max, -- struct list_head *resources, resource_size_t *io_base) -+ struct list_head *resources, -+ struct list_head *ib_resources, -+ resource_size_t *io_base) - { - return -EINVAL; - } ---- a/include/linux/pci.h -+++ b/include/linux/pci.h -@@ -2278,6 +2278,7 @@ struct irq_domain; - struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus); - int pci_parse_request_of_pci_ranges(struct device *dev, - struct list_head *resources, -+ struct list_head *ib_resources, - struct resource **bus_range); - - /* Arch may override this (weak) */ -@@ -2286,9 +2287,11 @@ struct device_node *pcibios_get_phb_of_n - #else /* CONFIG_OF */ - static inline struct irq_domain * - pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; } --static inline int pci_parse_request_of_pci_ranges(struct device *dev, -- struct list_head *resources, -- struct resource **bus_range) -+static inline int -+pci_parse_request_of_pci_ranges(struct device *dev, -+ struct list_head *resources, -+ struct list_head *ib_resources, -+ struct resource **bus_range) - { - return -EINVAL; - } diff --git a/target/linux/bcm27xx/patches-5.4/950-0453-dma-direct-unify-the-dma_capable-definitions.patch b/target/linux/bcm27xx/patches-5.4/950-0453-dma-direct-unify-the-dma_capable-definitions.patch new file mode 100644 index 00000000000..d115f0eb809 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0453-dma-direct-unify-the-dma_capable-definitions.patch @@ -0,0 +1,103 @@ +From 203e0c39b262fc1da6f976495c32ec38ea93a137 Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Tue, 12 Nov 2019 17:06:04 +0100 +Subject: [PATCH] dma-direct: unify the dma_capable definitions + +commit 130c1ccbf55330b55e82612a6e54eebb82c9d746 upstream. + +Currently each architectures that wants to override dma_to_phys and +phys_to_dma also has to provide dma_capable. But there isn't really +any good reason for that. powerpc and mips just have copies of the +generic one minus the latests fix, and the arm one was the inspiration +for said fix, but misses the bus_dma_mask handling. +Make all architectures use the generic version instead. + +Signed-off-by: Christoph Hellwig +Acked-by: Michael Ellerman (powerpc) +Reviewed-by: Nicolas Saenz Julienne +--- + arch/arm/include/asm/dma-direct.h | 19 ------------------- + arch/mips/include/asm/dma-direct.h | 8 -------- + arch/powerpc/include/asm/dma-direct.h | 9 --------- + include/linux/dma-direct.h | 2 +- + 4 files changed, 1 insertion(+), 37 deletions(-) + +--- a/arch/arm/include/asm/dma-direct.h ++++ b/arch/arm/include/asm/dma-direct.h +@@ -14,23 +14,4 @@ static inline phys_addr_t __dma_to_phys( + return __pfn_to_phys(dma_to_pfn(dev, dev_addr)) + offset; + } + +-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +-{ +- u64 limit, mask; +- +- if (!dev->dma_mask) +- return 0; +- +- mask = *dev->dma_mask; +- +- limit = (mask + 1) & ~mask; +- if (limit && size > limit) +- return 0; +- +- if ((addr | (addr + size - 1)) & ~mask) +- return 0; +- +- return 1; +-} +- + #endif /* ASM_ARM_DMA_DIRECT_H */ +--- a/arch/mips/include/asm/dma-direct.h ++++ b/arch/mips/include/asm/dma-direct.h +@@ -2,14 +2,6 @@ + #ifndef _MIPS_DMA_DIRECT_H + #define _MIPS_DMA_DIRECT_H 1 + +-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +-{ +- if (!dev->dma_mask) +- return false; +- +- return addr + size - 1 <= *dev->dma_mask; +-} +- + dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr); + phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr); + +--- a/arch/powerpc/include/asm/dma-direct.h ++++ b/arch/powerpc/include/asm/dma-direct.h +@@ -2,15 +2,6 @@ + #ifndef ASM_POWERPC_DMA_DIRECT_H + #define ASM_POWERPC_DMA_DIRECT_H 1 + +-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +-{ +- if (!dev->dma_mask) +- return false; +- +- return addr + size - 1 <= +- min_not_zero(*dev->dma_mask, dev->bus_dma_mask); +-} +- + static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) + { + if (!dev) +--- a/include/linux/dma-direct.h ++++ b/include/linux/dma-direct.h +@@ -26,6 +26,7 @@ static inline phys_addr_t __dma_to_phys( + + return paddr + ((phys_addr_t)dev->dma_pfn_offset << PAGE_SHIFT); + } ++#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ + + static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) + { +@@ -40,7 +41,6 @@ static inline bool dma_capable(struct de + + return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); + } +-#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ + + #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED + bool force_dma_unencrypted(struct device *dev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0454-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch b/target/linux/bcm27xx/patches-5.4/950-0454-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch new file mode 100644 index 00000000000..a98f1d38527 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0454-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch @@ -0,0 +1,69 @@ +From a3794022e928547de664abd03b61280163c7f13a Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Tue, 12 Nov 2019 17:07:43 +0100 +Subject: [PATCH] dma-direct: avoid a forward declaration for + phys_to_dma + +Move dma_capable down a bit so that we don't need a forward declaration +for phys_to_dma. + +Signed-off-by: Christoph Hellwig +Reviewed-by: Nicolas Saenz Julienne +(cherry picked from commit c7345159f7db6fb69ec1c3b3f8f28cd05c731be2) +--- + include/linux/dma-direct.h | 30 ++++++++++++++---------------- + 1 file changed, 14 insertions(+), 16 deletions(-) + +--- a/include/linux/dma-direct.h ++++ b/include/linux/dma-direct.h +@@ -6,8 +6,6 @@ + #include /* for min_low_pfn */ + #include + +-static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); +- + extern unsigned int zone_dma_bits; + + #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA +@@ -28,20 +26,6 @@ static inline phys_addr_t __dma_to_phys( + } + #endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ + +-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) +-{ +- dma_addr_t end = addr + size - 1; +- +- if (!dev->dma_mask) +- return false; +- +- if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && +- min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) +- return false; +- +- return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); +-} +- + #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED + bool force_dma_unencrypted(struct device *dev); + #else +@@ -67,6 +51,20 @@ static inline phys_addr_t dma_to_phys(st + return __sme_clr(__dma_to_phys(dev, daddr)); + } + ++static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) ++{ ++ dma_addr_t end = addr + size - 1; ++ ++ if (!dev->dma_mask) ++ return false; ++ ++ if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && ++ min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) ++ return false; ++ ++ return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); ++} ++ + u64 dma_direct_get_required_mask(struct device *dev); + void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, + gfp_t gfp, unsigned long attrs); diff --git a/target/linux/bcm27xx/patches-5.4/950-0454-dma-direct-unify-the-dma_capable-definitions.patch b/target/linux/bcm27xx/patches-5.4/950-0454-dma-direct-unify-the-dma_capable-definitions.patch deleted file mode 100644 index d115f0eb809..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0454-dma-direct-unify-the-dma_capable-definitions.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 203e0c39b262fc1da6f976495c32ec38ea93a137 Mon Sep 17 00:00:00 2001 -From: Christoph Hellwig -Date: Tue, 12 Nov 2019 17:06:04 +0100 -Subject: [PATCH] dma-direct: unify the dma_capable definitions - -commit 130c1ccbf55330b55e82612a6e54eebb82c9d746 upstream. - -Currently each architectures that wants to override dma_to_phys and -phys_to_dma also has to provide dma_capable. But there isn't really -any good reason for that. powerpc and mips just have copies of the -generic one minus the latests fix, and the arm one was the inspiration -for said fix, but misses the bus_dma_mask handling. -Make all architectures use the generic version instead. - -Signed-off-by: Christoph Hellwig -Acked-by: Michael Ellerman (powerpc) -Reviewed-by: Nicolas Saenz Julienne ---- - arch/arm/include/asm/dma-direct.h | 19 ------------------- - arch/mips/include/asm/dma-direct.h | 8 -------- - arch/powerpc/include/asm/dma-direct.h | 9 --------- - include/linux/dma-direct.h | 2 +- - 4 files changed, 1 insertion(+), 37 deletions(-) - ---- a/arch/arm/include/asm/dma-direct.h -+++ b/arch/arm/include/asm/dma-direct.h -@@ -14,23 +14,4 @@ static inline phys_addr_t __dma_to_phys( - return __pfn_to_phys(dma_to_pfn(dev, dev_addr)) + offset; - } - --static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) --{ -- u64 limit, mask; -- -- if (!dev->dma_mask) -- return 0; -- -- mask = *dev->dma_mask; -- -- limit = (mask + 1) & ~mask; -- if (limit && size > limit) -- return 0; -- -- if ((addr | (addr + size - 1)) & ~mask) -- return 0; -- -- return 1; --} -- - #endif /* ASM_ARM_DMA_DIRECT_H */ ---- a/arch/mips/include/asm/dma-direct.h -+++ b/arch/mips/include/asm/dma-direct.h -@@ -2,14 +2,6 @@ - #ifndef _MIPS_DMA_DIRECT_H - #define _MIPS_DMA_DIRECT_H 1 - --static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) --{ -- if (!dev->dma_mask) -- return false; -- -- return addr + size - 1 <= *dev->dma_mask; --} -- - dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr); - phys_addr_t __dma_to_phys(struct device *dev, dma_addr_t daddr); - ---- a/arch/powerpc/include/asm/dma-direct.h -+++ b/arch/powerpc/include/asm/dma-direct.h -@@ -2,15 +2,6 @@ - #ifndef ASM_POWERPC_DMA_DIRECT_H - #define ASM_POWERPC_DMA_DIRECT_H 1 - --static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) --{ -- if (!dev->dma_mask) -- return false; -- -- return addr + size - 1 <= -- min_not_zero(*dev->dma_mask, dev->bus_dma_mask); --} -- - static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) - { - if (!dev) ---- a/include/linux/dma-direct.h -+++ b/include/linux/dma-direct.h -@@ -26,6 +26,7 @@ static inline phys_addr_t __dma_to_phys( - - return paddr + ((phys_addr_t)dev->dma_pfn_offset << PAGE_SHIFT); - } -+#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ - - static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) - { -@@ -40,7 +41,6 @@ static inline bool dma_capable(struct de - - return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); - } --#endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ - - #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED - bool force_dma_unencrypted(struct device *dev); diff --git a/target/linux/bcm27xx/patches-5.4/950-0455-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch b/target/linux/bcm27xx/patches-5.4/950-0455-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch deleted file mode 100644 index a98f1d38527..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0455-dma-direct-avoid-a-forward-declaration-for-phys_to_d.patch +++ /dev/null @@ -1,69 +0,0 @@ -From a3794022e928547de664abd03b61280163c7f13a Mon Sep 17 00:00:00 2001 -From: Christoph Hellwig -Date: Tue, 12 Nov 2019 17:07:43 +0100 -Subject: [PATCH] dma-direct: avoid a forward declaration for - phys_to_dma - -Move dma_capable down a bit so that we don't need a forward declaration -for phys_to_dma. - -Signed-off-by: Christoph Hellwig -Reviewed-by: Nicolas Saenz Julienne -(cherry picked from commit c7345159f7db6fb69ec1c3b3f8f28cd05c731be2) ---- - include/linux/dma-direct.h | 30 ++++++++++++++---------------- - 1 file changed, 14 insertions(+), 16 deletions(-) - ---- a/include/linux/dma-direct.h -+++ b/include/linux/dma-direct.h -@@ -6,8 +6,6 @@ - #include /* for min_low_pfn */ - #include - --static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr); -- - extern unsigned int zone_dma_bits; - - #ifdef CONFIG_ARCH_HAS_PHYS_TO_DMA -@@ -28,20 +26,6 @@ static inline phys_addr_t __dma_to_phys( - } - #endif /* !CONFIG_ARCH_HAS_PHYS_TO_DMA */ - --static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) --{ -- dma_addr_t end = addr + size - 1; -- -- if (!dev->dma_mask) -- return false; -- -- if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && -- min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) -- return false; -- -- return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); --} -- - #ifdef CONFIG_ARCH_HAS_FORCE_DMA_UNENCRYPTED - bool force_dma_unencrypted(struct device *dev); - #else -@@ -67,6 +51,20 @@ static inline phys_addr_t dma_to_phys(st - return __sme_clr(__dma_to_phys(dev, daddr)); - } - -+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) -+{ -+ dma_addr_t end = addr + size - 1; -+ -+ if (!dev->dma_mask) -+ return false; -+ -+ if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && -+ min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) -+ return false; -+ -+ return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); -+} -+ - u64 dma_direct_get_required_mask(struct device *dev); - void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, - gfp_t gfp, unsigned long attrs); diff --git a/target/linux/bcm27xx/patches-5.4/950-0455-dma-direct-exclude-dma_direct_map_resource-from-the-.patch b/target/linux/bcm27xx/patches-5.4/950-0455-dma-direct-exclude-dma_direct_map_resource-from-the-.patch new file mode 100644 index 00000000000..94a1329d849 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0455-dma-direct-exclude-dma_direct_map_resource-from-the-.patch @@ -0,0 +1,115 @@ +From b763f24aed409296eb76d085c279b2c40462f8a1 Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Tue, 19 Nov 2019 17:38:58 +0100 +Subject: [PATCH] dma-direct: exclude dma_direct_map_resource from the + min_low_pfn check + +commit 68a33b1794665ba8a1d1ef1d3bfcc7c587d380a6 upstream. + +The valid memory address check in dma_capable only makes sense when mapping +normal memory, not when using dma_map_resource to map a device resource. +Add a new boolean argument to dma_capable to exclude that check for the +dma_map_resource case. + +Fixes: b12d66278dd6 ("dma-direct: check for overflows on 32 bit DMA addresses") +Reported-by: Marek Szyprowski +Signed-off-by: Christoph Hellwig +Acked-by: Marek Szyprowski +Tested-by: Marek Szyprowski +--- + arch/x86/kernel/amd_gart_64.c | 4 ++-- + drivers/xen/swiotlb-xen.c | 4 ++-- + include/linux/dma-direct.h | 5 +++-- + kernel/dma/direct.c | 4 ++-- + kernel/dma/swiotlb.c | 2 +- + 5 files changed, 10 insertions(+), 9 deletions(-) + +--- a/arch/x86/kernel/amd_gart_64.c ++++ b/arch/x86/kernel/amd_gart_64.c +@@ -185,13 +185,13 @@ static void iommu_full(struct device *de + static inline int + need_iommu(struct device *dev, unsigned long addr, size_t size) + { +- return force_iommu || !dma_capable(dev, addr, size); ++ return force_iommu || !dma_capable(dev, addr, size, true); + } + + static inline int + nonforced_iommu(struct device *dev, unsigned long addr, size_t size) + { +- return !dma_capable(dev, addr, size); ++ return !dma_capable(dev, addr, size, true); + } + + /* Map a single continuous physical area into the IOMMU. +--- a/drivers/xen/swiotlb-xen.c ++++ b/drivers/xen/swiotlb-xen.c +@@ -375,7 +375,7 @@ static dma_addr_t xen_swiotlb_map_page(s + * we can safely return the device addr and not worry about bounce + * buffering it. + */ +- if (dma_capable(dev, dev_addr, size) && ++ if (dma_capable(dev, dev_addr, size, true) && + !range_straddles_page_boundary(phys, size) && + !xen_arch_need_swiotlb(dev, phys, dev_addr) && + swiotlb_force != SWIOTLB_FORCE) +@@ -397,7 +397,7 @@ static dma_addr_t xen_swiotlb_map_page(s + /* + * Ensure that the address returned is DMA'ble + */ +- if (unlikely(!dma_capable(dev, dev_addr, size))) { ++ if (unlikely(!dma_capable(dev, dev_addr, size, true))) { + swiotlb_tbl_unmap_single(dev, map, size, size, dir, + attrs | DMA_ATTR_SKIP_CPU_SYNC); + return DMA_MAPPING_ERROR; +--- a/include/linux/dma-direct.h ++++ b/include/linux/dma-direct.h +@@ -51,14 +51,15 @@ static inline phys_addr_t dma_to_phys(st + return __sme_clr(__dma_to_phys(dev, daddr)); + } + +-static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) ++static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size, ++ bool is_ram) + { + dma_addr_t end = addr + size - 1; + + if (!dev->dma_mask) + return false; + +- if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && ++ if (is_ram && !IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && + min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) + return false; + +--- a/kernel/dma/direct.c ++++ b/kernel/dma/direct.c +@@ -325,7 +325,7 @@ static inline bool dma_direct_possible(s + size_t size) + { + return swiotlb_force != SWIOTLB_FORCE && +- dma_capable(dev, dma_addr, size); ++ dma_capable(dev, dma_addr, size, true); + } + + dma_addr_t dma_direct_map_page(struct device *dev, struct page *page, +@@ -374,7 +374,7 @@ dma_addr_t dma_direct_map_resource(struc + { + dma_addr_t dma_addr = paddr; + +- if (unlikely(!dma_capable(dev, dma_addr, size))) { ++ if (unlikely(!dma_capable(dev, dma_addr, size, false))) { + report_addr(dev, dma_addr, size); + return DMA_MAPPING_ERROR; + } +--- a/kernel/dma/swiotlb.c ++++ b/kernel/dma/swiotlb.c +@@ -678,7 +678,7 @@ bool swiotlb_map(struct device *dev, phy + + /* Ensure that the address returned is DMA'ble */ + *dma_addr = __phys_to_dma(dev, *phys); +- if (unlikely(!dma_capable(dev, *dma_addr, size))) { ++ if (unlikely(!dma_capable(dev, *dma_addr, size, true))) { + swiotlb_tbl_unmap_single(dev, *phys, size, size, dir, + attrs | DMA_ATTR_SKIP_CPU_SYNC); + return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0456-dma-direct-exclude-dma_direct_map_resource-from-the-.patch b/target/linux/bcm27xx/patches-5.4/950-0456-dma-direct-exclude-dma_direct_map_resource-from-the-.patch deleted file mode 100644 index 94a1329d849..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0456-dma-direct-exclude-dma_direct_map_resource-from-the-.patch +++ /dev/null @@ -1,115 +0,0 @@ -From b763f24aed409296eb76d085c279b2c40462f8a1 Mon Sep 17 00:00:00 2001 -From: Christoph Hellwig -Date: Tue, 19 Nov 2019 17:38:58 +0100 -Subject: [PATCH] dma-direct: exclude dma_direct_map_resource from the - min_low_pfn check - -commit 68a33b1794665ba8a1d1ef1d3bfcc7c587d380a6 upstream. - -The valid memory address check in dma_capable only makes sense when mapping -normal memory, not when using dma_map_resource to map a device resource. -Add a new boolean argument to dma_capable to exclude that check for the -dma_map_resource case. - -Fixes: b12d66278dd6 ("dma-direct: check for overflows on 32 bit DMA addresses") -Reported-by: Marek Szyprowski -Signed-off-by: Christoph Hellwig -Acked-by: Marek Szyprowski -Tested-by: Marek Szyprowski ---- - arch/x86/kernel/amd_gart_64.c | 4 ++-- - drivers/xen/swiotlb-xen.c | 4 ++-- - include/linux/dma-direct.h | 5 +++-- - kernel/dma/direct.c | 4 ++-- - kernel/dma/swiotlb.c | 2 +- - 5 files changed, 10 insertions(+), 9 deletions(-) - ---- a/arch/x86/kernel/amd_gart_64.c -+++ b/arch/x86/kernel/amd_gart_64.c -@@ -185,13 +185,13 @@ static void iommu_full(struct device *de - static inline int - need_iommu(struct device *dev, unsigned long addr, size_t size) - { -- return force_iommu || !dma_capable(dev, addr, size); -+ return force_iommu || !dma_capable(dev, addr, size, true); - } - - static inline int - nonforced_iommu(struct device *dev, unsigned long addr, size_t size) - { -- return !dma_capable(dev, addr, size); -+ return !dma_capable(dev, addr, size, true); - } - - /* Map a single continuous physical area into the IOMMU. ---- a/drivers/xen/swiotlb-xen.c -+++ b/drivers/xen/swiotlb-xen.c -@@ -375,7 +375,7 @@ static dma_addr_t xen_swiotlb_map_page(s - * we can safely return the device addr and not worry about bounce - * buffering it. - */ -- if (dma_capable(dev, dev_addr, size) && -+ if (dma_capable(dev, dev_addr, size, true) && - !range_straddles_page_boundary(phys, size) && - !xen_arch_need_swiotlb(dev, phys, dev_addr) && - swiotlb_force != SWIOTLB_FORCE) -@@ -397,7 +397,7 @@ static dma_addr_t xen_swiotlb_map_page(s - /* - * Ensure that the address returned is DMA'ble - */ -- if (unlikely(!dma_capable(dev, dev_addr, size))) { -+ if (unlikely(!dma_capable(dev, dev_addr, size, true))) { - swiotlb_tbl_unmap_single(dev, map, size, size, dir, - attrs | DMA_ATTR_SKIP_CPU_SYNC); - return DMA_MAPPING_ERROR; ---- a/include/linux/dma-direct.h -+++ b/include/linux/dma-direct.h -@@ -51,14 +51,15 @@ static inline phys_addr_t dma_to_phys(st - return __sme_clr(__dma_to_phys(dev, daddr)); - } - --static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) -+static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size, -+ bool is_ram) - { - dma_addr_t end = addr + size - 1; - - if (!dev->dma_mask) - return false; - -- if (!IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && -+ if (is_ram && !IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT) && - min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) - return false; - ---- a/kernel/dma/direct.c -+++ b/kernel/dma/direct.c -@@ -325,7 +325,7 @@ static inline bool dma_direct_possible(s - size_t size) - { - return swiotlb_force != SWIOTLB_FORCE && -- dma_capable(dev, dma_addr, size); -+ dma_capable(dev, dma_addr, size, true); - } - - dma_addr_t dma_direct_map_page(struct device *dev, struct page *page, -@@ -374,7 +374,7 @@ dma_addr_t dma_direct_map_resource(struc - { - dma_addr_t dma_addr = paddr; - -- if (unlikely(!dma_capable(dev, dma_addr, size))) { -+ if (unlikely(!dma_capable(dev, dma_addr, size, false))) { - report_addr(dev, dma_addr, size); - return DMA_MAPPING_ERROR; - } ---- a/kernel/dma/swiotlb.c -+++ b/kernel/dma/swiotlb.c -@@ -678,7 +678,7 @@ bool swiotlb_map(struct device *dev, phy - - /* Ensure that the address returned is DMA'ble */ - *dma_addr = __phys_to_dma(dev, *phys); -- if (unlikely(!dma_capable(dev, *dma_addr, size))) { -+ if (unlikely(!dma_capable(dev, *dma_addr, size, true))) { - swiotlb_tbl_unmap_single(dev, *phys, size, size, dir, - attrs | DMA_ATTR_SKIP_CPU_SYNC); - return false; diff --git a/target/linux/bcm27xx/patches-5.4/950-0456-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch b/target/linux/bcm27xx/patches-5.4/950-0456-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch new file mode 100644 index 00000000000..05dad5ddaf3 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0456-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch @@ -0,0 +1,366 @@ +From d5430c466b3c3b5f631ee37be333a40924575b72 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Thu, 21 Nov 2019 10:26:44 +0100 +Subject: [PATCH] dma-mapping: treat dev->bus_dma_mask as a DMA limit + +commit a7ba70f1787f977f970cd116076c6fce4b9e01cc upstream. + +Using a mask to represent bus DMA constraints has a set of limitations. +The biggest one being it can only hold a power of two (minus one). The +DMA mapping code is already aware of this and treats dev->bus_dma_mask +as a limit. This quirk is already used by some architectures although +still rare. + +With the introduction of the Raspberry Pi 4 we've found a new contender +for the use of bus DMA limits, as its PCIe bus can only address the +lower 3GB of memory (of a total of 4GB). This is impossible to represent +with a mask. To make things worse the device-tree code rounds non power +of two bus DMA limits to the next power of two, which is unacceptable in +this case. + +In the light of this, rename dev->bus_dma_mask to dev->bus_dma_limit all +over the tree and treat it as such. Note that dev->bus_dma_limit should +contain the higher accessible DMA address. + +Signed-off-by: Nicolas Saenz Julienne +Reviewed-by: Robin Murphy +Signed-off-by: Christoph Hellwig +--- + arch/mips/pci/fixup-sb1250.c | 16 ++++++++-------- + arch/powerpc/sysdev/fsl_pci.c | 6 +++--- + arch/x86/kernel/pci-dma.c | 2 +- + arch/x86/mm/mem_encrypt.c | 2 +- + arch/x86/pci/sta2x11-fixup.c | 2 +- + drivers/acpi/arm64/iort.c | 20 +++++++------------- + drivers/ata/ahci.c | 2 +- + drivers/iommu/dma-iommu.c | 3 +-- + drivers/of/device.c | 9 +++++---- + include/linux/device.h | 6 +++--- + include/linux/dma-direct.h | 2 +- + include/linux/dma-mapping.h | 2 +- + kernel/dma/direct.c | 27 +++++++++++++-------------- + 13 files changed, 46 insertions(+), 53 deletions(-) + +--- a/arch/mips/pci/fixup-sb1250.c ++++ b/arch/mips/pci/fixup-sb1250.c +@@ -21,22 +21,22 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SI + + /* + * The BCM1250, etc. PCI host bridge does not support DAC on its 32-bit +- * bus, so we set the bus's DMA mask accordingly. However the HT link ++ * bus, so we set the bus's DMA limit accordingly. However the HT link + * down the artificial PCI-HT bridge supports 40-bit addressing and the + * SP1011 HT-PCI bridge downstream supports both DAC and a 64-bit bus + * width, so we record the PCI-HT bridge's secondary and subordinate bus +- * numbers and do not set the mask for devices present in the inclusive ++ * numbers and do not set the limit for devices present in the inclusive + * range of those. + */ +-struct sb1250_bus_dma_mask_exclude { ++struct sb1250_bus_dma_limit_exclude { + bool set; + unsigned char start; + unsigned char end; + }; + +-static int sb1250_bus_dma_mask(struct pci_dev *dev, void *data) ++static int sb1250_bus_dma_limit(struct pci_dev *dev, void *data) + { +- struct sb1250_bus_dma_mask_exclude *exclude = data; ++ struct sb1250_bus_dma_limit_exclude *exclude = data; + bool exclude_this; + bool ht_bridge; + +@@ -55,7 +55,7 @@ static int sb1250_bus_dma_mask(struct pc + exclude->start, exclude->end); + } else { + dev_dbg(&dev->dev, "disabling DAC for device"); +- dev->dev.bus_dma_mask = DMA_BIT_MASK(32); ++ dev->dev.bus_dma_limit = DMA_BIT_MASK(32); + } + + return 0; +@@ -63,9 +63,9 @@ static int sb1250_bus_dma_mask(struct pc + + static void quirk_sb1250_pci_dac(struct pci_dev *dev) + { +- struct sb1250_bus_dma_mask_exclude exclude = { .set = false }; ++ struct sb1250_bus_dma_limit_exclude exclude = { .set = false }; + +- pci_walk_bus(dev->bus, sb1250_bus_dma_mask, &exclude); ++ pci_walk_bus(dev->bus, sb1250_bus_dma_limit, &exclude); + } + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI, + quirk_sb1250_pci_dac); +--- a/arch/powerpc/sysdev/fsl_pci.c ++++ b/arch/powerpc/sysdev/fsl_pci.c +@@ -115,8 +115,8 @@ static void pci_dma_dev_setup_swiotlb(st + { + struct pci_controller *hose = pci_bus_to_host(pdev->bus); + +- pdev->dev.bus_dma_mask = +- hose->dma_window_base_cur + hose->dma_window_size; ++ pdev->dev.bus_dma_limit = ++ hose->dma_window_base_cur + hose->dma_window_size - 1; + } + + static void setup_swiotlb_ops(struct pci_controller *hose) +@@ -135,7 +135,7 @@ static void fsl_pci_dma_set_mask(struct + * mapping that allows addressing any RAM address from across PCI. + */ + if (dev_is_pci(dev) && dma_mask >= pci64_dma_offset * 2 - 1) { +- dev->bus_dma_mask = 0; ++ dev->bus_dma_limit = 0; + dev->archdata.dma_offset = pci64_dma_offset; + } + } +--- a/arch/x86/kernel/pci-dma.c ++++ b/arch/x86/kernel/pci-dma.c +@@ -146,7 +146,7 @@ rootfs_initcall(pci_iommu_init); + + static int via_no_dac_cb(struct pci_dev *pdev, void *data) + { +- pdev->dev.bus_dma_mask = DMA_BIT_MASK(32); ++ pdev->dev.bus_dma_limit = DMA_BIT_MASK(32); + return 0; + } + +--- a/arch/x86/mm/mem_encrypt.c ++++ b/arch/x86/mm/mem_encrypt.c +@@ -367,7 +367,7 @@ bool force_dma_unencrypted(struct device + if (sme_active()) { + u64 dma_enc_mask = DMA_BIT_MASK(__ffs64(sme_me_mask)); + u64 dma_dev_mask = min_not_zero(dev->coherent_dma_mask, +- dev->bus_dma_mask); ++ dev->bus_dma_limit); + + if (dma_dev_mask <= dma_enc_mask) + return true; +--- a/arch/x86/pci/sta2x11-fixup.c ++++ b/arch/x86/pci/sta2x11-fixup.c +@@ -143,7 +143,7 @@ static void sta2x11_map_ep(struct pci_de + + dev->dma_pfn_offset = PFN_DOWN(-amba_base); + +- dev->bus_dma_mask = max_amba_addr; ++ dev->bus_dma_limit = max_amba_addr; + pci_set_consistent_dma_mask(pdev, max_amba_addr); + pci_set_dma_mask(pdev, max_amba_addr); + +--- a/drivers/acpi/arm64/iort.c ++++ b/drivers/acpi/arm64/iort.c +@@ -1057,8 +1057,8 @@ static int rc_dma_get_range(struct devic + */ + void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) + { +- u64 mask, dmaaddr = 0, size = 0, offset = 0; +- int ret, msb; ++ u64 end, mask, dmaaddr = 0, size = 0, offset = 0; ++ int ret; + + /* + * If @dev is expected to be DMA-capable then the bus code that created +@@ -1085,19 +1085,13 @@ void iort_dma_setup(struct device *dev, + } + + if (!ret) { +- msb = fls64(dmaaddr + size - 1); + /* +- * Round-up to the power-of-two mask or set +- * the mask to the whole 64-bit address space +- * in case the DMA region covers the full +- * memory window. ++ * Limit coherent and dma mask based on size retrieved from ++ * firmware. + */ +- mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1; +- /* +- * Limit coherent and dma mask based on size +- * retrieved from firmware. +- */ +- dev->bus_dma_mask = mask; ++ end = dmaaddr + size - 1; ++ mask = DMA_BIT_MASK(ilog2(end) + 1); ++ dev->bus_dma_limit = end; + dev->coherent_dma_mask = mask; + *dev->dma_mask = mask; + } +--- a/drivers/ata/ahci.c ++++ b/drivers/ata/ahci.c +@@ -899,7 +899,7 @@ static int ahci_configure_dma_masks(stru + * value, don't extend it here. This happens on STA2X11, for example. + * + * XXX: manipulating the DMA mask from platform code is completely +- * bogus, platform code should use dev->bus_dma_mask instead.. ++ * bogus, platform code should use dev->bus_dma_limit instead.. + */ + if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32)) + return 0; +--- a/drivers/iommu/dma-iommu.c ++++ b/drivers/iommu/dma-iommu.c +@@ -404,8 +404,7 @@ static dma_addr_t iommu_dma_alloc_iova(s + if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1))) + iova_len = roundup_pow_of_two(iova_len); + +- if (dev->bus_dma_mask) +- dma_limit &= dev->bus_dma_mask; ++ dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit); + + if (domain->geometry.force_aperture) + dma_limit = min(dma_limit, domain->geometry.aperture_end); +--- a/drivers/of/device.c ++++ b/drivers/of/device.c +@@ -93,7 +93,7 @@ int of_dma_configure(struct device *dev, + bool coherent; + unsigned long offset; + const struct iommu_ops *iommu; +- u64 mask; ++ u64 mask, end; + + ret = of_dma_get_range(np, &dma_addr, &paddr, &size); + if (ret < 0) { +@@ -148,12 +148,13 @@ int of_dma_configure(struct device *dev, + * Limit coherent and dma mask based on size and default mask + * set by the driver. + */ +- mask = DMA_BIT_MASK(ilog2(dma_addr + size - 1) + 1); ++ end = dma_addr + size - 1; ++ mask = DMA_BIT_MASK(ilog2(end) + 1); + dev->coherent_dma_mask &= mask; + *dev->dma_mask &= mask; +- /* ...but only set bus mask if we found valid dma-ranges earlier */ ++ /* ...but only set bus limit if we found valid dma-ranges earlier */ + if (!ret) +- dev->bus_dma_mask = mask; ++ dev->bus_dma_limit = end; + + coherent = of_dma_is_coherent(np); + dev_dbg(dev, "device is%sdma coherent\n", +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -1186,8 +1186,8 @@ struct dev_links_info { + * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all + * hardware supports 64-bit addresses for consistent allocations + * such descriptors. +- * @bus_dma_mask: Mask of an upstream bridge or bus which imposes a smaller DMA +- * limit than the device itself supports. ++ * @bus_dma_limit: Limit of an upstream bridge or bus which imposes a smaller ++ * DMA limit than the device itself supports. + * @dma_pfn_offset: offset of DMA memory range relatively of RAM + * @dma_parms: A low level driver may set these to teach IOMMU code about + * segment limitations. +@@ -1270,7 +1270,7 @@ struct device { + not all hardware supports + 64 bit addresses for consistent + allocations such descriptors. */ +- u64 bus_dma_mask; /* upstream dma_mask constraint */ ++ u64 bus_dma_limit; /* upstream dma constraint */ + unsigned long dma_pfn_offset; + + struct device_dma_parameters *dma_parms; +--- a/include/linux/dma-direct.h ++++ b/include/linux/dma-direct.h +@@ -63,7 +63,7 @@ static inline bool dma_capable(struct de + min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) + return false; + +- return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); ++ return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_limit); + } + + u64 dma_direct_get_required_mask(struct device *dev); +--- a/include/linux/dma-mapping.h ++++ b/include/linux/dma-mapping.h +@@ -697,7 +697,7 @@ static inline int dma_coerce_mask_and_co + */ + static inline bool dma_addressing_limited(struct device *dev) + { +- return min_not_zero(dma_get_mask(dev), dev->bus_dma_mask) < ++ return min_not_zero(dma_get_mask(dev), dev->bus_dma_limit) < + dma_get_required_mask(dev); + } + +--- a/kernel/dma/direct.c ++++ b/kernel/dma/direct.c +@@ -26,10 +26,10 @@ static void report_addr(struct device *d + { + if (!dev->dma_mask) { + dev_err_once(dev, "DMA map on device without dma_mask\n"); +- } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_mask) { ++ } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_limit) { + dev_err_once(dev, +- "overflow %pad+%zu of DMA mask %llx bus mask %llx\n", +- &dma_addr, size, *dev->dma_mask, dev->bus_dma_mask); ++ "overflow %pad+%zu of DMA mask %llx bus limit %llx\n", ++ &dma_addr, size, *dev->dma_mask, dev->bus_dma_limit); + } + WARN_ON_ONCE(1); + } +@@ -50,15 +50,14 @@ u64 dma_direct_get_required_mask(struct + } + + static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask, +- u64 *phys_mask) ++ u64 *phys_limit) + { +- if (dev->bus_dma_mask && dev->bus_dma_mask < dma_mask) +- dma_mask = dev->bus_dma_mask; ++ u64 dma_limit = min_not_zero(dma_mask, dev->bus_dma_limit); + + if (force_dma_unencrypted(dev)) +- *phys_mask = __dma_to_phys(dev, dma_mask); ++ *phys_limit = __dma_to_phys(dev, dma_limit); + else +- *phys_mask = dma_to_phys(dev, dma_mask); ++ *phys_limit = dma_to_phys(dev, dma_limit); + + /* + * Optimistically try the zone that the physical address mask falls +@@ -68,9 +67,9 @@ static gfp_t __dma_direct_optimal_gfp_ma + * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding + * zones. + */ +- if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits)) ++ if (*phys_limit <= DMA_BIT_MASK(zone_dma_bits)) + return GFP_DMA; +- if (*phys_mask <= DMA_BIT_MASK(32)) ++ if (*phys_limit <= DMA_BIT_MASK(32)) + return GFP_DMA32; + return 0; + } +@@ -78,7 +77,7 @@ static gfp_t __dma_direct_optimal_gfp_ma + static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size) + { + return phys_to_dma_direct(dev, phys) + size - 1 <= +- min_not_zero(dev->coherent_dma_mask, dev->bus_dma_mask); ++ min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit); + } + + struct page *__dma_direct_alloc_pages(struct device *dev, size_t size, +@@ -87,7 +86,7 @@ struct page *__dma_direct_alloc_pages(st + size_t alloc_size = PAGE_ALIGN(size); + int node = dev_to_node(dev); + struct page *page = NULL; +- u64 phys_mask; ++ u64 phys_limit; + + if (attrs & DMA_ATTR_NO_WARN) + gfp |= __GFP_NOWARN; +@@ -95,7 +94,7 @@ struct page *__dma_direct_alloc_pages(st + /* we always manually zero the memory once we are done: */ + gfp &= ~__GFP_ZERO; + gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask, +- &phys_mask); ++ &phys_limit); + page = dma_alloc_contiguous(dev, alloc_size, gfp); + if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) { + dma_free_contiguous(dev, page, alloc_size); +@@ -109,7 +108,7 @@ again: + page = NULL; + + if (IS_ENABLED(CONFIG_ZONE_DMA32) && +- phys_mask < DMA_BIT_MASK(64) && ++ phys_limit < DMA_BIT_MASK(64) && + !(gfp & (GFP_DMA32 | GFP_DMA))) { + gfp |= GFP_DMA32; + goto again; diff --git a/target/linux/bcm27xx/patches-5.4/950-0457-ARM-dts-bcm2711-Enable-PCIe-controller.patch b/target/linux/bcm27xx/patches-5.4/950-0457-ARM-dts-bcm2711-Enable-PCIe-controller.patch new file mode 100644 index 00000000000..9f114c1633e --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0457-ARM-dts-bcm2711-Enable-PCIe-controller.patch @@ -0,0 +1,56 @@ +From 0ec0bc884f6cf1ec9775c750f78ce28be7da4340 Mon Sep 17 00:00:00 2001 +From: Nicolas Saenz Julienne +Date: Mon, 16 Dec 2019 12:01:08 +0100 +Subject: [PATCH] ARM: dts: bcm2711: Enable PCIe controller + +commit d5c8dc0d4c880fbde5293cc186b1ab23466254c4 upstream. + +This enables bcm2711's PCIe bus, which is hardwired to a VIA +Technologies XHCI USB 3.0 controller. + +Signed-off-by: Nicolas Saenz Julienne +Signed-off-by: Florian Fainelli +--- + arch/arm/boot/dts/bcm2711.dtsi | 31 ++++++++++++++++++++++++++++++- + 1 file changed, 30 insertions(+), 1 deletion(-) + +--- a/arch/arm/boot/dts/bcm2711.dtsi ++++ b/arch/arm/boot/dts/bcm2711.dtsi +@@ -331,7 +331,36 @@ + #address-cells = <2>; + #size-cells = <1>; + +- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>; ++ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>, ++ <0x6 0x00000000 0x6 0x00000000 0x40000000>; ++ ++ pcie0: pcie@7d500000 { ++ compatible = "brcm,bcm2711-pcie"; ++ reg = <0x0 0x7d500000 0x9310>; ++ device_type = "pci"; ++ #address-cells = <3>; ++ #interrupt-cells = <1>; ++ #size-cells = <2>; ++ interrupts = , ++ ; ++ interrupt-names = "pcie", "msi"; ++ interrupt-map-mask = <0x0 0x0 0x0 0x7>; ++ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 ++ IRQ_TYPE_LEVEL_HIGH>; ++ msi-controller; ++ msi-parent = <&pcie0>; ++ ++ ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 ++ 0x0 0x04000000>; ++ /* ++ * The wrapper around the PCIe block has a bug ++ * preventing it from accessing beyond the first 3GB of ++ * memory. ++ */ ++ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 ++ 0x0 0xc0000000>; ++ brcm,enable-ssc; ++ }; + + genet: ethernet@7d580000 { + compatible = "brcm,bcm2711-genet-v5"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0457-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch b/target/linux/bcm27xx/patches-5.4/950-0457-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch deleted file mode 100644 index 05dad5ddaf3..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0457-dma-mapping-treat-dev-bus_dma_mask-as-a-DMA-limit.patch +++ /dev/null @@ -1,366 +0,0 @@ -From d5430c466b3c3b5f631ee37be333a40924575b72 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Thu, 21 Nov 2019 10:26:44 +0100 -Subject: [PATCH] dma-mapping: treat dev->bus_dma_mask as a DMA limit - -commit a7ba70f1787f977f970cd116076c6fce4b9e01cc upstream. - -Using a mask to represent bus DMA constraints has a set of limitations. -The biggest one being it can only hold a power of two (minus one). The -DMA mapping code is already aware of this and treats dev->bus_dma_mask -as a limit. This quirk is already used by some architectures although -still rare. - -With the introduction of the Raspberry Pi 4 we've found a new contender -for the use of bus DMA limits, as its PCIe bus can only address the -lower 3GB of memory (of a total of 4GB). This is impossible to represent -with a mask. To make things worse the device-tree code rounds non power -of two bus DMA limits to the next power of two, which is unacceptable in -this case. - -In the light of this, rename dev->bus_dma_mask to dev->bus_dma_limit all -over the tree and treat it as such. Note that dev->bus_dma_limit should -contain the higher accessible DMA address. - -Signed-off-by: Nicolas Saenz Julienne -Reviewed-by: Robin Murphy -Signed-off-by: Christoph Hellwig ---- - arch/mips/pci/fixup-sb1250.c | 16 ++++++++-------- - arch/powerpc/sysdev/fsl_pci.c | 6 +++--- - arch/x86/kernel/pci-dma.c | 2 +- - arch/x86/mm/mem_encrypt.c | 2 +- - arch/x86/pci/sta2x11-fixup.c | 2 +- - drivers/acpi/arm64/iort.c | 20 +++++++------------- - drivers/ata/ahci.c | 2 +- - drivers/iommu/dma-iommu.c | 3 +-- - drivers/of/device.c | 9 +++++---- - include/linux/device.h | 6 +++--- - include/linux/dma-direct.h | 2 +- - include/linux/dma-mapping.h | 2 +- - kernel/dma/direct.c | 27 +++++++++++++-------------- - 13 files changed, 46 insertions(+), 53 deletions(-) - ---- a/arch/mips/pci/fixup-sb1250.c -+++ b/arch/mips/pci/fixup-sb1250.c -@@ -21,22 +21,22 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SI - - /* - * The BCM1250, etc. PCI host bridge does not support DAC on its 32-bit -- * bus, so we set the bus's DMA mask accordingly. However the HT link -+ * bus, so we set the bus's DMA limit accordingly. However the HT link - * down the artificial PCI-HT bridge supports 40-bit addressing and the - * SP1011 HT-PCI bridge downstream supports both DAC and a 64-bit bus - * width, so we record the PCI-HT bridge's secondary and subordinate bus -- * numbers and do not set the mask for devices present in the inclusive -+ * numbers and do not set the limit for devices present in the inclusive - * range of those. - */ --struct sb1250_bus_dma_mask_exclude { -+struct sb1250_bus_dma_limit_exclude { - bool set; - unsigned char start; - unsigned char end; - }; - --static int sb1250_bus_dma_mask(struct pci_dev *dev, void *data) -+static int sb1250_bus_dma_limit(struct pci_dev *dev, void *data) - { -- struct sb1250_bus_dma_mask_exclude *exclude = data; -+ struct sb1250_bus_dma_limit_exclude *exclude = data; - bool exclude_this; - bool ht_bridge; - -@@ -55,7 +55,7 @@ static int sb1250_bus_dma_mask(struct pc - exclude->start, exclude->end); - } else { - dev_dbg(&dev->dev, "disabling DAC for device"); -- dev->dev.bus_dma_mask = DMA_BIT_MASK(32); -+ dev->dev.bus_dma_limit = DMA_BIT_MASK(32); - } - - return 0; -@@ -63,9 +63,9 @@ static int sb1250_bus_dma_mask(struct pc - - static void quirk_sb1250_pci_dac(struct pci_dev *dev) - { -- struct sb1250_bus_dma_mask_exclude exclude = { .set = false }; -+ struct sb1250_bus_dma_limit_exclude exclude = { .set = false }; - -- pci_walk_bus(dev->bus, sb1250_bus_dma_mask, &exclude); -+ pci_walk_bus(dev->bus, sb1250_bus_dma_limit, &exclude); - } - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI, - quirk_sb1250_pci_dac); ---- a/arch/powerpc/sysdev/fsl_pci.c -+++ b/arch/powerpc/sysdev/fsl_pci.c -@@ -115,8 +115,8 @@ static void pci_dma_dev_setup_swiotlb(st - { - struct pci_controller *hose = pci_bus_to_host(pdev->bus); - -- pdev->dev.bus_dma_mask = -- hose->dma_window_base_cur + hose->dma_window_size; -+ pdev->dev.bus_dma_limit = -+ hose->dma_window_base_cur + hose->dma_window_size - 1; - } - - static void setup_swiotlb_ops(struct pci_controller *hose) -@@ -135,7 +135,7 @@ static void fsl_pci_dma_set_mask(struct - * mapping that allows addressing any RAM address from across PCI. - */ - if (dev_is_pci(dev) && dma_mask >= pci64_dma_offset * 2 - 1) { -- dev->bus_dma_mask = 0; -+ dev->bus_dma_limit = 0; - dev->archdata.dma_offset = pci64_dma_offset; - } - } ---- a/arch/x86/kernel/pci-dma.c -+++ b/arch/x86/kernel/pci-dma.c -@@ -146,7 +146,7 @@ rootfs_initcall(pci_iommu_init); - - static int via_no_dac_cb(struct pci_dev *pdev, void *data) - { -- pdev->dev.bus_dma_mask = DMA_BIT_MASK(32); -+ pdev->dev.bus_dma_limit = DMA_BIT_MASK(32); - return 0; - } - ---- a/arch/x86/mm/mem_encrypt.c -+++ b/arch/x86/mm/mem_encrypt.c -@@ -367,7 +367,7 @@ bool force_dma_unencrypted(struct device - if (sme_active()) { - u64 dma_enc_mask = DMA_BIT_MASK(__ffs64(sme_me_mask)); - u64 dma_dev_mask = min_not_zero(dev->coherent_dma_mask, -- dev->bus_dma_mask); -+ dev->bus_dma_limit); - - if (dma_dev_mask <= dma_enc_mask) - return true; ---- a/arch/x86/pci/sta2x11-fixup.c -+++ b/arch/x86/pci/sta2x11-fixup.c -@@ -143,7 +143,7 @@ static void sta2x11_map_ep(struct pci_de - - dev->dma_pfn_offset = PFN_DOWN(-amba_base); - -- dev->bus_dma_mask = max_amba_addr; -+ dev->bus_dma_limit = max_amba_addr; - pci_set_consistent_dma_mask(pdev, max_amba_addr); - pci_set_dma_mask(pdev, max_amba_addr); - ---- a/drivers/acpi/arm64/iort.c -+++ b/drivers/acpi/arm64/iort.c -@@ -1057,8 +1057,8 @@ static int rc_dma_get_range(struct devic - */ - void iort_dma_setup(struct device *dev, u64 *dma_addr, u64 *dma_size) - { -- u64 mask, dmaaddr = 0, size = 0, offset = 0; -- int ret, msb; -+ u64 end, mask, dmaaddr = 0, size = 0, offset = 0; -+ int ret; - - /* - * If @dev is expected to be DMA-capable then the bus code that created -@@ -1085,19 +1085,13 @@ void iort_dma_setup(struct device *dev, - } - - if (!ret) { -- msb = fls64(dmaaddr + size - 1); - /* -- * Round-up to the power-of-two mask or set -- * the mask to the whole 64-bit address space -- * in case the DMA region covers the full -- * memory window. -+ * Limit coherent and dma mask based on size retrieved from -+ * firmware. - */ -- mask = msb == 64 ? U64_MAX : (1ULL << msb) - 1; -- /* -- * Limit coherent and dma mask based on size -- * retrieved from firmware. -- */ -- dev->bus_dma_mask = mask; -+ end = dmaaddr + size - 1; -+ mask = DMA_BIT_MASK(ilog2(end) + 1); -+ dev->bus_dma_limit = end; - dev->coherent_dma_mask = mask; - *dev->dma_mask = mask; - } ---- a/drivers/ata/ahci.c -+++ b/drivers/ata/ahci.c -@@ -899,7 +899,7 @@ static int ahci_configure_dma_masks(stru - * value, don't extend it here. This happens on STA2X11, for example. - * - * XXX: manipulating the DMA mask from platform code is completely -- * bogus, platform code should use dev->bus_dma_mask instead.. -+ * bogus, platform code should use dev->bus_dma_limit instead.. - */ - if (pdev->dma_mask && pdev->dma_mask < DMA_BIT_MASK(32)) - return 0; ---- a/drivers/iommu/dma-iommu.c -+++ b/drivers/iommu/dma-iommu.c -@@ -404,8 +404,7 @@ static dma_addr_t iommu_dma_alloc_iova(s - if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1))) - iova_len = roundup_pow_of_two(iova_len); - -- if (dev->bus_dma_mask) -- dma_limit &= dev->bus_dma_mask; -+ dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit); - - if (domain->geometry.force_aperture) - dma_limit = min(dma_limit, domain->geometry.aperture_end); ---- a/drivers/of/device.c -+++ b/drivers/of/device.c -@@ -93,7 +93,7 @@ int of_dma_configure(struct device *dev, - bool coherent; - unsigned long offset; - const struct iommu_ops *iommu; -- u64 mask; -+ u64 mask, end; - - ret = of_dma_get_range(np, &dma_addr, &paddr, &size); - if (ret < 0) { -@@ -148,12 +148,13 @@ int of_dma_configure(struct device *dev, - * Limit coherent and dma mask based on size and default mask - * set by the driver. - */ -- mask = DMA_BIT_MASK(ilog2(dma_addr + size - 1) + 1); -+ end = dma_addr + size - 1; -+ mask = DMA_BIT_MASK(ilog2(end) + 1); - dev->coherent_dma_mask &= mask; - *dev->dma_mask &= mask; -- /* ...but only set bus mask if we found valid dma-ranges earlier */ -+ /* ...but only set bus limit if we found valid dma-ranges earlier */ - if (!ret) -- dev->bus_dma_mask = mask; -+ dev->bus_dma_limit = end; - - coherent = of_dma_is_coherent(np); - dev_dbg(dev, "device is%sdma coherent\n", ---- a/include/linux/device.h -+++ b/include/linux/device.h -@@ -1186,8 +1186,8 @@ struct dev_links_info { - * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all - * hardware supports 64-bit addresses for consistent allocations - * such descriptors. -- * @bus_dma_mask: Mask of an upstream bridge or bus which imposes a smaller DMA -- * limit than the device itself supports. -+ * @bus_dma_limit: Limit of an upstream bridge or bus which imposes a smaller -+ * DMA limit than the device itself supports. - * @dma_pfn_offset: offset of DMA memory range relatively of RAM - * @dma_parms: A low level driver may set these to teach IOMMU code about - * segment limitations. -@@ -1270,7 +1270,7 @@ struct device { - not all hardware supports - 64 bit addresses for consistent - allocations such descriptors. */ -- u64 bus_dma_mask; /* upstream dma_mask constraint */ -+ u64 bus_dma_limit; /* upstream dma constraint */ - unsigned long dma_pfn_offset; - - struct device_dma_parameters *dma_parms; ---- a/include/linux/dma-direct.h -+++ b/include/linux/dma-direct.h -@@ -63,7 +63,7 @@ static inline bool dma_capable(struct de - min(addr, end) < phys_to_dma(dev, PFN_PHYS(min_low_pfn))) - return false; - -- return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_mask); -+ return end <= min_not_zero(*dev->dma_mask, dev->bus_dma_limit); - } - - u64 dma_direct_get_required_mask(struct device *dev); ---- a/include/linux/dma-mapping.h -+++ b/include/linux/dma-mapping.h -@@ -697,7 +697,7 @@ static inline int dma_coerce_mask_and_co - */ - static inline bool dma_addressing_limited(struct device *dev) - { -- return min_not_zero(dma_get_mask(dev), dev->bus_dma_mask) < -+ return min_not_zero(dma_get_mask(dev), dev->bus_dma_limit) < - dma_get_required_mask(dev); - } - ---- a/kernel/dma/direct.c -+++ b/kernel/dma/direct.c -@@ -26,10 +26,10 @@ static void report_addr(struct device *d - { - if (!dev->dma_mask) { - dev_err_once(dev, "DMA map on device without dma_mask\n"); -- } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_mask) { -+ } else if (*dev->dma_mask >= DMA_BIT_MASK(32) || dev->bus_dma_limit) { - dev_err_once(dev, -- "overflow %pad+%zu of DMA mask %llx bus mask %llx\n", -- &dma_addr, size, *dev->dma_mask, dev->bus_dma_mask); -+ "overflow %pad+%zu of DMA mask %llx bus limit %llx\n", -+ &dma_addr, size, *dev->dma_mask, dev->bus_dma_limit); - } - WARN_ON_ONCE(1); - } -@@ -50,15 +50,14 @@ u64 dma_direct_get_required_mask(struct - } - - static gfp_t __dma_direct_optimal_gfp_mask(struct device *dev, u64 dma_mask, -- u64 *phys_mask) -+ u64 *phys_limit) - { -- if (dev->bus_dma_mask && dev->bus_dma_mask < dma_mask) -- dma_mask = dev->bus_dma_mask; -+ u64 dma_limit = min_not_zero(dma_mask, dev->bus_dma_limit); - - if (force_dma_unencrypted(dev)) -- *phys_mask = __dma_to_phys(dev, dma_mask); -+ *phys_limit = __dma_to_phys(dev, dma_limit); - else -- *phys_mask = dma_to_phys(dev, dma_mask); -+ *phys_limit = dma_to_phys(dev, dma_limit); - - /* - * Optimistically try the zone that the physical address mask falls -@@ -68,9 +67,9 @@ static gfp_t __dma_direct_optimal_gfp_ma - * Note that GFP_DMA32 and GFP_DMA are no ops without the corresponding - * zones. - */ -- if (*phys_mask <= DMA_BIT_MASK(zone_dma_bits)) -+ if (*phys_limit <= DMA_BIT_MASK(zone_dma_bits)) - return GFP_DMA; -- if (*phys_mask <= DMA_BIT_MASK(32)) -+ if (*phys_limit <= DMA_BIT_MASK(32)) - return GFP_DMA32; - return 0; - } -@@ -78,7 +77,7 @@ static gfp_t __dma_direct_optimal_gfp_ma - static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size) - { - return phys_to_dma_direct(dev, phys) + size - 1 <= -- min_not_zero(dev->coherent_dma_mask, dev->bus_dma_mask); -+ min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit); - } - - struct page *__dma_direct_alloc_pages(struct device *dev, size_t size, -@@ -87,7 +86,7 @@ struct page *__dma_direct_alloc_pages(st - size_t alloc_size = PAGE_ALIGN(size); - int node = dev_to_node(dev); - struct page *page = NULL; -- u64 phys_mask; -+ u64 phys_limit; - - if (attrs & DMA_ATTR_NO_WARN) - gfp |= __GFP_NOWARN; -@@ -95,7 +94,7 @@ struct page *__dma_direct_alloc_pages(st - /* we always manually zero the memory once we are done: */ - gfp &= ~__GFP_ZERO; - gfp |= __dma_direct_optimal_gfp_mask(dev, dev->coherent_dma_mask, -- &phys_mask); -+ &phys_limit); - page = dma_alloc_contiguous(dev, alloc_size, gfp); - if (page && !dma_coherent_ok(dev, page_to_phys(page), size)) { - dma_free_contiguous(dev, page, alloc_size); -@@ -109,7 +108,7 @@ again: - page = NULL; - - if (IS_ENABLED(CONFIG_ZONE_DMA32) && -- phys_mask < DMA_BIT_MASK(64) && -+ phys_limit < DMA_BIT_MASK(64) && - !(gfp & (GFP_DMA32 | GFP_DMA))) { - gfp |= GFP_DMA32; - goto again; diff --git a/target/linux/bcm27xx/patches-5.4/950-0458-ARM-dts-bcm2711-Enable-PCIe-controller.patch b/target/linux/bcm27xx/patches-5.4/950-0458-ARM-dts-bcm2711-Enable-PCIe-controller.patch deleted file mode 100644 index 9f114c1633e..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0458-ARM-dts-bcm2711-Enable-PCIe-controller.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0ec0bc884f6cf1ec9775c750f78ce28be7da4340 Mon Sep 17 00:00:00 2001 -From: Nicolas Saenz Julienne -Date: Mon, 16 Dec 2019 12:01:08 +0100 -Subject: [PATCH] ARM: dts: bcm2711: Enable PCIe controller - -commit d5c8dc0d4c880fbde5293cc186b1ab23466254c4 upstream. - -This enables bcm2711's PCIe bus, which is hardwired to a VIA -Technologies XHCI USB 3.0 controller. - -Signed-off-by: Nicolas Saenz Julienne -Signed-off-by: Florian Fainelli ---- - arch/arm/boot/dts/bcm2711.dtsi | 31 ++++++++++++++++++++++++++++++- - 1 file changed, 30 insertions(+), 1 deletion(-) - ---- a/arch/arm/boot/dts/bcm2711.dtsi -+++ b/arch/arm/boot/dts/bcm2711.dtsi -@@ -331,7 +331,36 @@ - #address-cells = <2>; - #size-cells = <1>; - -- ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>; -+ ranges = <0x0 0x7c000000 0x0 0xfc000000 0x03800000>, -+ <0x6 0x00000000 0x6 0x00000000 0x40000000>; -+ -+ pcie0: pcie@7d500000 { -+ compatible = "brcm,bcm2711-pcie"; -+ reg = <0x0 0x7d500000 0x9310>; -+ device_type = "pci"; -+ #address-cells = <3>; -+ #interrupt-cells = <1>; -+ #size-cells = <2>; -+ interrupts = , -+ ; -+ interrupt-names = "pcie", "msi"; -+ interrupt-map-mask = <0x0 0x0 0x0 0x7>; -+ interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 -+ IRQ_TYPE_LEVEL_HIGH>; -+ msi-controller; -+ msi-parent = <&pcie0>; -+ -+ ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 -+ 0x0 0x04000000>; -+ /* -+ * The wrapper around the PCIe block has a bug -+ * preventing it from accessing beyond the first 3GB of -+ * memory. -+ */ -+ dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 -+ 0x0 0xc0000000>; -+ brcm,enable-ssc; -+ }; - - genet: ethernet@7d580000 { - compatible = "brcm,bcm2711-genet-v5"; diff --git a/target/linux/bcm27xx/patches-5.4/950-0458-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch b/target/linux/bcm27xx/patches-5.4/950-0458-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch new file mode 100644 index 00000000000..ca97a1966e6 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0458-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch @@ -0,0 +1,810 @@ +From 4d9470c29736bf81bdb0d21da24cf350b1e99402 Mon Sep 17 00:00:00 2001 +From: Jim Quinlan +Date: Mon, 16 Dec 2019 12:01:09 +0100 +Subject: [PATCH] PCI: brcmstb: Add Broadcom STB PCIe host controller + driver + +commit c0452137034bda8f686dd9a2e167949bfffd6776 upstream. + +This adds a basic driver for Broadcom's STB PCIe controller, for now +aimed at Raspberry Pi 4's SoC, bcm2711. + +Signed-off-by: Jim Quinlan +Co-developed-by: Nicolas Saenz Julienne +Signed-off-by: Nicolas Saenz Julienne +[lorenzo.pieralisi@arm.com: updated brcm_pcie_get_rc_bar2_size_and_offset()according to https://lore.kernel.org/linux-pci/be8ddb33a7360af1815cf686f77f3f0913d02be3.camel@suse.de] +Signed-off-by: Lorenzo Pieralisi +Reviewed-by: Andrew Murray +Reviewed-by: Jeremy Linton +--- + drivers/pci/controller/Kconfig | 8 + + drivers/pci/controller/Makefile | 1 + + drivers/pci/controller/pcie-brcmstb.c | 755 ++++++++++++++++++++++++++ + 3 files changed, 764 insertions(+) + create mode 100644 drivers/pci/controller/pcie-brcmstb.c + +--- a/drivers/pci/controller/Kconfig ++++ b/drivers/pci/controller/Kconfig +@@ -281,6 +281,14 @@ config VMD + To compile this driver as a module, choose M here: the + module will be called vmd. + ++config PCIE_BRCMSTB ++ tristate "Broadcom Brcmstb PCIe host controller" ++ depends on ARCH_BCM2835 || COMPILE_TEST ++ depends on OF ++ help ++ Say Y here to enable PCIe host controller support for ++ Broadcom STB based SoCs, like the Raspberry Pi 4. ++ + config PCI_HYPERV_INTERFACE + tristate "Hyper-V PCI Interface" + depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64 +--- a/drivers/pci/controller/Makefile ++++ b/drivers/pci/controller/Makefile +@@ -30,6 +30,7 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-medi + obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o + obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o + obj-$(CONFIG_VMD) += vmd.o ++obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o + # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW + obj-y += dwc/ + +--- /dev/null ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -0,0 +1,755 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* Copyright (C) 2009 - 2019 Broadcom */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../pci.h" ++ ++/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */ ++#define BRCM_PCIE_CAP_REGS 0x00ac ++ ++/* Broadcom STB PCIe Register Offsets */ ++#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 0x0188 ++#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc ++#define PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN 0x0 ++ ++#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c ++#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff ++ ++#define PCIE_RC_DL_MDIO_ADDR 0x1100 ++#define PCIE_RC_DL_MDIO_WR_DATA 0x1104 ++#define PCIE_RC_DL_MDIO_RD_DATA 0x1108 ++ ++#define PCIE_MISC_MISC_CTRL 0x4008 ++#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000 ++#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000 ++#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000 ++#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128 0x0 ++#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000 ++ ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c ++#define PCIE_MEM_WIN0_LO(win) \ ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 4) ++ ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010 ++#define PCIE_MEM_WIN0_HI(win) \ ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 4) ++ ++#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c ++#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f ++ ++#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034 ++#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f ++#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038 ++ ++#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c ++#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f ++ ++#define PCIE_MISC_PCIE_CTRL 0x4064 ++#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 ++ ++#define PCIE_MISC_PCIE_STATUS 0x4068 ++#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80 ++#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20 ++#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10 ++#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40 ++ ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070 ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000 ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0 ++#define PCIE_MEM_WIN0_BASE_LIMIT(win) \ ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT + ((win) * 4) ++ ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080 ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK 0xff ++#define PCIE_MEM_WIN0_BASE_HI(win) \ ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI + ((win) * 8) ++ ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084 ++#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff ++#define PCIE_MEM_WIN0_LIMIT_HI(win) \ ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8) ++ ++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204 ++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2 ++#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 ++ ++#define PCIE_MSI_INTR2_STATUS 0x4500 ++#define PCIE_MSI_INTR2_CLR 0x4508 ++#define PCIE_MSI_INTR2_MASK_SET 0x4510 ++#define PCIE_MSI_INTR2_MASK_CLR 0x4514 ++ ++#define PCIE_EXT_CFG_DATA 0x8000 ++ ++#define PCIE_EXT_CFG_INDEX 0x9000 ++#define PCIE_EXT_BUSNUM_SHIFT 20 ++#define PCIE_EXT_SLOT_SHIFT 15 ++#define PCIE_EXT_FUNC_SHIFT 12 ++ ++#define PCIE_RGR1_SW_INIT_1 0x9210 ++#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1 ++#define PCIE_RGR1_SW_INIT_1_INIT_MASK 0x2 ++ ++/* PCIe parameters */ ++#define BRCM_NUM_PCIE_OUT_WINS 0x4 ++ ++/* MDIO registers */ ++#define MDIO_PORT0 0x0 ++#define MDIO_DATA_MASK 0x7fffffff ++#define MDIO_PORT_MASK 0xf0000 ++#define MDIO_REGAD_MASK 0xffff ++#define MDIO_CMD_MASK 0xfff00000 ++#define MDIO_CMD_READ 0x1 ++#define MDIO_CMD_WRITE 0x0 ++#define MDIO_DATA_DONE_MASK 0x80000000 ++#define MDIO_RD_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 1 : 0) ++#define MDIO_WT_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 0 : 1) ++#define SSC_REGS_ADDR 0x1100 ++#define SET_ADDR_OFFSET 0x1f ++#define SSC_CNTL_OFFSET 0x2 ++#define SSC_CNTL_OVRD_EN_MASK 0x8000 ++#define SSC_CNTL_OVRD_VAL_MASK 0x4000 ++#define SSC_STATUS_OFFSET 0x1 ++#define SSC_STATUS_SSC_MASK 0x400 ++#define SSC_STATUS_PLL_LOCK_MASK 0x800 ++ ++/* Internal PCIe Host Controller Information.*/ ++struct brcm_pcie { ++ struct device *dev; ++ void __iomem *base; ++ struct clk *clk; ++ struct pci_bus *root_bus; ++ struct device_node *np; ++ bool ssc; ++ int gen; ++}; ++ ++/* ++ * This is to convert the size of the inbound "BAR" region to the ++ * non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE ++ */ ++static int brcm_pcie_encode_ibar_size(u64 size) ++{ ++ int log2_in = ilog2(size); ++ ++ if (log2_in >= 12 && log2_in <= 15) ++ /* Covers 4KB to 32KB (inclusive) */ ++ return (log2_in - 12) + 0x1c; ++ else if (log2_in >= 16 && log2_in <= 35) ++ /* Covers 64KB to 32GB, (inclusive) */ ++ return log2_in - 15; ++ /* Something is awry so disable */ ++ return 0; ++} ++ ++static u32 brcm_pcie_mdio_form_pkt(int port, int regad, int cmd) ++{ ++ u32 pkt = 0; ++ ++ pkt |= FIELD_PREP(MDIO_PORT_MASK, port); ++ pkt |= FIELD_PREP(MDIO_REGAD_MASK, regad); ++ pkt |= FIELD_PREP(MDIO_CMD_MASK, cmd); ++ ++ return pkt; ++} ++ ++/* negative return value indicates error */ ++static int brcm_pcie_mdio_read(void __iomem *base, u8 port, u8 regad, u32 *val) ++{ ++ int tries; ++ u32 data; ++ ++ writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_READ), ++ base + PCIE_RC_DL_MDIO_ADDR); ++ readl(base + PCIE_RC_DL_MDIO_ADDR); ++ ++ data = readl(base + PCIE_RC_DL_MDIO_RD_DATA); ++ for (tries = 0; !MDIO_RD_DONE(data) && tries < 10; tries++) { ++ udelay(10); ++ data = readl(base + PCIE_RC_DL_MDIO_RD_DATA); ++ } ++ ++ *val = FIELD_GET(MDIO_DATA_MASK, data); ++ return MDIO_RD_DONE(data) ? 0 : -EIO; ++} ++ ++/* negative return value indicates error */ ++static int brcm_pcie_mdio_write(void __iomem *base, u8 port, ++ u8 regad, u16 wrdata) ++{ ++ int tries; ++ u32 data; ++ ++ writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_WRITE), ++ base + PCIE_RC_DL_MDIO_ADDR); ++ readl(base + PCIE_RC_DL_MDIO_ADDR); ++ writel(MDIO_DATA_DONE_MASK | wrdata, base + PCIE_RC_DL_MDIO_WR_DATA); ++ ++ data = readl(base + PCIE_RC_DL_MDIO_WR_DATA); ++ for (tries = 0; !MDIO_WT_DONE(data) && tries < 10; tries++) { ++ udelay(10); ++ data = readl(base + PCIE_RC_DL_MDIO_WR_DATA); ++ } ++ ++ return MDIO_WT_DONE(data) ? 0 : -EIO; ++} ++ ++/* ++ * Configures device for Spread Spectrum Clocking (SSC) mode; a negative ++ * return value indicates error. ++ */ ++static int brcm_pcie_set_ssc(struct brcm_pcie *pcie) ++{ ++ int pll, ssc; ++ int ret; ++ u32 tmp; ++ ++ ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET, ++ SSC_REGS_ADDR); ++ if (ret < 0) ++ return ret; ++ ++ ret = brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, ++ SSC_CNTL_OFFSET, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ u32p_replace_bits(&tmp, 1, SSC_CNTL_OVRD_EN_MASK); ++ u32p_replace_bits(&tmp, 1, SSC_CNTL_OVRD_VAL_MASK); ++ ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, ++ SSC_CNTL_OFFSET, tmp); ++ if (ret < 0) ++ return ret; ++ ++ usleep_range(1000, 2000); ++ ret = brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, ++ SSC_STATUS_OFFSET, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ ssc = FIELD_GET(SSC_STATUS_SSC_MASK, tmp); ++ pll = FIELD_GET(SSC_STATUS_PLL_LOCK_MASK, tmp); ++ ++ return ssc && pll ? 0 : -EIO; ++} ++ ++/* Limits operation to a specific generation (1, 2, or 3) */ ++static void brcm_pcie_set_gen(struct brcm_pcie *pcie, int gen) ++{ ++ u16 lnkctl2 = readw(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2); ++ u32 lnkcap = readl(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP); ++ ++ lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen; ++ writel(lnkcap, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP); ++ ++ lnkctl2 = (lnkctl2 & ~0xf) | gen; ++ writew(lnkctl2, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2); ++} ++ ++static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie, ++ unsigned int win, u64 cpu_addr, ++ u64 pcie_addr, u64 size) ++{ ++ u32 cpu_addr_mb_high, limit_addr_mb_high; ++ phys_addr_t cpu_addr_mb, limit_addr_mb; ++ int high_addr_shift; ++ u32 tmp; ++ ++ /* Set the base of the pcie_addr window */ ++ writel(lower_32_bits(pcie_addr), pcie->base + PCIE_MEM_WIN0_LO(win)); ++ writel(upper_32_bits(pcie_addr), pcie->base + PCIE_MEM_WIN0_HI(win)); ++ ++ /* Write the addr base & limit lower bits (in MBs) */ ++ cpu_addr_mb = cpu_addr / SZ_1M; ++ limit_addr_mb = (cpu_addr + size - 1) / SZ_1M; ++ ++ tmp = readl(pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win)); ++ u32p_replace_bits(&tmp, cpu_addr_mb, ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK); ++ u32p_replace_bits(&tmp, limit_addr_mb, ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK); ++ writel(tmp, pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win)); ++ ++ /* Write the cpu & limit addr upper bits */ ++ high_addr_shift = ++ HWEIGHT32(PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK); ++ ++ cpu_addr_mb_high = cpu_addr_mb >> high_addr_shift; ++ tmp = readl(pcie->base + PCIE_MEM_WIN0_BASE_HI(win)); ++ u32p_replace_bits(&tmp, cpu_addr_mb_high, ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK); ++ writel(tmp, pcie->base + PCIE_MEM_WIN0_BASE_HI(win)); ++ ++ limit_addr_mb_high = limit_addr_mb >> high_addr_shift; ++ tmp = readl(pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); ++ u32p_replace_bits(&tmp, limit_addr_mb_high, ++ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK); ++ writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); ++} ++ ++/* The controller is capable of serving in both RC and EP roles */ ++static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) ++{ ++ void __iomem *base = pcie->base; ++ u32 val = readl(base + PCIE_MISC_PCIE_STATUS); ++ ++ return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK, val); ++} ++ ++static bool brcm_pcie_link_up(struct brcm_pcie *pcie) ++{ ++ u32 val = readl(pcie->base + PCIE_MISC_PCIE_STATUS); ++ u32 dla = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK, val); ++ u32 plu = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK, val); ++ ++ return dla && plu; ++} ++ ++/* Configuration space read/write support */ ++static inline int brcm_pcie_cfg_index(int busnr, int devfn, int reg) ++{ ++ return ((PCI_SLOT(devfn) & 0x1f) << PCIE_EXT_SLOT_SHIFT) ++ | ((PCI_FUNC(devfn) & 0x07) << PCIE_EXT_FUNC_SHIFT) ++ | (busnr << PCIE_EXT_BUSNUM_SHIFT) ++ | (reg & ~3); ++} ++ ++static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn, ++ int where) ++{ ++ struct brcm_pcie *pcie = bus->sysdata; ++ void __iomem *base = pcie->base; ++ int idx; ++ ++ /* Accesses to the RC go right to the RC registers if slot==0 */ ++ if (pci_is_root_bus(bus)) ++ return PCI_SLOT(devfn) ? NULL : base + where; ++ ++ /* For devices, write to the config space index register */ ++ idx = brcm_pcie_cfg_index(bus->number, devfn, 0); ++ writel(idx, pcie->base + PCIE_EXT_CFG_INDEX); ++ return base + PCIE_EXT_CFG_DATA + where; ++} ++ ++static struct pci_ops brcm_pcie_ops = { ++ .map_bus = brcm_pcie_map_conf, ++ .read = pci_generic_config_read, ++ .write = pci_generic_config_write, ++}; ++ ++static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val) ++{ ++ u32 tmp; ++ ++ tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1); ++ u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_INIT_MASK); ++ writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1); ++} ++ ++static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie, u32 val) ++{ ++ u32 tmp; ++ ++ tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1); ++ u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_PERST_MASK); ++ writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1); ++} ++ ++static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, ++ u64 *rc_bar2_size, ++ u64 *rc_bar2_offset) ++{ ++ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); ++ struct device *dev = pcie->dev; ++ struct resource_entry *entry; ++ ++ entry = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM); ++ if (!entry) ++ return -ENODEV; ++ ++ ++ /* ++ * The controller expects the inbound window offset to be calculated as ++ * the difference between PCIe's address space and CPU's. The offset ++ * provided by the firmware is calculated the opposite way, so we ++ * negate it. ++ */ ++ *rc_bar2_offset = -entry->offset; ++ *rc_bar2_size = 1ULL << fls64(entry->res->end - entry->res->start); ++ ++ /* ++ * We validate the inbound memory view even though we should trust ++ * whatever the device-tree provides. This is because of an HW issue on ++ * early Raspberry Pi 4's revisions (bcm2711). It turns out its ++ * firmware has to dynamically edit dma-ranges due to a bug on the ++ * PCIe controller integration, which prohibits any access above the ++ * lower 3GB of memory. Given this, we decided to keep the dma-ranges ++ * in check, avoiding hard to debug device-tree related issues in the ++ * future: ++ * ++ * The PCIe host controller by design must set the inbound viewport to ++ * be a contiguous arrangement of all of the system's memory. In ++ * addition, its size mut be a power of two. To further complicate ++ * matters, the viewport must start on a pcie-address that is aligned ++ * on a multiple of its size. If a portion of the viewport does not ++ * represent system memory -- e.g. 3GB of memory requires a 4GB ++ * viewport -- we can map the outbound memory in or after 3GB and even ++ * though the viewport will overlap the outbound memory the controller ++ * will know to send outbound memory downstream and everything else ++ * upstream. ++ * ++ * For example: ++ * ++ * - The best-case scenario, memory up to 3GB, is to place the inbound ++ * region in the first 4GB of pcie-space, as some legacy devices can ++ * only address 32bits. We would also like to put the MSI under 4GB ++ * as well, since some devices require a 32bit MSI target address. ++ * ++ * - If the system memory is 4GB or larger we cannot start the inbound ++ * region at location 0 (since we have to allow some space for ++ * outbound memory @ 3GB). So instead it will start at the 1x ++ * multiple of its size ++ */ ++ if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size || ++ (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) { ++ dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n", ++ *rc_bar2_size, *rc_bar2_offset); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int brcm_pcie_setup(struct brcm_pcie *pcie) ++{ ++ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); ++ u64 rc_bar2_offset, rc_bar2_size; ++ void __iomem *base = pcie->base; ++ struct device *dev = pcie->dev; ++ struct resource_entry *entry; ++ unsigned int scb_size_val; ++ bool ssc_good = false; ++ struct resource *res; ++ int num_out_wins = 0; ++ u16 nlw, cls, lnksta; ++ int i, ret; ++ u32 tmp; ++ ++ /* Reset the bridge */ ++ brcm_pcie_bridge_sw_init_set(pcie, 1); ++ ++ usleep_range(100, 200); ++ ++ /* Take the bridge out of reset */ ++ brcm_pcie_bridge_sw_init_set(pcie, 0); ++ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK; ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ /* Wait for SerDes to be stable */ ++ usleep_range(100, 200); ++ ++ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */ ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK); ++ u32p_replace_bits(&tmp, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128, ++ PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK); ++ writel(tmp, base + PCIE_MISC_MISC_CTRL); ++ ++ ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size, ++ &rc_bar2_offset); ++ if (ret) ++ return ret; ++ ++ tmp = lower_32_bits(rc_bar2_offset); ++ u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(rc_bar2_size), ++ PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK); ++ writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO); ++ writel(upper_32_bits(rc_bar2_offset), ++ base + PCIE_MISC_RC_BAR2_CONFIG_HI); ++ ++ scb_size_val = rc_bar2_size ? ++ ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */ ++ tmp = readl(base + PCIE_MISC_MISC_CTRL); ++ u32p_replace_bits(&tmp, scb_size_val, ++ PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK); ++ writel(tmp, base + PCIE_MISC_MISC_CTRL); ++ ++ /* disable the PCIe->GISB memory window (RC_BAR1) */ ++ tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO); ++ tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK; ++ writel(tmp, base + PCIE_MISC_RC_BAR1_CONFIG_LO); ++ ++ /* disable the PCIe->SCB memory window (RC_BAR3) */ ++ tmp = readl(base + PCIE_MISC_RC_BAR3_CONFIG_LO); ++ tmp &= ~PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK; ++ writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO); ++ ++ /* Mask all interrupts since we are not handling any yet */ ++ writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_MASK_SET); ++ ++ /* clear any interrupts we find on boot */ ++ writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_CLR); ++ ++ if (pcie->gen) ++ brcm_pcie_set_gen(pcie, pcie->gen); ++ ++ /* Unassert the fundamental reset */ ++ brcm_pcie_perst_set(pcie, 0); ++ ++ /* ++ * Give the RC/EP time to wake up, before trying to configure RC. ++ * Intermittently check status for link-up, up to a total of 100ms. ++ */ ++ for (i = 0; i < 100 && !brcm_pcie_link_up(pcie); i += 5) ++ msleep(5); ++ ++ if (!brcm_pcie_link_up(pcie)) { ++ dev_err(dev, "link down\n"); ++ return -ENODEV; ++ } ++ ++ if (!brcm_pcie_rc_mode(pcie)) { ++ dev_err(dev, "PCIe misconfigured; is in EP mode\n"); ++ return -EINVAL; ++ } ++ ++ resource_list_for_each_entry(entry, &bridge->windows) { ++ res = entry->res; ++ ++ if (resource_type(res) != IORESOURCE_MEM) ++ continue; ++ ++ if (num_out_wins >= BRCM_NUM_PCIE_OUT_WINS) { ++ dev_err(pcie->dev, "too many outbound wins\n"); ++ return -EINVAL; ++ } ++ ++ brcm_pcie_set_outbound_win(pcie, num_out_wins, res->start, ++ res->start - entry->offset, ++ resource_size(res)); ++ num_out_wins++; ++ } ++ ++ /* ++ * For config space accesses on the RC, show the right class for ++ * a PCIe-PCIe bridge (the default setting is to be EP mode). ++ */ ++ tmp = readl(base + PCIE_RC_CFG_PRIV1_ID_VAL3); ++ u32p_replace_bits(&tmp, 0x060400, ++ PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK); ++ writel(tmp, base + PCIE_RC_CFG_PRIV1_ID_VAL3); ++ ++ if (pcie->ssc) { ++ ret = brcm_pcie_set_ssc(pcie); ++ if (ret == 0) ++ ssc_good = true; ++ else ++ dev_err(dev, "failed attempt to enter ssc mode\n"); ++ } ++ ++ lnksta = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA); ++ cls = FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta); ++ nlw = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta); ++ dev_info(dev, "link up, %s x%u %s\n", ++ PCIE_SPEED2STR(cls + PCI_SPEED_133MHz_PCIX_533), ++ nlw, ssc_good ? "(SSC)" : "(!SSC)"); ++ ++ /* PCIe->SCB endian mode for BAR */ ++ tmp = readl(base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1); ++ u32p_replace_bits(&tmp, PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN, ++ PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK); ++ writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1); ++ ++ /* ++ * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1 ++ * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1. ++ */ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ ++ return 0; ++} ++ ++/* L23 is a low-power PCIe link state */ ++static void brcm_pcie_enter_l23(struct brcm_pcie *pcie) ++{ ++ void __iomem *base = pcie->base; ++ int l23, i; ++ u32 tmp; ++ ++ /* Assert request for L23 */ ++ tmp = readl(base + PCIE_MISC_PCIE_CTRL); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK); ++ writel(tmp, base + PCIE_MISC_PCIE_CTRL); ++ ++ /* Wait up to 36 msec for L23 */ ++ tmp = readl(base + PCIE_MISC_PCIE_STATUS); ++ l23 = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK, tmp); ++ for (i = 0; i < 15 && !l23; i++) { ++ usleep_range(2000, 2400); ++ tmp = readl(base + PCIE_MISC_PCIE_STATUS); ++ l23 = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK, ++ tmp); ++ } ++ ++ if (!l23) ++ dev_err(pcie->dev, "failed to enter low-power link state\n"); ++} ++ ++static void brcm_pcie_turn_off(struct brcm_pcie *pcie) ++{ ++ void __iomem *base = pcie->base; ++ int tmp; ++ ++ if (brcm_pcie_link_up(pcie)) ++ brcm_pcie_enter_l23(pcie); ++ /* Assert fundamental reset */ ++ brcm_pcie_perst_set(pcie, 1); ++ ++ /* Deassert request for L23 in case it was asserted */ ++ tmp = readl(base + PCIE_MISC_PCIE_CTRL); ++ u32p_replace_bits(&tmp, 0, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK); ++ writel(tmp, base + PCIE_MISC_PCIE_CTRL); ++ ++ /* Turn off SerDes */ ++ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); ++ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); ++ ++ /* Shutdown PCIe bridge */ ++ brcm_pcie_bridge_sw_init_set(pcie, 1); ++} ++ ++static void __brcm_pcie_remove(struct brcm_pcie *pcie) ++{ ++ brcm_pcie_turn_off(pcie); ++ clk_disable_unprepare(pcie->clk); ++ clk_put(pcie->clk); ++} ++ ++static int brcm_pcie_remove(struct platform_device *pdev) ++{ ++ struct brcm_pcie *pcie = platform_get_drvdata(pdev); ++ ++ pci_stop_root_bus(pcie->root_bus); ++ pci_remove_root_bus(pcie->root_bus); ++ __brcm_pcie_remove(pcie); ++ ++ return 0; ++} ++ ++static int brcm_pcie_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct pci_host_bridge *bridge; ++ struct brcm_pcie *pcie; ++ struct pci_bus *child; ++ struct resource *res; ++ int ret; ++ ++ bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie)); ++ if (!bridge) ++ return -ENOMEM; ++ ++ pcie = pci_host_bridge_priv(bridge); ++ pcie->dev = &pdev->dev; ++ pcie->np = np; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ pcie->base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(pcie->base)) ++ return PTR_ERR(pcie->base); ++ ++ pcie->clk = devm_clk_get_optional(&pdev->dev, "sw_pcie"); ++ if (IS_ERR(pcie->clk)) ++ return PTR_ERR(pcie->clk); ++ ++ ret = of_pci_get_max_link_speed(np); ++ pcie->gen = (ret < 0) ? 0 : ret; ++ ++ pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc"); ++ ++ ret = pci_parse_request_of_pci_ranges(pcie->dev, &bridge->windows, ++ &bridge->dma_ranges, NULL); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(pcie->clk); ++ if (ret) { ++ dev_err(&pdev->dev, "could not enable clock\n"); ++ return ret; ++ } ++ ++ ret = brcm_pcie_setup(pcie); ++ if (ret) ++ goto fail; ++ ++ bridge->dev.parent = &pdev->dev; ++ bridge->busnr = 0; ++ bridge->ops = &brcm_pcie_ops; ++ bridge->sysdata = pcie; ++ bridge->map_irq = of_irq_parse_and_map_pci; ++ bridge->swizzle_irq = pci_common_swizzle; ++ ++ ret = pci_scan_root_bus_bridge(bridge); ++ if (ret < 0) { ++ dev_err(pcie->dev, "Scanning root bridge failed\n"); ++ goto fail; ++ } ++ ++ pci_assign_unassigned_bus_resources(bridge->bus); ++ list_for_each_entry(child, &bridge->bus->children, node) ++ pcie_bus_configure_settings(child); ++ pci_bus_add_devices(bridge->bus); ++ platform_set_drvdata(pdev, pcie); ++ pcie->root_bus = bridge->bus; ++ ++ return 0; ++fail: ++ __brcm_pcie_remove(pcie); ++ return ret; ++} ++ ++static const struct of_device_id brcm_pcie_match[] = { ++ { .compatible = "brcm,bcm2711-pcie" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, brcm_pcie_match); ++ ++static struct platform_driver brcm_pcie_driver = { ++ .probe = brcm_pcie_probe, ++ .remove = brcm_pcie_remove, ++ .driver = { ++ .name = "brcm-pcie", ++ .of_match_table = brcm_pcie_match, ++ }, ++}; ++module_platform_driver(brcm_pcie_driver); ++ ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("Broadcom STB PCIe RC driver"); ++MODULE_AUTHOR("Broadcom"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0459-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch b/target/linux/bcm27xx/patches-5.4/950-0459-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch deleted file mode 100644 index ca97a1966e6..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0459-PCI-brcmstb-Add-Broadcom-STB-PCIe-host-controller-dr.patch +++ /dev/null @@ -1,810 +0,0 @@ -From 4d9470c29736bf81bdb0d21da24cf350b1e99402 Mon Sep 17 00:00:00 2001 -From: Jim Quinlan -Date: Mon, 16 Dec 2019 12:01:09 +0100 -Subject: [PATCH] PCI: brcmstb: Add Broadcom STB PCIe host controller - driver - -commit c0452137034bda8f686dd9a2e167949bfffd6776 upstream. - -This adds a basic driver for Broadcom's STB PCIe controller, for now -aimed at Raspberry Pi 4's SoC, bcm2711. - -Signed-off-by: Jim Quinlan -Co-developed-by: Nicolas Saenz Julienne -Signed-off-by: Nicolas Saenz Julienne -[lorenzo.pieralisi@arm.com: updated brcm_pcie_get_rc_bar2_size_and_offset()according to https://lore.kernel.org/linux-pci/be8ddb33a7360af1815cf686f77f3f0913d02be3.camel@suse.de] -Signed-off-by: Lorenzo Pieralisi -Reviewed-by: Andrew Murray -Reviewed-by: Jeremy Linton ---- - drivers/pci/controller/Kconfig | 8 + - drivers/pci/controller/Makefile | 1 + - drivers/pci/controller/pcie-brcmstb.c | 755 ++++++++++++++++++++++++++ - 3 files changed, 764 insertions(+) - create mode 100644 drivers/pci/controller/pcie-brcmstb.c - ---- a/drivers/pci/controller/Kconfig -+++ b/drivers/pci/controller/Kconfig -@@ -281,6 +281,14 @@ config VMD - To compile this driver as a module, choose M here: the - module will be called vmd. - -+config PCIE_BRCMSTB -+ tristate "Broadcom Brcmstb PCIe host controller" -+ depends on ARCH_BCM2835 || COMPILE_TEST -+ depends on OF -+ help -+ Say Y here to enable PCIe host controller support for -+ Broadcom STB based SoCs, like the Raspberry Pi 4. -+ - config PCI_HYPERV_INTERFACE - tristate "Hyper-V PCI Interface" - depends on X86 && HYPERV && PCI_MSI && PCI_MSI_IRQ_DOMAIN && X86_64 ---- a/drivers/pci/controller/Makefile -+++ b/drivers/pci/controller/Makefile -@@ -30,6 +30,7 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-medi - obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o - obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o - obj-$(CONFIG_VMD) += vmd.o -+obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o - # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW - obj-y += dwc/ - ---- /dev/null -+++ b/drivers/pci/controller/pcie-brcmstb.c -@@ -0,0 +1,755 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* Copyright (C) 2009 - 2019 Broadcom */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "../pci.h" -+ -+/* BRCM_PCIE_CAP_REGS - Offset for the mandatory capability config regs */ -+#define BRCM_PCIE_CAP_REGS 0x00ac -+ -+/* Broadcom STB PCIe Register Offsets */ -+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1 0x0188 -+#define PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK 0xc -+#define PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN 0x0 -+ -+#define PCIE_RC_CFG_PRIV1_ID_VAL3 0x043c -+#define PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK 0xffffff -+ -+#define PCIE_RC_DL_MDIO_ADDR 0x1100 -+#define PCIE_RC_DL_MDIO_WR_DATA 0x1104 -+#define PCIE_RC_DL_MDIO_RD_DATA 0x1108 -+ -+#define PCIE_MISC_MISC_CTRL 0x4008 -+#define PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK 0x1000 -+#define PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK 0x2000 -+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK 0x300000 -+#define PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128 0x0 -+#define PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK 0xf8000000 -+ -+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO 0x400c -+#define PCIE_MEM_WIN0_LO(win) \ -+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LO + ((win) * 4) -+ -+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI 0x4010 -+#define PCIE_MEM_WIN0_HI(win) \ -+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_HI + ((win) * 4) -+ -+#define PCIE_MISC_RC_BAR1_CONFIG_LO 0x402c -+#define PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK 0x1f -+ -+#define PCIE_MISC_RC_BAR2_CONFIG_LO 0x4034 -+#define PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK 0x1f -+#define PCIE_MISC_RC_BAR2_CONFIG_HI 0x4038 -+ -+#define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c -+#define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f -+ -+#define PCIE_MISC_PCIE_CTRL 0x4064 -+#define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 -+ -+#define PCIE_MISC_PCIE_STATUS 0x4068 -+#define PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK 0x80 -+#define PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK 0x20 -+#define PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK 0x10 -+#define PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK 0x40 -+ -+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT 0x4070 -+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK 0xfff00000 -+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK 0xfff0 -+#define PCIE_MEM_WIN0_BASE_LIMIT(win) \ -+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT + ((win) * 4) -+ -+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI 0x4080 -+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK 0xff -+#define PCIE_MEM_WIN0_BASE_HI(win) \ -+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI + ((win) * 8) -+ -+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI 0x4084 -+#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK 0xff -+#define PCIE_MEM_WIN0_LIMIT_HI(win) \ -+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI + ((win) * 8) -+ -+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG 0x4204 -+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK 0x2 -+#define PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK 0x08000000 -+ -+#define PCIE_MSI_INTR2_STATUS 0x4500 -+#define PCIE_MSI_INTR2_CLR 0x4508 -+#define PCIE_MSI_INTR2_MASK_SET 0x4510 -+#define PCIE_MSI_INTR2_MASK_CLR 0x4514 -+ -+#define PCIE_EXT_CFG_DATA 0x8000 -+ -+#define PCIE_EXT_CFG_INDEX 0x9000 -+#define PCIE_EXT_BUSNUM_SHIFT 20 -+#define PCIE_EXT_SLOT_SHIFT 15 -+#define PCIE_EXT_FUNC_SHIFT 12 -+ -+#define PCIE_RGR1_SW_INIT_1 0x9210 -+#define PCIE_RGR1_SW_INIT_1_PERST_MASK 0x1 -+#define PCIE_RGR1_SW_INIT_1_INIT_MASK 0x2 -+ -+/* PCIe parameters */ -+#define BRCM_NUM_PCIE_OUT_WINS 0x4 -+ -+/* MDIO registers */ -+#define MDIO_PORT0 0x0 -+#define MDIO_DATA_MASK 0x7fffffff -+#define MDIO_PORT_MASK 0xf0000 -+#define MDIO_REGAD_MASK 0xffff -+#define MDIO_CMD_MASK 0xfff00000 -+#define MDIO_CMD_READ 0x1 -+#define MDIO_CMD_WRITE 0x0 -+#define MDIO_DATA_DONE_MASK 0x80000000 -+#define MDIO_RD_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 1 : 0) -+#define MDIO_WT_DONE(x) (((x) & MDIO_DATA_DONE_MASK) ? 0 : 1) -+#define SSC_REGS_ADDR 0x1100 -+#define SET_ADDR_OFFSET 0x1f -+#define SSC_CNTL_OFFSET 0x2 -+#define SSC_CNTL_OVRD_EN_MASK 0x8000 -+#define SSC_CNTL_OVRD_VAL_MASK 0x4000 -+#define SSC_STATUS_OFFSET 0x1 -+#define SSC_STATUS_SSC_MASK 0x400 -+#define SSC_STATUS_PLL_LOCK_MASK 0x800 -+ -+/* Internal PCIe Host Controller Information.*/ -+struct brcm_pcie { -+ struct device *dev; -+ void __iomem *base; -+ struct clk *clk; -+ struct pci_bus *root_bus; -+ struct device_node *np; -+ bool ssc; -+ int gen; -+}; -+ -+/* -+ * This is to convert the size of the inbound "BAR" region to the -+ * non-linear values of PCIE_X_MISC_RC_BAR[123]_CONFIG_LO.SIZE -+ */ -+static int brcm_pcie_encode_ibar_size(u64 size) -+{ -+ int log2_in = ilog2(size); -+ -+ if (log2_in >= 12 && log2_in <= 15) -+ /* Covers 4KB to 32KB (inclusive) */ -+ return (log2_in - 12) + 0x1c; -+ else if (log2_in >= 16 && log2_in <= 35) -+ /* Covers 64KB to 32GB, (inclusive) */ -+ return log2_in - 15; -+ /* Something is awry so disable */ -+ return 0; -+} -+ -+static u32 brcm_pcie_mdio_form_pkt(int port, int regad, int cmd) -+{ -+ u32 pkt = 0; -+ -+ pkt |= FIELD_PREP(MDIO_PORT_MASK, port); -+ pkt |= FIELD_PREP(MDIO_REGAD_MASK, regad); -+ pkt |= FIELD_PREP(MDIO_CMD_MASK, cmd); -+ -+ return pkt; -+} -+ -+/* negative return value indicates error */ -+static int brcm_pcie_mdio_read(void __iomem *base, u8 port, u8 regad, u32 *val) -+{ -+ int tries; -+ u32 data; -+ -+ writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_READ), -+ base + PCIE_RC_DL_MDIO_ADDR); -+ readl(base + PCIE_RC_DL_MDIO_ADDR); -+ -+ data = readl(base + PCIE_RC_DL_MDIO_RD_DATA); -+ for (tries = 0; !MDIO_RD_DONE(data) && tries < 10; tries++) { -+ udelay(10); -+ data = readl(base + PCIE_RC_DL_MDIO_RD_DATA); -+ } -+ -+ *val = FIELD_GET(MDIO_DATA_MASK, data); -+ return MDIO_RD_DONE(data) ? 0 : -EIO; -+} -+ -+/* negative return value indicates error */ -+static int brcm_pcie_mdio_write(void __iomem *base, u8 port, -+ u8 regad, u16 wrdata) -+{ -+ int tries; -+ u32 data; -+ -+ writel(brcm_pcie_mdio_form_pkt(port, regad, MDIO_CMD_WRITE), -+ base + PCIE_RC_DL_MDIO_ADDR); -+ readl(base + PCIE_RC_DL_MDIO_ADDR); -+ writel(MDIO_DATA_DONE_MASK | wrdata, base + PCIE_RC_DL_MDIO_WR_DATA); -+ -+ data = readl(base + PCIE_RC_DL_MDIO_WR_DATA); -+ for (tries = 0; !MDIO_WT_DONE(data) && tries < 10; tries++) { -+ udelay(10); -+ data = readl(base + PCIE_RC_DL_MDIO_WR_DATA); -+ } -+ -+ return MDIO_WT_DONE(data) ? 0 : -EIO; -+} -+ -+/* -+ * Configures device for Spread Spectrum Clocking (SSC) mode; a negative -+ * return value indicates error. -+ */ -+static int brcm_pcie_set_ssc(struct brcm_pcie *pcie) -+{ -+ int pll, ssc; -+ int ret; -+ u32 tmp; -+ -+ ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET, -+ SSC_REGS_ADDR); -+ if (ret < 0) -+ return ret; -+ -+ ret = brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, -+ SSC_CNTL_OFFSET, &tmp); -+ if (ret < 0) -+ return ret; -+ -+ u32p_replace_bits(&tmp, 1, SSC_CNTL_OVRD_EN_MASK); -+ u32p_replace_bits(&tmp, 1, SSC_CNTL_OVRD_VAL_MASK); -+ ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, -+ SSC_CNTL_OFFSET, tmp); -+ if (ret < 0) -+ return ret; -+ -+ usleep_range(1000, 2000); -+ ret = brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, -+ SSC_STATUS_OFFSET, &tmp); -+ if (ret < 0) -+ return ret; -+ -+ ssc = FIELD_GET(SSC_STATUS_SSC_MASK, tmp); -+ pll = FIELD_GET(SSC_STATUS_PLL_LOCK_MASK, tmp); -+ -+ return ssc && pll ? 0 : -EIO; -+} -+ -+/* Limits operation to a specific generation (1, 2, or 3) */ -+static void brcm_pcie_set_gen(struct brcm_pcie *pcie, int gen) -+{ -+ u16 lnkctl2 = readw(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2); -+ u32 lnkcap = readl(pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP); -+ -+ lnkcap = (lnkcap & ~PCI_EXP_LNKCAP_SLS) | gen; -+ writel(lnkcap, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCAP); -+ -+ lnkctl2 = (lnkctl2 & ~0xf) | gen; -+ writew(lnkctl2, pcie->base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKCTL2); -+} -+ -+static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie, -+ unsigned int win, u64 cpu_addr, -+ u64 pcie_addr, u64 size) -+{ -+ u32 cpu_addr_mb_high, limit_addr_mb_high; -+ phys_addr_t cpu_addr_mb, limit_addr_mb; -+ int high_addr_shift; -+ u32 tmp; -+ -+ /* Set the base of the pcie_addr window */ -+ writel(lower_32_bits(pcie_addr), pcie->base + PCIE_MEM_WIN0_LO(win)); -+ writel(upper_32_bits(pcie_addr), pcie->base + PCIE_MEM_WIN0_HI(win)); -+ -+ /* Write the addr base & limit lower bits (in MBs) */ -+ cpu_addr_mb = cpu_addr / SZ_1M; -+ limit_addr_mb = (cpu_addr + size - 1) / SZ_1M; -+ -+ tmp = readl(pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win)); -+ u32p_replace_bits(&tmp, cpu_addr_mb, -+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK); -+ u32p_replace_bits(&tmp, limit_addr_mb, -+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK); -+ writel(tmp, pcie->base + PCIE_MEM_WIN0_BASE_LIMIT(win)); -+ -+ /* Write the cpu & limit addr upper bits */ -+ high_addr_shift = -+ HWEIGHT32(PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK); -+ -+ cpu_addr_mb_high = cpu_addr_mb >> high_addr_shift; -+ tmp = readl(pcie->base + PCIE_MEM_WIN0_BASE_HI(win)); -+ u32p_replace_bits(&tmp, cpu_addr_mb_high, -+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_HI_BASE_MASK); -+ writel(tmp, pcie->base + PCIE_MEM_WIN0_BASE_HI(win)); -+ -+ limit_addr_mb_high = limit_addr_mb >> high_addr_shift; -+ tmp = readl(pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); -+ u32p_replace_bits(&tmp, limit_addr_mb_high, -+ PCIE_MISC_CPU_2_PCIE_MEM_WIN0_LIMIT_HI_LIMIT_MASK); -+ writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); -+} -+ -+/* The controller is capable of serving in both RC and EP roles */ -+static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) -+{ -+ void __iomem *base = pcie->base; -+ u32 val = readl(base + PCIE_MISC_PCIE_STATUS); -+ -+ return !!FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PORT_MASK, val); -+} -+ -+static bool brcm_pcie_link_up(struct brcm_pcie *pcie) -+{ -+ u32 val = readl(pcie->base + PCIE_MISC_PCIE_STATUS); -+ u32 dla = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_DL_ACTIVE_MASK, val); -+ u32 plu = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK, val); -+ -+ return dla && plu; -+} -+ -+/* Configuration space read/write support */ -+static inline int brcm_pcie_cfg_index(int busnr, int devfn, int reg) -+{ -+ return ((PCI_SLOT(devfn) & 0x1f) << PCIE_EXT_SLOT_SHIFT) -+ | ((PCI_FUNC(devfn) & 0x07) << PCIE_EXT_FUNC_SHIFT) -+ | (busnr << PCIE_EXT_BUSNUM_SHIFT) -+ | (reg & ~3); -+} -+ -+static void __iomem *brcm_pcie_map_conf(struct pci_bus *bus, unsigned int devfn, -+ int where) -+{ -+ struct brcm_pcie *pcie = bus->sysdata; -+ void __iomem *base = pcie->base; -+ int idx; -+ -+ /* Accesses to the RC go right to the RC registers if slot==0 */ -+ if (pci_is_root_bus(bus)) -+ return PCI_SLOT(devfn) ? NULL : base + where; -+ -+ /* For devices, write to the config space index register */ -+ idx = brcm_pcie_cfg_index(bus->number, devfn, 0); -+ writel(idx, pcie->base + PCIE_EXT_CFG_INDEX); -+ return base + PCIE_EXT_CFG_DATA + where; -+} -+ -+static struct pci_ops brcm_pcie_ops = { -+ .map_bus = brcm_pcie_map_conf, -+ .read = pci_generic_config_read, -+ .write = pci_generic_config_write, -+}; -+ -+static inline void brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val) -+{ -+ u32 tmp; -+ -+ tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1); -+ u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_INIT_MASK); -+ writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1); -+} -+ -+static inline void brcm_pcie_perst_set(struct brcm_pcie *pcie, u32 val) -+{ -+ u32 tmp; -+ -+ tmp = readl(pcie->base + PCIE_RGR1_SW_INIT_1); -+ u32p_replace_bits(&tmp, val, PCIE_RGR1_SW_INIT_1_PERST_MASK); -+ writel(tmp, pcie->base + PCIE_RGR1_SW_INIT_1); -+} -+ -+static inline int brcm_pcie_get_rc_bar2_size_and_offset(struct brcm_pcie *pcie, -+ u64 *rc_bar2_size, -+ u64 *rc_bar2_offset) -+{ -+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); -+ struct device *dev = pcie->dev; -+ struct resource_entry *entry; -+ -+ entry = resource_list_first_type(&bridge->dma_ranges, IORESOURCE_MEM); -+ if (!entry) -+ return -ENODEV; -+ -+ -+ /* -+ * The controller expects the inbound window offset to be calculated as -+ * the difference between PCIe's address space and CPU's. The offset -+ * provided by the firmware is calculated the opposite way, so we -+ * negate it. -+ */ -+ *rc_bar2_offset = -entry->offset; -+ *rc_bar2_size = 1ULL << fls64(entry->res->end - entry->res->start); -+ -+ /* -+ * We validate the inbound memory view even though we should trust -+ * whatever the device-tree provides. This is because of an HW issue on -+ * early Raspberry Pi 4's revisions (bcm2711). It turns out its -+ * firmware has to dynamically edit dma-ranges due to a bug on the -+ * PCIe controller integration, which prohibits any access above the -+ * lower 3GB of memory. Given this, we decided to keep the dma-ranges -+ * in check, avoiding hard to debug device-tree related issues in the -+ * future: -+ * -+ * The PCIe host controller by design must set the inbound viewport to -+ * be a contiguous arrangement of all of the system's memory. In -+ * addition, its size mut be a power of two. To further complicate -+ * matters, the viewport must start on a pcie-address that is aligned -+ * on a multiple of its size. If a portion of the viewport does not -+ * represent system memory -- e.g. 3GB of memory requires a 4GB -+ * viewport -- we can map the outbound memory in or after 3GB and even -+ * though the viewport will overlap the outbound memory the controller -+ * will know to send outbound memory downstream and everything else -+ * upstream. -+ * -+ * For example: -+ * -+ * - The best-case scenario, memory up to 3GB, is to place the inbound -+ * region in the first 4GB of pcie-space, as some legacy devices can -+ * only address 32bits. We would also like to put the MSI under 4GB -+ * as well, since some devices require a 32bit MSI target address. -+ * -+ * - If the system memory is 4GB or larger we cannot start the inbound -+ * region at location 0 (since we have to allow some space for -+ * outbound memory @ 3GB). So instead it will start at the 1x -+ * multiple of its size -+ */ -+ if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size || -+ (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) { -+ dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n", -+ *rc_bar2_size, *rc_bar2_offset); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int brcm_pcie_setup(struct brcm_pcie *pcie) -+{ -+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie); -+ u64 rc_bar2_offset, rc_bar2_size; -+ void __iomem *base = pcie->base; -+ struct device *dev = pcie->dev; -+ struct resource_entry *entry; -+ unsigned int scb_size_val; -+ bool ssc_good = false; -+ struct resource *res; -+ int num_out_wins = 0; -+ u16 nlw, cls, lnksta; -+ int i, ret; -+ u32 tmp; -+ -+ /* Reset the bridge */ -+ brcm_pcie_bridge_sw_init_set(pcie, 1); -+ -+ usleep_range(100, 200); -+ -+ /* Take the bridge out of reset */ -+ brcm_pcie_bridge_sw_init_set(pcie, 0); -+ -+ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); -+ tmp &= ~PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK; -+ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); -+ /* Wait for SerDes to be stable */ -+ usleep_range(100, 200); -+ -+ /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */ -+ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_SCB_ACCESS_EN_MASK); -+ u32p_replace_bits(&tmp, 1, PCIE_MISC_MISC_CTRL_CFG_READ_UR_MODE_MASK); -+ u32p_replace_bits(&tmp, PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_128, -+ PCIE_MISC_MISC_CTRL_MAX_BURST_SIZE_MASK); -+ writel(tmp, base + PCIE_MISC_MISC_CTRL); -+ -+ ret = brcm_pcie_get_rc_bar2_size_and_offset(pcie, &rc_bar2_size, -+ &rc_bar2_offset); -+ if (ret) -+ return ret; -+ -+ tmp = lower_32_bits(rc_bar2_offset); -+ u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(rc_bar2_size), -+ PCIE_MISC_RC_BAR2_CONFIG_LO_SIZE_MASK); -+ writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO); -+ writel(upper_32_bits(rc_bar2_offset), -+ base + PCIE_MISC_RC_BAR2_CONFIG_HI); -+ -+ scb_size_val = rc_bar2_size ? -+ ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */ -+ tmp = readl(base + PCIE_MISC_MISC_CTRL); -+ u32p_replace_bits(&tmp, scb_size_val, -+ PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK); -+ writel(tmp, base + PCIE_MISC_MISC_CTRL); -+ -+ /* disable the PCIe->GISB memory window (RC_BAR1) */ -+ tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO); -+ tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK; -+ writel(tmp, base + PCIE_MISC_RC_BAR1_CONFIG_LO); -+ -+ /* disable the PCIe->SCB memory window (RC_BAR3) */ -+ tmp = readl(base + PCIE_MISC_RC_BAR3_CONFIG_LO); -+ tmp &= ~PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK; -+ writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO); -+ -+ /* Mask all interrupts since we are not handling any yet */ -+ writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_MASK_SET); -+ -+ /* clear any interrupts we find on boot */ -+ writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_CLR); -+ -+ if (pcie->gen) -+ brcm_pcie_set_gen(pcie, pcie->gen); -+ -+ /* Unassert the fundamental reset */ -+ brcm_pcie_perst_set(pcie, 0); -+ -+ /* -+ * Give the RC/EP time to wake up, before trying to configure RC. -+ * Intermittently check status for link-up, up to a total of 100ms. -+ */ -+ for (i = 0; i < 100 && !brcm_pcie_link_up(pcie); i += 5) -+ msleep(5); -+ -+ if (!brcm_pcie_link_up(pcie)) { -+ dev_err(dev, "link down\n"); -+ return -ENODEV; -+ } -+ -+ if (!brcm_pcie_rc_mode(pcie)) { -+ dev_err(dev, "PCIe misconfigured; is in EP mode\n"); -+ return -EINVAL; -+ } -+ -+ resource_list_for_each_entry(entry, &bridge->windows) { -+ res = entry->res; -+ -+ if (resource_type(res) != IORESOURCE_MEM) -+ continue; -+ -+ if (num_out_wins >= BRCM_NUM_PCIE_OUT_WINS) { -+ dev_err(pcie->dev, "too many outbound wins\n"); -+ return -EINVAL; -+ } -+ -+ brcm_pcie_set_outbound_win(pcie, num_out_wins, res->start, -+ res->start - entry->offset, -+ resource_size(res)); -+ num_out_wins++; -+ } -+ -+ /* -+ * For config space accesses on the RC, show the right class for -+ * a PCIe-PCIe bridge (the default setting is to be EP mode). -+ */ -+ tmp = readl(base + PCIE_RC_CFG_PRIV1_ID_VAL3); -+ u32p_replace_bits(&tmp, 0x060400, -+ PCIE_RC_CFG_PRIV1_ID_VAL3_CLASS_CODE_MASK); -+ writel(tmp, base + PCIE_RC_CFG_PRIV1_ID_VAL3); -+ -+ if (pcie->ssc) { -+ ret = brcm_pcie_set_ssc(pcie); -+ if (ret == 0) -+ ssc_good = true; -+ else -+ dev_err(dev, "failed attempt to enter ssc mode\n"); -+ } -+ -+ lnksta = readw(base + BRCM_PCIE_CAP_REGS + PCI_EXP_LNKSTA); -+ cls = FIELD_GET(PCI_EXP_LNKSTA_CLS, lnksta); -+ nlw = FIELD_GET(PCI_EXP_LNKSTA_NLW, lnksta); -+ dev_info(dev, "link up, %s x%u %s\n", -+ PCIE_SPEED2STR(cls + PCI_SPEED_133MHz_PCIX_533), -+ nlw, ssc_good ? "(SSC)" : "(!SSC)"); -+ -+ /* PCIe->SCB endian mode for BAR */ -+ tmp = readl(base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1); -+ u32p_replace_bits(&tmp, PCIE_RC_CFG_VENDOR_SPCIFIC_REG1_LITTLE_ENDIAN, -+ PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1_ENDIAN_MODE_BAR2_MASK); -+ writel(tmp, base + PCIE_RC_CFG_VENDOR_VENDOR_SPECIFIC_REG1); -+ -+ /* -+ * Refclk from RC should be gated with CLKREQ# input when ASPM L0s,L1 -+ * is enabled => setting the CLKREQ_DEBUG_ENABLE field to 1. -+ */ -+ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); -+ tmp |= PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK; -+ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); -+ -+ return 0; -+} -+ -+/* L23 is a low-power PCIe link state */ -+static void brcm_pcie_enter_l23(struct brcm_pcie *pcie) -+{ -+ void __iomem *base = pcie->base; -+ int l23, i; -+ u32 tmp; -+ -+ /* Assert request for L23 */ -+ tmp = readl(base + PCIE_MISC_PCIE_CTRL); -+ u32p_replace_bits(&tmp, 1, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK); -+ writel(tmp, base + PCIE_MISC_PCIE_CTRL); -+ -+ /* Wait up to 36 msec for L23 */ -+ tmp = readl(base + PCIE_MISC_PCIE_STATUS); -+ l23 = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK, tmp); -+ for (i = 0; i < 15 && !l23; i++) { -+ usleep_range(2000, 2400); -+ tmp = readl(base + PCIE_MISC_PCIE_STATUS); -+ l23 = FIELD_GET(PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK, -+ tmp); -+ } -+ -+ if (!l23) -+ dev_err(pcie->dev, "failed to enter low-power link state\n"); -+} -+ -+static void brcm_pcie_turn_off(struct brcm_pcie *pcie) -+{ -+ void __iomem *base = pcie->base; -+ int tmp; -+ -+ if (brcm_pcie_link_up(pcie)) -+ brcm_pcie_enter_l23(pcie); -+ /* Assert fundamental reset */ -+ brcm_pcie_perst_set(pcie, 1); -+ -+ /* Deassert request for L23 in case it was asserted */ -+ tmp = readl(base + PCIE_MISC_PCIE_CTRL); -+ u32p_replace_bits(&tmp, 0, PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK); -+ writel(tmp, base + PCIE_MISC_PCIE_CTRL); -+ -+ /* Turn off SerDes */ -+ tmp = readl(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); -+ u32p_replace_bits(&tmp, 1, PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); -+ writel(tmp, base + PCIE_MISC_HARD_PCIE_HARD_DEBUG); -+ -+ /* Shutdown PCIe bridge */ -+ brcm_pcie_bridge_sw_init_set(pcie, 1); -+} -+ -+static void __brcm_pcie_remove(struct brcm_pcie *pcie) -+{ -+ brcm_pcie_turn_off(pcie); -+ clk_disable_unprepare(pcie->clk); -+ clk_put(pcie->clk); -+} -+ -+static int brcm_pcie_remove(struct platform_device *pdev) -+{ -+ struct brcm_pcie *pcie = platform_get_drvdata(pdev); -+ -+ pci_stop_root_bus(pcie->root_bus); -+ pci_remove_root_bus(pcie->root_bus); -+ __brcm_pcie_remove(pcie); -+ -+ return 0; -+} -+ -+static int brcm_pcie_probe(struct platform_device *pdev) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct pci_host_bridge *bridge; -+ struct brcm_pcie *pcie; -+ struct pci_bus *child; -+ struct resource *res; -+ int ret; -+ -+ bridge = devm_pci_alloc_host_bridge(&pdev->dev, sizeof(*pcie)); -+ if (!bridge) -+ return -ENOMEM; -+ -+ pcie = pci_host_bridge_priv(bridge); -+ pcie->dev = &pdev->dev; -+ pcie->np = np; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ pcie->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(pcie->base)) -+ return PTR_ERR(pcie->base); -+ -+ pcie->clk = devm_clk_get_optional(&pdev->dev, "sw_pcie"); -+ if (IS_ERR(pcie->clk)) -+ return PTR_ERR(pcie->clk); -+ -+ ret = of_pci_get_max_link_speed(np); -+ pcie->gen = (ret < 0) ? 0 : ret; -+ -+ pcie->ssc = of_property_read_bool(np, "brcm,enable-ssc"); -+ -+ ret = pci_parse_request_of_pci_ranges(pcie->dev, &bridge->windows, -+ &bridge->dma_ranges, NULL); -+ if (ret) -+ return ret; -+ -+ ret = clk_prepare_enable(pcie->clk); -+ if (ret) { -+ dev_err(&pdev->dev, "could not enable clock\n"); -+ return ret; -+ } -+ -+ ret = brcm_pcie_setup(pcie); -+ if (ret) -+ goto fail; -+ -+ bridge->dev.parent = &pdev->dev; -+ bridge->busnr = 0; -+ bridge->ops = &brcm_pcie_ops; -+ bridge->sysdata = pcie; -+ bridge->map_irq = of_irq_parse_and_map_pci; -+ bridge->swizzle_irq = pci_common_swizzle; -+ -+ ret = pci_scan_root_bus_bridge(bridge); -+ if (ret < 0) { -+ dev_err(pcie->dev, "Scanning root bridge failed\n"); -+ goto fail; -+ } -+ -+ pci_assign_unassigned_bus_resources(bridge->bus); -+ list_for_each_entry(child, &bridge->bus->children, node) -+ pcie_bus_configure_settings(child); -+ pci_bus_add_devices(bridge->bus); -+ platform_set_drvdata(pdev, pcie); -+ pcie->root_bus = bridge->bus; -+ -+ return 0; -+fail: -+ __brcm_pcie_remove(pcie); -+ return ret; -+} -+ -+static const struct of_device_id brcm_pcie_match[] = { -+ { .compatible = "brcm,bcm2711-pcie" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, brcm_pcie_match); -+ -+static struct platform_driver brcm_pcie_driver = { -+ .probe = brcm_pcie_probe, -+ .remove = brcm_pcie_remove, -+ .driver = { -+ .name = "brcm-pcie", -+ .of_match_table = brcm_pcie_match, -+ }, -+}; -+module_platform_driver(brcm_pcie_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Broadcom STB PCIe RC driver"); -+MODULE_AUTHOR("Broadcom"); diff --git a/target/linux/bcm27xx/patches-5.4/950-0459-PCI-brcmstb-Add-MSI-support.patch b/target/linux/bcm27xx/patches-5.4/950-0459-PCI-brcmstb-Add-MSI-support.patch new file mode 100644 index 00000000000..a27259bd196 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0459-PCI-brcmstb-Add-MSI-support.patch @@ -0,0 +1,383 @@ +From 1a90ecdfae1c0cf1b242276f6f0e3d98b5877f14 Mon Sep 17 00:00:00 2001 +From: Jim Quinlan +Date: Mon, 16 Dec 2019 12:01:10 +0100 +Subject: [PATCH] PCI: brcmstb: Add MSI support + +commit 40ca1bf580ef24df30702032ba5e40dfdcaa200b upstream. + +This adds MSI support to the Broadcom STB PCIe host controller. The MSI +controller is physically located within the PCIe block, however, there +is no reason why the MSI controller could not be moved elsewhere in the +future. MSIX is not supported by the HW. + +Since the internal Brcmstb MSI controller is intertwined with the PCIe +controller, it is not its own platform device but rather part of the +PCIe platform device. + +Signed-off-by: Jim Quinlan +Co-developed-by: Nicolas Saenz Julienne +Signed-off-by: Nicolas Saenz Julienne +Signed-off-by: Lorenzo Pieralisi +Reviewed-by: Marc Zyngier +Reviewed-by: Andrew Murray +--- + drivers/pci/controller/Kconfig | 1 + + drivers/pci/controller/pcie-brcmstb.c | 262 +++++++++++++++++++++++++- + 2 files changed, 262 insertions(+), 1 deletion(-) + +--- a/drivers/pci/controller/Kconfig ++++ b/drivers/pci/controller/Kconfig +@@ -285,6 +285,7 @@ config PCIE_BRCMSTB + tristate "Broadcom Brcmstb PCIe host controller" + depends on ARCH_BCM2835 || COMPILE_TEST + depends on OF ++ depends on PCI_MSI_IRQ_DOMAIN + help + Say Y here to enable PCIe host controller support for + Broadcom STB based SoCs, like the Raspberry Pi 4. +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -2,6 +2,7 @@ + /* Copyright (C) 2009 - 2019 Broadcom */ + + #include ++#include + #include + #include + #include +@@ -9,11 +10,13 @@ + #include + #include + #include ++#include + #include + #include + #include + #include + #include ++#include + #include + #include + #include +@@ -67,6 +70,12 @@ + #define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c + #define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f + ++#define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044 ++#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048 ++ ++#define PCIE_MISC_MSI_DATA_CONFIG 0x404c ++#define PCIE_MISC_MSI_DATA_CONFIG_VAL 0xffe06540 ++ + #define PCIE_MISC_PCIE_CTRL 0x4064 + #define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 + +@@ -114,6 +123,11 @@ + + /* PCIe parameters */ + #define BRCM_NUM_PCIE_OUT_WINS 0x4 ++#define BRCM_INT_PCI_MSI_NR 32 ++ ++/* MSI target adresses */ ++#define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL ++#define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL + + /* MDIO registers */ + #define MDIO_PORT0 0x0 +@@ -135,6 +149,19 @@ + #define SSC_STATUS_SSC_MASK 0x400 + #define SSC_STATUS_PLL_LOCK_MASK 0x800 + ++struct brcm_msi { ++ struct device *dev; ++ void __iomem *base; ++ struct device_node *np; ++ struct irq_domain *msi_domain; ++ struct irq_domain *inner_domain; ++ struct mutex lock; /* guards the alloc/free operations */ ++ u64 target_addr; ++ int irq; ++ /* used indicates which MSI interrupts have been alloc'd */ ++ unsigned long used; ++}; ++ + /* Internal PCIe Host Controller Information.*/ + struct brcm_pcie { + struct device *dev; +@@ -144,6 +171,8 @@ struct brcm_pcie { + struct device_node *np; + bool ssc; + int gen; ++ u64 msi_target_addr; ++ struct brcm_msi *msi; + }; + + /* +@@ -309,6 +338,215 @@ static void brcm_pcie_set_outbound_win(s + writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); + } + ++static struct irq_chip brcm_msi_irq_chip = { ++ .name = "BRCM STB PCIe MSI", ++ .irq_ack = irq_chip_ack_parent, ++ .irq_mask = pci_msi_mask_irq, ++ .irq_unmask = pci_msi_unmask_irq, ++}; ++ ++static struct msi_domain_info brcm_msi_domain_info = { ++ /* Multi MSI is supported by the controller, but not by this driver */ ++ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), ++ .chip = &brcm_msi_irq_chip, ++}; ++ ++static void brcm_pcie_msi_isr(struct irq_desc *desc) ++{ ++ struct irq_chip *chip = irq_desc_get_chip(desc); ++ unsigned long status, virq; ++ struct brcm_msi *msi; ++ struct device *dev; ++ u32 bit; ++ ++ chained_irq_enter(chip, desc); ++ msi = irq_desc_get_handler_data(desc); ++ dev = msi->dev; ++ ++ status = readl(msi->base + PCIE_MSI_INTR2_STATUS); ++ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) { ++ virq = irq_find_mapping(msi->inner_domain, bit); ++ if (virq) ++ generic_handle_irq(virq); ++ else ++ dev_dbg(dev, "unexpected MSI\n"); ++ } ++ ++ chained_irq_exit(chip, desc); ++} ++ ++static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) ++{ ++ struct brcm_msi *msi = irq_data_get_irq_chip_data(data); ++ ++ msg->address_lo = lower_32_bits(msi->target_addr); ++ msg->address_hi = upper_32_bits(msi->target_addr); ++ msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL) | data->hwirq; ++} ++ ++static int brcm_msi_set_affinity(struct irq_data *irq_data, ++ const struct cpumask *mask, bool force) ++{ ++ return -EINVAL; ++} ++ ++static void brcm_msi_ack_irq(struct irq_data *data) ++{ ++ struct brcm_msi *msi = irq_data_get_irq_chip_data(data); ++ ++ writel(1 << data->hwirq, msi->base + PCIE_MSI_INTR2_CLR); ++} ++ ++ ++static struct irq_chip brcm_msi_bottom_irq_chip = { ++ .name = "BRCM STB MSI", ++ .irq_compose_msi_msg = brcm_msi_compose_msi_msg, ++ .irq_set_affinity = brcm_msi_set_affinity, ++ .irq_ack = brcm_msi_ack_irq, ++}; ++ ++static int brcm_msi_alloc(struct brcm_msi *msi) ++{ ++ int hwirq; ++ ++ mutex_lock(&msi->lock); ++ hwirq = bitmap_find_free_region(&msi->used, BRCM_INT_PCI_MSI_NR, 0); ++ mutex_unlock(&msi->lock); ++ ++ return hwirq; ++} ++ ++static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq) ++{ ++ mutex_lock(&msi->lock); ++ bitmap_release_region(&msi->used, hwirq, 0); ++ mutex_unlock(&msi->lock); ++} ++ ++static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, ++ unsigned int nr_irqs, void *args) ++{ ++ struct brcm_msi *msi = domain->host_data; ++ int hwirq; ++ ++ hwirq = brcm_msi_alloc(msi); ++ ++ if (hwirq < 0) ++ return hwirq; ++ ++ irq_domain_set_info(domain, virq, (irq_hw_number_t)hwirq, ++ &brcm_msi_bottom_irq_chip, domain->host_data, ++ handle_edge_irq, NULL, NULL); ++ return 0; ++} ++ ++static void brcm_irq_domain_free(struct irq_domain *domain, ++ unsigned int virq, unsigned int nr_irqs) ++{ ++ struct irq_data *d = irq_domain_get_irq_data(domain, virq); ++ struct brcm_msi *msi = irq_data_get_irq_chip_data(d); ++ ++ brcm_msi_free(msi, d->hwirq); ++} ++ ++static const struct irq_domain_ops msi_domain_ops = { ++ .alloc = brcm_irq_domain_alloc, ++ .free = brcm_irq_domain_free, ++}; ++ ++static int brcm_allocate_domains(struct brcm_msi *msi) ++{ ++ struct fwnode_handle *fwnode = of_node_to_fwnode(msi->np); ++ struct device *dev = msi->dev; ++ ++ msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR, ++ &msi_domain_ops, msi); ++ if (!msi->inner_domain) { ++ dev_err(dev, "failed to create IRQ domain\n"); ++ return -ENOMEM; ++ } ++ ++ msi->msi_domain = pci_msi_create_irq_domain(fwnode, ++ &brcm_msi_domain_info, ++ msi->inner_domain); ++ if (!msi->msi_domain) { ++ dev_err(dev, "failed to create MSI domain\n"); ++ irq_domain_remove(msi->inner_domain); ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static void brcm_free_domains(struct brcm_msi *msi) ++{ ++ irq_domain_remove(msi->msi_domain); ++ irq_domain_remove(msi->inner_domain); ++} ++ ++static void brcm_msi_remove(struct brcm_pcie *pcie) ++{ ++ struct brcm_msi *msi = pcie->msi; ++ ++ if (!msi) ++ return; ++ irq_set_chained_handler(msi->irq, NULL); ++ irq_set_handler_data(msi->irq, NULL); ++ brcm_free_domains(msi); ++} ++ ++static void brcm_msi_set_regs(struct brcm_msi *msi) ++{ ++ writel(0xffffffff, msi->base + PCIE_MSI_INTR2_MASK_CLR); ++ ++ /* ++ * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI ++ * enable, which we set to 1. ++ */ ++ writel(lower_32_bits(msi->target_addr) | 0x1, ++ msi->base + PCIE_MISC_MSI_BAR_CONFIG_LO); ++ writel(upper_32_bits(msi->target_addr), ++ msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI); ++ ++ writel(PCIE_MISC_MSI_DATA_CONFIG_VAL, ++ msi->base + PCIE_MISC_MSI_DATA_CONFIG); ++} ++ ++static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) ++{ ++ struct brcm_msi *msi; ++ int irq, ret; ++ struct device *dev = pcie->dev; ++ ++ irq = irq_of_parse_and_map(dev->of_node, 1); ++ if (irq <= 0) { ++ dev_err(dev, "cannot map MSI interrupt\n"); ++ return -ENODEV; ++ } ++ ++ msi = devm_kzalloc(dev, sizeof(struct brcm_msi), GFP_KERNEL); ++ if (!msi) ++ return -ENOMEM; ++ ++ mutex_init(&msi->lock); ++ msi->dev = dev; ++ msi->base = pcie->base; ++ msi->np = pcie->np; ++ msi->target_addr = pcie->msi_target_addr; ++ msi->irq = irq; ++ ++ ret = brcm_allocate_domains(msi); ++ if (ret) ++ return ret; ++ ++ irq_set_chained_handler_and_data(msi->irq, brcm_pcie_msi_isr, msi); ++ ++ brcm_msi_set_regs(msi); ++ pcie->msi = msi; ++ ++ return 0; ++} ++ + /* The controller is capable of serving in both RC and EP roles */ + static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) + { +@@ -497,6 +735,18 @@ static int brcm_pcie_setup(struct brcm_p + PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK); + writel(tmp, base + PCIE_MISC_MISC_CTRL); + ++ /* ++ * We ideally want the MSI target address to be located in the 32bit ++ * addressable memory area. Some devices might depend on it. This is ++ * possible either when the inbound window is located above the lower ++ * 4GB or when the inbound area is smaller than 4GB (taking into ++ * account the rounding-up we're forced to perform). ++ */ ++ if (rc_bar2_offset >= SZ_4G || (rc_bar2_size + rc_bar2_offset) < SZ_4G) ++ pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB; ++ else ++ pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB; ++ + /* disable the PCIe->GISB memory window (RC_BAR1) */ + tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO); + tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK; +@@ -646,6 +896,7 @@ static void brcm_pcie_turn_off(struct br + + static void __brcm_pcie_remove(struct brcm_pcie *pcie) + { ++ brcm_msi_remove(pcie); + brcm_pcie_turn_off(pcie); + clk_disable_unprepare(pcie->clk); + clk_put(pcie->clk); +@@ -664,7 +915,7 @@ static int brcm_pcie_remove(struct platf + + static int brcm_pcie_probe(struct platform_device *pdev) + { +- struct device_node *np = pdev->dev.of_node; ++ struct device_node *np = pdev->dev.of_node, *msi_np; + struct pci_host_bridge *bridge; + struct brcm_pcie *pcie; + struct pci_bus *child; +@@ -708,6 +959,15 @@ static int brcm_pcie_probe(struct platfo + if (ret) + goto fail; + ++ msi_np = of_parse_phandle(pcie->np, "msi-parent", 0); ++ if (pci_msi_enabled() && msi_np == pcie->np) { ++ ret = brcm_pcie_enable_msi(pcie); ++ if (ret) { ++ dev_err(pcie->dev, "probe of internal MSI failed"); ++ goto fail; ++ } ++ } ++ + bridge->dev.parent = &pdev->dev; + bridge->busnr = 0; + bridge->ops = &brcm_pcie_ops; diff --git a/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch b/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch deleted file mode 100644 index a27259bd196..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Add-MSI-support.patch +++ /dev/null @@ -1,383 +0,0 @@ -From 1a90ecdfae1c0cf1b242276f6f0e3d98b5877f14 Mon Sep 17 00:00:00 2001 -From: Jim Quinlan -Date: Mon, 16 Dec 2019 12:01:10 +0100 -Subject: [PATCH] PCI: brcmstb: Add MSI support - -commit 40ca1bf580ef24df30702032ba5e40dfdcaa200b upstream. - -This adds MSI support to the Broadcom STB PCIe host controller. The MSI -controller is physically located within the PCIe block, however, there -is no reason why the MSI controller could not be moved elsewhere in the -future. MSIX is not supported by the HW. - -Since the internal Brcmstb MSI controller is intertwined with the PCIe -controller, it is not its own platform device but rather part of the -PCIe platform device. - -Signed-off-by: Jim Quinlan -Co-developed-by: Nicolas Saenz Julienne -Signed-off-by: Nicolas Saenz Julienne -Signed-off-by: Lorenzo Pieralisi -Reviewed-by: Marc Zyngier -Reviewed-by: Andrew Murray ---- - drivers/pci/controller/Kconfig | 1 + - drivers/pci/controller/pcie-brcmstb.c | 262 +++++++++++++++++++++++++- - 2 files changed, 262 insertions(+), 1 deletion(-) - ---- a/drivers/pci/controller/Kconfig -+++ b/drivers/pci/controller/Kconfig -@@ -285,6 +285,7 @@ config PCIE_BRCMSTB - tristate "Broadcom Brcmstb PCIe host controller" - depends on ARCH_BCM2835 || COMPILE_TEST - depends on OF -+ depends on PCI_MSI_IRQ_DOMAIN - help - Say Y here to enable PCIe host controller support for - Broadcom STB based SoCs, like the Raspberry Pi 4. ---- a/drivers/pci/controller/pcie-brcmstb.c -+++ b/drivers/pci/controller/pcie-brcmstb.c -@@ -2,6 +2,7 @@ - /* Copyright (C) 2009 - 2019 Broadcom */ - - #include -+#include - #include - #include - #include -@@ -9,11 +10,13 @@ - #include - #include - #include -+#include - #include - #include - #include - #include - #include -+#include - #include - #include - #include -@@ -67,6 +70,12 @@ - #define PCIE_MISC_RC_BAR3_CONFIG_LO 0x403c - #define PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK 0x1f - -+#define PCIE_MISC_MSI_BAR_CONFIG_LO 0x4044 -+#define PCIE_MISC_MSI_BAR_CONFIG_HI 0x4048 -+ -+#define PCIE_MISC_MSI_DATA_CONFIG 0x404c -+#define PCIE_MISC_MSI_DATA_CONFIG_VAL 0xffe06540 -+ - #define PCIE_MISC_PCIE_CTRL 0x4064 - #define PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK 0x1 - -@@ -114,6 +123,11 @@ - - /* PCIe parameters */ - #define BRCM_NUM_PCIE_OUT_WINS 0x4 -+#define BRCM_INT_PCI_MSI_NR 32 -+ -+/* MSI target adresses */ -+#define BRCM_MSI_TARGET_ADDR_LT_4GB 0x0fffffffcULL -+#define BRCM_MSI_TARGET_ADDR_GT_4GB 0xffffffffcULL - - /* MDIO registers */ - #define MDIO_PORT0 0x0 -@@ -135,6 +149,19 @@ - #define SSC_STATUS_SSC_MASK 0x400 - #define SSC_STATUS_PLL_LOCK_MASK 0x800 - -+struct brcm_msi { -+ struct device *dev; -+ void __iomem *base; -+ struct device_node *np; -+ struct irq_domain *msi_domain; -+ struct irq_domain *inner_domain; -+ struct mutex lock; /* guards the alloc/free operations */ -+ u64 target_addr; -+ int irq; -+ /* used indicates which MSI interrupts have been alloc'd */ -+ unsigned long used; -+}; -+ - /* Internal PCIe Host Controller Information.*/ - struct brcm_pcie { - struct device *dev; -@@ -144,6 +171,8 @@ struct brcm_pcie { - struct device_node *np; - bool ssc; - int gen; -+ u64 msi_target_addr; -+ struct brcm_msi *msi; - }; - - /* -@@ -309,6 +338,215 @@ static void brcm_pcie_set_outbound_win(s - writel(tmp, pcie->base + PCIE_MEM_WIN0_LIMIT_HI(win)); - } - -+static struct irq_chip brcm_msi_irq_chip = { -+ .name = "BRCM STB PCIe MSI", -+ .irq_ack = irq_chip_ack_parent, -+ .irq_mask = pci_msi_mask_irq, -+ .irq_unmask = pci_msi_unmask_irq, -+}; -+ -+static struct msi_domain_info brcm_msi_domain_info = { -+ /* Multi MSI is supported by the controller, but not by this driver */ -+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS), -+ .chip = &brcm_msi_irq_chip, -+}; -+ -+static void brcm_pcie_msi_isr(struct irq_desc *desc) -+{ -+ struct irq_chip *chip = irq_desc_get_chip(desc); -+ unsigned long status, virq; -+ struct brcm_msi *msi; -+ struct device *dev; -+ u32 bit; -+ -+ chained_irq_enter(chip, desc); -+ msi = irq_desc_get_handler_data(desc); -+ dev = msi->dev; -+ -+ status = readl(msi->base + PCIE_MSI_INTR2_STATUS); -+ for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) { -+ virq = irq_find_mapping(msi->inner_domain, bit); -+ if (virq) -+ generic_handle_irq(virq); -+ else -+ dev_dbg(dev, "unexpected MSI\n"); -+ } -+ -+ chained_irq_exit(chip, desc); -+} -+ -+static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) -+{ -+ struct brcm_msi *msi = irq_data_get_irq_chip_data(data); -+ -+ msg->address_lo = lower_32_bits(msi->target_addr); -+ msg->address_hi = upper_32_bits(msi->target_addr); -+ msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL) | data->hwirq; -+} -+ -+static int brcm_msi_set_affinity(struct irq_data *irq_data, -+ const struct cpumask *mask, bool force) -+{ -+ return -EINVAL; -+} -+ -+static void brcm_msi_ack_irq(struct irq_data *data) -+{ -+ struct brcm_msi *msi = irq_data_get_irq_chip_data(data); -+ -+ writel(1 << data->hwirq, msi->base + PCIE_MSI_INTR2_CLR); -+} -+ -+ -+static struct irq_chip brcm_msi_bottom_irq_chip = { -+ .name = "BRCM STB MSI", -+ .irq_compose_msi_msg = brcm_msi_compose_msi_msg, -+ .irq_set_affinity = brcm_msi_set_affinity, -+ .irq_ack = brcm_msi_ack_irq, -+}; -+ -+static int brcm_msi_alloc(struct brcm_msi *msi) -+{ -+ int hwirq; -+ -+ mutex_lock(&msi->lock); -+ hwirq = bitmap_find_free_region(&msi->used, BRCM_INT_PCI_MSI_NR, 0); -+ mutex_unlock(&msi->lock); -+ -+ return hwirq; -+} -+ -+static void brcm_msi_free(struct brcm_msi *msi, unsigned long hwirq) -+{ -+ mutex_lock(&msi->lock); -+ bitmap_release_region(&msi->used, hwirq, 0); -+ mutex_unlock(&msi->lock); -+} -+ -+static int brcm_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, -+ unsigned int nr_irqs, void *args) -+{ -+ struct brcm_msi *msi = domain->host_data; -+ int hwirq; -+ -+ hwirq = brcm_msi_alloc(msi); -+ -+ if (hwirq < 0) -+ return hwirq; -+ -+ irq_domain_set_info(domain, virq, (irq_hw_number_t)hwirq, -+ &brcm_msi_bottom_irq_chip, domain->host_data, -+ handle_edge_irq, NULL, NULL); -+ return 0; -+} -+ -+static void brcm_irq_domain_free(struct irq_domain *domain, -+ unsigned int virq, unsigned int nr_irqs) -+{ -+ struct irq_data *d = irq_domain_get_irq_data(domain, virq); -+ struct brcm_msi *msi = irq_data_get_irq_chip_data(d); -+ -+ brcm_msi_free(msi, d->hwirq); -+} -+ -+static const struct irq_domain_ops msi_domain_ops = { -+ .alloc = brcm_irq_domain_alloc, -+ .free = brcm_irq_domain_free, -+}; -+ -+static int brcm_allocate_domains(struct brcm_msi *msi) -+{ -+ struct fwnode_handle *fwnode = of_node_to_fwnode(msi->np); -+ struct device *dev = msi->dev; -+ -+ msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR, -+ &msi_domain_ops, msi); -+ if (!msi->inner_domain) { -+ dev_err(dev, "failed to create IRQ domain\n"); -+ return -ENOMEM; -+ } -+ -+ msi->msi_domain = pci_msi_create_irq_domain(fwnode, -+ &brcm_msi_domain_info, -+ msi->inner_domain); -+ if (!msi->msi_domain) { -+ dev_err(dev, "failed to create MSI domain\n"); -+ irq_domain_remove(msi->inner_domain); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} -+ -+static void brcm_free_domains(struct brcm_msi *msi) -+{ -+ irq_domain_remove(msi->msi_domain); -+ irq_domain_remove(msi->inner_domain); -+} -+ -+static void brcm_msi_remove(struct brcm_pcie *pcie) -+{ -+ struct brcm_msi *msi = pcie->msi; -+ -+ if (!msi) -+ return; -+ irq_set_chained_handler(msi->irq, NULL); -+ irq_set_handler_data(msi->irq, NULL); -+ brcm_free_domains(msi); -+} -+ -+static void brcm_msi_set_regs(struct brcm_msi *msi) -+{ -+ writel(0xffffffff, msi->base + PCIE_MSI_INTR2_MASK_CLR); -+ -+ /* -+ * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI -+ * enable, which we set to 1. -+ */ -+ writel(lower_32_bits(msi->target_addr) | 0x1, -+ msi->base + PCIE_MISC_MSI_BAR_CONFIG_LO); -+ writel(upper_32_bits(msi->target_addr), -+ msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI); -+ -+ writel(PCIE_MISC_MSI_DATA_CONFIG_VAL, -+ msi->base + PCIE_MISC_MSI_DATA_CONFIG); -+} -+ -+static int brcm_pcie_enable_msi(struct brcm_pcie *pcie) -+{ -+ struct brcm_msi *msi; -+ int irq, ret; -+ struct device *dev = pcie->dev; -+ -+ irq = irq_of_parse_and_map(dev->of_node, 1); -+ if (irq <= 0) { -+ dev_err(dev, "cannot map MSI interrupt\n"); -+ return -ENODEV; -+ } -+ -+ msi = devm_kzalloc(dev, sizeof(struct brcm_msi), GFP_KERNEL); -+ if (!msi) -+ return -ENOMEM; -+ -+ mutex_init(&msi->lock); -+ msi->dev = dev; -+ msi->base = pcie->base; -+ msi->np = pcie->np; -+ msi->target_addr = pcie->msi_target_addr; -+ msi->irq = irq; -+ -+ ret = brcm_allocate_domains(msi); -+ if (ret) -+ return ret; -+ -+ irq_set_chained_handler_and_data(msi->irq, brcm_pcie_msi_isr, msi); -+ -+ brcm_msi_set_regs(msi); -+ pcie->msi = msi; -+ -+ return 0; -+} -+ - /* The controller is capable of serving in both RC and EP roles */ - static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) - { -@@ -497,6 +735,18 @@ static int brcm_pcie_setup(struct brcm_p - PCIE_MISC_MISC_CTRL_SCB0_SIZE_MASK); - writel(tmp, base + PCIE_MISC_MISC_CTRL); - -+ /* -+ * We ideally want the MSI target address to be located in the 32bit -+ * addressable memory area. Some devices might depend on it. This is -+ * possible either when the inbound window is located above the lower -+ * 4GB or when the inbound area is smaller than 4GB (taking into -+ * account the rounding-up we're forced to perform). -+ */ -+ if (rc_bar2_offset >= SZ_4G || (rc_bar2_size + rc_bar2_offset) < SZ_4G) -+ pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_LT_4GB; -+ else -+ pcie->msi_target_addr = BRCM_MSI_TARGET_ADDR_GT_4GB; -+ - /* disable the PCIe->GISB memory window (RC_BAR1) */ - tmp = readl(base + PCIE_MISC_RC_BAR1_CONFIG_LO); - tmp &= ~PCIE_MISC_RC_BAR1_CONFIG_LO_SIZE_MASK; -@@ -646,6 +896,7 @@ static void brcm_pcie_turn_off(struct br - - static void __brcm_pcie_remove(struct brcm_pcie *pcie) - { -+ brcm_msi_remove(pcie); - brcm_pcie_turn_off(pcie); - clk_disable_unprepare(pcie->clk); - clk_put(pcie->clk); -@@ -664,7 +915,7 @@ static int brcm_pcie_remove(struct platf - - static int brcm_pcie_probe(struct platform_device *pdev) - { -- struct device_node *np = pdev->dev.of_node; -+ struct device_node *np = pdev->dev.of_node, *msi_np; - struct pci_host_bridge *bridge; - struct brcm_pcie *pcie; - struct pci_bus *child; -@@ -708,6 +959,15 @@ static int brcm_pcie_probe(struct platfo - if (ret) - goto fail; - -+ msi_np = of_parse_phandle(pcie->np, "msi-parent", 0); -+ if (pci_msi_enabled() && msi_np == pcie->np) { -+ ret = brcm_pcie_enable_msi(pcie); -+ if (ret) { -+ dev_err(pcie->dev, "probe of internal MSI failed"); -+ goto fail; -+ } -+ } -+ - bridge->dev.parent = &pdev->dev; - bridge->busnr = 0; - bridge->ops = &brcm_pcie_ops; diff --git a/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch b/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch new file mode 100644 index 00000000000..6bb45ccb1fd --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0460-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch @@ -0,0 +1,38 @@ +From 39192141aa16809323c24d8910e3a63488f7f55d Mon Sep 17 00:00:00 2001 +From: Marek Szyprowski +Date: Thu, 27 Feb 2020 12:51:46 +0100 +Subject: [PATCH] PCI: brcmstb: Fix build on 32bit ARM platforms with + older compilers + +commit 73a7a271b3eee7b83f29b13866163776f1cbef89 upstream. + +Some older compilers have no implementation for the helper for 64-bit +unsigned division/modulo, so linking pcie-brcmstb driver causes the +"undefined reference to `__aeabi_uldivmod'" error. + +*rc_bar2_size is always a power of two, because it is calculated as: +"1ULL << fls64(entry->res->end - entry->res->start)", so the modulo +operation in the subsequent check can be replaced by a simple logical +AND with a proper mask. + +Link: https://lore.kernel.org/r/20200227115146.24515-1-m.szyprowski@samsung.com +Fixes: c0452137034b ("PCI: brcmstb: Add Broadcom STB PCIe host controller driver") +Signed-off-by: Marek Szyprowski +Signed-off-by: Bjorn Helgaas +Acked-by: Nicolas Saenz Julienne +Acked-by: Lorenzo Pieralisi +--- + drivers/pci/controller/pcie-brcmstb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/pci/controller/pcie-brcmstb.c ++++ b/drivers/pci/controller/pcie-brcmstb.c +@@ -670,7 +670,7 @@ static inline int brcm_pcie_get_rc_bar2_ + * outbound memory @ 3GB). So instead it will start at the 1x + * multiple of its size + */ +- if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size || ++ if (!*rc_bar2_size || (*rc_bar2_offset & (*rc_bar2_size - 1)) || + (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) { + dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n", + *rc_bar2_size, *rc_bar2_offset); diff --git a/target/linux/bcm27xx/patches-5.4/950-0461-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch b/target/linux/bcm27xx/patches-5.4/950-0461-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch deleted file mode 100644 index 6bb45ccb1fd..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0461-PCI-brcmstb-Fix-build-on-32bit-ARM-platforms-with-ol.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 39192141aa16809323c24d8910e3a63488f7f55d Mon Sep 17 00:00:00 2001 -From: Marek Szyprowski -Date: Thu, 27 Feb 2020 12:51:46 +0100 -Subject: [PATCH] PCI: brcmstb: Fix build on 32bit ARM platforms with - older compilers - -commit 73a7a271b3eee7b83f29b13866163776f1cbef89 upstream. - -Some older compilers have no implementation for the helper for 64-bit -unsigned division/modulo, so linking pcie-brcmstb driver causes the -"undefined reference to `__aeabi_uldivmod'" error. - -*rc_bar2_size is always a power of two, because it is calculated as: -"1ULL << fls64(entry->res->end - entry->res->start)", so the modulo -operation in the subsequent check can be replaced by a simple logical -AND with a proper mask. - -Link: https://lore.kernel.org/r/20200227115146.24515-1-m.szyprowski@samsung.com -Fixes: c0452137034b ("PCI: brcmstb: Add Broadcom STB PCIe host controller driver") -Signed-off-by: Marek Szyprowski -Signed-off-by: Bjorn Helgaas -Acked-by: Nicolas Saenz Julienne -Acked-by: Lorenzo Pieralisi ---- - drivers/pci/controller/pcie-brcmstb.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/pci/controller/pcie-brcmstb.c -+++ b/drivers/pci/controller/pcie-brcmstb.c -@@ -670,7 +670,7 @@ static inline int brcm_pcie_get_rc_bar2_ - * outbound memory @ 3GB). So instead it will start at the 1x - * multiple of its size - */ -- if (!*rc_bar2_size || *rc_bar2_offset % *rc_bar2_size || -+ if (!*rc_bar2_size || (*rc_bar2_offset & (*rc_bar2_size - 1)) || - (*rc_bar2_offset < SZ_4G && *rc_bar2_offset > SZ_2G)) { - dev_err(dev, "Invalid rc_bar2_offset/size: size 0x%llx, off 0x%llx\n", - *rc_bar2_size, *rc_bar2_offset); diff --git a/target/linux/bcm27xx/patches-5.4/950-0461-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch b/target/linux/bcm27xx/patches-5.4/950-0461-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch new file mode 100644 index 00000000000..729d6e68baf --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0461-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch @@ -0,0 +1,75 @@ +From 5e9b9f246802f492e7740ab2589aa8c81df5ef20 Mon Sep 17 00:00:00 2001 +From: Phil Elwell +Date: Mon, 2 Mar 2020 15:05:25 +0000 +Subject: [PATCH] bcm2711-rpi.dtsi: Use upstream pcie node + +Now that the upstream bcm2711 DT has a pcie DT node there's no need to +define one downstream. + +Signed-off-by: Phil Elwell +--- + arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 +- + arch/arm/boot/dts/bcm2711-rpi.dtsi | 41 --------------------------- + 2 files changed, 1 insertion(+), 42 deletions(-) + +--- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts ++++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +@@ -163,7 +163,7 @@ + i2c6 = &i2c6; + /delete-property/ ethernet; + /delete-property/ intc; +- pcie0 = &pcie_0; ++ pcie0 = &pcie0; + }; + + /delete-node/ wifi-pwrseq; +--- a/arch/arm/boot/dts/bcm2711-rpi.dtsi ++++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi +@@ -66,47 +66,6 @@ + <0x0 0x00000000 0x0 0x00000000 0xfc000000>; + dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>; + +- pcie_0: pcie@7d500000 { +- reg = <0x0 0x7d500000 0x9310>, +- <0x0 0x7e00f300 0x20>; +- msi-controller; +- msi-parent = <&pcie_0>; +- #address-cells = <3>; +- #interrupt-cells = <1>; +- #size-cells = <2>; +- bus-range = <0x0 0x01>; +- compatible = "brcm,bcm2711b0-pcie", // Safe value +- "brcm,bcm2711-pcie", +- "brcm,pci-plat-dev"; +- max-link-speed = <2>; +- tot-num-pcie = <1>; +- linux,pci-domain = <0>; +- interrupts = , +- ; +- interrupt-names = "pcie", "msi"; +- interrupt-map-mask = <0x0 0x0 0x0 0x7>; +- interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 +- IRQ_TYPE_LEVEL_HIGH +- 0 0 0 2 &gicv2 GIC_SPI 144 +- IRQ_TYPE_LEVEL_HIGH +- 0 0 0 3 &gicv2 GIC_SPI 145 +- IRQ_TYPE_LEVEL_HIGH +- 0 0 0 4 &gicv2 GIC_SPI 146 +- IRQ_TYPE_LEVEL_HIGH>; +- +- /* Map outbound accesses from scb:0x6_00000000-03ffffff +- * to pci:0x0_f8000000-fbffffff +- */ +- ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 +- 0x0 0x04000000>; +- /* Map inbound accesses from pci:0x0_00000000..ffffffff +- * to scb:0x0_00000000-ffffffff +- */ +- dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 +- 0x1 0x00000000>; +- status = "okay"; +- }; +- + dma40: dma@7e007b00 { + compatible = "brcm,bcm2711-dma"; + reg = <0x0 0x7e007b00 0x400>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0462-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch b/target/linux/bcm27xx/patches-5.4/950-0462-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch deleted file mode 100644 index 729d6e68baf..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0462-bcm2711-rpi.dtsi-Use-upstream-pcie-node.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 5e9b9f246802f492e7740ab2589aa8c81df5ef20 Mon Sep 17 00:00:00 2001 -From: Phil Elwell -Date: Mon, 2 Mar 2020 15:05:25 +0000 -Subject: [PATCH] bcm2711-rpi.dtsi: Use upstream pcie node - -Now that the upstream bcm2711 DT has a pcie DT node there's no need to -define one downstream. - -Signed-off-by: Phil Elwell ---- - arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 2 +- - arch/arm/boot/dts/bcm2711-rpi.dtsi | 41 --------------------------- - 2 files changed, 1 insertion(+), 42 deletions(-) - ---- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -+++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts -@@ -163,7 +163,7 @@ - i2c6 = &i2c6; - /delete-property/ ethernet; - /delete-property/ intc; -- pcie0 = &pcie_0; -+ pcie0 = &pcie0; - }; - - /delete-node/ wifi-pwrseq; ---- a/arch/arm/boot/dts/bcm2711-rpi.dtsi -+++ b/arch/arm/boot/dts/bcm2711-rpi.dtsi -@@ -66,47 +66,6 @@ - <0x0 0x00000000 0x0 0x00000000 0xfc000000>; - dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>; - -- pcie_0: pcie@7d500000 { -- reg = <0x0 0x7d500000 0x9310>, -- <0x0 0x7e00f300 0x20>; -- msi-controller; -- msi-parent = <&pcie_0>; -- #address-cells = <3>; -- #interrupt-cells = <1>; -- #size-cells = <2>; -- bus-range = <0x0 0x01>; -- compatible = "brcm,bcm2711b0-pcie", // Safe value -- "brcm,bcm2711-pcie", -- "brcm,pci-plat-dev"; -- max-link-speed = <2>; -- tot-num-pcie = <1>; -- linux,pci-domain = <0>; -- interrupts = , -- ; -- interrupt-names = "pcie", "msi"; -- interrupt-map-mask = <0x0 0x0 0x0 0x7>; -- interrupt-map = <0 0 0 1 &gicv2 GIC_SPI 143 -- IRQ_TYPE_LEVEL_HIGH -- 0 0 0 2 &gicv2 GIC_SPI 144 -- IRQ_TYPE_LEVEL_HIGH -- 0 0 0 3 &gicv2 GIC_SPI 145 -- IRQ_TYPE_LEVEL_HIGH -- 0 0 0 4 &gicv2 GIC_SPI 146 -- IRQ_TYPE_LEVEL_HIGH>; -- -- /* Map outbound accesses from scb:0x6_00000000-03ffffff -- * to pci:0x0_f8000000-fbffffff -- */ -- ranges = <0x02000000 0x0 0xf8000000 0x6 0x00000000 -- 0x0 0x04000000>; -- /* Map inbound accesses from pci:0x0_00000000..ffffffff -- * to scb:0x0_00000000-ffffffff -- */ -- dma-ranges = <0x02000000 0x0 0x00000000 0x0 0x00000000 -- 0x1 0x00000000>; -- status = "okay"; -- }; -- - dma40: dma@7e007b00 { - compatible = "brcm,bcm2711-dma"; - reg = <0x0 0x7e007b00 0x400>; diff --git a/target/linux/bcm27xx/patches-5.4/950-0462-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch b/target/linux/bcm27xx/patches-5.4/950-0462-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch new file mode 100644 index 00000000000..16eaeddb29f --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0462-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch @@ -0,0 +1,156 @@ +From a3ceeebaaa66e6786490e850b5019808da3785c0 Mon Sep 17 00:00:00 2001 +From: Andrey Konovalov +Date: Mon, 20 Jan 2020 05:15:57 -0300 +Subject: [PATCH] media: dt-bindings: media: i2c: Add IMX219 CMOS + sensor binding + +Commit 9d730f2cf4c0391785855dd231577d2de2594df9 upstream. +(Currently on linux-media/master, queued for 5.7) + +Add YAML device tree binding for IMX219 CMOS image sensor, and +the relevant MAINTAINERS entries. + +Signed-off-by: Andrey Konovalov +Reviewed-by: Rob Herring +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +--- + .../devicetree/bindings/media/i2c/imx219.yaml | 114 ++++++++++++++++++ + MAINTAINERS | 8 ++ + 2 files changed, 122 insertions(+) + create mode 100644 Documentation/devicetree/bindings/media/i2c/imx219.yaml + +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/i2c/imx219.yaml +@@ -0,0 +1,114 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/media/i2c/imx219.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor ++ ++maintainers: ++ - Dave Stevenson ++ ++description: |- ++ The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor ++ with an active array size of 3280H x 2464V. It is programmable through ++ I2C interface. The I2C address is fixed to 0x10 as per sensor data sheet. ++ Image data is sent through MIPI CSI-2, which is configured as either 2 or ++ 4 data lanes. ++ ++properties: ++ compatible: ++ const: sony,imx219 ++ ++ reg: ++ description: I2C device address ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ VDIG-supply: ++ description: ++ Digital I/O voltage supply, 1.8 volts ++ ++ VANA-supply: ++ description: ++ Analog voltage supply, 2.8 volts ++ ++ VDDL-supply: ++ description: ++ Digital core voltage supply, 1.2 volts ++ ++ reset-gpios: ++ description: |- ++ Reference to the GPIO connected to the xclr pin, if any. ++ Must be released (set high) after all supplies are applied. ++ ++ # See ../video-interfaces.txt for more details ++ port: ++ type: object ++ properties: ++ endpoint: ++ type: object ++ properties: ++ data-lanes: ++ description: |- ++ The sensor supports either two-lane, or four-lane operation. ++ If this property is omitted four-lane operation is assumed. ++ For two-lane operation the property must be set to <1 2>. ++ items: ++ - const: 1 ++ - const: 2 ++ ++ clock-noncontinuous: ++ type: boolean ++ description: |- ++ MIPI CSI-2 clock is non-continuous if this property is present, ++ otherwise it's continuous. ++ ++ link-frequencies: ++ allOf: ++ - $ref: /schemas/types.yaml#/definitions/uint64-array ++ description: ++ Allowed data bus frequencies. ++ ++ required: ++ - link-frequencies ++ ++required: ++ - compatible ++ - reg ++ - clocks ++ - VANA-supply ++ - VDIG-supply ++ - VDDL-supply ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ i2c0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ imx219: sensor@10 { ++ compatible = "sony,imx219"; ++ reg = <0x10>; ++ clocks = <&imx219_clk>; ++ VANA-supply = <&imx219_vana>; /* 2.8v */ ++ VDIG-supply = <&imx219_vdig>; /* 1.8v */ ++ VDDL-supply = <&imx219_vddl>; /* 1.2v */ ++ ++ port { ++ imx219_0: endpoint { ++ remote-endpoint = <&csi1_ep>; ++ data-lanes = <1 2>; ++ clock-noncontinuous; ++ link-frequencies = /bits/ 64 <456000000>; ++ }; ++ }; ++ }; ++ }; ++ ++... +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15142,6 +15142,14 @@ S: Maintained + F: drivers/media/i2c/imx214.c + F: Documentation/devicetree/bindings/media/i2c/sony,imx214.txt + ++SONY IMX219 SENSOR DRIVER ++M: Dave Stevenson ++L: linux-media@vger.kernel.org ++T: git git://linuxtv.org/media_tree.git ++S: Maintained ++F: drivers/media/i2c/imx219.c ++F: Documentation/devicetree/bindings/media/i2c/imx219.yaml ++ + SONY IMX258 SENSOR DRIVER + M: Sakari Ailus + L: linux-media@vger.kernel.org diff --git a/target/linux/bcm27xx/patches-5.4/950-0463-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch b/target/linux/bcm27xx/patches-5.4/950-0463-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch deleted file mode 100644 index 16eaeddb29f..00000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0463-media-dt-bindings-media-i2c-Add-IMX219-CMOS-sensor-b.patch +++ /dev/null @@ -1,156 +0,0 @@ -From a3ceeebaaa66e6786490e850b5019808da3785c0 Mon Sep 17 00:00:00 2001 -From: Andrey Konovalov -Date: Mon, 20 Jan 2020 05:15:57 -0300 -Subject: [PATCH] media: dt-bindings: media: i2c: Add IMX219 CMOS - sensor binding - -Commit 9d730f2cf4c0391785855dd231577d2de2594df9 upstream. -(Currently on linux-media/master, queued for 5.7) - -Add YAML device tree binding for IMX219 CMOS image sensor, and -the relevant MAINTAINERS entries. - -Signed-off-by: Andrey Konovalov -Reviewed-by: Rob Herring -Signed-off-by: Sakari Ailus -Signed-off-by: Mauro Carvalho Chehab ---- - .../devicetree/bindings/media/i2c/imx219.yaml | 114 ++++++++++++++++++ - MAINTAINERS | 8 ++ - 2 files changed, 122 insertions(+) - create mode 100644 Documentation/devicetree/bindings/media/i2c/imx219.yaml - ---- /dev/null -+++ b/Documentation/devicetree/bindings/media/i2c/imx219.yaml -@@ -0,0 +1,114 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/media/i2c/imx219.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor -+ -+maintainers: -+ - Dave Stevenson -+ -+description: |- -+ The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor -+ with an active array size of 3280H x 2464V. It is programmable through -+ I2C interface. The I2C address is fixed to 0x10 as per sensor data sheet. -+ Image data is sent through MIPI CSI-2, which is configured as either 2 or -+ 4 data lanes. -+ -+properties: -+ compatible: -+ const: sony,imx219 -+ -+ reg: -+ description: I2C device address -+ maxItems: 1 -+ -+ clocks: -+ maxItems: 1 -+ -+ VDIG-supply: -+ description: -+ Digital I/O voltage supply, 1.8 volts -+ -+ VANA-supply: -+ description: -+ Analog voltage supply, 2.8 volts -+ -+ VDDL-supply: -+ description: -+ Digital core voltage supply, 1.2 volts -+ -+ reset-gpios: -+ description: |- -+ Reference to the GPIO connected to the xclr pin, if any. -+ Must be released (set high) after all supplies are applied. -+ -+ # See ../video-interfaces.txt for more details -+ port: -+ type: object -+ properties: -+ endpoint: -+ type: object -+ properties: -+ data-lanes: -+ description: |- -+ The sensor supports either two-lane, or four-lane operation. -+ If this property is omitted four-lane operation is assumed. -+ For two-lane operation the property must be set to <1 2>. -+ items: -+ - const: 1 -+ - const: 2 -+ -+ clock-noncontinuous: -+ type: boolean -+ description: |- -+ MIPI CSI-2 clock is non-continuous if this property is present, -+ otherwise it's continuous. -+ -+ link-frequencies: -+ allOf: -+ - $ref: /schemas/types.yaml#/definitions/uint64-array -+ description: -+ Allowed data bus frequencies. -+ -+ required: -+ - link-frequencies -+ -+required: -+ - compatible -+ - reg -+ - clocks -+ - VANA-supply -+ - VDIG-supply -+ - VDDL-supply -+ - port -+ -+additionalProperties: false -+ -+examples: -+ - | -+ i2c0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ imx219: sensor@10 { -+ compatible = "sony,imx219"; -+ reg = <0x10>; -+ clocks = <&imx219_clk>; -+ VANA-supply = <&imx219_vana>; /* 2.8v */ -+ VDIG-supply = <&imx219_vdig>; /* 1.8v */ -+ VDDL-supply = <&imx219_vddl>; /* 1.2v */ -+ -+ port { -+ imx219_0: endpoint { -+ remote-endpoint = <&csi1_ep>; -+ data-lanes = <1 2>; -+ clock-noncontinuous; -+ link-frequencies = /bits/ 64 <456000000>; -+ }; -+ }; -+ }; -+ }; -+ -+... ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -15142,6 +15142,14 @@ S: Maintained - F: drivers/media/i2c/imx214.c - F: Documentation/devicetree/bindings/media/i2c/sony,imx214.txt - -+SONY IMX219 SENSOR DRIVER -+M: Dave Stevenson -+L: linux-media@vger.kernel.org -+T: git git://linuxtv.org/media_tree.git -+S: Maintained -+F: drivers/media/i2c/imx219.c -+F: Documentation/devicetree/bindings/media/i2c/imx219.yaml -+ - SONY IMX258 SENSOR DRIVER - M: Sakari Ailus - L: linux-media@vger.kernel.org diff --git a/target/linux/bcm27xx/patches-5.4/950-0463-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch b/target/linux/bcm27xx/patches-5.4/950-0463-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch new file mode 100644 index 00000000000..4ca345f2ad5 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0463-media-i2c-Add-driver-for-Sony-IMX219-sensor.patch @@ -0,0 +1,1372 @@ +From 5cd8c4efeb46ce1ef370dd3012a7951ba430b58f Mon Sep 17 00:00:00 2001 +From: Dave Stevenson +Date: Mon, 20 Jan 2020 05:15:58 -0300 +Subject: [PATCH] media: i2c: Add driver for Sony IMX219 sensor + +Commit 1283b3b8f82b9004fbb94398cade5c8e797a2c8d upstream. +(Currently on linux-media/master, queued for 5.7) + +Adds a driver for the 8MPix Sony IMX219 CSI2 sensor. +Whilst the sensor supports 2 or 4 CSI2 data lanes, this driver +currently only supports 2 lanes. +8MPix @ 15fps, 1080P @ 30fps (cropped FOV), and 1640x1232 (2x2 binned) +@ 30fps are currently supported. + +[Sakari Ailus: make imx219_check_hwcfg static] + +Signed-off-by: Dave Stevenson +Signed-off-by: Andrey Konovalov +Signed-off-by: Sakari Ailus +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/media/i2c/Kconfig | 11 + + drivers/media/i2c/Makefile | 1 + + drivers/media/i2c/imx219.c | 1312 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 1324 insertions(+) + create mode 100644 drivers/media/i2c/imx219.c + +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -578,6 +578,17 @@ config VIDEO_IMX214 + To compile this driver as a module, choose M here: the + module will be called imx214. + ++config VIDEO_IMX219 ++ tristate "Sony IMX219 sensor support" ++ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API ++ select V4L2_FWNODE ++ help ++ This is a Video4Linux2 sensor driver for the Sony ++ IMX219 camera. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called imx219. ++ + config VIDEO_IMX258 + tristate "Sony IMX258 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API +--- a/drivers/media/i2c/Makefile ++++ b/drivers/media/i2c/Makefile +@@ -111,6 +111,7 @@ obj-$(CONFIG_VIDEO_ML86V7667) += ml86v76 + obj-$(CONFIG_VIDEO_OV2659) += ov2659.o + obj-$(CONFIG_VIDEO_TC358743) += tc358743.o + obj-$(CONFIG_VIDEO_IMX214) += imx214.o ++obj-$(CONFIG_VIDEO_IMX219) += imx219.o + obj-$(CONFIG_VIDEO_IMX258) += imx258.o + obj-$(CONFIG_VIDEO_IMX274) += imx274.o + obj-$(CONFIG_VIDEO_IMX319) += imx319.o +--- /dev/null ++++ b/drivers/media/i2c/imx219.c +@@ -0,0 +1,1312 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * A V4L2 driver for Sony IMX219 cameras. ++ * Copyright (C) 2019, Raspberry Pi (Trading) Ltd ++ * ++ * Based on Sony imx258 camera driver ++ * Copyright (C) 2018 Intel Corporation ++ * ++ * DT / fwnode changes, and regulator / GPIO control taken from imx214 driver ++ * Copyright 2018 Qtechnology A/S ++ * ++ * Flip handling taken from the Sony IMX319 driver. ++ * Copyright (C) 2018 Intel Corporation ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define IMX219_REG_VALUE_08BIT 1 ++#define IMX219_REG_VALUE_16BIT 2 ++ ++#define IMX219_REG_MODE_SELECT 0x0100 ++#define IMX219_MODE_STANDBY 0x00 ++#define IMX219_MODE_STREAMING 0x01 ++ ++/* Chip ID */ ++#define IMX219_REG_CHIP_ID 0x0000 ++#define IMX219_CHIP_ID 0x0219 ++ ++/* External clock frequency is 24.0M */ ++#define IMX219_XCLK_FREQ 24000000 ++ ++/* Pixel rate is fixed at 182.4M for all the modes */ ++#define IMX219_PIXEL_RATE 182400000 ++ ++#define IMX219_DEFAULT_LINK_FREQ 456000000 ++ ++/* V_TIMING internal */ ++#define IMX219_REG_VTS 0x0160 ++#define IMX219_VTS_15FPS 0x0dc6 ++#define IMX219_VTS_30FPS_1080P 0x06e3 ++#define IMX219_VTS_30FPS_BINNED 0x06e3 ++#define IMX219_VTS_MAX 0xffff ++ ++#define IMX219_VBLANK_MIN 4 ++ ++/*Frame Length Line*/ ++#define IMX219_FLL_MIN 0x08a6 ++#define IMX219_FLL_MAX 0xffff ++#define IMX219_FLL_STEP 1 ++#define IMX219_FLL_DEFAULT 0x0c98 ++ ++/* HBLANK control - read only */ ++#define IMX219_PPL_DEFAULT 3448 ++ ++/* Exposure control */ ++#define IMX219_REG_EXPOSURE 0x015a ++#define IMX219_EXPOSURE_MIN 4 ++#define IMX219_EXPOSURE_STEP 1 ++#define IMX219_EXPOSURE_DEFAULT 0x640 ++#define IMX219_EXPOSURE_MAX 65535 ++ ++/* Analog gain control */ ++#define IMX219_REG_ANALOG_GAIN 0x0157 ++#define IMX219_ANA_GAIN_MIN 0 ++#define IMX219_ANA_GAIN_MAX 232 ++#define IMX219_ANA_GAIN_STEP 1 ++#define IMX219_ANA_GAIN_DEFAULT 0x0 ++ ++/* Digital gain control */ ++#define IMX219_REG_DIGITAL_GAIN 0x0158 ++#define IMX219_DGTL_GAIN_MIN 0x0100 ++#define IMX219_DGTL_GAIN_MAX 0x0fff ++#define IMX219_DGTL_GAIN_DEFAULT 0x0100 ++#define IMX219_DGTL_GAIN_STEP 1 ++ ++#define IMX219_REG_ORIENTATION 0x0172 ++ ++/* Test Pattern Control */ ++#define IMX219_REG_TEST_PATTERN 0x0600 ++#define IMX219_TEST_PATTERN_DISABLE 0 ++#define IMX219_TEST_PATTERN_SOLID_COLOR 1 ++#define IMX219_TEST_PATTERN_COLOR_BARS 2 ++#define IMX219_TEST_PATTERN_GREY_COLOR 3 ++#define IMX219_TEST_PATTERN_PN9 4 ++ ++/* Test pattern colour components */ ++#define IMX219_REG_TESTP_RED 0x0602 ++#define IMX219_REG_TESTP_GREENR 0x0604 ++#define IMX219_REG_TESTP_BLUE 0x0606 ++#define IMX219_REG_TESTP_GREENB 0x0608 ++#define IMX219_TESTP_COLOUR_MIN 0 ++#define IMX219_TESTP_COLOUR_MAX 0x03ff ++#define IMX219_TESTP_COLOUR_STEP 1 ++#define IMX219_TESTP_RED_DEFAULT IMX219_TESTP_COLOUR_MAX ++#define IMX219_TESTP_GREENR_DEFAULT 0 ++#define IMX219_TESTP_BLUE_DEFAULT 0 ++#define IMX219_TESTP_GREENB_DEFAULT 0 ++ ++struct imx219_reg { ++ u16 address; ++ u8 val; ++}; ++ ++struct imx219_reg_list { ++ unsigned int num_of_regs; ++ const struct imx219_reg *regs; ++}; ++ ++/* Mode : resolution and related config&values */ ++struct imx219_mode { ++ /* Frame width */ ++ unsigned int width; ++ /* Frame height */ ++ unsigned int height; ++ ++ /* V-timing */ ++ unsigned int vts_def; ++ ++ /* Default register values */ ++ struct imx219_reg_list reg_list; ++}; ++ ++/* ++ * Register sets lifted off the i2C interface from the Raspberry Pi firmware ++ * driver. ++ * 3280x2464 = mode 2, 1920x1080 = mode 1, and 1640x1232 = mode 4. ++ */ ++static const struct imx219_reg mode_3280x2464_regs[] = { ++ {0x0100, 0x00}, ++ {0x30eb, 0x0c}, ++ {0x30eb, 0x05}, ++ {0x300a, 0xff}, ++ {0x300b, 0xff}, ++ {0x30eb, 0x05}, ++ {0x30eb, 0x09}, ++ {0x0114, 0x01}, ++ {0x0128, 0x00}, ++ {0x012a, 0x18}, ++ {0x012b, 0x00}, ++ {0x0164, 0x00}, ++ {0x0165, 0x00}, ++ {0x0166, 0x0c}, ++ {0x0167, 0xcf}, ++ {0x0168, 0x00}, ++ {0x0169, 0x00}, ++ {0x016a, 0x09}, ++ {0x016b, 0x9f}, ++ {0x016c, 0x0c}, ++ {0x016d, 0xd0}, ++ {0x016e, 0x09}, ++ {0x016f, 0xa0}, ++ {0x0170, 0x01}, ++ {0x0171, 0x01}, ++ {0x0174, 0x00}, ++ {0x0175, 0x00}, ++ {0x018c, 0x0a}, ++ {0x018d, 0x0a}, ++ {0x0301, 0x05}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x0305, 0x03}, ++ {0x0306, 0x00}, ++ {0x0307, 0x39}, ++ {0x0309, 0x0a}, ++ {0x030b, 0x01}, ++ {0x030c, 0x00}, ++ {0x030d, 0x72}, ++ {0x0624, 0x0c}, ++ {0x0625, 0xd0}, ++ {0x0626, 0x09}, ++ {0x0627, 0xa0}, ++ {0x455e, 0x00}, ++ {0x471e, 0x4b}, ++ {0x4767, 0x0f}, ++ {0x4750, 0x14}, ++ {0x4540, 0x00}, ++ {0x47b4, 0x14}, ++ {0x4713, 0x30}, ++ {0x478b, 0x10}, ++ {0x478f, 0x10}, ++ {0x4793, 0x10}, ++ {0x4797, 0x0e}, ++ {0x479b, 0x0e}, ++ {0x0162, 0x0d}, ++ {0x0163, 0x78}, ++}; ++ ++static const struct imx219_reg mode_1920_1080_regs[] = { ++ {0x0100, 0x00}, ++ {0x30eb, 0x05}, ++ {0x30eb, 0x0c}, ++ {0x300a, 0xff}, ++ {0x300b, 0xff}, ++ {0x30eb, 0x05}, ++ {0x30eb, 0x09}, ++ {0x0114, 0x01}, ++ {0x0128, 0x00}, ++ {0x012a, 0x18}, ++ {0x012b, 0x00}, ++ {0x0162, 0x0d}, ++ {0x0163, 0x78}, ++ {0x0164, 0x02}, ++ {0x0165, 0xa8}, ++ {0x0166, 0x0a}, ++ {0x0167, 0x27}, ++ {0x0168, 0x02}, ++ {0x0169, 0xb4}, ++ {0x016a, 0x06}, ++ {0x016b, 0xeb}, ++ {0x016c, 0x07}, ++ {0x016d, 0x80}, ++ {0x016e, 0x04}, ++ {0x016f, 0x38}, ++ {0x0170, 0x01}, ++ {0x0171, 0x01}, ++ {0x0174, 0x00}, ++ {0x0175, 0x00}, ++ {0x018c, 0x0a}, ++ {0x018d, 0x0a}, ++ {0x0301, 0x05}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x0305, 0x03}, ++ {0x0306, 0x00}, ++ {0x0307, 0x39}, ++ {0x0309, 0x0a}, ++ {0x030b, 0x01}, ++ {0x030c, 0x00}, ++ {0x030d, 0x72}, ++ {0x0624, 0x07}, ++ {0x0625, 0x80}, ++ {0x0626, 0x04}, ++ {0x0627, 0x38}, ++ {0x455e, 0x00}, ++ {0x471e, 0x4b}, ++ {0x4767, 0x0f}, ++ {0x4750, 0x14}, ++ {0x4540, 0x00}, ++ {0x47b4, 0x14}, ++ {0x4713, 0x30}, ++ {0x478b, 0x10}, ++ {0x478f, 0x10}, ++ {0x4793, 0x10}, ++ {0x4797, 0x0e}, ++ {0x479b, 0x0e}, ++ {0x0162, 0x0d}, ++ {0x0163, 0x78}, ++}; ++ ++static const struct imx219_reg mode_1640_1232_regs[] = { ++ {0x0100, 0x00}, ++ {0x30eb, 0x0c}, ++ {0x30eb, 0x05}, ++ {0x300a, 0xff}, ++ {0x300b, 0xff}, ++ {0x30eb, 0x05}, ++ {0x30eb, 0x09}, ++ {0x0114, 0x01}, ++ {0x0128, 0x00}, ++ {0x012a, 0x18}, ++ {0x012b, 0x00}, ++ {0x0164, 0x00}, ++ {0x0165, 0x00}, ++ {0x0166, 0x0c}, ++ {0x0167, 0xcf}, ++ {0x0168, 0x00}, ++ {0x0169, 0x00}, ++ {0x016a, 0x09}, ++ {0x016b, 0x9f}, ++ {0x016c, 0x06}, ++ {0x016d, 0x68}, ++ {0x016e, 0x04}, ++ {0x016f, 0xd0}, ++ {0x0170, 0x01}, ++ {0x0171, 0x01}, ++ {0x0174, 0x01}, ++ {0x0175, 0x01}, ++ {0x018c, 0x0a}, ++ {0x018d, 0x0a}, ++ {0x0301, 0x05}, ++ {0x0303, 0x01}, ++ {0x0304, 0x03}, ++ {0x0305, 0x03}, ++ {0x0306, 0x00}, ++ {0x0307, 0x39}, ++ {0x0309, 0x0a}, ++ {0x030b, 0x01}, ++ {0x030c, 0x00}, ++ {0x030d, 0x72}, ++ {0x0624, 0x06}, ++ {0x0625, 0x68}, ++ {0x0626, 0x04}, ++ {0x0627, 0xd0}, ++ {0x455e, 0x00}, ++ {0x471e, 0x4b}, ++ {0x4767, 0x0f}, ++ {0x4750, 0x14}, ++ {0x4540, 0x00}, ++ {0x47b4, 0x14}, ++ {0x4713, 0x30}, ++ {0x478b, 0x10}, ++ {0x478f, 0x10}, ++ {0x4793, 0x10}, ++ {0x4797, 0x0e}, ++ {0x479b, 0x0e}, ++ {0x0162, 0x0d}, ++ {0x0163, 0x78}, ++}; ++ ++static const char * const imx219_test_pattern_menu[] = { ++ "Disabled", ++ "Color Bars", ++ "Solid Color", ++ "Grey Color Bars", ++ "PN9" ++}; ++ ++static const int imx219_test_pattern_val[] = { ++ IMX219_TEST_PATTERN_DISABLE, ++ IMX219_TEST_PATTERN_COLOR_BARS, ++ IMX219_TEST_PATTERN_SOLID_COLOR, ++ IMX219_TEST_PATTERN_GREY_COLOR, ++ IMX219_TEST_PATTERN_PN9, ++}; ++ ++/* regulator supplies */ ++static const char * const imx219_supply_name[] = { ++ /* Supplies can be enabled in any order */ ++ "VANA", /* Analog (2.8V) supply */ ++ "VDIG", /* Digital Core (1.8V) supply */ ++ "VDDL", /* IF (1.2V) supply */ ++}; ++ ++#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name) ++ ++/* ++ * Initialisation delay between XCLR low->high and the moment when the sensor ++ * can start capture (i.e. can leave software stanby) must be not less than: ++ * t4 + max(t5, t6 +