18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  arch/arm/mach-sti/platsmp.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
68c2ecf20Sopenharmony_ci *		http://www.st.com
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Cloned from linux/arch/arm/mach-vexpress/platsmp.c
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  Copyright (C) 2002 ARM Ltd.
118c2ecf20Sopenharmony_ci *  All Rights Reserved
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/errno.h>
158c2ecf20Sopenharmony_ci#include <linux/delay.h>
168c2ecf20Sopenharmony_ci#include <linux/smp.h>
178c2ecf20Sopenharmony_ci#include <linux/io.h>
188c2ecf20Sopenharmony_ci#include <linux/of.h>
198c2ecf20Sopenharmony_ci#include <linux/of_address.h>
208c2ecf20Sopenharmony_ci#include <linux/memblock.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <asm/cacheflush.h>
238c2ecf20Sopenharmony_ci#include <asm/smp_plat.h>
248c2ecf20Sopenharmony_ci#include <asm/smp_scu.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "smp.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic u32 __iomem *cpu_strt_ptr;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic int sti_boot_secondary(unsigned int cpu, struct task_struct *idle)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	unsigned long entry_pa = __pa_symbol(secondary_startup);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	/*
358c2ecf20Sopenharmony_ci	 * Secondary CPU is initialised and started by a U-BOOTROM firmware.
368c2ecf20Sopenharmony_ci	 * Secondary CPU is spinning and waiting for a write at cpu_strt_ptr.
378c2ecf20Sopenharmony_ci	 * Writing secondary_startup address at cpu_strt_ptr makes it to
388c2ecf20Sopenharmony_ci	 * jump directly to secondary_startup().
398c2ecf20Sopenharmony_ci	 */
408c2ecf20Sopenharmony_ci	__raw_writel(entry_pa, cpu_strt_ptr);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	/* wmb so that data is actually written before cache flush is done */
438c2ecf20Sopenharmony_ci	smp_wmb();
448c2ecf20Sopenharmony_ci	sync_cache_w(cpu_strt_ptr);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	return 0;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic void __init sti_smp_prepare_cpus(unsigned int max_cpus)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct device_node *np;
528c2ecf20Sopenharmony_ci	void __iomem *scu_base;
538c2ecf20Sopenharmony_ci	u32 release_phys;
548c2ecf20Sopenharmony_ci	int cpu;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (np) {
598c2ecf20Sopenharmony_ci		scu_base = of_iomap(np, 0);
608c2ecf20Sopenharmony_ci		scu_enable(scu_base);
618c2ecf20Sopenharmony_ci		of_node_put(np);
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if (max_cpus <= 1)
658c2ecf20Sopenharmony_ci		return;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	for_each_possible_cpu(cpu) {
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci		np = of_get_cpu_node(cpu, NULL);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci		if (!np)
728c2ecf20Sopenharmony_ci			continue;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		if (of_property_read_u32(np, "cpu-release-addr",
758c2ecf20Sopenharmony_ci						&release_phys)) {
768c2ecf20Sopenharmony_ci			pr_err("CPU %d: missing or invalid cpu-release-addr "
778c2ecf20Sopenharmony_ci				"property\n", cpu);
788c2ecf20Sopenharmony_ci			continue;
798c2ecf20Sopenharmony_ci		}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci		/*
828c2ecf20Sopenharmony_ci		 * cpu-release-addr is usually configured in SBC DMEM but can
838c2ecf20Sopenharmony_ci		 * also be in RAM.
848c2ecf20Sopenharmony_ci		 */
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		if (!memblock_is_memory(release_phys))
878c2ecf20Sopenharmony_ci			cpu_strt_ptr =
888c2ecf20Sopenharmony_ci				ioremap(release_phys, sizeof(release_phys));
898c2ecf20Sopenharmony_ci		else
908c2ecf20Sopenharmony_ci			cpu_strt_ptr =
918c2ecf20Sopenharmony_ci				(u32 __iomem *)phys_to_virt(release_phys);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		set_cpu_possible(cpu, true);
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ciconst struct smp_operations sti_smp_ops __initconst = {
988c2ecf20Sopenharmony_ci	.smp_prepare_cpus	= sti_smp_prepare_cpus,
998c2ecf20Sopenharmony_ci	.smp_boot_secondary	= sti_boot_secondary,
1008c2ecf20Sopenharmony_ci};
101