aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/arm/css/mhu/css_mhu.c100
-rw-r--r--drivers/arm/css/mhu/css_mhu_doorbell.c38
-rw-r--r--drivers/arm/css/scmi/scmi_ap_core_proto.c79
-rw-r--r--drivers/arm/css/scmi/scmi_common.c208
-rw-r--r--drivers/arm/css/scmi/scmi_private.h155
-rw-r--r--drivers/arm/css/scmi/scmi_pwr_dmn_proto.c86
-rw-r--r--drivers/arm/css/scmi/scmi_sys_pwr_proto.c76
-rw-r--r--drivers/arm/css/scp/css_bom_bootloader.c195
-rw-r--r--drivers/arm/css/scp/css_pm_scmi.c421
-rw-r--r--drivers/arm/css/scp/css_pm_scpi.c165
-rw-r--r--drivers/arm/css/scp/css_sds.c95
-rw-r--r--drivers/arm/css/scpi/css_scpi.c262
-rw-r--r--drivers/arm/css/sds/aarch32/sds_helpers.S64
-rw-r--r--drivers/arm/css/sds/aarch64/sds_helpers.S62
-rw-r--r--drivers/arm/css/sds/sds.c259
-rw-r--r--drivers/arm/css/sds/sds_private.h100
-rw-r--r--drivers/arm/fvp/fvp_pwrc.c78
-rw-r--r--drivers/console/multi_console.c8
-rw-r--r--drivers/partition/partition.c2
-rw-r--r--drivers/rpi3/gpio/rpi3_gpio.c169
-rw-r--r--drivers/st/bsec/bsec.c913
-rw-r--r--drivers/st/clk/stm32mp1_clkfunc.c32
-rw-r--r--drivers/st/ddr/stm32mp1_ddr.c287
-rw-r--r--drivers/st/ddr/stm32mp1_ram.c35
-rw-r--r--drivers/st/gpio/stm32_gpio.c261
-rw-r--r--drivers/st/i2c/stm32_i2c.c (renamed from drivers/st/pmic/stm32_i2c.c)2
-rw-r--r--drivers/st/io/io_stm32image.c48
-rw-r--r--drivers/st/mmc/stm32_sdmmc2.c16
-rw-r--r--drivers/st/pmic/stm32mp_pmic.c (renamed from drivers/st/pmic/stm32mp1_pmic.c)95
-rw-r--r--drivers/st/pmic/stpmic1.c (renamed from drivers/st/pmic/stpmu1.c)263
-rw-r--r--drivers/synopsys/ufs/dw_ufs.c2
-rw-r--r--drivers/ufs/ufs.c2
32 files changed, 4260 insertions, 318 deletions
diff --git a/drivers/arm/css/mhu/css_mhu.c b/drivers/arm/css/mhu/css_mhu.c
new file mode 100644
index 000000000..b7faf7ed9
--- /dev/null
+++ b/drivers/arm/css/mhu/css_mhu.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014-2018, 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 <drivers/arm/css/css_mhu.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+
+/* SCP MHU secure channel registers */
+#define SCP_INTR_S_STAT 0x200
+#define SCP_INTR_S_SET 0x208
+#define SCP_INTR_S_CLEAR 0x210
+
+/* CPU MHU secure channel registers */
+#define CPU_INTR_S_STAT 0x300
+#define CPU_INTR_S_SET 0x308
+#define CPU_INTR_S_CLEAR 0x310
+
+ARM_INSTANTIATE_LOCK;
+
+/* Weak definition may be overridden in specific CSS based platform */
+#pragma weak plat_arm_pwrc_setup
+
+
+/*
+ * Slot 31 is reserved because the MHU hardware uses this register bit to
+ * indicate a non-secure access attempt. The total number of available slots is
+ * therefore 31 [30:0].
+ */
+#define MHU_MAX_SLOT_ID 30
+
+void mhu_secure_message_start(unsigned int slot_id)
+{
+ assert(slot_id <= MHU_MAX_SLOT_ID);
+
+ arm_lock_get();
+
+ /* Make sure any previous command has finished */
+ while (mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) &
+ (1 << slot_id))
+ ;
+}
+
+void mhu_secure_message_send(unsigned int slot_id)
+{
+ assert(slot_id <= MHU_MAX_SLOT_ID);
+ assert(!(mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) &
+ (1 << slot_id)));
+
+ /* Send command to SCP */
+ mmio_write_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id);
+}
+
+uint32_t mhu_secure_message_wait(void)
+{
+ /* Wait for response from SCP */
+ uint32_t response;
+ while (!(response = mmio_read_32(PLAT_CSS_MHU_BASE + SCP_INTR_S_STAT)))
+ ;
+
+ return response;
+}
+
+void mhu_secure_message_end(unsigned int slot_id)
+{
+ assert(slot_id <= MHU_MAX_SLOT_ID);
+
+ /*
+ * Clear any response we got by writing one in the relevant slot bit to
+ * the CLEAR register
+ */
+ mmio_write_32(PLAT_CSS_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id);
+
+ arm_lock_release();
+}
+
+void __init mhu_secure_init(void)
+{
+ arm_lock_init();
+
+ /*
+ * The STAT register resets to zero. Ensure it is in the expected state,
+ * as a stale or garbage value would make us think it's a message we've
+ * already sent.
+ */
+ assert(mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) == 0);
+}
+
+void __init plat_arm_pwrc_setup(void)
+{
+ mhu_secure_init();
+}
diff --git a/drivers/arm/css/mhu/css_mhu_doorbell.c b/drivers/arm/css/mhu/css_mhu_doorbell.c
new file mode 100644
index 000000000..885874272
--- /dev/null
+++ b/drivers/arm/css/mhu/css_mhu_doorbell.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <drivers/arm/css/css_mhu_doorbell.h>
+#include <drivers/arm/css/scmi.h>
+
+void mhu_ring_doorbell(struct scmi_channel_plat_info *plat_info)
+{
+ MHU_RING_DOORBELL(plat_info->db_reg_addr,
+ plat_info->db_modify_mask,
+ plat_info->db_preserve_mask);
+ return;
+}
+
+void mhuv2_ring_doorbell(struct scmi_channel_plat_info *plat_info)
+{
+ /* wake receiver */
+ MHU_V2_ACCESS_REQUEST(MHUV2_BASE_ADDR);
+
+ /* wait for receiver to acknowledge its ready */
+ while (MHU_V2_IS_ACCESS_READY(MHUV2_BASE_ADDR) == 0)
+ ;
+
+ MHU_RING_DOORBELL(plat_info->db_reg_addr,
+ plat_info->db_modify_mask,
+ plat_info->db_preserve_mask);
+
+ /* clear the access request for the receiver */
+ MHU_V2_CLEAR_REQUEST(MHUV2_BASE_ADDR);
+
+ return;
+}
diff --git a/drivers/arm/css/scmi/scmi_ap_core_proto.c b/drivers/arm/css/scmi/scmi_ap_core_proto.c
new file mode 100644
index 000000000..2caccc2b8
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_ap_core_proto.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#include "scmi_private.h"
+
+/*
+ * API to set the SCMI AP core reset address and attributes
+ */
+int scmi_ap_core_set_reset_addr(void *p, uint64_t reset_addr, uint32_t attr)
+{
+ mailbox_mem_t *mbx_mem;
+ int token = 0, ret;
+ scmi_channel_t *ch = (scmi_channel_t *)p;
+
+ validate_scmi_channel(ch);
+
+ scmi_get_channel(ch);
+
+ mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+ mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_AP_CORE_PROTO_ID,
+ SCMI_AP_CORE_RESET_ADDR_SET_MSG, token);
+ mbx_mem->len = SCMI_AP_CORE_RESET_ADDR_SET_MSG_LEN;
+ mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+ SCMI_PAYLOAD_ARG3(mbx_mem->payload, reset_addr & 0xffffffff,
+ reset_addr >> 32, attr);
+
+ scmi_send_sync_command(ch);
+
+ /* Get the return values */
+ SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
+ assert(mbx_mem->len == SCMI_AP_CORE_RESET_ADDR_SET_RESP_LEN);
+ assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+ scmi_put_channel(ch);
+
+ return ret;
+}
+
+/*
+ * API to get the SCMI AP core reset address and attributes
+ */
+int scmi_ap_core_get_reset_addr(void *p, uint64_t *reset_addr, uint32_t *attr)
+{
+ mailbox_mem_t *mbx_mem;
+ int token = 0, ret;
+ scmi_channel_t *ch = (scmi_channel_t *)p;
+ uint32_t lo_addr, hi_addr;
+
+ validate_scmi_channel(ch);
+
+ scmi_get_channel(ch);
+
+ mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+ mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_AP_CORE_PROTO_ID,
+ SCMI_AP_CORE_RESET_ADDR_GET_MSG, token);
+ mbx_mem->len = SCMI_AP_CORE_RESET_ADDR_GET_MSG_LEN;
+ mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+
+ scmi_send_sync_command(ch);
+
+ /* Get the return values */
+ SCMI_PAYLOAD_RET_VAL4(mbx_mem->payload, ret, lo_addr, hi_addr, *attr);
+ *reset_addr = lo_addr | (uint64_t)hi_addr << 32;
+ assert(mbx_mem->len == SCMI_AP_CORE_RESET_ADDR_GET_RESP_LEN);
+ assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+ scmi_put_channel(ch);
+
+ return ret;
+}
diff --git a/drivers/arm/css/scmi/scmi_common.c b/drivers/arm/css/scmi/scmi_common.c
new file mode 100644
index 000000000..e2c353d85
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_common.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#include "scmi_private.h"
+
+#if HW_ASSISTED_COHERENCY
+#define scmi_lock_init(lock)
+#define scmi_lock_get(lock) spin_lock(lock)
+#define scmi_lock_release(lock) spin_unlock(lock)
+#else
+#define scmi_lock_init(lock) bakery_lock_init(lock)
+#define scmi_lock_get(lock) bakery_lock_get(lock)
+#define scmi_lock_release(lock) bakery_lock_release(lock)
+#endif
+
+
+/*
+ * Private helper function to get exclusive access to SCMI channel.
+ */
+void scmi_get_channel(scmi_channel_t *ch)
+{
+ assert(ch->lock);
+ scmi_lock_get(ch->lock);
+
+ /* Make sure any previous command has finished */
+ assert(SCMI_IS_CHANNEL_FREE(
+ ((mailbox_mem_t *)(ch->info->scmi_mbx_mem))->status));
+}
+
+/*
+ * Private helper function to transfer ownership of channel from AP to SCP.
+ */
+void scmi_send_sync_command(scmi_channel_t *ch)
+{
+ mailbox_mem_t *mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+
+ SCMI_MARK_CHANNEL_BUSY(mbx_mem->status);
+
+ /*
+ * Ensure that any write to the SCMI payload area is seen by SCP before
+ * we write to the doorbell register. If these 2 writes were reordered
+ * by the CPU then SCP would read stale payload data
+ */
+ dmbst();
+
+ ch->info->ring_doorbell(ch->info);
+ /*
+ * Ensure that the write to the doorbell register is ordered prior to
+ * checking whether the channel is free.
+ */
+ dmbsy();
+
+ /* Wait for channel to be free */
+ while (!SCMI_IS_CHANNEL_FREE(mbx_mem->status))
+ ;
+
+ /*
+ * Ensure that any read to the SCMI payload area is done after reading
+ * mailbox status. If these 2 reads were reordered then the CPU would
+ * read invalid payload data
+ */
+ dmbld();
+}
+
+/*
+ * Private helper function to release exclusive access to SCMI channel.
+ */
+void scmi_put_channel(scmi_channel_t *ch)
+{
+ /* Make sure any previous command has finished */
+ assert(SCMI_IS_CHANNEL_FREE(
+ ((mailbox_mem_t *)(ch->info->scmi_mbx_mem))->status));
+
+ assert(ch->lock);
+ scmi_lock_release(ch->lock);
+}
+
+/*
+ * API to query the SCMI protocol version.
+ */
+int scmi_proto_version(void *p, uint32_t proto_id, uint32_t *version)
+{
+ mailbox_mem_t *mbx_mem;
+ int token = 0, ret;
+ scmi_channel_t *ch = (scmi_channel_t *)p;
+
+ validate_scmi_channel(ch);
+
+ scmi_get_channel(ch);
+
+ mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+ mbx_mem->msg_header = SCMI_MSG_CREATE(proto_id, SCMI_PROTO_VERSION_MSG,
+ token);
+ mbx_mem->len = SCMI_PROTO_VERSION_MSG_LEN;
+ mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+
+ scmi_send_sync_command(ch);
+
+ /* Get the return values */
+ SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *version);
+ assert(mbx_mem->len == SCMI_PROTO_VERSION_RESP_LEN);
+ assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+ scmi_put_channel(ch);
+
+ return ret;
+}
+
+/*
+ * API to query the protocol message attributes for a SCMI protocol.
+ */
+int scmi_proto_msg_attr(void *p, uint32_t proto_id,
+ uint32_t command_id, uint32_t *attr)
+{
+ mailbox_mem_t *mbx_mem;
+ int token = 0, ret;
+ scmi_channel_t *ch = (scmi_channel_t *)p;
+
+ validate_scmi_channel(ch);
+
+ scmi_get_channel(ch);
+
+ mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+ mbx_mem->msg_header = SCMI_MSG_CREATE(proto_id,
+ SCMI_PROTO_MSG_ATTR_MSG, token);
+ mbx_mem->len = SCMI_PROTO_MSG_ATTR_MSG_LEN;
+ mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+ SCMI_PAYLOAD_ARG1(mbx_mem->payload, command_id);
+
+ scmi_send_sync_command(ch);
+
+ /* Get the return values */
+ SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *attr);
+ assert(mbx_mem->len == SCMI_PROTO_MSG_ATTR_RESP_LEN);
+ assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+ scmi_put_channel(ch);
+
+ return ret;
+}
+
+/*
+ * SCMI Driver initialization API. Returns initialized channel on success
+ * or NULL on error. The return type is an opaque void pointer.
+ */
+void *scmi_init(scmi_channel_t *ch)
+{
+ uint32_t version;
+ int ret;
+
+ assert(ch && ch->info);
+ assert(ch->info->db_reg_addr);
+ assert(ch->info->db_modify_mask);
+ assert(ch->info->db_preserve_mask);
+ assert(ch->info->ring_doorbell != NULL);
+
+ assert(ch->lock);
+
+ scmi_lock_init(ch->lock);
+
+ ch->is_initialized = 1;
+
+ ret = scmi_proto_version(ch, SCMI_PWR_DMN_PROTO_ID, &version);
+ if (ret != SCMI_E_SUCCESS) {
+ WARN("SCMI power domain protocol version message failed");
+ goto error;
+ }
+
+ if (!is_scmi_version_compatible(SCMI_PWR_DMN_PROTO_VER, version)) {
+ WARN("SCMI power domain protocol version 0x%x incompatible with driver version 0x%x",
+ version, SCMI_PWR_DMN_PROTO_VER);
+ goto error;
+ }
+
+ VERBOSE("SCMI power domain protocol version 0x%x detected\n", version);
+
+ ret = scmi_proto_version(ch, SCMI_SYS_PWR_PROTO_ID, &version);
+ if ((ret != SCMI_E_SUCCESS)) {
+ WARN("SCMI system power protocol version message failed");
+ goto error;
+ }
+
+ if (!is_scmi_version_compatible(SCMI_SYS_PWR_PROTO_VER, version)) {
+ WARN("SCMI system power management protocol version 0x%x incompatible with driver version 0x%x",
+ version, SCMI_SYS_PWR_PROTO_VER);
+ goto error;
+ }
+
+ VERBOSE("SCMI system power management protocol version 0x%x detected\n",
+ version);
+
+ INFO("SCMI driver initialized\n");
+
+ return (void *)ch;
+
+error:
+ ch->is_initialized = 0;
+ return NULL;
+}
diff --git a/drivers/arm/css/scmi/scmi_private.h b/drivers/arm/css/scmi/scmi_private.h
new file mode 100644
index 000000000..65305736c
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_private.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCMI_PRIVATE_H
+#define SCMI_PRIVATE_H
+
+#include <lib/mmio.h>
+
+/*
+ * SCMI power domain management protocol message and response lengths. It is
+ * calculated as sum of length in bytes of the message header (4) and payload
+ * area (the number of bytes of parameters or return values in the payload).
+ */
+#define SCMI_PROTO_VERSION_MSG_LEN 4
+#define SCMI_PROTO_VERSION_RESP_LEN 12
+
+#define SCMI_PROTO_MSG_ATTR_MSG_LEN 8
+#define SCMI_PROTO_MSG_ATTR_RESP_LEN 12
+
+#define SCMI_AP_CORE_RESET_ADDR_SET_MSG_LEN 16
+#define SCMI_AP_CORE_RESET_ADDR_SET_RESP_LEN 8
+
+#define SCMI_AP_CORE_RESET_ADDR_GET_MSG_LEN 4
+#define SCMI_AP_CORE_RESET_ADDR_GET_RESP_LEN 20
+
+#define SCMI_PWR_STATE_SET_MSG_LEN 16
+#define SCMI_PWR_STATE_SET_RESP_LEN 8
+
+#define SCMI_PWR_STATE_GET_MSG_LEN 8
+#define SCMI_PWR_STATE_GET_RESP_LEN 12
+
+#define SCMI_SYS_PWR_STATE_SET_MSG_LEN 12
+#define SCMI_SYS_PWR_STATE_SET_RESP_LEN 8
+
+#define SCMI_SYS_PWR_STATE_GET_MSG_LEN 4
+#define SCMI_SYS_PWR_STATE_GET_RESP_LEN 12
+
+/* SCMI message header format bit field */
+#define SCMI_MSG_ID_SHIFT 0
+#define SCMI_MSG_ID_WIDTH 8
+#define SCMI_MSG_ID_MASK ((1 << SCMI_MSG_ID_WIDTH) - 1)
+
+#define SCMI_MSG_TYPE_SHIFT 8
+#define SCMI_MSG_TYPE_WIDTH 2
+#define SCMI_MSG_TYPE_MASK ((1 << SCMI_MSG_TYPE_WIDTH) - 1)
+
+#define SCMI_MSG_PROTO_ID_SHIFT 10
+#define SCMI_MSG_PROTO_ID_WIDTH 8
+#define SCMI_MSG_PROTO_ID_MASK ((1 << SCMI_MSG_PROTO_ID_WIDTH) - 1)
+
+#define SCMI_MSG_TOKEN_SHIFT 18
+#define SCMI_MSG_TOKEN_WIDTH 10
+#define SCMI_MSG_TOKEN_MASK ((1 << SCMI_MSG_TOKEN_WIDTH) - 1)
+
+
+/* SCMI mailbox flags */
+#define SCMI_FLAG_RESP_POLL 0
+#define SCMI_FLAG_RESP_INT 1
+
+/* SCMI power domain protocol `POWER_STATE_SET` message flags */
+#define SCMI_PWR_STATE_SET_FLAG_SYNC 0
+#define SCMI_PWR_STATE_SET_FLAG_ASYNC 1
+
+/*
+ * Helper macro to create an SCMI message header given protocol, message id
+ * and token.
+ */
+#define SCMI_MSG_CREATE(_protocol, _msg_id, _token) \
+ ((((_protocol) & SCMI_MSG_PROTO_ID_MASK) << SCMI_MSG_PROTO_ID_SHIFT) | \
+ (((_msg_id) & SCMI_MSG_ID_MASK) << SCMI_MSG_ID_SHIFT) | \
+ (((_token) & SCMI_MSG_TOKEN_MASK) << SCMI_MSG_TOKEN_SHIFT))
+
+/* Helper macro to get the token from a SCMI message header */
+#define SCMI_MSG_GET_TOKEN(_msg) \
+ (((_msg) >> SCMI_MSG_TOKEN_SHIFT) & SCMI_MSG_TOKEN_MASK)
+
+/* SCMI Channel Status bit fields */
+#define SCMI_CH_STATUS_RES0_MASK 0xFFFFFFFE
+#define SCMI_CH_STATUS_FREE_SHIFT 0
+#define SCMI_CH_STATUS_FREE_WIDTH 1
+#define SCMI_CH_STATUS_FREE_MASK ((1 << SCMI_CH_STATUS_FREE_WIDTH) - 1)
+
+/* Helper macros to check and write the channel status */
+#define SCMI_IS_CHANNEL_FREE(status) \
+ (!!(((status) >> SCMI_CH_STATUS_FREE_SHIFT) & SCMI_CH_STATUS_FREE_MASK))
+
+#define SCMI_MARK_CHANNEL_BUSY(status) do { \
+ assert(SCMI_IS_CHANNEL_FREE(status)); \
+ (status) &= ~(SCMI_CH_STATUS_FREE_MASK << \
+ SCMI_CH_STATUS_FREE_SHIFT); \
+ } while (0)
+
+/* Helper macros to copy arguments to the mailbox payload */
+#define SCMI_PAYLOAD_ARG1(payld_arr, arg1) \
+ mmio_write_32((uintptr_t)&payld_arr[0], arg1)
+
+#define SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2) do { \
+ SCMI_PAYLOAD_ARG1(payld_arr, arg1); \
+ mmio_write_32((uintptr_t)&payld_arr[1], arg2); \
+ } while (0)
+
+#define SCMI_PAYLOAD_ARG3(payld_arr, arg1, arg2, arg3) do { \
+ SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2); \
+ mmio_write_32((uintptr_t)&payld_arr[2], arg3); \
+ } while (0)
+
+/* Helper macros to read return values from the mailbox payload */
+#define SCMI_PAYLOAD_RET_VAL1(payld_arr, val1) \
+ (val1) = mmio_read_32((uintptr_t)&payld_arr[0])
+
+#define SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2) do { \
+ SCMI_PAYLOAD_RET_VAL1(payld_arr, val1); \
+ (val2) = mmio_read_32((uintptr_t)&payld_arr[1]); \
+ } while (0)
+
+#define SCMI_PAYLOAD_RET_VAL3(payld_arr, val1, val2, val3) do { \
+ SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2); \
+ (val3) = mmio_read_32((uintptr_t)&payld_arr[2]); \
+ } while (0)
+
+#define SCMI_PAYLOAD_RET_VAL4(payld_arr, val1, val2, val3, val4) do { \
+ SCMI_PAYLOAD_RET_VAL3(payld_arr, val1, val2, val3); \
+ (val4) = mmio_read_32((uintptr_t)&payld_arr[3]); \
+ } while (0)
+
+/*
+ * Private data structure for representing the mailbox memory layout. Refer
+ * the SCMI specification for more details.
+ */
+typedef struct mailbox_mem {
+ uint32_t res_a; /* Reserved */
+ volatile uint32_t status;
+ uint64_t res_b; /* Reserved */
+ uint32_t flags;
+ volatile uint32_t len;
+ uint32_t msg_header;
+ uint32_t payload[];
+} mailbox_mem_t;
+
+
+/* Private APIs for use within SCMI driver */
+void scmi_get_channel(scmi_channel_t *ch);
+void scmi_send_sync_command(scmi_channel_t *ch);
+void scmi_put_channel(scmi_channel_t *ch);
+
+static inline void validate_scmi_channel(scmi_channel_t *ch)
+{
+ assert(ch && ch->is_initialized);
+ assert(ch->info && ch->info->scmi_mbx_mem);
+}
+
+#endif /* SCMI_PRIVATE_H */
diff --git a/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c b/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c
new file mode 100644
index 000000000..70165dec2
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#include "scmi_private.h"
+
+/*
+ * API to set the SCMI power domain power state.
+ */
+int scmi_pwr_state_set(void *p, uint32_t domain_id,
+ uint32_t scmi_pwr_state)
+{
+ mailbox_mem_t *mbx_mem;
+ int token = 0, ret;
+
+ /*
+ * Only asynchronous mode of `set power state` command is allowed on
+ * application processors.
+ */
+ uint32_t pwr_state_set_msg_flag = SCMI_PWR_STATE_SET_FLAG_ASYNC;
+ scmi_channel_t *ch = (scmi_channel_t *)p;
+
+ validate_scmi_channel(ch);
+
+ scmi_get_channel(ch);
+
+ mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+ mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_PWR_DMN_PROTO_ID,
+ SCMI_PWR_STATE_SET_MSG, token);
+ mbx_mem->len = SCMI_PWR_STATE_SET_MSG_LEN;
+ mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+ SCMI_PAYLOAD_ARG3(mbx_mem->payload, pwr_state_set_msg_flag,
+ domain_id, scmi_pwr_state);
+
+ scmi_send_sync_command(ch);
+
+ /* Get the return values */
+ SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
+ assert(mbx_mem->len == SCMI_PWR_STATE_SET_RESP_LEN);
+ assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+ scmi_put_channel(ch);
+
+ return ret;
+}
+
+/*
+ * API to get the SCMI power domain power state.
+ */
+int scmi_pwr_state_get(void *p, uint32_t domain_id,
+ uint32_t *scmi_pwr_state)
+{
+ mailbox_mem_t *mbx_mem;
+ int token = 0, ret;
+ scmi_channel_t *ch = (scmi_channel_t *)p;
+
+ validate_scmi_channel(ch);
+
+ scmi_get_channel(ch);
+
+ mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+ mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_PWR_DMN_PROTO_ID,
+ SCMI_PWR_STATE_GET_MSG, token);
+ mbx_mem->len = SCMI_PWR_STATE_GET_MSG_LEN;
+ mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+ SCMI_PAYLOAD_ARG1(mbx_mem->payload, domain_id);
+
+ scmi_send_sync_command(ch);
+
+ /* Get the return values */
+ SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *scmi_pwr_state);
+ assert(mbx_mem->len == SCMI_PWR_STATE_GET_RESP_LEN);
+ assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+ scmi_put_channel(ch);
+
+ return ret;
+}
diff --git a/drivers/arm/css/scmi/scmi_sys_pwr_proto.c b/drivers/arm/css/scmi/scmi_sys_pwr_proto.c
new file mode 100644
index 000000000..a27c4a5d0
--- /dev/null
+++ b/drivers/arm/css/scmi/scmi_sys_pwr_proto.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/scmi.h>
+
+#include "scmi_private.h"
+
+/*
+ * API to set the SCMI system power state
+ */
+int scmi_sys_pwr_state_set(void *p, uint32_t flags, uint32_t system_state)
+{
+ mailbox_mem_t *mbx_mem;
+ int token = 0, ret;
+ scmi_channel_t *ch = (scmi_channel_t *)p;
+
+ validate_scmi_channel(ch);
+
+ scmi_get_channel(ch);
+
+ mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+ mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_PWR_PROTO_ID,
+ SCMI_SYS_PWR_STATE_SET_MSG, token);
+ mbx_mem->len = SCMI_SYS_PWR_STATE_SET_MSG_LEN;
+ mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+ SCMI_PAYLOAD_ARG2(mbx_mem->payload, flags, system_state);
+
+ scmi_send_sync_command(ch);
+
+ /* Get the return values */
+ SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret);
+ assert(mbx_mem->len == SCMI_SYS_PWR_STATE_SET_RESP_LEN);
+ assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+ scmi_put_channel(ch);
+
+ return ret;
+}
+
+/*
+ * API to get the SCMI system power state
+ */
+int scmi_sys_pwr_state_get(void *p, uint32_t *system_state)
+{
+ mailbox_mem_t *mbx_mem;
+ int token = 0, ret;
+ scmi_channel_t *ch = (scmi_channel_t *)p;
+
+ validate_scmi_channel(ch);
+
+ scmi_get_channel(ch);
+
+ mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem);
+ mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_PWR_PROTO_ID,
+ SCMI_SYS_PWR_STATE_GET_MSG, token);
+ mbx_mem->len = SCMI_SYS_PWR_STATE_GET_MSG_LEN;
+ mbx_mem->flags = SCMI_FLAG_RESP_POLL;
+
+ scmi_send_sync_command(ch);
+
+ /* Get the return values */
+ SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *system_state);
+ assert(mbx_mem->len == SCMI_SYS_PWR_STATE_GET_RESP_LEN);
+ assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header));
+
+ scmi_put_channel(ch);
+
+ return ret;
+}
diff --git a/drivers/arm/css/scp/css_bom_bootloader.c b/drivers/arm/css/scp/css_bom_bootloader.c
new file mode 100644
index 000000000..1fc1270ba
--- /dev/null
+++ b/drivers/arm/css/scp/css_bom_bootloader.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/css_scpi.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/* ID of the MHU slot used for the BOM protocol */
+#define BOM_MHU_SLOT_ID 0
+
+/* Boot commands sent from AP -> SCP */
+#define BOOT_CMD_INFO 0x00
+#define BOOT_CMD_DATA 0x01
+
+/* BOM command header */
+typedef struct {
+ uint32_t id : 8;
+ uint32_t reserved : 24;
+} bom_cmd_t;
+
+typedef struct {
+ uint32_t image_size;
+ uint32_t checksum;
+} cmd_info_payload_t;
+
+/*
+ * Unlike the SCPI protocol, the boot protocol uses the same memory region
+ * for both AP -> SCP and SCP -> AP transfers; define the address of this...
+ */
+#define BOM_SHARED_MEM PLAT_CSS_SCP_COM_SHARED_MEM_BASE
+#define BOM_CMD_HEADER ((bom_cmd_t *) BOM_SHARED_MEM)
+#define BOM_CMD_PAYLOAD ((void *) (BOM_SHARED_MEM + sizeof(bom_cmd_t)))
+
+typedef struct {
+ /* Offset from the base address of the Trusted RAM */
+ uint32_t offset;
+ uint32_t block_size;
+} cmd_data_payload_t;
+
+/*
+ * All CSS platforms load SCP_BL2/SCP_BL2U just below BL2 (this is where BL31
+ * usually resides except when ARM_BL31_IN_DRAM is
+ * set). Ensure that SCP_BL2/SCP_BL2U do not overflow into shared RAM and
+ * the tb_fw_config.
+ */
+CASSERT(SCP_BL2_LIMIT <= BL2_BASE, assert_scp_bl2_overwrite_bl2);
+CASSERT(SCP_BL2U_LIMIT <= BL2_BASE, assert_scp_bl2u_overwrite_bl2);
+
+CASSERT(SCP_BL2_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_scp_bl2_overflow);
+CASSERT(SCP_BL2U_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_scp_bl2u_overflow);
+
+static void scp_boot_message_start(void)
+{
+ mhu_secure_message_start(BOM_MHU_SLOT_ID);
+}
+
+static void scp_boot_message_send(size_t payload_size)
+{
+ /* Ensure that any write to the BOM payload area is seen by SCP before
+ * we write to the MHU register. If these 2 writes were reordered by
+ * the CPU then SCP would read stale payload data */
+ dmbst();
+
+ /* Send command to SCP */
+ mhu_secure_message_send(BOM_MHU_SLOT_ID);
+}
+
+static uint32_t scp_boot_message_wait(size_t size)
+{
+ uint32_t mhu_status;
+
+ mhu_status = mhu_secure_message_wait();
+
+ /* Expect an SCP Boot Protocol message, reject any other protocol */
+ if (mhu_status != (1 << BOM_MHU_SLOT_ID)) {
+ ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n",
+ mhu_status);
+ panic();
+ }
+
+ /* Ensure that any read to the BOM payload area is done after reading
+ * the MHU register. If these 2 reads were reordered then the CPU would
+ * read invalid payload data */
+ dmbld();
+
+ return *(uint32_t *) BOM_SHARED_MEM;
+}
+
+static void scp_boot_message_end(void)
+{
+ mhu_secure_message_end(BOM_MHU_SLOT_ID);
+}
+
+int css_scp_boot_image_xfer(void *image, unsigned int image_size)
+{
+ uint32_t response;
+ uint32_t checksum;
+ cmd_info_payload_t *cmd_info_payload;
+ cmd_data_payload_t *cmd_data_payload;
+
+ assert((uintptr_t) image == SCP_BL2_BASE);
+
+ if ((image_size == 0) || (image_size % 4 != 0)) {
+ ERROR("Invalid size for the SCP_BL2 image. Must be a multiple of "
+ "4 bytes and not zero (current size = 0x%x)\n",
+ image_size);
+ return -1;
+ }
+
+ /* Extract the checksum from the image */
+ checksum = *(uint32_t *) image;
+ image = (char *) image + sizeof(checksum);
+ image_size -= sizeof(checksum);
+
+ mhu_secure_init();
+
+ VERBOSE("Send info about the SCP_BL2 image to be transferred to SCP\n");
+
+ /*
+ * Send information about the SCP firmware image about to be transferred
+ * to SCP
+ */
+ scp_boot_message_start();
+
+ BOM_CMD_HEADER->id = BOOT_CMD_INFO;
+ cmd_info_payload = BOM_CMD_PAYLOAD;
+ cmd_info_payload->image_size = image_size;
+ cmd_info_payload->checksum = checksum;
+
+ scp_boot_message_send(sizeof(*cmd_info_payload));
+#if CSS_DETECT_PRE_1_7_0_SCP
+ {
+ const uint32_t deprecated_scp_nack_cmd = 0x404;
+ uint32_t mhu_status;
+
+ VERBOSE("Detecting SCP version incompatibility\n");
+
+ mhu_status = mhu_secure_message_wait();
+ if (mhu_status == deprecated_scp_nack_cmd) {
+ ERROR("Detected an incompatible version of the SCP firmware.\n");
+ ERROR("Only versions from v1.7.0 onwards are supported.\n");
+ ERROR("Please update the SCP firmware.\n");
+ return -1;
+ }
+
+ VERBOSE("SCP version looks OK\n");
+ }
+#endif /* CSS_DETECT_PRE_1_7_0_SCP */
+ response = scp_boot_message_wait(sizeof(response));
+ scp_boot_message_end();
+
+ if (response != 0) {
+ ERROR("SCP BOOT_CMD_INFO returned error %u\n", response);
+ return -1;
+ }
+
+ VERBOSE("Transferring SCP_BL2 image to SCP\n");
+
+ /* Transfer SCP_BL2 image to SCP */
+ scp_boot_message_start();
+
+ BOM_CMD_HEADER->id = BOOT_CMD_DATA;
+ cmd_data_payload = BOM_CMD_PAYLOAD;
+ cmd_data_payload->offset = (uintptr_t) image - ARM_TRUSTED_SRAM_BASE;
+ cmd_data_payload->block_size = image_size;
+
+ scp_boot_message_send(sizeof(*cmd_data_payload));
+ response = scp_boot_message_wait(sizeof(response));
+ scp_boot_message_end();
+
+ if (response != 0) {
+ ERROR("SCP BOOT_CMD_DATA returned error %u\n", response);
+ return -1;
+ }
+
+ return 0;
+}
+
+int css_scp_boot_ready(void)
+{
+ VERBOSE("Waiting for SCP to signal it is ready to go on\n");
+
+ /* Wait for SCP to signal it's ready */
+ return scpi_wait_ready();
+}
diff --git a/drivers/arm/css/scp/css_pm_scmi.c b/drivers/arm/css/scp/css_pm_scmi.c
new file mode 100644
index 000000000..1966c44ca
--- /dev/null
+++ b/drivers/arm/css/scp/css_pm_scmi.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/scmi.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+/*
+ * This file implements the SCP helper functions using SCMI protocol.
+ */
+
+/*
+ * SCMI power state parameter bit field encoding for ARM CSS platforms.
+ *
+ * 31 20 19 16 15 12 11 8 7 4 3 0
+ * +-------------------------------------------------------------+
+ * | SBZ | Max level | Level 3 | Level 2 | Level 1 | Level 0 |
+ * | | | state | state | state | state |
+ * +-------------------------------------------------------------+
+ *
+ * `Max level` encodes the highest level that has a valid power state
+ * encoded in the power state.
+ */
+#define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT 16
+#define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH 4
+#define SCMI_PWR_STATE_MAX_PWR_LVL_MASK \
+ ((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1)
+#define SCMI_SET_PWR_STATE_MAX_PWR_LVL(_power_state, _max_level) \
+ (_power_state) |= ((_max_level) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)\
+ << SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT
+#define SCMI_GET_PWR_STATE_MAX_PWR_LVL(_power_state) \
+ (((_power_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT) \
+ & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)
+
+#define SCMI_PWR_STATE_LVL_WIDTH 4
+#define SCMI_PWR_STATE_LVL_MASK \
+ ((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1)
+#define SCMI_SET_PWR_STATE_LVL(_power_state, _level, _level_state) \
+ (_power_state) |= ((_level_state) & SCMI_PWR_STATE_LVL_MASK) \
+ << (SCMI_PWR_STATE_LVL_WIDTH * (_level))
+#define SCMI_GET_PWR_STATE_LVL(_power_state, _level) \
+ (((_power_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (_level))) & \
+ SCMI_PWR_STATE_LVL_MASK)
+
+/*
+ * The SCMI power state enumeration for a power domain level
+ */
+typedef enum {
+ scmi_power_state_off = 0,
+ scmi_power_state_on = 1,
+ scmi_power_state_sleep = 2,
+} scmi_power_state_t;
+
+/*
+ * The global handle for invoking the SCMI driver APIs after the driver
+ * has been initialized.
+ */
+static void *scmi_handle;
+
+/* The SCMI channel global object */
+static scmi_channel_t channel;
+
+ARM_SCMI_INSTANTIATE_LOCK;
+
+/*
+ * Helper function to suspend a CPU power domain and its parent power domains
+ * if applicable.
+ */
+void css_scp_suspend(const struct psci_power_state *target_state)
+{
+ int ret;
+
+ /* At least power domain level 0 should be specified to be suspended */
+ assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+ ARM_LOCAL_STATE_OFF);
+
+ /* Check if power down at system power domain level is requested */
+ if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) {
+ /* Issue SCMI command for SYSTEM_SUSPEND */
+ ret = scmi_sys_pwr_state_set(scmi_handle,
+ SCMI_SYS_PWR_FORCEFUL_REQ,
+ SCMI_SYS_PWR_SUSPEND);
+ if (ret != SCMI_E_SUCCESS) {
+ ERROR("SCMI system power domain suspend return 0x%x unexpected\n",
+ ret);
+ panic();
+ }
+ return;
+ }
+#if !HW_ASSISTED_COHERENCY
+ int lvl;
+ uint32_t scmi_pwr_state = 0;
+ /*
+ * If we reach here, then assert that power down at system power domain
+ * level is running.
+ */
+ assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN);
+
+ /* For level 0, specify `scmi_power_state_sleep` as the power state */
+ SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, ARM_PWR_LVL0,
+ scmi_power_state_sleep);
+
+ for (lvl = ARM_PWR_LVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+ if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN)
+ break;
+
+ assert(target_state->pwr_domain_state[lvl] ==
+ ARM_LOCAL_STATE_OFF);
+ /*
+ * Specify `scmi_power_state_off` as power state for higher
+ * levels.
+ */
+ SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+ scmi_power_state_off);
+ }
+
+ SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
+
+ ret = scmi_pwr_state_set(scmi_handle,
+ plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()],
+ scmi_pwr_state);
+
+ if (ret != SCMI_E_SUCCESS) {
+ ERROR("SCMI set power state command return 0x%x unexpected\n",
+ ret);
+ panic();
+ }
+#endif
+}
+
+/*
+ * Helper function to turn off a CPU power domain and its parent power domains
+ * if applicable.
+ */
+void css_scp_off(const struct psci_power_state *target_state)
+{
+ int lvl = 0, ret;
+ uint32_t scmi_pwr_state = 0;
+
+ /* At-least the CPU level should be specified to be OFF */
+ assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+ ARM_LOCAL_STATE_OFF);
+
+ /* PSCI CPU OFF cannot be used to turn OFF system power domain */
+ assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN);
+
+ for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) {
+ if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN)
+ break;
+
+ assert(target_state->pwr_domain_state[lvl] ==
+ ARM_LOCAL_STATE_OFF);
+ SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+ scmi_power_state_off);
+ }
+
+ SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
+
+ ret = scmi_pwr_state_set(scmi_handle,
+ plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()],
+ scmi_pwr_state);
+
+ if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
+ ERROR("SCMI set power state command return 0x%x unexpected\n",
+ ret);
+ panic();
+ }
+}
+
+/*
+ * Helper function to turn ON a CPU power domain and its parent power domains
+ * if applicable.
+ */
+void css_scp_on(u_register_t mpidr)
+{
+ int lvl = 0, ret, core_pos;
+ uint32_t scmi_pwr_state = 0;
+
+ for (; lvl <= PLAT_MAX_PWR_LVL; lvl++)
+ SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl,
+ scmi_power_state_on);
+
+ SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1);
+
+ core_pos = plat_core_pos_by_mpidr(mpidr);
+ assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT);
+
+ ret = scmi_pwr_state_set(scmi_handle,
+ plat_css_core_pos_to_scmi_dmn_id_map[core_pos],
+ scmi_pwr_state);
+
+ if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) {
+ ERROR("SCMI set power state command return 0x%x unexpected\n",
+ ret);
+ panic();
+ }
+}
+
+/*
+ * Helper function to get the power state of a power domain node as reported
+ * by the SCP.
+ */
+int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
+{
+ int ret, cpu_idx;
+ uint32_t scmi_pwr_state = 0, lvl_state;
+
+ /* We don't support get power state at the system power domain level */
+ if ((power_level > PLAT_MAX_PWR_LVL) ||
+ (power_level == CSS_SYSTEM_PWR_DMN_LVL)) {
+ WARN("Invalid power level %u specified for SCMI get power state\n",
+ power_level);
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ cpu_idx = plat_core_pos_by_mpidr(mpidr);
+ assert(cpu_idx > -1);
+
+ ret = scmi_pwr_state_get(scmi_handle,
+ plat_css_core_pos_to_scmi_dmn_id_map[cpu_idx],
+ &scmi_pwr_state);
+
+ if (ret != SCMI_E_SUCCESS) {
+ WARN("SCMI get power state command return 0x%x unexpected\n",
+ ret);
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ /*
+ * Find the maximum power level described in the get power state
+ * command. If it is less than the requested power level, then assume
+ * the requested power level is ON.
+ */
+ if (SCMI_GET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state) < power_level)
+ return HW_ON;
+
+ lvl_state = SCMI_GET_PWR_STATE_LVL(scmi_pwr_state, power_level);
+ if (lvl_state == scmi_power_state_on)
+ return HW_ON;
+
+ assert((lvl_state == scmi_power_state_off) ||
+ (lvl_state == scmi_power_state_sleep));
+ return HW_OFF;
+}
+
+void __dead2 css_scp_system_off(int state)
+{
+ int ret;
+
+ /*
+ * Disable GIC CPU interface to prevent pending interrupt from waking
+ * up the AP from WFI.
+ */
+ plat_arm_gic_cpuif_disable();
+
+ /*
+ * Issue SCMI command. First issue a graceful
+ * request and if that fails force the request.
+ */
+ ret = scmi_sys_pwr_state_set(scmi_handle,
+ SCMI_SYS_PWR_FORCEFUL_REQ,
+ state);
+
+ if (ret != SCMI_E_SUCCESS) {
+ ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n",
+ state, ret);
+ panic();
+ }
+ wfi();
+ ERROR("CSS set power state: operation not handled.\n");
+ panic();
+}
+
+/*
+ * Helper function to shutdown the system via SCMI.
+ */
+void __dead2 css_scp_sys_shutdown(void)
+{
+ css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN);
+}
+
+/*
+ * Helper function to reset the system via SCMI.
+ */
+void __dead2 css_scp_sys_reboot(void)
+{
+ css_scp_system_off(SCMI_SYS_PWR_COLD_RESET);
+}
+
+static int scmi_ap_core_init(scmi_channel_t *ch)
+{
+#if PROGRAMMABLE_RESET_ADDRESS
+ uint32_t version;
+ int ret;
+
+ ret = scmi_proto_version(ch, SCMI_AP_CORE_PROTO_ID, &version);
+ if (ret != SCMI_E_SUCCESS) {
+ WARN("SCMI AP core protocol version message failed\n");
+ return -1;
+ }
+
+ if (!is_scmi_version_compatible(SCMI_AP_CORE_PROTO_VER, version)) {
+ WARN("SCMI AP core protocol version 0x%x incompatible with driver version 0x%x\n",
+ version, SCMI_AP_CORE_PROTO_VER);
+ return -1;
+ }
+ INFO("SCMI AP core protocol version 0x%x detected\n", version);
+#endif
+ return 0;
+}
+
+void __init plat_arm_pwrc_setup(void)
+{
+ channel.info = plat_css_get_scmi_info();
+ channel.lock = ARM_SCMI_LOCK_GET_INSTANCE;
+ scmi_handle = scmi_init(&channel);
+ if (scmi_handle == NULL) {
+ ERROR("SCMI Initialization failed\n");
+ panic();
+ }
+ if (scmi_ap_core_init(&channel) < 0) {
+ ERROR("SCMI AP core protocol initialization failed\n");
+ panic();
+ }
+}
+
+/******************************************************************************
+ * This function overrides the default definition for ARM platforms. Initialize
+ * the SCMI driver, query capability via SCMI and modify the PSCI capability
+ * based on that.
+ *****************************************************************************/
+const plat_psci_ops_t *css_scmi_override_pm_ops(plat_psci_ops_t *ops)
+{
+ uint32_t msg_attr;
+ int ret;
+
+ assert(scmi_handle);
+
+ /* Check that power domain POWER_STATE_SET message is supported */
+ ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID,
+ SCMI_PWR_STATE_SET_MSG, &msg_attr);
+ if (ret != SCMI_E_SUCCESS) {
+ ERROR("Set power state command is not supported by SCMI\n");
+ panic();
+ }
+
+ /*
+ * Don't support PSCI NODE_HW_STATE call if SCMI doesn't support
+ * POWER_STATE_GET message.
+ */
+ ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID,
+ SCMI_PWR_STATE_GET_MSG, &msg_attr);
+ if (ret != SCMI_E_SUCCESS)
+ ops->get_node_hw_state = NULL;
+
+ /* Check if the SCMI SYSTEM_POWER_STATE_SET message is supported */
+ ret = scmi_proto_msg_attr(scmi_handle, SCMI_SYS_PWR_PROTO_ID,
+ SCMI_SYS_PWR_STATE_SET_MSG, &msg_attr);
+ if (ret != SCMI_E_SUCCESS) {
+ /* System power management operations are not supported */
+ ops->system_off = NULL;
+ ops->system_reset = NULL;
+ ops->get_sys_suspend_power_state = NULL;
+ } else {
+ if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) {
+ /*
+ * System power management protocol is available, but
+ * it does not support SYSTEM SUSPEND.
+ */
+ ops->get_sys_suspend_power_state = NULL;
+ }
+ if (!(msg_attr & SCMI_SYS_PWR_WARM_RESET_SUPPORTED)) {
+ /*
+ * WARM reset is not available.
+ */
+ ops->system_reset2 = NULL;
+ }
+ }
+
+ return ops;
+}
+
+int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie)
+{
+ if (is_vendor || (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET))
+ return PSCI_E_INVALID_PARAMS;
+
+ css_scp_system_off(SCMI_SYS_PWR_WARM_RESET);
+ /*
+ * css_scp_system_off cannot return (it is a __dead function),
+ * but css_system_reset2 has to return some value, even in
+ * this case.
+ */
+ return 0;
+}
+
+#if PROGRAMMABLE_RESET_ADDRESS
+void plat_arm_program_trusted_mailbox(uintptr_t address)
+{
+ int ret;
+
+ assert(scmi_handle);
+ ret = scmi_ap_core_set_reset_addr(scmi_handle, address,
+ SCMI_AP_CORE_LOCK_ATTR);
+ if (ret != SCMI_E_SUCCESS) {
+ ERROR("CSS: Failed to program reset address: %d\n", ret);
+ panic();
+ }
+}
+#endif
diff --git a/drivers/arm/css/scp/css_pm_scpi.c b/drivers/arm/css/scp/css_pm_scpi.c
new file mode 100644
index 000000000..b4019ce03
--- /dev/null
+++ b/drivers/arm/css/scp/css_pm_scpi.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/css_scpi.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/arm/css/common/css_pm.h>
+
+/*
+ * This file implements the SCP power management functions using SCPI protocol.
+ */
+
+/*
+ * Helper function to inform power down state to SCP.
+ */
+void css_scp_suspend(const struct psci_power_state *target_state)
+{
+ uint32_t cluster_state = scpi_power_on;
+ uint32_t system_state = scpi_power_on;
+
+ /* Check if power down at system power domain level is requested */
+ if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF)
+ system_state = scpi_power_retention;
+
+ /* Cluster is to be turned off, so disable coherency */
+ if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
+ cluster_state = scpi_power_off;
+
+ /*
+ * Ask the SCP to power down the appropriate components depending upon
+ * their state.
+ */
+ scpi_set_css_power_state(read_mpidr_el1(),
+ scpi_power_off,
+ cluster_state,
+ system_state);
+}
+
+/*
+ * Helper function to turn off a CPU power domain and its parent power domains
+ * if applicable. Since SCPI doesn't differentiate between OFF and suspend, we
+ * call the suspend helper here.
+ */
+void css_scp_off(const struct psci_power_state *target_state)
+{
+ css_scp_suspend(target_state);
+}
+
+/*
+ * Helper function to turn ON a CPU power domain and its parent power domains
+ * if applicable.
+ */
+void css_scp_on(u_register_t mpidr)
+{
+ /*
+ * SCP takes care of powering up parent power domains so we
+ * only need to care about level 0
+ */
+ scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on,
+ scpi_power_on);
+}
+
+/*
+ * Helper function to get the power state of a power domain node as reported
+ * by the SCP.
+ */
+int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
+{
+ int rc, element;
+ unsigned int cpu_state, cluster_state;
+
+ /*
+ * The format of 'power_level' is implementation-defined, but 0 must
+ * mean a CPU. We also allow 1 to denote the cluster
+ */
+ if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1)
+ return PSCI_E_INVALID_PARAMS;
+
+ /* Query SCP */
+ rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state);
+ if (rc != 0)
+ return PSCI_E_INVALID_PARAMS;
+
+ /* Map power states of CPU and cluster to expected PSCI return codes */
+ if (power_level == ARM_PWR_LVL0) {
+ /*
+ * The CPU state returned by SCP is an 8-bit bit mask
+ * corresponding to each CPU in the cluster
+ */
+#if ARM_PLAT_MT
+ /*
+ * The current SCPI driver only caters for single-threaded
+ * platforms. Hence we ignore the thread ID (which is always 0)
+ * for such platforms.
+ */
+ element = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+#else
+ element = mpidr & MPIDR_AFFLVL_MASK;
+#endif /* ARM_PLAT_MT */
+ return CSS_CPU_PWR_STATE(cpu_state, element) ==
+ CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF;
+ } else {
+ assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON ||
+ cluster_state == CSS_CLUSTER_PWR_STATE_OFF);
+ return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON :
+ HW_OFF;
+ }
+}
+
+/*
+ * Helper function to shutdown the system via SCPI.
+ */
+void __dead2 css_scp_sys_shutdown(void)
+{
+ uint32_t response;
+
+ /*
+ * Disable GIC CPU interface to prevent pending interrupt
+ * from waking up the AP from WFI.
+ */
+ plat_arm_gic_cpuif_disable();
+
+ /* Send the power down request to the SCP */
+ response = scpi_sys_power_state(scpi_system_shutdown);
+
+ if (response != SCP_OK) {
+ ERROR("CSS System Off: SCP error %u.\n", response);
+ panic();
+ }
+ wfi();
+ ERROR("CSS System Off: operation not handled.\n");
+ panic();
+}
+
+/*
+ * Helper function to reset the system via SCPI.
+ */
+void __dead2 css_scp_sys_reboot(void)
+{
+ uint32_t response;
+
+ /*
+ * Disable GIC CPU interface to prevent pending interrupt
+ * from waking up the AP from WFI.
+ */
+ plat_arm_gic_cpuif_disable();
+
+ /* Send the system reset request to the SCP */
+ response = scpi_sys_power_state(scpi_system_reboot);
+
+ if (response != SCP_OK) {
+ ERROR("CSS System Reset: SCP error %u.\n", response);
+ panic();
+ }
+ wfi();
+ ERROR("CSS System Reset: operation not handled.\n");
+ panic();
+}
diff --git a/drivers/arm/css/scp/css_sds.c b/drivers/arm/css/scp/css_sds.c
new file mode 100644
index 000000000..e42ee10d7
--- /dev/null
+++ b/drivers/arm/css/scp/css_sds.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_scp.h>
+#include <drivers/arm/css/sds.h>
+#include <drivers/delay_timer.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+int css_scp_boot_image_xfer(void *image, unsigned int image_size)
+{
+ int ret;
+ unsigned int image_offset, image_flags;
+
+ ret = sds_init();
+ if (ret != SDS_OK) {
+ ERROR("SCP SDS initialization failed\n");
+ panic();
+ }
+
+ VERBOSE("Writing SCP image metadata\n");
+ image_offset = (uintptr_t) image - ARM_TRUSTED_SRAM_BASE;
+ ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_ADDR_OFFSET,
+ &image_offset, SDS_SCP_IMG_ADDR_SIZE,
+ SDS_ACCESS_MODE_NON_CACHED);
+ if (ret != SDS_OK)
+ goto sds_fail;
+
+ ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_SIZE_OFFSET,
+ &image_size, SDS_SCP_IMG_SIZE_SIZE,
+ SDS_ACCESS_MODE_NON_CACHED);
+ if (ret != SDS_OK)
+ goto sds_fail;
+
+ VERBOSE("Marking SCP image metadata as valid\n");
+ image_flags = SDS_SCP_IMG_VALID_FLAG_BIT;
+ ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_FLAG_OFFSET,
+ &image_flags, SDS_SCP_IMG_FLAG_SIZE,
+ SDS_ACCESS_MODE_NON_CACHED);
+ if (ret != SDS_OK)
+ goto sds_fail;
+
+ return 0;
+sds_fail:
+ ERROR("SCP SDS write to SCP IMG struct failed\n");
+ panic();
+}
+
+/*
+ * API to wait for SCP to signal till it's ready after booting the transferred
+ * image.
+ */
+int css_scp_boot_ready(void)
+{
+ uint32_t scp_feature_availability_flags;
+ int ret, retry = CSS_SCP_READY_10US_RETRIES;
+
+
+ VERBOSE("Waiting for SCP RAM to complete its initialization process\n");
+
+ /* Wait for the SCP RAM Firmware to complete its initialization process */
+ while (retry > 0) {
+ ret = sds_struct_read(SDS_FEATURE_AVAIL_STRUCT_ID, 0,
+ &scp_feature_availability_flags,
+ SDS_FEATURE_AVAIL_SIZE,
+ SDS_ACCESS_MODE_NON_CACHED);
+ if (ret == SDS_ERR_STRUCT_NOT_FINALIZED)
+ continue;
+
+ if (ret != SDS_OK) {
+ ERROR(" sds_struct_read failed\n");
+ panic();
+ }
+
+ if (scp_feature_availability_flags &
+ SDS_FEATURE_AVAIL_SCP_RAM_READY_BIT)
+ return 0;
+
+ udelay(10);
+ retry--;
+ }
+
+ ERROR("Timeout of %d ms expired waiting for SCP RAM Ready flag\n",
+ CSS_SCP_READY_10US_RETRIES/100);
+
+ plat_panic_handler();
+}
diff --git a/drivers/arm/css/scpi/css_scpi.c b/drivers/arm/css/scpi/css_scpi.c
new file mode 100644
index 000000000..4b73265ad
--- /dev/null
+++ b/drivers/arm/css/scpi/css_scpi.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/css_mhu.h>
+#include <drivers/arm/css/css_scpi.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#define SCPI_SHARED_MEM_SCP_TO_AP PLAT_CSS_SCP_COM_SHARED_MEM_BASE
+#define SCPI_SHARED_MEM_AP_TO_SCP (PLAT_CSS_SCP_COM_SHARED_MEM_BASE \
+ + 0x100)
+
+/* Header and payload addresses for commands from AP to SCP */
+#define SCPI_CMD_HEADER_AP_TO_SCP \
+ ((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP)
+#define SCPI_CMD_PAYLOAD_AP_TO_SCP \
+ ((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t)))
+
+/* Header and payload addresses for responses from SCP to AP */
+#define SCPI_RES_HEADER_SCP_TO_AP \
+ ((scpi_cmd_t *) SCPI_SHARED_MEM_SCP_TO_AP)
+#define SCPI_RES_PAYLOAD_SCP_TO_AP \
+ ((void *) (SCPI_SHARED_MEM_SCP_TO_AP + sizeof(scpi_cmd_t)))
+
+/* ID of the MHU slot used for the SCPI protocol */
+#define SCPI_MHU_SLOT_ID 0
+
+static void scpi_secure_message_start(void)
+{
+ mhu_secure_message_start(SCPI_MHU_SLOT_ID);
+}
+
+static void scpi_secure_message_send(size_t payload_size)
+{
+ /*
+ * Ensure that any write to the SCPI payload area is seen by SCP before
+ * we write to the MHU register. If these 2 writes were reordered by
+ * the CPU then SCP would read stale payload data
+ */
+ dmbst();
+
+ mhu_secure_message_send(SCPI_MHU_SLOT_ID);
+}
+
+static void scpi_secure_message_receive(scpi_cmd_t *cmd)
+{
+ uint32_t mhu_status;
+
+ assert(cmd != NULL);
+
+ mhu_status = mhu_secure_message_wait();
+
+ /* Expect an SCPI message, reject any other protocol */
+ if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) {
+ ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n",
+ mhu_status);
+ panic();
+ }
+
+ /*
+ * Ensure that any read to the SCPI payload area is done after reading
+ * the MHU register. If these 2 reads were reordered then the CPU would
+ * read invalid payload data
+ */
+ dmbld();
+
+ memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd));
+}
+
+static void scpi_secure_message_end(void)
+{
+ mhu_secure_message_end(SCPI_MHU_SLOT_ID);
+}
+
+int scpi_wait_ready(void)
+{
+ scpi_cmd_t scpi_cmd;
+
+ VERBOSE("Waiting for SCP_READY command...\n");
+
+ /* Get a message from the SCP */
+ scpi_secure_message_start();
+ scpi_secure_message_receive(&scpi_cmd);
+ scpi_secure_message_end();
+
+ /* We are expecting 'SCP Ready', produce correct error if it's not */
+ scpi_status_t status = SCP_OK;
+ if (scpi_cmd.id != SCPI_CMD_SCP_READY) {
+ ERROR("Unexpected SCP command: expected command #%u, got command #%u\n",
+ SCPI_CMD_SCP_READY, scpi_cmd.id);
+ status = SCP_E_SUPPORT;
+ } else if (scpi_cmd.size != 0) {
+ ERROR("SCP_READY command has incorrect size: expected 0, got %u\n",
+ scpi_cmd.size);
+ status = SCP_E_SIZE;
+ }
+
+ VERBOSE("Sending response for SCP_READY command\n");
+
+ /*
+ * Send our response back to SCP.
+ * We are using the same SCPI header, just update the status field.
+ */
+ scpi_cmd.status = status;
+ scpi_secure_message_start();
+ memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd));
+ scpi_secure_message_send(0);
+ scpi_secure_message_end();
+
+ return status == SCP_OK ? 0 : -1;
+}
+
+void scpi_set_css_power_state(unsigned int mpidr,
+ scpi_power_state_t cpu_state, scpi_power_state_t cluster_state,
+ scpi_power_state_t css_state)
+{
+ scpi_cmd_t *cmd;
+ uint32_t state = 0;
+ uint32_t *payload_addr;
+
+#if ARM_PLAT_MT
+ /*
+ * The current SCPI driver only caters for single-threaded platforms.
+ * Hence we ignore the thread ID (which is always 0) for such platforms.
+ */
+ state |= (mpidr >> MPIDR_AFF1_SHIFT) & 0x0f; /* CPU ID */
+ state |= ((mpidr >> MPIDR_AFF2_SHIFT) & 0x0f) << 4; /* Cluster ID */
+#else
+ state |= mpidr & 0x0f; /* CPU ID */
+ state |= (mpidr & 0xf00) >> 4; /* Cluster ID */
+#endif /* ARM_PLAT_MT */
+
+ state |= cpu_state << 8;
+ state |= cluster_state << 12;
+ state |= css_state << 16;
+
+ scpi_secure_message_start();
+
+ /* Populate the command header */
+ cmd = SCPI_CMD_HEADER_AP_TO_SCP;
+ cmd->id = SCPI_CMD_SET_CSS_POWER_STATE;
+ cmd->set = SCPI_SET_NORMAL;
+ cmd->sender = 0;
+ cmd->size = sizeof(state);
+ /* Populate the command payload */
+ payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
+ *payload_addr = state;
+ scpi_secure_message_send(sizeof(state));
+ /*
+ * SCP does not reply to this command in order to avoid MHU interrupts
+ * from the sender, which could interfere with its power state request.
+ */
+
+ scpi_secure_message_end();
+}
+
+/*
+ * Query and obtain CSS power state from SCP.
+ *
+ * In response to the query, SCP returns power states of all CPUs in all
+ * clusters of the system. The returned response is then filtered based on the
+ * supplied MPIDR. Power states of requested cluster and CPUs within are updated
+ * via. supplied non-NULL pointer arguments.
+ *
+ * Returns 0 on success, or -1 on errors.
+ */
+int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p,
+ unsigned int *cluster_state_p)
+{
+ scpi_cmd_t *cmd;
+ scpi_cmd_t response;
+ int power_state, cpu, cluster, rc = -1;
+
+ /*
+ * Extract CPU and cluster membership of the given MPIDR. SCPI caters
+ * for only up to 0xf clusters, and 8 CPUs per cluster
+ */
+#if ARM_PLAT_MT
+ /*
+ * The current SCPI driver only caters for single-threaded platforms.
+ * Hence we ignore the thread ID (which is always 0) for such platforms.
+ */
+ cpu = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+ cluster = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK;
+#else
+ cpu = mpidr & MPIDR_AFFLVL_MASK;
+ cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
+#endif /* ARM_PLAT_MT */
+ if (cpu >= 8 || cluster >= 0xf)
+ return -1;
+
+ scpi_secure_message_start();
+
+ /* Populate request headers */
+ zeromem(SCPI_CMD_HEADER_AP_TO_SCP, sizeof(*cmd));
+ cmd = SCPI_CMD_HEADER_AP_TO_SCP;
+ cmd->id = SCPI_CMD_GET_CSS_POWER_STATE;
+
+ /*
+ * Send message and wait for SCP's response
+ */
+ scpi_secure_message_send(0);
+ scpi_secure_message_receive(&response);
+
+ if (response.status != SCP_OK)
+ goto exit;
+
+ /* Validate SCP response */
+ if (!CHECK_RESPONSE(response, cluster))
+ goto exit;
+
+ /* Extract power states for required cluster */
+ power_state = *(((uint16_t *) SCPI_RES_PAYLOAD_SCP_TO_AP) + cluster);
+ if (CLUSTER_ID(power_state) != cluster)
+ goto exit;
+
+ /* Update power state via. pointers */
+ if (cluster_state_p)
+ *cluster_state_p = CLUSTER_POWER_STATE(power_state);
+ if (cpu_state_p)
+ *cpu_state_p = CPU_POWER_STATE(power_state);
+ rc = 0;
+
+exit:
+ scpi_secure_message_end();
+ return rc;
+}
+
+uint32_t scpi_sys_power_state(scpi_system_state_t system_state)
+{
+ scpi_cmd_t *cmd;
+ uint8_t *payload_addr;
+ scpi_cmd_t response;
+
+ scpi_secure_message_start();
+
+ /* Populate the command header */
+ cmd = SCPI_CMD_HEADER_AP_TO_SCP;
+ cmd->id = SCPI_CMD_SYS_POWER_STATE;
+ cmd->set = 0;
+ cmd->sender = 0;
+ cmd->size = sizeof(*payload_addr);
+ /* Populate the command payload */
+ payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP;
+ *payload_addr = system_state & 0xff;
+ scpi_secure_message_send(sizeof(*payload_addr));
+
+ scpi_secure_message_receive(&response);
+
+ scpi_secure_message_end();
+
+ return response.status;
+}
diff --git a/drivers/arm/css/sds/aarch32/sds_helpers.S b/drivers/arm/css/sds/aarch32/sds_helpers.S
new file mode 100644
index 000000000..13ff0e186
--- /dev/null
+++ b/drivers/arm/css/sds/aarch32/sds_helpers.S
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/css/sds.h>
+#include <platform_def.h>
+
+#include "../sds_private.h"
+
+ .globl sds_get_primary_cpu_id
+
+ /*
+ * int sds_get_primary_cpu_id(void);
+ * Return the primary CPU ID from SDS Structure
+ * Returns CPUID on success or -1 on failure
+ */
+func sds_get_primary_cpu_id
+ ldr r0, =PLAT_ARM_SDS_MEM_BASE
+ ldr r2, =SDS_REGION_SIGNATURE
+ ldr r1, [r0]
+ ubfx r3, r1, #0, #16
+
+ /* Check if the SDS region signature found */
+ cmp r2, r3
+ bne 2f
+
+ /* Get the structure count from region descriptor in r1 */
+ ubfx r1, r1, #SDS_REGION_STRUCT_COUNT_SHIFT, #SDS_REGION_STRUCT_COUNT_WIDTH
+ cmp r1, #0
+ beq 2f
+ add r0, r0, #SDS_REGION_DESC_SIZE
+
+ /* Initialize the loop iterator count in r3 */
+ mov r3, #0
+loop_begin:
+ ldrh r2, [r0]
+ cmp r2, #SDS_AP_CPU_INFO_STRUCT_ID
+ bne continue_loop
+
+ /* We have found the required structure */
+ ldr r0, [r0,#(SDS_HEADER_SIZE + SDS_AP_CPU_INFO_PRIMARY_CPUID_OFFSET)]
+ bx lr
+continue_loop:
+ /* Increment the loop counter and exit loop if counter == structure count */
+ add r3, r3, #0x1
+ cmp r1, r3
+ beq 2f
+
+ /* Read the 2nd word in header */
+ ldr r2, [r0,#4]
+ /* Get the structure size from header */
+ ubfx r2, r2, #SDS_HEADER_STRUCT_SIZE_SHIFT, #SDS_HEADER_STRUCT_SIZE_WIDTH
+ /* Add the structure size and SDS HEADER SIZE to point to next header */
+ add r2, r2, #SDS_HEADER_SIZE
+ add r0, r0, r2
+ b loop_begin
+2:
+ mov r0, #0xffffffff
+ bx lr
+endfunc sds_get_primary_cpu_id
diff --git a/drivers/arm/css/sds/aarch64/sds_helpers.S b/drivers/arm/css/sds/aarch64/sds_helpers.S
new file mode 100644
index 000000000..3256c2b54
--- /dev/null
+++ b/drivers/arm/css/sds/aarch64/sds_helpers.S
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/css/sds.h>
+#include <platform_def.h>
+
+#include "../sds_private.h"
+
+ .globl sds_get_primary_cpu_id
+
+ /*
+ * int sds_get_primary_cpu_id(void);
+ * Return the primary CPI ID from SDS Structure
+ * Returns CPUID on success or -1 on failure
+ */
+func sds_get_primary_cpu_id
+ mov_imm x0, PLAT_ARM_SDS_MEM_BASE
+ mov w2, #SDS_REGION_SIGNATURE
+ ldr w1, [x0]
+
+ /* Check if the SDS region signature found */
+ cmp w2, w1, uxth
+ b.ne 2f
+
+ /* Get the structure count from region descriptor in `w1 */
+ ubfx w1, w1, #SDS_REGION_STRUCT_COUNT_SHIFT, #SDS_REGION_STRUCT_COUNT_WIDTH
+ cbz w1, 2f
+ add x0, x0, #SDS_REGION_DESC_SIZE
+
+ /* Initialize the loop iterator count in w3 */
+ mov w3, #0
+loop_begin:
+ ldrh w2, [x0]
+ cmp w2, #SDS_AP_CPU_INFO_STRUCT_ID
+ b.ne continue_loop
+
+ /* We have found the required structure */
+ ldr w0, [x0,#(SDS_HEADER_SIZE + SDS_AP_CPU_INFO_PRIMARY_CPUID_OFFSET)]
+ ret
+continue_loop:
+ /* Increment the loop counter and exit loop if counter == structure count */
+ add w3, w3, #0x1
+ cmp w1, w3
+ b.eq 2f
+
+ /* Read the 2nd word in header */
+ ldr w2, [x0,#4]
+ /* Get the structure size from header */
+ ubfx x2, x2, #SDS_HEADER_STRUCT_SIZE_SHIFT, #SDS_HEADER_STRUCT_SIZE_WIDTH
+ /* Add the structure size and SDS HEADER SIZE to point to next header */
+ add x2, x2, #SDS_HEADER_SIZE
+ add x0, x0, x2
+ b loop_begin
+2:
+ mov w0, #0xffffffff
+ ret
+endfunc sds_get_primary_cpu_id
diff --git a/drivers/arm/css/sds/sds.c b/drivers/arm/css/sds/sds.c
new file mode 100644
index 000000000..1fb196c70
--- /dev/null
+++ b/drivers/arm/css/sds/sds.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/css/sds.h>
+#include <platform_def.h>
+
+#include "sds_private.h"
+
+/*
+ * Variables used to track and maintain the state of the memory region reserved
+ * for usage by the SDS framework.
+ */
+
+/* Pointer to the base of the SDS memory region */
+static uintptr_t sds_mem_base;
+
+/* Size of the SDS memory region in bytes */
+static size_t sds_mem_size;
+
+/*
+ * Perform some non-exhaustive tests to determine whether any of the fields
+ * within a Structure Header contain obviously invalid data.
+ * Returns SDS_OK on success, SDS_ERR_FAIL on error.
+ */
+static int sds_struct_is_valid(uintptr_t header)
+{
+ size_t struct_size = GET_SDS_HEADER_STRUCT_SIZE(header);
+
+ /* Zero is not a valid identifier */
+ if (GET_SDS_HEADER_ID(header) == 0)
+ return SDS_ERR_FAIL;
+
+ /* Check SDS Schema version */
+ if (GET_SDS_HEADER_VERSION(header) == SDS_REGION_SCH_VERSION)
+ return SDS_ERR_FAIL;
+
+ /* The SDS Structure sizes have to be multiple of 8 */
+ if ((struct_size == 0) || ((struct_size % 8) != 0))
+ return SDS_ERR_FAIL;
+
+ if (struct_size > sds_mem_size)
+ return SDS_ERR_FAIL;
+
+ return SDS_OK;
+}
+
+/*
+ * Validate the SDS structure headers.
+ * Returns SDS_OK on success, SDS_ERR_FAIL on error.
+ */
+static int validate_sds_struct_headers(void)
+{
+ unsigned int i, structure_count;
+ uintptr_t header;
+
+ structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base);
+
+ if (structure_count == 0)
+ return SDS_ERR_FAIL;
+
+ header = sds_mem_base + SDS_REGION_DESC_SIZE;
+
+ /* Iterate over structure headers and validate each one */
+ for (i = 0; i < structure_count; i++) {
+ if (sds_struct_is_valid(header) != SDS_OK) {
+ WARN("SDS: Invalid structure header detected\n");
+ return SDS_ERR_FAIL;
+ }
+ header += GET_SDS_HEADER_STRUCT_SIZE(header) + SDS_HEADER_SIZE;
+ }
+ return SDS_OK;
+}
+
+/*
+ * Get the structure header pointer corresponding to the structure ID.
+ * Returns SDS_OK on success, SDS_ERR_STRUCT_NOT_FOUND on error.
+ */
+static int get_struct_header(uint32_t structure_id, struct_header_t **header)
+{
+ unsigned int i, structure_count;
+ uintptr_t current_header;
+
+ assert(header);
+
+ structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base);
+ if (structure_count == 0)
+ return SDS_ERR_STRUCT_NOT_FOUND;
+
+ current_header = ((uintptr_t)sds_mem_base) + SDS_REGION_DESC_SIZE;
+
+ /* Iterate over structure headers to find one with a matching ID */
+ for (i = 0; i < structure_count; i++) {
+ if (GET_SDS_HEADER_ID(current_header) == structure_id) {
+ *header = (struct_header_t *)current_header;
+ return SDS_OK;
+ }
+ current_header += GET_SDS_HEADER_STRUCT_SIZE(current_header) +
+ SDS_HEADER_SIZE;
+ }
+
+ *header = NULL;
+ return SDS_ERR_STRUCT_NOT_FOUND;
+}
+
+/*
+ * Check if a structure header corresponding to the structure ID exists.
+ * Returns SDS_OK if structure header exists else SDS_ERR_STRUCT_NOT_FOUND
+ * if not found.
+ */
+int sds_struct_exists(unsigned int structure_id)
+{
+ struct_header_t *header = NULL;
+ int ret;
+
+ ret = get_struct_header(structure_id, &header);
+ if (ret == SDS_OK) {
+ assert(header);
+ }
+
+ return ret;
+}
+
+/*
+ * Read from field in the structure corresponding to `structure_id`.
+ * `fld_off` is the offset to the field in the structure and `mode`
+ * indicates whether cache maintenance need to performed prior to the read.
+ * The `data` is the pointer to store the read data of size specified by `size`.
+ * Returns SDS_OK on success or corresponding error codes on failure.
+ */
+int sds_struct_read(uint32_t structure_id, unsigned int fld_off,
+ void *data, size_t size, sds_access_mode_t mode)
+{
+ int status;
+ uintptr_t field_base;
+ struct_header_t *header = NULL;
+
+ if (!data)
+ return SDS_ERR_INVALID_PARAMS;
+
+ /* Check if a structure with this ID exists */
+ status = get_struct_header(structure_id, &header);
+ if (status != SDS_OK)
+ return status;
+
+ assert(header);
+
+ if (mode == SDS_ACCESS_MODE_CACHED)
+ inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size);
+
+ if (!IS_SDS_HEADER_VALID(header)) {
+ WARN("SDS: Reading from un-finalized structure 0x%x\n",
+ structure_id);
+ return SDS_ERR_STRUCT_NOT_FINALIZED;
+ }
+
+ if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header))
+ return SDS_ERR_FAIL;
+
+ field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off;
+ if (check_uptr_overflow(field_base, size - 1))
+ return SDS_ERR_FAIL;
+
+ /* Copy the required field in the struct */
+ memcpy(data, (void *)field_base, size);
+
+ return SDS_OK;
+}
+
+/*
+ * Write to the field in the structure corresponding to `structure_id`.
+ * `fld_off` is the offset to the field in the structure and `mode`
+ * indicates whether cache maintenance need to performed for the write.
+ * The `data` is the pointer to data of size specified by `size`.
+ * Returns SDS_OK on success or corresponding error codes on failure.
+ */
+int sds_struct_write(uint32_t structure_id, unsigned int fld_off,
+ void *data, size_t size, sds_access_mode_t mode)
+{
+ int status;
+ uintptr_t field_base;
+ struct_header_t *header = NULL;
+
+ if (!data)
+ return SDS_ERR_INVALID_PARAMS;
+
+ /* Check if a structure with this ID exists */
+ status = get_struct_header(structure_id, &header);
+ if (status != SDS_OK)
+ return status;
+
+ assert(header);
+
+ if (mode == SDS_ACCESS_MODE_CACHED)
+ inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size);
+
+ if (!IS_SDS_HEADER_VALID(header)) {
+ WARN("SDS: Writing to un-finalized structure 0x%x\n",
+ structure_id);
+ return SDS_ERR_STRUCT_NOT_FINALIZED;
+ }
+
+ if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header))
+ return SDS_ERR_FAIL;
+
+ field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off;
+ if (check_uptr_overflow(field_base, size - 1))
+ return SDS_ERR_FAIL;
+
+ /* Copy the required field in the struct */
+ memcpy((void *)field_base, data, size);
+
+ if (mode == SDS_ACCESS_MODE_CACHED)
+ flush_dcache_range((uintptr_t)field_base, size);
+
+ return SDS_OK;
+}
+
+/*
+ * Initialize the SDS driver. Also verifies the SDS version and sanity of
+ * the SDS structure headers.
+ * Returns SDS_OK on success, SDS_ERR_FAIL on error.
+ */
+int sds_init(void)
+{
+ sds_mem_base = (uintptr_t)PLAT_ARM_SDS_MEM_BASE;
+
+ if (!IS_SDS_REGION_VALID(sds_mem_base)) {
+ WARN("SDS: No valid SDS Memory Region found\n");
+ return SDS_ERR_FAIL;
+ }
+
+ if (GET_SDS_REGION_SCHEMA_VERSION(sds_mem_base)
+ != SDS_REGION_SCH_VERSION) {
+ WARN("SDS: Unsupported SDS schema version\n");
+ return SDS_ERR_FAIL;
+ }
+
+ sds_mem_size = GET_SDS_REGION_SIZE(sds_mem_base);
+ if (sds_mem_size > PLAT_ARM_SDS_MEM_SIZE_MAX) {
+ WARN("SDS: SDS Memory Region exceeds size limit\n");
+ return SDS_ERR_FAIL;
+ }
+
+ INFO("SDS: Detected SDS Memory Region (%zu bytes)\n", sds_mem_size);
+
+ if (validate_sds_struct_headers() != SDS_OK)
+ return SDS_ERR_FAIL;
+
+ return SDS_OK;
+}
diff --git a/drivers/arm/css/sds/sds_private.h b/drivers/arm/css/sds/sds_private.h
new file mode 100644
index 000000000..2101dd049
--- /dev/null
+++ b/drivers/arm/css/sds/sds_private.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SDS_PRIVATE_H
+#define SDS_PRIVATE_H
+
+/* SDS Header defines */
+#define SDS_HEADER_ID_SHIFT 0
+#define SDS_HEADER_ID_WIDTH 16
+#define SDS_HEADER_ID_MASK ((1 << SDS_HEADER_ID_WIDTH) - 1)
+
+#define SDS_HEADER_MINOR_VERSION_WIDTH 8
+#define SDS_HEADER_MINOR_VERSION_SHIFT 16
+#define SDS_HEADER_MAJOR_VERSION_WIDTH 8
+
+#define MAKE_SDS_HEADER_VERSION(major, minor) \
+ (((((major) & 0xff) << SDS_HEADER_MINOR_VERSION_WIDTH) | ((minor) & 0xff)))
+#define SDS_HEADER_VERSION_MASK \
+ ((1 << (SDS_HEADER_MINOR_VERSION_WIDTH + SDS_HEADER_MAJOR_VERSION_WIDTH)) - 1)
+
+#define SDS_HEADER_VERSION MAKE_SDS_HEADER_VERSION(1, 0)
+#define SDS_HEADER_STRUCT_SIZE_WIDTH 23
+#define SDS_HEADER_STRUCT_SIZE_SHIFT 1
+#define SDS_HEADER_STRUCT_SIZE_MASK ((1 << SDS_HEADER_STRUCT_SIZE_WIDTH) - 1)
+#define SDS_HEADER_VALID_MASK 0x1
+#define SDS_HEADER_VALID_SHIFT 0
+#define SDS_HEADER_SIZE 0x8
+
+/* Arbitrary, 16 bit value that indicates a valid SDS Memory Region */
+#define SDS_REGION_SIGNATURE 0xAA7A
+#define SDS_REGION_SIGNATURE_WIDTH 16
+#define SDS_REGION_SIGNATURE_SHIFT 0
+#define SDS_REGION_SIGNATURE_MASK ((1 << SDS_REGION_SIGNATURE_WIDTH) - 1)
+
+#define SDS_REGION_STRUCT_COUNT_SHIFT 16
+#define SDS_REGION_STRUCT_COUNT_WIDTH 8
+#define SDS_REGION_STRUCT_COUNT_MASK ((1 << SDS_REGION_STRUCT_COUNT_WIDTH) - 1)
+
+#define SDS_REGION_SCH_MINOR_SHIFT 24
+#define SDS_REGION_SCH_MINOR_WIDTH 4
+#define SDS_REGION_SCH_MINOR_MASK ((1 << SDS_REGION_SCH_MINOR_WIDTH) - 1)
+
+#define SDS_REGION_SCH_MAJOR_SHIFT 28
+#define SDS_REGION_SCH_MAJOR_WIDTH 4
+#define SDS_REGION_SCH_MAJOR_MASK ((1 << SDS_REGION_SCH_MAJOR_WIDTH) - 1)
+
+#define SDS_REGION_SCH_VERSION_MASK \
+ ((1 << (SDS_REGION_SCH_MINOR_WIDTH + SDS_REGION_SCH_MAJOR_WIDTH)) - 1)
+
+#define MAKE_SDS_REGION_SCH_VERSION(maj, min) \
+ ((((maj) & SDS_REGION_SCH_MAJOR_MASK) << SDS_REGION_SCH_MINOR_WIDTH) | \
+ ((min) & SDS_REGION_SCH_MINOR_MASK))
+
+#define SDS_REGION_SCH_VERSION MAKE_SDS_REGION_SCH_VERSION(1, 0)
+#define SDS_REGION_REGIONSIZE_OFFSET 0x4
+#define SDS_REGION_DESC_SIZE 0x8
+
+#ifndef __ASSEMBLY__
+#include <stddef.h>
+#include <stdint.h>
+
+/* Header containing Shared Data Structure metadata */
+typedef struct structure_header {
+ uint32_t reg[2];
+} struct_header_t;
+
+#define GET_SDS_HEADER_ID(_header) \
+ ((((struct_header_t *)(_header))->reg[0]) & SDS_HEADER_ID_MASK)
+#define GET_SDS_HEADER_VERSION(_header) \
+ (((((struct_header_t *)(_header))->reg[0]) >> SDS_HEADER_MINOR_VERSION_SHIFT)\
+ & SDS_HEADER_VERSION_MASK)
+#define GET_SDS_HEADER_STRUCT_SIZE(_header) \
+ (((((struct_header_t *)(_header))->reg[1]) >> SDS_HEADER_STRUCT_SIZE_SHIFT)\
+ & SDS_HEADER_STRUCT_SIZE_MASK)
+#define IS_SDS_HEADER_VALID(_header) \
+ ((((struct_header_t *)(_header))->reg[1]) & SDS_HEADER_VALID_MASK)
+#define GET_SDS_STRUCT_FIELD(_header, _field_offset) \
+ ((((uint8_t *)(_header)) + sizeof(struct_header_t)) + (_field_offset))
+
+/* Region Descriptor describing the SDS Memory Region */
+typedef struct region_descriptor {
+ uint32_t reg[2];
+} region_desc_t;
+
+#define IS_SDS_REGION_VALID(region) \
+ (((((region_desc_t *)(region))->reg[0]) & SDS_REGION_SIGNATURE_MASK) == SDS_REGION_SIGNATURE)
+#define GET_SDS_REGION_STRUCTURE_COUNT(region) \
+ (((((region_desc_t *)(region))->reg[0]) >> SDS_REGION_STRUCT_COUNT_SHIFT)\
+ & SDS_REGION_STRUCT_COUNT_MASK)
+#define GET_SDS_REGION_SCHEMA_VERSION(region) \
+ (((((region_desc_t *)(region))->reg[0]) >> SDS_REGION_SCH_MINOR_SHIFT)\
+ & SDS_REGION_SCH_VERSION_MASK)
+#define GET_SDS_REGION_SIZE(region) ((((region_desc_t *)(region))->reg[1]))
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* SDS_PRIVATE_H */
diff --git a/drivers/arm/fvp/fvp_pwrc.c b/drivers/arm/fvp/fvp_pwrc.c
new file mode 100644
index 000000000..75a2b66c5
--- /dev/null
+++ b/drivers/arm/fvp/fvp_pwrc.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/arm/fvp/fvp_pwrc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/*
+ * TODO: Someday there will be a generic power controller api. At the moment
+ * each platform has its own pwrc so just exporting functions is fine.
+ */
+ARM_INSTANTIATE_LOCK;
+
+unsigned int fvp_pwrc_get_cpu_wkr(u_register_t mpidr)
+{
+ return PSYSR_WK(fvp_pwrc_read_psysr(mpidr));
+}
+
+unsigned int fvp_pwrc_read_psysr(u_register_t mpidr)
+{
+ unsigned int rc;
+ arm_lock_get();
+ mmio_write_32(PWRC_BASE + PSYSR_OFF, (unsigned int) mpidr);
+ rc = mmio_read_32(PWRC_BASE + PSYSR_OFF);
+ arm_lock_release();
+ return rc;
+}
+
+void fvp_pwrc_write_pponr(u_register_t mpidr)
+{
+ arm_lock_get();
+ mmio_write_32(PWRC_BASE + PPONR_OFF, (unsigned int) mpidr);
+ arm_lock_release();
+}
+
+void fvp_pwrc_write_ppoffr(u_register_t mpidr)
+{
+ arm_lock_get();
+ mmio_write_32(PWRC_BASE + PPOFFR_OFF, (unsigned int) mpidr);
+ arm_lock_release();
+}
+
+void fvp_pwrc_set_wen(u_register_t mpidr)
+{
+ arm_lock_get();
+ mmio_write_32(PWRC_BASE + PWKUPR_OFF,
+ (unsigned int) (PWKUPR_WEN | mpidr));
+ arm_lock_release();
+}
+
+void fvp_pwrc_clr_wen(u_register_t mpidr)
+{
+ arm_lock_get();
+ mmio_write_32(PWRC_BASE + PWKUPR_OFF,
+ (unsigned int) mpidr);
+ arm_lock_release();
+}
+
+void fvp_pwrc_write_pcoffr(u_register_t mpidr)
+{
+ arm_lock_get();
+ mmio_write_32(PWRC_BASE + PCOFFR_OFF, (unsigned int) mpidr);
+ arm_lock_release();
+}
+
+/* Nothing else to do here apart from initializing the lock */
+void __init plat_arm_pwrc_setup(void)
+{
+ arm_lock_init();
+}
+
+
+
diff --git a/drivers/console/multi_console.c b/drivers/console/multi_console.c
index e94de35c7..a13595923 100644
--- a/drivers/console/multi_console.c
+++ b/drivers/console/multi_console.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -76,7 +76,7 @@ int console_putc(int c)
console_t *console;
for (console = console_list; console != NULL; console = console->next)
- if (console->flags & console_state) {
+ if ((console->flags & console_state) && console->putc) {
int ret = console->putc(c, console);
if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err))
err = ret;
@@ -93,7 +93,7 @@ int console_getc(void)
do { /* Keep polling while at least one console works correctly. */
for (console = console_list; console != NULL;
console = console->next)
- if (console->flags & console_state) {
+ if ((console->flags & console_state) && console->getc) {
int ret = console->getc(console);
if (ret >= 0)
return ret;
@@ -111,7 +111,7 @@ int console_flush(void)
console_t *console;
for (console = console_list; console != NULL; console = console->next)
- if (console->flags & console_state) {
+ if ((console->flags & console_state) && console->flush) {
int ret = console->flush(console);
if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err))
err = ret;
diff --git a/drivers/partition/partition.c b/drivers/partition/partition.c
index 630c1d808..6fa3df0f2 100644
--- a/drivers/partition/partition.c
+++ b/drivers/partition/partition.c
@@ -16,7 +16,7 @@
#include <plat/common/platform.h>
static uint8_t mbr_sector[PARTITION_BLOCK_SIZE];
-partition_entry_list_t list;
+static partition_entry_list_t list;
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
static void dump_entries(int num)
diff --git a/drivers/rpi3/gpio/rpi3_gpio.c b/drivers/rpi3/gpio/rpi3_gpio.c
new file mode 100644
index 000000000..b39808ff7
--- /dev/null
+++ b/drivers/rpi3/gpio/rpi3_gpio.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2019, Linaro Limited
+ * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <lib/mmio.h>
+#include <drivers/delay_timer.h>
+#include <drivers/rpi3/gpio/rpi3_gpio.h>
+
+static struct rpi3_gpio_params rpi3_gpio_params;
+
+static int rpi3_gpio_get_direction(int gpio);
+static void rpi3_gpio_set_direction(int gpio, int direction);
+static int rpi3_gpio_get_value(int gpio);
+static void rpi3_gpio_set_value(int gpio, int value);
+static void rpi3_gpio_set_pull(int gpio, int pull);
+
+static const gpio_ops_t rpi3_gpio_ops = {
+ .get_direction = rpi3_gpio_get_direction,
+ .set_direction = rpi3_gpio_set_direction,
+ .get_value = rpi3_gpio_get_value,
+ .set_value = rpi3_gpio_set_value,
+ .set_pull = rpi3_gpio_set_pull,
+};
+
+/**
+ * Get selection of GPIO pinmux settings.
+ *
+ * @param gpio The pin number of GPIO. From 0 to 53.
+ * @return The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
+ * RPI3_GPIO_FUNC_OUTPUT: output,
+ * RPI3_GPIO_FUNC_ALT0: alt-0,
+ * RPI3_GPIO_FUNC_ALT1: alt-1,
+ * RPI3_GPIO_FUNC_ALT2: alt-2,
+ * RPI3_GPIO_FUNC_ALT3: alt-3,
+ * RPI3_GPIO_FUNC_ALT4: alt-4,
+ * RPI3_GPIO_FUNC_ALT5: alt-5
+ */
+int rpi3_gpio_get_select(int gpio)
+{
+ int ret;
+ uintptr_t reg_base = rpi3_gpio_params.reg_base;
+ int regN = gpio / 10;
+ int shift = 3 * (gpio % 10);
+ uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
+ uint32_t sel = mmio_read_32(reg_sel);
+
+ ret = (sel >> shift) & 0x07;
+
+ return ret;
+}
+
+/**
+ * Set selection of GPIO pinmux settings.
+ *
+ * @param gpio The pin number of GPIO. From 0 to 53.
+ * @param fsel The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input,
+ * RPI3_GPIO_FUNC_OUTPUT: output,
+ * RPI3_GPIO_FUNC_ALT0: alt-0,
+ * RPI3_GPIO_FUNC_ALT1: alt-1,
+ * RPI3_GPIO_FUNC_ALT2: alt-2,
+ * RPI3_GPIO_FUNC_ALT3: alt-3,
+ * RPI3_GPIO_FUNC_ALT4: alt-4,
+ * RPI3_GPIO_FUNC_ALT5: alt-5
+ */
+void rpi3_gpio_set_select(int gpio, int fsel)
+{
+ uintptr_t reg_base = rpi3_gpio_params.reg_base;
+ int regN = gpio / 10;
+ int shift = 3 * (gpio % 10);
+ uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN);
+ uint32_t sel = mmio_read_32(reg_sel);
+ uint32_t mask = U(0x07) << shift;
+
+ sel = (sel & (~mask)) | ((fsel << shift) & mask);
+ mmio_write_32(reg_sel, sel);
+}
+
+static int rpi3_gpio_get_direction(int gpio)
+{
+ int result = rpi3_gpio_get_select(gpio);
+
+ if (result == RPI3_GPIO_FUNC_INPUT)
+ return GPIO_DIR_IN;
+ else if (result == RPI3_GPIO_FUNC_OUTPUT)
+ return GPIO_DIR_OUT;
+
+ return GPIO_DIR_IN;
+}
+
+static void rpi3_gpio_set_direction(int gpio, int direction)
+{
+ switch (direction) {
+ case GPIO_DIR_IN:
+ rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_INPUT);
+ break;
+ case GPIO_DIR_OUT:
+ rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_OUTPUT);
+ break;
+ }
+}
+
+static int rpi3_gpio_get_value(int gpio)
+{
+ uintptr_t reg_base = rpi3_gpio_params.reg_base;
+ int regN = gpio / 32;
+ int shift = gpio % 32;
+ uintptr_t reg_lev = reg_base + RPI3_GPIO_GPLEV(regN);
+ uint32_t value = mmio_read_32(reg_lev);
+
+ if ((value >> shift) & 0x01)
+ return GPIO_LEVEL_HIGH;
+ return GPIO_LEVEL_LOW;
+}
+
+static void rpi3_gpio_set_value(int gpio, int value)
+{
+ uintptr_t reg_base = rpi3_gpio_params.reg_base;
+ int regN = gpio / 32;
+ int shift = gpio % 32;
+ uintptr_t reg_set = reg_base + RPI3_GPIO_GPSET(regN);
+ uintptr_t reg_clr = reg_base + RPI3_GPIO_GPSET(regN);
+
+ switch (value) {
+ case GPIO_LEVEL_LOW:
+ mmio_write_32(reg_clr, U(1) << shift);
+ break;
+ case GPIO_LEVEL_HIGH:
+ mmio_write_32(reg_set, U(1) << shift);
+ break;
+ }
+}
+
+static void rpi3_gpio_set_pull(int gpio, int pull)
+{
+ uintptr_t reg_base = rpi3_gpio_params.reg_base;
+ int regN = gpio / 32;
+ int shift = gpio % 32;
+ uintptr_t reg_pud = reg_base + RPI3_GPIO_GPPUD;
+ uintptr_t reg_clk = reg_base + RPI3_GPIO_GPPUDCLK(regN);
+
+ switch (pull) {
+ case GPIO_PULL_NONE:
+ mmio_write_32(reg_pud, 0x0);
+ break;
+ case GPIO_PULL_UP:
+ mmio_write_32(reg_pud, 0x2);
+ break;
+ case GPIO_PULL_DOWN:
+ mmio_write_32(reg_pud, 0x1);
+ break;
+ }
+ mdelay(150);
+ mmio_write_32(reg_clk, U(1) << shift);
+ mdelay(150);
+ mmio_write_32(reg_clk, 0x0);
+ mmio_write_32(reg_pud, 0x0);
+}
+
+void rpi3_gpio_init(struct rpi3_gpio_params *params)
+{
+ assert(params != 0);
+ memcpy(&rpi3_gpio_params, params, sizeof(struct rpi3_gpio_params));
+ gpio_init(&rpi3_gpio_ops);
+}
diff --git a/drivers/st/bsec/bsec.c b/drivers/st/bsec/bsec.c
new file mode 100644
index 000000000..aaecf1f83
--- /dev/null
+++ b/drivers/st/bsec/bsec.c
@@ -0,0 +1,913 @@
+/*
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include <libfdt.h>
+
+#include <platform_def.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/st/bsec.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+
+#define BSEC_IP_VERSION_1_0 0x10
+#define BSEC_COMPAT "st,stm32mp15-bsec"
+
+#define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT)
+
+static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __unused;
+
+static uint32_t bsec_power_safmem(bool power);
+
+/* BSEC access protection */
+static spinlock_t bsec_spinlock;
+static uintptr_t bsec_base;
+
+static void bsec_lock(void)
+{
+ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
+
+ /* Lock is currently required only when MMU and cache are enabled */
+ if ((read_sctlr() & mask) == mask) {
+ spin_lock(&bsec_spinlock);
+ }
+}
+
+static void bsec_unlock(void)
+{
+ const uint32_t mask = SCTLR_M_BIT | SCTLR_C_BIT;
+
+ /* Unlock is required only when MMU and cache are enabled */
+ if ((read_sctlr() & mask) == mask) {
+ spin_unlock(&bsec_spinlock);
+ }
+}
+
+static int bsec_get_dt_node(struct dt_node_info *info)
+{
+ int node;
+
+ node = dt_get_node(info, -1, BSEC_COMPAT);
+ if (node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ return node;
+}
+
+#if defined(IMAGE_BL32)
+static void enable_non_secure_access(uint32_t otp)
+{
+ otp_nsec_access[otp / __WORD_BIT] |= BIT(otp % __WORD_BIT);
+
+ if (bsec_shadow_register(otp) != BSEC_OK) {
+ panic();
+ }
+}
+
+static bool non_secure_can_access(uint32_t otp)
+{
+ return (otp_nsec_access[otp / __WORD_BIT] &
+ BIT(otp % __WORD_BIT)) != 0;
+}
+
+static int bsec_dt_otp_nsec_access(void *fdt, int bsec_node)
+{
+ int bsec_subnode;
+
+ fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) {
+ const fdt32_t *cuint;
+ uint32_t reg;
+ uint32_t i;
+ uint32_t size;
+ uint8_t status;
+
+ cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL);
+ if (cuint == NULL) {
+ panic();
+ }
+
+ reg = fdt32_to_cpu(*cuint) / sizeof(uint32_t);
+ if (reg < STM32MP1_UPPER_OTP_START) {
+ continue;
+ }
+
+ status = fdt_get_status(bsec_subnode);
+ if ((status & DT_NON_SECURE) == 0U) {
+ continue;
+ }
+
+ size = fdt32_to_cpu(*(cuint + 1)) / sizeof(uint32_t);
+
+ if ((fdt32_to_cpu(*(cuint + 1)) % sizeof(uint32_t)) != 0) {
+ size++;
+ }
+
+ for (i = reg; i < (reg + size); i++) {
+ enable_non_secure_access(i);
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static uint32_t otp_bank_offset(uint32_t otp)
+{
+ assert(otp <= STM32MP1_OTP_MAX_ID);
+
+ return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) *
+ sizeof(uint32_t);
+}
+
+static uint32_t bsec_check_error(uint32_t otp)
+{
+ uint32_t bit = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank = otp_bank_offset(otp);
+
+ if ((mmio_read_32(bsec_base + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
+ return BSEC_DISTURBED;
+ }
+
+ if ((mmio_read_32(bsec_base + BSEC_ERROR_OFF + bank) & bit) != 0U) {
+ return BSEC_ERROR;
+ }
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_probe: initialize BSEC driver.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_probe(void)
+{
+ void *fdt;
+ int node;
+ struct dt_node_info bsec_info;
+
+ if (fdt_get_address(&fdt) == 0) {
+ panic();
+ }
+
+ node = bsec_get_dt_node(&bsec_info);
+ if (node < 0) {
+ panic();
+ }
+
+ bsec_base = bsec_info.base;
+
+#if defined(IMAGE_BL32)
+ bsec_dt_otp_nsec_access(fdt, node);
+#endif
+ return BSEC_OK;
+}
+
+/*
+ * bsec_get_base: return BSEC base address.
+ */
+uint32_t bsec_get_base(void)
+{
+ return bsec_base;
+}
+
+/*
+ * bsec_set_config: enable and configure BSEC.
+ * cfg: pointer to param structure used to set register.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_set_config(struct bsec_config *cfg)
+{
+ uint32_t value;
+ int32_t result;
+
+ value = ((((uint32_t)cfg->freq << BSEC_CONF_FRQ_SHIFT) &
+ BSEC_CONF_FRQ_MASK) |
+ (((uint32_t)cfg->pulse_width << BSEC_CONF_PRG_WIDTH_SHIFT) &
+ BSEC_CONF_PRG_WIDTH_MASK) |
+ (((uint32_t)cfg->tread << BSEC_CONF_TREAD_SHIFT) &
+ BSEC_CONF_TREAD_MASK));
+
+ bsec_lock();
+
+ mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, value);
+
+ bsec_unlock();
+
+ result = bsec_power_safmem((bool)cfg->power &
+ BSEC_CONF_POWER_UP_MASK);
+ if (result != BSEC_OK) {
+ return result;
+ }
+
+ value = ((((uint32_t)cfg->upper_otp_lock << UPPER_OTP_LOCK_SHIFT) &
+ UPPER_OTP_LOCK_MASK) |
+ (((uint32_t)cfg->den_lock << DENREG_LOCK_SHIFT) &
+ DENREG_LOCK_MASK) |
+ (((uint32_t)cfg->prog_lock << GPLOCK_LOCK_SHIFT) &
+ GPLOCK_LOCK_MASK));
+
+ bsec_lock();
+
+ mmio_write_32(bsec_base + BSEC_OTP_LOCK_OFF, value);
+
+ bsec_unlock();
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_get_config: return config parameters set in BSEC registers.
+ * cfg: config param return.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_get_config(struct bsec_config *cfg)
+{
+ uint32_t value;
+
+ if (cfg == NULL) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ value = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF);
+ cfg->power = (uint8_t)((value & BSEC_CONF_POWER_UP_MASK) >>
+ BSEC_CONF_POWER_UP_SHIFT);
+ cfg->freq = (uint8_t)((value & BSEC_CONF_FRQ_MASK) >>
+ BSEC_CONF_FRQ_SHIFT);
+ cfg->pulse_width = (uint8_t)((value & BSEC_CONF_PRG_WIDTH_MASK) >>
+ BSEC_CONF_PRG_WIDTH_SHIFT);
+ cfg->tread = (uint8_t)((value & BSEC_CONF_TREAD_MASK) >>
+ BSEC_CONF_TREAD_SHIFT);
+
+ value = mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF);
+ cfg->upper_otp_lock = (uint8_t)((value & UPPER_OTP_LOCK_MASK) >>
+ UPPER_OTP_LOCK_SHIFT);
+ cfg->den_lock = (uint8_t)((value & DENREG_LOCK_MASK) >>
+ DENREG_LOCK_SHIFT);
+ cfg->prog_lock = (uint8_t)((value & GPLOCK_LOCK_MASK) >>
+ GPLOCK_LOCK_SHIFT);
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_shadow_register: copy SAFMEM OTP to BSEC data.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_shadow_register(uint32_t otp)
+{
+ uint32_t result;
+ bool power_up = false;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ /* Check if shadowing of OTP is locked */
+ if (bsec_read_sr_lock(otp)) {
+ VERBOSE("BSEC: OTP %i is locked and will not be refreshed\n",
+ otp);
+ }
+
+ if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
+ result = bsec_power_safmem(true);
+
+ if (result != BSEC_OK) {
+ return result;
+ }
+
+ power_up = true;
+ }
+
+ bsec_lock();
+
+ /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
+ mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_READ);
+
+ while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
+ ;
+ }
+
+ result = bsec_check_error(otp);
+
+ bsec_unlock();
+
+ if (power_up) {
+ if (bsec_power_safmem(false) != BSEC_OK) {
+ panic();
+ }
+ }
+
+ return result;
+}
+
+/*
+ * bsec_read_otp: read an OTP data value.
+ * val: read value.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_read_otp(uint32_t *val, uint32_t otp)
+{
+ uint32_t result;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ bsec_lock();
+
+ *val = mmio_read_32(bsec_base + BSEC_OTP_DATA_OFF +
+ (otp * sizeof(uint32_t)));
+
+ result = bsec_check_error(otp);
+
+ bsec_unlock();
+
+ return result;
+}
+
+/*
+ * bsec_write_otp: write value in BSEC data register.
+ * val: value to write.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_write_otp(uint32_t val, uint32_t otp)
+{
+ uint32_t result;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ /* Check if programming of OTP is locked */
+ if (bsec_read_sw_lock(otp)) {
+ VERBOSE("BSEC: OTP %i is locked and write will be ignored\n",
+ otp);
+ }
+
+ bsec_lock();
+
+ mmio_write_32(bsec_base + BSEC_OTP_DATA_OFF +
+ (otp * sizeof(uint32_t)), val);
+
+ result = bsec_check_error(otp);
+
+ bsec_unlock();
+
+ return result;
+}
+
+/*
+ * bsec_program_otp: program a bit in SAFMEM after the prog.
+ * The OTP data is not refreshed.
+ * val: value to program.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_program_otp(uint32_t val, uint32_t otp)
+{
+ uint32_t result;
+ bool power_up = false;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ /* Check if programming of OTP is locked */
+ if (bsec_read_sp_lock(otp)) {
+ WARN("BSEC: OTP locked, prog will be ignored\n");
+ }
+
+ if ((mmio_read_32(bsec_base + BSEC_OTP_LOCK_OFF) &
+ BIT(BSEC_LOCK_PROGRAM)) != 0U) {
+ WARN("BSEC: GPLOCK activated, prog will be ignored\n");
+ }
+
+ if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
+ result = bsec_power_safmem(true);
+
+ if (result != BSEC_OK) {
+ return result;
+ }
+
+ power_up = true;
+ }
+
+ bsec_lock();
+
+ /* Set value in write register */
+ mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, val);
+
+ /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
+ mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF, otp | BSEC_WRITE);
+
+ while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
+ ;
+ }
+
+ if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
+ result = BSEC_PROG_FAIL;
+ } else {
+ result = bsec_check_error(otp);
+ }
+
+ bsec_unlock();
+
+ if (power_up) {
+ if (bsec_power_safmem(false) != BSEC_OK) {
+ panic();
+ }
+ }
+
+ return result;
+}
+
+/*
+ * bsec_permanent_lock_otp: permanent lock of OTP in SAFMEM.
+ * otp: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_permanent_lock_otp(uint32_t otp)
+{
+ uint32_t result;
+ bool power_up = false;
+ uint32_t data;
+ uint32_t addr;
+
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ if ((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) {
+ result = bsec_power_safmem(true);
+
+ if (result != BSEC_OK) {
+ return result;
+ }
+
+ power_up = true;
+ }
+
+ if (otp < STM32MP1_UPPER_OTP_START) {
+ addr = otp >> ADDR_LOWER_OTP_PERLOCK_SHIFT;
+ data = DATA_LOWER_OTP_PERLOCK_BIT <<
+ ((otp & DATA_LOWER_OTP_PERLOCK_MASK) << 1U);
+ } else {
+ addr = (otp >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U;
+ data = DATA_UPPER_OTP_PERLOCK_BIT <<
+ (otp & DATA_UPPER_OTP_PERLOCK_MASK);
+ }
+
+ bsec_lock();
+
+ /* Set value in write register */
+ mmio_write_32(bsec_base + BSEC_OTP_WRDATA_OFF, data);
+
+ /* Set BSEC_OTP_CTRL_OFF and set ADDR with the OTP value */
+ mmio_write_32(bsec_base + BSEC_OTP_CTRL_OFF,
+ addr | BSEC_WRITE | BSEC_LOCK);
+
+ while ((bsec_get_status() & BSEC_MODE_BUSY_MASK) != 0U) {
+ ;
+ }
+
+ if ((bsec_get_status() & BSEC_MODE_PROGFAIL_MASK) != 0U) {
+ result = BSEC_PROG_FAIL;
+ } else {
+ result = bsec_check_error(otp);
+ }
+
+ bsec_unlock();
+
+ if (power_up) {
+ if (bsec_power_safmem(false) != BSEC_OK) {
+ panic();
+ }
+ }
+
+ return result;
+}
+
+/*
+ * bsec_write_debug_conf: write value in debug feature
+ * to enable/disable debug service.
+ * val: value to write.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_write_debug_conf(uint32_t val)
+{
+ uint32_t result = BSEC_ERROR;
+ uint32_t masked_val = val & BSEC_DEN_ALL_MSK;
+
+ bsec_lock();
+
+ mmio_write_32(bsec_base + BSEC_DEN_OFF, masked_val);
+
+ if ((mmio_read_32(bsec_base + BSEC_DEN_OFF) ^ masked_val) == 0U) {
+ result = BSEC_OK;
+ }
+
+ bsec_unlock();
+
+ return result;
+}
+
+/*
+ * bsec_read_debug_conf: read debug configuration.
+ */
+uint32_t bsec_read_debug_conf(void)
+{
+ return mmio_read_32(bsec_base + BSEC_DEN_OFF);
+}
+
+/*
+ * bsec_get_status: return status register value.
+ */
+uint32_t bsec_get_status(void)
+{
+ return mmio_read_32(bsec_base + BSEC_OTP_STATUS_OFF);
+}
+
+/*
+ * bsec_get_hw_conf: return hardware configuration.
+ */
+uint32_t bsec_get_hw_conf(void)
+{
+ return mmio_read_32(bsec_base + BSEC_IPHW_CFG_OFF);
+}
+
+/*
+ * bsec_get_version: return BSEC version.
+ */
+uint32_t bsec_get_version(void)
+{
+ return mmio_read_32(bsec_base + BSEC_IPVR_OFF);
+}
+
+/*
+ * bsec_get_id: return BSEC ID.
+ */
+uint32_t bsec_get_id(void)
+{
+ return mmio_read_32(bsec_base + BSEC_IP_ID_OFF);
+}
+
+/*
+ * bsec_get_magic_id: return BSEC magic number.
+ */
+uint32_t bsec_get_magic_id(void)
+{
+ return mmio_read_32(bsec_base + BSEC_IP_MAGIC_ID_OFF);
+}
+
+/*
+ * bsec_write_sr_lock: write shadow-read lock.
+ * otp: OTP number.
+ * value: value to write in the register.
+ * Must be always 1.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_write_sr_lock(uint32_t otp, uint32_t value)
+{
+ bool result = false;
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t bank_value;
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+
+ bsec_lock();
+
+ bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
+
+ if ((bank_value & otp_mask) == value) {
+ /*
+ * In case of write don't need to write,
+ * the lock is already set.
+ */
+ if (value != 0U) {
+ result = true;
+ }
+ } else {
+ if (value != 0U) {
+ bank_value = bank_value | otp_mask;
+ } else {
+ bank_value = bank_value & ~otp_mask;
+ }
+
+ /*
+ * We can write 0 in all other OTP
+ * if the lock is activated in one of other OTP.
+ * Write 0 has no effect.
+ */
+ mmio_write_32(bsec_base + BSEC_SRLOCK_OFF + bank, bank_value);
+ result = true;
+ }
+
+ bsec_unlock();
+
+ return result;
+}
+
+/*
+ * bsec_read_sr_lock: read shadow-read lock.
+ * otp: OTP number.
+ * return: true if otp is locked, else false.
+ */
+bool bsec_read_sr_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SRLOCK_OFF + bank);
+
+ return (bank_value & otp_mask) != 0U;
+}
+
+/*
+ * bsec_write_sw_lock: write shadow-write lock.
+ * otp: OTP number.
+ * value: Value to write in the register.
+ * Must be always 1.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_write_sw_lock(uint32_t otp, uint32_t value)
+{
+ bool result = false;
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank_value;
+
+ bsec_lock();
+
+ bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
+
+ if ((bank_value & otp_mask) == value) {
+ /*
+ * In case of write don't need to write,
+ * the lock is already set.
+ */
+ if (value != 0U) {
+ result = true;
+ }
+ } else {
+ if (value != 0U) {
+ bank_value = bank_value | otp_mask;
+ } else {
+ bank_value = bank_value & ~otp_mask;
+ }
+
+ /*
+ * We can write 0 in all other OTP
+ * if the lock is activated in one of other OTP.
+ * Write 0 has no effect.
+ */
+ mmio_write_32(bsec_base + BSEC_SWLOCK_OFF + bank, bank_value);
+ result = true;
+ }
+
+ bsec_unlock();
+
+ return result;
+}
+
+/*
+ * bsec_read_sw_lock: read shadow-write lock.
+ * otp: OTP number.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_read_sw_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SWLOCK_OFF + bank);
+
+ return (bank_value & otp_mask) != 0U;
+}
+
+/*
+ * bsec_write_sp_lock: write shadow-program lock.
+ * otp: OTP number.
+ * value: Value to write in the register.
+ * Must be always 1.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_write_sp_lock(uint32_t otp, uint32_t value)
+{
+ bool result = false;
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t bank_value;
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+
+ bsec_lock();
+
+ bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
+
+ if ((bank_value & otp_mask) == value) {
+ /*
+ * In case of write don't need to write,
+ * the lock is already set.
+ */
+ if (value != 0U) {
+ result = true;
+ }
+ } else {
+ if (value != 0U) {
+ bank_value = bank_value | otp_mask;
+ } else {
+ bank_value = bank_value & ~otp_mask;
+ }
+
+ /*
+ * We can write 0 in all other OTP
+ * if the lock is activated in one of other OTP.
+ * Write 0 has no effect.
+ */
+ mmio_write_32(bsec_base + BSEC_SPLOCK_OFF + bank, bank_value);
+ result = true;
+ }
+
+ bsec_unlock();
+
+ return result;
+}
+
+/*
+ * bsec_read_sp_lock: read shadow-program lock.
+ * otp: OTP number.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_read_sp_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
+ uint32_t bank_value = mmio_read_32(bsec_base + BSEC_SPLOCK_OFF + bank);
+
+ return (bank_value & otp_mask) != 0U;
+}
+
+/*
+ * bsec_wr_lock: Read permanent lock status.
+ * otp: OTP number.
+ * return: true if OTP is locked, else false.
+ */
+bool bsec_wr_lock(uint32_t otp)
+{
+ uint32_t bank = otp_bank_offset(otp);
+ uint32_t lock_bit = BIT(otp & BSEC_OTP_MASK);
+
+ if ((mmio_read_32(bsec_base + BSEC_WRLOCK_OFF + bank) &
+ lock_bit) != 0U) {
+ /*
+ * In case of write don't need to write,
+ * the lock is already set.
+ */
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * bsec_otp_lock: Lock Upper OTP or Global programming or debug enable
+ * service: Service to lock see header file.
+ * value: Value to write must always set to 1 (only use for debug purpose).
+ * return: BSEC_OK if succeed.
+ */
+uint32_t bsec_otp_lock(uint32_t service, uint32_t value)
+{
+ uintptr_t reg = bsec_base + BSEC_OTP_LOCK_OFF;
+
+ switch (service) {
+ case BSEC_LOCK_UPPER_OTP:
+ mmio_write_32(reg, value << BSEC_LOCK_UPPER_OTP);
+ break;
+ case BSEC_LOCK_DEBUG:
+ mmio_write_32(reg, value << BSEC_LOCK_DEBUG);
+ break;
+ case BSEC_LOCK_PROGRAM:
+ mmio_write_32(reg, value << BSEC_LOCK_PROGRAM);
+ break;
+ default:
+ return BSEC_INVALID_PARAM;
+ }
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_power_safmem: Activate or deactivate SAFMEM power.
+ * power: true to power up, false to power down.
+ * return: BSEC_OK if succeed.
+ */
+static uint32_t bsec_power_safmem(bool power)
+{
+ uint32_t register_val;
+ uint32_t timeout = BSEC_TIMEOUT_VALUE;
+
+ bsec_lock();
+
+ register_val = mmio_read_32(bsec_base + BSEC_OTP_CONF_OFF);
+
+ if (power) {
+ register_val |= BSEC_CONF_POWER_UP_MASK;
+ } else {
+ register_val &= ~BSEC_CONF_POWER_UP_MASK;
+ }
+
+ mmio_write_32(bsec_base + BSEC_OTP_CONF_OFF, register_val);
+
+ /* Waiting loop */
+ if (power) {
+ while (((bsec_get_status() & BSEC_MODE_PWR_MASK) == 0U) &&
+ (timeout != 0U)) {
+ timeout--;
+ }
+ } else {
+ while (((bsec_get_status() & BSEC_MODE_PWR_MASK) != 0U) &&
+ (timeout != 0U)) {
+ timeout--;
+ }
+ }
+
+ bsec_unlock();
+
+ if (timeout == 0U) {
+ return BSEC_TIMEOUT;
+ }
+
+ return BSEC_OK;
+}
+
+/*
+ * bsec_mode_is_closed_device: read OTP secure sub-mode.
+ * return: false if open_device and true of closed_device.
+ */
+bool bsec_mode_is_closed_device(void)
+{
+ uint32_t value;
+
+ if ((bsec_shadow_register(DATA0_OTP) != BSEC_OK) ||
+ (bsec_read_otp(&value, DATA0_OTP) != BSEC_OK)) {
+ return true;
+ }
+
+ return (value & DATA0_OTP_SECURED) == DATA0_OTP_SECURED;
+}
+
+/*
+ * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value
+ * otp_value: read value.
+ * word: OTP number.
+ * return value: BSEC_OK if no error.
+ */
+uint32_t bsec_shadow_read_otp(uint32_t *otp_value, uint32_t word)
+{
+ uint32_t result;
+
+ result = bsec_shadow_register(word);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Shadowing Error %i\n", word, result);
+ return result;
+ }
+
+ result = bsec_read_otp(otp_value, word);
+ if (result != BSEC_OK) {
+ ERROR("BSEC: %u Read Error %i\n", word, result);
+ }
+
+ return result;
+}
+
+/*
+ * bsec_check_nsec_access_rights: check non-secure access rights to target OTP.
+ * otp: OTP number.
+ * return: BSEC_OK if authorized access.
+ */
+uint32_t bsec_check_nsec_access_rights(uint32_t otp)
+{
+#if defined(IMAGE_BL32)
+ if (otp > STM32MP1_OTP_MAX_ID) {
+ return BSEC_INVALID_PARAM;
+ }
+
+ if (otp >= STM32MP1_UPPER_OTP_START) {
+ /* Check if BSEC is in OTP-SECURED closed_device state. */
+ if (bsec_mode_is_closed_device()) {
+ if (!non_secure_can_access(otp)) {
+ return BSEC_ERROR;
+ }
+ }
+ }
+#endif
+
+ return BSEC_OK;
+}
+
diff --git a/drivers/st/clk/stm32mp1_clkfunc.c b/drivers/st/clk/stm32mp1_clkfunc.c
index 1d9227106..19dfe1b25 100644
--- a/drivers/st/clk/stm32mp1_clkfunc.c
+++ b/drivers/st/clk/stm32mp1_clkfunc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -32,10 +32,18 @@ const char *stm32mp_osc_node_label[NB_OSC] = {
};
/*******************************************************************************
+ * This function returns the RCC node in the device tree.
+ ******************************************************************************/
+static int fdt_get_rcc_node(void *fdt)
+{
+ return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+}
+
+/*******************************************************************************
* This function reads the frequency of an oscillator from its name.
* It reads the value indicated inside the device tree.
- * Returns 0 if success, and a negative value else.
- * If success, value is stored in the second parameter.
+ * Returns 0 on success, and a negative FDT/ERRNO error code on failure.
+ * On success, value is stored in the second parameter.
******************************************************************************/
int fdt_osc_read_freq(const char *name, uint32_t *freq)
{
@@ -127,7 +135,7 @@ bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name)
/*******************************************************************************
* This function reads a value of a oscillator property from its id.
- * Returns value if success, and a default value if property not found.
+ * Returns value on success, and a default value if property not found.
* Default value is passed as parameter.
******************************************************************************/
uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id,
@@ -240,7 +248,7 @@ int fdt_rcc_read_uint32_array(const char *prop_name,
/*******************************************************************************
* This function gets the subnode offset in rcc-clk section from its name.
* It reads the values indicated inside the device tree.
- * Returns offset if success, and a negative value else.
+ * Returns offset on success, and a negative FDT/ERRNO error code on failure.
******************************************************************************/
int fdt_rcc_subnode_offset(const char *name)
{
@@ -251,7 +259,7 @@ int fdt_rcc_subnode_offset(const char *name)
return -ENOENT;
}
- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+ node = fdt_get_rcc_node(fdt);
if (node < 0) {
return -FDT_ERR_NOTFOUND;
}
@@ -280,7 +288,7 @@ const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
return NULL;
}
- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT);
+ node = fdt_get_rcc_node(fdt);
if (node < 0) {
return NULL;
}
@@ -297,7 +305,7 @@ const fdt32_t *fdt_rcc_read_prop(const char *prop_name, int *lenp)
/*******************************************************************************
* This function gets the secure status for rcc node.
* It reads secure-status in device tree.
- * Returns 1 if rcc is available from secure world, 0 else.
+ * Returns true if rcc is available from secure world, false if not.
******************************************************************************/
bool fdt_get_rcc_secure_status(void)
{
@@ -308,18 +316,18 @@ bool fdt_get_rcc_secure_status(void)
return false;
}
- node = fdt_node_offset_by_compatible(fdt, -1, DT_RCC_COMPAT);
+ node = fdt_get_rcc_node(fdt);
if (node < 0) {
return false;
}
- return fdt_check_secure_status(node);
+ return (fdt_get_status(node) & DT_SECURE) != 0U;
}
/*******************************************************************************
* This function reads the stgen base address.
* It reads the value indicated inside the device tree.
- * Returns address if success, and NULL value else.
+ * Returns address on success, and NULL value on failure.
******************************************************************************/
uintptr_t fdt_get_stgen_base(void)
{
@@ -347,7 +355,7 @@ uintptr_t fdt_get_stgen_base(void)
/*******************************************************************************
* This function gets the clock ID of the given node.
* It reads the value indicated inside the device tree.
- * Returns ID if success, and a negative value else.
+ * Returns ID on success, and a negative FDT/ERRNO error code on failure.
******************************************************************************/
int fdt_get_clock_id(int node)
{
diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c
index aca04504f..79aff6e73 100644
--- a/drivers/st/ddr/stm32mp1_ddr.c
+++ b/drivers/st/ddr/stm32mp1_ddr.c
@@ -1,9 +1,10 @@
/*
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
+#include <errno.h>
#include <stddef.h>
#include <platform_def.h>
@@ -12,10 +13,10 @@
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp_pmic.h>
#include <drivers/st/stm32mp1_clk.h>
#include <drivers/st/stm32mp1_ddr.h>
#include <drivers/st/stm32mp1_ddr_regs.h>
-#include <drivers/st/stm32mp1_pmic.h>
#include <drivers/st/stm32mp1_pwr.h>
#include <drivers/st/stm32mp1_ram.h>
#include <drivers/st/stm32mp1_rcc.h>
@@ -233,40 +234,67 @@ struct ddr_reg_info {
static const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = {
[REG_REG] = {
- "static", ddr_reg, ARRAY_SIZE(ddr_reg), DDR_BASE
+ .name = "static",
+ .desc = ddr_reg,
+ .size = ARRAY_SIZE(ddr_reg),
+ .base = DDR_BASE
},
[REG_TIMING] = {
- "timing", ddr_timing, ARRAY_SIZE(ddr_timing), DDR_BASE
+ .name = "timing",
+ .desc = ddr_timing,
+ .size = ARRAY_SIZE(ddr_timing),
+ .base = DDR_BASE
},
[REG_PERF] = {
- "perf", ddr_perf, ARRAY_SIZE(ddr_perf), DDR_BASE
+ .name = "perf",
+ .desc = ddr_perf,
+ .size = ARRAY_SIZE(ddr_perf),
+ .base = DDR_BASE
},
[REG_MAP] = {
- "map", ddr_map, ARRAY_SIZE(ddr_map), DDR_BASE
+ .name = "map",
+ .desc = ddr_map,
+ .size = ARRAY_SIZE(ddr_map),
+ .base = DDR_BASE
},
[REGPHY_REG] = {
- "static", ddrphy_reg, ARRAY_SIZE(ddrphy_reg), DDRPHY_BASE
+ .name = "static",
+ .desc = ddrphy_reg,
+ .size = ARRAY_SIZE(ddrphy_reg),
+ .base = DDRPHY_BASE
},
[REGPHY_TIMING] = {
- "timing", ddrphy_timing, ARRAY_SIZE(ddrphy_timing), DDRPHY_BASE
+ .name = "timing",
+ .desc = ddrphy_timing,
+ .size = ARRAY_SIZE(ddrphy_timing),
+ .base = DDRPHY_BASE
},
[REGPHY_CAL] = {
- "cal", ddrphy_cal, ARRAY_SIZE(ddrphy_cal), DDRPHY_BASE
+ .name = "cal",
+ .desc = ddrphy_cal,
+ .size = ARRAY_SIZE(ddrphy_cal),
+ .base = DDRPHY_BASE
},
[REG_DYN] = {
- "dyn", ddr_dyn, ARRAY_SIZE(ddr_dyn), DDR_BASE
+ .name = "dyn",
+ .desc = ddr_dyn,
+ .size = ARRAY_SIZE(ddr_dyn),
+ .base = DDR_BASE
},
[REGPHY_DYN] = {
- "dyn", ddrphy_dyn, ARRAY_SIZE(ddrphy_dyn), DDRPHY_BASE
+ .name = "dyn",
+ .desc = ddrphy_dyn,
+ .size = ARRAY_SIZE(ddrphy_dyn),
+ .base = DDRPHY_BASE
},
};
-static uint32_t get_base_addr(const struct ddr_info *priv, enum base_type base)
+static uintptr_t get_base_addr(const struct ddr_info *priv, enum base_type base)
{
if (base == DDRPHY_BASE) {
- return (uint32_t)priv->phy;
+ return (uintptr_t)priv->phy;
} else {
- return (uint32_t)priv->ctl;
+ return (uintptr_t)priv->ctl;
}
}
@@ -275,21 +303,22 @@ static void set_reg(const struct ddr_info *priv,
const void *param)
{
unsigned int i;
- unsigned int *ptr, value;
+ unsigned int value;
enum base_type base = ddr_registers[type].base;
- uint32_t base_addr = get_base_addr(priv, base);
+ uintptr_t base_addr = get_base_addr(priv, base);
const struct reg_desc *desc = ddr_registers[type].desc;
VERBOSE("init %s\n", ddr_registers[type].name);
for (i = 0; i < ddr_registers[type].size; i++) {
- ptr = (unsigned int *)(base_addr + desc[i].offset);
+ uintptr_t ptr = base_addr + desc[i].offset;
+
if (desc[i].par_offset == INVALID_OFFSET) {
ERROR("invalid parameter offset for %s", desc[i].name);
panic();
} else {
- value = *((uint32_t *)((uint32_t)param +
+ value = *((uint32_t *)((uintptr_t)param +
desc[i].par_offset));
- mmio_write_32((uint32_t)ptr, value);
+ mmio_write_32(ptr, value);
}
}
}
@@ -305,15 +334,15 @@ static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
time0 = start;
do {
- pgsr = mmio_read_32((uint32_t)&phy->pgsr);
+ pgsr = mmio_read_32((uintptr_t)&phy->pgsr);
time = get_timer(start);
if (time != time0) {
- VERBOSE(" > [0x%x] pgsr = 0x%x &\n",
- (uint32_t)&phy->pgsr, pgsr);
- VERBOSE(" [0x%x] pir = 0x%x (time=%x)\n",
- (uint32_t)&phy->pir,
- mmio_read_32((uint32_t)&phy->pir),
- (uint32_t)time);
+ VERBOSE(" > [0x%lx] pgsr = 0x%x &\n",
+ (uintptr_t)&phy->pgsr, pgsr);
+ VERBOSE(" [0x%lx] pir = 0x%x (time=%lx)\n",
+ (uintptr_t)&phy->pir,
+ mmio_read_32((uintptr_t)&phy->pir),
+ time);
}
time0 = time;
@@ -341,18 +370,18 @@ static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy)
error++;
}
} while ((pgsr & DDRPHYC_PGSR_IDONE) == 0U && error == 0);
- VERBOSE("\n[0x%x] pgsr = 0x%x\n",
- (uint32_t)&phy->pgsr, pgsr);
+ VERBOSE("\n[0x%lx] pgsr = 0x%x\n",
+ (uintptr_t)&phy->pgsr, pgsr);
}
static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, uint32_t pir)
{
uint32_t pir_init = pir | DDRPHYC_PIR_INIT;
- mmio_write_32((uint32_t)&phy->pir, pir_init);
- VERBOSE("[0x%x] pir = 0x%x -> 0x%x\n",
- (uint32_t)&phy->pir, pir_init,
- mmio_read_32((uint32_t)&phy->pir));
+ mmio_write_32((uintptr_t)&phy->pir, pir_init);
+ VERBOSE("[0x%lx] pir = 0x%x -> 0x%x\n",
+ (uintptr_t)&phy->pir, pir_init,
+ mmio_read_32((uintptr_t)&phy->pir));
/* Need to wait 10 configuration clock before start polling */
udelay(10);
@@ -364,9 +393,9 @@ static void stm32mp1_ddrphy_init(struct stm32mp1_ddrphy *phy, uint32_t pir)
/* Start quasi dynamic register update */
static void stm32mp1_start_sw_done(struct stm32mp1_ddrctl *ctl)
{
- mmio_clrbits_32((uint32_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
- VERBOSE("[0x%x] swctl = 0x%x\n",
- (uint32_t)&ctl->swctl, mmio_read_32((uint32_t)&ctl->swctl));
+ mmio_clrbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
+ VERBOSE("[0x%lx] swctl = 0x%x\n",
+ (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl));
}
/* Wait quasi dynamic register update */
@@ -375,15 +404,15 @@ static void stm32mp1_wait_sw_done_ack(struct stm32mp1_ddrctl *ctl)
unsigned long start;
uint32_t swstat;
- mmio_setbits_32((uint32_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
- VERBOSE("[0x%x] swctl = 0x%x\n",
- (uint32_t)&ctl->swctl, mmio_read_32((uint32_t)&ctl->swctl));
+ mmio_setbits_32((uintptr_t)&ctl->swctl, DDRCTRL_SWCTL_SW_DONE);
+ VERBOSE("[0x%lx] swctl = 0x%x\n",
+ (uintptr_t)&ctl->swctl, mmio_read_32((uintptr_t)&ctl->swctl));
start = get_timer(0);
do {
- swstat = mmio_read_32((uint32_t)&ctl->swstat);
- VERBOSE("[0x%x] swstat = 0x%x ",
- (uint32_t)&ctl->swstat, swstat);
+ swstat = mmio_read_32((uintptr_t)&ctl->swstat);
+ VERBOSE("[0x%lx] swstat = 0x%x ",
+ (uintptr_t)&ctl->swstat, swstat);
VERBOSE("timer in ms 0x%x = start 0x%lx\r",
get_timer(0), start);
if (get_timer(start) > plat_get_syscnt_freq2()) {
@@ -391,8 +420,8 @@ static void stm32mp1_wait_sw_done_ack(struct stm32mp1_ddrctl *ctl)
}
} while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U);
- VERBOSE("[0x%x] swstat = 0x%x\n",
- (uint32_t)&ctl->swstat, swstat);
+ VERBOSE("[0x%lx] swstat = 0x%x\n",
+ (uintptr_t)&ctl->swstat, swstat);
}
/* Wait quasi dynamic register update */
@@ -406,11 +435,11 @@ static void stm32mp1_wait_operating_mode(struct ddr_info *priv, uint32_t mode)
start = get_timer(0);
for ( ; ; ) {
- stat = mmio_read_32((uint32_t)&priv->ctl->stat);
+ stat = mmio_read_32((uintptr_t)&priv->ctl->stat);
operating_mode = stat & DDRCTRL_STAT_OPERATING_MODE_MASK;
selref_type = stat & DDRCTRL_STAT_SELFREF_TYPE_MASK;
- VERBOSE("[0x%x] stat = 0x%x\n",
- (uint32_t)&priv->ctl->stat, stat);
+ VERBOSE("[0x%lx] stat = 0x%x\n",
+ (uintptr_t)&priv->ctl->stat, stat);
VERBOSE("timer in ms 0x%x = start 0x%lx\r",
get_timer(0), start);
if (get_timer(start) > plat_get_syscnt_freq2()) {
@@ -441,8 +470,8 @@ static void stm32mp1_wait_operating_mode(struct ddr_info *priv, uint32_t mode)
}
}
- VERBOSE("[0x%x] stat = 0x%x\n",
- (uint32_t)&priv->ctl->stat, stat);
+ VERBOSE("[0x%lx] stat = 0x%x\n",
+ (uintptr_t)&priv->ctl->stat, stat);
}
/* Mode Register Writes (MRW or MRS) */
@@ -459,7 +488,7 @@ static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr,
* No write should be performed to MRCTRL0 and MRCTRL1
* if MRSTAT.mr_wr_busy = 1.
*/
- while ((mmio_read_32((uint32_t)&priv->ctl->mrstat) &
+ while ((mmio_read_32((uintptr_t)&priv->ctl->mrstat) &
DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) {
;
}
@@ -472,14 +501,14 @@ static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr,
DDRCTRL_MRCTRL0_MR_RANK_ALL |
(((uint32_t)addr << DDRCTRL_MRCTRL0_MR_ADDR_SHIFT) &
DDRCTRL_MRCTRL0_MR_ADDR_MASK);
- mmio_write_32((uint32_t)&priv->ctl->mrctrl0, mrctrl0);
- VERBOSE("[0x%x] mrctrl0 = 0x%x (0x%x)\n",
- (uint32_t)&priv->ctl->mrctrl0,
- mmio_read_32((uint32_t)&priv->ctl->mrctrl0), mrctrl0);
- mmio_write_32((uint32_t)&priv->ctl->mrctrl1, data);
- VERBOSE("[0x%x] mrctrl1 = 0x%x\n",
- (uint32_t)&priv->ctl->mrctrl1,
- mmio_read_32((uint32_t)&priv->ctl->mrctrl1));
+ mmio_write_32((uintptr_t)&priv->ctl->mrctrl0, mrctrl0);
+ VERBOSE("[0x%lx] mrctrl0 = 0x%x (0x%x)\n",
+ (uintptr_t)&priv->ctl->mrctrl0,
+ mmio_read_32((uintptr_t)&priv->ctl->mrctrl0), mrctrl0);
+ mmio_write_32((uintptr_t)&priv->ctl->mrctrl1, data);
+ VERBOSE("[0x%lx] mrctrl1 = 0x%x\n",
+ (uintptr_t)&priv->ctl->mrctrl1,
+ mmio_read_32((uintptr_t)&priv->ctl->mrctrl1));
/*
* 3. In a separate APB transaction, write the MRCTRL0.mr_wr to 1. This
@@ -489,22 +518,22 @@ static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr,
* initiated until it is deasserted.
*/
mrctrl0 |= DDRCTRL_MRCTRL0_MR_WR;
- mmio_write_32((uint32_t)&priv->ctl->mrctrl0, mrctrl0);
+ mmio_write_32((uintptr_t)&priv->ctl->mrctrl0, mrctrl0);
- while ((mmio_read_32((uint32_t)&priv->ctl->mrstat) &
+ while ((mmio_read_32((uintptr_t)&priv->ctl->mrstat) &
DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) {
;
}
- VERBOSE("[0x%x] mrctrl0 = 0x%x\n",
- (uint32_t)&priv->ctl->mrctrl0, mrctrl0);
+ VERBOSE("[0x%lx] mrctrl0 = 0x%x\n",
+ (uintptr_t)&priv->ctl->mrctrl0, mrctrl0);
}
/* Switch DDR3 from DLL-on to DLL-off */
static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
{
- uint32_t mr1 = mmio_read_32((uint32_t)&priv->phy->mr1);
- uint32_t mr2 = mmio_read_32((uint32_t)&priv->phy->mr2);
+ uint32_t mr1 = mmio_read_32((uintptr_t)&priv->phy->mr1);
+ uint32_t mr2 = mmio_read_32((uintptr_t)&priv->phy->mr2);
uint32_t dbgcam;
VERBOSE("mr1: 0x%x\n", mr1);
@@ -514,10 +543,10 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
* 1. Set the DBG1.dis_hif = 1.
* This prevents further reads/writes being received on the HIF.
*/
- mmio_setbits_32((uint32_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF);
- VERBOSE("[0x%x] dbg1 = 0x%x\n",
- (uint32_t)&priv->ctl->dbg1,
- mmio_read_32((uint32_t)&priv->ctl->dbg1));
+ mmio_setbits_32((uintptr_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF);
+ VERBOSE("[0x%lx] dbg1 = 0x%x\n",
+ (uintptr_t)&priv->ctl->dbg1,
+ mmio_read_32((uintptr_t)&priv->ctl->dbg1));
/*
* 2. Ensure all commands have been flushed from the uMCTL2 by polling
@@ -528,9 +557,9 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
* DBGCAM.dbg_hpr_q_depth = 0.
*/
do {
- dbgcam = mmio_read_32((uint32_t)&priv->ctl->dbgcam);
- VERBOSE("[0x%x] dbgcam = 0x%x\n",
- (uint32_t)&priv->ctl->dbgcam, dbgcam);
+ dbgcam = mmio_read_32((uintptr_t)&priv->ctl->dbgcam);
+ VERBOSE("[0x%lx] dbgcam = 0x%x\n",
+ (uintptr_t)&priv->ctl->dbgcam, dbgcam);
} while ((((dbgcam & DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY) ==
DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY)) &&
((dbgcam & DDRCTRL_DBGCAM_DBG_Q_DEPTH) == 0U));
@@ -574,11 +603,11 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
* PWRCTL.selfref_sw = 1, and polling STAT.operating_mode to ensure
* the DDRC has entered self-refresh.
*/
- mmio_setbits_32((uint32_t)&priv->ctl->pwrctl,
+ mmio_setbits_32((uintptr_t)&priv->ctl->pwrctl,
DDRCTRL_PWRCTL_SELFREF_SW);
- VERBOSE("[0x%x] pwrctl = 0x%x\n",
- (uint32_t)&priv->ctl->pwrctl,
- mmio_read_32((uint32_t)&priv->ctl->pwrctl));
+ VERBOSE("[0x%lx] pwrctl = 0x%x\n",
+ (uintptr_t)&priv->ctl->pwrctl,
+ mmio_read_32((uintptr_t)&priv->ctl->pwrctl));
/*
* 8. Wait until STAT.operating_mode[1:0]==11 indicating that the
@@ -594,10 +623,10 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
*/
stm32mp1_start_sw_done(priv->ctl);
- mmio_setbits_32((uint32_t)&priv->ctl->mstr, DDRCTRL_MSTR_DLL_OFF_MODE);
- VERBOSE("[0x%x] mstr = 0x%x\n",
- (uint32_t)&priv->ctl->mstr,
- mmio_read_32((uint32_t)&priv->ctl->mstr));
+ mmio_setbits_32((uintptr_t)&priv->ctl->mstr, DDRCTRL_MSTR_DLL_OFF_MODE);
+ VERBOSE("[0x%lx] mstr = 0x%x\n",
+ (uintptr_t)&priv->ctl->mstr,
+ mmio_read_32((uintptr_t)&priv->ctl->mstr));
stm32mp1_wait_sw_done_ack(priv->ctl);
@@ -611,26 +640,26 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
/* Change Bypass Mode Frequency Range */
if (stm32mp1_clk_get_rate(DDRPHYC) < 100000000U) {
- mmio_clrbits_32((uint32_t)&priv->phy->dllgcr,
+ mmio_clrbits_32((uintptr_t)&priv->phy->dllgcr,
DDRPHYC_DLLGCR_BPS200);
} else {
- mmio_setbits_32((uint32_t)&priv->phy->dllgcr,
+ mmio_setbits_32((uintptr_t)&priv->phy->dllgcr,
DDRPHYC_DLLGCR_BPS200);
}
- mmio_setbits_32((uint32_t)&priv->phy->acdllcr, DDRPHYC_ACDLLCR_DLLDIS);
+ mmio_setbits_32((uintptr_t)&priv->phy->acdllcr, DDRPHYC_ACDLLCR_DLLDIS);
- mmio_setbits_32((uint32_t)&priv->phy->dx0dllcr,
+ mmio_setbits_32((uintptr_t)&priv->phy->dx0dllcr,
DDRPHYC_DXNDLLCR_DLLDIS);
- mmio_setbits_32((uint32_t)&priv->phy->dx1dllcr,
+ mmio_setbits_32((uintptr_t)&priv->phy->dx1dllcr,
DDRPHYC_DXNDLLCR_DLLDIS);
- mmio_setbits_32((uint32_t)&priv->phy->dx2dllcr,
+ mmio_setbits_32((uintptr_t)&priv->phy->dx2dllcr,
DDRPHYC_DXNDLLCR_DLLDIS);
- mmio_setbits_32((uint32_t)&priv->phy->dx3dllcr,
+ mmio_setbits_32((uintptr_t)&priv->phy->dx3dllcr,
DDRPHYC_DXNDLLCR_DLLDIS);
/* 12. Exit the self-refresh state by setting PWRCTL.selfref_sw = 0. */
- mmio_clrbits_32((uint32_t)&priv->ctl->pwrctl,
+ mmio_clrbits_32((uintptr_t)&priv->ctl->pwrctl,
DDRCTRL_PWRCTL_SELFREF_SW);
stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
@@ -646,20 +675,20 @@ static void stm32mp1_ddr3_dll_off(struct ddr_info *priv)
*/
/* 15. Write DBG1.dis_hif = 0 to re-enable reads and writes. */
- mmio_clrbits_32((uint32_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF);
- VERBOSE("[0x%x] dbg1 = 0x%x\n",
- (uint32_t)&priv->ctl->dbg1,
- mmio_read_32((uint32_t)&priv->ctl->dbg1));
+ mmio_clrbits_32((uintptr_t)&priv->ctl->dbg1, DDRCTRL_DBG1_DIS_HIF);
+ VERBOSE("[0x%lx] dbg1 = 0x%x\n",
+ (uintptr_t)&priv->ctl->dbg1,
+ mmio_read_32((uintptr_t)&priv->ctl->dbg1));
}
static void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
{
stm32mp1_start_sw_done(ctl);
/* Quasi-dynamic register update*/
- mmio_setbits_32((uint32_t)&ctl->rfshctl3,
+ mmio_setbits_32((uintptr_t)&ctl->rfshctl3,
DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
- mmio_clrbits_32((uint32_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
- mmio_clrbits_32((uint32_t)&ctl->dfimisc,
+ mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
+ mmio_clrbits_32((uintptr_t)&ctl->dfimisc,
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
stm32mp1_wait_sw_done_ack(ctl);
}
@@ -669,14 +698,14 @@ static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
{
stm32mp1_start_sw_done(ctl);
if ((rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH) == 0U) {
- mmio_clrbits_32((uint32_t)&ctl->rfshctl3,
+ mmio_clrbits_32((uintptr_t)&ctl->rfshctl3,
DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
}
if ((pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN) != 0U) {
- mmio_setbits_32((uint32_t)&ctl->pwrctl,
+ mmio_setbits_32((uintptr_t)&ctl->pwrctl,
DDRCTRL_PWRCTL_POWERDOWN_EN);
}
- mmio_setbits_32((uint32_t)&ctl->dfimisc,
+ mmio_setbits_32((uintptr_t)&ctl->dfimisc,
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
stm32mp1_wait_sw_done_ack(ctl);
}
@@ -694,12 +723,14 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
struct stm32mp1_ddr_config *config)
{
uint32_t pir;
- int ret;
+ int ret = -EINVAL;
if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) {
ret = board_ddr_power_init(STM32MP_DDR3);
- } else {
+ } else if ((config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) != 0U) {
ret = board_ddr_power_init(STM32MP_LPDDR2);
+ } else {
+ ERROR("DDR type not supported\n");
}
if (ret != 0) {
@@ -707,7 +738,7 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
}
VERBOSE("name = %s\n", config->info.name);
- VERBOSE("speed = %d MHz\n", config->info.speed);
+ VERBOSE("speed = %d kHz\n", config->info.speed);
VERBOSE("size = 0x%x\n", config->info.size);
/* DDR INIT SEQUENCE */
@@ -746,11 +777,11 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
/* 1.5. initialize registers ddr_umctl2 */
/* Stop uMCTL2 before PHY is ready */
- mmio_clrbits_32((uint32_t)&priv->ctl->dfimisc,
+ mmio_clrbits_32((uintptr_t)&priv->ctl->dfimisc,
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
- VERBOSE("[0x%x] dfimisc = 0x%x\n",
- (uint32_t)&priv->ctl->dfimisc,
- mmio_read_32((uint32_t)&priv->ctl->dfimisc));
+ VERBOSE("[0x%lx] dfimisc = 0x%x\n",
+ (uintptr_t)&priv->ctl->dfimisc,
+ mmio_read_32((uintptr_t)&priv->ctl->dfimisc));
set_reg(priv, REG_REG, &config->c_reg);
@@ -759,23 +790,23 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
(DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE))
== (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) {
VERBOSE("deactivate DLL OFF in mstr\n");
- mmio_clrbits_32((uint32_t)&priv->ctl->mstr,
+ mmio_clrbits_32((uintptr_t)&priv->ctl->mstr,
DDRCTRL_MSTR_DLL_OFF_MODE);
- VERBOSE("[0x%x] mstr = 0x%x\n",
- (uint32_t)&priv->ctl->mstr,
- mmio_read_32((uint32_t)&priv->ctl->mstr));
+ VERBOSE("[0x%lx] mstr = 0x%x\n",
+ (uintptr_t)&priv->ctl->mstr,
+ mmio_read_32((uintptr_t)&priv->ctl->mstr));
}
set_reg(priv, REG_TIMING, &config->c_timing);
set_reg(priv, REG_MAP, &config->c_map);
/* Skip CTRL init, SDRAM init is done by PHY PUBL */
- mmio_clrsetbits_32((uint32_t)&priv->ctl->init0,
+ mmio_clrsetbits_32((uintptr_t)&priv->ctl->init0,
DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK,
DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL);
- VERBOSE("[0x%x] init0 = 0x%x\n",
- (uint32_t)&priv->ctl->init0,
- mmio_read_32((uint32_t)&priv->ctl->init0));
+ VERBOSE("[0x%lx] init0 = 0x%x\n",
+ (uintptr_t)&priv->ctl->init0,
+ mmio_read_32((uintptr_t)&priv->ctl->init0));
set_reg(priv, REG_PERF, &config->c_perf);
@@ -797,10 +828,10 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
(DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE))
== (DDRCTRL_MSTR_DDR3 | DDRCTRL_MSTR_DLL_OFF_MODE)) {
VERBOSE("deactivate DLL OFF in mr1\n");
- mmio_clrbits_32((uint32_t)&priv->phy->mr1, BIT(0));
- VERBOSE("[0x%x] mr1 = 0x%x\n",
- (uint32_t)&priv->phy->mr1,
- mmio_read_32((uint32_t)&priv->phy->mr1));
+ mmio_clrbits_32((uintptr_t)&priv->phy->mr1, BIT(0));
+ VERBOSE("[0x%lx] mr1 = 0x%x\n",
+ (uintptr_t)&priv->phy->mr1,
+ mmio_read_32((uintptr_t)&priv->phy->mr1));
}
/*
@@ -830,11 +861,11 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
*/
stm32mp1_start_sw_done(priv->ctl);
- mmio_setbits_32((uint32_t)&priv->ctl->dfimisc,
+ mmio_setbits_32((uintptr_t)&priv->ctl->dfimisc,
DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
- VERBOSE("[0x%x] dfimisc = 0x%x\n",
- (uint32_t)&priv->ctl->dfimisc,
- mmio_read_32((uint32_t)&priv->ctl->dfimisc));
+ VERBOSE("[0x%lx] dfimisc = 0x%x\n",
+ (uintptr_t)&priv->ctl->dfimisc,
+ mmio_read_32((uintptr_t)&priv->ctl->dfimisc));
stm32mp1_wait_sw_done_ack(priv->ctl);
@@ -884,14 +915,16 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
config->c_reg.pwrctl);
/* Enable uMCTL2 AXI port 0 */
- mmio_setbits_32((uint32_t)&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
- VERBOSE("[0x%x] pctrl_0 = 0x%x\n",
- (uint32_t)&priv->ctl->pctrl_0,
- mmio_read_32((uint32_t)&priv->ctl->pctrl_0));
+ mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_0,
+ DDRCTRL_PCTRL_N_PORT_EN);
+ VERBOSE("[0x%lx] pctrl_0 = 0x%x\n",
+ (uintptr_t)&priv->ctl->pctrl_0,
+ mmio_read_32((uintptr_t)&priv->ctl->pctrl_0));
/* Enable uMCTL2 AXI port 1 */
- mmio_setbits_32((uint32_t)&priv->ctl->pctrl_1, DDRCTRL_PCTRL_N_PORT_EN);
- VERBOSE("[0x%x] pctrl_1 = 0x%x\n",
- (uint32_t)&priv->ctl->pctrl_1,
- mmio_read_32((uint32_t)&priv->ctl->pctrl_1));
+ mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_1,
+ DDRCTRL_PCTRL_N_PORT_EN);
+ VERBOSE("[0x%lx] pctrl_1 = 0x%x\n",
+ (uintptr_t)&priv->ctl->pctrl_1,
+ mmio_read_32((uintptr_t)&priv->ctl->pctrl_1));
}
diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c
index 127b6c7c1..e65fbeaa2 100644
--- a/drivers/st/ddr/stm32mp1_ram.c
+++ b/drivers/st/ddr/stm32mp1_ram.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
*/
@@ -25,7 +25,7 @@
static struct ddr_info ddr_priv_data;
-int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
+int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed)
{
unsigned long ddrphy_clk, ddr_clk, mem_speed_hz;
@@ -33,10 +33,10 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
ddrphy_clk = stm32mp1_clk_get_rate(DDRPHYC);
- VERBOSE("DDR: mem_speed (%d MHz), RCC %ld MHz\n",
- mem_speed, ddrphy_clk / 1000U / 1000U);
+ VERBOSE("DDR: mem_speed (%d kHz), RCC %ld kHz\n",
+ mem_speed, ddrphy_clk / 1000U);
- mem_speed_hz = (uint32_t)mem_speed * 1000U * 1000U;
+ mem_speed_hz = mem_speed * 1000U;
/* Max 10% frequency delta */
if (ddrphy_clk > mem_speed_hz) {
@@ -44,9 +44,9 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint16_t mem_speed)
} else {
ddr_clk = mem_speed_hz - ddrphy_clk;
}
- if (ddr_clk > mem_speed_hz) {
- ERROR("DDR expected freq %d MHz, current is %ld MHz\n",
- mem_speed, ddrphy_clk / 1000U / 1000U);
+ if (ddr_clk > (mem_speed_hz / 10)) {
+ ERROR("DDR expected freq %d kHz, current is %ld kHz\n",
+ mem_speed, ddrphy_clk / 1000U);
return -1;
}
return 0;
@@ -208,11 +208,16 @@ static int stm32mp1_ddr_setup(void)
return -EINVAL;
}
- config.info.speed =
- (uint16_t)fdt_read_uint32_default(node, "st,mem-speed",
- STM32MP1_DDR_SPEED_DFLT);
- config.info.size = fdt_read_uint32_default(node, "st,mem-size",
- STM32MP1_DDR_SIZE_DFLT);
+ config.info.speed = fdt_read_uint32_default(node, "st,mem-speed", 0);
+ if (!config.info.speed) {
+ VERBOSE("%s: no st,mem-speed\n", __func__);
+ return -EINVAL;
+ }
+ config.info.size = fdt_read_uint32_default(node, "st,mem-size", 0);
+ if (!config.info.size) {
+ VERBOSE("%s: no st,mem-size\n", __func__);
+ return -EINVAL;
+ }
config.info.name = fdt_getprop(fdt, node, "st,mem-name", &len);
if (config.info.name == NULL) {
VERBOSE("%s: no st,mem-name\n", __func__);
@@ -222,7 +227,7 @@ static int stm32mp1_ddr_setup(void)
for (idx = 0; idx < ARRAY_SIZE(param); idx++) {
ret = fdt_read_uint32_array(node, param[idx].name,
- (void *)((uint32_t)&config +
+ (void *)((uintptr_t)&config +
param[idx].offset),
param[idx].size);
@@ -261,8 +266,8 @@ static int stm32mp1_ddr_setup(void)
VERBOSE("%s : ram size(%x, %x)\n", __func__,
(uint32_t)priv->info.base, (uint32_t)priv->info.size);
- dcsw_op_all(DC_OP_CISW);
write_sctlr(read_sctlr() & ~SCTLR_C_BIT);
+ dcsw_op_all(DC_OP_CISW);
uret = ddr_test_data_bus();
if (uret != 0U) {
diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c
index 9591e3738..d217c4501 100644
--- a/drivers/st/gpio/stm32_gpio.c
+++ b/drivers/st/gpio/stm32_gpio.c
@@ -1,87 +1,276 @@
/*
- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+#include <assert.h>
+#include <errno.h>
#include <stdbool.h>
+#include <libfdt.h>
+
+#include <platform_def.h>
+
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/st/stm32_gpio.h>
+#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/st/stm32mp1_clkfunc.h>
#include <lib/mmio.h>
+#include <lib/utils_def.h>
-static bool check_gpio(uint32_t bank, uint32_t pin)
+#define DT_GPIO_BANK_SHIFT 12
+#define DT_GPIO_BANK_MASK GENMASK(16, 12)
+#define DT_GPIO_PIN_SHIFT 8
+#define DT_GPIO_PIN_MASK GENMASK(11, 8)
+#define DT_GPIO_MODE_MASK GENMASK(7, 0)
+
+/*******************************************************************************
+ * This function gets GPIO bank node in DT.
+ * Returns node offset if status is okay in DT, else return 0
+ ******************************************************************************/
+static int ckeck_gpio_bank(void *fdt, uint32_t bank, int pinctrl_node)
{
- if (pin > GPIO_PIN_MAX) {
- ERROR("%s: wrong pin number (%d)\n", __func__, pin);
- return false;
- }
+ int pinctrl_subnode;
+ uint32_t bank_offset = stm32_get_gpio_bank_offset(bank);
- if ((bank > GPIO_BANK_K) && (bank != GPIO_BANK_Z)) {
- ERROR("%s: wrong GPIO bank number (%d)\n", __func__, bank);
- return false;
+ fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) {
+ const fdt32_t *cuint;
+
+ if (fdt_getprop(fdt, pinctrl_subnode,
+ "gpio-controller", NULL) == NULL) {
+ continue;
+ }
+
+ cuint = fdt_getprop(fdt, pinctrl_subnode, "reg", NULL);
+ if (cuint == NULL) {
+ continue;
+ }
+
+ if ((fdt32_to_cpu(*cuint) == bank_offset) &&
+ (fdt_get_status(pinctrl_subnode) != DT_DISABLED)) {
+ return pinctrl_subnode;
+ }
}
- return true;
+ return 0;
}
-void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
- uint32_t pull, uint32_t alternate)
+/*******************************************************************************
+ * This function gets the pin settings from DT information.
+ * When analyze and parsing is done, set the GPIO registers.
+ * Returns 0 on success and a negative FDT error code on failure.
+ ******************************************************************************/
+static int dt_set_gpio_config(void *fdt, int node, uint8_t status)
{
- volatile uint32_t bank_address;
+ const fdt32_t *cuint, *slewrate;
+ int len;
+ int pinctrl_node;
+ uint32_t i;
+ uint32_t speed = GPIO_SPEED_LOW;
+ uint32_t pull = GPIO_NO_PULL;
- if (!check_gpio(bank, pin)) {
- return;
+ cuint = fdt_getprop(fdt, node, "pinmux", &len);
+ if (cuint == NULL) {
+ return -FDT_ERR_NOTFOUND;
}
- if (bank == GPIO_BANK_Z) {
- bank_address = STM32_GPIOZ_BANK;
+ pinctrl_node = fdt_parent_offset(fdt, fdt_parent_offset(fdt, node));
+ if (pinctrl_node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ slewrate = fdt_getprop(fdt, node, "slew-rate", NULL);
+ if (slewrate != NULL) {
+ speed = fdt32_to_cpu(*slewrate);
+ }
+
+ if (fdt_getprop(fdt, node, "bias-pull-up", NULL) != NULL) {
+ pull = GPIO_PULL_UP;
+ } else if (fdt_getprop(fdt, node, "bias-pull-down", NULL) != NULL) {
+ pull = GPIO_PULL_DOWN;
} else {
- bank_address = STM32_GPIOA_BANK +
- (bank * STM32_GPIO_BANK_OFFSET);
+ VERBOSE("No bias configured in node %d\n", node);
+ }
+
+ for (i = 0U; i < ((uint32_t)len / sizeof(uint32_t)); i++) {
+ uint32_t pincfg;
+ uint32_t bank;
+ uint32_t pin;
+ uint32_t mode;
+ uint32_t alternate = GPIO_ALTERNATE_(0);
+ int bank_node;
+ int clk;
+
+ pincfg = fdt32_to_cpu(*cuint);
+ cuint++;
+
+ bank = (pincfg & DT_GPIO_BANK_MASK) >> DT_GPIO_BANK_SHIFT;
+
+ pin = (pincfg & DT_GPIO_PIN_MASK) >> DT_GPIO_PIN_SHIFT;
+
+ mode = pincfg & DT_GPIO_MODE_MASK;
+
+ switch (mode) {
+ case 0:
+ mode = GPIO_MODE_INPUT;
+ break;
+ case 1 ... 16:
+ alternate = mode - 1U;
+ mode = GPIO_MODE_ALTERNATE;
+ break;
+ case 17:
+ mode = GPIO_MODE_ANALOG;
+ break;
+ default:
+ mode = GPIO_MODE_OUTPUT;
+ break;
+ }
+
+ if (fdt_getprop(fdt, node, "drive-open-drain", NULL) != NULL) {
+ mode |= GPIO_OPEN_DRAIN;
+ }
+
+ bank_node = ckeck_gpio_bank(fdt, bank, pinctrl_node);
+ if (bank_node == 0) {
+ ERROR("PINCTRL inconsistent in DT\n");
+ panic();
+ }
+
+ clk = fdt_get_clock_id(bank_node);
+ if (clk < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ /* Platform knows the clock: assert it is okay */
+ assert((unsigned long)clk == stm32_get_gpio_bank_clock(bank));
+
+ set_gpio(bank, pin, mode, speed, pull, alternate, status);
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ * This function gets the pin settings from DT information.
+ * When analyze and parsing is done, set the GPIO registers.
+ * Returns 0 on success and a negative FDT/ERRNO error code on failure.
+ ******************************************************************************/
+int dt_set_pinctrl_config(int node)
+{
+ const fdt32_t *cuint;
+ int lenp = 0;
+ uint32_t i;
+ uint8_t status = fdt_get_status(node);
+ void *fdt;
+
+ if (fdt_get_address(&fdt) == 0) {
+ return -ENOENT;
+ }
+
+ if (status == DT_DISABLED) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ cuint = fdt_getprop(fdt, node, "pinctrl-0", &lenp);
+ if (cuint == NULL) {
+ return -FDT_ERR_NOTFOUND;
}
- mmio_clrbits_32(bank_address + GPIO_MODE_OFFSET,
+ for (i = 0; i < ((uint32_t)lenp / 4U); i++) {
+ int p_node, p_subnode;
+
+ p_node = fdt_node_offset_by_phandle(fdt, fdt32_to_cpu(*cuint));
+ if (p_node < 0) {
+ return -FDT_ERR_NOTFOUND;
+ }
+
+ fdt_for_each_subnode(p_subnode, fdt, p_node) {
+ int ret = dt_set_gpio_config(fdt, p_subnode, status);
+
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ cuint++;
+ }
+
+ return 0;
+}
+
+void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed,
+ uint32_t pull, uint32_t alternate, uint8_t status)
+{
+ uintptr_t base = stm32_get_gpio_bank_base(bank);
+ unsigned long clock = stm32_get_gpio_bank_clock(bank);
+
+ assert(pin <= GPIO_PIN_MAX);
+
+ stm32mp1_clk_enable(clock);
+
+ mmio_clrbits_32(base + GPIO_MODE_OFFSET,
((uint32_t)GPIO_MODE_MASK << (pin << 1)));
- mmio_setbits_32(bank_address + GPIO_MODE_OFFSET,
+ mmio_setbits_32(base + GPIO_MODE_OFFSET,
(mode & ~GPIO_OPEN_DRAIN) << (pin << 1));
if ((mode & GPIO_OPEN_DRAIN) != 0U) {
- mmio_setbits_32(bank_address + GPIO_TYPE_OFFSET,
- BIT(pin));
+ mmio_setbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
+ } else {
+ mmio_clrbits_32(base + GPIO_TYPE_OFFSET, BIT(pin));
}
- mmio_clrbits_32(bank_address + GPIO_SPEED_OFFSET,
+ mmio_clrbits_32(base + GPIO_SPEED_OFFSET,
((uint32_t)GPIO_SPEED_MASK << (pin << 1)));
- mmio_setbits_32(bank_address + GPIO_SPEED_OFFSET, speed << (pin << 1));
+ mmio_setbits_32(base + GPIO_SPEED_OFFSET, speed << (pin << 1));
- mmio_clrbits_32(bank_address + GPIO_PUPD_OFFSET,
+ mmio_clrbits_32(base + GPIO_PUPD_OFFSET,
((uint32_t)GPIO_PULL_MASK << (pin << 1)));
- mmio_setbits_32(bank_address + GPIO_PUPD_OFFSET, pull << (pin << 1));
+ mmio_setbits_32(base + GPIO_PUPD_OFFSET, pull << (pin << 1));
if (pin < GPIO_ALT_LOWER_LIMIT) {
- mmio_clrbits_32(bank_address + GPIO_AFRL_OFFSET,
+ mmio_clrbits_32(base + GPIO_AFRL_OFFSET,
((uint32_t)GPIO_ALTERNATE_MASK << (pin << 2)));
- mmio_setbits_32(bank_address + GPIO_AFRL_OFFSET,
+ mmio_setbits_32(base + GPIO_AFRL_OFFSET,
alternate << (pin << 2));
} else {
- mmio_clrbits_32(bank_address + GPIO_AFRH_OFFSET,
+ mmio_clrbits_32(base + GPIO_AFRH_OFFSET,
((uint32_t)GPIO_ALTERNATE_MASK <<
((pin - GPIO_ALT_LOWER_LIMIT) << 2)));
- mmio_setbits_32(bank_address + GPIO_AFRH_OFFSET,
+ mmio_setbits_32(base + GPIO_AFRH_OFFSET,
alternate << ((pin - GPIO_ALT_LOWER_LIMIT) <<
2));
}
VERBOSE("GPIO %u mode set to 0x%x\n", bank,
- mmio_read_32(bank_address + GPIO_MODE_OFFSET));
+ mmio_read_32(base + GPIO_MODE_OFFSET));
VERBOSE("GPIO %u speed set to 0x%x\n", bank,
- mmio_read_32(bank_address + GPIO_SPEED_OFFSET));
+ mmio_read_32(base + GPIO_SPEED_OFFSET));
VERBOSE("GPIO %u mode pull to 0x%x\n", bank,
- mmio_read_32(bank_address + GPIO_PUPD_OFFSET));
+ mmio_read_32(base + GPIO_PUPD_OFFSET));
VERBOSE("GPIO %u mode alternate low to 0x%x\n", bank,
- mmio_read_32(bank_address + GPIO_AFRL_OFFSET));
+ mmio_read_32(base + GPIO_AFRL_OFFSET));
VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank,
- mmio_read_32(bank_address + GPIO_AFRH_OFFSET));
+ mmio_read_32(base + GPIO_AFRH_OFFSET));
+
+ stm32mp1_clk_disable((unsigned long)clock);
+}
+
+void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure)
+{
+ uintptr_t base = stm32_get_gpio_bank_base(bank);
+ int clock = stm32_get_gpio_bank_clock(bank);
+
+ assert(pin <= GPIO_PIN_MAX);
+
+ stm32mp1_clk_enable((unsigned long)clock);
+
+ if (secure) {
+ mmio_setbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
+ } else {
+ mmio_clrbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
+ }
+
+ stm32mp1_clk_disable((unsigned long)clock);
}
diff --git a/drivers/st/pmic/stm32_i2c.c b/drivers/st/i2c/stm32_i2c.c
index f861ba296..2be7afe2d 100644
--- a/drivers/st/pmic/stm32_i2c.c
+++ b/drivers/st/i2c/stm32_i2c.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
diff --git a/drivers/st/io/io_stm32image.c b/drivers/st/io/io_stm32image.c
index 0164a2d43..dc2977d5a 100644
--- a/drivers/st/io/io_stm32image.c
+++ b/drivers/st/io/io_stm32image.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -94,6 +94,8 @@ static int stm32image_dev_open(const uintptr_t init_params,
for (i = 0; i < STM32_PART_NUM; i++) {
memcpy(stm32image_dev.part_info[i].name,
device_info->part_info[i].name, MAX_PART_NAME_SIZE);
+ stm32image_dev.part_info[i].binary_type =
+ device_info->part_info[i].binary_type;
stm32image_dev.part_info[i].part_offset =
device_info->part_info[i].part_offset;
stm32image_dev.part_info[i].bkp_offset =
@@ -193,21 +195,29 @@ static int stm32image_partition_size(io_entity_t *entity, size_t *length)
result = io_read(backend_handle, (uintptr_t)header,
MAX_LBA_SIZE, (size_t *)&bytes_read);
if (result != 0) {
- ERROR("%s: io_read (%i)\n", __func__, result);
- break;
+ if (current_part->bkp_offset == 0U) {
+ ERROR("%s: io_read (%i)\n", __func__, result);
+ }
+ header->magic = 0;
}
if ((header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) ||
(header->binary_type != current_part->binary_type) ||
(header->image_length >= stm32image_dev.device_size)) {
- WARN("%s: partition %s wrong header\n",
- __func__, current_part->name);
+ VERBOSE("%s: partition %s not found at %x\n",
+ __func__, current_part->name, *stm32_img);
+
+ if (current_part->bkp_offset == 0U) {
+ result = -ENOMEM;
+ break;
+ }
/* Header not correct, check next offset for backup */
*stm32_img += current_part->bkp_offset;
if (*stm32_img > stm32image_dev.device_size) {
/* No backup found, end of device reached */
- WARN("Out of memory\n");
+ WARN("%s : partition %s not found\n",
+ __func__, current_part->name);
result = -ENOMEM;
break;
}
@@ -221,9 +231,13 @@ static int stm32image_partition_size(io_entity_t *entity, size_t *length)
return result;
}
- *length = header->image_length;
+ if (header->image_length < stm32image_dev.lba_size) {
+ *length = stm32image_dev.lba_size;
+ } else {
+ *length = header->image_length;
+ }
- INFO("STM32 Image size : %i\n", *length);
+ INFO("STM32 Image size : %lu\n", (unsigned long)*length);
return 0;
}
@@ -266,11 +280,10 @@ static int check_header(boot_api_image_header_t *header, uintptr_t buffer)
static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
size_t length, size_t *length_read)
{
- int result = 0, offset, local_length = 0;
+ int result = 0;
uint8_t *local_buffer = (uint8_t *)buffer;
boot_api_image_header_t *header =
(boot_api_image_header_t *)first_lba_buffer;
- uintptr_t backend_handle;
assert(entity != NULL);
assert(buffer != 0U);
@@ -279,8 +292,17 @@ static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
*length_read = 0U;
while (*length_read == 0U) {
+ int offset;
+ int local_length;
+ uintptr_t backend_handle;
+
if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) {
/* Check for backup as image is corrupted */
+ if (current_part->bkp_offset == 0U) {
+ result = -ENOMEM;
+ break;
+ }
+
*stm32_img += current_part->bkp_offset;
if (*stm32_img >= stm32image_dev.device_size) {
/* End of device reached */
@@ -342,8 +364,8 @@ static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
if (result != 0) {
ERROR("%s: io_read (%i)\n", __func__, result);
*length_read = 0;
- io_close(backend_handle);
- break;
+ header->magic = 0;
+ continue;
}
result = check_header(header, buffer);
@@ -351,8 +373,6 @@ static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer,
ERROR("Header check failed\n");
*length_read = 0;
header->magic = 0;
- io_close(backend_handle);
- break;
}
io_close(backend_handle);
diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c
index 05f5ae17c..57812d899 100644
--- a/drivers/st/mmc/stm32_sdmmc2.c
+++ b/drivers/st/mmc/stm32_sdmmc2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -17,6 +17,7 @@
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <drivers/mmc.h>
+#include <drivers/st/stm32_gpio.h>
#include <drivers/st/stm32_sdmmc2.h>
#include <drivers/st/stm32mp1_clk.h>
#include <drivers/st/stm32mp1_rcc.h>
@@ -470,12 +471,11 @@ static int stm32_sdmmc2_prepare(int lba, uintptr_t buf, size_t size)
}
/* Prepare CMD 16*/
- mmio_write_32(base + SDMMC_DTIMER, UINT32_MAX);
+ mmio_write_32(base + SDMMC_DTIMER, 0);
mmio_write_32(base + SDMMC_DLENR, 0);
- mmio_clrsetbits_32(base + SDMMC_DCTRLR,
- SDMMC_DCTRLR_CLEAR_MASK, SDMMC_DCTRLR_DTDIR);
+ mmio_write_32(base + SDMMC_DCTRLR, 0);
zeromem(&cmd, sizeof(struct mmc_cmd));
@@ -643,7 +643,7 @@ static int stm32_sdmmc2_dt_get_config(void)
return -FDT_ERR_NOTFOUND;
}
- if (fdt_check_status(sdmmc_node) == 0) {
+ if (fdt_get_status(sdmmc_node) == DT_DISABLED) {
return -FDT_ERR_NOTFOUND;
}
@@ -667,15 +667,15 @@ static int stm32_sdmmc2_dt_get_config(void)
cuint++;
sdmmc2_params.reset_id = fdt32_to_cpu(*cuint);
- if ((fdt_getprop(fdt, sdmmc_node, "st,pin-ckin", NULL)) != NULL) {
+ if ((fdt_getprop(fdt, sdmmc_node, "st,use-ckin", NULL)) != NULL) {
sdmmc2_params.pin_ckin = SDMMC_CLKCR_SELCLKRX_0;
}
- if ((fdt_getprop(fdt, sdmmc_node, "st,dirpol", NULL)) != NULL) {
+ if ((fdt_getprop(fdt, sdmmc_node, "st,sig-dir", NULL)) != NULL) {
sdmmc2_params.dirpol = SDMMC_POWER_DIRPOL;
}
- if ((fdt_getprop(fdt, sdmmc_node, "st,negedge", NULL)) != NULL) {
+ if ((fdt_getprop(fdt, sdmmc_node, "st,neg-edge", NULL)) != NULL) {
sdmmc2_params.negedge = SDMMC_CLKCR_NEGEDGE;
}
diff --git a/drivers/st/pmic/stm32mp1_pmic.c b/drivers/st/pmic/stm32mp_pmic.c
index c5bdfc07d..6beabc153 100644
--- a/drivers/st/pmic/stm32mp1_pmic.c
+++ b/drivers/st/pmic/stm32mp_pmic.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -13,10 +13,10 @@
#include <common/debug.h>
#include <drivers/delay_timer.h>
+#include <drivers/st/stm32mp_pmic.h>
#include <drivers/st/stm32_gpio.h>
#include <drivers/st/stm32mp1_clk.h>
-#include <drivers/st/stm32mp1_pmic.h>
-#include <drivers/st/stpmu1.h>
+#include <drivers/st/stpmic1.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
@@ -27,23 +27,23 @@
#define MASK_RESET_BUCK3 BIT(2)
-#define STPMU1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2))
-#define STPMU1_LDO12356_OUTPUT_SHIFT 2
-#define STPMU1_LDO3_MODE (uint8_t)(BIT(7))
-#define STPMU1_LDO3_DDR_SEL 31U
-#define STPMU1_LDO3_1800000 (9U << STPMU1_LDO12356_OUTPUT_SHIFT)
+#define STPMIC1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2))
+#define STPMIC1_LDO12356_OUTPUT_SHIFT 2
+#define STPMIC1_LDO3_MODE (uint8_t)(BIT(7))
+#define STPMIC1_LDO3_DDR_SEL 31U
+#define STPMIC1_LDO3_1800000 (9U << STPMIC1_LDO12356_OUTPUT_SHIFT)
-#define STPMU1_BUCK_OUTPUT_SHIFT 2
-#define STPMU1_BUCK3_1V8 (39U << STPMU1_BUCK_OUTPUT_SHIFT)
+#define STPMIC1_BUCK_OUTPUT_SHIFT 2
+#define STPMIC1_BUCK3_1V8 (39U << STPMIC1_BUCK_OUTPUT_SHIFT)
-#define STPMU1_DEFAULT_START_UP_DELAY_MS 1
+#define STPMIC1_DEFAULT_START_UP_DELAY_MS 1
static struct i2c_handle_s i2c_handle;
static uint32_t pmic_i2c_addr;
static int dt_get_pmic_node(void *fdt)
{
- return fdt_node_offset_by_compatible(fdt, -1, "st,stpmu1");
+ return fdt_node_offset_by_compatible(fdt, -1, "st,stpmic1");
}
bool dt_check_pmic(void)
@@ -61,7 +61,7 @@ bool dt_check_pmic(void)
return false;
}
- return fdt_check_status(node);
+ return fdt_get_status(node);
}
static int dt_pmic_i2c_config(struct dt_node_info *i2c_info)
@@ -138,16 +138,16 @@ int dt_pmic_enable_boot_on_regulators(void)
voltage = (uint16_t)(fdt32_to_cpu(*cuint) / 1000U);
node_name = fdt_get_name(fdt, regulator_node, NULL);
- if (stpmu1_is_regulator_enabled(node_name) == 0U) {
+ if (stpmic1_is_regulator_enabled(node_name) == 0U) {
int status;
- status = stpmu1_regulator_voltage_set(node_name,
- voltage);
+ status = stpmic1_regulator_voltage_set(node_name,
+ voltage);
if (status != 0) {
return status;
}
- status = stpmu1_regulator_enable(node_name);
+ status = stpmic1_regulator_enable(node_name);
if (status != 0) {
return status;
}
@@ -204,7 +204,7 @@ void initialize_pmic_i2c(void)
panic();
}
- stpmu1_bind_i2c(&i2c_handle, (uint16_t)pmic_i2c_addr);
+ stpmic1_bind_i2c(&i2c_handle, (uint16_t)pmic_i2c_addr);
}
void initialize_pmic(void)
@@ -214,7 +214,7 @@ void initialize_pmic(void)
initialize_pmic_i2c();
- status = stpmu1_register_read(VERSION_STATUS_REG, &read_val);
+ status = stpmic1_register_read(VERSION_STATUS_REG, &read_val);
if (status != 0) {
panic();
}
@@ -222,7 +222,7 @@ void initialize_pmic(void)
INFO("PMIC version = 0x%x\n", read_val);
/* Keep VDD on during the reset cycle */
- status = stpmu1_register_update(MASK_RESET_BUCK_REG,
+ status = stpmic1_register_update(MASK_RESET_BUCK_REG,
MASK_RESET_BUCK3,
MASK_RESET_BUCK3);
if (status != 0) {
@@ -239,45 +239,46 @@ int pmic_ddr_power_init(enum ddr_type ddr_type)
switch (ddr_type) {
case STM32MP_DDR3:
/* Set LDO3 to sync mode */
- status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val);
+ status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val);
if (status != 0) {
return status;
}
- read_val &= ~STPMU1_LDO3_MODE;
- read_val &= ~STPMU1_LDO12356_OUTPUT_MASK;
- read_val |= STPMU1_LDO3_DDR_SEL << STPMU1_LDO12356_OUTPUT_SHIFT;
+ read_val &= ~STPMIC1_LDO3_MODE;
+ read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK;
+ read_val |= STPMIC1_LDO3_DDR_SEL <<
+ STPMIC1_LDO12356_OUTPUT_SHIFT;
- status = stpmu1_register_write(LDO3_CONTROL_REG, read_val);
+ status = stpmic1_register_write(LDO3_CONTROL_REG, read_val);
if (status != 0) {
return status;
}
- status = stpmu1_regulator_voltage_set("buck2", 1350);
+ status = stpmic1_regulator_voltage_set("buck2", 1350);
if (status != 0) {
return status;
}
- status = stpmu1_regulator_enable("buck2");
+ status = stpmic1_regulator_enable("buck2");
if (status != 0) {
return status;
}
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
- status = stpmu1_regulator_enable("vref_ddr");
+ status = stpmic1_regulator_enable("vref_ddr");
if (status != 0) {
return status;
}
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
- status = stpmu1_regulator_enable("ldo3");
+ status = stpmic1_regulator_enable("ldo3");
if (status != 0) {
return status;
}
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
break;
case STM32MP_LPDDR2:
@@ -286,57 +287,57 @@ int pmic_ddr_power_init(enum ddr_type ddr_type)
* Set LDO3 to bypass mode if BUCK3 = 1.8V
* Set LDO3 to normal mode if BUCK3 != 1.8V
*/
- status = stpmu1_register_read(BUCK3_CONTROL_REG, &read_val);
+ status = stpmic1_register_read(BUCK3_CONTROL_REG, &read_val);
if (status != 0) {
return status;
}
- if ((read_val & STPMU1_BUCK3_1V8) == STPMU1_BUCK3_1V8) {
+ if ((read_val & STPMIC1_BUCK3_1V8) == STPMIC1_BUCK3_1V8) {
buck3_at_1v8 = true;
}
- status = stpmu1_register_read(LDO3_CONTROL_REG, &read_val);
+ status = stpmic1_register_read(LDO3_CONTROL_REG, &read_val);
if (status != 0) {
return status;
}
- read_val &= ~STPMU1_LDO3_MODE;
- read_val &= ~STPMU1_LDO12356_OUTPUT_MASK;
- read_val |= STPMU1_LDO3_1800000;
+ read_val &= ~STPMIC1_LDO3_MODE;
+ read_val &= ~STPMIC1_LDO12356_OUTPUT_MASK;
+ read_val |= STPMIC1_LDO3_1800000;
if (buck3_at_1v8) {
- read_val |= STPMU1_LDO3_MODE;
+ read_val |= STPMIC1_LDO3_MODE;
}
- status = stpmu1_register_write(LDO3_CONTROL_REG, read_val);
+ status = stpmic1_register_write(LDO3_CONTROL_REG, read_val);
if (status != 0) {
return status;
}
- status = stpmu1_regulator_voltage_set("buck2", 1200);
+ status = stpmic1_regulator_voltage_set("buck2", 1200);
if (status != 0) {
return status;
}
- status = stpmu1_regulator_enable("ldo3");
+ status = stpmic1_regulator_enable("ldo3");
if (status != 0) {
return status;
}
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
- status = stpmu1_regulator_enable("buck2");
+ status = stpmic1_regulator_enable("buck2");
if (status != 0) {
return status;
}
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
- status = stpmu1_regulator_enable("vref_ddr");
+ status = stpmic1_regulator_enable("vref_ddr");
if (status != 0) {
return status;
}
- mdelay(STPMU1_DEFAULT_START_UP_DELAY_MS);
+ mdelay(STPMIC1_DEFAULT_START_UP_DELAY_MS);
break;
default:
diff --git a/drivers/st/pmic/stpmu1.c b/drivers/st/pmic/stpmic1.c
index 9c36bf64a..465996da9 100644
--- a/drivers/st/pmic/stpmu1.c
+++ b/drivers/st/pmic/stpmic1.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -7,7 +7,7 @@
#include <string.h>
#include <common/debug.h>
-#include <drivers/st/stpmu1.h>
+#include <drivers/st/stpmic1.h>
#include <plat/common/platform.h>
struct regul_struct {
@@ -16,18 +16,22 @@ struct regul_struct {
uint8_t voltage_table_size;
uint8_t control_reg;
uint8_t low_power_reg;
+ uint8_t pull_down_reg;
+ uint8_t pull_down;
+ uint8_t mask_reset_reg;
+ uint8_t mask_reset;
};
-static struct i2c_handle_s *stpmu_i2c_handle;
-static uint16_t stpmu_i2c_addr;
+static struct i2c_handle_s *pmic_i2c_handle;
+static uint16_t pmic_i2c_addr;
/* Voltage tables in mV */
static const uint16_t buck1_voltage_table[] = {
- 600,
- 625,
- 650,
- 675,
- 700,
+ 725,
+ 725,
+ 725,
+ 725,
+ 725,
725,
750,
775,
@@ -54,7 +58,39 @@ static const uint16_t buck1_voltage_table[] = {
1300,
1325,
1350,
- 1350,
+ 1375,
+ 1400,
+ 1425,
+ 1450,
+ 1475,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
+ 1500,
};
static const uint16_t buck2_voltage_table[] = {
@@ -308,6 +344,7 @@ static const uint16_t ldo3_voltage_table[] = {
3300,
3300,
3300,
+ 500,
0xFFFF, /* VREFDDR */
};
@@ -389,6 +426,10 @@ static const struct regul_struct regulators_table[] = {
.voltage_table_size = ARRAY_SIZE(buck1_voltage_table),
.control_reg = BUCK1_CONTROL_REG,
.low_power_reg = BUCK1_PWRCTRL_REG,
+ .pull_down_reg = BUCK_PULL_DOWN_REG,
+ .pull_down = BUCK1_PULL_DOWN_SHIFT,
+ .mask_reset_reg = MASK_RESET_BUCK_REG,
+ .mask_reset = BUCK1_MASK_RESET,
},
{
.dt_node_name = "buck2",
@@ -396,6 +437,10 @@ static const struct regul_struct regulators_table[] = {
.voltage_table_size = ARRAY_SIZE(buck2_voltage_table),
.control_reg = BUCK2_CONTROL_REG,
.low_power_reg = BUCK2_PWRCTRL_REG,
+ .pull_down_reg = BUCK_PULL_DOWN_REG,
+ .pull_down = BUCK2_PULL_DOWN_SHIFT,
+ .mask_reset_reg = MASK_RESET_BUCK_REG,
+ .mask_reset = BUCK2_MASK_RESET,
},
{
.dt_node_name = "buck3",
@@ -403,6 +448,10 @@ static const struct regul_struct regulators_table[] = {
.voltage_table_size = ARRAY_SIZE(buck3_voltage_table),
.control_reg = BUCK3_CONTROL_REG,
.low_power_reg = BUCK3_PWRCTRL_REG,
+ .pull_down_reg = BUCK_PULL_DOWN_REG,
+ .pull_down = BUCK3_PULL_DOWN_SHIFT,
+ .mask_reset_reg = MASK_RESET_BUCK_REG,
+ .mask_reset = BUCK3_MASK_RESET,
},
{
.dt_node_name = "buck4",
@@ -410,6 +459,10 @@ static const struct regul_struct regulators_table[] = {
.voltage_table_size = ARRAY_SIZE(buck4_voltage_table),
.control_reg = BUCK4_CONTROL_REG,
.low_power_reg = BUCK4_PWRCTRL_REG,
+ .pull_down_reg = BUCK_PULL_DOWN_REG,
+ .pull_down = BUCK4_PULL_DOWN_SHIFT,
+ .mask_reset_reg = MASK_RESET_BUCK_REG,
+ .mask_reset = BUCK4_MASK_RESET,
},
{
.dt_node_name = "ldo1",
@@ -417,6 +470,8 @@ static const struct regul_struct regulators_table[] = {
.voltage_table_size = ARRAY_SIZE(ldo1_voltage_table),
.control_reg = LDO1_CONTROL_REG,
.low_power_reg = LDO1_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO1_MASK_RESET,
},
{
.dt_node_name = "ldo2",
@@ -424,6 +479,8 @@ static const struct regul_struct regulators_table[] = {
.voltage_table_size = ARRAY_SIZE(ldo2_voltage_table),
.control_reg = LDO2_CONTROL_REG,
.low_power_reg = LDO2_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO2_MASK_RESET,
},
{
.dt_node_name = "ldo3",
@@ -431,6 +488,8 @@ static const struct regul_struct regulators_table[] = {
.voltage_table_size = ARRAY_SIZE(ldo3_voltage_table),
.control_reg = LDO3_CONTROL_REG,
.low_power_reg = LDO3_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO3_MASK_RESET,
},
{
.dt_node_name = "ldo4",
@@ -438,6 +497,8 @@ static const struct regul_struct regulators_table[] = {
.voltage_table_size = ARRAY_SIZE(ldo4_voltage_table),
.control_reg = LDO4_CONTROL_REG,
.low_power_reg = LDO4_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO4_MASK_RESET,
},
{
.dt_node_name = "ldo5",
@@ -445,6 +506,8 @@ static const struct regul_struct regulators_table[] = {
.voltage_table_size = ARRAY_SIZE(ldo5_voltage_table),
.control_reg = LDO5_CONTROL_REG,
.low_power_reg = LDO5_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO5_MASK_RESET,
},
{
.dt_node_name = "ldo6",
@@ -452,6 +515,8 @@ static const struct regul_struct regulators_table[] = {
.voltage_table_size = ARRAY_SIZE(ldo6_voltage_table),
.control_reg = LDO6_CONTROL_REG,
.low_power_reg = LDO6_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = LDO6_MASK_RESET,
},
{
.dt_node_name = "vref_ddr",
@@ -459,12 +524,14 @@ static const struct regul_struct regulators_table[] = {
.voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table),
.control_reg = VREF_DDR_CONTROL_REG,
.low_power_reg = VREF_DDR_PWRCTRL_REG,
+ .mask_reset_reg = MASK_RESET_LDO_REG,
+ .mask_reset = VREF_DDR_MASK_RESET,
},
};
-#define MAX_REGUL ARRAY_SIZE(regulators_table)
+#define MAX_REGUL ARRAY_SIZE(regulators_table)
-static const struct regul_struct *stpmu1_get_regulator_data(const char *name)
+static const struct regul_struct *get_regulator_data(const char *name)
{
uint8_t i;
@@ -480,10 +547,9 @@ static const struct regul_struct *stpmu1_get_regulator_data(const char *name)
return NULL;
}
-static uint8_t stpmu1_voltage_find_index(const char *name,
- uint16_t millivolts)
+static uint8_t voltage_to_index(const char *name, uint16_t millivolts)
{
- const struct regul_struct *regul = stpmu1_get_regulator_data(name);
+ const struct regul_struct *regul = get_regulator_data(name);
uint8_t i;
for (i = 0 ; i < regul->voltage_table_size ; i++) {
@@ -498,62 +564,132 @@ static uint8_t stpmu1_voltage_find_index(const char *name,
return 0;
}
-int stpmu1_switch_off(void)
+int stpmic1_powerctrl_on(void)
+{
+ return stpmic1_register_update(MAIN_CONTROL_REG, PWRCTRL_PIN_VALID,
+ PWRCTRL_PIN_VALID);
+}
+
+int stpmic1_switch_off(void)
{
- return stpmu1_register_update(MAIN_CONTROL_REG, 1,
- SOFTWARE_SWITCH_OFF_ENABLED);
+ return stpmic1_register_update(MAIN_CONTROL_REG, 1,
+ SOFTWARE_SWITCH_OFF_ENABLED);
}
-int stpmu1_regulator_enable(const char *name)
+int stpmic1_regulator_enable(const char *name)
{
- const struct regul_struct *regul = stpmu1_get_regulator_data(name);
+ const struct regul_struct *regul = get_regulator_data(name);
- return stpmu1_register_update(regul->control_reg, BIT(0), BIT(0));
+ return stpmic1_register_update(regul->control_reg, BIT(0), BIT(0));
}
-int stpmu1_regulator_disable(const char *name)
+int stpmic1_regulator_disable(const char *name)
{
- const struct regul_struct *regul = stpmu1_get_regulator_data(name);
+ const struct regul_struct *regul = get_regulator_data(name);
- return stpmu1_register_update(regul->control_reg, 0, BIT(0));
+ return stpmic1_register_update(regul->control_reg, 0, BIT(0));
}
-uint8_t stpmu1_is_regulator_enabled(const char *name)
+uint8_t stpmic1_is_regulator_enabled(const char *name)
{
uint8_t val;
- const struct regul_struct *regul = stpmu1_get_regulator_data(name);
+ const struct regul_struct *regul = get_regulator_data(name);
- if (stpmu1_register_read(regul->control_reg, &val) != 0) {
+ if (stpmic1_register_read(regul->control_reg, &val) != 0) {
panic();
}
return (val & 0x1U);
}
-int stpmu1_regulator_voltage_set(const char *name, uint16_t millivolts)
+int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts)
+{
+ uint8_t voltage_index = voltage_to_index(name, millivolts);
+ const struct regul_struct *regul = get_regulator_data(name);
+ uint8_t mask;
+
+ /* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
+ if (strncmp(name, "buck", 4) == 0) {
+ mask = BUCK_VOLTAGE_MASK;
+ } else if ((strncmp(name, "ldo", 3) == 0) &&
+ (strncmp(name, "ldo4", 4) != 0)) {
+ mask = LDO_VOLTAGE_MASK;
+ } else {
+ return 0;
+ }
+
+ return stpmic1_register_update(regul->control_reg,
+ voltage_index << LDO_BUCK_VOLTAGE_SHIFT,
+ mask);
+}
+
+int stpmic1_regulator_pull_down_set(const char *name)
{
- uint8_t voltage_index = stpmu1_voltage_find_index(name, millivolts);
- const struct regul_struct *regul = stpmu1_get_regulator_data(name);
+ const struct regul_struct *regul = get_regulator_data(name);
- return stpmu1_register_update(regul->control_reg, voltage_index << 2,
- 0xFC);
+ if (regul->pull_down_reg != 0) {
+ return stpmic1_register_update(regul->pull_down_reg,
+ BIT(regul->pull_down),
+ LDO_BUCK_PULL_DOWN_MASK <<
+ regul->pull_down);
+ }
+
+ return 0;
}
-int stpmu1_register_read(uint8_t register_id, uint8_t *value)
+int stpmic1_regulator_mask_reset_set(const char *name)
{
- return stm32_i2c_mem_read(stpmu_i2c_handle, stpmu_i2c_addr,
- (uint16_t)register_id, I2C_MEMADD_SIZE_8BIT,
- value, 1, 100000);
+ const struct regul_struct *regul = get_regulator_data(name);
+
+ return stpmic1_register_update(regul->mask_reset_reg,
+ BIT(regul->mask_reset),
+ LDO_BUCK_RESET_MASK <<
+ regul->mask_reset);
}
-int stpmu1_register_write(uint8_t register_id, uint8_t value)
+int stpmic1_regulator_voltage_get(const char *name)
+{
+ const struct regul_struct *regul = get_regulator_data(name);
+ uint8_t value;
+ uint8_t mask;
+
+ /* Voltage can be set for buck<N> or ldo<N> (except ldo4) regulators */
+ if (strncmp(name, "buck", 4) == 0) {
+ mask = BUCK_VOLTAGE_MASK;
+ } else if ((strncmp(name, "ldo", 3) == 0) &&
+ (strncmp(name, "ldo4", 4) != 0)) {
+ mask = LDO_VOLTAGE_MASK;
+ } else {
+ return 0;
+ }
+
+ if (stpmic1_register_read(regul->control_reg, &value))
+ return -1;
+
+ value = (value & mask) >> LDO_BUCK_VOLTAGE_SHIFT;
+
+ if (value > regul->voltage_table_size)
+ return -1;
+
+ return (int)regul->voltage_table[value];
+}
+
+int stpmic1_register_read(uint8_t register_id, uint8_t *value)
+{
+ return stm32_i2c_mem_read(pmic_i2c_handle, pmic_i2c_addr,
+ (uint16_t)register_id, I2C_MEMADD_SIZE_8BIT,
+ value, 1, 100000);
+}
+
+int stpmic1_register_write(uint8_t register_id, uint8_t value)
{
int status;
- status = stm32_i2c_mem_write(stpmu_i2c_handle, stpmu_i2c_addr,
+ status = stm32_i2c_mem_write(pmic_i2c_handle, pmic_i2c_addr,
(uint16_t)register_id,
I2C_MEMADD_SIZE_8BIT, &value, 1, 100000);
+#if ENABLE_ASSERTIONS
if (status != 0) {
return status;
}
@@ -561,7 +697,7 @@ int stpmu1_register_write(uint8_t register_id, uint8_t value)
if ((register_id != WATCHDOG_CONTROL_REG) && (register_id <= 0x40U)) {
uint8_t readval;
- status = stpmu1_register_read(register_id, &readval);
+ status = stpmic1_register_read(register_id, &readval);
if (status != 0) {
return status;
}
@@ -570,32 +706,57 @@ int stpmu1_register_write(uint8_t register_id, uint8_t value)
return -1;
}
}
+#endif
- return 0;
+ return status;
}
-int stpmu1_register_update(uint8_t register_id, uint8_t value, uint8_t mask)
+int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask)
{
int status;
uint8_t val;
- status = stpmu1_register_read(register_id, &val);
+ status = stpmic1_register_read(register_id, &val);
if (status != 0) {
return status;
}
- /* Clear bits to update */
- val &= ~mask;
+ val = (val & ~mask) | (value & mask);
- /* Update appropriate bits*/
- val |= (value & mask);
+ return stpmic1_register_write(register_id, val);
+}
- /* Send new value on I2C Bus */
- return stpmu1_register_write(register_id, val);
+void stpmic1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr)
+{
+ pmic_i2c_handle = i2c_handle;
+ pmic_i2c_addr = i2c_addr;
}
-void stpmu1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr)
+void stpmic1_dump_regulators(void)
{
- stpmu_i2c_handle = i2c_handle;
- stpmu_i2c_addr = i2c_addr;
+ uint32_t i;
+
+ for (i = 0U; i < MAX_REGUL; i++) {
+ const char *name __unused = regulators_table[i].dt_node_name;
+
+ VERBOSE("PMIC regul %s: %sable, %dmV",
+ name,
+ stpmic1_is_regulator_enabled(name) ? "en" : "dis",
+ stpmic1_regulator_voltage_get(name));
+ }
+}
+
+int stpmic1_get_version(unsigned long *version)
+{
+ int rc;
+ uint8_t read_val;
+
+ rc = stpmic1_register_read(VERSION_STATUS_REG, &read_val);
+ if (rc) {
+ return -1;
+ }
+
+ *version = (unsigned long)read_val;
+
+ return 0;
}
diff --git a/drivers/synopsys/ufs/dw_ufs.c b/drivers/synopsys/ufs/dw_ufs.c
index c7c8fc22d..6bed981db 100644
--- a/drivers/synopsys/ufs/dw_ufs.c
+++ b/drivers/synopsys/ufs/dw_ufs.c
@@ -183,7 +183,7 @@ static int dwufs_phy_set_pwr_mode(ufs_params_t *params)
return 0;
}
-const ufs_ops_t dw_ufs_ops = {
+static const ufs_ops_t dw_ufs_ops = {
.phy_init = dwufs_phy_init,
.phy_set_pwr_mode = dwufs_phy_set_pwr_mode,
};
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index 2351c9b04..b2c104612 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -591,7 +591,7 @@ void ufs_write_desc(int idn, int index, uintptr_t buf, size_t size)
ufs_query(QUERY_WRITE_DESC, idn, index, 0, buf, size);
}
-void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size)
+static void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size)
{
utp_utrd_t utrd;
resp_upiu_t *resp;