Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3745b59 authored by Abhimanyu Kapur's avatar Abhimanyu Kapur Committed by Matt Wagantall
Browse files

soc: qcom: Add cpu_ops snapshot



This is a snapshot of the cpu_ops driver as of
msm-3.14 commit:

3bc54cf86bdc7affa7cd4bf7faa3c57fe8f8819d (Merge "msm:
camera: Add dummy sub module in sensor pipeline")

Update documentation to reflect msm8996 ops.

Signed-off-by: default avatarAbhimanyu Kapur <abhimany@codeaurora.org>
parent a0ace6a6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -184,6 +184,8 @@ nodes to be present and contain the properties described below.
			  be one of:
			     "psci"
			     "spin-table"
			     "qcom,msm8996-acc"

			# On ARM 32-bit systems this property is optional and
			  can be one of:
			    "allwinner,sun6i-a31"
+19 −0
Original line number Diff line number Diff line
Application Processor Sub-system (APSS) Application Clock Controller (ACC)

The ACC provides clock, power domain, and reset control to a CPU. There is one ACC
register region per CPU within the APSS remapped region as well as an alias register
region that remaps accesses to the ACC associated with the CPU accessing the region.

Required properties:
- compatible:		Must be "qcom,arm-cortex-acc" or "qcom,msm8996-acc"
- reg:			The first element specifies the base address and size of
			the register region. An optional second element specifies
			the base address and size of the alias register region.

Example:

	clock-controller@b088000 {
		compatible = "qcom,arm-cortex-acc";
		reg = <0x0b088000 0x1000>,
		      <0x0b008000 0x1000>;
	}
+0 −1
Original line number Diff line number Diff line
@@ -396,7 +396,6 @@ ENTRY(secondary_holding_pen)
pen:	ldr	x4, [x3]
	cmp	x4, x0
	b.eq	secondary_startup
	wfe
	b	pen
ENDPROC(secondary_holding_pen)

+1 −1
Original line number Diff line number Diff line
obj-$(CONFIG_ARM64) += cpu_ops.o
obj-$(CONFIG_MSM_BOOT_STATS) += boot_stats.o
obj-$(CONFIG_QCOM_GSBI)	+=	qcom_gsbi.o
obj-$(CONFIG_MSM_MEMORY_DUMP) += memory_dump.o
obj-$(CONFIG_MSM_MEMORY_DUMP_V2) += memory_dump_v2.o
obj-$(CONFIG_MSM_WATCHDOG_V2) += watchdog_v2.o
obj-$(CONFIG_MSM_CPU_PWR_CTL) += cpu_pwr_ctl.o
obj-$(CONFIG_ARM64) += cpu_ops.o
+291 −0
Original line number Diff line number Diff line
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013 ARM 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 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

/* MSM ARMv8 CPU Operations
 * Based on arch/arm64/kernel/smp_spin_table.c
 */

#include <linux/bitops.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/smp.h>

#include <soc/qcom/cpu_pwr_ctl.h>
#include <soc/qcom/scm-boot.h>
#include <soc/qcom/socinfo.h>
#include <soc/qcom/pm.h>
#include <soc/qcom/spm.h>
#include <soc/qcom/jtag.h>

#include <asm/barrier.h>
#include <asm/cacheflush.h>
#include <asm/cpu_ops.h>
#include <asm/cputype.h>
#include <asm/smp_plat.h>

static DEFINE_RAW_SPINLOCK(boot_lock);

DEFINE_PER_CPU(int, cold_boot_done);

static int cold_boot_flags[] = {
	0,
	SCM_FLAG_COLDBOOT_CPU1,
	SCM_FLAG_COLDBOOT_CPU2,
	SCM_FLAG_COLDBOOT_CPU3,
};

static void write_pen_release(u64 val)
{
	void *start = (void *)&secondary_holding_pen_release;
	unsigned long size = sizeof(secondary_holding_pen_release);

	secondary_holding_pen_release = val;
	smp_wmb();
	__flush_dcache_area(start, size);
}

static int secondary_pen_release(unsigned int cpu)
{
	unsigned long timeout;

	/*
	 * Set synchronisation state between this boot processor
	 * and the secondary one
	 */
	raw_spin_lock(&boot_lock);
	write_pen_release(cpu_logical_map(cpu));

	/*
	 * Wake-up cpu with am IPI
	 */
	arch_send_wakeup_ipi_mask(cpumask_of(cpu));

	timeout = jiffies + (1 * HZ);
	while (time_before(jiffies, timeout)) {
		if (secondary_holding_pen_release == INVALID_HWID)
			break;
		udelay(10);
	}
	raw_spin_unlock(&boot_lock);

	return secondary_holding_pen_release != INVALID_HWID ? -ENOSYS : 0;
}

static int __init msm_cpu_init(struct device_node *dn, unsigned int cpu)
{
	return 0;
}

static int __init msm_cpu_prepare(unsigned int cpu)
{
	u64 mpidr_el1 = cpu_logical_map(cpu);

	if (scm_is_mc_boot_available()) {

		if (mpidr_el1 & ~MPIDR_HWID_BITMASK) {
			pr_err("CPU%d:Failed to set boot address\n", cpu);
			return -ENOSYS;
		}

		if (scm_set_boot_addr_mc(virt_to_phys(secondary_holding_pen),
				BIT(MPIDR_AFFINITY_LEVEL(mpidr_el1, 0)),
				BIT(MPIDR_AFFINITY_LEVEL(mpidr_el1, 1)),
				BIT(MPIDR_AFFINITY_LEVEL(mpidr_el1, 2)),
				SCM_FLAG_COLDBOOT_MC)) {
			pr_warn("CPU%d:Failed to set boot address\n", cpu);
			return -ENOSYS;
		}

	} else {
		if (scm_set_boot_addr(virt_to_phys(secondary_holding_pen),
			cold_boot_flags[cpu])) {
			pr_warn("Failed to set CPU %u boot address\n", cpu);
			return -ENOSYS;
		}
	}

	/* Mark CPU0 cold boot flag as done */
	if (per_cpu(cold_boot_done, 0) == false)
		per_cpu(cold_boot_done, 0) = true;

	return 0;
}


static int __init msm8994_cpu_prepare(unsigned int cpu)
{
	int ret;

	if (per_cpu(cold_boot_done, 0) == false) {
		ret = msm8994_cpu_ldo_config(0);
		if (ret)
			return ret;
	}

	return msm_cpu_prepare(cpu);
}

static int msm_cpu_boot(unsigned int cpu)
{
	int ret = 0;

	if (per_cpu(cold_boot_done, cpu) == false) {
		if (of_board_is_sim()) {
			ret = msm_unclamp_secondary_arm_cpu_sim(cpu);
			if (ret)
				return ret;
		} else {
			ret = msm_unclamp_secondary_arm_cpu(cpu);
			if (ret)
				return ret;
		}
		per_cpu(cold_boot_done, cpu) = true;
	}
	return secondary_pen_release(cpu);
}

static int msm8994_cpu_boot(unsigned int cpu)
{
	int ret = 0;

	if (per_cpu(cold_boot_done, cpu) == false) {
		if (of_board_is_sim()) {
			ret = msm_unclamp_secondary_arm_cpu_sim(cpu);
			if (ret)
				return ret;
		} else {
			ret = msm8994_unclamp_secondary_arm_cpu(cpu);
			if (ret)
				return ret;
		}
		ret = msm8994_cpu_ldo_config(cpu);
		if (ret)
			return ret;
		per_cpu(cold_boot_done, cpu) = true;
	}
	return secondary_pen_release(cpu);
}

static int __init msm8996_cpu_prepare(unsigned int cpu)
{
	int ret;

	if (per_cpu(cold_boot_done, 0) == false) {
		ret = msm8996_cpuss_pm_init(0);
		if (ret)
			return ret;
	}

	return msm_cpu_prepare(cpu);
}

static int msm8996_cpu_boot(unsigned int cpu)
{
	int ret = 0;

	if (per_cpu(cold_boot_done, cpu) == false) {
		ret = msm8996_unclamp_secondary_arm_cpu(cpu);
		if (ret)
			return ret;

		per_cpu(cold_boot_done, cpu) = true;
	}
	return secondary_pen_release(cpu);
}

void msm_cpu_postboot(void)
{
	msm_jtag_restore_state();
	/*
	 * Let the primary processor know we're out of the pen.
	 */
	write_pen_release(INVALID_HWID);

	msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING, false);

	/*
	 * Synchronise with the boot thread.
	 */
	raw_spin_lock(&boot_lock);
	raw_spin_unlock(&boot_lock);
}

#ifdef CONFIG_HOTPLUG_CPU
static void msm_wfi_cpu_die(unsigned int cpu)
{
	if (unlikely(cpu != smp_processor_id())) {
		pr_crit("%s: running on %u, should be %u\n",
			__func__, smp_processor_id(), cpu);
		BUG();
	}
	for (;;) {
		lpm_cpu_hotplug_enter(cpu);
		if (secondary_holding_pen_release == cpu_logical_map(cpu)) {
			/*Proper wake up */
			break;
		}
		pr_debug("CPU%u: spurious wakeup call\n", cpu);
		BUG();
	}
}

static int msm_cpu_kill(unsigned int cpu)
{
	return msm_pm_wait_cpu_shutdown(cpu) ? 0 : 1;
}
#endif

static const struct cpu_operations msm_cortex_a_ops = {
	.name		= "qcom,arm-cortex-acc",
	.cpu_init	= msm_cpu_init,
	.cpu_prepare	= msm_cpu_prepare,
	.cpu_boot	= msm_cpu_boot,
	.cpu_postboot	= msm_cpu_postboot,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_die        = msm_wfi_cpu_die,
#endif
	.cpu_suspend       = msm_pm_collapse,
};
CPU_METHOD_OF_DECLARE(msm_cortex_a_ops, &msm_cortex_a_ops);

static const struct cpu_operations msm8994_cortex_a_ops = {
	.name		= "qcom,8994-arm-cortex-acc",
	.cpu_init	= msm_cpu_init,
	.cpu_prepare	= msm8994_cpu_prepare,
	.cpu_boot	= msm8994_cpu_boot,
	.cpu_postboot	= msm_cpu_postboot,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_die        = msm_wfi_cpu_die,
#endif
	.cpu_suspend       = msm_pm_collapse,
};
CPU_METHOD_OF_DECLARE(msm8994_cortex_a_ops, &msm8994_cortex_a_ops);

static const struct cpu_operations msm8996_ops = {
	.name		= "qcom,msm8996-acc",
	.cpu_init	= msm_cpu_init,
	.cpu_prepare	= msm8996_cpu_prepare,
	.cpu_boot	= msm8996_cpu_boot,
	.cpu_postboot	= msm_cpu_postboot,
#ifdef CONFIG_HOTPLUG_CPU
	.cpu_die        = msm_wfi_cpu_die,
	.cpu_kill	= msm_cpu_kill,
#endif
	.cpu_suspend       = msm_pm_collapse,
};
CPU_METHOD_OF_DECLARE(msm8996_ops, &msm8996_ops);