aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/arm/gic/v3/gicv3_main.c147
-rw-r--r--drivers/partition/gpt.c5
-rw-r--r--drivers/partition/partition.c14
-rw-r--r--drivers/rpi3/mailbox/rpi3_mbox.c82
-rw-r--r--drivers/rpi3/rng/rpi3_rng.c75
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);
+ }
+}