Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2013 Linaro Ltd.
0004  * Copyright (c) 2013 HiSilicon Limited.
0005  */
0006 
0007 #include <linux/cpu.h>
0008 #include <linux/delay.h>
0009 #include <linux/io.h>
0010 #include <linux/of_address.h>
0011 #include <linux/of_platform.h>
0012 #include <asm/cacheflush.h>
0013 #include <asm/smp_plat.h>
0014 #include "core.h"
0015 
0016 /* Sysctrl registers in Hi3620 SoC */
0017 #define SCISOEN             0xc0
0018 #define SCISODIS            0xc4
0019 #define SCPERPWREN          0xd0
0020 #define SCPERPWRDIS         0xd4
0021 #define SCCPUCOREEN         0xf4
0022 #define SCCPUCOREDIS            0xf8
0023 #define SCPERCTRL0          0x200
0024 #define SCCPURSTEN          0x410
0025 #define SCCPURSTDIS         0x414
0026 
0027 /*
0028  * bit definition in SCISOEN/SCPERPWREN/...
0029  *
0030  * CPU2_ISO_CTRL    (1 << 5)
0031  * CPU3_ISO_CTRL    (1 << 6)
0032  * ...
0033  */
0034 #define CPU2_ISO_CTRL           (1 << 5)
0035 
0036 /*
0037  * bit definition in SCPERCTRL0
0038  *
0039  * CPU0_WFI_MASK_CFG    (1 << 28)
0040  * CPU1_WFI_MASK_CFG    (1 << 29)
0041  * ...
0042  */
0043 #define CPU0_WFI_MASK_CFG       (1 << 28)
0044 
0045 /*
0046  * bit definition in SCCPURSTEN/...
0047  *
0048  * CPU0_SRST_REQ_EN (1 << 0)
0049  * CPU1_SRST_REQ_EN (1 << 1)
0050  * ...
0051  */
0052 #define CPU0_HPM_SRST_REQ_EN        (1 << 22)
0053 #define CPU0_DBG_SRST_REQ_EN        (1 << 12)
0054 #define CPU0_NEON_SRST_REQ_EN       (1 << 4)
0055 #define CPU0_SRST_REQ_EN        (1 << 0)
0056 
0057 #define HIX5HD2_PERI_CRG20      0x50
0058 #define CRG20_CPU1_RESET        (1 << 17)
0059 
0060 #define HIX5HD2_PERI_PMC0       0x1000
0061 #define PMC0_CPU1_WAIT_MTCOMS_ACK   (1 << 8)
0062 #define PMC0_CPU1_PMC_ENABLE        (1 << 7)
0063 #define PMC0_CPU1_POWERDOWN     (1 << 3)
0064 
0065 #define HIP01_PERI9                    0x50
0066 #define PERI9_CPU1_RESET               (1 << 1)
0067 
0068 enum {
0069     HI3620_CTRL,
0070     ERROR_CTRL,
0071 };
0072 
0073 static void __iomem *ctrl_base;
0074 static int id;
0075 
0076 static void set_cpu_hi3620(int cpu, bool enable)
0077 {
0078     u32 val = 0;
0079 
0080     if (enable) {
0081         /* MTCMOS set */
0082         if ((cpu == 2) || (cpu == 3))
0083             writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
0084                        ctrl_base + SCPERPWREN);
0085         udelay(100);
0086 
0087         /* Enable core */
0088         writel_relaxed(0x01 << cpu, ctrl_base + SCCPUCOREEN);
0089 
0090         /* unreset */
0091         val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
0092             | CPU0_SRST_REQ_EN;
0093         writel_relaxed(val << cpu, ctrl_base + SCCPURSTDIS);
0094         /* reset */
0095         val |= CPU0_HPM_SRST_REQ_EN;
0096         writel_relaxed(val << cpu, ctrl_base + SCCPURSTEN);
0097 
0098         /* ISO disable */
0099         if ((cpu == 2) || (cpu == 3))
0100             writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
0101                        ctrl_base + SCISODIS);
0102         udelay(1);
0103 
0104         /* WFI Mask */
0105         val = readl_relaxed(ctrl_base + SCPERCTRL0);
0106         val &= ~(CPU0_WFI_MASK_CFG << cpu);
0107         writel_relaxed(val, ctrl_base + SCPERCTRL0);
0108 
0109         /* Unreset */
0110         val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
0111             | CPU0_SRST_REQ_EN | CPU0_HPM_SRST_REQ_EN;
0112         writel_relaxed(val << cpu, ctrl_base + SCCPURSTDIS);
0113     } else {
0114         /* wfi mask */
0115         val = readl_relaxed(ctrl_base + SCPERCTRL0);
0116         val |= (CPU0_WFI_MASK_CFG << cpu);
0117         writel_relaxed(val, ctrl_base + SCPERCTRL0);
0118 
0119         /* disable core*/
0120         writel_relaxed(0x01 << cpu, ctrl_base + SCCPUCOREDIS);
0121 
0122         if ((cpu == 2) || (cpu == 3)) {
0123             /* iso enable */
0124             writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
0125                        ctrl_base + SCISOEN);
0126             udelay(1);
0127         }
0128 
0129         /* reset */
0130         val = CPU0_DBG_SRST_REQ_EN | CPU0_NEON_SRST_REQ_EN
0131             | CPU0_SRST_REQ_EN | CPU0_HPM_SRST_REQ_EN;
0132         writel_relaxed(val << cpu, ctrl_base + SCCPURSTEN);
0133 
0134         if ((cpu == 2) || (cpu == 3)) {
0135             /* MTCMOS unset */
0136             writel_relaxed(CPU2_ISO_CTRL << (cpu - 2),
0137                        ctrl_base + SCPERPWRDIS);
0138             udelay(100);
0139         }
0140     }
0141 }
0142 
0143 static int hi3xxx_hotplug_init(void)
0144 {
0145     struct device_node *node;
0146 
0147     node = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
0148     if (!node) {
0149         id = ERROR_CTRL;
0150         return -ENOENT;
0151     }
0152 
0153     ctrl_base = of_iomap(node, 0);
0154     of_node_put(node);
0155     if (!ctrl_base) {
0156         id = ERROR_CTRL;
0157         return -ENOMEM;
0158     }
0159 
0160     id = HI3620_CTRL;
0161     return 0;
0162 }
0163 
0164 void hi3xxx_set_cpu(int cpu, bool enable)
0165 {
0166     if (!ctrl_base) {
0167         if (hi3xxx_hotplug_init() < 0)
0168             return;
0169     }
0170 
0171     if (id == HI3620_CTRL)
0172         set_cpu_hi3620(cpu, enable);
0173 }
0174 
0175 static bool hix5hd2_hotplug_init(void)
0176 {
0177     struct device_node *np;
0178 
0179     np = of_find_compatible_node(NULL, NULL, "hisilicon,cpuctrl");
0180     if (!np)
0181         return false;
0182 
0183     ctrl_base = of_iomap(np, 0);
0184     of_node_put(np);
0185     if (!ctrl_base)
0186         return false;
0187 
0188     return true;
0189 }
0190 
0191 void hix5hd2_set_cpu(int cpu, bool enable)
0192 {
0193     u32 val = 0;
0194 
0195     if (!ctrl_base)
0196         if (!hix5hd2_hotplug_init())
0197             BUG();
0198 
0199     if (enable) {
0200         /* power on cpu1 */
0201         val = readl_relaxed(ctrl_base + HIX5HD2_PERI_PMC0);
0202         val &= ~(PMC0_CPU1_WAIT_MTCOMS_ACK | PMC0_CPU1_POWERDOWN);
0203         val |= PMC0_CPU1_PMC_ENABLE;
0204         writel_relaxed(val, ctrl_base + HIX5HD2_PERI_PMC0);
0205         /* unreset */
0206         val = readl_relaxed(ctrl_base + HIX5HD2_PERI_CRG20);
0207         val &= ~CRG20_CPU1_RESET;
0208         writel_relaxed(val, ctrl_base + HIX5HD2_PERI_CRG20);
0209     } else {
0210         /* power down cpu1 */
0211         val = readl_relaxed(ctrl_base + HIX5HD2_PERI_PMC0);
0212         val |= PMC0_CPU1_PMC_ENABLE | PMC0_CPU1_POWERDOWN;
0213         val &= ~PMC0_CPU1_WAIT_MTCOMS_ACK;
0214         writel_relaxed(val, ctrl_base + HIX5HD2_PERI_PMC0);
0215 
0216         /* reset */
0217         val = readl_relaxed(ctrl_base + HIX5HD2_PERI_CRG20);
0218         val |= CRG20_CPU1_RESET;
0219         writel_relaxed(val, ctrl_base + HIX5HD2_PERI_CRG20);
0220     }
0221 }
0222 
0223 void hip01_set_cpu(int cpu, bool enable)
0224 {
0225     unsigned int temp;
0226     struct device_node *np;
0227 
0228     if (!ctrl_base) {
0229         np = of_find_compatible_node(NULL, NULL, "hisilicon,hip01-sysctrl");
0230         BUG_ON(!np);
0231         ctrl_base = of_iomap(np, 0);
0232         of_node_put(np);
0233         BUG_ON(!ctrl_base);
0234     }
0235 
0236     if (enable) {
0237         /* reset on CPU1  */
0238         temp = readl_relaxed(ctrl_base + HIP01_PERI9);
0239         temp |= PERI9_CPU1_RESET;
0240         writel_relaxed(temp, ctrl_base + HIP01_PERI9);
0241 
0242         udelay(50);
0243 
0244         /* unreset on CPU1 */
0245         temp = readl_relaxed(ctrl_base + HIP01_PERI9);
0246         temp &= ~PERI9_CPU1_RESET;
0247         writel_relaxed(temp, ctrl_base + HIP01_PERI9);
0248     }
0249 }
0250 
0251 static inline void cpu_enter_lowpower(void)
0252 {
0253     unsigned int v;
0254 
0255     flush_cache_all();
0256 
0257     /*
0258      * Turn off coherency and L1 D-cache
0259      */
0260     asm volatile(
0261     "   mrc p15, 0, %0, c1, c0, 1\n"
0262     "   bic %0, %0, #0x40\n"
0263     "   mcr p15, 0, %0, c1, c0, 1\n"
0264     "   mrc p15, 0, %0, c1, c0, 0\n"
0265     "   bic %0, %0, #0x04\n"
0266     "   mcr p15, 0, %0, c1, c0, 0\n"
0267       : "=&r" (v)
0268       : "r" (0)
0269       : "cc");
0270 }
0271 
0272 #ifdef CONFIG_HOTPLUG_CPU
0273 void hi3xxx_cpu_die(unsigned int cpu)
0274 {
0275     cpu_enter_lowpower();
0276     hi3xxx_set_cpu_jump(cpu, phys_to_virt(0));
0277     cpu_do_idle();
0278 
0279     /* We should have never returned from idle */
0280     panic("cpu %d unexpectedly exit from shutdown\n", cpu);
0281 }
0282 
0283 int hi3xxx_cpu_kill(unsigned int cpu)
0284 {
0285     unsigned long timeout = jiffies + msecs_to_jiffies(50);
0286 
0287     while (hi3xxx_get_cpu_jump(cpu))
0288         if (time_after(jiffies, timeout))
0289             return 0;
0290     hi3xxx_set_cpu(cpu, false);
0291     return 1;
0292 }
0293 
0294 void hix5hd2_cpu_die(unsigned int cpu)
0295 {
0296     flush_cache_all();
0297     hix5hd2_set_cpu(cpu, false);
0298 }
0299 #endif