cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

platsmp.c (3474B)


      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
     33static void __iomem *scu_base_addr;
     34static void __iomem *sps_base_addr;
     35static void __iomem *timer_base_addr;
     36static int ncores;
     37
     38static 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
     77static 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
     95static 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
    148static 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};
    152CPU_METHOD_OF_DECLARE(s500_smp, "actions,s500-smp", &s500_smp_ops);