root/arch/arm/mach-actions/platsmp.c

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

DEFINITIONS

This source file includes following definitions.
  1. s500_wakeup_secondary
  2. s500_smp_boot_secondary
  3. s500_smp_prepare_cpus

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Actions Semi Leopard
   4  *
   5  * This file is based on arm realview smp platform.
   6  *
   7  * Copyright 2012 Actions Semi Inc.
   8  * Author: Actions Semi, Inc.
   9  *
  10  * Copyright (c) 2017 Andreas Färber
  11  */
  12 
  13 #include <linux/delay.h>
  14 #include <linux/io.h>
  15 #include <linux/of.h>
  16 #include <linux/of_address.h>
  17 #include <linux/smp.h>
  18 #include <linux/soc/actions/owl-sps.h>
  19 #include <asm/cacheflush.h>
  20 #include <asm/smp_plat.h>
  21 #include <asm/smp_scu.h>
  22 
  23 #define OWL_CPU1_ADDR   0x50
  24 #define OWL_CPU1_FLAG   0x5c
  25 
  26 #define OWL_CPUx_FLAG_BOOT      0x55aa
  27 
  28 #define OWL_SPS_PG_CTL_PWR_CPU2 BIT(5)
  29 #define OWL_SPS_PG_CTL_PWR_CPU3 BIT(6)
  30 #define OWL_SPS_PG_CTL_ACK_CPU2 BIT(21)
  31 #define OWL_SPS_PG_CTL_ACK_CPU3 BIT(22)
  32 
  33 static void __iomem *scu_base_addr;
  34 static void __iomem *sps_base_addr;
  35 static void __iomem *timer_base_addr;
  36 static int ncores;
  37 
  38 static int s500_wakeup_secondary(unsigned int cpu)
  39 {
  40         int ret;
  41 
  42         if (cpu > 3)
  43                 return -EINVAL;
  44 
  45         /* The generic PM domain driver is not available this early. */
  46         switch (cpu) {
  47         case 2:
  48                 ret = owl_sps_set_pg(sps_base_addr,
  49                                      OWL_SPS_PG_CTL_PWR_CPU2,
  50                                      OWL_SPS_PG_CTL_ACK_CPU2, true);
  51                 if (ret)
  52                         return ret;
  53                 break;
  54         case 3:
  55                 ret = owl_sps_set_pg(sps_base_addr,
  56                                      OWL_SPS_PG_CTL_PWR_CPU3,
  57                                      OWL_SPS_PG_CTL_ACK_CPU3, true);
  58                 if (ret)
  59                         return ret;
  60                 break;
  61         }
  62 
  63         /* wait for CPUx to run to WFE instruction */
  64         udelay(200);
  65 
  66         writel(__pa_symbol(secondary_startup),
  67                timer_base_addr + OWL_CPU1_ADDR + (cpu - 1) * 4);
  68         writel(OWL_CPUx_FLAG_BOOT,
  69                timer_base_addr + OWL_CPU1_FLAG + (cpu - 1) * 4);
  70 
  71         dsb_sev();
  72         mb();
  73 
  74         return 0;
  75 }
  76 
  77 static int s500_smp_boot_secondary(unsigned int cpu, struct task_struct *idle)
  78 {
  79         int ret;
  80 
  81         ret = s500_wakeup_secondary(cpu);
  82         if (ret)
  83                 return ret;
  84 
  85         udelay(10);
  86 
  87         smp_send_reschedule(cpu);
  88 
  89         writel(0, timer_base_addr + OWL_CPU1_ADDR + (cpu - 1) * 4);
  90         writel(0, timer_base_addr + OWL_CPU1_FLAG + (cpu - 1) * 4);
  91 
  92         return 0;
  93 }
  94 
  95 static void __init s500_smp_prepare_cpus(unsigned int max_cpus)
  96 {
  97         struct device_node *node;
  98 
  99         node = of_find_compatible_node(NULL, NULL, "actions,s500-timer");
 100         if (!node) {
 101                 pr_err("%s: missing timer\n", __func__);
 102                 return;
 103         }
 104 
 105         timer_base_addr = of_iomap(node, 0);
 106         if (!timer_base_addr) {
 107                 pr_err("%s: could not map timer registers\n", __func__);
 108                 return;
 109         }
 110 
 111         node = of_find_compatible_node(NULL, NULL, "actions,s500-sps");
 112         if (!node) {
 113                 pr_err("%s: missing sps\n", __func__);
 114                 return;
 115         }
 116 
 117         sps_base_addr = of_iomap(node, 0);
 118         if (!sps_base_addr) {
 119                 pr_err("%s: could not map sps registers\n", __func__);
 120                 return;
 121         }
 122 
 123         if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
 124                 node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
 125                 if (!node) {
 126                         pr_err("%s: missing scu\n", __func__);
 127                         return;
 128                 }
 129 
 130                 scu_base_addr = of_iomap(node, 0);
 131                 if (!scu_base_addr) {
 132                         pr_err("%s: could not map scu registers\n", __func__);
 133                         return;
 134                 }
 135 
 136                 /*
 137                  * While the number of cpus is gathered from dt, also get the
 138                  * number of cores from the scu to verify this value when
 139                  * booting the cores.
 140                  */
 141                 ncores = scu_get_core_count(scu_base_addr);
 142                 pr_debug("%s: ncores %d\n", __func__, ncores);
 143 
 144                 scu_enable(scu_base_addr);
 145         }
 146 }
 147 
 148 static const struct smp_operations s500_smp_ops __initconst = {
 149         .smp_prepare_cpus = s500_smp_prepare_cpus,
 150         .smp_boot_secondary = s500_smp_boot_secondary,
 151 };
 152 CPU_METHOD_OF_DECLARE(s500_smp, "actions,s500-smp", &s500_smp_ops);

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