From 4007844b05815717f522c7ea9914e24ad0ff6c79 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Mon, 28 Sep 2020 11:31:35 +0800 Subject: soc: mediatek: Check if power domains can be powered on at boot time In the error case, where a power domain cannot be powered on successfully at boot time (in mtk_register_power_domains), pm_genpd_init would still be called with is_off=false, and the system would later try to disable the power domain again, triggering warnings as disabled clocks are disabled again (and other potential issues). Also print a warning splat in that case, as this should never happen. Fixes: c84e358718a66f7 ("soc: Mediatek: Add SCPSYS power domain driver") Signed-off-by: Nicolas Boichat Link: https://lore.kernel.org/r/20200928113107.v2.1.I5e6f8c262031d0451fe7241b744f4f3111c1ce71@changeid Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-scpsys.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index f669d3754627..ca75b14931ec 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -524,6 +524,7 @@ static void mtk_register_power_domains(struct platform_device *pdev, for (i = 0; i < num; i++) { struct scp_domain *scpd = &scp->domains[i]; struct generic_pm_domain *genpd = &scpd->genpd; + bool on; /* * Initially turn on all domains to make the domains usable @@ -531,9 +532,9 @@ static void mtk_register_power_domains(struct platform_device *pdev, * software. The unused domains will be switched off during * late_init time. */ - genpd->power_on(genpd); + on = !WARN_ON(genpd->power_on(genpd) < 0); - pm_genpd_init(genpd, NULL, false); + pm_genpd_init(genpd, NULL, !on); } /* -- cgit From cc7a16b14f386a9f67ba16195dfb85d2a9f3a007 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Tue, 20 Oct 2020 17:26:39 +0200 Subject: MAINTAINERS: change mediatek wiki page The old wiki page unfortunately got lost by server crash. The new wiki can be found on the kernel.org infrastructure Signed-off-by: Matthias Brugger Reviewed-by: Chun-Kuang Hu Link: https://lore.kernel.org/r/20201020152639.21950-1-matthias.bgg@kernel.org Signed-off-by: Matthias Brugger --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index e73636b75f29..0e1289658d55 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2067,7 +2067,7 @@ M: Matthias Brugger L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Maintained -W: https://mtk.bcnfs.org/ +W: https://mtk.wiki.kernel.org/ C: irc://chat.freenode.net/linux-mediatek F: arch/arm/boot/dts/mt6* F: arch/arm/boot/dts/mt7* -- cgit From 86b9d170da98bae13b307d621638954aef645331 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Tue, 10 Nov 2020 17:13:37 +0100 Subject: mfd: syscon: Add syscon_regmap_lookup_by_phandle_optional() function. This adds syscon_regmap_lookup_by_phandle_optional() function to get an optional regmap. It behaves the same as syscon_regmap_lookup_by_phandle() except where there is no regmap phandle. In this case, instead of returning -ENODEV, the function returns NULL. This makes error checking simpler when the regmap phandle is optional. Suggested-by: Nicolas Boichat Signed-off-by: Enric Balletbo i Serra Reviewed-by: Matthias Brugger Reviewed-by: Arnd Bergmann Signed-off-by: Lee Jones --- drivers/mfd/syscon.c | 18 ++++++++++++++++++ include/linux/mfd/syscon.h | 11 +++++++++++ 2 files changed, 29 insertions(+) diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index ca465794ea9c..c6f139b2e0c0 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -255,6 +255,24 @@ struct regmap *syscon_regmap_lookup_by_phandle_args(struct device_node *np, } EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle_args); +/* + * It behaves the same as syscon_regmap_lookup_by_phandle() except where + * there is no regmap phandle. In this case, instead of returning -ENODEV, + * the function returns NULL. + */ +struct regmap *syscon_regmap_lookup_by_phandle_optional(struct device_node *np, + const char *property) +{ + struct regmap *regmap; + + regmap = syscon_regmap_lookup_by_phandle(np, property); + if (IS_ERR(regmap) && PTR_ERR(regmap) == -ENODEV) + return NULL; + + return regmap; +} +EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle_optional); + static int syscon_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; diff --git a/include/linux/mfd/syscon.h b/include/linux/mfd/syscon.h index 7f20e9b502a5..fecc2fa2a364 100644 --- a/include/linux/mfd/syscon.h +++ b/include/linux/mfd/syscon.h @@ -28,6 +28,9 @@ extern struct regmap *syscon_regmap_lookup_by_phandle_args( const char *property, int arg_count, unsigned int *out_args); +extern struct regmap *syscon_regmap_lookup_by_phandle_optional( + struct device_node *np, + const char *property); #else static inline struct regmap *device_node_to_regmap(struct device_node *np) { @@ -59,6 +62,14 @@ static inline struct regmap *syscon_regmap_lookup_by_phandle_args( { return ERR_PTR(-ENOTSUPP); } + +static inline struct regmap *syscon_regmap_lookup_by_phandle_optional( + struct device_node *np, + const char *property) +{ + return NULL; +} + #endif #endif /* __LINUX_MFD_SYSCON_H__ */ -- cgit From d392fe78f50bc9e08ac6dfd976ad6e922704b1bf Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Fri, 30 Oct 2020 12:36:07 +0100 Subject: dt-bindings: power: Add bindings for the Mediatek SCPSYS power domains controller The System Control Processor System (SCPSYS) has several power management related tasks in the system. Add the bindings to define the power domains for the SCPSYS power controller. Co-developed-by: Matthias Brugger Signed-off-by: Matthias Brugger Signed-off-by: Enric Balletbo i Serra Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20201030113622.201188-2-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- .../bindings/power/mediatek,power-controller.yaml | 289 +++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/mediatek,power-controller.yaml diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml new file mode 100644 index 000000000000..73b8988bd063 --- /dev/null +++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml @@ -0,0 +1,289 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/power/mediatek,power-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Mediatek Power Domains Controller + +maintainers: + - Weiyi Lu + - Matthias Brugger + +description: | + Mediatek processors include support for multiple power domains which can be + powered up/down by software based on different application scenes to save power. + + IP cores belonging to a power domain should contain a 'power-domains' + property that is a phandle for SCPSYS node representing the domain. + +properties: + $nodename: + const: power-controller + + compatible: + enum: + - mediatek,mt8173-power-controller + + '#power-domain-cells': + const: 1 + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +patternProperties: + "^power-domain@[0-9a-f]+$": + type: object + description: | + Represents the power domains within the power controller node as documented + in Documentation/devicetree/bindings/power/power-domain.yaml. + + properties: + + '#power-domain-cells': + description: + Must be 0 for nodes representing a single PM domain and 1 for nodes + providing multiple PM domains. + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + reg: + description: | + Power domain index. Valid values are defined in: + "include/dt-bindings/power/mt8173-power.h" - for MT8173 type power domain. + maxItems: 1 + + clocks: + description: | + A number of phandles to clocks that need to be enabled during domain + power-up sequencing. + + clock-names: + description: | + List of names of clocks, in order to match the power-up sequencing + for each power domain we need to group the clocks by name. BASIC + clocks need to be enabled before enabling the corresponding power + domain, and should not have a '-' in their name (i.e mm, mfg, venc). + SUSBYS clocks need to be enabled before releasing the bus protection, + and should contain a '-' in their name (i.e mm-0, isp-0, cam-0). + + In order to follow properly the power-up sequencing, the clocks must + be specified by order, adding first the BASIC clocks followed by the + SUSBSYS clocks. + + mediatek,infracfg: + $ref: /schemas/types.yaml#definitions/phandle + description: phandle to the device containing the INFRACFG register range. + + mediatek,smi: + $ref: /schemas/types.yaml#definitions/phandle + description: phandle to the device containing the SMI register range. + + patternProperties: + "^power-domain@[0-9a-f]+$": + type: object + description: | + Represents a power domain child within a power domain parent node. + + properties: + + '#power-domain-cells': + description: + Must be 0 for nodes representing a single PM domain and 1 for nodes + providing multiple PM domains. + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + reg: + maxItems: 1 + + clocks: + description: | + A number of phandles to clocks that need to be enabled during domain + power-up sequencing. + + clock-names: + description: | + List of names of clocks, in order to match the power-up sequencing + for each power domain we need to group the clocks by name. BASIC + clocks need to be enabled before enabling the corresponding power + domain, and should not have a '-' in their name (i.e mm, mfg, venc). + SUSBYS clocks need to be enabled before releasing the bus protection, + and should contain a '-' in their name (i.e mm-0, isp-0, cam-0). + + In order to follow properly the power-up sequencing, the clocks must + be specified by order, adding first the BASIC clocks followed by the + SUSBSYS clocks. + + mediatek,infracfg: + $ref: /schemas/types.yaml#definitions/phandle + description: phandle to the device containing the INFRACFG register range. + + mediatek,smi: + $ref: /schemas/types.yaml#definitions/phandle + description: phandle to the device containing the SMI register range. + + patternProperties: + "^power-domain@[0-9a-f]+$": + type: object + description: | + Represents a power domain child within a power domain parent node. + + properties: + + '#power-domain-cells': + description: + Must be 0 for nodes representing a single PM domain and 1 for nodes + providing multiple PM domains. + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + reg: + maxItems: 1 + + clocks: + description: | + A number of phandles to clocks that need to be enabled during domain + power-up sequencing. + + clock-names: + description: | + List of names of clocks, in order to match the power-up sequencing + for each power domain we need to group the clocks by name. BASIC + clocks need to be enabled before enabling the corresponding power + domain, and should not have a '-' in their name (i.e mm, mfg, venc). + SUSBYS clocks need to be enabled before releasing the bus protection, + and should contain a '-' in their name (i.e mm-0, isp-0, cam-0). + + In order to follow properly the power-up sequencing, the clocks must + be specified by order, adding first the BASIC clocks followed by the + SUSBSYS clocks. + + mediatek,infracfg: + $ref: /schemas/types.yaml#definitions/phandle + description: phandle to the device containing the INFRACFG register range. + + mediatek,smi: + $ref: /schemas/types.yaml#definitions/phandle + description: phandle to the device containing the SMI register range. + + required: + - reg + + additionalProperties: false + + required: + - reg + + additionalProperties: false + + required: + - reg + + additionalProperties: false + +required: + - compatible + +additionalProperties: false + +examples: + - | + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + scpsys: syscon@10006000 { + compatible = "syscon", "simple-mfd"; + reg = <0 0x10006000 0 0x1000>; + + spm: power-controller { + compatible = "mediatek,mt8173-power-controller"; + #address-cells = <1>; + #size-cells = <0>; + #power-domain-cells = <1>; + + /* power domains of the SoC */ + power-domain@MT8173_POWER_DOMAIN_VDEC { + reg = ; + clocks = <&topckgen CLK_TOP_MM_SEL>; + clock-names = "mm"; + #power-domain-cells = <0>; + }; + power-domain@MT8173_POWER_DOMAIN_VENC { + reg = ; + clocks = <&topckgen CLK_TOP_MM_SEL>, + <&topckgen CLK_TOP_VENC_SEL>; + clock-names = "mm", "venc"; + #power-domain-cells = <0>; + }; + power-domain@MT8173_POWER_DOMAIN_ISP { + reg = ; + clocks = <&topckgen CLK_TOP_MM_SEL>; + clock-names = "mm"; + #power-domain-cells = <0>; + }; + power-domain@MT8173_POWER_DOMAIN_MM { + reg = ; + clocks = <&topckgen CLK_TOP_MM_SEL>; + clock-names = "mm"; + #power-domain-cells = <0>; + mediatek,infracfg = <&infracfg>; + }; + power-domain@MT8173_POWER_DOMAIN_VENC_LT { + reg = ; + clocks = <&topckgen CLK_TOP_MM_SEL>, + <&topckgen CLK_TOP_VENC_LT_SEL>; + clock-names = "mm", "venclt"; + #power-domain-cells = <0>; + }; + power-domain@MT8173_POWER_DOMAIN_AUDIO { + reg = ; + #power-domain-cells = <0>; + }; + power-domain@MT8173_POWER_DOMAIN_USB { + reg = ; + #power-domain-cells = <0>; + }; + power-domain@MT8173_POWER_DOMAIN_MFG_ASYNC { + reg = ; + clocks = <&clk26m>; + clock-names = "mfg"; + #address-cells = <1>; + #size-cells = <0>; + #power-domain-cells = <1>; + + power-domain@MT8173_POWER_DOMAIN_MFG_2D { + reg = ; + #address-cells = <1>; + #size-cells = <0>; + #power-domain-cells = <1>; + + power-domain@MT8173_POWER_DOMAIN_MFG { + reg = ; + #power-domain-cells = <0>; + mediatek,infracfg = <&infracfg>; + }; + }; + }; + }; + }; + }; -- cgit From 86a378bb1e98793409e5decfef50edadbca659c5 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Fri, 30 Oct 2020 12:36:16 +0100 Subject: dt-bindings: power: Add MT8183 power domains Add power domains dt-bindings for MT8183. Signed-off-by: Matthias Brugger Signed-off-by: Enric Balletbo i Serra Acked-by: Rob Herring Link: https://lore.kernel.org/r/20201030113622.201188-11-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- .../bindings/power/mediatek,power-controller.yaml | 2 ++ include/dt-bindings/power/mt8183-power.h | 26 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 include/dt-bindings/power/mt8183-power.h diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml index 73b8988bd063..8cae43412327 100644 --- a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml +++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml @@ -24,6 +24,7 @@ properties: compatible: enum: - mediatek,mt8173-power-controller + - mediatek,mt8183-power-controller '#power-domain-cells': const: 1 @@ -58,6 +59,7 @@ patternProperties: description: | Power domain index. Valid values are defined in: "include/dt-bindings/power/mt8173-power.h" - for MT8173 type power domain. + "include/dt-bindings/power/mt8183-power.h" - for MT8183 type power domain. maxItems: 1 clocks: diff --git a/include/dt-bindings/power/mt8183-power.h b/include/dt-bindings/power/mt8183-power.h new file mode 100644 index 000000000000..d1ab387ba8c7 --- /dev/null +++ b/include/dt-bindings/power/mt8183-power.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 MediaTek Inc. + * Author: Weiyi Lu + */ + +#ifndef _DT_BINDINGS_POWER_MT8183_POWER_H +#define _DT_BINDINGS_POWER_MT8183_POWER_H + +#define MT8183_POWER_DOMAIN_AUDIO 0 +#define MT8183_POWER_DOMAIN_CONN 1 +#define MT8183_POWER_DOMAIN_MFG_ASYNC 2 +#define MT8183_POWER_DOMAIN_MFG 3 +#define MT8183_POWER_DOMAIN_MFG_CORE0 4 +#define MT8183_POWER_DOMAIN_MFG_CORE1 5 +#define MT8183_POWER_DOMAIN_MFG_2D 6 +#define MT8183_POWER_DOMAIN_DISP 7 +#define MT8183_POWER_DOMAIN_CAM 8 +#define MT8183_POWER_DOMAIN_ISP 9 +#define MT8183_POWER_DOMAIN_VDEC 10 +#define MT8183_POWER_DOMAIN_VENC 11 +#define MT8183_POWER_DOMAIN_VPU_TOP 12 +#define MT8183_POWER_DOMAIN_VPU_CORE0 13 +#define MT8183_POWER_DOMAIN_VPU_CORE1 14 + +#endif /* _DT_BINDINGS_POWER_MT8183_POWER_H */ -- cgit From 343106d9e61260e4ac569c54dd19201b9e704d46 Mon Sep 17 00:00:00 2001 From: Weiyi Lu Date: Fri, 30 Oct 2020 12:36:20 +0100 Subject: dt-bindings: power: Add MT8192 power domains Add power domains dt-bindings for MT8192. Signed-off-by: Weiyi Lu Signed-off-by: Enric Balletbo i Serra Acked-by: Rob Herring Link: https://lore.kernel.org/r/20201030113622.201188-15-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- .../bindings/power/mediatek,power-controller.yaml | 2 ++ include/dt-bindings/power/mt8192-power.h | 32 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 include/dt-bindings/power/mt8192-power.h diff --git a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml index 8cae43412327..fd12bafe3548 100644 --- a/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml +++ b/Documentation/devicetree/bindings/power/mediatek,power-controller.yaml @@ -25,6 +25,7 @@ properties: enum: - mediatek,mt8173-power-controller - mediatek,mt8183-power-controller + - mediatek,mt8192-power-controller '#power-domain-cells': const: 1 @@ -60,6 +61,7 @@ patternProperties: Power domain index. Valid values are defined in: "include/dt-bindings/power/mt8173-power.h" - for MT8173 type power domain. "include/dt-bindings/power/mt8183-power.h" - for MT8183 type power domain. + "include/dt-bindings/power/mt8192-power.h" - for MT8192 type power domain. maxItems: 1 clocks: diff --git a/include/dt-bindings/power/mt8192-power.h b/include/dt-bindings/power/mt8192-power.h new file mode 100644 index 000000000000..4eaa53d7270a --- /dev/null +++ b/include/dt-bindings/power/mt8192-power.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (c) 2020 MediaTek Inc. + * Author: Weiyi Lu + */ + +#ifndef _DT_BINDINGS_POWER_MT8192_POWER_H +#define _DT_BINDINGS_POWER_MT8192_POWER_H + +#define MT8192_POWER_DOMAIN_AUDIO 0 +#define MT8192_POWER_DOMAIN_CONN 1 +#define MT8192_POWER_DOMAIN_MFG0 2 +#define MT8192_POWER_DOMAIN_MFG1 3 +#define MT8192_POWER_DOMAIN_MFG2 4 +#define MT8192_POWER_DOMAIN_MFG3 5 +#define MT8192_POWER_DOMAIN_MFG4 6 +#define MT8192_POWER_DOMAIN_MFG5 7 +#define MT8192_POWER_DOMAIN_MFG6 8 +#define MT8192_POWER_DOMAIN_DISP 9 +#define MT8192_POWER_DOMAIN_IPE 10 +#define MT8192_POWER_DOMAIN_ISP 11 +#define MT8192_POWER_DOMAIN_ISP2 12 +#define MT8192_POWER_DOMAIN_MDP 13 +#define MT8192_POWER_DOMAIN_VENC 14 +#define MT8192_POWER_DOMAIN_VDEC 15 +#define MT8192_POWER_DOMAIN_VDEC2 16 +#define MT8192_POWER_DOMAIN_CAM 17 +#define MT8192_POWER_DOMAIN_CAM_RAWA 18 +#define MT8192_POWER_DOMAIN_CAM_RAWB 19 +#define MT8192_POWER_DOMAIN_CAM_RAWC 20 + +#endif /* _DT_BINDINGS_POWER_MT8192_POWER_H */ -- cgit From 59b644b01cf48d6042f3c5983d464921a4920845 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Fri, 30 Oct 2020 12:36:08 +0100 Subject: soc: mediatek: Add MediaTek SCPSYS power domains The System Control Processor System (SCPSYS) has several power management related tasks in the system. This driver implements support to handle the different power domains supported in order to meet high performance and low power requirements. Co-developed-by: Matthias Brugger Signed-off-by: Matthias Brugger Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20201030113622.201188-3-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/Kconfig | 13 + drivers/soc/mediatek/Makefile | 1 + drivers/soc/mediatek/mt8173-pm-domains.h | 96 +++++++ drivers/soc/mediatek/mtk-pm-domains.c | 456 +++++++++++++++++++++++++++++++ drivers/soc/mediatek/mtk-pm-domains.h | 65 +++++ 5 files changed, 631 insertions(+) create mode 100644 drivers/soc/mediatek/mt8173-pm-domains.h create mode 100644 drivers/soc/mediatek/mtk-pm-domains.c create mode 100644 drivers/soc/mediatek/mtk-pm-domains.h diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index 59a56cd790ec..68d800f9e4a5 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -44,6 +44,19 @@ config MTK_SCPSYS Say yes here to add support for the MediaTek SCPSYS power domain driver. +config MTK_SCPSYS_PM_DOMAINS + bool "MediaTek SCPSYS generic power domain" + default ARCH_MEDIATEK + depends on PM + depends on MTK_INFRACFG + select PM_GENERIC_DOMAINS + select REGMAP + help + Say y here to enable power domain support. + In order to meet high performance and low power requirements, the System + Control Processor System (SCPSYS) has several power management related + tasks in the system. + config MTK_MMSYS bool "MediaTek MMSYS Support" default ARCH_MEDIATEK diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile index 01f9f873634a..1e60fb4f89d4 100644 --- a/drivers/soc/mediatek/Makefile +++ b/drivers/soc/mediatek/Makefile @@ -3,4 +3,5 @@ obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o +obj-$(CONFIG_MTK_SCPSYS_PM_DOMAINS) += mtk-pm-domains.o obj-$(CONFIG_MTK_MMSYS) += mtk-mmsys.o diff --git a/drivers/soc/mediatek/mt8173-pm-domains.h b/drivers/soc/mediatek/mt8173-pm-domains.h new file mode 100644 index 000000000000..5f2b5d4ad02b --- /dev/null +++ b/drivers/soc/mediatek/mt8173-pm-domains.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_MEDIATEK_MT8173_PM_DOMAINS_H +#define __SOC_MEDIATEK_MT8173_PM_DOMAINS_H + +#include "mtk-pm-domains.h" +#include + +/* + * MT8173 power domain support + */ + +static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { + [MT8173_POWER_DOMAIN_VDEC] = { + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8173_POWER_DOMAIN_VENC] = { + .sta_mask = PWR_STATUS_VENC, + .ctl_offs = SPM_VEN_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + }, + [MT8173_POWER_DOMAIN_ISP] = { + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + }, + [MT8173_POWER_DOMAIN_MM] = { + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + .bus_prot_reg_update = true, + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | + MT8173_TOP_AXI_PROT_EN_MM_M1, + }, + }, + [MT8173_POWER_DOMAIN_VENC_LT] = { + .sta_mask = PWR_STATUS_VENC_LT, + .ctl_offs = SPM_VEN2_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + }, + [MT8173_POWER_DOMAIN_AUDIO] = { + .sta_mask = PWR_STATUS_AUDIO, + .ctl_offs = SPM_AUDIO_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + }, + [MT8173_POWER_DOMAIN_USB] = { + .sta_mask = PWR_STATUS_USB, + .ctl_offs = SPM_USB_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .caps = MTK_SCPD_ACTIVE_WAKEUP, + }, + [MT8173_POWER_DOMAIN_MFG_ASYNC] = { + .sta_mask = PWR_STATUS_MFG_ASYNC, + .ctl_offs = SPM_MFG_ASYNC_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = 0, + }, + [MT8173_POWER_DOMAIN_MFG_2D] = { + .sta_mask = PWR_STATUS_MFG_2D, + .ctl_offs = SPM_MFG_2D_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + }, + [MT8173_POWER_DOMAIN_MFG] = { + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(13, 8), + .sram_pdn_ack_bits = GENMASK(21, 16), + .bp_infracfg = { + .bus_prot_reg_update = true, + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | + MT8173_TOP_AXI_PROT_EN_MFG_M0 | + MT8173_TOP_AXI_PROT_EN_MFG_M1 | + MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, + }, + }, +}; + +static const struct scpsys_soc_data mt8173_scpsys_data = { + .domains_data = scpsys_domain_data_mt8173, + .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8173), + .pwr_sta_offs = SPM_PWR_STATUS, + .pwr_sta2nd_offs = SPM_PWR_STATUS_2ND, +}; + +#endif /* __SOC_MEDIATEK_MT8173_PM_DOMAINS_H */ diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c new file mode 100644 index 000000000000..f8e88308f2e0 --- /dev/null +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -0,0 +1,456 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020 Collabora Ltd. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mt8173-pm-domains.h" + +#define MTK_POLL_DELAY_US 10 +#define MTK_POLL_TIMEOUT USEC_PER_SEC + +#define PWR_RST_B_BIT BIT(0) +#define PWR_ISO_BIT BIT(1) +#define PWR_ON_BIT BIT(2) +#define PWR_ON_2ND_BIT BIT(3) +#define PWR_CLK_DIS_BIT BIT(4) + +struct scpsys_domain { + struct generic_pm_domain genpd; + const struct scpsys_domain_data *data; + struct scpsys *scpsys; + int num_clks; + struct clk_bulk_data *clks; + struct regmap *infracfg; +}; + +struct scpsys { + struct device *dev; + struct regmap *base; + const struct scpsys_soc_data *soc_data; + struct genpd_onecell_data pd_data; + struct generic_pm_domain *domains[]; +}; + +#define to_scpsys_domain(gpd) container_of(gpd, struct scpsys_domain, genpd) + +static bool scpsys_domain_is_on(struct scpsys_domain *pd) +{ + struct scpsys *scpsys = pd->scpsys; + u32 status, status2; + + regmap_read(scpsys->base, scpsys->soc_data->pwr_sta_offs, &status); + status &= pd->data->sta_mask; + + regmap_read(scpsys->base, scpsys->soc_data->pwr_sta2nd_offs, &status2); + status2 &= pd->data->sta_mask; + + /* A domain is on when both status bits are set. */ + return status && status2; +} + +static int scpsys_sram_enable(struct scpsys_domain *pd) +{ + u32 pdn_ack = pd->data->sram_pdn_ack_bits; + struct scpsys *scpsys = pd->scpsys; + unsigned int tmp; + + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); + + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ + return regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp, + (tmp & pdn_ack) == 0, MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); +} + +static int scpsys_sram_disable(struct scpsys_domain *pd) +{ + u32 pdn_ack = pd->data->sram_pdn_ack_bits; + struct scpsys *scpsys = pd->scpsys; + unsigned int tmp; + + regmap_set_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); + + /* Either wait until SRAM_PDN_ACK all 1 or 0 */ + return regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp, + (tmp & pdn_ack) == pdn_ack, MTK_POLL_DELAY_US, + MTK_POLL_TIMEOUT); +} + +static int scpsys_bus_protect_enable(struct scpsys_domain *pd) +{ + const struct scpsys_bus_prot_data *bp_data = &pd->data->bp_infracfg; + + if (!bp_data->bus_prot_mask) + return 0; + + return mtk_infracfg_set_bus_protection(pd->infracfg, bp_data->bus_prot_mask, + bp_data->bus_prot_reg_update); +} + +static int scpsys_bus_protect_disable(struct scpsys_domain *pd) +{ + const struct scpsys_bus_prot_data *bp_data = &pd->data->bp_infracfg; + + if (!bp_data->bus_prot_mask) + return 0; + + return mtk_infracfg_clear_bus_protection(pd->infracfg, bp_data->bus_prot_mask, + bp_data->bus_prot_reg_update); +} + +static int scpsys_power_on(struct generic_pm_domain *genpd) +{ + struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); + struct scpsys *scpsys = pd->scpsys; + bool tmp; + int ret; + + ret = clk_bulk_enable(pd->num_clks, pd->clks); + if (ret) + return ret; + + /* subsys power on */ + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT); + + /* wait until PWR_ACK = 1 */ + ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, tmp, MTK_POLL_DELAY_US, + MTK_POLL_TIMEOUT); + if (ret < 0) + goto err_pwr_ack; + + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); + + ret = scpsys_sram_enable(pd); + if (ret < 0) + goto err_pwr_ack; + + ret = scpsys_bus_protect_disable(pd); + if (ret < 0) + goto err_disable_sram; + + return 0; + +err_disable_sram: + scpsys_sram_disable(pd); +err_pwr_ack: + clk_bulk_disable(pd->num_clks, pd->clks); + return ret; +} + +static int scpsys_power_off(struct generic_pm_domain *genpd) +{ + struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); + struct scpsys *scpsys = pd->scpsys; + bool tmp; + int ret; + + ret = scpsys_bus_protect_enable(pd); + if (ret < 0) + return ret; + + ret = scpsys_sram_disable(pd); + if (ret < 0) + return ret; + + /* subsys power off */ + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_CLK_DIS_BIT); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_2ND_BIT); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ON_BIT); + + /* wait until PWR_ACK = 0 */ + ret = readx_poll_timeout(scpsys_domain_is_on, pd, tmp, !tmp, MTK_POLL_DELAY_US, + MTK_POLL_TIMEOUT); + if (ret < 0) + return ret; + + clk_bulk_disable(pd->num_clks, pd->clks); + + return 0; +} + +static struct +generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_node *node) +{ + const struct scpsys_domain_data *domain_data; + struct scpsys_domain *pd; + int i, ret; + u32 id; + + ret = of_property_read_u32(node, "reg", &id); + if (ret) { + dev_err(scpsys->dev, "%pOF: failed to retrieve domain id from reg: %d\n", + node, ret); + return ERR_PTR(-EINVAL); + } + + if (id >= scpsys->soc_data->num_domains) { + dev_err(scpsys->dev, "%pOF: invalid domain id %d\n", node, id); + return ERR_PTR(-EINVAL); + } + + domain_data = &scpsys->soc_data->domains_data[id]; + if (domain_data->sta_mask == 0) { + dev_err(scpsys->dev, "%pOF: undefined domain id %d\n", node, id); + return ERR_PTR(-EINVAL); + } + + pd = devm_kzalloc(scpsys->dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return ERR_PTR(-ENOMEM); + + pd->data = domain_data; + pd->scpsys = scpsys; + + pd->infracfg = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,infracfg"); + if (IS_ERR(pd->infracfg)) + return ERR_CAST(pd->infracfg); + + pd->num_clks = of_clk_get_parent_count(node); + if (pd->num_clks > 0) { + pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks, sizeof(*pd->clks), GFP_KERNEL); + if (!pd->clks) + return ERR_PTR(-ENOMEM); + } + + for (i = 0; i < pd->num_clks; i++) { + pd->clks[i].clk = of_clk_get(node, i); + if (IS_ERR(pd->clks[i].clk)) { + dev_err(scpsys->dev, "%pOF: failed to get clk at index %d\n", + node, i); + return ERR_PTR(-EINVAL); + } + } + + ret = clk_bulk_prepare(pd->num_clks, pd->clks); + if (ret) + goto err_put_clocks; + + /* + * Initially turn on all domains to make the domains usable + * with !CONFIG_PM and to get the hardware in sync with the + * software. The unused domains will be switched off during + * late_init time. + */ + ret = scpsys_power_on(&pd->genpd); + if (ret < 0) { + dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret); + goto err_unprepare_clocks; + } + + if (scpsys->domains[id]) { + ret = -EINVAL; + dev_err(scpsys->dev, + "power domain with id %d already exists, check your device-tree\n", id); + goto err_unprepare_clocks; + } + + pd->genpd.name = node->name; + pd->genpd.power_off = scpsys_power_off; + pd->genpd.power_on = scpsys_power_on; + + pm_genpd_init(&pd->genpd, NULL, false); + scpsys->domains[id] = &pd->genpd; + + return scpsys->pd_data.domains[id]; + +err_unprepare_clocks: + clk_bulk_unprepare(pd->num_clks, pd->clks); +err_put_clocks: + clk_bulk_put(pd->num_clks, pd->clks); + return ERR_PTR(ret); +} + +static int scpsys_add_subdomain(struct scpsys *scpsys, struct device_node *parent) +{ + struct generic_pm_domain *child_pd, *parent_pd; + struct device_node *child; + int ret; + + for_each_child_of_node(parent, child) { + u32 id; + + ret = of_property_read_u32(parent, "reg", &id); + if (ret) { + dev_err(scpsys->dev, "%pOF: failed to get parent domain id\n", child); + goto err_put_node; + } + + if (!scpsys->pd_data.domains[id]) { + ret = -EINVAL; + dev_err(scpsys->dev, "power domain with id %d does not exist\n", id); + goto err_put_node; + } + + parent_pd = scpsys->pd_data.domains[id]; + + child_pd = scpsys_add_one_domain(scpsys, child); + if (IS_ERR(child_pd)) { + ret = PTR_ERR(child_pd); + dev_err(scpsys->dev, "%pOF: failed to get child domain id\n", child); + goto err_put_node; + } + + ret = pm_genpd_add_subdomain(parent_pd, child_pd); + if (ret) { + dev_err(scpsys->dev, "failed to add %s subdomain to parent %s\n", + child_pd->name, parent_pd->name); + goto err_put_node; + } else { + dev_dbg(scpsys->dev, "%s add subdomain: %s\n", parent_pd->name, + child_pd->name); + } + + /* recursive call to add all subdomains */ + ret = scpsys_add_subdomain(scpsys, child); + if (ret) + goto err_put_node; + } + + return 0; + +err_put_node: + of_node_put(child); + return ret; +} + +static void scpsys_remove_one_domain(struct scpsys_domain *pd) +{ + int ret; + + /* + * We're in the error cleanup already, so we only complain, + * but won't emit another error on top of the original one. + */ + ret = pm_genpd_remove(&pd->genpd); + if (ret < 0) + dev_err(pd->scpsys->dev, + "failed to remove domain '%s' : %d - state may be inconsistent\n", + pd->genpd.name, ret); + + scpsys_power_off(&pd->genpd); + + clk_bulk_unprepare(pd->num_clks, pd->clks); + clk_bulk_put(pd->num_clks, pd->clks); +} + +static void scpsys_domain_cleanup(struct scpsys *scpsys) +{ + struct generic_pm_domain *genpd; + struct scpsys_domain *pd; + int i; + + for (i = scpsys->pd_data.num_domains - 1; i >= 0; i--) { + genpd = scpsys->pd_data.domains[i]; + if (genpd) { + pd = to_scpsys_domain(genpd); + scpsys_remove_one_domain(pd); + } + } +} + +static const struct of_device_id scpsys_of_match[] = { + { + .compatible = "mediatek,mt8173-power-controller", + .data = &mt8173_scpsys_data, + }, + { } +}; + +static int scpsys_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const struct scpsys_soc_data *soc; + struct device_node *node; + struct device *parent; + struct scpsys *scpsys; + int ret; + + soc = of_device_get_match_data(&pdev->dev); + if (!soc) { + dev_err(&pdev->dev, "no power controller data\n"); + return -EINVAL; + } + + scpsys = devm_kzalloc(dev, struct_size(scpsys, domains, soc->num_domains), GFP_KERNEL); + if (!scpsys) + return -ENOMEM; + + scpsys->dev = dev; + scpsys->soc_data = soc; + + scpsys->pd_data.domains = scpsys->domains; + scpsys->pd_data.num_domains = soc->num_domains; + + parent = dev->parent; + if (!parent) { + dev_err(dev, "no parent for syscon devices\n"); + return -ENODEV; + } + + scpsys->base = syscon_node_to_regmap(parent->of_node); + if (IS_ERR(scpsys->base)) { + dev_err(dev, "no regmap available\n"); + return PTR_ERR(scpsys->base); + } + + ret = -ENODEV; + for_each_available_child_of_node(np, node) { + struct generic_pm_domain *domain; + + domain = scpsys_add_one_domain(scpsys, node); + if (IS_ERR(domain)) { + ret = PTR_ERR(domain); + of_node_put(node); + goto err_cleanup_domains; + } + + ret = scpsys_add_subdomain(scpsys, node); + if (ret) { + of_node_put(node); + goto err_cleanup_domains; + } + } + + if (ret) { + dev_dbg(dev, "no power domains present\n"); + return ret; + } + + ret = of_genpd_add_provider_onecell(np, &scpsys->pd_data); + if (ret) { + dev_err(dev, "failed to add provider: %d\n", ret); + goto err_cleanup_domains; + } + + return 0; + +err_cleanup_domains: + scpsys_domain_cleanup(scpsys); + return ret; +} + +static struct platform_driver scpsys_pm_domain_driver = { + .probe = scpsys_probe, + .driver = { + .name = "mtk-power-controller", + .suppress_bind_attrs = true, + .of_match_table = scpsys_of_match, + }, +}; +builtin_platform_driver(scpsys_pm_domain_driver); diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h new file mode 100644 index 000000000000..7c479021d404 --- /dev/null +++ b/drivers/soc/mediatek/mtk-pm-domains.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_MEDIATEK_MTK_PM_DOMAINS_H +#define __SOC_MEDIATEK_MTK_PM_DOMAINS_H + +#define MTK_SCPD_ACTIVE_WAKEUP BIT(0) +#define MTK_SCPD_FWAIT_SRAM BIT(1) +#define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) + +#define SPM_VDE_PWR_CON 0x0210 +#define SPM_MFG_PWR_CON 0x0214 +#define SPM_VEN_PWR_CON 0x0230 +#define SPM_ISP_PWR_CON 0x0238 +#define SPM_DIS_PWR_CON 0x023c +#define SPM_VEN2_PWR_CON 0x0298 +#define SPM_AUDIO_PWR_CON 0x029c +#define SPM_MFG_2D_PWR_CON 0x02c0 +#define SPM_MFG_ASYNC_PWR_CON 0x02c4 +#define SPM_USB_PWR_CON 0x02cc + +#define SPM_PWR_STATUS 0x060c +#define SPM_PWR_STATUS_2ND 0x0610 + +#define PWR_STATUS_DISP BIT(3) +#define PWR_STATUS_MFG BIT(4) +#define PWR_STATUS_ISP BIT(5) +#define PWR_STATUS_VDEC BIT(7) +#define PWR_STATUS_VENC_LT BIT(20) +#define PWR_STATUS_VENC BIT(21) +#define PWR_STATUS_MFG_2D BIT(22) +#define PWR_STATUS_MFG_ASYNC BIT(23) +#define PWR_STATUS_AUDIO BIT(24) +#define PWR_STATUS_USB BIT(25) + +struct scpsys_bus_prot_data { + u32 bus_prot_mask; + bool bus_prot_reg_update; +}; + +/** + * struct scpsys_domain_data - scp domain data for power on/off flow + * @sta_mask: The mask for power on/off status bit. + * @ctl_offs: The offset for main power control register. + * @sram_pdn_bits: The mask for sram power control bits. + * @sram_pdn_ack_bits: The mask for sram power control acked bits. + * @caps: The flag for active wake-up action. + * @bp_infracfg: bus protection for infracfg subsystem + */ +struct scpsys_domain_data { + u32 sta_mask; + int ctl_offs; + u32 sram_pdn_bits; + u32 sram_pdn_ack_bits; + u8 caps; + const struct scpsys_bus_prot_data bp_infracfg; +}; + +struct scpsys_soc_data { + const struct scpsys_domain_data *domains_data; + int num_domains; + int pwr_sta_offs; + int pwr_sta2nd_offs; +}; + +#endif /* __SOC_MEDIATEK_MTK_PM_DOMAINS_H */ -- cgit From 916d6d71ba56cfc19a0bfd8a0e181443a13cb865 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Fri, 30 Oct 2020 12:36:10 +0100 Subject: soc: mediatek: pm-domains: Add bus protection protocol Bus protection will need to update more then one register in infracfg. Add support for several operations. Signed-off-by: Matthias Brugger Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20201030113622.201188-5-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mt8173-pm-domains.h | 4 ++-- drivers/soc/mediatek/mtk-pm-domains.c | 36 +++++++++++++++++++++++--------- drivers/soc/mediatek/mtk-pm-domains.h | 4 +++- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/drivers/soc/mediatek/mt8173-pm-domains.h b/drivers/soc/mediatek/mt8173-pm-domains.h index 5f2b5d4ad02b..72b3acaf74fb 100644 --- a/drivers/soc/mediatek/mt8173-pm-domains.h +++ b/drivers/soc/mediatek/mt8173-pm-domains.h @@ -34,7 +34,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { .ctl_offs = SPM_DIS_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(12, 12), - .bp_infracfg = { + .bp_infracfg[0] = { .bus_prot_reg_update = true, .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | MT8173_TOP_AXI_PROT_EN_MM_M1, @@ -76,7 +76,7 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { .ctl_offs = SPM_MFG_PWR_CON, .sram_pdn_bits = GENMASK(13, 8), .sram_pdn_ack_bits = GENMASK(21, 16), - .bp_infracfg = { + .bp_infracfg[0] = { .bus_prot_reg_update = true, .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | MT8173_TOP_AXI_PROT_EN_MFG_M0 | diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index f8e88308f2e0..06a16e45356a 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -88,24 +88,40 @@ static int scpsys_sram_disable(struct scpsys_domain *pd) static int scpsys_bus_protect_enable(struct scpsys_domain *pd) { - const struct scpsys_bus_prot_data *bp_data = &pd->data->bp_infracfg; + const struct scpsys_bus_prot_data *bpd = pd->data->bp_infracfg; + int i, ret; - if (!bp_data->bus_prot_mask) - return 0; + for (i = 0; i < SPM_MAX_BUS_PROT_DATA; i++) { + if (!bpd[i].bus_prot_mask) + break; - return mtk_infracfg_set_bus_protection(pd->infracfg, bp_data->bus_prot_mask, - bp_data->bus_prot_reg_update); + ret = mtk_infracfg_set_bus_protection(pd->infracfg, + bpd[i].bus_prot_mask, + bpd[i].bus_prot_reg_update); + if (ret) + return ret; + } + + return 0; } static int scpsys_bus_protect_disable(struct scpsys_domain *pd) { - const struct scpsys_bus_prot_data *bp_data = &pd->data->bp_infracfg; + const struct scpsys_bus_prot_data *bpd = pd->data->bp_infracfg; + int i, ret; - if (!bp_data->bus_prot_mask) - return 0; + for (i = SPM_MAX_BUS_PROT_DATA; i > 0; i--) { + if (!bpd[i].bus_prot_mask) + continue; - return mtk_infracfg_clear_bus_protection(pd->infracfg, bp_data->bus_prot_mask, - bp_data->bus_prot_reg_update); + ret = mtk_infracfg_clear_bus_protection(pd->infracfg, + bpd[i].bus_prot_mask, + bpd[i].bus_prot_reg_update); + if (ret) + return ret; + } + + return 0; } static int scpsys_power_on(struct generic_pm_domain *genpd) diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h index 7c479021d404..125880a58170 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.h +++ b/drivers/soc/mediatek/mtk-pm-domains.h @@ -32,6 +32,8 @@ #define PWR_STATUS_AUDIO BIT(24) #define PWR_STATUS_USB BIT(25) +#define SPM_MAX_BUS_PROT_DATA 5 + struct scpsys_bus_prot_data { u32 bus_prot_mask; bool bus_prot_reg_update; @@ -52,7 +54,7 @@ struct scpsys_domain_data { u32 sram_pdn_bits; u32 sram_pdn_ack_bits; u8 caps; - const struct scpsys_bus_prot_data bp_infracfg; + const struct scpsys_bus_prot_data bp_infracfg[SPM_MAX_BUS_PROT_DATA]; }; struct scpsys_soc_data { -- cgit From 928296ea5da37838d7127de4b10f47cd97401b13 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Fri, 30 Oct 2020 12:36:11 +0100 Subject: soc: mediatek: pm_domains: Make bus protection generic Bus protection is not exclusively done by calling the infracfg misc driver. Make the calls for setting and clearing the bus protection generic so that we can use other blocks for it as well. Signed-off-by: Matthias Brugger Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20201030113622.201188-6-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/Kconfig | 1 - drivers/soc/mediatek/mtk-infracfg.c | 5 --- drivers/soc/mediatek/mtk-pm-domains.c | 57 +++++++++++++++++++++++++++-------- include/linux/soc/mediatek/infracfg.h | 5 +++ 4 files changed, 49 insertions(+), 19 deletions(-) diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index 68d800f9e4a5..67cef12dc585 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -48,7 +48,6 @@ config MTK_SCPSYS_PM_DOMAINS bool "MediaTek SCPSYS generic power domain" default ARCH_MEDIATEK depends on PM - depends on MTK_INFRACFG select PM_GENERIC_DOMAINS select REGMAP help diff --git a/drivers/soc/mediatek/mtk-infracfg.c b/drivers/soc/mediatek/mtk-infracfg.c index 4a123796aad3..0590b68e0d78 100644 --- a/drivers/soc/mediatek/mtk-infracfg.c +++ b/drivers/soc/mediatek/mtk-infracfg.c @@ -12,11 +12,6 @@ #define MTK_POLL_DELAY_US 10 #define MTK_POLL_TIMEOUT (jiffies_to_usecs(HZ)) -#define INFRA_TOPAXI_PROTECTEN 0x0220 -#define INFRA_TOPAXI_PROTECTSTA1 0x0228 -#define INFRA_TOPAXI_PROTECTEN_SET 0x0260 -#define INFRA_TOPAXI_PROTECTEN_CLR 0x0264 - /** * mtk_infracfg_set_bus_protection - enable bus protection * @infracfg: The infracfg regmap diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index 06a16e45356a..6122701d018f 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -86,18 +86,24 @@ static int scpsys_sram_disable(struct scpsys_domain *pd) MTK_POLL_TIMEOUT); } -static int scpsys_bus_protect_enable(struct scpsys_domain *pd) +static int _scpsys_bus_protect_enable(const struct scpsys_bus_prot_data *bpd, struct regmap *regmap) { - const struct scpsys_bus_prot_data *bpd = pd->data->bp_infracfg; int i, ret; for (i = 0; i < SPM_MAX_BUS_PROT_DATA; i++) { - if (!bpd[i].bus_prot_mask) + u32 val, mask = bpd[i].bus_prot_mask; + + if (!mask) break; - ret = mtk_infracfg_set_bus_protection(pd->infracfg, - bpd[i].bus_prot_mask, - bpd[i].bus_prot_reg_update); + if (bpd[i].bus_prot_reg_update) + regmap_set_bits(regmap, bpd[i].bus_prot_set, mask); + else + regmap_write(regmap, INFRA_TOPAXI_PROTECTEN_SET, mask); + + ret = regmap_read_poll_timeout(regmap, INFRA_TOPAXI_PROTECTSTA1, + val, (val & mask) == mask, + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); if (ret) return ret; } @@ -105,18 +111,34 @@ static int scpsys_bus_protect_enable(struct scpsys_domain *pd) return 0; } -static int scpsys_bus_protect_disable(struct scpsys_domain *pd) +static int scpsys_bus_protect_enable(struct scpsys_domain *pd) +{ + int ret; + + ret = _scpsys_bus_protect_enable(pd->data->bp_infracfg, pd->infracfg); + + return ret; +} + +static int _scpsys_bus_protect_disable(const struct scpsys_bus_prot_data *bpd, + struct regmap *regmap) { - const struct scpsys_bus_prot_data *bpd = pd->data->bp_infracfg; int i, ret; - for (i = SPM_MAX_BUS_PROT_DATA; i > 0; i--) { - if (!bpd[i].bus_prot_mask) + for (i = SPM_MAX_BUS_PROT_DATA - 1; i >= 0; i--) { + u32 val, mask = bpd[i].bus_prot_mask; + + if (!mask) continue; - ret = mtk_infracfg_clear_bus_protection(pd->infracfg, - bpd[i].bus_prot_mask, - bpd[i].bus_prot_reg_update); + if (bpd[i].bus_prot_reg_update) + regmap_clear_bits(regmap, bpd[i].bus_prot_clr, mask); + else + regmap_write(regmap, INFRA_TOPAXI_PROTECTEN_CLR, mask); + + ret = regmap_read_poll_timeout(regmap, INFRA_TOPAXI_PROTECTSTA1, + val, !(val & mask), + MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); if (ret) return ret; } @@ -124,6 +146,15 @@ static int scpsys_bus_protect_disable(struct scpsys_domain *pd) return 0; } +static int scpsys_bus_protect_disable(struct scpsys_domain *pd) +{ + int ret; + + ret = _scpsys_bus_protect_disable(pd->data->bp_infracfg, pd->infracfg); + + return ret; +} + static int scpsys_power_on(struct generic_pm_domain *genpd) { struct scpsys_domain *pd = container_of(genpd, struct scpsys_domain, genpd); diff --git a/include/linux/soc/mediatek/infracfg.h b/include/linux/soc/mediatek/infracfg.h index 233463d789c6..5bcaab767f6a 100644 --- a/include/linux/soc/mediatek/infracfg.h +++ b/include/linux/soc/mediatek/infracfg.h @@ -32,6 +32,11 @@ #define MT7622_TOP_AXI_PROT_EN_WB (BIT(2) | BIT(6) | \ BIT(7) | BIT(8)) +#define INFRA_TOPAXI_PROTECTEN 0x0220 +#define INFRA_TOPAXI_PROTECTSTA1 0x0228 +#define INFRA_TOPAXI_PROTECTEN_SET 0x0260 +#define INFRA_TOPAXI_PROTECTEN_CLR 0x0264 + #define REG_INFRA_MISC 0xf00 #define F_DDR_4GB_SUPPORT_EN BIT(13) -- cgit From f414854c884364b8a563760054be615555a62b3a Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Fri, 30 Oct 2020 12:36:12 +0100 Subject: soc: mediatek: pm-domains: Add SMI block as bus protection block Apart from the infracfg block, the SMI block is used to enable the bus protection for some power domains. Add support for this block. Signed-off-by: Matthias Brugger Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20201030113622.201188-7-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mt8173-pm-domains.h | 18 ++++++++---------- drivers/soc/mediatek/mtk-pm-domains.c | 23 ++++++++++++++++------- drivers/soc/mediatek/mtk-pm-domains.h | 25 +++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 17 deletions(-) diff --git a/drivers/soc/mediatek/mt8173-pm-domains.h b/drivers/soc/mediatek/mt8173-pm-domains.h index 72b3acaf74fb..3e8ee5dabb43 100644 --- a/drivers/soc/mediatek/mt8173-pm-domains.h +++ b/drivers/soc/mediatek/mt8173-pm-domains.h @@ -34,10 +34,9 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { .ctl_offs = SPM_DIS_PWR_CON, .sram_pdn_bits = GENMASK(11, 8), .sram_pdn_ack_bits = GENMASK(12, 12), - .bp_infracfg[0] = { - .bus_prot_reg_update = true, - .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | - MT8173_TOP_AXI_PROT_EN_MM_M1, + .bp_infracfg = { + BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MM_M0 | + MT8173_TOP_AXI_PROT_EN_MM_M1), }, }, [MT8173_POWER_DOMAIN_VENC_LT] = { @@ -76,12 +75,11 @@ static const struct scpsys_domain_data scpsys_domain_data_mt8173[] = { .ctl_offs = SPM_MFG_PWR_CON, .sram_pdn_bits = GENMASK(13, 8), .sram_pdn_ack_bits = GENMASK(21, 16), - .bp_infracfg[0] = { - .bus_prot_reg_update = true, - .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | - MT8173_TOP_AXI_PROT_EN_MFG_M0 | - MT8173_TOP_AXI_PROT_EN_MFG_M1 | - MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, + .bp_infracfg = { + BUS_PROT_UPDATE_TOPAXI(MT8173_TOP_AXI_PROT_EN_MFG_S | + MT8173_TOP_AXI_PROT_EN_MFG_M0 | + MT8173_TOP_AXI_PROT_EN_MFG_M1 | + MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT), }, }, }; diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index 6122701d018f..8a21847464c2 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -32,6 +32,7 @@ struct scpsys_domain { int num_clks; struct clk_bulk_data *clks; struct regmap *infracfg; + struct regmap *smi; }; struct scpsys { @@ -99,9 +100,9 @@ static int _scpsys_bus_protect_enable(const struct scpsys_bus_prot_data *bpd, st if (bpd[i].bus_prot_reg_update) regmap_set_bits(regmap, bpd[i].bus_prot_set, mask); else - regmap_write(regmap, INFRA_TOPAXI_PROTECTEN_SET, mask); + regmap_write(regmap, bpd[i].bus_prot_set, mask); - ret = regmap_read_poll_timeout(regmap, INFRA_TOPAXI_PROTECTSTA1, + ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta, val, (val & mask) == mask, MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); if (ret) @@ -116,8 +117,10 @@ static int scpsys_bus_protect_enable(struct scpsys_domain *pd) int ret; ret = _scpsys_bus_protect_enable(pd->data->bp_infracfg, pd->infracfg); + if (ret) + return ret; - return ret; + return _scpsys_bus_protect_enable(pd->data->bp_smi, pd->smi); } static int _scpsys_bus_protect_disable(const struct scpsys_bus_prot_data *bpd, @@ -134,9 +137,9 @@ static int _scpsys_bus_protect_disable(const struct scpsys_bus_prot_data *bpd, if (bpd[i].bus_prot_reg_update) regmap_clear_bits(regmap, bpd[i].bus_prot_clr, mask); else - regmap_write(regmap, INFRA_TOPAXI_PROTECTEN_CLR, mask); + regmap_write(regmap, bpd[i].bus_prot_clr, mask); - ret = regmap_read_poll_timeout(regmap, INFRA_TOPAXI_PROTECTSTA1, + ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta, val, !(val & mask), MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); if (ret) @@ -150,9 +153,11 @@ static int scpsys_bus_protect_disable(struct scpsys_domain *pd) { int ret; - ret = _scpsys_bus_protect_disable(pd->data->bp_infracfg, pd->infracfg); + ret = _scpsys_bus_protect_disable(pd->data->bp_smi, pd->smi); + if (ret) + return ret; - return ret; + return _scpsys_bus_protect_disable(pd->data->bp_infracfg, pd->infracfg); } static int scpsys_power_on(struct generic_pm_domain *genpd) @@ -267,6 +272,10 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no if (IS_ERR(pd->infracfg)) return ERR_CAST(pd->infracfg); + pd->smi = syscon_regmap_lookup_by_phandle_optional(node, "mediatek,smi"); + if (IS_ERR(pd->smi)) + return ERR_CAST(pd->smi); + pd->num_clks = of_clk_get_parent_count(node); if (pd->num_clks > 0) { pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks, sizeof(*pd->clks), GFP_KERNEL); diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h index 125880a58170..c2defbdcdf31 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.h +++ b/drivers/soc/mediatek/mtk-pm-domains.h @@ -34,8 +34,31 @@ #define SPM_MAX_BUS_PROT_DATA 5 +#define _BUS_PROT(_mask, _set, _clr, _sta, _update) { \ + .bus_prot_mask = (_mask), \ + .bus_prot_set = _set, \ + .bus_prot_clr = _clr, \ + .bus_prot_sta = _sta, \ + .bus_prot_reg_update = _update, \ + } + +#define BUS_PROT_WR(_mask, _set, _clr, _sta) \ + _BUS_PROT(_mask, _set, _clr, _sta, false) + +#define BUS_PROT_UPDATE(_mask, _set, _clr, _sta) \ + _BUS_PROT(_mask, _set, _clr, _sta, true) + +#define BUS_PROT_UPDATE_TOPAXI(_mask) \ + BUS_PROT_UPDATE(_mask, \ + INFRA_TOPAXI_PROTECTEN, \ + INFRA_TOPAXI_PROTECTEN_CLR, \ + INFRA_TOPAXI_PROTECTSTA1) + struct scpsys_bus_prot_data { u32 bus_prot_mask; + u32 bus_prot_set; + u32 bus_prot_clr; + u32 bus_prot_sta; bool bus_prot_reg_update; }; @@ -47,6 +70,7 @@ struct scpsys_bus_prot_data { * @sram_pdn_ack_bits: The mask for sram power control acked bits. * @caps: The flag for active wake-up action. * @bp_infracfg: bus protection for infracfg subsystem + * @bp_smi: bus protection for smi subsystem */ struct scpsys_domain_data { u32 sta_mask; @@ -55,6 +79,7 @@ struct scpsys_domain_data { u32 sram_pdn_ack_bits; u8 caps; const struct scpsys_bus_prot_data bp_infracfg[SPM_MAX_BUS_PROT_DATA]; + const struct scpsys_bus_prot_data bp_smi[SPM_MAX_BUS_PROT_DATA]; }; struct scpsys_soc_data { -- cgit From 58a17e310a1c638a71892506f14c1e09b326ed56 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Fri, 30 Oct 2020 12:36:13 +0100 Subject: soc: mediatek: pm-domains: Add extra sram control For some power domains like vpu_core on MT8183 whose sram need to do clock and internal isolation while power on/off sram. We add a cap "MTK_SCPD_SRAM_ISO" to judge if we need to do the extra sram isolation control or not. Signed-off-by: Weiyi Lu Signed-off-by: Matthias Brugger Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20201030113622.201188-8-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pm-domains.c | 23 +++++++++++++++++++++-- drivers/soc/mediatek/mtk-pm-domains.h | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index 8a21847464c2..a6f25933dbf0 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -24,6 +24,8 @@ #define PWR_ON_BIT BIT(2) #define PWR_ON_2ND_BIT BIT(3) #define PWR_CLK_DIS_BIT BIT(4) +#define PWR_SRAM_CLKISO_BIT BIT(5) +#define PWR_SRAM_ISOINT_B_BIT BIT(6) struct scpsys_domain { struct generic_pm_domain genpd; @@ -65,12 +67,23 @@ static int scpsys_sram_enable(struct scpsys_domain *pd) u32 pdn_ack = pd->data->sram_pdn_ack_bits; struct scpsys *scpsys = pd->scpsys; unsigned int tmp; + int ret; regmap_clear_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); /* Either wait until SRAM_PDN_ACK all 1 or 0 */ - return regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp, - (tmp & pdn_ack) == 0, MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + ret = regmap_read_poll_timeout(scpsys->base, pd->data->ctl_offs, tmp, + (tmp & pdn_ack) == 0, MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); + if (ret < 0) + return ret; + + if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_ISO)) { + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_ISOINT_B_BIT); + udelay(1); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_CLKISO_BIT); + } + + return 0; } static int scpsys_sram_disable(struct scpsys_domain *pd) @@ -79,6 +92,12 @@ static int scpsys_sram_disable(struct scpsys_domain *pd) struct scpsys *scpsys = pd->scpsys; unsigned int tmp; + if (MTK_SCPD_CAPS(pd, MTK_SCPD_SRAM_ISO)) { + regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_CLKISO_BIT); + udelay(1); + regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_SRAM_ISOINT_B_BIT); + } + regmap_set_bits(scpsys->base, pd->data->ctl_offs, pd->data->sram_pdn_bits); /* Either wait until SRAM_PDN_ACK all 1 or 0 */ diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h index c2defbdcdf31..f190a0d9e592 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.h +++ b/drivers/soc/mediatek/mtk-pm-domains.h @@ -5,6 +5,7 @@ #define MTK_SCPD_ACTIVE_WAKEUP BIT(0) #define MTK_SCPD_FWAIT_SRAM BIT(1) +#define MTK_SCPD_SRAM_ISO BIT(2) #define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) #define SPM_VDE_PWR_CON 0x0210 -- cgit From 123e8b4fd0cd9999dd384bef1d7417da68fde962 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Fri, 30 Oct 2020 12:36:14 +0100 Subject: soc: mediatek: pm-domains: Add subsystem clocks For the bus protection operations, some subsystem clocks need to be enabled before releasing the protection. This patch identifies the subsystem clocks by it's name. Suggested-by: Weiyi Lu [Adapted the patch to the mtk-pm-domains driver] Signed-off-by: Matthias Brugger Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20201030113622.201188-9-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pm-domains.c | 81 ++++++++++++++++++++++++++++++----- drivers/soc/mediatek/mtk-pm-domains.h | 2 + 2 files changed, 72 insertions(+), 11 deletions(-) diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index a6f25933dbf0..88dec58aedd9 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -3,6 +3,7 @@ * Copyright (c) 2020 Collabora Ltd. */ #include +#include #include #include #include @@ -33,6 +34,8 @@ struct scpsys_domain { struct scpsys *scpsys; int num_clks; struct clk_bulk_data *clks; + int num_subsys_clks; + struct clk_bulk_data *subsys_clks; struct regmap *infracfg; struct regmap *smi; }; @@ -204,9 +207,13 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); + ret = clk_bulk_enable(pd->num_subsys_clks, pd->subsys_clks); + if (ret) + goto err_pwr_ack; + ret = scpsys_sram_enable(pd); if (ret < 0) - goto err_pwr_ack; + goto err_disable_subsys_clks; ret = scpsys_bus_protect_disable(pd); if (ret < 0) @@ -216,6 +223,8 @@ static int scpsys_power_on(struct generic_pm_domain *genpd) err_disable_sram: scpsys_sram_disable(pd); +err_disable_subsys_clks: + clk_bulk_disable(pd->num_subsys_clks, pd->subsys_clks); err_pwr_ack: clk_bulk_disable(pd->num_clks, pd->clks); return ret; @@ -236,6 +245,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) if (ret < 0) return ret; + clk_bulk_disable(pd->num_subsys_clks, pd->subsys_clks); + /* subsys power off */ regmap_clear_bits(scpsys->base, pd->data->ctl_offs, PWR_RST_B_BIT); regmap_set_bits(scpsys->base, pd->data->ctl_offs, PWR_ISO_BIT); @@ -259,7 +270,11 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no { const struct scpsys_domain_data *domain_data; struct scpsys_domain *pd; - int i, ret; + struct property *prop; + const char *clk_name; + int i, ret, num_clks; + struct clk *clk; + int clk_ind = 0; u32 id; ret = of_property_read_u32(node, "reg", &id); @@ -295,25 +310,62 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no if (IS_ERR(pd->smi)) return ERR_CAST(pd->smi); - pd->num_clks = of_clk_get_parent_count(node); - if (pd->num_clks > 0) { + num_clks = of_clk_get_parent_count(node); + if (num_clks > 0) { + /* Calculate number of subsys_clks */ + of_property_for_each_string(node, "clock-names", prop, clk_name) { + char *subsys; + + subsys = strchr(clk_name, '-'); + if (subsys) + pd->num_subsys_clks++; + else + pd->num_clks++; + } + pd->clks = devm_kcalloc(scpsys->dev, pd->num_clks, sizeof(*pd->clks), GFP_KERNEL); if (!pd->clks) return ERR_PTR(-ENOMEM); + + pd->subsys_clks = devm_kcalloc(scpsys->dev, pd->num_subsys_clks, + sizeof(*pd->subsys_clks), GFP_KERNEL); + if (!pd->subsys_clks) + return ERR_PTR(-ENOMEM); + } for (i = 0; i < pd->num_clks; i++) { - pd->clks[i].clk = of_clk_get(node, i); - if (IS_ERR(pd->clks[i].clk)) { - dev_err(scpsys->dev, "%pOF: failed to get clk at index %d\n", - node, i); - return ERR_PTR(-EINVAL); + clk = of_clk_get(node, i); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err_probe(scpsys->dev, ret, + "%pOF: failed to get clk at index %d: %d\n", node, i, ret); + goto err_put_clocks; } + + pd->clks[clk_ind++].clk = clk; + } + + for (i = 0; i < pd->num_subsys_clks; i++) { + clk = of_clk_get(node, i + clk_ind); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err_probe(scpsys->dev, ret, + "%pOF: failed to get clk at index %d: %d\n", node, + i + clk_ind, ret); + goto err_put_subsys_clocks; + } + + pd->subsys_clks[i].clk = clk; } ret = clk_bulk_prepare(pd->num_clks, pd->clks); if (ret) - goto err_put_clocks; + goto err_put_subsys_clocks; + + ret = clk_bulk_prepare(pd->num_subsys_clks, pd->subsys_clks); + if (ret) + goto err_unprepare_clocks; /* * Initially turn on all domains to make the domains usable @@ -331,7 +383,7 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no ret = -EINVAL; dev_err(scpsys->dev, "power domain with id %d already exists, check your device-tree\n", id); - goto err_unprepare_clocks; + goto err_unprepare_subsys_clocks; } pd->genpd.name = node->name; @@ -343,8 +395,12 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no return scpsys->pd_data.domains[id]; +err_unprepare_subsys_clocks: + clk_bulk_unprepare(pd->num_subsys_clks, pd->subsys_clks); err_unprepare_clocks: clk_bulk_unprepare(pd->num_clks, pd->clks); +err_put_subsys_clocks: + clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks); err_put_clocks: clk_bulk_put(pd->num_clks, pd->clks); return ERR_PTR(ret); @@ -421,6 +477,9 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd) clk_bulk_unprepare(pd->num_clks, pd->clks); clk_bulk_put(pd->num_clks, pd->clks); + + clk_bulk_unprepare(pd->num_subsys_clks, pd->subsys_clks); + clk_bulk_put(pd->num_subsys_clks, pd->subsys_clks); } static void scpsys_domain_cleanup(struct scpsys *scpsys) diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h index f190a0d9e592..20df5689739b 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.h +++ b/drivers/soc/mediatek/mtk-pm-domains.h @@ -63,6 +63,8 @@ struct scpsys_bus_prot_data { bool bus_prot_reg_update; }; +#define MAX_SUBSYS_CLKS 10 + /** * struct scpsys_domain_data - scp domain data for power on/off flow * @sta_mask: The mask for power on/off status bit. -- cgit From 1d4597fa18b2e5d38deebdaa8121734a166a6c73 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Fri, 30 Oct 2020 12:36:15 +0100 Subject: soc: mediatek: pm-domains: Allow bus protection to ignore clear ack In some cases the hardware does not create an acknowledgment of the bus protection clearing. Add a flag to the bus protection indicating that a clear event will be ignored. Signed-off-by: Matthias Brugger Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20201030113622.201188-10-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pm-domains.c | 3 +++ drivers/soc/mediatek/mtk-pm-domains.h | 23 ++++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index 88dec58aedd9..03279a999dfc 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -161,6 +161,9 @@ static int _scpsys_bus_protect_disable(const struct scpsys_bus_prot_data *bpd, else regmap_write(regmap, bpd[i].bus_prot_clr, mask); + if (bpd[i].ignore_clr_ack) + continue; + ret = regmap_read_poll_timeout(regmap, bpd[i].bus_prot_sta, val, !(val & mask), MTK_POLL_DELAY_US, MTK_POLL_TIMEOUT); diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h index 20df5689739b..809d2d43f01d 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.h +++ b/drivers/soc/mediatek/mtk-pm-domains.h @@ -35,19 +35,23 @@ #define SPM_MAX_BUS_PROT_DATA 5 -#define _BUS_PROT(_mask, _set, _clr, _sta, _update) { \ - .bus_prot_mask = (_mask), \ - .bus_prot_set = _set, \ - .bus_prot_clr = _clr, \ - .bus_prot_sta = _sta, \ - .bus_prot_reg_update = _update, \ +#define _BUS_PROT(_mask, _set, _clr, _sta, _update, _ignore) { \ + .bus_prot_mask = (_mask), \ + .bus_prot_set = _set, \ + .bus_prot_clr = _clr, \ + .bus_prot_sta = _sta, \ + .bus_prot_reg_update = _update, \ + .ignore_clr_ack = _ignore, \ } -#define BUS_PROT_WR(_mask, _set, _clr, _sta) \ - _BUS_PROT(_mask, _set, _clr, _sta, false) +#define BUS_PROT_WR(_mask, _set, _clr, _sta) \ + _BUS_PROT(_mask, _set, _clr, _sta, false, false) + +#define BUS_PROT_WR_IGN(_mask, _set, _clr, _sta) \ + _BUS_PROT(_mask, _set, _clr, _sta, false, true) #define BUS_PROT_UPDATE(_mask, _set, _clr, _sta) \ - _BUS_PROT(_mask, _set, _clr, _sta, true) + _BUS_PROT(_mask, _set, _clr, _sta, true, false) #define BUS_PROT_UPDATE_TOPAXI(_mask) \ BUS_PROT_UPDATE(_mask, \ @@ -61,6 +65,7 @@ struct scpsys_bus_prot_data { u32 bus_prot_clr; u32 bus_prot_sta; bool bus_prot_reg_update; + bool ignore_clr_ack; }; #define MAX_SUBSYS_CLKS 10 -- cgit From eb9fa767fbe19d3db7d303e9fde7f3056221ffe1 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Fri, 30 Oct 2020 12:36:17 +0100 Subject: soc: mediatek: pm-domains: Add support for mt8183 Add the needed board data to support mt8183 SoC. Signed-off-by: Matthias Brugger Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20201030113622.201188-12-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mt8183-pm-domains.h | 221 +++++++++++++++++++++++++++++++ drivers/soc/mediatek/mtk-pm-domains.c | 5 + drivers/soc/mediatek/mtk-pm-domains.h | 1 + include/linux/soc/mediatek/infracfg.h | 46 +++++++ 4 files changed, 273 insertions(+) create mode 100644 drivers/soc/mediatek/mt8183-pm-domains.h diff --git a/drivers/soc/mediatek/mt8183-pm-domains.h b/drivers/soc/mediatek/mt8183-pm-domains.h new file mode 100644 index 000000000000..8d996c5d2682 --- /dev/null +++ b/drivers/soc/mediatek/mt8183-pm-domains.h @@ -0,0 +1,221 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_MEDIATEK_MT8183_PM_DOMAINS_H +#define __SOC_MEDIATEK_MT8183_PM_DOMAINS_H + +#include "mtk-pm-domains.h" +#include + +/* + * MT8183 power domain support + */ + +static const struct scpsys_domain_data scpsys_domain_data_mt8183[] = { + [MT8183_POWER_DOMAIN_AUDIO] = { + .sta_mask = PWR_STATUS_AUDIO, + .ctl_offs = 0x0314, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + }, + [MT8183_POWER_DOMAIN_CONN] = { + .sta_mask = PWR_STATUS_CONN, + .ctl_offs = 0x032c, + .sram_pdn_bits = 0, + .sram_pdn_ack_bits = 0, + .bp_infracfg = { + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_CONN, MT8183_TOP_AXI_PROT_EN_SET, + MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1), + }, + }, + [MT8183_POWER_DOMAIN_MFG_ASYNC] = { + .sta_mask = PWR_STATUS_MFG_ASYNC, + .ctl_offs = 0x0334, + .sram_pdn_bits = 0, + .sram_pdn_ack_bits = 0, + }, + [MT8183_POWER_DOMAIN_MFG] = { + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = 0x0338, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8183_POWER_DOMAIN_MFG_CORE0] = { + .sta_mask = BIT(7), + .ctl_offs = 0x034c, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8183_POWER_DOMAIN_MFG_CORE1] = { + .sta_mask = BIT(20), + .ctl_offs = 0x0310, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8183_POWER_DOMAIN_MFG_2D] = { + .sta_mask = PWR_STATUS_MFG_2D, + .ctl_offs = 0x0348, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_1_MFG, MT8183_TOP_AXI_PROT_EN_1_SET, + MT8183_TOP_AXI_PROT_EN_1_CLR, MT8183_TOP_AXI_PROT_EN_STA1_1), + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MFG, MT8183_TOP_AXI_PROT_EN_SET, + MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1), + }, + }, + [MT8183_POWER_DOMAIN_DISP] = { + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = 0x030c, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_1_DISP, MT8183_TOP_AXI_PROT_EN_1_SET, + MT8183_TOP_AXI_PROT_EN_1_CLR, MT8183_TOP_AXI_PROT_EN_STA1_1), + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_DISP, MT8183_TOP_AXI_PROT_EN_SET, + MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1), + }, + .bp_smi = { + BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_DISP, + MT8183_SMI_COMMON_CLAMP_EN_SET, + MT8183_SMI_COMMON_CLAMP_EN_CLR, + MT8183_SMI_COMMON_CLAMP_EN), + }, + }, + [MT8183_POWER_DOMAIN_CAM] = { + .sta_mask = BIT(25), + .ctl_offs = 0x0344, + .sram_pdn_bits = GENMASK(9, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_CAM, MT8183_TOP_AXI_PROT_EN_MM_SET, + MT8183_TOP_AXI_PROT_EN_MM_CLR, MT8183_TOP_AXI_PROT_EN_MM_STA1), + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_CAM, MT8183_TOP_AXI_PROT_EN_SET, + MT8183_TOP_AXI_PROT_EN_CLR, MT8183_TOP_AXI_PROT_EN_STA1), + BUS_PROT_WR_IGN(MT8183_TOP_AXI_PROT_EN_MM_CAM_2ND, + MT8183_TOP_AXI_PROT_EN_MM_SET, + MT8183_TOP_AXI_PROT_EN_MM_CLR, + MT8183_TOP_AXI_PROT_EN_MM_STA1), + }, + .bp_smi = { + BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_CAM, + MT8183_SMI_COMMON_CLAMP_EN_SET, + MT8183_SMI_COMMON_CLAMP_EN_CLR, + MT8183_SMI_COMMON_CLAMP_EN), + }, + }, + [MT8183_POWER_DOMAIN_ISP] = { + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = 0x0308, + .sram_pdn_bits = GENMASK(9, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_ISP, + MT8183_TOP_AXI_PROT_EN_MM_SET, + MT8183_TOP_AXI_PROT_EN_MM_CLR, + MT8183_TOP_AXI_PROT_EN_MM_STA1), + BUS_PROT_WR_IGN(MT8183_TOP_AXI_PROT_EN_MM_ISP_2ND, + MT8183_TOP_AXI_PROT_EN_MM_SET, + MT8183_TOP_AXI_PROT_EN_MM_CLR, + MT8183_TOP_AXI_PROT_EN_MM_STA1), + }, + .bp_smi = { + BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_ISP, + MT8183_SMI_COMMON_CLAMP_EN_SET, + MT8183_SMI_COMMON_CLAMP_EN_CLR, + MT8183_SMI_COMMON_CLAMP_EN), + }, + }, + [MT8183_POWER_DOMAIN_VDEC] = { + .sta_mask = BIT(31), + .ctl_offs = 0x0300, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_smi = { + BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_VDEC, + MT8183_SMI_COMMON_CLAMP_EN_SET, + MT8183_SMI_COMMON_CLAMP_EN_CLR, + MT8183_SMI_COMMON_CLAMP_EN), + }, + }, + [MT8183_POWER_DOMAIN_VENC] = { + .sta_mask = PWR_STATUS_VENC, + .ctl_offs = 0x0304, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .bp_smi = { + BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_VENC, + MT8183_SMI_COMMON_CLAMP_EN_SET, + MT8183_SMI_COMMON_CLAMP_EN_CLR, + MT8183_SMI_COMMON_CLAMP_EN), + }, + }, + [MT8183_POWER_DOMAIN_VPU_TOP] = { + .sta_mask = BIT(26), + .ctl_offs = 0x0324, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_VPU_TOP, + MT8183_TOP_AXI_PROT_EN_MM_SET, + MT8183_TOP_AXI_PROT_EN_MM_CLR, + MT8183_TOP_AXI_PROT_EN_MM_STA1), + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_VPU_TOP, + MT8183_TOP_AXI_PROT_EN_SET, + MT8183_TOP_AXI_PROT_EN_CLR, + MT8183_TOP_AXI_PROT_EN_STA1), + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MM_VPU_TOP_2ND, + MT8183_TOP_AXI_PROT_EN_MM_SET, + MT8183_TOP_AXI_PROT_EN_MM_CLR, + MT8183_TOP_AXI_PROT_EN_MM_STA1), + }, + .bp_smi = { + BUS_PROT_WR(MT8183_SMI_COMMON_SMI_CLAMP_VPU_TOP, + MT8183_SMI_COMMON_CLAMP_EN_SET, + MT8183_SMI_COMMON_CLAMP_EN_CLR, + MT8183_SMI_COMMON_CLAMP_EN), + }, + }, + [MT8183_POWER_DOMAIN_VPU_CORE0] = { + .sta_mask = BIT(27), + .ctl_offs = 0x33c, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE0, + MT8183_TOP_AXI_PROT_EN_MCU_SET, + MT8183_TOP_AXI_PROT_EN_MCU_CLR, + MT8183_TOP_AXI_PROT_EN_MCU_STA1), + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE0_2ND, + MT8183_TOP_AXI_PROT_EN_MCU_SET, + MT8183_TOP_AXI_PROT_EN_MCU_CLR, + MT8183_TOP_AXI_PROT_EN_MCU_STA1), + }, + .caps = MTK_SCPD_SRAM_ISO, + }, + [MT8183_POWER_DOMAIN_VPU_CORE1] = { + .sta_mask = BIT(28), + .ctl_offs = 0x0340, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE1, + MT8183_TOP_AXI_PROT_EN_MCU_SET, + MT8183_TOP_AXI_PROT_EN_MCU_CLR, + MT8183_TOP_AXI_PROT_EN_MCU_STA1), + BUS_PROT_WR(MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE1_2ND, + MT8183_TOP_AXI_PROT_EN_MCU_SET, + MT8183_TOP_AXI_PROT_EN_MCU_CLR, + MT8183_TOP_AXI_PROT_EN_MCU_STA1), + }, + .caps = MTK_SCPD_SRAM_ISO, + }, +}; + +static const struct scpsys_soc_data mt8183_scpsys_data = { + .domains_data = scpsys_domain_data_mt8183, + .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8183), + .pwr_sta_offs = 0x0180, + .pwr_sta2nd_offs = 0x0184 +}; + +#endif /* __SOC_MEDIATEK_MT8183_PM_DOMAINS_H */ diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index 03279a999dfc..8703d50cd2b7 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -16,6 +16,7 @@ #include #include "mt8173-pm-domains.h" +#include "mt8183-pm-domains.h" #define MTK_POLL_DELAY_US 10 #define MTK_POLL_TIMEOUT USEC_PER_SEC @@ -505,6 +506,10 @@ static const struct of_device_id scpsys_of_match[] = { .compatible = "mediatek,mt8173-power-controller", .data = &mt8173_scpsys_data, }, + { + .compatible = "mediatek,mt8183-power-controller", + .data = &mt8183_scpsys_data, + }, { } }; diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h index 809d2d43f01d..2c745f11b422 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.h +++ b/drivers/soc/mediatek/mtk-pm-domains.h @@ -22,6 +22,7 @@ #define SPM_PWR_STATUS 0x060c #define SPM_PWR_STATUS_2ND 0x0610 +#define PWR_STATUS_CONN BIT(1) #define PWR_STATUS_DISP BIT(3) #define PWR_STATUS_MFG BIT(4) #define PWR_STATUS_ISP BIT(5) diff --git a/include/linux/soc/mediatek/infracfg.h b/include/linux/soc/mediatek/infracfg.h index 5bcaab767f6a..9d01e32e19bc 100644 --- a/include/linux/soc/mediatek/infracfg.h +++ b/include/linux/soc/mediatek/infracfg.h @@ -2,6 +2,52 @@ #ifndef __SOC_MEDIATEK_INFRACFG_H #define __SOC_MEDIATEK_INFRACFG_H +#define MT8183_TOP_AXI_PROT_EN_STA1 0x228 +#define MT8183_TOP_AXI_PROT_EN_STA1_1 0x258 +#define MT8183_TOP_AXI_PROT_EN_SET 0x2a0 +#define MT8183_TOP_AXI_PROT_EN_CLR 0x2a4 +#define MT8183_TOP_AXI_PROT_EN_1_SET 0x2a8 +#define MT8183_TOP_AXI_PROT_EN_1_CLR 0x2ac +#define MT8183_TOP_AXI_PROT_EN_MCU_SET 0x2c4 +#define MT8183_TOP_AXI_PROT_EN_MCU_CLR 0x2c8 +#define MT8183_TOP_AXI_PROT_EN_MCU_STA1 0x2e4 +#define MT8183_TOP_AXI_PROT_EN_MM_SET 0x2d4 +#define MT8183_TOP_AXI_PROT_EN_MM_CLR 0x2d8 +#define MT8183_TOP_AXI_PROT_EN_MM_STA1 0x2ec + +#define MT8183_TOP_AXI_PROT_EN_DISP (BIT(10) | BIT(11)) +#define MT8183_TOP_AXI_PROT_EN_CONN (BIT(13) | BIT(14)) +#define MT8183_TOP_AXI_PROT_EN_MFG (BIT(21) | BIT(22)) +#define MT8183_TOP_AXI_PROT_EN_CAM BIT(28) +#define MT8183_TOP_AXI_PROT_EN_VPU_TOP BIT(27) +#define MT8183_TOP_AXI_PROT_EN_1_DISP (BIT(16) | BIT(17)) +#define MT8183_TOP_AXI_PROT_EN_1_MFG GENMASK(21, 19) +#define MT8183_TOP_AXI_PROT_EN_MM_ISP (BIT(3) | BIT(8)) +#define MT8183_TOP_AXI_PROT_EN_MM_ISP_2ND BIT(10) +#define MT8183_TOP_AXI_PROT_EN_MM_CAM (BIT(4) | BIT(5) | \ + BIT(9) | BIT(13)) +#define MT8183_TOP_AXI_PROT_EN_MM_VPU_TOP (GENMASK(9, 6) | \ + BIT(12)) +#define MT8183_TOP_AXI_PROT_EN_MM_VPU_TOP_2ND (BIT(10) | BIT(11)) +#define MT8183_TOP_AXI_PROT_EN_MM_CAM_2ND BIT(11) +#define MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE0_2ND (BIT(0) | BIT(2) | \ + BIT(4)) +#define MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE1_2ND (BIT(1) | BIT(3) | \ + BIT(5)) +#define MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE0 BIT(6) +#define MT8183_TOP_AXI_PROT_EN_MCU_VPU_CORE1 BIT(7) + +#define MT8183_SMI_COMMON_CLAMP_EN 0x3c0 +#define MT8183_SMI_COMMON_CLAMP_EN_SET 0x3c4 +#define MT8183_SMI_COMMON_CLAMP_EN_CLR 0x3c8 + +#define MT8183_SMI_COMMON_SMI_CLAMP_DISP GENMASK(7, 0) +#define MT8183_SMI_COMMON_SMI_CLAMP_VENC BIT(1) +#define MT8183_SMI_COMMON_SMI_CLAMP_ISP BIT(2) +#define MT8183_SMI_COMMON_SMI_CLAMP_CAM (BIT(3) | BIT(4)) +#define MT8183_SMI_COMMON_SMI_CLAMP_VPU_TOP (BIT(5) | BIT(6)) +#define MT8183_SMI_COMMON_SMI_CLAMP_VDEC BIT(7) + #define MT8173_TOP_AXI_PROT_EN_MCI_M2 BIT(0) #define MT8173_TOP_AXI_PROT_EN_MM_M0 BIT(1) #define MT8173_TOP_AXI_PROT_EN_MM_M1 BIT(2) -- cgit From c1f3163d8ff36f5b75d467bf95581b8f2319cd64 Mon Sep 17 00:00:00 2001 From: Weiyi Lu Date: Fri, 30 Oct 2020 12:36:21 +0100 Subject: soc: mediatek: pm-domains: Add default power off flag For some power domain, like conn on MT8192, it should be default OFF. Because the power on/off control relies the function of connectivity chip and its firmware. And if project choose other chip vendor solution, those necessary connectivity functions will not provided. Signed-off-by: Weiyi Lu Signed-off-by: Enric Balletbo i Serra Link: https://lore.kernel.org/r/20201030113622.201188-16-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pm-domains.c | 25 ++++++++++++++++++------- drivers/soc/mediatek/mtk-pm-domains.h | 1 + 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index 8703d50cd2b7..c3b85b69f2f7 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -377,10 +377,16 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no * software. The unused domains will be switched off during * late_init time. */ - ret = scpsys_power_on(&pd->genpd); - if (ret < 0) { - dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret); - goto err_unprepare_clocks; + if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) { + if (scpsys_domain_is_on(pd)) + dev_warn(scpsys->dev, + "%pOF: A default off power domain has been ON\n", node); + } else { + ret = scpsys_power_on(&pd->genpd); + if (ret < 0) { + dev_err(scpsys->dev, "%pOF: failed to power on domain: %d\n", node, ret); + goto err_unprepare_clocks; + } } if (scpsys->domains[id]) { @@ -394,7 +400,11 @@ generic_pm_domain *scpsys_add_one_domain(struct scpsys *scpsys, struct device_no pd->genpd.power_off = scpsys_power_off; pd->genpd.power_on = scpsys_power_on; - pm_genpd_init(&pd->genpd, NULL, false); + if (MTK_SCPD_CAPS(pd, MTK_SCPD_KEEP_DEFAULT_OFF)) + pm_genpd_init(&pd->genpd, NULL, true); + else + pm_genpd_init(&pd->genpd, NULL, false); + scpsys->domains[id] = &pd->genpd; return scpsys->pd_data.domains[id]; @@ -467,6 +477,9 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd) { int ret; + if (scpsys_domain_is_on(pd)) + scpsys_power_off(&pd->genpd); + /* * We're in the error cleanup already, so we only complain, * but won't emit another error on top of the original one. @@ -477,8 +490,6 @@ static void scpsys_remove_one_domain(struct scpsys_domain *pd) "failed to remove domain '%s' : %d - state may be inconsistent\n", pd->genpd.name, ret); - scpsys_power_off(&pd->genpd); - clk_bulk_unprepare(pd->num_clks, pd->clks); clk_bulk_put(pd->num_clks, pd->clks); diff --git a/drivers/soc/mediatek/mtk-pm-domains.h b/drivers/soc/mediatek/mtk-pm-domains.h index 2c745f11b422..a2f4d8f97e05 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.h +++ b/drivers/soc/mediatek/mtk-pm-domains.h @@ -6,6 +6,7 @@ #define MTK_SCPD_ACTIVE_WAKEUP BIT(0) #define MTK_SCPD_FWAIT_SRAM BIT(1) #define MTK_SCPD_SRAM_ISO BIT(2) +#define MTK_SCPD_KEEP_DEFAULT_OFF BIT(3) #define MTK_SCPD_CAPS(_scpd, _x) ((_scpd)->data->caps & (_x)) #define SPM_VDE_PWR_CON 0x0210 -- cgit From a49d5e7a89d644a5c0ddc851be4bbf08614e6015 Mon Sep 17 00:00:00 2001 From: Weiyi Lu Date: Fri, 30 Oct 2020 12:36:22 +0100 Subject: soc: mediatek: pm-domains: Add support for mt8192 Add the needed board data to support mt8192 SoC. Signed-off-by: Weiyi Lu Signed-off-by: Enric Balletbo i Serra Tested-by: Weiyi Lu Link: https://lore.kernel.org/r/20201030113622.201188-17-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mt8192-pm-domains.h | 292 +++++++++++++++++++++++++++++++ drivers/soc/mediatek/mtk-pm-domains.c | 5 + include/linux/soc/mediatek/infracfg.h | 56 ++++++ 3 files changed, 353 insertions(+) create mode 100644 drivers/soc/mediatek/mt8192-pm-domains.h diff --git a/drivers/soc/mediatek/mt8192-pm-domains.h b/drivers/soc/mediatek/mt8192-pm-domains.h new file mode 100644 index 000000000000..0fdf6dc6231f --- /dev/null +++ b/drivers/soc/mediatek/mt8192-pm-domains.h @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_MEDIATEK_MT8192_PM_DOMAINS_H +#define __SOC_MEDIATEK_MT8192_PM_DOMAINS_H + +#include "mtk-pm-domains.h" +#include + +/* + * MT8192 power domain support + */ + +static const struct scpsys_domain_data scpsys_domain_data_mt8192[] = { + [MT8192_POWER_DOMAIN_AUDIO] = { + .sta_mask = BIT(21), + .ctl_offs = 0x0354, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_AUDIO, + MT8192_TOP_AXI_PROT_EN_2_SET, + MT8192_TOP_AXI_PROT_EN_2_CLR, + MT8192_TOP_AXI_PROT_EN_2_STA1), + }, + }, + [MT8192_POWER_DOMAIN_CONN] = { + .sta_mask = PWR_STATUS_CONN, + .ctl_offs = 0x0304, + .sram_pdn_bits = 0, + .sram_pdn_ack_bits = 0, + .bp_infracfg = { + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_CONN, + MT8192_TOP_AXI_PROT_EN_SET, + MT8192_TOP_AXI_PROT_EN_CLR, + MT8192_TOP_AXI_PROT_EN_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_CONN_2ND, + MT8192_TOP_AXI_PROT_EN_SET, + MT8192_TOP_AXI_PROT_EN_CLR, + MT8192_TOP_AXI_PROT_EN_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_1_CONN, + MT8192_TOP_AXI_PROT_EN_1_SET, + MT8192_TOP_AXI_PROT_EN_1_CLR, + MT8192_TOP_AXI_PROT_EN_1_STA1), + }, + .caps = MTK_SCPD_KEEP_DEFAULT_OFF, + }, + [MT8192_POWER_DOMAIN_MFG0] = { + .sta_mask = BIT(2), + .ctl_offs = 0x0308, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8192_POWER_DOMAIN_MFG1] = { + .sta_mask = BIT(3), + .ctl_offs = 0x030c, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_1_MFG1, + MT8192_TOP_AXI_PROT_EN_1_SET, + MT8192_TOP_AXI_PROT_EN_1_CLR, + MT8192_TOP_AXI_PROT_EN_1_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_MFG1, + MT8192_TOP_AXI_PROT_EN_2_SET, + MT8192_TOP_AXI_PROT_EN_2_CLR, + MT8192_TOP_AXI_PROT_EN_2_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MFG1, + MT8192_TOP_AXI_PROT_EN_SET, + MT8192_TOP_AXI_PROT_EN_CLR, + MT8192_TOP_AXI_PROT_EN_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_MFG1_2ND, + MT8192_TOP_AXI_PROT_EN_2_SET, + MT8192_TOP_AXI_PROT_EN_2_CLR, + MT8192_TOP_AXI_PROT_EN_2_STA1), + }, + }, + [MT8192_POWER_DOMAIN_MFG2] = { + .sta_mask = BIT(4), + .ctl_offs = 0x0310, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8192_POWER_DOMAIN_MFG3] = { + .sta_mask = BIT(5), + .ctl_offs = 0x0314, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8192_POWER_DOMAIN_MFG4] = { + .sta_mask = BIT(6), + .ctl_offs = 0x0318, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8192_POWER_DOMAIN_MFG5] = { + .sta_mask = BIT(7), + .ctl_offs = 0x031c, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8192_POWER_DOMAIN_MFG6] = { + .sta_mask = BIT(8), + .ctl_offs = 0x0320, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8192_POWER_DOMAIN_DISP] = { + .sta_mask = BIT(20), + .ctl_offs = 0x0350, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR_IGN(MT8192_TOP_AXI_PROT_EN_MM_DISP, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + BUS_PROT_WR_IGN(MT8192_TOP_AXI_PROT_EN_MM_2_DISP, + MT8192_TOP_AXI_PROT_EN_MM_2_SET, + MT8192_TOP_AXI_PROT_EN_MM_2_CLR, + MT8192_TOP_AXI_PROT_EN_MM_2_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_DISP, + MT8192_TOP_AXI_PROT_EN_SET, + MT8192_TOP_AXI_PROT_EN_CLR, + MT8192_TOP_AXI_PROT_EN_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_DISP_2ND, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_DISP_2ND, + MT8192_TOP_AXI_PROT_EN_MM_2_SET, + MT8192_TOP_AXI_PROT_EN_MM_2_CLR, + MT8192_TOP_AXI_PROT_EN_MM_2_STA1), + }, + }, + [MT8192_POWER_DOMAIN_IPE] = { + .sta_mask = BIT(14), + .ctl_offs = 0x0338, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_IPE, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_IPE_2ND, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + }, + }, + [MT8192_POWER_DOMAIN_ISP] = { + .sta_mask = BIT(12), + .ctl_offs = 0x0330, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_ISP, + MT8192_TOP_AXI_PROT_EN_MM_2_SET, + MT8192_TOP_AXI_PROT_EN_MM_2_CLR, + MT8192_TOP_AXI_PROT_EN_MM_2_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_ISP_2ND, + MT8192_TOP_AXI_PROT_EN_MM_2_SET, + MT8192_TOP_AXI_PROT_EN_MM_2_CLR, + MT8192_TOP_AXI_PROT_EN_MM_2_STA1), + }, + }, + [MT8192_POWER_DOMAIN_ISP2] = { + .sta_mask = BIT(13), + .ctl_offs = 0x0334, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_ISP2, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_ISP2_2ND, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + }, + }, + [MT8192_POWER_DOMAIN_MDP] = { + .sta_mask = BIT(19), + .ctl_offs = 0x034c, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_MDP, + MT8192_TOP_AXI_PROT_EN_MM_2_SET, + MT8192_TOP_AXI_PROT_EN_MM_2_CLR, + MT8192_TOP_AXI_PROT_EN_MM_2_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_2_MDP_2ND, + MT8192_TOP_AXI_PROT_EN_MM_2_SET, + MT8192_TOP_AXI_PROT_EN_MM_2_CLR, + MT8192_TOP_AXI_PROT_EN_MM_2_STA1), + }, + }, + [MT8192_POWER_DOMAIN_VENC] = { + .sta_mask = BIT(17), + .ctl_offs = 0x0344, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VENC, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VENC_2ND, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + }, + }, + [MT8192_POWER_DOMAIN_VDEC] = { + .sta_mask = BIT(15), + .ctl_offs = 0x033c, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VDEC, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_VDEC_2ND, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + }, + }, + [MT8192_POWER_DOMAIN_VDEC2] = { + .sta_mask = BIT(16), + .ctl_offs = 0x0340, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8192_POWER_DOMAIN_CAM] = { + .sta_mask = BIT(23), + .ctl_offs = 0x035c, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .bp_infracfg = { + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_2_CAM, + MT8192_TOP_AXI_PROT_EN_2_SET, + MT8192_TOP_AXI_PROT_EN_2_CLR, + MT8192_TOP_AXI_PROT_EN_2_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_CAM, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_1_CAM, + MT8192_TOP_AXI_PROT_EN_1_SET, + MT8192_TOP_AXI_PROT_EN_1_CLR, + MT8192_TOP_AXI_PROT_EN_1_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_MM_CAM_2ND, + MT8192_TOP_AXI_PROT_EN_MM_SET, + MT8192_TOP_AXI_PROT_EN_MM_CLR, + MT8192_TOP_AXI_PROT_EN_MM_STA1), + BUS_PROT_WR(MT8192_TOP_AXI_PROT_EN_VDNR_CAM, + MT8192_TOP_AXI_PROT_EN_VDNR_SET, + MT8192_TOP_AXI_PROT_EN_VDNR_CLR, + MT8192_TOP_AXI_PROT_EN_VDNR_STA1), + }, + }, + [MT8192_POWER_DOMAIN_CAM_RAWA] = { + .sta_mask = BIT(24), + .ctl_offs = 0x0360, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8192_POWER_DOMAIN_CAM_RAWB] = { + .sta_mask = BIT(25), + .ctl_offs = 0x0364, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, + [MT8192_POWER_DOMAIN_CAM_RAWC] = { + .sta_mask = BIT(26), + .ctl_offs = 0x0368, + .sram_pdn_bits = GENMASK(8, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + }, +}; + +static const struct scpsys_soc_data mt8192_scpsys_data = { + .domains_data = scpsys_domain_data_mt8192, + .num_domains = ARRAY_SIZE(scpsys_domain_data_mt8192), + .pwr_sta_offs = 0x016c, + .pwr_sta2nd_offs = 0x0170, +}; + +#endif /* __SOC_MEDIATEK_MT8192_PM_DOMAINS_H */ diff --git a/drivers/soc/mediatek/mtk-pm-domains.c b/drivers/soc/mediatek/mtk-pm-domains.c index c3b85b69f2f7..fb70cb3b07b3 100644 --- a/drivers/soc/mediatek/mtk-pm-domains.c +++ b/drivers/soc/mediatek/mtk-pm-domains.c @@ -17,6 +17,7 @@ #include "mt8173-pm-domains.h" #include "mt8183-pm-domains.h" +#include "mt8192-pm-domains.h" #define MTK_POLL_DELAY_US 10 #define MTK_POLL_TIMEOUT USEC_PER_SEC @@ -521,6 +522,10 @@ static const struct of_device_id scpsys_of_match[] = { .compatible = "mediatek,mt8183-power-controller", .data = &mt8183_scpsys_data, }, + { + .compatible = "mediatek,mt8192-power-controller", + .data = &mt8192_scpsys_data, + }, { } }; diff --git a/include/linux/soc/mediatek/infracfg.h b/include/linux/soc/mediatek/infracfg.h index 9d01e32e19bc..e7842debc05d 100644 --- a/include/linux/soc/mediatek/infracfg.h +++ b/include/linux/soc/mediatek/infracfg.h @@ -2,6 +2,62 @@ #ifndef __SOC_MEDIATEK_INFRACFG_H #define __SOC_MEDIATEK_INFRACFG_H +#define MT8192_TOP_AXI_PROT_EN_STA1 0x228 +#define MT8192_TOP_AXI_PROT_EN_1_STA1 0x258 +#define MT8192_TOP_AXI_PROT_EN_SET 0x2a0 +#define MT8192_TOP_AXI_PROT_EN_CLR 0x2a4 +#define MT8192_TOP_AXI_PROT_EN_1_SET 0x2a8 +#define MT8192_TOP_AXI_PROT_EN_1_CLR 0x2ac +#define MT8192_TOP_AXI_PROT_EN_MM_SET 0x2d4 +#define MT8192_TOP_AXI_PROT_EN_MM_CLR 0x2d8 +#define MT8192_TOP_AXI_PROT_EN_MM_STA1 0x2ec +#define MT8192_TOP_AXI_PROT_EN_2_SET 0x714 +#define MT8192_TOP_AXI_PROT_EN_2_CLR 0x718 +#define MT8192_TOP_AXI_PROT_EN_2_STA1 0x724 +#define MT8192_TOP_AXI_PROT_EN_VDNR_SET 0xb84 +#define MT8192_TOP_AXI_PROT_EN_VDNR_CLR 0xb88 +#define MT8192_TOP_AXI_PROT_EN_VDNR_STA1 0xb90 +#define MT8192_TOP_AXI_PROT_EN_MM_2_SET 0xdcc +#define MT8192_TOP_AXI_PROT_EN_MM_2_CLR 0xdd0 +#define MT8192_TOP_AXI_PROT_EN_MM_2_STA1 0xdd8 + +#define MT8192_TOP_AXI_PROT_EN_DISP (BIT(6) | BIT(23)) +#define MT8192_TOP_AXI_PROT_EN_CONN (BIT(13) | BIT(18)) +#define MT8192_TOP_AXI_PROT_EN_CONN_2ND BIT(14) +#define MT8192_TOP_AXI_PROT_EN_MFG1 GENMASK(22, 21) +#define MT8192_TOP_AXI_PROT_EN_1_CONN BIT(10) +#define MT8192_TOP_AXI_PROT_EN_1_MFG1 BIT(21) +#define MT8192_TOP_AXI_PROT_EN_1_CAM BIT(22) +#define MT8192_TOP_AXI_PROT_EN_2_CAM BIT(0) +#define MT8192_TOP_AXI_PROT_EN_2_ADSP BIT(3) +#define MT8192_TOP_AXI_PROT_EN_2_AUDIO BIT(4) +#define MT8192_TOP_AXI_PROT_EN_2_MFG1 GENMASK(6, 5) +#define MT8192_TOP_AXI_PROT_EN_2_MFG1_2ND BIT(7) +#define MT8192_TOP_AXI_PROT_EN_MM_CAM (BIT(0) | BIT(2)) +#define MT8192_TOP_AXI_PROT_EN_MM_DISP (BIT(0) | BIT(2) | \ + BIT(10) | BIT(12) | \ + BIT(14) | BIT(16) | \ + BIT(24) | BIT(26)) +#define MT8192_TOP_AXI_PROT_EN_MM_CAM_2ND (BIT(1) | BIT(3)) +#define MT8192_TOP_AXI_PROT_EN_MM_DISP_2ND (BIT(1) | BIT(3) | \ + BIT(15) | BIT(17) | \ + BIT(25) | BIT(27)) +#define MT8192_TOP_AXI_PROT_EN_MM_ISP2 BIT(14) +#define MT8192_TOP_AXI_PROT_EN_MM_ISP2_2ND BIT(15) +#define MT8192_TOP_AXI_PROT_EN_MM_IPE BIT(16) +#define MT8192_TOP_AXI_PROT_EN_MM_IPE_2ND BIT(17) +#define MT8192_TOP_AXI_PROT_EN_MM_VDEC BIT(24) +#define MT8192_TOP_AXI_PROT_EN_MM_VDEC_2ND BIT(25) +#define MT8192_TOP_AXI_PROT_EN_MM_VENC BIT(26) +#define MT8192_TOP_AXI_PROT_EN_MM_VENC_2ND BIT(27) +#define MT8192_TOP_AXI_PROT_EN_MM_2_ISP BIT(8) +#define MT8192_TOP_AXI_PROT_EN_MM_2_DISP (BIT(8) | BIT(12)) +#define MT8192_TOP_AXI_PROT_EN_MM_2_ISP_2ND BIT(9) +#define MT8192_TOP_AXI_PROT_EN_MM_2_DISP_2ND (BIT(9) | BIT(13)) +#define MT8192_TOP_AXI_PROT_EN_MM_2_MDP BIT(12) +#define MT8192_TOP_AXI_PROT_EN_MM_2_MDP_2ND BIT(13) +#define MT8192_TOP_AXI_PROT_EN_VDNR_CAM BIT(21) + #define MT8183_TOP_AXI_PROT_EN_STA1 0x228 #define MT8183_TOP_AXI_PROT_EN_STA1_1 0x258 #define MT8183_TOP_AXI_PROT_EN_SET 0x2a0 -- cgit From a69dcdfc2dd21f86cb1f79f98fc94c52f96cff64 Mon Sep 17 00:00:00 2001 From: Chun-Kuang Hu Date: Mon, 2 Nov 2020 08:04:38 +0800 Subject: soc / drm: mediatek: cmdq: Remove timeout handler in helper function For each client driver, its timeout handler need to dump hardware register or its state machine information, and their way to detect timeout are also different, so remove timeout handler in helper function and let client driver implement its own timeout handler. Signed-off-by: Chun-Kuang Hu Acked-by: Matthias Brugger Link: https://lore.kernel.org/r/20201102000438.29225-1-chunkuang.hu@kernel.org Signed-off-by: Matthias Brugger --- drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 3 +-- drivers/soc/mediatek/mtk-cmdq-helper.c | 41 +-------------------------------- include/linux/soc/mediatek/mtk-cmdq.h | 10 +------- 3 files changed, 3 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index ac038572164d..4be5d1fccf2e 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -824,8 +824,7 @@ int mtk_drm_crtc_create(struct drm_device *drm_dev, #if IS_REACHABLE(CONFIG_MTK_CMDQ) mtk_crtc->cmdq_client = cmdq_mbox_create(mtk_crtc->mmsys_dev, - drm_crtc_index(&mtk_crtc->base), - 2000); + drm_crtc_index(&mtk_crtc->base)); if (IS_ERR(mtk_crtc->cmdq_client)) { dev_dbg(dev, "mtk_crtc %d failed to create mailbox client, writing register by CPU now\n", drm_crtc_index(&mtk_crtc->base)); diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c index 505651b0d715..280d3bd9f675 100644 --- a/drivers/soc/mediatek/mtk-cmdq-helper.c +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c @@ -70,14 +70,7 @@ int cmdq_dev_get_client_reg(struct device *dev, } EXPORT_SYMBOL(cmdq_dev_get_client_reg); -static void cmdq_client_timeout(struct timer_list *t) -{ - struct cmdq_client *client = from_timer(client, t, timer); - - dev_err(client->client.dev, "cmdq timeout!\n"); -} - -struct cmdq_client *cmdq_mbox_create(struct device *dev, int index, u32 timeout) +struct cmdq_client *cmdq_mbox_create(struct device *dev, int index) { struct cmdq_client *client; @@ -85,12 +78,6 @@ struct cmdq_client *cmdq_mbox_create(struct device *dev, int index, u32 timeout) if (!client) return (struct cmdq_client *)-ENOMEM; - client->timeout_ms = timeout; - if (timeout != CMDQ_NO_TIMEOUT) { - spin_lock_init(&client->lock); - timer_setup(&client->timer, cmdq_client_timeout, 0); - } - client->pkt_cnt = 0; client->client.dev = dev; client->client.tx_block = false; client->client.knows_txdone = true; @@ -112,11 +99,6 @@ EXPORT_SYMBOL(cmdq_mbox_create); void cmdq_mbox_destroy(struct cmdq_client *client) { - if (client->timeout_ms != CMDQ_NO_TIMEOUT) { - spin_lock(&client->lock); - del_timer_sync(&client->timer); - spin_unlock(&client->lock); - } mbox_free_channel(client->chan); kfree(client); } @@ -449,18 +431,6 @@ static void cmdq_pkt_flush_async_cb(struct cmdq_cb_data data) struct cmdq_task_cb *cb = &pkt->cb; struct cmdq_client *client = (struct cmdq_client *)pkt->cl; - if (client->timeout_ms != CMDQ_NO_TIMEOUT) { - unsigned long flags = 0; - - spin_lock_irqsave(&client->lock, flags); - if (--client->pkt_cnt == 0) - del_timer(&client->timer); - else - mod_timer(&client->timer, jiffies + - msecs_to_jiffies(client->timeout_ms)); - spin_unlock_irqrestore(&client->lock, flags); - } - dma_sync_single_for_cpu(client->chan->mbox->dev, pkt->pa_base, pkt->cmd_buf_size, DMA_TO_DEVICE); if (cb->cb) { @@ -473,7 +443,6 @@ int cmdq_pkt_flush_async(struct cmdq_pkt *pkt, cmdq_async_flush_cb cb, void *data) { int err; - unsigned long flags = 0; struct cmdq_client *client = (struct cmdq_client *)pkt->cl; pkt->cb.cb = cb; @@ -484,14 +453,6 @@ int cmdq_pkt_flush_async(struct cmdq_pkt *pkt, cmdq_async_flush_cb cb, dma_sync_single_for_device(client->chan->mbox->dev, pkt->pa_base, pkt->cmd_buf_size, DMA_TO_DEVICE); - if (client->timeout_ms != CMDQ_NO_TIMEOUT) { - spin_lock_irqsave(&client->lock, flags); - if (client->pkt_cnt++ == 0) - mod_timer(&client->timer, jiffies + - msecs_to_jiffies(client->timeout_ms)); - spin_unlock_irqrestore(&client->lock, flags); - } - err = mbox_send_message(client->chan, pkt); if (err < 0) return err; diff --git a/include/linux/soc/mediatek/mtk-cmdq.h b/include/linux/soc/mediatek/mtk-cmdq.h index 960704d75994..8e9996610978 100644 --- a/include/linux/soc/mediatek/mtk-cmdq.h +++ b/include/linux/soc/mediatek/mtk-cmdq.h @@ -11,7 +11,6 @@ #include #include -#define CMDQ_NO_TIMEOUT 0xffffffffu #define CMDQ_ADDR_HIGH(addr) ((u32)(((addr) >> 16) & GENMASK(31, 0))) #define CMDQ_ADDR_LOW(addr) ((u16)(addr) | BIT(1)) @@ -24,12 +23,8 @@ struct cmdq_client_reg { }; struct cmdq_client { - spinlock_t lock; - u32 pkt_cnt; struct mbox_client client; struct mbox_chan *chan; - struct timer_list timer; - u32 timeout_ms; /* in unit of microsecond */ }; /** @@ -51,13 +46,10 @@ int cmdq_dev_get_client_reg(struct device *dev, * cmdq_mbox_create() - create CMDQ mailbox client and channel * @dev: device of CMDQ mailbox client * @index: index of CMDQ mailbox channel - * @timeout: timeout of a pkt execution by GCE, in unit of microsecond, set - * CMDQ_NO_TIMEOUT if a timer is not used. * * Return: CMDQ mailbox client pointer */ -struct cmdq_client *cmdq_mbox_create(struct device *dev, int index, - u32 timeout); +struct cmdq_client *cmdq_mbox_create(struct device *dev, int index); /** * cmdq_mbox_destroy() - destroy CMDQ mailbox client and channel -- cgit From aaf162d4a5dfdf623a48b3bd6af2af4c237c38f3 Mon Sep 17 00:00:00 2001 From: Neal Liu Date: Thu, 15 Oct 2020 11:20:38 +0800 Subject: dt-bindings: devapc: add bindings for mtk-devapc Add bindings for mtk-devapc. Signed-off-by: Neal Liu Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/1602732039-12179-2-git-send-email-neal.liu@mediatek.com Signed-off-by: Matthias Brugger --- .../devicetree/bindings/soc/mediatek/devapc.yaml | 58 ++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/mediatek/devapc.yaml diff --git a/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml new file mode 100644 index 000000000000..6c763f873a63 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# # Copyright 2020 MediaTek Inc. +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/soc/mediatek/devapc.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: MediaTek Device Access Permission Control driver + +description: | + MediaTek bus fabric provides TrustZone security support and data + protection to prevent slaves from being accessed by unexpected masters. + The security violation is logged and sent to the processor for further + analysis and countermeasures. + +maintainers: + - Neal Liu + +properties: + compatible: + enum: + - mediatek,mt6779-devapc + + reg: + description: The base address of devapc register bank + maxItems: 1 + + interrupts: + description: A single interrupt specifier + maxItems: 1 + + clocks: + description: Contains module clock source and clock names + maxItems: 1 + + clock-names: + description: Names of the clocks list in clocks property + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +examples: + - | + #include + #include + + devapc: devapc@10207000 { + compatible = "mediatek,mt6779-devapc"; + reg = <0x10207000 0x1000>; + interrupts = ; + clocks = <&infracfg_ao CLK_INFRA_DEVICE_APC>; + clock-names = "devapc-infra-clock"; + }; -- cgit From 0890beb22618c0359f1e2652fc1e49bb5c5e876d Mon Sep 17 00:00:00 2001 From: Neal Liu Date: Thu, 15 Oct 2020 11:20:39 +0800 Subject: soc: mediatek: add mt6779 devapc driver MediaTek bus fabric provides TrustZone security support and data protection to prevent slaves from being accessed by unexpected masters. The security violation is logged and sent to the processor for further analysis or countermeasures. Any occurrence of security violation would raise an interrupt, and it will be handled by mtk-devapc driver. The violation information is printed in order to find the murderer. Signed-off-by: Neal Liu Link: https://lore.kernel.org/r/1602732039-12179-3-git-send-email-neal.liu@mediatek.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/Kconfig | 9 ++ drivers/soc/mediatek/Makefile | 1 + drivers/soc/mediatek/mtk-devapc.c | 308 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 drivers/soc/mediatek/mtk-devapc.c diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index 67cef12dc585..851121d83f14 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -17,6 +17,15 @@ config MTK_CMDQ time limitation, such as updating display configuration during the vblank. +config MTK_DEVAPC + tristate "Mediatek Device APC Support" + help + Say yes here to enable support for Mediatek Device APC driver. + This driver is mainly used to handle the violation which catches + unexpected transaction. + The violation information is logged for further analysis or + countermeasures. + config MTK_INFRACFG bool "MediaTek INFRACFG Support" select REGMAP diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile index 1e60fb4f89d4..b6908db534c2 100644 --- a/drivers/soc/mediatek/Makefile +++ b/drivers/soc/mediatek/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o +obj-$(CONFIG_MTK_DEVAPC) += mtk-devapc.o obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c new file mode 100644 index 000000000000..f1cea041dc5a --- /dev/null +++ b/drivers/soc/mediatek/mtk-devapc.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define VIO_MOD_TO_REG_IND(m) ((m) / 32) +#define VIO_MOD_TO_REG_OFF(m) ((m) % 32) + +struct mtk_devapc_vio_dbgs { + union { + u32 vio_dbg0; + struct { + u32 mstid:16; + u32 dmnid:6; + u32 vio_w:1; + u32 vio_r:1; + u32 addr_h:4; + u32 resv:4; + } dbg0_bits; + }; + + u32 vio_dbg1; +}; + +struct mtk_devapc_data { + /* numbers of violation index */ + u32 vio_idx_num; + + /* reg offset */ + u32 vio_mask_offset; + u32 vio_sta_offset; + u32 vio_dbg0_offset; + u32 vio_dbg1_offset; + u32 apc_con_offset; + u32 vio_shift_sta_offset; + u32 vio_shift_sel_offset; + u32 vio_shift_con_offset; +}; + +struct mtk_devapc_context { + struct device *dev; + void __iomem *infra_base; + struct clk *infra_clk; + const struct mtk_devapc_data *data; +}; + +static void clear_vio_status(struct mtk_devapc_context *ctx) +{ + void __iomem *reg; + int i; + + reg = ctx->infra_base + ctx->data->vio_sta_offset; + + for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++) + writel(GENMASK(31, 0), reg + 4 * i); + + writel(GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1, 0), + reg + 4 * i); +} + +static void mask_module_irq(struct mtk_devapc_context *ctx, bool mask) +{ + void __iomem *reg; + u32 val; + int i; + + reg = ctx->infra_base + ctx->data->vio_mask_offset; + + if (mask) + val = GENMASK(31, 0); + else + val = 0; + + for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++) + writel(val, reg + 4 * i); + + val = readl(reg + 4 * i); + if (mask) + val |= GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1, + 0); + else + val &= ~GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1, + 0); + + writel(val, reg + 4 * i); +} + +#define PHY_DEVAPC_TIMEOUT 0x10000 + +/* + * devapc_sync_vio_dbg - do "shift" mechansim" to get full violation information. + * shift mechanism is depends on devapc hardware design. + * Mediatek devapc set multiple slaves as a group. + * When violation is triggered, violation info is kept + * inside devapc hardware. + * Driver should do shift mechansim to sync full violation + * info to VIO_DBGs registers. + * + */ +static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx) +{ + void __iomem *pd_vio_shift_sta_reg; + void __iomem *pd_vio_shift_sel_reg; + void __iomem *pd_vio_shift_con_reg; + int min_shift_group; + int ret; + u32 val; + + pd_vio_shift_sta_reg = ctx->infra_base + + ctx->data->vio_shift_sta_offset; + pd_vio_shift_sel_reg = ctx->infra_base + + ctx->data->vio_shift_sel_offset; + pd_vio_shift_con_reg = ctx->infra_base + + ctx->data->vio_shift_con_offset; + + /* Find the minimum shift group which has violation */ + val = readl(pd_vio_shift_sta_reg); + if (!val) + return false; + + min_shift_group = __ffs(val); + + /* Assign the group to sync */ + writel(0x1 << min_shift_group, pd_vio_shift_sel_reg); + + /* Start syncing */ + writel(0x1, pd_vio_shift_con_reg); + + ret = readl_poll_timeout(pd_vio_shift_con_reg, val, val == 0x3, 0, + PHY_DEVAPC_TIMEOUT); + if (ret) { + dev_err(ctx->dev, "%s: Shift violation info failed\n", __func__); + return false; + } + + /* Stop syncing */ + writel(0x0, pd_vio_shift_con_reg); + + /* Write clear */ + writel(0x1 << min_shift_group, pd_vio_shift_sta_reg); + + return true; +} + +/* + * devapc_extract_vio_dbg - extract full violation information after doing + * shift mechanism. + */ +static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx) +{ + struct mtk_devapc_vio_dbgs vio_dbgs; + void __iomem *vio_dbg0_reg; + void __iomem *vio_dbg1_reg; + + vio_dbg0_reg = ctx->infra_base + ctx->data->vio_dbg0_offset; + vio_dbg1_reg = ctx->infra_base + ctx->data->vio_dbg1_offset; + + vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg); + vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg); + + /* Print violation information */ + if (vio_dbgs.dbg0_bits.vio_w) + dev_info(ctx->dev, "Write Violation\n"); + else if (vio_dbgs.dbg0_bits.vio_r) + dev_info(ctx->dev, "Read Violation\n"); + + dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%x\n", + vio_dbgs.dbg0_bits.mstid, vio_dbgs.dbg0_bits.dmnid, + vio_dbgs.vio_dbg1); +} + +/* + * devapc_violation_irq - the devapc Interrupt Service Routine (ISR) will dump + * violation information including which master violates + * access slave. + */ +static irqreturn_t devapc_violation_irq(int irq_number, void *data) +{ + struct mtk_devapc_context *ctx = data; + + while (devapc_sync_vio_dbg(ctx)) + devapc_extract_vio_dbg(ctx); + + clear_vio_status(ctx); + + return IRQ_HANDLED; +} + +/* + * start_devapc - unmask slave's irq to start receiving devapc violation. + */ +static void start_devapc(struct mtk_devapc_context *ctx) +{ + writel(BIT(31), ctx->infra_base + ctx->data->apc_con_offset); + + mask_module_irq(ctx, false); +} + +/* + * stop_devapc - mask slave's irq to stop service. + */ +static void stop_devapc(struct mtk_devapc_context *ctx) +{ + mask_module_irq(ctx, true); + + writel(BIT(2), ctx->infra_base + ctx->data->apc_con_offset); +} + +static const struct mtk_devapc_data devapc_mt6779 = { + .vio_idx_num = 511, + .vio_mask_offset = 0x0, + .vio_sta_offset = 0x400, + .vio_dbg0_offset = 0x900, + .vio_dbg1_offset = 0x904, + .apc_con_offset = 0xF00, + .vio_shift_sta_offset = 0xF10, + .vio_shift_sel_offset = 0xF14, + .vio_shift_con_offset = 0xF20, +}; + +static const struct of_device_id mtk_devapc_dt_match[] = { + { + .compatible = "mediatek,mt6779-devapc", + .data = &devapc_mt6779, + }, { + }, +}; + +static int mtk_devapc_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct mtk_devapc_context *ctx; + u32 devapc_irq; + int ret; + + if (IS_ERR(node)) + return -ENODEV; + + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->data = of_device_get_match_data(&pdev->dev); + ctx->dev = &pdev->dev; + + ctx->infra_base = of_iomap(node, 0); + if (!ctx->infra_base) + return -EINVAL; + + devapc_irq = irq_of_parse_and_map(node, 0); + if (!devapc_irq) + return -EINVAL; + + ctx->infra_clk = devm_clk_get(&pdev->dev, "devapc-infra-clock"); + if (IS_ERR(ctx->infra_clk)) + return -EINVAL; + + if (clk_prepare_enable(ctx->infra_clk)) + return -EINVAL; + + ret = devm_request_irq(&pdev->dev, devapc_irq, devapc_violation_irq, + IRQF_TRIGGER_NONE, "devapc", ctx); + if (ret) { + clk_disable_unprepare(ctx->infra_clk); + return ret; + } + + platform_set_drvdata(pdev, ctx); + + start_devapc(ctx); + + return 0; +} + +static int mtk_devapc_remove(struct platform_device *pdev) +{ + struct mtk_devapc_context *ctx = platform_get_drvdata(pdev); + + stop_devapc(ctx); + + clk_disable_unprepare(ctx->infra_clk); + + return 0; +} + +static struct platform_driver mtk_devapc_driver = { + .probe = mtk_devapc_probe, + .remove = mtk_devapc_remove, + .driver = { + .name = "mtk-devapc", + .of_match_table = mtk_devapc_dt_match, + }, +}; + +module_platform_driver(mtk_devapc_driver); + +MODULE_DESCRIPTION("Mediatek Device APC Driver"); +MODULE_AUTHOR("Neal Liu "); +MODULE_LICENSE("GPL"); -- cgit From 51c0e618b219c025ddaaf14baea8942cb7e2105b Mon Sep 17 00:00:00 2001 From: Yongqiang Niu Date: Tue, 6 Oct 2020 21:33:17 +0200 Subject: soc / drm: mediatek: Move DDP component defines into mtk-mmsys.h MMSYS is the driver which controls the routing of these DDP components, so the definition of the mtk_ddp_comp_id enum should be placed in mtk-mmsys.h Signed-off-by: Yongqiang Niu Signed-off-by: Enric Balletbo i Serra Reviewed-by: Chun-Kuang Hu Link: https://lore.kernel.org/r/20201006193320.405529-2-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 34 +---------------------------- drivers/soc/mediatek/mtk-mmsys.c | 4 +--- include/linux/soc/mediatek/mtk-mmsys.h | 33 ++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h index 1d9e00b69462..5aa52b7afeec 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h @@ -7,6 +7,7 @@ #define MTK_DRM_DDP_COMP_H #include +#include struct device; struct device_node; @@ -35,39 +36,6 @@ enum mtk_ddp_comp_type { MTK_DDP_COMP_TYPE_MAX, }; -enum mtk_ddp_comp_id { - DDP_COMPONENT_AAL0, - DDP_COMPONENT_AAL1, - DDP_COMPONENT_BLS, - DDP_COMPONENT_CCORR, - DDP_COMPONENT_COLOR0, - DDP_COMPONENT_COLOR1, - DDP_COMPONENT_DITHER, - DDP_COMPONENT_DPI0, - DDP_COMPONENT_DPI1, - DDP_COMPONENT_DSI0, - DDP_COMPONENT_DSI1, - DDP_COMPONENT_DSI2, - DDP_COMPONENT_DSI3, - DDP_COMPONENT_GAMMA, - DDP_COMPONENT_OD0, - DDP_COMPONENT_OD1, - DDP_COMPONENT_OVL0, - DDP_COMPONENT_OVL_2L0, - DDP_COMPONENT_OVL_2L1, - DDP_COMPONENT_OVL1, - DDP_COMPONENT_PWM0, - DDP_COMPONENT_PWM1, - DDP_COMPONENT_PWM2, - DDP_COMPONENT_RDMA0, - DDP_COMPONENT_RDMA1, - DDP_COMPONENT_RDMA2, - DDP_COMPONENT_UFOE, - DDP_COMPONENT_WDMA0, - DDP_COMPONENT_WDMA1, - DDP_COMPONENT_ID_MAX, -}; - struct mtk_ddp_comp; struct cmdq_pkt; struct mtk_ddp_comp_funcs { diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index a55f25511173..36ad66bb221b 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -5,13 +5,11 @@ */ #include +#include #include #include #include -#include "../../gpu/drm/mediatek/mtk_drm_ddp.h" -#include "../../gpu/drm/mediatek/mtk_drm_ddp_comp.h" - #define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040 #define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044 #define DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048 diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h index 7bab5d9a3d31..2228bf6133da 100644 --- a/include/linux/soc/mediatek/mtk-mmsys.h +++ b/include/linux/soc/mediatek/mtk-mmsys.h @@ -9,6 +9,39 @@ enum mtk_ddp_comp_id; struct device; +enum mtk_ddp_comp_id { + DDP_COMPONENT_AAL0, + DDP_COMPONENT_AAL1, + DDP_COMPONENT_BLS, + DDP_COMPONENT_CCORR, + DDP_COMPONENT_COLOR0, + DDP_COMPONENT_COLOR1, + DDP_COMPONENT_DITHER, + DDP_COMPONENT_DPI0, + DDP_COMPONENT_DPI1, + DDP_COMPONENT_DSI0, + DDP_COMPONENT_DSI1, + DDP_COMPONENT_DSI2, + DDP_COMPONENT_DSI3, + DDP_COMPONENT_GAMMA, + DDP_COMPONENT_OD0, + DDP_COMPONENT_OD1, + DDP_COMPONENT_OVL0, + DDP_COMPONENT_OVL_2L0, + DDP_COMPONENT_OVL_2L1, + DDP_COMPONENT_OVL1, + DDP_COMPONENT_PWM0, + DDP_COMPONENT_PWM1, + DDP_COMPONENT_PWM2, + DDP_COMPONENT_RDMA0, + DDP_COMPONENT_RDMA1, + DDP_COMPONENT_RDMA2, + DDP_COMPONENT_UFOE, + DDP_COMPONENT_WDMA0, + DDP_COMPONENT_WDMA1, + DDP_COMPONENT_ID_MAX, +}; + void mtk_mmsys_ddp_connect(struct device *dev, enum mtk_ddp_comp_id cur, enum mtk_ddp_comp_id next); -- cgit From cc6576029aedc79ce87b9fcb22cbd396d47f2852 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Tue, 6 Oct 2020 21:33:18 +0200 Subject: soc: mediatek: mmsys: Use devm_platform_ioremap_resource() For the common platform_get_resource()+devm_platform_ioremap() combination, there is a helper, so use it and make the code a bit more compact. Signed-off-by: Enric Balletbo i Serra Reviewed-by: Chun-Kuang Hu Link: https://lore.kernel.org/r/20201006193320.405529-3-enric.balletbo@collabora.com Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-mmsys.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index 36ad66bb221b..18f93979e14a 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -306,15 +306,12 @@ static int mtk_mmsys_probe(struct platform_device *pdev) struct platform_device *clks; struct platform_device *drm; void __iomem *config_regs; - struct resource *mem; int ret; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - config_regs = devm_ioremap_resource(dev, mem); + config_regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(config_regs)) { ret = PTR_ERR(config_regs); - dev_err(dev, "Failed to ioremap mmsys-config resource: %d\n", - ret); + dev_err(dev, "Failed to ioremap mmsys registers: %d\n", ret); return ret; } -- cgit