Merge changes from topic "trng-svc" into integration
* changes:
plat/arm: juno: Use TRNG entropy source for SMCCC TRNG interface
plat/arm: juno: Condition Juno entropy source with CRC instructions
diff --git a/docs/plat/stm32mp1.rst b/docs/plat/stm32mp1.rst
index f597460..0ef2923 100644
--- a/docs/plat/stm32mp1.rst
+++ b/docs/plat/stm32mp1.rst
@@ -95,6 +95,7 @@
------------------
Boot media(s) supported by BL2 must be specified in the build command.
Available storage medias are:
+
- ``STM32MP_SDMMC``
- ``STM32MP_EMMC``
- ``STM32MP_RAW_NAND``
@@ -112,6 +113,7 @@
make DEVICE_TREE=stm32mp157c-ev1 all
To build TF-A with OP-TEE support for all bootable devices:
+
.. code:: bash
make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=optee STM32MP_SDMMC=1 STM32MP_EMMC=1 STM32MP_RAW_NAND=1 STM32MP_SPI_NAND=1 STM32MP_SPI_NOR=1 DTB_FILE_NAME=stm32mp157c-ev1.dtb
diff --git a/drivers/arm/tzc/tzc400.c b/drivers/arm/tzc/tzc400.c
index 95a5e7f..9798ed4 100644
--- a/drivers/arm/tzc/tzc400.c
+++ b/drivers/arm/tzc/tzc400.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -162,7 +162,9 @@
/*
* `tzc400_configure_region` is used to program regions into the TrustZone
* controller. A region can be associated with more than one filter. The
- * associated filters are passed in as a bitmap (bit0 = filter0).
+ * associated filters are passed in as a bitmap (bit0 = filter0), except that
+ * the value TZC_400_REGION_ATTR_FILTER_BIT_ALL selects all filters, based on
+ * the value of tzc400.num_filters.
* NOTE:
* Region 0 is special; it is preferable to use tzc400_configure_region0
* for this region (see comment for that function).
@@ -176,6 +178,11 @@
{
assert(tzc400.base != 0U);
+ /* Adjust filter mask by real filter number */
+ if (filters == TZC_400_REGION_ATTR_FILTER_BIT_ALL) {
+ filters = (1U << tzc400.num_filters) - 1U;
+ }
+
/* Do range checks on filters and regions. */
assert(((filters >> tzc400.num_filters) == 0U) &&
(region < tzc400.num_regions));
diff --git a/drivers/marvell/iob.c b/drivers/marvell/iob.c
index 87f147a..29088aa 100644
--- a/drivers/marvell/iob.c
+++ b/drivers/marvell/iob.c
@@ -44,6 +44,10 @@
#define IOB_WIN_ALR_OFFSET(win) (iob_base + 0x8 + (0x20 * win))
#define IOB_WIN_AHR_OFFSET(win) (iob_base + 0xC + (0x20 * win))
+#define IOB_WIN_DIOB_CR_OFFSET(win) (iob_base + 0x10 + (0x20 * win))
+#define IOB_WIN_XOR0_DIOB_EN BIT(0)
+#define IOB_WIN_XOR1_DIOB_EN BIT(1)
+
uintptr_t iob_base;
static void iob_win_check(struct addr_map_win *win, uint32_t win_num)
@@ -71,6 +75,17 @@
uint32_t iob_win_reg;
uint32_t alr, ahr;
uint64_t end_addr;
+ uint32_t reg_en;
+
+ /* move XOR (DMA) to use WIN1 which is used for PCI-EP address space */
+ reg_en = IOB_WIN_XOR0_DIOB_EN | IOB_WIN_XOR1_DIOB_EN;
+ iob_win_reg = mmio_read_32(IOB_WIN_DIOB_CR_OFFSET(0));
+ iob_win_reg &= ~reg_en;
+ mmio_write_32(IOB_WIN_DIOB_CR_OFFSET(0), iob_win_reg);
+
+ iob_win_reg = mmio_read_32(IOB_WIN_DIOB_CR_OFFSET(1));
+ iob_win_reg |= reg_en;
+ mmio_write_32(IOB_WIN_DIOB_CR_OFFSET(1), iob_win_reg);
end_addr = (win->base_addr + win->win_size - 1);
alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK);
diff --git a/drivers/marvell/mochi/ap807_setup.c b/drivers/marvell/mochi/ap807_setup.c
index 1069f8c..75e9654 100644
--- a/drivers/marvell/mochi/ap807_setup.c
+++ b/drivers/marvell/mochi/ap807_setup.c
@@ -15,8 +15,9 @@
#include <drivers/marvell/mci.h>
#include <drivers/marvell/mochi/ap_setup.h>
#include <lib/mmio.h>
+#include <lib/utils_def.h>
-#include <mvebu_def.h>
+#include <a8k_plat_def.h>
#define SMMU_sACR (MVEBU_SMMU_BASE + 0x10)
#define SMMU_sACR_PG_64K (1 << 16)
@@ -71,6 +72,23 @@
#define MVEBU_AXI_ATTR_REG(index) (MVEBU_AXI_ATTR_BASE + \
0x4 * index)
+#define XOR_STREAM_ID_REG(ch) (MVEBU_REGS_BASE + 0x410010 + (ch) * 0x20000)
+#define XOR_STREAM_ID_MASK 0xFFFF
+#define SDIO_STREAM_ID_REG (MVEBU_RFU_BASE + 0x4600)
+#define SDIO_STREAM_ID_MASK 0xFF
+
+/* Do not use the default Stream ID 0 */
+#define A807_STREAM_ID_BASE (0x1)
+
+static uintptr_t stream_id_reg[] = {
+ XOR_STREAM_ID_REG(0),
+ XOR_STREAM_ID_REG(1),
+ XOR_STREAM_ID_REG(2),
+ XOR_STREAM_ID_REG(3),
+ SDIO_STREAM_ID_REG,
+ 0
+};
+
enum axi_attr {
AXI_SDIO_ATTR = 0,
AXI_DFX_ATTR,
@@ -162,6 +180,21 @@
MCI_REMAP_OFF_SHIFT);
}
+/* Set a unique stream id for all DMA capable devices */
+static void ap807_stream_id_init(void)
+{
+ uint32_t i;
+
+ for (i = 0;
+ stream_id_reg[i] != 0 && i < ARRAY_SIZE(stream_id_reg); i++) {
+ uint32_t mask = stream_id_reg[i] == SDIO_STREAM_ID_REG ?
+ SDIO_STREAM_ID_MASK : XOR_STREAM_ID_MASK;
+
+ mmio_clrsetbits_32(stream_id_reg[i], mask,
+ i + A807_STREAM_ID_BASE);
+ }
+}
+
static void ap807_axi_attr_init(void)
{
uint32_t index, data;
@@ -265,6 +298,9 @@
/* configure CCU windows */
init_ccu(MVEBU_AP0);
+ /* Set the stream IDs for DMA masters */
+ ap807_stream_id_init();
+
/* configure the SMMU */
setup_smmu();
diff --git a/drivers/marvell/mochi/apn806_setup.c b/drivers/marvell/mochi/apn806_setup.c
index 8c3ba92..5c71fed 100644
--- a/drivers/marvell/mochi/apn806_setup.c
+++ b/drivers/marvell/mochi/apn806_setup.c
@@ -15,7 +15,7 @@
#include <drivers/marvell/mochi/ap_setup.h>
#include <lib/mmio.h>
-#include <mvebu_def.h>
+#include <a8k_plat_def.h>
#define SMMU_sACR (MVEBU_SMMU_BASE + 0x10)
#define SMMU_sACR_PG_64K (1 << 16)
@@ -67,6 +67,23 @@
#define MVEBU_AXI_ATTR_REG(index) (MVEBU_AXI_ATTR_BASE + \
0x4 * index)
+#define XOR_STREAM_ID_REG(ch) (MVEBU_REGS_BASE + 0x410010 + (ch) * 0x20000)
+#define XOR_STREAM_ID_MASK 0xFFFF
+#define SDIO_STREAM_ID_REG (MVEBU_RFU_BASE + 0x4600)
+#define SDIO_STREAM_ID_MASK 0xFF
+
+/* Do not use the default Stream ID 0 */
+#define A806_STREAM_ID_BASE (0x1)
+
+static uintptr_t stream_id_reg[] = {
+ XOR_STREAM_ID_REG(0),
+ XOR_STREAM_ID_REG(1),
+ XOR_STREAM_ID_REG(2),
+ XOR_STREAM_ID_REG(3),
+ SDIO_STREAM_ID_REG,
+ 0
+};
+
enum axi_attr {
AXI_SDIO_ATTR = 0,
AXI_DFX_ATTR,
@@ -158,6 +175,20 @@
MCI_REMAP_OFF_SHIFT);
}
+/* Set a unique stream id for all DMA capable devices */
+static void ap806_stream_id_init(void)
+{
+ int i;
+
+ for (i = 0; stream_id_reg[i] != 0; i++) {
+ uint32_t mask = stream_id_reg[i] == SDIO_STREAM_ID_REG ?
+ SDIO_STREAM_ID_MASK : XOR_STREAM_ID_MASK;
+
+ mmio_clrsetbits_32(stream_id_reg[i], mask,
+ i + A806_STREAM_ID_BASE);
+ }
+}
+
static void apn806_axi_attr_init(void)
{
uint32_t index, data;
@@ -236,6 +267,9 @@
/* configure DSS */
dss_setup();
+ /* Set the stream IDs for DMA masters */
+ ap806_stream_id_init();
+
/* configure the SMMU */
setup_smmu();
diff --git a/drivers/marvell/mochi/cp110_setup.c b/drivers/marvell/mochi/cp110_setup.c
index 0fa0497..906df66 100644
--- a/drivers/marvell/mochi/cp110_setup.c
+++ b/drivers/marvell/mochi/cp110_setup.c
@@ -12,6 +12,7 @@
#include <drivers/marvell/amb_adec.h>
#include <drivers/marvell/iob.h>
#include <drivers/marvell/mochi/cp110_setup.h>
+#include <drivers/rambus/trng_ip_76.h>
#include <plat_marvell.h>
@@ -105,6 +106,11 @@
#define MVEBU_RTC_READ_OUTPUT_DELAY_MASK 0xFFFF
#define MVEBU_RTC_READ_OUTPUT_DELAY_DEFAULT 0x1F
+/*******************************************************************************
+ * TRNG Configuration
+ ******************************************************************************/
+#define MVEBU_TRNG_BASE (0x760000)
+
enum axi_attr {
AXI_ADUNIT_ATTR = 0,
AXI_COMUNIT_ATTR,
@@ -130,7 +136,7 @@
#define USB3H_1_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x10)
#define SATA_0_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x14)
#define SATA_1_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x18)
-#define SDIO_0_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x28)
+#define SDIO_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x28)
#define CP_DMA_0_STREAM_ID_REG (0x6B0010)
#define CP_DMA_1_STREAM_ID_REG (0x6D0010)
@@ -138,14 +144,14 @@
/* We allocate IDs 128-255 for PCIe */
#define MAX_STREAM_ID (0x80)
-uintptr_t stream_id_reg[] = {
+static uintptr_t stream_id_reg[] = {
USB3H_0_STREAM_ID_REG,
USB3H_1_STREAM_ID_REG,
CP_DMA_0_STREAM_ID_REG,
CP_DMA_1_STREAM_ID_REG,
SATA_0_STREAM_ID_REG,
SATA_1_STREAM_ID_REG,
- SDIO_0_STREAM_ID_REG,
+ SDIO_STREAM_ID_REG,
0
};
@@ -180,8 +186,9 @@
pcie0_clk = (reg & SAR_PCIE0_CLK_CFG_MASK) >> SAR_PCIE0_CLK_CFG_OFFSET;
pcie1_clk = (reg & SAR_PCIE1_CLK_CFG_MASK) >> SAR_PCIE1_CLK_CFG_OFFSET;
- /* CP110 revision A2 */
- if (cp110_rev_id_get(base) == MVEBU_CP110_REF_ID_A2) {
+ /* CP110 revision A2 or CN913x */
+ if (cp110_rev_id_get(base) == MVEBU_CP110_REF_ID_A2 ||
+ cp110_device_id_get(base) == MVEBU_CN9130_DEV_ID) {
/*
* PCIe Reference Clock Buffer Control register must be
* set according to the clock direction (input/output)
@@ -378,6 +385,20 @@
init_amb_adec(base);
}
+static void cp110_trng_init(uintptr_t base)
+{
+ static bool done;
+ int ret;
+
+ if (!done) {
+ ret = eip76_rng_probe(base + MVEBU_TRNG_BASE);
+ if (ret != 0) {
+ ERROR("Failed to init TRNG @ 0x%lx\n", base);
+ return;
+ }
+ done = true;
+ }
+}
void cp110_init(uintptr_t cp110_base, uint32_t stream_id)
{
INFO("%s: Initialize CPx - base = %lx\n", __func__, cp110_base);
@@ -405,6 +426,9 @@
/* Reset RTC if needed */
cp110_rtc_init(cp110_base);
+
+ /* TRNG init - for CP0 only */
+ cp110_trng_init(cp110_base);
}
/* Do the minimal setup required to configure the CP in BLE */
diff --git a/drivers/marvell/uart/a3700_console.S b/drivers/marvell/uart/a3700_console.S
index 58dad7a..b377321 100644
--- a/drivers/marvell/uart/a3700_console.S
+++ b/drivers/marvell/uart/a3700_console.S
@@ -60,10 +60,10 @@
str w3, [x0, #UART_POSSR_REG]
/*
- * Wait for the TX (THR and TSR) to be empty. If wait for 20ms, the TX FIFO is
+ * Wait for the TX (THR and TSR) to be empty. If wait for 3ms, the TX FIFO is
* still not empty, TX FIFO will reset by all means.
*/
- mov w1, #20 /* max time out 20ms */
+ mov w1, #30 /* max time out 30 * 100 us */
2:
/* Check whether TX (THR and TSR) is empty */
ldr w3, [x0, #UART_STATUS_REG]
@@ -72,13 +72,13 @@
b.ne 4f
/* Delay */
- mov w2, #30000
+ mov w2, #60000 /* 60000 cycles of below 3 instructions on 1200 MHz CPU ~~ 100 us */
3:
sub w2, w2, #1
cmp w2, #0
b.ne 3b
- /* Check whether 10ms is waited */
+ /* Check whether wait timeout expired */
sub w1, w1, #1
cmp w1, #0
b.ne 2b
diff --git a/drivers/rambus/trng_ip_76.c b/drivers/rambus/trng_ip_76.c
new file mode 100644
index 0000000..8de12e9
--- /dev/null
+++ b/drivers/rambus/trng_ip_76.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2020, Marvell Technology Group Ltd. All rights reserved.
+ *
+ * Based on Linux kernel omap-rng.c - RNG driver for TI OMAP CPU family
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * Mostly based on original driver:
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <drivers/rambus/trng_ip_76.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+
+#define RNG_REG_STATUS_RDY (1 << 0)
+
+#define RNG_REG_INTACK_RDY_MASK (1 << 0)
+
+#define RNG_CONTROL_ENABLE_TRNG_MASK (1 << 10)
+
+#define RNG_CONFIG_NOISE_BLOCKS(val) ((0xff & (val)) << 0)
+#define RNG_CONFIG_NOISE_BLK_VAL 0x5
+
+#define RNG_CONFIG_SAMPLE_CYCLES(val) ((0xff & (val)) << 16)
+#define RNG_CONFIG_SAMPLE_CYCLES_VAL 0x22
+
+#define RNG_REG_FRO_ENABLE_MASK 0xffffff
+#define RNG_REG_FRO_DETUNE_MASK 0x0
+
+#define EIP76_RNG_OUTPUT_SIZE 0x10
+#define EIP76_RNG_WAIT_ROUNDS 10
+
+#define RNG_HW_IS_EIP76(ver) ((ver) & (0xff == 0x4C))
+#define RNG_HW_VER_MAJOR(ver) (((ver) & (0xf << 24)) >> 24)
+#define RNG_HW_VER_MINOR(ver) (((ver) & (0xf << 20)) >> 20)
+#define RNG_HW_VER_PATCH(ver) (((ver) & (0xf << 16)) >> 16)
+
+
+enum {
+ RNG_OUTPUT_0_REG = 0,
+ RNG_OUTPUT_1_REG,
+ RNG_OUTPUT_2_REG,
+ RNG_OUTPUT_3_REG,
+ RNG_STATUS_REG,
+ RNG_INTMASK_REG,
+ RNG_INTACK_REG,
+ RNG_CONTROL_REG,
+ RNG_CONFIG_REG,
+ RNG_ALARMCNT_REG,
+ RNG_FROENABLE_REG,
+ RNG_FRODETUNE_REG,
+ RNG_ALARMMASK_REG,
+ RNG_ALARMSTOP_REG,
+ RNG_REV_REG
+};
+
+static uint16_t reg_map_eip76[] = {
+ [RNG_OUTPUT_0_REG] = 0x0,
+ [RNG_OUTPUT_1_REG] = 0x4,
+ [RNG_OUTPUT_2_REG] = 0x8,
+ [RNG_OUTPUT_3_REG] = 0xc,
+ [RNG_STATUS_REG] = 0x10,
+ [RNG_INTACK_REG] = 0x10,
+ [RNG_CONTROL_REG] = 0x14,
+ [RNG_CONFIG_REG] = 0x18,
+ [RNG_ALARMCNT_REG] = 0x1c,
+ [RNG_FROENABLE_REG] = 0x20,
+ [RNG_FRODETUNE_REG] = 0x24,
+ [RNG_ALARMMASK_REG] = 0x28,
+ [RNG_ALARMSTOP_REG] = 0x2c,
+ [RNG_REV_REG] = 0x7c,
+};
+
+struct eip76_rng_dev {
+ uintptr_t base;
+ uint16_t *regs;
+};
+
+/* Locals */
+static struct eip76_rng_dev eip76_dev;
+static spinlock_t rng_lock;
+
+static inline uint32_t eip76_rng_read(struct eip76_rng_dev *dev, uint16_t reg)
+{
+ return mmio_read_32(dev->base + dev->regs[reg]);
+}
+
+static inline void eip76_rng_write(struct eip76_rng_dev *dev,
+ uint16_t reg, uint32_t val)
+{
+ mmio_write_32(dev->base + dev->regs[reg], val);
+}
+
+static void eip76_rng_init(struct eip76_rng_dev *dev)
+{
+ uint32_t val;
+
+ /* Return if RNG is already running. */
+ if (eip76_rng_read(dev, RNG_CONTROL_REG) &
+ RNG_CONTROL_ENABLE_TRNG_MASK) {
+ return;
+ }
+
+ /* This field sets the number of 512-bit blocks of raw Noise Source
+ * output data that must be processed by either the Conditioning
+ * Function or the SP 800-90 DRBG ‘BC_DF’ functionality to yield
+ * a ‘full entropy’ output value. As according to [SP 800-90B draft]
+ * the amount of entropy input to this functionality must be twice
+ * the amount that is output and the 8-bit samples output by the Noise
+ * Source are supposed to have one bit of entropy each, the settings
+ * for this field are as follows:
+ * - SHA-1 Conditioning Function:
+ * generates 160 bits output, requiring 2560 sample bits,
+ * equivalent to 5 blocks of raw Noise Source input.
+ * - SHA-256 Conditioning Function:
+ * generates 256 bits output, requiring 4096 sample bits, equivalent
+ * to 8 blocks of raw Noise Source input. Note that two blocks of 256
+ * bits are needed to start or re-seed the SP 800-90 DRBG
+ * (in the EIP-76d-*-SHA2 configurations)
+ * - SP 800-90 DRBG ‘BC_DF’ functionality:
+ * generates 384 bits output, requiring 6144 sample bits, equivalent
+ * to 12 blocks of raw Noise Source input.
+ * This field can only be modified when ‘enable_trng’ in TRNG_CONTROL
+ * is ‘0’ or when either of the ‘test_known_noise’ or ‘test_cond_func’
+ * bits in TRNG_TEST is ‘1’. Value 0 in this field selects 256 blocks
+ * of 512 bits to be processed.
+ */
+ val = RNG_CONFIG_NOISE_BLOCKS(RNG_CONFIG_NOISE_BLK_VAL);
+
+ /* This field sets the number of FRO samples that are XOR-ed together
+ * into one bit to be shifted into the main shift register.
+ * This value must be such that there is at least one bit of entropy
+ * (in total) in each 8 bits that are shifted.
+ * This field can only be modified when ‘enable_trng’ in TRNG_CONTROL
+ * is ‘0’ or when either of the ‘test_known_noise’ or ‘test_cond_func’
+ * bits in TRNG_TEST is ‘1’. Value 0 in this field selects 65536 FRO
+ * samples to be XOR-ed together
+ */
+ val |= RNG_CONFIG_SAMPLE_CYCLES(RNG_CONFIG_SAMPLE_CYCLES_VAL);
+ eip76_rng_write(dev, RNG_CONFIG_REG, val);
+
+ /* Enable all available FROs */
+ eip76_rng_write(dev, RNG_FRODETUNE_REG, RNG_REG_FRO_DETUNE_MASK);
+ eip76_rng_write(dev, RNG_FROENABLE_REG, RNG_REG_FRO_ENABLE_MASK);
+
+ /* Enable TRNG */
+ eip76_rng_write(dev, RNG_CONTROL_REG, RNG_CONTROL_ENABLE_TRNG_MASK);
+}
+
+int32_t eip76_rng_read_rand_buf(void *data, bool wait)
+{
+ uint32_t i, present;
+
+ if (!eip76_dev.base) /* not initialized */
+ return -1;
+
+ for (i = 0; i < EIP76_RNG_WAIT_ROUNDS; i++) {
+ present = eip76_rng_read(&eip76_dev, RNG_STATUS_REG) &
+ RNG_REG_STATUS_RDY;
+ if (present || !wait) {
+ break;
+ }
+
+ udelay(10);
+ }
+
+ if (present != 0U) {
+ return 0;
+ }
+
+ memcpy(data,
+ (void *)(eip76_dev.base + eip76_dev.regs[RNG_OUTPUT_0_REG]),
+ EIP76_RNG_OUTPUT_SIZE);
+
+ eip76_rng_write(&eip76_dev, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK);
+
+ return EIP76_RNG_OUTPUT_SIZE;
+}
+
+int32_t eip76_rng_probe(uintptr_t base_addr)
+{
+ uint32_t ver;
+
+ eip76_dev.base = base_addr;
+ eip76_dev.regs = reg_map_eip76;
+
+ eip76_rng_init(&eip76_dev);
+
+ ver = eip76_rng_read(&eip76_dev, RNG_REV_REG);
+
+ INFO("%s Random Number Generator HW ver. %01x.%01x.%01x\n",
+ RNG_HW_IS_EIP76(ver) ? "TRNG-IP-76" : "Unknown",
+ RNG_HW_VER_MAJOR(ver), RNG_HW_VER_MINOR(ver),
+ RNG_HW_VER_PATCH(ver));
+
+ return 0;
+}
+
+int32_t eip76_rng_get_random(uint8_t *data, uint32_t len)
+{
+ static uint8_t rand[EIP76_RNG_OUTPUT_SIZE];
+ static uint8_t pos;
+ uint32_t i;
+ int32_t ret = 0;
+
+ if (!data)
+ return -1;
+
+ spin_lock(&rng_lock);
+
+ for (i = 0; i < len; i++) {
+ if (pos >= EIP76_RNG_OUTPUT_SIZE) {
+ pos = 0;
+ }
+
+ if (pos != 0U) {
+ ret = eip76_rng_read_rand_buf(rand, true);
+ }
+
+ /* Only advance FIFO index if it is non zero or
+ * the update from TRNG HW was successful
+ */
+ if (pos || ret > 0) {
+ data[i] = rand[pos++];
+ ret = 0;
+ } else {
+ ret = -1;
+ break;
+ }
+ }
+
+ spin_unlock(&rng_lock);
+
+ return ret;
+}
diff --git a/drivers/st/fmc/stm32_fmc2_nand.c b/drivers/st/fmc/stm32_fmc2_nand.c
index a58a243..453069b 100644
--- a/drivers/st/fmc/stm32_fmc2_nand.c
+++ b/drivers/st/fmc/stm32_fmc2_nand.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
@@ -200,9 +200,6 @@
if ((twait < NAND_TCS_MIN) && (tset_mem < (NAND_TCS_MIN - twait))) {
tset_mem = NAND_TCS_MIN - twait;
}
- if ((twait < NAND_TALS_MIN) && (tset_mem < (NAND_TALS_MIN - twait))) {
- tset_mem = NAND_TALS_MIN - twait;
- }
if ((twait > thiz) && ((twait - thiz) < NAND_TDS_MIN) &&
(tset_mem < (NAND_TDS_MIN - (twait - thiz)))) {
tset_mem = NAND_TDS_MIN - (twait - thiz);
@@ -244,12 +241,6 @@
if ((twait < NAND_TCS_MIN) && (tset_att < (NAND_TCS_MIN - twait))) {
tset_att = NAND_TCS_MIN - twait;
}
- if ((twait < NAND_TCLS_MIN) && (tset_att < (NAND_TCLS_MIN - twait))) {
- tset_att = NAND_TCLS_MIN - twait;
- }
- if ((twait < NAND_TALS_MIN) && (tset_att < (NAND_TALS_MIN - twait))) {
- tset_att = NAND_TALS_MIN - twait;
- }
if ((thold_mem < NAND_TRHW_MIN) &&
(tset_att < (NAND_TRHW_MIN - thold_mem))) {
tset_att = NAND_TRHW_MIN - thold_mem;
diff --git a/include/drivers/arm/tzc400.h b/include/drivers/arm/tzc400.h
index 32aeb03..cf2e82b 100644
--- a/include/drivers/arm/tzc400.h
+++ b/include/drivers/arm/tzc400.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -80,11 +80,8 @@
/* Filter enable bits in a TZC */
#define TZC_400_REGION_ATTR_F_EN_MASK U(0xf)
-#define TZC_400_REGION_ATTR_FILTER_BIT(x) \
- ((U(1) << (x)) << TZC_REGION_ATTR_F_EN_SHIFT)
-#define TZC_400_REGION_ATTR_FILTER_BIT_ALL \
- (TZC_400_REGION_ATTR_F_EN_MASK << \
- TZC_REGION_ATTR_F_EN_SHIFT)
+#define TZC_400_REGION_ATTR_FILTER_BIT(x) (U(1) << (x))
+#define TZC_400_REGION_ATTR_FILTER_BIT_ALL TZC_400_REGION_ATTR_F_EN_MASK
/*
* All TZC region configuration registers are placed one after another. It
diff --git a/include/drivers/marvell/mochi/cp110_setup.h b/include/drivers/marvell/mochi/cp110_setup.h
index 11dc4e0..4a69257 100644
--- a/include/drivers/marvell/mochi/cp110_setup.h
+++ b/include/drivers/marvell/mochi/cp110_setup.h
@@ -31,6 +31,9 @@
#define MAX_STREAM_ID_PER_CP (0x10)
#define STREAM_ID_BASE (0x40)
+#define MVEBU_SECUREBOOT_CTRL_REG (MVEBU_RFU_BASE + 0x4730)
+#define MVEBU_SECUREBOOT_EN_MASK BIT(0)
+
static inline uint32_t cp110_device_id_get(uintptr_t base)
{
/* Returns:
@@ -50,6 +53,12 @@
MVEBU_DEVICE_REV_OFFSET;
}
+static inline uint32_t is_secure(void)
+{
+ return !!(mmio_read_32(MVEBU_SECUREBOOT_CTRL_REG) &
+ MVEBU_SECUREBOOT_EN_MASK);
+}
+
void cp110_init(uintptr_t cp110_base, uint32_t stream_id);
void cp110_ble_init(uintptr_t cp110_base);
void cp110_amb_init(uintptr_t base);
diff --git a/include/drivers/rambus/trng_ip_76.h b/include/drivers/rambus/trng_ip_76.h
new file mode 100644
index 0000000..6de8fc7
--- /dev/null
+++ b/include/drivers/rambus/trng_ip_76.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2020, Marvell Technology Group Ltd. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#ifndef __TRNG_IP_76_H__
+#define __TRNG_IP_76_H__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+int32_t eip76_rng_read_rand_buf(void *data, bool wait);
+int32_t eip76_rng_probe(uintptr_t base_addr);
+int32_t eip76_rng_get_random(uint8_t *data, uint32_t len);
+
+#endif /* __TRNG_IP_76_H__ */
diff --git a/lib/cpus/aarch32/cpu_helpers.S b/lib/cpus/aarch32/cpu_helpers.S
index 9b5d787..6ed800c 100644
--- a/lib/cpus/aarch32/cpu_helpers.S
+++ b/lib/cpus/aarch32/cpu_helpers.S
@@ -78,6 +78,10 @@
mov r1, #CPU_PWR_DWN_OPS
add r1, r1, r2, lsl #2
ldr r1, [r0, r1]
+#if ENABLE_ASSERTIONS
+ cmp r1, #0
+ ASM_ASSERT(ne)
+#endif
bx r1
endfunc prepare_cpu_pwr_dwn
@@ -146,6 +150,10 @@
/* Subtract the increment and offset to get the cpu-ops pointer */
sub r0, r4, #(CPU_OPS_SIZE + CPU_MIDR)
+#if ENABLE_ASSERTIONS
+ cmp r0, #0
+ ASM_ASSERT(ne)
+#endif
error_exit:
bx lr
endfunc get_cpu_ops_ptr
@@ -224,7 +232,15 @@
* function. If it's non-NULL, jump to the function in turn.
*/
bl _cpu_data
+#if ENABLE_ASSERTIONS
+ cmp r0, #0
+ ASM_ASSERT(ne)
+#endif
ldr r1, [r0, #CPU_DATA_CPU_OPS_PTR]
+#if ENABLE_ASSERTIONS
+ cmp r1, #0
+ ASM_ASSERT(ne)
+#endif
ldr r0, [r1, #CPU_ERRATA_FUNC]
cmp r0, #0
beq 1f
diff --git a/lib/libc/memset.c b/lib/libc/memset.c
index f9dd4c5..17f798c 100644
--- a/lib/libc/memset.c
+++ b/lib/libc/memset.c
@@ -10,19 +10,20 @@
void *memset(void *dst, int val, size_t count)
{
- char *ptr = dst;
+ uint8_t *ptr = dst;
uint64_t *ptr64;
uint64_t fill = (unsigned char)val;
/* Simplify code below by making sure we write at least one byte. */
- if (count == 0) {
+ if (count == 0U) {
return dst;
}
/* Handle the first part, until the pointer becomes 64-bit aligned. */
- while (((uintptr_t)ptr & 7)) {
- *ptr++ = val;
- if (--count == 0) {
+ while (((uintptr_t)ptr & 7U) != 0U) {
+ *ptr = (uint8_t)val;
+ ptr++;
+ if (--count == 0U) {
return dst;
}
}
@@ -33,15 +34,17 @@
fill |= fill << 32;
/* Use 64-bit writes for as long as possible. */
- ptr64 = (void *)ptr;
- for (; count >= 8; count -= 8) {
- *ptr64++ = fill;
+ ptr64 = (uint64_t *)ptr;
+ for (; count >= 8U; count -= 8) {
+ *ptr64 = fill;
+ ptr64++;
}
/* Handle the remaining part byte-per-byte. */
- ptr = (void *)ptr64;
- while (count--) {
- *ptr++ = val;
+ ptr = (uint8_t *)ptr64;
+ while (count-- > 0U) {
+ *ptr = (uint8_t)val;
+ ptr++;
}
return dst;
diff --git a/plat/allwinner/common/allwinner-common.mk b/plat/allwinner/common/allwinner-common.mk
index 901d888..da83b5e 100644
--- a/plat/allwinner/common/allwinner-common.mk
+++ b/plat/allwinner/common/allwinner-common.mk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@@ -20,8 +20,6 @@
${AW_PLAT}/common/sunxi_common.c
BL31_SOURCES += drivers/allwinner/axp/common.c \
- drivers/allwinner/sunxi_msgbox.c \
- drivers/arm/css/scpi/css_scpi.c \
${GICV2_SOURCES} \
drivers/delay_timer/delay_timer.c \
drivers/delay_timer/generic_delay_timer.c \
@@ -29,12 +27,40 @@
plat/common/plat_gicv2.c \
plat/common/plat_psci_common.c \
${AW_PLAT}/common/sunxi_bl31_setup.c \
- ${AW_PLAT}/common/sunxi_cpu_ops.c \
${AW_PLAT}/common/sunxi_pm.c \
${AW_PLAT}/${PLAT}/sunxi_power.c \
${AW_PLAT}/common/sunxi_security.c \
${AW_PLAT}/common/sunxi_topology.c
+# By default, attempt to use SCPI to the ARISC management processor. If SCPI
+# is not enabled or SCP firmware is not loaded, fall back to a simpler native
+# implementation that does not support CPU or system suspend.
+#
+# If SCP firmware will always be present (or absent), the unused implementation
+# can be compiled out.
+SUNXI_PSCI_USE_NATIVE ?= 1
+SUNXI_PSCI_USE_SCPI ?= 1
+
+$(eval $(call assert_boolean,SUNXI_PSCI_USE_NATIVE))
+$(eval $(call assert_boolean,SUNXI_PSCI_USE_SCPI))
+$(eval $(call add_define,SUNXI_PSCI_USE_NATIVE))
+$(eval $(call add_define,SUNXI_PSCI_USE_SCPI))
+
+ifeq (${SUNXI_PSCI_USE_NATIVE}${SUNXI_PSCI_USE_SCPI},00)
+$(error "At least one of SCPI or native PSCI ops must be enabled")
+endif
+
+ifeq (${SUNXI_PSCI_USE_NATIVE},1)
+BL31_SOURCES += ${AW_PLAT}/common/sunxi_cpu_ops.c \
+ ${AW_PLAT}/common/sunxi_native_pm.c
+endif
+
+ifeq (${SUNXI_PSCI_USE_SCPI},1)
+BL31_SOURCES += drivers/allwinner/sunxi_msgbox.c \
+ drivers/arm/css/scpi/css_scpi.c \
+ ${AW_PLAT}/common/sunxi_scpi_pm.c
+endif
+
# The bootloader is guaranteed to only run on CPU 0 by the boot ROM.
COLD_BOOT_SINGLE_CPU := 1
diff --git a/plat/allwinner/common/include/sunxi_private.h b/plat/allwinner/common/include/sunxi_private.h
index dcf3dc9..b68d23f 100644
--- a/plat/allwinner/common/include/sunxi_private.h
+++ b/plat/allwinner/common/include/sunxi_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,13 +7,32 @@
#ifndef SUNXI_PRIVATE_H
#define SUNXI_PRIVATE_H
+#include <lib/psci/psci.h>
+
void sunxi_configure_mmu_el3(int flags);
void sunxi_cpu_on(u_register_t mpidr);
-void sunxi_cpu_off(u_register_t mpidr);
-void sunxi_disable_secondary_cpus(u_register_t primary_mpidr);
+void sunxi_cpu_power_off_others(void);
+void sunxi_cpu_power_off_self(void);
void sunxi_power_down(void);
+#if SUNXI_PSCI_USE_NATIVE
+void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops);
+#else
+static inline void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+}
+#endif
+#if SUNXI_PSCI_USE_SCPI
+int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops);
+#else
+static inline int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+ return -1;
+}
+#endif
+int sunxi_validate_ns_entrypoint(uintptr_t ns_entrypoint);
+
int sunxi_pmic_setup(uint16_t socid, const void *fdt);
void sunxi_security_setup(void);
diff --git a/plat/allwinner/common/sunxi_cpu_ops.c b/plat/allwinner/common/sunxi_cpu_ops.c
index 6e29b69..cbad720 100644
--- a/plat/allwinner/common/sunxi_cpu_ops.c
+++ b/plat/allwinner/common/sunxi_cpu_ops.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -45,7 +45,8 @@
mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x00);
}
-void sunxi_cpu_off(u_register_t mpidr)
+/* We can't turn ourself off like this, but it works for other cores. */
+static void sunxi_cpu_off(u_register_t mpidr)
{
unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr);
unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
@@ -54,23 +55,22 @@
/* Deassert DBGPWRDUP */
mmio_clrbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
+ /* Activate the core output clamps, but not for core 0. */
+ if (core != 0)
+ mmio_setbits_32(SUNXI_POWEROFF_GATING_REG(cluster), BIT(core));
+ /* Assert CPU power-on reset */
+ mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
+ /* Remove power from the CPU */
+ sunxi_cpu_disable_power(cluster, core);
+}
- /* We can't turn ourself off like this, but it works for other cores. */
- if (read_mpidr() != mpidr) {
- /* Activate the core output clamps, but not for core 0. */
- if (core != 0)
- mmio_setbits_32(SUNXI_POWEROFF_GATING_REG(cluster),
- BIT(core));
- /* Assert CPU power-on reset */
- mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core));
- /* Remove power from the CPU */
- sunxi_cpu_disable_power(cluster, core);
-
- return;
- }
+void sunxi_cpu_power_off_self(void)
+{
+ u_register_t mpidr = read_mpidr();
+ unsigned int core = MPIDR_AFFLVL0_VAL(mpidr);
/* Simplifies assembly, all SoCs so far are single cluster anyway. */
- assert(cluster == 0);
+ assert(MPIDR_AFFLVL1_VAL(mpidr) == 0);
/*
* If we are supposed to turn ourself off, tell the arisc SCP
@@ -106,8 +106,9 @@
mmio_setbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core));
}
-void sunxi_disable_secondary_cpus(u_register_t primary_mpidr)
+void sunxi_cpu_power_off_others(void)
{
+ u_register_t self = read_mpidr();
unsigned int cluster;
unsigned int core;
@@ -116,7 +117,7 @@
u_register_t mpidr = (cluster << MPIDR_AFF1_SHIFT) |
(core << MPIDR_AFF0_SHIFT) |
BIT(31);
- if (mpidr != primary_mpidr)
+ if (mpidr != self)
sunxi_cpu_off(mpidr);
}
}
diff --git a/plat/allwinner/common/sunxi_native_pm.c b/plat/allwinner/common/sunxi_native_pm.c
new file mode 100644
index 0000000..148f50e
--- /dev/null
+++ b/plat/allwinner/common/sunxi_native_pm.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+#define SUNXI_WDOG0_CTRL_REG (SUNXI_R_WDOG_BASE + 0x0010)
+#define SUNXI_WDOG0_CFG_REG (SUNXI_R_WDOG_BASE + 0x0014)
+#define SUNXI_WDOG0_MODE_REG (SUNXI_R_WDOG_BASE + 0x0018)
+
+static int sunxi_pwr_domain_on(u_register_t mpidr)
+{
+ sunxi_cpu_on(mpidr);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ gicv2_cpuif_disable();
+
+ sunxi_cpu_power_off_self();
+}
+
+static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+}
+
+static void __dead2 sunxi_system_off(void)
+{
+ gicv2_cpuif_disable();
+
+ /* Attempt to power down the board (may not return) */
+ sunxi_power_down();
+
+ /* Turn off all CPUs */
+ sunxi_cpu_power_off_others();
+ sunxi_cpu_power_off_self();
+ psci_power_down_wfi();
+}
+
+static void __dead2 sunxi_system_reset(void)
+{
+ gicv2_cpuif_disable();
+
+ /* Reset the whole system when the watchdog times out */
+ mmio_write_32(SUNXI_WDOG0_CFG_REG, 1);
+ /* Enable the watchdog with the shortest timeout (0.5 seconds) */
+ mmio_write_32(SUNXI_WDOG0_MODE_REG, (0 << 4) | 1);
+ /* Wait for twice the watchdog timeout before panicking */
+ mdelay(1000);
+
+ ERROR("PSCI: System reset failed\n");
+ panic();
+}
+
+static const plat_psci_ops_t sunxi_native_psci_ops = {
+ .pwr_domain_on = sunxi_pwr_domain_on,
+ .pwr_domain_off = sunxi_pwr_domain_off,
+ .pwr_domain_on_finish = sunxi_pwr_domain_on_finish,
+ .system_off = sunxi_system_off,
+ .system_reset = sunxi_system_reset,
+ .validate_ns_entrypoint = sunxi_validate_ns_entrypoint,
+};
+
+void sunxi_set_native_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+ *psci_ops = &sunxi_native_psci_ops;
+}
diff --git a/plat/allwinner/common/sunxi_pm.c b/plat/allwinner/common/sunxi_pm.c
index aa80c52..eb1b7e7 100644
--- a/plat/allwinner/common/sunxi_pm.c
+++ b/plat/allwinner/common/sunxi_pm.c
@@ -8,203 +8,14 @@
#include <platform_def.h>
-#include <arch_helpers.h>
#include <common/debug.h>
-#include <drivers/arm/css/css_scpi.h>
-#include <drivers/arm/gicv2.h>
-#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
-#include <plat/common/platform.h>
#include <sunxi_cpucfg.h>
-#include <sunxi_def.h>
-#include <sunxi_mmap.h>
#include <sunxi_private.h>
-#define SUNXI_WDOG0_CTRL_REG (SUNXI_R_WDOG_BASE + 0x0010)
-#define SUNXI_WDOG0_CFG_REG (SUNXI_R_WDOG_BASE + 0x0014)
-#define SUNXI_WDOG0_MODE_REG (SUNXI_R_WDOG_BASE + 0x0018)
-
-#define CPU_PWR_LVL MPIDR_AFFLVL0
-#define CLUSTER_PWR_LVL MPIDR_AFFLVL1
-#define SYSTEM_PWR_LVL MPIDR_AFFLVL2
-
-#define CPU_PWR_STATE(state) \
- ((state)->pwr_domain_state[CPU_PWR_LVL])
-#define CLUSTER_PWR_STATE(state) \
- ((state)->pwr_domain_state[CLUSTER_PWR_LVL])
-#define SYSTEM_PWR_STATE(state) \
- ((state)->pwr_domain_state[SYSTEM_PWR_LVL])
-
-/*
- * The addresses for the SCP exception vectors are defined in the or1k
- * architecture specification.
- */
-#define OR1K_VEC_FIRST 0x01
-#define OR1K_VEC_LAST 0x0e
-#define OR1K_VEC_ADDR(n) (0x100 * (n))
-
-/*
- * This magic value is the little-endian representation of the or1k
- * instruction "l.mfspr r2, r0, 0x12", which is guaranteed to be the
- * first instruction in the SCP firmware.
- */
-#define SCP_FIRMWARE_MAGIC 0xb4400012
-
-static bool scpi_available;
-
-static inline scpi_power_state_t scpi_map_state(plat_local_state_t psci_state)
-{
- if (is_local_state_run(psci_state))
- return scpi_power_on;
- if (is_local_state_retn(psci_state))
- return scpi_power_retention;
- return scpi_power_off;
-}
-
-static void sunxi_cpu_standby(plat_local_state_t cpu_state)
-{
- u_register_t scr = read_scr_el3();
-
- assert(is_local_state_retn(cpu_state));
-
- write_scr_el3(scr | SCR_IRQ_BIT);
- wfi();
- write_scr_el3(scr);
-}
-
-static int sunxi_pwr_domain_on(u_register_t mpidr)
-{
- if (scpi_available) {
- scpi_set_css_power_state(mpidr,
- scpi_power_on,
- scpi_power_on,
- scpi_power_on);
- } else {
- sunxi_cpu_on(mpidr);
- }
-
- return PSCI_E_SUCCESS;
-}
-
-static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
-{
- plat_local_state_t cpu_pwr_state = CPU_PWR_STATE(target_state);
- plat_local_state_t cluster_pwr_state = CLUSTER_PWR_STATE(target_state);
- plat_local_state_t system_pwr_state = SYSTEM_PWR_STATE(target_state);
-
- if (is_local_state_off(cpu_pwr_state))
- gicv2_cpuif_disable();
-
- if (scpi_available) {
- scpi_set_css_power_state(read_mpidr(),
- scpi_map_state(cpu_pwr_state),
- scpi_map_state(cluster_pwr_state),
- scpi_map_state(system_pwr_state));
- }
-}
-
-static void __dead2 sunxi_pwr_down_wfi(const psci_power_state_t *target_state)
-{
- sunxi_cpu_off(read_mpidr());
-
- while (1)
- wfi();
-}
-
-static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
-{
- if (is_local_state_off(SYSTEM_PWR_STATE(target_state)))
- gicv2_distif_init();
- if (is_local_state_off(CPU_PWR_STATE(target_state))) {
- gicv2_pcpu_distif_init();
- gicv2_cpuif_enable();
- }
-}
-
-static void __dead2 sunxi_system_off(void)
-{
- gicv2_cpuif_disable();
-
- if (scpi_available) {
- /* Send the power down request to the SCP */
- uint32_t ret = scpi_sys_power_state(scpi_system_shutdown);
-
- if (ret != SCP_OK)
- ERROR("PSCI: SCPI %s failed: %d\n", "shutdown", ret);
- }
-
- /* Turn off all secondary CPUs */
- sunxi_disable_secondary_cpus(read_mpidr());
-
- sunxi_power_down();
-
- udelay(1000);
- ERROR("PSCI: Cannot turn off system, halting\n");
- wfi();
- panic();
-}
-
-static void __dead2 sunxi_system_reset(void)
-{
- gicv2_cpuif_disable();
-
- if (scpi_available) {
- /* Send the system reset request to the SCP */
- uint32_t ret = scpi_sys_power_state(scpi_system_reboot);
-
- if (ret != SCP_OK)
- ERROR("PSCI: SCPI %s failed: %d\n", "reboot", ret);
- }
-
- /* Reset the whole system when the watchdog times out */
- mmio_write_32(SUNXI_WDOG0_CFG_REG, 1);
- /* Enable the watchdog with the shortest timeout (0.5 seconds) */
- mmio_write_32(SUNXI_WDOG0_MODE_REG, (0 << 4) | 1);
- /* Wait for twice the watchdog timeout before panicking */
- mdelay(1000);
-
- ERROR("PSCI: System reset failed\n");
- wfi();
- panic();
-}
-
-static int sunxi_validate_power_state(unsigned int power_state,
- psci_power_state_t *req_state)
-{
- unsigned int power_level = psci_get_pstate_pwrlvl(power_state);
- unsigned int type = psci_get_pstate_type(power_state);
-
- assert(req_state != NULL);
-
- if (power_level > PLAT_MAX_PWR_LVL)
- return PSCI_E_INVALID_PARAMS;
-
- if (type == PSTATE_TYPE_STANDBY) {
- /* Only one retention power state is supported. */
- if (psci_get_pstate_id(power_state) > 0)
- return PSCI_E_INVALID_PARAMS;
- /* The SoC cannot be suspended without losing state */
- if (power_level == SYSTEM_PWR_LVL)
- return PSCI_E_INVALID_PARAMS;
- for (unsigned int i = 0; i <= power_level; ++i)
- req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
- } else {
- /* Only one off power state is supported. */
- if (psci_get_pstate_id(power_state) > 0)
- return PSCI_E_INVALID_PARAMS;
- for (unsigned int i = 0; i <= power_level; ++i)
- req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
- }
- /* Higher power domain levels should all remain running */
- for (unsigned int i = power_level + 1; i <= PLAT_MAX_PWR_LVL; ++i)
- req_state->pwr_domain_state[i] = PSCI_LOCAL_STATE_RUN;
-
- return PSCI_E_SUCCESS;
-}
-
-static int sunxi_validate_ns_entrypoint(uintptr_t ns_entrypoint)
+int sunxi_validate_ns_entrypoint(uintptr_t ns_entrypoint)
{
/* The non-secure entry point must be in DRAM */
if (ns_entrypoint < SUNXI_DRAM_BASE) {
@@ -214,25 +25,6 @@
return PSCI_E_SUCCESS;
}
-static void sunxi_get_sys_suspend_power_state(psci_power_state_t *req_state)
-{
- assert(req_state);
-
- for (unsigned int i = 0; i <= PLAT_MAX_PWR_LVL; ++i)
- req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
-}
-
-static plat_psci_ops_t sunxi_psci_ops = {
- .cpu_standby = sunxi_cpu_standby,
- .pwr_domain_on = sunxi_pwr_domain_on,
- .pwr_domain_off = sunxi_pwr_domain_off,
- .pwr_domain_on_finish = sunxi_pwr_domain_on_finish,
- .system_off = sunxi_system_off,
- .system_reset = sunxi_system_reset,
- .validate_power_state = sunxi_validate_power_state,
- .validate_ns_entrypoint = sunxi_validate_ns_entrypoint,
-};
-
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
@@ -246,36 +38,12 @@
sec_entrypoint >> 32);
}
- /* Check for a valid SCP firmware, and boot the SCP if found. */
- if (mmio_read_32(SUNXI_SCP_BASE) == SCP_FIRMWARE_MAGIC) {
- /* Program SCP exception vectors to the firmware entrypoint. */
- for (unsigned int i = OR1K_VEC_FIRST; i <= OR1K_VEC_LAST; ++i) {
- uint32_t vector = SUNXI_SRAM_A2_BASE + OR1K_VEC_ADDR(i);
- uint32_t offset = SUNXI_SCP_BASE - vector;
-
- mmio_write_32(vector, offset >> 2);
- clean_dcache_range(vector, sizeof(uint32_t));
- }
- /* Take the SCP out of reset. */
- mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0));
- /* Wait for the SCP firmware to boot. */
- if (scpi_wait_ready() == 0)
- scpi_available = true;
- }
-
- NOTICE("PSCI: System suspend is %s\n",
- scpi_available ? "available via SCPI" : "unavailable");
- if (scpi_available) {
- /* Suspend is only available via SCPI. */
- sunxi_psci_ops.pwr_domain_suspend = sunxi_pwr_domain_off;
- sunxi_psci_ops.pwr_domain_suspend_finish = sunxi_pwr_domain_on_finish;
- sunxi_psci_ops.get_sys_suspend_power_state = sunxi_get_sys_suspend_power_state;
+ if (sunxi_set_scpi_psci_ops(psci_ops) == 0) {
+ INFO("PSCI: Suspend is available via SCPI\n");
} else {
- /* This is only needed when SCPI is unavailable. */
- sunxi_psci_ops.pwr_domain_pwr_down_wfi = sunxi_pwr_down_wfi;
+ INFO("PSCI: Suspend is unavailable\n");
+ sunxi_set_native_psci_ops(psci_ops);
}
- *psci_ops = &sunxi_psci_ops;
-
return 0;
}
diff --git a/plat/allwinner/common/sunxi_scpi_pm.c b/plat/allwinner/common/sunxi_scpi_pm.c
new file mode 100644
index 0000000..74763ef
--- /dev/null
+++ b/plat/allwinner/common/sunxi_scpi_pm.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scpi.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+
+#include <sunxi_mmap.h>
+#include <sunxi_private.h>
+
+/*
+ * The addresses for the SCP exception vectors are defined in the or1k
+ * architecture specification.
+ */
+#define OR1K_VEC_FIRST 0x01
+#define OR1K_VEC_LAST 0x0e
+#define OR1K_VEC_ADDR(n) (0x100 * (n))
+
+/*
+ * This magic value is the little-endian representation of the or1k
+ * instruction "l.mfspr r2, r0, 0x12", which is guaranteed to be the
+ * first instruction in the SCP firmware.
+ */
+#define SCP_FIRMWARE_MAGIC 0xb4400012
+
+#define CPU_PWR_LVL MPIDR_AFFLVL0
+#define CLUSTER_PWR_LVL MPIDR_AFFLVL1
+#define SYSTEM_PWR_LVL MPIDR_AFFLVL2
+
+#define CPU_PWR_STATE(state) \
+ ((state)->pwr_domain_state[CPU_PWR_LVL])
+#define CLUSTER_PWR_STATE(state) \
+ ((state)->pwr_domain_state[CLUSTER_PWR_LVL])
+#define SYSTEM_PWR_STATE(state) \
+ ((state)->pwr_domain_state[SYSTEM_PWR_LVL])
+
+static inline scpi_power_state_t scpi_map_state(plat_local_state_t psci_state)
+{
+ if (is_local_state_run(psci_state)) {
+ return scpi_power_on;
+ }
+ if (is_local_state_retn(psci_state)) {
+ return scpi_power_retention;
+ }
+ return scpi_power_off;
+}
+
+static void sunxi_cpu_standby(plat_local_state_t cpu_state)
+{
+ u_register_t scr = read_scr_el3();
+
+ assert(is_local_state_retn(cpu_state));
+
+ write_scr_el3(scr | SCR_IRQ_BIT);
+ wfi();
+ write_scr_el3(scr);
+}
+
+static int sunxi_pwr_domain_on(u_register_t mpidr)
+{
+ scpi_set_css_power_state(mpidr,
+ scpi_power_on,
+ scpi_power_on,
+ scpi_power_on);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void sunxi_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ plat_local_state_t cpu_pwr_state = CPU_PWR_STATE(target_state);
+ plat_local_state_t cluster_pwr_state = CLUSTER_PWR_STATE(target_state);
+ plat_local_state_t system_pwr_state = SYSTEM_PWR_STATE(target_state);
+
+ if (is_local_state_off(cpu_pwr_state)) {
+ gicv2_cpuif_disable();
+ }
+
+ scpi_set_css_power_state(read_mpidr(),
+ scpi_map_state(cpu_pwr_state),
+ scpi_map_state(cluster_pwr_state),
+ scpi_map_state(system_pwr_state));
+}
+
+static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
+ gicv2_distif_init();
+ }
+ if (is_local_state_off(CPU_PWR_STATE(target_state))) {
+ gicv2_pcpu_distif_init();
+ gicv2_cpuif_enable();
+ }
+}
+
+static void __dead2 sunxi_system_off(void)
+{
+ uint32_t ret;
+
+ gicv2_cpuif_disable();
+
+ /* Send the power down request to the SCP. */
+ ret = scpi_sys_power_state(scpi_system_shutdown);
+ if (ret != SCP_OK) {
+ ERROR("PSCI: SCPI %s failed: %d\n", "shutdown", ret);
+ }
+
+ psci_power_down_wfi();
+}
+
+static void __dead2 sunxi_system_reset(void)
+{
+ uint32_t ret;
+
+ gicv2_cpuif_disable();
+
+ /* Send the system reset request to the SCP. */
+ ret = scpi_sys_power_state(scpi_system_reboot);
+ if (ret != SCP_OK) {
+ ERROR("PSCI: SCPI %s failed: %d\n", "reboot", ret);
+ }
+
+ psci_power_down_wfi();
+}
+
+static int sunxi_validate_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ unsigned int power_level = psci_get_pstate_pwrlvl(power_state);
+ unsigned int type = psci_get_pstate_type(power_state);
+
+ assert(req_state != NULL);
+
+ if (power_level > PLAT_MAX_PWR_LVL) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ if (type == PSTATE_TYPE_STANDBY) {
+ /* Only one retention power state is supported. */
+ if (psci_get_pstate_id(power_state) > 0) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+ /* The SoC cannot be suspended without losing state */
+ if (power_level == SYSTEM_PWR_LVL) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+ for (unsigned int i = 0; i <= power_level; ++i) {
+ req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE;
+ }
+ } else {
+ /* Only one off power state is supported. */
+ if (psci_get_pstate_id(power_state) > 0) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+ for (unsigned int i = 0; i <= power_level; ++i) {
+ req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+ }
+ }
+ /* Higher power domain levels should all remain running */
+ for (unsigned int i = power_level + 1; i <= PLAT_MAX_PWR_LVL; ++i) {
+ req_state->pwr_domain_state[i] = PSCI_LOCAL_STATE_RUN;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+static void sunxi_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ assert(req_state != NULL);
+
+ for (unsigned int i = 0; i <= PLAT_MAX_PWR_LVL; ++i) {
+ req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+ }
+}
+
+static const plat_psci_ops_t sunxi_scpi_psci_ops = {
+ .cpu_standby = sunxi_cpu_standby,
+ .pwr_domain_on = sunxi_pwr_domain_on,
+ .pwr_domain_off = sunxi_pwr_domain_off,
+ .pwr_domain_suspend = sunxi_pwr_domain_off,
+ .pwr_domain_on_finish = sunxi_pwr_domain_on_finish,
+ .pwr_domain_suspend_finish = sunxi_pwr_domain_on_finish,
+ .system_off = sunxi_system_off,
+ .system_reset = sunxi_system_reset,
+ .validate_power_state = sunxi_validate_power_state,
+ .validate_ns_entrypoint = sunxi_validate_ns_entrypoint,
+ .get_sys_suspend_power_state = sunxi_get_sys_suspend_power_state,
+};
+
+int sunxi_set_scpi_psci_ops(const plat_psci_ops_t **psci_ops)
+{
+ *psci_ops = &sunxi_scpi_psci_ops;
+
+ /* Check for a valid SCP firmware. */
+ if (mmio_read_32(SUNXI_SCP_BASE) != SCP_FIRMWARE_MAGIC) {
+ return -1;
+ }
+
+ /* Program SCP exception vectors to the firmware entrypoint. */
+ for (unsigned int i = OR1K_VEC_FIRST; i <= OR1K_VEC_LAST; ++i) {
+ uint32_t vector = SUNXI_SRAM_A2_BASE + OR1K_VEC_ADDR(i);
+ uint32_t offset = SUNXI_SCP_BASE - vector;
+
+ mmio_write_32(vector, offset >> 2);
+ clean_dcache_range(vector, sizeof(uint32_t));
+ }
+
+ /* Take the SCP out of reset. */
+ mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0));
+
+ /* Wait for the SCP firmware to boot. */
+ return scpi_wait_ready();
+}
diff --git a/plat/arm/css/sgi/sgi_bl31_setup.c b/plat/arm/css/sgi/sgi_bl31_setup.c
index 36c3fbb..e8238ba 100644
--- a/plat/arm/css/sgi/sgi_bl31_setup.c
+++ b/plat/arm/css/sgi/sgi_bl31_setup.c
@@ -28,7 +28,7 @@
.ring_doorbell = &mhu_ring_doorbell,
};
-static scmi_channel_plat_info_t rd_n1e1_edge_scmi_plat_info[] = {
+static scmi_channel_plat_info_t plat_rd_scmi_info[] = {
{
.scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE,
.db_reg_addr = PLAT_CSS_MHU_BASE + SENDER_REG_SET(0),
@@ -76,9 +76,9 @@
if (sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM ||
sgi_plat_info.platform_id == RD_V1_SID_VER_PART_NUM ||
sgi_plat_info.platform_id == RD_N2_SID_VER_PART_NUM) {
- if (channel_id >= ARRAY_SIZE(rd_n1e1_edge_scmi_plat_info))
+ if (channel_id >= ARRAY_SIZE(plat_rd_scmi_info))
panic();
- return &rd_n1e1_edge_scmi_plat_info[channel_id];
+ return &plat_rd_scmi_info[channel_id];
}
else if (sgi_plat_info.platform_id == SGI575_SSC_VER_PART_NUM)
return &sgi575_scmi_plat_info;
diff --git a/plat/marvell/armada/a8k/a80x0/board/dram_port.c b/plat/marvell/armada/a8k/a80x0/board/dram_port.c
index 381c871..47bc0a8 100644
--- a/plat/marvell/armada/a8k/a80x0/board/dram_port.c
+++ b/plat/marvell/armada/a8k/a80x0/board/dram_port.c
@@ -138,7 +138,7 @@
i2c_init((void *)MVEBU_CP0_I2C_BASE);
/* select SPD memory page 0 to access DRAM configuration */
- i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 1);
+ i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 0);
/* read data from spd */
i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
diff --git a/plat/marvell/armada/a8k/a80x0_mcbin/board/dram_port.c b/plat/marvell/armada/a8k/a80x0_mcbin/board/dram_port.c
index 50a68b3..85c931c 100644
--- a/plat/marvell/armada/a8k/a80x0_mcbin/board/dram_port.c
+++ b/plat/marvell/armada/a8k/a80x0_mcbin/board/dram_port.c
@@ -123,7 +123,7 @@
/* initialize the i2c */
i2c_init((void *)MVEBU_CP0_I2C_BASE);
/* select SPD memory page 0 to access DRAM configuration */
- i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 1);
+ i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 0);
/* read data from spd */
i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
sizeof(tm->spd_data.all_bytes));
diff --git a/plat/marvell/armada/a8k/a80x0_puzzle/board/dram_port.c b/plat/marvell/armada/a8k/a80x0_puzzle/board/dram_port.c
index 3879c98..1d8e9d2 100644
--- a/plat/marvell/armada/a8k/a80x0_puzzle/board/dram_port.c
+++ b/plat/marvell/armada/a8k/a80x0_puzzle/board/dram_port.c
@@ -132,7 +132,7 @@
/* initialize the MVEBU_AP_I2C_BASE I2C bus */
i2c_init((void *)MVEBU_AP_I2C_BASE);
/* select SPD memory page 0 to access DRAM configuration */
- i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 1);
+ i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 0);
/* read data from spd */
i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
sizeof(tm->spd_data.all_bytes));
diff --git a/plat/marvell/armada/a8k/common/a8k_common.mk b/plat/marvell/armada/a8k/common/a8k_common.mk
index 63cfce2..8a463ea 100644
--- a/plat/marvell/armada/a8k/common/a8k_common.mk
+++ b/plat/marvell/armada/a8k/common/a8k_common.mk
@@ -114,7 +114,8 @@
$(MARVELL_DRV_BASE)/cache_llc.c \
$(MARVELL_DRV_BASE)/comphy/phy-comphy-cp110.c \
$(MARVELL_DRV_BASE)/mc_trustzone/mc_trustzone.c \
- $(MARVELL_DRV_BASE)/mg_conf_cm3/mg_conf_cm3.c
+ $(MARVELL_DRV_BASE)/mg_conf_cm3/mg_conf_cm3.c \
+ drivers/rambus/trng_ip_76.c
BL31_PORTING_SOURCES := $(BOARD_DIR)/board/marvell_plat_config.c
diff --git a/plat/marvell/armada/a8k/common/ble/ble.mk b/plat/marvell/armada/a8k/common/ble/ble.mk
index 78c62a0..d6d72c1 100644
--- a/plat/marvell/armada/a8k/common/ble/ble.mk
+++ b/plat/marvell/armada/a8k/common/ble/ble.mk
@@ -13,6 +13,7 @@
BLE_SOURCES += $(BLE_PATH)/ble_main.c \
$(BLE_PATH)/ble_mem.S \
drivers/delay_timer/delay_timer.c \
+ drivers/marvell/iob.c \
$(PLAT_MARVELL)/common/aarch64/marvell_helpers.S \
$(PLAT_MARVELL)/common/plat_delay_timer.c \
$(PLAT_MARVELL)/common/marvell_console.c
diff --git a/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c b/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c
index b919cb3..71fa2b8 100644
--- a/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c
+++ b/plat/marvell/armada/a8k/common/mss/mss_bl2_setup.c
@@ -30,6 +30,10 @@
#define MSS_EXTERNAL_ADDR_MASK 0xfffffff
#define MSS_INTERNAL_ACCESS_BIT 28
+#define MSS_AP_REGS_OFFSET 0x580000
+#define MSS_CP_SRAM_OFFSET 0x220000
+#define MSS_CP_REGS_OFFSET 0x280000
+
struct addr_map_win ccu_mem_map[] = {
{MVEBU_CP_REGS_BASE(0), 0x4000000, IO_0_TID}
};
@@ -121,12 +125,21 @@
uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx)
{
- return MVEBU_CP_REGS_BASE(cp_idx) + 0x280000;
+ return MVEBU_CP_REGS_BASE(cp_idx) + MSS_CP_REGS_OFFSET;
+}
+
+uintptr_t bl2_plat_get_cp_mss_sram(int ap_idx, int cp_idx)
+{
+ if (is_secure()) {
+ return MVEBU_CP_REGS_BASE(cp_idx) + MSS_CP_SRAM_OFFSET;
+ }
+
+ return 0; /* SRAM will not be used */
}
uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx)
{
- return MVEBU_REGS_BASE + 0x580000;
+ return MVEBU_REGS_BASE + MSS_AP_REGS_OFFSET;
}
uint32_t bl2_plat_get_cp_count(int ap_idx)
diff --git a/plat/marvell/armada/a8k/common/plat_ble_setup.c b/plat/marvell/armada/a8k/common/plat_ble_setup.c
index e4e09fb..4114327 100644
--- a/plat/marvell/armada/a8k/common/plat_ble_setup.c
+++ b/plat/marvell/armada/a8k/common/plat_ble_setup.c
@@ -720,7 +720,7 @@
int ble_plat_setup(int *skip)
{
- int ret;
+ int ret, cp;
unsigned int freq_mode;
/* Power down unused CPUs */
@@ -745,6 +745,10 @@
/* Do required CP-110 setups for BLE stage */
cp110_ble_init(MVEBU_CP_REGS_BASE(0));
+ /* Config address for each cp other than cp0 */
+ for (cp = 1; cp < CP_COUNT; cp++)
+ update_cp110_default_win(cp);
+
/* Setup AVS */
ble_plat_svc_config();
diff --git a/plat/marvell/armada/common/mrvl_sip_svc.c b/plat/marvell/armada/common/mrvl_sip_svc.c
index 0291024..64187fb 100644
--- a/plat/marvell/armada/common/mrvl_sip_svc.c
+++ b/plat/marvell/armada/common/mrvl_sip_svc.c
@@ -9,6 +9,7 @@
#include <common/runtime_svc.h>
#include <drivers/marvell/cache_llc.h>
#include <drivers/marvell/mochi/ap_setup.h>
+#include <drivers/rambus/trng_ip_76.h>
#include <lib/smccc.h>
#include <marvell_plat_priv.h>
@@ -37,6 +38,9 @@
#define MV_SIP_PMU_IRQ_ENABLE 0x82000012
#define MV_SIP_PMU_IRQ_DISABLE 0x82000013
+/* TRNG */
+#define MV_SIP_RNG_64 0xC200FF11
+
#define MAX_LANE_NR 6
#define MVEBU_COMPHY_OFFSET 0x441000
#define MVEBU_CP_BASE_MASK (~0xffffff)
@@ -68,6 +72,7 @@
u_register_t flags)
{
u_register_t ret;
+ uint32_t w2[2] = {0, 0};
int i;
debug("%s: got SMC (0x%x) x1 0x%lx, x2 0x%lx, x3 0x%lx\n",
@@ -131,7 +136,9 @@
mvebu_pmu_interrupt_disable();
SMC_RET1(handle, 0);
#endif
-
+ case MV_SIP_RNG_64:
+ ret = eip76_rng_get_random((uint8_t *)&w2, 4 * (x1 % 2 + 1));
+ SMC_RET3(handle, ret, w2[0], w2[1]);
default:
ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
SMC_RET1(handle, SMC_UNK);
diff --git a/plat/marvell/armada/common/mss/mss_scp_bl2_format.h b/plat/marvell/armada/common/mss/mss_scp_bl2_format.h
index 74dddc6..90913b0 100644
--- a/plat/marvell/armada/common/mss/mss_scp_bl2_format.h
+++ b/plat/marvell/armada/common/mss/mss_scp_bl2_format.h
@@ -13,6 +13,7 @@
#define HEADER_VERSION 0x1
#define MSS_IDRAM_SIZE 0x10000 /* 64KB */
+#define MSS_SRAM_SIZE 0x8000 /* 32KB */
/* Types definitions */
typedef struct file_header {
diff --git a/plat/marvell/armada/common/mss/mss_scp_bootloader.c b/plat/marvell/armada/common/mss/mss_scp_bootloader.c
index adf570e..f669a77 100644
--- a/plat/marvell/armada/common/mss/mss_scp_bootloader.c
+++ b/plat/marvell/armada/common/mss/mss_scp_bootloader.c
@@ -38,6 +38,8 @@
#define MSS_DMA_TIMEOUT 1000
#define MSS_EXTERNAL_SPACE 0x50000000
#define MSS_EXTERNAL_ADDR_MASK 0xfffffff
+#define MSS_INTERNAL_SPACE 0x40000000
+#define MSS_INTERNAL_ADDR_MASK 0x00ffffff
#define DMA_SIZE 128
@@ -60,60 +62,113 @@
return 0;
}
-static int mss_image_load(uint32_t src_addr, uint32_t size, uintptr_t mss_regs)
+static int mss_iram_dma_load(uint32_t src_addr, uint32_t size,
+ uintptr_t mss_regs)
{
uint32_t i, loop_num, timeout;
+ /* load image to MSS RAM using DMA */
+ loop_num = (size / DMA_SIZE) + !!(size % DMA_SIZE);
+ for (i = 0; i < loop_num; i++) {
+ /* write source address */
+ mmio_write_32(MSS_DMA_SRCBR(mss_regs),
+ src_addr + (i * DMA_SIZE));
+ /* write destination address */
+ mmio_write_32(MSS_DMA_DSTBR(mss_regs), (i * DMA_SIZE));
+ /* make sure DMA data is ready before triggering it */
+ dsb();
+ /* set the DMA control register */
+ mmio_write_32(MSS_DMA_CTRLR(mss_regs),
+ ((MSS_DMA_CTRLR_REQ_SET <<
+ MSS_DMA_CTRLR_REQ_OFFSET) |
+ (DMA_SIZE << MSS_DMA_CTRLR_SIZE_OFFSET)));
+ /* Poll DMA_ACK at MSS_DMACTLR until it is ready */
+ timeout = MSS_DMA_TIMEOUT;
+ while (timeout > 0U) {
+ if ((mmio_read_32(MSS_DMA_CTRLR(mss_regs)) >>
+ (MSS_DMA_CTRLR_ACK_OFFSET &
+ MSS_DMA_CTRLR_ACK_MASK))
+ == MSS_DMA_CTRLR_ACK_READY) {
+ break;
+ }
+ udelay(50);
+ timeout--;
+ }
+ if (timeout == 0) {
+ ERROR("\nMSS DMA failed (timeout)\n");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int mss_image_load(uint32_t src_addr, uint32_t size,
+ uintptr_t mss_regs, uintptr_t sram)
+{
+ uint32_t chunks = 1; /* !sram case */
+ uint32_t chunk_num;
+ int ret;
+
/* Check if the img size is not bigger than ID-RAM size of MSS CM3 */
if (size > MSS_IDRAM_SIZE) {
ERROR("image is too big to fit into MSS CM3 memory\n");
return 1;
}
- NOTICE("Loading MSS image from addr. 0x%x Size 0x%x to MSS at 0x%lx\n",
- src_addr, size, mss_regs);
- /* load image to MSS RAM using DMA */
- loop_num = (size / DMA_SIZE) + (((size & (DMA_SIZE - 1)) == 0) ? 0 : 1);
+ /* The CPx MSS DMA cannot access DRAM directly in secure boot mode
+ * Copy the MSS FW image to MSS SRAM by the CPU first, then run
+ * MSS DMA for SRAM to IRAM copy
+ */
+ if (sram != 0) {
+ chunks = size / MSS_SRAM_SIZE + !!(size % MSS_SRAM_SIZE);
+ }
- for (i = 0; i < loop_num; i++) {
- /* write destination and source addresses */
- mmio_write_32(MSS_DMA_SRCBR(mss_regs),
- MSS_EXTERNAL_SPACE |
- ((src_addr & MSS_EXTERNAL_ADDR_MASK) +
- (i * DMA_SIZE)));
- mmio_write_32(MSS_DMA_DSTBR(mss_regs), (i * DMA_SIZE));
+ NOTICE("%s Loading MSS FW from addr. 0x%x Size 0x%x to MSS at 0x%lx\n",
+ sram == 0 ? "" : "SECURELY", src_addr, size, mss_regs);
+ for (chunk_num = 0; chunk_num < chunks; chunk_num++) {
+ size_t chunk_size = size;
+ uint32_t img_src = MSS_EXTERNAL_SPACE | /* no SRAM */
+ (src_addr & MSS_EXTERNAL_ADDR_MASK);
- dsb(); /* make sure DMA data is ready before triggering it */
+ if (sram != 0) {
+ uintptr_t chunk_source =
+ src_addr + MSS_SRAM_SIZE * chunk_num;
- /* set the DMA control register */
- mmio_write_32(MSS_DMA_CTRLR(mss_regs), ((MSS_DMA_CTRLR_REQ_SET
- << MSS_DMA_CTRLR_REQ_OFFSET) |
- (DMA_SIZE << MSS_DMA_CTRLR_SIZE_OFFSET)));
+ if (chunk_num != (size / MSS_SRAM_SIZE)) {
+ chunk_size = MSS_SRAM_SIZE;
+ } else {
+ chunk_size = size % MSS_SRAM_SIZE;
+ }
- /* Poll DMA_ACK at MSS_DMACTLR until it is ready */
- timeout = MSS_DMA_TIMEOUT;
- while (timeout) {
- if ((mmio_read_32(MSS_DMA_CTRLR(mss_regs)) >>
- MSS_DMA_CTRLR_ACK_OFFSET & MSS_DMA_CTRLR_ACK_MASK)
- == MSS_DMA_CTRLR_ACK_READY) {
+ if (chunk_size == 0) {
break;
}
- udelay(50);
- timeout--;
+ VERBOSE("Chunk %d -> SRAM 0x%lx from 0x%lx SZ 0x%lx\n",
+ chunk_num, sram, chunk_source, chunk_size);
+ memcpy((void *)sram, (void *)chunk_source, chunk_size);
+ dsb();
+ img_src = MSS_INTERNAL_SPACE |
+ (sram & MSS_INTERNAL_ADDR_MASK);
}
- if (timeout == 0) {
- ERROR("\nDMA failed to load MSS image\n");
- return 1;
+ ret = mss_iram_dma_load(img_src, chunk_size, mss_regs);
+ if (ret != 0) {
+ ERROR("MSS FW chunk %d load failed\n", chunk_num);
+ return ret;
}
}
bl2_plat_configure_mss_windows(mss_regs);
+ /* Wipe the MSS SRAM after using it as copy buffer */
+ if (sram) {
+ memset((void *)sram, 0, MSS_SRAM_SIZE);
+ }
+
/* Release M3 from reset */
- mmio_write_32(MSS_M3_RSTCR(mss_regs), (MSS_M3_RSTCR_RST_OFF <<
- MSS_M3_RSTCR_RST_OFFSET));
+ mmio_write_32(MSS_M3_RSTCR(mss_regs),
+ (MSS_M3_RSTCR_RST_OFF << MSS_M3_RSTCR_RST_OFFSET));
NOTICE("Done\n");
@@ -162,7 +217,7 @@
VERBOSE("Send info about the SCP_BL2 image to be transferred to SCP\n");
ret = mss_image_load(single_img, image_size,
- bl2_plat_get_ap_mss_regs(ap_idx));
+ bl2_plat_get_ap_mss_regs(ap_idx), 0);
if (ret != 0) {
ERROR("SCP Image load failed\n");
return -1;
@@ -218,6 +273,8 @@
cp_index, ap_idx);
ret = mss_image_load(single_img, image_size,
bl2_plat_get_cp_mss_regs(
+ ap_idx, cp_index),
+ bl2_plat_get_cp_mss_sram(
ap_idx, cp_index));
if (ret != 0) {
ERROR("SCP Image load failed\n");
diff --git a/plat/marvell/armada/common/mss/mss_scp_bootloader.h b/plat/marvell/armada/common/mss/mss_scp_bootloader.h
index 4950d24..d65354a 100644
--- a/plat/marvell/armada/common/mss/mss_scp_bootloader.h
+++ b/plat/marvell/armada/common/mss/mss_scp_bootloader.h
@@ -10,6 +10,7 @@
int scp_bootloader_transfer(void *image, unsigned int image_size);
uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx);
+uintptr_t bl2_plat_get_cp_mss_sram(int ap_idx, int cp_idx);
uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx);
uint32_t bl2_plat_get_cp_count(int ap_idx);
uint32_t bl2_plat_get_ap_count(void);
diff --git a/plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c b/plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c
index 0befadf..82ce07b 100644
--- a/plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c
+++ b/plat/marvell/octeontx/otx2/t91/t9130/board/dram_port.c
@@ -149,7 +149,7 @@
i2c_init((void *)MVEBU_CP0_I2C_BASE);
/* select SPD memory page 0 to access DRAM configuration */
- i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 1);
+ i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 0);
/* read data from spd */
i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes,
diff --git a/plat/marvell/octeontx/otx2/t91/t9130/board/marvell_plat_config.c b/plat/marvell/octeontx/otx2/t91/t9130/board/marvell_plat_config.c
index 7debd65..fbacf54 100644
--- a/plat/marvell/octeontx/otx2/t91/t9130/board/marvell_plat_config.c
+++ b/plat/marvell/octeontx/otx2/t91/t9130/board/marvell_plat_config.c
@@ -46,15 +46,19 @@
*****************************************************************************
*/
struct addr_map_win io_win_memory_map[] = {
+#if (CP_COUNT > 1)
+ /* SB (MCi0) internal regs */
+ {0x00000000f4000000, 0x2000000, MCI_0_TID},
+#if (CP_COUNT > 2)
+ /* SB (MCi1) internal regs */
+ {0x00000000f6000000, 0x2000000, MCI_1_TID},
+#endif
+#endif
#ifndef IMAGE_BLE
/* SB (MCi0) PCIe0-2 on CP1 */
{0x00000000e2000000, 0x3000000, MCI_0_TID},
/* SB (MCi1) PCIe0-2 on CP2 */
{0x00000000e5000000, 0x3000000, MCI_1_TID},
- /* SB (MCi0) internal regs */
- {0x00000000f4000000, 0x2000000, MCI_0_TID},
- /* SB (MCi1) internal regs */
- {0x00000000f6000000, 0x2000000, MCI_1_TID},
/* MCI 0 indirect window */
{MVEBU_MCI_REG_BASE_REMAP(0), 0x100000, MCI_0_TID},
/* MCI 1 indirect window */
diff --git a/plat/qemu/common/qemu_bl31_setup.c b/plat/qemu/common/qemu_bl31_setup.c
index 4d36b03..4f60eb1 100644
--- a/plat/qemu/common/qemu_bl31_setup.c
+++ b/plat/qemu/common/qemu_bl31_setup.c
@@ -7,6 +7,7 @@
#include <assert.h>
#include <common/bl_common.h>
+#include <drivers/arm/pl061_gpio.h>
#include <plat/common/platform.h>
#include "qemu_private.h"
@@ -69,9 +70,18 @@
BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END);
}
+static void qemu_gpio_init(void)
+{
+#ifdef SECURE_GPIO_BASE
+ pl061_gpio_init();
+ pl061_gpio_register(SECURE_GPIO_BASE, 0);
+#endif
+}
+
void bl31_platform_setup(void)
{
plat_qemu_gic_init();
+ qemu_gpio_init();
}
unsigned int plat_get_syscnt_freq2(void)
diff --git a/plat/qemu/common/qemu_pm.c b/plat/qemu/common/qemu_pm.c
index cf80009..c4ffcf9 100644
--- a/plat/qemu/common/qemu_pm.c
+++ b/plat/qemu/common/qemu_pm.c
@@ -12,6 +12,7 @@
#include <lib/psci/psci.h>
#include <lib/semihosting.h>
#include <plat/common/platform.h>
+#include <drivers/gpio.h>
#include "qemu_private.h"
@@ -201,16 +202,31 @@
/*******************************************************************************
* Platform handlers to shutdown/reboot the system
******************************************************************************/
+
static void __dead2 qemu_system_off(void)
{
+#ifdef SECURE_GPIO_BASE
+ ERROR("QEMU System Power off: with GPIO.\n");
+ gpio_set_direction(SECURE_GPIO_POWEROFF, GPIO_DIR_OUT);
+ gpio_set_value(SECURE_GPIO_POWEROFF, GPIO_LEVEL_HIGH);
+ gpio_set_value(SECURE_GPIO_POWEROFF, GPIO_LEVEL_LOW);
+#else
semihosting_exit(ADP_STOPPED_APPLICATION_EXIT, 0);
ERROR("QEMU System Off: semihosting call unexpectedly returned.\n");
+#endif
panic();
}
static void __dead2 qemu_system_reset(void)
{
+ ERROR("QEMU System Reset: with GPIO.\n");
+#ifdef SECURE_GPIO_BASE
+ gpio_set_direction(SECURE_GPIO_RESET, GPIO_DIR_OUT);
+ gpio_set_value(SECURE_GPIO_RESET, GPIO_LEVEL_HIGH);
+ gpio_set_value(SECURE_GPIO_RESET, GPIO_LEVEL_LOW);
+#else
ERROR("QEMU System Reset: operation not handled.\n");
+#endif
panic();
}
diff --git a/plat/qemu/qemu/include/platform_def.h b/plat/qemu/qemu/include/platform_def.h
index e6bb1e6..fbcaa63 100644
--- a/plat/qemu/qemu/include/platform_def.h
+++ b/plat/qemu/qemu/include/platform_def.h
@@ -89,6 +89,11 @@
#define SEC_DRAM_BASE 0x0e100000
#define SEC_DRAM_SIZE 0x00f00000
+#define SECURE_GPIO_BASE 0x090b0000
+#define SECURE_GPIO_SIZE 0x00001000
+#define SECURE_GPIO_POWEROFF 0
+#define SECURE_GPIO_RESET 1
+
/* Load pageable part of OP-TEE 2MB above secure DRAM base */
#define QEMU_OPTEE_PAGEABLE_LOAD_BASE (SEC_DRAM_BASE + 0x00200000)
#define QEMU_OPTEE_PAGEABLE_LOAD_SIZE 0x00400000
@@ -210,7 +215,7 @@
#define DEVICE0_BASE 0x08000000
#define DEVICE0_SIZE 0x01000000
#define DEVICE1_BASE 0x09000000
-#define DEVICE1_SIZE 0x00041000
+#define DEVICE1_SIZE 0x00c00000
/*
* GIC related constants
diff --git a/plat/qemu/qemu/platform.mk b/plat/qemu/qemu/platform.mk
index 14bf049..88a95c8 100644
--- a/plat/qemu/qemu/platform.mk
+++ b/plat/qemu/qemu/platform.mk
@@ -163,6 +163,8 @@
lib/semihosting/semihosting.c \
lib/semihosting/${ARCH}/semihosting_call.S \
plat/common/plat_psci_common.c \
+ drivers/arm/pl061/pl061_gpio.c \
+ drivers/gpio/gpio.c \
${PLAT_QEMU_COMMON_PATH}/qemu_pm.c \
${PLAT_QEMU_COMMON_PATH}/topology.c \
${PLAT_QEMU_COMMON_PATH}/aarch64/plat_helpers.S \
diff --git a/plat/qti/common/src/spmi_arb.c b/plat/qti/common/src/spmi_arb.c
index 16e85a6..4213ed1 100644
--- a/plat/qti/common/src/spmi_arb.c
+++ b/plat/qti/common/src/spmi_arb.c
@@ -10,8 +10,8 @@
#include <spmi_arb.h>
-#define REG_APID_MAP(apid) (0x0C440900U + 4U * i)
-#define NUM_APID 0x80
+#define REG_APID_MAP(apid) (0x0C440900U + sizeof(uint32_t) * apid)
+#define NUM_APID ((0x1100U - 0x900U) / sizeof(uint32_t))
#define PPID_MASK (0xfffU << 8)
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
index 7eab337..d8439f7 100644
--- a/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
@@ -12,9 +12,6 @@
.globl plat_is_my_cpu_primary
.globl zynqmp_calc_core_pos
.globl plat_my_core_pos
- .globl plat_crash_console_init
- .globl plat_crash_console_putc
- .globl plat_crash_console_flush
.globl platform_mem_init
/* -----------------------------------------------------
@@ -79,45 +76,6 @@
ret
endfunc zynqmp_calc_core_pos
- /* ---------------------------------------------
- * int plat_crash_console_init(void)
- * Function to initialize the crash console
- * without a C Runtime to print crash report.
- * Clobber list : x0 - x4
- * ---------------------------------------------
- */
-func plat_crash_console_init
- mov_imm x0, ZYNQMP_CRASH_UART_BASE
- mov_imm x1, ZYNQMP_CRASH_UART_CLK_IN_HZ
- mov_imm x2, ZYNQMP_UART_BAUDRATE
- b console_cdns_core_init
-endfunc plat_crash_console_init
-
- /* ---------------------------------------------
- * int plat_crash_console_putc(int c)
- * Function to print a character on the crash
- * console without a C Runtime.
- * Clobber list : x1, x2
- * ---------------------------------------------
- */
-func plat_crash_console_putc
- mov_imm x1, ZYNQMP_CRASH_UART_BASE
- b console_cdns_core_putc
-endfunc plat_crash_console_putc
-
- /* ---------------------------------------------
- * void plat_crash_console_flush()
- * Function to force a write of all buffered
- * data that hasn't been output.
- * Out : void.
- * Clobber list : r0
- * ---------------------------------------------
- */
-func plat_crash_console_flush
- mov_imm x0, ZYNQMP_CRASH_UART_BASE
- b console_cdns_core_flush
-endfunc plat_crash_console_flush
-
/* ---------------------------------------------------------------------
* We don't need to carry out any memory initialization on ARM
* platforms. The Secure RAM is accessible straight away.
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
index 1cd168f..6e700b9 100644
--- a/plat/xilinx/zynqmp/platform.mk
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -73,7 +73,8 @@
plat/arm/common/arm_gicv2.c \
plat/common/plat_gicv2.c \
plat/xilinx/common/ipi.c \
- plat/xilinx/zynqmp/zynqmp_ipi.c \
+ plat/xilinx/zynqmp/zynqmp_ipi.c \
+ plat/common/aarch64/crash_console_helpers.S \
plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S \
plat/xilinx/zynqmp/aarch64/zynqmp_common.c
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
index a076be2..6aab558 100644
--- a/services/std_svc/spmd/spmd_main.c
+++ b/services/std_svc/spmd/spmd_main.c
@@ -109,7 +109,6 @@
/* Restore the context assigned above */
cm_el1_sysregs_context_restore(SECURE);
-
#if SPMD_SPM_AT_SEL2
cm_el2_sysregs_context_restore(SECURE);
#endif
@@ -349,18 +348,12 @@
/* Save incoming security state */
cm_el1_sysregs_context_save(secure_state_in);
-#if CTX_INCLUDE_FPREGS
- fpregs_context_save(get_fpregs_ctx(cm_get_context(secure_state_in)));
-#endif
#if SPMD_SPM_AT_SEL2
cm_el2_sysregs_context_save(secure_state_in);
#endif
/* Restore outgoing security state */
cm_el1_sysregs_context_restore(secure_state_out);
-#if CTX_INCLUDE_FPREGS
- fpregs_context_restore(get_fpregs_ctx(cm_get_context(secure_state_out)));
-#endif
#if SPMD_SPM_AT_SEL2
cm_el2_sysregs_context_restore(secure_state_out);
#endif