linux/arch/arm/mach-hisi/hotplug.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2013 Linaro Ltd.
   4 * Copyright (c) 2013 HiSilicon Limited.
   5 */
   6
   7#include <linux/cpu.h>
   8#include <linux/delay.h>
   9#include <linux/io.h>
  10#include <linux/of_address.h>
  11#include <linux/of_platform.h>
  12#include <asm/cacheflush.h>
  13#include <asm/smp_plat.h>
  14#include "core.h"
  15
  16/* Sysctrl registers in Hi3620 SoC */
  17#define SCISOEN                         0xc0
  18#define SCISODIS                        0xc4
  19#define SCPERPWREN                      0xd0
  20#define SCPERPWRDIS                     0xd4
  21#define SCCPUCOREEN                     0xf4
  22#define SCCPUCOREDIS                    0xf8
  23#define SCPERCTRL0                      0x200
  24#define SCCPURSTEN                      0x410
  25#define SCCPURSTDIS                     0x414
  26
  27/*
  28 * bit definition in SCISOEN/SCPERPWREN/...
  29 *
  30 * CPU2_ISO_CTRL        (1 << 5)
  31 * CPU3_ISO_CTRL        (1 << 6)
  32 * ...
  33 */
  34#define CPU2_ISO_CTRL                   (1 << 5)
  35
  36/*
  37 * bit definition in SCPERCTRL0
  38 *
  39 * CPU0_WFI_MASK_CFG    (1 << 28)
  40 * CPU1_WFI_MASK_CFG    (1 << 29)
  41 * ...
  42 */
  43#define CPU0_WFI_MASK_CFG               (1 << 28)
  44
  45/*
  46 * bit definition in SCCPURSTEN/...
  47 *
  48 * CPU0_SRST_REQ_EN     (1 << 0)
  49 * CPU1_SRST_REQ_EN     (1 << 1)
  50 * ...
  51 */
  52#define CPU0_HPM_SRST_REQ_EN            (1 << 22)
  53#define CPU0_DBG_SRST_REQ_EN            (1 << 12)
  54#define CPU0_NEON_SRST_REQ_EN           (1 << 4)
  55#define CPU0_SRST_REQ_EN                (1 << 0)
  56
  57#define HIX5HD2_PERI_CRG20              0x50
  58#define CRG20_CPU1_RESET                (1 << 17)
  59
  60#define HIX5HD2_PERI_PMC0               0x1000
  61#define PMC0_CPU1_WAIT_MTCOMS_ACK       (1 << 8)
  62#define PMC0_CPU1_PMC_ENABLE            (1 << 7)
  63#define PMC0_CPU1_POWERDOWN             (1 << 3)
  64
  65#define HIP01_PERI9                    0x50
  66#define PERI9_CPU1_RESET               (1 << 1)
  67
  68enum {
  69        HI3620_CTRL,
  70        ERROR_CTRL,
  71};
  72
  73static void __iomem *ctrl_base;
  74static int id;
  75
  76static void set_cpu_hi3620(int cpu, bool enable)
  77{
  78        u32 val = 0;
  79
  80        if (enable) {
  81                /* MTCMOS set */
  82                if ((cpu == 2) || (cpu == 3))
  83                        writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
  84                                       ctrl_base + SCPERPWREN);
  85                udelay(100);
  86
  87                /* Enable core */
  88                writel_relaxed(0x01 << cpu, ctrl_base + SCCPUCOREEN);
  89
  90                /* unreset */
  91                val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
  92                        | CPU0_SRST_REQ_EN;
  93                writel_relaxed(val << cpu, ctrl_base + SCCPURSTDIS);
  94                /* reset */
  95                val |= CPU0_HPM_SRST_REQ_EN;
  96                writel_relaxed(val << cpu, ctrl_base + SCCPURSTEN);
  97
  98                /* ISO disable */
  99                if ((cpu == 2) || (cpu == 3))
 100                        writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
 101                                       ctrl_base + SCISODIS);
 102                udelay(1);
 103
 104                /* WFI Mask */
 105                val = readl_relaxed(ctrl_base + SCPERCTRL0);
 106                val &= ~(CPU0_WFI_MASK_CFG << cpu);
 107                writel_relaxed(val, ctrl_base + SCPERCTRL0);
 108
 109                /* Unreset */
 110                val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
 111                        | CPU0_SRST_REQ_EN | CPU0_HPM_SRST_REQ_EN;
 112                writel_relaxed(val << cpu, ctrl_base + SCCPURSTDIS);
 113        } else {
 114                /* wfi mask */
 115                val = readl_relaxed(ctrl_base + SCPERCTRL0);
 116                val |= (CPU0_WFI_MASK_CFG << cpu);
 117                writel_relaxed(val, ctrl_base + SCPERCTRL0);
 118
 119                /* disable core*/
 120                writel_relaxed(0x01 << cpu, ctrl_base + SCCPUCOREDIS);
 121
 122                if ((cpu == 2) || (cpu == 3)) {
 123                        /* iso enable */
 124                        writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
 125                                       ctrl_base + SCISOEN);
 126                        udelay(1);
 127                }
 128
 129                /* reset */
 130                val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
 131                        | CPU0_SRST_REQ_EN | CPU0_HPM_SRST_REQ_EN;
 132                writel_relaxed(val << cpu, ctrl_base + SCCPURSTEN);
 133
 134                if ((cpu == 2) || (cpu == 3)) {
 135                        /* MTCMOS unset */
 136                        writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
 137                                       ctrl_base + SCPERPWRDIS);
 138                        udelay(100);
 139                }
 140        }
 141}
 142
 143static int hi3xxx_hotplug_init(void)
 144{
 145        struct device_node *node;
 146
 147        node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
 148        if (!node) {
 149                id = ERROR_CTRL;
 150                return -ENOENT;
 151        }
 152
 153        ctrl_base = of_iomap(node, 0);
 154        of_node_put(node);
 155        if (!ctrl_base) {
 156                id = ERROR_CTRL;
 157                return -ENOMEM;
 158        }
 159
 160        id = HI3620_CTRL;
 161        return 0;
 162}
 163
 164void hi3xxx_set_cpu(int cpu, bool enable)
 165{
 166        if (!ctrl_base) {
 167                if (hi3xxx_hotplug_init() < 0)
 168                        return;
 169        }
 170
 171        if (id == HI3620_CTRL)
 172                set_cpu_hi3620(cpu, enable);
 173}
 174
 175static bool hix5hd2_hotplug_init(void)
 176{
 177        struct device_node *np;
 178
 179        np = of_find_compatible_node(NULL, NULL, "hisilicon,cpuctrl");
 180        if (!np)
 181                return false;
 182
 183        ctrl_base = of_iomap(np, 0);
 184        of_node_put(np);
 185        if (!ctrl_base)
 186                return false;
 187
 188        return true;
 189}
 190
 191void hix5hd2_set_cpu(int cpu, bool enable)
 192{
 193        u32 val = 0;
 194
 195        if (!ctrl_base)
 196                if (!hix5hd2_hotplug_init())
 197                        BUG();
 198
 199        if (enable) {
 200                /* power on cpu1 */
 201                val = readl_relaxed(ctrl_base + HIX5HD2_PERI_PMC0);
 202                val &= ~(PMC0_CPU1_WAIT_MTCOMS_ACK | PMC0_CPU1_POWERDOWN);
 203                val |= PMC0_CPU1_PMC_ENABLE;
 204                writel_relaxed(val, ctrl_base + HIX5HD2_PERI_PMC0);
 205                /* unreset */
 206                val = readl_relaxed(ctrl_base + HIX5HD2_PERI_CRG20);
 207                val &= ~CRG20_CPU1_RESET;
 208                writel_relaxed(val, ctrl_base + HIX5HD2_PERI_CRG20);
 209        } else {
 210                /* power down cpu1 */
 211                val = readl_relaxed(ctrl_base + HIX5HD2_PERI_PMC0);
 212                val |= PMC0_CPU1_PMC_ENABLE | PMC0_CPU1_POWERDOWN;
 213                val &= ~PMC0_CPU1_WAIT_MTCOMS_ACK;
 214                writel_relaxed(val, ctrl_base + HIX5HD2_PERI_PMC0);
 215
 216                /* reset */
 217                val = readl_relaxed(ctrl_base + HIX5HD2_PERI_CRG20);
 218                val |= CRG20_CPU1_RESET;
 219                writel_relaxed(val, ctrl_base + HIX5HD2_PERI_CRG20);
 220        }
 221}
 222
 223void hip01_set_cpu(int cpu, bool enable)
 224{
 225        unsigned int temp;
 226        struct device_node *np;
 227
 228        if (!ctrl_base) {
 229                np = of_find_compatible_node(NULL, NULL, "hisilicon,hip01-sysctrl");
 230                BUG_ON(!np);
 231                ctrl_base = of_iomap(np, 0);
 232                of_node_put(np);
 233                BUG_ON(!ctrl_base);
 234        }
 235
 236        if (enable) {
 237                /* reset on CPU1  */
 238                temp = readl_relaxed(ctrl_base + HIP01_PERI9);
 239                temp |= PERI9_CPU1_RESET;
 240                writel_relaxed(temp, ctrl_base + HIP01_PERI9);
 241
 242                udelay(50);
 243
 244                /* unreset on CPU1 */
 245                temp = readl_relaxed(ctrl_base + HIP01_PERI9);
 246                temp &= ~PERI9_CPU1_RESET;
 247                writel_relaxed(temp, ctrl_base + HIP01_PERI9);
 248        }
 249}
 250
 251static inline void cpu_enter_lowpower(void)
 252{
 253        unsigned int v;
 254
 255        flush_cache_all();
 256
 257        /*
 258         * Turn off coherency and L1 D-cache
 259         */
 260        asm volatile(
 261        "       mrc     p15, 0, %0, c1, c0, 1\n"
 262        "       bic     %0, %0, #0x40\n"
 263        "       mcr     p15, 0, %0, c1, c0, 1\n"
 264        "       mrc     p15, 0, %0, c1, c0, 0\n"
 265        "       bic     %0, %0, #0x04\n"
 266        "       mcr     p15, 0, %0, c1, c0, 0\n"
 267          : "=&r" (v)
 268          : "r" (0)
 269          : "cc");
 270}
 271
 272#ifdef CONFIG_HOTPLUG_CPU
 273void hi3xxx_cpu_die(unsigned int cpu)
 274{
 275        cpu_enter_lowpower();
 276        hi3xxx_set_cpu_jump(cpu, phys_to_virt(0));
 277        cpu_do_idle();
 278
 279        /* We should have never returned from idle */
 280        panic("cpu %d unexpectedly exit from shutdown\n", cpu);
 281}
 282
 283int hi3xxx_cpu_kill(unsigned int cpu)
 284{
 285        unsigned long timeout = jiffies + msecs_to_jiffies(50);
 286
 287        while (hi3xxx_get_cpu_jump(cpu))
 288                if (time_after(jiffies, timeout))
 289                        return 0;
 290        hi3xxx_set_cpu(cpu, false);
 291        return 1;
 292}
 293
 294void hix5hd2_cpu_die(unsigned int cpu)
 295{
 296        flush_cache_all();
 297        hix5hd2_set_cpu(cpu, false);
 298}
 299#endif
 300