xref: /linux/arch/arm/mach-hisi/platsmp.c (revision cf40a76e7d5874bb25f4404eecc58a2e033af885)
1a9434e96SKevin Hilman /*
2a9434e96SKevin Hilman  * Copyright (c) 2013 Linaro Ltd.
3a9434e96SKevin Hilman  * Copyright (c) 2013 Hisilicon Limited.
4a9434e96SKevin Hilman  * Based on arch/arm/mach-vexpress/platsmp.c, Copyright (C) 2002 ARM Ltd.
5a9434e96SKevin Hilman  *
6a9434e96SKevin Hilman  * This program is free software; you can redistribute it and/or modify it
7a9434e96SKevin Hilman  * under the terms and conditions of the GNU General Public License,
8a9434e96SKevin Hilman  * version 2, as published by the Free Software Foundation.
9a9434e96SKevin Hilman  */
10a9434e96SKevin Hilman #include <linux/smp.h>
11a9434e96SKevin Hilman #include <linux/io.h>
12a9434e96SKevin Hilman #include <linux/of_address.h>
137fda91e7SWang Long #include <linux/delay.h>
14a9434e96SKevin Hilman 
15a9434e96SKevin Hilman #include <asm/cacheflush.h>
16a9434e96SKevin Hilman #include <asm/smp_plat.h>
17a9434e96SKevin Hilman #include <asm/smp_scu.h>
187fda91e7SWang Long #include <asm/mach/map.h>
19a9434e96SKevin Hilman 
20a9434e96SKevin Hilman #include "core.h"
21a9434e96SKevin Hilman 
2206cc5c1dSHaifeng Yan #define HIX5HD2_BOOT_ADDRESS		0xffff0000
2306cc5c1dSHaifeng Yan 
24a9434e96SKevin Hilman static void __iomem *ctrl_base;
25a9434e96SKevin Hilman 
26a9434e96SKevin Hilman void hi3xxx_set_cpu_jump(int cpu, void *jump_addr)
27a9434e96SKevin Hilman {
28a9434e96SKevin Hilman 	cpu = cpu_logical_map(cpu);
29a9434e96SKevin Hilman 	if (!cpu || !ctrl_base)
30a9434e96SKevin Hilman 		return;
3164fc2a94SFlorian Fainelli 	writel_relaxed(__pa_symbol(jump_addr), ctrl_base + ((cpu - 1) << 2));
32a9434e96SKevin Hilman }
33a9434e96SKevin Hilman 
34a9434e96SKevin Hilman int hi3xxx_get_cpu_jump(int cpu)
35a9434e96SKevin Hilman {
36a9434e96SKevin Hilman 	cpu = cpu_logical_map(cpu);
37a9434e96SKevin Hilman 	if (!cpu || !ctrl_base)
38a9434e96SKevin Hilman 		return 0;
39a9434e96SKevin Hilman 	return readl_relaxed(ctrl_base + ((cpu - 1) << 2));
40a9434e96SKevin Hilman }
41a9434e96SKevin Hilman 
4206cc5c1dSHaifeng Yan static void __init hisi_enable_scu_a9(void)
43a9434e96SKevin Hilman {
44a9434e96SKevin Hilman 	unsigned long base = 0;
45a9434e96SKevin Hilman 	void __iomem *scu_base = NULL;
46a9434e96SKevin Hilman 
47a9434e96SKevin Hilman 	if (scu_a9_has_base()) {
48a9434e96SKevin Hilman 		base = scu_a9_get_base();
49a9434e96SKevin Hilman 		scu_base = ioremap(base, SZ_4K);
50a9434e96SKevin Hilman 		if (!scu_base) {
51a9434e96SKevin Hilman 			pr_err("ioremap(scu_base) failed\n");
52a9434e96SKevin Hilman 			return;
53a9434e96SKevin Hilman 		}
54a9434e96SKevin Hilman 		scu_enable(scu_base);
55a9434e96SKevin Hilman 		iounmap(scu_base);
56a9434e96SKevin Hilman 	}
5706cc5c1dSHaifeng Yan }
5806cc5c1dSHaifeng Yan 
5906cc5c1dSHaifeng Yan static void __init hi3xxx_smp_prepare_cpus(unsigned int max_cpus)
6006cc5c1dSHaifeng Yan {
6106cc5c1dSHaifeng Yan 	struct device_node *np = NULL;
6206cc5c1dSHaifeng Yan 	u32 offset = 0;
6306cc5c1dSHaifeng Yan 
6406cc5c1dSHaifeng Yan 	hisi_enable_scu_a9();
65a9434e96SKevin Hilman 	if (!ctrl_base) {
66a9434e96SKevin Hilman 		np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
67a9434e96SKevin Hilman 		if (!np) {
68a9434e96SKevin Hilman 			pr_err("failed to find hisilicon,sysctrl node\n");
69a9434e96SKevin Hilman 			return;
70a9434e96SKevin Hilman 		}
71a9434e96SKevin Hilman 		ctrl_base = of_iomap(np, 0);
72a9434e96SKevin Hilman 		if (!ctrl_base) {
73a9434e96SKevin Hilman 			pr_err("failed to map address\n");
74a9434e96SKevin Hilman 			return;
75a9434e96SKevin Hilman 		}
76a9434e96SKevin Hilman 		if (of_property_read_u32(np, "smp-offset", &offset) < 0) {
77a9434e96SKevin Hilman 			pr_err("failed to find smp-offset property\n");
78a9434e96SKevin Hilman 			return;
79a9434e96SKevin Hilman 		}
80a9434e96SKevin Hilman 		ctrl_base += offset;
81a9434e96SKevin Hilman 	}
82a9434e96SKevin Hilman }
83a9434e96SKevin Hilman 
84a9434e96SKevin Hilman static int hi3xxx_boot_secondary(unsigned int cpu, struct task_struct *idle)
85a9434e96SKevin Hilman {
8622bae429SZhangfei Gao 	hi3xxx_set_cpu(cpu, true);
87a9434e96SKevin Hilman 	hi3xxx_set_cpu_jump(cpu, secondary_startup);
88a9434e96SKevin Hilman 	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
89a9434e96SKevin Hilman 	return 0;
90a9434e96SKevin Hilman }
91a9434e96SKevin Hilman 
9275305275SMasahiro Yamada static const struct smp_operations hi3xxx_smp_ops __initconst = {
93a9434e96SKevin Hilman 	.smp_prepare_cpus	= hi3xxx_smp_prepare_cpus,
94a9434e96SKevin Hilman 	.smp_boot_secondary	= hi3xxx_boot_secondary,
9522bae429SZhangfei Gao #ifdef CONFIG_HOTPLUG_CPU
9622bae429SZhangfei Gao 	.cpu_die		= hi3xxx_cpu_die,
9722bae429SZhangfei Gao 	.cpu_kill		= hi3xxx_cpu_kill,
9822bae429SZhangfei Gao #endif
99a9434e96SKevin Hilman };
10006cc5c1dSHaifeng Yan 
101e243f943SWang Long static void __init hisi_common_smp_prepare_cpus(unsigned int max_cpus)
10206cc5c1dSHaifeng Yan {
10306cc5c1dSHaifeng Yan 	hisi_enable_scu_a9();
10406cc5c1dSHaifeng Yan }
10506cc5c1dSHaifeng Yan 
10609ca62f5SBen Dooks static void hix5hd2_set_scu_boot_addr(phys_addr_t start_addr, phys_addr_t jump_addr)
10706cc5c1dSHaifeng Yan {
10806cc5c1dSHaifeng Yan 	void __iomem *virt;
10906cc5c1dSHaifeng Yan 
11006cc5c1dSHaifeng Yan 	virt = ioremap(start_addr, PAGE_SIZE);
11106cc5c1dSHaifeng Yan 
112*d2057bbbSYunzhi Li 	writel_relaxed(0xe51ff004, virt);	/* ldr pc, [pc, #-4] */
11306cc5c1dSHaifeng Yan 	writel_relaxed(jump_addr, virt + 4);	/* pc jump phy address */
11406cc5c1dSHaifeng Yan 	iounmap(virt);
11506cc5c1dSHaifeng Yan }
11606cc5c1dSHaifeng Yan 
11706cc5c1dSHaifeng Yan static int hix5hd2_boot_secondary(unsigned int cpu, struct task_struct *idle)
11806cc5c1dSHaifeng Yan {
11906cc5c1dSHaifeng Yan 	phys_addr_t jumpaddr;
12006cc5c1dSHaifeng Yan 
12164fc2a94SFlorian Fainelli 	jumpaddr = __pa_symbol(secondary_startup);
12206cc5c1dSHaifeng Yan 	hix5hd2_set_scu_boot_addr(HIX5HD2_BOOT_ADDRESS, jumpaddr);
12306cc5c1dSHaifeng Yan 	hix5hd2_set_cpu(cpu, true);
12406cc5c1dSHaifeng Yan 	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
12506cc5c1dSHaifeng Yan 	return 0;
12606cc5c1dSHaifeng Yan }
12706cc5c1dSHaifeng Yan 
12806cc5c1dSHaifeng Yan 
12975305275SMasahiro Yamada static const struct smp_operations hix5hd2_smp_ops __initconst = {
130e243f943SWang Long 	.smp_prepare_cpus	= hisi_common_smp_prepare_cpus,
13106cc5c1dSHaifeng Yan 	.smp_boot_secondary	= hix5hd2_boot_secondary,
13206cc5c1dSHaifeng Yan #ifdef CONFIG_HOTPLUG_CPU
13306cc5c1dSHaifeng Yan 	.cpu_die		= hix5hd2_cpu_die,
13406cc5c1dSHaifeng Yan #endif
13506cc5c1dSHaifeng Yan };
136c2fff85eSHaojian Zhuang 
1377fda91e7SWang Long 
1387fda91e7SWang Long #define SC_SCTL_REMAP_CLR      0x00000100
1397fda91e7SWang Long #define HIP01_BOOT_ADDRESS     0x80000000
1407fda91e7SWang Long #define REG_SC_CTRL            0x000
1417fda91e7SWang Long 
14209ca62f5SBen Dooks static void hip01_set_boot_addr(phys_addr_t start_addr, phys_addr_t jump_addr)
1437fda91e7SWang Long {
1447fda91e7SWang Long 	void __iomem *virt;
1457fda91e7SWang Long 
1467fda91e7SWang Long 	virt = phys_to_virt(start_addr);
1477fda91e7SWang Long 
1487fda91e7SWang Long 	writel_relaxed(0xe51ff004, virt);
1497fda91e7SWang Long 	writel_relaxed(jump_addr, virt + 4);
1507fda91e7SWang Long }
1517fda91e7SWang Long 
1527fda91e7SWang Long static int hip01_boot_secondary(unsigned int cpu, struct task_struct *idle)
1537fda91e7SWang Long {
1547fda91e7SWang Long 	phys_addr_t jumpaddr;
1557fda91e7SWang Long 	unsigned int remap_reg_value = 0;
1567fda91e7SWang Long 	struct device_node *node;
1577fda91e7SWang Long 
1587fda91e7SWang Long 
15964fc2a94SFlorian Fainelli 	jumpaddr = __pa_symbol(secondary_startup);
1607fda91e7SWang Long 	hip01_set_boot_addr(HIP01_BOOT_ADDRESS, jumpaddr);
1617fda91e7SWang Long 
1627fda91e7SWang Long 	node = of_find_compatible_node(NULL, NULL, "hisilicon,hip01-sysctrl");
1637fda91e7SWang Long 	if (WARN_ON(!node))
1647fda91e7SWang Long 		return -1;
1657fda91e7SWang Long 	ctrl_base = of_iomap(node, 0);
1667fda91e7SWang Long 
1677fda91e7SWang Long 	/* set the secondary core boot from DDR */
1687fda91e7SWang Long 	remap_reg_value = readl_relaxed(ctrl_base + REG_SC_CTRL);
1697fda91e7SWang Long 	barrier();
1707fda91e7SWang Long 	remap_reg_value |= SC_SCTL_REMAP_CLR;
1717fda91e7SWang Long 	barrier();
1727fda91e7SWang Long 	writel_relaxed(remap_reg_value, ctrl_base + REG_SC_CTRL);
1737fda91e7SWang Long 
1747fda91e7SWang Long 	hip01_set_cpu(cpu, true);
1757fda91e7SWang Long 
1767fda91e7SWang Long 	return 0;
1777fda91e7SWang Long }
1787fda91e7SWang Long 
17975305275SMasahiro Yamada static const struct smp_operations hip01_smp_ops __initconst = {
1807fda91e7SWang Long 	.smp_prepare_cpus       = hisi_common_smp_prepare_cpus,
1817fda91e7SWang Long 	.smp_boot_secondary     = hip01_boot_secondary,
1827fda91e7SWang Long };
1837fda91e7SWang Long 
184c2fff85eSHaojian Zhuang CPU_METHOD_OF_DECLARE(hi3xxx_smp, "hisilicon,hi3620-smp", &hi3xxx_smp_ops);
185c2fff85eSHaojian Zhuang CPU_METHOD_OF_DECLARE(hix5hd2_smp, "hisilicon,hix5hd2-smp", &hix5hd2_smp_ops);
1867fda91e7SWang Long CPU_METHOD_OF_DECLARE(hip01_smp, "hisilicon,hip01-smp", &hip01_smp_ops);
187