linux/arch/arm/mach-hisi/platmcpm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2013-2014 Linaro Ltd.
   4 * Copyright (c) 2013-2014 HiSilicon Limited.
   5 */
   6#include <linux/init.h>
   7#include <linux/smp.h>
   8#include <linux/delay.h>
   9#include <linux/io.h>
  10#include <linux/memblock.h>
  11#include <linux/of_address.h>
  12
  13#include <asm/cputype.h>
  14#include <asm/cp15.h>
  15#include <asm/cacheflush.h>
  16#include <asm/smp.h>
  17#include <asm/smp_plat.h>
  18
  19#include "core.h"
  20
  21/* bits definition in SC_CPU_RESET_REQ[x]/SC_CPU_RESET_DREQ[x]
  22 * 1 -- unreset; 0 -- reset
  23 */
  24#define CORE_RESET_BIT(x)               (1 << x)
  25#define NEON_RESET_BIT(x)               (1 << (x + 4))
  26#define CORE_DEBUG_RESET_BIT(x)         (1 << (x + 9))
  27#define CLUSTER_L2_RESET_BIT            (1 << 8)
  28#define CLUSTER_DEBUG_RESET_BIT         (1 << 13)
  29
  30/*
  31 * bits definition in SC_CPU_RESET_STATUS[x]
  32 * 1 -- reset status; 0 -- unreset status
  33 */
  34#define CORE_RESET_STATUS(x)            (1 << x)
  35#define NEON_RESET_STATUS(x)            (1 << (x + 4))
  36#define CORE_DEBUG_RESET_STATUS(x)      (1 << (x + 9))
  37#define CLUSTER_L2_RESET_STATUS         (1 << 8)
  38#define CLUSTER_DEBUG_RESET_STATUS      (1 << 13)
  39#define CORE_WFI_STATUS(x)              (1 << (x + 16))
  40#define CORE_WFE_STATUS(x)              (1 << (x + 20))
  41#define CORE_DEBUG_ACK(x)               (1 << (x + 24))
  42
  43#define SC_CPU_RESET_REQ(x)             (0x520 + (x << 3))      /* reset */
  44#define SC_CPU_RESET_DREQ(x)            (0x524 + (x << 3))      /* unreset */
  45#define SC_CPU_RESET_STATUS(x)          (0x1520 + (x << 3))
  46
  47#define FAB_SF_MODE                     0x0c
  48#define FAB_SF_INVLD                    0x10
  49
  50/* bits definition in FB_SF_INVLD */
  51#define FB_SF_INVLD_START               (1 << 8)
  52
  53#define HIP04_MAX_CLUSTERS              4
  54#define HIP04_MAX_CPUS_PER_CLUSTER      4
  55
  56#define POLL_MSEC       10
  57#define TIMEOUT_MSEC    1000
  58
  59static void __iomem *sysctrl, *fabric;
  60static int hip04_cpu_table[HIP04_MAX_CLUSTERS][HIP04_MAX_CPUS_PER_CLUSTER];
  61static DEFINE_SPINLOCK(boot_lock);
  62static u32 fabric_phys_addr;
  63/*
  64 * [0]: bootwrapper physical address
  65 * [1]: bootwrapper size
  66 * [2]: relocation address
  67 * [3]: relocation size
  68 */
  69static u32 hip04_boot_method[4];
  70
  71static bool hip04_cluster_is_down(unsigned int cluster)
  72{
  73        int i;
  74
  75        for (i = 0; i < HIP04_MAX_CPUS_PER_CLUSTER; i++)
  76                if (hip04_cpu_table[cluster][i])
  77                        return false;
  78        return true;
  79}
  80
  81static void hip04_set_snoop_filter(unsigned int cluster, unsigned int on)
  82{
  83        unsigned long data;
  84
  85        if (!fabric)
  86                BUG();
  87        data = readl_relaxed(fabric + FAB_SF_MODE);
  88        if (on)
  89                data |= 1 << cluster;
  90        else
  91                data &= ~(1 << cluster);
  92        writel_relaxed(data, fabric + FAB_SF_MODE);
  93        do {
  94                cpu_relax();
  95        } while (data != readl_relaxed(fabric + FAB_SF_MODE));
  96}
  97
  98static int hip04_boot_secondary(unsigned int l_cpu, struct task_struct *idle)
  99{
 100        unsigned int mpidr, cpu, cluster;
 101        unsigned long data;
 102        void __iomem *sys_dreq, *sys_status;
 103
 104        mpidr = cpu_logical_map(l_cpu);
 105        cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
 106        cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
 107
 108        if (!sysctrl)
 109                return -ENODEV;
 110        if (cluster >= HIP04_MAX_CLUSTERS || cpu >= HIP04_MAX_CPUS_PER_CLUSTER)
 111                return -EINVAL;
 112
 113        spin_lock_irq(&boot_lock);
 114
 115        if (hip04_cpu_table[cluster][cpu])
 116                goto out;
 117
 118        sys_dreq = sysctrl + SC_CPU_RESET_DREQ(cluster);
 119        sys_status = sysctrl + SC_CPU_RESET_STATUS(cluster);
 120        if (hip04_cluster_is_down(cluster)) {
 121                data = CLUSTER_DEBUG_RESET_BIT;
 122                writel_relaxed(data, sys_dreq);
 123                do {
 124                        cpu_relax();
 125                        data = readl_relaxed(sys_status);
 126                } while (data & CLUSTER_DEBUG_RESET_STATUS);
 127                hip04_set_snoop_filter(cluster, 1);
 128        }
 129
 130        data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
 131               CORE_DEBUG_RESET_BIT(cpu);
 132        writel_relaxed(data, sys_dreq);
 133        do {
 134                cpu_relax();
 135        } while (data == readl_relaxed(sys_status));
 136
 137        /*
 138         * We may fail to power up core again without this delay.
 139         * It's not mentioned in document. It's found by test.
 140         */
 141        udelay(20);
 142
 143        arch_send_wakeup_ipi_mask(cpumask_of(l_cpu));
 144
 145out:
 146        hip04_cpu_table[cluster][cpu]++;
 147        spin_unlock_irq(&boot_lock);
 148
 149        return 0;
 150}
 151
 152#ifdef CONFIG_HOTPLUG_CPU
 153static void hip04_cpu_die(unsigned int l_cpu)
 154{
 155        unsigned int mpidr, cpu, cluster;
 156        bool last_man;
 157
 158        mpidr = cpu_logical_map(l_cpu);
 159        cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
 160        cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
 161
 162        spin_lock(&boot_lock);
 163        hip04_cpu_table[cluster][cpu]--;
 164        if (hip04_cpu_table[cluster][cpu] == 1) {
 165                /* A power_up request went ahead of us. */
 166                spin_unlock(&boot_lock);
 167                return;
 168        } else if (hip04_cpu_table[cluster][cpu] > 1) {
 169                pr_err("Cluster %d CPU%d boots multiple times\n", cluster, cpu);
 170                BUG();
 171        }
 172
 173        last_man = hip04_cluster_is_down(cluster);
 174        spin_unlock(&boot_lock);
 175        if (last_man) {
 176                /* Since it's Cortex A15, disable L2 prefetching. */
 177                asm volatile(
 178                "mcr    p15, 1, %0, c15, c0, 3 \n\t"
 179                "isb    \n\t"
 180                "dsb    "
 181                : : "r" (0x400) );
 182                v7_exit_coherency_flush(all);
 183        } else {
 184                v7_exit_coherency_flush(louis);
 185        }
 186
 187        for (;;)
 188                wfi();
 189}
 190
 191static int hip04_cpu_kill(unsigned int l_cpu)
 192{
 193        unsigned int mpidr, cpu, cluster;
 194        unsigned int data, tries, count;
 195
 196        mpidr = cpu_logical_map(l_cpu);
 197        cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
 198        cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
 199        BUG_ON(cluster >= HIP04_MAX_CLUSTERS ||
 200               cpu >= HIP04_MAX_CPUS_PER_CLUSTER);
 201
 202        count = TIMEOUT_MSEC / POLL_MSEC;
 203        spin_lock_irq(&boot_lock);
 204        for (tries = 0; tries < count; tries++) {
 205                if (hip04_cpu_table[cluster][cpu])
 206                        goto err;
 207                cpu_relax();
 208                data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
 209                if (data & CORE_WFI_STATUS(cpu))
 210                        break;
 211                spin_unlock_irq(&boot_lock);
 212                /* Wait for clean L2 when the whole cluster is down. */
 213                msleep(POLL_MSEC);
 214                spin_lock_irq(&boot_lock);
 215        }
 216        if (tries >= count)
 217                goto err;
 218        data = CORE_RESET_BIT(cpu) | NEON_RESET_BIT(cpu) | \
 219               CORE_DEBUG_RESET_BIT(cpu);
 220        writel_relaxed(data, sysctrl + SC_CPU_RESET_REQ(cluster));
 221        for (tries = 0; tries < count; tries++) {
 222                cpu_relax();
 223                data = readl_relaxed(sysctrl + SC_CPU_RESET_STATUS(cluster));
 224                if (data & CORE_RESET_STATUS(cpu))
 225                        break;
 226        }
 227        if (tries >= count)
 228                goto err;
 229        if (hip04_cluster_is_down(cluster))
 230                hip04_set_snoop_filter(cluster, 0);
 231        spin_unlock_irq(&boot_lock);
 232        return 1;
 233err:
 234        spin_unlock_irq(&boot_lock);
 235        return 0;
 236}
 237#endif
 238
 239static const struct smp_operations hip04_smp_ops __initconst = {
 240        .smp_boot_secondary     = hip04_boot_secondary,
 241#ifdef CONFIG_HOTPLUG_CPU
 242        .cpu_die                = hip04_cpu_die,
 243        .cpu_kill               = hip04_cpu_kill,
 244#endif
 245};
 246
 247static bool __init hip04_cpu_table_init(void)
 248{
 249        unsigned int mpidr, cpu, cluster;
 250
 251        mpidr = read_cpuid_mpidr();
 252        cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
 253        cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
 254
 255        if (cluster >= HIP04_MAX_CLUSTERS ||
 256            cpu >= HIP04_MAX_CPUS_PER_CLUSTER) {
 257                pr_err("%s: boot CPU is out of bound!\n", __func__);
 258                return false;
 259        }
 260        hip04_set_snoop_filter(cluster, 1);
 261        hip04_cpu_table[cluster][cpu] = 1;
 262        return true;
 263}
 264
 265static int __init hip04_smp_init(void)
 266{
 267        struct device_node *np, *np_sctl, *np_fab;
 268        struct resource fab_res;
 269        void __iomem *relocation;
 270        int ret = -ENODEV;
 271
 272        np = of_find_compatible_node(NULL, NULL, "hisilicon,hip04-bootwrapper");
 273        if (!np)
 274                goto err;
 275        ret = of_property_read_u32_array(np, "boot-method",
 276                                         &hip04_boot_method[0], 4);
 277        if (ret)
 278                goto err;
 279
 280        ret = -ENODEV;
 281        np_sctl = of_find_compatible_node(NULL, NULL, "hisilicon,sysctrl");
 282        if (!np_sctl)
 283                goto err;
 284        np_fab = of_find_compatible_node(NULL, NULL, "hisilicon,hip04-fabric");
 285        if (!np_fab)
 286                goto err;
 287
 288        ret = memblock_reserve(hip04_boot_method[0], hip04_boot_method[1]);
 289        if (ret)
 290                goto err;
 291
 292        relocation = ioremap(hip04_boot_method[2], hip04_boot_method[3]);
 293        if (!relocation) {
 294                pr_err("failed to map relocation space\n");
 295                ret = -ENOMEM;
 296                goto err_reloc;
 297        }
 298        sysctrl = of_iomap(np_sctl, 0);
 299        if (!sysctrl) {
 300                pr_err("failed to get sysctrl base\n");
 301                ret = -ENOMEM;
 302                goto err_sysctrl;
 303        }
 304        ret = of_address_to_resource(np_fab, 0, &fab_res);
 305        if (ret) {
 306                pr_err("failed to get fabric base phys\n");
 307                goto err_fabric;
 308        }
 309        fabric_phys_addr = fab_res.start;
 310        sync_cache_w(&fabric_phys_addr);
 311        fabric = of_iomap(np_fab, 0);
 312        if (!fabric) {
 313                pr_err("failed to get fabric base\n");
 314                ret = -ENOMEM;
 315                goto err_fabric;
 316        }
 317
 318        if (!hip04_cpu_table_init()) {
 319                ret = -EINVAL;
 320                goto err_table;
 321        }
 322
 323        /*
 324         * Fill the instruction address that is used after secondary core
 325         * out of reset.
 326         */
 327        writel_relaxed(hip04_boot_method[0], relocation);
 328        writel_relaxed(0xa5a5a5a5, relocation + 4);     /* magic number */
 329        writel_relaxed(__pa_symbol(secondary_startup), relocation + 8);
 330        writel_relaxed(0, relocation + 12);
 331        iounmap(relocation);
 332
 333        smp_set_ops(&hip04_smp_ops);
 334        return ret;
 335err_table:
 336        iounmap(fabric);
 337err_fabric:
 338        iounmap(sysctrl);
 339err_sysctrl:
 340        iounmap(relocation);
 341err_reloc:
 342        memblock_free(hip04_boot_method[0], hip04_boot_method[1]);
 343err:
 344        return ret;
 345}
 346early_initcall(hip04_smp_init);
 347