linux/arch/arm/mach-zx/platsmp.c
<<
>>
Prefs
   1/*
   2 * Copyright 2014 Linaro Ltd.
   3 * Copyright (C) 2014 ZTE Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 */
   9
  10#include <linux/delay.h>
  11#include <linux/errno.h>
  12#include <linux/init.h>
  13#include <linux/io.h>
  14#include <linux/jiffies.h>
  15#include <linux/of.h>
  16#include <linux/of_address.h>
  17#include <linux/smp.h>
  18
  19#include <asm/cacheflush.h>
  20#include <asm/cp15.h>
  21#include <asm/fncpy.h>
  22#include <asm/proc-fns.h>
  23#include <asm/smp_scu.h>
  24#include <asm/smp_plat.h>
  25
  26#include "core.h"
  27
  28#define AON_SYS_CTRL_RESERVED1          0xa8
  29
  30#define BUS_MATRIX_REMAP_CONFIG         0x00
  31
  32#define PCU_CPU0_CTRL                   0x00
  33#define PCU_CPU1_CTRL                   0x04
  34#define PCU_CPU1_ST                     0x0c
  35#define PCU_GLOBAL_CTRL                 0x14
  36#define PCU_EXPEND_CONTROL              0x34
  37
  38#define ZX_IRAM_BASE                    0x00200000
  39
  40static void __iomem *pcu_base;
  41static void __iomem *matrix_base;
  42static void __iomem *scu_base;
  43
  44void __init zx_smp_prepare_cpus(unsigned int max_cpus)
  45{
  46        struct device_node *np;
  47        unsigned long base = 0;
  48        void __iomem *aonsysctrl_base;
  49        void __iomem *sys_iram;
  50
  51        base = scu_a9_get_base();
  52        scu_base = ioremap(base, SZ_256);
  53        if (!scu_base) {
  54                pr_err("%s: failed to map scu\n", __func__);
  55                return;
  56        }
  57
  58        scu_enable(scu_base);
  59
  60        np = of_find_compatible_node(NULL, NULL, "zte,sysctrl");
  61        if (!np) {
  62                pr_err("%s: failed to find sysctrl node\n", __func__);
  63                return;
  64        }
  65
  66        aonsysctrl_base = of_iomap(np, 0);
  67        if (!aonsysctrl_base) {
  68                pr_err("%s: failed to map aonsysctrl\n", __func__);
  69                of_node_put(np);
  70                return;
  71        }
  72
  73        /*
  74         * Write the address of secondary startup into the
  75         * system-wide flags register. The BootMonitor waits
  76         * until it receives a soft interrupt, and then the
  77         * secondary CPU branches to this address.
  78         */
  79        __raw_writel(__pa_symbol(zx_secondary_startup),
  80                     aonsysctrl_base + AON_SYS_CTRL_RESERVED1);
  81
  82        iounmap(aonsysctrl_base);
  83        of_node_put(np);
  84
  85        np = of_find_compatible_node(NULL, NULL, "zte,zx296702-pcu");
  86        pcu_base = of_iomap(np, 0);
  87        of_node_put(np);
  88        WARN_ON(!pcu_base);
  89
  90        np = of_find_compatible_node(NULL, NULL, "zte,zx-bus-matrix");
  91        matrix_base = of_iomap(np, 0);
  92        of_node_put(np);
  93        WARN_ON(!matrix_base);
  94
  95        /* Map the first 4 KB IRAM for suspend usage */
  96        sys_iram = __arm_ioremap_exec(ZX_IRAM_BASE, PAGE_SIZE, false);
  97        zx_secondary_startup_pa = __pa_symbol(zx_secondary_startup);
  98        fncpy(sys_iram, &zx_resume_jump, zx_suspend_iram_sz);
  99}
 100
 101static int zx_boot_secondary(unsigned int cpu, struct task_struct *idle)
 102{
 103        static bool first_boot = true;
 104
 105        if (first_boot) {
 106                arch_send_wakeup_ipi_mask(cpumask_of(cpu));
 107                first_boot = false;
 108                return 0;
 109        }
 110
 111        /* Swap the base address mapping between IRAM and IROM */
 112        writel_relaxed(0x1, matrix_base + BUS_MATRIX_REMAP_CONFIG);
 113
 114        /* Power on CPU1 */
 115        writel_relaxed(0x0, pcu_base + PCU_CPU1_CTRL);
 116
 117        /* Wait for power on ack */
 118        while (readl_relaxed(pcu_base + PCU_CPU1_ST) & 0x4)
 119                cpu_relax();
 120
 121        /* Swap back the mapping of IRAM and IROM */
 122        writel_relaxed(0x0, matrix_base + BUS_MATRIX_REMAP_CONFIG);
 123
 124        return 0;
 125}
 126
 127#ifdef CONFIG_HOTPLUG_CPU
 128static inline void cpu_enter_lowpower(void)
 129{
 130        unsigned int v;
 131
 132        asm volatile(
 133                "mcr    p15, 0, %1, c7, c5, 0\n"
 134        "       mcr     p15, 0, %1, c7, c10, 4\n"
 135        /*
 136         * Turn off coherency
 137         */
 138        "       mrc     p15, 0, %0, c1, c0, 1\n"
 139        "       bic     %0, %0, %3\n"
 140        "       mcr     p15, 0, %0, c1, c0, 1\n"
 141        "       mrc     p15, 0, %0, c1, c0, 0\n"
 142        "       bic     %0, %0, %2\n"
 143        "       mcr     p15, 0, %0, c1, c0, 0\n"
 144          : "=&r" (v)
 145          : "r" (0), "Ir" (CR_C), "Ir" (0x40)
 146          : "cc");
 147}
 148
 149static int zx_cpu_kill(unsigned int cpu)
 150{
 151        unsigned long timeout = jiffies + msecs_to_jiffies(2000);
 152
 153        writel_relaxed(0x2, pcu_base + PCU_CPU1_CTRL);
 154
 155        while ((readl_relaxed(pcu_base + PCU_CPU1_ST) & 0x3) != 0x0) {
 156                if (time_after(jiffies, timeout)) {
 157                        pr_err("*** cpu1 poweroff timeout\n");
 158                        break;
 159                }
 160        }
 161        return 1;
 162}
 163
 164static void zx_cpu_die(unsigned int cpu)
 165{
 166        scu_power_mode(scu_base, SCU_PM_POWEROFF);
 167        cpu_enter_lowpower();
 168
 169        while (1)
 170                cpu_do_idle();
 171}
 172#endif
 173
 174static void zx_secondary_init(unsigned int cpu)
 175{
 176        scu_power_mode(scu_base, SCU_PM_NORMAL);
 177}
 178
 179static const struct smp_operations zx_smp_ops __initconst = {
 180        .smp_prepare_cpus       = zx_smp_prepare_cpus,
 181        .smp_secondary_init     = zx_secondary_init,
 182        .smp_boot_secondary     = zx_boot_secondary,
 183#ifdef CONFIG_HOTPLUG_CPU
 184        .cpu_kill               = zx_cpu_kill,
 185        .cpu_die                = zx_cpu_die,
 186#endif
 187};
 188
 189CPU_METHOD_OF_DECLARE(zx_smp, "zte,zx296702-smp", &zx_smp_ops);
 190