mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 22:59:29 +02:00
Merge tag 'soc-drivers-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull SoC driver updates from Arnd Bergmann:
"The SoC driver changes once more consist of many small fixes and
cleanups, that are to a large part the result of automated testing.
On platform specific drivers, this includes SoC specific code for
xilinx, freescale/nxp, qualcomm, TI, aspeed, omap, tegra, samsung,
rockchip, renesas, ixp4xx. In firmware drivers, we see a similar
picture for SCMI and qcomtee.
Aside from these, we see actual new hardware support in a few areas:
- The Apple platform gets a new driver for low power states
- Updates to Qualcomm platform drivers add several new hardware
specific features and additional SoCs.
- Amlogic SoC support for A1 and T7 is added
- The Mediatek MMSYS driver is refactored as a cleanup"
* tag 'soc-drivers-7.3' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (157 commits)
soc: qcom: make QCOM_PDR_MSG selectable
soc: qcom: ubwc: Fix missing include
soc: qcom: ubwc: Fix link error when QCOM_SMEM=n
media: iris: Guard the QCOM_UBWC_CONFIG select with QCOM_SMEM
drm/msm: Guard the QCOM_UBWC_CONFIG select with QCOM_SMEM
dt-bindings: arm: qcom,ids: Add SoC ID for Snapdragon SDM 850
firmware: xilinx: Clear firmware notifiers across kexec transitions
firmware: xilinx: Release all peripheral devices from firmware
firmware: xilinx: Add support to clear EL3 PM state
firmware: xilinx: Propagate actual error from feature check
firmware: xilinx: Use TF-A feature check for TF-A-specific APIs
bus: fsl-mc: drop unused assignment of acpi_device_id::driver_data
soc: fsl: qe: check platform_driver_register() in qe_ic_of_init()
phy: lynx-10g: use RCW override procedure for dynamic protocol change
soc: fsl: guts: implement the RCW override procedure
dt-bindings: fsl: layerscape-dcfg: define DCFG_DCSR region
soc: fsl: guts: make fsl_soc_data available after fsl_guts_init()
soc: fsl: guts: make it easier to determine on which SoC we are running
soc: fsl: guts: add a central fsl_guts_read() function
soc: fsl: guts: add a global structure to hold state
...
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
>;
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -176,6 +176,20 @@ allOf:
|
||||
properties:
|
||||
dp-phy: false
|
||||
|
||||
- if:
|
||||
properties:
|
||||
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:
|
||||
@@ -183,6 +197,13 @@ allOf:
|
||||
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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
+11
-1
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+10
-34
@@ -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 devm_of_platform_populate(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_clk:
|
||||
clk_disable_unprepare(ebi2clk);
|
||||
err_disable_2x_clk:
|
||||
clk_disable_unprepare(ebi2xclk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id qcom_ebi2_of_match[] = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+110
-72
@@ -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);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -1706,6 +1697,25 @@ err:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
@@ -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 */
|
||||
@@ -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");
|
||||
@@ -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;
|
||||
|
||||
|
||||
+288
-211
@@ -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];
|
||||
}
|
||||
|
||||
int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
|
||||
struct qcom_scm_pas_context *ctx)
|
||||
{
|
||||
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);
|
||||
|
||||
/**
|
||||
* qcom_scm_pas_metadata_release() - release metadata context
|
||||
* @ctx: pas context
|
||||
*/
|
||||
void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
|
||||
static void __qcom_scm_pas_metadata_release(struct device *dev,
|
||||
struct qcom_pas_context *ctx)
|
||||
{
|
||||
if (!ctx->ptr)
|
||||
return;
|
||||
|
||||
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[] = {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
if (ret)
|
||||
ret = -EOPNOTSUPP;
|
||||
else
|
||||
ret = ret_payload[1];
|
||||
|
||||
return ret;
|
||||
/*
|
||||
* 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)
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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->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);
|
||||
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_EMC);
|
||||
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 Controller";
|
||||
else
|
||||
node->name = dev_name(emc->dev);
|
||||
|
||||
icc_node_add(node, &emc->provider);
|
||||
|
||||
/* link External Memory Controller to External Memory (DRAM) */
|
||||
err = tegra_mc_icc_link_create(node, node_id, TEGRA_ICC_EMEM);
|
||||
if (err)
|
||||
goto remove_nodes;
|
||||
|
||||
/* create External Memory node */
|
||||
node = tegra_mc_icc_node_create(node_id, TEGRA_ICC_EMEM);
|
||||
if (IS_ERR(node)) {
|
||||
err = PTR_ERR(node);
|
||||
goto remove_nodes;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>");
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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)))
|
||||
|
||||
+488
-40
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
setbits32(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_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);
|
||||
|
||||
out_be32(data->reg + CEPIER, 1 << (31 - irqd_to_hwirq(d)));
|
||||
iowrite32be(d->mask, gc->reg_base + CEPIER);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct qepic_data *data = irq_desc_get_handler_data(desc);
|
||||
u32 event = in_be32(data->reg + CEPIER);
|
||||
|
||||
if (!event)
|
||||
return -1;
|
||||
|
||||
return irq_find_mapping(data->host, 32 - ffs(event));
|
||||
}
|
||||
|
||||
static void qepic_cascade(struct irq_desc *desc)
|
||||
{
|
||||
generic_handle_irq(qepic_get_irq(desc));
|
||||
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;
|
||||
}
|
||||
|
||||
for_each_set_bit(bit, &event, 32)
|
||||
generic_handle_domain_irq(domain, 31 - bit);
|
||||
|
||||
out:
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static int qepic_host_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw)
|
||||
static int qepic_chip_init(struct irq_chip_generic *gc)
|
||||
{
|
||||
irq_set_chip_data(virq, h->host_data);
|
||||
irq_set_chip_and_handler(virq, &qepic, handle_fasteoi_irq);
|
||||
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 const struct irq_domain_ops qepic_host_ops = {
|
||||
.map = qepic_host_map,
|
||||
};
|
||||
|
||||
static void qepic_remove(void *res)
|
||||
static int qepic_domain_init(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, qepic_cascade, d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qepic_domain_exit(struct irq_domain *d)
|
||||
{
|
||||
struct qepic_data *data = d->host_data;
|
||||
|
||||
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[] = {
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
+128
-172
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
/*
|
||||
|
||||
+75
-52
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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, },
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+26
-11
@@ -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[] = {
|
||||
|
||||
+49
-32
@@ -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,6 +677,30 @@ invalid_canary:
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
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 (item >= smem->item_count)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
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);
|
||||
} else {
|
||||
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
|
||||
@@ -683,28 +712,9 @@ invalid_canary:
|
||||
*
|
||||
* 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(unsigned int host, unsigned int item, size_t *size)
|
||||
{
|
||||
struct smem_partition *part;
|
||||
void *ptr;
|
||||
|
||||
if (IS_ERR(__smem))
|
||||
return __smem;
|
||||
|
||||
if (item >= __smem->item_count)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
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);
|
||||
} else {
|
||||
ptr = qcom_smem_get_global(__smem, item, size);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
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);
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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) },
|
||||
|
||||
+158
-252
@@ -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 */
|
||||
.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 = {
|
||||
.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 = {
|
||||
.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 = {
|
||||
static const struct qcom_ubwc_cfg_data ubwc_0_0_hbb15 = {
|
||||
/* no UBWC */
|
||||
.highest_bank_bit = 15,
|
||||
};
|
||||
|
||||
static const struct qcom_ubwc_cfg_data ubwc_1_0_hbb14 = {
|
||||
.ubwc_enc_version = UBWC_1_0,
|
||||
.highest_bank_bit = 14,
|
||||
};
|
||||
|
||||
static const struct qcom_ubwc_cfg_data ubwc_1_0_hbb15 = {
|
||||
.ubwc_enc_version = UBWC_1_0,
|
||||
.highest_bank_bit = 15,
|
||||
};
|
||||
|
||||
static const struct qcom_ubwc_cfg_data ubwc_2_0_hbb14 = {
|
||||
.ubwc_enc_version = UBWC_2_0,
|
||||
.highest_bank_bit = 14,
|
||||
};
|
||||
|
||||
static const struct qcom_ubwc_cfg_data ubwc_2_0_hbb15 = {
|
||||
.ubwc_enc_version = UBWC_2_0,
|
||||
.highest_bank_bit = 15,
|
||||
};
|
||||
|
||||
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 ubwc_3_1_hbb13 = {
|
||||
.ubwc_enc_version = UBWC_3_1,
|
||||
.highest_bank_bit = 13,
|
||||
};
|
||||
|
||||
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 ubwc_3_1_hbb16 = {
|
||||
.ubwc_enc_version = UBWC_3_1,
|
||||
.highest_bank_bit = 16,
|
||||
};
|
||||
|
||||
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 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 ubwc_5_0_hbb16 = {
|
||||
.ubwc_enc_version = UBWC_5_0,
|
||||
.highest_bank_bit = 16,
|
||||
};
|
||||
|
||||
static const struct qcom_ubwc_cfg_data ubwc_6_0_hbb16 = {
|
||||
.ubwc_enc_version = UBWC_6_0,
|
||||
.highest_bank_bit = 16,
|
||||
};
|
||||
|
||||
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,
|
||||
.flags = UBWC_FLAG_DISABLE_SWIZZLE_LVL2,
|
||||
.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 = {
|
||||
.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 = {
|
||||
.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 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 sm6150_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 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 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 sm8150_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 = 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 */
|
||||
.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 */
|
||||
.highest_bank_bit = 16,
|
||||
.macrotile_mode = true,
|
||||
};
|
||||
|
||||
static const struct qcom_ubwc_cfg_data sm8550_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,
|
||||
};
|
||||
|
||||
static const struct qcom_ubwc_cfg_data sm8750_data = {
|
||||
.ubwc_enc_version = UBWC_5_0,
|
||||
.ubwc_dec_version = UBWC_5_0,
|
||||
.ubwc_swizzle = 6,
|
||||
.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 glymur_data = {
|
||||
.ubwc_enc_version = UBWC_5_0,
|
||||
.ubwc_dec_version = UBWC_5_0,
|
||||
.ubwc_swizzle = 0,
|
||||
.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 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");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user