blob: 33e79bd720d8f576bd2fb948cc3cc68177a2ba6c [file] [log] [blame]
/*
 * Copyright (c) 2016, 2020, The Linux Foundation. All rights reserved.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* IPQ ARMv8 CPU Operations
* Based on arch/arm64/kernel/smp_spin_table.c
*/
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/smp.h>
#include <linux/types.h>
#include <asm/cacheflush.h>
#include <asm/cpu_ops.h>
#include <asm/cputype.h>
#include <asm/smp_plat.h>
#include <linux/qcom_scm.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
extern void a53ss_unclamp_cpu(void __iomem *reg);
static DEFINE_SPINLOCK(boot_lock);
static DEFINE_PER_CPU(int, cold_boot_done);
static int a53ss_release_secondary(unsigned int cpu)
{
int ret = 0;
struct device_node *cpu_node, *acc_node;
void __iomem *reg;
cpu_node = of_get_cpu_node(cpu, NULL);
if (!cpu_node)
return -ENODEV;
acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0);
if (!acc_node) {
ret = -ENODEV;
goto err_cpu_node;
}
reg = of_iomap(acc_node, 0);
if (!reg) {
ret = -ENOMEM;
goto err_acc_node;
}
a53ss_unclamp_cpu(reg);
per_cpu(cold_boot_done, cpu) = true;
/* Secondary CPU-N is now alive */
iounmap(reg);
err_acc_node:
of_node_put(acc_node);
err_cpu_node:
of_node_put(cpu_node);
return ret;
}
static void qti_wake_cpu(unsigned int cpu)
{
spin_lock(&boot_lock);
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
spin_unlock(&boot_lock);
}
static int qti_boot_cpu(unsigned int cpu, int (*func)(unsigned int))
{
int ret = 0;
if (!per_cpu(cold_boot_done, cpu)) {
ret = func(cpu);
}
qti_wake_cpu(cpu);
return ret;
}
static int __init qti_cpu_init(unsigned int cpu)
{
return 0;
}
static int __init qti_cpu_prepare(unsigned int cpu)
{
return 0;
}
static int a53ss_cpu_boot(unsigned int cpu)
{
return qti_boot_cpu(cpu, a53ss_release_secondary);
}
void qti_cpu_postboot(void)
{
}
#ifdef CONFIG_HOTPLUG_CPU
static void a53ss_wfi_cpu_die(unsigned int cpu)
{
}
#endif
struct cpu_operations smp_a53ss_ops = {
.name = "qcom,arm-cortex-acc",
.cpu_init = qti_cpu_init,
.cpu_prepare = qti_cpu_prepare,
.cpu_boot = a53ss_cpu_boot,
.cpu_postboot = qti_cpu_postboot,
#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = a53ss_wfi_cpu_die,
#endif
};
CPU_METHOD_OF_DECLARE(qcom_smp_a53ss, "qcom,arm-cortex-acc", &smp_a53ss_ops);