diff options
121 files changed, 4518 insertions, 1444 deletions
diff --git a/Documentation/devicetree/bindings/arm/rockchip/pmu.yaml b/Documentation/devicetree/bindings/arm/rockchip/pmu.yaml index 55b2200d6e75..1cff2328cd01 100644 --- a/Documentation/devicetree/bindings/arm/rockchip/pmu.yaml +++ b/Documentation/devicetree/bindings/arm/rockchip/pmu.yaml @@ -61,7 +61,13 @@ properties: type: object reboot-mode: - type: object + $ref: /schemas/power/reset/syscon-reboot-mode.yaml + unevaluatedProperties: false + + patternProperties: + # Negative look-ahead to disallow unsupported modes. The '$' has to be + # part of lookahead group to work, instead of trailing outside of (). + "^mode-(?!(bootloader$|loader$|normal$|recovery$))": false required: - compatible diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml index 25f62bacbc91..24a49613c869 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml @@ -37,6 +37,7 @@ properties: - qcom,scm-ipq9574 - qcom,scm-ipq9650 - qcom,scm-kaanapali + - qcom,scm-maili - qcom,scm-mdm9607 - qcom,scm-milos - qcom,scm-msm8226 @@ -129,6 +130,13 @@ properties: - description: offset of the download mode control register description: TCSR hardware block + sram: + description: + Phandle to a region in always-on SRAM used to store the download + mode value for boot firmware to read before DDR is initialised on + the next warm reset. + maxItems: 1 + allOf: # Clocks - if: @@ -212,6 +220,7 @@ allOf: - qcom,scm-eliza - qcom,scm-hawi - qcom,scm-kaanapali + - qcom,scm-maili - qcom,scm-milos - qcom,scm-sm8450 - qcom,scm-sm8550 diff --git a/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml new file mode 100644 index 000000000000..1d2ab44fcd3c --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/fsl,mpc8323-qe-pario-bank.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/fsl,mpc8323-qe-pario-bank.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale QUICC Engine Parallel I/O (QE PARIO) GPIO Bank + +maintainers: + - Christophe Leroy <christophe.leroy@csgroup.eu> + +properties: + compatible: + oneOf: + - items: + - enum: + - fsl,mpc8360-qe-pario-bank + - fsl,mpc8569-qe-pario-bank + - const: fsl,mpc8323-qe-pario-bank + - const: fsl,mpc8323-qe-pario-bank + + reg: + maxItems: 1 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + "#address-cells": + const: 0 + + "#interrupt-cells": + const: 2 + + interrupt-map: + description: | + Specifies the mapping of GPIO lines to the parent interrupt controller, as the + GPIO controller does not do interrupt handling itself. + +required: + - compatible + - reg + - gpio-controller + - "#gpio-cells" + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + + gpio-controller@1400 { + compatible = "fsl,mpc8360-qe-pario-bank", "fsl,mpc8323-qe-pario-bank"; + reg = <0x1400 0x18>; + gpio-controller; + #gpio-cells = <2>; + }; + + gpio-controller@1418 { + compatible = "fsl,mpc8323-qe-pario-bank"; + reg = <0x1418 0x18>; + gpio-controller; + #gpio-cells = <2>; + #address-cells = <0>; + #interrupt-cells = <2>; + interrupt-map = < + 7 IRQ_TYPE_EDGE_FALLING &pic 4 IRQ_TYPE_EDGE_FALLING + 7 IRQ_TYPE_EDGE_BOTH &pic 4 IRQ_TYPE_EDGE_BOTH + 7 0 &pic 4 IRQ_TYPE_NONE + + 9 IRQ_TYPE_EDGE_FALLING &pic 5 IRQ_TYPE_EDGE_FALLING + 9 IRQ_TYPE_EDGE_BOTH &pic 5 IRQ_TYPE_EDGE_BOTH + 9 0 &pic 5 IRQ_TYPE_NONE + + 25 IRQ_TYPE_EDGE_FALLING &pic 6 IRQ_TYPE_EDGE_FALLING + 25 IRQ_TYPE_EDGE_BOTH &pic 6 IRQ_TYPE_EDGE_BOTH + 25 0 &pic 6 IRQ_TYPE_NONE + + 27 IRQ_TYPE_EDGE_FALLING &pic 7 IRQ_TYPE_EDGE_FALLING + 27 IRQ_TYPE_EDGE_BOTH &pic 7 IRQ_TYPE_EDGE_BOTH + 27 0 &pic 7 IRQ_TYPE_NONE + >; + }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml b/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml index 2b8e7b9c6d7a..2b7c6b4f0389 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/fsl,qe-ports-ic.yaml @@ -23,7 +23,7 @@ properties: const: 0 '#interrupt-cells': - const: 1 + const: 2 interrupts: maxItems: 1 @@ -45,7 +45,7 @@ examples: reg = <0xc00 0x18>; interrupt-controller; #address-cells = <0>; - #interrupt-cells = <1>; + #interrupt-cells = <2>; interrupts = <74 0x8>; interrupt-parent = <&ipic>; }; diff --git a/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-clk-measure.yaml b/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-clk-measure.yaml index 39d4637c2d08..b1200e6940ac 100644 --- a/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-clk-measure.yaml +++ b/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-gx-clk-measure.yaml @@ -24,6 +24,8 @@ properties: - amlogic,meson-sm1-clk-measure - amlogic,c3-clk-measure - amlogic,s4-clk-measure + - amlogic,a1-clk-measure + - amlogic,t7-clk-measure reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/soc/apple/apple,t6000-pmgr-misc.yaml b/Documentation/devicetree/bindings/soc/apple/apple,t6000-pmgr-misc.yaml new file mode 100644 index 000000000000..588100222f89 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/apple/apple,t6000-pmgr-misc.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/apple/apple,t6000-pmgr-misc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple SoC PMGR Misc Power States + +maintainers: + - Sasha Finkelstein <k@chaosmail.tech> + +description: | + Certain Apple SoCs include additional PMGR power states that are controlled + via a different "misc" control block. This includes the fabric and memory + controller states. + +properties: + compatible: + enum: + - apple,t6000-pmgr-misc + - apple,t6020-pmgr-misc + + reg: + maxItems: 2 + + reg-names: + items: + - const: fabric-ps + - const: dcs-ps + +required: + - compatible + - reg + - reg-names + +additionalProperties: false + +examples: + - | + power-management@8e20c000 { + compatible = "apple,t6000-pmgr-misc"; + reg = <0x8e20c000 0x400>, + <0x8e20c800 0x400>; + reg-names = "fabric-ps", "dcs-ps"; + }; diff --git a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt index 09b1b05fa677..782699c14567 100644 --- a/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt +++ b/Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe/par_io.txt @@ -24,28 +24,4 @@ par_io@1400 { Note that "par_io" nodes are obsolete, and should not be used for the new device trees. Instead, each Par I/O bank should be represented -via its own gpio-controller node: - -Required properties: -- #gpio-cells : should be "2". -- compatible : should be "fsl,<chip>-qe-pario-bank", - "fsl,mpc8323-qe-pario-bank". -- reg : offset to the register set and its length. -- gpio-controller : node to identify gpio controllers. - -Example: - qe_pio_a: gpio-controller@1400 { - #gpio-cells = <2>; - compatible = "fsl,mpc8360-qe-pario-bank", - "fsl,mpc8323-qe-pario-bank"; - reg = <0x1400 0x18>; - gpio-controller; - }; - - qe_pio_e: gpio-controller@1460 { - #gpio-cells = <2>; - compatible = "fsl,mpc8360-qe-pario-bank", - "fsl,mpc8323-qe-pario-bank"; - reg = <0x1460 0x18>; - gpio-controller; - }; +via its own gpio-controller node. diff --git a/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml b/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml index 3fb0534ea597..fc14fd0bf84b 100644 --- a/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml +++ b/Documentation/devicetree/bindings/soc/fsl/fsl,layerscape-dcfg.yaml @@ -36,7 +36,20 @@ properties: - const: simple-mfd reg: - maxItems: 1 + minItems: 1 + items: + - description: + Customer-visible DCFG register map from CCSR address space + (Configuration, Control and Status Registers) + - description: + Customer-hidden DCFG register map from DCSR address space + (Debug Control and Status Registers) + + reg-names: + minItems: 1 + items: + - const: dcfg_ccsr + - const: dcfg_dcsr little-endian: true big-endian: true diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index 8eaa04431d74..d2ae2ae87a95 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -29,7 +29,9 @@ properties: - qcom,glymur-aoss-qmp - qcom,hawi-aoss-qmp - qcom,kaanapali-aoss-qmp + - qcom,maili-aoss-qmp - qcom,milos-aoss-qmp + - qcom,nord-aoss-qmp - qcom,qcs615-aoss-qmp - qcom,qcs8300-aoss-qmp - qcom,qdu1000-aoss-qmp diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml index 2db4288a8a54..16ad4f5698fc 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml @@ -35,6 +35,7 @@ properties: - items: - enum: - qcom,hawi-pmic-glink + - qcom,maili-pmic-glink - const: qcom,kaanapali-pmic-glink - const: qcom,pmic-glink - items: diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml index 270bcd079f88..bd1d32898461 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml @@ -57,6 +57,7 @@ properties: - qcom,rpm-qcm2290 - qcom,rpm-qcs404 - qcom,rpm-sdm660 + - qcom,rpm-shikra - qcom,rpm-sm6115 - qcom,rpm-sm6125 - qcom,rpm-sm6375 diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.yaml index 4fcae6bedfff..56a4152633e5 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,wcnss.yaml @@ -19,8 +19,8 @@ properties: const: qcom,wcnss firmware-name: - $ref: /schemas/types.yaml#/definitions/string - default: wlan/prima/WCNSS_qcom_wlan_nv.bin + maxItems: 1 + default: [ wlan/prima/WCNSS_qcom_wlan_nv.bin ] description: Relative firmware image path for the WLAN NV blob. diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml index 2cc43742b8e3..7bcb4e2f47ec 100644 --- a/Documentation/devicetree/bindings/soc/rockchip/grf.yaml +++ b/Documentation/devicetree/bindings/soc/rockchip/grf.yaml @@ -239,11 +239,14 @@ allOf: properties: reboot-mode: type: object - $ref: /schemas/power/reset/syscon-reboot-mode.yaml# - unevaluatedProperties: false + patternProperties: + # Negative look-ahead to disallow unsupported modes. The '$' has to be + # part of lookahead group to work, instead of trailing outside of (). + "^mode-(?!(bootloader$|fastboot$|loader$|normal$|recovery$))": false + - if: properties: compatible: diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml index 76ce7e98c10f..5bd39876e3b3 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/exynos-pmu.yaml @@ -94,19 +94,19 @@ properties: reboot-mode: $ref: /schemas/power/reset/syscon-reboot-mode.yaml - type: object + unevaluatedProperties: false description: Reboot mode to alter bootloader behavior for the next boot syscon-poweroff: $ref: /schemas/power/reset/syscon-poweroff.yaml# - type: object + unevaluatedProperties: false description: Node for power off method syscon-reboot: $ref: /schemas/power/reset/syscon-reboot.yaml# - type: object + unevaluatedProperties: false description: Node for reboot method @@ -181,8 +181,29 @@ allOf: compatible: contains: enum: + - samsung,exynos7-pmu + then: + properties: + reboot-mode: + patternProperties: + # Negative look-ahead to disallow unsupported modes. The '$' has to be + # part of lookahead group to work, instead of trailing outside of (). + "^mode-(?!(bootloader$|download$|fastboot$|recovery$))": false + + - if: + properties: + compatible: + contains: + enum: - google,gs101-pmu then: + properties: + reboot-mode: + patternProperties: + # Negative look-ahead to disallow unsupported modes. The '$' has to be + # part of lookahead group to work, instead of trailing outside of (). + "^mode-(?!(bootloader$|charge$|dm-verity-device-corrupted$|fastboot$|reboot-ab-update$|recovery$)|rescue$|shutdown-thermal$|shutdown-thermal-battery$)": false + required: - google,pmu-intr-gen-syscon else: diff --git a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml index 9c63dbcd4d77..fcdb9ffd2644 100644 --- a/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml +++ b/Documentation/devicetree/bindings/soc/samsung/samsung,exynos-sysreg.yaml @@ -37,6 +37,7 @@ properties: - samsung,exynos8895-peric1-sysreg - samsung,exynos990-peric0-sysreg - samsung,exynos990-peric1-sysreg + - samsung,exynosautov920-hsi0-sysreg - samsung,exynosautov920-hsi2-sysreg - samsung,exynosautov920-peric0-sysreg - samsung,exynosautov920-peric1-sysreg diff --git a/Documentation/devicetree/bindings/sram/qcom,imem.yaml b/Documentation/devicetree/bindings/sram/qcom,imem.yaml index c63026904061..17adced6d3a4 100644 --- a/Documentation/devicetree/bindings/sram/qcom,imem.yaml +++ b/Documentation/devicetree/bindings/sram/qcom,imem.yaml @@ -67,6 +67,22 @@ properties: $ref: /schemas/power/reset/syscon-reboot-mode.yaml# patternProperties: + "^minidump-sram@[0-9a-f]+$": + type: object + description: + A word in always-on SRAM shared between the kernel and boot firmware. + Before DDR is initialised on the warm reset following a crash, firmware + reads this word to decide where to deliver the minidump (USB or storage). + + properties: + reg: + maxItems: 1 + + required: + - reg + + additionalProperties: false + "^modem-tables@[0-9a-f]+$": type: object description: diff --git a/Documentation/devicetree/bindings/sram/sram.yaml b/Documentation/devicetree/bindings/sram/sram.yaml index 5bf27c5f63e2..b83fc6831947 100644 --- a/Documentation/devicetree/bindings/sram/sram.yaml +++ b/Documentation/devicetree/bindings/sram/sram.yaml @@ -38,8 +38,10 @@ properties: - qcom,glymur-imem - qcom,hawi-imem - qcom,kaanapali-imem + - qcom,maili-imem - qcom,milos-imem - qcom,rpm-msg-ram + - qcom,shikra-imem - rockchip,rk3288-pmu-sram reg: diff --git a/MAINTAINERS b/MAINTAINERS index f8fb866d7929..db53a82699b6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2607,6 +2607,7 @@ F: Documentation/devicetree/bindings/power/apple* F: Documentation/devicetree/bindings/power/reset/apple,smc-reboot.yaml F: Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml F: Documentation/devicetree/bindings/rtc/apple,smc-rtc.yaml +F: Documentation/devicetree/bindings/soc/apple/apple,t6000-pmgr-misc.yaml F: Documentation/devicetree/bindings/spi/apple,spi.yaml F: Documentation/devicetree/bindings/spmi/apple,spmi.yaml F: Documentation/devicetree/bindings/usb/apple,dwc3.yaml @@ -7816,7 +7817,7 @@ F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9807-vcm.yaml F: drivers/media/i2c/dw9807-vcm.c DPAA2 DATAPATH I/O (DPIO) DRIVER -M: Roy Pledge <Roy.Pledge@nxp.com> +M: Ioana Ciornei <ioana.ciornei@nxp.com> L: linux-kernel@vger.kernel.org S: Maintained F: drivers/soc/fsl/dpio @@ -22311,6 +22312,15 @@ F: Documentation/devicetree/bindings/media/*qcom* F: drivers/media/platform/qcom F: include/dt-bindings/media/*qcom* +QUALCOMM PAS TZ SERVICE +M: Sumit Garg <sumit.garg@oss.qualcomm.com> +L: linux-arm-msm@vger.kernel.org +S: Maintained +F: drivers/firmware/qcom/qcom_pas.c +F: drivers/firmware/qcom/qcom_pas.h +F: drivers/firmware/qcom/qcom_pas_tee.c +F: include/linux/firmware/qcom/qcom_pas.h + QUALCOMM SMB CHARGER DRIVER M: Casey Connolly <casey.connolly@linaro.org> L: linux-arm-msm@vger.kernel.org diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index c4e61843d9d9..2f797ac6f1b3 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -228,14 +228,6 @@ config TAU_AVERAGE If in doubt, say N here. -config QE_GPIO - bool "QE GPIO support" - depends on QUICC_ENGINE - select GPIOLIB - help - Say Y here if you're going to use hardware that connects to the - QE GPIOs. - config CPM2 bool "Enable support for the CPM2 (Communications Processor Module)" depends on (FSL_SOC_BOOKE && PPC32) || PPC_82xx diff --git a/drivers/bus/fsl-mc/dprc-driver.c b/drivers/bus/fsl-mc/dprc-driver.c index a85706826fa0..a81188cb06f2 100644 --- a/drivers/bus/fsl-mc/dprc-driver.c +++ b/drivers/bus/fsl-mc/dprc-driver.c @@ -521,12 +521,8 @@ static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev) IRQF_NO_SUSPEND | IRQF_ONESHOT, dev_name(&mc_dev->dev), &mc_dev->dev); - if (error < 0) { - dev_err(&mc_dev->dev, - "devm_request_threaded_irq() failed: %d\n", - error); + if (error < 0) return error; - } return 0; } diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 64d75eed0d34..66a4fa73c5b8 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -908,7 +908,7 @@ struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev, int state, err; mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent); - strcpy(endpoint1.type, mc_dev->obj_desc.type); + strscpy(endpoint1.type, mc_dev->obj_desc.type); endpoint1.id = mc_dev->obj_desc.id; endpoint1.if_id = if_id; @@ -925,7 +925,7 @@ struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev, return ERR_PTR(err); } - strcpy(endpoint_desc.type, endpoint2.type); + strscpy(endpoint_desc.type, endpoint2.type); endpoint_desc.id = endpoint2.id; endpoint = fsl_mc_device_lookup(&endpoint_desc, mc_bus_dev); if (endpoint) @@ -1202,7 +1202,7 @@ static const struct of_device_id fsl_mc_bus_match_table[] = { MODULE_DEVICE_TABLE(of, fsl_mc_bus_match_table); static const struct acpi_device_id fsl_mc_bus_acpi_match_table[] = { - {"NXP0008", 0 }, + { .id = "NXP0008" }, { } }; MODULE_DEVICE_TABLE(acpi, fsl_mc_bus_acpi_match_table); diff --git a/drivers/bus/qcom-ebi2.c b/drivers/bus/qcom-ebi2.c index be8166565e7c..8d2eb955dc92 100644 --- a/drivers/bus/qcom-ebi2.c +++ b/drivers/bus/qcom-ebi2.c @@ -302,41 +302,23 @@ static int qcom_ebi2_probe(struct platform_device *pdev) u32 val; int ret; - ebi2xclk = devm_clk_get(dev, "ebi2x"); + ebi2xclk = devm_clk_get_enabled(dev, "ebi2x"); if (IS_ERR(ebi2xclk)) return PTR_ERR(ebi2xclk); - ret = clk_prepare_enable(ebi2xclk); - if (ret) { - dev_err(dev, "could not enable EBI2X clk (%d)\n", ret); - return ret; - } - - ebi2clk = devm_clk_get(dev, "ebi2"); - if (IS_ERR(ebi2clk)) { - ret = PTR_ERR(ebi2clk); - goto err_disable_2x_clk; - } - - ret = clk_prepare_enable(ebi2clk); - if (ret) { - dev_err(dev, "could not enable EBI2 clk\n"); - goto err_disable_2x_clk; - } + ebi2clk = devm_clk_get_enabled(dev, "ebi2"); + if (IS_ERR(ebi2clk)) + return PTR_ERR(ebi2clk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ebi2_base = devm_ioremap_resource(dev, res); - if (IS_ERR(ebi2_base)) { - ret = PTR_ERR(ebi2_base); - goto err_disable_clk; - } + if (IS_ERR(ebi2_base)) + return PTR_ERR(ebi2_base); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); ebi2_xmem = devm_ioremap_resource(dev, res); - if (IS_ERR(ebi2_xmem)) { - ret = PTR_ERR(ebi2_xmem); - goto err_disable_clk; - } + if (IS_ERR(ebi2_xmem)) + return PTR_ERR(ebi2_xmem); /* Allegedly this turns the power save mode off */ writel(0UL, ebi2_xmem + EBI2_XMEM_CFG); @@ -373,15 +355,9 @@ static int qcom_ebi2_probe(struct platform_device *pdev) } if (have_children) - return of_platform_default_populate(np, NULL, dev); - return 0; + return devm_of_platform_populate(dev); -err_disable_clk: - clk_disable_unprepare(ebi2clk); -err_disable_2x_clk: - clk_disable_unprepare(ebi2xclk); - - return ret; + return 0; } static const struct of_device_id qcom_ebi2_of_match[] = { diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index a5b9507de37c..e118b900c9ac 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -682,6 +682,7 @@ static struct device_node *stdout_path; static void sysc_init_stdout_path(struct sysc *ddata) { + struct device_node *chosen; struct device_node *np = NULL; const char *uart; @@ -691,15 +692,18 @@ static void sysc_init_stdout_path(struct sysc *ddata) if (stdout_path) return; - np = of_find_node_by_path("/chosen"); - if (!np) + chosen = of_find_node_by_path("/chosen"); + if (!chosen) goto err; - uart = of_get_property(np, "stdout-path", NULL); - if (!uart) + uart = of_get_property(chosen, "stdout-path", NULL); + if (!uart) { + of_node_put(chosen); goto err; + } np = of_find_node_by_path(uart); + of_node_put(chosen); if (!np) goto err; diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index a1ee475d180d..b88b01aa5829 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -120,11 +120,11 @@ config ARM_QCOM_SPM_CPUIDLE bool "CPU Idle Driver for Qualcomm Subsystem Power Manager (SPM)" depends on (ARCH_QCOM || COMPILE_TEST) && !ARM64 && MMU depends on ARCH_SUSPEND_POSSIBLE + depends on QCOM_SCM=y + depends on QCOM_SPM=y select ARM_CPU_SUSPEND select CPU_IDLE_MULTIPLE_DRIVERS select DT_IDLE_STATES - select QCOM_SCM - select QCOM_SPM help Select this to enable cpuidle for Qualcomm processors. The Subsystem Power Manager (SPM) controls low power modes for the diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c index 793be9eabaed..e060edbe7e83 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -7,7 +7,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <linux/atomic.h> #include <linux/types.h> #include <linux/module.h> #include <linux/of.h> @@ -33,8 +32,8 @@ struct scmi_requested_dev { struct list_head node; }; -/* Track globally the creation of SCMI SystemPower related devices */ -static atomic_t scmi_syspower_registered = ATOMIC_INIT(0); +/* Track globally the SCMI SystemPower protocol device. */ +static struct scmi_device *scmi_syspower_registered; /** * scmi_protocol_device_request - Helper to request a device @@ -136,17 +135,6 @@ out: return ret; } -static int scmi_protocol_table_register(const struct scmi_device_id *id_table) -{ - int ret = 0; - const struct scmi_device_id *entry; - - for (entry = id_table; entry->name && ret == 0; entry++) - ret = scmi_protocol_device_request(entry); - - return ret; -} - /** * scmi_protocol_device_unrequest - Helper to unrequest a device * @@ -159,6 +147,7 @@ static int scmi_protocol_table_register(const struct scmi_device_id *id_table) */ static void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table) { + struct scmi_requested_dev *rdev, *victim = NULL; struct list_head *phead; pr_debug("Unrequesting SCMI device (%s) for protocol %x\n", @@ -167,29 +156,48 @@ static void scmi_protocol_device_unrequest(const struct scmi_device_id *id_table mutex_lock(&scmi_requested_devices_mtx); phead = idr_find(&scmi_requested_devices, id_table->protocol_id); if (phead) { - struct scmi_requested_dev *victim, *tmp; - - list_for_each_entry_safe(victim, tmp, phead, node) { - if (!strcmp(victim->id_table->name, id_table->name)) { - list_del(&victim->node); - - mutex_unlock(&scmi_requested_devices_mtx); - blocking_notifier_call_chain(&scmi_requested_devices_nh, - SCMI_BUS_NOTIFY_DEVICE_UNREQUEST, - (void *)victim->id_table); - kfree(victim); - mutex_lock(&scmi_requested_devices_mtx); + list_for_each_entry(rdev, phead, node) { + if (!strcmp(rdev->id_table->name, id_table->name)) { + victim = rdev; + list_del(&rdev->node); break; } } - if (list_empty(phead)) { + if (victim && list_empty(phead)) { idr_remove(&scmi_requested_devices, id_table->protocol_id); kfree(phead); } } mutex_unlock(&scmi_requested_devices_mtx); + + if (victim) { + blocking_notifier_call_chain(&scmi_requested_devices_nh, + SCMI_BUS_NOTIFY_DEVICE_UNREQUEST, + (void *)victim->id_table); + kfree(victim); + } +} + +static int scmi_protocol_table_register(const struct scmi_device_id *id_table) +{ + const struct scmi_device_id *entry; + int ret; + + for (entry = id_table; entry->name; entry++) { + ret = scmi_protocol_device_request(entry); + if (ret) + goto err_unrequest; + } + + return 0; + +err_unrequest: + while (entry != id_table) + scmi_protocol_device_unrequest(--entry); + + return ret; } static void @@ -201,21 +209,33 @@ scmi_protocol_table_unregister(const struct scmi_device_id *id_table) scmi_protocol_device_unrequest(entry); } -static int scmi_dev_match_by_id_table(struct scmi_device *scmi_dev, - const struct scmi_device_id *id_table) +static bool scmi_device_is_transport(const struct scmi_device *scmi_dev) +{ + return !strncmp(scmi_dev->name, SCMI_TRANSPORT_DEVNAME_PREFIX, + strlen(SCMI_TRANSPORT_DEVNAME_PREFIX)); +} + +static int __scmi_dev_match_by_id_table(struct scmi_device *scmi_dev, + const struct scmi_device_id *id_table, + bool skip_transport) { if (!id_table || !id_table->name) return 0; - /* Always skip transport devices from matching */ for (; id_table->protocol_id && id_table->name; id_table++) if (id_table->protocol_id == scmi_dev->protocol_id && - strncmp(scmi_dev->name, "__scmi_transport_device", 23) && + !(skip_transport && scmi_device_is_transport(scmi_dev)) && !strcmp(id_table->name, scmi_dev->name)) return 1; return 0; } +static int scmi_dev_match_by_id_table(struct scmi_device *scmi_dev, + const struct scmi_device_id *id_table) +{ + return __scmi_dev_match_by_id_table(scmi_dev, id_table, true); +} + static int scmi_dev_match_id(struct scmi_device *scmi_dev, const struct scmi_driver *scmi_drv) { @@ -235,11 +255,12 @@ static int scmi_match_by_id_table(struct device *dev, const void *data) struct scmi_device *scmi_dev = to_scmi_dev(dev); const struct scmi_device_id *id_table = data; - return scmi_dev_match_by_id_table(scmi_dev, id_table); + return __scmi_dev_match_by_id_table(scmi_dev, id_table, false); } -static struct scmi_device *scmi_child_dev_find(struct device *parent, - int prot_id, const char *name) +/* Returns a device_find_child() reference which must be dropped by caller. */ +static struct scmi_device * +scmi_child_dev_find_get(struct device *parent, int prot_id, const char *name) { struct scmi_device_id id_table[2] = { 0 }; struct device *dev; @@ -251,9 +272,6 @@ static struct scmi_device *scmi_child_dev_find(struct device *parent, if (!dev) return NULL; - /* Drop the refcnt bumped implicitly by device_find_child */ - put_device(dev); - return to_scmi_dev(dev); } @@ -377,10 +395,14 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner, driver->driver.mod_name = mod_name; retval = driver_register(&driver->driver); - if (!retval) - pr_debug("Registered new scmi driver %s\n", driver->name); + if (retval) { + scmi_protocol_table_unregister(driver->id_table); + return retval; + } - return retval; + pr_debug("Registered new scmi driver %s\n", driver->name); + + return 0; } EXPORT_SYMBOL_GPL(scmi_driver_register); @@ -391,10 +413,23 @@ void scmi_driver_unregister(struct scmi_driver *driver) } EXPORT_SYMBOL_GPL(scmi_driver_unregister); +static void scmi_device_release_resources(struct scmi_device *scmi_dev) +{ + if (scmi_dev->protocol_id == SCMI_PROTOCOL_SYSTEM) + cmpxchg(&scmi_syspower_registered, scmi_dev, NULL); + + if (scmi_dev->id) { + ida_free(&scmi_bus_id, scmi_dev->id); + scmi_dev->id = 0; + } +} + static void scmi_device_release(struct device *dev) { struct scmi_device *scmi_dev = to_scmi_dev(dev); + scmi_device_release_resources(scmi_dev); + of_node_put(dev->of_node); kfree_const(scmi_dev->name); kfree(scmi_dev); } @@ -406,11 +441,9 @@ static void __scmi_device_destroy(struct scmi_device *scmi_dev) dev_name(&scmi_dev->dev), scmi_dev->protocol_id, scmi_dev->name); - if (scmi_dev->protocol_id == SCMI_PROTOCOL_SYSTEM) - atomic_set(&scmi_syspower_registered, 0); - - ida_free(&scmi_bus_id, scmi_dev->id); - device_unregister(&scmi_dev->dev); + device_del(&scmi_dev->dev); + scmi_device_release_resources(scmi_dev); + put_device(&scmi_dev->dev); } static struct scmi_device * @@ -419,6 +452,7 @@ __scmi_device_create(struct device_node *np, struct device *parent, { int id, retval; struct scmi_device *scmi_dev; + bool syspower = (protocol == SCMI_PROTOCOL_SYSTEM); /* * If the same protocol/name device already exist under the same parent @@ -427,45 +461,41 @@ __scmi_device_create(struct device_node *np, struct device *parent, * each DT defined protocol at probe time, and the concurrent * registration of SCMI drivers. */ - scmi_dev = scmi_child_dev_find(parent, protocol, name); - if (scmi_dev) + scmi_dev = scmi_child_dev_find_get(parent, protocol, name); + if (scmi_dev) { + put_device(&scmi_dev->dev); return scmi_dev; - - /* - * Ignore any possible subsequent failures while creating the device - * since we are doomed anyway at that point; not using a mutex which - * spans across this whole function to keep things simple and to avoid - * to serialize all the __scmi_device_create calls across possibly - * different SCMI server instances (parent) - */ - if (protocol == SCMI_PROTOCOL_SYSTEM && - atomic_cmpxchg(&scmi_syspower_registered, 0, 1)) { - dev_warn(parent, - "SCMI SystemPower protocol device must be unique !\n"); - return NULL; } scmi_dev = kzalloc_obj(*scmi_dev); if (!scmi_dev) return NULL; - scmi_dev->name = kstrdup_const(name ?: "unknown", GFP_KERNEL); - if (!scmi_dev->name) { + scmi_dev->protocol_id = protocol; + + /* + * Reserve the singleton SystemPower protocol device using the device + * pointer itself, so delayed release of an older device cannot clear + * a reservation owned by a newer device. + */ + if (syspower && cmpxchg(&scmi_syspower_registered, NULL, scmi_dev)) { + dev_warn(parent, + "SCMI SystemPower protocol device must be unique !\n"); kfree(scmi_dev); return NULL; } + scmi_dev->name = kstrdup_const(name ?: "unknown", GFP_KERNEL); + if (!scmi_dev->name) + goto free_dev; + id = ida_alloc_min(&scmi_bus_id, 1, GFP_KERNEL); - if (id < 0) { - kfree_const(scmi_dev->name); - kfree(scmi_dev); - return NULL; - } + if (id < 0) + goto free_name; scmi_dev->id = id; - scmi_dev->protocol_id = protocol; scmi_dev->dev.parent = parent; - device_set_node(&scmi_dev->dev, of_fwnode_handle(np)); + device_set_node(&scmi_dev->dev, of_fwnode_handle(of_node_get(np))); scmi_dev->dev.bus = &scmi_bus_type; scmi_dev->dev.release = scmi_device_release; dev_set_name(&scmi_dev->dev, "scmi_dev.%d", id); @@ -479,8 +509,14 @@ __scmi_device_create(struct device_node *np, struct device *parent, return scmi_dev; put_dev: + scmi_device_release_resources(scmi_dev); put_device(&scmi_dev->dev); - ida_free(&scmi_bus_id, id); + return NULL; +free_name: + kfree_const(scmi_dev->name); +free_dev: + scmi_device_release_resources(scmi_dev); + kfree(scmi_dev); return NULL; } @@ -561,9 +597,11 @@ void scmi_device_destroy(struct device *parent, int protocol, const char *name) { struct scmi_device *scmi_dev; - scmi_dev = scmi_child_dev_find(parent, protocol, name); - if (scmi_dev) + scmi_dev = scmi_child_dev_find_get(parent, protocol, name); + if (scmi_dev) { __scmi_device_destroy(scmi_dev); + put_device(&scmi_dev->dev); + } } EXPORT_SYMBOL_GPL(scmi_device_destroy); diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index b9723c105fc1..fe8c22cfb9f7 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -34,6 +34,8 @@ #define SCMI_SHMEM_MAX_PAYLOAD_SIZE 104 +#define SCMI_TRANSPORT_DEVNAME_PREFIX "__scmi_transport_device" + enum scmi_error_codes { SCMI_SUCCESS = 0, /* Success */ SCMI_ERR_SUPPORT = -1, /* Not supported */ diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 3e0d975ec94c..ef29fd223287 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -33,6 +33,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/processor.h> +#include <linux/rcupdate.h> #include <linux/refcount.h> #include <linux/slab.h> #include <linux/xarray.h> @@ -2628,21 +2629,31 @@ static int scmi_handle_put(const struct scmi_handle *handle) return 0; } -static void scmi_device_link_add(struct device *consumer, +static bool scmi_device_link_add(struct device *consumer, struct device *supplier) { struct device_link *link; link = device_link_add(consumer, supplier, DL_FLAG_AUTOREMOVE_CONSUMER); - WARN_ON(!link); + return !WARN_ON(!link); +} + +static void scmi_clear_handle(struct scmi_device *scmi_dev) +{ + if (!scmi_dev->handle) + return; + + scmi_handle_put(scmi_dev->handle); + scmi_dev->handle = NULL; } static void scmi_set_handle(struct scmi_device *scmi_dev) { scmi_dev->handle = scmi_handle_get(&scmi_dev->dev); - if (scmi_dev->handle) - scmi_device_link_add(&scmi_dev->dev, scmi_dev->handle->dev); + if (scmi_dev->handle && + !scmi_device_link_add(&scmi_dev->dev, scmi_dev->handle->dev)) + scmi_clear_handle(scmi_dev); } static int __scmi_xfer_info_init(struct scmi_info *sinfo, @@ -2751,6 +2762,9 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node, idx = tx ? 0 : 1; idr = tx ? &info->tx_idr : &info->rx_idr; + if (idr_find(idr, prot_id)) + return -EEXIST; + if (!info->desc->ops->chan_available(of_node, idx)) { cinfo = idr_find(idr, SCMI_PROTOCOL_BASE); if (unlikely(!cinfo)) /* Possible only if platform has no Rx */ @@ -2768,7 +2782,7 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node, cinfo->no_completion_irq = info->desc->no_completion_irq; /* Create a unique name for this transport device */ - snprintf(name, 32, "__scmi_transport_device_%s_%02X", + snprintf(name, sizeof(name), SCMI_TRANSPORT_DEVNAME_PREFIX "_%s_%02X", idx ? "rx" : "tx", prot_id); /* Create a uniquely named, dedicated transport device for this chan */ tdev = scmi_device_create(of_node, info->dev, prot_id, name); @@ -2778,13 +2792,12 @@ static int scmi_chan_setup(struct scmi_info *info, struct device_node *of_node, devm_kfree(info->dev, cinfo); return -EINVAL; } - of_node_get(of_node); cinfo->id = prot_id; cinfo->dev = &tdev->dev; + cinfo->handle = &info->handle; ret = info->desc->ops->chan_setup(cinfo, info->dev, tx); if (ret) { - of_node_put(of_node); scmi_device_destroy(info->dev, prot_id, name); devm_kfree(info->dev, cinfo); return ret; @@ -2807,14 +2820,13 @@ idr_alloc: "unable to allocate SCMI idr slot err %d\n", ret); /* Destroy channel and device only if created by this call. */ if (tdev) { - of_node_put(of_node); + info->desc->ops->chan_free(prot_id, cinfo, idr); scmi_device_destroy(info->dev, prot_id, name); devm_kfree(info->dev, cinfo); } return ret; } - cinfo->handle = &info->handle; return 0; } @@ -2872,9 +2884,11 @@ static int scmi_channels_setup(struct scmi_info *info) if (of_property_read_u32(child, "reg", &prot_id)) continue; - if (!FIELD_FIT(MSG_PROTOCOL_ID_MASK, prot_id)) + if (!FIELD_FIT(MSG_PROTOCOL_ID_MASK, prot_id)) { dev_err(info->dev, "Out of range protocol %d\n", prot_id); + continue; + } ret = scmi_txrx_setup(info, child, prot_id); if (ret) @@ -2884,7 +2898,7 @@ static int scmi_channels_setup(struct scmi_info *info) return 0; } -static int scmi_chan_destroy(int id, void *p, void *idr) +static int scmi_chan_destroy(int id, void *p, void *data) { struct scmi_chan_info *cinfo = p; @@ -2892,13 +2906,10 @@ static int scmi_chan_destroy(int id, void *p, void *idr) struct scmi_info *info = handle_to_scmi_info(cinfo->handle); struct scmi_device *sdev = to_scmi_dev(cinfo->dev); - of_node_put(cinfo->dev->of_node); - scmi_device_destroy(info->dev, id, sdev->name); + scmi_device_destroy(info->dev, cinfo->id, sdev->name); cinfo->dev = NULL; } - idr_remove(idr, id); - return 0; } @@ -2925,6 +2936,7 @@ static int scmi_bus_notifier(struct notifier_block *nb, { struct scmi_info *info = bus_nb_to_scmi_info(nb); struct scmi_device *sdev = to_scmi_dev(data); + const char *status; /* Skip devices of different SCMI instances */ if (sdev->dev.parent != info->dev) @@ -2934,18 +2946,22 @@ static int scmi_bus_notifier(struct notifier_block *nb, case BUS_NOTIFY_BIND_DRIVER: /* setup handle now as the transport is ready */ scmi_set_handle(sdev); + status = "about to be BOUND."; + break; + case BUS_NOTIFY_DRIVER_NOT_BOUND: + scmi_clear_handle(sdev); + status = "NOT BOUND."; break; case BUS_NOTIFY_UNBOUND_DRIVER: - scmi_handle_put(sdev->handle); - sdev->handle = NULL; + scmi_clear_handle(sdev); + status = "UNBOUND."; break; default: return NOTIFY_DONE; } dev_dbg(info->dev, "Device %s (%s) is now %s\n", dev_name(&sdev->dev), - sdev->name, action == BUS_NOTIFY_BIND_DRIVER ? - "about to be BOUND." : "UNBOUND."); + sdev->name, status); return NOTIFY_OK; } @@ -2957,7 +2973,9 @@ static int scmi_device_request_notifier(struct notifier_block *nb, struct scmi_device_id *id_table = data; struct scmi_info *info = req_nb_to_scmi_info(nb); + rcu_read_lock(); np = idr_find(&info->active_protocols, id_table->protocol_id); + rcu_read_unlock(); if (!np) return NOTIFY_DONE; @@ -3263,7 +3281,7 @@ static int scmi_probe(struct platform_device *pdev) ret = scmi_channels_setup(info); if (ret) { err_str = "failed to setup channels\n"; - goto clear_ida; + goto clear_txrx_setup; } ret = bus_register_notifier(&scmi_bus_type, &info->bus_nb); @@ -3325,7 +3343,7 @@ static int scmi_probe(struct platform_device *pdev) dev_err(dev, "%s", err_str); return 0; } - goto notification_exit; + goto raw_mode_cleanup; } mutex_lock(&scmi_list_mutex); @@ -3340,8 +3358,10 @@ static int scmi_probe(struct platform_device *pdev) if (of_property_read_u32(child, "reg", &prot_id)) continue; - if (!FIELD_FIT(MSG_PROTOCOL_ID_MASK, prot_id)) + if (!FIELD_FIT(MSG_PROTOCOL_ID_MASK, prot_id)) { dev_err(dev, "Out of range protocol %d\n", prot_id); + continue; + } if (!scmi_is_protocol_implemented(handle, prot_id)) { dev_err(dev, "SCMI protocol %d not implemented\n", @@ -3367,18 +3387,18 @@ static int scmi_probe(struct platform_device *pdev) return 0; -notification_exit: +raw_mode_cleanup: if (IS_ENABLED(CONFIG_ARM_SCMI_RAW_MODE_SUPPORT)) scmi_raw_mode_cleanup(info->raw); - scmi_notification_exit(&info->handle); clear_dev_req_notifier: blocking_notifier_chain_unregister(&scmi_requested_devices_nh, &info->dev_req_nb); clear_bus_notifier: bus_unregister_notifier(&scmi_bus_type, &info->bus_nb); clear_txrx_setup: + scmi_notification_quiesce(&info->handle); scmi_cleanup_txrx_channels(info); -clear_ida: + scmi_notification_exit(&info->handle); ida_free(&scmi_id, info->id); out_err: @@ -3401,6 +3421,12 @@ static void scmi_remove(struct platform_device *pdev) list_del(&info->node); mutex_unlock(&scmi_list_mutex); + blocking_notifier_chain_unregister(&scmi_requested_devices_nh, + &info->dev_req_nb); + + /* Stop transport callbacks before tearing down notifications. */ + scmi_notification_quiesce(&info->handle); + scmi_cleanup_txrx_channels(info); scmi_notification_exit(&info->handle); mutex_lock(&info->protocols_mtx); @@ -3411,13 +3437,8 @@ static void scmi_remove(struct platform_device *pdev) of_node_put(child); idr_destroy(&info->active_protocols); - blocking_notifier_chain_unregister(&scmi_requested_devices_nh, - &info->dev_req_nb); bus_unregister_notifier(&scmi_bus_type, &info->bus_nb); - /* Safe to free channels since no more users */ - scmi_cleanup_txrx_channels(info); - ida_free(&scmi_id, info->id); } diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c index 0a192cf2deab..fb60fb07c0ed 100644 --- a/drivers/firmware/arm_scmi/notify.c +++ b/drivers/firmware/arm_scmi/notify.c @@ -209,11 +209,11 @@ struct scmi_registered_events_desc; * @init_work: A work item to perform final initializations of pending handlers * @notify_wq: A reference to the allocated Kernel cmwq * @pending_mtx: A mutex to protect @pending_events_handlers + * @pending_events_handlers: An hashtable containing all pending events' + * handlers descriptors * @registered_protocols: A statically allocated array containing pointers to * all the registered protocol-level specific information * related to events' handling - * @pending_events_handlers: An hashtable containing all pending events' - * handlers descriptors * * Each platform instance, represented by a handle, has its own instance of * the notification subsystem represented by this structure. @@ -225,8 +225,8 @@ struct scmi_notify_instance { struct workqueue_struct *notify_wq; /* lock to protect pending_events_handlers */ struct mutex pending_mtx; - struct scmi_registered_events_desc **registered_protocols; DECLARE_HASHTABLE(pending_events_handlers, SCMI_PENDING_HASH_SZ); + struct scmi_registered_events_desc *registered_protocols[SCMI_MAX_PROTO]; }; /** @@ -276,13 +276,13 @@ struct scmi_registered_event; * @eh_sz: Size of the pre-allocated buffer @eh * @in_flight: A reference to an in flight &struct scmi_registered_event * @num_events: Number of events in @registered_events - * @registered_events: A dynamically allocated array holding all the registered - * events' descriptors, whose fixed-size is determined at - * compile time. * @registered_mtx: A mutex to protect @registered_events_handlers * @ph: SCMI protocol handle reference * @registered_events_handlers: An hashtable containing all events' handlers * descriptors registered for this protocol + * @registered_events: A dynamically allocated array holding all the registered + * events' descriptors, whose fixed-size is determined at + * compile time. * * All protocols that register at least one event have their protocol-specific * information stored here, together with the embedded allocated events_queue. @@ -302,11 +302,11 @@ struct scmi_registered_events_desc { size_t eh_sz; void *in_flight; int num_events; - struct scmi_registered_event **registered_events; /* mutex to protect registered_events_handlers */ struct mutex registered_mtx; const struct scmi_protocol_handle *ph; DECLARE_HASHTABLE(registered_events_handlers, SCMI_REGISTERED_HASH_SZ); + struct scmi_registered_event *registered_events[] __counted_by(num_events); }; /** @@ -338,9 +338,9 @@ struct scmi_registered_event { void *report; u32 num_sources; bool not_supported_by_platform; - refcount_t *sources; /* locking to serialize the access to sources */ struct mutex sources_mtx; + refcount_t sources[] __counted_by(num_sources); }; /** @@ -706,9 +706,13 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni, if (WARN_ON(ni->registered_protocols[proto_id])) return ERR_PTR(-EINVAL); - pd = devm_kzalloc(ni->handle->dev, sizeof(*pd), GFP_KERNEL); + pd = devm_kzalloc(ni->handle->dev, + struct_size(pd, registered_events, num_events), + GFP_KERNEL); if (!pd) return ERR_PTR(-ENOMEM); + + pd->num_events = num_events; pd->id = proto_id; pd->ops = ops; pd->ni = ni; @@ -722,12 +726,6 @@ scmi_allocate_registered_events_desc(struct scmi_notify_instance *ni, return ERR_PTR(-ENOMEM); pd->eh_sz = eh_sz; - pd->registered_events = devm_kcalloc(ni->handle->dev, num_events, - sizeof(char *), GFP_KERNEL); - if (!pd->registered_events) - return ERR_PTR(-ENOMEM); - pd->num_events = num_events; - /* Initialize per protocol handlers table */ mutex_init(&pd->registered_mtx); hash_init(pd->registered_events_handlers); @@ -796,18 +794,16 @@ int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id, int id; struct scmi_registered_event *r_evt; - r_evt = devm_kzalloc(ni->handle->dev, sizeof(*r_evt), + r_evt = devm_kzalloc(ni->handle->dev, + struct_size(r_evt, sources, num_sources), GFP_KERNEL); if (!r_evt) return -ENOMEM; + + r_evt->num_sources = num_sources; r_evt->proto = pd; r_evt->evt = evt; - r_evt->sources = devm_kcalloc(ni->handle->dev, num_sources, - sizeof(refcount_t), GFP_KERNEL); - if (!r_evt->sources) - return -ENOMEM; - r_evt->num_sources = num_sources; mutex_init(&r_evt->sources_mtx); r_evt->report = devm_kzalloc(ni->handle->dev, @@ -1673,11 +1669,6 @@ int scmi_notification_init(struct scmi_handle *handle) ni->gid = gid; ni->handle = handle; - ni->registered_protocols = devm_kcalloc(handle->dev, SCMI_MAX_PROTO, - sizeof(char *), GFP_KERNEL); - if (!ni->registered_protocols) - goto err; - ni->notify_wq = alloc_workqueue(dev_name(handle->dev), WQ_UNBOUND | WQ_FREEZABLE | WQ_SYSFS, 0); @@ -1707,6 +1698,25 @@ err: } /** + * scmi_notification_quiesce() - Stop notification late initialization + * @handle: The handle identifying the platform instance to quiesce + * + * Prevent new late-init work from being queued and wait for any already queued + * or running late-init work to complete before transport channels are torn + * down. + */ +void scmi_notification_quiesce(struct scmi_handle *handle) +{ + struct scmi_notify_instance *ni; + + ni = scmi_notification_instance_data_get(handle); + if (!ni) + return; + + disable_work_sync(&ni->init_work); +} + +/** * scmi_notification_exit() - Shutdown and clean Notification core * @handle: The handle identifying the platform instance to shutdown */ @@ -1717,6 +1727,8 @@ void scmi_notification_exit(struct scmi_handle *handle) ni = scmi_notification_instance_data_get(handle); if (!ni) return; + + scmi_notification_quiesce(handle); scmi_notification_instance_data_set(handle, NULL); /* Destroy while letting pending work complete */ diff --git a/drivers/firmware/arm_scmi/notify.h b/drivers/firmware/arm_scmi/notify.h index 76758a736cf4..f18f98c5ab3b 100644 --- a/drivers/firmware/arm_scmi/notify.h +++ b/drivers/firmware/arm_scmi/notify.h @@ -82,6 +82,7 @@ struct scmi_protocol_events { }; int scmi_notification_init(struct scmi_handle *handle); +void scmi_notification_quiesce(struct scmi_handle *handle); void scmi_notification_exit(struct scmi_handle *handle); int scmi_register_protocol_events(const struct scmi_handle *handle, u8 proto_id, const struct scmi_protocol_handle *ph, diff --git a/drivers/firmware/arm_scmi/transports/mailbox.c b/drivers/firmware/arm_scmi/transports/mailbox.c index ae0f67e6cc45..308736c3ead9 100644 --- a/drivers/firmware/arm_scmi/transports/mailbox.c +++ b/drivers/firmware/arm_scmi/transports/mailbox.c @@ -211,13 +211,18 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, cl->tx_block = false; cl->knows_txdone = tx; + cinfo->transport_info = smbox; + smbox->cinfo = cinfo; + mutex_init(&smbox->chan_lock); + smbox->chan = mbox_request_channel(cl, tx ? 0 : p2a_chan); if (IS_ERR(smbox->chan)) { ret = PTR_ERR(smbox->chan); + smbox->chan = NULL; if (ret != -EPROBE_DEFER) dev_err(cdev, "failed to request SCMI %s mailbox\n", desc); - return ret; + goto err_clear_cinfo; } /* Additional unidirectional channel for TX if needed */ @@ -225,9 +230,10 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, smbox->chan_receiver = mbox_request_channel(cl, a2p_rx_chan); if (IS_ERR(smbox->chan_receiver)) { ret = PTR_ERR(smbox->chan_receiver); + smbox->chan_receiver = NULL; if (ret != -EPROBE_DEFER) dev_err(cdev, "failed to request SCMI Tx Receiver mailbox\n"); - return ret; + goto err_free_chan; } } @@ -235,17 +241,23 @@ static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, smbox->chan_platform_receiver = mbox_request_channel(cl, p2a_rx_chan); if (IS_ERR(smbox->chan_platform_receiver)) { ret = PTR_ERR(smbox->chan_platform_receiver); + smbox->chan_platform_receiver = NULL; if (ret != -EPROBE_DEFER) dev_err(cdev, "failed to request SCMI P2A Receiver mailbox\n"); - return ret; + goto err_free_chan; } } - cinfo->transport_info = smbox; - smbox->cinfo = cinfo; - mutex_init(&smbox->chan_lock); - return 0; + +err_free_chan: + mbox_free_channel(smbox->chan); +err_clear_cinfo: + cinfo->transport_info = NULL; + smbox->cinfo = NULL; + devm_iounmap(dev, smbox->shmem); + devm_kfree(dev, smbox); + return ret; } static int mailbox_chan_free(int id, void *p, void *data) diff --git a/drivers/firmware/arm_scmi/transports/smc.c b/drivers/firmware/arm_scmi/transports/smc.c index 21abb571e4f2..1fce3ccdeb7f 100644 --- a/drivers/firmware/arm_scmi/transports/smc.c +++ b/drivers/firmware/arm_scmi/transports/smc.c @@ -172,6 +172,13 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, scmi_info->param_page = SHMEM_PAGE(res.start); scmi_info->param_offset = SHMEM_OFFSET(res.start); } + + scmi_info->func_id = func_id; + scmi_info->cap_id = cap_id; + scmi_info->cinfo = cinfo; + smc_channel_lock_init(scmi_info); + cinfo->transport_info = scmi_info; + /* * If there is an interrupt named "a2p", then the service and * completion of a message is signaled by an interrupt rather than by @@ -183,18 +190,14 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, IRQF_NO_SUSPEND, dev_name(dev), scmi_info); if (ret) { dev_err(dev, "failed to setup SCMI smc irq\n"); + cinfo->transport_info = NULL; + scmi_info->cinfo = NULL; return ret; } } else { cinfo->no_completion_irq = true; } - scmi_info->func_id = func_id; - scmi_info->cap_id = cap_id; - scmi_info->cinfo = cinfo; - smc_channel_lock_init(scmi_info); - cinfo->transport_info = scmi_info; - return 0; } diff --git a/drivers/firmware/qcom/Kconfig b/drivers/firmware/qcom/Kconfig index b477d54b495a..c7f8413ab996 100644 --- a/drivers/firmware/qcom/Kconfig +++ b/drivers/firmware/qcom/Kconfig @@ -6,9 +6,29 @@ menu "Qualcomm firmware drivers" +config QCOM_PAS + tristate "Qualcomm generic PAS interface driver" + help + Enable the generic Peripheral Authentication Service (PAS) provided + by the firmware. It acts as the common layer with different TZ + backends plugged in whether it's an SCM implementation or a proper + TEE bus based PAS service implementation. + +config QCOM_PAS_TEE + tristate "Qualcomm PAS TEE interface driver" + select QCOM_PAS + depends on TEE + depends on !CPU_BIG_ENDIAN + default m if ARCH_QCOM + help + Enable the generic Peripheral Authentication Service (PAS) provided + by the firmware TEE implementation as the backend. + config QCOM_SCM + tristate "Qualcomm PAS SCM interface driver" + select QCOM_PAS select QCOM_TZMEM - tristate + default y if ARCH_QCOM config QCOM_TZMEM tristate diff --git a/drivers/firmware/qcom/Makefile b/drivers/firmware/qcom/Makefile index 0be40a1abc13..88ce74d74c3e 100644 --- a/drivers/firmware/qcom/Makefile +++ b/drivers/firmware/qcom/Makefile @@ -5,6 +5,9 @@ obj-$(CONFIG_QCOM_SCM) += qcom-scm.o qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o +CFLAGS_qcom_scm-smc.o := -I$(src) obj-$(CONFIG_QCOM_TZMEM) += qcom_tzmem.o obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o +obj-$(CONFIG_QCOM_PAS) += qcom_pas.o +obj-$(CONFIG_QCOM_PAS_TEE) += qcom_pas_tee.o diff --git a/drivers/firmware/qcom/qcom_pas.c b/drivers/firmware/qcom/qcom_pas.c new file mode 100644 index 000000000000..24485dd0fa10 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <linux/device/devres.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/kernel.h> +#include <linux/module.h> + +#include "qcom_pas.h" + +static struct qcom_pas_ops *ops_ptr; + +/** + * devm_qcom_pas_context_alloc() - Allocate peripheral authentication service + * context for a given peripheral + * + * PAS context is device-resource managed, so the caller does not need + * to worry about freeing the context memory. + * + * @dev: PAS firmware device + * @pas_id: peripheral authentication service id + * @mem_phys: Subsystem reserve memory start address + * @mem_size: Subsystem reserve memory size + * + * Return: The new PAS context, or ERR_PTR() on failure. + */ +struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev, + u32 pas_id, + phys_addr_t mem_phys, + size_t mem_size) +{ + struct qcom_pas_context *ctx; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + ctx->dev = dev; + ctx->pas_id = pas_id; + ctx->mem_phys = mem_phys; + ctx->mem_size = mem_size; + + return ctx; +} +EXPORT_SYMBOL_GPL(devm_qcom_pas_context_alloc); + +/** + * qcom_pas_init_image() - Initialize peripheral authentication service state + * machine for a given peripheral, using the metadata + * @pas_id: peripheral authentication service id + * @metadata: pointer to memory containing ELF header, program header table + * and optional blob of data used for authenticating the metadata + * and the rest of the firmware + * @size: size of the metadata + * @ctx: optional pas context + * + * Return: 0 on success. + * + * Upon successful return, the PAS metadata context (@ctx) will be used to + * track the metadata allocation, this needs to be released by invoking + * qcom_pas_metadata_release() by the caller. + */ +int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size, + struct qcom_pas_context *ctx) +{ + if (!ops_ptr) + return -ENODEV; + + return ops_ptr->init_image(ops_ptr->dev, pas_id, metadata, size, ctx); +} +EXPORT_SYMBOL_GPL(qcom_pas_init_image); + +/** + * qcom_pas_metadata_release() - release metadata context + * @ctx: pas context + */ +void qcom_pas_metadata_release(struct qcom_pas_context *ctx) +{ + if (!ops_ptr || !ctx || !ctx->ptr) + return; + + ops_ptr->metadata_release(ops_ptr->dev, ctx); +} +EXPORT_SYMBOL_GPL(qcom_pas_metadata_release); + +/** + * qcom_pas_mem_setup() - Prepare the memory related to a given peripheral + * for firmware loading + * @pas_id: peripheral authentication service id + * @addr: start address of memory area to prepare + * @size: size of the memory area to prepare + * + * Return: 0 on success. + */ +int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) +{ + if (!ops_ptr) + return -ENODEV; + + return ops_ptr->mem_setup(ops_ptr->dev, pas_id, addr, size); +} +EXPORT_SYMBOL_GPL(qcom_pas_mem_setup); + +/** + * qcom_pas_get_rsc_table() - Retrieve the resource table in passed output buffer + * for a given peripheral. + * + * Qualcomm remote processor may rely on both static and dynamic resources for + * its functionality. Static resources typically refer to memory-mapped + * addresses required by the subsystem and are often embedded within the + * firmware binary and dynamic resources, such as shared memory in DDR etc., + * are determined at runtime during the boot process. + * + * On Qualcomm Technologies devices, it's possible that static resources are + * not embedded in the firmware binary and instead are provided by TrustZone. + * However, dynamic resources are always expected to come from TrustZone. This + * indicates that for Qualcomm devices, all resources (static and dynamic) will + * be provided by TrustZone PAS service. + * + * If the remote processor firmware binary does contain static resources, they + * should be passed in input_rt. These will be forwarded to TrustZone for + * authentication. TrustZone will then append the dynamic resources and return + * the complete resource table in output_rt_tzm. + * + * If the remote processor firmware binary does not include a resource table, + * the caller of this function should set input_rt as NULL and input_rt_size + * as zero respectively. + * + * More about documentation on resource table data structures can be found in + * include/linux/remoteproc.h + * + * @ctx: PAS context + * @input_rt: resource table buffer which is present in firmware binary + * @input_rt_size: size of the resource table present in firmware binary + * @output_rt_size: TrustZone expects caller should pass worst case size for + * the output_rt_tzm. + * + * Return: + * On success, returns a pointer to the allocated buffer containing the final + * resource table and output_rt_size will have actual resource table size from + * TrustZone. The caller is responsible for freeing the buffer. On failure, + * returns ERR_PTR(-errno). + */ +struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx, + void *input_rt, + size_t input_rt_size, + size_t *output_rt_size) +{ + if (!ops_ptr) + return ERR_PTR(-ENODEV); + if (!ctx) + return ERR_PTR(-EINVAL); + + return ops_ptr->get_rsc_table(ops_ptr->dev, ctx, input_rt, + input_rt_size, output_rt_size); +} +EXPORT_SYMBOL_GPL(qcom_pas_get_rsc_table); + +/** + * qcom_pas_auth_and_reset() - Authenticate the given peripheral firmware + * and reset the remote processor + * @pas_id: peripheral authentication service id + * + * Return: 0 on success. + */ +int qcom_pas_auth_and_reset(u32 pas_id) +{ + if (!ops_ptr) + return -ENODEV; + + return ops_ptr->auth_and_reset(ops_ptr->dev, pas_id); +} +EXPORT_SYMBOL_GPL(qcom_pas_auth_and_reset); + +/** + * qcom_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the + * remote processor + * + * @ctx: Context saved during call to devm_qcom_pas_context_alloc() + * + * This function performs the necessary steps to prepare a PAS subsystem, + * authenticate it using the provided metadata, and initiate a reset sequence. + * + * It should be used when Linux is in control setting up the IOMMU hardware + * for remote subsystem during secure firmware loading processes. The + * preparation step sets up a shmbridge over the firmware memory before + * TrustZone accesses the firmware memory region for authentication. The + * authentication step verifies the integrity and authenticity of the firmware + * or configuration using secure metadata. Finally, the reset step ensures the + * subsystem starts in a clean and sane state. + * + * Return: 0 on success, negative errno on failure. + */ +int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx) +{ + if (!ops_ptr) + return -ENODEV; + if (!ctx) + return -EINVAL; + + return ops_ptr->prepare_and_auth_reset(ops_ptr->dev, ctx); +} +EXPORT_SYMBOL_GPL(qcom_pas_prepare_and_auth_reset); + +/** + * qcom_pas_set_remote_state() - Set the remote processor state + * @state: peripheral state + * @pas_id: peripheral authentication service id + * + * Return: 0 on success. + */ +int qcom_pas_set_remote_state(u32 state, u32 pas_id) +{ + if (!ops_ptr) + return -ENODEV; + + return ops_ptr->set_remote_state(ops_ptr->dev, state, pas_id); +} +EXPORT_SYMBOL_GPL(qcom_pas_set_remote_state); + +/** + * qcom_pas_shutdown() - Shut down the remote processor + * @pas_id: peripheral authentication service id + * + * Return: 0 on success. + */ +int qcom_pas_shutdown(u32 pas_id) +{ + if (!ops_ptr) + return -ENODEV; + + return ops_ptr->shutdown(ops_ptr->dev, pas_id); +} +EXPORT_SYMBOL_GPL(qcom_pas_shutdown); + +/** + * qcom_pas_supported() - Check if the peripheral authentication service is + * supported for the given peripheral + * @pas_id: peripheral authentication service id + * + * Return: true if PAS is supported for this peripheral, otherwise false. + */ +bool qcom_pas_supported(u32 pas_id) +{ + if (!ops_ptr) + return false; + + return ops_ptr->supported(ops_ptr->dev, pas_id); +} +EXPORT_SYMBOL_GPL(qcom_pas_supported); + +/** + * qcom_pas_is_available() - Check if the peripheral authentication service is + * available. Note that it is mandatory for any PAS + * client to invoke this API. If it returns true then + * only any other PAS API can be invoked. + * + * Return: true if PAS is available, otherwise false. + */ +bool qcom_pas_is_available(void) +{ + /* + * The barrier for ops_ptr is intended to synchronize the data stores + * for the ops data structure when client drivers are in parallel + * checking for PAS service availability. + * + * Once the PAS backend becomes available, it is allowed for multiple + * threads to enter TZ for parallel bringup of co-processors during + * boot. + */ + return !!smp_load_acquire(&ops_ptr); +} +EXPORT_SYMBOL_GPL(qcom_pas_is_available); + +void qcom_pas_ops_register(struct qcom_pas_ops *ops) +{ + if (!qcom_pas_is_available()) + /* Paired with smp_load_acquire() in qcom_pas_is_available() */ + smp_store_release(&ops_ptr, ops); + else + pr_err("qcom_pas: ops already registered by %s\n", + ops_ptr->drv_name); +} +EXPORT_SYMBOL_GPL(qcom_pas_ops_register); + +void qcom_pas_ops_unregister(void) +{ + /* Paired with smp_load_acquire() in qcom_pas_is_available() */ + smp_store_release(&ops_ptr, NULL); +} +EXPORT_SYMBOL_GPL(qcom_pas_ops_unregister); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Qualcomm generic TZ PAS driver"); diff --git a/drivers/firmware/qcom/qcom_pas.h b/drivers/firmware/qcom/qcom_pas.h new file mode 100644 index 000000000000..8643e2760602 --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __QCOM_PAS_INT_H +#define __QCOM_PAS_INT_H + +struct device; + +/** + * struct qcom_pas_ops - Qcom Peripheral Authentication Service (PAS) ops + * @drv_name: PAS driver name. + * @dev: PAS device pointer. + * @supported: Peripheral supported callback. + * @init_image: Peripheral image initialization callback. + * @mem_setup: Peripheral memory setup callback. + * @get_rsc_table: Peripheral get resource table callback. + * @prepare_and_auth_reset: Peripheral prepare firmware authentication and + * reset callback. + * @auth_and_reset: Peripheral firmware authentication and reset + * callback. + * @set_remote_state: Peripheral set remote state callback. + * @shutdown: Peripheral shutdown callback. + * @metadata_release: Image metadata release callback. + */ +struct qcom_pas_ops { + const char *drv_name; + struct device *dev; + bool (*supported)(struct device *dev, u32 pas_id); + int (*init_image)(struct device *dev, u32 pas_id, const void *metadata, + size_t size, struct qcom_pas_context *ctx); + int (*mem_setup)(struct device *dev, u32 pas_id, phys_addr_t addr, + phys_addr_t size); + void *(*get_rsc_table)(struct device *dev, struct qcom_pas_context *ctx, + void *input_rt, size_t input_rt_size, + size_t *output_rt_size); + int (*prepare_and_auth_reset)(struct device *dev, + struct qcom_pas_context *ctx); + int (*auth_and_reset)(struct device *dev, u32 pas_id); + int (*set_remote_state)(struct device *dev, u32 state, u32 pas_id); + int (*shutdown)(struct device *dev, u32 pas_id); + void (*metadata_release)(struct device *dev, + struct qcom_pas_context *ctx); +}; + +void qcom_pas_ops_register(struct qcom_pas_ops *ops); +void qcom_pas_ops_unregister(void); + +#endif /* __QCOM_PAS_INT_H */ diff --git a/drivers/firmware/qcom/qcom_pas_tee.c b/drivers/firmware/qcom/qcom_pas_tee.c new file mode 100644 index 000000000000..ac33a00687aa --- /dev/null +++ b/drivers/firmware/qcom/qcom_pas_tee.c @@ -0,0 +1,479 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/firmware/qcom/qcom_pas.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/tee_drv.h> +#include <linux/uuid.h> + +#include "qcom_pas.h" + +/* + * Peripheral Authentication Service (PAS) supported. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + */ +#define TA_QCOM_PAS_IS_SUPPORTED 1 + +/* + * PAS capabilities. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [out] params[1].value.a: PAS capability flags + */ +#define TA_QCOM_PAS_CAPABILITIES 2 + +/* + * PAS image initialization. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [in] params[1].memref: Loadable firmware metadata + */ +#define TA_QCOM_PAS_INIT_IMAGE 3 + +/* + * PAS memory setup. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [in] params[0].value.b: Relocatable firmware size + * [in] params[1].value.a: 32bit LSB relocatable firmware memory address + * [in] params[1].value.b: 32bit MSB relocatable firmware memory address + */ +#define TA_QCOM_PAS_MEM_SETUP 4 + +/* + * PAS get resource table. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [inout] params[1].memref: Resource table config + */ +#define TA_QCOM_PAS_GET_RESOURCE_TABLE 5 + +/* + * PAS image authentication and co-processor reset. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [in] params[0].value.b: Firmware size + * [in] params[1].value.a: 32bit LSB firmware memory address + * [in] params[1].value.b: 32bit MSB firmware memory address + * [in] params[2].memref: Optional fw memory space shared/lent + */ +#define TA_QCOM_PAS_AUTH_AND_RESET 6 + +/* + * PAS co-processor set suspend/resume state. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + * [in] params[0].value.b: Co-processor state identifier + */ +#define TA_QCOM_PAS_SET_REMOTE_STATE 7 + +/* + * PAS co-processor shutdown. + * + * [in] params[0].value.a: Unique 32bit remote processor identifier + */ +#define TA_QCOM_PAS_SHUTDOWN 8 + +#define TEE_NUM_PARAMS 4 + +/** + * struct qcom_pas_tee_private - PAS service private data + * @dev: PAS service device. + * @ctx: TEE context handler. + * @session_id: PAS TA session identifier. + */ +struct qcom_pas_tee_private { + struct device *dev; + struct tee_context *ctx; + u32 session_id; +}; + +static bool qcom_pas_tee_supported(struct device *dev, u32 pas_id) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = TA_QCOM_PAS_IS_SUPPORTED, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id + } + }; + int ret; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS not supported, pas_id: %d, ret: %d, err: 0x%x\n", + pas_id, ret, inv_arg.ret); + return false; + } + + return true; +} + +static int qcom_pas_tee_init_image(struct device *dev, u32 pas_id, + const void *metadata, size_t size, + struct qcom_pas_context *ctx) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = TA_QCOM_PAS_INIT_IMAGE, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id + }, + [1] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT, + } + }; + struct tee_shm *mdata_shm; + u8 *mdata_buf = NULL; + int ret; + + mdata_shm = tee_shm_alloc_kernel_buf(data->ctx, size); + if (IS_ERR(mdata_shm)) { + dev_err(dev, "mdata_shm allocation failed\n"); + return PTR_ERR(mdata_shm); + } + + mdata_buf = tee_shm_get_va(mdata_shm, 0); + if (IS_ERR(mdata_buf)) { + dev_err(dev, "mdata_buf get VA failed\n"); + tee_shm_free(mdata_shm); + return PTR_ERR(mdata_buf); + } + memcpy(mdata_buf, metadata, size); + + param[1].u.memref.shm = mdata_shm; + param[1].u.memref.size = size; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS init image failed, pas_id: %d, ret: %d, err: 0x%x\n", + pas_id, ret, inv_arg.ret); + tee_shm_free(mdata_shm); + return ret ?: -EINVAL; + } + + if (ctx) + ctx->ptr = (void *)mdata_shm; + else + tee_shm_free(mdata_shm); + + return ret; +} + +static int qcom_pas_tee_mem_setup(struct device *dev, u32 pas_id, + phys_addr_t addr, phys_addr_t size) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = TA_QCOM_PAS_MEM_SETUP, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id, + .u.value.b = size, + }, + [1] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = lower_32_bits(addr), + .u.value.b = upper_32_bits(addr), + } + }; + int ret; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS mem setup failed, pas_id: %d, ret: %d, err: 0x%x\n", + pas_id, ret, inv_arg.ret); + return ret ?: -EINVAL; + } + + return ret; +} + +DEFINE_FREE(shm_free, struct tee_shm *, tee_shm_free(_T)) + +static void *qcom_pas_tee_get_rsc_table(struct device *dev, + struct qcom_pas_context *ctx, + void *input_rt, size_t input_rt_size, + size_t *output_rt_size) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = TA_QCOM_PAS_GET_RESOURCE_TABLE, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = ctx->pas_id, + }, + [1] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT, + .u.memref.size = input_rt_size, + } + }; + void *rt_buf = NULL; + int ret; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n", + ctx->pas_id, ret, inv_arg.ret); + return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL); + } + + if (param[1].u.memref.size >= input_rt_size) { + struct tee_shm *rt_shm __free(shm_free) = + tee_shm_alloc_kernel_buf(data->ctx, + param[1].u.memref.size); + void *rt_shm_va; + + if (IS_ERR_OR_NULL(rt_shm)) { + dev_err(dev, "rt_shm allocation failed\n"); + rt_shm = NULL; + return ERR_PTR(-ENOMEM); + } + + rt_shm_va = tee_shm_get_va(rt_shm, 0); + if (IS_ERR(rt_shm_va)) { + dev_err(dev, "rt_shm get VA failed\n"); + return ERR_CAST(rt_shm_va); + } + memcpy(rt_shm_va, input_rt, input_rt_size); + + param[1].u.memref.shm = rt_shm; + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS get RT failed, pas_id: %d, ret: %d, err: 0x%x\n", + ctx->pas_id, ret, inv_arg.ret); + return ret ? ERR_PTR(ret) : ERR_PTR(-EINVAL); + } + + if (param[1].u.memref.size) { + *output_rt_size = param[1].u.memref.size; + rt_buf = kmemdup(rt_shm_va, *output_rt_size, GFP_KERNEL); + if (!rt_buf) + return ERR_PTR(-ENOMEM); + } + } else { + *output_rt_size = 0; + } + + return rt_buf; +} + +static int __qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id, + phys_addr_t mem_phys, size_t mem_size) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = TA_QCOM_PAS_AUTH_AND_RESET, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id, + .u.value.b = mem_size, + }, + [1] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = lower_32_bits(mem_phys), + .u.value.b = upper_32_bits(mem_phys), + }, + /* Reserved for fw memory space to be shared or lent */ + [2] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT, + } + }; + int ret; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS auth reset failed, pas_id: %d, ret: %d, err: 0x%x\n", + pas_id, ret, inv_arg.ret); + return ret ?: -EINVAL; + } + + return ret; +} + +static int qcom_pas_tee_auth_and_reset(struct device *dev, u32 pas_id) +{ + return __qcom_pas_tee_auth_and_reset(dev, pas_id, 0, 0); +} + +static int qcom_pas_tee_prepare_and_auth_reset(struct device *dev, + struct qcom_pas_context *ctx) +{ + return __qcom_pas_tee_auth_and_reset(dev, ctx->pas_id, ctx->mem_phys, + ctx->mem_size); +} + +static int qcom_pas_tee_set_remote_state(struct device *dev, u32 state, + u32 pas_id) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = TA_QCOM_PAS_SET_REMOTE_STATE, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id, + .u.value.b = state, + } + }; + int ret; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS set remote state failed, pas_id: %d, ret: %d, err: 0x%x\n", + pas_id, ret, inv_arg.ret); + return ret ?: -EINVAL; + } + + return ret; +} + +static int qcom_pas_tee_shutdown(struct device *dev, u32 pas_id) +{ + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + struct tee_ioctl_invoke_arg inv_arg = { + .func = TA_QCOM_PAS_SHUTDOWN, + .session = data->session_id, + .num_params = TEE_NUM_PARAMS + }; + struct tee_param param[4] = { + [0] = { + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + .u.value.a = pas_id + } + }; + int ret; + + ret = tee_client_invoke_func(data->ctx, &inv_arg, param); + if (ret < 0 || inv_arg.ret != 0) { + dev_err(dev, "PAS shutdown failed, pas_id: %d, ret: %d, err: 0x%x\n", + pas_id, ret, inv_arg.ret); + return ret ?: -EINVAL; + } + + return ret; +} + +static void qcom_pas_tee_metadata_release(struct device *dev, + struct qcom_pas_context *ctx) +{ + struct tee_shm *mdata_shm = ctx->ptr; + + tee_shm_free(mdata_shm); + ctx->ptr = NULL; +} + +static struct qcom_pas_ops qcom_pas_ops_tee = { + .drv_name = "qcom-pas-tee", + .supported = qcom_pas_tee_supported, + .init_image = qcom_pas_tee_init_image, + .mem_setup = qcom_pas_tee_mem_setup, + .get_rsc_table = qcom_pas_tee_get_rsc_table, + .auth_and_reset = qcom_pas_tee_auth_and_reset, + .prepare_and_auth_reset = qcom_pas_tee_prepare_and_auth_reset, + .set_remote_state = qcom_pas_tee_set_remote_state, + .shutdown = qcom_pas_tee_shutdown, + .metadata_release = qcom_pas_tee_metadata_release, +}; + +static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) +{ + return ver->impl_id == TEE_IMPL_ID_OPTEE; +} + +static int qcom_pas_tee_probe(struct tee_client_device *pas_dev) +{ + struct device *dev = &pas_dev->dev; + struct qcom_pas_tee_private *data; + struct tee_ioctl_open_session_arg sess_arg = { + .clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL + }; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->ctx = tee_client_open_context(NULL, optee_ctx_match, NULL, NULL); + if (IS_ERR(data->ctx)) + return -ENODEV; + + export_uuid(sess_arg.uuid, &pas_dev->id.uuid); + ret = tee_client_open_session(data->ctx, &sess_arg, NULL); + if (ret < 0 || sess_arg.ret != 0) { + dev_err(dev, "tee_client_open_session failed, ret: %d, err: 0x%x\n", + ret, sess_arg.ret); + tee_client_close_context(data->ctx); + return ret ?: -EINVAL; + } + + data->session_id = sess_arg.session; + dev_set_drvdata(dev, data); + qcom_pas_ops_tee.dev = dev; + qcom_pas_ops_register(&qcom_pas_ops_tee); + + return ret; +} + +static void qcom_pas_tee_remove(struct tee_client_device *pas_dev) +{ + struct device *dev = &pas_dev->dev; + struct qcom_pas_tee_private *data = dev_get_drvdata(dev); + + qcom_pas_ops_unregister(); + tee_client_close_session(data->ctx, data->session_id); + tee_client_close_context(data->ctx); +} + +static const struct tee_client_device_id qcom_pas_tee_id_table[] = { + {UUID_INIT(0xcff7d191, 0x7ca0, 0x4784, + 0xaf, 0x13, 0x48, 0x22, 0x3b, 0x9a, 0x4f, 0xbe)}, + {} +}; +MODULE_DEVICE_TABLE(tee, qcom_pas_tee_id_table); + +static struct tee_client_driver optee_pas_tee_driver = { + .probe = qcom_pas_tee_probe, + .remove = qcom_pas_tee_remove, + .id_table = qcom_pas_tee_id_table, + .driver = { + .name = "qcom-pas-tee", + }, +}; + +module_tee_client_driver(optee_pas_tee_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Qualcomm PAS TEE driver"); diff --git a/drivers/firmware/qcom/qcom_scm-smc.c b/drivers/firmware/qcom/qcom_scm-smc.c index 574930729ddd..127365ab11fc 100644 --- a/drivers/firmware/qcom/qcom_scm-smc.c +++ b/drivers/firmware/qcom/qcom_scm-smc.c @@ -24,6 +24,9 @@ struct arm_smccc_args { unsigned long args[8]; }; +#define CREATE_TRACE_POINTS +#include "qcom_scm_trace.h" + static DEFINE_MUTEX(qcom_scm_lock); #define QCOM_SCM_EBUSY_WAIT_MS 30 @@ -44,6 +47,7 @@ static void __scm_smc_do_quirk(const struct arm_smccc_args *smc, quirk.state.a6 = 0; do { + trace_scm_smc_request(a0, smc); arm_smccc_smc_quirk(a0, smc->args[1], smc->args[2], smc->args[3], smc->args[4], smc->args[5], quirk.state.a6, smc->args[7], res, &quirk); @@ -83,6 +87,7 @@ int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending) if (ret) return ret; + trace_scm_waitq_get_wq_ctx(get_wq_res.a1, get_wq_res.a2, get_wq_res.a3); *wq_ctx = get_wq_res.a1; *flags = get_wq_res.a2; *more_pending = get_wq_res.a3; @@ -105,10 +110,12 @@ static int __scm_smc_do_quirk_handle_waitq(struct device *dev, struct arm_smccc_ wq_ctx = res->a1; smc_call_ctx = res->a2; - ret = qcom_scm_wait_for_wq_completion(wq_ctx); + trace_scm_waitq_sleep(wq_ctx, smc_call_ctx); + ret = qcom_scm_wait_for_wq_completion(dev, wq_ctx); if (ret) return ret; + trace_scm_waitq_resume(smc_call_ctx); fill_wq_resume_args(&resume, smc_call_ctx); smc = &resume; } @@ -201,6 +208,9 @@ int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, } ret = __scm_smc_do(dev, &smc, &smc_res, atomic); + + trace_scm_smc_done(ret, smc.args[0], &smc_res); + if (ret) return ret; diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 6b601a4b89db..3eaa4c9ccf3c 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -13,6 +13,7 @@ #include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/export.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/firmware/qcom/qcom_tzmem.h> #include <linux/init.h> @@ -33,6 +34,7 @@ #include <dt-bindings/interrupt-controller/arm-gic.h> +#include "qcom_pas.h" #include "qcom_scm.h" #include "qcom_tzmem.h" @@ -57,6 +59,7 @@ struct qcom_scm { int scm_vote_count; u64 dload_mode_addr; + void __iomem *minidump_sram; struct qcom_tzmem_pool *mempool; unsigned int wq_cnt; @@ -141,6 +144,20 @@ static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = { #define QCOM_DLOAD_MINIDUMP 2 #define QCOM_DLOAD_BOTHDUMP 3 +/* Minidump destination values written to always-on SRAM for boot firmware */ +#define QCOM_MINIDUMP_DEST_USB 0x0 +#define QCOM_MINIDUMP_DEST_STORAGE 0x2 + +static u32 minidump_dest = QCOM_MINIDUMP_DEST_USB; + +static const struct { + const char *name; + u32 val; +} minidump_dest_map[] = { + { "usb", QCOM_MINIDUMP_DEST_USB }, + { "storage", QCOM_MINIDUMP_DEST_STORAGE }, +}; + #define QCOM_SCM_DEFAULT_WAITQ_COUNT 1 static const char * const qcom_scm_convention_names[] = { @@ -479,25 +496,6 @@ void qcom_scm_cpu_power_down(u32 flags) } EXPORT_SYMBOL_GPL(qcom_scm_cpu_power_down); -int qcom_scm_set_remote_state(u32 state, u32 id) -{ - struct qcom_scm_desc desc = { - .svc = QCOM_SCM_SVC_BOOT, - .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE, - .arginfo = QCOM_SCM_ARGS(2), - .args[0] = state, - .args[1] = id, - .owner = ARM_SMCCC_OWNER_SIP, - }; - struct qcom_scm_res res; - int ret; - - ret = qcom_scm_call(__scm->dev, &desc, &res); - - return ret ? : res.result[0]; -} -EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state); - static int qcom_scm_disable_sdi(void) { int ret; @@ -551,45 +549,39 @@ static int qcom_scm_io_rmw(phys_addr_t addr, unsigned int mask, unsigned int val return qcom_scm_io_writel(addr, new); } -static void qcom_scm_set_download_mode(u32 dload_mode) +static void qcom_scm_set_download_mode(struct qcom_scm *scm, u32 dload_mode) { int ret = 0; - if (__scm->dload_mode_addr) { - ret = qcom_scm_io_rmw(__scm->dload_mode_addr, QCOM_DLOAD_MASK, + if (scm->dload_mode_addr) { + ret = qcom_scm_io_rmw(scm->dload_mode_addr, QCOM_DLOAD_MASK, FIELD_PREP(QCOM_DLOAD_MASK, dload_mode)); - } else if (__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_BOOT, + } else if (__qcom_scm_is_call_available(scm->dev, QCOM_SCM_SVC_BOOT, QCOM_SCM_BOOT_SET_DLOAD_MODE)) { - ret = __qcom_scm_set_dload_mode(__scm->dev, !!dload_mode); + ret = __qcom_scm_set_dload_mode(scm->dev, !!dload_mode); } else if (dload_mode) { - dev_err(__scm->dev, + dev_err(scm->dev, "No available mechanism for setting download mode\n"); } if (ret) - dev_err(__scm->dev, "failed to set download mode: %d\n", ret); + dev_err(scm->dev, "failed to set download mode: %d\n", ret); + + /* + * Write the destination into the always-on SRAM so boot firmware + * can read it before DDR is initialised on the next warm reset. + * Only written when minidump is active; + */ + if (scm->minidump_sram && (dload_mode & QCOM_DLOAD_MINIDUMP)) + writel_relaxed(minidump_dest, scm->minidump_sram); } -/** - * devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service - * context for a given peripheral - * - * PAS context is device-resource managed, so the caller does not need - * to worry about freeing the context memory. - * - * @dev: PAS firmware device - * @pas_id: peripheral authentication service id - * @mem_phys: Subsystem reserve memory start address - * @mem_size: Subsystem reserve memory size - * - * Returns: The new PAS context, or ERR_PTR() on failure. - */ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, u32 pas_id, phys_addr_t mem_phys, size_t mem_size) { - struct qcom_scm_pas_context *ctx; + struct qcom_pas_context *ctx; ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -600,11 +592,12 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev, ctx->mem_phys = mem_phys; ctx->mem_size = mem_size; - return ctx; + return (struct qcom_scm_pas_context *)ctx; } EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc); -static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, +static int __qcom_scm_pas_init_image(struct device *dev, u32 pas_id, + dma_addr_t mdata_phys, struct qcom_scm_res *res) { struct qcom_scm_desc desc = { @@ -626,7 +619,7 @@ static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys, desc.args[1] = mdata_phys; - ret = qcom_scm_call(__scm->dev, &desc, res); + ret = qcom_scm_call(dev, &desc, res); qcom_scm_bw_disable(); disable_clk: @@ -635,7 +628,8 @@ disable_clk: return ret; } -static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, +static int qcom_scm_pas_prep_and_init_image(struct device *dev, + struct qcom_pas_context *ctx, const void *metadata, size_t size) { struct qcom_scm_res res; @@ -650,7 +644,7 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, memcpy(mdata_buf, metadata, size); mdata_phys = qcom_tzmem_to_phys(mdata_buf); - ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res); + ret = __qcom_scm_pas_init_image(dev, ctx->pas_id, mdata_phys, &res); if (ret < 0) qcom_tzmem_free(mdata_buf); else @@ -659,25 +653,9 @@ static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx, return ret ? : res.result[0]; } -/** - * qcom_scm_pas_init_image() - Initialize peripheral authentication service - * state machine for a given peripheral, using the - * metadata - * @pas_id: peripheral authentication service id - * @metadata: pointer to memory containing ELF header, program header table - * and optional blob of data used for authenticating the metadata - * and the rest of the firmware - * @size: size of the metadata - * @ctx: optional pas context - * - * Return: 0 on success. - * - * Upon successful return, the PAS metadata context (@ctx) will be used to - * track the metadata allocation, this needs to be released by invoking - * qcom_scm_pas_metadata_release() by the caller. - */ -int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, - struct qcom_scm_pas_context *ctx) +static int __qcom_scm_pas_init_image2(struct device *dev, u32 pas_id, + const void *metadata, size_t size, + struct qcom_pas_context *ctx) { struct qcom_scm_res res; dma_addr_t mdata_phys; @@ -685,7 +663,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, int ret; if (ctx && ctx->use_tzmem) - return qcom_scm_pas_prep_and_init_image(ctx, metadata, size); + return qcom_scm_pas_prep_and_init_image(dev, ctx, metadata, size); /* * During the scm call memory protection will be enabled for the meta @@ -699,16 +677,15 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, * If we pass a buffer that is already part of an SHM Bridge to this * call, it will fail. */ - mdata_buf = dma_alloc_coherent(__scm->dev, size, &mdata_phys, - GFP_KERNEL); + mdata_buf = dma_alloc_coherent(dev, size, &mdata_phys, GFP_KERNEL); if (!mdata_buf) return -ENOMEM; memcpy(mdata_buf, metadata, size); - ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res); + ret = __qcom_scm_pas_init_image(dev, pas_id, mdata_phys, &res); if (ret < 0 || !ctx) { - dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys); + dma_free_coherent(dev, size, mdata_buf, mdata_phys); } else if (ctx) { ctx->ptr = mdata_buf; ctx->phys = mdata_phys; @@ -717,36 +694,35 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, return ret ? : res.result[0]; } -EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image); -/** - * qcom_scm_pas_metadata_release() - release metadata context - * @ctx: pas context - */ -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) +int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size, + struct qcom_scm_pas_context *ctx) { - if (!ctx->ptr) - return; + return __qcom_scm_pas_init_image2(__scm->dev, pas_id, metadata, size, + (struct qcom_pas_context *)ctx); +} +EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image); +static void __qcom_scm_pas_metadata_release(struct device *dev, + struct qcom_pas_context *ctx) +{ if (ctx->use_tzmem) qcom_tzmem_free(ctx->ptr); else - dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys); + dma_free_coherent(dev, ctx->size, ctx->ptr, ctx->phys); ctx->ptr = NULL; } + +void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx) +{ + __qcom_scm_pas_metadata_release(__scm->dev, + (struct qcom_pas_context *)ctx); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); -/** - * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral - * for firmware loading - * @pas_id: peripheral authentication service id - * @addr: start address of memory area to prepare - * @size: size of the memory area to prepare - * - * Returns 0 on success. - */ -int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) +static int __qcom_scm_pas_mem_setup(struct device *dev, u32 pas_id, + phys_addr_t addr, phys_addr_t size) { int ret; struct qcom_scm_desc desc = { @@ -768,7 +744,7 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) if (ret) goto disable_clk; - ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call(dev, &desc, &res); qcom_scm_bw_disable(); disable_clk: @@ -776,9 +752,15 @@ disable_clk: return ret ? : res.result[0]; } + +int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size) +{ + return __qcom_scm_pas_mem_setup(__scm->dev, pas_id, addr, size); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); -static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm, +static void *__qcom_scm_pas_get_rsc_table(struct device *dev, u32 pas_id, + void *input_rt_tzm, size_t input_rt_size, size_t *output_rt_size) { @@ -813,7 +795,7 @@ static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm, * with output_rt_tzm buffer with res.result[2] size however, It should not * be of unresonable size. */ - ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call(dev, &desc, &res); if (!ret && res.result[2] > SZ_1G) { ret = -E2BIG; goto free_output_rt; @@ -830,51 +812,11 @@ free_output_rt: return ret ? ERR_PTR(ret) : output_rt_tzm; } -/** - * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer - * for a given peripheral. - * - * Qualcomm remote processor may rely on both static and dynamic resources for - * its functionality. Static resources typically refer to memory-mapped addresses - * required by the subsystem and are often embedded within the firmware binary - * and dynamic resources, such as shared memory in DDR etc., are determined at - * runtime during the boot process. - * - * On Qualcomm Technologies devices, it's possible that static resources are not - * embedded in the firmware binary and instead are provided by TrustZone However, - * dynamic resources are always expected to come from TrustZone. This indicates - * that for Qualcomm devices, all resources (static and dynamic) will be provided - * by TrustZone via the SMC call. - * - * If the remote processor firmware binary does contain static resources, they - * should be passed in input_rt. These will be forwarded to TrustZone for - * authentication. TrustZone will then append the dynamic resources and return - * the complete resource table in output_rt_tzm. - * - * If the remote processor firmware binary does not include a resource table, - * the caller of this function should set input_rt as NULL and input_rt_size - * as zero respectively. - * - * More about documentation on resource table data structures can be found in - * include/linux/remoteproc.h - * - * @ctx: PAS context - * @pas_id: peripheral authentication service id - * @input_rt: resource table buffer which is present in firmware binary - * @input_rt_size: size of the resource table present in firmware binary - * @output_rt_size: TrustZone expects caller should pass worst case size for - * the output_rt_tzm. - * - * Return: - * On success, returns a pointer to the allocated buffer containing the final - * resource table and output_rt_size will have actual resource table size from - * TrustZone. The caller is responsible for freeing the buffer. On failure, - * returns ERR_PTR(-errno). - */ -struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, - void *input_rt, - size_t input_rt_size, - size_t *output_rt_size) +static void *__qcom_scm_pas_get_rsc_table2(struct device *dev, + struct qcom_pas_context *ctx, + void *input_rt, + size_t input_rt_size, + size_t *output_rt_size) { struct resource_table empty_rsc = {}; size_t size = SZ_16K; @@ -909,11 +851,12 @@ struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *c memcpy(input_rt_tzm, input_rt, input_rt_size); - output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt_tzm, + output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id, + input_rt_tzm, input_rt_size, &size); if (PTR_ERR(output_rt_tzm) == -EOVERFLOW) /* Try again with the size requested by the TZ */ - output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, + output_rt_tzm = __qcom_scm_pas_get_rsc_table(dev, ctx->pas_id, input_rt_tzm, input_rt_size, &size); @@ -943,16 +886,20 @@ disable_clk: return ret ? ERR_PTR(ret) : tbl_ptr; } + +struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx, + void *input_rt, + size_t input_rt_size, + size_t *output_rt_size) +{ + return __qcom_scm_pas_get_rsc_table2(__scm->dev, + (struct qcom_pas_context *)ctx, + input_rt, input_rt_size, + output_rt_size); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table); -/** - * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware - * and reset the remote processor - * @pas_id: peripheral authentication service id - * - * Return 0 on success. - */ -int qcom_scm_pas_auth_and_reset(u32 pas_id) +static int __qcom_scm_pas_auth_and_reset(struct device *dev, u32 pas_id) { int ret; struct qcom_scm_desc desc = { @@ -972,7 +919,7 @@ int qcom_scm_pas_auth_and_reset(u32 pas_id) if (ret) goto disable_clk; - ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call(dev, &desc, &res); qcom_scm_bw_disable(); disable_clk: @@ -980,28 +927,15 @@ disable_clk: return ret ? : res.result[0]; } + +int qcom_scm_pas_auth_and_reset(u32 pas_id) +{ + return __qcom_scm_pas_auth_and_reset(__scm->dev, pas_id); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); -/** - * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the - * remote processor - * - * @ctx: Context saved during call to qcom_scm_pas_context_init() - * - * This function performs the necessary steps to prepare a PAS subsystem, - * authenticate it using the provided metadata, and initiate a reset sequence. - * - * It should be used when Linux is in control setting up the IOMMU hardware - * for remote subsystem during secure firmware loading processes. The preparation - * step sets up a shmbridge over the firmware memory before TrustZone accesses the - * firmware memory region for authentication. The authentication step verifies - * the integrity and authenticity of the firmware or configuration using secure - * metadata. Finally, the reset step ensures the subsystem starts in a clean and - * sane state. - * - * Return: 0 on success, negative errno on failure. - */ -int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) +static int __qcom_scm_pas_prepare_and_auth_reset(struct device *dev, + struct qcom_pas_context *ctx) { u64 handle; int ret; @@ -1012,7 +946,7 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) * memory region and then invokes a call to TrustZone to authenticate. */ if (!ctx->use_tzmem) - return qcom_scm_pas_auth_and_reset(ctx->pas_id); + return __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id); /* * When Linux runs @ EL2 Linux must create the shmbridge itself and then @@ -1022,20 +956,45 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) if (ret) return ret; - ret = qcom_scm_pas_auth_and_reset(ctx->pas_id); + ret = __qcom_scm_pas_auth_and_reset(dev, ctx->pas_id); qcom_tzmem_shm_bridge_delete(handle); return ret; } + +int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx) +{ + return __qcom_scm_pas_prepare_and_auth_reset(__scm->dev, + (struct qcom_pas_context *)ctx); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset); -/** - * qcom_scm_pas_shutdown() - Shut down the remote processor - * @pas_id: peripheral authentication service id - * - * Returns 0 on success. - */ -int qcom_scm_pas_shutdown(u32 pas_id) +static int __qcom_scm_pas_set_remote_state(struct device *dev, u32 state, + u32 pas_id) +{ + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_BOOT, + .cmd = QCOM_SCM_BOOT_SET_REMOTE_STATE, + .arginfo = QCOM_SCM_ARGS(2), + .args[0] = state, + .args[1] = pas_id, + .owner = ARM_SMCCC_OWNER_SIP, + }; + struct qcom_scm_res res; + int ret; + + ret = qcom_scm_call(dev, &desc, &res); + + return ret ? : res.result[0]; +} + +int qcom_scm_set_remote_state(u32 state, u32 id) +{ + return __qcom_scm_pas_set_remote_state(__scm->dev, state, id); +} +EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state); + +static int __qcom_scm_pas_shutdown(struct device *dev, u32 pas_id) { int ret; struct qcom_scm_desc desc = { @@ -1055,7 +1014,7 @@ int qcom_scm_pas_shutdown(u32 pas_id) if (ret) goto disable_clk; - ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call(dev, &desc, &res); qcom_scm_bw_disable(); disable_clk: @@ -1063,16 +1022,14 @@ disable_clk: return ret ? : res.result[0]; } + +int qcom_scm_pas_shutdown(u32 pas_id) +{ + return __qcom_scm_pas_shutdown(__scm->dev, pas_id); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown); -/** - * qcom_scm_pas_supported() - Check if the peripheral authentication service is - * available for the given peripherial - * @pas_id: peripheral authentication service id - * - * Returns true if PAS is supported for this peripheral, otherwise false. - */ -bool qcom_scm_pas_supported(u32 pas_id) +static bool __qcom_scm_pas_supported(struct device *dev, u32 pas_id) { int ret; struct qcom_scm_desc desc = { @@ -1084,16 +1041,49 @@ bool qcom_scm_pas_supported(u32 pas_id) }; struct qcom_scm_res res; - if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL, + if (!__qcom_scm_is_call_available(dev, QCOM_SCM_SVC_PIL, QCOM_SCM_PIL_PAS_IS_SUPPORTED)) return false; - ret = qcom_scm_call(__scm->dev, &desc, &res); + ret = qcom_scm_call(dev, &desc, &res); return ret ? false : !!res.result[0]; } + +bool qcom_scm_pas_supported(u32 pas_id) +{ + return __qcom_scm_pas_supported(__scm->dev, pas_id); +} EXPORT_SYMBOL_GPL(qcom_scm_pas_supported); +static struct qcom_pas_ops qcom_pas_ops_scm = { + .drv_name = "qcom_scm", + .supported = __qcom_scm_pas_supported, + .init_image = __qcom_scm_pas_init_image2, + .mem_setup = __qcom_scm_pas_mem_setup, + .get_rsc_table = __qcom_scm_pas_get_rsc_table2, + .auth_and_reset = __qcom_scm_pas_auth_and_reset, + .prepare_and_auth_reset = __qcom_scm_pas_prepare_and_auth_reset, + .set_remote_state = __qcom_scm_pas_set_remote_state, + .shutdown = __qcom_scm_pas_shutdown, + .metadata_release = __qcom_scm_pas_metadata_release, +}; + +/** + * qcom_scm_is_pas_available() - Check if the peripheral authentication service + * is available via SCM or not + * + * Returns true if PAS is available, otherwise false. + */ +static bool qcom_scm_is_pas_available(void) +{ + if (!__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_PIL, + QCOM_SCM_PIL_PAS_AUTH_AND_RESET)) + return false; + + return true; +} + static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset) { struct qcom_scm_desc desc = { @@ -2040,6 +2030,29 @@ int qcom_scm_gpu_init_regs(u32 gpu_req) } EXPORT_SYMBOL_GPL(qcom_scm_gpu_init_regs); +static int qcom_scm_map_minidump_sram(struct device *dev, void __iomem **out) +{ + struct device_node *np = dev->of_node; + struct device_node *sram_np; + struct resource res; + int ret; + + sram_np = of_parse_phandle(np, "sram", 0); + if (!sram_np) + return 0; + + ret = of_address_to_resource(sram_np, 0, &res); + of_node_put(sram_np); + if (ret) + return ret; + + *out = devm_ioremap(dev, res.start, resource_size(&res)); + if (!*out) + return -ENOMEM; + + return 0; +} + static int qcom_scm_find_dload_address(struct device *dev, u64 *addr) { struct device_node *tcsr; @@ -2291,10 +2304,12 @@ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { { .compatible = "asus,vivobook-s15-x1p4" }, { .compatible = "asus,zenbook-a14-ux3407qa" }, { .compatible = "asus,zenbook-a14-ux3407ra" }, + { .compatible = "asus,zenbook-a16-ux3607oa" }, { .compatible = "dell,inspiron-14-plus-7441" }, { .compatible = "dell,latitude-7455" }, { .compatible = "dell,xps13-9345" }, { .compatible = "ecs,liva-qc710" }, + { .compatible = "honor,magicbook-art-14-snapdragon" }, { .compatible = "hp,elitebook-ultra-g1q" }, { .compatible = "hp,omnibook-x14" }, { .compatible = "huawei,gaokun3" }, @@ -2630,23 +2645,20 @@ static int qcom_scm_get_waitq_irq(struct qcom_scm *scm) return irq_create_fwspec_mapping(&fwspec); } -static struct completion *qcom_scm_get_completion(u32 wq_ctx) +static struct completion *qcom_scm_get_completion(struct qcom_scm *scm, u32 wq_ctx) { - struct completion *wq; - - if (WARN_ON_ONCE(wq_ctx >= __scm->wq_cnt)) + if (WARN_ON_ONCE(wq_ctx >= scm->wq_cnt)) return ERR_PTR(-EINVAL); - wq = &__scm->waitq_comps[wq_ctx]; - - return wq; + return &scm->waitq_comps[wq_ctx]; } -int qcom_scm_wait_for_wq_completion(u32 wq_ctx) +int qcom_scm_wait_for_wq_completion(struct device *dev, u32 wq_ctx) { + struct qcom_scm *scm = dev_get_drvdata(dev); struct completion *wq; - wq = qcom_scm_get_completion(wq_ctx); + wq = qcom_scm_get_completion(scm, wq_ctx); if (IS_ERR(wq)) return PTR_ERR(wq); @@ -2655,11 +2667,11 @@ int qcom_scm_wait_for_wq_completion(u32 wq_ctx) return 0; } -static int qcom_scm_waitq_wakeup(unsigned int wq_ctx) +static int qcom_scm_waitq_wakeup(struct qcom_scm *scm, unsigned int wq_ctx) { struct completion *wq; - wq = qcom_scm_get_completion(wq_ctx); + wq = qcom_scm_get_completion(scm, wq_ctx); if (IS_ERR(wq)) return PTR_ERR(wq); @@ -2686,7 +2698,7 @@ static irqreturn_t qcom_scm_irq_handler(int irq, void *data) goto out; } - ret = qcom_scm_waitq_wakeup(wq_ctx); + ret = qcom_scm_waitq_wakeup(scm, wq_ctx); if (ret) goto out; } while (more_pending); @@ -2705,6 +2717,7 @@ static int get_download_mode(char *buffer, const struct kernel_param *kp) static int set_download_mode(const char *val, const struct kernel_param *kp) { + struct qcom_scm *scm; bool tmp; int ret; @@ -2720,8 +2733,10 @@ static int set_download_mode(const char *val, const struct kernel_param *kp) } download_mode = ret; - if (__scm) - qcom_scm_set_download_mode(download_mode); + /* Pairs with smp_store_release() in qcom_scm_probe(). */ + scm = smp_load_acquire(&__scm); + if (scm) + qcom_scm_set_download_mode(scm, download_mode); return 0; } @@ -2734,6 +2749,47 @@ static const struct kernel_param_ops download_mode_param_ops = { module_param_cb(download_mode, &download_mode_param_ops, NULL, 0644); MODULE_PARM_DESC(download_mode, "download mode: off/0/N for no dump mode, full/on/1/Y for full dump mode, mini for minidump mode and full,mini for both full and minidump mode together are acceptable values"); +static int get_minidump_dest(char *buffer, const struct kernel_param *kp) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(minidump_dest_map); i++) + if (minidump_dest == minidump_dest_map[i].val) + return sysfs_emit(buffer, "%s\n", minidump_dest_map[i].name); + + return sysfs_emit(buffer, "unknown\n"); +} + +static int set_minidump_dest(const char *val, const struct kernel_param *kp) +{ + struct qcom_scm *scm; + int i; + + for (i = 0; i < ARRAY_SIZE(minidump_dest_map); i++) + if (sysfs_streq(val, minidump_dest_map[i].name)) + break; + + if (i >= ARRAY_SIZE(minidump_dest_map)) + return -EINVAL; + + minidump_dest = minidump_dest_map[i].val; + + /* Pairs with smp_store_release() in qcom_scm_probe(). */ + scm = smp_load_acquire(&__scm); + if (scm && scm->minidump_sram && (download_mode & QCOM_DLOAD_MINIDUMP)) + writel_relaxed(minidump_dest, scm->minidump_sram); + + return 0; +} + +static const struct kernel_param_ops minidump_dest_param_ops = { + .get = get_minidump_dest, + .set = set_minidump_dest, +}; + +module_param_cb(minidump_dest, &minidump_dest_param_ops, NULL, 0644); +MODULE_PARM_DESC(minidump_dest, "Minidump SRAM destination: usb (default) or storage"); + static int qcom_scm_probe(struct platform_device *pdev) { struct qcom_tzmem_pool_config pool_config; @@ -2746,9 +2802,16 @@ static int qcom_scm_probe(struct platform_device *pdev) return -ENOMEM; scm->dev = &pdev->dev; + platform_set_drvdata(pdev, scm); ret = qcom_scm_find_dload_address(&pdev->dev, &scm->dload_mode_addr); if (ret < 0) - return ret; + return dev_err_probe(&pdev->dev, ret, + "Failed to get download mode address\n"); + + ret = qcom_scm_map_minidump_sram(&pdev->dev, &scm->minidump_sram); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Failed to map minidump SRAM\n"); mutex_init(&scm->scm_bw_lock); @@ -2787,9 +2850,11 @@ static int qcom_scm_probe(struct platform_device *pdev) "Failed to setup the reserved memory region for TZ mem\n"); ret = qcom_tzmem_enable(scm->dev); - if (ret) - return dev_err_probe(scm->dev, ret, - "Failed to enable the TrustZone memory allocator\n"); + if (ret) { + ret = dev_err_probe(scm->dev, ret, + "Failed to enable the TrustZone memory allocator\n"); + goto err_rmem; + } memset(&pool_config, 0, sizeof(pool_config)); pool_config.initial_size = 0; @@ -2797,9 +2862,11 @@ static int qcom_scm_probe(struct platform_device *pdev) pool_config.max_size = SZ_256K; scm->mempool = devm_qcom_tzmem_pool_new(scm->dev, &pool_config); - if (IS_ERR(scm->mempool)) - return dev_err_probe(scm->dev, PTR_ERR(scm->mempool), - "Failed to create the SCM memory pool\n"); + if (IS_ERR(scm->mempool)) { + ret = dev_err_probe(scm->dev, PTR_ERR(scm->mempool), + "Failed to create the SCM memory pool\n"); + goto err_rmem; + } ret = qcom_scm_query_waitq_count(scm); scm->wq_cnt = ret < 0 ? QCOM_SCM_DEFAULT_WAITQ_COUNT : ret; @@ -2837,12 +2904,17 @@ static int qcom_scm_probe(struct platform_device *pdev) __get_convention(); + if (qcom_scm_is_pas_available()) { + qcom_pas_ops_scm.dev = scm->dev; + qcom_pas_ops_register(&qcom_pas_ops_scm); + } + /* * If "download mode" is requested, from this point on warmboot * will cause the boot stages to enter download mode, unless * disabled below by a clean shutdown/reboot. */ - qcom_scm_set_download_mode(download_mode); + qcom_scm_set_download_mode(scm, download_mode); /* * Disable SDI if indicated by DT that it is enabled by default. @@ -2870,12 +2942,17 @@ static int qcom_scm_probe(struct platform_device *pdev) qcom_scm_gunyah_wdt_init(scm); return 0; + +err_rmem: + of_reserved_mem_device_release(scm->dev); + return ret; } static void qcom_scm_shutdown(struct platform_device *pdev) { /* Clean shutdown, disable download mode to allow normal restart */ - qcom_scm_set_download_mode(QCOM_DLOAD_NODUMP); + qcom_scm_set_download_mode(__scm, QCOM_DLOAD_NODUMP); + qcom_pas_ops_unregister(); } static const struct of_device_id qcom_scm_dt_match[] = { diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h index caab80a73e17..cf90a565fdfb 100644 --- a/drivers/firmware/qcom/qcom_scm.h +++ b/drivers/firmware/qcom/qcom_scm.h @@ -66,7 +66,7 @@ struct qcom_scm_res { u64 result[MAX_QCOM_SCM_RETS]; }; -int qcom_scm_wait_for_wq_completion(u32 wq_ctx); +int qcom_scm_wait_for_wq_completion(struct device *dev, u32 wq_ctx); int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending); #define SCM_SMC_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF)) diff --git a/drivers/firmware/qcom/qcom_scm_trace.h b/drivers/firmware/qcom/qcom_scm_trace.h new file mode 100644 index 000000000000..6c911124fc56 --- /dev/null +++ b/drivers/firmware/qcom/qcom_scm_trace.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM qcom_scm + +#if !defined(_TRACE_SCM_SMC_INTERFACE_H) || defined(TRACE_HEADER_MULTI_READ) + +#define _TRACE_SCM_SMC_INTERFACE_H + +#include <linux/tracepoint.h> + +TRACE_EVENT(scm_smc_request, + + TP_PROTO(unsigned long a0, const struct arm_smccc_args *smc), + + TP_ARGS(a0, smc), + + TP_STRUCT__entry( + __field(u64, smc_id) + __field(u8, svc_id) + __field(u8, cmd_id) + __field(u8, args_cnt) + __dynamic_array(unsigned long, args, + min_t(u8, (smc->args[1] & 0xF), (u8)6)) + ), + + TP_fast_assign( + __entry->smc_id = a0; + __entry->svc_id = (smc->args[0] >> 8) & 0xFF; + __entry->cmd_id = smc->args[0] & 0xFF; + u8 n = min_t(u8, (smc->args[1] & 0xF), (u8)6); + + __entry->args_cnt = n; + + unsigned long *dst = __get_dynamic_array(args); + + for (int i = 0; i < n; i++) + dst[i] = smc->args[2 + i]; + ), + + TP_printk("smc_id:0x%08llx svc_id:0x%02x cmd_id:0x%02x args_cnt:%u args:%s", + __entry->smc_id, __entry->svc_id, __entry->cmd_id, __entry->args_cnt, + __print_dynamic_array(args, sizeof(unsigned long))) +); + +TRACE_EVENT(scm_waitq_sleep, + + TP_PROTO(u32 wq_ctx, u32 smc_ctx), + + TP_ARGS(wq_ctx, smc_ctx), + + TP_STRUCT__entry( + __field(u32, wq_ctx) + __field(u32, smc_call_ctx) + ), + + TP_fast_assign( + __entry->wq_ctx = wq_ctx; + __entry->smc_call_ctx = smc_ctx; + ), + + TP_printk("wq_ctx:%u, smc_call_ctx:%u", __entry->wq_ctx, __entry->smc_call_ctx) +); + +TRACE_EVENT(scm_waitq_resume, + + TP_PROTO(u32 smc_ctx), + + TP_ARGS(smc_ctx), + + TP_STRUCT__entry( + __field(u32, smc_call_ctx) + ), + + TP_fast_assign( + __entry->smc_call_ctx = smc_ctx; + ), + + TP_printk("smc_call_ctx:%u", __entry->smc_call_ctx) +); + +TRACE_EVENT(scm_waitq_get_wq_ctx, + + TP_PROTO(u32 wq_ctx, u32 flags, u32 pending), + + TP_ARGS(wq_ctx, flags, pending), + + TP_STRUCT__entry( + __field(u32, wq_ctx) + __field(u32, flags) + __field(u32, more_pending) + ), + + TP_fast_assign( + __entry->wq_ctx = wq_ctx; + __entry->flags = flags; + __entry->more_pending = pending; + ), + + TP_printk("wq_ctx:%u, flags:%u, more_pending:%u", + __entry->wq_ctx, __entry->flags, __entry->more_pending) +); + +TRACE_EVENT(scm_smc_done, + + TP_PROTO(int ret, u64 smc_id, struct arm_smccc_res *smc_res), + + TP_ARGS(ret, smc_id, smc_res), + + TP_STRUCT__entry( + __field(int, ret) + __field(u64, smc_id) + __field(unsigned long, res) + __field(unsigned long, res0) + __field(unsigned long, res1) + __field(unsigned long, res2) + ), + + TP_fast_assign( + __entry->ret = ret; + __entry->smc_id = smc_id; + __entry->res = smc_res->a0; + __entry->res0 = smc_res->a1; + __entry->res1 = smc_res->a2; + __entry->res2 = smc_res->a3; + ), + + TP_printk("smc_id:0x%08llx, ret:%d res_to_callee:0x%lx res0:0x%lx res1:0x%lx res2:0x%lx", + __entry->smc_id, __entry->ret, __entry->res, + __entry->res0, __entry->res1, __entry->res2) +); + +#endif /* _TRACE_SCM_SMC_INTERFACE_H */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE qcom_scm_trace + +#include <trace/define_trace.h> + diff --git a/drivers/firmware/qcom/qcom_tzmem.c b/drivers/firmware/qcom/qcom_tzmem.c index 0635cbeacfc8..0fd9581275f1 100644 --- a/drivers/firmware/qcom/qcom_tzmem.c +++ b/drivers/firmware/qcom/qcom_tzmem.c @@ -15,6 +15,7 @@ #include <linux/kernel.h> #include <linux/list.h> #include <linux/mm.h> +#include <linux/once.h> #include <linux/radix-tree.h> #include <linux/slab.h> #include <linux/spinlock.h> @@ -507,14 +508,18 @@ phys_addr_t qcom_tzmem_to_phys(void *vaddr) } EXPORT_SYMBOL_GPL(qcom_tzmem_to_phys); +static void qcom_tzmem_do_init(int *result) +{ + *result = qcom_tzmem_init(); +} + int qcom_tzmem_enable(struct device *dev) { - if (qcom_tzmem_dev) - return -EBUSY; + static int result; qcom_tzmem_dev = dev; - - return qcom_tzmem_init(); + DO_ONCE(qcom_tzmem_do_init, &result); + return result; } EXPORT_SYMBOL_GPL(qcom_tzmem_enable); diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 590a464403c5..cc747ab0237f 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -4225,6 +4225,10 @@ static int ti_sci_probe(struct platform_device *pdev) ret = of_platform_populate(dev->of_node, NULL, NULL, dev); if (ret) { dev_err(dev, "platform_populate failed %pe\n", ERR_PTR(ret)); + of_platform_depopulate(dev); + mutex_lock(&ti_sci_list_mutex); + list_del(&info->node); + mutex_unlock(&ti_sci_list_mutex); goto out; } return 0; diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index af838b2dc327..f44785aee808 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -3,7 +3,7 @@ * Xilinx Zynq MPSoC Firmware layer * * Copyright (C) 2014-2022 Xilinx, Inc. - * Copyright (C) 2022 - 2025 Advanced Micro Devices, Inc. + * Copyright (C) 2022 - 2026 Advanced Micro Devices, Inc. * * Michal Simek <michal.simek@amd.com> * Davorin Mista <davorin.mista@aggios.com> @@ -13,6 +13,7 @@ #include <linux/arm-smccc.h> #include <linux/compiler.h> +#include <linux/crash_dump.h> #include <linux/device.h> #include <linux/init.h> #include <linux/mfd/core.h> @@ -223,34 +224,37 @@ static int __do_feature_check_call(const u32 api_id, u32 *ret_payload) module_id = FIELD_GET(MODULE_ID_MASK, api_id); /* - * Feature check of APIs belonging to PM, XSEM, and TF-A are handled by calling + * Feature check of APIs belonging to PM and XSEM are handled by calling * PM_FEATURE_CHECK API. For other modules, call PM_API_FEATURES API. */ - if (module_id == PM_MODULE_ID || module_id == XSEM_MODULE_ID || module_id == TF_A_MODULE_ID) + if (module_id == PM_MODULE_ID || module_id == XSEM_MODULE_ID) feature_check_api_id = PM_FEATURE_CHECK; else feature_check_api_id = PM_API_FEATURES; - /* - * Feature check of TF-A APIs is done in the TF-A layer and it expects for - * MODULE_ID_MASK bits of SMC's arg[0] to be the same as PM_MODULE_ID. - */ - if (module_id == TF_A_MODULE_ID) { - module_id = PM_MODULE_ID; + if (module_id == TF_A_MODULE_ID) smc_arg[1] = api_id; - } else { + else smc_arg[1] = (api_id & API_ID_MASK); - } smc_arg[0] = PM_SIP_SVC | FIELD_PREP(MODULE_ID_MASK, module_id) | feature_check_api_id; ret = do_fw_call(ret_payload, 2, smc_arg[0], smc_arg[1]); + + /* + * For TF-A APIs, if the feature check with PM_API_FEATURES fails, + * retry with the legacy PM_FEATURE_CHECK for backward compatibility. + */ + if (module_id == TF_A_MODULE_ID && ret) { + smc_arg[0] = PM_SIP_SVC | FIELD_PREP(MODULE_ID_MASK, PM_MODULE_ID) | + PM_FEATURE_CHECK; + ret = do_fw_call(ret_payload, 2, smc_arg[0], smc_arg[1]); + } + if (ret) - ret = -EOPNOTSUPP; - else - ret = ret_payload[1]; + return ret; - return ret; + return ret_payload[1]; } static int do_feature_check_call(const u32 api_id) @@ -2065,6 +2069,71 @@ static struct attribute *zynqmp_firmware_attrs[] = { ATTRIBUTE_GROUPS(zynqmp_firmware); +/** + * zynqmp_clear_pm_state() - Clear subsystem state + * @dev: Device pointer used for logging + * + * Clears PM specific data in EL3 and platform firmware. + * + * Return: Returns status, either success or error + */ +static int zynqmp_clear_pm_state(struct device *dev) +{ + u32 pm_family_code; + int ret; + + /* Get the Family code of platform */ + ret = zynqmp_pm_get_family_info(&pm_family_code); + if (ret < 0) + return ret; + + /* Supporting on Versal and Versal Net platforms only */ + if (pm_family_code == PM_VERSAL_FAMILY_CODE || + pm_family_code == PM_VERSAL_NET_FAMILY_CODE) { + /* Check if EL3 firmware supports TF_A_CLEAR_PM_STATE */ + ret = do_feature_check_call(TF_A_CLEAR_PM_STATE); + if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_1)) { + /* Clear PM specific data in EL3 firmware */ + ret = zynqmp_pm_invoke_fn(TF_A_CLEAR_PM_STATE, NULL, 0); + if (ret) + dev_err(dev, + "Failed to clear EL3 PM subsystem state: %d\n", ret); + } else { + dev_warn(dev, "TF_A_CLEAR_PM_STATE is not supported by EL3 firmware: %d\n", ret); + ret = 0; + } + + /* Check if the firmware supports the PM_DEV_ALL_PERIPH node ID */ + ret = do_feature_check_call(PM_RELEASE_NODE); + if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_3)) { + /* Attempt to release all peripheral devices via firmware */ + ret = zynqmp_pm_release_node(PM_DEV_ALL_PERIPH); + if (ret) + dev_err(dev, "Failed to release all peripheral devices: %d\n", ret); + } else { + dev_warn(dev, + "Bulk device release is not supported by firmware: %d\n", ret); + ret = 0; + } + + /* Check if the firmware supports the PM_ALL_NOTIFIERS node ID */ + ret = do_feature_check_call(PM_REGISTER_NOTIFIER); + if (ret >= 0 && ((ret & FIRMWARE_VERSION_MASK) >= PM_API_VERSION_3)) { + /* Attempt to unregister all notifier callbacks via firmware */ + ret = zynqmp_pm_register_notifier(PM_ALL_NOTIFIERS, 0, 0, 0); + if (ret) + dev_err(dev, "Failed to unregister all notifiers: %d\n", ret); + } else { + dev_warn(dev, + "Firmware doesn't support unregister all notifiers at once: %d\n", + ret); + ret = 0; + } + } + + return ret; +} + static int zynqmp_firmware_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -2118,6 +2187,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) if (ret < 0) return ret; + if (is_kdump_kernel()) + zynqmp_clear_pm_state(dev); + /* Check trustzone version number */ ret = zynqmp_pm_get_trustzone_version(&pm_tz_version); if (ret) @@ -2151,6 +2223,11 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) return of_platform_populate(dev->of_node, NULL, NULL, dev); } +static void zynqmp_firmware_shutdown(struct platform_device *pdev) +{ + zynqmp_clear_pm_state(&pdev->dev); +} + static void zynqmp_firmware_remove(struct platform_device *pdev) { struct pm_api_feature_data *feature_data; @@ -2210,5 +2287,6 @@ static struct platform_driver zynqmp_firmware_driver = { }, .probe = zynqmp_firmware_probe, .remove = zynqmp_firmware_remove, + .shutdown = zynqmp_firmware_shutdown, }; module_platform_driver(zynqmp_firmware_driver); diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 250246f81ea9..ed1c4775d1e9 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -11,6 +11,7 @@ config DRM_MSM depends on QCOM_OCMEM || QCOM_OCMEM=n depends on QCOM_LLCC || QCOM_LLCC=n depends on QCOM_COMMAND_DB || QCOM_COMMAND_DB=n + depends on QCOM_SMEM || QCOM_SMEM=n depends on PM select IOMMU_IO_PGTABLE select QCOM_MDT_LOADER if ARCH_QCOM @@ -21,7 +22,8 @@ config DRM_MSM select SHMEM select TMPFS select QCOM_SCM - select QCOM_UBWC_CONFIG + select QCOM_PAS + select QCOM_UBWC_CONFIG if ARCH_QCOM && QCOM_SMEM select WANT_DEV_COREDUMP select SND_SOC_HDMI_CODEC if SND_SOC select SYNC_FILE diff --git a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c index 2c0bbac43c52..57135acc8e2c 100644 --- a/drivers/gpu/drm/msm/adreno/a5xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a5xx_gpu.c @@ -5,7 +5,7 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/cpumask.h> -#include <linux/firmware/qcom/qcom_scm.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/pm_opp.h> #include <linux/nvmem-consumer.h> #include <linux/slab.h> @@ -653,7 +653,7 @@ static int a5xx_zap_shader_resume(struct msm_gpu *gpu) if (adreno_is_a506(adreno_gpu)) return 0; - ret = qcom_scm_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID); + ret = qcom_pas_set_remote_state(SCM_GPU_ZAP_SHADER_RESUME, GPU_PAS_ID); if (ret) DRM_ERROR("%s: zap-shader resume failed: %d\n", gpu->name, ret); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index c62c45bb0ddb..489462065ea9 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -8,6 +8,7 @@ #include <linux/ascii85.h> #include <linux/interconnect.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/kernel.h> #include <linux/of_reserved_mem.h> @@ -146,10 +147,10 @@ static int zap_shader_load_mdt(struct msm_gpu *gpu, const char *fwname, goto out; /* Send the image to the secure world */ - ret = qcom_scm_pas_auth_and_reset(pasid); + ret = qcom_pas_auth_and_reset(pasid); /* - * If the scm call returns -EOPNOTSUPP we assume that this target + * If the pas call returns -EOPNOTSUPP we assume that this target * doesn't need/support the zap shader so quietly fail */ if (ret == -EOPNOTSUPP) @@ -175,9 +176,9 @@ int adreno_zap_shader_load(struct msm_gpu *gpu, u32 pasid) if (!zap_available) return -ENODEV; - /* We need SCM to be able to load the firmware */ - if (!qcom_scm_is_available()) { - DRM_DEV_ERROR(&pdev->dev, "SCM is not available\n"); + /* We need PAS to be able to load the firmware */ + if (!qcom_pas_is_available()) { + DRM_DEV_ERROR(&pdev->dev, "PAS is not available\n"); return -EPROBE_DEFER; } diff --git a/drivers/media/platform/qcom/iris/Kconfig b/drivers/media/platform/qcom/iris/Kconfig index af78a1775937..0996213e71e7 100644 --- a/drivers/media/platform/qcom/iris/Kconfig +++ b/drivers/media/platform/qcom/iris/Kconfig @@ -1,14 +1,16 @@ config VIDEO_QCOM_IRIS - tristate "Qualcomm iris V4L2 decoder driver" - depends on VIDEO_DEV - depends on ARCH_QCOM || COMPILE_TEST - select V4L2_MEM2MEM_DEV - select QCOM_MDT_LOADER - select QCOM_SCM - select QCOM_UBWC_CONFIG - select VIDEOBUF2_DMA_CONTIG - help - This is a V4L2 driver for Qualcomm iris video accelerator - hardware. It accelerates decoding operations on various - Qualcomm SoCs. - To compile this driver as a module choose m here. + tristate "Qualcomm iris V4L2 decoder driver" + depends on VIDEO_DEV + depends on ARCH_QCOM || COMPILE_TEST + depends on QCOM_SMEM || QCOM_SMEM=n + select V4L2_MEM2MEM_DEV + select QCOM_MDT_LOADER + select QCOM_SCM + select QCOM_PAS + select QCOM_UBWC_CONFIG if ARCH_QCOM && QCOM_SMEM + select VIDEOBUF2_DMA_CONTIG + help + This is a V4L2 driver for Qualcomm iris video accelerator + hardware. It accelerates decoding operations on various + Qualcomm SoCs. + To compile this driver as a module choose m here. diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index 1a476146d758..ea9654dd679e 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -4,6 +4,7 @@ */ #include <linux/firmware.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/of_address.h> #include <linux/of_reserved_mem.h> @@ -80,7 +81,7 @@ int iris_fw_load(struct iris_core *core) return -ENOMEM; } - ret = qcom_scm_pas_auth_and_reset(IRIS_PAS_ID); + ret = qcom_pas_auth_and_reset(IRIS_PAS_ID); if (ret) { dev_err(core->dev, "auth and reset failed: %d\n", ret); return ret; @@ -94,7 +95,7 @@ int iris_fw_load(struct iris_core *core) cp_config->cp_nonpixel_size); if (ret) { dev_err(core->dev, "qcom_scm_mem_protect_video_var failed: %d\n", ret); - qcom_scm_pas_shutdown(IRIS_PAS_ID); + qcom_pas_shutdown(IRIS_PAS_ID); return ret; } } @@ -104,10 +105,10 @@ int iris_fw_load(struct iris_core *core) int iris_fw_unload(struct iris_core *core) { - return qcom_scm_pas_shutdown(IRIS_PAS_ID); + return qcom_pas_shutdown(IRIS_PAS_ID); } int iris_set_hw_state(struct iris_core *core, bool resume) { - return qcom_scm_set_remote_state(resume, 0); + return qcom_pas_set_remote_state(resume, 0); } diff --git a/drivers/media/platform/qcom/venus/Kconfig b/drivers/media/platform/qcom/venus/Kconfig index 63ee8c78dc6d..7997b8aa427a 100644 --- a/drivers/media/platform/qcom/venus/Kconfig +++ b/drivers/media/platform/qcom/venus/Kconfig @@ -6,6 +6,7 @@ config VIDEO_QCOM_VENUS select OF_DYNAMIC if ARCH_QCOM select QCOM_MDT_LOADER select QCOM_SCM + select QCOM_PAS select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 1de7436713ed..3a38ff985822 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -12,6 +12,7 @@ #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> #include <linux/of_device.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/sizes.h> #include <linux/soc/qcom/mdt_loader.h> @@ -58,7 +59,7 @@ int venus_set_hw_state(struct venus_core *core, bool resume) int ret; if (core->use_tz) { - ret = qcom_scm_set_remote_state(resume, 0); + ret = qcom_pas_set_remote_state(resume, 0); if (resume && ret == -EINVAL) ret = 0; return ret; @@ -218,7 +219,7 @@ int venus_boot(struct venus_core *core) int ret; if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || - (core->use_tz && !qcom_scm_is_available())) + (core->use_tz && !qcom_pas_is_available())) return -EPROBE_DEFER; ret = of_property_read_string_index(dev->of_node, "firmware-name", 0, @@ -236,7 +237,7 @@ int venus_boot(struct venus_core *core) core->fw.mem_phys = mem_phys; if (core->use_tz) - ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID); + ret = qcom_pas_auth_and_reset(VENUS_PAS_ID); else ret = venus_boot_no_tz(core, mem_phys, mem_size); @@ -259,7 +260,7 @@ int venus_boot(struct venus_core *core) res->cp_nonpixel_start, res->cp_nonpixel_size); if (ret) { - qcom_scm_pas_shutdown(VENUS_PAS_ID); + qcom_pas_shutdown(VENUS_PAS_ID); dev_err(dev, "set virtual address ranges fail (%d)\n", ret); return ret; @@ -274,7 +275,7 @@ int venus_shutdown(struct venus_core *core) int ret; if (core->use_tz) - ret = qcom_scm_pas_shutdown(VENUS_PAS_ID); + ret = qcom_pas_shutdown(VENUS_PAS_ID); else ret = venus_shutdown_no_tz(core); diff --git a/drivers/memory/jz4780-nemc.c b/drivers/memory/jz4780-nemc.c index 1a8161514d03..1bf17057cbf5 100644 --- a/drivers/memory/jz4780-nemc.c +++ b/drivers/memory/jz4780-nemc.c @@ -313,10 +313,9 @@ static int jz4780_nemc_probe(struct platform_device *pdev) writel(0, nemc->base + NEMC_NFCSR); nemc->clk = devm_clk_get(dev, NULL); - if (IS_ERR(nemc->clk)) { - dev_err(dev, "failed to get clock\n"); - return PTR_ERR(nemc->clk); - } + if (IS_ERR(nemc->clk)) + return dev_err_probe(dev, PTR_ERR(nemc->clk), + "failed to get clock\n"); ret = clk_prepare_enable(nemc->clk); if (ret) { diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c index 0e891396bdb6..84eb23c824f5 100644 --- a/drivers/memory/stm32_omm.c +++ b/drivers/memory/stm32_omm.c @@ -46,7 +46,7 @@ static int stm32_omm_set_amcr(struct device *dev, bool set) struct device_node *node; struct resource res, res1; unsigned int syscon_args[2]; - int ret, idx; + int ret = 0, idx; unsigned int i, amcr, read_amcr; for (i = 0; i < omm->nb_child; i++) { diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index ec80ea9cc173..458ce99916ad 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -3,6 +3,7 @@ * Copyright (C) 2014-2026 NVIDIA CORPORATION. All rights reserved. */ +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/dma-mapping.h> @@ -10,6 +11,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> @@ -22,6 +24,9 @@ #include "mc.h" +static DEFINE_MUTEX(tegra_mc_debugfs_root_lock); +static struct dentry *tegra_mc_debugfs_root; + static const struct of_device_id tegra_mc_of_match[] = { #ifdef CONFIG_ARCH_TEGRA_2x_SOC { .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc }, @@ -598,6 +603,13 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data) if (!status) return IRQ_NONE; + if (!mc->soc->regs) { + dev_err_ratelimited(mc->dev, + "MC error interrupt 0x%08lx with no error register map, Clearing.\n", + status); + goto clear; + } + for_each_set_bit(bit, &status, 32) { const char *error = tegra_mc_status_names[bit] ?: "unknown"; const char *client = "unknown", *desc; @@ -736,6 +748,7 @@ irqreturn_t tegra30_mc_handle_irq(int irq, void *data) desc, perm); } +clear: /* clear interrupts */ if (mc->soc->num_channels) { mc_ch_writel(mc, channel, status, MC_INTSTATUS); @@ -778,7 +791,7 @@ struct icc_node *tegra_mc_icc_xlate(const struct of_phandle_args *spec, void *da struct icc_node *node; list_for_each_entry(node, &mc->provider.nodes, node_list) { - if (node->id == spec->args[0]) + if (tegra_mc_client_id_from_node(node) == spec->args[0]) return node; } @@ -834,6 +847,7 @@ const struct tegra_mc_icc_ops tegra_mc_icc_ops = { */ static int tegra_mc_interconnect_setup(struct tegra_mc *mc) { + int node_id = dev_to_node(mc->dev); struct icc_node *node; unsigned int i; int err; @@ -854,31 +868,40 @@ static int tegra_mc_interconnect_setup(struct tegra_mc *mc) icc_provider_init(&mc->provider); /* create Memory Controller node */ - node = icc_node_create(TEGRA_ICC_MC); + node = tegra_mc_icc_node_create(node_id, TEGRA_ICC_MC); if (IS_ERR(node)) return PTR_ERR(node); - node->name = "Memory Controller"; + if (node_id == NUMA_NO_NODE) + node->name = "Memory Controller"; + else + node->name = dev_name(mc->dev); + icc_node_add(node, &mc->provider); /* link Memory Controller to External Memory Controller */ - err = icc_link_create(node, TEGRA_ICC_EMC); + err = tegra_mc_icc_link_create(node, node_id, TEGRA_ICC_EMC); if (err) goto remove_nodes; for (i = 0; i < mc->soc->num_clients; i++) { /* create MC client node */ - node = icc_node_create(mc->soc->clients[i].id); + node = tegra_mc_icc_node_create(node_id, mc->soc->clients[i].id); if (IS_ERR(node)) { err = PTR_ERR(node); goto remove_nodes; } - node->name = mc->soc->clients[i].name; + if (node_id == NUMA_NO_NODE) + node->name = mc->soc->clients[i].name; + else + node->name = devm_kasprintf(mc->dev, GFP_KERNEL, "%d-%s", + node_id, mc->soc->clients[i].name); + icc_node_add(node, &mc->provider); /* link Memory Client to Memory Controller */ - err = icc_link_create(node, TEGRA_ICC_MC); + err = tegra_mc_icc_link_create(node, node_id, TEGRA_ICC_MC); if (err) goto remove_nodes; @@ -957,7 +980,16 @@ static int tegra_mc_probe(struct platform_device *pdev) if (IS_ERR(mc->regs)) return PTR_ERR(mc->regs); - mc->debugfs.root = debugfs_create_dir("mc", NULL); + scoped_guard(mutex, &tegra_mc_debugfs_root_lock) { + if (!tegra_mc_debugfs_root) + tegra_mc_debugfs_root = debugfs_create_dir("mc", NULL); + + if (dev_to_node(mc->dev) == NUMA_NO_NODE) + mc->debugfs.root = tegra_mc_debugfs_root; + else + mc->debugfs.root = debugfs_create_dir(dev_name(mc->dev), + tegra_mc_debugfs_root); + } if (mc->soc->ops && mc->soc->ops->probe) { err = mc->soc->ops->probe(mc); diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index e94d265d7b67..01499292dd5f 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h @@ -8,6 +8,7 @@ #include <linux/bits.h> #include <linux/io.h> +#include <linux/numa.h> #include <linux/types.h> #include <soc/tegra/mc.h> @@ -167,6 +168,42 @@ icc_provider_to_tegra_mc(struct icc_provider *provider) return container_of(provider, struct tegra_mc, provider); } +/* + * Compose a globally-unique ICC node ID. On single-socket + * systems (NUMA_NO_NODE), the SoC client ID is returned unchanged. + * On multi-socket systems, the NUMA node ID is encoded in the + * upper bits of the returned ID. + * + * The client ID field is sized to keep composed IDs below + * ICC_DYN_ID_START (the start of the ICC core's dynamic-ID range). + */ +#define TEGRA_MC_CLIENT_ID_BITS 12 +#define TEGRA_MC_CLIENT_ID_MASK ((1U << TEGRA_MC_CLIENT_ID_BITS) - 1) + +static inline u32 tegra_mc_get_client_id(int node_id, int id) +{ + if (node_id == NUMA_NO_NODE) + return id; + + return ((node_id + 1) << TEGRA_MC_CLIENT_ID_BITS) | id; +} + +static inline struct icc_node *tegra_mc_icc_node_create(int node_id, int id) +{ + return icc_node_create(tegra_mc_get_client_id(node_id, id)); +} + +static inline int tegra_mc_icc_link_create(struct icc_node *node, int node_id, int id) +{ + return icc_link_create(node, tegra_mc_get_client_id(node_id, id)); +} + +/* Return the SoC client ID encoded in an ICC node ID. */ +static inline u32 tegra_mc_client_id_from_node(const struct icc_node *node) +{ + return node->id & TEGRA_MC_CLIENT_ID_MASK; +} + static inline u32 mc_ch_readl(const struct tegra_mc *mc, int ch, unsigned long offset) { diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c index 2a4cb64c4c4c..c9583b66f18d 100644 --- a/drivers/memory/tegra/tegra186-emc.c +++ b/drivers/memory/tegra/tegra186-emc.c @@ -3,15 +3,21 @@ * Copyright (C) 2019-2025 NVIDIA CORPORATION. All rights reserved. */ +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/debugfs.h> +#include <linux/fs.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <soc/tegra/bpmp.h> #include "mc.h" +static DEFINE_MUTEX(tegra_emc_debugfs_root_lock); +static struct dentry *tegra_emc_debugfs_root; + struct tegra186_emc_dvfs { unsigned long latency; unsigned long rate; @@ -206,7 +212,17 @@ static int tegra186_emc_get_emc_dvfs_latency(struct tegra186_emc *emc) return err; } - emc->debugfs.root = debugfs_create_dir("emc", NULL); + scoped_guard(mutex, &tegra_emc_debugfs_root_lock) { + if (!tegra_emc_debugfs_root) + tegra_emc_debugfs_root = debugfs_create_dir("emc", NULL); + + if (dev_to_node(emc->dev) == NUMA_NO_NODE) + emc->debugfs.root = tegra_emc_debugfs_root; + else + emc->debugfs.root = debugfs_create_dir(dev_name(emc->dev), + tegra_emc_debugfs_root); + } + debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc, &tegra186_emc_debug_available_rates_fops); debugfs_create_file("min_rate", 0644, emc->debugfs.root, emc, @@ -238,7 +254,7 @@ tegra186_emc_of_icc_xlate(const struct of_phandle_args *spec, void *data) /* External Memory is the only possible ICC route */ list_for_each_entry(node, &provider->nodes, node_list) { - if (node->id != TEGRA_ICC_EMEM) + if (tegra_mc_client_id_from_node(node) != TEGRA_ICC_EMEM) continue; return node; @@ -257,6 +273,7 @@ static int tegra186_emc_icc_get_init_bw(struct icc_node *node, u32 *avg, u32 *pe static int tegra186_emc_interconnect_init(struct tegra186_emc *emc) { + int node_id = dev_to_node(emc->dev->parent); struct icc_node *node; int err; @@ -270,26 +287,36 @@ static int tegra186_emc_interconnect_init(struct tegra186_emc *emc) icc_provider_init(&emc->provider); /* create External Memory Controller node */ - node = icc_node_create(TEGRA_ICC_EMC); - if (IS_ERR(node)) - return PTR_ERR(node); + node = tegra_mc_icc_node_create(node_id, TEGRA_ICC_EMC); + if (IS_ERR(node)) { + err = PTR_ERR(node); + goto remove_nodes; + } + + if (node_id == NUMA_NO_NODE) + node->name = "External Memory Controller"; + else + node->name = dev_name(emc->dev); - node->name = "External Memory Controller"; icc_node_add(node, &emc->provider); /* link External Memory Controller to External Memory (DRAM) */ - err = icc_link_create(node, TEGRA_ICC_EMEM); + err = tegra_mc_icc_link_create(node, node_id, TEGRA_ICC_EMEM); if (err) goto remove_nodes; /* create External Memory node */ - node = icc_node_create(TEGRA_ICC_EMEM); + node = tegra_mc_icc_node_create(node_id, TEGRA_ICC_EMEM); if (IS_ERR(node)) { err = PTR_ERR(node); goto remove_nodes; } - node->name = "External Memory (DRAM)"; + if (node_id == NUMA_NO_NODE) + node->name = "External Memory (DRAM)"; + else + node->name = devm_kasprintf(emc->dev, GFP_KERNEL, "%d-dram", node_id); + icc_node_add(node, &emc->provider); err = icc_provider_register(&emc->provider); @@ -382,6 +409,16 @@ static void tegra186_emc_remove(struct platform_device *pdev) debugfs_remove_recursive(emc->debugfs.root); + scoped_guard(mutex, &tegra_emc_debugfs_root_lock) { + if (emc->debugfs.root == tegra_emc_debugfs_root) { + tegra_emc_debugfs_root = NULL; + } else if (tegra_emc_debugfs_root && + simple_empty(tegra_emc_debugfs_root)) { + debugfs_remove(tegra_emc_debugfs_root); + tegra_emc_debugfs_root = NULL; + } + } + mc->bpmp = NULL; tegra_bpmp_put(emc->bpmp); } diff --git a/drivers/net/ipa/Kconfig b/drivers/net/ipa/Kconfig index 01d219d3760c..a9aff1b7977d 100644 --- a/drivers/net/ipa/Kconfig +++ b/drivers/net/ipa/Kconfig @@ -6,7 +6,7 @@ config QCOM_IPA depends on QCOM_RPROC_COMMON || (QCOM_RPROC_COMMON=n && COMPILE_TEST) depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n select QCOM_MDT_LOADER - select QCOM_SCM + select QCOM_PAS select QCOM_QMI_HELPERS help Choose Y or M here to include support for the Qualcomm diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 788dd99af2a4..3cd9e44680e9 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -14,7 +14,7 @@ #include <linux/pm_runtime.h> #include <linux/types.h> -#include <linux/firmware/qcom/qcom_scm.h> +#include <linux/firmware/qcom/qcom_pas.h> #include <linux/soc/qcom/mdt_loader.h> #include "ipa.h" @@ -624,10 +624,13 @@ static int ipa_firmware_load(struct device *dev) } ret = qcom_mdt_load(dev, fw, path, IPA_PAS_ID, virt, phys, size, NULL); - if (ret) + if (ret) { dev_err(dev, "error %d loading \"%s\"\n", ret, path); - else if ((ret = qcom_scm_pas_auth_and_reset(IPA_PAS_ID))) - dev_err(dev, "error %d authenticating \"%s\"\n", ret, path); + } else { + ret = qcom_pas_auth_and_reset(IPA_PAS_ID); + if (ret) + dev_err(dev, "error %d authenticating \"%s\"\n", ret, path); + } memunmap(virt); out_release_firmware: @@ -758,7 +761,7 @@ static enum ipa_firmware_loader ipa_firmware_loader(struct device *dev) return IPA_LOADER_INVALID; out_self: /* We need Trust Zone to load firmware; make sure it's available */ - if (qcom_scm_is_available()) + if (qcom_pas_is_available()) return IPA_LOADER_SELF; return IPA_LOADER_DEFER; diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig index 5bf3864fbe64..d4e189fffbf8 100644 --- a/drivers/phy/freescale/Kconfig +++ b/drivers/phy/freescale/Kconfig @@ -58,6 +58,7 @@ config PHY_FSL_LYNX_10G tristate "Freescale Layerscape Lynx 10G SerDes PHY support" depends on OF depends on ARCH_LAYERSCAPE || COMPILE_TEST + select FSL_GUTS select GENERIC_PHY select PHY_FSL_LYNX_CORE help diff --git a/drivers/phy/freescale/phy-fsl-lynx-10g.c b/drivers/phy/freescale/phy-fsl-lynx-10g.c index 38def160ef1a..60c85d08c33e 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-10g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-10g.c @@ -8,6 +8,7 @@ #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/workqueue.h> +#include <linux/fsl/guts.h> #include "phy-fsl-lynx-core.h" @@ -1167,14 +1168,7 @@ static bool lynx_10g_lane_mode_needs_rcw_override(struct lynx_lane *lane, /* Major protocol changes, which involve changing the PCS connection to * the GMII MAC with the one to the XGMII MAC, require an RCW override - * procedure to reconfigure an internal mux, as documented here: - * https://lore.kernel.org/linux-phy/20230810102631.bvozjer3t67r67iy@skbuf/ - * This is SoC-specific, and not yet implemented in drivers/soc/fsl/guts.c. - * - * So the supported set of protocols depends on the initial lane mode. - * - * Minor protocol changes (SGMII <-> 1000Base-X <-> 2500Base-X or - * 10GBase-R <-> USXGMII) are supported. + * procedure to reconfigure an internal mux. */ if ((lynx_lane_mode_uses_gmii_mac(curr) && lynx_lane_mode_uses_xgmii_mac(new)) || @@ -1189,6 +1183,7 @@ static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode, union phy_configure_opts *opts) { struct lynx_lane *lane = phy_get_drvdata(phy); + struct lynx_priv *priv = lane->priv; enum lynx_lane_mode lane_mode; int err; @@ -1197,7 +1192,8 @@ static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode, return err; if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode)) - return -EINVAL; + return fsl_guts_lane_validate(priv->info->index, lane->id, + lane_mode); return 0; } @@ -1205,6 +1201,7 @@ static int lynx_10g_validate(struct phy *phy, enum phy_mode mode, int submode, static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct lynx_lane *lane = phy_get_drvdata(phy); + struct lynx_priv *priv = lane->priv; bool powered_up = lane->powered_up; enum lynx_lane_mode lane_mode; int err; @@ -1225,6 +1222,13 @@ static int lynx_10g_set_mode(struct phy *phy, enum phy_mode mode, int submode) if (powered_up) lynx_10g_lane_halt(phy); + if (lynx_10g_lane_mode_needs_rcw_override(lane, lane_mode)) { + err = fsl_guts_lane_set_mode(priv->info->index, lane->id, + lane_mode); + if (err) + goto out; + } + err = lynx_10g_lane_disable_pcvt(lane, lane->mode); if (err) goto out; @@ -1314,6 +1318,7 @@ static struct platform_driver lynx_10g_driver = { }; module_platform_driver(lynx_10g_driver); +MODULE_IMPORT_NS("FSL_GUTS"); MODULE_IMPORT_NS("PHY_FSL_LYNX"); MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>"); MODULE_AUTHOR("Vladimir Oltean <vladimir.oltean@nxp.com>"); diff --git a/drivers/soc/amlogic/meson-clk-measure.c b/drivers/soc/amlogic/meson-clk-measure.c index d862e30a244e..8a1a9fed0e74 100644 --- a/drivers/soc/amlogic/meson-clk-measure.c +++ b/drivers/soc/amlogic/meson-clk-measure.c @@ -7,6 +7,7 @@ #include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/bitfield.h> +#include <linux/err.h> #include <linux/seq_file.h> #include <linux/debugfs.h> #include <linux/regmap.h> @@ -50,6 +51,7 @@ struct meson_msr_data { struct meson_msr { struct regmap *regmap; struct meson_msr_data data; + struct dentry *debugfs_root; }; #define CLK_MSR_ID(__id, __name) \ @@ -787,6 +789,258 @@ static const struct meson_msr_id clk_msr_s4[] = { }; +static const struct meson_msr_id clk_msr_a1[] = { + CLK_MSR_ID(0, "tdmout_b_sclk"), + CLK_MSR_ID(1, "tdmout_a_sclk"), + CLK_MSR_ID(2, "tdmin_lb_sclk"), + CLK_MSR_ID(3, "tdmin_b_sclk"), + CLK_MSR_ID(4, "tdmin_a_sclk"), + CLK_MSR_ID(5, "vad"), + CLK_MSR_ID(6, "resamplea"), + CLK_MSR_ID(7, "pdm_sysclk"), + CLK_MSR_ID(8, "pdm_dclk"), + CLK_MSR_ID(9, "locker_out"), + CLK_MSR_ID(10, "locker_in"), + CLK_MSR_ID(11, "spdifin"), + CLK_MSR_ID(12, "tdmin_vad"), + CLK_MSR_ID(13, "au_adc"), + CLK_MSR_ID(14, "au_dac"), + CLK_MSR_ID(16, "spicc_a"), + CLK_MSR_ID(17, "spifc"), + CLK_MSR_ID(18, "sd_emmc_a"), + CLK_MSR_ID(19, "dmcx4"), + CLK_MSR_ID(20, "dmc"), + CLK_MSR_ID(21, "psram"), + CLK_MSR_ID(22, "cecb"), + CLK_MSR_ID(23, "ceca"), + CLK_MSR_ID(24, "ts"), + CLK_MSR_ID(25, "pwm_f"), + CLK_MSR_ID(26, "pwm_e"), + CLK_MSR_ID(27, "pwm_d"), + CLK_MSR_ID(28, "pwm_c"), + CLK_MSR_ID(29, "pwm_b"), + CLK_MSR_ID(30, "pwm_a"), + CLK_MSR_ID(31, "saradc"), + CLK_MSR_ID(32, "usb_bus"), + CLK_MSR_ID(33, "dsp_b"), + CLK_MSR_ID(34, "dsp_a"), + CLK_MSR_ID(35, "axi"), + CLK_MSR_ID(36, "sys"), + CLK_MSR_ID(40, "rng_ring_osc0"), + CLK_MSR_ID(41, "rng_ring_osc1"), + CLK_MSR_ID(42, "rng_ring_osc2"), + CLK_MSR_ID(43, "rng_ring_osc3"), + CLK_MSR_ID(44, "dds_out"), + CLK_MSR_ID(45, "cpu_clk_div16"), + CLK_MSR_ID(46, "gpio_msr"), + CLK_MSR_ID(50, "osc_ring_cpu0"), + CLK_MSR_ID(51, "osc_ring_cpu1"), + CLK_MSR_ID(54, "osc_ring_top0"), + CLK_MSR_ID(55, "osc_ring_top1"), + CLK_MSR_ID(56, "osc_ring_ddr"), + CLK_MSR_ID(57, "osc_ring_dmc"), + CLK_MSR_ID(58, "osc_ring_dspa"), + CLK_MSR_ID(59, "osc_ring_dspb"), + CLK_MSR_ID(60, "osc_ring_rama"), + CLK_MSR_ID(61, "osc_ring_ramb"), +}; + +static const struct meson_msr_id clk_msr_t7[] = { + CLK_MSR_ID(0, "sys"), + CLK_MSR_ID(1, "axi"), + CLK_MSR_ID(2, "rtc"), + CLK_MSR_ID(3, "dspa"), + CLK_MSR_ID(4, "dspb"), + CLK_MSR_ID(5, "mali"), + CLK_MSR_ID(6, "sys_cpu_clk_div16"), + CLK_MSR_ID(7, "ceca"), + CLK_MSR_ID(8, "cecb"), + CLK_MSR_ID(10, "fclk_div5"), + CLK_MSR_ID(11, "mpll0"), + CLK_MSR_ID(12, "mpll1"), + CLK_MSR_ID(13, "mpll2"), + CLK_MSR_ID(14, "mpll3"), + CLK_MSR_ID(15, "mpll_50m"), + CLK_MSR_ID(16, "pcie_inp"), + CLK_MSR_ID(17, "pcie_inn"), + CLK_MSR_ID(18, "mpll_test_out"), + CLK_MSR_ID(19, "hifi_pll"), + CLK_MSR_ID(20, "gp0_pll"), + CLK_MSR_ID(21, "gp1_pll"), + CLK_MSR_ID(22, "eth_mppll_50m"), + CLK_MSR_ID(23, "sys_pll_div16"), + CLK_MSR_ID(24, "ddr_dpll_pt"), + CLK_MSR_ID(25, "earcrx_pll"), + CLK_MSR_ID(26, "paie1_clk_inp"), + CLK_MSR_ID(27, "paie1_clk_inn"), + CLK_MSR_ID(28, "amlgdc"), + CLK_MSR_ID(29, "gdc"), + CLK_MSR_ID(30, "mod_eth_phy_ref"), + CLK_MSR_ID(31, "mod_eth_tx"), + CLK_MSR_ID(32, "eth_clk125Mhz"), + CLK_MSR_ID(33, "eth_clk_rmii"), + CLK_MSR_ID(34, "co_clkin_to_mac"), + CLK_MSR_ID(35, "mod_eth_rx_clk_rmii"), + CLK_MSR_ID(36, "co_rx"), + CLK_MSR_ID(37, "co_tx"), + CLK_MSR_ID(38, "eth_phy_rxclk"), + CLK_MSR_ID(39, "eth_phy_plltxclk"), + CLK_MSR_ID(40, "ephy_test"), + CLK_MSR_ID(41, "dsi_b_meas"), + CLK_MSR_ID(42, "hdmirx_apl"), + CLK_MSR_ID(43, "hdmirx_tmds"), + CLK_MSR_ID(44, "hdmirx_cable"), + CLK_MSR_ID(45, "hdmirx_apll_clk_audio"), + CLK_MSR_ID(46, "hdmirx_5m"), + CLK_MSR_ID(47, "hdmirx_2m"), + CLK_MSR_ID(48, "hdmirx_cfg"), + CLK_MSR_ID(49, "hdmirx_hdcp2x_eclk"), + CLK_MSR_ID(50, "vid_pll0_div"), + CLK_MSR_ID(51, "hdmi_vid_pll"), + CLK_MSR_ID(54, "vdac_clk"), + CLK_MSR_ID(55, "vpu_clk_buf"), + CLK_MSR_ID(56, "mod_tcon_clko"), + CLK_MSR_ID(57, "lcd_an_clk_ph2"), + CLK_MSR_ID(58, "lcd_an_clk_ph3"), + CLK_MSR_ID(59, "hdmi_tx_pixel"), + CLK_MSR_ID(60, "vdin_meas"), + CLK_MSR_ID(61, "vpu_clk"), + CLK_MSR_ID(62, "vpu_clkb"), + CLK_MSR_ID(63, "vpu_clkb_tmp"), + CLK_MSR_ID(64, "vpu_clkc"), + CLK_MSR_ID(65, "vid_lock"), + CLK_MSR_ID(66, "vapbclk"), + CLK_MSR_ID(67, "ge2d"), + CLK_MSR_ID(68, "aud_pll"), + CLK_MSR_ID(69, "aud_sck"), + CLK_MSR_ID(70, "dsi_a_meas"), + CLK_MSR_ID(72, "mipi_csi_phy"), + CLK_MSR_ID(73, "mipi_isp"), + CLK_MSR_ID(76, "hdmitx_tmds"), + CLK_MSR_ID(77, "hdmitx_sys"), + CLK_MSR_ID(78, "hdmitx_fe"), + CLK_MSR_ID(80, "hdmitx_prif"), + CLK_MSR_ID(81, "hdmitx_200m"), + CLK_MSR_ID(82, "hdmitx_aud"), + CLK_MSR_ID(83, "hdmitx_pnx"), + CLK_MSR_ID(84, "spicc5"), + CLK_MSR_ID(85, "spicc4"), + CLK_MSR_ID(86, "spicc3"), + CLK_MSR_ID(87, "spicc2"), + CLK_MSR_ID(93, "vdec"), + CLK_MSR_ID(94, "wave521_aclk"), + CLK_MSR_ID(95, "wave521_cclk"), + CLK_MSR_ID(96, "wave521_bclk"), + CLK_MSR_ID(97, "hcodec"), + CLK_MSR_ID(98, "hevcb"), + CLK_MSR_ID(99, "hevcf"), + CLK_MSR_ID(100, "hdmi_aud_pll"), + CLK_MSR_ID(101, "hdmi_acr_ref"), + CLK_MSR_ID(102, "hdmi_meter"), + CLK_MSR_ID(103, "hdmi_vid"), + CLK_MSR_ID(104, "hdmi_aud"), + CLK_MSR_ID(105, "hdmi_dsd"), + CLK_MSR_ID(108, "dsi1_phy"), + CLK_MSR_ID(109, "dsi0_phy"), + CLK_MSR_ID(110, "smartcard"), + CLK_MSR_ID(111, "sar_adc"), + CLK_MSR_ID(113, "sd_emmc_c"), + CLK_MSR_ID(114, "sd_emmc_b"), + CLK_MSR_ID(115, "sd_emmc_a"), + CLK_MSR_ID(116, "gpio_msr"), + CLK_MSR_ID(117, "spicc1"), + CLK_MSR_ID(118, "spicc0"), + CLK_MSR_ID(119, "anakin"), + CLK_MSR_ID(121, "ts_clk(temp sensor)"), + CLK_MSR_ID(122, "ts_a73"), + CLK_MSR_ID(123, "ts_a53"), + CLK_MSR_ID(124, "ts_nna"), + CLK_MSR_ID(130, "audio_vad"), + CLK_MSR_ID(131, "acodec_dac_clk_x128"), + CLK_MSR_ID(132, "audio_locker_in"), + CLK_MSR_ID(133, "audio_locker_out"), + CLK_MSR_ID(134, "audio_tdmout_c_sclk"), + CLK_MSR_ID(135, "audio_tdmout_b_sclk"), + CLK_MSR_ID(136, "audio_tdmout_a_sclk"), + CLK_MSR_ID(137, "audio_tdmin_lb_sclk"), + CLK_MSR_ID(138, "audio_tdmin_c_sclk"), + CLK_MSR_ID(139, "audio_tdmin_b_sclk"), + CLK_MSR_ID(140, "audio_tdmin_a_sclk"), + CLK_MSR_ID(141, "audio_resamplea"), + CLK_MSR_ID(142, "audio_pdm_sysclk"), + CLK_MSR_ID(143, "audio_spdifoutb_mst"), + CLK_MSR_ID(144, "audio_spdifout_mst"), + CLK_MSR_ID(145, "audio_spdifin_mst"), + CLK_MSR_ID(146, "audio_pdm_dclk"), + CLK_MSR_ID(147, "audio_resampleb"), + CLK_MSR_ID(148, "earcrx_pll_dmac"), + CLK_MSR_ID(156, "pwm_ao_h"), + CLK_MSR_ID(157, "pwm_ao_g"), + CLK_MSR_ID(158, "pwm_ao_f"), + CLK_MSR_ID(159, "pwm_ao_e"), + CLK_MSR_ID(160, "pwm_ao_d"), + CLK_MSR_ID(161, "pwm_ao_c"), + CLK_MSR_ID(162, "pwm_ao_b"), + CLK_MSR_ID(163, "pwm_ao_a"), + CLK_MSR_ID(164, "pwm_f"), + CLK_MSR_ID(165, "pwm_e"), + CLK_MSR_ID(166, "pwm_d"), + CLK_MSR_ID(167, "pwm_c"), + CLK_MSR_ID(168, "pwm_b"), + CLK_MSR_ID(169, "pwm_a"), + CLK_MSR_ID(170, "aclkm"), + CLK_MSR_ID(171, "mclk_pll"), + CLK_MSR_ID(172, "a73_sys_pll_div16"), + CLK_MSR_ID(173, "a73_cpu_clk_div16"), + CLK_MSR_ID(176, "rng_ring_0"), + CLK_MSR_ID(177, "rng_ring_1"), + CLK_MSR_ID(178, "rng_ring_2"), + CLK_MSR_ID(179, "rng_ring_3"), + CLK_MSR_ID(180, "am_ring_out0"), + CLK_MSR_ID(181, "am_ring_out1"), + CLK_MSR_ID(182, "am_ring_out2"), + CLK_MSR_ID(183, "am_ring_out3"), + CLK_MSR_ID(184, "am_ring_out4"), + CLK_MSR_ID(185, "am_ring_out5"), + CLK_MSR_ID(186, "am_ring_out6"), + CLK_MSR_ID(187, "am_ring_out7"), + CLK_MSR_ID(188, "am_ring_out8"), + CLK_MSR_ID(189, "am_ring_out9"), + CLK_MSR_ID(190, "am_ring_out10"), + CLK_MSR_ID(191, "am_ring_out11"), + CLK_MSR_ID(192, "am_ring_out12"), + CLK_MSR_ID(193, "am_ring_out13"), + CLK_MSR_ID(194, "am_ring_out14"), + CLK_MSR_ID(195, "am_ring_out15"), + CLK_MSR_ID(196, "am_ring_out16"), + CLK_MSR_ID(197, "am_ring_out17"), + CLK_MSR_ID(198, "am_ring_out18"), + CLK_MSR_ID(199, "am_ring_out19"), + CLK_MSR_ID(200, "mipi_csi_phy0"), + CLK_MSR_ID(201, "mipi_csi_phy1"), + CLK_MSR_ID(202, "mipi_csi_phy2"), + CLK_MSR_ID(203, "mipi_csi_phy3"), + CLK_MSR_ID(204, "vid_pll1_div"), + CLK_MSR_ID(205, "vid_pll2_div"), + CLK_MSR_ID(206, "am_ring_out20"), + CLK_MSR_ID(207, "am_ring_out21"), + CLK_MSR_ID(208, "am_ring_out22"), + CLK_MSR_ID(209, "am_ring_out23"), + CLK_MSR_ID(210, "am_ring_out24"), + CLK_MSR_ID(211, "am_ring_out25"), + CLK_MSR_ID(212, "am_ring_out26"), + CLK_MSR_ID(213, "am_ring_out27"), + CLK_MSR_ID(214, "am_ring_out28"), + CLK_MSR_ID(215, "am_ring_out29"), + CLK_MSR_ID(216, "am_ring_out30"), + CLK_MSR_ID(217, "am_ring_out31"), + CLK_MSR_ID(218, "am_ring_out32"), + CLK_MSR_ID(219, "enc0_if"), + CLK_MSR_ID(220, "enc2"), + CLK_MSR_ID(221, "enc1"), + CLK_MSR_ID(222, "enc0") +}; + static int meson_measure_id(struct meson_msr_id *clk_msr_id, unsigned int duration) { @@ -952,6 +1206,7 @@ static int meson_msr_probe(struct platform_device *pdev) sizeof(struct msr_reg_offset)); root = debugfs_create_dir("meson-clk-msr", NULL); + priv->debugfs_root = root; clks = debugfs_create_dir("clks", root); debugfs_create_file("measure_summary", 0444, root, @@ -967,9 +1222,19 @@ static int meson_msr_probe(struct platform_device *pdev) &priv->data.msr_table[i], &clk_msr_fops); } + platform_set_drvdata(pdev, priv); + return 0; } +static void meson_msr_remove(struct platform_device *pdev) +{ + struct meson_msr *priv = platform_get_drvdata(pdev); + + if (!IS_ERR_OR_NULL(priv->debugfs_root)) + debugfs_remove_recursive(priv->debugfs_root); +} + static const struct msr_reg_offset msr_reg_offset = { .duty_val = 0x0, .freq_ctrl = 0x4, @@ -1026,6 +1291,18 @@ static const struct meson_msr_data clk_msr_s4_data = { .reg = &msr_reg_offset_v2, }; +static const struct meson_msr_data clk_msr_a1_data = { + .msr_table = (void *)clk_msr_a1, + .msr_count = ARRAY_SIZE(clk_msr_a1), + .reg = &msr_reg_offset_v2, +}; + +static const struct meson_msr_data clk_msr_t7_data = { + .msr_table = (void *)clk_msr_t7, + .msr_count = ARRAY_SIZE(clk_msr_t7), + .reg = &msr_reg_offset_v2, +}; + static const struct of_device_id meson_msr_match_table[] = { { .compatible = "amlogic,meson-gx-clk-measure", @@ -1059,12 +1336,21 @@ static const struct of_device_id meson_msr_match_table[] = { .compatible = "amlogic,s4-clk-measure", .data = &clk_msr_s4_data, }, + { + .compatible = "amlogic,a1-clk-measure", + .data = &clk_msr_a1_data, + }, + { + .compatible = "amlogic,t7-clk-measure", + .data = &clk_msr_t7_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, meson_msr_match_table); static struct platform_driver meson_msr_driver = { .probe = meson_msr_probe, + .remove = meson_msr_remove, .driver = { .name = "meson_msr", .of_match_table = meson_msr_match_table, diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index d0ff32182a2b..db30c0ade948 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -16,6 +16,16 @@ config APPLE_MAILBOX Say Y here if you have an Apple SoC. +config APPLE_PMGR_MISC + tristate "Apple SoC PMGR miscellaneous support" + depends on PM + help + The PMGR block in Apple SoCs provides high-level power state + controls for SoC devices. This driver manages miscellaneous + power controls. + + Say 'y' here if you have a Pro/Max/Ultra Apple SoC. + config APPLE_RTKIT tristate "Apple RTKit co-processor IPC protocol" depends on APPLE_MAILBOX diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile index 0b85ab61aefe..0481f7f43b06 100644 --- a/drivers/soc/apple/Makefile +++ b/drivers/soc/apple/Makefile @@ -3,6 +3,8 @@ obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o apple-mailbox-y = mailbox.o +obj-$(CONFIG_APPLE_PMGR_MISC) += apple-pmgr-misc.o + obj-$(CONFIG_APPLE_RTKIT) += apple-rtkit.o apple-rtkit-y = rtkit.o rtkit-crashlog.o diff --git a/drivers/soc/apple/apple-pmgr-misc.c b/drivers/soc/apple/apple-pmgr-misc.c new file mode 100644 index 000000000000..7db29f7de329 --- /dev/null +++ b/drivers/soc/apple/apple-pmgr-misc.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SoC PMGR device power state driver + * + * Copyright The Asahi Linux Contributors + */ + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#define APPLE_CLKGEN_PSTATE 0 +#define APPLE_CLKGEN_PSTATE_DESIRED GENMASK(3, 0) + +#define DCS_DEV_PSTATE_MIN_T600X 7 +#define SYS_DEV_PSTATE_SUSPEND 1 + +enum sys_device { + DEV_FABRIC, + DEV_DCS, + DEV_MAX, +}; + +struct apple_pmgr_sys_device { + void __iomem *base; + u32 active_state; + u32 suspend_state; +}; + +struct apple_pmgr_misc_hw { + u32 dev_min_ps[DEV_MAX]; +}; + +struct apple_pmgr_misc { + struct device *dev; + struct apple_pmgr_sys_device devices[DEV_MAX]; +}; + +static void apple_pmgr_sys_dev_set_pstate(struct apple_pmgr_misc *misc, + enum sys_device dev, bool active) +{ + u32 pstate; + u32 val; + + if (!misc->devices[dev].base) + return; + + if (active) + pstate = misc->devices[dev].active_state; + else + pstate = misc->devices[dev].suspend_state; + + dev_dbg(misc->dev, "set %d ps to pstate %d\n", dev, pstate); + + val = readl_relaxed(misc->devices[dev].base + APPLE_CLKGEN_PSTATE); + FIELD_MODIFY(APPLE_CLKGEN_PSTATE_DESIRED, &val, pstate); + writel_relaxed(val, misc->devices[dev].base + APPLE_CLKGEN_PSTATE); +} + +static int __maybe_unused apple_pmgr_misc_suspend_noirq(struct device *dev) +{ + struct apple_pmgr_misc *misc = dev_get_drvdata(dev); + int i; + + for (i = 0; i < DEV_MAX; i++) + apple_pmgr_sys_dev_set_pstate(misc, i, false); + + return 0; +} + +static int __maybe_unused apple_pmgr_misc_resume_noirq(struct device *dev) +{ + struct apple_pmgr_misc *misc = dev_get_drvdata(dev); + int i; + + for (i = 0; i < DEV_MAX; i++) + apple_pmgr_sys_dev_set_pstate(misc, i, true); + + return 0; +} + +static int apple_pmgr_init_device(struct apple_pmgr_misc *misc, + const struct apple_pmgr_misc_hw *hw, + enum sys_device dev, + const char *device_name) +{ + void __iomem *base; + char name[32]; + u32 val; + + snprintf(name, sizeof(name), "%s-ps", device_name); + + base = devm_platform_ioremap_resource_byname( + to_platform_device(misc->dev), name); + if (IS_ERR(base)) + return PTR_ERR(base); + + val = readl_relaxed(base + APPLE_CLKGEN_PSTATE); + + misc->devices[dev].base = base; + misc->devices[dev].active_state = + FIELD_GET(APPLE_CLKGEN_PSTATE_DESIRED, val); + misc->devices[dev].suspend_state = hw->dev_min_ps[dev]; + + return 0; +} + +static int apple_pmgr_misc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct apple_pmgr_misc_hw *hw; + struct apple_pmgr_misc *misc; + int ret; + + misc = devm_kzalloc(dev, sizeof(*misc), GFP_KERNEL); + if (!misc) + return -ENOMEM; + + misc->dev = dev; + hw = of_device_get_match_data(dev); + if (!hw) + return -EINVAL; + + ret = apple_pmgr_init_device(misc, hw, DEV_FABRIC, "fabric"); + if (ret) + return ret; + + ret = apple_pmgr_init_device(misc, hw, DEV_DCS, "dcs"); + if (ret) + return ret; + + platform_set_drvdata(pdev, misc); + + return 0; +} + +static const struct apple_pmgr_misc_hw apple_pmgr_misc_hw_t600x = { + .dev_min_ps = { + [DEV_FABRIC] = SYS_DEV_PSTATE_SUSPEND, + [DEV_DCS] = DCS_DEV_PSTATE_MIN_T600X, + }, +}; + +static const struct apple_pmgr_misc_hw apple_pmgr_misc_hw_t602x = { + .dev_min_ps = { + [DEV_FABRIC] = SYS_DEV_PSTATE_SUSPEND, + [DEV_DCS] = SYS_DEV_PSTATE_SUSPEND, + }, +}; + +static const struct of_device_id apple_pmgr_misc_of_match[] = { + { .compatible = "apple,t6000-pmgr-misc", .data = &apple_pmgr_misc_hw_t600x }, + { .compatible = "apple,t6020-pmgr-misc", .data = &apple_pmgr_misc_hw_t602x }, + {} +}; + +MODULE_DEVICE_TABLE(of, apple_pmgr_misc_of_match); + +static const struct dev_pm_ops apple_pmgr_misc_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(apple_pmgr_misc_suspend_noirq, + apple_pmgr_misc_resume_noirq) +}; + +static struct platform_driver apple_pmgr_misc_driver = { + .probe = apple_pmgr_misc_probe, + .driver = { + .name = "apple-pmgr-misc", + .of_match_table = apple_pmgr_misc_of_match, + .pm = pm_ptr(&apple_pmgr_misc_pm_ops), + }, +}; + +MODULE_AUTHOR("Hector Martin <marcan@marcan.st>"); +MODULE_DESCRIPTION("PMGR misc driver for Apple SoCs"); +MODULE_LICENSE("GPL"); + +module_platform_driver(apple_pmgr_misc_driver); diff --git a/drivers/soc/apple/sart.c b/drivers/soc/apple/sart.c index 9eaf3febb382..66b99955b395 100644 --- a/drivers/soc/apple/sart.c +++ b/drivers/soc/apple/sart.c @@ -218,6 +218,7 @@ struct apple_sart *devm_apple_sart_get(struct device *dev) { struct device_node *sart_node; struct platform_device *sart_pdev; + struct device_link *link; struct apple_sart *sart; sart_node = of_parse_phandle(dev->of_node, "apple,sart", 0); @@ -236,8 +237,12 @@ struct apple_sart *devm_apple_sart_get(struct device *dev) return ERR_PTR(-EPROBE_DEFER); } - device_link_add(dev, &sart_pdev->dev, - DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER); + link = device_link_add(dev, &sart_pdev->dev, + DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER); + if (!link) { + put_device(&sart_pdev->dev); + return ERR_PTR(-ENODEV); + } put_device(&sart_pdev->dev); diff --git a/drivers/soc/aspeed/aspeed-uart-routing.c b/drivers/soc/aspeed/aspeed-uart-routing.c index 0191e36e66e1..b4b521b5ddf1 100644 --- a/drivers/soc/aspeed/aspeed-uart-routing.c +++ b/drivers/soc/aspeed/aspeed-uart-routing.c @@ -582,6 +582,7 @@ static const struct of_device_id aspeed_uart_routing_table[] = { .data = &ast2600_uart_routing_attr_group }, { }, }; +MODULE_DEVICE_TABLE(of, aspeed_uart_routing_table); static struct platform_driver aspeed_uart_routing_driver = { .driver = { diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 9e3fddd8f5a9..d5198ffc4455 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -102,12 +102,8 @@ static int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu) 0, dev_name(&dpio_dev->dev), &dpio_dev->dev); - if (error < 0) { - dev_err(&dpio_dev->dev, - "devm_request_irq() failed: %d\n", - error); + if (error < 0) return error; - } /* set the affinity hint */ if (irq_set_affinity_hint(irq->virq, cpumask_of(cpu))) diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c index 9bee7baec2b9..28361c63e26c 100644 --- a/drivers/soc/fsl/guts.c +++ b/drivers/soc/fsl/guts.c @@ -5,7 +5,10 @@ * Copyright (C) 2016 Freescale Semiconductor, Inc. */ +#include <linux/bitfield.h> +#include <linux/bitops.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/of_fdt.h> @@ -14,15 +17,110 @@ #include <linux/platform_device.h> #include <linux/fsl/guts.h> +#define DCFG_CCSR 0 +#define DCFG_DCSR 1 + +#define RCW_TIMEOUT_US 1 + +#define LS1046A_RCWSR5_SRDS_PRTCL_S1(lane) \ + GENMASK(19 + 4 * (lane), 16 + 4 * (lane)) +#define LS1046A_SRDS_PRTCL_XFI 1 +#define LS1046A_SRDS_PRTCL_100BASEX_SGMII 3 + +#define LS1088A_RCWSR29_SRDS_PRTCL_S1_LNn(lane) \ + GENMASK(19 + 4 * (3 - (lane)), 16 + 4 * (3 - (lane))) +#define LS1088A_RCWSR30_SRDS_PRTCL_S2_LNn(lane) \ + GENMASK(3 + 4 * (3 - (lane)), 4 * (3 - (lane))) +#define LS1088A_SRDS_PRTCL_XFI 1 +#define LS1088A_SRDS_PRTCL_100BASEX_SGMII 3 + +#define LS2088A_RCWSR29_SRDS_PRTCL_S1 GENMASK(23, 16) +#define LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1 BIT(14) +#define LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(lane) BIT(6 + (7 - (lane))) +#define LS2088A_RCWSR30_SRDS_CLK_SEL_MSK GENMASK(13, 6) +#define LS2088A_SRDS_CLK_SEL_XGMII 1 +#define LS2088A_SRDS_CLK_SEL_GMII 0 + struct fsl_soc_die_attr { char *die; u32 svr; u32 mask; }; +struct fsl_soc_serdes_rcw_override { + int offset; + int mask; + int val; +}; + struct fsl_soc_data { const char *sfp_compat; u32 uid_offset; + int num_serdes_blocks; + int num_serdes_lanes; + int (*serdes_init_rcwcr)(int index); + int (*serdes_get_rcw_override)(int index, int lane, + enum lynx_lane_mode lane_mode, + struct fsl_soc_serdes_rcw_override *override); +}; + +enum qoriq_die { + DIE_T4240, + DIE_T1040, + DIE_T2080, + DIE_T1024, + DIE_LS1043A, + DIE_LS2080A, + DIE_LS1088A, + DIE_LS1012A, + DIE_LS1046A, + DIE_LS2088A, + DIE_LS1021A, + DIE_LX2160A, + DIE_LS1028A, + DIE_MAX, +}; + +struct rcw_full_srds_proto { + int srds_proto_val; + unsigned long xgmii_lanes; +}; + +static const struct rcw_full_srds_proto ls2088a_rcw_full_srds1_protos[] = { + { 0x05, 0 }, + { 0x07, 0 }, + { 0x09, 0 }, + { 0x0a, 0 }, + { 0x0c, 0 }, + { 0x0e, 0 }, + { 0x10, 0 }, + { 0x12, 0 }, + { 0x14, 0 }, + { 0x16, 0 }, + { 0x18, 0 }, + { 0x1a, 0 }, + { 0x1c, 0 }, + { 0x1e, 0 }, + { 0x20, 0 }, + { 0x22, 0 }, + { 0x24, 0 }, + { 0x26, GENMASK(7, 6) }, + { 0x28, GENMASK(7, 4) }, + { 0x2a, GENMASK(7, 0) }, + /* 0x2b: unimplemented because of XAUI1 (lanes E-H) */ + /* 0x2d: unimplemented because of XAUI1 (lanes E-H) */ + /* 0x2e: unimplemented because of XAUI1 (lanes E-H) */ + /* 0x30: unimplemented because of XAUI1 (lanes E-H) */ + /* 0x32: unimplemented because of XAUI1 (lanes E-H) and XAUI2 (A-D) */ + /* 0x33: unimplemented because of QSGMII (lanes E-H) */ + /* 0x35: unimplemented because of QSGMII (lanes A-C) */ + /* 0x37: unimplemented because of QSGMII (lanes E-F) */ + { 0x39, 0 }, + { 0x3b, GENMASK(6, 4) | GENMASK(2, 0) }, + { 0x4b, GENMASK(7, 4) }, + { 0x4c, GENMASK(3, 0) }, + { 0x4d, 0 }, + { 0x58, 0 }, }; /* SoC die attribute definition for QorIQ platform */ @@ -32,21 +130,25 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = { */ /* Die: T4240, SoC: T4240/T4160/T4080 */ + [DIE_T4240] = { .die = "T4240", .svr = 0x82400000, .mask = 0xfff00000, }, /* Die: T1040, SoC: T1040/T1020/T1042/T1022 */ + [DIE_T1040] = { .die = "T1040", .svr = 0x85200000, .mask = 0xfff00000, }, /* Die: T2080, SoC: T2080/T2081 */ + [DIE_T2080] = { .die = "T2080", .svr = 0x85300000, .mask = 0xfff00000, }, /* Die: T1024, SoC: T1024/T1014/T1023/T1013 */ + [DIE_T1024] = { .die = "T1024", .svr = 0x85400000, .mask = 0xfff00000, @@ -57,46 +159,55 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = { */ /* Die: LS1043A, SoC: LS1043A/LS1023A */ + [DIE_LS1043A] = { .die = "LS1043A", .svr = 0x87920000, .mask = 0xffff0000, }, /* Die: LS2080A, SoC: LS2080A/LS2040A/LS2085A */ + [DIE_LS2080A] = { .die = "LS2080A", .svr = 0x87010000, .mask = 0xff3f0000, }, /* Die: LS1088A, SoC: LS1088A/LS1048A/LS1084A/LS1044A */ + [DIE_LS1088A] = { .die = "LS1088A", .svr = 0x87030000, .mask = 0xff3f0000, }, /* Die: LS1012A, SoC: LS1012A */ + [DIE_LS1012A] = { .die = "LS1012A", .svr = 0x87040000, .mask = 0xffff0000, }, /* Die: LS1046A, SoC: LS1046A/LS1026A */ + [DIE_LS1046A] = { .die = "LS1046A", .svr = 0x87070000, .mask = 0xffff0000, }, /* Die: LS2088A, SoC: LS2088A/LS2048A/LS2084A/LS2044A */ + [DIE_LS2088A] = { .die = "LS2088A", .svr = 0x87090000, .mask = 0xff3f0000, }, /* Die: LS1021A, SoC: LS1021A/LS1020A/LS1022A */ + [DIE_LS1021A] = { .die = "LS1021A", .svr = 0x87000000, .mask = 0xfff70000, }, /* Die: LX2160A, SoC: LX2160A/LX2120A/LX2080A */ + [DIE_LX2160A] = { .die = "LX2160A", .svr = 0x87360000, .mask = 0xff3f0000, }, /* Die: LS1028A, SoC: LS1028A */ + [DIE_LS1028A] = { .die = "LS1028A", .svr = 0x870b0000, .mask = 0xff3f0000, @@ -104,17 +215,160 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = { { }, }; +static struct fsl_soc_guts { + struct ccsr_guts __iomem *dcfg_ccsr; + struct ccsr_guts __iomem *dcfg_dcsr; + const struct fsl_soc_data *data; + bool little_endian; + u32 svr; + spinlock_t rcwcr_lock; /* serializes concurrent writes to the RCWCR */ +} soc; + +static unsigned int fsl_guts_read(const void __iomem *reg) +{ + if (soc.little_endian) + return ioread32(reg); + + return ioread32be(reg); +} + +static void fsl_guts_write(void __iomem *reg, u32 val) +{ + if (soc.little_endian) + iowrite32(val, reg); + else + iowrite32be(val, reg); +} + +/* Some fields of the Reset Configuration Word (RCW) can be overridden at + * runtime by writing to the RCWCRn registers contained within the DCSR space + * of the Device Configuration (DCFG) block. The layout of the RCWCRn registers + * is identical with the read-only RCWSRn from the CCSR space. + */ +static int fsl_guts_rcw_rmw(int offset, u32 val, u32 mask) +{ + u32 rcwcr, rcwsr = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[offset]); + + rcwcr = rcwsr & ~mask; + rcwcr |= val; + fsl_guts_write(&soc.dcfg_dcsr->rcwcr[offset], rcwcr); + + pr_debug("RCW override: RCWSR%d 0x%x -> RCWCR%d 0x%x\n", + offset + 1, rcwsr, offset + 1, rcwcr); + + /* Updates to RCWCR should be visible back in RCWSR immediately */ + return read_poll_timeout_atomic(fsl_guts_read, rcwsr, rcwsr == rcwcr, + 0, RCW_TIMEOUT_US, false, + &soc.dcfg_ccsr->rcwsr[offset]); +} + +static bool fsl_soc_die_match_one(u32 svr, const struct fsl_soc_die_attr *match) +{ + return match->svr == (svr & match->mask); +} + static const struct fsl_soc_die_attr *fsl_soc_die_match( u32 svr, const struct fsl_soc_die_attr *matches) { while (matches->svr) { - if (matches->svr == (svr & matches->mask)) + if (fsl_soc_die_match_one(svr, matches)) return matches; matches++; } return NULL; } +static int +fsl_guts_serdes_get_rcw_override(int serdes_idx, int lane, + enum lynx_lane_mode lane_mode, + struct fsl_soc_serdes_rcw_override *override) +{ + const struct fsl_soc_data *soc_data = soc.data; + + if (!soc_data) + return -ENODEV; + + /* serdes_idx is one-based */ + if (serdes_idx > soc_data->num_serdes_blocks || serdes_idx <= 0) + return -ERANGE; + + if (lane >= soc_data->num_serdes_lanes || lane < 0) + return -ERANGE; + + if (!soc_data->serdes_get_rcw_override) { + pr_debug("RCW override not implemented for SoC\n"); + return -EINVAL; + } + + if (!soc.dcfg_dcsr) { + pr_debug("Device tree does not define DCFG_DCSR region necessary for RCW override\n"); + return -EINVAL; + } + + return soc_data->serdes_get_rcw_override(serdes_idx, lane, lane_mode, + override); +} + +/** + * fsl_guts_lane_validate() - Validate that SerDes protocol is implemented and + * supported on current SoC + * @serdes_idx: one-based SerDes block index + * @lane: zero-based lane index within SerDes + * @lane_mode: requested SerDes protocol + * + * Should be called before actually requesting the RCW override procedure to be + * applied using %fsl_guts_lane_set_mode() + * + * Return: 0 if RCW override to protocol is possible, negative error otherwise + */ +int fsl_guts_lane_validate(int serdes_idx, int lane, enum lynx_lane_mode lane_mode) +{ + struct fsl_soc_serdes_rcw_override override; + + return fsl_guts_serdes_get_rcw_override(serdes_idx, lane, lane_mode, + &override); +} +EXPORT_SYMBOL_NS_GPL(fsl_guts_lane_validate, "FSL_GUTS"); + +/** + * fsl_guts_lane_set_mode() - apply RCW override procedure for SerDes lane + * @serdes_idx: one-based SerDes block index + * @lane: zero-based lane index within SerDes + * @lane_mode: requested SerDes protocol + * + * Return: 0 on success, negative error otherwise + */ +int fsl_guts_lane_set_mode(int serdes_idx, int lane, enum lynx_lane_mode lane_mode) +{ + struct fsl_soc_serdes_rcw_override override; + int err; + + err = fsl_guts_serdes_get_rcw_override(serdes_idx, lane, lane_mode, + &override); + if (err) + return err; + + spin_lock(&soc.rcwcr_lock); + + if (soc.data->serdes_init_rcwcr) { + err = soc.data->serdes_init_rcwcr(serdes_idx); + if (err) + goto out_unlock; + } + + err = fsl_guts_rcw_rmw(override.offset, + override.val << __ffs(override.mask), + override.mask); + if (err) + pr_err("RCW override failed: %pe\n", ERR_PTR(err)); + +out_unlock: + spin_unlock(&soc.rcwcr_lock); + + return err; +} +EXPORT_SYMBOL_NS_GPL(fsl_guts_lane_set_mode, "FSL_GUTS"); + static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset) { struct device_node *np; @@ -141,9 +395,188 @@ static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset) return uid; } +static int ls1046a_serdes_get_rcw_override(int index, int lane, + enum lynx_lane_mode lane_mode, + struct fsl_soc_serdes_rcw_override *override) +{ + /* The RCW override procedure has to write to different registers + * depending on the SerDes block index. + */ + switch (index) { + case 1: + override->offset = 4; + override->mask = LS1046A_RCWSR5_SRDS_PRTCL_S1(lane); + break; + default: + return -EINVAL; + } + + if (lynx_lane_mode_uses_xgmii_mac(lane_mode)) + override->val = LS1046A_SRDS_PRTCL_XFI; + else if (lynx_lane_mode_uses_gmii_mac(lane_mode)) + override->val = LS1046A_SRDS_PRTCL_100BASEX_SGMII; + else + return -EINVAL; + + return 0; +} + +static int ls1088a_serdes_get_rcw_override(int index, int lane, + enum lynx_lane_mode lane_mode, + struct fsl_soc_serdes_rcw_override *override) +{ + /* The RCW override procedure has to write to different registers + * depending on the SerDes block index. + */ + switch (index) { + case 1: + override->offset = 28; + override->mask = LS1088A_RCWSR29_SRDS_PRTCL_S1_LNn(lane); + break; + case 2: + override->offset = 29; + override->mask = LS1088A_RCWSR30_SRDS_PRTCL_S2_LNn(lane); + break; + default: + return -EINVAL; + } + + if (lynx_lane_mode_uses_xgmii_mac(lane_mode)) + override->val = LS1088A_SRDS_PRTCL_XFI; + else if (lynx_lane_mode_uses_gmii_mac(lane_mode)) + override->val = LS1088A_SRDS_PRTCL_100BASEX_SGMII; + else + return -EINVAL; + + return 0; +} + +static const struct rcw_full_srds_proto *ls2088a_get_full_serdes1_proto(void) +{ + u32 rcwsr29 = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[28]); + u32 srds_prtcl_s1 = FIELD_GET(LS2088A_RCWSR29_SRDS_PRTCL_S1, rcwsr29); + + for (int i = 0; i < ARRAY_SIZE(ls2088a_rcw_full_srds1_protos); i++) { + const struct rcw_full_srds_proto *proto; + + proto = &ls2088a_rcw_full_srds1_protos[i]; + if (proto->srds_proto_val == srds_prtcl_s1) + return proto; + } + + return NULL; +} + +static int ls2088a_serdes_get_rcw_override(int index, int lane, + enum lynx_lane_mode lane_mode, + struct fsl_soc_serdes_rcw_override *override) +{ + switch (index) { + case 1: + override->offset = 29; + override->mask = LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(lane); + break; + default: + return -EINVAL; + } + + /* RCW override only supported if we know how to handle the initial + * RCWSR29[SRDS_PRTCL_S1] value and turn it into an override. + */ + if (!ls2088a_get_full_serdes1_proto()) { + u32 rcwsr30 = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[29]); + + /* If a SerDes-level override is already in place (probably + * left there by a previous boot stage), use it. + */ + if (!(rcwsr30 & LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1)) + return -EINVAL; + } + + if (lynx_lane_mode_uses_xgmii_mac(lane_mode)) + override->val = LS2088A_SRDS_CLK_SEL_XGMII; + else if (lynx_lane_mode_uses_gmii_mac(lane_mode)) + override->val = LS2088A_SRDS_CLK_SEL_GMII; + else + return -EINVAL; + + return 0; +} + +static int ls2088a_serdes_init_rcwcr(int serdes_idx) +{ + const struct rcw_full_srds_proto *srds_prtcl_s1; + const struct fsl_soc_data *soc_data = soc.data; + u32 rcwsr30; + int i, err; + + /* SerDes 2 supports only SGMII for networking. There should be + * no need for RCW override + */ + if (serdes_idx != 1) + return -EINVAL; + + /* SRDS_CLK_EN_SEL_XGMII_S1: SerDes Clock Enable Select XGMII Serdes 1: + * Enables to select GMII/XGMII clock according to + * SRDS_CLK_SEL_XGMII_Ln_S1. + * If the GMII/XGMII select override has already been set, use it. + * Otherwise, derive an initial override for all lanes based on the + * full SerDes protocol table. + */ + rcwsr30 = fsl_guts_read(&soc.dcfg_ccsr->rcwsr[29]); + if (rcwsr30 & LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1) { + pr_debug("RCWSR30 = 0x%x, using this.\n", rcwsr30); + return 0; + } + + srds_prtcl_s1 = ls2088a_get_full_serdes1_proto(); + + rcwsr30 = LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1; + + /* We need to configure the initial state of all lanes for + * the SerDes block #1 + */ + for_each_set_bit(i, &srds_prtcl_s1->xgmii_lanes, soc_data->num_serdes_lanes) + rcwsr30 |= LS2088A_RCWSR30_SRDS_CLK_SEL_XGMII_Ln_S1(i); + + pr_debug("Setting initial RCWSR30 = 0x%x based on SRDS_PRTCL_S1 = 0x%x\n", + rcwsr30, srds_prtcl_s1->srds_proto_val); + + err = fsl_guts_rcw_rmw(29, rcwsr30, + LS2088A_RCWSR30_SRDS_CLK_EN_SEL_XGMII_S1 | + LS2088A_RCWSR30_SRDS_CLK_SEL_MSK); + if (err) { + pr_err("Setting up initial RCWCR failed: %pe\n", ERR_PTR(err)); + return err; + } + + return 0; +} + +static const struct fsl_soc_data ls1088a_data = { + .serdes_get_rcw_override = ls1088a_serdes_get_rcw_override, + .num_serdes_blocks = 2, + .num_serdes_lanes = 4, +}; + +static const struct fsl_soc_data ls1046a_data = { + .serdes_get_rcw_override = ls1046a_serdes_get_rcw_override, + .num_serdes_blocks = 2, + .num_serdes_lanes = 4, +}; + +static const struct fsl_soc_data ls2088a_data = { + .serdes_get_rcw_override = ls2088a_serdes_get_rcw_override, + .serdes_init_rcwcr = ls2088a_serdes_init_rcwcr, + .num_serdes_blocks = 2, + .num_serdes_lanes = 8, +}; + static const struct fsl_soc_data ls1028a_data = { .sfp_compat = "fsl,ls1028a-sfp", .uid_offset = 0x21c, + .num_serdes_blocks = 1, + .num_serdes_lanes = 4, }; /* @@ -169,10 +602,10 @@ static const struct of_device_id fsl_guts_of_match[] = { { .compatible = "fsl,mpc8572-guts", }, { .compatible = "fsl,ls1021a-dcfg", }, { .compatible = "fsl,ls1043a-dcfg", }, - { .compatible = "fsl,ls2080a-dcfg", }, - { .compatible = "fsl,ls1088a-dcfg", }, + { .compatible = "fsl,ls2080a-dcfg", .data = &ls2088a_data}, + { .compatible = "fsl,ls1088a-dcfg", .data = &ls1088a_data}, { .compatible = "fsl,ls1012a-dcfg", }, - { .compatible = "fsl,ls1046a-dcfg", }, + { .compatible = "fsl,ls1046a-dcfg", .data = &ls1046a_data}, { .compatible = "fsl,lx2160a-dcfg", }, { .compatible = "fsl,ls1028a-dcfg", .data = &ls1028a_data}, {} @@ -180,68 +613,73 @@ static const struct of_device_id fsl_guts_of_match[] = { static int __init fsl_guts_init(void) { - struct soc_device_attribute *soc_dev_attr; + struct soc_device_attribute *soc_dev_attr = NULL; static struct soc_device *soc_dev; const struct fsl_soc_die_attr *soc_die; - const struct fsl_soc_data *soc_data; const struct of_device_id *match; - struct ccsr_guts __iomem *regs; struct device_node *np; - bool little_endian; u64 soc_uid = 0; - u32 svr; int ret; + spin_lock_init(&soc.rcwcr_lock); + np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match); if (!np) return 0; - soc_data = match->data; + soc.data = match->data; - regs = of_iomap(np, 0); - if (!regs) { + soc.dcfg_ccsr = of_iomap(np, DCFG_CCSR); + if (!soc.dcfg_ccsr) { of_node_put(np); - return -ENOMEM; + ret = -ENOMEM; + goto err_clear_soc_data; } + /* DCFG_DCSR is optional */ + soc.dcfg_dcsr = of_iomap(np, DCFG_DCSR); - little_endian = of_property_read_bool(np, "little-endian"); - if (little_endian) - svr = ioread32(®s->svr); - else - svr = ioread32be(®s->svr); - iounmap(regs); + soc.little_endian = of_property_read_bool(np, "little-endian"); + soc.svr = fsl_guts_read(&soc.dcfg_ccsr->svr); of_node_put(np); /* Register soc device */ soc_dev_attr = kzalloc_obj(*soc_dev_attr); - if (!soc_dev_attr) - return -ENOMEM; + if (!soc_dev_attr) { + ret = -ENOMEM; + goto err_unmap_dcfg_ccsr_dcsr; + } ret = soc_attr_read_machine(soc_dev_attr); if (ret) of_machine_read_compatible(&soc_dev_attr->machine, 0); - soc_die = fsl_soc_die_match(svr, fsl_soc_die); + soc_die = fsl_soc_die_match(soc.svr, fsl_soc_die); if (soc_die) { soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ %s", soc_die->die); } else { soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ"); } - if (!soc_dev_attr->family) - goto err_nomem; + if (!soc_dev_attr->family) { + ret = -ENOMEM; + goto err_free_soc_dev_attr; + } - soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr); - if (!soc_dev_attr->soc_id) - goto err_nomem; + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", soc.svr); + if (!soc_dev_attr->soc_id) { + ret = -ENOMEM; + goto err_free_family; + } soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d", - (svr >> 4) & 0xf, svr & 0xf); - if (!soc_dev_attr->revision) - goto err_nomem; + (soc.svr >> 4) & 0xf, soc.svr & 0xf); + if (!soc_dev_attr->revision) { + ret = -ENOMEM; + goto err_free_soc_id; + } - if (soc_data) - soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat, - soc_data->uid_offset); + if (soc.data) + soc_uid = fsl_guts_get_soc_uid(soc.data->sfp_compat, + soc.data->uid_offset); if (soc_uid) soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX", soc_uid); @@ -249,7 +687,7 @@ static int __init fsl_guts_init(void) soc_dev = soc_device_register(soc_dev_attr); if (IS_ERR(soc_dev)) { ret = PTR_ERR(soc_dev); - goto err; + goto err_free_serial_number; } pr_info("Machine: %s\n", soc_dev_attr->machine); @@ -259,14 +697,24 @@ static int __init fsl_guts_init(void) return 0; -err_nomem: - ret = -ENOMEM; -err: - kfree(soc_dev_attr->family); - kfree(soc_dev_attr->soc_id); - kfree(soc_dev_attr->revision); +err_free_serial_number: kfree(soc_dev_attr->serial_number); + kfree(soc_dev_attr->revision); +err_free_soc_id: + kfree(soc_dev_attr->soc_id); +err_free_family: + kfree(soc_dev_attr->family); +err_free_soc_dev_attr: kfree(soc_dev_attr); +err_unmap_dcfg_ccsr_dcsr: + if (soc.dcfg_dcsr) { + iounmap(soc.dcfg_dcsr); + soc.dcfg_dcsr = NULL; + } + iounmap(soc.dcfg_ccsr); + soc.dcfg_ccsr = NULL; +err_clear_soc_data: + soc.data = NULL; return ret; } diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig index eb03f42ab978..9e2350551bb1 100644 --- a/drivers/soc/fsl/qe/Kconfig +++ b/drivers/soc/fsl/qe/Kconfig @@ -67,3 +67,13 @@ config QE_USB default y if USB_FSL_QE help QE USB Controller support + +config QE_GPIO + bool "QE GPIO support" + depends on QUICC_ENGINE + depends on !SPARC # Should be OF_IRQ but it leads to circ. dependency + select GENERIC_IRQ_CHIP + select GPIOLIB + help + Say Y here if you're going to use hardware that connects to the + QE GPIOs. diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c index 66828f2a3577..5cd59cfbf22f 100644 --- a/drivers/soc/fsl/qe/gpio.c +++ b/drivers/soc/fsl/qe/gpio.c @@ -16,6 +16,7 @@ #include <linux/gpio/driver.h> #include <linux/slab.h> #include <linux/export.h> +#include <linux/of_irq.h> #include <linux/platform_device.h> #include <soc/fsl/qe/qe.h> @@ -23,6 +24,7 @@ #define PIN_MASK(gpio) (1UL << (QE_PIO_PINS - 1 - (gpio))) struct qe_gpio_chip { + struct device_node *np; struct gpio_chip gc; void __iomem *regs; spinlock_t lock; @@ -135,6 +137,53 @@ static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } +static int qe_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) +{ + struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); + struct qe_pio_regs __iomem *regs = qe_gc->regs; + unsigned long flags; + u32 val, mask; + + spin_lock_irqsave(&qe_gc->lock, flags); + + if (gpio < QE_PIO_PINS / 2) + val = ioread32be(®s->cpdir1); + else + val = ioread32be(®s->cpdir2); + + spin_unlock_irqrestore(&qe_gc->lock, flags); + + mask = (u32)QE_PIO_DIR_OUT << (QE_PIO_PINS - 2 - (gpio % (QE_PIO_PINS / 2)) * 2); + + if (val & mask) + return GPIO_LINE_DIRECTION_OUT; + else + return GPIO_LINE_DIRECTION_IN; +} + +static int qe_gpio_to_irq(struct gpio_chip *gc, unsigned int gpio) +{ + struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); + struct of_phandle_args oirq; + struct irq_domain *domain; + int ret; + + oirq.np = qe_gc->np; + oirq.args_count = 2; + oirq.args[0] = gpio; + oirq.args[1] = 0; + + ret = of_irq_parse_raw(NULL, &oirq); + if (ret) + return ret; + + domain = irq_find_host(oirq.np); + if (!domain) + return -EPROBE_DEFER; + + return irq_create_of_mapping(&oirq); +} + struct qe_pin { /* * The qe_gpio_chip name is unfortunate, we should change that to @@ -299,7 +348,7 @@ static int qe_gpio_probe(struct platform_device *ofdev) qe_gc = devm_kzalloc(dev, sizeof(*qe_gc), GFP_KERNEL); if (!qe_gc) return -ENOMEM; - + qe_gc->np = np; spin_lock_init(&qe_gc->lock); gc = &qe_gc->gc; @@ -308,9 +357,11 @@ static int qe_gpio_probe(struct platform_device *ofdev) gc->ngpio = QE_PIO_PINS; gc->direction_input = qe_gpio_dir_in; gc->direction_output = qe_gpio_dir_out; + gc->get_direction = qe_gpio_get_direction; gc->get = qe_gpio_get; gc->set = qe_gpio_set; gc->set_multiple = qe_gpio_set_multiple; + gc->to_irq = qe_gpio_to_irq; gc->parent = dev; gc->owner = THIS_MODULE; diff --git a/drivers/soc/fsl/qe/qe_ic.c b/drivers/soc/fsl/qe/qe_ic.c index 943911053af6..bccc7d612009 100644 --- a/drivers/soc/fsl/qe/qe_ic.c +++ b/drivers/soc/fsl/qe/qe_ic.c @@ -473,7 +473,6 @@ static struct platform_driver qe_ic_driver = static int __init qe_ic_of_init(void) { - platform_driver_register(&qe_ic_driver); - return 0; + return platform_driver_register(&qe_ic_driver); } subsys_initcall(qe_ic_of_init); diff --git a/drivers/soc/fsl/qe/qe_io.c b/drivers/soc/fsl/qe/qe_io.c index a5e2d0e5ab51..150913fce981 100644 --- a/drivers/soc/fsl/qe/qe_io.c +++ b/drivers/soc/fsl/qe/qe_io.c @@ -15,6 +15,7 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/ioport.h> +#include <linux/of_platform.h> #include <asm/io.h> #include <soc/fsl/qe/qe.h> @@ -184,3 +185,17 @@ int par_io_of_config(struct device_node *np) return 0; } EXPORT_SYMBOL(par_io_of_config); + +static int __init par_io_populate(void) +{ + struct device_node *np = of_find_node_by_type(NULL, "par_io"); + + if (!np) + return 0; + + of_platform_default_populate(np, NULL, NULL); + of_node_put(np); + + return 0; +} +arch_initcall(par_io_populate); diff --git a/drivers/soc/fsl/qe/qe_ports_ic.c b/drivers/soc/fsl/qe/qe_ports_ic.c index 9b0bba64e91e..7375f92f528b 100644 --- a/drivers/soc/fsl/qe/qe_ports_ic.c +++ b/drivers/soc/fsl/qe/qe_ports_ic.c @@ -5,7 +5,9 @@ * Copyright (c) 2025 Christophe Leroy CS GROUP France (christophe.leroy@csgroup.eu) */ +#include <linux/bitops.h> #include <linux/irq.h> +#include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h> #include <linux/platform_device.h> @@ -16,116 +18,158 @@ struct qepic_data { void __iomem *reg; - struct irq_domain *host; - int irq; + int parent_irq; }; static void qepic_mask(struct irq_data *d) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 val; - clrbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d))); + guard(raw_spinlock)(&gc->lock); + + val = ioread32be(gc->reg_base + CEPIMR); + iowrite32be(val & ~d->mask, gc->reg_base + CEPIMR); } static void qepic_unmask(struct irq_data *d) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 val; + + guard(raw_spinlock)(&gc->lock); - setbits32(data->reg + CEPIMR, 1 << (31 - irqd_to_hwirq(d))); + val = ioread32be(gc->reg_base + CEPIMR); + iowrite32be(val | d->mask, gc->reg_base + CEPIMR); } static void qepic_end(struct irq_data *d) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + + iowrite32be(d->mask, gc->reg_base + CEPIER); +} - out_be32(data->reg + CEPIER, 1 << (31 - irqd_to_hwirq(d))); +static void qepic_calc_mask(struct irq_data *d) +{ + d->mask = 1 << (31 - irqd_to_hwirq(d)); } static int qepic_set_type(struct irq_data *d, unsigned int flow_type) { - struct qepic_data *data = irq_data_get_irq_chip_data(d); - unsigned int vec = (unsigned int)irqd_to_hwirq(d); + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + u32 val; + + guard(raw_spinlock)(&gc->lock); + val = ioread32be(gc->reg_base + CEPICR); switch (flow_type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_FALLING: - setbits32(data->reg + CEPICR, 1 << (31 - vec)); + iowrite32be(val | d->mask, gc->reg_base + CEPICR); return 0; case IRQ_TYPE_EDGE_BOTH: case IRQ_TYPE_NONE: - clrbits32(data->reg + CEPICR, 1 << (31 - vec)); + iowrite32be(val & ~d->mask, gc->reg_base + CEPICR); return 0; } return -EINVAL; } -static struct irq_chip qepic = { - .name = "QEPIC", - .irq_mask = qepic_mask, - .irq_unmask = qepic_unmask, - .irq_eoi = qepic_end, - .irq_set_type = qepic_set_type, -}; - -static int qepic_get_irq(struct irq_desc *desc) +static void qepic_cascade(struct irq_desc *desc) { - struct qepic_data *data = irq_desc_get_handler_data(desc); - u32 event = in_be32(data->reg + CEPIER); + struct irq_domain *domain = irq_desc_get_handler_data(desc); + struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned long event, bit; + + chained_irq_enter(chip, desc); + + event = ioread32be(gc->reg_base + CEPIER); + if (!event) { + handle_bad_irq(desc); + goto out; + } - if (!event) - return -1; + for_each_set_bit(bit, &event, 32) + generic_handle_domain_irq(domain, 31 - bit); - return irq_find_mapping(data->host, 32 - ffs(event)); +out: + chained_irq_exit(chip, desc); } -static void qepic_cascade(struct irq_desc *desc) +static int qepic_chip_init(struct irq_chip_generic *gc) { - generic_handle_irq(qepic_get_irq(desc)); + struct qepic_data *data = gc->domain->host_data; + struct irq_chip_type *ct = gc->chip_types; + + gc->reg_base = data->reg; + + ct->chip.irq_mask = qepic_mask; + ct->chip.irq_unmask = qepic_unmask; + ct->chip.irq_eoi = qepic_end; + ct->chip.irq_set_type = qepic_set_type; + ct->chip.irq_calc_mask = qepic_calc_mask; + + return 0; } -static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) +static int qepic_domain_init(struct irq_domain *d) { - irq_set_chip_data(virq, h->host_data); - irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq); + struct qepic_data *data = d->host_data; + + irq_set_chained_handler_and_data(data->parent_irq, qepic_cascade, d); + return 0; } -static const struct irq_domain_ops qepic_host_ops = { - .map = qepic_host_map, -}; - -static void qepic_remove(void *res) +static void qepic_domain_exit(struct irq_domain *d) { - struct qepic_data *data = res; + struct qepic_data *data = d->host_data; - irq_set_chained_handler_and_data(data->irq, NULL, NULL); - irq_domain_remove(data->host); + irq_set_chained_handler_and_data(data->parent_irq, NULL, NULL); } static int qepic_probe(struct platform_device *pdev) { + struct irq_domain_chip_generic_info dgc_info = { + .name = "QEPIC", + .handler = handle_fasteoi_irq, + .irqs_per_chip = 32, + .num_ct = 1, + .init = qepic_chip_init, + }; + struct irq_domain_info d_info = { + .fwnode = of_fwnode_handle(pdev->dev.of_node), + .domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC, + .size = 32, + .hwirq_max = 32, + .ops = &irq_generic_chip_ops, + .dgc_info = &dgc_info, + .init = qepic_domain_init, + .exit = qepic_domain_exit, + }; struct device *dev = &pdev->dev; + struct irq_domain *domain; struct qepic_data *data; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + d_info.host_data = data; data->reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(data->reg)) return PTR_ERR(data->reg); - data->irq = platform_get_irq(pdev, 0); - if (data->irq < 0) - return data->irq; + data->parent_irq = platform_get_irq(pdev, 0); + if (data->parent_irq < 0) + return data->parent_irq; - data->host = irq_domain_create_linear(dev_fwnode(dev), 32, &qepic_host_ops, data); - if (!data->host) - return -ENODEV; - - irq_set_chained_handler_and_data(data->irq, qepic_cascade, data); - - return devm_add_action_or_reset(dev, qepic_remove, data); + domain = devm_irq_domain_instantiate(dev, &d_info); + if (IS_ERR(domain)) + return PTR_ERR(domain); + return 0; } static const struct of_device_id qepic_match[] = { diff --git a/drivers/soc/ixp4xx/ixp4xx-npe.c b/drivers/soc/ixp4xx/ixp4xx-npe.c index 33e2e0366f19..0b3cc471ed62 100644 --- a/drivers/soc/ixp4xx/ixp4xx-npe.c +++ b/drivers/soc/ixp4xx/ixp4xx-npe.c @@ -752,6 +752,7 @@ static const struct of_device_id ixp4xx_npe_of_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, ixp4xx_npe_of_match); static struct platform_driver ixp4xx_npe_driver = { .driver = { diff --git a/drivers/soc/ixp4xx/ixp4xx-qmgr.c b/drivers/soc/ixp4xx/ixp4xx-qmgr.c index 475e229039e3..492a31660535 100644 --- a/drivers/soc/ixp4xx/ixp4xx-qmgr.c +++ b/drivers/soc/ixp4xx/ixp4xx-qmgr.c @@ -421,19 +421,13 @@ static int ixp4xx_qmgr_probe(struct platform_device *pdev) err = devm_request_irq(dev, irq1, handler1, 0, "IXP4xx Queue Manager", NULL); - if (err) { - dev_err(dev, "failed to request IRQ%i (%i)\n", - irq1, err); + if (err) return err; - } err = devm_request_irq(dev, irq2, handler2, 0, "IXP4xx Queue Manager", NULL); - if (err) { - dev_err(dev, "failed to request IRQ%i (%i)\n", - irq2, err); + if (err) return err; - } used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */ spin_lock_init(&qmgr_lock); @@ -454,6 +448,7 @@ static const struct of_device_id ixp4xx_qmgr_of_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, ixp4xx_qmgr_of_match); static struct platform_driver ixp4xx_qmgr_driver = { .driver = { diff --git a/drivers/soc/mediatek/mt8167-mmsys.h b/drivers/soc/mediatek/mt8167-mmsys.h index eef14083c47b..001379373507 100644 --- a/drivers/soc/mediatek/mt8167-mmsys.h +++ b/drivers/soc/mediatek/mt8167-mmsys.h @@ -19,19 +19,19 @@ #define MT8167_DSI0_SEL_IN_MASK 0x3 static const struct mtk_mmsys_routes mt8167_mmsys_routing_table[] = { - MMSYS_ROUTE(OVL0, COLOR0, + MMSYS_ROUTE(OVL, 0, COLOR, 0, MT8167_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0, OVL0_MOUT_EN_COLOR0), - MMSYS_ROUTE(DITHER0, RDMA0, + MMSYS_ROUTE(DITHER, 0, RDMA, 0, MT8167_DISP_REG_CONFIG_DISP_DITHER_MOUT_EN, MT8167_DITHER_MOUT_EN_MASK, MT8167_DITHER_MOUT_EN_RDMA0), - MMSYS_ROUTE(OVL0, COLOR0, + MMSYS_ROUTE(OVL, 0, COLOR, 0, MT8167_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0, COLOR0_SEL_IN_OVL0), - MMSYS_ROUTE(RDMA0, DSI0, + MMSYS_ROUTE(RDMA, 0, DSI, 0, MT8167_DISP_REG_CONFIG_DISP_DSI0_SEL_IN, MT8167_DSI0_SEL_IN_MASK, MT8167_DSI0_SEL_IN_RDMA0), - MMSYS_ROUTE(RDMA0, DSI0, + MMSYS_ROUTE(RDMA, 0, DSI, 0, MT8167_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8167_RDMA0_SOUT_MASK, MT8167_RDMA0_SOUT_DSI0), }; diff --git a/drivers/soc/mediatek/mt8173-mmsys.h b/drivers/soc/mediatek/mt8173-mmsys.h index 957876d7c166..af67879ff8b4 100644 --- a/drivers/soc/mediatek/mt8173-mmsys.h +++ b/drivers/soc/mediatek/mt8173-mmsys.h @@ -33,46 +33,46 @@ #define MT8173_RDMA0_SOUT_COLOR0 BIT(0) static const struct mtk_mmsys_routes mt8173_mmsys_routing_table[] = { - MMSYS_ROUTE(OVL0, COLOR0, + MMSYS_ROUTE(OVL, 0, COLOR, 0, MT8173_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, MT8173_OVL0_MOUT_EN_COLOR0, MT8173_OVL0_MOUT_EN_COLOR0), - MMSYS_ROUTE(OD0, RDMA0, + MMSYS_ROUTE(OD, 0, RDMA, 0, MT8173_DISP_REG_CONFIG_DISP_OD_MOUT_EN, MT8173_OD0_MOUT_EN_RDMA0, MT8173_OD0_MOUT_EN_RDMA0), - MMSYS_ROUTE(UFOE, DSI0, + MMSYS_ROUTE(UFOE, 0, DSI, 0, MT8173_DISP_REG_CONFIG_DISP_UFOE_MOUT_EN, MT8173_UFOE_MOUT_EN_DSI0, MT8173_UFOE_MOUT_EN_DSI0), - MMSYS_ROUTE(COLOR0, AAL0, + MMSYS_ROUTE(COLOR, 0, AAL, 0, MT8173_DISP_REG_CONFIG_DISP_COLOR0_SOUT_SEL_IN, MT8173_COLOR0_SOUT_MERGE, 0 /* SOUT to AAL */), - MMSYS_ROUTE(RDMA0, UFOE, + MMSYS_ROUTE(RDMA, 0, UFOE, 0, MT8173_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL_IN, MT8173_RDMA0_SOUT_COLOR0, 0 /* SOUT to UFOE */), - MMSYS_ROUTE(OVL0, COLOR0, + MMSYS_ROUTE(OVL, 0, COLOR, 0, MT8173_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, MT8173_COLOR0_SEL_IN_OVL0, MT8173_COLOR0_SEL_IN_OVL0), - MMSYS_ROUTE(AAL0, COLOR0, + MMSYS_ROUTE(AAL, 0, COLOR, 0, MT8173_DISP_REG_CONFIG_DISP_AAL_SEL_IN, MT8173_AAL_SEL_IN_MERGE, 0 /* SEL_IN from COLOR0 */), - MMSYS_ROUTE(RDMA0, UFOE, + MMSYS_ROUTE(RDMA, 0, UFOE, 0, MT8173_DISP_REG_CONFIG_DISP_UFOE_SEL_IN, MT8173_UFOE_SEL_IN_RDMA0, 0 /* SEL_IN from RDMA0 */), - MMSYS_ROUTE(UFOE, DSI0, + MMSYS_ROUTE(UFOE, 0, DSI, 0, MT8173_DISP_REG_CONFIG_DSI0_SEL_IN, MT8173_DSI0_SEL_IN_UFOE, 0 /* SEL_IN from UFOE */), - MMSYS_ROUTE(OVL1, COLOR1, + MMSYS_ROUTE(OVL, 1, COLOR, 1, MT8173_DISP_REG_CONFIG_DISP_OVL1_MOUT_EN, MT8173_OVL1_MOUT_EN_COLOR1, MT8173_OVL1_MOUT_EN_COLOR1), - MMSYS_ROUTE(GAMMA, RDMA1, + MMSYS_ROUTE(GAMMA, 0, RDMA, 1, MT8173_DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN, MT8173_GAMMA_MOUT_EN_RDMA1, MT8173_GAMMA_MOUT_EN_RDMA1), - MMSYS_ROUTE(RDMA1, DPI0, + MMSYS_ROUTE(RDMA, 1, DPI, 0, MT8173_DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK, RDMA1_SOUT_DPI0), - MMSYS_ROUTE(OVL1, COLOR1, + MMSYS_ROUTE(OVL, 1, COLOR, 1, MT8173_DISP_REG_CONFIG_DISP_COLOR1_SEL_IN, COLOR1_SEL_IN_OVL1, COLOR1_SEL_IN_OVL1), - MMSYS_ROUTE(RDMA1, DPI0, + MMSYS_ROUTE(RDMA, 1, DPI, 0, MT8173_DISP_REG_CONFIG_DPI_SEL_IN, MT8173_DPI0_SEL_IN_MASK, MT8173_DPI0_SEL_IN_RDMA1), }; diff --git a/drivers/soc/mediatek/mt8183-mmsys.h b/drivers/soc/mediatek/mt8183-mmsys.h index 123384958c4b..cf221ef203d2 100644 --- a/drivers/soc/mediatek/mt8183-mmsys.h +++ b/drivers/soc/mediatek/mt8183-mmsys.h @@ -28,25 +28,25 @@ #define MT8183_MMSYS_SW0_RST_B 0x140 static const struct mtk_mmsys_routes mmsys_mt8183_routing_table[] = { - MMSYS_ROUTE(OVL0, OVL_2L0, + MMSYS_ROUTE(OVL, 0, OVL_2L, 0, MT8183_DISP_OVL0_MOUT_EN, MT8183_OVL0_MOUT_EN_OVL0_2L, MT8183_OVL0_MOUT_EN_OVL0_2L), - MMSYS_ROUTE(OVL_2L0, RDMA0, + MMSYS_ROUTE(OVL_2L, 0, RDMA, 0, MT8183_DISP_OVL0_2L_MOUT_EN, MT8183_OVL0_2L_MOUT_EN_DISP_PATH0, MT8183_OVL0_2L_MOUT_EN_DISP_PATH0), - MMSYS_ROUTE(OVL_2L1, RDMA1, + MMSYS_ROUTE(OVL_2L, 1, RDMA, 1, MT8183_DISP_OVL1_2L_MOUT_EN, MT8183_OVL1_2L_MOUT_EN_RDMA1, MT8183_OVL1_2L_MOUT_EN_RDMA1), - MMSYS_ROUTE(DITHER0, DSI0, + MMSYS_ROUTE(DITHER, 0, DSI, 0, MT8183_DISP_DITHER0_MOUT_EN, MT8183_DITHER0_MOUT_IN_DSI0, MT8183_DITHER0_MOUT_IN_DSI0), - MMSYS_ROUTE(OVL_2L0, RDMA0, + MMSYS_ROUTE(OVL_2L, 0, RDMA, 0, MT8183_DISP_PATH0_SEL_IN, MT8183_DISP_PATH0_SEL_IN_OVL0_2L, MT8183_DISP_PATH0_SEL_IN_OVL0_2L), - MMSYS_ROUTE(RDMA1, DPI0, + MMSYS_ROUTE(RDMA, 1, DPI, 0, MT8183_DISP_DPI0_SEL_IN, MT8183_DPI0_SEL_IN_RDMA1, MT8183_DPI0_SEL_IN_RDMA1), - MMSYS_ROUTE(RDMA0, COLOR0, + MMSYS_ROUTE(RDMA, 0, COLOR, 0, MT8183_DISP_RDMA0_SOUT_SEL_IN, MT8183_RDMA0_SOUT_COLOR0, MT8183_RDMA0_SOUT_COLOR0), }; diff --git a/drivers/soc/mediatek/mt8186-mmsys.h b/drivers/soc/mediatek/mt8186-mmsys.h index 354664be72bd..0c6941be6fa5 100644 --- a/drivers/soc/mediatek/mt8186-mmsys.h +++ b/drivers/soc/mediatek/mt8186-mmsys.h @@ -63,37 +63,37 @@ #define MT8186_MMSYS_SW0_RST_B 0x160 static const struct mtk_mmsys_routes mmsys_mt8186_routing_table[] = { - MMSYS_ROUTE(OVL0, RDMA0, + MMSYS_ROUTE(OVL, 0, RDMA, 0, MT8186_DISP_OVL0_MOUT_EN, MT8186_OVL0_MOUT_EN_MASK, MT8186_OVL0_MOUT_TO_RDMA0), - MMSYS_ROUTE(OVL0, RDMA0, + MMSYS_ROUTE(OVL, 0, RDMA, 0, MT8186_DISP_RDMA0_SEL_IN, MT8186_RDMA0_SEL_IN_MASK, MT8186_RDMA0_FROM_OVL0), - MMSYS_ROUTE(OVL0, RDMA0, + MMSYS_ROUTE(OVL, 0, RDMA, 0, MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_CON_MASK, MT8186_OVL0_GO_BLEND), - MMSYS_ROUTE(RDMA0, COLOR0, + MMSYS_ROUTE(RDMA, 0, COLOR, 0, MT8186_DISP_RDMA0_SOUT_SEL, MT8186_RDMA0_SOUT_SEL_MASK, MT8186_RDMA0_SOUT_TO_COLOR0), - MMSYS_ROUTE(DITHER0, DSI0, + MMSYS_ROUTE(DITHER, 0, DSI, 0, MT8186_DISP_DITHER0_MOUT_EN, MT8186_DITHER0_MOUT_EN_MASK, MT8186_DITHER0_MOUT_TO_DSI0), - MMSYS_ROUTE(DITHER0, DSI0, + MMSYS_ROUTE(DITHER, 0, DSI, 0, MT8186_DISP_DSI0_SEL_IN, MT8186_DSI0_SEL_IN_MASK, MT8186_DSI0_FROM_DITHER0), - MMSYS_ROUTE(OVL_2L0, RDMA1, + MMSYS_ROUTE(OVL_2L, 0, RDMA, 1, MT8186_DISP_OVL0_2L_MOUT_EN, MT8186_OVL0_2L_MOUT_EN_MASK, MT8186_OVL0_2L_MOUT_TO_RDMA1), - MMSYS_ROUTE(OVL_2L0, RDMA1, + MMSYS_ROUTE(OVL_2L, 0, RDMA, 1, MT8186_DISP_RDMA1_SEL_IN, MT8186_RDMA1_SEL_IN_MASK, MT8186_RDMA1_FROM_OVL0_2L), - MMSYS_ROUTE(OVL_2L0, RDMA1, + MMSYS_ROUTE(OVL_2L, 0, RDMA, 1, MT8186_MMSYS_OVL_CON, MT8186_MMSYS_OVL0_2L_CON_MASK, MT8186_OVL0_2L_GO_BLEND), - MMSYS_ROUTE(RDMA1, DPI0, + MMSYS_ROUTE(RDMA, 1, DPI, 0, MT8186_DISP_RDMA1_MOUT_EN, MT8186_RDMA1_MOUT_EN_MASK, MT8186_RDMA1_MOUT_TO_DPI0_SEL), - MMSYS_ROUTE(RDMA1, DPI0, + MMSYS_ROUTE(RDMA, 1, DPI, 0, MT8186_DISP_DPI0_SEL_IN, MT8186_DPI0_SEL_IN_MASK, MT8186_DPI0_FROM_RDMA1), }; diff --git a/drivers/soc/mediatek/mt8188-mmsys.h b/drivers/soc/mediatek/mt8188-mmsys.h index 99080afead7e..c70c4b462381 100644 --- a/drivers/soc/mediatek/mt8188-mmsys.h +++ b/drivers/soc/mediatek/mt8188-mmsys.h @@ -202,124 +202,124 @@ static const u8 mmsys_mt8188_vdo1_rst_tb[] = { }; static const struct mtk_mmsys_routes mmsys_mt8188_routing_table[] = { - MMSYS_ROUTE(OVL0, RDMA0, + MMSYS_ROUTE(OVL, 0, RDMA, 0, MT8188_VDO0_OVL_MOUT_EN, MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0, MT8188_MOUT_DISP_OVL0_TO_DISP_RDMA0), - MMSYS_ROUTE(OVL0, WDMA0, + MMSYS_ROUTE(OVL, 0, WDMA, 0, MT8188_VDO0_OVL_MOUT_EN, MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0, MT8188_MOUT_DISP_OVL0_TO_DISP_WDMA0), - MMSYS_ROUTE(OVL0, RDMA0, + MMSYS_ROUTE(OVL, 0, RDMA, 0, MT8188_VDO0_DISP_RDMA_SEL, MT8188_SEL_IN_DISP_RDMA0_FROM_MASK, MT8188_SEL_IN_DISP_RDMA0_FROM_DISP_OVL0), - MMSYS_ROUTE(DITHER0, DSI0, + MMSYS_ROUTE(DITHER, 0, DSI, 0, MT8188_VDO0_DSI0_SEL_IN, MT8188_SEL_IN_DSI0_FROM_MASK, MT8188_SEL_IN_DSI0_FROM_DISP_DITHER0), - MMSYS_ROUTE(DITHER0, MERGE0, + MMSYS_ROUTE(DITHER, 0, MERGE, 0, MT8188_VDO0_VPP_MERGE_SEL, MT8188_SEL_IN_VPP_MERGE_FROM_MASK, MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0), - MMSYS_ROUTE(DITHER0, DSC0, + MMSYS_ROUTE(DITHER, 0, DSC, 0, MT8188_VDO0_DSC_WARP_SEL, MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_MASK, MT8188_SEL_IN_DSC_WRAP0C0_IN_FROM_DISP_DITHER0), - MMSYS_ROUTE(DITHER0, DP_INTF0, + MMSYS_ROUTE(DITHER, 0, DP_INTF, 0, MT8188_VDO0_DP_INTF0_SEL_IN, MT8188_SEL_IN_DP_INTF0_FROM_MASK, MT8188_SEL_IN_DP_INTF0_FROM_DISP_DITHER0), - MMSYS_ROUTE(DSC0, MERGE0, + MMSYS_ROUTE(DSC, 0, MERGE, 0, MT8188_VDO0_VPP_MERGE_SEL, MT8188_SEL_IN_VPP_MERGE_FROM_MASK, MT8188_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT), - MMSYS_ROUTE(MERGE0, DP_INTF0, + MMSYS_ROUTE(MERGE, 0, DP_INTF, 0, MT8188_VDO0_DP_INTF0_SEL_IN, MT8188_SEL_IN_DP_INTF0_FROM_MASK, MT8188_SEL_IN_DP_INTF0_FROM_VPP_MERGE), - MMSYS_ROUTE(DSC0, DSI0, + MMSYS_ROUTE(DSC, 0, DSI, 0, MT8188_VDO0_DSI0_SEL_IN, MT8188_SEL_IN_DSI0_FROM_MASK, MT8188_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT), - MMSYS_ROUTE(RDMA0, COLOR0, + MMSYS_ROUTE(RDMA, 0, COLOR, 0, MT8188_VDO0_DISP_RDMA_SEL, GENMASK(1, 0), MT8188_SOUT_DISP_RDMA0_TO_DISP_COLOR0), - MMSYS_ROUTE(DITHER0, DSC0, + MMSYS_ROUTE(DITHER, 0, DSC, 0, MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK, MT8188_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN), - MMSYS_ROUTE(DITHER0, DSI0, + MMSYS_ROUTE(DITHER, 0, DSI, 0, MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK, MT8188_SOUT_DISP_DITHER0_TO_DSI0), - MMSYS_ROUTE(DITHER0, MERGE0, + MMSYS_ROUTE(DITHER, 0, MERGE, 0, MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK, MT8188_SOUT_DISP_DITHER0_TO_VPP_MERGE0), - MMSYS_ROUTE(DITHER0, DP_INTF0, + MMSYS_ROUTE(DITHER, 0, DP_INTF, 0, MT8188_VDO0_DISP_DITHER0_SEL_OUT, MT8188_SOUT_DISP_DITHER0_TO_MASK, MT8188_SOUT_DISP_DITHER0_TO_DP_INTF0), - MMSYS_ROUTE(MERGE0, DP_INTF0, + MMSYS_ROUTE(MERGE, 0, DP_INTF, 0, MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK, MT8188_SOUT_VPP_MERGE_TO_DP_INTF0), - MMSYS_ROUTE(MERGE0, DPI0, + MMSYS_ROUTE(MERGE, 0, DPI, 0, MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK, MT8188_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0), - MMSYS_ROUTE(MERGE0, WDMA0, + MMSYS_ROUTE(MERGE, 0, WDMA, 0, MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK, MT8188_SOUT_VPP_MERGE_TO_DISP_WDMA0), - MMSYS_ROUTE(MERGE0, DSC0, + MMSYS_ROUTE(MERGE, 0, DSC, 0, MT8188_VDO0_VPP_MERGE_SEL, MT8188_SOUT_VPP_MERGE_TO_MASK, MT8188_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN), - MMSYS_ROUTE(DSC0, DSI0, + MMSYS_ROUTE(DSC, 0, DSI, 0, MT8188_VDO0_DSC_WARP_SEL, MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK, MT8188_SOUT_DSC_WRAP0_OUT_TO_DSI0), - MMSYS_ROUTE(DSC0, MERGE0, + MMSYS_ROUTE(DSC, 0, MERGE, 0, MT8188_VDO0_DSC_WARP_SEL, MT8188_SOUT_DSC_WRAP0_OUT_TO_MASK, MT8188_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE), }; static const struct mtk_mmsys_routes mmsys_mt8188_vdo1_routing_table[] = { - MMSYS_ROUTE(MDP_RDMA0, MERGE1, + MMSYS_ROUTE(MDP_RDMA, 0, MERGE, 1, MT8188_VDO1_VPP_MERGE0_P0_SEL_IN, GENMASK(0, 0), MT8188_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0), - MMSYS_ROUTE(MDP_RDMA1, MERGE1, + MMSYS_ROUTE(MDP_RDMA, 1, MERGE, 1, MT8188_VDO1_VPP_MERGE0_P1_SEL_IN, GENMASK(0, 0), MT8188_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1), - MMSYS_ROUTE(MDP_RDMA2, MERGE2, + MMSYS_ROUTE(MDP_RDMA, 2, MERGE, 2, MT8188_VDO1_VPP_MERGE1_P0_SEL_IN, GENMASK(0, 0), MT8188_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2), - MMSYS_ROUTE(MERGE1, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 1, ETHDR_MIXER, 0, MT8188_VDO1_MERGE0_ASYNC_SOUT_SEL, GENMASK(1, 0), MT8188_SOUT_TO_MIXER_IN1_SEL), - MMSYS_ROUTE(MERGE2, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 2, ETHDR_MIXER, 0, MT8188_VDO1_MERGE1_ASYNC_SOUT_SEL, GENMASK(1, 0), MT8188_SOUT_TO_MIXER_IN2_SEL), - MMSYS_ROUTE(MERGE3, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 3, ETHDR_MIXER, 0, MT8188_VDO1_MERGE2_ASYNC_SOUT_SEL, GENMASK(1, 0), MT8188_SOUT_TO_MIXER_IN3_SEL), - MMSYS_ROUTE(MERGE4, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 4, ETHDR_MIXER, 0, MT8188_VDO1_MERGE3_ASYNC_SOUT_SEL, GENMASK(1, 0), MT8188_SOUT_TO_MIXER_IN4_SEL), - MMSYS_ROUTE(ETHDR_MIXER, MERGE5, + MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5, MT8188_VDO1_MIXER_OUT_SOUT_SEL, GENMASK(0, 0), MT8188_MIXER_SOUT_TO_MERGE4_ASYNC_SEL), - MMSYS_ROUTE(MERGE1, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 1, ETHDR_MIXER, 0, MT8188_VDO1_MIXER_IN1_SEL_IN, GENMASK(0, 0), MT8188_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT), - MMSYS_ROUTE(MERGE2, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 2, ETHDR_MIXER, 0, MT8188_VDO1_MIXER_IN2_SEL_IN, GENMASK(0, 0), MT8188_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT), - MMSYS_ROUTE(MERGE3, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 3, ETHDR_MIXER, 0, MT8188_VDO1_MIXER_IN3_SEL_IN, GENMASK(0, 0), MT8188_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT), - MMSYS_ROUTE(MERGE4, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 4, ETHDR_MIXER, 0, MT8188_VDO1_MIXER_IN4_SEL_IN, GENMASK(0, 0), MT8188_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT), - MMSYS_ROUTE(ETHDR_MIXER, MERGE5, + MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5, MT8188_VDO1_MIXER_SOUT_SEL_IN, GENMASK(2, 0), MT8188_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER), - MMSYS_ROUTE(ETHDR_MIXER, MERGE5, + MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5, MT8188_VDO1_MERGE4_ASYNC_SEL_IN, GENMASK(2, 0), MT8188_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT), - MMSYS_ROUTE(MERGE5, DPI1, + MMSYS_ROUTE(MERGE, 5, DPI, 1, MT8188_VDO1_DISP_DPI1_SEL_IN, GENMASK(1, 0), MT8188_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT), - MMSYS_ROUTE(MERGE5, DPI1, + MMSYS_ROUTE(MERGE, 5, DPI, 1, MT8188_VDO1_MERGE4_SOUT_SEL, GENMASK(3, 0), MT8188_MERGE4_SOUT_TO_DPI1_SEL), - MMSYS_ROUTE(MERGE5, DP_INTF1, + MMSYS_ROUTE(MERGE, 5, DP_INTF, 1, MT8188_VDO1_DISP_DP_INTF0_SEL_IN, GENMASK(1, 0), MT8188_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT), - MMSYS_ROUTE(MERGE5, DP_INTF1, + MMSYS_ROUTE(MERGE, 5, DP_INTF, 1, MT8188_VDO1_MERGE4_SOUT_SEL, GENMASK(3, 0), MT8188_MERGE4_SOUT_TO_DP_INTF0_SEL), }; diff --git a/drivers/soc/mediatek/mt8192-mmsys.h b/drivers/soc/mediatek/mt8192-mmsys.h index 7cafa2455fd0..37ced5152ba7 100644 --- a/drivers/soc/mediatek/mt8192-mmsys.h +++ b/drivers/soc/mediatek/mt8192-mmsys.h @@ -31,34 +31,34 @@ #define MT8192_DSI0_SEL_IN_DITHER0 0x1 static const struct mtk_mmsys_routes mmsys_mt8192_routing_table[] = { - MMSYS_ROUTE(OVL_2L0, RDMA0, + MMSYS_ROUTE(OVL_2L, 0, RDMA, 0, MT8192_DISP_OVL0_2L_MOUT_EN, MT8192_OVL0_MOUT_EN_DISP_RDMA0, MT8192_OVL0_MOUT_EN_DISP_RDMA0), - MMSYS_ROUTE(OVL_2L2, RDMA4, + MMSYS_ROUTE(OVL_2L, 2, RDMA, 4, MT8192_DISP_OVL2_2L_MOUT_EN, MT8192_OVL2_2L_MOUT_EN_RDMA4, MT8192_OVL2_2L_MOUT_EN_RDMA4), - MMSYS_ROUTE(DITHER0, DSI0, + MMSYS_ROUTE(DITHER, 0, DSI, 0, MT8192_DISP_DITHER0_MOUT_EN, MT8192_DITHER0_MOUT_IN_DSI0, MT8192_DITHER0_MOUT_IN_DSI0), - MMSYS_ROUTE(OVL_2L0, RDMA0, + MMSYS_ROUTE(OVL_2L, 0, RDMA, 0, MT8192_DISP_RDMA0_SEL_IN, MT8192_RDMA0_SEL_IN_OVL0_2L, MT8192_RDMA0_SEL_IN_OVL0_2L), - MMSYS_ROUTE(CCORR, AAL0, + MMSYS_ROUTE(CCORR, 0, AAL, 0, MT8192_DISP_AAL0_SEL_IN, MT8192_AAL0_SEL_IN_CCORR0, MT8192_AAL0_SEL_IN_CCORR0), - MMSYS_ROUTE(DITHER0, DSI0, + MMSYS_ROUTE(DITHER, 0, DSI, 0, MT8192_DISP_DSI0_SEL_IN, MT8192_DSI0_SEL_IN_DITHER0, MT8192_DSI0_SEL_IN_DITHER0), - MMSYS_ROUTE(RDMA0, COLOR0, + MMSYS_ROUTE(RDMA, 0, COLOR, 0, MT8192_DISP_RDMA0_SOUT_SEL, MT8192_RDMA0_SOUT_COLOR0, MT8192_RDMA0_SOUT_COLOR0), - MMSYS_ROUTE(CCORR, AAL0, + MMSYS_ROUTE(CCORR, 0, AAL, 0, MT8192_DISP_CCORR0_SOUT_SEL, MT8192_CCORR0_SOUT_AAL0, MT8192_CCORR0_SOUT_AAL0), - MMSYS_ROUTE(OVL0, OVL_2L0, + MMSYS_ROUTE(OVL, 0, OVL_2L, 0, MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_GO_BG, MT8192_DISP_OVL0_GO_BG), - MMSYS_ROUTE(OVL_2L0, RDMA0, + MMSYS_ROUTE(OVL_2L, 0, RDMA, 0, MT8192_MMSYS_OVL_MOUT_EN, MT8192_DISP_OVL0_2L_GO_BLEND, MT8192_DISP_OVL0_2L_GO_BLEND), }; diff --git a/drivers/soc/mediatek/mt8195-mmsys.h b/drivers/soc/mediatek/mt8195-mmsys.h index f69929a2a4d4..3a58b9b74282 100644 --- a/drivers/soc/mediatek/mt8195-mmsys.h +++ b/drivers/soc/mediatek/mt8195-mmsys.h @@ -160,278 +160,279 @@ #define MT8195_SVPP3_MDP_RSZ BIT(5) static const struct mtk_mmsys_routes mmsys_mt8195_routing_table[] = { - MMSYS_ROUTE(OVL0, RDMA0, + MMSYS_ROUTE(OVL, 0, RDMA, 0, MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0, MT8195_MOUT_DISP_OVL0_TO_DISP_RDMA0), - MMSYS_ROUTE(OVL0, WDMA0, + MMSYS_ROUTE(OVL, 0, WDMA, 0, MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0, MT8195_MOUT_DISP_OVL0_TO_DISP_WDMA0), - MMSYS_ROUTE(OVL0, OVL1, + MMSYS_ROUTE(OVL, 0, OVL, 1, MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1, MT8195_MOUT_DISP_OVL0_TO_DISP_OVL1), - MMSYS_ROUTE(OVL1, RDMA1, + MMSYS_ROUTE(OVL, 1, RDMA, 1, MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1, MT8195_MOUT_DISP_OVL1_TO_DISP_RDMA1), - MMSYS_ROUTE(OVL1, WDMA1, + MMSYS_ROUTE(OVL, 1, WDMA, 1, MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1, MT8195_MOUT_DISP_OVL1_TO_DISP_WDMA1), - MMSYS_ROUTE(OVL1, OVL0, + MMSYS_ROUTE(OVL, 1, OVL, 0, MT8195_VDO0_OVL_MOUT_EN, MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0, MT8195_MOUT_DISP_OVL1_TO_DISP_OVL0), - MMSYS_ROUTE(DSC0, MERGE0, + MMSYS_ROUTE(DSC, 0, MERGE, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK, MT8195_SEL_IN_VPP_MERGE_FROM_DSC_WRAP0_OUT), - MMSYS_ROUTE(DITHER1, MERGE0, + MMSYS_ROUTE(DITHER, 1, MERGE, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK, MT8195_SEL_IN_VPP_MERGE_FROM_DISP_DITHER1), - MMSYS_ROUTE(MERGE5, MERGE0, + MMSYS_ROUTE(MERGE, 5, MERGE, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_VPP_MERGE_FROM_MASK, MT8195_SEL_IN_VPP_MERGE_FROM_VDO1_VIRTUAL0), - MMSYS_ROUTE(DITHER0, DSC0, + MMSYS_ROUTE(DITHER, 0, DSC, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_DISP_DITHER0), - MMSYS_ROUTE(MERGE0, DSC0, + MMSYS_ROUTE(MERGE, 0, DSC, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_MASK, MT8195_SEL_IN_DSC_WRAP0_IN_FROM_VPP_MERGE), - MMSYS_ROUTE(DITHER1, DSC1, + MMSYS_ROUTE(DITHER, 1, DSC, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_DISP_DITHER1), - MMSYS_ROUTE(MERGE0, DSC1, + MMSYS_ROUTE(MERGE, 0, DSC, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_IN_FROM_VPP_MERGE), - MMSYS_ROUTE(MERGE0, DP_INTF1, + MMSYS_ROUTE(MERGE, 0, DP_INTF, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE), - MMSYS_ROUTE(MERGE0, DPI0, + MMSYS_ROUTE(MERGE, 0, DPI, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE), - MMSYS_ROUTE(MERGE0, DPI1, + MMSYS_ROUTE(MERGE, 0, DPI, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_VPP_MERGE), - MMSYS_ROUTE(DSC1, DP_INTF1, + MMSYS_ROUTE(DSC, 1, DP_INTF, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT), - MMSYS_ROUTE(DSC1, DPI0, + MMSYS_ROUTE(DSC, 1, DPI, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT), - MMSYS_ROUTE(DSC1, DPI1, + MMSYS_ROUTE(DSC, 1, DPI, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_MASK, MT8195_SEL_IN_SINA_VIRTUAL0_FROM_DSC_WRAP1_OUT), - MMSYS_ROUTE(DSC0, DP_INTF1, + MMSYS_ROUTE(DSC, 0, DP_INTF, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT), - MMSYS_ROUTE(DSC0, DPI0, + MMSYS_ROUTE(DSC, 0, DPI, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT), - MMSYS_ROUTE(DSC0, DPI1, + MMSYS_ROUTE(DSC, 0, DPI, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_MASK, MT8195_SEL_IN_SINB_VIRTUAL0_FROM_DSC_WRAP0_OUT), - MMSYS_ROUTE(DSC1, DP_INTF0, + MMSYS_ROUTE(DSC, 1, DP_INTF, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK, MT8195_SEL_IN_DP_INTF0_FROM_DSC_WRAP1_OUT), - MMSYS_ROUTE(MERGE0, DP_INTF0, + MMSYS_ROUTE(MERGE, 0, DP_INTF, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK, MT8195_SEL_IN_DP_INTF0_FROM_VPP_MERGE), - MMSYS_ROUTE(MERGE5, DP_INTF0, + MMSYS_ROUTE(MERGE, 5, DP_INTF, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DP_INTF0_FROM_MASK, MT8195_SEL_IN_DP_INTF0_FROM_VDO1_VIRTUAL0), - MMSYS_ROUTE(DSC0, DSI0, + MMSYS_ROUTE(DSC, 0, DSI, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK, MT8195_SEL_IN_DSI0_FROM_DSC_WRAP0_OUT), - MMSYS_ROUTE(DITHER0, DSI0, + MMSYS_ROUTE(DITHER, 0, DSI, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI0_FROM_MASK, MT8195_SEL_IN_DSI0_FROM_DISP_DITHER0), - MMSYS_ROUTE(DSC1, DSI1, + MMSYS_ROUTE(DSC, 1, DSI, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK, MT8195_SEL_IN_DSI1_FROM_DSC_WRAP1_OUT), - MMSYS_ROUTE(MERGE0, DSI1, + MMSYS_ROUTE(MERGE, 0, DSI, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSI1_FROM_MASK, MT8195_SEL_IN_DSI1_FROM_VPP_MERGE), - MMSYS_ROUTE(OVL1, WDMA1, + MMSYS_ROUTE(OVL, 1, WDMA, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK, MT8195_SEL_IN_DISP_WDMA1_FROM_DISP_OVL1), - MMSYS_ROUTE(MERGE0, WDMA1, + MMSYS_ROUTE(MERGE, 0, WDMA, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA1_FROM_MASK, MT8195_SEL_IN_DISP_WDMA1_FROM_VPP_MERGE), - MMSYS_ROUTE(DSC1, DSI1, + MMSYS_ROUTE(DSC, 1, DSI, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN), - MMSYS_ROUTE(DSC1, DP_INTF0, + MMSYS_ROUTE(DSC, 1, DP_INTF, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN), - MMSYS_ROUTE(DSC1, DP_INTF1, + MMSYS_ROUTE(DSC, 1, DP_INTF, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN), - MMSYS_ROUTE(DSC1, DPI0, + MMSYS_ROUTE(DSC, 1, DPI, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN), - MMSYS_ROUTE(DSC1, DPI1, + MMSYS_ROUTE(DSC, 1, DPI, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN), - MMSYS_ROUTE(DSC1, MERGE0, + MMSYS_ROUTE(DSC, 1, MERGE, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DSC_WRAP1_IN), - MMSYS_ROUTE(DITHER1, DSI1, + MMSYS_ROUTE(DITHER, 1, DSI, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1), - MMSYS_ROUTE(DITHER1, DP_INTF0, + MMSYS_ROUTE(DITHER, 1, DP_INTF, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1), - MMSYS_ROUTE(DITHER1, DPI0, + MMSYS_ROUTE(DITHER, 1, DPI, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1), - MMSYS_ROUTE(DITHER1, DPI1, + MMSYS_ROUTE(DITHER, 1, DPI, 1, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DSC_WRAP1_FROM_MASK, MT8195_SEL_IN_DSC_WRAP1_OUT_FROM_DISP_DITHER1), - MMSYS_ROUTE(OVL0, WDMA0, + MMSYS_ROUTE(OVL, 0, WDMA, 0, MT8195_VDO0_SEL_IN, MT8195_SEL_IN_DISP_WDMA0_FROM_MASK, MT8195_SEL_IN_DISP_WDMA0_FROM_DISP_OVL0), - MMSYS_ROUTE(DITHER0, DSC0, + MMSYS_ROUTE(DITHER, 0, DSC, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK, MT8195_SOUT_DISP_DITHER0_TO_DSC_WRAP0_IN), - MMSYS_ROUTE(DITHER0, DSI0, + MMSYS_ROUTE(DITHER, 0, DSI, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER0_TO_MASK, MT8195_SOUT_DISP_DITHER0_TO_DSI0), - MMSYS_ROUTE(DITHER1, DSC1, + MMSYS_ROUTE(DITHER, 1, DSC, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK, MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_IN), - MMSYS_ROUTE(DITHER1, MERGE0, + MMSYS_ROUTE(DITHER, 1, MERGE, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK, MT8195_SOUT_DISP_DITHER1_TO_VPP_MERGE), - MMSYS_ROUTE(DITHER1, DSI1, + MMSYS_ROUTE(DITHER, 1, DSI, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK, MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT), - MMSYS_ROUTE(DITHER1, DP_INTF0, + MMSYS_ROUTE(DITHER, 1, DP_INTF, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK, MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT), - MMSYS_ROUTE(DITHER1, DP_INTF1, + MMSYS_ROUTE(DITHER, 1, DP_INTF, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK, MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT), - MMSYS_ROUTE(DITHER1, DPI0, + MMSYS_ROUTE(DITHER, 1, DPI, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK, MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT), - MMSYS_ROUTE(DITHER1, DPI1, + MMSYS_ROUTE(DITHER, 1, DPI, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DISP_DITHER1_TO_MASK, MT8195_SOUT_DISP_DITHER1_TO_DSC_WRAP1_OUT), - MMSYS_ROUTE(MERGE5, MERGE0, + MMSYS_ROUTE(MERGE, 5, MERGE, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK, MT8195_SOUT_VDO1_VIRTUAL0_TO_VPP_MERGE), - MMSYS_ROUTE(MERGE5, DP_INTF0, + MMSYS_ROUTE(MERGE, 5, DP_INTF, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_VDO1_VIRTUAL0_TO_MASK, MT8195_SOUT_VDO1_VIRTUAL0_TO_DP_INTF0), - MMSYS_ROUTE(MERGE0, DSI1, + MMSYS_ROUTE(MERGE, 0, DSI, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK, MT8195_SOUT_VPP_MERGE_TO_DSI1), - MMSYS_ROUTE(MERGE0, DP_INTF0, + MMSYS_ROUTE(MERGE, 0, DP_INTF, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK, MT8195_SOUT_VPP_MERGE_TO_DP_INTF0), - MMSYS_ROUTE(MERGE0, DP_INTF1, + MMSYS_ROUTE(MERGE, 0, DP_INTF, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK, MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0), - MMSYS_ROUTE(MERGE0, DPI0, + MMSYS_ROUTE(MERGE, 0, DPI, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK, MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0), - MMSYS_ROUTE(MERGE0, DPI1, + MMSYS_ROUTE(MERGE, 0, DPI, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK, MT8195_SOUT_VPP_MERGE_TO_SINA_VIRTUAL0), - MMSYS_ROUTE(MERGE0, WDMA1, + MMSYS_ROUTE(MERGE, 0, WDMA, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK, MT8195_SOUT_VPP_MERGE_TO_DISP_WDMA1), - MMSYS_ROUTE(MERGE0, DSC0, + MMSYS_ROUTE(MERGE, 0, DSC, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_MASK, MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP0_IN), - MMSYS_ROUTE(MERGE0, DSC1, + MMSYS_ROUTE(MERGE, 0, DSC, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN_MASK, MT8195_SOUT_VPP_MERGE_TO_DSC_WRAP1_IN), - MMSYS_ROUTE(DSC0, DSI0, + MMSYS_ROUTE(DSC, 0, DSI, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK, MT8195_SOUT_DSC_WRAP0_OUT_TO_DSI0), - MMSYS_ROUTE(DSC0, DP_INTF1, + MMSYS_ROUTE(DSC, 0, DP_INTF, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK, MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0), - MMSYS_ROUTE(DSC0, DPI0, + MMSYS_ROUTE(DSC, 0, DPI, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK, MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0), - MMSYS_ROUTE(DSC0, DPI1, + MMSYS_ROUTE(DSC, 0, DPI, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK, MT8195_SOUT_DSC_WRAP0_OUT_TO_SINB_VIRTUAL0), - MMSYS_ROUTE(DSC0, MERGE0, + MMSYS_ROUTE(DSC, 0, MERGE, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP0_OUT_TO_MASK, MT8195_SOUT_DSC_WRAP0_OUT_TO_VPP_MERGE), - MMSYS_ROUTE(DSC1, DSI1, + MMSYS_ROUTE(DSC, 1, DSI, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK, MT8195_SOUT_DSC_WRAP1_OUT_TO_DSI1), - MMSYS_ROUTE(DSC1, DP_INTF0, + MMSYS_ROUTE(DSC, 1, DP_INTF, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK, MT8195_SOUT_DSC_WRAP1_OUT_TO_DP_INTF0), - MMSYS_ROUTE(DSC1, DP_INTF1, + MMSYS_ROUTE(DSC, 1, DP_INTF, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK, MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0), - MMSYS_ROUTE(DSC1, DPI0, + MMSYS_ROUTE(DSC, 1, DPI, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK, MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0), - MMSYS_ROUTE(DSC1, DPI1, + MMSYS_ROUTE(DSC, 1, DPI, 1, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK, MT8195_SOUT_DSC_WRAP1_OUT_TO_SINA_VIRTUAL0), - MMSYS_ROUTE(DSC1, MERGE0, + MMSYS_ROUTE(DSC, 1, MERGE, 0, MT8195_VDO0_SEL_OUT, MT8195_SOUT_DSC_WRAP1_OUT_TO_MASK, MT8195_SOUT_DSC_WRAP1_OUT_TO_VPP_MERGE), }; static const struct mtk_mmsys_routes mmsys_mt8195_vdo1_routing_table[] = { - MMSYS_ROUTE(MDP_RDMA0, MERGE1, + MMSYS_ROUTE(MDP_RDMA, 0, MERGE, 1, MT8195_VDO1_VPP_MERGE0_P0_SEL_IN, GENMASK(0, 0), MT8195_VPP_MERGE0_P0_SEL_IN_FROM_MDP_RDMA0), - MMSYS_ROUTE(MDP_RDMA1, MERGE1, + MMSYS_ROUTE(MDP_RDMA, 1, MERGE, 1, MT8195_VDO1_VPP_MERGE0_P1_SEL_IN, GENMASK(0, 0), MT8195_VPP_MERGE0_P1_SEL_IN_FROM_MDP_RDMA1), - MMSYS_ROUTE(MDP_RDMA2, MERGE2, + MMSYS_ROUTE(MDP_RDMA, 2, MERGE, 2, MT8195_VDO1_VPP_MERGE1_P0_SEL_IN, GENMASK(0, 0), MT8195_VPP_MERGE1_P0_SEL_IN_FROM_MDP_RDMA2), - MMSYS_ROUTE(MERGE1, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 1, ETHDR_MIXER, 0, MT8195_VDO1_MERGE0_ASYNC_SOUT_SEL, GENMASK(1, 0), MT8195_SOUT_TO_MIXER_IN1_SEL), - MMSYS_ROUTE(MERGE2, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 2, ETHDR_MIXER, 0, MT8195_VDO1_MERGE1_ASYNC_SOUT_SEL, GENMASK(1, 0), MT8195_SOUT_TO_MIXER_IN2_SEL), - MMSYS_ROUTE(MERGE3, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 3, ETHDR_MIXER, 0, MT8195_VDO1_MERGE2_ASYNC_SOUT_SEL, GENMASK(1, 0), MT8195_SOUT_TO_MIXER_IN3_SEL), - MMSYS_ROUTE(MERGE4, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 4, ETHDR_MIXER, 0, MT8195_VDO1_MERGE3_ASYNC_SOUT_SEL, GENMASK(1, 0), MT8195_SOUT_TO_MIXER_IN4_SEL), - MMSYS_ROUTE(ETHDR_MIXER, MERGE5, + MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5, MT8195_VDO1_MIXER_OUT_SOUT_SEL, GENMASK(0, 0), MT8195_MIXER_SOUT_TO_MERGE4_ASYNC_SEL), - MMSYS_ROUTE(MERGE1, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 1, ETHDR_MIXER, 0, MT8195_VDO1_MIXER_IN1_SEL_IN, GENMASK(0, 0), MT8195_MIXER_IN1_SEL_IN_FROM_MERGE0_ASYNC_SOUT), - MMSYS_ROUTE(MERGE2, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 2, ETHDR_MIXER, 0, MT8195_VDO1_MIXER_IN2_SEL_IN, GENMASK(0, 0), MT8195_MIXER_IN2_SEL_IN_FROM_MERGE1_ASYNC_SOUT), - MMSYS_ROUTE(MERGE3, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 3, ETHDR_MIXER, 0, MT8195_VDO1_MIXER_IN3_SEL_IN, GENMASK(0, 0), MT8195_MIXER_IN3_SEL_IN_FROM_MERGE2_ASYNC_SOUT), - MMSYS_ROUTE(MERGE4, ETHDR_MIXER, + MMSYS_ROUTE(MERGE, 4, ETHDR_MIXER, 0, MT8195_VDO1_MIXER_IN4_SEL_IN, GENMASK(0, 0), MT8195_MIXER_IN4_SEL_IN_FROM_MERGE3_ASYNC_SOUT), - MMSYS_ROUTE(ETHDR_MIXER, MERGE5, + MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5, MT8195_VDO1_MIXER_SOUT_SEL_IN, GENMASK(2, 0), MT8195_MIXER_SOUT_SEL_IN_FROM_DISP_MIXER), - MMSYS_ROUTE(ETHDR_MIXER, MERGE5, + MMSYS_ROUTE(ETHDR_MIXER, 0, MERGE, 5, MT8195_VDO1_MERGE4_ASYNC_SEL_IN, GENMASK(2, 0), MT8195_MERGE4_ASYNC_SEL_IN_FROM_MIXER_OUT_SOUT), - MMSYS_ROUTE(MERGE5, DPI1, + MMSYS_ROUTE(MERGE, 5, DPI, 1, MT8195_VDO1_DISP_DPI1_SEL_IN, GENMASK(1, 0), MT8195_DISP_DPI1_SEL_IN_FROM_VPP_MERGE4_MOUT), - MMSYS_ROUTE(MERGE5, DPI1, + MMSYS_ROUTE(MERGE, 5, DPI, 1, MT8195_VDO1_MERGE4_SOUT_SEL, GENMASK(1, 0), MT8195_MERGE4_SOUT_TO_DPI1_SEL), - MMSYS_ROUTE(MERGE5, DP_INTF1, + MMSYS_ROUTE(MERGE, 5, DP_INTF, 1, MT8195_VDO1_DISP_DP_INTF0_SEL_IN, GENMASK(1, 0), MT8195_DISP_DP_INTF0_SEL_IN_FROM_VPP_MERGE4_MOUT), - MMSYS_ROUTE(MERGE5, DP_INTF1, + MMSYS_ROUTE(MERGE, 5, DP_INTF, 1, MT8195_VDO1_MERGE4_SOUT_SEL, GENMASK(1, 0), MT8195_MERGE4_SOUT_TO_DP_INTF0_SEL), }; + #endif /* __SOC_MEDIATEK_MT8195_MMSYS_H */ diff --git a/drivers/soc/mediatek/mt8365-mmsys.h b/drivers/soc/mediatek/mt8365-mmsys.h index 533a3fd0923b..b438ab7ae00b 100644 --- a/drivers/soc/mediatek/mt8365-mmsys.h +++ b/drivers/soc/mediatek/mt8365-mmsys.h @@ -28,35 +28,35 @@ #define MT8365_DPI0_SEL_IN_RDMA1 0x0 static const struct mtk_mmsys_routes mt8365_mmsys_routing_table[] = { - MMSYS_ROUTE(OVL0, RDMA0, + MMSYS_ROUTE(OVL, 0, RDMA, 0, MT8365_DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, MT8365_DISP_MS_IN_OUT_MASK, MT8365_OVL0_MOUT_PATH0_SEL), - MMSYS_ROUTE(OVL0, RDMA0, + MMSYS_ROUTE(OVL, 0, RDMA, 0, MT8365_DISP_REG_CONFIG_DISP_RDMA0_SEL_IN, MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_SEL_IN_OVL0), - MMSYS_ROUTE(RDMA0, COLOR0, + MMSYS_ROUTE(RDMA, 0, COLOR, 0, MT8365_DISP_REG_CONFIG_DISP_RDMA0_SOUT_SEL, MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_SOUT_COLOR0), - MMSYS_ROUTE(COLOR0, CCORR, + MMSYS_ROUTE(COLOR, 0, CCORR, 0, MT8365_DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, MT8365_DISP_MS_IN_OUT_MASK, MT8365_DISP_COLOR_SEL_IN_COLOR0), - MMSYS_ROUTE(DITHER0, DSI0, + MMSYS_ROUTE(DITHER, 0, DSI, 0, MT8365_DISP_REG_CONFIG_DISP_DITHER0_MOUT_EN, MT8365_DISP_MS_IN_OUT_MASK, MT8365_DITHER_MOUT_EN_DSI0), - MMSYS_ROUTE(DITHER0, DSI0, + MMSYS_ROUTE(DITHER, 0, DSI, 0, MT8365_DISP_REG_CONFIG_DISP_DSI0_SEL_IN, MT8365_DISP_MS_IN_OUT_MASK, MT8365_DSI0_SEL_IN_DITHER), - MMSYS_ROUTE(RDMA0, COLOR0, + MMSYS_ROUTE(RDMA, 0, COLOR, 0, MT8365_DISP_REG_CONFIG_DISP_RDMA0_RSZ0_SEL_IN, MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA0_RSZ0_SEL_IN_RDMA0), - MMSYS_ROUTE(RDMA1, DPI0, + MMSYS_ROUTE(RDMA, 1, DPI, 0, MT8365_DISP_REG_CONFIG_DISP_LVDS_SYS_CFG_00, MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK, MT8365_LVDS_SYS_CFG_00_SEL_LVDS_PXL_CLK), - MMSYS_ROUTE(RDMA1, DPI0, + MMSYS_ROUTE(RDMA, 1, DPI, 0, MT8365_DISP_REG_CONFIG_DISP_DPI0_SEL_IN, MT8365_DISP_MS_IN_OUT_MASK, MT8365_DPI0_SEL_IN_RDMA1), - MMSYS_ROUTE(RDMA1, DPI0, + MMSYS_ROUTE(RDMA, 1, DPI, 0, MT8365_DISP_REG_CONFIG_DISP_RDMA1_SOUT_SEL, MT8365_DISP_MS_IN_OUT_MASK, MT8365_RDMA1_SOUT_DPI0), }; diff --git a/drivers/soc/mediatek/mtk-dvfsrc.c b/drivers/soc/mediatek/mtk-dvfsrc.c index 548a28f50242..e8cdee8aed35 100644 --- a/drivers/soc/mediatek/mtk-dvfsrc.c +++ b/drivers/soc/mediatek/mtk-dvfsrc.c @@ -862,6 +862,7 @@ static const struct of_device_id mtk_dvfsrc_of_match[] = { { .compatible = "mediatek,mt8196-dvfsrc", .data = &mt8196_data }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, mtk_dvfsrc_of_match); static struct platform_driver mtk_dvfsrc_driver = { .probe = mtk_dvfsrc_probe, diff --git a/drivers/soc/mediatek/mtk-mmsys.h b/drivers/soc/mediatek/mtk-mmsys.h index fe628d5f5198..c51a5e334e29 100644 --- a/drivers/soc/mediatek/mtk-mmsys.h +++ b/drivers/soc/mediatek/mtk-mmsys.h @@ -80,18 +80,25 @@ #define MMSYS_RST_NR(bank, bit) (((bank) * 32) + (bit)) +/* Temporary compatibility definitions */ +#define DDP_COMPONENT_BLS0 DDP_COMPONENT_BLS +#define DDP_COMPONENT_CCORR0 DDP_COMPONENT_CCORR +#define DDP_COMPONENT_UFOE0 DDP_COMPONENT_UFOE +#define DDP_COMPONENT_GAMMA0 DDP_COMPONENT_GAMMA +#define DDP_COMPONENT_ETHDR_MIXER0 DDP_COMPONENT_ETHDR_MIXER + /* * This macro adds a compile time check to make sure that the in/out * selection bit(s) fit in the register mask, similar to bitfield * macros, but this does not transform the value. */ -#define MMSYS_ROUTE(from, to, reg_addr, reg_mask, selection) \ - { DDP_COMPONENT_##from, DDP_COMPONENT_##to, reg_addr, reg_mask, \ - (__BUILD_BUG_ON_ZERO_MSG((reg_mask) == 0, "Invalid mask") + \ - __BUILD_BUG_ON_ZERO_MSG(~(reg_mask) & (selection), \ - #selection " does not fit in " \ - #reg_mask) + \ - (selection)) \ +#define MMSYS_ROUTE(from, fsid, to, tsid, reg_addr, reg_mask, selection) \ + { DDP_COMPONENT_##from##fsid, DDP_COMPONENT_##to##tsid, reg_addr, reg_mask, \ + (__BUILD_BUG_ON_ZERO_MSG((reg_mask) == 0, "Invalid mask") + \ + __BUILD_BUG_ON_ZERO_MSG(~(reg_mask) & (selection), \ + #selection " does not fit in " \ + #reg_mask) + \ + (selection)) \ } struct mtk_mmsys_routes { @@ -151,171 +158,120 @@ struct mtk_mmsys_driver_data { * to an independent table. */ static const struct mtk_mmsys_routes mmsys_default_routing_table[] = { - { - DDP_COMPONENT_BLS, DDP_COMPONENT_DSI0, - DISP_REG_CONFIG_OUT_SEL, BLS_RDMA1_DSI_DPI_MASK, - BLS_TO_DSI_RDMA1_TO_DPI1 - }, { - DDP_COMPONENT_BLS, DDP_COMPONENT_DSI0, - DISP_REG_CONFIG_DSI_SEL, DSI_SEL_IN_MASK, - DSI_SEL_IN_BLS - }, { - DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0, - DISP_REG_CONFIG_OUT_SEL, BLS_RDMA1_DSI_DPI_MASK, - BLS_TO_DPI_RDMA1_TO_DSI - }, { - DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0, - DISP_REG_CONFIG_DSI_SEL, DSI_SEL_IN_MASK, - DSI_SEL_IN_RDMA - }, { - DDP_COMPONENT_BLS, DDP_COMPONENT_DPI0, - DISP_REG_CONFIG_DPI_SEL, DPI_SEL_IN_MASK, - DPI_SEL_IN_BLS - }, { - DDP_COMPONENT_GAMMA, DDP_COMPONENT_RDMA1, - DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN, GAMMA_MOUT_EN_RDMA1, - GAMMA_MOUT_EN_RDMA1 - }, { - DDP_COMPONENT_OD0, DDP_COMPONENT_RDMA0, - DISP_REG_CONFIG_DISP_OD_MOUT_EN, OD_MOUT_EN_RDMA0, - OD_MOUT_EN_RDMA0 - }, { - DDP_COMPONENT_OD1, DDP_COMPONENT_RDMA1, - DISP_REG_CONFIG_DISP_OD_MOUT_EN, OD1_MOUT_EN_RDMA1, - OD1_MOUT_EN_RDMA1 - }, { - DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0, - DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0, - OVL0_MOUT_EN_COLOR0 - }, { - DDP_COMPONENT_OVL0, DDP_COMPONENT_COLOR0, - DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0, - COLOR0_SEL_IN_OVL0 - }, { - DDP_COMPONENT_OVL0, DDP_COMPONENT_RDMA0, - DISP_REG_CONFIG_DISP_OVL_MOUT_EN, OVL_MOUT_EN_RDMA, - OVL_MOUT_EN_RDMA - }, { - DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1, - DISP_REG_CONFIG_DISP_OVL1_MOUT_EN, OVL1_MOUT_EN_COLOR1, - OVL1_MOUT_EN_COLOR1 - }, { - DDP_COMPONENT_OVL1, DDP_COMPONENT_COLOR1, - DISP_REG_CONFIG_DISP_COLOR1_SEL_IN, COLOR1_SEL_IN_OVL1, - COLOR1_SEL_IN_OVL1 - }, { - DDP_COMPONENT_RDMA0, DDP_COMPONENT_DPI0, - DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK, - RDMA0_SOUT_DPI0 - }, { - DDP_COMPONENT_RDMA0, DDP_COMPONENT_DPI1, - DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK, - RDMA0_SOUT_DPI1 - }, { - DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI1, - DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK, - RDMA0_SOUT_DSI1 - }, { - DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI2, - DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK, - RDMA0_SOUT_DSI2 - }, { - DDP_COMPONENT_RDMA0, DDP_COMPONENT_DSI3, - DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK, - RDMA0_SOUT_DSI3 - }, { - DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0, - DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK, - RDMA1_SOUT_DPI0 - }, { - DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI0, - DISP_REG_CONFIG_DPI_SEL_IN, DPI0_SEL_IN_MASK, - DPI0_SEL_IN_RDMA1 - }, { - DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI1, - DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK, - RDMA1_SOUT_DPI1 - }, { - DDP_COMPONENT_RDMA1, DDP_COMPONENT_DPI1, - DISP_REG_CONFIG_DPI_SEL_IN, DPI1_SEL_IN_MASK, - DPI1_SEL_IN_RDMA1 - }, { - DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI0, - DISP_REG_CONFIG_DSIE_SEL_IN, DSI0_SEL_IN_MASK, - DSI0_SEL_IN_RDMA1 - }, { - DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI1, - DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK, - RDMA1_SOUT_DSI1 - }, { - DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI1, - DISP_REG_CONFIG_DSIO_SEL_IN, DSI1_SEL_IN_MASK, - DSI1_SEL_IN_RDMA1 - }, { - DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI2, - DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK, - RDMA1_SOUT_DSI2 - }, { - DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI2, - DISP_REG_CONFIG_DSIE_SEL_IN, DSI2_SEL_IN_MASK, - DSI2_SEL_IN_RDMA1 - }, { - DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI3, - DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK, - RDMA1_SOUT_DSI3 - }, { - DDP_COMPONENT_RDMA1, DDP_COMPONENT_DSI3, - DISP_REG_CONFIG_DSIO_SEL_IN, DSI3_SEL_IN_MASK, - DSI3_SEL_IN_RDMA1 - }, { - DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI0, - DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK, - RDMA2_SOUT_DPI0 - }, { - DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI0, - DISP_REG_CONFIG_DPI_SEL_IN, DPI0_SEL_IN_MASK, - DPI0_SEL_IN_RDMA2 - }, { - DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI1, - DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK, - RDMA2_SOUT_DPI1 - }, { - DDP_COMPONENT_RDMA2, DDP_COMPONENT_DPI1, - DISP_REG_CONFIG_DPI_SEL_IN, DPI1_SEL_IN_MASK, - DPI1_SEL_IN_RDMA2 - }, { - DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI0, - DISP_REG_CONFIG_DSIE_SEL_IN, DSI0_SEL_IN_MASK, - DSI0_SEL_IN_RDMA2 - }, { - DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI1, - DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK, - RDMA2_SOUT_DSI1 - }, { - DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI1, - DISP_REG_CONFIG_DSIO_SEL_IN, DSI1_SEL_IN_MASK, - DSI1_SEL_IN_RDMA2 - }, { - DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI2, - DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK, - RDMA2_SOUT_DSI2 - }, { - DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI2, - DISP_REG_CONFIG_DSIE_SEL_IN, DSI2_SEL_IN_MASK, - DSI2_SEL_IN_RDMA2 - }, { - DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI3, - DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK, - RDMA2_SOUT_DSI3 - }, { - DDP_COMPONENT_RDMA2, DDP_COMPONENT_DSI3, - DISP_REG_CONFIG_DSIO_SEL_IN, DSI3_SEL_IN_MASK, - DSI3_SEL_IN_RDMA2 - }, { - DDP_COMPONENT_UFOE, DDP_COMPONENT_DSI0, - DISP_REG_CONFIG_DISP_UFOE_MOUT_EN, UFOE_MOUT_EN_DSI0, - UFOE_MOUT_EN_DSI0 - } + MMSYS_ROUTE(BLS, 0, DSI, 0, + DISP_REG_CONFIG_OUT_SEL, BLS_RDMA1_DSI_DPI_MASK, + BLS_TO_DSI_RDMA1_TO_DPI1), + MMSYS_ROUTE(BLS, 0, DSI, 0, + DISP_REG_CONFIG_DSI_SEL, DSI_SEL_IN_MASK, + DSI_SEL_IN_BLS), + MMSYS_ROUTE(BLS, 0, DPI, 0, + DISP_REG_CONFIG_OUT_SEL, BLS_RDMA1_DSI_DPI_MASK, + BLS_TO_DPI_RDMA1_TO_DSI), + MMSYS_ROUTE(BLS, 0, DPI, 0, + DISP_REG_CONFIG_DSI_SEL, DSI_SEL_IN_MASK, + DSI_SEL_IN_RDMA), + MMSYS_ROUTE(BLS, 0, DPI, 0, + DISP_REG_CONFIG_DPI_SEL, DPI_SEL_IN_MASK, + DPI_SEL_IN_BLS), + MMSYS_ROUTE(GAMMA, 0, RDMA, 1, + DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN, GAMMA_MOUT_EN_RDMA1, + GAMMA_MOUT_EN_RDMA1), + MMSYS_ROUTE(OD, 0, RDMA, 0, + DISP_REG_CONFIG_DISP_OD_MOUT_EN, OD_MOUT_EN_RDMA0, + OD_MOUT_EN_RDMA0), + MMSYS_ROUTE(OD, 1, RDMA, 1, + DISP_REG_CONFIG_DISP_OD_MOUT_EN, OD1_MOUT_EN_RDMA1, + OD1_MOUT_EN_RDMA1), + MMSYS_ROUTE(OVL, 0, COLOR, 0, + DISP_REG_CONFIG_DISP_OVL0_MOUT_EN, OVL0_MOUT_EN_COLOR0, + OVL0_MOUT_EN_COLOR0), + MMSYS_ROUTE(OVL, 0, COLOR, 0, + DISP_REG_CONFIG_DISP_COLOR0_SEL_IN, COLOR0_SEL_IN_OVL0, + COLOR0_SEL_IN_OVL0), + MMSYS_ROUTE(OVL, 0, RDMA, 0, + DISP_REG_CONFIG_DISP_OVL_MOUT_EN, OVL_MOUT_EN_RDMA, + OVL_MOUT_EN_RDMA), + MMSYS_ROUTE(OVL, 1, COLOR, 1, + DISP_REG_CONFIG_DISP_OVL1_MOUT_EN, OVL1_MOUT_EN_COLOR1, + OVL1_MOUT_EN_COLOR1), + MMSYS_ROUTE(OVL, 1, COLOR, 1, + DISP_REG_CONFIG_DISP_COLOR1_SEL_IN, COLOR1_SEL_IN_OVL1, + COLOR1_SEL_IN_OVL1), + MMSYS_ROUTE(RDMA, 0, DPI, 0, + DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK, + RDMA0_SOUT_DPI0), + MMSYS_ROUTE(RDMA, 0, DPI, 1, + DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK, + RDMA0_SOUT_DPI1), + MMSYS_ROUTE(RDMA, 0, DSI, 1, + DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK, + RDMA0_SOUT_DSI1), + MMSYS_ROUTE(RDMA, 0, DSI, 2, + DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK, + RDMA0_SOUT_DSI2), + MMSYS_ROUTE(RDMA, 0, DSI, 3, + DISP_REG_CONFIG_DISP_RDMA0_SOUT_EN, RDMA0_SOUT_MASK, + RDMA0_SOUT_DSI3), + MMSYS_ROUTE(RDMA, 1, DPI, 0, + DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK, + RDMA1_SOUT_DPI0), + MMSYS_ROUTE(RDMA, 1, DPI, 0, + DISP_REG_CONFIG_DPI_SEL_IN, DPI0_SEL_IN_MASK, + DPI0_SEL_IN_RDMA1), + MMSYS_ROUTE(RDMA, 1, DPI, 1, + DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK, + RDMA1_SOUT_DPI1), + MMSYS_ROUTE(RDMA, 1, DPI, 1, + DISP_REG_CONFIG_DPI_SEL_IN, DPI1_SEL_IN_MASK, + DPI1_SEL_IN_RDMA1), + MMSYS_ROUTE(RDMA, 1, DSI, 0, + DISP_REG_CONFIG_DSIE_SEL_IN, DSI0_SEL_IN_MASK, + DSI0_SEL_IN_RDMA1), + MMSYS_ROUTE(RDMA, 1, DSI, 1, + DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK, + RDMA1_SOUT_DSI1), + MMSYS_ROUTE(RDMA, 1, DSI, 1, + DISP_REG_CONFIG_DSIO_SEL_IN, DSI1_SEL_IN_MASK, + DSI1_SEL_IN_RDMA1), + MMSYS_ROUTE(RDMA, 1, DSI, 2, + DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK, + RDMA1_SOUT_DSI2), + MMSYS_ROUTE(RDMA, 1, DSI, 2, + DISP_REG_CONFIG_DSIE_SEL_IN, DSI2_SEL_IN_MASK, + DSI2_SEL_IN_RDMA1), + MMSYS_ROUTE(RDMA, 1, DSI, 3, + DISP_REG_CONFIG_DISP_RDMA1_SOUT_EN, RDMA1_SOUT_MASK, + RDMA1_SOUT_DSI3), + MMSYS_ROUTE(RDMA, 1, DSI, 3, + DISP_REG_CONFIG_DSIO_SEL_IN, DSI3_SEL_IN_MASK, + DSI3_SEL_IN_RDMA1), + MMSYS_ROUTE(RDMA, 2, DPI, 0, + DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK, + RDMA2_SOUT_DPI0), + MMSYS_ROUTE(RDMA, 2, DPI, 0, + DISP_REG_CONFIG_DPI_SEL_IN, DPI0_SEL_IN_MASK, + DPI0_SEL_IN_RDMA2), + MMSYS_ROUTE(RDMA, 2, DPI, 1, + DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK, + RDMA2_SOUT_DPI1), + MMSYS_ROUTE(RDMA, 2, DPI, 1, + DISP_REG_CONFIG_DPI_SEL_IN, DPI1_SEL_IN_MASK, + DPI1_SEL_IN_RDMA2), + MMSYS_ROUTE(RDMA, 2, DSI, 0, + DISP_REG_CONFIG_DSIE_SEL_IN, DSI0_SEL_IN_MASK, + DSI0_SEL_IN_RDMA2), + MMSYS_ROUTE(RDMA, 2, DSI, 1, + DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK, + RDMA2_SOUT_DSI1), + MMSYS_ROUTE(RDMA, 2, DSI, 1, + DISP_REG_CONFIG_DSIO_SEL_IN, DSI1_SEL_IN_MASK, + DSI1_SEL_IN_RDMA2), + MMSYS_ROUTE(RDMA, 2, DSI, 2, + DISP_REG_CONFIG_DISP_RDMA2_SOUT, RDMA2_SOUT_MASK, + RDMA2_SOUT_DSI2), + MMSYS_ROUTE(RDMA, 2, DSI, 2, + DISP_REG_CONFIG_DSIE_SEL_IN, DSI2_SEL_IN_MASK, + DSI2_SEL_IN_RDMA2), }; #endif /* __SOC_MEDIATEK_MTK_MMSYS_H */ diff --git a/drivers/soc/mediatek/mtk-socinfo.c b/drivers/soc/mediatek/mtk-socinfo.c index 424a1eb82c20..e294730ba709 100644 --- a/drivers/soc/mediatek/mtk-socinfo.c +++ b/drivers/soc/mediatek/mtk-socinfo.c @@ -76,11 +76,14 @@ static int mtk_socinfo_create_socinfo_node(struct mtk_socinfo *mtk_socinfop) if (!attrs) return -ENOMEM; - if (data->marketing_name != NULL && data->marketing_name[0] != '\0') + if (data->marketing_name != NULL && data->marketing_name[0] != '\0') { attrs->family = devm_kasprintf(mtk_socinfop->dev, GFP_KERNEL, "MediaTek %s", data->marketing_name); - else + if (!attrs->family) + return -ENOMEM; + } else { attrs->family = soc_manufacturer; + } attrs->soc_id = data->soc_name; /* diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 2caadbbcf830..2b524154d9fb 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -2,14 +2,25 @@ # # QCOM Soc drivers # -menu "Qualcomm SoC drivers" +menuconfig QCOM_SOC + bool "Qualcomm SoC drivers" + depends on ARCH_QCOM || COMPILE_TEST + default ARCH_QCOM + help + This collection of drivers is specific to Qualcomm System-on-Chips + and most of them are necessary for a fully functional boot of the + Linux kernel (plus a few debugging drivers). + Drivers can be skipped when building Linux kernel not intended to run + said processors. + +if QCOM_SOC config QCOM_AOSS_QMP tristate "Qualcomm AOSS Driver" - depends on ARCH_QCOM || COMPILE_TEST depends on MAILBOX depends on COMMON_CLK && PM select PM_GENERIC_DOMAINS + default ARCH_QCOM help This driver provides the means of communicating with and controlling the low-power state for resources related to the remoteproc @@ -18,8 +29,8 @@ config QCOM_AOSS_QMP config QCOM_COMMAND_DB tristate "Qualcomm Command DB" - depends on ARCH_QCOM || COMPILE_TEST depends on OF_RESERVED_MEM + default ARCH_QCOM help Command DB queries shared memory by key string for shared system resources. Platform drivers that require to set state of a shared @@ -27,8 +38,9 @@ config QCOM_COMMAND_DB SoC specific identifier and information for the shared resources. config QCOM_GENI_SE - tristate "QCOM GENI Serial Engine Driver" - depends on ARCH_QCOM || COMPILE_TEST + tristate "Qualcomm GENI Serial Engine Driver" + depends on ARM64 || COMPILE_TEST + default ARCH_QCOM help This driver is used to manage Generic Interface (GENI) firmware based Qualcomm Technologies, Inc. Universal Peripheral (QUP) Wrapper. This @@ -36,8 +48,9 @@ config QCOM_GENI_SE Engines present in the QUP. config QCOM_GSBI - tristate "QCOM General Serial Bus Interface" - depends on ARCH_QCOM || COMPILE_TEST + tristate "Qualcomm General Serial Bus Interface" + depends on ARM || COMPILE_TEST + default ARCH_QCOM select MFD_SYSCON help Say y here to enable GSBI support. The GSBI provides control @@ -45,27 +58,19 @@ config QCOM_GSBI devices to the output pins. config QCOM_LLCC - tristate "Qualcomm Technologies, Inc. LLCC driver" - depends on ARCH_QCOM || COMPILE_TEST + tristate "Qualcomm LLCC driver" select REGMAP_MMIO + default m if ARCH_QCOM help Qualcomm Technologies, Inc. platform specific Last Level Cache Controller(LLCC) driver for platforms such as, SDM845. This provides interfaces to clients that use the LLCC. Say yes here to enable LLCC slice driver. -config QCOM_KRYO_L2_ACCESSORS - bool - depends on (ARCH_QCOM || COMPILE_TEST) && ARM64 - -config QCOM_MDT_LOADER - tristate - select QCOM_SCM - config QCOM_OCMEM tristate "Qualcomm On Chip Memory (OCMEM) driver" - depends on ARCH_QCOM select QCOM_SCM + default m if ARCH_QCOM help The On Chip Memory (OCMEM) allocator allows various clients to allocate memory from OCMEM based on performance, latency and power @@ -77,7 +82,7 @@ config QCOM_PD_MAPPER select QCOM_QMI_HELPERS select QCOM_PDR_MSG select AUXILIARY_BUS - depends on NET && QRTR && (ARCH_QCOM || COMPILE_TEST) + depends on NET && QRTR default QCOM_RPROC_COMMON help The Protection Domain Mapper maps registered services to the domains @@ -85,15 +90,6 @@ config QCOM_PD_MAPPER implementation of the service. It is a simpler alternative to the userspace daemon. -config QCOM_PDR_HELPERS - tristate - select QCOM_QMI_HELPERS - select QCOM_PDR_MSG - depends on NET - -config QCOM_PDR_MSG - tristate - config QCOM_PMIC_PDCHARGER_ULOG tristate "Qualcomm PMIC PDCharger ULOG driver" depends on RPMSG @@ -113,9 +109,11 @@ config QCOM_PMIC_GLINK depends on DRM depends on NET depends on OF + depends on ARM64 || COMPILE_TEST select AUXILIARY_BUS select QCOM_PDR_HELPERS select DRM_AUX_HPD_BRIDGE + default m if ARCH_QCOM help The Qualcomm PMIC GLINK driver provides access, over GLINK, to the USB and battery firmware running on one of the coprocessors in @@ -124,13 +122,8 @@ config QCOM_PMIC_GLINK Say yes here to support USB-C and battery status on modern Qualcomm platforms. -config QCOM_QMI_HELPERS - tristate - depends on NET - config QCOM_RAMP_CTRL tristate "Qualcomm Ramp Controller driver" - depends on ARCH_QCOM || COMPILE_TEST help The Ramp Controller is used to program the sequence ID for pulse swallowing, enable sequence and link sequence IDs for the CPU @@ -139,8 +132,8 @@ config QCOM_RAMP_CTRL config QCOM_RMTFS_MEM tristate "Qualcomm Remote Filesystem memory driver" - depends on ARCH_QCOM || COMPILE_TEST select QCOM_SCM + default m if ARCH_QCOM help The Qualcomm remote filesystem memory driver is used for allocating and exposing regions of shared memory with remote processors for the @@ -151,7 +144,6 @@ config QCOM_RMTFS_MEM config QCOM_RPM_MASTER_STATS tristate "Qualcomm RPM Master stats" - depends on ARCH_QCOM || COMPILE_TEST help The RPM Master sleep stats driver provides detailed per-subsystem sleep/wake data, read from the RPM message RAM. It can be used to @@ -162,8 +154,8 @@ config QCOM_RPM_MASTER_STATS config QCOM_RPMH tristate "Qualcomm RPM-Hardened (RPMH) Communication" - depends on ARCH_QCOM || COMPILE_TEST depends on (QCOM_COMMAND_DB || !QCOM_COMMAND_DB) + default ARCH_QCOM help Support for communication with the hardened-RPM blocks in Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an @@ -173,8 +165,8 @@ config QCOM_RPMH config QCOM_SMEM tristate "Qualcomm Shared Memory Manager (SMEM)" - depends on ARCH_QCOM || COMPILE_TEST depends on HWSPINLOCK + default ARCH_QCOM help Say y here to enable support for the Qualcomm Shared Memory Manager. The driver provides an interface to items in a heap shared among all @@ -182,9 +174,9 @@ config QCOM_SMEM config QCOM_SMD_RPM tristate "Qualcomm Resource Power Manager (RPM) over SMD" - depends on ARCH_QCOM || COMPILE_TEST depends on RPMSG depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n + default ARCH_QCOM help If you say yes to this option, support will be included for the Resource Power Manager system found in the Qualcomm 8974 based @@ -205,6 +197,7 @@ config QCOM_SMP2P depends on QCOM_SMEM select QCOM_SMEM_STATE select IRQ_DOMAIN + default ARCH_QCOM help Say yes here to support the Qualcomm Shared Memory Point to Point protocol. @@ -215,6 +208,7 @@ config QCOM_SMSM depends on QCOM_SMEM select QCOM_SMEM_STATE select IRQ_DOMAIN + default ARCH_QCOM help Say yes here to support the Qualcomm Shared Memory State Machine. The state machine is represented by bits in shared memory. @@ -223,24 +217,26 @@ config QCOM_SOCINFO tristate "Qualcomm socinfo driver" depends on QCOM_SMEM select SOC_BUS + default m if ARCH_QCOM help Say yes here to support the Qualcomm socinfo driver, providing information about the SoC to user space. config QCOM_SPM tristate "Qualcomm Subsystem Power Manager (SPM)" - depends on ARCH_QCOM || COMPILE_TEST - select QCOM_SCM + depends on QCOM_SCM + default ARCH_QCOM if ARM help Enable the support for the Qualcomm Subsystem Power Manager, used to manage cores, L2 low power modes and to configure the internal Adaptive Voltage Scaler parameters, where supported. config QCOM_STATS - tristate "Qualcomm Technologies, Inc. (QTI) Sleep stats driver" - depends on (ARCH_QCOM && DEBUG_FS) || COMPILE_TEST + tristate "Qualcomm Sleep stats driver" + depends on DEBUG_FS || COMPILE_TEST depends on QCOM_SMEM depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n + default m if ARCH_QCOM help Qualcomm Technologies, Inc. (QTI) Sleep stats driver to read the shared memory exported by the remote processor related to @@ -249,18 +245,18 @@ config QCOM_STATS config QCOM_WCNSS_CTRL tristate "Qualcomm WCNSS control driver" - depends on ARCH_QCOM || COMPILE_TEST depends on RPMSG + default m if ARCH_QCOM help Client driver for the WCNSS_CTRL SMD channel, used to download nv firmware to a newly booted WCNSS chip. config QCOM_APR tristate "Qualcomm APR/GPR Bus (Asynchronous/Generic Packet Router)" - depends on ARCH_QCOM || COMPILE_TEST depends on RPMSG depends on NET select QCOM_PDR_HELPERS + default m if ARCH_QCOM help Enable APR IPC protocol support between application processor and QDSP6. APR is @@ -268,10 +264,11 @@ config QCOM_APR ASM, ADM and AFE modules. config QCOM_ICC_BWMON - tristate "QCOM Interconnect Bandwidth Monitor driver" - depends on ARCH_QCOM || COMPILE_TEST + tristate "Qualcomm Interconnect Bandwidth Monitor driver" + depends on ARM64 || COMPILE_TEST select PM_OPP select REGMAP_MMIO + default m if ARCH_QCOM help Sets up driver monitoring bandwidth on various interconnects and based on that voting for interconnect bandwidth, adjusting their @@ -282,23 +279,49 @@ config QCOM_ICC_BWMON the fixed bandwidth votes from cpufreq (CPU nodes) thus achieve high memory throughput even with lower CPU frequencies. -config QCOM_INLINE_CRYPTO_ENGINE - tristate - select QCOM_SCM - config QCOM_PBS - tristate "PBS trigger support for Qualcomm Technologies, Inc. PMICS" + tristate "PBS trigger support for Qualcomm PMICs" depends on SPMI + default m if ARCH_QCOM help This driver supports configuring software programmable boot sequencer (PBS) trigger event through PBS RAM on Qualcomm Technologies, Inc. PMICs. This module provides the APIs to the client drivers that wants to send the PBS trigger event to the PBS RAM. -endmenu +endif + +# Options selected by other drivers from different subsystems must be outside +# of the menuconfig if-block: + +config QCOM_INLINE_CRYPTO_ENGINE + tristate + select QCOM_SCM + +config QCOM_KRYO_L2_ACCESSORS + bool + depends on ARM64 + +config QCOM_MDT_LOADER + tristate + select QCOM_SCM + +config QCOM_PDR_HELPERS + tristate + select QCOM_QMI_HELPERS + select QCOM_PDR_MSG + depends on NET + +config QCOM_PDR_MSG + tristate + +config QCOM_QMI_HELPERS + tristate + depends on NET config QCOM_UBWC_CONFIG tristate + depends on QCOM_SMEM help Most Qualcomm SoCs feature a number of Universal Bandwidth Compression (UBWC) engines across various IP blocks, which need to be initialized diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index b7f1d2a57367..798643be3590 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -23,7 +23,8 @@ obj-$(CONFIG_QCOM_RPMH) += qcom_rpmh.o qcom_rpmh-y += rpmh-rsc.o qcom_rpmh-y += rpmh.o obj-$(CONFIG_QCOM_SMD_RPM) += rpm-proc.o smd-rpm.o -obj-$(CONFIG_QCOM_SMEM) += smem.o +qcom_smem-y += smem.o smem_dramc.o +obj-$(CONFIG_QCOM_SMEM) += qcom_smem.o obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o CFLAGS_smp2p.o := -I$(src) obj-$(CONFIG_QCOM_SMP2P) += smp2p.o diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index 84a75d8c4b70..3f1eee784387 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved. * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c index 5f20108aa03e..e256595b9826 100644 --- a/drivers/soc/qcom/ice.c +++ b/drivers/soc/qcom/ice.c @@ -126,8 +126,8 @@ static bool qcom_ice_check_supported(struct qcom_ice *ice) int minor = FIELD_GET(GENMASK(23, 16), regval); int step = FIELD_GET(GENMASK(15, 0), regval); - /* For now this driver only supports ICE version 3 and 4. */ - if (major != 3 && major != 4) { + /* Support ICE version 3 and above. */ + if (major < 3) { dev_warn(dev, "Unsupported ICE version: v%d.%d.%d\n", major, minor, step); return false; diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 8948b5fd42d2..733999867bbf 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -2305,6 +2305,20 @@ static const struct llcc_slice_config sdm845_data[] = {{ }, }; +static const struct llcc_slice_config shikra_data[] = { + { + .usecase_id = LLCC_ECC, + .slice_id = 26, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0x3, + .cache_mode = 0, + .activate_on_init = true, + .vict_prio = true, + }, +}; + static const struct llcc_slice_config sm6350_data[] = { { .usecase_id = LLCC_CPUSS, @@ -4575,6 +4589,16 @@ static const struct qcom_llcc_config sdm845_cfg[] = { }, }; +static const struct qcom_llcc_config shikra_cfg[] = { + { + .sct_data = shikra_data, + .size = ARRAY_SIZE(shikra_data), + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + .irq_configured = true, + }, +}; + static const struct qcom_llcc_config sm6350_cfg[] = { { .sct_data = sm6350_data, @@ -4752,6 +4776,11 @@ static const struct qcom_sct_config sdm845_cfgs = { .num_config = ARRAY_SIZE(sdm845_cfg), }; +static const struct qcom_sct_config shikra_cfgs = { + .llcc_config = shikra_cfg, + .num_config = ARRAY_SIZE(shikra_cfg), +}; + static const struct qcom_sct_config sm6350_cfgs = { .llcc_config = sm6350_cfg, .num_config = ARRAY_SIZE(sm6350_cfg), @@ -5632,6 +5661,7 @@ static const struct of_device_id qcom_llcc_of_match[] = { { .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfgs }, { .compatible = "qcom,sdm670-llcc", .data = &sdm670_cfgs }, { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfgs }, + { .compatible = "qcom,shikra-llcc", .data = &shikra_cfgs }, { .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfgs }, { .compatible = "qcom,sm7150-llcc", .data = &sm7150_cfgs }, { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfgs }, diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c index 619bad2c27ee..13c434f8d03a 100644 --- a/drivers/soc/qcom/pmic_glink_altmode.c +++ b/drivers/soc/qcom/pmic_glink_altmode.c @@ -53,7 +53,7 @@ struct usbc_sc8280x_tbt_data { /* This field is NOP on USB4, all cables support rounded rates by spec */ u8 rounded_cable : 1; u8 power_limited : 1; - u8 res[11]; + u8 res[7]; }; struct usbc_notify { @@ -74,6 +74,7 @@ struct usbc_notify { struct usbc_sc8280x_dp_data dp; struct usbc_sc8280x_tbt_data tbt; } extended_data; + u32 reserved; }; struct usbc_sc8180x_notify { diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 15636a8dc907..107fa2057654 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -154,8 +154,6 @@ struct se_fw_hdr { /*Magic numbers*/ #define SE_MAGIC_NUM 0x57464553 -#define MAX_GENI_CFG_RAMn_CNT 455 - #define MI_PBT_NON_PAGED_SEGMENT 0x0 #define MI_PBT_HASH_SEGMENT 0x2 #define MI_PBT_NOTUSED_SEGMENT 0x3 @@ -1224,24 +1222,27 @@ EXPORT_SYMBOL_GPL(geni_se_resources_init); /** * geni_find_protocol_fw() - Locate and validate SE firmware for a protocol. - * @dev: Pointer to the device structure. + * @se: Pointer to the serial engine structure. * @fw: Pointer to the firmware image. * @protocol: Expected serial engine protocol type. * * Identifies the appropriate firmware image or configuration required for a - * specific communication protocol instance running on a Qualcomm GENI - * controller. + * specific communication protocol instance running on a Qualcomm GENI + * controller. Validates the firmware size against the hardware PROG_RAM_DEPTH + * read from SE_HW_PARAM_2. * * Return: pointer to a valid 'struct se_fw_hdr' if found, or NULL otherwise. */ -static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct firmware *fw, +static struct se_fw_hdr *geni_find_protocol_fw(struct geni_se *se, const struct firmware *fw, enum geni_se_protocol_type protocol) { + struct device *dev = se->dev; const struct elf32_hdr *ehdr; const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; struct se_fw_hdr *sefw; u32 fw_end, cfg_idx_end, cfg_val_end; + u32 prog_ram_depth; u16 fw_size; int i; @@ -1300,10 +1301,11 @@ static struct se_fw_hdr *geni_find_protocol_fw(struct device *dev, const struct sefw->fw_size_in_items = cpu_to_le16(fw_size); } - if (fw_size >= MAX_GENI_CFG_RAMn_CNT) { - dev_err(dev, - "Firmware size (%u) exceeds max allowed RAMn count (%u)\n", - fw_size, MAX_GENI_CFG_RAMn_CNT); + prog_ram_depth = FIELD_GET(PROG_RAM_DEPTH_MSK, + readl_relaxed(se->base + SE_HW_PARAM_2)); + if (fw_size >= prog_ram_depth) { + dev_err(dev, "Firmware size (%u) exceeds RAM size (%u)\n", + fw_size, prog_ram_depth); continue; } @@ -1427,7 +1429,7 @@ static int geni_load_se_fw(struct geni_se *se, const struct firmware *fw, int ret; struct se_fw_hdr *hdr; - hdr = geni_find_protocol_fw(se->dev, fw, protocol); + hdr = geni_find_protocol_fw(se, fw, protocol); if (!hdr) return -EINVAL; diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c index 0dc1a7946050..64ca99d7fad9 100644 --- a/drivers/soc/qcom/qcom_pd_mapper.c +++ b/drivers/soc/qcom/qcom_pd_mapper.c @@ -310,6 +310,24 @@ static const struct qcom_pdm_domain_data cdsp_root_pd = { .services = { NULL }, }; +static const struct qcom_pdm_domain_data cdsp1_root_pd = { + .domain = "msm/cdsp1/root_pd", + .instance_id = 125, + .services = { NULL }, +}; + +static const struct qcom_pdm_domain_data gpdsp_root_pd = { + .domain = "msm/gpdsp/root_pd", + .instance_id = 192, + .services = { NULL }, +}; + +static const struct qcom_pdm_domain_data gpdsp1_root_pd = { + .domain = "msm/gpdsp1/root_pd", + .instance_id = 241, + .services = { NULL }, +}; + static const struct qcom_pdm_domain_data slpi_root_pd = { .domain = "msm/slpi/root_pd", .instance_id = 90, @@ -425,6 +443,24 @@ static const struct qcom_pdm_domain_data *qcs615_domains[] = { NULL, }; +static const struct qcom_pdm_domain_data *qcs8300_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &cdsp_root_pd, + &gpdsp_root_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sa8775p_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &cdsp_root_pd, + &cdsp1_root_pd, + &gpdsp_root_pd, + &gpdsp1_root_pd, + NULL, +}; + static const struct qcom_pdm_domain_data *sc7180_domains[] = { &adsp_audio_pd, &adsp_root_pd_pdr, @@ -602,6 +638,8 @@ static const struct of_device_id qcom_pdm_domains[] __maybe_unused = { { .compatible = "qcom,qcm6490", .data = sc7280_domains, }, { .compatible = "qcom,qcs404", .data = qcs404_domains, }, { .compatible = "qcom,qcs615", .data = qcs615_domains, }, + { .compatible = "qcom,qcs8300", .data = qcs8300_domains, }, + { .compatible = "qcom,sa8775p", .data = sa8775p_domains, }, { .compatible = "qcom,sc7180", .data = sc7180_domains, }, { .compatible = "qcom,sc7280", .data = sc7280_domains, }, { .compatible = "qcom,sc8180x", .data = sc8180x_domains, }, diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index 2e380faf9080..06923408bfce 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -20,13 +20,6 @@ #define RPM_DYNAMIC_ADDR 0x14 #define RPM_DYNAMIC_ADDR_MASK 0xFFFF -#define STAT_TYPE_OFFSET 0x0 -#define COUNT_OFFSET 0x4 -#define LAST_ENTERED_AT_OFFSET 0x8 -#define LAST_EXITED_AT_OFFSET 0x10 -#define ACCUMULATED_OFFSET 0x18 -#define CLIENT_VOTES_OFFSET 0x20 - #define DDR_STATS_MAGIC_KEY 0xA1157A75 #define DDR_STATS_MAX_NUM_MODES 20 #define DDR_STATS_MAGIC_KEY_ADDR 0x0 @@ -54,6 +47,8 @@ static const struct subsystem_data subsystems[] = { { "cdsp1", 607, 12 }, { "gpdsp0", 607, 17 }, { "gpdsp1", 607, 18 }, + { "soccp", 607, 19 }, + { "dcp", 607, 22 }, { "slpi", 608, 3 }, { "gpu", 609, 0 }, { "display", 610, 0 }, @@ -138,7 +133,7 @@ static int qcom_soc_sleep_stats_show(struct seq_file *s, void *unused) if (d->appended_stats_avail) { struct appended_stats votes; - memcpy_fromio(&votes, reg + CLIENT_VOTES_OFFSET, sizeof(votes)); + memcpy_fromio(&votes, reg + sizeof(struct sleep_stats), sizeof(votes)); seq_printf(s, "Client Votes: %#x\n", votes.client_votes); } diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index c6f7d5c9c493..66928ca40b9a 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -944,17 +944,30 @@ static int rpmh_rsc_pd_callback(struct notifier_block *nfb, return NOTIFY_OK; } +static void rpmh_rsc_pd_detach(void *data) +{ + dev_pm_genpd_remove_notifier(data); +} + static int rpmh_rsc_pd_attach(struct rsc_drv *drv, struct device *dev) { int ret; - pm_runtime_enable(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + drv->genpd_nb.notifier_call = rpmh_rsc_pd_callback; ret = dev_pm_genpd_add_notifier(dev, &drv->genpd_nb); if (ret) - pm_runtime_disable(dev); + return ret; - return ret; + return devm_add_action_or_reset(dev, rpmh_rsc_pd_detach, dev); +} + +static void rpmh_rsc_cpu_pm_unregister(void *data) +{ + cpu_pm_unregister_notifier(data); } static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *drv) @@ -1107,7 +1120,15 @@ static int rpmh_rsc_probe(struct platform_device *pdev) return ret; } else { drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback; - cpu_pm_register_notifier(&drv->rsc_pm); + ret = cpu_pm_register_notifier(&drv->rsc_pm); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&pdev->dev, + rpmh_rsc_cpu_pm_unregister, + &drv->rsc_pm); + if (ret) + return ret; } } @@ -1122,13 +1143,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, drv); drv->dev = &pdev->dev; - ret = devm_of_platform_populate(&pdev->dev); - if (ret && pdev->dev.pm_domain) { - dev_pm_genpd_remove_notifier(&pdev->dev); - pm_runtime_disable(&pdev->dev); - } - - return ret; + return devm_of_platform_populate(&pdev->dev); } static const struct of_device_id rpmh_drv_match[] = { diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index afb21a778fe7..b5e7bd8c1512 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -4,6 +4,7 @@ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. */ +#include <linux/debugfs.h> #include <linux/hwspinlock.h> #include <linux/io.h> #include <linux/module.h> @@ -16,6 +17,8 @@ #include <linux/soc/qcom/smem.h> #include <linux/soc/qcom/socinfo.h> +#include "smem.h" + /* * The Qualcomm shared memory system is a allocate only heap structure that * consists of one of more memory areas that can be accessed by the processors @@ -267,6 +270,7 @@ struct smem_region { * @partitions: list of partitions of current processor/host * @item_count: max accepted item number * @socinfo: platform device pointer + * @debugfs_dir: directory for SMEM-related debugfs attributes * @num_regions: number of @regions * @regions: list of the memory regions defining the shared memory */ @@ -281,7 +285,9 @@ struct qcom_smem { struct smem_partition global_partition; struct xarray partitions; - unsigned num_regions; + struct dentry *debugfs_dir; + + unsigned int num_regions; struct smem_region regions[] __counted_by(num_regions); }; @@ -399,7 +405,7 @@ EXPORT_SYMBOL_GPL(qcom_smem_is_available); static int qcom_smem_alloc_private(struct qcom_smem *smem, struct smem_partition *part, - unsigned item, + unsigned int item, size_t size) { struct smem_private_entry *hdr, *end; @@ -460,7 +466,7 @@ bad_canary: } static int qcom_smem_alloc_global(struct qcom_smem *smem, - unsigned item, + unsigned int item, size_t size) { struct smem_global_entry *entry; @@ -503,7 +509,7 @@ static int qcom_smem_alloc_global(struct qcom_smem *smem, * * Return: 0 on success, negative errno on failure. */ -int qcom_smem_alloc(unsigned host, unsigned item, size_t size) +int qcom_smem_alloc(unsigned int host, unsigned int item, size_t size) { struct smem_partition *part; unsigned long flags; @@ -544,7 +550,7 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size) EXPORT_SYMBOL_GPL(qcom_smem_alloc); static void *qcom_smem_get_global(struct qcom_smem *smem, - unsigned item, + unsigned int item, size_t *size) { struct smem_header *header; @@ -553,7 +559,6 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, u64 entry_offset; u32 e_size; u32 aux_base; - unsigned i; header = smem->regions[0].virt_base; entry = &header->toc[item]; @@ -562,7 +567,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK; - for (i = 0; i < smem->num_regions; i++) { + for (unsigned int i = 0; i < smem->num_regions; i++) { region = &smem->regions[i]; if ((u32)region->aux_base == aux_base || !aux_base) { @@ -584,7 +589,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, static void *qcom_smem_get_private(struct qcom_smem *smem, struct smem_partition *part, - unsigned item, + unsigned int item, size_t *size) { struct smem_private_entry *e, *end; @@ -672,40 +677,45 @@ invalid_canary: return ERR_PTR(-EINVAL); } -/** - * qcom_smem_get() - resolve ptr of size of a smem item - * @host: the remote processor, or -1 - * @item: smem item handle - * @size: pointer to be filled out with size of the item - * - * Looks up smem item and returns pointer to it. Size of smem - * item is returned in @size. - * - * Return: a pointer to an SMEM item on success, ERR_PTR() on failure. - */ -void *qcom_smem_get(unsigned host, unsigned item, size_t *size) +void *__qcom_smem_get(struct qcom_smem *smem, unsigned int host, unsigned int item, size_t *size) { struct smem_partition *part; void *ptr; - if (IS_ERR(__smem)) - return __smem; + if (IS_ERR(smem)) + return smem; - if (item >= __smem->item_count) + if (item >= smem->item_count) return ERR_PTR(-EINVAL); - part = xa_load(&__smem->partitions, host); + part = xa_load(&smem->partitions, host); if (part) { - ptr = qcom_smem_get_private(__smem, part, item, size); - } else if (__smem->global_partition.virt_base) { - part = &__smem->global_partition; - ptr = qcom_smem_get_private(__smem, part, item, size); + ptr = qcom_smem_get_private(smem, part, item, size); + } else if (smem->global_partition.virt_base) { + part = &smem->global_partition; + ptr = qcom_smem_get_private(smem, part, item, size); } else { - ptr = qcom_smem_get_global(__smem, item, size); + ptr = qcom_smem_get_global(smem, item, size); } return ptr; } + +/** + * qcom_smem_get() - resolve ptr of size of a smem item + * @host: the remote processor, or -1 + * @item: smem item handle + * @size: pointer to be filled out with size of the item + * + * Looks up smem item and returns pointer to it. Size of smem + * item is returned in @size. + * + * Return: a pointer to an SMEM item on success, ERR_PTR() on failure. + */ +void *qcom_smem_get(unsigned int host, unsigned int item, size_t *size) +{ + return __qcom_smem_get(__smem, host, item, size); +} EXPORT_SYMBOL_GPL(qcom_smem_get); /** @@ -717,12 +727,12 @@ EXPORT_SYMBOL_GPL(qcom_smem_get); * * Return: number of available bytes on success, negative errno on failure. */ -int qcom_smem_get_free_space(unsigned host) +int qcom_smem_get_free_space(unsigned int host) { struct smem_partition *part; struct smem_partition_header *phdr; struct smem_header *header; - unsigned ret; + unsigned int ret; if (IS_ERR(__smem)) return PTR_ERR(__smem); @@ -1237,19 +1247,26 @@ static int qcom_smem_probe(struct platform_device *pdev) if (ret < 0 && ret != -ENOENT) return ret; + smem->debugfs_dir = smem_dram_parse(smem, smem->dev); + __smem = smem; smem->socinfo = platform_device_register_data(&pdev->dev, "qcom-socinfo", PLATFORM_DEVID_NONE, NULL, 0); - if (IS_ERR(smem->socinfo)) + if (IS_ERR(smem->socinfo)) { + debugfs_remove_recursive(smem->debugfs_dir); + dev_dbg(&pdev->dev, "failed to register socinfo device\n"); + } return 0; } static void qcom_smem_remove(struct platform_device *pdev) { + debugfs_remove_recursive(__smem->debugfs_dir); + platform_device_unregister(__smem->socinfo); xa_destroy(&__smem->partitions); diff --git a/drivers/soc/qcom/smem.h b/drivers/soc/qcom/smem.h new file mode 100644 index 000000000000..40523eb87231 --- /dev/null +++ b/drivers/soc/qcom/smem.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __QCOM_SMEM_INTERNAL__ +#define __QCOM_SMEM_INTERNAL__ + +#include <linux/device.h> + +struct qcom_smem; + +struct dentry *smem_dram_parse(struct qcom_smem *smem, struct device *dev); +void *__qcom_smem_get(struct qcom_smem *smem, unsigned int host, unsigned int item, size_t *size); + +#endif diff --git a/drivers/soc/qcom/smem_dramc.c b/drivers/soc/qcom/smem_dramc.c new file mode 100644 index 000000000000..63ebe7f6db59 --- /dev/null +++ b/drivers/soc/qcom/smem_dramc.c @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#include <linux/debugfs.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/soc/qcom/smem.h> +#include <linux/units.h> + +#include "smem.h" + +#define SMEM_DDR_INFO_ID 603 + +#define MAX_DDR_FREQ_NUM_V3 13 +#define MAX_DDR_FREQ_NUM_V5 14 + +#define MAX_CHAN_NUM 8 +#define MAX_RANK_NUM 2 + +#define DDR_HBB_MIN 13 +#define DDR_HBB_MAX 19 + +#define MAX_SHUB_ENTRIES 8 + +static struct smem_dram *__dram; + +enum ddr_info_version { + INFO_UNKNOWN, + INFO_V3, + INFO_V3_WITH_14_FREQS, + INFO_V4, + INFO_V5, + INFO_V5_WITH_6_REGIONS, + INFO_V6, /* INFO_V6 seems to only have shipped with 6 DDR regions, unlike V7 */ + INFO_V7, + INFO_V7_WITH_6_REGIONS, +}; + +struct smem_dram { + unsigned long frequencies[MAX_DDR_FREQ_NUM_V5]; + u32 num_frequencies; + u8 hbb; +}; + +enum ddr_type { + DDR_TYPE_NODDR = 0, + DDR_TYPE_LPDDR1 = 1, + DDR_TYPE_LPDDR2 = 2, + DDR_TYPE_PCDDR2 = 3, + DDR_TYPE_PCDDR3 = 4, + DDR_TYPE_LPDDR3 = 5, + DDR_TYPE_LPDDR4 = 6, + DDR_TYPE_LPDDR4X = 7, + DDR_TYPE_LPDDR5 = 8, + DDR_TYPE_LPDDR5X = 9, +}; + +/* The data structures below are NOT __packed on purpose! */ + +/* Structs used across multiple versions */ +struct ddr_part_details { + __le16 revision_id1; + __le16 revision_id2; + __le16 width; + __le16 density; +}; + +struct ddr_freq_table { + __le32 freq_khz; + u8 enabled; +}; + +/* V3 */ +struct ddr_freq_plan_v3 { + struct ddr_freq_table ddr_freq[MAX_DDR_FREQ_NUM_V3]; + u8 num_ddr_freqs; + phys_addr_t clk_period_address; +}; + +struct ddr_details_v3 { + u8 manufacturer_id; + u8 device_type; + struct ddr_part_details ddr_params[MAX_CHAN_NUM]; + struct ddr_freq_plan_v3 ddr_freq_tbl; + u8 num_channels; +}; + +/* Some V3 structs have an additional frequency level */ +struct ddr_freq_plan_v3_14freqs { + struct ddr_freq_table ddr_freq[MAX_DDR_FREQ_NUM_V3 + 1]; + u8 num_ddr_freqs; + phys_addr_t clk_period_address; +}; + +struct ddr_details_v3_14freqs { + u8 manufacturer_id; + u8 device_type; + struct ddr_part_details ddr_params[MAX_CHAN_NUM]; + struct ddr_freq_plan_v3_14freqs ddr_freq_tbl; + u8 num_channels; +}; + +/* V4 */ +struct ddr_details_v4 { + u8 manufacturer_id; + u8 device_type; + struct ddr_part_details ddr_params[MAX_CHAN_NUM]; + struct ddr_freq_plan_v3 ddr_freq_tbl; + u8 num_channels; + u8 num_ranks[MAX_CHAN_NUM]; + u8 highest_bank_addr_bit[MAX_CHAN_NUM][MAX_RANK_NUM]; +}; + +/* V5 */ +struct shub_freq_table { + u8 enable; + __le32 freq_khz; +}; + +struct shub_freq_plan_entry { + u8 num_shub_freqs; + struct shub_freq_table shub_freq[MAX_SHUB_ENTRIES]; +}; + +struct ddr_xbl2quantum_smem_data { + phys_addr_t ssr_cookie_addr; + __le32 reserved[10]; +}; + +struct ddr_freq_plan_v5 { + struct ddr_freq_table ddr_freq[MAX_DDR_FREQ_NUM_V5]; + u8 num_ddr_freqs; + phys_addr_t clk_period_address; + __le32 max_nom_ddr_freq; +}; + +struct ddr_region_v5 { + __le64 start_address; + __le64 size; + __le64 mem_controller_address; + __le32 granule_size; /* MiB */ + u8 ddr_rank; +#define DDR_RANK_0 BIT(0) +#define DDR_RANK_1 BIT(1) + u8 segments_start_index; + __le64 segments_start_offset; +}; + +struct ddr_regions_v5 { + __le32 ddr_region_num; /* We expect this to always be 4 or 6 */ + __le64 ddr_rank0_size; + __le64 ddr_rank1_size; + __le64 ddr_cs0_start_addr; + __le64 ddr_cs1_start_addr; + __le32 highest_bank_addr_bit; + struct ddr_region_v5 ddr_region[] __counted_by_le(ddr_region_num); +}; + +struct ddr_details_v5 { + u8 manufacturer_id; + u8 device_type; + struct ddr_part_details ddr_params[MAX_CHAN_NUM]; + struct ddr_freq_plan_v5 ddr_freq_tbl; + u8 num_channels; + u8 _padding; + struct ddr_regions_v5 ddr_regions; +}; + +/* V6 */ +struct ddr_misc_info_v6 { + __le32 dsf_version; + __le32 reserved[10]; +}; + +/* V7 */ +struct ddr_details_v7 { + u8 manufacturer_id; + u8 device_type; + struct ddr_part_details ddr_params[MAX_CHAN_NUM]; + struct ddr_freq_plan_v5 ddr_freq_tbl; + u8 num_channels; + u8 sct_config; + struct ddr_regions_v5 ddr_regions; +}; + +/** + * qcom_smem_dram_get_hbb(): Get the Highest bank address bit + * + * Context: Check qcom_smem_is_available() before calling this function. + * Because __dram * is initialized by smem_dram_parse(), which is in turn + * called from * qcom_smem_probe(), __dram will only be NULL if the data + * couldn't have been found/interpreted correctly. + * + * Return: highest bank bit on success, -ENODATA on failure. + */ +int qcom_smem_dram_get_hbb(void) +{ + if (!__dram || !__dram->hbb) + return -ENODATA; + + if (__dram->hbb < DDR_HBB_MIN || __dram->hbb > DDR_HBB_MAX) + return -ENODATA; + + return __dram->hbb; +} +EXPORT_SYMBOL_GPL(qcom_smem_dram_get_hbb); + +static void smem_dram_parse_v3_data(struct smem_dram *dram, void *data) +{ + struct ddr_details_v3 *details = data; + + for (int i = 0; i < MAX_DDR_FREQ_NUM_V3; i++) { + struct ddr_freq_table *freq_entry = &details->ddr_freq_tbl.ddr_freq[i]; + + if (freq_entry->freq_khz && freq_entry->enabled) { + u32 freq_khz = le32_to_cpu(freq_entry->freq_khz); + dram->frequencies[dram->num_frequencies++] = 1000 * freq_khz; + } + } +} + +static void smem_dram_parse_v3_14freqs_data(struct smem_dram *dram, void *data) +{ + struct ddr_details_v3_14freqs *details = data; + + for (int i = 0; i < MAX_DDR_FREQ_NUM_V3 + 1; i++) { + struct ddr_freq_table *freq_entry = &details->ddr_freq_tbl.ddr_freq[i]; + + if (freq_entry->freq_khz && freq_entry->enabled) + dram->frequencies[dram->num_frequencies++] = 1000 * freq_entry->freq_khz; + } +} + +static void smem_dram_parse_v4_data(struct smem_dram *dram, void *data) +{ + struct ddr_details_v4 *details = data; + + /* Rank 0 channel 0 entry holds the correct value */ + dram->hbb = details->highest_bank_addr_bit[0][0]; + + for (int i = 0; i < MAX_DDR_FREQ_NUM_V3; i++) { + struct ddr_freq_table *freq_entry = &details->ddr_freq_tbl.ddr_freq[i]; + + if (freq_entry->freq_khz && freq_entry->enabled) { + u32 freq_khz = le32_to_cpu(freq_entry->freq_khz); + dram->frequencies[dram->num_frequencies++] = 1000 * freq_khz; + } + } +} + +static void smem_dram_parse_v5_data(struct smem_dram *dram, void *data) +{ + struct ddr_details_v5 *details = data; + struct ddr_regions_v5 *region = &details->ddr_regions; + + dram->hbb = le32_to_cpu(region[0].highest_bank_addr_bit); + + for (int i = 0; i < MAX_DDR_FREQ_NUM_V5; i++) { + struct ddr_freq_table *freq_entry = &details->ddr_freq_tbl.ddr_freq[i]; + + if (freq_entry->freq_khz && freq_entry->enabled) { + u32 freq_khz = le32_to_cpu(freq_entry->freq_khz); + dram->frequencies[dram->num_frequencies++] = 1000 * freq_khz; + } + } +} + +static void smem_dram_parse_v7_data(struct smem_dram *dram, void *data) +{ + struct ddr_details_v7 *details = data; + struct ddr_regions_v5 *region = &details->ddr_regions; + + dram->hbb = le32_to_cpu(region[0].highest_bank_addr_bit); + + for (int i = 0; i < MAX_DDR_FREQ_NUM_V5; i++) { + struct ddr_freq_table *freq_entry = &details->ddr_freq_tbl.ddr_freq[i]; + + if (freq_entry->freq_khz && freq_entry->enabled) { + u32 freq_khz = le32_to_cpu(freq_entry->freq_khz); + dram->frequencies[dram->num_frequencies++] = 1000 * freq_khz; + } + } +} + +/* The structure contains no version field, so we have to perform some guesswork.. */ +static int smem_dram_infer_struct_version(size_t size) +{ + /* Some early versions provided less bytes of less useful data */ + if (size < sizeof(struct ddr_details_v3)) + return -EINVAL; + + if (size == sizeof(struct ddr_details_v3)) + return INFO_V3; + + if (size == sizeof(struct ddr_details_v3_14freqs)) + return INFO_V3_WITH_14_FREQS; + + if (size == sizeof(struct ddr_details_v4)) + return INFO_V4; + + if (size == sizeof(struct ddr_details_v5) + + 4 * sizeof(struct ddr_region_v5)) + return INFO_V5; + + if (size == sizeof(struct ddr_details_v5) + + 4 * sizeof(struct ddr_region_v5) + + sizeof(struct ddr_xbl2quantum_smem_data) + + sizeof(struct shub_freq_plan_entry)) + return INFO_V5; + + if (size == sizeof(struct ddr_details_v5) + + 6 * sizeof(struct ddr_region_v5)) + return INFO_V5_WITH_6_REGIONS; + + if (size == sizeof(struct ddr_details_v5) + + 6 * sizeof(struct ddr_region_v5) + + sizeof(struct ddr_xbl2quantum_smem_data) + + sizeof(struct shub_freq_plan_entry)) + return INFO_V5_WITH_6_REGIONS; + + if (size == sizeof(struct ddr_details_v5) + + 6 * sizeof(struct ddr_region_v5) + + sizeof(struct ddr_misc_info_v6) + + sizeof(struct shub_freq_plan_entry)) + return INFO_V6; + + if (size == sizeof(struct ddr_details_v7) + + 4 * sizeof(struct ddr_region_v5) + + sizeof(struct ddr_misc_info_v6) + + sizeof(struct shub_freq_plan_entry)) + return INFO_V7; + + if (size == sizeof(struct ddr_details_v7) + + 6 * sizeof(struct ddr_region_v5) + + sizeof(struct ddr_misc_info_v6) + + sizeof(struct shub_freq_plan_entry)) + return INFO_V7_WITH_6_REGIONS; + + return INFO_UNKNOWN; +} + +static int smem_dram_frequencies_show(struct seq_file *s, void *unused) +{ + struct smem_dram *dram = s->private; + + for (int i = 0; i < dram->num_frequencies; i++) + seq_printf(s, "%lu\n", dram->frequencies[i]); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(smem_dram_frequencies); + +static int smem_hbb_show(struct seq_file *s, void *unused) +{ + struct smem_dram *dram = s->private; + + if (!dram->hbb) + return -EINVAL; + + seq_printf(s, "%d\n", dram->hbb); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(smem_hbb); + +struct dentry *smem_dram_parse(struct qcom_smem *smem, struct device *dev) +{ + struct dentry *debugfs_dir; + enum ddr_info_version ver; + struct smem_dram *dram; + size_t actual_size; + void *data; + + /* No need to check qcom_smem_is_available(), this func is called by the SMEM driver */ + data = __qcom_smem_get(smem, QCOM_SMEM_HOST_ANY, SMEM_DDR_INFO_ID, &actual_size); + if (IS_ERR_OR_NULL(data)) + return ERR_PTR(-ENODATA); + + ver = smem_dram_infer_struct_version(actual_size); + if (ver < 0) { + /* Some SoCs don't provide data that's useful for us */ + return ERR_PTR(-ENODATA); + } else if (ver == INFO_UNKNOWN) { + /* In other cases, we may not have added support for a newer struct revision */ + dev_err(dev, "Found an unknown type of DRAM info struct (size = %zu)\n", + actual_size); + return ERR_PTR(-EINVAL); + } + + dram = devm_kzalloc(dev, sizeof(*dram), GFP_KERNEL); + if (!dram) + return ERR_PTR(-ENOMEM); + + switch (ver) { + case INFO_V3: + smem_dram_parse_v3_data(dram, data); + break; + case INFO_V3_WITH_14_FREQS: + smem_dram_parse_v3_14freqs_data(dram, data); + break; + case INFO_V4: + smem_dram_parse_v4_data(dram, data); + break; + case INFO_V5: + case INFO_V5_WITH_6_REGIONS: + case INFO_V6: + smem_dram_parse_v5_data(dram, data); + break; + case INFO_V7: + case INFO_V7_WITH_6_REGIONS: + smem_dram_parse_v7_data(dram, data); + break; + default: + return ERR_PTR(-EINVAL); + } + + debugfs_dir = debugfs_create_dir("qcom_smem", NULL); + debugfs_create_file("dram_frequencies", 0444, debugfs_dir, dram, + &smem_dram_frequencies_fops); + debugfs_create_file("hbb", 0444, debugfs_dir, dram, &smem_hbb_fops); + + __dram = dram; + + return debugfs_dir; +} diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index af418adad7aa..1836e226a294 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -425,6 +425,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(IPQ8078) }, { qcom_board_id(SDM636) }, { qcom_board_id(SDA636) }, + { qcom_board_id(SDM850) }, { qcom_board_id(SDM632) }, { qcom_board_id(SDA632) }, { qcom_board_id(SDA450) }, diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c index 3fe47d8f0f63..23901a4c51f7 100644 --- a/drivers/soc/qcom/ubwc_config.c +++ b/drivers/soc/qcom/ubwc_config.c @@ -11,298 +11,183 @@ #include <linux/platform_device.h> #include <linux/soc/qcom/ubwc.h> +#include <linux/soc/qcom/smem.h> static const struct qcom_ubwc_cfg_data no_ubwc_data = { /* no UBWC, no HBB */ }; -static const struct qcom_ubwc_cfg_data eliza_data = { - .ubwc_enc_version = UBWC_5_0, - .ubwc_dec_version = UBWC_5_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, - /* TODO: highest_bank_bit = 14 for LP_DDR4 */ +static const struct qcom_ubwc_cfg_data ubwc_0_0_hbb15 = { + /* no UBWC */ .highest_bank_bit = 15, - .macrotile_mode = true, }; -static const struct qcom_ubwc_cfg_data kaanapali_data = { - .ubwc_enc_version = UBWC_6_0, - .ubwc_dec_version = UBWC_6_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, - .highest_bank_bit = 16, - .macrotile_mode = true, -}; - -static const struct qcom_ubwc_cfg_data msm8937_data = { +static const struct qcom_ubwc_cfg_data ubwc_1_0_hbb14 = { .ubwc_enc_version = UBWC_1_0, - .ubwc_dec_version = UBWC_1_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 | - UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, .highest_bank_bit = 14, }; -static const struct qcom_ubwc_cfg_data msm8998_data = { +static const struct qcom_ubwc_cfg_data ubwc_1_0_hbb15 = { .ubwc_enc_version = UBWC_1_0, - .ubwc_dec_version = UBWC_1_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 | - UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .highest_bank_bit = 15, -}; - -static const struct qcom_ubwc_cfg_data qcm2290_data = { - /* no UBWC */ .highest_bank_bit = 15, }; -static const struct qcom_ubwc_cfg_data sa8775p_data = { - .ubwc_enc_version = UBWC_4_0, - .ubwc_dec_version = UBWC_4_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, - .highest_bank_bit = 13, - .macrotile_mode = true, -}; - -static const struct qcom_ubwc_cfg_data sar2130p_data = { - .ubwc_enc_version = UBWC_3_0, /* 4.0.2 in hw */ - .ubwc_dec_version = UBWC_4_3, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, - .highest_bank_bit = 13, - .macrotile_mode = true, -}; - -static const struct qcom_ubwc_cfg_data sc7180_data = { +static const struct qcom_ubwc_cfg_data ubwc_2_0_hbb14 = { .ubwc_enc_version = UBWC_2_0, - .ubwc_dec_version = UBWC_2_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, .highest_bank_bit = 14, }; -static const struct qcom_ubwc_cfg_data sc7280_data = { - .ubwc_enc_version = UBWC_3_0, - .ubwc_dec_version = UBWC_4_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, - .highest_bank_bit = 14, - .macrotile_mode = true, -}; - -static const struct qcom_ubwc_cfg_data sc8180x_data = { - .ubwc_enc_version = UBWC_3_0, - .ubwc_dec_version = UBWC_3_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .highest_bank_bit = 16, - .macrotile_mode = true, -}; - -static const struct qcom_ubwc_cfg_data sc8280xp_data = { - .ubwc_enc_version = UBWC_4_0, - .ubwc_dec_version = UBWC_4_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, - .highest_bank_bit = 16, - .macrotile_mode = true, -}; - -static const struct qcom_ubwc_cfg_data sdm670_data = { +static const struct qcom_ubwc_cfg_data ubwc_2_0_hbb15 = { .ubwc_enc_version = UBWC_2_0, - .ubwc_dec_version = UBWC_2_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .highest_bank_bit = 14, -}; - -static const struct qcom_ubwc_cfg_data sdm845_data = { - .ubwc_enc_version = UBWC_2_0, - .ubwc_dec_version = UBWC_2_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, .highest_bank_bit = 15, }; -static const struct qcom_ubwc_cfg_data sm6115_data = { - .ubwc_enc_version = UBWC_1_0, - .ubwc_dec_version = UBWC_2_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 | - UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, - .highest_bank_bit = 14, +static const struct qcom_ubwc_cfg_data ubwc_3_0_hbb15 = { + .ubwc_enc_version = UBWC_3_0, + .highest_bank_bit = 15, }; -static const struct qcom_ubwc_cfg_data sm6125_data = { - .ubwc_enc_version = UBWC_1_0, - .ubwc_dec_version = UBWC_3_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 | - UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .highest_bank_bit = 14, +static const struct qcom_ubwc_cfg_data ubwc_3_1_hbb13 = { + .ubwc_enc_version = UBWC_3_1, + .highest_bank_bit = 13, }; -static const struct qcom_ubwc_cfg_data sm6150_data = { - .ubwc_enc_version = UBWC_2_0, - .ubwc_dec_version = UBWC_2_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, +static const struct qcom_ubwc_cfg_data ubwc_3_1_hbb14 = { + .ubwc_enc_version = UBWC_3_1, .highest_bank_bit = 14, }; -static const struct qcom_ubwc_cfg_data sm6350_data = { - .ubwc_enc_version = UBWC_2_0, - .ubwc_dec_version = UBWC_2_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, - .highest_bank_bit = 14, +static const struct qcom_ubwc_cfg_data ubwc_3_1_hbb16 = { + .ubwc_enc_version = UBWC_3_1, + .highest_bank_bit = 16, }; -static const struct qcom_ubwc_cfg_data sm7150_data = { - .ubwc_enc_version = UBWC_2_0, - .ubwc_dec_version = UBWC_2_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .highest_bank_bit = 14, +static const struct qcom_ubwc_cfg_data ubwc_4_0_hbb16 = { + .ubwc_enc_version = UBWC_4_0, + .highest_bank_bit = 16, }; -static const struct qcom_ubwc_cfg_data sm8150_data = { - .ubwc_enc_version = UBWC_3_0, - .ubwc_dec_version = UBWC_3_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, +static const struct qcom_ubwc_cfg_data ubwc_5_0_hbb15 = { + .ubwc_enc_version = UBWC_5_0, + /* TODO: highest_bank_bit = 14 for LP_DDR4 */ .highest_bank_bit = 15, }; -static const struct qcom_ubwc_cfg_data sm8250_data = { - .ubwc_enc_version = UBWC_4_0, - .ubwc_dec_version = UBWC_4_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, - /* TODO: highest_bank_bit = 15 for LP_DDR4 */ +static const struct qcom_ubwc_cfg_data ubwc_5_0_hbb16 = { + .ubwc_enc_version = UBWC_5_0, .highest_bank_bit = 16, - .macrotile_mode = true, }; -static const struct qcom_ubwc_cfg_data sm8350_data = { - .ubwc_enc_version = UBWC_4_0, - .ubwc_dec_version = UBWC_4_0, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, - /* TODO: highest_bank_bit = 15 for LP_DDR4 */ +static const struct qcom_ubwc_cfg_data ubwc_6_0_hbb16 = { + .ubwc_enc_version = UBWC_6_0, .highest_bank_bit = 16, - .macrotile_mode = true, }; -static const struct qcom_ubwc_cfg_data sm8550_data = { +static const struct qcom_ubwc_cfg_data sa8775p_data = { .ubwc_enc_version = UBWC_4_0, - .ubwc_dec_version = UBWC_4_3, - .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | - UBWC_SWIZZLE_ENABLE_LVL3, - .ubwc_bank_spread = true, - /* TODO: highest_bank_bit = 15 for LP_DDR4 */ - .highest_bank_bit = 16, - .macrotile_mode = true, + .flags = UBWC_FLAG_DISABLE_SWIZZLE_LVL2, + .highest_bank_bit = 13, }; -static const struct qcom_ubwc_cfg_data sm8750_data = { +static const struct qcom_ubwc_cfg_data glymur_data = { .ubwc_enc_version = UBWC_5_0, - .ubwc_dec_version = UBWC_5_0, - .ubwc_swizzle = 6, - .ubwc_bank_spread = true, + .flags = UBWC_FLAG_DISABLE_SWIZZLE_LVL2 | + UBWC_FLAG_DISABLE_SWIZZLE_LVL3, /* TODO: highest_bank_bit = 15 for LP_DDR4 */ .highest_bank_bit = 16, - .macrotile_mode = true, }; -static const struct qcom_ubwc_cfg_data glymur_data = { - .ubwc_enc_version = UBWC_5_0, - .ubwc_dec_version = UBWC_5_0, - .ubwc_swizzle = 0, - .ubwc_bank_spread = true, - /* TODO: highest_bank_bit = 15 for LP_DDR4 */ - .highest_bank_bit = 16, - .macrotile_mode = true, +static const struct qcom_ubwc_cfg_data milos_data = { + .ubwc_enc_version = UBWC_4_0, + .flags = UBWC_SWIZZLE_ENABLE_LVL2 | + UBWC_SWIZZLE_ENABLE_LVL3, + /* TODO: highest_bank_bit = 14 for LP_DDR4 */ + .highest_bank_bit = 15, }; static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = { { .compatible = "qcom,apq8016", .data = &no_ubwc_data }, { .compatible = "qcom,apq8026", .data = &no_ubwc_data }, { .compatible = "qcom,apq8074", .data = &no_ubwc_data }, - { .compatible = "qcom,apq8096", .data = &msm8998_data }, - { .compatible = "qcom,eliza", .data = &eliza_data, }, - { .compatible = "qcom,kaanapali", .data = &kaanapali_data, }, + { .compatible = "qcom,apq8096", .data = &ubwc_1_0_hbb15 }, + { .compatible = "qcom,eliza", .data = &ubwc_5_0_hbb15 }, { .compatible = "qcom,glymur", .data = &glymur_data}, + { .compatible = "qcom,kaanapali", .data = &ubwc_6_0_hbb16 }, { .compatible = "qcom,mahua", .data = &glymur_data }, + { .compatible = "qcom,milos", .data = &milos_data }, { .compatible = "qcom,msm8226", .data = &no_ubwc_data }, { .compatible = "qcom,msm8916", .data = &no_ubwc_data }, { .compatible = "qcom,msm8917", .data = &no_ubwc_data }, - { .compatible = "qcom,msm8937", .data = &msm8937_data }, + { .compatible = "qcom,msm8937", .data = &ubwc_1_0_hbb14 }, { .compatible = "qcom,msm8929", .data = &no_ubwc_data }, { .compatible = "qcom,msm8939", .data = &no_ubwc_data }, - { .compatible = "qcom,msm8953", .data = &msm8937_data }, + { .compatible = "qcom,msm8953", .data = &ubwc_1_0_hbb14 }, { .compatible = "qcom,msm8956", .data = &no_ubwc_data }, { .compatible = "qcom,msm8974", .data = &no_ubwc_data }, { .compatible = "qcom,msm8976", .data = &no_ubwc_data }, - { .compatible = "qcom,msm8996", .data = &msm8998_data }, - { .compatible = "qcom,msm8998", .data = &msm8998_data }, - { .compatible = "qcom,qcm2290", .data = &qcm2290_data, }, - { .compatible = "qcom,qcm6490", .data = &sc7280_data, }, - { .compatible = "qcom,qcs8300", .data = &sc8280xp_data, }, - { .compatible = "qcom,sa8155p", .data = &sm8150_data, }, - { .compatible = "qcom,sa8540p", .data = &sc8280xp_data, }, + { .compatible = "qcom,msm8996", .data = &ubwc_1_0_hbb15 }, + { .compatible = "qcom,msm8998", .data = &ubwc_1_0_hbb15 }, + { .compatible = "qcom,qcm2290", .data = &ubwc_0_0_hbb15, }, + { .compatible = "qcom,qcm6490", .data = &ubwc_3_1_hbb14, }, + { .compatible = "qcom,qcs8300", .data = &ubwc_4_0_hbb16, }, + { .compatible = "qcom,sa8155p", .data = &ubwc_3_0_hbb15, }, + { .compatible = "qcom,sa8540p", .data = &ubwc_4_0_hbb16, }, { .compatible = "qcom,sa8775p", .data = &sa8775p_data, }, - { .compatible = "qcom,sar2130p", .data = &sar2130p_data }, - { .compatible = "qcom,sc7180", .data = &sc7180_data }, - { .compatible = "qcom,sc7280", .data = &sc7280_data, }, - { .compatible = "qcom,sc8180x", .data = &sc8180x_data, }, - { .compatible = "qcom,sc8280xp", .data = &sc8280xp_data, }, - { .compatible = "qcom,sda660", .data = &msm8937_data }, - { .compatible = "qcom,sdm450", .data = &msm8937_data }, - { .compatible = "qcom,sdm630", .data = &msm8937_data }, - { .compatible = "qcom,sdm632", .data = &msm8937_data }, - { .compatible = "qcom,sdm636", .data = &msm8937_data }, - { .compatible = "qcom,sdm660", .data = &msm8937_data }, - { .compatible = "qcom,sdm670", .data = &sdm670_data, }, - { .compatible = "qcom,sdm845", .data = &sdm845_data, }, - { .compatible = "qcom,sm4250", .data = &sm6115_data, }, - { .compatible = "qcom,sm6115", .data = &sm6115_data, }, - { .compatible = "qcom,sm6125", .data = &sm6125_data, }, - { .compatible = "qcom,sm6150", .data = &sm6150_data, }, - { .compatible = "qcom,sm6350", .data = &sm6350_data, }, - { .compatible = "qcom,sm6375", .data = &sm6350_data, }, - { .compatible = "qcom,sm7125", .data = &sc7180_data }, - { .compatible = "qcom,sm7150", .data = &sm7150_data, }, - { .compatible = "qcom,sm7225", .data = &sm6350_data, }, - { .compatible = "qcom,sm7325", .data = &sc7280_data, }, - { .compatible = "qcom,sm8150", .data = &sm8150_data, }, - { .compatible = "qcom,sm8250", .data = &sm8250_data, }, - { .compatible = "qcom,sm8350", .data = &sm8350_data, }, - { .compatible = "qcom,sm8450", .data = &sm8350_data, }, - { .compatible = "qcom,sm8550", .data = &sm8550_data, }, - { .compatible = "qcom,sm8650", .data = &sm8550_data, }, - { .compatible = "qcom,sm8750", .data = &sm8750_data, }, - { .compatible = "qcom,x1e80100", .data = &sm8550_data, }, - { .compatible = "qcom,x1p42100", .data = &sm8550_data, }, + { .compatible = "qcom,sar2130p", .data = &ubwc_3_1_hbb13 }, + { .compatible = "qcom,sc7180", .data = &ubwc_2_0_hbb14, }, + { .compatible = "qcom,sc7280", .data = &ubwc_3_1_hbb14, }, + { .compatible = "qcom,sc8180x", .data = &ubwc_3_1_hbb16, }, + { .compatible = "qcom,sc8280xp", .data = &ubwc_4_0_hbb16, }, + { .compatible = "qcom,sda660", .data = &ubwc_1_0_hbb14 }, + { .compatible = "qcom,sdm450", .data = &ubwc_1_0_hbb14 }, + { .compatible = "qcom,sdm630", .data = &ubwc_1_0_hbb14 }, + { .compatible = "qcom,sdm632", .data = &ubwc_1_0_hbb14 }, + { .compatible = "qcom,sdm636", .data = &ubwc_1_0_hbb14 }, + { .compatible = "qcom,sdm660", .data = &ubwc_1_0_hbb14 }, + { .compatible = "qcom,sdm670", .data = &ubwc_2_0_hbb14, }, + { .compatible = "qcom,sdm845", .data = &ubwc_2_0_hbb15, }, + { .compatible = "qcom,shikra", .data = &ubwc_0_0_hbb15, }, + { .compatible = "qcom,sm4250", .data = &ubwc_1_0_hbb14, }, + { .compatible = "qcom,sm6115", .data = &ubwc_1_0_hbb14, }, + { .compatible = "qcom,sm6125", .data = &ubwc_1_0_hbb14, }, + { .compatible = "qcom,sm6150", .data = &ubwc_2_0_hbb14, }, + { .compatible = "qcom,sm6350", .data = &ubwc_2_0_hbb14, }, + { .compatible = "qcom,sm6375", .data = &ubwc_2_0_hbb14, }, + { .compatible = "qcom,sm7125", .data = &ubwc_2_0_hbb14, }, + { .compatible = "qcom,sm7150", .data = &ubwc_2_0_hbb14, }, + { .compatible = "qcom,sm7225", .data = &ubwc_2_0_hbb14, }, + { .compatible = "qcom,sm7325", .data = &ubwc_3_1_hbb14, }, + { .compatible = "qcom,sm8150", .data = &ubwc_3_0_hbb15, }, + { .compatible = "qcom,sm8250", .data = &ubwc_4_0_hbb16, }, + { .compatible = "qcom,sm8350", .data = &ubwc_4_0_hbb16, }, + { .compatible = "qcom,sm8450", .data = &ubwc_4_0_hbb16, }, + { .compatible = "qcom,sm8550", .data = &ubwc_4_0_hbb16, }, + { .compatible = "qcom,sm8650", .data = &ubwc_4_0_hbb16, }, + { .compatible = "qcom,sm8750", .data = &ubwc_5_0_hbb16, }, + { .compatible = "qcom,x1e80100", .data = &ubwc_4_0_hbb16, }, + { .compatible = "qcom,x1p42100", .data = &ubwc_4_0_hbb16, }, { } }; +static struct qcom_ubwc_cfg_data *cfg; +static DEFINE_MUTEX(cfg_mutex); +/** + * qcom_ubwc_config_get_data() - Retrieve UBWC data for the platform. + * + * Return: Pointer to valid struct qcom_ubwc_cfg_data on success, negative + * errno on failure. Note that this may return EPROBE_DEFER. + */ const struct qcom_ubwc_cfg_data *qcom_ubwc_config_get_data(void) { const struct qcom_ubwc_cfg_data *data; + int hbb; + + guard(mutex)(&cfg_mutex); + if (cfg) + return cfg; + + if (!qcom_smem_is_available()) + return ERR_PTR(-EPROBE_DEFER); data = of_machine_get_match_data(qcom_ubwc_configs); if (!data) { @@ -310,9 +195,30 @@ const struct qcom_ubwc_cfg_data *qcom_ubwc_config_get_data(void) return ERR_PTR(-EINVAL); } - return data; + hbb = qcom_smem_dram_get_hbb(); + if (hbb == -ENODATA) { + /* Lack of HBB data is OK - it was only introduced later */ + return data; + } else if (hbb < 0) { + pr_err("Couldn't get HBB data from SMEM: %d\n", hbb); + return ERR_PTR(hbb); + } + + cfg = kmemdup(data, sizeof(*data), GFP_KERNEL); + if (!cfg) + return ERR_PTR(-ENOMEM); + + cfg->highest_bank_bit = hbb; + + return cfg; } EXPORT_SYMBOL_GPL(qcom_ubwc_config_get_data); +static void __exit ubwc_config_exit(void) +{ + kfree(cfg); +} +module_exit(ubwc_config_exit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("UBWC config database for QTI SoCs"); diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 2ab150d04bb1..fdf18ed2dfc2 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -356,7 +356,6 @@ config ARCH_R8A779H0 config ARCH_R8A78000 bool "ARM64 Platform support for R8A78000 (R-Car X5H)" default y if ARCH_RENESAS - default ARCH_RENESAS select ARCH_RCAR_GEN5 help This enables support for the Renesas R-Car X5H SoC. diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c index d58376c38179..f5fcdde9750e 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -167,8 +167,8 @@ static const struct mfd_cell exynos_pmu_devs[] = { */ struct regmap *exynos_get_pmu_regmap(void) { - struct device_node *np = of_find_matching_node(NULL, - exynos_pmu_of_device_ids); + struct device_node *np __free(device_node) = + of_find_matching_node(NULL, exynos_pmu_of_device_ids); if (np) return exynos_get_pmu_regmap_by_phandle(np, NULL); return ERR_PTR(-ENODEV); diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index 073346c1542b..8b6fdb9ad1ea 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig @@ -171,6 +171,7 @@ config SOC_TEGRA_FLOWCTRL config SOC_TEGRA_PMC bool + depends on PM select GENERIC_PINCONF select IRQ_DOMAIN_HIERARCHY select PM_OPP diff --git a/drivers/soc/tegra/cbb/tegra194-cbb.c b/drivers/soc/tegra/cbb/tegra194-cbb.c index 2f69e104c838..69ef929e04f8 100644 --- a/drivers/soc/tegra/cbb/tegra194-cbb.c +++ b/drivers/soc/tegra/cbb/tegra194-cbb.c @@ -2072,20 +2072,15 @@ static int tegra194_cbb_interrupt_enable(struct tegra_cbb *cbb) if (priv->sec_irq) { err = devm_request_irq(dev, priv->sec_irq, tegra194_cbb_err_isr, 0, dev_name(dev), priv); - if (err) { - dev_err(dev, "failed to register interrupt %u: %d\n", priv->sec_irq, err); + if (err) return err; - } } if (priv->nonsec_irq) { err = devm_request_irq(dev, priv->nonsec_irq, tegra194_cbb_err_isr, 0, dev_name(dev), priv); - if (err) { - dev_err(dev, "failed to register interrupt %u: %d\n", priv->nonsec_irq, - err); + if (err) return err; - } } return 0; diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index 78b054d43a42..39654964c35c 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -258,6 +258,7 @@ static int tegra_fuse_probe(struct platform_device *pdev) static int __maybe_unused tegra_fuse_runtime_resume(struct device *dev) { + struct tegra_fuse *fuse = dev_get_drvdata(dev); int err; err = clk_prepare_enable(fuse->clk); @@ -271,6 +272,8 @@ static int __maybe_unused tegra_fuse_runtime_resume(struct device *dev) static int __maybe_unused tegra_fuse_runtime_suspend(struct device *dev) { + struct tegra_fuse *fuse = dev_get_drvdata(dev); + clk_disable_unprepare(fuse->clk); return 0; @@ -278,6 +281,7 @@ static int __maybe_unused tegra_fuse_runtime_suspend(struct device *dev) static int __maybe_unused tegra_fuse_suspend(struct device *dev) { + struct tegra_fuse *fuse = dev_get_drvdata(dev); int ret; /* @@ -294,6 +298,7 @@ static int __maybe_unused tegra_fuse_suspend(struct device *dev) static int __maybe_unused tegra_fuse_resume(struct device *dev) { + struct tegra_fuse *fuse = dev_get_drvdata(dev); int ret = 0; if (fuse->soc->clk_suspend_on) diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 524fa1b0cd3d..2fad8b13a3b9 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -64,28 +64,6 @@ static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset) return value; } -static void __init tegra30_fuse_add_randomness(void) -{ - u32 randomness[12]; - - randomness[0] = tegra_sku_info.sku_id; - randomness[1] = tegra_read_straps(); - randomness[2] = tegra_read_chipid(); - randomness[3] = tegra_sku_info.cpu_process_id << 16; - randomness[3] |= tegra_sku_info.soc_process_id; - randomness[4] = tegra_sku_info.cpu_speedo_id << 16; - randomness[4] |= tegra_sku_info.soc_speedo_id; - randomness[5] = tegra_fuse_read_early(FUSE_VENDOR_CODE); - randomness[6] = tegra_fuse_read_early(FUSE_FAB_CODE); - randomness[7] = tegra_fuse_read_early(FUSE_LOT_CODE_0); - randomness[8] = tegra_fuse_read_early(FUSE_LOT_CODE_1); - randomness[9] = tegra_fuse_read_early(FUSE_WAFER_ID); - randomness[10] = tegra_fuse_read_early(FUSE_X_COORDINATE); - randomness[11] = tegra_fuse_read_early(FUSE_Y_COORDINATE); - - add_device_randomness(randomness, sizeof(randomness)); -} - static void __init tegra30_fuse_init(struct tegra_fuse *fuse) { fuse->read_early = tegra30_fuse_read_early; @@ -95,8 +73,6 @@ static void __init tegra30_fuse_init(struct tegra_fuse *fuse) if (fuse->soc->speedo_init) fuse->soc->speedo_init(&tegra_sku_info); - - tegra30_fuse_add_randomness(); } #endif diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index f419a5395545..41ed716d5857 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -3074,15 +3074,18 @@ static int tegra_pmc_probe(struct platform_device *pdev) } } - err = devm_register_sys_off_handler(&pdev->dev, - SYS_OFF_MODE_RESTART, - SYS_OFF_PRIO_LOW, - tegra_pmc_restart_handler, - pmc); - if (err) { - dev_err(&pdev->dev, "failed to register sys-off handler: %d\n", - err); - return err; + if (dev_to_node(&pdev->dev) == NUMA_NO_NODE) { + err = devm_register_sys_off_handler(&pdev->dev, + SYS_OFF_MODE_RESTART, + SYS_OFF_PRIO_LOW, + tegra_pmc_restart_handler, + pmc); + if (err) { + dev_err(&pdev->dev, + "failed to register sys-off handler: %d\n", + err); + return err; + } } /* diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h index 037dc1b36645..8a624fbda84a 100644 --- a/drivers/soc/ti/knav_qmss.h +++ b/drivers/soc/ti/knav_qmss.h @@ -304,6 +304,7 @@ struct knav_device { struct list_head pools; struct list_head pdsps; struct list_head qmgrs; + struct dentry *debugfs_file; enum qmss_version version; }; diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 7410b63af0e6..3e4041454f69 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -1849,8 +1849,9 @@ static int knav_queue_probe(struct platform_device *pdev) goto err; } - debugfs_create_file("qmss", S_IFREG | S_IRUGO, NULL, NULL, - &knav_queue_debug_fops); + knav_qdev->debugfs_file = + debugfs_create_file("qmss", 0444, NULL, NULL, + &knav_queue_debug_fops); device_ready = true; return 0; @@ -1868,6 +1869,8 @@ static void knav_queue_remove(struct platform_device *pdev) struct knav_device *kdev = platform_get_drvdata(pdev); device_ready = false; + debugfs_remove(kdev->debugfs_file); + kdev->debugfs_file = NULL; knav_queue_stop_pdsps(kdev); knav_queue_free_regions(kdev); knav_free_queue_ranges(kdev); diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 5845fc652adc..f8640cdc2a21 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -630,10 +630,8 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, wkup_m3_txev_handler, 0, "wkup_m3_txev", m3_ipc); - if (ret) { - dev_err(dev, "request_irq failed\n"); + if (ret) return ret; - } m3_ipc->mbox_client.dev = dev; m3_ipc->mbox_client.tx_done = NULL; diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index 370e61ac47d8..54c796afb89e 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c @@ -368,11 +368,8 @@ static int zynqmp_pm_probe(struct platform_device *pdev) IRQF_NO_SUSPEND | IRQF_ONESHOT, dev_name(&pdev->dev), &pdev->dev); - if (ret) { - dev_err(&pdev->dev, "devm_request_threaded_irq '%d' failed with %d\n", - irq, ret); + if (ret) return ret; - } } else { dev_err(&pdev->dev, "Required property not found in DT node\n"); return -ENOENT; diff --git a/drivers/tee/qcomtee/call.c b/drivers/tee/qcomtee/call.c index 0efc5646242a..4a597eeaf174 100644 --- a/drivers/tee/qcomtee/call.c +++ b/drivers/tee/qcomtee/call.c @@ -798,7 +798,12 @@ static void qcomtee_remove(struct platform_device *pdev) kfree(qcomtee); } -static const struct platform_device_id qcomtee_ids[] = { { "qcomtee", 0 }, {} }; +static const struct platform_device_id qcomtee_ids[] = { + { + .name = "qcomtee", + }, + { } +}; MODULE_DEVICE_TABLE(platform, qcomtee_ids); static struct platform_driver qcomtee_platform_driver = { diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index b3b1ec696bf5..10cff12a3f31 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -611,6 +611,7 @@ config USB_UHCI_ASPEED config USB_FHCI_HCD tristate "Freescale QE USB Host Controller support" depends on QE_GPIO && QUICC_ENGINE + depends on PPC select FSL_GTM select QE_USB help diff --git a/include/linux/firmware/qcom/qcom_pas.h b/include/linux/firmware/qcom/qcom_pas.h new file mode 100644 index 000000000000..65b1c9564458 --- /dev/null +++ b/include/linux/firmware/qcom/qcom_pas.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2010-2015, 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __QCOM_PAS_H +#define __QCOM_PAS_H + +#include <linux/err.h> +#include <linux/types.h> + +struct qcom_pas_context { + struct device *dev; + u32 pas_id; + phys_addr_t mem_phys; + size_t mem_size; + void *ptr; + dma_addr_t phys; + ssize_t size; + bool use_tzmem; +}; + +bool qcom_pas_is_available(void); +struct qcom_pas_context *devm_qcom_pas_context_alloc(struct device *dev, + u32 pas_id, + phys_addr_t mem_phys, + size_t mem_size); +int qcom_pas_init_image(u32 pas_id, const void *metadata, size_t size, + struct qcom_pas_context *ctx); +struct resource_table *qcom_pas_get_rsc_table(struct qcom_pas_context *ctx, + void *input_rt, size_t input_rt_size, + size_t *output_rt_size); +int qcom_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size); +int qcom_pas_auth_and_reset(u32 pas_id); +int qcom_pas_prepare_and_auth_reset(struct qcom_pas_context *ctx); +int qcom_pas_set_remote_state(u32 state, u32 pas_id); +int qcom_pas_shutdown(u32 pas_id); +bool qcom_pas_supported(u32 pas_id); +void qcom_pas_metadata_release(struct qcom_pas_context *ctx); + +#endif /* __QCOM_PAS_H */ diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index 7e27b0f7bf7e..69a2f74269f3 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -3,7 +3,7 @@ * Xilinx Zynq MPSoC Firmware layer * * Copyright (C) 2014-2021 Xilinx - * Copyright (C) 2022 - 2025 Advanced Micro Devices, Inc. + * Copyright (C) 2022 - 2026 Advanced Micro Devices, Inc. * * Michal Simek <michal.simek@amd.com> * Davorin Mista <davorin.mista@aggios.com> @@ -50,6 +50,7 @@ /* PM API versions */ #define PM_API_VERSION_1 1 #define PM_API_VERSION_2 2 +#define PM_API_VERSION_3 3 #define PM_PINCTRL_PARAM_SET_VERSION 2 @@ -66,6 +67,7 @@ #define FIRMWARE_VERSION_MASK 0xFFFFU /* ATF only commands */ +#define TF_A_CLEAR_PM_STATE 0xa05 #define TF_A_PM_REGISTER_SGI 0xa04 #define PM_GET_TRUSTZONE_VERSION 0xa03 #define PM_SET_SUSPEND_MODE 0xa02 @@ -144,6 +146,12 @@ #define XPM_EVENT_ERROR_MASK_NOC_NCR BIT(13) #define XPM_EVENT_ERROR_MASK_NOC_CR BIT(12) +/* Node ID for all peripheral devices */ +#define PM_DEV_ALL_PERIPH 0x18224FFFU + +/* Node ID for all notifier callbacks */ +#define PM_ALL_NOTIFIERS 0xFFFFFFFFU + enum pm_module_id { PM_MODULE_ID = 0x0, XPM_MODULE_ID = 0x2, diff --git a/include/linux/fsl/guts.h b/include/linux/fsl/guts.h index fdb55ca47a4f..8d5ffb985fee 100644 --- a/include/linux/fsl/guts.h +++ b/include/linux/fsl/guts.h @@ -13,6 +13,7 @@ #include <linux/types.h> #include <linux/io.h> +#include <soc/fsl/phy-fsl-lynx.h> /* * Global Utility Registers. @@ -91,9 +92,15 @@ struct ccsr_guts { u32 iovselsr; /* 0x.00c0 - I/O voltage select status register Called 'elbcvselcr' on 86xx SOCs */ u8 res0c4[0x100 - 0xc4]; - u32 rcwsr[16]; /* 0x.0100 - Reset Control Word Status registers - There are 16 registers */ - u8 res140[0x224 - 0x140]; + /* 0x.0100 - read-only Reset Configuration Word Status registers in + * CCSR, or write-only Reset Configuration Word Control registers in + * DCSR. In both cases there are 32 registers. + */ + union { + u32 rcwsr[32]; + u32 rcwcr[32]; + }; + u8 res180[0x224 - 0x180]; u32 iodelay1; /* 0x.0224 - IO delay control register 1 */ u32 iodelay2; /* 0x.0228 - IO delay control register 2 */ u8 res22c[0x604 - 0x22c]; @@ -131,6 +138,11 @@ struct ccsr_guts { u32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */ } __attribute__ ((packed)); +int fsl_guts_lane_validate(int serdes_idx, int lane, + enum lynx_lane_mode lane_mode); +int fsl_guts_lane_set_mode(int serdes_idx, int lane, + enum lynx_lane_mode lane_mode); + /* Alternate function signal multiplex control */ #define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x)) diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h index c5e6ab85df09..0991ef7ec092 100644 --- a/include/linux/soc/qcom/geni-se.h +++ b/include/linux/soc/qcom/geni-se.h @@ -124,6 +124,7 @@ struct geni_se { #define SE_DMA_RX_FSM_RST 0xd58 #define SE_HW_PARAM_0 0xe24 #define SE_HW_PARAM_1 0xe28 +#define SE_HW_PARAM_2 0xe2c /* GENI_FORCE_DEFAULT_REG fields */ #define FORCE_DEFAULT BIT(0) @@ -291,6 +292,9 @@ struct geni_se { #define RX_FIFO_DEPTH_MSK GENMASK(21, 16) #define RX_FIFO_DEPTH_SHFT 16 +/* SE_HW_PARAM_2 fields */ +#define PROG_RAM_DEPTH_MSK GENMASK(10, 0) + #define HW_VER_MAJOR_MASK GENMASK(31, 28) #define HW_VER_MAJOR_SHFT 28 #define HW_VER_MINOR_MASK GENMASK(27, 16) diff --git a/include/linux/soc/qcom/smem.h b/include/linux/soc/qcom/smem.h index f946e3beca21..3249cbd2016b 100644 --- a/include/linux/soc/qcom/smem.h +++ b/include/linux/soc/qcom/smem.h @@ -17,4 +17,6 @@ int qcom_smem_get_feature_code(u32 *code); int qcom_smem_bust_hwspin_lock_by_host(unsigned int host); +int qcom_smem_dram_get_hbb(void); + #endif diff --git a/include/linux/soc/qcom/ubwc.h b/include/linux/soc/qcom/ubwc.h index 83d2c2a7116c..f3a70360b177 100644 --- a/include/linux/soc/qcom/ubwc.h +++ b/include/linux/soc/qcom/ubwc.h @@ -8,25 +8,12 @@ #define __QCOM_UBWC_H__ #include <linux/bits.h> +#include <linux/err.h> #include <linux/printk.h> #include <linux/types.h> struct qcom_ubwc_cfg_data { u32 ubwc_enc_version; - /* Can be read from MDSS_BASE + 0x58 */ - u32 ubwc_dec_version; - - /** - * @ubwc_swizzle: Whether to enable level 1, 2 & 3 bank swizzling. - * - * UBWC 1.0 always enables all three levels. - * UBWC 2.0 removes level 1 bank swizzling, leaving levels 2 & 3. - * UBWC 4.0 adds the optional ability to disable levels 2 & 3. - */ - u32 ubwc_swizzle; -#define UBWC_SWIZZLE_ENABLE_LVL1 BIT(0) -#define UBWC_SWIZZLE_ENABLE_LVL2 BIT(1) -#define UBWC_SWIZZLE_ENABLE_LVL3 BIT(2) /** * @highest_bank_bit: Highest Bank Bit @@ -35,16 +22,10 @@ struct qcom_ubwc_cfg_data { * DDR bank. This should ideally use DRAM type detection. */ int highest_bank_bit; - bool ubwc_bank_spread; - /** - * @macrotile_mode: Macrotile Mode - * - * Whether to use 4-channel macrotiling mode or the newer - * 8-channel macrotiling mode introduced in UBWC 3.1. 0 is - * 4-channel and 1 is 8-channel. - */ - bool macrotile_mode; + unsigned int flags; +#define UBWC_FLAG_DISABLE_SWIZZLE_LVL2 BIT(0) +#define UBWC_FLAG_DISABLE_SWIZZLE_LVL3 BIT(1) }; #define UBWC_1_0 0x10000000 @@ -67,37 +48,62 @@ static inline const struct qcom_ubwc_cfg_data *qcom_ubwc_config_get_data(void) static inline bool qcom_ubwc_get_ubwc_mode(const struct qcom_ubwc_cfg_data *cfg) { - bool ret = cfg->ubwc_enc_version == UBWC_1_0; - - if (ret && !(cfg->ubwc_swizzle & UBWC_SWIZZLE_ENABLE_LVL1)) - pr_err("UBWC config discrepancy - level 1 swizzling disabled on UBWC 1.0\n"); - - return ret; + return cfg->ubwc_enc_version == UBWC_1_0; } -/* - * This is the best guess, based on the MDSS driver, which worked so far. - */ static inline bool qcom_ubwc_min_acc_length_64b(const struct qcom_ubwc_cfg_data *cfg) { - return cfg->ubwc_enc_version == UBWC_1_0 && - (cfg->ubwc_dec_version == UBWC_2_0 || - cfg->ubwc_dec_version == UBWC_3_0); + return cfg->ubwc_enc_version == UBWC_1_0; } +/* + * @qcom_ubwc_macrotile_mode: whether to use 4-channel or 8-channel macrotiling + * + * The 8-channel macrotiling mode was introduced in UBWC 3.1. + * + * Returns: false for the 4-channel and true for 8-channel. + */ static inline bool qcom_ubwc_macrotile_mode(const struct qcom_ubwc_cfg_data *cfg) { - return cfg->macrotile_mode; + return cfg->ubwc_enc_version >= UBWC_3_1; } static inline bool qcom_ubwc_bank_spread(const struct qcom_ubwc_cfg_data *cfg) { - return cfg->ubwc_bank_spread; + return true; } +#define UBWC_SWIZZLE_ENABLE_LVL1 BIT(0) +#define UBWC_SWIZZLE_ENABLE_LVL2 BIT(1) +#define UBWC_SWIZZLE_ENABLE_LVL3 BIT(2) + +/** + * @qcom_ubwc_swizzle: Whether to enable level 1, 2 & 3 bank swizzling. + * + * UBWC 1.0 always enables all three levels. + * UBWC 2.0 removes level 1 bank swizzling, leaving levels 2 & 3. + * UBWC 4.0 adds the optional ability to disable levels 2 & 3. + */ static inline u32 qcom_ubwc_swizzle(const struct qcom_ubwc_cfg_data *cfg) { - return cfg->ubwc_swizzle; + if (cfg->ubwc_enc_version == 0) + return 0; + + if (cfg->ubwc_enc_version == UBWC_1_0) + return UBWC_SWIZZLE_ENABLE_LVL1 | + UBWC_SWIZZLE_ENABLE_LVL2 | + UBWC_SWIZZLE_ENABLE_LVL3; + + u32 ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 | + UBWC_SWIZZLE_ENABLE_LVL3; + + if (cfg->flags & UBWC_FLAG_DISABLE_SWIZZLE_LVL2) + ubwc_swizzle &= ~UBWC_SWIZZLE_ENABLE_LVL2; + + if (cfg->flags & UBWC_FLAG_DISABLE_SWIZZLE_LVL3) + ubwc_swizzle &= ~UBWC_SWIZZLE_ENABLE_LVL3; + + return ubwc_swizzle; } static inline u32 qcom_ubwc_version_tag(const struct qcom_ubwc_cfg_data *cfg) diff --git a/include/soc/fsl/dpaa2-fd.h b/include/soc/fsl/dpaa2-fd.h index bae490cac0aa..0ca0766b2b0d 100644 --- a/include/soc/fsl/dpaa2-fd.h +++ b/include/soc/fsl/dpaa2-fd.h @@ -25,14 +25,15 @@ /** * struct dpaa2_fd - Struct describing FDs - * @words: for easier/faster copying the whole FD structure - * @addr: address in the FD - * @len: length in the FD - * @bpid: buffer pool ID - * @format_offset: format, offset, and short-length fields - * @frc: frame context - * @ctrl: control bits...including dd, sc, va, err, etc - * @flc: flow context address + * @words: for easier/faster copying the whole FD structure + * @simple: struct for the FD fields + * @simple.addr: address in the FD + * @simple.len: length in the FD + * @simple.bpid: buffer pool ID + * @simple.format_offset: format, offset, and short-length fields + * @simple.frc: frame context + * @simple.ctrl: control bits...including dd, sc, va, err, etc + * @simple.flc: flow context address * * This structure represents the basic Frame Descriptor used in the system. */ @@ -497,7 +498,7 @@ static inline void dpaa2_fl_set_addr(struct dpaa2_fl_entry *fle, * dpaa2_fl_get_frc() - Get the frame context in the FLE * @fle: the given frame list entry * - * Return the frame context field in the frame lsit entry. + * Return the frame context field in the frame list entry. */ static inline u32 dpaa2_fl_get_frc(const struct dpaa2_fl_entry *fle) { diff --git a/include/soc/fsl/dpaa2-io.h b/include/soc/fsl/dpaa2-io.h index 4bf62de2e00e..2a748fafa5b7 100644 --- a/include/soc/fsl/dpaa2-io.h +++ b/include/soc/fsl/dpaa2-io.h @@ -22,7 +22,7 @@ struct device; * DOC: DPIO Service * * The DPIO service provides APIs for users to interact with the datapath - * by enqueueing and dequeing frame descriptors. + * by enqueueing and dequeueing frame descriptors. * * The following set of APIs can be used to enqueue and dequeue frames * as well as producing notification callbacks when data is available @@ -33,7 +33,7 @@ struct device; /** * struct dpaa2_io_desc - The DPIO descriptor - * @receives_notifications: Use notificaton mode. Non-zero if the DPIO + * @receives_notifications: Use notification mode. Non-zero if the DPIO * has a channel. * @has_8prio: Set to non-zero for channel with 8 priority WQs. Ignored * unless receives_notification is TRUE. |
