diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/arm/gic/v3/gicv3_main.c | 147 | ||||
-rw-r--r-- | drivers/partition/gpt.c | 5 | ||||
-rw-r--r-- | drivers/partition/partition.c | 14 | ||||
-rw-r--r-- | drivers/rpi3/mailbox/rpi3_mbox.c | 82 | ||||
-rw-r--r-- | drivers/rpi3/rng/rpi3_rng.c | 75 |
5 files changed, 280 insertions, 43 deletions
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index 44f5cd809..fb49a579d 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -16,7 +16,6 @@ #include "gicv3_private.h" const gicv3_driver_data_t *gicv3_driver_data; -static unsigned int gicv2_compat; /* * Spinlock to guard registers needing read-modify-write. APIs protected by this @@ -60,51 +59,61 @@ static spinlock_t gic_lock; void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data) { unsigned int gic_version; + unsigned int gicv2_compat; assert(plat_driver_data != NULL); assert(plat_driver_data->gicd_base != 0U); - assert(plat_driver_data->gicr_base != 0U); assert(plat_driver_data->rdistif_num != 0U); assert(plat_driver_data->rdistif_base_addrs != NULL); assert(IS_IN_EL3()); - assert(plat_driver_data->interrupt_props_num > 0 ? - plat_driver_data->interrupt_props != NULL : 1); + assert((plat_driver_data->interrupt_props_num != 0U) ? + (plat_driver_data->interrupt_props != NULL) : 1); /* Check for system register support */ -#ifdef __aarch64__ +#ifndef __aarch64__ + assert((read_id_pfr1() & + (ID_PFR1_GIC_MASK << ID_PFR1_GIC_SHIFT)) != 0U); +#else assert((read_id_aa64pfr0_el1() & (ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT)) != 0U); -#else - assert((read_id_pfr1() & (ID_PFR1_GIC_MASK << ID_PFR1_GIC_SHIFT)) != 0U); -#endif /* __aarch64__ */ +#endif /* !__aarch64__ */ /* The GIC version should be 3.0 */ gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); - gic_version >>= PIDR2_ARCH_REV_SHIFT; + gic_version >>= PIDR2_ARCH_REV_SHIFT; gic_version &= PIDR2_ARCH_REV_MASK; assert(gic_version == ARCH_REV_GICV3); /* - * Find out whether the GIC supports the GICv2 compatibility mode. The - * ARE_S bit resets to 0 if supported + * Find out whether the GIC supports the GICv2 compatibility mode. + * The ARE_S bit resets to 0 if supported */ gicv2_compat = gicd_read_ctlr(plat_driver_data->gicd_base); gicv2_compat >>= CTLR_ARE_S_SHIFT; - gicv2_compat = !(gicv2_compat & CTLR_ARE_S_MASK); - - /* - * Find the base address of each implemented Redistributor interface. - * The number of interfaces should be equal to the number of CPUs in the - * system. The memory for saving these addresses has to be allocated by - * the platform port - */ - gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs, - plat_driver_data->rdistif_num, - plat_driver_data->gicr_base, - plat_driver_data->mpidr_to_core_pos); - + gicv2_compat = gicv2_compat & CTLR_ARE_S_MASK; + + if (plat_driver_data->gicr_base != 0U) { + /* + * Find the base address of each implemented Redistributor interface. + * The number of interfaces should be equal to the number of CPUs in the + * system. The memory for saving these addresses has to be allocated by + * the platform port + */ + gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs, + plat_driver_data->rdistif_num, + plat_driver_data->gicr_base, + plat_driver_data->mpidr_to_core_pos); +#if !HW_ASSISTED_COHERENCY + /* + * Flush the rdistif_base_addrs[] contents linked to the GICv3 driver. + */ + flush_dcache_range((uintptr_t)(plat_driver_data->rdistif_base_addrs), + plat_driver_data->rdistif_num * + sizeof(*(plat_driver_data->rdistif_base_addrs))); +#endif + } gicv3_driver_data = plat_driver_data; /* @@ -112,19 +121,19 @@ void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data) * enabled. When the secondary CPU boots up, it initializes the * GICC/GICR interface with the caches disabled. Hence flush the * driver data to ensure coherency. This is not required if the - * platform has HW_ASSISTED_COHERENCY or WARMBOOT_ENABLE_DCACHE_EARLY - * enabled. + * platform has HW_ASSISTED_COHERENCY enabled. */ -#if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) - flush_dcache_range((uintptr_t) &gicv3_driver_data, - sizeof(gicv3_driver_data)); - flush_dcache_range((uintptr_t) gicv3_driver_data, - sizeof(*gicv3_driver_data)); +#if !HW_ASSISTED_COHERENCY + flush_dcache_range((uintptr_t)&gicv3_driver_data, + sizeof(gicv3_driver_data)); + flush_dcache_range((uintptr_t)gicv3_driver_data, + sizeof(*gicv3_driver_data)); #endif - INFO("GICv3 %s legacy support detected." - " ARM GICV3 driver initialized in EL3\n", - gicv2_compat ? "with" : "without"); + INFO("GICv3 with%s legacy support detected." + " ARM GICv3 driver initialized in EL3\n", + (gicv2_compat == 0U) ? "" : "out"); + } /******************************************************************************* @@ -192,6 +201,7 @@ void gicv3_rdistif_init(unsigned int proc_num) gicv3_rdistif_on(proc_num); gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; + assert(gicr_base != 0U); /* Set the default attribute of all SGIs and PPIs */ gicv3_ppi_sgi_config_defaults(gicr_base); @@ -313,6 +323,7 @@ void gicv3_cpuif_disable(unsigned int proc_num) /* Mark the connected core as asleep */ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; + assert(gicr_base != 0U); gicv3_rdistif_mark_core_asleep(gicr_base); } @@ -1085,3 +1096,71 @@ unsigned int gicv3_set_pmr(unsigned int mask) return old_mask; } + +/******************************************************************************* + * This function delegates the responsibility of discovering the corresponding + * Redistributor frames to each CPU itself. It is a modified version of + * gicv3_rdistif_base_addrs_probe() and is executed by each CPU in the platform + * unlike the previous way in which only the Primary CPU did the discovery of + * all the Redistributor frames for every CPU. It also handles the scenario in + * which the frames of various CPUs are not contiguous in physical memory. + ******************************************************************************/ +int gicv3_rdistif_probe(const uintptr_t gicr_frame) +{ + u_register_t mpidr; + unsigned int proc_num, proc_self; + uint64_t typer_val; + uintptr_t rdistif_base; + bool gicr_frame_found = false; + + assert(gicv3_driver_data->gicr_base == 0U); + + /* Ensure this function is called with Data Cache enabled */ +#ifndef __aarch64__ + assert((read_sctlr() & SCTLR_C_BIT) != 0U); +#else + assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U); +#endif /* !__aarch64__ */ + + proc_self = gicv3_driver_data->mpidr_to_core_pos(read_mpidr_el1()); + rdistif_base = gicr_frame; + do { + typer_val = gicr_read_typer(rdistif_base); + if (gicv3_driver_data->mpidr_to_core_pos != NULL) { + mpidr = mpidr_from_gicr_typer(typer_val); + proc_num = gicv3_driver_data->mpidr_to_core_pos(mpidr); + } else { + proc_num = (unsigned int)(typer_val >> TYPER_PROC_NUM_SHIFT) & + TYPER_PROC_NUM_MASK; + } + if (proc_num == proc_self) { + /* The base address doesn't need to be initialized on + * every warm boot. + */ + if (gicv3_driver_data->rdistif_base_addrs[proc_num] != 0U) + return 0; + gicv3_driver_data->rdistif_base_addrs[proc_num] = + rdistif_base; + gicr_frame_found = true; + break; + } + rdistif_base += (uintptr_t)(ULL(1) << GICR_PCPUBASE_SHIFT); + } while ((typer_val & TYPER_LAST_BIT) == 0U); + + if (!gicr_frame_found) + return -1; + + /* + * Flush the driver data to ensure coherency. This is + * not required if platform has HW_ASSISTED_COHERENCY + * enabled. + */ +#if !HW_ASSISTED_COHERENCY + /* + * Flush the rdistif_base_addrs[] contents linked to the GICv3 driver. + */ + flush_dcache_range((uintptr_t)&(gicv3_driver_data->rdistif_base_addrs[proc_num]), + sizeof(*(gicv3_driver_data->rdistif_base_addrs))); +#endif + return 0; /* Found matching GICR frame */ +} diff --git a/drivers/partition/gpt.c b/drivers/partition/gpt.c index 4577f06a2..1b804deef 100644 --- a/drivers/partition/gpt.c +++ b/drivers/partition/gpt.c @@ -52,9 +52,10 @@ int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry) if (result != 0) { return result; } - entry->start = (uint64_t)gpt_entry->first_lba * PARTITION_BLOCK_SIZE; + entry->start = (uint64_t)gpt_entry->first_lba * + PLAT_PARTITION_BLOCK_SIZE; entry->length = (uint64_t)(gpt_entry->last_lba - gpt_entry->first_lba + 1) * - PARTITION_BLOCK_SIZE; + PLAT_PARTITION_BLOCK_SIZE; return 0; } diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c index 7fdbf5385..68133eaf4 100644 --- a/drivers/partition/partition.c +++ b/drivers/partition/partition.c @@ -15,7 +15,7 @@ #include <drivers/partition/mbr.h> #include <plat/common/platform.h> -static uint8_t mbr_sector[PARTITION_BLOCK_SIZE]; +static uint8_t mbr_sector[PLAT_PARTITION_BLOCK_SIZE]; static partition_entry_list_t list; #if LOG_LEVEL >= LOG_LEVEL_VERBOSE @@ -57,15 +57,15 @@ static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry) return result; } result = io_read(image_handle, (uintptr_t)&mbr_sector, - PARTITION_BLOCK_SIZE, &bytes_read); + PLAT_PARTITION_BLOCK_SIZE, &bytes_read); if (result != 0) { WARN("Failed to read data (%i)\n", result); return result; } /* Check MBR boot signature. */ - if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || - (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { + if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || + (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { return -ENOENT; } offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET; @@ -120,15 +120,15 @@ static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry, return result; } result = io_read(image_handle, (uintptr_t)&mbr_sector, - PARTITION_BLOCK_SIZE, &bytes_read); + PLAT_PARTITION_BLOCK_SIZE, &bytes_read); if (result != 0) { WARN("Failed to read data (%i)\n", result); return result; } /* Check MBR boot signature. */ - if ((mbr_sector[PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || - (mbr_sector[PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { + if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || + (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { return -ENOENT; } offset = (uintptr_t)&mbr_sector + diff --git a/drivers/rpi3/mailbox/rpi3_mbox.c b/drivers/rpi3/mailbox/rpi3_mbox.c new file mode 100644 index 000000000..aef1f39a7 --- /dev/null +++ b/drivers/rpi3/mailbox/rpi3_mbox.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform_def.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <lib/mmio.h> + +#include <rpi_hw.h> + +#include <drivers/rpi3/mailbox/rpi3_mbox.h> + +#define RPI3_MAILBOX_MAX_RETRIES U(1000000) + +/******************************************************************************* + * Routine to send requests to the VideoCore using the mailboxes. + ******************************************************************************/ +void rpi3_vc_mailbox_request_send(rpi3_mbox_request_t *req, int req_size) +{ + uint32_t st, data; + uintptr_t resp_addr, addr; + unsigned int retries; + + /* This is the location of the request buffer */ + addr = (uintptr_t)req; + + /* Make sure that the changes are seen by the VideoCore */ + flush_dcache_range(addr, req_size); + + /* Wait until the outbound mailbox is empty */ + retries = 0U; + + do { + st = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX1_STATUS_OFFSET); + + retries++; + if (retries == RPI3_MAILBOX_MAX_RETRIES) { + ERROR("rpi3: mbox: Send request timeout\n"); + return; + } + + } while ((st & RPI3_MBOX_STATUS_EMPTY_MASK) == 0U); + + /* Send base address of this message to start request */ + mmio_write_32(RPI3_MBOX_BASE + RPI3_MBOX1_WRITE_OFFSET, + RPI3_CHANNEL_ARM_TO_VC | (uint32_t) addr); + + /* Wait until the inbound mailbox isn't empty */ + retries = 0U; + + do { + st = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX0_STATUS_OFFSET); + + retries++; + if (retries == RPI3_MAILBOX_MAX_RETRIES) { + ERROR("rpi3: mbox: Receive response timeout\n"); + return; + } + + } while ((st & RPI3_MBOX_STATUS_EMPTY_MASK) != 0U); + + /* Get location and channel */ + data = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX0_READ_OFFSET); + + if ((data & RPI3_CHANNEL_MASK) != RPI3_CHANNEL_ARM_TO_VC) { + ERROR("rpi3: mbox: Wrong channel: 0x%08x\n", data); + panic(); + } + + resp_addr = (uintptr_t)(data & ~RPI3_CHANNEL_MASK); + if (addr != resp_addr) { + ERROR("rpi3: mbox: Unexpected address: 0x%08x\n", data); + panic(); + } + + /* Make sure that the data seen by the CPU is up to date */ + inv_dcache_range(addr, req_size); +} diff --git a/drivers/rpi3/rng/rpi3_rng.c b/drivers/rpi3/rng/rpi3_rng.c new file mode 100644 index 000000000..b6bf0052a --- /dev/null +++ b/drivers/rpi3/rng/rpi3_rng.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <string.h> + +#include <lib/mmio.h> + +#include <rpi_hw.h> + +/* Initial amount of values to discard */ +#define RNG_WARMUP_COUNT U(0x40000) + +static void rpi3_rng_initialize(void) +{ + uint32_t int_mask, ctrl; + + /* Return if it is already enabled */ + ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET); + if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) { + return; + } + + /* Mask interrupts */ + int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET); + int_mask |= RPI3_RNG_INT_MASK_DISABLE; + mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask); + + /* Discard several values when initializing to give it time to warmup */ + mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT); + + mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET, + RPI3_RNG_CTRL_ENABLE); +} + +static uint32_t rpi3_rng_get_word(void) +{ + size_t nwords; + + do { + /* Get number of available words to read */ + nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET) + >> RPI3_RNG_STATUS_NUM_WORDS_SHIFT) + & RPI3_RNG_STATUS_NUM_WORDS_MASK; + } while (nwords == 0U); + + return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET); +} + +void rpi3_rng_read(void *buf, size_t len) +{ + uint32_t data; + size_t left = len; + uint32_t *dst = buf; + + assert(buf != NULL); + assert(len != 0U); + assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0); + + rpi3_rng_initialize(); + + while (left >= sizeof(uint32_t)) { + data = rpi3_rng_get_word(); + *dst++ = data; + left -= sizeof(uint32_t); + } + + if (left > 0U) { + data = rpi3_rng_get_word(); + memcpy(dst, &data, left); + } +} |