466 lines
11 KiB
Diff
466 lines
11 KiB
Diff
From 3bd5d90889173031e1a4177835225e3f9ffd6e49 Mon Sep 17 00:00:00 2001
|
|
From: XiaoDong Huang <derrick.huang@rock-chips.com>
|
|
Date: Sun, 25 Jun 2023 17:38:13 +0800
|
|
Subject: [PATCH] feat(rockchip): support SCMI for clock/reset domain
|
|
|
|
Signed-off-by: XiaoDong Huang <derrick.huang@rock-chips.com>
|
|
Change-Id: I5b983877a5b4e8acababbf7e0a3e2725e6479e08
|
|
---
|
|
|
|
diff --git a/plat/rockchip/common/include/rockchip_sip_svc.h b/plat/rockchip/common/include/rockchip_sip_svc.h
|
|
index 340d653..8836f9b 100644
|
|
--- a/plat/rockchip/common/include/rockchip_sip_svc.h
|
|
+++ b/plat/rockchip/common/include/rockchip_sip_svc.h
|
|
@@ -11,6 +11,7 @@
|
|
#define SIP_SVC_CALL_COUNT 0x8200ff00
|
|
#define SIP_SVC_UID 0x8200ff01
|
|
#define SIP_SVC_VERSION 0x8200ff03
|
|
+#define RK_SIP_SCMI_AGENT0 0x82000010
|
|
|
|
/* rockchip SiP Service Calls version numbers */
|
|
#define RK_SIP_SVC_VERSION_MAJOR 0x0
|
|
diff --git a/plat/rockchip/common/scmi/scmi.c b/plat/rockchip/common/scmi/scmi.c
|
|
new file mode 100644
|
|
index 0000000..23ea991
|
|
--- /dev/null
|
|
+++ b/plat/rockchip/common/scmi/scmi.c
|
|
@@ -0,0 +1,88 @@
|
|
+/*
|
|
+ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <assert.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include <plat_scmi_def.h>
|
|
+
|
|
+#include <drivers/scmi-msg.h>
|
|
+#include <drivers/scmi.h>
|
|
+#include <lib/utils.h>
|
|
+#include <lib/utils_def.h>
|
|
+
|
|
+#define MAX_PROTOCOL_IN_LIST 8U
|
|
+
|
|
+static const char vendor[] = "rockchip";
|
|
+static const char sub_vendor[] = "";
|
|
+
|
|
+#pragma weak rockchip_scmi_protocol_table
|
|
+
|
|
+const uint8_t rockchip_scmi_protocol_table[1][MAX_PROTOCOL_IN_LIST] = {
|
|
+ { SCMI_PROTOCOL_ID_CLOCK,
|
|
+ SCMI_PROTOCOL_ID_RESET_DOMAIN,
|
|
+ 0
|
|
+ }
|
|
+};
|
|
+
|
|
+const char *plat_scmi_vendor_name(void)
|
|
+{
|
|
+ return vendor;
|
|
+}
|
|
+
|
|
+const char *plat_scmi_sub_vendor_name(void)
|
|
+{
|
|
+ return sub_vendor;
|
|
+}
|
|
+
|
|
+size_t plat_scmi_protocol_count(void)
|
|
+{
|
|
+ unsigned int count = 0U;
|
|
+ const uint8_t *protocol_list = rockchip_scmi_protocol_table[0];
|
|
+
|
|
+ while (protocol_list[count])
|
|
+ count++;
|
|
+
|
|
+ return count;
|
|
+}
|
|
+
|
|
+const uint8_t *plat_scmi_protocol_list(unsigned int agent_id)
|
|
+{
|
|
+ assert(agent_id < ARRAY_SIZE(rockchip_scmi_protocol_table));
|
|
+
|
|
+ return rockchip_scmi_protocol_table[agent_id];
|
|
+}
|
|
+
|
|
+static struct scmi_msg_channel scmi_channel[] = {
|
|
+ [0] = {
|
|
+ .shm_addr = SMT_BUFFER0_BASE,
|
|
+ .shm_size = SMT_BUF_SLOT_SIZE,
|
|
+ },
|
|
+
|
|
+#ifdef SMT_BUFFER1_BASE
|
|
+ [1] = {
|
|
+ .shm_addr = SMT_BUFFER1_BASE,
|
|
+ .shm_size = SMT_BUF_SLOT_SIZE,
|
|
+ },
|
|
+#endif
|
|
+};
|
|
+
|
|
+struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id)
|
|
+{
|
|
+ assert(agent_id < ARRAY_SIZE(scmi_channel));
|
|
+
|
|
+ return &scmi_channel[agent_id];
|
|
+}
|
|
+
|
|
+#pragma weak rockchip_init_scmi_server
|
|
+
|
|
+void rockchip_init_scmi_server(void)
|
|
+{
|
|
+ size_t i;
|
|
+
|
|
+ for (i = 0U; i < ARRAY_SIZE(scmi_channel); i++)
|
|
+ scmi_smt_init_agent_channel(&scmi_channel[i]);
|
|
+}
|
|
diff --git a/plat/rockchip/common/scmi/scmi_clock.c b/plat/rockchip/common/scmi/scmi_clock.c
|
|
new file mode 100644
|
|
index 0000000..4921d49
|
|
--- /dev/null
|
|
+++ b/plat/rockchip/common/scmi/scmi_clock.c
|
|
@@ -0,0 +1,157 @@
|
|
+/*
|
|
+ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <drivers/scmi-msg.h>
|
|
+#include <drivers/scmi.h>
|
|
+
|
|
+#include "scmi_clock.h"
|
|
+
|
|
+#pragma weak rockchip_scmi_clock_count
|
|
+#pragma weak rockchip_scmi_get_clock
|
|
+
|
|
+size_t rockchip_scmi_clock_count(unsigned int agent_id __unused)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+rk_scmi_clock_t *rockchip_scmi_get_clock(uint32_t agent_id __unused,
|
|
+ uint32_t scmi_id __unused)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+size_t plat_scmi_clock_count(unsigned int agent_id)
|
|
+{
|
|
+ return rockchip_scmi_clock_count(agent_id);
|
|
+}
|
|
+
|
|
+const char *plat_scmi_clock_get_name(unsigned int agent_id,
|
|
+ unsigned int scmi_id)
|
|
+{
|
|
+ rk_scmi_clock_t *clock;
|
|
+
|
|
+ clock = rockchip_scmi_get_clock(agent_id, scmi_id);
|
|
+ if (clock == 0)
|
|
+ return NULL;
|
|
+
|
|
+ return clock->name;
|
|
+}
|
|
+
|
|
+int32_t plat_scmi_clock_rates_array(unsigned int agent_id,
|
|
+ unsigned int scmi_id,
|
|
+ unsigned long *rates,
|
|
+ size_t *nb_elts,
|
|
+ uint32_t start_idx)
|
|
+{
|
|
+ uint32_t i;
|
|
+ unsigned long *rate_table;
|
|
+ rk_scmi_clock_t *clock;
|
|
+
|
|
+ clock = rockchip_scmi_get_clock(agent_id, scmi_id);
|
|
+ if (clock == 0)
|
|
+ return SCMI_NOT_FOUND;
|
|
+
|
|
+ rate_table = clock->rate_table;
|
|
+ if (rate_table == 0)
|
|
+ return SCMI_NOT_SUPPORTED;
|
|
+
|
|
+ if (rates == 0) {
|
|
+ *nb_elts = clock->rate_cnt;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (start_idx + *nb_elts > clock->rate_cnt)
|
|
+ return SCMI_OUT_OF_RANGE;
|
|
+
|
|
+ for (i = 0; i < *nb_elts; i++)
|
|
+ rates[i] = rate_table[start_idx + i];
|
|
+
|
|
+out:
|
|
+ return SCMI_SUCCESS;
|
|
+}
|
|
+
|
|
+int32_t plat_scmi_clock_rates_by_step(unsigned int agent_id __unused,
|
|
+ unsigned int scmi_id __unused,
|
|
+ unsigned long *steps __unused)
|
|
+{
|
|
+ return SCMI_NOT_SUPPORTED;
|
|
+}
|
|
+
|
|
+unsigned long plat_scmi_clock_get_rate(unsigned int agent_id,
|
|
+ unsigned int scmi_id)
|
|
+{
|
|
+ rk_scmi_clock_t *clock;
|
|
+ unsigned long rate = 0;
|
|
+
|
|
+ clock = rockchip_scmi_get_clock(agent_id, scmi_id);
|
|
+ if (clock == 0)
|
|
+ return 0;
|
|
+
|
|
+ if (clock->clk_ops && clock->clk_ops->get_rate)
|
|
+ rate = clock->clk_ops->get_rate(clock);
|
|
+
|
|
+ /* return cur_rate if no get_rate ops or get_rate return 0 */
|
|
+ if (rate == 0)
|
|
+ rate = clock->cur_rate;
|
|
+
|
|
+ return rate;
|
|
+}
|
|
+
|
|
+int32_t plat_scmi_clock_set_rate(unsigned int agent_id,
|
|
+ unsigned int scmi_id,
|
|
+ unsigned long rate)
|
|
+{
|
|
+ rk_scmi_clock_t *clock;
|
|
+ int32_t status = 0;
|
|
+
|
|
+ clock = rockchip_scmi_get_clock(agent_id, scmi_id);
|
|
+ if (clock == 0)
|
|
+ return SCMI_NOT_FOUND;
|
|
+
|
|
+ if (clock->clk_ops && clock->clk_ops->set_rate) {
|
|
+ status = clock->clk_ops->set_rate(clock, rate);
|
|
+ if (status == SCMI_SUCCESS)
|
|
+ clock->cur_rate = rate;
|
|
+ } else {
|
|
+ status = SCMI_NOT_SUPPORTED;
|
|
+ }
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+int32_t plat_scmi_clock_get_state(unsigned int agent_id,
|
|
+ unsigned int scmi_id)
|
|
+{
|
|
+ rk_scmi_clock_t *clock;
|
|
+
|
|
+ clock = rockchip_scmi_get_clock(agent_id, scmi_id);
|
|
+ if (clock == 0)
|
|
+ return 0;
|
|
+
|
|
+ return clock->enable;
|
|
+}
|
|
+
|
|
+int32_t plat_scmi_clock_set_state(unsigned int agent_id,
|
|
+ unsigned int scmi_id,
|
|
+ bool enable_not_disable)
|
|
+{
|
|
+ rk_scmi_clock_t *clock;
|
|
+ int32_t status = 0;
|
|
+
|
|
+ clock = rockchip_scmi_get_clock(agent_id, scmi_id);
|
|
+ if (clock == 0)
|
|
+ return SCMI_NOT_FOUND;
|
|
+
|
|
+ if (clock->clk_ops && clock->clk_ops->set_status) {
|
|
+ status = clock->clk_ops->set_status(clock, enable_not_disable);
|
|
+ if (status == SCMI_SUCCESS)
|
|
+ clock->enable = enable_not_disable;
|
|
+ } else {
|
|
+ status = SCMI_NOT_SUPPORTED;
|
|
+ }
|
|
+
|
|
+ return status;
|
|
+}
|
|
diff --git a/plat/rockchip/common/scmi/scmi_clock.h b/plat/rockchip/common/scmi/scmi_clock.h
|
|
new file mode 100644
|
|
index 0000000..e640fe1
|
|
--- /dev/null
|
|
+++ b/plat/rockchip/common/scmi/scmi_clock.h
|
|
@@ -0,0 +1,50 @@
|
|
+/*
|
|
+ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef RK_SCMI_CLOCK_H
|
|
+#define RK_SCMI_CLOCK_H
|
|
+
|
|
+#include <stdint.h>
|
|
+
|
|
+#include <common.h>
|
|
+
|
|
+struct rk_scmi_clock;
|
|
+
|
|
+struct rk_clk_ops {
|
|
+ unsigned long (*get_rate)(struct rk_scmi_clock *clock);
|
|
+ int (*set_rate)(struct rk_scmi_clock *clock, unsigned long rate);
|
|
+ int (*set_status)(struct rk_scmi_clock *clock, bool status);
|
|
+};
|
|
+
|
|
+typedef struct rk_scmi_clock {
|
|
+ char name[SCMI_CLOCK_NAME_LENGTH_MAX];
|
|
+ uint8_t enable;
|
|
+ int8_t is_security;
|
|
+ uint32_t id;
|
|
+ uint32_t rate_cnt;
|
|
+ uint64_t cur_rate;
|
|
+ uint32_t enable_count;
|
|
+ const struct rk_clk_ops *clk_ops;
|
|
+ unsigned long *rate_table;
|
|
+} rk_scmi_clock_t;
|
|
+
|
|
+/*
|
|
+ * Return number of clock controllers for an agent
|
|
+ * @agent_id: SCMI agent ID
|
|
+ * Return number of clock controllers
|
|
+ */
|
|
+size_t rockchip_scmi_clock_count(unsigned int agent_id);
|
|
+
|
|
+/*
|
|
+ * Get rk_scmi_clock_t point
|
|
+ * @agent_id: SCMI agent ID
|
|
+ * @scmi_id: SCMI clock ID
|
|
+ * Return a rk_scmi_clock_t point
|
|
+ */
|
|
+rk_scmi_clock_t *rockchip_scmi_get_clock(uint32_t agent_id,
|
|
+ uint32_t scmi_id);
|
|
+
|
|
+#endif /* RK_SCMI_CLOCK_H */
|
|
diff --git a/plat/rockchip/common/scmi/scmi_rstd.c b/plat/rockchip/common/scmi/scmi_rstd.c
|
|
new file mode 100644
|
|
index 0000000..404d85e
|
|
--- /dev/null
|
|
+++ b/plat/rockchip/common/scmi/scmi_rstd.c
|
|
@@ -0,0 +1,74 @@
|
|
+/*
|
|
+ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#include <drivers/scmi-msg.h>
|
|
+#include <drivers/scmi.h>
|
|
+
|
|
+#include "scmi_rstd.h"
|
|
+
|
|
+#pragma weak rockchip_scmi_rstd_count
|
|
+#pragma weak rockchip_scmi_get_rstd
|
|
+
|
|
+size_t rockchip_scmi_rstd_count(unsigned int agent_id __unused)
|
|
+{
|
|
+ return 0U;
|
|
+}
|
|
+
|
|
+rk_scmi_rstd_t *rockchip_scmi_get_rstd(unsigned int agent_id __unused,
|
|
+ unsigned int scmi_id __unused)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+size_t plat_scmi_rstd_count(unsigned int agent_id)
|
|
+{
|
|
+ return rockchip_scmi_rstd_count(agent_id);
|
|
+}
|
|
+
|
|
+const char *plat_scmi_rstd_get_name(unsigned int agent_id,
|
|
+ unsigned int scmi_id)
|
|
+{
|
|
+ rk_scmi_rstd_t *rstd;
|
|
+
|
|
+ rstd = rockchip_scmi_get_rstd(agent_id, scmi_id);
|
|
+ if (rstd == 0)
|
|
+ return NULL;
|
|
+
|
|
+ return rstd->name;
|
|
+}
|
|
+
|
|
+int32_t plat_scmi_rstd_autonomous(unsigned int agent_id,
|
|
+ unsigned int scmi_id,
|
|
+ unsigned int state)
|
|
+{
|
|
+ rk_scmi_rstd_t *rstd;
|
|
+
|
|
+ rstd = rockchip_scmi_get_rstd(agent_id, scmi_id);
|
|
+ if (rstd == 0)
|
|
+ return SCMI_NOT_FOUND;
|
|
+
|
|
+ if ((rstd->rstd_ops && rstd->rstd_ops->reset_auto) != 0)
|
|
+ return rstd->rstd_ops->reset_auto(rstd, state);
|
|
+ else
|
|
+ return SCMI_NOT_SUPPORTED;
|
|
+}
|
|
+
|
|
+int32_t plat_scmi_rstd_set_state(unsigned int agent_id,
|
|
+ unsigned int scmi_id,
|
|
+ bool assert_not_deassert)
|
|
+{
|
|
+ rk_scmi_rstd_t *rstd;
|
|
+
|
|
+ rstd = rockchip_scmi_get_rstd(agent_id, scmi_id);
|
|
+ if (rstd == 0)
|
|
+ return SCMI_NOT_FOUND;
|
|
+
|
|
+ if ((rstd->rstd_ops && rstd->rstd_ops->reset_explicit) != 0)
|
|
+ return rstd->rstd_ops->reset_explicit(rstd,
|
|
+ assert_not_deassert);
|
|
+ else
|
|
+ return SCMI_NOT_SUPPORTED;
|
|
+}
|
|
diff --git a/plat/rockchip/common/scmi/scmi_rstd.h b/plat/rockchip/common/scmi/scmi_rstd.h
|
|
new file mode 100644
|
|
index 0000000..1af5881
|
|
--- /dev/null
|
|
+++ b/plat/rockchip/common/scmi/scmi_rstd.h
|
|
@@ -0,0 +1,45 @@
|
|
+/*
|
|
+ * Copyright (c) 2024, Rockchip, Inc. All rights reserved.
|
|
+ *
|
|
+ * SPDX-License-Identifier: BSD-3-Clause
|
|
+ */
|
|
+
|
|
+#ifndef RK_SCMI_RESET_DOMAIN_H
|
|
+#define RK_SCMI_RESET_DOMAIN_H
|
|
+
|
|
+#include <stdint.h>
|
|
+
|
|
+#include <common.h>
|
|
+
|
|
+struct rk_scmi_rstd;
|
|
+
|
|
+struct rk_scmi_rstd_ops {
|
|
+ int (*reset_auto)(struct rk_scmi_rstd *rstd, uint32_t state);
|
|
+ int (*reset_explicit)(struct rk_scmi_rstd *rstd, bool assert_not_deassert);
|
|
+};
|
|
+
|
|
+typedef struct rk_scmi_rstd {
|
|
+ char name[SCMI_RESET_DOMAIN_ATTR_NAME_SZ];
|
|
+ uint32_t id;
|
|
+ uint32_t attribute;
|
|
+ uint32_t latency;
|
|
+ struct rk_scmi_rstd_ops *rstd_ops;
|
|
+} rk_scmi_rstd_t;
|
|
+
|
|
+/*
|
|
+ * Return number of reset domain for an agent
|
|
+ * @agent_id: SCMI agent ID
|
|
+ * Return number of reset domain
|
|
+ */
|
|
+size_t rockchip_scmi_rstd_count(unsigned int agent_id);
|
|
+
|
|
+/*
|
|
+ * Get rk_scmi_rstd_t point
|
|
+ * @agent_id: SCMI agent ID
|
|
+ * @scmi_id: SCMI rstd ID
|
|
+ * Return a rk_scmi_rstd_t point
|
|
+ */
|
|
+rk_scmi_rstd_t *rockchip_scmi_get_rstd(unsigned int agent_id,
|
|
+ unsigned int scmi_id);
|
|
+
|
|
+#endif /* RK_SCMI_RESET_DOMAIN_H */
|