diff options
| author | Kees Cook <kees+treewide@kernel.org> | 2026-09-02 15:31:14 -0700 |
|---|---|---|
| committer | Kees Cook <kees@kernel.org> | 2026-09-04 21:37:00 -0700 |
| commit | 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d (patch) | |
| tree | c65086f9bdcd48c6360fb7cb4598bca084da1f32 /drivers/pmdomain/renesas | |
| download | linux-stable-3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d.tar.gz linux-stable-3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d.zip | |
treewide: refresh kmalloc_obj() conversionsgrafted
This is another run of the Coccinelle script for converting kmalloc()
family of allocations to kmalloc_obj() via the existing rules in
scripts/coccinelle/api/kmalloc_objs.cocci
This catches both the set of kmalloc() uses added since the first
kmalloc_obj() conversions in v7.0 and adds a large group missed in the
first pass due to Coccinelle not interacting well with the cleanup.h
scoped_...() family of macros[1]. I worked around this with spatch's
"--macro-file" argument to a file with all the scoped_...() macros mapped
to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control
flow indicator I could find.
Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc,
riscv, and s390 with no new warnings.
Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1]
Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2]
Signed-off-by: Kees Cook <kees+treewide@kernel.org>
Diffstat (limited to 'drivers/pmdomain/renesas')
33 files changed, 2870 insertions, 0 deletions
diff --git a/drivers/pmdomain/renesas/Kconfig b/drivers/pmdomain/renesas/Kconfig new file mode 100644 index 000000000..f2f52d3c2 --- /dev/null +++ b/drivers/pmdomain/renesas/Kconfig @@ -0,0 +1,121 @@ +# SPDX-License-Identifier: GPL-2.0 +if SOC_RENESAS +menu "Renesas PM Domains" + +# SoC Family +config SYSC_RCAR + bool "System Controller support for R-Car" if COMPILE_TEST + +config SYSC_RCAR_GEN4 + bool "System Controller support for R-Car Gen4" if COMPILE_TEST + +config SYSC_RMOBILE + bool "System Controller support for R-Mobile" if COMPILE_TEST + +# SoC +config MDLC_R8A78000 + bool "Module Controller support for R8A78000 (R-Car X5H)" if COMPILE_TEST + select RESET_CONTROLLER + +config SYSC_R8A7742 + bool "System Controller support for R8A7742 (RZ/G1H)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A7743 + bool "System Controller support for R8A7743 (RZ/G1M)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A7745 + bool "System Controller support for R8A7745 (RZ/G1E)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A77470 + bool "System Controller support for R8A77470 (RZ/G1C)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A774A1 + bool "System Controller support for R8A774A1 (RZ/G2M)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A774B1 + bool "System Controller support for R8A774B1 (RZ/G2N)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A774C0 + bool "System Controller support for R8A774C0 (RZ/G2E)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A774E1 + bool "System Controller support for R8A774E1 (RZ/G2H)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A7779 + bool "System Controller support for R8A7779 (R-Car H1)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A7790 + bool "System Controller support for R8A7790 (R-Car H2)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A7791 + bool "System Controller support for R8A7791/R8A7793 (R-Car M2-W/N)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A7792 + bool "System Controller support for R8A7792 (R-Car V2H)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A7794 + bool "System Controller support for R8A7794 (R-Car E2)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A7795 + bool "System Controller support for R8A7795 (R-Car H3)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A77960 + bool "System Controller support for R8A77960 (R-Car M3-W)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A77961 + bool "System Controller support for R8A77961 (R-Car M3-W+)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A77965 + bool "System Controller support for R8A77965 (R-Car M3-N)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A77970 + bool "System Controller support for R8A77970 (R-Car V3M)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A77980 + bool "System Controller support for R8A77980 (R-Car V3H)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A77990 + bool "System Controller support for R8A77990 (R-Car E3)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A77995 + bool "System Controller support for R8A77995 (R-Car D3)" if COMPILE_TEST + select SYSC_RCAR + +config SYSC_R8A779A0 + bool "System Controller support for R8A779A0 (R-Car V3U)" if COMPILE_TEST + select SYSC_RCAR_GEN4 + +config SYSC_R8A779F0 + bool "System Controller support for R8A779F0 (R-Car S4-8)" if COMPILE_TEST + select SYSC_RCAR_GEN4 + +config SYSC_R8A779G0 + bool "System Controller support for R8A779G0 (R-Car V4H)" if COMPILE_TEST + select SYSC_RCAR_GEN4 + +config SYSC_R8A779H0 + bool "System Controller support for R8A779H0 (R-Car V4M)" if COMPILE_TEST + select SYSC_RCAR_GEN4 + +endmenu +endif diff --git a/drivers/pmdomain/renesas/Makefile b/drivers/pmdomain/renesas/Makefile new file mode 100644 index 000000000..17849aad3 --- /dev/null +++ b/drivers/pmdomain/renesas/Makefile @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +# SoC +obj-$(CONFIG_MDLC_R8A78000) += r8a78000-mdlc.o +obj-$(CONFIG_SYSC_R8A7742) += r8a7742-sysc.o +obj-$(CONFIG_SYSC_R8A7743) += r8a7743-sysc.o +obj-$(CONFIG_SYSC_R8A7745) += r8a7745-sysc.o +obj-$(CONFIG_SYSC_R8A77470) += r8a77470-sysc.o +obj-$(CONFIG_SYSC_R8A774A1) += r8a774a1-sysc.o +obj-$(CONFIG_SYSC_R8A774B1) += r8a774b1-sysc.o +obj-$(CONFIG_SYSC_R8A774C0) += r8a774c0-sysc.o +obj-$(CONFIG_SYSC_R8A774E1) += r8a774e1-sysc.o +obj-$(CONFIG_SYSC_R8A7779) += r8a7779-sysc.o +obj-$(CONFIG_SYSC_R8A7790) += r8a7790-sysc.o +obj-$(CONFIG_SYSC_R8A7791) += r8a7791-sysc.o +obj-$(CONFIG_SYSC_R8A7792) += r8a7792-sysc.o +obj-$(CONFIG_SYSC_R8A7794) += r8a7794-sysc.o +obj-$(CONFIG_SYSC_R8A7795) += r8a7795-sysc.o +obj-$(CONFIG_SYSC_R8A77960) += r8a77960-sysc.o +obj-$(CONFIG_SYSC_R8A77961) += r8a77961-sysc.o +obj-$(CONFIG_SYSC_R8A77965) += r8a77965-sysc.o +obj-$(CONFIG_SYSC_R8A77970) += r8a77970-sysc.o +obj-$(CONFIG_SYSC_R8A77980) += r8a77980-sysc.o +obj-$(CONFIG_SYSC_R8A77990) += r8a77990-sysc.o +obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o +obj-$(CONFIG_SYSC_R8A779A0) += r8a779a0-sysc.o +obj-$(CONFIG_SYSC_R8A779F0) += r8a779f0-sysc.o +obj-$(CONFIG_SYSC_R8A779G0) += r8a779g0-sysc.o +obj-$(CONFIG_SYSC_R8A779H0) += r8a779h0-sysc.o +# Family +obj-$(CONFIG_SYSC_RCAR) += rcar-sysc.o +obj-$(CONFIG_SYSC_RCAR_GEN4) += rcar-gen4-sysc.o +obj-$(CONFIG_SYSC_RMOBILE) += rmobile-sysc.o diff --git a/drivers/pmdomain/renesas/r8a7742-sysc.c b/drivers/pmdomain/renesas/r8a7742-sysc.c new file mode 100644 index 000000000..219a675f8 --- /dev/null +++ b/drivers/pmdomain/renesas/r8a7742-sysc.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G1H System Controller + * + * Copyright (C) 2020 Renesas Electronics Corp. + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7742-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7742_areas[] __initconst = { + { "always-on", 0, 0, R8A7742_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca15-scu", 0x180, 0, R8A7742_PD_CA15_SCU, R8A7742_PD_ALWAYS_ON, + PD_SCU }, + { "ca15-cpu0", 0x40, 0, R8A7742_PD_CA15_CPU0, R8A7742_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca15-cpu1", 0x40, 1, R8A7742_PD_CA15_CPU1, R8A7742_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca15-cpu2", 0x40, 2, R8A7742_PD_CA15_CPU2, R8A7742_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca15-cpu3", 0x40, 3, R8A7742_PD_CA15_CPU3, R8A7742_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca7-scu", 0x100, 0, R8A7742_PD_CA7_SCU, R8A7742_PD_ALWAYS_ON, + PD_SCU }, + { "ca7-cpu0", 0x1c0, 0, R8A7742_PD_CA7_CPU0, R8A7742_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu1", 0x1c0, 1, R8A7742_PD_CA7_CPU1, R8A7742_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu2", 0x1c0, 2, R8A7742_PD_CA7_CPU2, R8A7742_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu3", 0x1c0, 3, R8A7742_PD_CA7_CPU3, R8A7742_PD_CA7_SCU, + PD_CPU_NOCR }, + { "rgx", 0xc0, 0, R8A7742_PD_RGX, R8A7742_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7742_sysc_info __initconst = { + .areas = r8a7742_areas, + .num_areas = ARRAY_SIZE(r8a7742_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a7743-sysc.c b/drivers/pmdomain/renesas/r8a7743-sysc.c new file mode 100644 index 000000000..4e2c0ab95 --- /dev/null +++ b/drivers/pmdomain/renesas/r8a7743-sysc.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G1M System Controller + * + * Copyright (C) 2016 Cogent Embedded Inc. + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7743-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7743_areas[] __initconst = { + { "always-on", 0, 0, R8A7743_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca15-scu", 0x180, 0, R8A7743_PD_CA15_SCU, R8A7743_PD_ALWAYS_ON, + PD_SCU }, + { "ca15-cpu0", 0x40, 0, R8A7743_PD_CA15_CPU0, R8A7743_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca15-cpu1", 0x40, 1, R8A7743_PD_CA15_CPU1, R8A7743_PD_CA15_SCU, + PD_CPU_NOCR }, + { "sgx", 0xc0, 0, R8A7743_PD_SGX, R8A7743_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7743_sysc_info __initconst = { + .areas = r8a7743_areas, + .num_areas = ARRAY_SIZE(r8a7743_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a7745-sysc.c b/drivers/pmdomain/renesas/r8a7745-sysc.c new file mode 100644 index 000000000..865821a2f --- /dev/null +++ b/drivers/pmdomain/renesas/r8a7745-sysc.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G1E System Controller + * + * Copyright (C) 2016 Cogent Embedded Inc. + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7745-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7745_areas[] __initconst = { + { "always-on", 0, 0, R8A7745_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca7-scu", 0x100, 0, R8A7745_PD_CA7_SCU, R8A7745_PD_ALWAYS_ON, + PD_SCU }, + { "ca7-cpu0", 0x1c0, 0, R8A7745_PD_CA7_CPU0, R8A7745_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu1", 0x1c0, 1, R8A7745_PD_CA7_CPU1, R8A7745_PD_CA7_SCU, + PD_CPU_NOCR }, + { "sgx", 0xc0, 0, R8A7745_PD_SGX, R8A7745_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7745_sysc_info __initconst = { + .areas = r8a7745_areas, + .num_areas = ARRAY_SIZE(r8a7745_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a77470-sysc.c b/drivers/pmdomain/renesas/r8a77470-sysc.c new file mode 100644 index 000000000..1eeb8018d --- /dev/null +++ b/drivers/pmdomain/renesas/r8a77470-sysc.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G1C System Controller + * + * Copyright (C) 2018 Renesas Electronics Corp. + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a77470-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a77470_areas[] __initconst = { + { "always-on", 0, 0, R8A77470_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca7-scu", 0x100, 0, R8A77470_PD_CA7_SCU, R8A77470_PD_ALWAYS_ON, + PD_SCU }, + { "ca7-cpu0", 0x1c0, 0, R8A77470_PD_CA7_CPU0, R8A77470_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu1", 0x1c0, 1, R8A77470_PD_CA7_CPU1, R8A77470_PD_CA7_SCU, + PD_CPU_NOCR }, + { "sgx", 0xc0, 0, R8A77470_PD_SGX, R8A77470_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a77470_sysc_info __initconst = { + .areas = r8a77470_areas, + .num_areas = ARRAY_SIZE(r8a77470_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a774a1-sysc.c b/drivers/pmdomain/renesas/r8a774a1-sysc.c new file mode 100644 index 000000000..38ac2c689 --- /dev/null +++ b/drivers/pmdomain/renesas/r8a774a1-sysc.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G2M System Controller + * Copyright (C) 2018 Renesas Electronics Corp. + * + * Based on Renesas R-Car M3-W System Controller + * Copyright (C) 2016 Glider bvba + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a774a1-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a774a1_areas[] __initconst = { + { "always-on", 0, 0, R8A774A1_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca57-scu", 0x1c0, 0, R8A774A1_PD_CA57_SCU, R8A774A1_PD_ALWAYS_ON, + PD_SCU }, + { "ca57-cpu0", 0x80, 0, R8A774A1_PD_CA57_CPU0, R8A774A1_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca57-cpu1", 0x80, 1, R8A774A1_PD_CA57_CPU1, R8A774A1_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca53-scu", 0x140, 0, R8A774A1_PD_CA53_SCU, R8A774A1_PD_ALWAYS_ON, + PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A774A1_PD_CA53_CPU0, R8A774A1_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A774A1_PD_CA53_CPU1, R8A774A1_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu2", 0x200, 2, R8A774A1_PD_CA53_CPU2, R8A774A1_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu3", 0x200, 3, R8A774A1_PD_CA53_CPU3, R8A774A1_PD_CA53_SCU, + PD_CPU_NOCR }, + { "a3vc", 0x380, 0, R8A774A1_PD_A3VC, R8A774A1_PD_ALWAYS_ON }, + { "a2vc0", 0x3c0, 0, R8A774A1_PD_A2VC0, R8A774A1_PD_A3VC }, + { "a2vc1", 0x3c0, 1, R8A774A1_PD_A2VC1, R8A774A1_PD_A3VC }, + { "3dg-a", 0x100, 0, R8A774A1_PD_3DG_A, R8A774A1_PD_ALWAYS_ON }, + { "3dg-b", 0x100, 1, R8A774A1_PD_3DG_B, R8A774A1_PD_3DG_A }, +}; + +const struct rcar_sysc_info r8a774a1_sysc_info __initconst = { + .areas = r8a774a1_areas, + .num_areas = ARRAY_SIZE(r8a774a1_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a774b1-sysc.c b/drivers/pmdomain/renesas/r8a774b1-sysc.c new file mode 100644 index 000000000..5f97ff26f --- /dev/null +++ b/drivers/pmdomain/renesas/r8a774b1-sysc.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G2N System Controller + * Copyright (C) 2019 Renesas Electronics Corp. + * + * Based on Renesas R-Car M3-W System Controller + * Copyright (C) 2016 Glider bvba + */ + +#include <linux/bits.h> +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a774b1-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a774b1_areas[] __initconst = { + { "always-on", 0, 0, R8A774B1_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca57-scu", 0x1c0, 0, R8A774B1_PD_CA57_SCU, R8A774B1_PD_ALWAYS_ON, + PD_SCU }, + { "ca57-cpu0", 0x80, 0, R8A774B1_PD_CA57_CPU0, R8A774B1_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca57-cpu1", 0x80, 1, R8A774B1_PD_CA57_CPU1, R8A774B1_PD_CA57_SCU, + PD_CPU_NOCR }, + { "a3vc", 0x380, 0, R8A774B1_PD_A3VC, R8A774B1_PD_ALWAYS_ON }, + { "a3vp", 0x340, 0, R8A774B1_PD_A3VP, R8A774B1_PD_ALWAYS_ON }, + { "a2vc1", 0x3c0, 1, R8A774B1_PD_A2VC1, R8A774B1_PD_A3VC }, + { "3dg-a", 0x100, 0, R8A774B1_PD_3DG_A, R8A774B1_PD_ALWAYS_ON }, + { "3dg-b", 0x100, 1, R8A774B1_PD_3DG_B, R8A774B1_PD_3DG_A }, +}; + +const struct rcar_sysc_info r8a774b1_sysc_info __initconst = { + .areas = r8a774b1_areas, + .num_areas = ARRAY_SIZE(r8a774b1_areas), + .extmask_offs = 0x2f8, + .extmask_val = BIT(0), +}; diff --git a/drivers/pmdomain/renesas/r8a774c0-sysc.c b/drivers/pmdomain/renesas/r8a774c0-sysc.c new file mode 100644 index 000000000..c1c216f7d --- /dev/null +++ b/drivers/pmdomain/renesas/r8a774c0-sysc.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G2E System Controller + * Copyright (C) 2018 Renesas Electronics Corp. + * + * Based on Renesas R-Car E3 System Controller + */ + +#include <linux/bits.h> +#include <linux/kernel.h> +#include <linux/sys_soc.h> + +#include <dt-bindings/power/r8a774c0-sysc.h> + +#include "rcar-sysc.h" + +static struct rcar_sysc_area r8a774c0_areas[] __initdata = { + { "always-on", 0, 0, R8A774C0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca53-scu", 0x140, 0, R8A774C0_PD_CA53_SCU, R8A774C0_PD_ALWAYS_ON, + PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A774C0_PD_CA53_CPU0, R8A774C0_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A774C0_PD_CA53_CPU1, R8A774C0_PD_CA53_SCU, + PD_CPU_NOCR }, + { "a3vc", 0x380, 0, R8A774C0_PD_A3VC, R8A774C0_PD_ALWAYS_ON }, + { "a2vc1", 0x3c0, 1, R8A774C0_PD_A2VC1, R8A774C0_PD_A3VC }, + { "3dg-a", 0x100, 0, R8A774C0_PD_3DG_A, R8A774C0_PD_ALWAYS_ON }, + { "3dg-b", 0x100, 1, R8A774C0_PD_3DG_B, R8A774C0_PD_3DG_A }, +}; + +/* Fixups for RZ/G2E ES1.0 revision */ +static const struct soc_device_attribute r8a774c0[] __initconst = { + { .soc_id = "r8a774c0", .revision = "ES1.0" }, + { /* sentinel */ } +}; + +static int __init r8a774c0_sysc_init(void) +{ + if (soc_device_match(r8a774c0)) { + /* Fix incorrect 3DG hierarchy */ + swap(r8a774c0_areas[6], r8a774c0_areas[7]); + r8a774c0_areas[6].parent = R8A774C0_PD_ALWAYS_ON; + r8a774c0_areas[7].parent = R8A774C0_PD_3DG_B; + } + + return 0; +} + +const struct rcar_sysc_info r8a774c0_sysc_info __initconst = { + .init = r8a774c0_sysc_init, + .areas = r8a774c0_areas, + .num_areas = ARRAY_SIZE(r8a774c0_areas), + .extmask_offs = 0x2f8, + .extmask_val = BIT(0), +}; diff --git a/drivers/pmdomain/renesas/r8a774e1-sysc.c b/drivers/pmdomain/renesas/r8a774e1-sysc.c new file mode 100644 index 000000000..18449f746 --- /dev/null +++ b/drivers/pmdomain/renesas/r8a774e1-sysc.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/G2H System Controller + * Copyright (C) 2020 Renesas Electronics Corp. + * + * Based on Renesas R-Car H3 System Controller + * Copyright (C) 2016-2017 Glider bvba + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a774e1-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a774e1_areas[] __initconst = { + { "always-on", 0, 0, R8A774E1_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca57-scu", 0x1c0, 0, R8A774E1_PD_CA57_SCU, R8A774E1_PD_ALWAYS_ON, PD_SCU }, + { "ca57-cpu0", 0x80, 0, R8A774E1_PD_CA57_CPU0, R8A774E1_PD_CA57_SCU, PD_CPU_NOCR }, + { "ca57-cpu1", 0x80, 1, R8A774E1_PD_CA57_CPU1, R8A774E1_PD_CA57_SCU, PD_CPU_NOCR }, + { "ca57-cpu2", 0x80, 2, R8A774E1_PD_CA57_CPU2, R8A774E1_PD_CA57_SCU, PD_CPU_NOCR }, + { "ca57-cpu3", 0x80, 3, R8A774E1_PD_CA57_CPU3, R8A774E1_PD_CA57_SCU, PD_CPU_NOCR }, + { "ca53-scu", 0x140, 0, R8A774E1_PD_CA53_SCU, R8A774E1_PD_ALWAYS_ON, PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A774E1_PD_CA53_CPU0, R8A774E1_PD_CA53_SCU, PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A774E1_PD_CA53_CPU1, R8A774E1_PD_CA53_SCU, PD_CPU_NOCR }, + { "ca53-cpu2", 0x200, 2, R8A774E1_PD_CA53_CPU2, R8A774E1_PD_CA53_SCU, PD_CPU_NOCR }, + { "ca53-cpu3", 0x200, 3, R8A774E1_PD_CA53_CPU3, R8A774E1_PD_CA53_SCU, PD_CPU_NOCR }, + { "a3vp", 0x340, 0, R8A774E1_PD_A3VP, R8A774E1_PD_ALWAYS_ON }, + { "a3vc", 0x380, 0, R8A774E1_PD_A3VC, R8A774E1_PD_ALWAYS_ON }, + { "a2vc1", 0x3c0, 1, R8A774E1_PD_A2VC1, R8A774E1_PD_A3VC }, + { "3dg-a", 0x100, 0, R8A774E1_PD_3DG_A, R8A774E1_PD_ALWAYS_ON }, + { "3dg-b", 0x100, 1, R8A774E1_PD_3DG_B, R8A774E1_PD_3DG_A }, + { "3dg-c", 0x100, 2, R8A774E1_PD_3DG_C, R8A774E1_PD_3DG_B }, + { "3dg-d", 0x100, 3, R8A774E1_PD_3DG_D, R8A774E1_PD_3DG_C }, + { "3dg-e", 0x100, 4, R8A774E1_PD_3DG_E, R8A774E1_PD_3DG_D }, +}; + +const struct rcar_sysc_info r8a774e1_sysc_info __initconst = { + .areas = r8a774e1_areas, + .num_areas = ARRAY_SIZE(r8a774e1_areas), + .extmask_offs = 0x2f8, + .extmask_val = BIT(0), +}; diff --git a/drivers/pmdomain/renesas/r8a7779-sysc.c b/drivers/pmdomain/renesas/r8a7779-sysc.c new file mode 100644 index 000000000..e24a7151d --- /dev/null +++ b/drivers/pmdomain/renesas/r8a7779-sysc.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car H1 System Controller + * + * Copyright (C) 2016 Glider bvba + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7779-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7779_areas[] __initconst = { + { "always-on", 0, 0, R8A7779_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "arm1", 0x40, 1, R8A7779_PD_ARM1, R8A7779_PD_ALWAYS_ON, + PD_CPU_CR }, + { "arm2", 0x40, 2, R8A7779_PD_ARM2, R8A7779_PD_ALWAYS_ON, + PD_CPU_CR }, + { "arm3", 0x40, 3, R8A7779_PD_ARM3, R8A7779_PD_ALWAYS_ON, + PD_CPU_CR }, + { "sgx", 0xc0, 0, R8A7779_PD_SGX, R8A7779_PD_ALWAYS_ON }, + { "vdp", 0x100, 0, R8A7779_PD_VDP, R8A7779_PD_ALWAYS_ON }, + { "imp", 0x140, 0, R8A7779_PD_IMP, R8A7779_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7779_sysc_info __initconst = { + .areas = r8a7779_areas, + .num_areas = ARRAY_SIZE(r8a7779_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a7790-sysc.c b/drivers/pmdomain/renesas/r8a7790-sysc.c new file mode 100644 index 000000000..b9afe7f62 --- /dev/null +++ b/drivers/pmdomain/renesas/r8a7790-sysc.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car H2 System Controller + * + * Copyright (C) 2016 Glider bvba + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7790-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7790_areas[] __initconst = { + { "always-on", 0, 0, R8A7790_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca15-scu", 0x180, 0, R8A7790_PD_CA15_SCU, R8A7790_PD_ALWAYS_ON, + PD_SCU }, + { "ca15-cpu0", 0x40, 0, R8A7790_PD_CA15_CPU0, R8A7790_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca15-cpu1", 0x40, 1, R8A7790_PD_CA15_CPU1, R8A7790_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca15-cpu2", 0x40, 2, R8A7790_PD_CA15_CPU2, R8A7790_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca15-cpu3", 0x40, 3, R8A7790_PD_CA15_CPU3, R8A7790_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca7-scu", 0x100, 0, R8A7790_PD_CA7_SCU, R8A7790_PD_ALWAYS_ON, + PD_SCU }, + { "ca7-cpu0", 0x1c0, 0, R8A7790_PD_CA7_CPU0, R8A7790_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu1", 0x1c0, 1, R8A7790_PD_CA7_CPU1, R8A7790_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu2", 0x1c0, 2, R8A7790_PD_CA7_CPU2, R8A7790_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu3", 0x1c0, 3, R8A7790_PD_CA7_CPU3, R8A7790_PD_CA7_SCU, + PD_CPU_NOCR }, + { "sh-4a", 0x80, 0, R8A7790_PD_SH_4A, R8A7790_PD_ALWAYS_ON }, + { "rgx", 0xc0, 0, R8A7790_PD_RGX, R8A7790_PD_ALWAYS_ON }, + { "imp", 0x140, 0, R8A7790_PD_IMP, R8A7790_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7790_sysc_info __initconst = { + .areas = r8a7790_areas, + .num_areas = ARRAY_SIZE(r8a7790_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a7791-sysc.c b/drivers/pmdomain/renesas/r8a7791-sysc.c new file mode 100644 index 000000000..f00fa2452 --- /dev/null +++ b/drivers/pmdomain/renesas/r8a7791-sysc.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car M2-W/N System Controller + * + * Copyright (C) 2016 Glider bvba + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7791-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7791_areas[] __initconst = { + { "always-on", 0, 0, R8A7791_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca15-scu", 0x180, 0, R8A7791_PD_CA15_SCU, R8A7791_PD_ALWAYS_ON, + PD_SCU }, + { "ca15-cpu0", 0x40, 0, R8A7791_PD_CA15_CPU0, R8A7791_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca15-cpu1", 0x40, 1, R8A7791_PD_CA15_CPU1, R8A7791_PD_CA15_SCU, + PD_CPU_NOCR }, + { "sh-4a", 0x80, 0, R8A7791_PD_SH_4A, R8A7791_PD_ALWAYS_ON }, + { "sgx", 0xc0, 0, R8A7791_PD_SGX, R8A7791_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7791_sysc_info __initconst = { + .areas = r8a7791_areas, + .num_areas = ARRAY_SIZE(r8a7791_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a7792-sysc.c b/drivers/pmdomain/renesas/r8a7792-sysc.c new file mode 100644 index 000000000..60aae242c --- /dev/null +++ b/drivers/pmdomain/renesas/r8a7792-sysc.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car V2H (R8A7792) System Controller + * + * Copyright (C) 2016 Cogent Embedded Inc. + */ + +#include <linux/init.h> +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7792-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7792_areas[] __initconst = { + { "always-on", 0, 0, R8A7792_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca15-scu", 0x180, 0, R8A7792_PD_CA15_SCU, R8A7792_PD_ALWAYS_ON, + PD_SCU }, + { "ca15-cpu0", 0x40, 0, R8A7792_PD_CA15_CPU0, R8A7792_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca15-cpu1", 0x40, 1, R8A7792_PD_CA15_CPU1, R8A7792_PD_CA15_SCU, + PD_CPU_NOCR }, + { "sgx", 0xc0, 0, R8A7792_PD_SGX, R8A7792_PD_ALWAYS_ON }, + { "imp", 0x140, 0, R8A7792_PD_IMP, R8A7792_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7792_sysc_info __initconst = { + .areas = r8a7792_areas, + .num_areas = ARRAY_SIZE(r8a7792_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a7794-sysc.c b/drivers/pmdomain/renesas/r8a7794-sysc.c new file mode 100644 index 000000000..72ef4e854 --- /dev/null +++ b/drivers/pmdomain/renesas/r8a7794-sysc.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car E2 System Controller + * + * Copyright (C) 2016 Glider bvba + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7794-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7794_areas[] __initconst = { + { "always-on", 0, 0, R8A7794_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca7-scu", 0x100, 0, R8A7794_PD_CA7_SCU, R8A7794_PD_ALWAYS_ON, + PD_SCU }, + { "ca7-cpu0", 0x1c0, 0, R8A7794_PD_CA7_CPU0, R8A7794_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu1", 0x1c0, 1, R8A7794_PD_CA7_CPU1, R8A7794_PD_CA7_SCU, + PD_CPU_NOCR }, + { "sh-4a", 0x80, 0, R8A7794_PD_SH_4A, R8A7794_PD_ALWAYS_ON }, + { "sgx", 0xc0, 0, R8A7794_PD_SGX, R8A7794_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7794_sysc_info __initconst = { + .areas = r8a7794_areas, + .num_areas = ARRAY_SIZE(r8a7794_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a7795-sysc.c b/drivers/pmdomain/renesas/r8a7795-sysc.c new file mode 100644 index 000000000..cbe1ff0fc --- /dev/null +++ b/drivers/pmdomain/renesas/r8a7795-sysc.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car H3 System Controller + * + * Copyright (C) 2016-2017 Glider bvba + */ + +#include <linux/bits.h> +#include <linux/kernel.h> +#include <linux/sys_soc.h> + +#include <dt-bindings/power/r8a7795-sysc.h> + +#include "rcar-sysc.h" + +static struct rcar_sysc_area r8a7795_areas[] __initdata = { + { "always-on", 0, 0, R8A7795_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca57-scu", 0x1c0, 0, R8A7795_PD_CA57_SCU, R8A7795_PD_ALWAYS_ON, + PD_SCU }, + { "ca57-cpu0", 0x80, 0, R8A7795_PD_CA57_CPU0, R8A7795_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca57-cpu1", 0x80, 1, R8A7795_PD_CA57_CPU1, R8A7795_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca57-cpu2", 0x80, 2, R8A7795_PD_CA57_CPU2, R8A7795_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca57-cpu3", 0x80, 3, R8A7795_PD_CA57_CPU3, R8A7795_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca53-scu", 0x140, 0, R8A7795_PD_CA53_SCU, R8A7795_PD_ALWAYS_ON, + PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A7795_PD_CA53_CPU0, R8A7795_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A7795_PD_CA53_CPU1, R8A7795_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu2", 0x200, 2, R8A7795_PD_CA53_CPU2, R8A7795_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu3", 0x200, 3, R8A7795_PD_CA53_CPU3, R8A7795_PD_CA53_SCU, + PD_CPU_NOCR }, + { "a3vp", 0x340, 0, R8A7795_PD_A3VP, R8A7795_PD_ALWAYS_ON }, + { "cr7", 0x240, 0, R8A7795_PD_CR7, R8A7795_PD_ALWAYS_ON }, + { "a3vc", 0x380, 0, R8A7795_PD_A3VC, R8A7795_PD_ALWAYS_ON }, + { "a2vc1", 0x3c0, 1, R8A7795_PD_A2VC1, R8A7795_PD_A3VC }, + { "3dg-a", 0x100, 0, R8A7795_PD_3DG_A, R8A7795_PD_ALWAYS_ON }, + { "3dg-b", 0x100, 1, R8A7795_PD_3DG_B, R8A7795_PD_3DG_A }, + { "3dg-c", 0x100, 2, R8A7795_PD_3DG_C, R8A7795_PD_3DG_B }, + { "3dg-d", 0x100, 3, R8A7795_PD_3DG_D, R8A7795_PD_3DG_C }, + { "3dg-e", 0x100, 4, R8A7795_PD_3DG_E, R8A7795_PD_3DG_D }, + { "a3ir", 0x180, 0, R8A7795_PD_A3IR, R8A7795_PD_ALWAYS_ON }, +}; + + + /* + * Fixups for R-Car H3 revisions + */ + +#define NO_EXTMASK BIT(1) /* Missing SYSCEXTMASK register */ + +static const struct soc_device_attribute r8a7795_quirks_match[] __initconst = { + { + .soc_id = "r8a7795", .revision = "ES2.*", + .data = (void *)(NO_EXTMASK), + }, + { /* sentinel */ } +}; + +static int __init r8a7795_sysc_init(void) +{ + const struct soc_device_attribute *attr; + u32 quirks = 0; + + attr = soc_device_match(r8a7795_quirks_match); + if (attr) + quirks = (uintptr_t)attr->data; + + if (quirks & NO_EXTMASK) + r8a7795_sysc_info.extmask_val = 0; + + return 0; +} + +struct rcar_sysc_info r8a7795_sysc_info __initdata = { + .init = r8a7795_sysc_init, + .areas = r8a7795_areas, + .num_areas = ARRAY_SIZE(r8a7795_areas), + .extmask_offs = 0x2f8, + .extmask_val = BIT(0), +}; diff --git a/drivers/pmdomain/renesas/r8a77960-sysc.c b/drivers/pmdomain/renesas/r8a77960-sysc.c new file mode 100644 index 000000000..2ab3f565d --- /dev/null +++ b/drivers/pmdomain/renesas/r8a77960-sysc.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car M3-W System Controller + * + * Copyright (C) 2016 Glider bvba + * Copyright (C) 2018-2019 Renesas Electronics Corporation + */ + +#include <linux/bits.h> +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7796-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a77960_areas[] __initconst = { + { "always-on", 0, 0, R8A7796_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca57-scu", 0x1c0, 0, R8A7796_PD_CA57_SCU, R8A7796_PD_ALWAYS_ON, + PD_SCU }, + { "ca57-cpu0", 0x80, 0, R8A7796_PD_CA57_CPU0, R8A7796_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca57-cpu1", 0x80, 1, R8A7796_PD_CA57_CPU1, R8A7796_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca53-scu", 0x140, 0, R8A7796_PD_CA53_SCU, R8A7796_PD_ALWAYS_ON, + PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A7796_PD_CA53_CPU0, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A7796_PD_CA53_CPU1, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu2", 0x200, 2, R8A7796_PD_CA53_CPU2, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu3", 0x200, 3, R8A7796_PD_CA53_CPU3, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "cr7", 0x240, 0, R8A7796_PD_CR7, R8A7796_PD_ALWAYS_ON }, + { "a3vc", 0x380, 0, R8A7796_PD_A3VC, R8A7796_PD_ALWAYS_ON, + PD_OFF_DELAY }, + { "a2vc0", 0x3c0, 0, R8A7796_PD_A2VC0, R8A7796_PD_A3VC }, + { "a2vc1", 0x3c0, 1, R8A7796_PD_A2VC1, R8A7796_PD_A3VC }, + { "3dg-a", 0x100, 0, R8A7796_PD_3DG_A, R8A7796_PD_ALWAYS_ON }, + { "3dg-b", 0x100, 1, R8A7796_PD_3DG_B, R8A7796_PD_3DG_A }, + { "a3ir", 0x180, 0, R8A7796_PD_A3IR, R8A7796_PD_ALWAYS_ON, + PD_OFF_DELAY }, +}; + + +const struct rcar_sysc_info r8a77960_sysc_info __initconst = { + .areas = r8a77960_areas, + .num_areas = ARRAY_SIZE(r8a77960_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a77961-sysc.c b/drivers/pmdomain/renesas/r8a77961-sysc.c new file mode 100644 index 000000000..a1155068e --- /dev/null +++ b/drivers/pmdomain/renesas/r8a77961-sysc.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car M3-W+ System Controller + * + * Copyright (C) 2016 Glider bvba + * Copyright (C) 2018-2019 Renesas Electronics Corporation + */ + +#include <linux/bits.h> +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a7796-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a77961_areas[] __initconst = { + { "always-on", 0, 0, R8A7796_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca57-scu", 0x1c0, 0, R8A7796_PD_CA57_SCU, R8A7796_PD_ALWAYS_ON, + PD_SCU }, + { "ca57-cpu0", 0x80, 0, R8A7796_PD_CA57_CPU0, R8A7796_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca57-cpu1", 0x80, 1, R8A7796_PD_CA57_CPU1, R8A7796_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca53-scu", 0x140, 0, R8A7796_PD_CA53_SCU, R8A7796_PD_ALWAYS_ON, + PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A7796_PD_CA53_CPU0, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A7796_PD_CA53_CPU1, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu2", 0x200, 2, R8A7796_PD_CA53_CPU2, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu3", 0x200, 3, R8A7796_PD_CA53_CPU3, R8A7796_PD_CA53_SCU, + PD_CPU_NOCR }, + { "cr7", 0x240, 0, R8A7796_PD_CR7, R8A7796_PD_ALWAYS_ON }, + { "a3vc", 0x380, 0, R8A7796_PD_A3VC, R8A7796_PD_ALWAYS_ON }, + { "a2vc1", 0x3c0, 1, R8A7796_PD_A2VC1, R8A7796_PD_A3VC }, + { "3dg-a", 0x100, 0, R8A7796_PD_3DG_A, R8A7796_PD_ALWAYS_ON }, + { "3dg-b", 0x100, 1, R8A7796_PD_3DG_B, R8A7796_PD_3DG_A }, + { "a3ir", 0x180, 0, R8A7796_PD_A3IR, R8A7796_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a77961_sysc_info __initconst = { + .areas = r8a77961_areas, + .num_areas = ARRAY_SIZE(r8a77961_areas), + .extmask_offs = 0x2f8, + .extmask_val = BIT(0), +}; diff --git a/drivers/pmdomain/renesas/r8a77965-sysc.c b/drivers/pmdomain/renesas/r8a77965-sysc.c new file mode 100644 index 000000000..ff0b0d116 --- /dev/null +++ b/drivers/pmdomain/renesas/r8a77965-sysc.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car M3-N System Controller + * Copyright (C) 2018 Jacopo Mondi <jacopo+renesas@jmondi.org> + * + * Based on Renesas R-Car M3-W System Controller + * Copyright (C) 2016 Glider bvba + */ + +#include <linux/bits.h> +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a77965-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a77965_areas[] __initconst = { + { "always-on", 0, 0, R8A77965_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca57-scu", 0x1c0, 0, R8A77965_PD_CA57_SCU, R8A77965_PD_ALWAYS_ON, + PD_SCU }, + { "ca57-cpu0", 0x80, 0, R8A77965_PD_CA57_CPU0, R8A77965_PD_CA57_SCU, + PD_CPU_NOCR }, + { "ca57-cpu1", 0x80, 1, R8A77965_PD_CA57_CPU1, R8A77965_PD_CA57_SCU, + PD_CPU_NOCR }, + { "cr7", 0x240, 0, R8A77965_PD_CR7, R8A77965_PD_ALWAYS_ON }, + { "a3vc", 0x380, 0, R8A77965_PD_A3VC, R8A77965_PD_ALWAYS_ON }, + { "a3vp", 0x340, 0, R8A77965_PD_A3VP, R8A77965_PD_ALWAYS_ON }, + { "a2vc1", 0x3c0, 1, R8A77965_PD_A2VC1, R8A77965_PD_A3VC }, + { "3dg-a", 0x100, 0, R8A77965_PD_3DG_A, R8A77965_PD_ALWAYS_ON }, + { "3dg-b", 0x100, 1, R8A77965_PD_3DG_B, R8A77965_PD_3DG_A }, +}; + +const struct rcar_sysc_info r8a77965_sysc_info __initconst = { + .areas = r8a77965_areas, + .num_areas = ARRAY_SIZE(r8a77965_areas), + .extmask_offs = 0x2f8, + .extmask_val = BIT(0), +}; diff --git a/drivers/pmdomain/renesas/r8a77970-sysc.c b/drivers/pmdomain/renesas/r8a77970-sysc.c new file mode 100644 index 000000000..706258250 --- /dev/null +++ b/drivers/pmdomain/renesas/r8a77970-sysc.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car V3M System Controller + * + * Copyright (C) 2017 Cogent Embedded Inc. + */ + +#include <linux/bits.h> +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a77970-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a77970_areas[] __initconst = { + { "always-on", 0, 0, R8A77970_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca53-scu", 0x140, 0, R8A77970_PD_CA53_SCU, R8A77970_PD_ALWAYS_ON, + PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A77970_PD_CA53_CPU0, R8A77970_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A77970_PD_CA53_CPU1, R8A77970_PD_CA53_SCU, + PD_CPU_NOCR }, + { "a3ir", 0x180, 0, R8A77970_PD_A3IR, R8A77970_PD_ALWAYS_ON }, + { "a2ir0", 0x400, 0, R8A77970_PD_A2IR0, R8A77970_PD_A3IR }, + { "a2ir1", 0x400, 1, R8A77970_PD_A2IR1, R8A77970_PD_A3IR }, + { "a2dp", 0x400, 2, R8A77970_PD_A2DP, R8A77970_PD_A3IR }, + { "a2cn", 0x400, 3, R8A77970_PD_A2CN, R8A77970_PD_A3IR }, + { "a2sc0", 0x400, 4, R8A77970_PD_A2SC0, R8A77970_PD_A3IR }, + { "a2sc1", 0x400, 5, R8A77970_PD_A2SC1, R8A77970_PD_A3IR }, +}; + +const struct rcar_sysc_info r8a77970_sysc_info __initconst = { + .areas = r8a77970_areas, + .num_areas = ARRAY_SIZE(r8a77970_areas), + .extmask_offs = 0x1b0, + .extmask_val = BIT(0), +}; diff --git a/drivers/pmdomain/renesas/r8a77980-sysc.c b/drivers/pmdomain/renesas/r8a77980-sysc.c new file mode 100644 index 000000000..621e411fc --- /dev/null +++ b/drivers/pmdomain/renesas/r8a77980-sysc.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car V3H System Controller + * + * Copyright (C) 2018 Renesas Electronics Corp. + * Copyright (C) 2018 Cogent Embedded, Inc. + */ + +#include <linux/bits.h> +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a77980-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a77980_areas[] __initconst = { + { "always-on", 0, 0, R8A77980_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca53-scu", 0x140, 0, R8A77980_PD_CA53_SCU, R8A77980_PD_ALWAYS_ON, + PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A77980_PD_CA53_CPU0, R8A77980_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A77980_PD_CA53_CPU1, R8A77980_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu2", 0x200, 2, R8A77980_PD_CA53_CPU2, R8A77980_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu3", 0x200, 3, R8A77980_PD_CA53_CPU3, R8A77980_PD_CA53_SCU, + PD_CPU_NOCR }, + { "cr7", 0x240, 0, R8A77980_PD_CR7, R8A77980_PD_ALWAYS_ON, + PD_CPU_NOCR }, + { "a3ir", 0x180, 0, R8A77980_PD_A3IR, R8A77980_PD_ALWAYS_ON }, + { "a2ir0", 0x400, 0, R8A77980_PD_A2IR0, R8A77980_PD_A3IR }, + { "a2ir1", 0x400, 1, R8A77980_PD_A2IR1, R8A77980_PD_A3IR }, + { "a2ir2", 0x400, 2, R8A77980_PD_A2IR2, R8A77980_PD_A3IR }, + { "a2ir3", 0x400, 3, R8A77980_PD_A2IR3, R8A77980_PD_A3IR }, + { "a2ir4", 0x400, 4, R8A77980_PD_A2IR4, R8A77980_PD_A3IR }, + { "a2ir5", 0x400, 5, R8A77980_PD_A2IR5, R8A77980_PD_A3IR }, + { "a2sc0", 0x400, 6, R8A77980_PD_A2SC0, R8A77980_PD_A3IR }, + { "a2sc1", 0x400, 7, R8A77980_PD_A2SC1, R8A77980_PD_A3IR }, + { "a2sc2", 0x400, 8, R8A77980_PD_A2SC2, R8A77980_PD_A3IR }, + { "a2sc3", 0x400, 9, R8A77980_PD_A2SC3, R8A77980_PD_A3IR }, + { "a2sc4", 0x400, 10, R8A77980_PD_A2SC4, R8A77980_PD_A3IR }, + { "a2dp0", 0x400, 11, R8A77980_PD_A2DP0, R8A77980_PD_A3IR }, + { "a2dp1", 0x400, 12, R8A77980_PD_A2DP1, R8A77980_PD_A3IR }, + { "a2cn", 0x400, 13, R8A77980_PD_A2CN, R8A77980_PD_A3IR }, + { "a3vip0", 0x2c0, 0, R8A77980_PD_A3VIP0, R8A77980_PD_ALWAYS_ON }, + { "a3vip1", 0x300, 0, R8A77980_PD_A3VIP1, R8A77980_PD_ALWAYS_ON }, + { "a3vip2", 0x280, 0, R8A77980_PD_A3VIP2, R8A77980_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a77980_sysc_info __initconst = { + .areas = r8a77980_areas, + .num_areas = ARRAY_SIZE(r8a77980_areas), + .extmask_offs = 0x138, + .extmask_val = BIT(0), +}; diff --git a/drivers/pmdomain/renesas/r8a77990-sysc.c b/drivers/pmdomain/renesas/r8a77990-sysc.c new file mode 100644 index 000000000..9f92737dc --- /dev/null +++ b/drivers/pmdomain/renesas/r8a77990-sysc.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car E3 System Controller + * + * Copyright (C) 2018 Renesas Electronics Corp. + */ + +#include <linux/bits.h> +#include <linux/kernel.h> +#include <linux/sys_soc.h> + +#include <dt-bindings/power/r8a77990-sysc.h> + +#include "rcar-sysc.h" + +static struct rcar_sysc_area r8a77990_areas[] __initdata = { + { "always-on", 0, 0, R8A77990_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca53-scu", 0x140, 0, R8A77990_PD_CA53_SCU, R8A77990_PD_ALWAYS_ON, + PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A77990_PD_CA53_CPU0, R8A77990_PD_CA53_SCU, + PD_CPU_NOCR }, + { "ca53-cpu1", 0x200, 1, R8A77990_PD_CA53_CPU1, R8A77990_PD_CA53_SCU, + PD_CPU_NOCR }, + { "cr7", 0x240, 0, R8A77990_PD_CR7, R8A77990_PD_ALWAYS_ON }, + { "a3vc", 0x380, 0, R8A77990_PD_A3VC, R8A77990_PD_ALWAYS_ON }, + { "a2vc1", 0x3c0, 1, R8A77990_PD_A2VC1, R8A77990_PD_A3VC }, + { "3dg-a", 0x100, 0, R8A77990_PD_3DG_A, R8A77990_PD_ALWAYS_ON }, + { "3dg-b", 0x100, 1, R8A77990_PD_3DG_B, R8A77990_PD_3DG_A }, +}; + +/* Fixups for R-Car E3 ES1.0 revision */ +static const struct soc_device_attribute r8a77990[] __initconst = { + { .soc_id = "r8a77990", .revision = "ES1.0" }, + { /* sentinel */ } +}; + +static int __init r8a77990_sysc_init(void) +{ + if (soc_device_match(r8a77990)) { + /* Fix incorrect 3DG hierarchy */ + swap(r8a77990_areas[7], r8a77990_areas[8]); + r8a77990_areas[7].parent = R8A77990_PD_ALWAYS_ON; + r8a77990_areas[8].parent = R8A77990_PD_3DG_B; + } + + return 0; +} + +const struct rcar_sysc_info r8a77990_sysc_info __initconst = { + .init = r8a77990_sysc_init, + .areas = r8a77990_areas, + .num_areas = ARRAY_SIZE(r8a77990_areas), + .extmask_offs = 0x2f8, + .extmask_val = BIT(0), +}; diff --git a/drivers/pmdomain/renesas/r8a77995-sysc.c b/drivers/pmdomain/renesas/r8a77995-sysc.c new file mode 100644 index 000000000..efcc67e3d --- /dev/null +++ b/drivers/pmdomain/renesas/r8a77995-sysc.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car D3 System Controller + * + * Copyright (C) 2017 Glider bvba + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a77995-sysc.h> + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a77995_areas[] __initconst = { + { "always-on", 0, 0, R8A77995_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca53-scu", 0x140, 0, R8A77995_PD_CA53_SCU, R8A77995_PD_ALWAYS_ON, + PD_SCU }, + { "ca53-cpu0", 0x200, 0, R8A77995_PD_CA53_CPU0, R8A77995_PD_CA53_SCU, + PD_CPU_NOCR }, +}; + + +const struct rcar_sysc_info r8a77995_sysc_info __initconst = { + .areas = r8a77995_areas, + .num_areas = ARRAY_SIZE(r8a77995_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a779a0-sysc.c b/drivers/pmdomain/renesas/r8a779a0-sysc.c new file mode 100644 index 000000000..54cdf250f --- /dev/null +++ b/drivers/pmdomain/renesas/r8a779a0-sysc.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car V3U System Controller + * + * Copyright (C) 2020 Renesas Electronics Corp. + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a779a0-sysc.h> + +#include "rcar-gen4-sysc.h" + +static struct rcar_gen4_sysc_area r8a779a0_areas[] __initdata = { + { "always-on", R8A779A0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "a3e0", R8A779A0_PD_A3E0, R8A779A0_PD_ALWAYS_ON, PD_SCU }, + { "a3e1", R8A779A0_PD_A3E1, R8A779A0_PD_ALWAYS_ON, PD_SCU }, + { "a2e0d0", R8A779A0_PD_A2E0D0, R8A779A0_PD_A3E0, PD_SCU }, + { "a2e0d1", R8A779A0_PD_A2E0D1, R8A779A0_PD_A3E0, PD_SCU }, + { "a2e1d0", R8A779A0_PD_A2E1D0, R8A779A0_PD_A3E1, PD_SCU }, + { "a2e1d1", R8A779A0_PD_A2E1D1, R8A779A0_PD_A3E1, PD_SCU }, + { "a1e0d0c0", R8A779A0_PD_A1E0D0C0, R8A779A0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d0c1", R8A779A0_PD_A1E0D0C1, R8A779A0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d1c0", R8A779A0_PD_A1E0D1C0, R8A779A0_PD_A2E0D1, PD_CPU_NOCR }, + { "a1e0d1c1", R8A779A0_PD_A1E0D1C1, R8A779A0_PD_A2E0D1, PD_CPU_NOCR }, + { "a1e1d0c0", R8A779A0_PD_A1E1D0C0, R8A779A0_PD_A2E1D0, PD_CPU_NOCR }, + { "a1e1d0c1", R8A779A0_PD_A1E1D0C1, R8A779A0_PD_A2E1D0, PD_CPU_NOCR }, + { "a1e1d1c0", R8A779A0_PD_A1E1D1C0, R8A779A0_PD_A2E1D1, PD_CPU_NOCR }, + { "a1e1d1c1", R8A779A0_PD_A1E1D1C1, R8A779A0_PD_A2E1D1, PD_CPU_NOCR }, + { "3dg-a", R8A779A0_PD_3DG_A, R8A779A0_PD_ALWAYS_ON }, + { "3dg-b", R8A779A0_PD_3DG_B, R8A779A0_PD_3DG_A }, + { "a3vip0", R8A779A0_PD_A3VIP0, R8A779A0_PD_ALWAYS_ON }, + { "a3vip1", R8A779A0_PD_A3VIP1, R8A779A0_PD_ALWAYS_ON }, + { "a3vip3", R8A779A0_PD_A3VIP3, R8A779A0_PD_ALWAYS_ON }, + { "a3vip2", R8A779A0_PD_A3VIP2, R8A779A0_PD_ALWAYS_ON }, + { "a3isp01", R8A779A0_PD_A3ISP01, R8A779A0_PD_ALWAYS_ON }, + { "a3isp23", R8A779A0_PD_A3ISP23, R8A779A0_PD_ALWAYS_ON }, + { "a3ir", R8A779A0_PD_A3IR, R8A779A0_PD_ALWAYS_ON }, + { "a2cn0", R8A779A0_PD_A2CN0, R8A779A0_PD_A3IR }, + { "a2imp01", R8A779A0_PD_A2IMP01, R8A779A0_PD_A3IR }, + { "a2dp0", R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR }, + { "a2cv0", R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR }, + { "a2cv1", R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR }, + { "a2cv4", R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR }, + { "a2cv6", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR }, + { "a2cn2", R8A779A0_PD_A2CN2, R8A779A0_PD_A3IR }, + { "a2imp23", R8A779A0_PD_A2IMP23, R8A779A0_PD_A3IR }, + { "a2dp1", R8A779A0_PD_A2DP1, R8A779A0_PD_A3IR }, + { "a2cv2", R8A779A0_PD_A2CV2, R8A779A0_PD_A3IR }, + { "a2cv3", R8A779A0_PD_A2CV3, R8A779A0_PD_A3IR }, + { "a2cv5", R8A779A0_PD_A2CV5, R8A779A0_PD_A3IR }, + { "a2cv7", R8A779A0_PD_A2CV7, R8A779A0_PD_A3IR }, + { "a2cn1", R8A779A0_PD_A2CN1, R8A779A0_PD_A3IR }, + { "a1cnn0", R8A779A0_PD_A1CNN0, R8A779A0_PD_A2CN0 }, + { "a1cnn2", R8A779A0_PD_A1CNN2, R8A779A0_PD_A2CN2 }, + { "a1dsp0", R8A779A0_PD_A1DSP0, R8A779A0_PD_A2CN2 }, + { "a1cnn1", R8A779A0_PD_A1CNN1, R8A779A0_PD_A2CN1 }, + { "a1dsp1", R8A779A0_PD_A1DSP1, R8A779A0_PD_A2CN1 }, +}; + +const struct rcar_gen4_sysc_info r8a779a0_sysc_info __initconst = { + .areas = r8a779a0_areas, + .num_areas = ARRAY_SIZE(r8a779a0_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a779f0-sysc.c b/drivers/pmdomain/renesas/r8a779f0-sysc.c new file mode 100644 index 000000000..6ed13cd1c --- /dev/null +++ b/drivers/pmdomain/renesas/r8a779f0-sysc.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car S4-8 System Controller + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a779f0-sysc.h> + +#include "rcar-gen4-sysc.h" + +static struct rcar_gen4_sysc_area r8a779f0_areas[] __initdata = { + { "always-on", R8A779F0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "a3e0", R8A779F0_PD_A3E0, R8A779F0_PD_ALWAYS_ON, PD_SCU }, + { "a3e1", R8A779F0_PD_A3E1, R8A779F0_PD_ALWAYS_ON, PD_SCU }, + { "a2e0d0", R8A779F0_PD_A2E0D0, R8A779F0_PD_A3E0, PD_SCU }, + { "a2e0d1", R8A779F0_PD_A2E0D1, R8A779F0_PD_A3E0, PD_SCU }, + { "a2e1d0", R8A779F0_PD_A2E1D0, R8A779F0_PD_A3E1, PD_SCU }, + { "a2e1d1", R8A779F0_PD_A2E1D1, R8A779F0_PD_A3E1, PD_SCU }, + { "a1e0d0c0", R8A779F0_PD_A1E0D0C0, R8A779F0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d0c1", R8A779F0_PD_A1E0D0C1, R8A779F0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d1c0", R8A779F0_PD_A1E0D1C0, R8A779F0_PD_A2E0D1, PD_CPU_NOCR }, + { "a1e0d1c1", R8A779F0_PD_A1E0D1C1, R8A779F0_PD_A2E0D1, PD_CPU_NOCR }, + { "a1e1d0c0", R8A779F0_PD_A1E1D0C0, R8A779F0_PD_A2E1D0, PD_CPU_NOCR }, + { "a1e1d0c1", R8A779F0_PD_A1E1D0C1, R8A779F0_PD_A2E1D0, PD_CPU_NOCR }, + { "a1e1d1c0", R8A779F0_PD_A1E1D1C0, R8A779F0_PD_A2E1D1, PD_CPU_NOCR }, + { "a1e1d1c1", R8A779F0_PD_A1E1D1C1, R8A779F0_PD_A2E1D1, PD_CPU_NOCR }, +}; + +const struct rcar_gen4_sysc_info r8a779f0_sysc_info __initconst = { + .areas = r8a779f0_areas, + .num_areas = ARRAY_SIZE(r8a779f0_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a779g0-sysc.c b/drivers/pmdomain/renesas/r8a779g0-sysc.c new file mode 100644 index 000000000..249cf43af --- /dev/null +++ b/drivers/pmdomain/renesas/r8a779g0-sysc.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car V4H System Controller + * + * Copyright (C) 2022 Renesas Electronics Corp. + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/r8a779g0-sysc.h> + +#include "rcar-gen4-sysc.h" + +static struct rcar_gen4_sysc_area r8a779g0_areas[] __initdata = { + { "always-on", R8A779G0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "a3e0", R8A779G0_PD_A3E0, R8A779G0_PD_ALWAYS_ON, PD_SCU }, + { "a2e0d0", R8A779G0_PD_A2E0D0, R8A779G0_PD_A3E0, PD_SCU }, + { "a2e0d1", R8A779G0_PD_A2E0D1, R8A779G0_PD_A3E0, PD_SCU }, + { "a1e0d0c0", R8A779G0_PD_A1E0D0C0, R8A779G0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d0c1", R8A779G0_PD_A1E0D0C1, R8A779G0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d1c0", R8A779G0_PD_A1E0D1C0, R8A779G0_PD_A2E0D1, PD_CPU_NOCR }, + { "a1e0d1c1", R8A779G0_PD_A1E0D1C1, R8A779G0_PD_A2E0D1, PD_CPU_NOCR }, + { "a33dga", R8A779G0_PD_A33DGA, R8A779G0_PD_ALWAYS_ON }, + { "a23dgb", R8A779G0_PD_A23DGB, R8A779G0_PD_A33DGA }, + { "a3vip0", R8A779G0_PD_A3VIP0, R8A779G0_PD_ALWAYS_ON }, + { "a3vip1", R8A779G0_PD_A3VIP1, R8A779G0_PD_ALWAYS_ON }, + { "a3vip2", R8A779G0_PD_A3VIP2, R8A779G0_PD_ALWAYS_ON }, + { "a3dul", R8A779G0_PD_A3DUL, R8A779G0_PD_ALWAYS_ON }, + { "a3isp0", R8A779G0_PD_A3ISP0, R8A779G0_PD_ALWAYS_ON }, + { "a3isp1", R8A779G0_PD_A3ISP1, R8A779G0_PD_ALWAYS_ON }, + { "a3ir", R8A779G0_PD_A3IR, R8A779G0_PD_ALWAYS_ON }, + { "a2cn0", R8A779G0_PD_A2CN0, R8A779G0_PD_A3IR }, + { "a1cnn0", R8A779G0_PD_A1CNN0, R8A779G0_PD_A2CN0 }, + { "a1dsp0", R8A779G0_PD_A1DSP0, R8A779G0_PD_A2CN0 }, + { "a1dsp1", R8A779G0_PD_A1DSP1, R8A779G0_PD_A2CN0 }, + { "a1dsp2", R8A779G0_PD_A1DSP2, R8A779G0_PD_A2CN0 }, + { "a1dsp3", R8A779G0_PD_A1DSP3, R8A779G0_PD_A2CN0 }, + { "a2imp01", R8A779G0_PD_A2IMP01, R8A779G0_PD_A3IR }, + { "a2imp23", R8A779G0_PD_A2IMP23, R8A779G0_PD_A3IR }, + { "a2psc", R8A779G0_PD_A2PSC, R8A779G0_PD_A3IR }, + { "a2dma", R8A779G0_PD_A2DMA, R8A779G0_PD_A3IR }, + { "a2cv0", R8A779G0_PD_A2CV0, R8A779G0_PD_A3IR }, + { "a2cv1", R8A779G0_PD_A2CV1, R8A779G0_PD_A3IR }, + { "a2cv2", R8A779G0_PD_A2CV2, R8A779G0_PD_A3IR }, + { "a2cv3", R8A779G0_PD_A2CV3, R8A779G0_PD_A3IR }, +}; + +const struct rcar_gen4_sysc_info r8a779g0_sysc_info __initconst = { + .areas = r8a779g0_areas, + .num_areas = ARRAY_SIZE(r8a779g0_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a779h0-sysc.c b/drivers/pmdomain/renesas/r8a779h0-sysc.c new file mode 100644 index 000000000..e13372cb8 --- /dev/null +++ b/drivers/pmdomain/renesas/r8a779h0-sysc.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car V4M System Controller + * + * Copyright (C) 2023 Renesas Electronics Corp + */ + +#include <linux/kernel.h> + +#include <dt-bindings/power/renesas,r8a779h0-sysc.h> + +#include "rcar-gen4-sysc.h" + +static struct rcar_gen4_sysc_area r8a779h0_areas[] __initdata = { + { "always-on", R8A779H0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "c4", R8A779H0_PD_C4, R8A779H0_PD_ALWAYS_ON }, + { "a2e0d0", R8A779H0_PD_A2E0D0, R8A779H0_PD_C4, PD_SCU }, + { "a1e0d0c0", R8A779H0_PD_A1E0D0C0, R8A779H0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d0c1", R8A779H0_PD_A1E0D0C1, R8A779H0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d0c2", R8A779H0_PD_A1E0D0C2, R8A779H0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d0c3", R8A779H0_PD_A1E0D0C3, R8A779H0_PD_A2E0D0, PD_CPU_NOCR }, + { "a3cr0", R8A779H0_PD_A3CR0, R8A779H0_PD_ALWAYS_ON, PD_CPU_NOCR }, + { "a3cr1", R8A779H0_PD_A3CR1, R8A779H0_PD_ALWAYS_ON, PD_CPU_NOCR }, + { "a3cr2", R8A779H0_PD_A3CR2, R8A779H0_PD_ALWAYS_ON, PD_CPU_NOCR }, + { "a33dga", R8A779H0_PD_A33DGA, R8A779H0_PD_C4 }, + { "a23dgb", R8A779H0_PD_A23DGB, R8A779H0_PD_A33DGA }, + { "a3vip0", R8A779H0_PD_A3VIP0, R8A779H0_PD_C4 }, + { "a3vip2", R8A779H0_PD_A3VIP2, R8A779H0_PD_C4 }, + { "a3dul", R8A779H0_PD_A3DUL, R8A779H0_PD_C4 }, + { "a3isp0", R8A779H0_PD_A3ISP0, R8A779H0_PD_C4 }, + { "a2cn0", R8A779H0_PD_A2CN0, R8A779H0_PD_C4 }, + { "a1cn0", R8A779H0_PD_A1CN0, R8A779H0_PD_A2CN0 }, + { "a1dsp0", R8A779H0_PD_A1DSP0, R8A779H0_PD_A2CN0 }, + { "a1dsp1", R8A779H0_PD_A1DSP1, R8A779H0_PD_A2CN0 }, + { "a2imp01", R8A779H0_PD_A2IMP01, R8A779H0_PD_C4 }, + { "a2psc", R8A779H0_PD_A2PSC, R8A779H0_PD_C4 }, + { "a2dma", R8A779H0_PD_A2DMA, R8A779H0_PD_C4 }, + { "a2cv0", R8A779H0_PD_A2CV0, R8A779H0_PD_C4 }, + { "a2cv1", R8A779H0_PD_A2CV1, R8A779H0_PD_C4 }, + { "a2cv2", R8A779H0_PD_A2CV2, R8A779H0_PD_C4 }, + { "a2cv3", R8A779H0_PD_A2CV3, R8A779H0_PD_C4 }, + { "a3imr0", R8A779H0_PD_A3IMR0, R8A779H0_PD_C4 }, + { "a3imr1", R8A779H0_PD_A3IMR1, R8A779H0_PD_C4 }, + { "a3imr2", R8A779H0_PD_A3IMR2, R8A779H0_PD_C4 }, + { "a3imr3", R8A779H0_PD_A3IMR3, R8A779H0_PD_C4 }, + { "a3vc", R8A779H0_PD_A3VC, R8A779H0_PD_C4 }, + { "a3pci", R8A779H0_PD_A3PCI, R8A779H0_PD_C4 }, + { "a2pciphy", R8A779H0_PD_A2PCIPHY, R8A779H0_PD_A3PCI }, +}; + +const struct rcar_gen4_sysc_info r8a779h0_sysc_info __initconst = { + .areas = r8a779h0_areas, + .num_areas = ARRAY_SIZE(r8a779h0_areas), +}; diff --git a/drivers/pmdomain/renesas/r8a78000-mdlc.c b/drivers/pmdomain/renesas/r8a78000-mdlc.c new file mode 100644 index 000000000..2668fc2ac --- /dev/null +++ b/drivers/pmdomain/renesas/r8a78000-mdlc.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * R-Car X5H Module Controller + * + * Copyright (C) 2026 Glider bv + */ + +#include <linux/dev_printk.h> +#include <linux/device-id/of.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/reset-controller.h> +#include <linux/slab.h> + +#include <dt-bindings/power/renesas,r8a78000-mdlc.h> + +struct mod_map { + int hw_id; /* Hardware module ID or -1 sentinel */ +}; + +struct mdlc_info { + u32 base; + const struct mod_map *mod_map; +}; + +/** + * struct r8a78000_mdlc_priv - Module Controller Private Data + * + * @link: Link into list of MDLC instances + * @genpd_data: PM domain provider data + * @rcdev: Reset controller entity + * @dev: MDLC device + * @np: Device node in DT representing the MDLC + * @mod_map: Mapping from hardware module IDs + */ +struct r8a78000_mdlc_priv { + struct hlist_node link; + struct genpd_onecell_data genpd_data; + struct reset_controller_dev rcdev; + struct device *dev; + struct device_node *np; + const struct mod_map *mod_map; +}; + +static struct generic_pm_domain *r8a78000_genpd_always_on; +static HLIST_HEAD(r8a78000_mdlc_list); +static DEFINE_MUTEX(r8a78000_mdlc_lock); /* protects the two above */ + +static struct generic_pm_domain *r8a78000_genpd_xlate( + const struct of_phandle_args *spec, void *data) +{ + struct r8a78000_mdlc_priv *priv = container_of(data, + struct r8a78000_mdlc_priv, genpd_data); + struct device *dev = priv->dev; + u32 id; + + if (spec->args_count != 2) + return ERR_PTR(-EINVAL); + + id = spec->args[0]; + + if (id >= R8A78000_MDLC_PD_AON) { + dev_dbg(dev, + "Mapping HW power domain 0x%x to always-on domain\n", + id); + return r8a78000_genpd_always_on; + } + + /* For now only always-on domains are supported */ + dev_err(dev, "Unknown power domain 0x%x\n", id); + return ERR_PTR(-ENOENT); +} + +#define rcdev_to_priv(_rcdev) \ + container_of(_rcdev, struct r8a78000_mdlc_priv, rcdev) + +static const struct mod_map *mod_map_find(const struct mod_map *map, u32 id) +{ + if (!map) + return NULL; + + for (; map->hw_id >= 0; map++) { + if (map->hw_id == id) + return map; + } + + return NULL; +} + +static int r8a78000_mdlc_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *spec) +{ + struct r8a78000_mdlc_priv *priv = rcdev_to_priv(rcdev); + struct device *dev = priv->dev; + const struct mod_map *map; + u32 id; + + if (spec->args_count != 1) + return -EINVAL; + + id = spec->args[0]; + + map = mod_map_find(priv->mod_map, id); + if (!map) { + dev_err(dev, "Unknown reset 0x%x\n", id); + return -ENOENT; + } + + dev_dbg(dev, "Ignoring HW reset 0x%x\n", id); + return id; +} + +#define DEFINE_MDLC_RESET_WRAPPER(op) \ + static int r8a78000_mdlc_ ## op(struct reset_controller_dev *rcdev, \ + unsigned long id) \ + { \ + struct r8a78000_mdlc_priv *priv = rcdev_to_priv(rcdev); \ + \ + dev_dbg(priv->dev, "%s: Ignoring\n", __func__); \ + return 0; \ + } + +DEFINE_MDLC_RESET_WRAPPER(reset) +DEFINE_MDLC_RESET_WRAPPER(assert) +DEFINE_MDLC_RESET_WRAPPER(deassert) +DEFINE_MDLC_RESET_WRAPPER(status) + +static const struct reset_control_ops r8a78000_mdlc_reset_ops = { + .reset = r8a78000_mdlc_reset, + .assert = r8a78000_mdlc_assert, + .deassert = r8a78000_mdlc_deassert, + .status = r8a78000_mdlc_status, +}; + +static int r8a78000_mdlc_attach_dev(struct generic_pm_domain *domain, + struct device *dev) +{ + struct device_node *np = dev->of_node; + struct r8a78000_mdlc_priv *priv; + struct of_phandle_args pd_spec; + const struct mod_map *map; + unsigned int id; + int ret; + + ret = of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", 0, &pd_spec); + if (ret < 0) + return ret; + + scoped_guard(mutex, &r8a78000_mdlc_lock) { + hlist_for_each_entry(priv, &r8a78000_mdlc_list, link) { + if (priv->np == pd_spec.np) + break; + } + } + + if (!priv) { + dev_err(dev, "%s: MDLC %pOF not found\n", __func__, pd_spec.np); + of_node_put(pd_spec.np); + return -ENODEV; + } + + id = pd_spec.args[1]; + of_node_put(pd_spec.np); + + map = mod_map_find(priv->mod_map, id); + if (!map) { + dev_err(dev, "Unknown module 0x%x\n", id); + return -ENOENT; + } + + dev_dbg(dev, "Ignoring HW module 0x%x\n", id); + return 0; +} + +static void r8a78000_mdlc_unlink(void *data) +{ + struct r8a78000_mdlc_priv *priv = data; + + scoped_guard(mutex, &r8a78000_mdlc_lock) { + hlist_del(&priv->link); + } +} + +static void r8a78000_genpd_del_provider(void *data) +{ + of_genpd_del_provider(data); +} + +static int r8a78000_genpd_always_on_singleton(struct device *dev) +{ + struct generic_pm_domain *genpd; + int ret; + + guard(mutex)(&r8a78000_mdlc_lock); + + if (r8a78000_genpd_always_on) + return 0; + + genpd = kzalloc_obj(*genpd); + if (!genpd) + return -ENOMEM; + + genpd->name = "always-on"; + genpd->attach_dev = r8a78000_mdlc_attach_dev; + + ret = pm_genpd_init(genpd, &pm_domain_always_on_gov, false); + if (ret) { + kfree(genpd); + return dev_err_probe(dev, ret, + "Failed to create always-on domain\n"); + } + + r8a78000_genpd_always_on = genpd; + return 0; +} + +static int r8a78000_mdlc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct r8a78000_mdlc_priv *priv; + const struct mdlc_info *info; + struct resource *res; + int ret; + + ret = r8a78000_genpd_always_on_singleton(dev); + if (ret) + return ret; + + info = of_device_get_match_data(dev); + if (!info) + return -ENODEV; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->np = np; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + for (; info->base; info++) { + if (info->base == res->start) + break; + } + + if (!info->base) { + dev_dbg(dev, "Unsupported MDLC instance 0x%pa\n", &res->start); + return -ENODEV; + } + + priv->mod_map = info->mod_map; + + scoped_guard(mutex, &r8a78000_mdlc_lock) { + hlist_add_head(&priv->link, &r8a78000_mdlc_list); + } + + ret = devm_add_action_or_reset(dev, r8a78000_mdlc_unlink, priv); + if (ret) + return dev_err_probe(dev, ret, "failed to add action\n"); + + /* Note that no actual domains are registered, just need translation */ + priv->genpd_data.xlate = r8a78000_genpd_xlate; + ret = of_genpd_add_provider_onecell(np, &priv->genpd_data); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register genpd provider\n"); + + ret = devm_add_action_or_reset(dev, r8a78000_genpd_del_provider, np); + if (ret) + return dev_err_probe(dev, ret, + "failed to add unregister action\n"); + + priv->rcdev.ops = &r8a78000_mdlc_reset_ops; + priv->rcdev.of_node = np; + priv->rcdev.of_reset_n_cells = 1; + priv->rcdev.of_xlate = r8a78000_mdlc_reset_xlate; + + ret = devm_reset_controller_register(dev, &priv->rcdev); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register reset controller\n"); + + return 0; +} + +static const struct mod_map r8a78000_mdlc_perw_mod_default[] = { + { 0x54 }, /* HSCIF0 */ + { -1 } +}; + +static const struct mdlc_info r8a78000_mdlc_default[] = { + { + .base = 0xc05d0000 /* mdlc_perw */, + .mod_map = r8a78000_mdlc_perw_mod_default, + }, + { /* sentinel */ } +}; + +static const struct of_device_id r8a78000_mdlc_match[] = { + { + .compatible = "renesas,r8a78000-mdlc", + .data = &r8a78000_mdlc_default, + }, + { /* sentinel */ } +}; + +static struct platform_driver r8a78000_mdlc_driver = { + .probe = r8a78000_mdlc_probe, + .driver = { + .name = "r8a78000-mdlc", + .of_match_table = r8a78000_mdlc_match, + .suppress_bind_attrs = true, + }, +}; + +builtin_platform_driver(r8a78000_mdlc_driver) + +MODULE_DESCRIPTION("R-Car X5H MDLC Driver"); diff --git a/drivers/pmdomain/renesas/rcar-gen4-sysc.c b/drivers/pmdomain/renesas/rcar-gen4-sysc.c new file mode 100644 index 000000000..0c6c639a9 --- /dev/null +++ b/drivers/pmdomain/renesas/rcar-gen4-sysc.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * R-Car Gen4 SYSC Power management support + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +#include <linux/bits.h> +#include <linux/clk/renesas.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/of_address.h> +#include <linux/pm_domain.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/types.h> + +#include "rcar-gen4-sysc.h" + +/* SYSC Common */ +#define SYSCSR 0x000 /* SYSC Status Register */ +#define SYSCPONSR(x) (0x800 + ((x) * 0x4)) /* Power-ON Status Register 0 */ +#define SYSCPOFFSR(x) (0x808 + ((x) * 0x4)) /* Power-OFF Status Register */ +#define SYSCISCR(x) (0x810 + ((x) * 0x4)) /* Interrupt Status/Clear Register */ +#define SYSCIER(x) (0x820 + ((x) * 0x4)) /* Interrupt Enable Register */ +#define SYSCIMR(x) (0x830 + ((x) * 0x4)) /* Interrupt Mask Register */ + +/* Power Domain Registers */ +#define PDRSR(n) (0x1000 + ((n) * 0x40)) +#define PDRONCR(n) (0x1004 + ((n) * 0x40)) +#define PDROFFCR(n) (0x1008 + ((n) * 0x40)) +#define PDRESR(n) (0x100C + ((n) * 0x40)) + +/* PWRON/PWROFF */ +#define PWRON_PWROFF BIT(0) /* Power-ON/OFF request */ + +/* PDRESR */ +#define PDRESR_ERR BIT(0) + +/* PDRSR */ +#define PDRSR_OFF BIT(0) /* Power-OFF state */ +#define PDRSR_ON BIT(4) /* Power-ON state */ +#define PDRSR_OFF_STATE BIT(8) /* Processing Power-OFF sequence */ +#define PDRSR_ON_STATE BIT(12) /* Processing Power-ON sequence */ + +#define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */ + +#define SYSCSR_TIMEOUT 10000 +#define SYSCSR_DELAY_US 1 + +#define PDRESR_RETRIES 10000 +#define PDRESR_DELAY_US 1 + +#define SYSCISCR_TIMEOUT 10000 +#define SYSCISCR_DELAY_US 1 + +#define RCAR_GEN4_PD_ALWAYS_ON 64 +#define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32) + +static void __iomem *rcar_gen4_sysc_base; +static DEFINE_SPINLOCK(rcar_gen4_sysc_lock); /* SMP CPUs + I/O devices */ + +static int rcar_gen4_sysc_pwr_on_off(u8 pdr, bool on) +{ + unsigned int reg_offs; + u32 val; + int ret; + + if (on) + reg_offs = PDRONCR(pdr); + else + reg_offs = PDROFFCR(pdr); + + /* Wait until SYSC is ready to accept a power request */ + ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCSR, val, + (val & SYSCSR_BUSY) == SYSCSR_BUSY, + SYSCSR_DELAY_US, SYSCSR_TIMEOUT); + if (ret < 0) + return -EAGAIN; + + /* Submit power shutoff or power resume request */ + iowrite32(PWRON_PWROFF, rcar_gen4_sysc_base + reg_offs); + + return 0; +} + +static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask) +{ + u32 val; + int ret; + + iowrite32(isr_mask, rcar_gen4_sysc_base + SYSCISCR(reg_idx)); + + ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx), + val, !(val & isr_mask), + SYSCISCR_DELAY_US, SYSCISCR_TIMEOUT); + if (ret < 0) { + pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__); + return -EIO; + } + + return 0; +} + +static int rcar_gen4_sysc_power(u8 pdr, bool on) +{ + unsigned int isr_mask; + unsigned int reg_idx, bit_idx; + unsigned int status; + unsigned long flags; + int ret = 0; + u32 val; + int k; + + spin_lock_irqsave(&rcar_gen4_sysc_lock, flags); + + reg_idx = pdr / NUM_DOMAINS_EACH_REG; + bit_idx = pdr % NUM_DOMAINS_EACH_REG; + + isr_mask = BIT(bit_idx); + + /* + * The interrupt source needs to be enabled, but masked, to prevent the + * CPU from receiving it. + */ + iowrite32(ioread32(rcar_gen4_sysc_base + SYSCIER(reg_idx)) | isr_mask, + rcar_gen4_sysc_base + SYSCIER(reg_idx)); + iowrite32(ioread32(rcar_gen4_sysc_base + SYSCIMR(reg_idx)) | isr_mask, + rcar_gen4_sysc_base + SYSCIMR(reg_idx)); + + ret = clear_irq_flags(reg_idx, isr_mask); + if (ret) + goto out; + + /* Submit power shutoff or resume request until it was accepted */ + for (k = 0; k < PDRESR_RETRIES; k++) { + ret = rcar_gen4_sysc_pwr_on_off(pdr, on); + if (ret) + goto out; + + status = ioread32(rcar_gen4_sysc_base + PDRESR(pdr)); + if (!(status & PDRESR_ERR)) + break; + + udelay(PDRESR_DELAY_US); + } + + if (k == PDRESR_RETRIES) { + ret = -EIO; + goto out; + } + + /* Wait until the power shutoff or resume request has completed * */ + ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx), + val, (val & isr_mask), + SYSCISCR_DELAY_US, SYSCISCR_TIMEOUT); + if (ret < 0) { + ret = -EIO; + goto out; + } + + /* Clear interrupt flags */ + ret = clear_irq_flags(reg_idx, isr_mask); + if (ret) + goto out; + + out: + spin_unlock_irqrestore(&rcar_gen4_sysc_lock, flags); + + pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off", + pdr, ioread32(rcar_gen4_sysc_base + SYSCISCR(reg_idx)), ret); + return ret; +} + +static bool rcar_gen4_sysc_power_is_off(u8 pdr) +{ + unsigned int st; + + st = ioread32(rcar_gen4_sysc_base + PDRSR(pdr)); + + if (st & PDRSR_OFF) + return true; + + return false; +} + +struct rcar_gen4_sysc_pd { + struct generic_pm_domain genpd; + u8 pdr; + unsigned int flags; + char name[]; +}; + +static inline struct rcar_gen4_sysc_pd *to_rcar_gen4_pd(struct generic_pm_domain *d) +{ + return container_of(d, struct rcar_gen4_sysc_pd, genpd); +} + +static int rcar_gen4_sysc_pd_power_off(struct generic_pm_domain *genpd) +{ + struct rcar_gen4_sysc_pd *pd = to_rcar_gen4_pd(genpd); + + pr_debug("%s: %s\n", __func__, genpd->name); + return rcar_gen4_sysc_power(pd->pdr, false); +} + +static int rcar_gen4_sysc_pd_power_on(struct generic_pm_domain *genpd) +{ + struct rcar_gen4_sysc_pd *pd = to_rcar_gen4_pd(genpd); + + pr_debug("%s: %s\n", __func__, genpd->name); + return rcar_gen4_sysc_power(pd->pdr, true); +} + +static int __init rcar_gen4_sysc_pd_setup(struct rcar_gen4_sysc_pd *pd) +{ + struct generic_pm_domain *genpd = &pd->genpd; + const char *name = pd->genpd.name; + int error; + + if (pd->flags & PD_CPU) { + /* + * This domain contains a CPU core and therefore it should + * only be turned off if the CPU is not in use. + */ + pr_debug("PM domain %s contains %s\n", name, "CPU"); + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } else if (pd->flags & PD_SCU) { + /* + * This domain contains an SCU and cache-controller, and + * therefore it should only be turned off if the CPU cores are + * not in use. + */ + pr_debug("PM domain %s contains %s\n", name, "SCU"); + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } else if (pd->flags & PD_NO_CR) { + /* + * This domain cannot be turned off. + */ + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } + + if (!(pd->flags & (PD_CPU | PD_SCU))) { + /* Enable Clock Domain for I/O devices */ + genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; + genpd->attach_dev = cpg_mssr_attach_dev; + genpd->detach_dev = cpg_mssr_detach_dev; + } + + genpd->flags |= GENPD_FLAG_NO_STAY_ON; + genpd->power_off = rcar_gen4_sysc_pd_power_off; + genpd->power_on = rcar_gen4_sysc_pd_power_on; + + if (pd->flags & (PD_CPU | PD_NO_CR)) { + /* Skip CPUs (handled by SMP code) and areas without control */ + pr_debug("%s: Not touching %s\n", __func__, genpd->name); + goto finalize; + } + + if (!rcar_gen4_sysc_power_is_off(pd->pdr)) { + pr_debug("%s: %s is already powered\n", __func__, genpd->name); + goto finalize; + } + + rcar_gen4_sysc_power(pd->pdr, true); + +finalize: + error = pm_genpd_init(genpd, &simple_qos_governor, false); + if (error) + pr_err("Failed to init PM domain %s: %d\n", name, error); + + return error; +} + +static const struct of_device_id rcar_gen4_sysc_matches[] __initconst = { +#ifdef CONFIG_SYSC_R8A779A0 + { .compatible = "renesas,r8a779a0-sysc", .data = &r8a779a0_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A779F0 + { .compatible = "renesas,r8a779f0-sysc", .data = &r8a779f0_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A779G0 + { .compatible = "renesas,r8a779g0-sysc", .data = &r8a779g0_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A779H0 + { .compatible = "renesas,r8a779h0-sysc", .data = &r8a779h0_sysc_info }, +#endif + { /* sentinel */ } +}; + +struct rcar_gen4_pm_domains { + struct genpd_onecell_data onecell_data; + struct generic_pm_domain *domains[RCAR_GEN4_PD_ALWAYS_ON + 1]; +}; + +static struct genpd_onecell_data *rcar_gen4_sysc_onecell_data; + +static int __init rcar_gen4_sysc_pd_init(void) +{ + const struct rcar_gen4_sysc_info *info; + const struct of_device_id *match; + struct rcar_gen4_pm_domains *domains; + struct device_node *np; + void __iomem *base; + unsigned int i; + int error; + + np = of_find_matching_node_and_match(NULL, rcar_gen4_sysc_matches, &match); + if (!np) + return -ENODEV; + + info = match->data; + + base = of_iomap(np, 0); + if (!base) { + pr_warn("%pOF: Cannot map regs\n", np); + error = -ENOMEM; + goto out_put; + } + + rcar_gen4_sysc_base = base; + + domains = kzalloc_obj(*domains); + if (!domains) { + error = -ENOMEM; + goto out_put; + } + + domains->onecell_data.domains = domains->domains; + domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); + rcar_gen4_sysc_onecell_data = &domains->onecell_data; + + for (i = 0; i < info->num_areas; i++) { + const struct rcar_gen4_sysc_area *area = &info->areas[i]; + struct rcar_gen4_sysc_pd *pd; + size_t n; + + n = strlen(area->name) + 1; + pd = kzalloc(sizeof(*pd) + n, GFP_KERNEL); + if (!pd) { + error = -ENOMEM; + goto out_put; + } + + memcpy(pd->name, area->name, n); + pd->genpd.name = pd->name; + pd->pdr = area->pdr; + pd->flags = area->flags; + + error = rcar_gen4_sysc_pd_setup(pd); + if (error) + goto out_put; + + domains->domains[area->pdr] = &pd->genpd; + + if (area->parent < 0) + continue; + + error = pm_genpd_add_subdomain(domains->domains[area->parent], + &pd->genpd); + if (error) { + pr_warn("Failed to add PM subdomain %s to parent %u\n", + area->name, area->parent); + goto out_put; + } + } + + error = of_genpd_add_provider_onecell(np, &domains->onecell_data); + +out_put: + of_node_put(np); + return error; +} +postcore_initcall(rcar_gen4_sysc_pd_init); diff --git a/drivers/pmdomain/renesas/rcar-gen4-sysc.h b/drivers/pmdomain/renesas/rcar-gen4-sysc.h new file mode 100644 index 000000000..fdf843aa5 --- /dev/null +++ b/drivers/pmdomain/renesas/rcar-gen4-sysc.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * R-Car Gen4 System Controller + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ +#ifndef __SOC_RENESAS_RCAR_GEN4_SYSC_H__ +#define __SOC_RENESAS_RCAR_GEN4_SYSC_H__ + +#include <linux/types.h> + +/* + * Power Domain flags + */ +#define PD_CPU BIT(0) /* Area contains main CPU core */ +#define PD_SCU BIT(1) /* Area contains SCU and L2 cache */ +#define PD_NO_CR BIT(2) /* Area lacks PWR{ON,OFF}CR registers */ + +#define PD_CPU_NOCR (PD_CPU | PD_NO_CR) /* CPU area lacks CR */ +#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */ + +/* + * Description of a Power Area + */ +struct rcar_gen4_sysc_area { + const char *name; + u8 pdr; /* PDRn */ + s8 parent; /* -1 if none */ + u8 flags; /* See PD_* */ +}; + +/* + * SoC-specific Power Area Description + */ +struct rcar_gen4_sysc_info { + const struct rcar_gen4_sysc_area *areas; + unsigned int num_areas; +}; + +extern const struct rcar_gen4_sysc_info r8a779a0_sysc_info; +extern const struct rcar_gen4_sysc_info r8a779f0_sysc_info; +extern const struct rcar_gen4_sysc_info r8a779g0_sysc_info; +extern const struct rcar_gen4_sysc_info r8a779h0_sysc_info; + +#endif /* __SOC_RENESAS_RCAR_GEN4_SYSC_H__ */ diff --git a/drivers/pmdomain/renesas/rcar-sysc.c b/drivers/pmdomain/renesas/rcar-sysc.c new file mode 100644 index 000000000..bd7bb9cbd --- /dev/null +++ b/drivers/pmdomain/renesas/rcar-sysc.c @@ -0,0 +1,491 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * R-Car SYSC Power management support + * + * Copyright (C) 2014 Magnus Damm + * Copyright (C) 2015-2017 Glider bvba + */ + +#include <linux/clk/renesas.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/mm.h> +#include <linux/of_address.h> +#include <linux/pm_domain.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/soc/renesas/rcar-sysc.h> + +#include "rcar-sysc.h" + +/* SYSC Common */ +#define SYSCSR 0x00 /* SYSC Status Register */ +#define SYSCISR 0x04 /* Interrupt Status Register */ +#define SYSCISCR 0x08 /* Interrupt Status Clear Register */ +#define SYSCIER 0x0c /* Interrupt Enable Register */ +#define SYSCIMR 0x10 /* Interrupt Mask Register */ + +/* SYSC Status Register */ +#define SYSCSR_PONENB 1 /* Ready for power resume requests */ +#define SYSCSR_POFFENB 0 /* Ready for power shutoff requests */ + +/* + * Power Control Register Offsets inside the register block for each domain + * Note: The "CR" registers for ARM cores exist on H1 only + * Use WFI to power off, CPG/APMU to resume ARM cores on R-Car Gen2 + * Use PSCI on R-Car Gen3 + */ +#define PWRSR_OFFS 0x00 /* Power Status Register */ +#define PWROFFCR_OFFS 0x04 /* Power Shutoff Control Register */ +#define PWROFFSR_OFFS 0x08 /* Power Shutoff Status Register */ +#define PWRONCR_OFFS 0x0c /* Power Resume Control Register */ +#define PWRONSR_OFFS 0x10 /* Power Resume Status Register */ +#define PWRER_OFFS 0x14 /* Power Shutoff/Resume Error */ + + +#define SYSCSR_TIMEOUT 1000 +#define SYSCSR_DELAY_US 1 + +#define PWRER_RETRIES 1000 +#define PWRER_DELAY_US 1 + +#define SYSCISR_TIMEOUT 1000 +#define SYSCISR_DELAY_US 1 + +#define RCAR_PD_ALWAYS_ON 32 /* Always-on power area */ + +struct rcar_sysc_pd { + struct generic_pm_domain genpd; + u16 chan_offs; + u8 chan_bit; + u8 isr_bit; + unsigned int flags; + char name[]; +}; + +static void __iomem *rcar_sysc_base; +static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */ +static u32 rcar_sysc_extmask_offs, rcar_sysc_extmask_val; + +static int rcar_sysc_pwr_on_off(const struct rcar_sysc_pd *pd, bool on) +{ + unsigned int sr_bit, reg_offs; + u32 val; + int ret; + + if (on) { + sr_bit = SYSCSR_PONENB; + reg_offs = PWRONCR_OFFS; + } else { + sr_bit = SYSCSR_POFFENB; + reg_offs = PWROFFCR_OFFS; + } + + /* Wait until SYSC is ready to accept a power request */ + ret = readl_poll_timeout_atomic(rcar_sysc_base + SYSCSR, val, + val & BIT(sr_bit), SYSCSR_DELAY_US, + SYSCSR_TIMEOUT); + if (ret) + return -EAGAIN; + + /* Power-off delay quirk */ + if (!on && (pd->flags & PD_OFF_DELAY)) + udelay(1); + + /* Submit power shutoff or power resume request */ + iowrite32(BIT(pd->chan_bit), rcar_sysc_base + pd->chan_offs + reg_offs); + + return 0; +} + +static int rcar_sysc_power(const struct rcar_sysc_pd *pd, bool on) +{ + unsigned int isr_mask = BIT(pd->isr_bit); + unsigned int chan_mask = BIT(pd->chan_bit); + unsigned int status, k; + unsigned long flags; + int ret; + + spin_lock_irqsave(&rcar_sysc_lock, flags); + + /* + * Mask external power requests for CPU or 3DG domains + */ + if (rcar_sysc_extmask_val) { + iowrite32(rcar_sysc_extmask_val, + rcar_sysc_base + rcar_sysc_extmask_offs); + } + + /* + * The interrupt source needs to be enabled, but masked, to prevent the + * CPU from receiving it. + */ + iowrite32(ioread32(rcar_sysc_base + SYSCIMR) | isr_mask, + rcar_sysc_base + SYSCIMR); + iowrite32(ioread32(rcar_sysc_base + SYSCIER) | isr_mask, + rcar_sysc_base + SYSCIER); + + iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); + + /* Submit power shutoff or resume request until it was accepted */ + for (k = 0; k < PWRER_RETRIES; k++) { + ret = rcar_sysc_pwr_on_off(pd, on); + if (ret) + goto out; + + status = ioread32(rcar_sysc_base + pd->chan_offs + PWRER_OFFS); + if (!(status & chan_mask)) + break; + + udelay(PWRER_DELAY_US); + } + + if (k == PWRER_RETRIES) { + ret = -EIO; + goto out; + } + + /* Wait until the power shutoff or resume request has completed * */ + ret = readl_poll_timeout_atomic(rcar_sysc_base + SYSCISR, status, + status & isr_mask, SYSCISR_DELAY_US, + SYSCISR_TIMEOUT); + if (ret) + ret = -EIO; + + iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); + + out: + if (rcar_sysc_extmask_val) + iowrite32(0, rcar_sysc_base + rcar_sysc_extmask_offs); + + spin_unlock_irqrestore(&rcar_sysc_lock, flags); + + pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off", + pd->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret); + return ret; +} + +static bool rcar_sysc_power_is_off(const struct rcar_sysc_pd *pd) +{ + unsigned int st; + + st = ioread32(rcar_sysc_base + pd->chan_offs + PWRSR_OFFS); + if (st & BIT(pd->chan_bit)) + return true; + + return false; +} + +static inline struct rcar_sysc_pd *to_rcar_pd(struct generic_pm_domain *d) +{ + return container_of(d, struct rcar_sysc_pd, genpd); +} + +static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd) +{ + struct rcar_sysc_pd *pd = to_rcar_pd(genpd); + + pr_debug("%s: %s\n", __func__, genpd->name); + return rcar_sysc_power(pd, false); +} + +static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd) +{ + struct rcar_sysc_pd *pd = to_rcar_pd(genpd); + + pr_debug("%s: %s\n", __func__, genpd->name); + return rcar_sysc_power(pd, true); +} + +static bool has_cpg_mstp; + +static int __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd) +{ + struct generic_pm_domain *genpd = &pd->genpd; + const char *name = pd->genpd.name; + int error; + + if (pd->flags & PD_CPU) { + /* + * This domain contains a CPU core and therefore it should + * only be turned off if the CPU is not in use. + */ + pr_debug("PM domain %s contains %s\n", name, "CPU"); + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } else if (pd->flags & PD_SCU) { + /* + * This domain contains an SCU and cache-controller, and + * therefore it should only be turned off if the CPU cores are + * not in use. + */ + pr_debug("PM domain %s contains %s\n", name, "SCU"); + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } else if (pd->flags & PD_NO_CR) { + /* + * This domain cannot be turned off. + */ + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } + + if (!(pd->flags & (PD_CPU | PD_SCU))) { + /* Enable Clock Domain for I/O devices */ + genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; + if (has_cpg_mstp) { + genpd->attach_dev = cpg_mstp_attach_dev; + genpd->detach_dev = cpg_mstp_detach_dev; + } else { + genpd->attach_dev = cpg_mssr_attach_dev; + genpd->detach_dev = cpg_mssr_detach_dev; + } + } + + genpd->flags |= GENPD_FLAG_NO_STAY_ON; + genpd->power_off = rcar_sysc_pd_power_off; + genpd->power_on = rcar_sysc_pd_power_on; + + if (pd->flags & (PD_CPU | PD_NO_CR)) { + /* Skip CPUs (handled by SMP code) and areas without control */ + pr_debug("%s: Not touching %s\n", __func__, genpd->name); + goto finalize; + } + + if (!rcar_sysc_power_is_off(pd)) { + pr_debug("%s: %s is already powered\n", __func__, genpd->name); + goto finalize; + } + + rcar_sysc_power(pd, true); + +finalize: + error = pm_genpd_init(genpd, &simple_qos_governor, false); + if (error) + pr_err("Failed to init PM domain %s: %d\n", name, error); + + return error; +} + +static const struct of_device_id rcar_sysc_matches[] __initconst = { +#ifdef CONFIG_SYSC_R8A7742 + { .compatible = "renesas,r8a7742-sysc", .data = &r8a7742_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A7743 + { .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info }, + /* RZ/G1N is identical to RZ/G2M w.r.t. power domains. */ + { .compatible = "renesas,r8a7744-sysc", .data = &r8a7743_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A7745 + { .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A77470 + { .compatible = "renesas,r8a77470-sysc", .data = &r8a77470_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A774A1 + { .compatible = "renesas,r8a774a1-sysc", .data = &r8a774a1_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A774B1 + { .compatible = "renesas,r8a774b1-sysc", .data = &r8a774b1_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A774C0 + { .compatible = "renesas,r8a774c0-sysc", .data = &r8a774c0_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A774E1 + { .compatible = "renesas,r8a774e1-sysc", .data = &r8a774e1_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A7779 + { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A7790 + { .compatible = "renesas,r8a7790-sysc", .data = &r8a7790_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A7791 + { .compatible = "renesas,r8a7791-sysc", .data = &r8a7791_sysc_info }, + /* R-Car M2-N is identical to R-Car M2-W w.r.t. power domains. */ + { .compatible = "renesas,r8a7793-sysc", .data = &r8a7791_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A7792 + { .compatible = "renesas,r8a7792-sysc", .data = &r8a7792_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A7794 + { .compatible = "renesas,r8a7794-sysc", .data = &r8a7794_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A7795 + { .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A77960 + { .compatible = "renesas,r8a7796-sysc", .data = &r8a77960_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A77961 + { .compatible = "renesas,r8a77961-sysc", .data = &r8a77961_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A77965 + { .compatible = "renesas,r8a77965-sysc", .data = &r8a77965_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A77970 + { .compatible = "renesas,r8a77970-sysc", .data = &r8a77970_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A77980 + { .compatible = "renesas,r8a77980-sysc", .data = &r8a77980_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A77990 + { .compatible = "renesas,r8a77990-sysc", .data = &r8a77990_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A77995 + { .compatible = "renesas,r8a77995-sysc", .data = &r8a77995_sysc_info }, +#endif + { /* sentinel */ } +}; + +struct rcar_pm_domains { + struct genpd_onecell_data onecell_data; + struct generic_pm_domain *domains[RCAR_PD_ALWAYS_ON + 1]; +}; + +static struct genpd_onecell_data *rcar_sysc_onecell_data; +static struct device_node *rcar_sysc_onecell_np __initdata = NULL; + +static int __init rcar_sysc_pd_init(void) +{ + const struct rcar_sysc_info *info; + const struct of_device_id *match; + struct rcar_pm_domains *domains; + struct device_node *np; + void __iomem *base; + unsigned int i; + int error; + + np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match); + if (!np) + return -ENODEV; + + info = match->data; + + if (info->init) { + error = info->init(); + if (error) + goto out_put; + } + + has_cpg_mstp = of_find_compatible_node(NULL, NULL, + "renesas,cpg-mstp-clocks"); + + base = of_iomap(np, 0); + if (!base) { + pr_warn("%pOF: Cannot map regs\n", np); + error = -ENOMEM; + goto out_put; + } + + rcar_sysc_base = base; + + /* Optional External Request Mask Register */ + rcar_sysc_extmask_offs = info->extmask_offs; + rcar_sysc_extmask_val = info->extmask_val; + + domains = kzalloc_obj(*domains); + if (!domains) { + error = -ENOMEM; + goto out_put; + } + + domains->onecell_data.domains = domains->domains; + domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); + rcar_sysc_onecell_data = &domains->onecell_data; + + for (i = 0; i < info->num_areas; i++) { + const struct rcar_sysc_area *area = &info->areas[i]; + struct rcar_sysc_pd *pd; + size_t n; + + n = strlen(area->name) + 1; + pd = kzalloc(sizeof(*pd) + n, GFP_KERNEL); + if (!pd) { + error = -ENOMEM; + goto out_put; + } + + memcpy(pd->name, area->name, n); + pd->genpd.name = pd->name; + pd->chan_offs = area->chan_offs; + pd->chan_bit = area->chan_bit; + pd->isr_bit = area->isr_bit; + pd->flags = area->flags; + + error = rcar_sysc_pd_setup(pd); + if (error) + goto out_put; + + domains->domains[area->isr_bit] = &pd->genpd; + + if (area->parent < 0) + continue; + + error = pm_genpd_add_subdomain(domains->domains[area->parent], + &pd->genpd); + if (error) { + pr_warn("Failed to add PM subdomain %s to parent %u\n", + area->name, area->parent); + goto out_put; + } + } + + rcar_sysc_onecell_np = np; + return 0; + +out_put: + of_node_put(np); + return error; +} +early_initcall(rcar_sysc_pd_init); + +static int __init rcar_sysc_pd_init_provider(void) +{ + int error; + + if (!rcar_sysc_onecell_np) + return -ENODEV; + + error = of_genpd_add_provider_onecell(rcar_sysc_onecell_np, + rcar_sysc_onecell_data); + + of_node_put(rcar_sysc_onecell_np); + return error; +} +postcore_initcall(rcar_sysc_pd_init_provider); + +#ifdef CONFIG_ARCH_R8A7779 +static int rcar_sysc_power_cpu(unsigned int idx, bool on) +{ + struct generic_pm_domain *genpd; + struct rcar_sysc_pd *pd; + unsigned int i; + + if (!rcar_sysc_onecell_data) + return -ENODEV; + + for (i = 0; i < rcar_sysc_onecell_data->num_domains; i++) { + genpd = rcar_sysc_onecell_data->domains[i]; + if (!genpd) + continue; + + pd = to_rcar_pd(genpd); + if (!(pd->flags & PD_CPU) || pd->chan_bit != idx) + continue; + + return rcar_sysc_power(pd, on); + } + + return -ENOENT; +} + +int rcar_sysc_power_down_cpu(unsigned int cpu) +{ + return rcar_sysc_power_cpu(cpu, false); +} + +int rcar_sysc_power_up_cpu(unsigned int cpu) +{ + return rcar_sysc_power_cpu(cpu, true); +} +#endif /* CONFIG_ARCH_R8A7779 */ diff --git a/drivers/pmdomain/renesas/rcar-sysc.h b/drivers/pmdomain/renesas/rcar-sysc.h new file mode 100644 index 000000000..07ffce310 --- /dev/null +++ b/drivers/pmdomain/renesas/rcar-sysc.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Renesas R-Car System Controller + * + * Copyright (C) 2016 Glider bvba + */ +#ifndef __SOC_RENESAS_RCAR_SYSC_H__ +#define __SOC_RENESAS_RCAR_SYSC_H__ + +#include <linux/types.h> + + +/* + * Power Domain flags + */ +#define PD_CPU BIT(0) /* Area contains main CPU core */ +#define PD_SCU BIT(1) /* Area contains SCU and L2 cache */ +#define PD_NO_CR BIT(2) /* Area lacks PWR{ON,OFF}CR registers */ +#define PD_OFF_DELAY BIT(3) /* Area is subject to power-off delay quirk */ + +#define PD_CPU_CR PD_CPU /* CPU area has CR (R-Car H1) */ +#define PD_CPU_NOCR PD_CPU | PD_NO_CR /* CPU area lacks CR (R-Car Gen2/3) */ +#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */ + + +/* + * Description of a Power Area + */ + +struct rcar_sysc_area { + const char *name; + u16 chan_offs; /* Offset of PWRSR register for this area */ + u8 chan_bit; /* Bit in PWR* (except for PWRUP in PWRSR) */ + u8 isr_bit; /* Bit in SYSCI*R */ + s8 parent; /* -1 if none */ + u8 flags; /* See PD_* */ +}; + + +/* + * SoC-specific Power Area Description + */ + +struct rcar_sysc_info { + int (*init)(void); /* Optional */ + const struct rcar_sysc_area *areas; + unsigned int num_areas; + /* Optional External Request Mask Register */ + u32 extmask_offs; /* SYSCEXTMASK register offset */ + u32 extmask_val; /* SYSCEXTMASK register mask value */ +}; + +extern const struct rcar_sysc_info r8a7742_sysc_info; +extern const struct rcar_sysc_info r8a7743_sysc_info; +extern const struct rcar_sysc_info r8a7745_sysc_info; +extern const struct rcar_sysc_info r8a77470_sysc_info; +extern const struct rcar_sysc_info r8a774a1_sysc_info; +extern const struct rcar_sysc_info r8a774b1_sysc_info; +extern const struct rcar_sysc_info r8a774c0_sysc_info; +extern const struct rcar_sysc_info r8a774e1_sysc_info; +extern const struct rcar_sysc_info r8a7779_sysc_info; +extern const struct rcar_sysc_info r8a7790_sysc_info; +extern const struct rcar_sysc_info r8a7791_sysc_info; +extern const struct rcar_sysc_info r8a7792_sysc_info; +extern const struct rcar_sysc_info r8a7794_sysc_info; +extern struct rcar_sysc_info r8a7795_sysc_info; +extern const struct rcar_sysc_info r8a77960_sysc_info; +extern const struct rcar_sysc_info r8a77961_sysc_info; +extern const struct rcar_sysc_info r8a77965_sysc_info; +extern const struct rcar_sysc_info r8a77970_sysc_info; +extern const struct rcar_sysc_info r8a77980_sysc_info; +extern const struct rcar_sysc_info r8a77990_sysc_info; +extern const struct rcar_sysc_info r8a77995_sysc_info; + +#endif /* __SOC_RENESAS_RCAR_SYSC_H__ */ diff --git a/drivers/pmdomain/renesas/rmobile-sysc.c b/drivers/pmdomain/renesas/rmobile-sysc.c new file mode 100644 index 000000000..93103ff33 --- /dev/null +++ b/drivers/pmdomain/renesas/rmobile-sysc.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * rmobile power management support + * + * Copyright (C) 2012 Renesas Solutions Corp. + * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * Copyright (C) 2014 Glider bvba + * + * based on pm-sh7372.c + * Copyright (C) 2011 Magnus Damm + */ +#include <linux/clk/renesas.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/pm.h> +#include <linux/pm_clock.h> +#include <linux/pm_domain.h> +#include <linux/slab.h> + +/* SYSC */ +#define SPDCR 0x08 /* SYS Power Down Control Register */ +#define SWUCR 0x14 /* SYS Wakeup Control Register */ +#define PSTR 0x80 /* Power Status Register */ + +#define PSTR_RETRIES 100 +#define PSTR_DELAY_US 10 + +struct rmobile_pm_domain { + struct generic_pm_domain genpd; + struct dev_power_governor *gov; + int (*suspend)(void); + void __iomem *base; + unsigned int bit_shift; +}; + +static inline +struct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d) +{ + return container_of(d, struct rmobile_pm_domain, genpd); +} + +static int rmobile_pd_power_down(struct generic_pm_domain *genpd) +{ + struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd); + unsigned int mask = BIT(rmobile_pd->bit_shift); + u32 val; + + if (rmobile_pd->suspend) { + int ret = rmobile_pd->suspend(); + + if (ret) + return ret; + } + + if (readl(rmobile_pd->base + PSTR) & mask) { + writel(mask, rmobile_pd->base + SPDCR); + + readl_poll_timeout_atomic(rmobile_pd->base + SPDCR, val, + !(val & mask), 0, PSTR_RETRIES); + } + + pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", genpd->name, mask, + readl(rmobile_pd->base + PSTR)); + + return 0; +} + +static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd) +{ + unsigned int val, mask = BIT(rmobile_pd->bit_shift); + int ret = 0; + + if (readl(rmobile_pd->base + PSTR) & mask) + return ret; + + writel(mask, rmobile_pd->base + SWUCR); + + ret = readl_poll_timeout_atomic(rmobile_pd->base + SWUCR, val, + (val & mask), PSTR_DELAY_US, + PSTR_RETRIES * PSTR_DELAY_US); + + pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n", + rmobile_pd->genpd.name, mask, + readl(rmobile_pd->base + PSTR)); + + return ret; +} + +static int rmobile_pd_power_up(struct generic_pm_domain *genpd) +{ + return __rmobile_pd_power_up(to_rmobile_pd(genpd)); +} + +static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd) +{ + struct generic_pm_domain *genpd = &rmobile_pd->genpd; + struct dev_power_governor *gov = rmobile_pd->gov; + + genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP | + GENPD_FLAG_NO_STAY_ON; + genpd->attach_dev = cpg_mstp_attach_dev; + genpd->detach_dev = cpg_mstp_detach_dev; + + if (!(genpd->flags & GENPD_FLAG_ALWAYS_ON)) { + genpd->power_off = rmobile_pd_power_down; + genpd->power_on = rmobile_pd_power_up; + __rmobile_pd_power_up(rmobile_pd); + } + + pm_genpd_init(genpd, gov ? : &simple_qos_governor, false); +} + +static int rmobile_pd_suspend_console(void) +{ + /* + * Serial consoles make use of SCIF hardware located in this domain, + * hence keep the power domain on if "no_console_suspend" is set. + */ + return console_suspend_enabled ? 0 : -EBUSY; +} + +enum pd_types { + PD_NORMAL, + PD_CPU, + PD_CONSOLE, + PD_DEBUG, + PD_MEMCTL, +}; + +#define MAX_NUM_SPECIAL_PDS 16 + +static struct special_pd { + struct device_node *pd; + enum pd_types type; +} special_pds[MAX_NUM_SPECIAL_PDS] __initdata; + +static unsigned int num_special_pds __initdata; + +static const struct of_device_id special_ids[] __initconst = { + { .compatible = "arm,coresight-etm3x", .data = (void *)PD_DEBUG }, + { .compatible = "renesas,dbsc-r8a73a4", .data = (void *)PD_MEMCTL, }, + { .compatible = "renesas,dbsc3-r8a7740", .data = (void *)PD_MEMCTL, }, + { .compatible = "renesas,sbsc-sh73a0", .data = (void *)PD_MEMCTL, }, + { /* sentinel */ }, +}; + +static void __init add_special_pd(struct device_node *np, enum pd_types type) +{ + unsigned int i; + struct device_node *pd; + + pd = of_parse_phandle(np, "power-domains", 0); + if (!pd) + return; + + for (i = 0; i < num_special_pds; i++) + if (pd == special_pds[i].pd && type == special_pds[i].type) { + of_node_put(pd); + return; + } + + if (num_special_pds == ARRAY_SIZE(special_pds)) { + pr_warn("Too many special PM domains\n"); + of_node_put(pd); + return; + } + + pr_debug("Special PM domain %pOFn type %d for %pOF\n", pd, type, np); + + special_pds[num_special_pds].pd = pd; + special_pds[num_special_pds].type = type; + num_special_pds++; +} + +static void __init get_special_pds(void) +{ + struct device_node *np; + const struct of_device_id *id; + + /* PM domains containing CPUs */ + for_each_of_cpu_node(np) + add_special_pd(np, PD_CPU); + + /* PM domain containing console */ + if (of_stdout) + add_special_pd(of_stdout, PD_CONSOLE); + + /* PM domains containing other special devices */ + for_each_matching_node_and_match(np, special_ids, &id) + add_special_pd(np, (uintptr_t)id->data); +} + +static void __init put_special_pds(void) +{ + unsigned int i; + + for (i = 0; i < num_special_pds; i++) + of_node_put(special_pds[i].pd); +} + +static enum pd_types __init pd_type(const struct device_node *pd) +{ + unsigned int i; + + for (i = 0; i < num_special_pds; i++) + if (pd == special_pds[i].pd) + return special_pds[i].type; + + return PD_NORMAL; +} + +static void __init rmobile_setup_pm_domain(struct device_node *np, + struct rmobile_pm_domain *pd) +{ + const char *name = pd->genpd.name; + + switch (pd_type(np)) { + case PD_CPU: + /* + * This domain contains the CPU core and therefore it should + * only be turned off if the CPU is not in use. + */ + pr_debug("PM domain %s contains CPU\n", name); + pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON; + break; + + case PD_CONSOLE: + pr_debug("PM domain %s contains serial console\n", name); + pd->gov = &pm_domain_always_on_gov; + pd->suspend = rmobile_pd_suspend_console; + break; + + case PD_DEBUG: + /* + * This domain contains the Coresight-ETM hardware block and + * therefore it should only be turned off if the debug module + * is not in use. + */ + pr_debug("PM domain %s contains Coresight-ETM\n", name); + pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON; + break; + + case PD_MEMCTL: + /* + * This domain contains a memory-controller and therefore it + * should only be turned off if memory is not in use. + */ + pr_debug("PM domain %s contains MEMCTL\n", name); + pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON; + break; + + case PD_NORMAL: + if (pd->bit_shift == ~0) { + /* Top-level always-on domain */ + pr_debug("PM domain %s is always-on domain\n", name); + pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON; + } + break; + } + + rmobile_init_pm_domain(pd); +} + +static int __init rmobile_add_pm_domains(void __iomem *base, + struct device_node *parent, + struct generic_pm_domain *genpd_parent) +{ + for_each_child_of_node_scoped(parent, np) { + struct rmobile_pm_domain *pd; + u32 idx = ~0; + + if (of_property_read_u32(np, "reg", &idx)) { + /* always-on domain */ + } + + pd = kzalloc_obj(*pd); + if (!pd) + return -ENOMEM; + + pd->genpd.name = np->name; + pd->base = base; + pd->bit_shift = idx; + + rmobile_setup_pm_domain(np, pd); + if (genpd_parent) + pm_genpd_add_subdomain(genpd_parent, &pd->genpd); + of_genpd_add_provider_simple(np, &pd->genpd); + + rmobile_add_pm_domains(base, np, &pd->genpd); + } + return 0; +} + +static int __init rmobile_init_pm_domains(void) +{ + struct device_node *np, *pmd; + bool scanned = false; + void __iomem *base; + int ret = 0; + + for_each_compatible_node(np, NULL, "renesas,sysc-rmobile") { + base = of_iomap(np, 0); + if (!base) { + pr_warn("%pOF cannot map reg 0\n", np); + continue; + } + + pmd = of_get_child_by_name(np, "pm-domains"); + if (!pmd) { + iounmap(base); + pr_warn("%pOF lacks pm-domains node\n", np); + continue; + } + + if (!scanned) { + /* Find PM domains containing special blocks */ + get_special_pds(); + scanned = true; + } + + ret = rmobile_add_pm_domains(base, pmd, NULL); + of_node_put(pmd); + if (ret) { + of_node_put(np); + break; + } + + fwnode_dev_initialized(of_fwnode_handle(np), true); + } + + put_special_pds(); + + return ret; +} +postcore_initcall(rmobile_init_pm_domains); |
