From: nicolas.pitre@linaro.org (Nicolas Pitre)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 3/8] ARM: MB86S7X: Add MCPM support
Date: Fri, 9 Jan 2015 15:04:56 -0500 (EST) [thread overview]
Message-ID: <alpine.LFD.2.11.1501091503120.1322@knanqh.ubzr> (raw)
In-Reply-To: <1420802934-4084-1-git-send-email-Vincent.Yang@tw.fujitsu.com>
On Fri, 9 Jan 2015, Vincent Yang wrote:
> From: Jassi Brar <jaswinder.singh@linaro.org>
>
> The remote firmware(SCB) owns the SMP control. This MCPM driver gets
> CPU/CLUSTER power up/down done by SCB over mailbox.
>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
> Signed-off-by: Vincent Yang <Vincent.Yang@tw.fujitsu.com>
> Signed-off-by: Tetsuya Nuriya <nuriya.tetsuya@jp.fujitsu.com>
Once the initcall issue raised by Russell is fixed you can add:
Reviewed-by: Nicolas Pitre <nico@linaro.org>
> ---
> arch/arm/mach-mb86s7x/Makefile | 4 +-
> arch/arm/mach-mb86s7x/mcpm.c | 315 +++++++++++++++++++++++++++++++++++++++++
> arch/arm/mach-mb86s7x/smc.S | 27 ++++
> drivers/soc/mb86s7x/scb_mhu.c | 14 ++
> include/soc/mb86s7x/scb_mhu.h | 8 ++
> 5 files changed, 367 insertions(+), 1 deletion(-)
> create mode 100644 arch/arm/mach-mb86s7x/mcpm.c
> create mode 100644 arch/arm/mach-mb86s7x/smc.S
>
> diff --git a/arch/arm/mach-mb86s7x/Makefile b/arch/arm/mach-mb86s7x/Makefile
> index 97640b6..00e843c 100644
> --- a/arch/arm/mach-mb86s7x/Makefile
> +++ b/arch/arm/mach-mb86s7x/Makefile
> @@ -1 +1,3 @@
> -obj-$(CONFIG_ARCH_MB86S7X) += board.o
> +obj-$(CONFIG_ARCH_MB86S7X) += board.o mcpm.o smc.o
> +CFLAGS_smc.o += -march=armv7-a
> +CFLAGS_mcpm.o += -march=armv7-a
> diff --git a/arch/arm/mach-mb86s7x/mcpm.c b/arch/arm/mach-mb86s7x/mcpm.c
> new file mode 100644
> index 0000000..c278c6e
> --- /dev/null
> +++ b/arch/arm/mach-mb86s7x/mcpm.c
> @@ -0,0 +1,315 @@
> +/*
> + * arch/arm/mach-mb86s7x/mcpm.c
> + * Copyright: (C) 2013-2015 Fujitsu Semiconductor Limited
> + * Copyright: (C) 2015 Linaro Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/io.h>
> +#include <linux/pm.h>
> +#include <linux/delay.h>
> +#include <linux/cpu_pm.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/arm-cci.h>
> +#include <linux/spinlock.h>
> +#include <linux/suspend.h>
> +#include <linux/of_device.h>
> +#include <linux/irqchip/arm-gic.h>
> +#include <linux/platform_device.h>
> +
> +#include <soc/mb86s7x/scb_mhu.h>
> +
> +#include <asm/mcpm.h>
> +#include <asm/cp15.h>
> +#include <asm/cputype.h>
> +#include <asm/suspend.h>
> +#include <asm/idmap.h>
> +
> +#define S7X_MAX_CLUSTER 2
> +#define S7X_MAX_CPU 2
> +
> +#define MHU_SHM_OFFSET 0x3800
> +#define TRAMPOLINE_OFFSET 0x3c00
> +#define RESET_OFFSET (TRAMPOLINE_OFFSET + 0x3fc)
> +
> +static arch_spinlock_t mb86s7x_pm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
> +static int mb86s7x_pm_use_count[S7X_MAX_CLUSTER][S7X_MAX_CPU];
> +
> +struct mb86s7x_cpu_gate {
> + u32 payload_size;
> + u32 cluster_class;
> + u32 cluster_id;
> + u32 cpu_id;
> +#define SCB_CPU_STATE_OFF 0x0
> +#define SCB_CPU_STATE_ON 0x1
> +#define SCB_CPU_STATE_SUSP 0x2
> + u32 cpu_state;
> +};
> +
> +static int mb86s7x_pm_power_up(unsigned int cpu, unsigned int cluster)
> +{
> + int ret = 0;
> +
> + if (cluster >= S7X_MAX_CLUSTER || cpu >= S7X_MAX_CPU)
> + return -EINVAL;
> +
> + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> +
> + local_irq_disable();
> + arch_spin_lock(&mb86s7x_pm_lock);
> +
> + mb86s7x_pm_use_count[cluster][cpu]++;
> +
> + if (mb86s7x_pm_use_count[cluster][cpu] == 1) {
> + struct mb86s7x_cpu_gate cmd;
> +
> + mb86s7x_set_wficolor(cluster, cpu, AT_WFI_DO_NOTHING);
> + arch_spin_unlock(&mb86s7x_pm_lock);
> + local_irq_enable();
> +
> + cmd.payload_size = sizeof(cmd);
> + cmd.cluster_class = 0;
> + cmd.cluster_id = cluster;
> + cmd.cpu_id = cpu;
> + cmd.cpu_state = SCB_CPU_STATE_ON;
> +
> + pr_debug("%s:%d CMD Cl_Class-%u CL_ID-%u CPU_ID-%u STATE-%u}\n",
> + __func__, __LINE__, cmd.cluster_class,
> + cmd.cluster_id, cmd.cpu_id, cmd.cpu_state);
> +
> + ret = mb86s7x_send_packet(CMD_CPU_CLOCK_GATE_SET_REQ,
> + &cmd, sizeof(cmd));
> + if (ret < 0) {
> + pr_err("%s:%d failed!\n", __func__, __LINE__);
> + return ret;
> + }
> +
> + pr_debug("%s:%d REP Cl_Class-%u CL_ID-%u CPU_ID-%u STATE-%u}\n",
> + __func__, __LINE__, cmd.cluster_class,
> + cmd.cluster_id, cmd.cpu_id, cmd.cpu_state);
> +
> + if (cmd.cpu_state != SCB_CPU_STATE_ON)
> + return -ENODEV;
> + } else if (mb86s7x_pm_use_count[cluster][cpu] == 2) {
> + arch_spin_unlock(&mb86s7x_pm_lock);
> + local_irq_enable();
> + } else {
> + /*
> + * The only possible values are:
> + * 0 = CPU down
> + * 1 = CPU (still) up
> + * 2 = CPU requested to be up before it had a chance
> + * to actually make itself down.
> + * Any other value is a bug.
> + */
> + BUG();
> + }
> +
> + return 0;
> +}
> +
> +static void mb86s7x_pm_suspend(u64 ignored)
> +{
> + unsigned int mpidr, cpu, cluster;
> + bool last_man = false, skip_wfi = false;
> +
> + mpidr = read_cpuid_mpidr();
> + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +
> + pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> + __mcpm_cpu_going_down(cpu, cluster);
> +
> + arch_spin_lock(&mb86s7x_pm_lock);
> + BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
> +
> + mb86s7x_pm_use_count[cluster][cpu]--;
> +
> + if (mb86s7x_pm_use_count[cluster][cpu] == 0) {
> + if (!mb86s7x_pm_use_count[cluster][0] &&
> + !mb86s7x_pm_use_count[cluster][1])
> + last_man = true;
> + mb86s7x_set_wficolor(cluster, cpu, AT_WFI_DO_POWEROFF);
> + } else if (mb86s7x_pm_use_count[cluster][cpu] == 1) {
> + skip_wfi = true; /* Overtaken by a power up */
> + } else {
> + BUG();
> + }
> +
> + if (!skip_wfi)
> + gic_cpu_if_down();
> +
> + if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
> + arch_spin_unlock(&mb86s7x_pm_lock);
> +
> + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) {
> + /*
> + * On the Cortex-A15 we need to disable
> + * L2 prefetching before flushing the cache.
> + */
> + asm volatile(
> + "mcr p15, 1, %0, c15, c0, 3\n\t"
> + "isb\n\t"
> + "dsb"
> + : : "r" (0x400));
> + }
> +
> + v7_exit_coherency_flush(all);
> +
> + cci_disable_port_by_cpu(mpidr);
> +
> + __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
> + } else {
> + arch_spin_unlock(&mb86s7x_pm_lock);
> + v7_exit_coherency_flush(louis);
> + }
> +
> + __mcpm_cpu_down(cpu, cluster);
> +
> + /* Now we are prepared for power-down, do it: */
> + if (!skip_wfi)
> + wfi();
> +}
> +
> +static void mb86s7x_pm_power_down(void)
> +{
> + mb86s7x_pm_suspend(0);
> +}
> +
> +static int mb86s7x_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
> +{
> + struct mb86s7x_cpu_gate cmd;
> + int i, ret;
> +
> + BUG_ON(cluster >= S7X_MAX_CLUSTER || cpu >= S7X_MAX_CPU);
> +
> + cmd.payload_size = sizeof(cmd);
> + cmd.cluster_class = 0;
> + cmd.cluster_id = cluster;
> + cmd.cpu_id = cpu;
> + cmd.cpu_state = SCB_CPU_STATE_ON;
> +
> + for (i = 0; i < 50; i++) {
> + ret = mb86s7x_send_packet(CMD_CPU_CLOCK_GATE_GET_REQ,
> + &cmd, sizeof(cmd));
> + if (ret < 0) {
> + pr_err("%s:%d failed to get CPU status\n",
> + __func__, __LINE__);
> + return ret;
> + }
> +
> + pr_debug("%s:%d Cl_Class-%u CL_ID-%u CPU_ID-%u STATE-%u\n",
> + __func__, __LINE__,
> + cmd.cluster_class, cmd.cluster_id,
> + cmd.cpu_id, cmd.cpu_state);
> +
> + if (cmd.cpu_state == SCB_CPU_STATE_OFF)
> + return 0;
> +
> + msleep(20);
> + }
> +
> + return -ETIMEDOUT;
> +}
> +
> +static void mb86s7x_pm_powered_up(void)
> +{
> + unsigned int mpidr, cpu, cluster;
> +
> + mpidr = read_cpuid_mpidr();
> + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +
> + arch_spin_lock(&mb86s7x_pm_lock);
> + if (!mb86s7x_pm_use_count[cluster][cpu])
> + mb86s7x_pm_use_count[cluster][cpu] = 1;
> + arch_spin_unlock(&mb86s7x_pm_lock);
> +}
> +
> +static const struct mcpm_platform_ops mb86s7x_pm_power_ops = {
> + .power_up = mb86s7x_pm_power_up,
> + .power_down = mb86s7x_pm_power_down,
> + .wait_for_powerdown = mb86s7x_wait_for_powerdown,
> + .suspend = mb86s7x_pm_suspend,
> + .powered_up = mb86s7x_pm_powered_up,
> +};
> +
> +/*
> + * Enable cluster-level coherency, in preparation for turning on the MMU.
> + */
> +static void __naked mb86s7x_pm_power_up_setup(unsigned int affinity_level)
> +{
> + asm volatile ("\n"
> +" cmp r0, #1\n"
> +" bxne lr\n"
> +" b cci_enable_port_for_self");
> +}
> +
> +static void __init mb86s7x_cache_off(void)
> +{
> + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) {
> + /* disable L2 prefetching on the Cortex-A15 */
> + asm volatile(
> + "mcr p15, 1, %0, c15, c0, 3\n\t"
> + "isb\n\t"
> + "dsb"
> + : : "r" (0x400));
> + }
> + v7_exit_coherency_flush(all);
> +}
> +
> +struct mb86s7x_scb_version {
> + u32 payload_size;
> + u32 version;
> + u32 config_version;
> +};
> +
> +static int __init mb86s7x_mcpm_init(void)
> +{
> + unsigned int mpidr, cpu, cluster;
> + struct mb86s7x_scb_version cmd;
> + int ret;
> +
> + if (!cci_probed())
> + return -ENODEV;
> +
> + mpidr = read_cpuid_mpidr();
> + cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> + cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> +
> + pr_info("Booting on cpu_%u cluster_%u\n", cpu, cluster);
> + mb86s7x_pm_use_count[cluster][cpu] = 1;
> +
> + /* reset the wfi 'color' for primary cpu */
> + mb86s7x_set_wficolor(cluster, cpu, AT_WFI_DO_NOTHING);
> +
> + /* Do SMC to set entry address for CPUs coming online */
> + mb86s7x_cpu_entry(virt_to_phys(mcpm_entry_point));
> +
> + cmd.payload_size = sizeof(cmd);
> + cmd.version = 0;
> + cmd.config_version = 0;
> + ret = mb86s7x_send_packet(CMD_SCB_CAPABILITY_GET_REQ,
> + &cmd, sizeof(cmd));
> + if (ret < 0) /* non fatal */
> + pr_err("%s:%d failed to get SCB version\n",
> + __func__, __LINE__);
> + else
> + pr_err("MB86S7x SCB version 0x%x:0x%x\n",
> + cmd.version, cmd.config_version);
> +
> + ret = mcpm_platform_register(&mb86s7x_pm_power_ops);
> + if (!ret)
> + ret = mcpm_sync_init(mb86s7x_pm_power_up_setup);
> + if (!ret)
> + ret = mcpm_loopback(mb86s7x_cache_off); /* turn on the CCI */
> + if (!ret)
> + mcpm_smp_set_ops();
> +
> + return ret;
> +}
> +early_initcall(mb86s7x_mcpm_init);
> diff --git a/arch/arm/mach-mb86s7x/smc.S b/arch/arm/mach-mb86s7x/smc.S
> new file mode 100644
> index 0000000..3ffe4f7
> --- /dev/null
> +++ b/arch/arm/mach-mb86s7x/smc.S
> @@ -0,0 +1,27 @@
> +/*
> + * SMC command interface to set secondary entry point
> + * Copyright: (C) 2013-2015 Fujitsu Semiconductor Limited
> + * Copyright: (C) 2015 Linaro Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/linkage.h>
> +
> +.arch_extension sec
> +
> +/* void mb86s7x_cpu_entry(unsigned long secondary_entry); */
> +ENTRY(mb86s7x_cpu_entry)
> + stmfd sp!, {r1-r11, lr}
> + mov r1, r0
> + ldr r0, =1
> + mrc p15, 0, r3, c1, c0, 0
> + mov r4, r3
> + and r3, #0xbfffffff
> + mcr p15, 0, r3, c1, c0, 0
> + smc #0
> + mcr p15, 0, r4, c1, c0, 0
> + ldmfd sp!, {r1-r11, pc}
> +ENDPROC(mb86s7x_cpu_entry)
> diff --git a/drivers/soc/mb86s7x/scb_mhu.c b/drivers/soc/mb86s7x/scb_mhu.c
> index 08a3c88..a86ed0a 100644
> --- a/drivers/soc/mb86s7x/scb_mhu.c
> +++ b/drivers/soc/mb86s7x/scb_mhu.c
> @@ -89,6 +89,20 @@ static struct mhu_xfer {
> struct list_head node;
> } *ax; /* stages of xfer */
>
> +#define WFI_COLOR_OFFSET 0x3f00
> +
> +void mb86s7x_set_wficolor(unsigned clstr, unsigned cpu, unsigned clr)
> +{
> + u8 val;
> +
> + val = readb_relaxed(mb86s7x_shm_base
> + + WFI_COLOR_OFFSET + clstr * 2 + cpu);
> + val &= ~AT_WFI_COLOR_MASK;
> + val |= clr;
> + writeb_relaxed(val, mb86s7x_shm_base
> + + WFI_COLOR_OFFSET + clstr * 2 + cpu);
> +}
> +
> static int mhu_alloc_xfers(int n, struct list_head *list)
> {
> struct mhu_xfer *x = kcalloc(n, sizeof(struct mhu_xfer), GFP_ATOMIC);
> diff --git a/include/soc/mb86s7x/scb_mhu.h b/include/soc/mb86s7x/scb_mhu.h
> index 334fa9f..f792950 100644
> --- a/include/soc/mb86s7x/scb_mhu.h
> +++ b/include/soc/mb86s7x/scb_mhu.h
> @@ -87,6 +87,14 @@ enum {
> #define CMD_POWERDOMAIN_SET_REP ENC_REP(CMD_POWERDOMAIN_SET_REQ)
> #define CMD_STG_BLOCK_ERASE_REP ENC_REP(CMD_STG_BLOCK_ERASE_REQ)
>
> +#define AT_WFI_DO_NOTHING 0x0
> +#define AT_WFI_DO_SUSPEND 0x1
> +#define AT_WFI_DO_POWEROFF 0x2
> +#define AT_WFI_COLOR_MASK 0x3
> +
> +void mb86s7x_set_wficolor(unsigned clstr, unsigned cpu, unsigned clr);
> +void mb86s7x_cpu_entry(unsigned long secondary_entry);
> +
> /* Helper functions to talk to remote */
> int mb86s7x_send_packet(int cmd, void *buf, int len);
>
> --
> 1.9.0
>
>
next prev parent reply other threads:[~2015-01-09 20:04 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-09 11:19 [PATCH v3 0/8] Support for Fujitsu MB86S7X SoCs Vincent Yang
2015-01-09 11:19 ` Vincent Yang
[not found] ` <1420802369-3840-1-git-send-email-Vincent.Yang-l16TxrwUIHTQFUHtdCDX3A@public.gmane.org>
2015-01-09 11:24 ` [PATCH v3 1/8] ARM: Add platform support " Vincent Yang
2015-01-09 11:24 ` Vincent Yang
2015-01-09 11:28 ` [PATCH v3 2/8] mailbox: arm_mhu: add driver for ARM MHU controller Vincent Yang
2015-01-09 11:28 ` Vincent Yang
[not found] ` <1420802889-4041-1-git-send-email-Vincent.Yang-l16TxrwUIHTQFUHtdCDX3A@public.gmane.org>
2015-01-09 12:51 ` Russell King - ARM Linux
2015-01-09 12:51 ` Russell King - ARM Linux
[not found] ` <20150109125102.GL12302-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
2015-01-09 13:19 ` Jassi Brar
2015-01-09 13:19 ` Jassi Brar
2015-01-09 15:24 ` Russell King - ARM Linux
2015-01-09 15:24 ` Russell King - ARM Linux
[not found] ` <20150109152402.GQ12302-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
2015-01-09 15:29 ` Jassi Brar
2015-01-09 15:29 ` Jassi Brar
2015-01-09 11:29 ` [PATCH v3 4/8] clk: Add clock driver for mb86s7x Vincent Yang
2015-01-09 11:29 ` Vincent Yang
[not found] ` <1420802977-4126-1-git-send-email-Vincent.Yang-l16TxrwUIHTQFUHtdCDX3A@public.gmane.org>
2015-01-09 12:39 ` Russell King - ARM Linux
2015-01-09 12:39 ` Russell King - ARM Linux
[not found] ` <20150109123958.GJ12302-l+eeeJia6m9vn6HldHNs0ANdhmdF6hFW@public.gmane.org>
2015-01-09 13:03 ` Jassi Brar
2015-01-09 13:03 ` Jassi Brar
2015-01-09 11:35 ` [PATCH v3 7/8] of: add Fujitsu vendor prefix Vincent Yang
2015-01-09 11:35 ` Vincent Yang
2015-01-09 11:28 ` [PATCH v3 3/8] ARM: MB86S7X: Add MCPM support Vincent Yang
2015-01-09 12:41 ` Russell King - ARM Linux
2015-01-09 13:23 ` Jassi Brar
2015-01-09 20:04 ` Nicolas Pitre [this message]
2015-01-09 11:33 ` [PATCH v3 5/8] gpio: Add Fujitsu MB86S7x GPIO driver Vincent Yang
2015-01-09 11:33 ` Vincent Yang
[not found] ` <1420803212-4350-1-git-send-email-Vincent.Yang-l16TxrwUIHTQFUHtdCDX3A@public.gmane.org>
2015-01-09 12:52 ` Russell King - ARM Linux
2015-01-09 12:52 ` Russell King - ARM Linux
2015-01-09 13:20 ` Jassi Brar
2015-01-09 13:20 ` Jassi Brar
2015-01-11 22:40 ` Linus Walleij
2015-01-11 22:40 ` Linus Walleij
2015-01-12 0:04 ` Linus Walleij
2015-01-12 0:04 ` Linus Walleij
2015-01-09 11:34 ` [PATCH v3 6/8] dt: mb86s7x: add dt files for MB86S7x evbs Vincent Yang
2015-01-09 11:34 ` Vincent Yang
2015-01-09 11:36 ` [PATCH v3 8/8] ARM: MB86S7x: Add configs Vincent Yang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=alpine.LFD.2.11.1501091503120.1322@knanqh.ubzr \
--to=nicolas.pitre@linaro.org \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.