blob: 8bbe97f24ce6b33f0d6c3319494f0c4837ae61f3 [file]
/*
* Copyright Linux Kernel team
* Copyright 2020, HENSOLDT Cyber GmbH
*
* SPDX-License-Identifier: GPL-2.0-only
*
* The code in here is loosely derived from the Linux kernel
*/
#include <autoconf.h>
#include <elfloader/gen_config.h>
#include <elfloader_common.h>
#include <devices_gen.h>
#include <drivers/common.h>
#include <drivers/smp.h>
#include <printf.h>
#include <armv/machine.h>
#include <scu.h>
#include <abort.h>
#define REG(base, offs) ((volatile word_t *)(((uintptr_t)base) + (offs)))
#define SRC_SCR 0x000
#define SRC_GPR1 0x020
#define BP_SRC_SCR_WARM_RESET_ENABLE 0
#define BP_SRC_SCR_CORE1_RST 14
#define BP_SRC_SCR_CORE1_ENABLE 22
UNUSED static void *get_scu_base(void)
{
void *scu = NULL;
#if CONFIG_ARCH_AARCH32
asm("mrc p15, 4, %0, c15, c0, 0" : "=r"(scu));
#else
abort();
#endif
return scu;
}
UNUSED static void src_init(volatile void *mmio)
{
uint32_t val;
val = *REG(mmio, SRC_SCR);
val &= ~(1 << BP_SRC_SCR_WARM_RESET_ENABLE);
*REG(mmio, SRC_SCR) = val;
}
static int smp_imx6_cpu_on(UNUSED struct elfloader_device *dev,
UNUSED struct elfloader_cpu *cpu, UNUSED void *entry, UNUSED void *stack)
{
#if CONFIG_MAX_NUM_NODES > 1
volatile void *mmio = dev->region_bases[0];
secondary_data.entry = entry;
secondary_data.stack = stack;
*REG(mmio, SRC_GPR1 + (cpu->cpu_id * 8)) = (word_t)secondary_startup;
dsb();
if (cpu->cpu_id == 0) {
/* there is no core0_enable bit in the SCR register */
printf("error: cannot power on CPU 0!\n");
return -1;
}
uint32_t mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + (cpu->cpu_id - 1));
*REG(mmio, SRC_SCR) |= mask;
return 0;
#else
return -1;
#endif
}
static int smp_imx6_init(UNUSED struct elfloader_device *dev,
UNUSED void *match_data)
{
#if CONFIG_MAX_NUM_NODES > 1
void *scu = get_scu_base();
scu_enable(scu);
src_init(dev->region_bases[0]);
smp_register_handler(dev);
#endif
return 0;
}
static const struct dtb_match_table smp_imx6_matches[] = {
{ .compatible = "fsl,imx6q-src" },
{ .compatible = "fsl,imx6sx-src" },
{ .compatible = NULL /* sentinel */ },
};
static const struct elfloader_smp_ops smp_imx6_ops = {
.enable_method = NULL,
.cpu_on = &smp_imx6_cpu_on,
};
static const struct elfloader_driver smp_imx6 = {
.match_table = smp_imx6_matches,
.type = DRIVER_SMP,
.init = &smp_imx6_init,
.ops = &smp_imx6_ops,
};
ELFLOADER_DRIVER(smp_imx6);