linux/arch/arm/mach-hisi/platsmp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2013 Linaro Ltd.
   4 * Copyright (c) 2013 HiSilicon Limited.
   5 * Based on arch/arm/mach-vexpress/platsmp.c, Copyright (C) 2002 ARM Ltd.
   6 */
   7#include <linux/smp.h>
   8#include <linux/io.h>
   9#include <linux/of_address.h>
  10#include <linux/delay.h>
  11
  12#include <asm/cacheflush.h>
  13#include <asm/smp_plat.h>
  14#include <asm/smp_scu.h>
  15#include <asm/mach/map.h>
  16
  17#include "core.h"
  18
  19#define HIX5HD2_BOOT_ADDRESS            0xffff0000
  20
  21static void __iomem *ctrl_base;
  22
  23void hi3xxx_set_cpu_jump(int cpu, void *jump_addr)
  24{
  25        cpu = cpu_logical_map(cpu);
  26        if (!cpu || !ctrl_base)
  27                return;
  28        writel_relaxed(__pa_symbol(jump_addr), ctrl_base + ((cpu - 1) << 2));
  29}
  30
  31int hi3xxx_get_cpu_jump(int cpu)
  32{
  33        cpu = cpu_logical_map(cpu);
  34        if (!cpu || !ctrl_base)
  35                return 0;
  36        return readl_relaxed(ctrl_base + ((cpu - 1) << 2));
  37}
  38
  39static void __init hisi_enable_scu_a9(void)
  40{
  41        unsigned long base = 0;
  42        void __iomem *scu_base = NULL;
  43
  44        if (scu_a9_has_base()) {
  45                base = scu_a9_get_base();
  46                scu_base = ioremap(base, SZ_4K);
  47                if (!scu_base) {
  48                        pr_err("ioremap(scu_base) failed\n");
  49                        return;
  50                }
  51                scu_enable(scu_base);
  52                iounmap(scu_base);
  53        }
  54}
  55
  56static void __init hi3xxx_smp_prepare_cpus(unsigned int max_cpus)
  57{
  58        struct device_node *np = NULL;
  59        u32 offset = 0;
  60
  61        hisi_enable_scu_a9();
  62        if (!ctrl_base) {
  63                np = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
  64                if (!np) {
  65                        pr_err("failed to find hisilicon,sysctrl node\n");
  66                        return;
  67                }
  68                ctrl_base = of_iomap(np, 0);
  69                if (!ctrl_base) {
  70                        of_node_put(np);
  71                        pr_err("failed to map address\n");
  72                        return;
  73                }
  74                if (of_property_read_u32(np, "smp-offset", &offset) < 0) {
  75                        of_node_put(np);
  76                        pr_err("failed to find smp-offset property\n");
  77                        return;
  78                }
  79                ctrl_base += offset;
  80                of_node_put(np);
  81        }
  82}
  83
  84static int hi3xxx_boot_secondary(unsigned int cpu, struct task_struct *idle)
  85{
  86        hi3xxx_set_cpu(cpu, true);
  87        hi3xxx_set_cpu_jump(cpu, secondary_startup);
  88        arch_send_wakeup_ipi_mask(cpumask_of(cpu));
  89        return 0;
  90}
  91
  92static const struct smp_operations hi3xxx_smp_ops __initconst = {
  93        .smp_prepare_cpus       = hi3xxx_smp_prepare_cpus,
  94        .smp_boot_secondary     = hi3xxx_boot_secondary,
  95#ifdef CONFIG_HOTPLUG_CPU
  96        .cpu_die                = hi3xxx_cpu_die,
  97        .cpu_kill               = hi3xxx_cpu_kill,
  98#endif
  99};
 100
 101static void __init hisi_common_smp_prepare_cpus(unsigned int max_cpus)
 102{
 103        hisi_enable_scu_a9();
 104}
 105
 106static void hix5hd2_set_scu_boot_addr(phys_addr_t start_addr, phys_addr_t jump_addr)
 107{
 108        void __iomem *virt;
 109
 110        virt = ioremap(start_addr, PAGE_SIZE);
 111
 112        writel_relaxed(0xe51ff004, virt);       /* ldr pc, [pc, #-4] */
 113        writel_relaxed(jump_addr, virt + 4);    /* pc jump phy address */
 114        iounmap(virt);
 115}
 116
 117static int hix5hd2_boot_secondary(unsigned int cpu, struct task_struct *idle)
 118{
 119        phys_addr_t jumpaddr;
 120
 121        jumpaddr = __pa_symbol(secondary_startup);
 122        hix5hd2_set_scu_boot_addr(HIX5HD2_BOOT_ADDRESS, jumpaddr);
 123        hix5hd2_set_cpu(cpu, true);
 124        arch_send_wakeup_ipi_mask(cpumask_of(cpu));
 125        return 0;
 126}
 127
 128
 129static const struct smp_operations hix5hd2_smp_ops __initconst = {
 130        .smp_prepare_cpus       = hisi_common_smp_prepare_cpus,
 131        .smp_boot_secondary     = hix5hd2_boot_secondary,
 132#ifdef CONFIG_HOTPLUG_CPU
 133        .cpu_die                = hix5hd2_cpu_die,
 134#endif
 135};
 136
 137
 138#define SC_SCTL_REMAP_CLR      0x00000100
 139#define HIP01_BOOT_ADDRESS     0x80000000
 140#define REG_SC_CTRL            0x000
 141
 142static void hip01_set_boot_addr(phys_addr_t start_addr, phys_addr_t jump_addr)
 143{
 144        void __iomem *virt;
 145
 146        virt = phys_to_virt(start_addr);
 147
 148        writel_relaxed(0xe51ff004, virt);
 149        writel_relaxed(jump_addr, virt + 4);
 150}
 151
 152static int hip01_boot_secondary(unsigned int cpu, struct task_struct *idle)
 153{
 154        phys_addr_t jumpaddr;
 155        unsigned int remap_reg_value = 0;
 156        struct device_node *node;
 157
 158
 159        jumpaddr = __pa_symbol(secondary_startup);
 160        hip01_set_boot_addr(HIP01_BOOT_ADDRESS, jumpaddr);
 161
 162        node = of_find_compatible_node(NULL, NULL, "hisilicon,hip01-sysctrl");
 163        if (WARN_ON(!node))
 164                return -1;
 165        ctrl_base = of_iomap(node, 0);
 166        of_node_put(node);
 167
 168        /* set the secondary core boot from DDR */
 169        remap_reg_value = readl_relaxed(ctrl_base + REG_SC_CTRL);
 170        barrier();
 171        remap_reg_value |= SC_SCTL_REMAP_CLR;
 172        barrier();
 173        writel_relaxed(remap_reg_value, ctrl_base + REG_SC_CTRL);
 174
 175        hip01_set_cpu(cpu, true);
 176
 177        return 0;
 178}
 179
 180static const struct smp_operations hip01_smp_ops __initconst = {
 181        .smp_prepare_cpus       = hisi_common_smp_prepare_cpus,
 182        .smp_boot_secondary     = hip01_boot_secondary,
 183};
 184
 185CPU_METHOD_OF_DECLARE(hi3xxx_smp, "hisilicon,hi3620-smp", &hi3xxx_smp_ops);
 186CPU_METHOD_OF_DECLARE(hix5hd2_smp, "hisilicon,hix5hd2-smp", &hix5hd2_smp_ops);
 187CPU_METHOD_OF_DECLARE(hip01_smp, "hisilicon,hip01-smp", &hip01_smp_ops);
 188