mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-27 15:24:54 +00:00
Merge changes from topic "arm_fpga_auto" into integration
* changes: feat(arm_fpga): write UART baud base clock frequency into DTB feat(arm_fpga): query PL011 to learn system frequency refactor(arm_fpga): move command line code into separate function fix(fdt): avoid output on missing DT property feat(arm_fpga): add ITS autodetection feat(arm_fpga): determine GICR base by probing feat(gicv3): introduce GIC component identification feat(libfdt): also allow changing base address fix(arm_fpga): avoid re-linking from executable ELF file
This commit is contained in:
commit
683bb4d7bd
11 changed files with 348 additions and 78 deletions
|
@ -398,6 +398,7 @@ int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
|
||||||
* fdt_adjust_gic_redist() - Adjust GICv3 redistributor size
|
* fdt_adjust_gic_redist() - Adjust GICv3 redistributor size
|
||||||
* @dtb: Pointer to the DT blob in memory
|
* @dtb: Pointer to the DT blob in memory
|
||||||
* @nr_cores: Number of CPU cores on this system.
|
* @nr_cores: Number of CPU cores on this system.
|
||||||
|
* @gicr_base: Base address of the first GICR frame, or ~0 if unchanged
|
||||||
* @gicr_frame_size: Size of the GICR frame per core
|
* @gicr_frame_size: Size of the GICR frame per core
|
||||||
*
|
*
|
||||||
* On a GICv3 compatible interrupt controller, the redistributor provides
|
* On a GICv3 compatible interrupt controller, the redistributor provides
|
||||||
|
@ -410,17 +411,19 @@ int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
|
||||||
* A GICv4 compatible redistributor uses four 64K pages per core, whereas GICs
|
* A GICv4 compatible redistributor uses four 64K pages per core, whereas GICs
|
||||||
* without support for direct injection of virtual interrupts use two 64K pages.
|
* without support for direct injection of virtual interrupts use two 64K pages.
|
||||||
* The @gicr_frame_size parameter should be 262144 and 131072, respectively.
|
* The @gicr_frame_size parameter should be 262144 and 131072, respectively.
|
||||||
|
* Also optionally allow adjusting the GICR frame base address, when this is
|
||||||
|
* different due to ITS frames between distributor and redistributor.
|
||||||
*
|
*
|
||||||
* Return: 0 on success, negative error value otherwise.
|
* Return: 0 on success, negative error value otherwise.
|
||||||
*/
|
*/
|
||||||
int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores,
|
int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores,
|
||||||
unsigned int gicr_frame_size)
|
uintptr_t gicr_base, unsigned int gicr_frame_size)
|
||||||
{
|
{
|
||||||
int offset = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-v3");
|
int offset = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-v3");
|
||||||
uint64_t redist_size_64;
|
uint64_t reg_64;
|
||||||
uint32_t redist_size_32;
|
uint32_t reg_32;
|
||||||
void *val;
|
void *val;
|
||||||
int parent;
|
int parent, ret;
|
||||||
int ac, sc;
|
int ac, sc;
|
||||||
|
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
|
@ -437,13 +440,34 @@ int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc == 1) {
|
if (gicr_base != INVALID_BASE_ADDR) {
|
||||||
redist_size_32 = cpu_to_fdt32(nr_cores * gicr_frame_size);
|
if (ac == 1) {
|
||||||
val = &redist_size_32;
|
reg_32 = cpu_to_fdt32(gicr_base);
|
||||||
|
val = ®_32;
|
||||||
} else {
|
} else {
|
||||||
redist_size_64 = cpu_to_fdt64(nr_cores *
|
reg_64 = cpu_to_fdt64(gicr_base);
|
||||||
(uint64_t)gicr_frame_size);
|
val = ®_64;
|
||||||
val = &redist_size_64;
|
}
|
||||||
|
/*
|
||||||
|
* The redistributor base address is the second address in
|
||||||
|
* the "reg" entry, so we have to skip one address and one
|
||||||
|
* size cell.
|
||||||
|
*/
|
||||||
|
ret = fdt_setprop_inplace_namelen_partial(dtb, offset,
|
||||||
|
"reg", 3,
|
||||||
|
(ac + sc) * 4,
|
||||||
|
val, ac * 4);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc == 1) {
|
||||||
|
reg_32 = cpu_to_fdt32(nr_cores * gicr_frame_size);
|
||||||
|
val = ®_32;
|
||||||
|
} else {
|
||||||
|
reg_64 = cpu_to_fdt64(nr_cores * (uint64_t)gicr_frame_size);
|
||||||
|
val = ®_64;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -35,7 +35,7 @@ int fdt_read_uint32_array(const void *dtb, int node, const char *prop_name,
|
||||||
/* Access property and obtain its length (in bytes) */
|
/* Access property and obtain its length (in bytes) */
|
||||||
prop = fdt_getprop(dtb, node, prop_name, &value_len);
|
prop = fdt_getprop(dtb, node, prop_name, &value_len);
|
||||||
if (prop == NULL) {
|
if (prop == NULL) {
|
||||||
WARN("Couldn't find property %s in dtb\n", prop_name);
|
VERBOSE("Couldn't find property %s in dtb\n", prop_name);
|
||||||
return -FDT_ERR_NOTFOUND;
|
return -FDT_ERR_NOTFOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -393,3 +393,18 @@ unsigned int gicv3_rdistif_get_number_frames(const uintptr_t gicr_frame)
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int gicv3_get_component_partnum(const uintptr_t gic_frame)
|
||||||
|
{
|
||||||
|
unsigned int part_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The lower 8 bits of PIDR0, complemented by the lower 4 bits of
|
||||||
|
* PIDR1 contain a part number identifying the GIC component at a
|
||||||
|
* particular base address.
|
||||||
|
*/
|
||||||
|
part_id = mmio_read_32(gic_frame + GICD_PIDR0_GICV3) & 0xff;
|
||||||
|
part_id |= (mmio_read_32(gic_frame + GICD_PIDR1_GICV3) << 8) & 0xf00;
|
||||||
|
|
||||||
|
return part_id;
|
||||||
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
|
|
||||||
timer {
|
timer {
|
||||||
compatible = "arm,armv8-timer";
|
compatible = "arm,armv8-timer";
|
||||||
clock-frequency = <10000000>;
|
|
||||||
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
|
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
|
||||||
<GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
|
<GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
|
||||||
<GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
|
<GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
|
||||||
|
@ -98,5 +97,12 @@
|
||||||
/* The GICR size will be adjusted at runtime to match the cores. */
|
/* The GICR size will be adjusted at runtime to match the cores. */
|
||||||
<0x0 0x30040000 0x0 0x00020000>; /* GICR for one core */
|
<0x0 0x30040000 0x0 0x00020000>; /* GICR for one core */
|
||||||
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
|
||||||
|
its: msi-controller@30040000 {
|
||||||
|
compatible = "arm,gic-v3-its";
|
||||||
|
reg = <0x0 0x30040000 0x0 0x40000>;
|
||||||
|
#msi-cells = <1>;
|
||||||
|
msi-controller;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,13 +7,15 @@
|
||||||
#ifndef FDT_FIXUP_H
|
#ifndef FDT_FIXUP_H
|
||||||
#define FDT_FIXUP_H
|
#define FDT_FIXUP_H
|
||||||
|
|
||||||
|
#define INVALID_BASE_ADDR ((uintptr_t)~0UL)
|
||||||
|
|
||||||
int dt_add_psci_node(void *fdt);
|
int dt_add_psci_node(void *fdt);
|
||||||
int dt_add_psci_cpu_enable_methods(void *fdt);
|
int dt_add_psci_cpu_enable_methods(void *fdt);
|
||||||
int fdt_add_reserved_memory(void *dtb, const char *node_name,
|
int fdt_add_reserved_memory(void *dtb, const char *node_name,
|
||||||
uintptr_t base, size_t size);
|
uintptr_t base, size_t size);
|
||||||
int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
|
int fdt_add_cpus_node(void *dtb, unsigned int afflv0,
|
||||||
unsigned int afflv1, unsigned int afflv2);
|
unsigned int afflv1, unsigned int afflv2);
|
||||||
int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores,
|
int fdt_adjust_gic_redist(void *dtb, unsigned int nr_cores, uintptr_t gicr_base,
|
||||||
unsigned int gicr_frame_size);
|
unsigned int gicr_frame_size);
|
||||||
|
|
||||||
#endif /* FDT_FIXUP_H */
|
#endif /* FDT_FIXUP_H */
|
||||||
|
|
|
@ -21,4 +21,8 @@
|
||||||
#define IIDR_MODEL_ARM_GIC_600AE U(0x0300043b)
|
#define IIDR_MODEL_ARM_GIC_600AE U(0x0300043b)
|
||||||
#define IIDR_MODEL_ARM_GIC_700 U(0x0400043b)
|
#define IIDR_MODEL_ARM_GIC_700 U(0x0400043b)
|
||||||
|
|
||||||
|
#define PIDR_COMPONENT_ARM_DIST U(0x492)
|
||||||
|
#define PIDR_COMPONENT_ARM_REDIST U(0x493)
|
||||||
|
#define PIDR_COMPONENT_ARM_ITS U(0x494)
|
||||||
|
|
||||||
#endif /* ARM_GICV3_COMMON_H */
|
#endif /* ARM_GICV3_COMMON_H */
|
||||||
|
|
|
@ -104,6 +104,8 @@
|
||||||
#define GICD_IROUTER U(0x6000)
|
#define GICD_IROUTER U(0x6000)
|
||||||
#define GICD_IROUTERE U(0x8000)
|
#define GICD_IROUTERE U(0x8000)
|
||||||
|
|
||||||
|
#define GICD_PIDR0_GICV3 U(0xffe0)
|
||||||
|
#define GICD_PIDR1_GICV3 U(0xffe4)
|
||||||
#define GICD_PIDR2_GICV3 U(0xffe8)
|
#define GICD_PIDR2_GICV3 U(0xffe8)
|
||||||
|
|
||||||
#define IGRPMODR_SHIFT 5
|
#define IGRPMODR_SHIFT 5
|
||||||
|
@ -301,6 +303,8 @@
|
||||||
#define GITS_CTLR_ENABLED_BIT BIT_32(0)
|
#define GITS_CTLR_ENABLED_BIT BIT_32(0)
|
||||||
#define GITS_CTLR_QUIESCENT_BIT BIT_32(1)
|
#define GITS_CTLR_QUIESCENT_BIT BIT_32(1)
|
||||||
|
|
||||||
|
#define GITS_TYPER_VSGI BIT_64(39)
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -324,6 +328,8 @@ static inline uintptr_t gicv3_redist_size(uint64_t typer_val)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int gicv3_get_component_partnum(const uintptr_t gic_frame);
|
||||||
|
|
||||||
static inline bool gicv3_is_intr_id_special_identifier(unsigned int id)
|
static inline bool gicv3_is_intr_id_special_identifier(unsigned int id)
|
||||||
{
|
{
|
||||||
return (id >= PENDING_G1S_INTID) && (id <= GIC_SPURIOUS_INTERRUPT);
|
return (id >= PENDING_G1S_INTID) && (id <= GIC_SPURIOUS_INTERRUPT);
|
||||||
|
|
|
@ -15,11 +15,11 @@
|
||||||
OUTPUT_FORMAT("elf64-littleaarch64")
|
OUTPUT_FORMAT("elf64-littleaarch64")
|
||||||
OUTPUT_ARCH(aarch64)
|
OUTPUT_ARCH(aarch64)
|
||||||
|
|
||||||
INPUT(./bl31/bl31.elf)
|
|
||||||
INPUT(./rom_trampoline.o)
|
INPUT(./rom_trampoline.o)
|
||||||
INPUT(./kernel_trampoline.o)
|
INPUT(./kernel_trampoline.o)
|
||||||
|
|
||||||
TARGET(binary)
|
TARGET(binary)
|
||||||
|
INPUT(./bl31.bin)
|
||||||
INPUT(./fdts/arm_fpga.dtb)
|
INPUT(./fdts/arm_fpga.dtb)
|
||||||
|
|
||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
|
@ -33,7 +33,7 @@ SECTIONS
|
||||||
|
|
||||||
.bl31 (BL31_BASE): {
|
.bl31 (BL31_BASE): {
|
||||||
ASSERT(. == ALIGN(PAGE_SIZE), "BL31_BASE is not page aligned");
|
ASSERT(. == ALIGN(PAGE_SIZE), "BL31_BASE is not page aligned");
|
||||||
*bl31.elf(.text* .data* .rodata* ro* .bss*)
|
*bl31.bin
|
||||||
}
|
}
|
||||||
|
|
||||||
.dtb (FPGA_PRELOADED_DTB_BASE): {
|
.dtb (FPGA_PRELOADED_DTB_BASE): {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <drivers/delay_timer.h>
|
#include <drivers/delay_timer.h>
|
||||||
#include <drivers/generic_delay_timer.h>
|
#include <drivers/generic_delay_timer.h>
|
||||||
#include <lib/extensions/spe.h>
|
#include <lib/extensions/spe.h>
|
||||||
|
#include <lib/mmio.h>
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
|
|
||||||
#include "fpga_private.h"
|
#include "fpga_private.h"
|
||||||
|
@ -20,6 +21,7 @@
|
||||||
#include <platform_def.h>
|
#include <platform_def.h>
|
||||||
|
|
||||||
static entry_point_info_t bl33_image_ep_info;
|
static entry_point_info_t bl33_image_ep_info;
|
||||||
|
static unsigned int system_freq;
|
||||||
volatile uint32_t secondary_core_spinlock;
|
volatile uint32_t secondary_core_spinlock;
|
||||||
|
|
||||||
uintptr_t plat_get_ns_image_entrypoint(void)
|
uintptr_t plat_get_ns_image_entrypoint(void)
|
||||||
|
@ -118,18 +120,187 @@ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int plat_get_syscnt_freq2(void)
|
/*
|
||||||
{
|
* Even though we sell the FPGA UART as an SBSA variant, it is actually
|
||||||
const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
|
* a full fledged PL011. So the baudrate divider registers exist.
|
||||||
int node;
|
*/
|
||||||
|
#ifndef UARTIBRD
|
||||||
|
#define UARTIBRD 0x024
|
||||||
|
#define UARTFBRD 0x028
|
||||||
|
#endif
|
||||||
|
|
||||||
node = fdt_node_offset_by_compatible(fdt, 0, "arm,armv8-timer");
|
/* Round an integer to the closest multiple of a value. */
|
||||||
if (node < 0) {
|
static unsigned int round_multiple(unsigned int x, unsigned int multiple)
|
||||||
return FPGA_DEFAULT_TIMER_FREQUENCY;
|
{
|
||||||
|
if (multiple < 2) {
|
||||||
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fdt_read_uint32_default(fdt, node, "clock-frequency",
|
return ((x + (multiple / 2 - 1)) / multiple) * multiple;
|
||||||
FPGA_DEFAULT_TIMER_FREQUENCY);
|
}
|
||||||
|
|
||||||
|
#define PL011_FRAC_SHIFT 6
|
||||||
|
#define FPGA_DEFAULT_BAUDRATE 38400
|
||||||
|
#define PL011_OVERSAMPLING 16
|
||||||
|
static unsigned int pl011_freq_from_divider(unsigned int divider)
|
||||||
|
{
|
||||||
|
unsigned int freq;
|
||||||
|
|
||||||
|
freq = divider * FPGA_DEFAULT_BAUDRATE * PL011_OVERSAMPLING;
|
||||||
|
|
||||||
|
return freq >> PL011_FRAC_SHIFT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The FPGAs run most peripherals from one main clock, among them the CPUs,
|
||||||
|
* the arch timer, and the UART baud base clock.
|
||||||
|
* The SCP knows this frequency and programs the UART clock divider for a
|
||||||
|
* 38400 bps baudrate. Recalculate the base input clock from there.
|
||||||
|
*/
|
||||||
|
static unsigned int fpga_get_system_frequency(void)
|
||||||
|
{
|
||||||
|
const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
|
||||||
|
int node, err;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the arch timer DT node has an explicit clock-frequency property
|
||||||
|
* set, use that, to allow people overriding auto-detection.
|
||||||
|
*/
|
||||||
|
node = fdt_node_offset_by_compatible(fdt, 0, "arm,armv8-timer");
|
||||||
|
if (node >= 0) {
|
||||||
|
uint32_t freq;
|
||||||
|
|
||||||
|
err = fdt_read_uint32(fdt, node, "clock-frequency", &freq);
|
||||||
|
if (err >= 0) {
|
||||||
|
return freq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node = fdt_node_offset_by_compatible(fdt, 0, "arm,pl011");
|
||||||
|
if (node >= 0) {
|
||||||
|
uintptr_t pl011_base;
|
||||||
|
unsigned int divider;
|
||||||
|
|
||||||
|
err = fdt_get_reg_props_by_index(fdt, node, 0,
|
||||||
|
&pl011_base, NULL);
|
||||||
|
if (err >= 0) {
|
||||||
|
divider = mmio_read_32(pl011_base + UARTIBRD);
|
||||||
|
divider <<= PL011_FRAC_SHIFT;
|
||||||
|
divider += mmio_read_32(pl011_base + UARTFBRD);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The result won't be exact, due to rounding errors,
|
||||||
|
* but the input frequency was a multiple of 250 KHz.
|
||||||
|
*/
|
||||||
|
return round_multiple(pl011_freq_from_divider(divider),
|
||||||
|
250000);
|
||||||
|
} else {
|
||||||
|
WARN("Cannot read PL011 MMIO base\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WARN("No PL011 DT node\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No PL011 DT node or calculation failed. */
|
||||||
|
return FPGA_DEFAULT_TIMER_FREQUENCY;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int plat_get_syscnt_freq2(void)
|
||||||
|
{
|
||||||
|
if (system_freq == 0U) {
|
||||||
|
system_freq = fpga_get_system_frequency();
|
||||||
|
}
|
||||||
|
|
||||||
|
return system_freq;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fpga_dtb_update_clock(void *fdt, unsigned int freq)
|
||||||
|
{
|
||||||
|
uint32_t freq_dtb = fdt32_to_cpu(freq);
|
||||||
|
uint32_t phandle;
|
||||||
|
int node, err;
|
||||||
|
|
||||||
|
node = fdt_node_offset_by_compatible(fdt, 0, "arm,pl011");
|
||||||
|
if (node < 0) {
|
||||||
|
WARN("%s(): No PL011 DT node found\n", __func__);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_read_uint32(fdt, node, "clocks", &phandle);
|
||||||
|
if (err != 0) {
|
||||||
|
WARN("Cannot find clocks property\n");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = fdt_node_offset_by_phandle(fdt, phandle);
|
||||||
|
if (node < 0) {
|
||||||
|
WARN("Cannot get phandle\n");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_setprop_inplace(fdt, node,
|
||||||
|
"clock-frequency",
|
||||||
|
&freq_dtb,
|
||||||
|
sizeof(freq_dtb));
|
||||||
|
if (err < 0) {
|
||||||
|
WARN("Could not update DT baud clock frequency\n");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CMDLINE_SIGNATURE "CMD:"
|
||||||
|
|
||||||
|
static int fpga_dtb_set_commandline(void *fdt, const char *cmdline)
|
||||||
|
{
|
||||||
|
int chosen;
|
||||||
|
const char *eol;
|
||||||
|
char nul = 0;
|
||||||
|
int slen, err;
|
||||||
|
|
||||||
|
chosen = fdt_add_subnode(fdt, 0, "chosen");
|
||||||
|
if (chosen == -FDT_ERR_EXISTS) {
|
||||||
|
chosen = fdt_path_offset(fdt, "/chosen");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chosen < 0) {
|
||||||
|
return chosen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is most likely an EOL at the end of the
|
||||||
|
* command line, make sure we terminate the line there.
|
||||||
|
* We can't replace the EOL with a NUL byte in the
|
||||||
|
* source, as this is in read-only memory. So we first
|
||||||
|
* create the property without any termination, then
|
||||||
|
* append a single NUL byte.
|
||||||
|
*/
|
||||||
|
eol = strchr(cmdline, '\n');
|
||||||
|
if (eol == NULL) {
|
||||||
|
eol = strchr(cmdline, 0);
|
||||||
|
}
|
||||||
|
/* Skip the signature and omit the EOL/NUL byte. */
|
||||||
|
slen = eol - (cmdline + strlen(CMDLINE_SIGNATURE));
|
||||||
|
/*
|
||||||
|
* Let's limit the size of the property, just in case
|
||||||
|
* we find the signature by accident. The Linux kernel
|
||||||
|
* limits to 4096 characters at most (in fact 2048 for
|
||||||
|
* arm64), so that sounds like a reasonable number.
|
||||||
|
*/
|
||||||
|
if (slen > 4095) {
|
||||||
|
slen = 4095;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fdt_setprop(fdt, chosen, "bootargs",
|
||||||
|
cmdline + strlen(CMDLINE_SIGNATURE), slen);
|
||||||
|
if (err != 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fdt_appendprop(fdt, chosen, "bootargs", &nul, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fpga_prepare_dtb(void)
|
static void fpga_prepare_dtb(void)
|
||||||
|
@ -151,55 +322,13 @@ static void fpga_prepare_dtb(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for the command line signature. */
|
/* Check for the command line signature. */
|
||||||
if (!strncmp(cmdline, "CMD:", 4)) {
|
if (!strncmp(cmdline, CMDLINE_SIGNATURE, strlen(CMDLINE_SIGNATURE))) {
|
||||||
int chosen;
|
err = fpga_dtb_set_commandline(fdt, cmdline);
|
||||||
|
if (err == 0) {
|
||||||
INFO("using command line at 0x%x\n", FPGA_PRELOADED_CMD_LINE);
|
INFO("using command line at 0x%x\n",
|
||||||
|
FPGA_PRELOADED_CMD_LINE);
|
||||||
chosen = fdt_add_subnode(fdt, 0, "chosen");
|
|
||||||
if (chosen == -FDT_ERR_EXISTS) {
|
|
||||||
chosen = fdt_path_offset(fdt, "/chosen");
|
|
||||||
}
|
|
||||||
if (chosen < 0) {
|
|
||||||
ERROR("cannot find /chosen node: %d\n", chosen);
|
|
||||||
} else {
|
} else {
|
||||||
const char *eol;
|
ERROR("failed to put command line into DTB: %d\n", err);
|
||||||
char nul = 0;
|
|
||||||
int slen;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There is most likely an EOL at the end of the
|
|
||||||
* command line, make sure we terminate the line there.
|
|
||||||
* We can't replace the EOL with a NUL byte in the
|
|
||||||
* source, as this is in read-only memory. So we first
|
|
||||||
* create the property without any termination, then
|
|
||||||
* append a single NUL byte.
|
|
||||||
*/
|
|
||||||
eol = strchr(cmdline, '\n');
|
|
||||||
if (!eol) {
|
|
||||||
eol = strchr(cmdline, 0);
|
|
||||||
}
|
|
||||||
/* Skip the signature and omit the EOL/NUL byte. */
|
|
||||||
slen = eol - (cmdline + 4);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Let's limit the size of the property, just in case
|
|
||||||
* we find the signature by accident. The Linux kernel
|
|
||||||
* limits to 4096 characters at most (in fact 2048 for
|
|
||||||
* arm64), so that sounds like a reasonable number.
|
|
||||||
*/
|
|
||||||
if (slen > 4095) {
|
|
||||||
slen = 4095;
|
|
||||||
}
|
|
||||||
err = fdt_setprop(fdt, chosen, "bootargs",
|
|
||||||
cmdline + 4, slen);
|
|
||||||
if (!err) {
|
|
||||||
err = fdt_appendprop(fdt, chosen, "bootargs",
|
|
||||||
&nul, 1);
|
|
||||||
}
|
|
||||||
if (err) {
|
|
||||||
ERROR("Could not set command line: %d\n", err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,6 +353,7 @@ static void fpga_prepare_dtb(void)
|
||||||
INFO("Adjusting GICR DT region to cover %u cores\n",
|
INFO("Adjusting GICR DT region to cover %u cores\n",
|
||||||
nr_cores);
|
nr_cores);
|
||||||
err = fdt_adjust_gic_redist(fdt, nr_cores,
|
err = fdt_adjust_gic_redist(fdt, nr_cores,
|
||||||
|
fpga_get_redist_base(),
|
||||||
fpga_get_redist_size());
|
fpga_get_redist_size());
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
ERROR("Error %d fixing up GIC DT node\n", err);
|
ERROR("Error %d fixing up GIC DT node\n", err);
|
||||||
|
@ -231,6 +361,8 @@ static void fpga_prepare_dtb(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fpga_dtb_update_clock(fdt, system_freq);
|
||||||
|
|
||||||
/* Check whether we support the SPE PMU. Remove the DT node if not. */
|
/* Check whether we support the SPE PMU. Remove the DT node if not. */
|
||||||
if (!spe_supported()) {
|
if (!spe_supported()) {
|
||||||
int node = fdt_node_offset_by_compatible(fdt, 0,
|
int node = fdt_node_offset_by_compatible(fdt, 0,
|
||||||
|
@ -241,6 +373,16 @@ static void fpga_prepare_dtb(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check whether we have an ITS. Remove the DT node if not. */
|
||||||
|
if (!fpga_has_its()) {
|
||||||
|
int node = fdt_node_offset_by_compatible(fdt, 0,
|
||||||
|
"arm,gic-v3-its");
|
||||||
|
|
||||||
|
if (node >= 0) {
|
||||||
|
fdt_del_node(fdt, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = fdt_pack(fdt);
|
err = fdt_pack(fdt);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
ERROR("Failed to pack Device Tree at %p: error %d\n", fdt, err);
|
ERROR("Failed to pack Device Tree at %p: error %d\n", fdt, err);
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
|
* Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <common/debug.h>
|
#include <common/debug.h>
|
||||||
#include <common/fdt_wrappers.h>
|
#include <common/fdt_wrappers.h>
|
||||||
#include <drivers/arm/gicv3.h>
|
#include <drivers/arm/arm_gicv3_common.h>
|
||||||
#include <drivers/arm/gic_common.h>
|
#include <drivers/arm/gic_common.h>
|
||||||
|
#include <drivers/arm/gicv3.h>
|
||||||
#include <lib/mmio.h>
|
#include <lib/mmio.h>
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
|
|
||||||
|
@ -21,6 +22,7 @@ static const interrupt_prop_t fpga_interrupt_props[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static uintptr_t fpga_rdistif_base_addrs[PLATFORM_CORE_COUNT];
|
static uintptr_t fpga_rdistif_base_addrs[PLATFORM_CORE_COUNT];
|
||||||
|
static int nr_itses;
|
||||||
|
|
||||||
static unsigned int fpga_mpidr_to_core_pos(unsigned long mpidr)
|
static unsigned int fpga_mpidr_to_core_pos(unsigned long mpidr)
|
||||||
{
|
{
|
||||||
|
@ -38,6 +40,8 @@ static gicv3_driver_data_t fpga_gicv3_driver_data = {
|
||||||
void plat_fpga_gic_init(void)
|
void plat_fpga_gic_init(void)
|
||||||
{
|
{
|
||||||
const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
|
const void *fdt = (void *)(uintptr_t)FPGA_PRELOADED_DTB_BASE;
|
||||||
|
uintptr_t gicr_base = 0U;
|
||||||
|
uint32_t iidr;
|
||||||
int node, ret;
|
int node, ret;
|
||||||
|
|
||||||
node = fdt_node_offset_by_compatible(fdt, 0, "arm,gic-v3");
|
node = fdt_node_offset_by_compatible(fdt, 0, "arm,gic-v3");
|
||||||
|
@ -54,12 +58,67 @@ void plat_fpga_gic_init(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iidr = mmio_read_32(fpga_gicv3_driver_data.gicd_base + GICD_IIDR);
|
||||||
|
if (((iidr & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) ||
|
||||||
|
((iidr & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_700)) {
|
||||||
|
unsigned int frame_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* According to the GIC TRMs, if there are any ITSes, they
|
||||||
|
* start four 64K pages after the distributor. After all
|
||||||
|
* the ITSes then follow the redistributors.
|
||||||
|
*/
|
||||||
|
gicr_base = fpga_gicv3_driver_data.gicd_base + (4U << 16);
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint64_t its_typer;
|
||||||
|
|
||||||
|
/* Each GIC component can be identified by its ID. */
|
||||||
|
frame_id = gicv3_get_component_partnum(gicr_base);
|
||||||
|
|
||||||
|
if (frame_id == PIDR_COMPONENT_ARM_REDIST) {
|
||||||
|
INFO("Found %d ITSes, redistributors start at 0x%llx\n",
|
||||||
|
nr_itses, (unsigned long long)gicr_base);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frame_id != PIDR_COMPONENT_ARM_ITS) {
|
||||||
|
WARN("GICv3: found unexpected frame 0x%x\n",
|
||||||
|
frame_id);
|
||||||
|
gicr_base = 0U;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Found an ITS, now work out if it supports virtual
|
||||||
|
* SGIs (for direct guest injection). If yes, each
|
||||||
|
* ITS occupies four 64K pages, otherwise just two.
|
||||||
|
*/
|
||||||
|
its_typer = mmio_read_64(gicr_base + GITS_TYPER);
|
||||||
|
if ((its_typer & GITS_TYPER_VSGI) != 0U) {
|
||||||
|
gicr_base += 4U << 16;
|
||||||
|
} else {
|
||||||
|
gicr_base += 2U << 16;
|
||||||
|
}
|
||||||
|
nr_itses++;
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this is not a GIC-600 or -700, or the autodetection above failed,
|
||||||
|
* use the base address from the device tree.
|
||||||
|
*/
|
||||||
|
if (gicr_base == 0U) {
|
||||||
ret = fdt_get_reg_props_by_index(fdt, node, 1,
|
ret = fdt_get_reg_props_by_index(fdt, node, 1,
|
||||||
&fpga_gicv3_driver_data.gicr_base, NULL);
|
&fpga_gicv3_driver_data.gicr_base,
|
||||||
|
NULL);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
WARN("Could not read GIC redistributor address from DT.\n");
|
WARN("Could not read GIC redistributor address from DT.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fpga_gicv3_driver_data.gicr_base = gicr_base;
|
||||||
|
}
|
||||||
|
|
||||||
gicv3_driver_init(&fpga_gicv3_driver_data);
|
gicv3_driver_init(&fpga_gicv3_driver_data);
|
||||||
gicv3_distif_init();
|
gicv3_distif_init();
|
||||||
|
@ -91,3 +150,13 @@ uintptr_t fpga_get_redist_size(void)
|
||||||
|
|
||||||
return gicv3_redist_size(typer_val);
|
return gicv3_redist_size(typer_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uintptr_t fpga_get_redist_base(void)
|
||||||
|
{
|
||||||
|
return fpga_gicv3_driver_data.gicr_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fpga_has_its(void)
|
||||||
|
{
|
||||||
|
return nr_itses > 0;
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ void fpga_pwr_gic_off(void);
|
||||||
unsigned int plat_fpga_calc_core_pos(uint32_t mpid);
|
unsigned int plat_fpga_calc_core_pos(uint32_t mpid);
|
||||||
unsigned int fpga_get_nr_gic_cores(void);
|
unsigned int fpga_get_nr_gic_cores(void);
|
||||||
uintptr_t fpga_get_redist_size(void);
|
uintptr_t fpga_get_redist_size(void);
|
||||||
|
uintptr_t fpga_get_redist_base(void);
|
||||||
|
bool fpga_has_its(void);
|
||||||
|
|
||||||
#endif /* __ASSEMBLER__ */
|
#endif /* __ASSEMBLER__ */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue