From: Yann Sionneau <ysionneau@xxxxxxxxxxxxx> The Power Controller (pwr-ctrl) controls cores reset and wake-up procedure. Co-developed-by: Clement Leger <clement@xxxxxxxxxxxxxxxx> Signed-off-by: Clement Leger <clement@xxxxxxxxxxxxxxxx> Co-developed-by: Julian Vetter <jvetter@xxxxxxxxxxxxx> Signed-off-by: Julian Vetter <jvetter@xxxxxxxxxxxxx> Co-developed-by: Louis Morhet <lmorhet@xxxxxxxxxxxxx> Signed-off-by: Louis Morhet <lmorhet@xxxxxxxxxxxxx> Co-developed-by: Marius Gligor <mgligor@xxxxxxxxxxxxx> Signed-off-by: Marius Gligor <mgligor@xxxxxxxxxxxxx> Signed-off-by: Jules Maselbas <jmaselbas@xxxxxxxx> Signed-off-by: Yann Sionneau <ysionneau@xxxxxxxxxxxxx> --- Notes: V1 -> V2: new patch V2 -> V3: - Moved driver from arch/kvx/platform to drivers/soc/kvx/ see discussions there: - https://lore.kernel.org/bpf/Y8qlOpYgDefMPqWH@xxxxxxxxx/T/#m722d8f7c7501615251e4f97705198f5485865ce2 - indent - add missing static qualifier - driver now registers a cpu_method/smp_op via CPU_METHOD_OF_DECLARE like arm and sh, it puts a struct into a __cpu_method_of_table ELF section. the smp_ops is used by smpboot.c if its name matches the DT 'cpus' node enable-method property. --- arch/kvx/include/asm/pwr_ctrl.h | 57 ++++++++++++++++++++ drivers/soc/Kconfig | 1 + drivers/soc/Makefile | 1 + drivers/soc/kvx/Kconfig | 10 ++++ drivers/soc/kvx/Makefile | 2 + drivers/soc/kvx/coolidge_pwr_ctrl.c | 84 +++++++++++++++++++++++++++++ 6 files changed, 155 insertions(+) create mode 100644 arch/kvx/include/asm/pwr_ctrl.h create mode 100644 drivers/soc/kvx/Kconfig create mode 100644 drivers/soc/kvx/Makefile create mode 100644 drivers/soc/kvx/coolidge_pwr_ctrl.c diff --git a/arch/kvx/include/asm/pwr_ctrl.h b/arch/kvx/include/asm/pwr_ctrl.h new file mode 100644 index 0000000000000..715eddd45a88c --- /dev/null +++ b/arch/kvx/include/asm/pwr_ctrl.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2017-2024 Kalray Inc. + * Author(s): Clement Leger + * Marius Gligor + * Julian Vetter + * Yann Sionneau + */ + +#ifndef _ASM_KVX_PWR_CTRL_H +#define _ASM_KVX_PWR_CTRL_H + +#ifndef __ASSEMBLY__ + +static int kvx_pwr_ctrl_probe(void); + +int kvx_pwr_ctrl_cpu_poweron(unsigned int cpu); + +#endif + +#define PWR_CTRL_ADDR 0xA40000 + +/* Power controller vector register definitions */ +#define KVX_PWR_CTRL_VEC_OFFSET 0x1000 +#define KVX_PWR_CTRL_VEC_WUP_SET_OFFSET 0x10 +#define KVX_PWR_CTRL_VEC_WUP_CLEAR_OFFSET 0x20 + +/* Power controller PE reset PC register definitions */ +#define KVX_PWR_CTRL_RESET_PC_OFFSET 0x2000 + +/* Power controller global register definitions */ +#define KVX_PWR_CTRL_GLOBAL_OFFSET 0x4040 + +#define KVX_PWR_CTRL_GLOBAL_SET_OFFSET 0x10 +#define KVX_PWR_CTRL_GLOBAL_CLEAR_OFFSET 0x20 +#define KVX_PWR_CTRL_GLOBAL_SET_PE_EN_SHIFT 0x1 + +#define PWR_CTRL_WUP_SET_OFFSET \ + (KVX_PWR_CTRL_VEC_OFFSET + \ + KVX_PWR_CTRL_VEC_WUP_SET_OFFSET) + +#define PWR_CTRL_WUP_CLEAR_OFFSET \ + (KVX_PWR_CTRL_VEC_OFFSET + \ + KVX_PWR_CTRL_VEC_WUP_CLEAR_OFFSET) + +#define PWR_CTRL_GLOBAL_CONFIG_SET_OFFSET \ + (KVX_PWR_CTRL_GLOBAL_OFFSET + \ + KVX_PWR_CTRL_GLOBAL_SET_OFFSET) + +#define PWR_CTRL_GLOBAL_CONFIG_CLEAR_OFFSET \ + (KVX_PWR_CTRL_GLOBAL_OFFSET + \ + KVX_PWR_CTRL_GLOBAL_CLEAR_OFFSET) + +#define PWR_CTRL_GLOBAL_CONFIG_PE_EN \ + (1 << KVX_PWR_CTRL_GLOBAL_SET_PE_EN_SHIFT) + +#endif /* _ASM_KVX_PWR_CTRL_H */ diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 5d924e946507b..f28078620da14 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -12,6 +12,7 @@ source "drivers/soc/fujitsu/Kconfig" source "drivers/soc/hisilicon/Kconfig" source "drivers/soc/imx/Kconfig" source "drivers/soc/ixp4xx/Kconfig" +source "drivers/soc/kvx/Kconfig" source "drivers/soc/litex/Kconfig" source "drivers/soc/loongson/Kconfig" source "drivers/soc/mediatek/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index fb2bd31387d07..240e148eaaff8 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_GEMINI) += gemini/ obj-y += hisilicon/ obj-y += imx/ obj-y += ixp4xx/ +obj-$(CONFIG_KVX) += kvx/ obj-$(CONFIG_SOC_XWAY) += lantiq/ obj-$(CONFIG_LITEX_SOC_CONTROLLER) += litex/ obj-y += loongson/ diff --git a/drivers/soc/kvx/Kconfig b/drivers/soc/kvx/Kconfig new file mode 100644 index 0000000000000..96d05efe4bfb5 --- /dev/null +++ b/drivers/soc/kvx/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 + +config COOLIDGE_POWER_CONTROLLER + bool "Coolidge power controller" + default n + depends on KVX + help + The Kalray Coolidge Power Controller is used to manage the power + state of secondary CPU cores. Currently only powering up is + supported. diff --git a/drivers/soc/kvx/Makefile b/drivers/soc/kvx/Makefile new file mode 100644 index 0000000000000..c7b0b3e99eabc --- /dev/null +++ b/drivers/soc/kvx/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_COOLIDGE_POWER_CONTROLLER) += coolidge_pwr_ctrl.o diff --git a/drivers/soc/kvx/coolidge_pwr_ctrl.c b/drivers/soc/kvx/coolidge_pwr_ctrl.c new file mode 100644 index 0000000000000..67af3e446d0e7 --- /dev/null +++ b/drivers/soc/kvx/coolidge_pwr_ctrl.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2017-2024 Kalray Inc. + * Author(s): Clement Leger + * Yann Sionneau + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/slab.h> +#include <linux/smp.h> +#include <linux/types.h> + +#include <asm/pwr_ctrl.h> +#include <asm/symbols.h> + +struct kvx_pwr_ctrl { + void __iomem *regs; +}; + +static struct kvx_pwr_ctrl kvx_pwr_controller; + +static bool pwr_ctrl_not_initialized = true; + +/** + * kvx_pwr_ctrl_cpu_poweron() - Wakeup a cpu + * @cpu: cpu to wakeup + */ +int __init kvx_pwr_ctrl_cpu_poweron(unsigned int cpu) +{ + int ret = 0; + + if (pwr_ctrl_not_initialized) { + pr_err("KVX power controller not initialized!\n"); + return -ENODEV; + } + + /* Set PE boot address */ + writeq((unsigned long long)kvx_start, + kvx_pwr_controller.regs + KVX_PWR_CTRL_RESET_PC_OFFSET); + /* Wake up processor ! */ + writeq(1ULL << cpu, + kvx_pwr_controller.regs + PWR_CTRL_WUP_SET_OFFSET); + /* Then clear wakeup to allow processor to sleep */ + writeq(1ULL << cpu, + kvx_pwr_controller.regs + PWR_CTRL_WUP_CLEAR_OFFSET); + + return ret; +} + +static const struct smp_operations coolidge_smp_ops __initconst = { + .smp_boot_secondary = kvx_pwr_ctrl_cpu_poweron, +}; + +static int __init kvx_pwr_ctrl_probe(void) +{ + struct device_node *ctrl; + + ctrl = of_find_compatible_node(NULL, NULL, "kalray,coolidge-pwr-ctrl"); + if (!ctrl) { + pr_err("Failed to get power controller node\n"); + return -EINVAL; + } + + kvx_pwr_controller.regs = of_iomap(ctrl, 0); + if (!kvx_pwr_controller.regs) { + pr_err("Failed ioremap\n"); + return -EINVAL; + } + + pwr_ctrl_not_initialized = false; + pr_info("KVX power controller probed\n"); + + return 0; +} + +CPU_METHOD_OF_DECLARE(coolidge_pwr_ctrl, "kalray,coolidge-pwr-ctrl", + &coolidge_smp_ops); + +early_initcall(kvx_pwr_ctrl_probe); -- 2.45.2