162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  arch/arm/mach-sti/platsmp.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2013 STMicroelectronics (R&D) Limited.
662306a36Sopenharmony_ci *		http://www.st.com
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Cloned from linux/arch/arm/mach-vexpress/platsmp.c
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *  Copyright (C) 2002 ARM Ltd.
1162306a36Sopenharmony_ci *  All Rights Reserved
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/errno.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/smp.h>
1762306a36Sopenharmony_ci#include <linux/io.h>
1862306a36Sopenharmony_ci#include <linux/of.h>
1962306a36Sopenharmony_ci#include <linux/of_address.h>
2062306a36Sopenharmony_ci#include <linux/memblock.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <asm/cacheflush.h>
2362306a36Sopenharmony_ci#include <asm/smp_plat.h>
2462306a36Sopenharmony_ci#include <asm/smp_scu.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include "smp.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic u32 __iomem *cpu_strt_ptr;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic int sti_boot_secondary(unsigned int cpu, struct task_struct *idle)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	unsigned long entry_pa = __pa_symbol(secondary_startup);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	/*
3562306a36Sopenharmony_ci	 * Secondary CPU is initialised and started by a U-BOOTROM firmware.
3662306a36Sopenharmony_ci	 * Secondary CPU is spinning and waiting for a write at cpu_strt_ptr.
3762306a36Sopenharmony_ci	 * Writing secondary_startup address at cpu_strt_ptr makes it to
3862306a36Sopenharmony_ci	 * jump directly to secondary_startup().
3962306a36Sopenharmony_ci	 */
4062306a36Sopenharmony_ci	__raw_writel(entry_pa, cpu_strt_ptr);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	/* wmb so that data is actually written before cache flush is done */
4362306a36Sopenharmony_ci	smp_wmb();
4462306a36Sopenharmony_ci	sync_cache_w(cpu_strt_ptr);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	return 0;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic void __init sti_smp_prepare_cpus(unsigned int max_cpus)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct device_node *np;
5262306a36Sopenharmony_ci	void __iomem *scu_base;
5362306a36Sopenharmony_ci	u32 release_phys;
5462306a36Sopenharmony_ci	int cpu;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (np) {
5962306a36Sopenharmony_ci		scu_base = of_iomap(np, 0);
6062306a36Sopenharmony_ci		scu_enable(scu_base);
6162306a36Sopenharmony_ci		of_node_put(np);
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (max_cpus <= 1)
6562306a36Sopenharmony_ci		return;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	for_each_possible_cpu(cpu) {
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci		np = of_get_cpu_node(cpu, NULL);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci		if (!np)
7262306a36Sopenharmony_ci			continue;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci		if (of_property_read_u32(np, "cpu-release-addr",
7562306a36Sopenharmony_ci						&release_phys)) {
7662306a36Sopenharmony_ci			pr_err("CPU %d: missing or invalid cpu-release-addr "
7762306a36Sopenharmony_ci				"property\n", cpu);
7862306a36Sopenharmony_ci			continue;
7962306a36Sopenharmony_ci		}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci		/*
8262306a36Sopenharmony_ci		 * cpu-release-addr is usually configured in SBC DMEM but can
8362306a36Sopenharmony_ci		 * also be in RAM.
8462306a36Sopenharmony_ci		 */
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		if (!memblock_is_memory(release_phys))
8762306a36Sopenharmony_ci			cpu_strt_ptr =
8862306a36Sopenharmony_ci				ioremap(release_phys, sizeof(release_phys));
8962306a36Sopenharmony_ci		else
9062306a36Sopenharmony_ci			cpu_strt_ptr =
9162306a36Sopenharmony_ci				(u32 __iomem *)phys_to_virt(release_phys);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		set_cpu_possible(cpu, true);
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ciconst struct smp_operations sti_smp_ops __initconst = {
9862306a36Sopenharmony_ci	.smp_prepare_cpus	= sti_smp_prepare_cpus,
9962306a36Sopenharmony_ci	.smp_boot_secondary	= sti_boot_secondary,
10062306a36Sopenharmony_ci};
101