root/arch/arm/mach-hisi/hotplug.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_cpu_hi3620
  2. hi3xxx_hotplug_init
  3. hi3xxx_set_cpu
  4. hix5hd2_hotplug_init
  5. hix5hd2_set_cpu
  6. hip01_set_cpu
  7. cpu_enter_lowpower
  8. hi3xxx_cpu_die
  9. hi3xxx_cpu_kill
  10. hix5hd2_cpu_die

   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 
  68 enum {
  69         HI3620_CTRL,
  70         ERROR_CTRL,
  71 };
  72 
  73 static void __iomem *ctrl_base;
  74 static int id;
  75 
  76 static 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 
 143 static 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 
 164 void 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 
 175 static 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 
 191 void 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 
 223 void 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 
 251 static 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
 273 void 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 
 283 int 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 
 294 void hix5hd2_cpu_die(unsigned int cpu)
 295 {
 296         flush_cache_all();
 297         hix5hd2_set_cpu(cpu, false);
 298 }
 299 #endif

/* [<][>][^][v][top][bottom][index][help] */