mirror of
https://github.com/Fishwaldo/build.git
synced 2025-06-05 22:01:35 +00:00
Add A64 dev DVFS and THS
This commit is contained in:
parent
40e0e25454
commit
13a7b53d55
20 changed files with 2826 additions and 38 deletions
|
@ -619,9 +619,11 @@ CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
|
|||
#
|
||||
CONFIG_CPUFREQ_DT=y
|
||||
CONFIG_CPUFREQ_DT_PLATDEV=y
|
||||
# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set
|
||||
CONFIG_ARM_BIG_LITTLE_CPUFREQ=y
|
||||
# CONFIG_ARM_DT_BL_CPUFREQ is not set
|
||||
# CONFIG_ARM_DB8500_CPUFREQ is not set
|
||||
# CONFIG_ARM_KIRKWOOD_CPUFREQ is not set
|
||||
CONFIG_ARM_SCPI_CPUFREQ=y
|
||||
# CONFIG_QORIQ_CPUFREQ is not set
|
||||
CONFIG_NET=y
|
||||
CONFIG_COMPAT_NETLINK_MESSAGES=y
|
||||
|
@ -2596,7 +2598,7 @@ CONFIG_HWMON=y
|
|||
# CONFIG_SENSORS_ADT7470 is not set
|
||||
# CONFIG_SENSORS_ADT7475 is not set
|
||||
# CONFIG_SENSORS_ASC7621 is not set
|
||||
# CONFIG_SENSORS_ARM_SCPI is not set
|
||||
CONFIG_SENSORS_ARM_SCPI=y
|
||||
# CONFIG_SENSORS_ASPEED is not set
|
||||
# CONFIG_SENSORS_ATXP1 is not set
|
||||
# CONFIG_SENSORS_DS620 is not set
|
||||
|
@ -4278,6 +4280,7 @@ CONFIG_ARM_MHU=y
|
|||
# CONFIG_ALTERA_MBOX is not set
|
||||
# CONFIG_MAILBOX_TEST is not set
|
||||
# CONFIG_BCM_FLEXRM_MBOX is not set
|
||||
CONFIG_ARM_SMC_MBOX=y
|
||||
CONFIG_IOMMU_API=y
|
||||
CONFIG_IOMMU_SUPPORT=y
|
||||
|
||||
|
|
238
patch/atf/atf-sun50iw1/01-add-SMC-mailbox.patch
Normal file
238
patch/atf/atf-sun50iw1/01-add-SMC-mailbox.patch
Normal file
|
@ -0,0 +1,238 @@
|
|||
From 923ed37b583ad9f78ca36e0bb372e2d397a900af Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Tue, 12 Jul 2016 22:41:52 +0100
|
||||
Subject: [PATCH] sunxi: add smc service handler for an SMC mailbox
|
||||
|
||||
The SCPI protocol uses a combination of a shared memory region and a
|
||||
mailbox to signal requests from the application cores to the management
|
||||
processor. However the Allwinner mailbox device in the A64 SoC can only
|
||||
signal requests between the ARM cores and the OpenRISC core, not between
|
||||
the ARM cores themselves.
|
||||
As an alternative we can directly trigger SCPI requests by using an
|
||||
smc instruction to call routines in the runtime code of ARM Trusted
|
||||
Firmware (similar to what PSCI does).
|
||||
Add a vendor defined (SiP) runtime service handler, which dispatches
|
||||
incoming smc calls to the SCPI handler if the function ID matches.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
plat/sun50iw1p1/bl31_sunxi_setup.c | 2 +
|
||||
plat/sun50iw1p1/platform.mk | 1 +
|
||||
plat/sun50iw1p1/sunxi_sip_svc.c | 123 +++++++++++++++++++++++++++++++++++++
|
||||
plat/sun50iw1p1/sunxi_sip_svc.h | 53 ++++++++++++++++
|
||||
4 files changed, 179 insertions(+)
|
||||
create mode 100644 plat/sun50iw1p1/sunxi_sip_svc.c
|
||||
create mode 100644 plat/sun50iw1p1/sunxi_sip_svc.h
|
||||
|
||||
diff --git a/plat/sun50iw1p1/bl31_sunxi_setup.c b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
index 3e30814ff..5e71cc589 100644
|
||||
--- a/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
+++ b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
@@ -255,6 +255,8 @@ void bl31_platform_setup(void)
|
||||
}
|
||||
|
||||
sunxi_setup_clocks(socid);
|
||||
+
|
||||
+ NOTICE("SCPI: installed handler, implementation level: 000000\n");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
diff --git a/plat/sun50iw1p1/platform.mk b/plat/sun50iw1p1/platform.mk
|
||||
index b788f81f2..482b11567 100644
|
||||
--- a/plat/sun50iw1p1/platform.mk
|
||||
+++ b/plat/sun50iw1p1/platform.mk
|
||||
@@ -50,5 +50,6 @@ BL31_SOURCES += drivers/arm/gic/arm_gic.c \
|
||||
plat/sun50iw1p1/plat_topology.c \
|
||||
plat/sun50iw1p1/aarch64/plat_helpers.S \
|
||||
plat/sun50iw1p1/sunxi_clocks.c \
|
||||
+ plat/sun50iw1p1/sunxi_sip_svc.c \
|
||||
plat/sun50iw1p1/aarch64/sunxi_common.c
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_sip_svc.c b/plat/sun50iw1p1/sunxi_sip_svc.c
|
||||
new file mode 100644
|
||||
index 000000000..827aa70eb
|
||||
--- /dev/null
|
||||
+++ b/plat/sun50iw1p1/sunxi_sip_svc.c
|
||||
@@ -0,0 +1,123 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2016,2017 ARM Limited and Contributors. All rights reserved.
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions are met:
|
||||
+ *
|
||||
+ * Redistributions of source code must retain the above copyright notice, this
|
||||
+ * list of conditions and the following disclaimer.
|
||||
+ *
|
||||
+ * Redistributions in binary form must reproduce the above copyright notice,
|
||||
+ * this list of conditions and the following disclaimer in the documentation
|
||||
+ * and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * Neither the name of ARM nor the names of its contributors may be used
|
||||
+ * to endorse or promote products derived from this software without specific
|
||||
+ * prior written permission.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||
+ */
|
||||
+#include <assert.h>
|
||||
+#include <console.h>
|
||||
+#include <debug.h>
|
||||
+#include <mmio.h>
|
||||
+#include "sunxi_sip_svc.h"
|
||||
+#include "sunxi_private.h"
|
||||
+#include <runtime_svc.h>
|
||||
+#include <uuid.h>
|
||||
+
|
||||
+/* SiP Service UUID */
|
||||
+DEFINE_SVC_UUID(sunxi_sip_svc_uid,
|
||||
+ 0x06016e09, 0xd859, 0x4c24, 0xbb, 0x9d,
|
||||
+ 0x18, 0x92, 0xb4, 0x8d, 0xa5, 0x03);
|
||||
+
|
||||
+#pragma weak sunxi_plat_sip_handler
|
||||
+uint64_t sunxi_plat_sip_handler(uint32_t smc_fid,
|
||||
+ uint64_t x1,
|
||||
+ uint64_t x2,
|
||||
+ uint64_t x3,
|
||||
+ uint64_t x4,
|
||||
+ void *cookie,
|
||||
+ void *handle,
|
||||
+ uint64_t flags)
|
||||
+{
|
||||
+ ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
|
||||
+ SMC_RET1(handle, SMC_UNK);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * This function handles Allwinner defined SiP Calls */
|
||||
+uint64_t sunxi_sip_handler(uint32_t smc_fid,
|
||||
+ uint64_t x1,
|
||||
+ uint64_t x2,
|
||||
+ uint64_t x3,
|
||||
+ uint64_t x4,
|
||||
+ void *cookie,
|
||||
+ void *handle,
|
||||
+ uint64_t flags)
|
||||
+{
|
||||
+ /* Determine which security state this SMC originated from */
|
||||
+ if (!is_caller_non_secure(flags))
|
||||
+ SMC_RET1(handle, SMC_UNK);
|
||||
+
|
||||
+ /* SiP SMC service normal world's call */
|
||||
+ switch (smc_fid) {
|
||||
+ case SUNXI_SIP_MBOX_TRIGGER:
|
||||
+ SMC_RET1(handle, ~0);
|
||||
+ }
|
||||
+
|
||||
+ return sunxi_plat_sip_handler(smc_fid, x1, x2, x3, x4,
|
||||
+ cookie, handle, flags);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * This function is responsible for handling all SiP calls from the NS world
|
||||
+ */
|
||||
+uint64_t sip_smc_handler(uint32_t smc_fid,
|
||||
+ uint64_t x1,
|
||||
+ uint64_t x2,
|
||||
+ uint64_t x3,
|
||||
+ uint64_t x4,
|
||||
+ void *cookie,
|
||||
+ void *handle,
|
||||
+ uint64_t flags)
|
||||
+{
|
||||
+ switch (smc_fid) {
|
||||
+ case SIP_SVC_CALL_COUNT:
|
||||
+ /* Return the number of Allwinner SiP Service Calls. */
|
||||
+ SMC_RET1(handle, SUNXI_COMMON_SIP_NUM_CALLS);
|
||||
+
|
||||
+ case SIP_SVC_UID:
|
||||
+ /* Return UID to the caller */
|
||||
+ SMC_UUID_RET(handle, sunxi_sip_svc_uid);
|
||||
+
|
||||
+ case SIP_SVC_VERSION:
|
||||
+ /* Return the version of current implementation */
|
||||
+ SMC_RET2(handle, SUNXI_SIP_SVC_VERSION_MAJOR,
|
||||
+ SUNXI_SIP_SVC_VERSION_MINOR);
|
||||
+
|
||||
+ default:
|
||||
+ return sunxi_sip_handler(smc_fid, x1, x2, x3, x4,
|
||||
+ cookie, handle, flags);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* Define a runtime service descriptor for fast SMC calls */
|
||||
+DECLARE_RT_SVC(
|
||||
+ sunxi_sip_svc,
|
||||
+ OEN_SIP_START,
|
||||
+ OEN_SIP_END,
|
||||
+ SMC_TYPE_FAST,
|
||||
+ NULL,
|
||||
+ sip_smc_handler
|
||||
+);
|
||||
diff --git a/plat/sun50iw1p1/sunxi_sip_svc.h b/plat/sun50iw1p1/sunxi_sip_svc.h
|
||||
new file mode 100644
|
||||
index 000000000..08d52bd7b
|
||||
--- /dev/null
|
||||
+++ b/plat/sun50iw1p1/sunxi_sip_svc.h
|
||||
@@ -0,0 +1,53 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2016,2017 ARM Limited and Contributors. All rights reserved.
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions are met:
|
||||
+ *
|
||||
+ * Redistributions of source code must retain the above copyright notice, this
|
||||
+ * list of conditions and the following disclaimer.
|
||||
+ *
|
||||
+ * Redistributions in binary form must reproduce the above copyright notice,
|
||||
+ * this list of conditions and the following disclaimer in the documentation
|
||||
+ * and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * Neither the name of ARM nor the names of its contributors may be used
|
||||
+ * to endorse or promote products derived from this software without specific
|
||||
+ * prior written permission.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||
+ */
|
||||
+#ifndef __PLAT_SIP_SVC_H__
|
||||
+#define __PLAT_SIP_SVC_H__
|
||||
+
|
||||
+#include <stdint.h>
|
||||
+
|
||||
+/* SMC function IDs for SiP Service queries */
|
||||
+#define SIP_SVC_CALL_COUNT 0x8200ff00
|
||||
+#define SIP_SVC_UID 0x8200ff01
|
||||
+/* 0x8200ff02 is reserved */
|
||||
+#define SIP_SVC_VERSION 0x8200ff03
|
||||
+
|
||||
+/* Allwinner SiP Service Calls version numbers */
|
||||
+#define SUNXI_SIP_SVC_VERSION_MAJOR 0x0
|
||||
+#define SUNXI_SIP_SVC_VERSION_MINOR 0x1
|
||||
+
|
||||
+#define SMC_AARCH64_BIT 0x40000000
|
||||
+
|
||||
+/* Number of Allwinner SiP Calls implemented */
|
||||
+#define SUNXI_COMMON_SIP_NUM_CALLS 1
|
||||
+
|
||||
+/* Allwinner SiP Service Calls function IDs */
|
||||
+#define SUNXI_SIP_MBOX_TRIGGER 0x82000001
|
||||
+
|
||||
+#endif /* __PLAT_SIP_SVC_H__ */
|
193
patch/atf/atf-sun50iw1/02-add-handler-boilerplate.patch
Normal file
193
patch/atf/atf-sun50iw1/02-add-handler-boilerplate.patch
Normal file
|
@ -0,0 +1,193 @@
|
|||
From dbba58ae9f77912f2d6661e8b06817327f1e3565 Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Mon, 8 Aug 2016 23:45:41 +0100
|
||||
Subject: [PATCH] sunxi: SCPI: add handler boilerplate
|
||||
|
||||
Add the basic framework to handle request via the SCPI interface. This
|
||||
reads and decodes the request found in the shared memory region,
|
||||
provides the function framework to handle a certain command and takes
|
||||
care about passing on the return value.
|
||||
This for just the basic capability call is implemented.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
plat/sun50iw1p1/bl31_sunxi_setup.c | 2 +-
|
||||
plat/sun50iw1p1/platform.mk | 1 +
|
||||
plat/sun50iw1p1/sunxi_private.h | 3 +
|
||||
plat/sun50iw1p1/sunxi_scpi.c | 110 +++++++++++++++++++++++++++++++++++++
|
||||
plat/sun50iw1p1/sunxi_sip_svc.c | 7 ++-
|
||||
5 files changed, 120 insertions(+), 3 deletions(-)
|
||||
create mode 100644 plat/sun50iw1p1/sunxi_scpi.c
|
||||
|
||||
diff --git a/plat/sun50iw1p1/bl31_sunxi_setup.c b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
index 5e71cc589..9e303f688 100644
|
||||
--- a/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
+++ b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
@@ -256,7 +256,7 @@ void bl31_platform_setup(void)
|
||||
|
||||
sunxi_setup_clocks(socid);
|
||||
|
||||
- NOTICE("SCPI: installed handler, implementation level: 000000\n");
|
||||
+ NOTICE("SCPI: installed handler, implementation level: 100000\n");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
diff --git a/plat/sun50iw1p1/platform.mk b/plat/sun50iw1p1/platform.mk
|
||||
index 482b11567..188e4e84d 100644
|
||||
--- a/plat/sun50iw1p1/platform.mk
|
||||
+++ b/plat/sun50iw1p1/platform.mk
|
||||
@@ -51,5 +51,6 @@ BL31_SOURCES += drivers/arm/gic/arm_gic.c \
|
||||
plat/sun50iw1p1/aarch64/plat_helpers.S \
|
||||
plat/sun50iw1p1/sunxi_clocks.c \
|
||||
plat/sun50iw1p1/sunxi_sip_svc.c \
|
||||
+ plat/sun50iw1p1/sunxi_scpi.c \
|
||||
plat/sun50iw1p1/aarch64/sunxi_common.c
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h
|
||||
index aefa763c7..b07e56e79 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_private.h
|
||||
+++ b/plat/sun50iw1p1/sunxi_private.h
|
||||
@@ -75,6 +75,9 @@ int sunxi_pmic_write(uint8_t address, uint8_t value);
|
||||
void udelay(unsigned int delay);
|
||||
int sunxi_setup_clocks(uint16_t socid);
|
||||
|
||||
+/* Declarations for sunxi_scpi.c */
|
||||
+uint32_t sunxi_trigger_scpi(uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4);
|
||||
+
|
||||
/* Gets the SPSR for BL33 entry */
|
||||
uint32_t sunxi_get_spsr_for_bl33_entry(int aarch);
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_scpi.c b/plat/sun50iw1p1/sunxi_scpi.c
|
||||
new file mode 100644
|
||||
index 000000000..b13dfa7d5
|
||||
--- /dev/null
|
||||
+++ b/plat/sun50iw1p1/sunxi_scpi.c
|
||||
@@ -0,0 +1,110 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2016,2017 ARM Limited and Contributors. All rights reserved.
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions are met:
|
||||
+ *
|
||||
+ * Redistributions of source code must retain the above copyright notice, this
|
||||
+ * list of conditions and the following disclaimer.
|
||||
+ *
|
||||
+ * Redistributions in binary form must reproduce the above copyright notice,
|
||||
+ * this list of conditions and the following disclaimer in the documentation
|
||||
+ * and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * Neither the name of ARM nor the names of its contributors may be used
|
||||
+ * to endorse or promote products derived from this software without specific
|
||||
+ * prior written permission.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||
+ */
|
||||
+
|
||||
+#include <debug.h>
|
||||
+#include <plat_config.h>
|
||||
+#include <mmio.h>
|
||||
+#include <sys/errno.h>
|
||||
+#include "sunxi_def.h"
|
||||
+#include "sunxi_private.h"
|
||||
+
|
||||
+#define BIT(n) (1U << (n))
|
||||
+#define GENMASK(hi, lo) (BIT(hi) - 1 - BIT(lo) + 1)
|
||||
+
|
||||
+#define SCPI_OK 0
|
||||
+#define SCPI_E_PARAM 1
|
||||
+#define SCPI_E_ALIGN 2
|
||||
+#define SCPI_E_SIZE 3
|
||||
+#define SCPI_E_HANDLER 4
|
||||
+#define SCPI_E_ACCESS 5
|
||||
+#define SCPI_E_RANGE 6
|
||||
+#define SCPI_E_TIMEOUT 7
|
||||
+#define SCPI_E_NOMEM 8
|
||||
+#define SCPI_E_PWRSTATE 9
|
||||
+#define SCPI_E_SUPPORT 10
|
||||
+#define SCPI_E_DEVICE 11
|
||||
+#define SCPI_E_BUSY 12
|
||||
+
|
||||
+#define SCP_CMD_CAPABILITY 0x02
|
||||
+
|
||||
+#define SCP_CMDS_IMPLEMENTED \
|
||||
+ 0
|
||||
+
|
||||
+/* end of SRAM A1 */
|
||||
+#define SUNXI_SCPI_SHMEM_BASE 0x17e00
|
||||
+
|
||||
+static uint32_t scpi_handle_cmd(int cmd, uint8_t *payload_size,
|
||||
+ uintptr_t payload_in, uintptr_t payload_out)
|
||||
+{
|
||||
+ switch (cmd) {
|
||||
+ case SCP_CMD_CAPABILITY:
|
||||
+ mmio_write_32(payload_out + 0x00, (1U << 16) | (2U << 0));
|
||||
+ /*
|
||||
+ * The SCPI spec says this field holds the payload sizes for
|
||||
+ * the receive and transmit channel, but the Linux driver
|
||||
+ * decodes an event version ID from it.
|
||||
+ * Let's play nice with Linux for now and ignore the spec.
|
||||
+ *
|
||||
+ * mmio_write_32(payload_out + 0x04,
|
||||
+ * ((256 - 1) << 16) | (256 - 1));
|
||||
+ */
|
||||
+ mmio_write_32(payload_out + 0x04, 1U << 16);
|
||||
+
|
||||
+ mmio_write_32(payload_out + 0x08, 1U << 24);
|
||||
+ mmio_write_32(payload_out + 0x0c, SCP_CMDS_IMPLEMENTED);
|
||||
+ mmio_write_32(payload_out + 0x10, 0x0);
|
||||
+ mmio_write_32(payload_out + 0x14, 0x0);
|
||||
+ mmio_write_32(payload_out + 0x18, 0x0);
|
||||
+ *payload_size = 0x1c;
|
||||
+ return SCPI_OK;
|
||||
+ }
|
||||
+
|
||||
+ return SCPI_E_SUPPORT;
|
||||
+}
|
||||
+
|
||||
+uint32_t sunxi_trigger_scpi(uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4)
|
||||
+{
|
||||
+ uint32_t ret;
|
||||
+ uint64_t scpi_header;
|
||||
+ uint8_t payload_size;
|
||||
+
|
||||
+ scpi_header = *(uint64_t *)(SUNXI_SCPI_SHMEM_BASE + 0x100);
|
||||
+ payload_size = (scpi_header >> 16) & 0xff;
|
||||
+
|
||||
+ ret = scpi_handle_cmd(scpi_header & 0xff, &payload_size,
|
||||
+ SUNXI_SCPI_SHMEM_BASE + 0x108,
|
||||
+ SUNXI_SCPI_SHMEM_BASE + 0x8);
|
||||
+
|
||||
+ mmio_write_32(SUNXI_SCPI_SHMEM_BASE, (scpi_header & 0xffff) |
|
||||
+ (uint32_t)payload_size << 16);
|
||||
+ mmio_write_32(SUNXI_SCPI_SHMEM_BASE + 4, ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
diff --git a/plat/sun50iw1p1/sunxi_sip_svc.c b/plat/sun50iw1p1/sunxi_sip_svc.c
|
||||
index 827aa70eb..270b488f4 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_sip_svc.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_sip_svc.c
|
||||
@@ -72,8 +72,11 @@ uint64_t sunxi_sip_handler(uint32_t smc_fid,
|
||||
|
||||
/* SiP SMC service normal world's call */
|
||||
switch (smc_fid) {
|
||||
- case SUNXI_SIP_MBOX_TRIGGER:
|
||||
- SMC_RET1(handle, ~0);
|
||||
+ case SUNXI_SIP_MBOX_TRIGGER: {
|
||||
+ uint32_t ret = sunxi_trigger_scpi(x1, x2, x3, x4);
|
||||
+
|
||||
+ SMC_RET1(handle, ret);
|
||||
+ }
|
||||
}
|
||||
|
||||
return sunxi_plat_sip_handler(smc_fid, x1, x2, x3, x4,
|
208
patch/atf/atf-sun50iw1/03-add-clock-handling.patch
Normal file
208
patch/atf/atf-sun50iw1/03-add-clock-handling.patch
Normal file
|
@ -0,0 +1,208 @@
|
|||
From 426631883e372b3e95c94a148923396a11afc3ca Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Mon, 8 Aug 2016 23:45:41 +0100
|
||||
Subject: [PATCH] sunxi: SCPI: add clock handler framework
|
||||
|
||||
SCPI features an interface to control and query clocks with a variable
|
||||
frequency.
|
||||
Implement the SCPI protocol part of that interface and provide a
|
||||
framework to easily add any specific clock desired.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
plat/sun50iw1p1/sunxi_clocks.c | 78 +++++++++++++++++++++++++++++++++++++++++
|
||||
plat/sun50iw1p1/sunxi_private.h | 8 +++++
|
||||
plat/sun50iw1p1/sunxi_scpi.c | 59 ++++++++++++++++++++++++++++++-
|
||||
3 files changed, 144 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_clocks.c b/plat/sun50iw1p1/sunxi_clocks.c
|
||||
index ff02bfa14..1c5ec2975 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_clocks.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_clocks.c
|
||||
@@ -105,3 +105,81 @@ int sunxi_setup_clocks(uint16_t socid)
|
||||
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+struct scpi_clock {
|
||||
+ uint32_t min_freq;
|
||||
+ uint32_t max_freq;
|
||||
+ uint32_t (*getter)(uint32_t);
|
||||
+ uint32_t (*setter)(uint32_t, uint32_t);
|
||||
+ uint32_t reg_addr;
|
||||
+ const char *name;
|
||||
+ uint16_t clockid;
|
||||
+};
|
||||
+
|
||||
+struct scpi_clock sunxi_clocks[] = {
|
||||
+};
|
||||
+
|
||||
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
+
|
||||
+static struct scpi_clock *get_sunxi_clock(int clocknr)
|
||||
+{
|
||||
+ if (clocknr < 0 || clocknr >= ARRAY_SIZE(sunxi_clocks))
|
||||
+ return NULL;
|
||||
+
|
||||
+ return &sunxi_clocks[clocknr];
|
||||
+}
|
||||
+
|
||||
+uint32_t sunxi_clock_get_min_rate(int clocknr)
|
||||
+{
|
||||
+ struct scpi_clock *clk = get_sunxi_clock(clocknr);
|
||||
+
|
||||
+ if (!clk)
|
||||
+ return ~0;
|
||||
+
|
||||
+ return clk->min_freq;
|
||||
+}
|
||||
+
|
||||
+uint32_t sunxi_clock_get_max_rate(int clocknr)
|
||||
+{
|
||||
+ struct scpi_clock *clk = get_sunxi_clock(clocknr);
|
||||
+
|
||||
+ if (!clk)
|
||||
+ return ~0;
|
||||
+
|
||||
+ return clk->max_freq;
|
||||
+}
|
||||
+
|
||||
+const char* sunxi_clock_get_name(int clocknr)
|
||||
+{
|
||||
+ struct scpi_clock *clk = get_sunxi_clock(clocknr);
|
||||
+
|
||||
+ if (!clk)
|
||||
+ return NULL;
|
||||
+
|
||||
+ return clk->name;
|
||||
+}
|
||||
+
|
||||
+uint32_t sunxi_clock_get_rate(int clocknr)
|
||||
+{
|
||||
+ struct scpi_clock *clk = get_sunxi_clock(clocknr);
|
||||
+
|
||||
+ if (!clk)
|
||||
+ return ~0;
|
||||
+
|
||||
+ return clk->getter(clk->reg_addr);
|
||||
+}
|
||||
+
|
||||
+int sunxi_clock_set_rate(int clocknr, uint32_t freq)
|
||||
+{
|
||||
+ struct scpi_clock *clk = get_sunxi_clock(clocknr);
|
||||
+
|
||||
+ if (!clk)
|
||||
+ return ~0;
|
||||
+
|
||||
+ return clk->setter(clk->reg_addr, freq);
|
||||
+}
|
||||
+
|
||||
+int sunxi_clock_nr_clocks(void)
|
||||
+{
|
||||
+ return ARRAY_SIZE(sunxi_clocks);
|
||||
+}
|
||||
diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h
|
||||
index b07e56e79..08aeb94da 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_private.h
|
||||
+++ b/plat/sun50iw1p1/sunxi_private.h
|
||||
@@ -78,6 +78,14 @@ int sunxi_setup_clocks(uint16_t socid);
|
||||
/* Declarations for sunxi_scpi.c */
|
||||
uint32_t sunxi_trigger_scpi(uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4);
|
||||
|
||||
+/* Declarations for sunxi_clocks.c */
|
||||
+int sunxi_clock_nr_clocks(void);
|
||||
+uint32_t sunxi_clock_get_min_rate(int clocknr);
|
||||
+uint32_t sunxi_clock_get_max_rate(int clocknr);
|
||||
+const char* sunxi_clock_get_name(int clocknr);
|
||||
+uint32_t sunxi_clock_get_rate(int clocknr);
|
||||
+int sunxi_clock_set_rate(int clocknr, uint32_t freq);
|
||||
+
|
||||
/* Gets the SPSR for BL33 entry */
|
||||
uint32_t sunxi_get_spsr_for_bl33_entry(int aarch);
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_scpi.c b/plat/sun50iw1p1/sunxi_scpi.c
|
||||
index b13dfa7d5..3ca287ed2 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_scpi.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_scpi.c
|
||||
@@ -53,16 +53,42 @@
|
||||
#define SCPI_E_BUSY 12
|
||||
|
||||
#define SCP_CMD_CAPABILITY 0x02
|
||||
+#define SCP_CMD_CLOCKS_CAPS 0x0d
|
||||
+#define SCP_CMD_CLOCK_GET_INFO 0x0e
|
||||
+#define SCP_CMD_CLOCK_SET_RATE 0x0f
|
||||
+#define SCP_CMD_CLOCK_GET_RATE 0x10
|
||||
|
||||
#define SCP_CMDS_IMPLEMENTED \
|
||||
- 0
|
||||
+ GENMASK(SCP_CMD_CLOCK_GET_RATE, SCP_CMD_CLOCKS_CAPS)
|
||||
|
||||
/* end of SRAM A1 */
|
||||
#define SUNXI_SCPI_SHMEM_BASE 0x17e00
|
||||
|
||||
+static int write_clock_info(uintptr_t payload, int clocknr)
|
||||
+{
|
||||
+ const char *name, *s;
|
||||
+ int i;
|
||||
+
|
||||
+ name = sunxi_clock_get_name(clocknr);
|
||||
+ if (!name)
|
||||
+ return -SCPI_E_PARAM;
|
||||
+
|
||||
+ mmio_write_32(payload + 0x0, (clocknr & 0xffff) | (0x03 << 16));
|
||||
+ mmio_write_32(payload + 0x4, sunxi_clock_get_min_rate(clocknr));
|
||||
+ mmio_write_32(payload + 0x8, sunxi_clock_get_max_rate(clocknr));
|
||||
+ for (i = 0, s = name; s[i] != 0; i++)
|
||||
+ mmio_write_8(payload + 12 + i, s[i]);
|
||||
+ mmio_write_8(payload + 12 + i, 0);
|
||||
+
|
||||
+ return 12 + i;
|
||||
+}
|
||||
+
|
||||
static uint32_t scpi_handle_cmd(int cmd, uint8_t *payload_size,
|
||||
uintptr_t payload_in, uintptr_t payload_out)
|
||||
{
|
||||
+ uint32_t par1 = mmio_read_32(payload_in);
|
||||
+ uint32_t ret;
|
||||
+
|
||||
switch (cmd) {
|
||||
case SCP_CMD_CAPABILITY:
|
||||
mmio_write_32(payload_out + 0x00, (1U << 16) | (2U << 0));
|
||||
@@ -84,6 +110,37 @@ static uint32_t scpi_handle_cmd(int cmd, uint8_t *payload_size,
|
||||
mmio_write_32(payload_out + 0x18, 0x0);
|
||||
*payload_size = 0x1c;
|
||||
return SCPI_OK;
|
||||
+ case SCP_CMD_CLOCKS_CAPS:
|
||||
+ /* number of implemented clocks */
|
||||
+ mmio_write_32(payload_out, sunxi_clock_nr_clocks());
|
||||
+ *payload_size = 0x4;
|
||||
+ return SCPI_OK;
|
||||
+ case SCP_CMD_CLOCK_GET_INFO:
|
||||
+ ret = write_clock_info(payload_out, par1 & 0xffff);
|
||||
+ if (ret < 0) {
|
||||
+ *payload_size = 0;
|
||||
+ return SCPI_E_PARAM;
|
||||
+ }
|
||||
+
|
||||
+ *payload_size = ret;
|
||||
+ return SCPI_OK;
|
||||
+ case SCP_CMD_CLOCK_SET_RATE: {
|
||||
+ uint32_t freq = mmio_read_32(payload_in + 4);
|
||||
+
|
||||
+ ret = sunxi_clock_set_rate(par1 & 0xffff, freq);
|
||||
+ if (ret < 0)
|
||||
+ return SCPI_E_RANGE;
|
||||
+ *payload_size = 0;
|
||||
+ return SCPI_OK;
|
||||
+ }
|
||||
+ case SCP_CMD_CLOCK_GET_RATE:
|
||||
+ ret = sunxi_clock_get_rate(par1 & 0xffff);
|
||||
+ if (ret == ~0)
|
||||
+ return SCPI_E_RANGE;
|
||||
+
|
||||
+ mmio_write_32(payload_out, ret);
|
||||
+ *payload_size = 4;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
return SCPI_E_SUPPORT;
|
140
patch/atf/atf-sun50iw1/04-implement-CPU-clock.patch
Normal file
140
patch/atf/atf-sun50iw1/04-implement-CPU-clock.patch
Normal file
|
@ -0,0 +1,140 @@
|
|||
From a641a3a8523759cc73a79d062d934949620ba72f Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Thu, 22 Jun 2017 02:17:40 +0100
|
||||
Subject: [PATCH] sunxi: clocks: implement CPU clock and export as an SCPI
|
||||
clock
|
||||
|
||||
Add functions to read and set the frequency of the (single) CPU clock,
|
||||
which is done via a register controlling the CPUX PLL.
|
||||
This replaces the hardcoded reset value for the safe 816 MHz by a call
|
||||
to that function.
|
||||
Also export the CPU clock via the SCPI interface, so that any OS can
|
||||
easily change that clock.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
plat/sun50iw1p1/bl31_sunxi_setup.c | 2 +-
|
||||
plat/sun50iw1p1/sunxi_clocks.c | 61 ++++++++++++++++++++++++++++++++++----
|
||||
plat/sun50iw1p1/sunxi_private.h | 2 ++
|
||||
3 files changed, 59 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/plat/sun50iw1p1/bl31_sunxi_setup.c b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
index 9e303f688..dc9b3435a 100644
|
||||
--- a/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
+++ b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
@@ -256,7 +256,7 @@ void bl31_platform_setup(void)
|
||||
|
||||
sunxi_setup_clocks(socid);
|
||||
|
||||
- NOTICE("SCPI: installed handler, implementation level: 100000\n");
|
||||
+ NOTICE("SCPI: installed handler, implementation level: 101000\n");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
diff --git a/plat/sun50iw1p1/sunxi_clocks.c b/plat/sun50iw1p1/sunxi_clocks.c
|
||||
index 1c5ec2975..21e3b7cf8 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_clocks.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_clocks.c
|
||||
@@ -33,9 +33,10 @@
|
||||
#include <ccmu.h>
|
||||
#include "sunxi_private.h"
|
||||
|
||||
-#define PLL_CPUX_1008MHZ 0x1410
|
||||
-#define PLL_CPUX_816MHZ 0x1010
|
||||
-#define PLL_CPUX_408MHZ 0x1000
|
||||
+#define INITIAL_CPU_FREQ 816
|
||||
+
|
||||
+#define MHz(f) ((f) * 1000000)
|
||||
+#define inMHz(mhzf) ((mhzf) / 1000000)
|
||||
|
||||
static void mmio_clrsetbits32(uintptr_t addr, uint32_t mask, uint32_t bits)
|
||||
{
|
||||
@@ -64,6 +65,27 @@ static int pll_wait_until_stable(uintptr_t addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int sunxi_clock_set_cpu_clock(uint32_t freq_mhz, int enable)
|
||||
+{
|
||||
+ int n, k = 1, m = 1, factor;
|
||||
+ uint32_t reg;
|
||||
+
|
||||
+ factor = freq_mhz / 24;
|
||||
+ if (factor < 10 || factor > 88)
|
||||
+ return -1;
|
||||
+
|
||||
+ for (n = factor; n > 33 && k < 5; ++k, n = factor / k)
|
||||
+ ;
|
||||
+
|
||||
+ reg = (m - 1) | ((k - 1) << 4) | ((n - 1) << 8);
|
||||
+ if (enable)
|
||||
+ reg |= PLL_ENABLE_BIT;
|
||||
+
|
||||
+ mmio_write_32(CCMU_PLL_CPUX_CTRL_REG, reg);
|
||||
+
|
||||
+ return 24 * n * k / m;
|
||||
+}
|
||||
+
|
||||
int sunxi_setup_clocks(uint16_t socid)
|
||||
{
|
||||
uint32_t reg;
|
||||
@@ -80,8 +102,8 @@ int sunxi_setup_clocks(uint16_t socid)
|
||||
AXI_CLKDIV(3) ));
|
||||
udelay(20);
|
||||
|
||||
- /* Set to 816MHz, but don't enable yet. */
|
||||
- mmio_write_32(CCMU_PLL_CPUX_CTRL_REG, PLL_CPUX_816MHZ);
|
||||
+ /* Setup the clock parameters, but don't enable yet. */
|
||||
+ sunxi_clock_set_cpu_clock(INITIAL_CPU_FREQ, 0);
|
||||
|
||||
/* Enable PLL_CPUX again */
|
||||
mmio_setbits32(CCMU_PLL_CPUX_CTRL_REG, PLL_ENABLE_BIT);
|
||||
@@ -116,7 +138,36 @@ struct scpi_clock {
|
||||
uint16_t clockid;
|
||||
};
|
||||
|
||||
+static uint32_t set_cpu_clk_rate(uint32_t reg_addr, uint32_t freq)
|
||||
+{
|
||||
+ return sunxi_clock_set_cpu_clock(inMHz(freq), 1);
|
||||
+}
|
||||
+
|
||||
+static uint32_t get_cpu_clk_rate(uint32_t reg_addr)
|
||||
+{
|
||||
+ uint32_t clkreg = mmio_read_32(reg_addr);
|
||||
+ int n, k, m, p;
|
||||
+
|
||||
+ if (!(clkreg & PLL_ENABLE_BIT))
|
||||
+ return 0;
|
||||
+
|
||||
+ n = ((clkreg >> 8) & 0x1f) + 1;
|
||||
+ k = ((clkreg >> 4) & 0x03) + 1;
|
||||
+ m = ((clkreg >> 0) & 0x03) + 1;
|
||||
+ p = 1 << ((clkreg >> 16) & 0x3);
|
||||
+
|
||||
+ return MHz(24) * n * k / (m * p);
|
||||
+}
|
||||
+
|
||||
+#define CPU_CLK_DESC \
|
||||
+ {.min_freq = MHz(240), .max_freq= MHz(1536), \
|
||||
+ .getter = get_cpu_clk_rate, .setter = set_cpu_clk_rate, \
|
||||
+ .reg_addr = CCMU_PLL_CPUX_CTRL_REG, \
|
||||
+ .name = "cpu_clk", \
|
||||
+ .clockid = 0 }
|
||||
+
|
||||
struct scpi_clock sunxi_clocks[] = {
|
||||
+ CPU_CLK_DESC,
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h
|
||||
index 08aeb94da..519422343 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_private.h
|
||||
+++ b/plat/sun50iw1p1/sunxi_private.h
|
||||
@@ -86,6 +86,8 @@ const char* sunxi_clock_get_name(int clocknr);
|
||||
uint32_t sunxi_clock_get_rate(int clocknr);
|
||||
int sunxi_clock_set_rate(int clocknr, uint32_t freq);
|
||||
|
||||
+int sunxi_clock_set_cpu_clock(uint32_t freq_mhz, int enable);
|
||||
+
|
||||
/* Gets the SPSR for BL33 entry */
|
||||
uint32_t sunxi_get_spsr_for_bl33_entry(int aarch);
|
||||
|
78
patch/atf/atf-sun50iw1/05-allow-setting-CPU-voltage.patch
Normal file
78
patch/atf/atf-sun50iw1/05-allow-setting-CPU-voltage.patch
Normal file
|
@ -0,0 +1,78 @@
|
|||
From 8d1687f42bf86fe8197950b86a50936e28054534 Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Sat, 10 Dec 2016 12:21:38 +0000
|
||||
Subject: [PATCH] sunxi: power: allow setting CPU voltage
|
||||
|
||||
Provide high level functions to allow programming certain voltages for
|
||||
the CPU cores. This calculates the respective AXP803 register value for
|
||||
the DCDC2/DCDC3 pair from a given voltage.
|
||||
Also this allow to turn the CPU cores off completely, to easily
|
||||
implement a shutdown functionality.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
plat/sun50iw1p1/sunxi_power.c | 30 ++++++++++++++++++++++++++++++
|
||||
plat/sun50iw1p1/sunxi_private.h | 2 ++
|
||||
2 files changed, 32 insertions(+)
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_power.c b/plat/sun50iw1p1/sunxi_power.c
|
||||
index 0c2487e20..095a0e757 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_power.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_power.c
|
||||
@@ -176,6 +176,31 @@ static void rsb_wait(const char *desc)
|
||||
ERROR("%s: 0x%x\n", desc, reg);
|
||||
}
|
||||
|
||||
+static int axp803_set_cpu_voltage(int millivolt)
|
||||
+{
|
||||
+ uint8_t reg;
|
||||
+
|
||||
+ if (millivolt <= 0) { /* power off system */
|
||||
+ sunxi_pmic_write(0x32, sunxi_pmic_read(0x32) | 0x80);
|
||||
+ return 0; /* hopefully not ... */
|
||||
+ }
|
||||
+
|
||||
+ if (millivolt < 800 || millivolt > 1300)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (millivolt > 1200)
|
||||
+ reg = (millivolt - 1200) / 20 + 70;
|
||||
+ else
|
||||
+ reg = (millivolt - 500) / 10 + 0;
|
||||
+
|
||||
+ sunxi_pmic_write(0x21, reg); /* DCDC2 */
|
||||
+
|
||||
+ while (!(sunxi_pmic_read(0x21) & 0x80))
|
||||
+ ;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/* Initialize the RSB PMIC connection. */
|
||||
static int pmic_init(uint16_t hw_addr, uint8_t rt_addr)
|
||||
{
|
||||
@@ -266,6 +291,11 @@ static int pmic_setup(void)
|
||||
|
||||
sunxi_pmic_write(0x15, 0x1a); /* DLDO1 = VCC3V3_HDMI voltage = 3.3V */
|
||||
|
||||
+ ret = sunxi_rsb_read(0x14);
|
||||
+ sunxi_rsb_write(0x14, ret | 0x40); /* DCDC2/3 dual phase */
|
||||
+
|
||||
+ axp803_set_cpu_voltage(1100);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h
|
||||
index 519422343..0c8b640bd 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_private.h
|
||||
+++ b/plat/sun50iw1p1/sunxi_private.h
|
||||
@@ -72,6 +72,8 @@ int sunxi_pmic_setup(void);
|
||||
int sunxi_pmic_read(uint8_t address);
|
||||
int sunxi_pmic_write(uint8_t address, uint8_t value);
|
||||
|
||||
+int sunxi_power_set_cpu_voltage(int millivolt);
|
||||
+
|
||||
void udelay(unsigned int delay);
|
||||
int sunxi_setup_clocks(uint16_t socid);
|
||||
|
34
patch/atf/atf-sun50iw1/06-refactor-poweroff.patch
Normal file
34
patch/atf/atf-sun50iw1/06-refactor-poweroff.patch
Normal file
|
@ -0,0 +1,34 @@
|
|||
From b3272daf1df2eb8b96654d2884eab391f85549ea Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Fri, 16 Dec 2016 01:32:36 +0000
|
||||
Subject: [PATCH] sunxi: power: move system power off into set_voltage()
|
||||
function
|
||||
|
||||
Instead of directly poking the appropriate AXP PMIC register to turn the
|
||||
voltage for the ARM CPU cores off completely, call the newly exported
|
||||
function to set the CPU voltage with a negative argument.
|
||||
This abstracts the power off functionality from the actual PMIC used.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
plat/sun50iw1p1/plat_pm.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/plat/sun50iw1p1/plat_pm.c b/plat/sun50iw1p1/plat_pm.c
|
||||
index ec26248e0..c2ef5a6b7 100644
|
||||
--- a/plat/sun50iw1p1/plat_pm.c
|
||||
+++ b/plat/sun50iw1p1/plat_pm.c
|
||||
@@ -254,8 +254,11 @@ static int32_t sunxi_affinst_suspend_finish(uint64_t mpidr,
|
||||
******************************************************************************/
|
||||
static void __dead2 sunxi_system_off(void)
|
||||
{
|
||||
- sunxi_pmic_write(0x32, sunxi_pmic_read(0x32) | 0x80);
|
||||
- ERROR("PSCI system shutdown: still alive ...\n");
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = sunxi_power_set_cpu_voltage(-1);
|
||||
+
|
||||
+ ERROR("PSCI system shutdown: %d: still alive ...\n", ret);
|
||||
|
||||
wfi();
|
||||
panic();
|
648
patch/atf/atf-sun50iw1/07-refactor-power-code.patch
Normal file
648
patch/atf/atf-sun50iw1/07-refactor-power-code.patch
Normal file
|
@ -0,0 +1,648 @@
|
|||
From 7f15fa4721edf35fa3eb6494c9518379eea4604d Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Sun, 19 Mar 2017 01:02:19 +0000
|
||||
Subject: [PATCH] sunxi: power: refactor power specific code into extra file
|
||||
|
||||
At the moment the power code mixes the code to access the RSB bus with
|
||||
the actual PMIC register control and setup via this bus.
|
||||
Separate those two to make the code more readable, also to provide
|
||||
better abstraction.
|
||||
This for instance later allows using I2C to control different PMICs,
|
||||
for instance.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
plat/sun50iw1p1/bl31_sunxi_setup.c | 8 +-
|
||||
plat/sun50iw1p1/platform.mk | 1 +
|
||||
plat/sun50iw1p1/sunxi_power.c | 278 +++++++++++--------------------------
|
||||
plat/sun50iw1p1/sunxi_private.h | 9 +-
|
||||
plat/sun50iw1p1/sunxi_rsb.c | 198 ++++++++++++++++++++++++++
|
||||
5 files changed, 286 insertions(+), 208 deletions(-)
|
||||
create mode 100644 plat/sun50iw1p1/sunxi_rsb.c
|
||||
|
||||
diff --git a/plat/sun50iw1p1/bl31_sunxi_setup.c b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
index dc9b3435a..7c1109f4e 100644
|
||||
--- a/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
+++ b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
@@ -246,13 +246,7 @@ void bl31_platform_setup(void)
|
||||
/* Detect if this SoC is a multi-cluster one. */
|
||||
plat_setup_topology();
|
||||
|
||||
- switch (socid) {
|
||||
- case 0x1689:
|
||||
- sunxi_pmic_setup();
|
||||
- break;
|
||||
- case 0x1718:
|
||||
- break;
|
||||
- }
|
||||
+ sunxi_power_setup(socid);
|
||||
|
||||
sunxi_setup_clocks(socid);
|
||||
|
||||
diff --git a/plat/sun50iw1p1/platform.mk b/plat/sun50iw1p1/platform.mk
|
||||
index 188e4e84d..95cff562f 100644
|
||||
--- a/plat/sun50iw1p1/platform.mk
|
||||
+++ b/plat/sun50iw1p1/platform.mk
|
||||
@@ -52,5 +52,6 @@ BL31_SOURCES += drivers/arm/gic/arm_gic.c \
|
||||
plat/sun50iw1p1/sunxi_clocks.c \
|
||||
plat/sun50iw1p1/sunxi_sip_svc.c \
|
||||
plat/sun50iw1p1/sunxi_scpi.c \
|
||||
+ plat/sun50iw1p1/sunxi_rsb.c \
|
||||
plat/sun50iw1p1/aarch64/sunxi_common.c
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_power.c b/plat/sun50iw1p1/sunxi_power.c
|
||||
index 095a0e757..5aa63fe4f 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_power.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_power.c
|
||||
@@ -35,153 +35,17 @@
|
||||
#include "sunxi_def.h"
|
||||
#include "sunxi_private.h"
|
||||
|
||||
-#define R_PRCM_BASE 0x1f01400ULL
|
||||
-#define R_TWI_BASE 0x1f02400ULL
|
||||
-#define R_PIO_BASE 0x1f02c00ULL
|
||||
-
|
||||
-#define RSB_BASE 0x1f03400ULL
|
||||
-#define RSB_CTRL 0x00
|
||||
-#define RSB_CCR 0x04
|
||||
-#define RSB_INTE 0x08
|
||||
-#define RSB_STAT 0x0c
|
||||
-#define RSB_DADDR0 0x10
|
||||
-#define RSB_DLEN 0x18
|
||||
-#define RSB_DATA0 0x1c
|
||||
-#define RSB_LCR 0x24
|
||||
-#define RSB_PMCR 0x28
|
||||
-#define RSB_CMD 0x2c
|
||||
-#define RSB_SADDR 0x30
|
||||
-
|
||||
-#define RSBCMD_SRTA 0xE8
|
||||
-#define RSBCMD_RD8 0x8B
|
||||
-#define RSBCMD_RD16 0x9C
|
||||
-#define RSBCMD_RD32 0xA6
|
||||
-#define RSBCMD_WR8 0x4E
|
||||
-#define RSBCMD_WR16 0x59
|
||||
-#define RSBCMD_WR32 0x63
|
||||
-
|
||||
#define BIT(n) (1U << (n))
|
||||
|
||||
#define RUNTIME_ADDR 0x2d
|
||||
#define AXP803_HW_ADDR 0x3a3
|
||||
|
||||
-/* Initialize the RSB controller and its pins. */
|
||||
-static int init_rsb(void)
|
||||
-{
|
||||
- uint32_t reg;
|
||||
-
|
||||
- /* un-gate PIO clock */
|
||||
- reg = mmio_read_32(R_PRCM_BASE + 0x28);
|
||||
- mmio_write_32(R_PRCM_BASE + 0x28, reg | 0x01);
|
||||
-
|
||||
- /* get currently configured function for pins PL0 and PL1 */
|
||||
- reg = mmio_read_32(R_PIO_BASE + 0x00);
|
||||
- if ((reg & 0xff) == 0x33) {
|
||||
- NOTICE("already configured for TWI\n");
|
||||
- return -EBUSY;
|
||||
- }
|
||||
-
|
||||
- if ((reg & 0xff) == 0x22) {
|
||||
- NOTICE("PMIC: already configured for RSB\n");
|
||||
- return -EEXIST; /* configured for RSB mode already */
|
||||
- }
|
||||
-
|
||||
- /* switch pins PL0 and PL1 to RSB */
|
||||
- mmio_write_32(R_PIO_BASE + 0, (reg & ~0xff) | 0x22);
|
||||
-
|
||||
- /* level 2 drive strength */
|
||||
- reg = mmio_read_32(R_PIO_BASE + 0x14);
|
||||
- mmio_write_32(R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa);
|
||||
-
|
||||
- /* set both ports to pull-up */
|
||||
- reg = mmio_read_32(R_PIO_BASE + 0x1c);
|
||||
- mmio_write_32(R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5);
|
||||
-
|
||||
- /* assert & de-assert reset of RSB */
|
||||
- reg = mmio_read_32(R_PRCM_BASE + 0xb0);
|
||||
- mmio_write_32(R_PRCM_BASE + 0xb0, reg & ~0x08);
|
||||
- reg = mmio_read_32(R_PRCM_BASE + 0xb0);
|
||||
- mmio_write_32(R_PRCM_BASE + 0xb0, reg | 0x08);
|
||||
-
|
||||
- /* un-gate RSB clock */
|
||||
- reg = mmio_read_32(R_PRCM_BASE + 0x28);
|
||||
- mmio_write_32(R_PRCM_BASE + 0x28, reg | 0x08);
|
||||
-
|
||||
- mmio_write_32(RSB_BASE + RSB_CTRL, 0x01); /* soft reset */
|
||||
-
|
||||
- mmio_write_32(RSB_BASE + RSB_CCR, 0x11d); /* clock to 400 KHz */
|
||||
-
|
||||
- do {
|
||||
- reg = mmio_read_32(RSB_BASE + RSB_CTRL);
|
||||
- } while (reg & 1); /* transaction in progress */
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-int sunxi_pmic_read(uint8_t address)
|
||||
-{
|
||||
- uint32_t reg;
|
||||
-
|
||||
- mmio_write_32(RSB_BASE + RSB_DLEN, 0x10); /* read a byte, snake oil? */
|
||||
- mmio_write_32(RSB_BASE + RSB_CMD, RSBCMD_RD8); /* read a byte */
|
||||
- mmio_write_32(RSB_BASE + RSB_DADDR0, address);
|
||||
- mmio_write_32(RSB_BASE + RSB_CTRL, 0x80); /* start transaction */
|
||||
- do {
|
||||
- reg = mmio_read_32(RSB_BASE + RSB_CTRL);
|
||||
- } while (reg & 0x80); /* transaction in progress */
|
||||
-
|
||||
- reg = mmio_read_32(RSB_BASE + RSB_STAT);
|
||||
- if (reg == 0x01) { /* transaction complete */
|
||||
- reg = mmio_read_32(RSB_BASE + RSB_DATA0); /* result register */
|
||||
- return reg & 0xff;
|
||||
- }
|
||||
-
|
||||
- return -reg;
|
||||
-}
|
||||
-
|
||||
-int sunxi_pmic_write(uint8_t address, uint8_t value)
|
||||
-{
|
||||
- uint32_t reg;
|
||||
-
|
||||
- mmio_write_32(RSB_BASE + RSB_DLEN, 0x00); /* write a byte, snake oil? */
|
||||
- mmio_write_32(RSB_BASE + RSB_CMD, RSBCMD_WR8); /* write a byte */
|
||||
- mmio_write_32(RSB_BASE + RSB_DADDR0, address);
|
||||
- mmio_write_32(RSB_BASE + RSB_DATA0, value);
|
||||
- mmio_write_32(RSB_BASE + RSB_CTRL, 0x80); /* start transaction */
|
||||
- do {
|
||||
- reg = mmio_read_32(RSB_BASE + RSB_CTRL);
|
||||
- } while (reg & 0x80); /* transaction in progress */
|
||||
-
|
||||
- reg = mmio_read_32(RSB_BASE + RSB_STAT);
|
||||
- if (reg == 0x01) /* transaction complete */
|
||||
- return 0;
|
||||
-
|
||||
- return -reg;
|
||||
-}
|
||||
-
|
||||
-static void rsb_wait(const char *desc)
|
||||
-{
|
||||
- uint32_t reg;
|
||||
- int cnt = 0;
|
||||
-
|
||||
- do {
|
||||
- reg = mmio_read_32(RSB_BASE + RSB_CTRL);
|
||||
- cnt++;
|
||||
- } while (reg & 0x80); /* transaction in progress */
|
||||
-
|
||||
- reg = mmio_read_32(RSB_BASE + RSB_STAT);
|
||||
- if (reg == 0x01)
|
||||
- return;
|
||||
-
|
||||
- ERROR("%s: 0x%x\n", desc, reg);
|
||||
-}
|
||||
-
|
||||
static int axp803_set_cpu_voltage(int millivolt)
|
||||
{
|
||||
uint8_t reg;
|
||||
|
||||
if (millivolt <= 0) { /* power off system */
|
||||
- sunxi_pmic_write(0x32, sunxi_pmic_read(0x32) | 0x80);
|
||||
+ sunxi_rsb_write(0x32, sunxi_rsb_read(0x32) | 0x80);
|
||||
return 0; /* hopefully not ... */
|
||||
}
|
||||
|
||||
@@ -193,56 +57,30 @@ static int axp803_set_cpu_voltage(int millivolt)
|
||||
else
|
||||
reg = (millivolt - 500) / 10 + 0;
|
||||
|
||||
- sunxi_pmic_write(0x21, reg); /* DCDC2 */
|
||||
+ sunxi_rsb_write(0x21, reg); /* DCDC2 */
|
||||
|
||||
- while (!(sunxi_pmic_read(0x21) & 0x80))
|
||||
+ while (!(sunxi_rsb_read(0x21) & 0x80))
|
||||
;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
-/* Initialize the RSB PMIC connection. */
|
||||
-static int pmic_init(uint16_t hw_addr, uint8_t rt_addr)
|
||||
-{
|
||||
- int ret;
|
||||
-
|
||||
- /* Switch PMIC to RSB mode */
|
||||
- mmio_write_32(RSB_BASE + RSB_PMCR,
|
||||
- 0x00 | (0x3e << 8) | (0x7c << 16) | BIT(31));
|
||||
- do {
|
||||
- ret = mmio_read_32(RSB_BASE + RSB_PMCR);
|
||||
- } while (ret & (1U << 31)); /* transaction in progress */
|
||||
-
|
||||
- mmio_write_32(RSB_BASE + RSB_CCR, 0x103); /* 3 MHz */
|
||||
-
|
||||
- mmio_write_32(RSB_BASE + RSB_SADDR, hw_addr | (rt_addr << 16));
|
||||
- mmio_write_32(RSB_BASE + RSB_CMD, RSBCMD_SRTA);
|
||||
- mmio_write_32(RSB_BASE + RSB_CTRL, 0x80);
|
||||
- rsb_wait("set run-time address");
|
||||
-
|
||||
- /* Set slave runtime address */
|
||||
- mmio_write_32(RSB_BASE + RSB_SADDR, rt_addr << 16);
|
||||
-
|
||||
- ret = sunxi_pmic_read(0x03);
|
||||
- if (ret < 0) {
|
||||
- ERROR("PMIC: error %d reading PMIC type\n", ret);
|
||||
- return -2;
|
||||
- }
|
||||
-
|
||||
- if ((ret & 0xcf) != 0x41) {
|
||||
- ERROR("PMIC: unknown PMIC type number 0x%x\n", ret);
|
||||
- return -3;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-/* Setup the PMIC: DCDC1 to 3.3V, enable DC1SW and DLDO4 */
|
||||
-static int pmic_setup(void)
|
||||
+/*
|
||||
+ * Initial PMIC setup for boards using the AXP803 PMIC.
|
||||
+ * DCDC1 must be corrected to 3.3 volts. Also we enable:
|
||||
+ * - DC1SW: Ethernet PHY on most boards
|
||||
+ * - DLDO1: HDMI power
|
||||
+ * - DLDO4: WiFi power
|
||||
+ * Technically those should be enabled by the users (via SCPI), but until
|
||||
+ * U-Boot learns how to do this we do it here.
|
||||
+ * Also this contains a quirk to fix the DRAM voltage on Pine64 boards,
|
||||
+ * which have a wrong default (1.24V instead of 1.36V).
|
||||
+ */
|
||||
+static int axp803_initial_setup(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
- ret = sunxi_pmic_read(0x20);
|
||||
+ ret = sunxi_rsb_read(0x20);
|
||||
if (ret != 0x0e && ret != 0x11) {
|
||||
int voltage = (ret & 0x1f) * 10 + 16;
|
||||
|
||||
@@ -253,14 +91,14 @@ static int pmic_setup(void)
|
||||
|
||||
if (ret != 0x11) {
|
||||
/* Set DCDC1 voltage to 3.3 Volts */
|
||||
- ret = sunxi_pmic_write(0x20, 0x11);
|
||||
+ ret = sunxi_rsb_write(0x20, 0x11);
|
||||
if (ret < 0) {
|
||||
NOTICE("PMIC: error %d writing DCDC1 voltage\n", ret);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
- ret = sunxi_pmic_read(0x12);
|
||||
+ ret = sunxi_rsb_read(0x12);
|
||||
if ((ret & 0x37) != 0x01) {
|
||||
NOTICE("PMIC: Output power control 2 is an unexpected 0x%x\n",
|
||||
ret);
|
||||
@@ -268,10 +106,12 @@ static int pmic_setup(void)
|
||||
}
|
||||
|
||||
if ((ret & 0xc9) != 0xc9) {
|
||||
- /* Enable DC1SW to power PHY, DLDO4 for WiFi and DLDO1 for HDMI */
|
||||
- ret = sunxi_pmic_write(0x12, ret | 0xc8);
|
||||
+ /* Enable DC1SW to power PHY, DLDO4 for WiFi, DLDO1 for HDMI */
|
||||
+ /* TODO: keep WiFi disabled, as not needed in U-Boot? */
|
||||
+ ret = sunxi_rsb_write(0x12, ret | 0xc8);
|
||||
if (ret < 0) {
|
||||
- NOTICE("PMIC: error %d enabling DC1SW/DLDO4/DLDO1\n", ret);
|
||||
+ NOTICE("PMIC: error %d enabling DC1SW/DLDO4/DLDO1\n",
|
||||
+ ret);
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
@@ -283,13 +123,13 @@ static int pmic_setup(void)
|
||||
* changes. This should be further confined once we are able to
|
||||
* reliably detect a Pine64 board.
|
||||
*/
|
||||
- ret = sunxi_pmic_read(0x24); /* read DCDC5 register */
|
||||
+ ret = sunxi_rsb_read(0x24); /* read DCDC5 register */
|
||||
if ((ret & 0x7f) == 0x26) { /* check for 1.24V value */
|
||||
NOTICE("PMIC: fixing DRAM voltage from 1.24V to 1.36V\n");
|
||||
- sunxi_pmic_write(0x24, 0x2c);
|
||||
+ sunxi_rsb_write(0x24, 0x2c);
|
||||
}
|
||||
|
||||
- sunxi_pmic_write(0x15, 0x1a); /* DLDO1 = VCC3V3_HDMI voltage = 3.3V */
|
||||
+ sunxi_rsb_write(0x15, 0x1a); /* DLDO1 = VCC3V3_HDMI voltage = 3.3V */
|
||||
|
||||
ret = sunxi_rsb_read(0x14);
|
||||
sunxi_rsb_write(0x14, ret | 0x40); /* DCDC2/3 dual phase */
|
||||
@@ -302,31 +142,69 @@ static int pmic_setup(void)
|
||||
/*
|
||||
* Program the AXP803 via the RSB bus.
|
||||
*/
|
||||
-int sunxi_pmic_setup(void)
|
||||
+static int axp803_probe(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
- NOTICE("Configuring AXP PMIC\n");
|
||||
-
|
||||
- ret = init_rsb();
|
||||
+ ret = sunxi_rsb_init();
|
||||
if (ret && ret != -EEXIST) {
|
||||
ERROR("Could not init RSB controller.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
- if (ret != -EEXIST) {
|
||||
- ret = pmic_init(AXP803_HW_ADDR, RUNTIME_ADDR);
|
||||
+ if (ret == -EEXIST)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = sunxi_rsb_configure(AXP803_HW_ADDR, RUNTIME_ADDR);
|
||||
+ if (ret) {
|
||||
+ ERROR("Could not configure RSB.\n");
|
||||
+ return -2;
|
||||
+ }
|
||||
+ ret = sunxi_rsb_read(0x03);
|
||||
+ if (ret < 0) {
|
||||
+ ERROR("PMIC: error %d reading PMIC type\n", ret);
|
||||
+ return -2;
|
||||
+ }
|
||||
+ if ((ret & 0xcf) != 0x41) {
|
||||
+ ERROR("PMIC: unknown PMIC type number 0x%x\n", ret);
|
||||
+ return -3;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+enum pmic_type {
|
||||
+ PMIC_AXP803,
|
||||
+} pmic_type;
|
||||
+
|
||||
+int sunxi_power_setup(uint16_t socid)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ switch (socid) {
|
||||
+ case 0x1689:
|
||||
+ pmic_type = PMIC_AXP803;
|
||||
+
|
||||
+ NOTICE("PMIC: Probing for AXP803 on A64\n");
|
||||
+ ret = axp803_probe();
|
||||
if (ret) {
|
||||
- ERROR("Could not connect to AXP PMIC.\n");
|
||||
- return -2;
|
||||
+ ERROR("PMIC: AXP803 initialization failed: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ ret = axp803_initial_setup();
|
||||
+ if (ret) {
|
||||
+ ERROR("PMIC: AXP803 power setup failed: %d\n", ret);
|
||||
+ return ret;
|
||||
}
|
||||
+ NOTICE("PMIC: AXP803 successfully setup\n");
|
||||
+ break;
|
||||
+ case 0x1718:
|
||||
+ ret = -ENXIO;
|
||||
+ break;
|
||||
+ default:
|
||||
+ NOTICE("power setup not defined for SoC 0x%04x\n", socid);
|
||||
+ ret = -ENODEV;
|
||||
}
|
||||
|
||||
- ret = pmic_setup();
|
||||
- if (!ret)
|
||||
- NOTICE("PMIC: setup successful\n");
|
||||
- else
|
||||
- ERROR("PMIC: setup failed: %d\n", ret);
|
||||
-
|
||||
return ret;
|
||||
}
|
||||
diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h
|
||||
index 0c8b640bd..07a329598 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_private.h
|
||||
+++ b/plat/sun50iw1p1/sunxi_private.h
|
||||
@@ -71,7 +71,7 @@ void sunxi_security_setup(void);
|
||||
int sunxi_pmic_setup(void);
|
||||
int sunxi_pmic_read(uint8_t address);
|
||||
int sunxi_pmic_write(uint8_t address, uint8_t value);
|
||||
-
|
||||
+int sunxi_power_setup(uint16_t socid);
|
||||
int sunxi_power_set_cpu_voltage(int millivolt);
|
||||
|
||||
void udelay(unsigned int delay);
|
||||
@@ -90,6 +90,13 @@ int sunxi_clock_set_rate(int clocknr, uint32_t freq);
|
||||
|
||||
int sunxi_clock_set_cpu_clock(uint32_t freq_mhz, int enable);
|
||||
|
||||
+/* Declarations for sunxi_rsb.c */
|
||||
+int sunxi_rsb_init(void);
|
||||
+int sunxi_rsb_read(uint8_t address);
|
||||
+int sunxi_rsb_write(uint8_t address, uint8_t value);
|
||||
+void sunxi_rsb_wait(const char *desc);
|
||||
+int sunxi_rsb_configure(uint16_t hw_addr, uint8_t rt_addr);
|
||||
+
|
||||
/* Gets the SPSR for BL33 entry */
|
||||
uint32_t sunxi_get_spsr_for_bl33_entry(int aarch);
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_rsb.c b/plat/sun50iw1p1/sunxi_rsb.c
|
||||
new file mode 100644
|
||||
index 000000000..098c8ad0f
|
||||
--- /dev/null
|
||||
+++ b/plat/sun50iw1p1/sunxi_rsb.c
|
||||
@@ -0,0 +1,198 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2017 ARM Limited and Contributors. All rights reserved.
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions are met:
|
||||
+ *
|
||||
+ * Redistributions of source code must retain the above copyright notice, this
|
||||
+ * list of conditions and the following disclaimer.
|
||||
+ *
|
||||
+ * Redistributions in binary form must reproduce the above copyright notice,
|
||||
+ * this list of conditions and the following disclaimer in the documentation
|
||||
+ * and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * Neither the name of ARM nor the names of its contributors may be used
|
||||
+ * to endorse or promote products derived from this software without specific
|
||||
+ * prior written permission.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||
+ */
|
||||
+
|
||||
+#include <debug.h>
|
||||
+#include <plat_config.h>
|
||||
+#include <mmio.h>
|
||||
+#include <sys/errno.h>
|
||||
+#include "sunxi_def.h"
|
||||
+#include "sunxi_private.h"
|
||||
+
|
||||
+#define R_PRCM_BASE 0x1f01400ULL
|
||||
+#define R_TWI_BASE 0x1f02400ULL
|
||||
+#define R_PIO_BASE 0x1f02c00ULL
|
||||
+
|
||||
+#define RSB_BASE 0x1f03400ULL
|
||||
+#define RSB_CTRL 0x00
|
||||
+#define RSB_CCR 0x04
|
||||
+#define RSB_INTE 0x08
|
||||
+#define RSB_STAT 0x0c
|
||||
+#define RSB_DADDR0 0x10
|
||||
+#define RSB_DLEN 0x18
|
||||
+#define RSB_DATA0 0x1c
|
||||
+#define RSB_LCR 0x24
|
||||
+#define RSB_PMCR 0x28
|
||||
+#define RSB_CMD 0x2c
|
||||
+#define RSB_SADDR 0x30
|
||||
+
|
||||
+#define RSBCMD_SRTA 0xE8
|
||||
+#define RSBCMD_RD8 0x8B
|
||||
+#define RSBCMD_RD16 0x9C
|
||||
+#define RSBCMD_RD32 0xA6
|
||||
+#define RSBCMD_WR8 0x4E
|
||||
+#define RSBCMD_WR16 0x59
|
||||
+#define RSBCMD_WR32 0x63
|
||||
+
|
||||
+#define BIT(n) (1U << (n))
|
||||
+
|
||||
+/* Initialize the RSB controller and its pins. */
|
||||
+int sunxi_rsb_init(void)
|
||||
+{
|
||||
+ uint32_t reg;
|
||||
+
|
||||
+ /* un-gate PIO clock */
|
||||
+ reg = mmio_read_32(R_PRCM_BASE + 0x28);
|
||||
+ mmio_write_32(R_PRCM_BASE + 0x28, reg | 0x01);
|
||||
+
|
||||
+ /* get currently configured function for pins PL0 and PL1 */
|
||||
+ reg = mmio_read_32(R_PIO_BASE + 0x00);
|
||||
+ if ((reg & 0xff) == 0x33) {
|
||||
+ NOTICE("already configured for TWI\n");
|
||||
+ return -EBUSY;
|
||||
+ }
|
||||
+
|
||||
+ if ((reg & 0xff) == 0x22) {
|
||||
+ NOTICE("PMIC: already configured for RSB\n");
|
||||
+ return -EEXIST; /* configured for RSB mode already */
|
||||
+ }
|
||||
+
|
||||
+ /* switch pins PL0 and PL1 to RSB */
|
||||
+ mmio_write_32(R_PIO_BASE + 0, (reg & ~0xff) | 0x22);
|
||||
+
|
||||
+ /* level 2 drive strength */
|
||||
+ reg = mmio_read_32(R_PIO_BASE + 0x14);
|
||||
+ mmio_write_32(R_PIO_BASE + 0x14, (reg & ~0x0f) | 0xa);
|
||||
+
|
||||
+ /* set both ports to pull-up */
|
||||
+ reg = mmio_read_32(R_PIO_BASE + 0x1c);
|
||||
+ mmio_write_32(R_PIO_BASE + 0x1c, (reg & ~0x0f) | 0x5);
|
||||
+
|
||||
+ /* assert & de-assert reset of RSB */
|
||||
+ reg = mmio_read_32(R_PRCM_BASE + 0xb0);
|
||||
+ mmio_write_32(R_PRCM_BASE + 0xb0, reg & ~0x08);
|
||||
+ reg = mmio_read_32(R_PRCM_BASE + 0xb0);
|
||||
+ mmio_write_32(R_PRCM_BASE + 0xb0, reg | 0x08);
|
||||
+
|
||||
+ /* un-gate RSB clock */
|
||||
+ reg = mmio_read_32(R_PRCM_BASE + 0x28);
|
||||
+ mmio_write_32(R_PRCM_BASE + 0x28, reg | 0x08);
|
||||
+
|
||||
+ mmio_write_32(RSB_BASE + RSB_CTRL, 0x01); /* soft reset */
|
||||
+
|
||||
+ mmio_write_32(RSB_BASE + RSB_CCR, 0x11d); /* clock to 400 KHz */
|
||||
+
|
||||
+ do {
|
||||
+ reg = mmio_read_32(RSB_BASE + RSB_CTRL);
|
||||
+ } while (reg & 1); /* transaction in progress */
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int sunxi_rsb_read(uint8_t address)
|
||||
+{
|
||||
+ uint32_t reg;
|
||||
+
|
||||
+ mmio_write_32(RSB_BASE + RSB_DLEN, 0x10); /* read a byte, snake oil? */
|
||||
+ mmio_write_32(RSB_BASE + RSB_CMD, RSBCMD_RD8); /* read a byte */
|
||||
+ mmio_write_32(RSB_BASE + RSB_DADDR0, address);
|
||||
+ mmio_write_32(RSB_BASE + RSB_CTRL, 0x80); /* start transaction */
|
||||
+ do {
|
||||
+ reg = mmio_read_32(RSB_BASE + RSB_CTRL);
|
||||
+ } while (reg & 0x80); /* transaction in progress */
|
||||
+
|
||||
+ reg = mmio_read_32(RSB_BASE + RSB_STAT);
|
||||
+ if (reg == 0x01) { /* transaction complete */
|
||||
+ reg = mmio_read_32(RSB_BASE + RSB_DATA0); /* result register */
|
||||
+ return reg & 0xff;
|
||||
+ }
|
||||
+
|
||||
+ return -reg;
|
||||
+}
|
||||
+
|
||||
+int sunxi_rsb_write(uint8_t address, uint8_t value)
|
||||
+{
|
||||
+ uint32_t reg;
|
||||
+
|
||||
+ mmio_write_32(RSB_BASE + RSB_DLEN, 0x00); /* write a byte, snake oil? */
|
||||
+ mmio_write_32(RSB_BASE + RSB_CMD, RSBCMD_WR8); /* write a byte */
|
||||
+ mmio_write_32(RSB_BASE + RSB_DADDR0, address);
|
||||
+ mmio_write_32(RSB_BASE + RSB_DATA0, value);
|
||||
+ mmio_write_32(RSB_BASE + RSB_CTRL, 0x80); /* start transaction */
|
||||
+ do {
|
||||
+ reg = mmio_read_32(RSB_BASE + RSB_CTRL);
|
||||
+ } while (reg & 0x80); /* transaction in progress */
|
||||
+
|
||||
+ reg = mmio_read_32(RSB_BASE + RSB_STAT);
|
||||
+ if (reg == 0x01) /* transaction complete */
|
||||
+ return 0;
|
||||
+
|
||||
+ return -reg;
|
||||
+}
|
||||
+
|
||||
+void sunxi_rsb_wait(const char *desc)
|
||||
+{
|
||||
+ uint32_t reg;
|
||||
+ int cnt = 0;
|
||||
+
|
||||
+ do {
|
||||
+ reg = mmio_read_32(RSB_BASE + RSB_CTRL);
|
||||
+ cnt++;
|
||||
+ } while (reg & 0x80); /* transaction in progress */
|
||||
+
|
||||
+ reg = mmio_read_32(RSB_BASE + RSB_STAT);
|
||||
+ if (reg == 0x01)
|
||||
+ return;
|
||||
+
|
||||
+ ERROR("%s: 0x%x\n", desc, reg);
|
||||
+}
|
||||
+
|
||||
+/* Initialize the RSB PMIC connection. */
|
||||
+int sunxi_rsb_configure(uint16_t hw_addr, uint8_t rt_addr)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ mmio_write_32(RSB_BASE + RSB_PMCR,
|
||||
+ 0x00 | (0x3e << 8) | (0x7c << 16) | BIT(31));
|
||||
+
|
||||
+ do {
|
||||
+ ret = mmio_read_32(RSB_BASE + RSB_PMCR);
|
||||
+ } while (ret & (1U << 31)); /* transaction in progress */
|
||||
+
|
||||
+ mmio_write_32(RSB_BASE + RSB_CCR, 0x103); /* 3 MHz */
|
||||
+ mmio_write_32(RSB_BASE + RSB_SADDR, hw_addr | (rt_addr << 16));
|
||||
+ mmio_write_32(RSB_BASE + RSB_CMD, RSBCMD_SRTA);
|
||||
+ mmio_write_32(RSB_BASE + RSB_CTRL, 0x80);
|
||||
+ sunxi_rsb_wait("set run-time address");
|
||||
+
|
||||
+ /* Set slave runtime address */
|
||||
+ mmio_write_32(RSB_BASE + RSB_SADDR, rt_addr << 16);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
195
patch/atf/atf-sun50iw1/08-add-DVFS.patch
Normal file
195
patch/atf/atf-sun50iw1/08-add-DVFS.patch
Normal file
|
@ -0,0 +1,195 @@
|
|||
From e2b4f43ae7c138f3502e3df4e3928827a169592b Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Sat, 10 Dec 2016 12:22:49 +0000
|
||||
Subject: [PATCH] sunxi: SCPI: add DVFS functionality
|
||||
|
||||
DVFS (dynamic voltage and frequency scaling) allows an OS to set certain
|
||||
CPU operating points described by a pair of frequency and required voltage.
|
||||
Using the recently introduced wrappers for the CPU voltage and the PLL
|
||||
frequency implement the required SCPI boilerplate to export those
|
||||
operating points and allow an OS to choose from a provided list.
|
||||
The actual frequency/voltage data used here is taken from Allwinner's BSP
|
||||
code, which seems to provide stable and sensible values.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
plat/sun50iw1p1/bl31_sunxi_setup.c | 2 +-
|
||||
plat/sun50iw1p1/platform.mk | 1 +
|
||||
plat/sun50iw1p1/sunxi_dvfs.c | 65 ++++++++++++++++++++++++++++++++++++++
|
||||
plat/sun50iw1p1/sunxi_private.h | 7 ++++
|
||||
plat/sun50iw1p1/sunxi_scpi.c | 35 ++++++++++++++++++++
|
||||
5 files changed, 109 insertions(+), 1 deletion(-)
|
||||
create mode 100644 plat/sun50iw1p1/sunxi_dvfs.c
|
||||
|
||||
diff --git a/plat/sun50iw1p1/bl31_sunxi_setup.c b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
index 7c1109f4e..4c480e545 100644
|
||||
--- a/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
+++ b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
@@ -250,7 +250,7 @@ void bl31_platform_setup(void)
|
||||
|
||||
sunxi_setup_clocks(socid);
|
||||
|
||||
- NOTICE("SCPI: installed handler, implementation level: 101000\n");
|
||||
+ NOTICE("SCPI: installed handler, implementation level: 111000\n");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
diff --git a/plat/sun50iw1p1/platform.mk b/plat/sun50iw1p1/platform.mk
|
||||
index 95cff562f..f56e79355 100644
|
||||
--- a/plat/sun50iw1p1/platform.mk
|
||||
+++ b/plat/sun50iw1p1/platform.mk
|
||||
@@ -53,5 +53,6 @@ BL31_SOURCES += drivers/arm/gic/arm_gic.c \
|
||||
plat/sun50iw1p1/sunxi_sip_svc.c \
|
||||
plat/sun50iw1p1/sunxi_scpi.c \
|
||||
plat/sun50iw1p1/sunxi_rsb.c \
|
||||
+ plat/sun50iw1p1/sunxi_dvfs.c \
|
||||
plat/sun50iw1p1/aarch64/sunxi_common.c
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_dvfs.c b/plat/sun50iw1p1/sunxi_dvfs.c
|
||||
new file mode 100644
|
||||
index 000000000..16049e968
|
||||
--- /dev/null
|
||||
+++ b/plat/sun50iw1p1/sunxi_dvfs.c
|
||||
@@ -0,0 +1,65 @@
|
||||
+#include <debug.h>
|
||||
+#include <plat_config.h>
|
||||
+#include <mmio.h>
|
||||
+#include <sys/errno.h>
|
||||
+
|
||||
+#include "sunxi_def.h"
|
||||
+#include "sunxi_private.h"
|
||||
+
|
||||
+struct op_points
|
||||
+{
|
||||
+ uint32_t freq;
|
||||
+ uint32_t voltage;
|
||||
+} sunxi_op_points[] = {
|
||||
+ { 408, 1000}, { 648, 1040}, { 816, 1080}, { 912, 1120}, { 960, 1160},
|
||||
+ {1008, 1200}, {1056, 1240}, {1104, 1260}, {1152, 1300}
|
||||
+};
|
||||
+
|
||||
+#define NR_OPP (sizeof(sunxi_op_points) / sizeof(sunxi_op_points[0]))
|
||||
+
|
||||
+int current_opp_index = 2;
|
||||
+int current_opp_limit = NR_OPP;
|
||||
+
|
||||
+uint32_t sunxi_dvfs_get_get_opp_voltage(int oppnr)
|
||||
+{
|
||||
+ if (oppnr < 0 || oppnr >= NR_OPP)
|
||||
+ return ~0;
|
||||
+
|
||||
+ return sunxi_op_points[oppnr].voltage;
|
||||
+}
|
||||
+
|
||||
+uint32_t sunxi_dvfs_get_get_opp_frequency(int oppnr)
|
||||
+{
|
||||
+ if (oppnr < 0 || oppnr >= NR_OPP)
|
||||
+ return ~0;
|
||||
+
|
||||
+ return sunxi_op_points[oppnr].freq * 1000000;
|
||||
+}
|
||||
+
|
||||
+int sunxi_dvfs_set_index(int index)
|
||||
+{
|
||||
+ if (index < 0 || index >= NR_OPP)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (index < current_opp_index) {
|
||||
+ sunxi_clock_set_cpu_clock(sunxi_op_points[index].freq, 1);
|
||||
+ sunxi_power_set_cpu_voltage(sunxi_op_points[index].voltage);
|
||||
+ } else {
|
||||
+ sunxi_power_set_cpu_voltage(sunxi_op_points[index].voltage);
|
||||
+ sunxi_clock_set_cpu_clock(sunxi_op_points[index].freq, 1);
|
||||
+ }
|
||||
+
|
||||
+ current_opp_index = index;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int sunxi_dvfs_get_index(void)
|
||||
+{
|
||||
+ return current_opp_index;
|
||||
+}
|
||||
+
|
||||
+int sunxi_dvfs_get_nr_opp(void)
|
||||
+{
|
||||
+ return NR_OPP;
|
||||
+}
|
||||
diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h
|
||||
index 07a329598..b98400107 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_private.h
|
||||
+++ b/plat/sun50iw1p1/sunxi_private.h
|
||||
@@ -97,6 +97,13 @@ int sunxi_rsb_write(uint8_t address, uint8_t value);
|
||||
void sunxi_rsb_wait(const char *desc);
|
||||
int sunxi_rsb_configure(uint16_t hw_addr, uint8_t rt_addr);
|
||||
|
||||
+/* Declarations for sunxi_dvfs.c */
|
||||
+uint32_t sunxi_dvfs_get_get_opp_voltage(int oppnr);
|
||||
+uint32_t sunxi_dvfs_get_get_opp_frequency(int oppnr);
|
||||
+int sunxi_dvfs_set_index(int index);
|
||||
+int sunxi_dvfs_get_index(void);
|
||||
+int sunxi_dvfs_get_nr_opp(void);
|
||||
+
|
||||
/* Gets the SPSR for BL33 entry */
|
||||
uint32_t sunxi_get_spsr_for_bl33_entry(int aarch);
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_scpi.c b/plat/sun50iw1p1/sunxi_scpi.c
|
||||
index 3ca287ed2..50aabeb27 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_scpi.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_scpi.c
|
||||
@@ -53,12 +53,18 @@
|
||||
#define SCPI_E_BUSY 12
|
||||
|
||||
#define SCP_CMD_CAPABILITY 0x02
|
||||
+#define SCP_CMD_DVFS_CAPABILITY 0x08
|
||||
+#define SCP_CMD_DVFS_GET_INFO 0x09
|
||||
+#define SCP_CMD_DVFS_SET_INDEX 0x0a
|
||||
+#define SCP_CMD_DVFS_GET_INDEX 0x0b
|
||||
+#define SCP_CMD_DVFS_GET_STAT 0x0c
|
||||
#define SCP_CMD_CLOCKS_CAPS 0x0d
|
||||
#define SCP_CMD_CLOCK_GET_INFO 0x0e
|
||||
#define SCP_CMD_CLOCK_SET_RATE 0x0f
|
||||
#define SCP_CMD_CLOCK_GET_RATE 0x10
|
||||
|
||||
#define SCP_CMDS_IMPLEMENTED \
|
||||
+ GENMASK(SCP_CMD_DVFS_GET_INDEX, SCP_CMD_DVFS_CAPABILITY) | \
|
||||
GENMASK(SCP_CMD_CLOCK_GET_RATE, SCP_CMD_CLOCKS_CAPS)
|
||||
|
||||
/* end of SRAM A1 */
|
||||
@@ -141,6 +147,35 @@ static uint32_t scpi_handle_cmd(int cmd, uint8_t *payload_size,
|
||||
mmio_write_32(payload_out, ret);
|
||||
*payload_size = 4;
|
||||
return 0;
|
||||
+ case SCP_CMD_DVFS_CAPABILITY:
|
||||
+ /* number of implemented voltage domains: only one */
|
||||
+ mmio_write_32(payload_out, 1);
|
||||
+ *payload_size = 0x1;
|
||||
+ return SCPI_OK;
|
||||
+ case SCP_CMD_DVFS_GET_INFO: {
|
||||
+ int i, nr_opp = sunxi_dvfs_get_nr_opp();
|
||||
+
|
||||
+ mmio_write_32(payload_out, nr_opp << 8);
|
||||
+ for (i = 0; i < nr_opp; i++) {
|
||||
+ mmio_write_32(payload_out + 4 + 2 * i * 4,
|
||||
+ sunxi_dvfs_get_get_opp_frequency(i));
|
||||
+ mmio_write_32(payload_out + 4 + 2 * i * 4 + 4,
|
||||
+ sunxi_dvfs_get_get_opp_voltage(i));
|
||||
+ }
|
||||
+ *payload_size = 4 + 2 * nr_opp * 4;
|
||||
+ return SCPI_OK;
|
||||
+ }
|
||||
+ case SCP_CMD_DVFS_SET_INDEX:
|
||||
+ if ((par1 & 0xff) != 0)
|
||||
+ return SCPI_E_PARAM;
|
||||
+
|
||||
+ if (sunxi_dvfs_set_index((par1 >> 8) & 0xff))
|
||||
+ return SCPI_E_RANGE;
|
||||
+ return SCPI_OK;
|
||||
+ case SCP_CMD_DVFS_GET_INDEX:
|
||||
+ mmio_write_32(payload_out, sunxi_dvfs_get_index());
|
||||
+ *payload_size = 0x1;
|
||||
+ return SCPI_OK;
|
||||
}
|
||||
|
||||
return SCPI_E_SUPPORT;
|
317
patch/atf/atf-sun50iw1/09-add-THS-sensor.patch
Normal file
317
patch/atf/atf-sun50iw1/09-add-THS-sensor.patch
Normal file
|
@ -0,0 +1,317 @@
|
|||
From 96fcf67c30ca4526641e08e16ba0992cd15e05c0 Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Fri, 23 Sep 2016 01:30:18 +0100
|
||||
Subject: [PATCH] sunxi: SCPI: add temperature sensor readout
|
||||
|
||||
The SCPI interface provides abstracted access to sensors, to monitor
|
||||
voltage, current, power and temperature.
|
||||
Introduce the required code to read and decode Allwinner's CPU and GPU
|
||||
temperature sensors and export them via the SCPI interface.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
plat/sun50iw1p1/bl31_sunxi_setup.c | 4 +-
|
||||
plat/sun50iw1p1/platform.mk | 2 +
|
||||
plat/sun50iw1p1/sunxi_private.h | 10 ++++
|
||||
plat/sun50iw1p1/sunxi_scpi.c | 46 +++++++++++++-
|
||||
plat/sun50iw1p1/sunxi_sensors.c | 40 +++++++++++++
|
||||
plat/sun50iw1p1/sunxi_temp.c | 119 +++++++++++++++++++++++++++++++++++++
|
||||
6 files changed, 219 insertions(+), 2 deletions(-)
|
||||
create mode 100644 plat/sun50iw1p1/sunxi_sensors.c
|
||||
create mode 100644 plat/sun50iw1p1/sunxi_temp.c
|
||||
|
||||
diff --git a/plat/sun50iw1p1/bl31_sunxi_setup.c b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
index 4c480e545..503f4006d 100644
|
||||
--- a/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
+++ b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
@@ -248,9 +248,11 @@ void bl31_platform_setup(void)
|
||||
|
||||
sunxi_power_setup(socid);
|
||||
|
||||
+ sunxi_ths_setup();
|
||||
+
|
||||
sunxi_setup_clocks(socid);
|
||||
|
||||
- NOTICE("SCPI: installed handler, implementation level: 111000\n");
|
||||
+ NOTICE("SCPI: installed handler, implementation level: 111010\n");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
diff --git a/plat/sun50iw1p1/platform.mk b/plat/sun50iw1p1/platform.mk
|
||||
index f56e79355..b1b0ac298 100644
|
||||
--- a/plat/sun50iw1p1/platform.mk
|
||||
+++ b/plat/sun50iw1p1/platform.mk
|
||||
@@ -54,5 +54,7 @@ BL31_SOURCES += drivers/arm/gic/arm_gic.c \
|
||||
plat/sun50iw1p1/sunxi_scpi.c \
|
||||
plat/sun50iw1p1/sunxi_rsb.c \
|
||||
plat/sun50iw1p1/sunxi_dvfs.c \
|
||||
+ plat/sun50iw1p1/sunxi_sensors.c \
|
||||
+ plat/sun50iw1p1/sunxi_temp.c \
|
||||
plat/sun50iw1p1/aarch64/sunxi_common.c
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h
|
||||
index b98400107..d2ab0e6c2 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_private.h
|
||||
+++ b/plat/sun50iw1p1/sunxi_private.h
|
||||
@@ -104,6 +104,16 @@ int sunxi_dvfs_set_index(int index);
|
||||
int sunxi_dvfs_get_index(void);
|
||||
int sunxi_dvfs_get_nr_opp(void);
|
||||
|
||||
+/* Declarations for sunxi_sensors.c */
|
||||
+int sunxi_setup_sensors(void);
|
||||
+const char* sunxi_sensor_get_name(int sensornr);
|
||||
+uint32_t sunxi_sensor_get_value(int sensornr);
|
||||
+int sunxi_sensors_nr_sensors(void);
|
||||
+
|
||||
+/* Declarations for sunxi_temp.c */
|
||||
+int sunxi_ths_setup(void);
|
||||
+int sunxi_ths_read_temp(int sensornr);
|
||||
+
|
||||
/* Gets the SPSR for BL33 entry */
|
||||
uint32_t sunxi_get_spsr_for_bl33_entry(int aarch);
|
||||
|
||||
diff --git a/plat/sun50iw1p1/sunxi_scpi.c b/plat/sun50iw1p1/sunxi_scpi.c
|
||||
index 50aabeb27..4d0d71e97 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_scpi.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_scpi.c
|
||||
@@ -62,10 +62,14 @@
|
||||
#define SCP_CMD_CLOCK_GET_INFO 0x0e
|
||||
#define SCP_CMD_CLOCK_SET_RATE 0x0f
|
||||
#define SCP_CMD_CLOCK_GET_RATE 0x10
|
||||
+#define SCP_CMD_SENSORS_CAPS 0x15
|
||||
+#define SCP_CMD_SENSORS_INFO 0x16
|
||||
+#define SCP_CMD_SENSORS_VALUE 0x17
|
||||
|
||||
#define SCP_CMDS_IMPLEMENTED \
|
||||
GENMASK(SCP_CMD_DVFS_GET_INDEX, SCP_CMD_DVFS_CAPABILITY) | \
|
||||
- GENMASK(SCP_CMD_CLOCK_GET_RATE, SCP_CMD_CLOCKS_CAPS)
|
||||
+ GENMASK(SCP_CMD_CLOCK_GET_RATE, SCP_CMD_CLOCKS_CAPS) | \
|
||||
+ GENMASK(SCP_CMD_SENSORS_VALUE, SCP_CMD_SENSORS_CAPS)
|
||||
|
||||
/* end of SRAM A1 */
|
||||
#define SUNXI_SCPI_SHMEM_BASE 0x17e00
|
||||
@@ -89,6 +93,25 @@ static int write_clock_info(uintptr_t payload, int clocknr)
|
||||
return 12 + i;
|
||||
}
|
||||
|
||||
+static int write_sensor_info(uintptr_t payload, int sensornr)
|
||||
+{
|
||||
+ const char *name, *s;
|
||||
+ int i;
|
||||
+
|
||||
+ name = sunxi_sensor_get_name(sensornr);
|
||||
+ if (!name)
|
||||
+ return -SCPI_E_PARAM;
|
||||
+
|
||||
+ /* no triggers, always temperature sensor (for now) */
|
||||
+ mmio_write_32(payload + 0x0, (sensornr & 0xffff));
|
||||
+
|
||||
+ for (i = 0, s = name; s[i] != 0; i++)
|
||||
+ mmio_write_8(payload + 4 + i, s[i]);
|
||||
+ mmio_write_8(payload + 4 + i, 0);
|
||||
+
|
||||
+ return 4 + i;
|
||||
+}
|
||||
+
|
||||
static uint32_t scpi_handle_cmd(int cmd, uint8_t *payload_size,
|
||||
uintptr_t payload_in, uintptr_t payload_out)
|
||||
{
|
||||
@@ -176,6 +199,27 @@ static uint32_t scpi_handle_cmd(int cmd, uint8_t *payload_size,
|
||||
mmio_write_32(payload_out, sunxi_dvfs_get_index());
|
||||
*payload_size = 0x1;
|
||||
return SCPI_OK;
|
||||
+ case SCP_CMD_SENSORS_CAPS:
|
||||
+ /* number of implemented sensors */
|
||||
+ mmio_write_32(payload_out, sunxi_sensors_nr_sensors());
|
||||
+ *payload_size = 0x2;
|
||||
+ return SCPI_OK;
|
||||
+ case SCP_CMD_SENSORS_INFO:
|
||||
+ ret = write_sensor_info(payload_out, par1 & 0xffff);
|
||||
+ if (ret < 0) {
|
||||
+ *payload_size = 0;
|
||||
+ return SCPI_E_PARAM;
|
||||
+ }
|
||||
+ *payload_size = ret;
|
||||
+ return SCPI_OK;
|
||||
+ case SCP_CMD_SENSORS_VALUE:
|
||||
+ ret = sunxi_sensor_get_value(par1 & 0xffff);
|
||||
+ if (ret == ~0)
|
||||
+ return SCPI_E_RANGE;
|
||||
+ mmio_write_32(payload_out, ret);
|
||||
+ mmio_write_32(payload_out + 4, 0);
|
||||
+ *payload_size = 8;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
return SCPI_E_SUPPORT;
|
||||
diff --git a/plat/sun50iw1p1/sunxi_sensors.c b/plat/sun50iw1p1/sunxi_sensors.c
|
||||
new file mode 100644
|
||||
index 000000000..ee8f216b6
|
||||
--- /dev/null
|
||||
+++ b/plat/sun50iw1p1/sunxi_sensors.c
|
||||
@@ -0,0 +1,40 @@
|
||||
+#include <debug.h>
|
||||
+#include <plat_config.h>
|
||||
+#include <mmio.h>
|
||||
+#include <sys/errno.h>
|
||||
+
|
||||
+#include "sunxi_def.h"
|
||||
+#include "sunxi_private.h"
|
||||
+
|
||||
+int sunxi_setup_sensors(void)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+const char* sunxi_sensor_get_name(int sensornr)
|
||||
+{
|
||||
+ switch(sensornr) {
|
||||
+ case 0: return "cpu_temp";
|
||||
+ case 1: return "gpu_temp0";
|
||||
+ case 2: return "gpu_temp1";
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+uint32_t sunxi_sensor_get_value(int sensornr)
|
||||
+{
|
||||
+ switch(sensornr) {
|
||||
+ case 0:
|
||||
+ case 1:
|
||||
+ case 2:
|
||||
+ return sunxi_ths_read_temp(sensornr);
|
||||
+ }
|
||||
+
|
||||
+ return ~0;
|
||||
+}
|
||||
+
|
||||
+int sunxi_sensors_nr_sensors(void)
|
||||
+{
|
||||
+ return 3;
|
||||
+}
|
||||
diff --git a/plat/sun50iw1p1/sunxi_temp.c b/plat/sun50iw1p1/sunxi_temp.c
|
||||
new file mode 100644
|
||||
index 000000000..8c777a34f
|
||||
--- /dev/null
|
||||
+++ b/plat/sun50iw1p1/sunxi_temp.c
|
||||
@@ -0,0 +1,119 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
|
||||
+ *
|
||||
+ * Redistribution and use in source and binary forms, with or without
|
||||
+ * modification, are permitted provided that the following conditions are met:
|
||||
+ *
|
||||
+ * Redistributions of source code must retain the above copyright notice, this
|
||||
+ * list of conditions and the following disclaimer.
|
||||
+ *
|
||||
+ * Redistributions in binary form must reproduce the above copyright notice,
|
||||
+ * this list of conditions and the following disclaimer in the documentation
|
||||
+ * and/or other materials provided with the distribution.
|
||||
+ *
|
||||
+ * Neither the name of ARM nor the names of its contributors may be used
|
||||
+ * to endorse or promote products derived from this software without specific
|
||||
+ * prior written permission.
|
||||
+ *
|
||||
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||
+ */
|
||||
+
|
||||
+#include <debug.h>
|
||||
+#include <plat_config.h>
|
||||
+#include <mmio.h>
|
||||
+#include <assert.h>
|
||||
+#include <bl_common.h>
|
||||
+#include <context.h>
|
||||
+#include <context_mgmt.h>
|
||||
+#include <interrupt_mgmt.h>
|
||||
+#include <runtime_svc.h>
|
||||
+#include <sys/errno.h>
|
||||
+
|
||||
+#include "sunxi_def.h"
|
||||
+#include "sunxi_private.h"
|
||||
+
|
||||
+#define CCU_BASE 0x1c20000ULL
|
||||
+#define BUS_CLK_GATING_REG2 0x068
|
||||
+#define THS_CLK_REG 0x074
|
||||
+#define BUS_SOFT_RST_REG3 0x2d0
|
||||
+#define THS_BASE 0x1c25000ULL
|
||||
+
|
||||
+#define BIT(n) (1U << (n))
|
||||
+
|
||||
+/* temperature = ( MINUPA - reg * MULPA) / DIVPA */
|
||||
+#define MULPA 25000
|
||||
+#define DIVPA 214
|
||||
+#define MINUPA 2170
|
||||
+static int sun50_th_reg_to_temp(uint32_t reg_data)
|
||||
+{
|
||||
+ return ((MINUPA - (int)reg_data) * MULPA) / DIVPA;
|
||||
+}
|
||||
+
|
||||
+/* Initialize the temperature sensor */
|
||||
+static int init_ths(void)
|
||||
+{
|
||||
+ uint32_t reg;
|
||||
+
|
||||
+ /* de-assert reset of THS */
|
||||
+ reg = mmio_read_32(CCU_BASE + BUS_SOFT_RST_REG3);
|
||||
+ mmio_write_32(CCU_BASE + BUS_SOFT_RST_REG3, reg | BIT(8));
|
||||
+
|
||||
+ /* enable THS clock at 4 MHz */
|
||||
+ reg = mmio_read_32(CCU_BASE + THS_CLK_REG) & ~0x3;
|
||||
+ mmio_write_32(CCU_BASE + THS_CLK_REG, reg | 0x3 | BIT(31));
|
||||
+
|
||||
+ /* un-gate THS clock */
|
||||
+ reg = mmio_read_32(CCU_BASE + BUS_CLK_GATING_REG2);
|
||||
+ mmio_write_32(CCU_BASE + BUS_CLK_GATING_REG2, reg | BIT(8));
|
||||
+
|
||||
+ /* start calibration */
|
||||
+ mmio_write_32(THS_BASE + 0x04, BIT(17));
|
||||
+ /* set aquire times */
|
||||
+ mmio_write_32(THS_BASE + 0x00, 0x190);
|
||||
+ mmio_write_32(THS_BASE + 0x40, 0x190 << 16);
|
||||
+ /* enable filter, average over 8 values */
|
||||
+ mmio_write_32(THS_BASE + 0x70, 0x06);
|
||||
+ /* enable sensors 0-2 (CPU & GPUs) measurement */
|
||||
+ reg = mmio_read_32(THS_BASE + 0x40);
|
||||
+ mmio_write_32(THS_BASE + 0x40, reg | BIT(0) | BIT(1) | BIT(2));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* Setup the temperature sensor */
|
||||
+int sunxi_ths_setup(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ NOTICE("Configuring thermal sensors\n");
|
||||
+
|
||||
+ ret = init_ths();
|
||||
+ if (ret) {
|
||||
+ ERROR("THS: cannot initialize temperature sensor\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+int sunxi_ths_read_temp(int sensor)
|
||||
+{
|
||||
+ int reg;
|
||||
+
|
||||
+ if (sensor < 0 || sensor > 2)
|
||||
+ return ~0;
|
||||
+
|
||||
+ reg = mmio_read_32(THS_BASE + 0x80 + (4 * sensor));
|
||||
+
|
||||
+ return sun50_th_reg_to_temp(reg & 0xfff);
|
||||
+}
|
233
patch/atf/atf-sun50iw1/10-add-device-power-state.patch
Normal file
233
patch/atf/atf-sun50iw1/10-add-device-power-state.patch
Normal file
|
@ -0,0 +1,233 @@
|
|||
From 321bc21a00f9b46735bcfdca5a683ab240cd0f33 Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Mon, 27 Feb 2017 23:10:56 +0000
|
||||
Subject: [PATCH] UNTESTED: sunxi: SCPI: add device power state support
|
||||
|
||||
Some generic framework to toggle AXP power rails via the SCPI device
|
||||
power state interface.
|
||||
TODO:
|
||||
- testing
|
||||
- check how H5 folds in
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
plat/sun50iw1p1/bl31_sunxi_setup.c | 2 +-
|
||||
plat/sun50iw1p1/sunxi_power.c | 142 +++++++++++++++++++++++++++++++++++++
|
||||
plat/sun50iw1p1/sunxi_private.h | 2 +
|
||||
plat/sun50iw1p1/sunxi_scpi.c | 13 +++-
|
||||
4 files changed, 157 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/plat/sun50iw1p1/bl31_sunxi_setup.c b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
index 503f4006d..027436725 100644
|
||||
--- a/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
+++ b/plat/sun50iw1p1/bl31_sunxi_setup.c
|
||||
@@ -252,7 +252,7 @@ void bl31_platform_setup(void)
|
||||
|
||||
sunxi_setup_clocks(socid);
|
||||
|
||||
- NOTICE("SCPI: installed handler, implementation level: 111010\n");
|
||||
+ NOTICE("SCPI: installed handler, implementation level: 111011\n");
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
diff --git a/plat/sun50iw1p1/sunxi_power.c b/plat/sun50iw1p1/sunxi_power.c
|
||||
index 5aa63fe4f..8849af8bc 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_power.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_power.c
|
||||
@@ -177,6 +177,148 @@ enum pmic_type {
|
||||
PMIC_AXP803,
|
||||
} pmic_type;
|
||||
|
||||
+int sunxi_power_set_cpu_voltage(int millivolt)
|
||||
+{
|
||||
+ switch (pmic_type) {
|
||||
+ case PMIC_AXP803:
|
||||
+ return axp803_set_cpu_voltage(millivolt);
|
||||
+ }
|
||||
+
|
||||
+ return -ENODEV;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * device mapping: blocks of 8 (or 16?)
|
||||
+ * block 0: DCDCn
|
||||
+ * block 1: special (DC1SW, ...)
|
||||
+ * block 2: ALDO
|
||||
+ * block 3: DLDO
|
||||
+ * block 4: ELDO
|
||||
+ * block 5: FLDO
|
||||
+ * block 6: GPIO
|
||||
+ *
|
||||
+ * state: == 0: power off
|
||||
+ * != 0: power on
|
||||
+ */
|
||||
+
|
||||
+static uint32_t axp803_map_devices(uint16_t devid)
|
||||
+{
|
||||
+ unsigned int reg, bit;
|
||||
+
|
||||
+ switch (devid) {
|
||||
+ case 0: /* DCDC */
|
||||
+ case 1:
|
||||
+ case 2:
|
||||
+ case 3:
|
||||
+ case 4:
|
||||
+ case 5:
|
||||
+ reg = 0x10;
|
||||
+ bit = devid;
|
||||
+ break;
|
||||
+ case 8: /* DC1SW */
|
||||
+ reg = 0x12;
|
||||
+ bit = 7;
|
||||
+ break;
|
||||
+ case 16: /* ALDO */
|
||||
+ case 17:
|
||||
+ case 18:
|
||||
+ reg = 0x13;
|
||||
+ bit = (devid & 7) + 5;
|
||||
+ break;
|
||||
+ case 24: /* DLDO */
|
||||
+ case 25:
|
||||
+ case 26:
|
||||
+ case 27:
|
||||
+ reg = 0x12;
|
||||
+ bit = (devid & 7) + 3;
|
||||
+ break;
|
||||
+ case 32: /* ELDO */
|
||||
+ case 33:
|
||||
+ case 34:
|
||||
+ reg = 0x13;
|
||||
+ bit = (devid & 7) + 0;
|
||||
+ break;
|
||||
+ case 40: /* FLDO */
|
||||
+ case 41:
|
||||
+ reg = 0x13;
|
||||
+ bit = (devid & 7) + 2;
|
||||
+ break;
|
||||
+ case 48: /* GPIO0LDO */
|
||||
+ case 49: /* GPIO1LDO */
|
||||
+ /* TODO: implement */
|
||||
+ default:
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ return (bit & 0xff) | (reg << 8);
|
||||
+}
|
||||
+
|
||||
+static unsigned int axp803_pstate_get(uint16_t device)
|
||||
+{
|
||||
+ uint32_t regmap = axp803_map_devices(device);
|
||||
+ uint8_t reg;
|
||||
+ int bit, val;
|
||||
+
|
||||
+ if (regmap == -1)
|
||||
+ return -1;
|
||||
+
|
||||
+ reg = (regmap >> 8) & 0xff;
|
||||
+ bit = regmap & 0xff;
|
||||
+
|
||||
+ val = sunxi_rsb_read(reg);
|
||||
+ if (val < 0)
|
||||
+ return -2;
|
||||
+
|
||||
+ if (val & BIT(bit))
|
||||
+ return 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+unsigned int sunxi_pstate_get(uint16_t device)
|
||||
+{
|
||||
+ switch (pmic_type) {
|
||||
+ case PMIC_AXP803:
|
||||
+ return axp803_pstate_get(device);
|
||||
+ }
|
||||
+
|
||||
+ return ~0;
|
||||
+}
|
||||
+
|
||||
+static int axp803_pstate_set(uint16_t device, uint8_t state)
|
||||
+{
|
||||
+ uint32_t regmap = axp803_map_devices(device);
|
||||
+ uint8_t reg;
|
||||
+ int bit, val;
|
||||
+
|
||||
+ if (regmap == -1)
|
||||
+ return -1;
|
||||
+
|
||||
+ reg = (regmap >> 8) & 0xff;
|
||||
+ bit = regmap & 0xff;
|
||||
+
|
||||
+ val = sunxi_rsb_read(reg);
|
||||
+ if (val < 0)
|
||||
+ return -2;
|
||||
+
|
||||
+ if (state)
|
||||
+ val |= BIT(bit);
|
||||
+ else
|
||||
+ val &= ~BIT(bit);
|
||||
+
|
||||
+ return sunxi_rsb_write(reg, val);
|
||||
+}
|
||||
+
|
||||
+int sunxi_pstate_set(uint16_t device, uint8_t state)
|
||||
+{
|
||||
+ switch (pmic_type) {
|
||||
+ case PMIC_AXP803:
|
||||
+ return axp803_pstate_set(device, state);
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
int sunxi_power_setup(uint16_t socid)
|
||||
{
|
||||
int ret;
|
||||
diff --git a/plat/sun50iw1p1/sunxi_private.h b/plat/sun50iw1p1/sunxi_private.h
|
||||
index d2ab0e6c2..27f87839a 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_private.h
|
||||
+++ b/plat/sun50iw1p1/sunxi_private.h
|
||||
@@ -73,6 +73,8 @@ int sunxi_pmic_read(uint8_t address);
|
||||
int sunxi_pmic_write(uint8_t address, uint8_t value);
|
||||
int sunxi_power_setup(uint16_t socid);
|
||||
int sunxi_power_set_cpu_voltage(int millivolt);
|
||||
+unsigned int sunxi_pstate_get(uint16_t device);
|
||||
+int sunxi_pstate_set(uint16_t device, uint8_t state);
|
||||
|
||||
void udelay(unsigned int delay);
|
||||
int sunxi_setup_clocks(uint16_t socid);
|
||||
diff --git a/plat/sun50iw1p1/sunxi_scpi.c b/plat/sun50iw1p1/sunxi_scpi.c
|
||||
index 4d0d71e97..6856e400e 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_scpi.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_scpi.c
|
||||
@@ -65,11 +65,14 @@
|
||||
#define SCP_CMD_SENSORS_CAPS 0x15
|
||||
#define SCP_CMD_SENSORS_INFO 0x16
|
||||
#define SCP_CMD_SENSORS_VALUE 0x17
|
||||
+#define SCP_CMD_PSTATE_SET 0x1b
|
||||
+#define SCP_CMD_PSTATE_GET 0x1c
|
||||
|
||||
#define SCP_CMDS_IMPLEMENTED \
|
||||
GENMASK(SCP_CMD_DVFS_GET_INDEX, SCP_CMD_DVFS_CAPABILITY) | \
|
||||
GENMASK(SCP_CMD_CLOCK_GET_RATE, SCP_CMD_CLOCKS_CAPS) | \
|
||||
- GENMASK(SCP_CMD_SENSORS_VALUE, SCP_CMD_SENSORS_CAPS)
|
||||
+ GENMASK(SCP_CMD_SENSORS_VALUE, SCP_CMD_SENSORS_CAPS) | \
|
||||
+ GENMASK(SCP_CMD_PSTATE_SET, SCP_CMD_PSTATE_GET)
|
||||
|
||||
/* end of SRAM A1 */
|
||||
#define SUNXI_SCPI_SHMEM_BASE 0x17e00
|
||||
@@ -220,6 +223,14 @@ static uint32_t scpi_handle_cmd(int cmd, uint8_t *payload_size,
|
||||
mmio_write_32(payload_out + 4, 0);
|
||||
*payload_size = 8;
|
||||
return 0;
|
||||
+ case SCP_CMD_PSTATE_SET:
|
||||
+ if (sunxi_pstate_set(par1 & 0xffff, (par1 >> 16) & 0xff))
|
||||
+ return SCPI_E_RANGE;
|
||||
+ return SCPI_OK;
|
||||
+ case SCP_CMD_PSTATE_GET:
|
||||
+ mmio_write_32(payload_out, sunxi_pstate_get(par1 & 0xffff));
|
||||
+ *payload_size = 0x1;
|
||||
+ return SCPI_OK;
|
||||
}
|
||||
|
||||
return SCPI_E_SUPPORT;
|
29
patch/atf/atf-sun50iw1/add-SRAM-mapping-for-SCPI.patch
Normal file
29
patch/atf/atf-sun50iw1/add-SRAM-mapping-for-SCPI.patch
Normal file
|
@ -0,0 +1,29 @@
|
|||
From 5ff3a09d64b6b9172d9007e3f77116902b9c2965 Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Mon, 8 Aug 2016 02:34:27 +0100
|
||||
Subject: [PATCH] sunxi: add SRAM regions to EL3 mapping
|
||||
|
||||
Currently we only map the MMIO regions for actual peripheral devices
|
||||
in EL3. For the SCPI implementation we need access to the SRAM regions
|
||||
as well.
|
||||
Add a mapping entry that covers all three SRAM regions on the A64.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
plat/sun50iw1p1/aarch64/sunxi_common.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/plat/sun50iw1p1/aarch64/sunxi_common.c b/plat/sun50iw1p1/aarch64/sunxi_common.c
|
||||
index a2fa37a39..8ebcd9852 100644
|
||||
--- a/plat/sun50iw1p1/aarch64/sunxi_common.c
|
||||
+++ b/plat/sun50iw1p1/aarch64/sunxi_common.c
|
||||
@@ -56,6 +56,9 @@ plat_config_t plat_config;
|
||||
*/
|
||||
const mmap_region_t sunxi_mmap[] = {
|
||||
|
||||
+ // SRAM regions
|
||||
+ { 0x0010000, 0x0010000,
|
||||
+ 0x0030000, MT_DEVICE | MT_RW | MT_NS },
|
||||
// MMI/O region used by peripherals from 0x100.0000 to 0x200.0000
|
||||
{ 0x1000000, 0x1000000,
|
||||
0x1000000, MT_DEVICE | MT_RW | MT_SECURE },
|
|
@ -1,21 +1,13 @@
|
|||
diff --git a/plat/sun50iw1p1/sunxi_power.c b/plat/sun50iw1p1/sunxi_power.c
|
||||
index 0c2487e..30708f4 100644
|
||||
index 5aa63fe4..95bef606 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_power.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_power.c
|
||||
@@ -258,12 +258,10 @@ static int pmic_setup(void)
|
||||
* changes. This should be further confined once we are able to
|
||||
* reliably detect a Pine64 board.
|
||||
*/
|
||||
- ret = sunxi_pmic_read(0x24); /* read DCDC5 register */
|
||||
- if ((ret & 0x7f) == 0x26) { /* check for 1.24V value */
|
||||
- NOTICE("PMIC: fixing DRAM voltage from 1.24V to 1.36V\n");
|
||||
- sunxi_pmic_write(0x24, 0x2c);
|
||||
- }
|
||||
-
|
||||
+
|
||||
+ NOTICE("PMIC: setting DRAM voltage to 1.24V\n");
|
||||
+ sunxi_pmic_write(0x24, 0x25); /* DCDC5 = LPDDR RAM voltage = 1.24V */
|
||||
+
|
||||
sunxi_pmic_write(0x15, 0x1a); /* DLDO1 = VCC3V3_HDMI voltage = 3.3V */
|
||||
|
||||
return 0;
|
||||
@@ -126,7 +126,7 @@ static int axp803_initial_setup(void)
|
||||
ret = sunxi_rsb_read(0x24); /* read DCDC5 register */
|
||||
if ((ret & 0x7f) == 0x26) { /* check for 1.24V value */
|
||||
NOTICE("PMIC: fixing DRAM voltage from 1.24V to 1.36V\n");
|
||||
- sunxi_rsb_write(0x24, 0x2c);
|
||||
+ sunxi_rsb_write(0x24, 0x25);
|
||||
}
|
||||
|
||||
sunxi_rsb_write(0x15, 0x1a); /* DLDO1 = VCC3V3_HDMI voltage = 3.3V */
|
||||
|
|
|
@ -1,21 +1,13 @@
|
|||
diff --git a/plat/sun50iw1p1/sunxi_power.c b/plat/sun50iw1p1/sunxi_power.c
|
||||
index 0c2487e..30708f4 100644
|
||||
index 5aa63fe4..95bef606 100644
|
||||
--- a/plat/sun50iw1p1/sunxi_power.c
|
||||
+++ b/plat/sun50iw1p1/sunxi_power.c
|
||||
@@ -258,12 +258,10 @@ static int pmic_setup(void)
|
||||
* changes. This should be further confined once we are able to
|
||||
* reliably detect a Pine64 board.
|
||||
*/
|
||||
- ret = sunxi_pmic_read(0x24); /* read DCDC5 register */
|
||||
- if ((ret & 0x7f) == 0x26) { /* check for 1.24V value */
|
||||
- NOTICE("PMIC: fixing DRAM voltage from 1.24V to 1.36V\n");
|
||||
- sunxi_pmic_write(0x24, 0x2c);
|
||||
- }
|
||||
-
|
||||
+
|
||||
+ NOTICE("PMIC: setting DRAM voltage to 1.24V\n");
|
||||
+ sunxi_pmic_write(0x24, 0x25); /* DCDC5 = LPDDR RAM voltage = 1.24V */
|
||||
+
|
||||
sunxi_pmic_write(0x15, 0x1a); /* DLDO1 = VCC3V3_HDMI voltage = 3.3V */
|
||||
|
||||
return 0;
|
||||
@@ -126,7 +126,7 @@ static int axp803_initial_setup(void)
|
||||
ret = sunxi_rsb_read(0x24); /* read DCDC5 register */
|
||||
if ((ret & 0x7f) == 0x26) { /* check for 1.24V value */
|
||||
NOTICE("PMIC: fixing DRAM voltage from 1.24V to 1.36V\n");
|
||||
- sunxi_rsb_write(0x24, 0x2c);
|
||||
+ sunxi_rsb_write(0x24, 0x25);
|
||||
}
|
||||
|
||||
sunxi_rsb_write(0x15, 0x1a); /* DLDO1 = VCC3V3_HDMI voltage = 3.3V */
|
||||
|
|
28
patch/atf/atf-sun50iw1/enable-a53-errata-workaround.patch
Normal file
28
patch/atf/atf-sun50iw1/enable-a53-errata-workaround.patch
Normal file
|
@ -0,0 +1,28 @@
|
|||
From 3efb52570e581d79f6e451ef88933423a61a9b55 Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Mon, 27 Mar 2017 21:56:08 +0100
|
||||
Subject: [PATCH] Makefile: (re-)enable A53 errata workaround
|
||||
|
||||
The --fix-cortex-a53-843418 option to the linker was disabled before to
|
||||
also support older toolchains which don't know of this option.
|
||||
To not loose the bugfix for more recent toolchains introduce a feature
|
||||
check, which enables the option if the linker knows about it.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
Makefile | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index f96e2cb37..87c307ded 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -234,7 +234,7 @@ CFLAGS += -nostdinc -pedantic -ffreestanding -Wall \
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
LDFLAGS += --fatal-warnings -O1
|
||||
LDFLAGS += --gc-sections
|
||||
-#LDFLAGS += --fix-cortex-a53-843419
|
||||
+LDFLAGS += $(if $(shell $(LD) -v --fix-cortex-a53-843419 > /dev/null 2>&1 && echo 1),--fix-cortex-a53-843419)
|
||||
|
||||
|
||||
CC := ${CROSS_COMPILE}gcc
|
50
patch/kernel/sun50i-dev/add-smc-mailbox-a64-DT-01.patch
Normal file
50
patch/kernel/sun50i-dev/add-smc-mailbox-a64-DT-01.patch
Normal file
|
@ -0,0 +1,50 @@
|
|||
This adds support for the SCPI protocol using an SMC mailbox and some
|
||||
shared memory in SRAM.
|
||||
The SCPI provider is implemented in the ARM Trusted Firmware layer
|
||||
(running in EL3 on the application processor cores), triggered by an smc
|
||||
call.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.p...@arm.com>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 26 ++++++++++++++++++++++++++
|
||||
1 file changed, 26 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
index 9d00622..ef6f10e 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
@@ -124,6 +124,32 @@
|
||||
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
|
||||
};
|
||||
|
||||
+ mailbox: mbox@0 {
|
||||
+ compatible = "arm,smc-mbox";
|
||||
+ #mbox-cells = <1>;
|
||||
+ arm,smc-func-ids = <0x82000001>;
|
||||
+ };
|
||||
+
|
||||
+ sram: sram@10000{
|
||||
+ compatible = "mmio-sram";
|
||||
+ reg = <0x10000 0x8000>;
|
||||
+
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <1>;
|
||||
+ ranges = <0 0x10000 0x8000>;
|
||||
+
|
||||
+ cpu_scp_mem: scp-shmem@7e00 {
|
||||
+ compatible = "mmio-sram";
|
||||
+ reg = <0x7e00 0x200>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ scpi {
|
||||
+ compatible = "arm,scpi";
|
||||
+ mboxes = <&mailbox 0>;
|
||||
+ shmem = <&cpu_scp_mem>;
|
||||
+ };
|
||||
+
|
||||
soc {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
--
|
||||
2.9.0
|
67
patch/kernel/sun50i-dev/add-smc-mailbox-a64-DT-02.patch
Normal file
67
patch/kernel/sun50i-dev/add-smc-mailbox-a64-DT-02.patch
Normal file
|
@ -0,0 +1,67 @@
|
|||
One functionality provided by the SCPI handler is frequency scaling,
|
||||
which allows to switch the one CPU cluster between several operating
|
||||
points, each specifying a matching frequency and CPU voltage.
|
||||
The actual table is specified in firmware and can be queried by Linux
|
||||
using standardised SCPI calls.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.p...@arm.com>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 15 +++++++++++++++
|
||||
1 file changed, 15 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
index ef6f10e..58c3675 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
@@ -61,6 +61,7 @@
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
enable-method = "psci";
|
||||
+ clocks = <&scpi_dvfs 0>;
|
||||
};
|
||||
|
||||
cpu1: cpu@1 {
|
||||
@@ -68,6 +69,7 @@
|
||||
device_type = "cpu";
|
||||
reg = <1>;
|
||||
enable-method = "psci";
|
||||
+ clocks = <&scpi_dvfs 0>;
|
||||
};
|
||||
|
||||
cpu2: cpu@2 {
|
||||
@@ -75,6 +77,7 @@
|
||||
device_type = "cpu";
|
||||
reg = <2>;
|
||||
enable-method = "psci";
|
||||
+ clocks = <&scpi_dvfs 0>;
|
||||
};
|
||||
|
||||
cpu3: cpu@3 {
|
||||
@@ -82,6 +85,7 @@
|
||||
device_type = "cpu";
|
||||
reg = <3>;
|
||||
enable-method = "psci";
|
||||
+ clocks = <&scpi_dvfs 0>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -148,6 +152,17 @@
|
||||
compatible = "arm,scpi";
|
||||
mboxes = <&mailbox 0>;
|
||||
shmem = <&cpu_scp_mem>;
|
||||
+
|
||||
+ scpi-clocks {
|
||||
+ compatible = "arm,scpi-clocks";
|
||||
+
|
||||
+ scpi_dvfs: scpi_dvfs_clocks {
|
||||
+ compatible = "arm,scpi-dvfs-clocks";
|
||||
+ #clock-cells = <1>;
|
||||
+ clock-indices = <0>;
|
||||
+ clock-output-names = "cpu_clk";
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
soc {
|
||||
--
|
||||
2.9.0
|
40
patch/kernel/sun50i-dev/add-smc-mailbox-a64-DT-03.patch
Normal file
40
patch/kernel/sun50i-dev/add-smc-mailbox-a64-DT-03.patch
Normal file
|
@ -0,0 +1,40 @@
|
|||
The SCPI protocol allows various sensors to be exposed to the OS. The
|
||||
list of supported sensors (and their kind) is provided by the SCPI
|
||||
provider, which is in ARM Trusted Firmware. The current implementation
|
||||
exports the temperature sensors, for instance.
|
||||
Since the temperature sensor requires a clock to be running, we set
|
||||
a fixed clock rate for this particular clock to prevent the Linux driver
|
||||
from turning it off.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.p...@arm.com>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
index 58c3675..7cb1b04 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
@@ -163,6 +163,11 @@
|
||||
clock-output-names = "cpu_clk";
|
||||
};
|
||||
};
|
||||
+
|
||||
+ scpi_sensors0: sensors {
|
||||
+ compatible = "arm,scpi-sensors";
|
||||
+ #thermal-sensor-cells = <1>;
|
||||
+ };
|
||||
};
|
||||
|
||||
soc {
|
||||
@@ -307,6 +312,8 @@
|
||||
clock-names = "hosc", "losc";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
+ assigned-clocks = <&ccu CLK_THS>;
|
||||
+ assigned-clock-rates = <4000000>;
|
||||
};
|
||||
|
||||
pio: pinctrl@1c20800 {
|
||||
--
|
||||
2.9.0
|
78
patch/kernel/sun50i-dev/add-smc-mailbox-docs.patch
Normal file
78
patch/kernel/sun50i-dev/add-smc-mailbox-docs.patch
Normal file
|
@ -0,0 +1,78 @@
|
|||
Add binding documentation for the generic ARM SMC mailbox.
|
||||
This is not describing hardware, but a firmware interface.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.p...@arm.com>
|
||||
---
|
||||
.../devicetree/bindings/mailbox/arm-smc.txt | 61 ++++++++++++++++++++++
|
||||
1 file changed, 61 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/mailbox/arm-smc.txt
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/mailbox/arm-smc.txt b/Documentation/devicetree/bindings/mailbox/arm-smc.txt
|
||||
new file mode 100644
|
||||
index 0000000..90c5926
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/mailbox/arm-smc.txt
|
||||
@@ -0,0 +1,61 @@
|
||||
+ARM SMC Mailbox Driver
|
||||
+======================
|
||||
+
|
||||
+This mailbox uses the ARM smc (secure monitor call) instruction to
|
||||
+trigger a mailbox-connected activity in firmware, executing on the very same
|
||||
+core as the caller. By nature this operation is synchronous and this
|
||||
+mailbox provides no way for asynchronous messages to be delivered the other
|
||||
+way round, from firmware to the OS. However the value of r0/w0/x0 the firmware
|
||||
+returns after the smc call is delivered as a received message to the
|
||||
+mailbox framework, so a synchronous communication can be established.
|
||||
+
|
||||
+One use case of this mailbox is the SCP interface, which uses shared memory
|
||||
+to transfer commands and parameters, and a mailbox to trigger a function
|
||||
+call. This allows SoCs without a separate management processor (or
|
||||
+when such a processor is not available or used) to use this standardized
|
||||
+interface anyway.
|
||||
+
|
||||
+This binding describes no hardware, but establishes a firmware interface.
|
||||
+The communication follows the ARM SMC calling convention[1].
|
||||
+Any core which supports the SMC or HVC instruction can be used, as long as
|
||||
+a firmware component running in EL3 or EL2 is handling these calls.
|
||||
+
|
||||
+Mailbox Device Node:
|
||||
+====================
|
||||
+
|
||||
+Required properties:
|
||||
+--------------------
|
||||
+- compatible: Shall be "arm,smc-mbox"
|
||||
+- #mbox-cells Shall be 1 - the index of the channel needed.
|
||||
+- arm,smc-func-ids An array of 32-bit values specifying the function
|
||||
+ IDs used by each mailbox channel. Those function IDs
|
||||
+ follow the ARM SMC calling convention standard [1].
|
||||
+ There is one identifier per channel and the number
|
||||
+ of supported channels is determined by the length
|
||||
+ of this array.
|
||||
+
|
||||
+Optional properties:
|
||||
+--------------------
|
||||
+- method: A string, either:
|
||||
+ "hvc": if the driver shall use an HVC call, or
|
||||
+ "smc": if the driver shall use an SMC call
|
||||
+ If omitted, defaults to an SMC call.
|
||||
+
|
||||
+Example:
|
||||
+--------
|
||||
+
|
||||
+ mailbox: smc_mbox {
|
||||
+ #mbox-cells = <1>;
|
||||
+ compatible = "arm,smc-mbox";
|
||||
+ identifiers = <0x82000001>, <0x82000002>;
|
||||
+ };
|
||||
+
|
||||
+ scpi {
|
||||
+ compatible = "arm,scpi";
|
||||
+ mboxes = <&mailbox 0>;
|
||||
+ shmem = <&cpu_scp_shmem>;
|
||||
+ };
|
||||
+
|
||||
+
|
||||
+[1]
|
||||
+http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.den0028a/index.html
|
||||
--
|
||||
2.9.0
|
225
patch/kernel/sun50i-dev/add-smc-mailbox-driver.patch
Normal file
225
patch/kernel/sun50i-dev/add-smc-mailbox-driver.patch
Normal file
|
@ -0,0 +1,225 @@
|
|||
This mailbox driver implements a mailbox which signals transmitted data
|
||||
via an ARM smc (secure monitor call) instruction. The mailbox receiver
|
||||
is implemented in firmware and can synchronously return data when it
|
||||
returns execution to the non-secure world again.
|
||||
An asynchronous receive path is not implemented.
|
||||
This allows the usage of a mailbox to trigger firmware actions on SoCs
|
||||
which either don't have a separate management processor or on which such
|
||||
a core is not available. A user of this mailbox could be the SCP
|
||||
interface.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.p...@arm.com>
|
||||
---
|
||||
drivers/mailbox/Kconfig | 8 ++
|
||||
drivers/mailbox/Makefile | 2 +
|
||||
drivers/mailbox/arm-smc-mailbox.c | 172 ++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 182 insertions(+)
|
||||
create mode 100644 drivers/mailbox/arm-smc-mailbox.c
|
||||
|
||||
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
|
||||
index c5731e5..5664b7f 100644
|
||||
--- a/drivers/mailbox/Kconfig
|
||||
+++ b/drivers/mailbox/Kconfig
|
||||
@@ -170,4 +170,12 @@ config BCM_FLEXRM_MBOX
|
||||
Mailbox implementation of the Broadcom FlexRM ring manager,
|
||||
which provides access to various offload engines on Broadcom
|
||||
SoCs. Say Y here if you want to use the Broadcom FlexRM.
|
||||
+
|
||||
+config ARM_SMC_MBOX
|
||||
+ tristate "Generic ARM smc mailbox"
|
||||
+ depends on OF && HAVE_ARM_SMCCC
|
||||
+ help
|
||||
+ Generic mailbox driver which uses ARM smc calls to call into
|
||||
+ firmware for triggering mailboxes.
|
||||
+
|
||||
endif
|
||||
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
|
||||
index d54e412..8ec6869 100644
|
||||
--- a/drivers/mailbox/Makefile
|
||||
+++ b/drivers/mailbox/Makefile
|
||||
@@ -35,3 +35,5 @@ obj-$(CONFIG_BCM_FLEXRM_MBOX) += bcm-flexrm-mailbox.o
|
||||
obj-$(CONFIG_QCOM_APCS_IPC) += qcom-apcs-ipc-mailbox.o
|
||||
|
||||
obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o
|
||||
+
|
||||
+obj-$(CONFIG_ARM_SMC_MBOX) += arm-smc-mailbox.o
|
||||
diff --git a/drivers/mailbox/arm-smc-mailbox.c b/drivers/mailbox/arm-smc-mailbox.c
|
||||
new file mode 100644
|
||||
index 0000000..578aed2
|
||||
--- /dev/null
|
||||
+++ b/drivers/mailbox/arm-smc-mailbox.c
|
||||
@@ -0,0 +1,172 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2016,2017 ARM Ltd.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * This device provides a mechanism for emulating a mailbox by using
|
||||
+ * smc calls, allowing a "mailbox" consumer to sit in firmware running
|
||||
+ * on the same core.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/dma-mapping.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/irq.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mailbox_controller.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/arm-smccc.h>
|
||||
+
|
||||
+#define ARM_SMC_MBOX_SMC (0 << 0)
|
||||
+#define ARM_SMC_MBOX_HVC (1 << 0)
|
||||
+#define ARM_SMC_MBOX_METHOD_MASK (1 << 0)
|
||||
+
|
||||
+struct arm_smc_chan_data {
|
||||
+ u32 function_id;
|
||||
+ u32 flags;
|
||||
+};
|
||||
+
|
||||
+static int arm_smc_send_data(struct mbox_chan *link, void *data)
|
||||
+{
|
||||
+ struct arm_smc_chan_data *chan_data = link->con_priv;
|
||||
+ u32 function_id = chan_data->function_id;
|
||||
+ struct arm_smccc_res res;
|
||||
+ u32 msg = *(u32 *)data;
|
||||
+
|
||||
+ if ((chan_data->flags & ARM_SMC_MBOX_METHOD_MASK) == ARM_SMC_MBOX_SMC)
|
||||
+ arm_smccc_smc(function_id, msg, 0, 0, 0, 0, 0, 0, &res);
|
||||
+ else
|
||||
+ arm_smccc_hvc(function_id, msg, 0, 0, 0, 0, 0, 0, &res);
|
||||
+
|
||||
+ mbox_chan_received_data(link, (void *)res.a0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int arm_smc_startup(struct mbox_chan *link)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void arm_smc_shutdown(struct mbox_chan *link)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+/* This mailbox is synchronous, so we are always done. */
|
||||
+static bool arm_smc_last_tx_done(struct mbox_chan *link)
|
||||
+{
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+static const struct mbox_chan_ops arm_smc_mbox_chan_ops = {
|
||||
+ .send_data = arm_smc_send_data,
|
||||
+ .startup = arm_smc_startup,
|
||||
+ .shutdown = arm_smc_shutdown,
|
||||
+ .last_tx_done = arm_smc_last_tx_done
|
||||
+};
|
||||
+
|
||||
+static int arm_smc_mbox_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct mbox_controller *mbox;
|
||||
+ struct arm_smc_chan_data *chan_data;
|
||||
+ const char *method;
|
||||
+ bool use_hvc = false;
|
||||
+ int ret = 0, i;
|
||||
+
|
||||
+ ret = of_property_count_elems_of_size(dev->of_node, "arm,smc-func-ids",
|
||||
+ sizeof(u32));
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (!of_property_read_string(dev->of_node, "method", &method)) {
|
||||
+ if (!strcmp("hvc", method)) {
|
||||
+ use_hvc = true;
|
||||
+ } else if (!strcmp("smc", method)) {
|
||||
+ use_hvc = false;
|
||||
+ } else {
|
||||
+ dev_warn(dev, "invalid \"method\" property: %s\n",
|
||||
+ method);
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
|
||||
+ if (!mbox)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mbox->num_chans = ret;
|
||||
+ mbox->chans = devm_kcalloc(dev, mbox->num_chans, sizeof(*mbox->chans),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!mbox->chans)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ chan_data = devm_kcalloc(dev, mbox->num_chans, sizeof(*chan_data),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!chan_data)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ for (i = 0; i < mbox->num_chans; i++) {
|
||||
+ u32 function_id;
|
||||
+
|
||||
+ ret = of_property_read_u32_index(dev->of_node,
|
||||
+ "arm,smc-func-ids", i,
|
||||
+ &function_id);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ chan_data[i].function_id = function_id;
|
||||
+ if (use_hvc)
|
||||
+ chan_data[i].flags |= ARM_SMC_MBOX_HVC;
|
||||
+ mbox->chans[i].con_priv = &chan_data[i];
|
||||
+ }
|
||||
+
|
||||
+ mbox->txdone_poll = true;
|
||||
+ mbox->txdone_irq = false;
|
||||
+ mbox->txpoll_period = 1;
|
||||
+ mbox->ops = &arm_smc_mbox_chan_ops;
|
||||
+ mbox->dev = dev;
|
||||
+
|
||||
+ ret = mbox_controller_register(mbox);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, mbox);
|
||||
+ dev_info(dev, "ARM SMC mailbox enabled with %d chan%s.\n",
|
||||
+ mbox->num_chans, mbox->num_chans == 1 ? "" : "s");
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int arm_smc_mbox_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct mbox_controller *mbox = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ mbox_controller_unregister(mbox);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id arm_smc_mbox_of_match[] = {
|
||||
+ { .compatible = "arm,smc-mbox", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, arm_smc_mbox_of_match);
|
||||
+
|
||||
+static struct platform_driver arm_smc_mbox_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "arm-smc-mbox",
|
||||
+ .of_match_table = arm_smc_mbox_of_match,
|
||||
+ },
|
||||
+ .probe = arm_smc_mbox_probe,
|
||||
+ .remove = arm_smc_mbox_remove,
|
||||
+};
|
||||
+module_platform_driver(arm_smc_mbox_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Andre Przywara <andre.p...@arm.com>");
|
||||
+MODULE_DESCRIPTION("Generic ARM smc mailbox driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
2.9.0
|
Loading…
Add table
Reference in a new issue