summaryrefslogtreecommitdiff
path: root/drivers/firmware
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-11 07:45:30 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-11 07:45:30 +0300
commitbdbddf72a2ab1cfea699959795d70df3931eefe7 (patch)
treee3f8018c6e8d0354bf2a2fbd99569790ef521805 /drivers/firmware
parentf7fae9b4d38f0c52489640c9688e529c4a58e1b6 (diff)
parentcfd00b7e26c8331e3bb0f03ca770888866c15ff4 (diff)
downloadlinux-bdbddf72a2ab1cfea699959795d70df3931eefe7.tar.xz
Merge tag 'soc-drivers-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull SoC driver updates from Arnd Bergmann: "There are are a number of to firmware drivers, in particular the TEE subsystem: - a bus callback for TEE firmware that device drivers can register to - sysfs support for tee firmware information - minor updates to platform specific TEE drivers for AMD, NXP, Qualcomm and the generic optee driver - ARM SCMI firmware refactoring to improve the protocol discover among other fixes and cleanups - ARM FF-A firmware interoperability improvements The reset controller and memory controller subsystems gain support for additional hardware platforms from Mediatek, Renesas, NXP, Canaan and SpacemiT. Most of the other changes are for random drivers/soc code. Among a number of cleanups and newly added hardware support, including: - Mediatek MT8196 DVFS power management and mailbox support - Qualcomm SCM firmware and MDT loader refactoring, as part of the new Glymur platform support. - NXP i.MX9 System Manager firmware support for accessing the syslog - Minor updates for TI, Renesas, Samsung, Apple, Marvell and AMD SoCs" * tag 'soc-drivers-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (171 commits) bus: fsl-mc: fix an error handling in fsl_mc_device_add() reset: spacemit: Add SpacemiT K3 reset driver reset: spacemit: Extract common K1 reset code reset: Create subdirectory for SpacemiT drivers dt-bindings: soc: spacemit: Add K3 reset support and IDs reset: canaan: k230: drop OF dependency and enable by default reset: rzg2l-usbphy-ctrl: Add suspend/resume support reset: rzg2l-usbphy-ctrl: Propagate the return value of regmap_field_update_bits() reset: gpio: check the return value of gpiod_set_value_cansleep() reset: imx8mp-audiomix: Support i.MX8ULP SIM LPAV reset: imx8mp-audiomix: Extend the driver usage reset: imx8mp-audiomix: Switch to using regmap API reset: imx8mp-audiomix: Drop unneeded macros soc: fsl: qe: qe_ports_ic: Consolidate chained IRQ handler install/remove soc: mediatek: mtk-cmdq: Add mminfra_offset adjustment for DRAM addresses soc: mediatek: mtk-cmdq: Extend cmdq_pkt_write API for SoCs without subsys ID soc: mediatek: mtk-cmdq: Add pa_base parsing for hardware without subsys ID support soc: mediatek: mtk-cmdq: Add cmdq_get_mbox_priv() in cmdq_pkt_create() mailbox: mtk-cmdq: Add driver data to support for MT8196 mailbox: mtk-cmdq: Add mminfra_offset configuration for DRAM transaction ...
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/arm_ffa/driver.c48
-rw-r--r--drivers/firmware/arm_scmi/base.c11
-rw-r--r--drivers/firmware/arm_scmi/clock.c24
-rw-r--r--drivers/firmware/arm_scmi/driver.c98
-rw-r--r--drivers/firmware/arm_scmi/perf.c59
-rw-r--r--drivers/firmware/arm_scmi/pinctrl.c120
-rw-r--r--drivers/firmware/arm_scmi/power.c18
-rw-r--r--drivers/firmware/arm_scmi/powercap.c21
-rw-r--r--drivers/firmware/arm_scmi/protocols.h9
-rw-r--r--drivers/firmware/arm_scmi/reset.c68
-rw-r--r--drivers/firmware/arm_scmi/sensors.c22
-rw-r--r--drivers/firmware/arm_scmi/shmem.c5
-rw-r--r--drivers/firmware/arm_scmi/system.c14
-rw-r--r--drivers/firmware/arm_scmi/transports/optee.c32
-rw-r--r--drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c10
-rw-r--r--drivers/firmware/arm_scmi/vendors/imx/imx-sm-cpu.c9
-rw-r--r--drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c9
-rw-r--r--drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c93
-rw-r--r--drivers/firmware/arm_scmi/voltage.c13
-rw-r--r--drivers/firmware/broadcom/tee_bnxt_fw.c30
-rw-r--r--drivers/firmware/efi/stmm/tee_stmm_efi.c25
-rw-r--r--drivers/firmware/imx/sm-misc.c37
-rw-r--r--drivers/firmware/qcom/qcom_scm.c507
-rw-r--r--drivers/firmware/qcom/qcom_scm.h2
-rw-r--r--drivers/firmware/ti_sci.h29
25 files changed, 880 insertions, 433 deletions
diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
index c72ee4756585..8144f6a9f0e9 100644
--- a/drivers/firmware/arm_ffa/driver.c
+++ b/drivers/firmware/arm_ffa/driver.c
@@ -246,6 +246,11 @@ static int ffa_features(u32 func_feat_id, u32 input_props,
}
#define PARTITION_INFO_GET_RETURN_COUNT_ONLY BIT(0)
+#define FFA_SUPPORTS_GET_COUNT_ONLY(version) ((version) > FFA_VERSION_1_0)
+#define FFA_PART_INFO_HAS_SIZE_IN_RESP(version) ((version) > FFA_VERSION_1_0)
+#define FFA_PART_INFO_HAS_UUID_IN_RESP(version) ((version) > FFA_VERSION_1_0)
+#define FFA_PART_INFO_HAS_EXEC_STATE_IN_RESP(version) \
+ ((version) > FFA_VERSION_1_0)
/* buffer must be sizeof(struct ffa_partition_info) * num_partitions */
static int
@@ -255,7 +260,7 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
int idx, count, flags = 0, sz, buf_sz;
ffa_value_t partition_info;
- if (drv_info->version > FFA_VERSION_1_0 &&
+ if (FFA_SUPPORTS_GET_COUNT_ONLY(drv_info->version) &&
(!buffer || !num_partitions)) /* Just get the count for now */
flags = PARTITION_INFO_GET_RETURN_COUNT_ONLY;
@@ -273,12 +278,11 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
count = partition_info.a2;
- if (drv_info->version > FFA_VERSION_1_0) {
+ if (FFA_PART_INFO_HAS_SIZE_IN_RESP(drv_info->version)) {
buf_sz = sz = partition_info.a3;
if (sz > sizeof(*buffer))
buf_sz = sizeof(*buffer);
} else {
- /* FFA_VERSION_1_0 lacks size in the response */
buf_sz = sz = 8;
}
@@ -981,10 +985,27 @@ static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu)
}
}
+/*
+ * Map logical ID index to the u16 index within the packed ID list.
+ *
+ * For native responses (FF-A width == kernel word size), IDs are
+ * tightly packed: idx -> idx.
+ *
+ * For 32-bit responses on a 64-bit kernel, each 64-bit register
+ * contributes 4 x u16 values but only the lower 2 are defined; the
+ * upper 2 are garbage. This mapping skips those upper halves:
+ * 0,1,2,3,4,5,... -> 0,1,4,5,8,9,...
+ */
+static int list_idx_to_u16_idx(int idx, bool is_native_resp)
+{
+ return is_native_resp ? idx : idx + 2 * (idx >> 1);
+}
+
static void ffa_notification_info_get(void)
{
- int idx, list, max_ids, lists_cnt, ids_processed, ids_count[MAX_IDS_64];
- bool is_64b_resp;
+ int ids_processed, ids_count[MAX_IDS_64];
+ int idx, list, max_ids, lists_cnt;
+ bool is_64b_resp, is_native_resp;
ffa_value_t ret;
u64 id_list;
@@ -1001,6 +1022,7 @@ static void ffa_notification_info_get(void)
}
is_64b_resp = (ret.a0 == FFA_FN64_SUCCESS);
+ is_native_resp = (ret.a0 == FFA_FN_NATIVE(SUCCESS));
ids_processed = 0;
lists_cnt = FIELD_GET(NOTIFICATION_INFO_GET_ID_COUNT, ret.a2);
@@ -1017,12 +1039,16 @@ static void ffa_notification_info_get(void)
/* Process IDs */
for (list = 0; list < lists_cnt; list++) {
+ int u16_idx;
u16 vcpu_id, part_id, *packed_id_list = (u16 *)&ret.a3;
if (ids_processed >= max_ids - 1)
break;
- part_id = packed_id_list[ids_processed++];
+ u16_idx = list_idx_to_u16_idx(ids_processed,
+ is_native_resp);
+ part_id = packed_id_list[u16_idx];
+ ids_processed++;
if (ids_count[list] == 1) { /* Global Notification */
__do_sched_recv_cb(part_id, 0, false);
@@ -1034,7 +1060,10 @@ static void ffa_notification_info_get(void)
if (ids_processed >= max_ids - 1)
break;
- vcpu_id = packed_id_list[ids_processed++];
+ u16_idx = list_idx_to_u16_idx(ids_processed,
+ is_native_resp);
+ vcpu_id = packed_id_list[u16_idx];
+ ids_processed++;
__do_sched_recv_cb(part_id, vcpu_id, true);
}
@@ -1706,7 +1735,7 @@ static int ffa_setup_partitions(void)
struct ffa_device *ffa_dev;
struct ffa_partition_info *pbuf, *tpbuf;
- if (drv_info->version == FFA_VERSION_1_0) {
+ if (!FFA_PART_INFO_HAS_UUID_IN_RESP(drv_info->version)) {
ret = bus_register_notifier(&ffa_bus_type, &ffa_bus_nb);
if (ret)
pr_err("Failed to register FF-A bus notifiers\n");
@@ -1733,7 +1762,7 @@ static int ffa_setup_partitions(void)
continue;
}
- if (drv_info->version > FFA_VERSION_1_0 &&
+ if (FFA_PART_INFO_HAS_EXEC_STATE_IN_RESP(drv_info->version) &&
!(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC))
ffa_mode_32bit_set(ffa_dev);
@@ -2068,6 +2097,7 @@ static int __init ffa_init(void)
pr_err("failed to setup partitions\n");
ffa_notifications_cleanup();
+ ffa_rxtx_unmap(drv_info->vm_id);
free_pages:
if (drv_info->tx_buffer)
free_pages_exact(drv_info->tx_buffer, rxtx_bufsz);
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
index 86b376c50a13..22267bbd0f4d 100644
--- a/drivers/firmware/arm_scmi/base.c
+++ b/drivers/firmware/arm_scmi/base.c
@@ -375,18 +375,13 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph)
{
int id, ret;
u8 *prot_imp;
- u32 version;
char name[SCMI_SHORT_NAME_MAX_SIZE];
struct device *dev = ph->dev;
struct scmi_revision_info *rev = scmi_revision_area_get(ph);
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
- rev->major_ver = PROTOCOL_REV_MAJOR(version);
- rev->minor_ver = PROTOCOL_REV_MINOR(version);
- ph->set_priv(ph, rev, version);
+ rev->major_ver = PROTOCOL_REV_MAJOR(ph->version);
+ rev->minor_ver = PROTOCOL_REV_MINOR(ph->version);
+ ph->set_priv(ph, rev);
ret = scmi_base_attributes_get(ph);
if (ret)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index afa7981efe82..ab36871650a1 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -157,7 +157,6 @@ struct scmi_clock_rate_notify_payld {
};
struct clock_info {
- u32 version;
int num_clocks;
int max_async_req;
bool notify_rate_changed_cmd;
@@ -346,8 +345,7 @@ scmi_clock_get_permissions(const struct scmi_protocol_handle *ph, u32 clk_id,
}
static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
- u32 clk_id, struct clock_info *cinfo,
- u32 version)
+ u32 clk_id, struct clock_info *cinfo)
{
int ret;
u32 attributes;
@@ -370,7 +368,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
attributes = le32_to_cpu(attr->attributes);
strscpy(clk->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
/* clock_enable_latency field is present only since SCMI v3.1 */
- if (PROTOCOL_REV_MAJOR(version) >= 0x2)
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2)
latency = le32_to_cpu(attr->clock_enable_latency);
clk->enable_latency = latency ? : U32_MAX;
}
@@ -381,7 +379,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
* If supported overwrite short name with the extended one;
* on error just carry on and use already provided short name.
*/
- if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2) {
+ if (!ret && PROTOCOL_REV_MAJOR(ph->version) >= 0x2) {
if (SUPPORTS_EXTENDED_NAMES(attributes))
ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id,
NULL, clk->name,
@@ -393,7 +391,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
if (cinfo->notify_rate_change_requested_cmd &&
SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes))
clk->rate_change_requested_notifications = true;
- if (PROTOCOL_REV_MAJOR(version) >= 0x3) {
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3) {
if (SUPPORTS_PARENT_CLOCK(attributes))
scmi_clock_possible_parents(ph, clk_id, clk);
if (SUPPORTS_GET_PERMISSIONS(attributes))
@@ -1068,16 +1066,11 @@ static const struct scmi_protocol_events clk_protocol_events = {
static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
{
- u32 version;
int clkid, ret;
struct clock_info *cinfo;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_dbg(ph->dev, "Clock Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
cinfo = devm_kzalloc(ph->dev, sizeof(*cinfo), GFP_KERNEL);
if (!cinfo)
@@ -1095,12 +1088,12 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
for (clkid = 0; clkid < cinfo->num_clocks; clkid++) {
struct scmi_clock_info *clk = cinfo->clk + clkid;
- ret = scmi_clock_attributes_get(ph, clkid, cinfo, version);
+ ret = scmi_clock_attributes_get(ph, clkid, cinfo);
if (!ret)
scmi_clock_describe_rates_get(ph, clkid, clk);
}
- if (PROTOCOL_REV_MAJOR(version) >= 0x3) {
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3) {
cinfo->clock_config_set = scmi_clock_config_set_v2;
cinfo->clock_config_get = scmi_clock_config_get_v2;
} else {
@@ -1108,8 +1101,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
cinfo->clock_config_get = scmi_clock_config_get;
}
- cinfo->version = version;
- return ph->set_priv(ph, cinfo, version);
+ return ph->set_priv(ph, cinfo);
}
static const struct scmi_protocol scmi_clock = {
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c
index 5caa9191a8d1..3e76a3204ba4 100644
--- a/drivers/firmware/arm_scmi/driver.c
+++ b/drivers/firmware/arm_scmi/driver.c
@@ -1627,17 +1627,15 @@ static int version_get(const struct scmi_protocol_handle *ph, u32 *version)
*
* @ph: A reference to the protocol handle.
* @priv: The private data to set.
- * @version: The detected protocol version for the core to register.
*
* Return: 0 on Success
*/
static int scmi_set_protocol_priv(const struct scmi_protocol_handle *ph,
- void *priv, u32 version)
+ void *priv)
{
struct scmi_protocol_instance *pi = ph_to_pi(ph);
pi->priv = priv;
- pi->version = version;
return 0;
}
@@ -1657,7 +1655,6 @@ static void *scmi_get_protocol_priv(const struct scmi_protocol_handle *ph)
}
static const struct scmi_xfer_ops xfer_ops = {
- .version_get = version_get,
.xfer_get_init = xfer_get_init,
.reset_rx_to_maxsz = reset_rx_to_maxsz,
.do_xfer = do_xfer,
@@ -2113,6 +2110,76 @@ static int scmi_protocol_version_negotiate(struct scmi_protocol_handle *ph)
}
/**
+ * scmi_protocol_version_initialize - Initialize protocol version
+ * @dev: A device reference.
+ * @pi: A reference to the protocol instance being initialized
+ *
+ * At first retrieve the newest protocol version supported by the platform for
+ * this specific protoocol.
+ *
+ * Negotiation is attempted only when the platform advertised a protocol
+ * version newer than the most recent version known to this agent, since
+ * backward compatibility is NOT assured in general between versions.
+ *
+ * Failing to negotiate a fallback version or to query supported version at
+ * all will result in an attempt to use the newest version known to this agent
+ * even though compatibility is NOT assured.
+ *
+ * Versions are defined as:
+ *
+ * pi->version: the version supported by the platform as returned by the query.
+ * pi->proto->supported_version: the newest version supported by this agent
+ * for this protocol.
+ * pi->negotiated_version: The version successfully negotiated with the platform.
+ * ph->version: The final version effectively chosen for this session.
+ */
+static void scmi_protocol_version_initialize(struct device *dev,
+ struct scmi_protocol_instance *pi)
+{
+ struct scmi_protocol_handle *ph = &pi->ph;
+ int ret;
+
+ /*
+ * Query and store platform supported protocol version: this is usually
+ * the newest version the platfom can support.
+ */
+ ret = version_get(ph, &pi->version);
+ if (ret) {
+ dev_warn(dev,
+ "Failed to query supported version for protocol 0x%X.\n",
+ pi->proto->id);
+ goto best_effort;
+ }
+
+ /* Need to negotiate at all ? */
+ if (pi->version <= pi->proto->supported_version) {
+ ph->version = pi->version;
+ return;
+ }
+
+ /* Attempt negotiation */
+ ret = scmi_protocol_version_negotiate(ph);
+ if (!ret) {
+ ph->version = pi->negotiated_version;
+ dev_info(dev,
+ "Protocol 0x%X successfully negotiated version 0x%X\n",
+ pi->proto->id, ph->version);
+ return;
+ }
+
+ dev_warn(dev,
+ "Detected UNSUPPORTED higher version 0x%X for protocol 0x%X.\n",
+ pi->version, pi->proto->id);
+
+best_effort:
+ /* Fallback to use newest version known to this agent */
+ ph->version = pi->proto->supported_version;
+ dev_warn(dev,
+ "Trying version 0x%X. Backward compatibility is NOT assured.\n",
+ ph->version);
+}
+
+/**
* scmi_alloc_init_protocol_instance - Allocate and initialize a protocol
* instance descriptor.
* @info: The reference to the related SCMI instance.
@@ -2157,6 +2224,13 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
pi->ph.set_priv = scmi_set_protocol_priv;
pi->ph.get_priv = scmi_get_protocol_priv;
refcount_set(&pi->users, 1);
+
+ /*
+ * Initialize effectively used protocol version performing any
+ * possibly needed negotiations.
+ */
+ scmi_protocol_version_initialize(handle->dev, pi);
+
/* proto->init is assured NON NULL by scmi_protocol_register */
ret = pi->proto->instance_init(&pi->ph);
if (ret)
@@ -2184,22 +2258,6 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
devres_close_group(handle->dev, pi->gid);
dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id);
- if (pi->version > proto->supported_version) {
- ret = scmi_protocol_version_negotiate(&pi->ph);
- if (!ret) {
- dev_info(handle->dev,
- "Protocol 0x%X successfully negotiated version 0x%X\n",
- proto->id, pi->negotiated_version);
- } else {
- dev_warn(handle->dev,
- "Detected UNSUPPORTED higher version 0x%X for protocol 0x%X.\n",
- pi->version, pi->proto->id);
- dev_warn(handle->dev,
- "Trying version 0x%X. Backward compatibility is NOT assured.\n",
- pi->proto->supported_version);
- }
- }
-
return pi;
clean:
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index 683fd9b85c5c..4583d02bee1c 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -27,7 +27,7 @@
/* Updated only after ALL the mandatory features for that version are merged */
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x40000
-#define MAX_OPPS 32
+#define MAX_OPPS 64
enum scmi_performance_protocol_cmd {
PERF_DOMAIN_ATTRIBUTES = 0x3,
@@ -178,7 +178,6 @@ struct perf_dom_info {
})
struct scmi_perf_info {
- u32 version;
u16 num_domains;
enum scmi_power_scale power_scale;
u64 stats_addr;
@@ -215,7 +214,7 @@ static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph,
if (POWER_SCALE_IN_MILLIWATT(flags))
pi->power_scale = SCMI_POWER_MILLIWATTS;
- if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3)
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3)
if (POWER_SCALE_IN_MICROWATT(flags))
pi->power_scale = SCMI_POWER_MICROWATTS;
@@ -251,8 +250,7 @@ static void scmi_perf_xa_destroy(void *data)
static int
scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
struct perf_dom_info *dom_info,
- bool notify_lim_cmd, bool notify_lvl_cmd,
- u32 version)
+ bool notify_lim_cmd, bool notify_lvl_cmd)
{
int ret;
u32 flags;
@@ -280,7 +278,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
dom_info->perf_level_notify =
SUPPORTS_PERF_LEVEL_NOTIFY(flags);
dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags);
- if (PROTOCOL_REV_MAJOR(version) >= 0x4)
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x4)
dom_info->level_indexing_mode =
SUPPORTS_LEVEL_INDEXING(flags);
dom_info->rate_limit_us = le32_to_cpu(attr->rate_limit_us) &
@@ -323,7 +321,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
* If supported overwrite short name with the extended one;
* on error just carry on and use already provided short name.
*/
- if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
+ if (!ret && PROTOCOL_REV_MAJOR(ph->version) >= 0x3 &&
SUPPORTS_EXTENDED_NAMES(flags))
ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET,
dom_info->id, NULL, dom_info->info.name,
@@ -345,19 +343,14 @@ static int opp_cmp_func(const void *opp1, const void *opp2)
return t1->perf - t2->perf;
}
-struct scmi_perf_ipriv {
- u32 version;
- struct perf_dom_info *perf_dom;
-};
-
static void iter_perf_levels_prepare_message(void *message,
unsigned int desc_index,
const void *priv)
{
struct scmi_msg_perf_describe_levels *msg = message;
- const struct scmi_perf_ipriv *p = priv;
+ const struct perf_dom_info *perf_dom = priv;
- msg->domain = cpu_to_le32(p->perf_dom->id);
+ msg->domain = cpu_to_le32(perf_dom->id);
/* Set the number of OPPs to be skipped/already read */
msg->level_index = cpu_to_le32(desc_index);
}
@@ -445,21 +438,21 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph,
{
int ret;
struct scmi_opp *opp;
- struct scmi_perf_ipriv *p = priv;
+ struct perf_dom_info *perf_dom = priv;
- opp = &p->perf_dom->opp[p->perf_dom->opp_count];
- if (PROTOCOL_REV_MAJOR(p->version) <= 0x3)
- ret = process_response_opp(ph->dev, p->perf_dom, opp,
+ opp = &perf_dom->opp[perf_dom->opp_count];
+ if (PROTOCOL_REV_MAJOR(ph->version) <= 0x3)
+ ret = process_response_opp(ph->dev, perf_dom, opp,
st->loop_idx, response);
else
- ret = process_response_opp_v4(ph->dev, p->perf_dom, opp,
+ ret = process_response_opp_v4(ph->dev, perf_dom, opp,
st->loop_idx, response);
/* Skip BAD duplicates received from firmware */
if (ret)
return ret == -EBUSY ? 0 : ret;
- p->perf_dom->opp_count++;
+ perf_dom->opp_count++;
dev_dbg(ph->dev, "Level %d Power %d Latency %dus Ifreq %d Index %d\n",
opp->perf, opp->power, opp->trans_latency_us,
@@ -470,7 +463,7 @@ iter_perf_levels_process_response(const struct scmi_protocol_handle *ph,
static int
scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph,
- struct perf_dom_info *perf_dom, u32 version)
+ struct perf_dom_info *perf_dom)
{
int ret;
void *iter;
@@ -479,15 +472,11 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph,
.update_state = iter_perf_levels_update_state,
.process_response = iter_perf_levels_process_response,
};
- struct scmi_perf_ipriv ppriv = {
- .version = version,
- .perf_dom = perf_dom,
- };
iter = ph->hops->iter_response_init(ph, &ops, MAX_OPPS,
PERF_DESCRIBE_LEVELS,
sizeof(struct scmi_msg_perf_describe_levels),
- &ppriv);
+ perf_dom);
if (IS_ERR(iter))
return PTR_ERR(iter);
@@ -576,7 +565,6 @@ static int __scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
u32 domain, u32 max_perf, u32 min_perf)
{
- struct scmi_perf_info *pi = ph->get_priv(ph);
struct perf_dom_info *dom;
dom = scmi_perf_domain_lookup(ph, domain);
@@ -586,7 +574,7 @@ static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
if (!dom->set_limits)
return -EOPNOTSUPP;
- if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf)
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3 && !max_perf && !min_perf)
return -EINVAL;
if (dom->level_indexing_mode) {
@@ -1281,22 +1269,15 @@ static const struct scmi_protocol_events perf_protocol_events = {
static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
{
int domain, ret;
- u32 version;
struct scmi_perf_info *pinfo;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_dbg(ph->dev, "Performance Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
- pinfo->version = version;
-
ret = scmi_perf_attributes_get(ph, pinfo);
if (ret)
return ret;
@@ -1311,8 +1292,8 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
dom->id = domain;
scmi_perf_domain_attributes_get(ph, dom, pinfo->notify_lim_cmd,
- pinfo->notify_lvl_cmd, version);
- scmi_perf_describe_levels_get(ph, dom, version);
+ pinfo->notify_lvl_cmd);
+ scmi_perf_describe_levels_get(ph, dom);
if (dom->perf_fastchannels)
scmi_perf_domain_init_fc(ph, dom);
@@ -1322,7 +1303,7 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
if (ret)
return ret;
- return ph->set_priv(ph, pinfo, version);
+ return ph->set_priv(ph, pinfo);
}
static const struct scmi_protocol scmi_perf = {
diff --git a/drivers/firmware/arm_scmi/pinctrl.c b/drivers/firmware/arm_scmi/pinctrl.c
index 3855c98caf06..a020e23d7c49 100644
--- a/drivers/firmware/arm_scmi/pinctrl.c
+++ b/drivers/firmware/arm_scmi/pinctrl.c
@@ -117,7 +117,6 @@ struct scmi_pin_info {
};
struct scmi_pinctrl_info {
- u32 version;
int nr_groups;
int nr_functions;
int nr_pins;
@@ -596,11 +595,19 @@ static int scmi_pinctrl_pin_free(const struct scmi_protocol_handle *ph, u32 pin)
}
static int scmi_pinctrl_get_group_info(const struct scmi_protocol_handle *ph,
- u32 selector,
- struct scmi_group_info *group)
+ u32 selector)
{
+ struct scmi_pinctrl_info *pi = ph->get_priv(ph);
+ struct scmi_group_info *group;
int ret;
+ if (selector >= pi->nr_groups)
+ return -EINVAL;
+
+ group = &pi->groups[selector];
+ if (group->present)
+ return 0;
+
ret = scmi_pinctrl_attributes(ph, GROUP_TYPE, selector, group->name,
&group->nr_pins);
if (ret)
@@ -632,21 +639,14 @@ static int scmi_pinctrl_get_group_name(const struct scmi_protocol_handle *ph,
u32 selector, const char **name)
{
struct scmi_pinctrl_info *pi = ph->get_priv(ph);
+ int ret;
if (!name)
return -EINVAL;
- if (selector >= pi->nr_groups || pi->nr_groups == 0)
- return -EINVAL;
-
- if (!pi->groups[selector].present) {
- int ret;
-
- ret = scmi_pinctrl_get_group_info(ph, selector,
- &pi->groups[selector]);
- if (ret)
- return ret;
- }
+ ret = scmi_pinctrl_get_group_info(ph, selector);
+ if (ret)
+ return ret;
*name = pi->groups[selector].name;
@@ -658,21 +658,14 @@ static int scmi_pinctrl_group_pins_get(const struct scmi_protocol_handle *ph,
u32 *nr_pins)
{
struct scmi_pinctrl_info *pi = ph->get_priv(ph);
+ int ret;
if (!pins || !nr_pins)
return -EINVAL;
- if (selector >= pi->nr_groups || pi->nr_groups == 0)
- return -EINVAL;
-
- if (!pi->groups[selector].present) {
- int ret;
-
- ret = scmi_pinctrl_get_group_info(ph, selector,
- &pi->groups[selector]);
- if (ret)
- return ret;
- }
+ ret = scmi_pinctrl_get_group_info(ph, selector);
+ if (ret)
+ return ret;
*pins = pi->groups[selector].group_pins;
*nr_pins = pi->groups[selector].nr_pins;
@@ -681,11 +674,19 @@ static int scmi_pinctrl_group_pins_get(const struct scmi_protocol_handle *ph,
}
static int scmi_pinctrl_get_function_info(const struct scmi_protocol_handle *ph,
- u32 selector,
- struct scmi_function_info *func)
+ u32 selector)
{
+ struct scmi_pinctrl_info *pi = ph->get_priv(ph);
+ struct scmi_function_info *func;
int ret;
+ if (selector >= pi->nr_functions)
+ return -EINVAL;
+
+ func = &pi->functions[selector];
+ if (func->present)
+ return 0;
+
ret = scmi_pinctrl_attributes(ph, FUNCTION_TYPE, selector, func->name,
&func->nr_groups);
if (ret)
@@ -716,21 +717,14 @@ static int scmi_pinctrl_get_function_name(const struct scmi_protocol_handle *ph,
u32 selector, const char **name)
{
struct scmi_pinctrl_info *pi = ph->get_priv(ph);
+ int ret;
if (!name)
return -EINVAL;
- if (selector >= pi->nr_functions || pi->nr_functions == 0)
- return -EINVAL;
-
- if (!pi->functions[selector].present) {
- int ret;
-
- ret = scmi_pinctrl_get_function_info(ph, selector,
- &pi->functions[selector]);
- if (ret)
- return ret;
- }
+ ret = scmi_pinctrl_get_function_info(ph, selector);
+ if (ret)
+ return ret;
*name = pi->functions[selector].name;
return 0;
@@ -742,21 +736,14 @@ scmi_pinctrl_function_groups_get(const struct scmi_protocol_handle *ph,
const u32 **groups)
{
struct scmi_pinctrl_info *pi = ph->get_priv(ph);
+ int ret;
if (!groups || !nr_groups)
return -EINVAL;
- if (selector >= pi->nr_functions || pi->nr_functions == 0)
- return -EINVAL;
-
- if (!pi->functions[selector].present) {
- int ret;
-
- ret = scmi_pinctrl_get_function_info(ph, selector,
- &pi->functions[selector]);
- if (ret)
- return ret;
- }
+ ret = scmi_pinctrl_get_function_info(ph, selector);
+ if (ret)
+ return ret;
*groups = pi->functions[selector].groups;
*nr_groups = pi->functions[selector].nr_groups;
@@ -771,13 +758,19 @@ static int scmi_pinctrl_mux_set(const struct scmi_protocol_handle *ph,
}
static int scmi_pinctrl_get_pin_info(const struct scmi_protocol_handle *ph,
- u32 selector, struct scmi_pin_info *pin)
+ u32 selector)
{
+ struct scmi_pinctrl_info *pi = ph->get_priv(ph);
+ struct scmi_pin_info *pin;
int ret;
- if (!pin)
+ if (selector >= pi->nr_pins)
return -EINVAL;
+ pin = &pi->pins[selector];
+ if (pin->present)
+ return 0;
+
ret = scmi_pinctrl_attributes(ph, PIN_TYPE, selector, pin->name, NULL);
if (ret)
return ret;
@@ -790,20 +783,14 @@ static int scmi_pinctrl_get_pin_name(const struct scmi_protocol_handle *ph,
u32 selector, const char **name)
{
struct scmi_pinctrl_info *pi = ph->get_priv(ph);
+ int ret;
if (!name)
return -EINVAL;
- if (selector >= pi->nr_pins)
- return -EINVAL;
-
- if (!pi->pins[selector].present) {
- int ret;
-
- ret = scmi_pinctrl_get_pin_info(ph, selector, &pi->pins[selector]);
- if (ret)
- return ret;
- }
+ ret = scmi_pinctrl_get_pin_info(ph, selector);
+ if (ret)
+ return ret;
*name = pi->pins[selector].name;
@@ -843,15 +830,10 @@ static const struct scmi_pinctrl_proto_ops pinctrl_proto_ops = {
static int scmi_pinctrl_protocol_init(const struct scmi_protocol_handle *ph)
{
int ret;
- u32 version;
struct scmi_pinctrl_info *pinfo;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_dbg(ph->dev, "Pinctrl Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
@@ -876,9 +858,7 @@ static int scmi_pinctrl_protocol_init(const struct scmi_protocol_handle *ph)
if (!pinfo->functions)
return -ENOMEM;
- pinfo->version = version;
-
- return ph->set_priv(ph, pinfo, version);
+ return ph->set_priv(ph, pinfo);
}
static int scmi_pinctrl_protocol_deinit(const struct scmi_protocol_handle *ph)
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index 59aa16444c64..bb5062ab8280 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -67,7 +67,6 @@ struct power_dom_info {
};
struct scmi_power_info {
- u32 version;
bool notify_state_change_cmd;
int num_domains;
u64 stats_addr;
@@ -109,7 +108,7 @@ static int scmi_power_attributes_get(const struct scmi_protocol_handle *ph,
static int
scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
u32 domain, struct power_dom_info *dom_info,
- u32 version, bool notify_state_change_cmd)
+ bool notify_state_change_cmd)
{
int ret;
u32 flags;
@@ -141,7 +140,7 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
* If supported overwrite short name with the extended one;
* on error just carry on and use already provided short name.
*/
- if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
+ if (!ret && PROTOCOL_REV_MAJOR(ph->version) >= 0x3 &&
SUPPORTS_EXTENDED_NAMES(flags)) {
ph->hops->extended_name_get(ph, POWER_DOMAIN_NAME_GET,
domain, NULL, dom_info->name,
@@ -323,15 +322,10 @@ static const struct scmi_protocol_events power_protocol_events = {
static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)
{
int domain, ret;
- u32 version;
struct scmi_power_info *pinfo;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_dbg(ph->dev, "Power Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
@@ -349,13 +343,11 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)
for (domain = 0; domain < pinfo->num_domains; domain++) {
struct power_dom_info *dom = pinfo->dom_info + domain;
- scmi_power_domain_attributes_get(ph, domain, dom, version,
+ scmi_power_domain_attributes_get(ph, domain, dom,
pinfo->notify_state_change_cmd);
}
- pinfo->version = version;
-
- return ph->set_priv(ph, pinfo, version);
+ return ph->set_priv(ph, pinfo);
}
static const struct scmi_protocol scmi_power = {
diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c
index 1fa79bba492e..ab9733f4458b 100644
--- a/drivers/firmware/arm_scmi/powercap.c
+++ b/drivers/firmware/arm_scmi/powercap.c
@@ -122,7 +122,6 @@ struct scmi_powercap_state {
};
struct powercap_info {
- u32 version;
int num_domains;
bool notify_cap_cmd;
bool notify_measurements_cmd;
@@ -434,7 +433,7 @@ static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
}
/* Save the last explicitly set non-zero powercap value */
- if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 && !ret && power_cap)
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2 && !ret && power_cap)
pi->states[domain_id].last_pcap = power_cap;
return ret;
@@ -454,7 +453,7 @@ static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
return -EINVAL;
/* Just log the last set request if acting on a disabled domain */
- if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 &&
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2 &&
!pi->states[domain_id].enabled) {
pi->states[domain_id].last_pcap = power_cap;
return 0;
@@ -635,7 +634,7 @@ static int scmi_powercap_cap_enable_set(const struct scmi_protocol_handle *ph,
u32 power_cap;
struct powercap_info *pi = ph->get_priv(ph);
- if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
+ if (PROTOCOL_REV_MAJOR(ph->version) < 0x2)
return -EINVAL;
if (enable == pi->states[domain_id].enabled)
@@ -676,7 +675,7 @@ static int scmi_powercap_cap_enable_get(const struct scmi_protocol_handle *ph,
struct powercap_info *pi = ph->get_priv(ph);
*enable = true;
- if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
+ if (PROTOCOL_REV_MAJOR(ph->version) < 0x2)
return 0;
/*
@@ -961,15 +960,10 @@ static int
scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
{
int domain, ret;
- u32 version;
struct powercap_info *pinfo;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_dbg(ph->dev, "Powercap Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
@@ -1006,7 +1000,7 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
&pinfo->powercaps[domain].fc_info);
/* Grab initial state when disable is supported. */
- if (PROTOCOL_REV_MAJOR(version) >= 0x2) {
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2) {
ret = __scmi_powercap_cap_get(ph,
&pinfo->powercaps[domain],
&pinfo->states[domain].last_pcap);
@@ -1018,8 +1012,7 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
}
}
- pinfo->version = version;
- return ph->set_priv(ph, pinfo, version);
+ return ph->set_priv(ph, pinfo);
}
static const struct scmi_protocol scmi_powercap = {
diff --git a/drivers/firmware/arm_scmi/protocols.h b/drivers/firmware/arm_scmi/protocols.h
index d62c4469d1fd..4c75970326e6 100644
--- a/drivers/firmware/arm_scmi/protocols.h
+++ b/drivers/firmware/arm_scmi/protocols.h
@@ -159,6 +159,9 @@ struct scmi_proto_helpers_ops;
* struct scmi_protocol_handle - Reference to an initialized protocol instance
*
* @dev: A reference to the associated SCMI instance device (handle->dev).
+ * @version: The protocol version currently effectively in use by this
+ * initialized instance of the protocol as determined at the end of
+ * any possibly needed negotiations performed by the core.
* @xops: A reference to a struct holding refs to the core xfer operations that
* can be used by the protocol implementation to generate SCMI messages.
* @set_priv: A method to set protocol private data for this instance.
@@ -177,10 +180,10 @@ struct scmi_proto_helpers_ops;
*/
struct scmi_protocol_handle {
struct device *dev;
+ unsigned int version;
const struct scmi_xfer_ops *xops;
const struct scmi_proto_helpers_ops *hops;
- int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv,
- u32 version);
+ int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv);
void *(*get_priv)(const struct scmi_protocol_handle *ph);
};
@@ -287,7 +290,6 @@ struct scmi_proto_helpers_ops {
/**
* struct scmi_xfer_ops - References to the core SCMI xfer operations.
- * @version_get: Get this version protocol.
* @xfer_get_init: Initialize one struct xfer if any xfer slot is free.
* @reset_rx_to_maxsz: Reset rx size to max transport size.
* @do_xfer: Do the SCMI transfer.
@@ -300,7 +302,6 @@ struct scmi_proto_helpers_ops {
* another protocol.
*/
struct scmi_xfer_ops {
- int (*version_get)(const struct scmi_protocol_handle *ph, u32 *version);
int (*xfer_get_init)(const struct scmi_protocol_handle *ph, u8 msg_id,
size_t tx_size, size_t rx_size,
struct scmi_xfer **p);
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
index 0aa82b96f41b..4bc5c24c2d72 100644
--- a/drivers/firmware/arm_scmi/reset.c
+++ b/drivers/firmware/arm_scmi/reset.c
@@ -65,7 +65,6 @@ struct reset_dom_info {
};
struct scmi_reset_info {
- u32 version;
int num_domains;
bool notify_reset_cmd;
struct reset_dom_info *dom_info;
@@ -98,10 +97,20 @@ static int scmi_reset_attributes_get(const struct scmi_protocol_handle *ph,
return ret;
}
+static struct reset_dom_info *
+scmi_reset_domain_lookup(const struct scmi_protocol_handle *ph, u32 domain)
+{
+ struct scmi_reset_info *pi = ph->get_priv(ph);
+
+ if (domain >= pi->num_domains)
+ return ERR_PTR(-EINVAL);
+
+ return pi->dom_info + domain;
+}
+
static int
scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
- struct scmi_reset_info *pinfo,
- u32 domain, u32 version)
+ struct scmi_reset_info *pinfo, u32 domain)
{
int ret;
u32 attributes;
@@ -137,7 +146,7 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
* If supported overwrite short name with the extended one;
* on error just carry on and use already provided short name.
*/
- if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
+ if (!ret && PROTOCOL_REV_MAJOR(ph->version) >= 0x3 &&
SUPPORTS_EXTENDED_NAMES(attributes))
ph->hops->extended_name_get(ph, RESET_DOMAIN_NAME_GET, domain,
NULL, dom_info->name,
@@ -156,20 +165,25 @@ static int scmi_reset_num_domains_get(const struct scmi_protocol_handle *ph)
static const char *
scmi_reset_name_get(const struct scmi_protocol_handle *ph, u32 domain)
{
- struct scmi_reset_info *pi = ph->get_priv(ph);
+ struct reset_dom_info *dom_info;
- struct reset_dom_info *dom = pi->dom_info + domain;
+ dom_info = scmi_reset_domain_lookup(ph, domain);
+ if (IS_ERR(dom_info))
+ return "unknown";
- return dom->name;
+ return dom_info->name;
}
static int scmi_reset_latency_get(const struct scmi_protocol_handle *ph,
u32 domain)
{
- struct scmi_reset_info *pi = ph->get_priv(ph);
- struct reset_dom_info *dom = pi->dom_info + domain;
+ struct reset_dom_info *dom_info;
- return dom->latency_us;
+ dom_info = scmi_reset_domain_lookup(ph, domain);
+ if (IS_ERR(dom_info))
+ return PTR_ERR(dom_info);
+
+ return dom_info->latency_us;
}
static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain,
@@ -178,14 +192,13 @@ static int scmi_domain_reset(const struct scmi_protocol_handle *ph, u32 domain,
int ret;
struct scmi_xfer *t;
struct scmi_msg_reset_domain_reset *dom;
- struct scmi_reset_info *pi = ph->get_priv(ph);
- struct reset_dom_info *rdom;
+ struct reset_dom_info *dom_info;
- if (domain >= pi->num_domains)
- return -EINVAL;
+ dom_info = scmi_reset_domain_lookup(ph, domain);
+ if (IS_ERR(dom_info))
+ return PTR_ERR(dom_info);
- rdom = pi->dom_info + domain;
- if (rdom->async_reset && flags & AUTONOMOUS_RESET)
+ if (dom_info->async_reset && flags & AUTONOMOUS_RESET)
flags |= ASYNCHRONOUS_RESET;
ret = ph->xops->xfer_get_init(ph, RESET, sizeof(*dom), 0, &t);
@@ -238,15 +251,16 @@ static const struct scmi_reset_proto_ops reset_proto_ops = {
static bool scmi_reset_notify_supported(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id)
{
- struct reset_dom_info *dom;
- struct scmi_reset_info *pi = ph->get_priv(ph);
+ struct reset_dom_info *dom_info;
- if (evt_id != SCMI_EVENT_RESET_ISSUED || src_id >= pi->num_domains)
+ if (evt_id != SCMI_EVENT_RESET_ISSUED)
return false;
- dom = pi->dom_info + src_id;
+ dom_info = scmi_reset_domain_lookup(ph, src_id);
+ if (IS_ERR(dom_info))
+ return false;
- return dom->reset_notify;
+ return dom_info->reset_notify;
}
static int scmi_reset_notify(const struct scmi_protocol_handle *ph,
@@ -340,15 +354,10 @@ static const struct scmi_protocol_events reset_protocol_events = {
static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
{
int domain, ret;
- u32 version;
struct scmi_reset_info *pinfo;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_dbg(ph->dev, "Reset Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
@@ -364,10 +373,9 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
return -ENOMEM;
for (domain = 0; domain < pinfo->num_domains; domain++)
- scmi_reset_domain_attributes_get(ph, pinfo, domain, version);
+ scmi_reset_domain_attributes_get(ph, pinfo, domain);
- pinfo->version = version;
- return ph->set_priv(ph, pinfo, version);
+ return ph->set_priv(ph, pinfo);
}
static const struct scmi_protocol scmi_reset = {
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index 791efd0f82d7..882d55f987d2 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -214,7 +214,6 @@ struct scmi_sensor_update_notify_payld {
};
struct sensors_info {
- u32 version;
bool notify_trip_point_cmd;
bool notify_continuos_update_cmd;
int num_sensors;
@@ -524,8 +523,7 @@ scmi_sensor_axis_extended_names_get(const struct scmi_protocol_handle *ph,
}
static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
- struct scmi_sensor_info *s,
- u32 version)
+ struct scmi_sensor_info *s)
{
int ret;
void *iter;
@@ -555,7 +553,7 @@ static int scmi_sensor_axis_description(const struct scmi_protocol_handle *ph,
if (ret)
return ret;
- if (PROTOCOL_REV_MAJOR(version) >= 0x3 &&
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3 &&
apriv.any_axes_support_extended_names)
ret = scmi_sensor_axis_extended_names_get(ph, s);
@@ -621,7 +619,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
s->type = SENSOR_TYPE(attrh);
/* Use pre-allocated pool wherever possible */
s->intervals.desc = s->intervals.prealloc_pool;
- if (si->version == SCMIv2_SENSOR_PROTOCOL) {
+ if (ph->version == SCMIv2_SENSOR_PROTOCOL) {
s->intervals.segmented = false;
s->intervals.count = 1;
/*
@@ -659,7 +657,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
* one; on error just carry on and use already provided
* short name.
*/
- if (PROTOCOL_REV_MAJOR(si->version) >= 0x3 &&
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x3 &&
SUPPORTS_EXTENDED_NAMES(attrl))
ph->hops->extended_name_get(ph, SENSOR_NAME_GET, s->id,
NULL, s->name, SCMI_MAX_STR_SIZE);
@@ -683,7 +681,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
}
if (s->num_axis > 0)
- ret = scmi_sensor_axis_description(ph, s, si->version);
+ ret = scmi_sensor_axis_description(ph, s);
st->priv = ((u8 *)sdesc + dsize);
@@ -1148,21 +1146,15 @@ static const struct scmi_protocol_events sensor_protocol_events = {
static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph)
{
- u32 version;
int ret;
struct sensors_info *sinfo;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_dbg(ph->dev, "Sensor Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
sinfo = devm_kzalloc(ph->dev, sizeof(*sinfo), GFP_KERNEL);
if (!sinfo)
return -ENOMEM;
- sinfo->version = version;
ret = scmi_sensor_attributes_get(ph, sinfo);
if (ret)
@@ -1176,7 +1168,7 @@ static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph)
if (ret)
return ret;
- return ph->set_priv(ph, sinfo, version);
+ return ph->set_priv(ph, sinfo);
}
static const struct scmi_protocol scmi_sensors = {
diff --git a/drivers/firmware/arm_scmi/shmem.c b/drivers/firmware/arm_scmi/shmem.c
index 11c347bff766..dadb37557f8a 100644
--- a/drivers/firmware/arm_scmi/shmem.c
+++ b/drivers/firmware/arm_scmi/shmem.c
@@ -196,7 +196,6 @@ static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo,
struct resource *res,
struct scmi_shmem_io_ops **ops)
{
- struct device_node *shmem __free(device_node);
const char *desc = tx ? "Tx" : "Rx";
int ret, idx = tx ? 0 : 1;
struct device *cdev = cinfo->dev;
@@ -205,7 +204,9 @@ static void __iomem *shmem_setup_iomap(struct scmi_chan_info *cinfo,
void __iomem *addr;
u32 reg_io_width;
- shmem = of_parse_phandle(cdev->of_node, "shmem", idx);
+ struct device_node *shmem __free(device_node) = of_parse_phandle(cdev->of_node,
+ "shmem", idx);
+
if (!shmem)
return IOMEM_ERR_PTR(-ENODEV);
diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c
index ec3d355d1772..0f51c36f6a9d 100644
--- a/drivers/firmware/arm_scmi/system.c
+++ b/drivers/firmware/arm_scmi/system.c
@@ -34,7 +34,6 @@ struct scmi_system_power_state_notifier_payld {
};
struct scmi_system_info {
- u32 version;
bool graceful_timeout_supported;
bool power_state_notify_cmd;
};
@@ -141,29 +140,22 @@ static const struct scmi_protocol_events system_protocol_events = {
static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph)
{
- int ret;
- u32 version;
struct scmi_system_info *pinfo;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_dbg(ph->dev, "System Power Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
if (!pinfo)
return -ENOMEM;
- pinfo->version = version;
- if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2)
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2)
pinfo->graceful_timeout_supported = true;
if (!ph->hops->protocol_msg_check(ph, SYSTEM_POWER_STATE_NOTIFY, NULL))
pinfo->power_state_notify_cmd = true;
- return ph->set_priv(ph, pinfo, version);
+ return ph->set_priv(ph, pinfo);
}
static const struct scmi_protocol scmi_system = {
diff --git a/drivers/firmware/arm_scmi/transports/optee.c b/drivers/firmware/arm_scmi/transports/optee.c
index dc0f46340153..07ae18d5279d 100644
--- a/drivers/firmware/arm_scmi/transports/optee.c
+++ b/drivers/firmware/arm_scmi/transports/optee.c
@@ -529,8 +529,9 @@ static const struct of_device_id scmi_of_match[] = {
DEFINE_SCMI_TRANSPORT_DRIVER(scmi_optee, scmi_optee_driver, scmi_optee_desc,
scmi_of_match, core);
-static int scmi_optee_service_probe(struct device *dev)
+static int scmi_optee_service_probe(struct tee_client_device *scmi_pta)
{
+ struct device *dev = &scmi_pta->dev;
struct scmi_optee_agent *agent;
struct tee_context *tee_ctx;
int ret;
@@ -578,24 +579,22 @@ err:
return ret;
}
-static int scmi_optee_service_remove(struct device *dev)
+static void scmi_optee_service_remove(struct tee_client_device *scmi_pta)
{
struct scmi_optee_agent *agent = scmi_optee_private;
if (!scmi_optee_private)
- return -EINVAL;
+ return;
platform_driver_unregister(&scmi_optee_driver);
if (!list_empty(&scmi_optee_private->channel_list))
- return -EBUSY;
+ return;
/* Ensure cleared reference is visible before resources are released */
smp_store_mb(scmi_optee_private, NULL);
tee_client_close_context(agent->tee_ctx);
-
- return 0;
}
static const struct tee_client_device_id scmi_optee_service_id[] = {
@@ -609,26 +608,15 @@ static const struct tee_client_device_id scmi_optee_service_id[] = {
MODULE_DEVICE_TABLE(tee, scmi_optee_service_id);
static struct tee_client_driver scmi_optee_service_driver = {
- .id_table = scmi_optee_service_id,
- .driver = {
+ .probe = scmi_optee_service_probe,
+ .remove = scmi_optee_service_remove,
+ .id_table = scmi_optee_service_id,
+ .driver = {
.name = "scmi-optee",
- .bus = &tee_bus_type,
- .probe = scmi_optee_service_probe,
- .remove = scmi_optee_service_remove,
},
};
-static int __init scmi_transport_optee_init(void)
-{
- return driver_register(&scmi_optee_service_driver.driver);
-}
-module_init(scmi_transport_optee_init);
-
-static void __exit scmi_transport_optee_exit(void)
-{
- driver_unregister(&scmi_optee_service_driver.driver);
-}
-module_exit(scmi_transport_optee_exit);
+module_tee_client_driver(scmi_optee_service_driver);
MODULE_AUTHOR("Etienne Carriere <etienne.carriere@foss.st.com>");
MODULE_DESCRIPTION("SCMI OPTEE Transport driver");
diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c
index aa176c1a5eef..33f9ebf6092b 100644
--- a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c
+++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c
@@ -48,7 +48,6 @@ enum scmi_imx_bbm_protocol_cmd {
#define SCMI_IMX_BBM_EVENT_RTC_MASK GENMASK(31, 24)
struct scmi_imx_bbm_info {
- u32 version;
int nr_rtc;
int nr_gpr;
};
@@ -345,16 +344,11 @@ static const struct scmi_imx_bbm_proto_ops scmi_imx_bbm_proto_ops = {
static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph)
{
- u32 version;
int ret;
struct scmi_imx_bbm_info *binfo;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_info(ph->dev, "NXP SM BBM Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
binfo = devm_kzalloc(ph->dev, sizeof(*binfo), GFP_KERNEL);
if (!binfo)
@@ -364,7 +358,7 @@ static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph)
if (ret)
return ret;
- return ph->set_priv(ph, binfo, version);
+ return ph->set_priv(ph, binfo);
}
static const struct scmi_protocol scmi_imx_bbm = {
diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-cpu.c b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-cpu.c
index 66f47f5371e5..753274af11d2 100644
--- a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-cpu.c
+++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-cpu.c
@@ -233,15 +233,10 @@ static int scmi_imx_cpu_attributes_get(const struct scmi_protocol_handle *ph,
static int scmi_imx_cpu_protocol_init(const struct scmi_protocol_handle *ph)
{
struct scmi_imx_cpu_info *info;
- u32 version;
int ret, i;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_info(ph->dev, "NXP SM CPU Protocol Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
info = devm_kzalloc(ph->dev, sizeof(*info), GFP_KERNEL);
if (!info)
@@ -257,7 +252,7 @@ static int scmi_imx_cpu_protocol_init(const struct scmi_protocol_handle *ph)
return ret;
}
- return ph->set_priv(ph, info, version);
+ return ph->set_priv(ph, info);
}
static const struct scmi_protocol scmi_imx_cpu = {
diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c
index b519c67fe920..c56ae247774d 100644
--- a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c
+++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c
@@ -226,15 +226,10 @@ static int scmi_imx_lmm_protocol_attributes_get(const struct scmi_protocol_handl
static int scmi_imx_lmm_protocol_init(const struct scmi_protocol_handle *ph)
{
struct scmi_imx_lmm_priv *info;
- u32 version;
int ret;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_info(ph->dev, "NXP SM LMM Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
info = devm_kzalloc(ph->dev, sizeof(*info), GFP_KERNEL);
if (!info)
@@ -244,7 +239,7 @@ static int scmi_imx_lmm_protocol_init(const struct scmi_protocol_handle *ph)
if (ret)
return ret;
- return ph->set_priv(ph, info, version);
+ return ph->set_priv(ph, info);
}
static const struct scmi_protocol scmi_imx_lmm = {
diff --git a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
index 700a3f24f4ef..0ada753367ef 100644
--- a/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
+++ b/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
@@ -28,11 +28,11 @@ enum scmi_imx_misc_protocol_cmd {
SCMI_IMX_MISC_DISCOVER_BUILD_INFO = 0x6,
SCMI_IMX_MISC_CTRL_NOTIFY = 0x8,
SCMI_IMX_MISC_CFG_INFO_GET = 0xC,
+ SCMI_IMX_MISC_SYSLOG_GET = 0xD,
SCMI_IMX_MISC_BOARD_INFO = 0xE,
};
struct scmi_imx_misc_info {
- u32 version;
u32 nr_dev_ctrl;
u32 nr_brd_ctrl;
u32 nr_reason;
@@ -89,6 +89,19 @@ struct scmi_imx_misc_cfg_info_out {
u8 cfgname[MISC_MAX_CFGNAME];
};
+struct scmi_imx_misc_syslog_in {
+ __le32 flags;
+ __le32 index;
+};
+
+#define REMAINING(x) le32_get_bits((x), GENMASK(31, 20))
+#define RETURNED(x) le32_get_bits((x), GENMASK(11, 0))
+
+struct scmi_imx_misc_syslog_out {
+ __le32 numlogflags;
+ __le32 syslog[];
+};
+
static int scmi_imx_misc_attributes_get(const struct scmi_protocol_handle *ph,
struct scmi_imx_misc_info *mi)
{
@@ -371,24 +384,88 @@ static int scmi_imx_misc_cfg_info_get(const struct scmi_protocol_handle *ph)
return ret;
}
+struct scmi_imx_misc_syslog_ipriv {
+ u32 *array;
+ u16 *size;
+};
+
+static void iter_misc_syslog_prepare_message(void *message, u32 desc_index,
+ const void *priv)
+{
+ struct scmi_imx_misc_syslog_in *msg = message;
+
+ msg->flags = cpu_to_le32(0);
+ msg->index = cpu_to_le32(desc_index);
+}
+
+static int iter_misc_syslog_update_state(struct scmi_iterator_state *st,
+ const void *response, void *priv)
+{
+ const struct scmi_imx_misc_syslog_out *r = response;
+ struct scmi_imx_misc_syslog_ipriv *p = priv;
+
+ st->num_returned = RETURNED(r->numlogflags);
+ st->num_remaining = REMAINING(r->numlogflags);
+ *p->size = st->num_returned + st->num_remaining;
+
+ return 0;
+}
+
+static int
+iter_misc_syslog_process_response(const struct scmi_protocol_handle *ph,
+ const void *response,
+ struct scmi_iterator_state *st, void *priv)
+{
+ const struct scmi_imx_misc_syslog_out *r = response;
+ struct scmi_imx_misc_syslog_ipriv *p = priv;
+
+ p->array[st->desc_index + st->loop_idx] =
+ le32_to_cpu(r->syslog[st->loop_idx]);
+
+ return 0;
+}
+
+static int scmi_imx_misc_syslog_get(const struct scmi_protocol_handle *ph, u16 *size,
+ void *array)
+{
+ struct scmi_iterator_ops ops = {
+ .prepare_message = iter_misc_syslog_prepare_message,
+ .update_state = iter_misc_syslog_update_state,
+ .process_response = iter_misc_syslog_process_response,
+ };
+ struct scmi_imx_misc_syslog_ipriv ipriv = {
+ .array = array,
+ .size = size,
+ };
+ void *iter;
+
+ if (!array || !size || !*size)
+ return -EINVAL;
+
+ iter = ph->hops->iter_response_init(ph, &ops, *size, SCMI_IMX_MISC_SYSLOG_GET,
+ sizeof(struct scmi_imx_misc_syslog_in),
+ &ipriv);
+ if (IS_ERR(iter))
+ return PTR_ERR(iter);
+
+ /* If firmware return NOT SUPPORTED, propagate value to caller */
+ return ph->hops->iter_response_run(iter);
+}
+
static const struct scmi_imx_misc_proto_ops scmi_imx_misc_proto_ops = {
.misc_ctrl_set = scmi_imx_misc_ctrl_set,
.misc_ctrl_get = scmi_imx_misc_ctrl_get,
.misc_ctrl_req_notify = scmi_imx_misc_ctrl_notify,
+ .misc_syslog = scmi_imx_misc_syslog_get,
};
static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph)
{
struct scmi_imx_misc_info *minfo;
- u32 version;
int ret;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_info(ph->dev, "NXP SM MISC Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
minfo = devm_kzalloc(ph->dev, sizeof(*minfo), GFP_KERNEL);
if (!minfo)
@@ -410,7 +487,7 @@ static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph)
if (ret && ret != -EOPNOTSUPP)
return ret;
- return ph->set_priv(ph, minfo, version);
+ return ph->set_priv(ph, minfo);
}
static const struct scmi_protocol scmi_imx_misc = {
diff --git a/drivers/firmware/arm_scmi/voltage.c b/drivers/firmware/arm_scmi/voltage.c
index 17127880e10a..b9391c1ee8a0 100644
--- a/drivers/firmware/arm_scmi/voltage.c
+++ b/drivers/firmware/arm_scmi/voltage.c
@@ -66,7 +66,6 @@ struct scmi_resp_voltage_level_set_complete {
};
struct voltage_info {
- unsigned int version;
unsigned int num_domains;
struct scmi_voltage_info *domains;
};
@@ -243,7 +242,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
* If supported overwrite short name with the extended one;
* on error just carry on and use already provided short name.
*/
- if (PROTOCOL_REV_MAJOR(vinfo->version) >= 0x2) {
+ if (PROTOCOL_REV_MAJOR(ph->version) >= 0x2) {
if (SUPPORTS_EXTENDED_NAMES(attributes))
ph->hops->extended_name_get(ph,
VOLTAGE_DOMAIN_NAME_GET,
@@ -405,20 +404,14 @@ static const struct scmi_voltage_proto_ops voltage_proto_ops = {
static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
{
int ret;
- u32 version;
struct voltage_info *vinfo;
- ret = ph->xops->version_get(ph, &version);
- if (ret)
- return ret;
-
dev_dbg(ph->dev, "Voltage Version %d.%d\n",
- PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+ PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
vinfo = devm_kzalloc(ph->dev, sizeof(*vinfo), GFP_KERNEL);
if (!vinfo)
return -ENOMEM;
- vinfo->version = version;
ret = scmi_protocol_attributes_get(ph, vinfo);
if (ret)
@@ -437,7 +430,7 @@ static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
dev_warn(ph->dev, "No Voltage domains found.\n");
}
- return ph->set_priv(ph, vinfo, version);
+ return ph->set_priv(ph, vinfo);
}
static const struct scmi_protocol scmi_voltage = {
diff --git a/drivers/firmware/broadcom/tee_bnxt_fw.c b/drivers/firmware/broadcom/tee_bnxt_fw.c
index 40e3183a3d11..a706c84eb2b6 100644
--- a/drivers/firmware/broadcom/tee_bnxt_fw.c
+++ b/drivers/firmware/broadcom/tee_bnxt_fw.c
@@ -181,9 +181,9 @@ static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
return (ver->impl_id == TEE_IMPL_ID_OPTEE);
}
-static int tee_bnxt_fw_probe(struct device *dev)
+static int tee_bnxt_fw_probe(struct tee_client_device *bnxt_device)
{
- struct tee_client_device *bnxt_device = to_tee_client_device(dev);
+ struct device *dev = &bnxt_device->dev;
int ret, err = -ENODEV;
struct tee_ioctl_open_session_arg sess_arg;
struct tee_shm *fw_shm_pool;
@@ -231,17 +231,15 @@ out_ctx:
return err;
}
-static int tee_bnxt_fw_remove(struct device *dev)
+static void tee_bnxt_fw_remove(struct tee_client_device *bnxt_device)
{
tee_shm_free(pvt_data.fw_shm_pool);
tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
tee_client_close_context(pvt_data.ctx);
pvt_data.ctx = NULL;
-
- return 0;
}
-static void tee_bnxt_fw_shutdown(struct device *dev)
+static void tee_bnxt_fw_shutdown(struct tee_client_device *bnxt_device)
{
tee_shm_free(pvt_data.fw_shm_pool);
tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
@@ -258,28 +256,16 @@ static const struct tee_client_device_id tee_bnxt_fw_id_table[] = {
MODULE_DEVICE_TABLE(tee, tee_bnxt_fw_id_table);
static struct tee_client_driver tee_bnxt_fw_driver = {
+ .probe = tee_bnxt_fw_probe,
+ .remove = tee_bnxt_fw_remove,
+ .shutdown = tee_bnxt_fw_shutdown,
.id_table = tee_bnxt_fw_id_table,
.driver = {
.name = KBUILD_MODNAME,
- .bus = &tee_bus_type,
- .probe = tee_bnxt_fw_probe,
- .remove = tee_bnxt_fw_remove,
- .shutdown = tee_bnxt_fw_shutdown,
},
};
-static int __init tee_bnxt_fw_mod_init(void)
-{
- return driver_register(&tee_bnxt_fw_driver.driver);
-}
-
-static void __exit tee_bnxt_fw_mod_exit(void)
-{
- driver_unregister(&tee_bnxt_fw_driver.driver);
-}
-
-module_init(tee_bnxt_fw_mod_init);
-module_exit(tee_bnxt_fw_mod_exit);
+module_tee_client_driver(tee_bnxt_fw_driver);
MODULE_AUTHOR("Vikas Gupta <vikas.gupta@broadcom.com>");
MODULE_DESCRIPTION("Broadcom bnxt firmware manager");
diff --git a/drivers/firmware/efi/stmm/tee_stmm_efi.c b/drivers/firmware/efi/stmm/tee_stmm_efi.c
index 65c0fe1ba275..7b04dd649629 100644
--- a/drivers/firmware/efi/stmm/tee_stmm_efi.c
+++ b/drivers/firmware/efi/stmm/tee_stmm_efi.c
@@ -520,8 +520,9 @@ static void tee_stmm_restore_efivars_generic_ops(void)
efivars_generic_ops_register();
}
-static int tee_stmm_efi_probe(struct device *dev)
+static int tee_stmm_efi_probe(struct tee_client_device *tee_dev)
{
+ struct device *dev = &tee_dev->dev;
struct tee_ioctl_open_session_arg sess_arg;
efi_status_t ret;
int rc;
@@ -571,37 +572,23 @@ static int tee_stmm_efi_probe(struct device *dev)
return 0;
}
-static int tee_stmm_efi_remove(struct device *dev)
+static void tee_stmm_efi_remove(struct tee_client_device *dev)
{
tee_stmm_restore_efivars_generic_ops();
-
- return 0;
}
MODULE_DEVICE_TABLE(tee, tee_stmm_efi_id_table);
static struct tee_client_driver tee_stmm_efi_driver = {
.id_table = tee_stmm_efi_id_table,
+ .probe = tee_stmm_efi_probe,
+ .remove = tee_stmm_efi_remove,
.driver = {
.name = "tee-stmm-efi",
- .bus = &tee_bus_type,
- .probe = tee_stmm_efi_probe,
- .remove = tee_stmm_efi_remove,
},
};
-static int __init tee_stmm_efi_mod_init(void)
-{
- return driver_register(&tee_stmm_efi_driver.driver);
-}
-
-static void __exit tee_stmm_efi_mod_exit(void)
-{
- driver_unregister(&tee_stmm_efi_driver.driver);
-}
-
-module_init(tee_stmm_efi_mod_init);
-module_exit(tee_stmm_efi_mod_exit);
+module_tee_client_driver(tee_stmm_efi_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ilias Apalodimas <ilias.apalodimas@linaro.org>");
diff --git a/drivers/firmware/imx/sm-misc.c b/drivers/firmware/imx/sm-misc.c
index fc3ee12c2be8..0a8ada329c9d 100644
--- a/drivers/firmware/imx/sm-misc.c
+++ b/drivers/firmware/imx/sm-misc.c
@@ -3,12 +3,16 @@
* Copyright 2024 NXP
*/
+#include <linux/debugfs.h>
+#include <linux/device/devres.h>
#include <linux/firmware/imx/sm.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/scmi_protocol.h>
#include <linux/scmi_imx_protocol.h>
+#include <linux/seq_file.h>
+#include <linux/sizes.h>
static const struct scmi_imx_misc_proto_ops *imx_misc_ctrl_ops;
static struct scmi_protocol_handle *ph;
@@ -44,10 +48,38 @@ static int scmi_imx_misc_ctrl_notifier(struct notifier_block *nb,
return 0;
}
+static int syslog_show(struct seq_file *file, void *priv)
+{
+ /* 4KB is large enough for syslog */
+ void *syslog __free(kfree) = kmalloc(SZ_4K, GFP_KERNEL);
+ /* syslog API use num words, not num bytes */
+ u16 size = SZ_4K / 4;
+ int ret;
+
+ if (!ph)
+ return -ENODEV;
+
+ ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog);
+ if (ret)
+ return ret;
+
+ seq_hex_dump(file, " ", DUMP_PREFIX_NONE, 16, sizeof(u32), syslog, size * 4, false);
+ seq_putc(file, '\n');
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(syslog);
+
+static void scmi_imx_misc_put(void *p)
+{
+ debugfs_remove((struct dentry *)p);
+}
+
static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev)
{
const struct scmi_handle *handle = sdev->handle;
struct device_node *np = sdev->dev.of_node;
+ struct dentry *scmi_imx_dentry;
u32 src_id, flags;
int ret, i, num;
@@ -98,7 +130,10 @@ static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev)
}
}
- return 0;
+ scmi_imx_dentry = debugfs_create_dir("scmi_imx", NULL);
+ debugfs_create_file("syslog", 0444, scmi_imx_dentry, &sdev->dev, &syslog_fops);
+
+ return devm_add_action_or_reset(&sdev->dev, scmi_imx_misc_put, scmi_imx_dentry);
}
static const struct scmi_device_id scmi_id_table[] = {
diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c
index 1a6f85e463e0..8e3c2ac40341 100644
--- a/drivers/firmware/qcom/qcom_scm.c
+++ b/drivers/firmware/qcom/qcom_scm.c
@@ -27,21 +27,29 @@
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
+#include <linux/remoteproc.h>
#include <linux/sizes.h>
#include <linux/types.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
#include "qcom_scm.h"
#include "qcom_tzmem.h"
static u32 download_mode;
+#define GIC_SPI_BASE 32
+#define GIC_MAX_SPI 1019 // SPIs in GICv3 spec range from 32..1019
+#define GIC_ESPI_BASE 4096
+#define GIC_MAX_ESPI 5119 // ESPIs in GICv3 spec range from 4096..5119
+
struct qcom_scm {
struct device *dev;
struct clk *core_clk;
struct clk *iface_clk;
struct clk *bus_clk;
struct icc_path *path;
- struct completion waitq_comp;
+ struct completion *waitq_comps;
struct reset_controller_dev reset;
/* control access to the interconnect path */
@@ -51,6 +59,7 @@ struct qcom_scm {
u64 dload_mode_addr;
struct qcom_tzmem_pool *mempool;
+ unsigned int wq_cnt;
};
struct qcom_scm_current_perm_info {
@@ -111,6 +120,8 @@ enum qcom_scm_qseecom_tz_cmd_info {
QSEECOM_TZ_CMD_INFO_VERSION = 3,
};
+#define RSCTABLE_BUFFER_NOT_SUFFICIENT 20
+
#define QSEECOM_MAX_APP_NAME_SIZE 64
#define SHMBRIDGE_RESULT_NOTSUPP 4
@@ -130,6 +141,8 @@ static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
#define QCOM_DLOAD_MINIDUMP 2
#define QCOM_DLOAD_BOTHDUMP 3
+#define QCOM_SCM_DEFAULT_WAITQ_COUNT 1
+
static const char * const qcom_scm_convention_names[] = {
[SMC_CONVENTION_UNKNOWN] = "unknown",
[SMC_CONVENTION_ARM_32] = "smc arm 32",
@@ -559,15 +572,104 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
}
/**
+ * devm_qcom_scm_pas_context_alloc() - Allocate peripheral authentication service
+ * context for a given peripheral
+ *
+ * PAS context is device-resource managed, so the caller does not need
+ * to worry about freeing the context memory.
+ *
+ * @dev: PAS firmware device
+ * @pas_id: peripheral authentication service id
+ * @mem_phys: Subsystem reserve memory start address
+ * @mem_size: Subsystem reserve memory size
+ *
+ * Returns: The new PAS context, or ERR_PTR() on failure.
+ */
+struct qcom_scm_pas_context *devm_qcom_scm_pas_context_alloc(struct device *dev,
+ u32 pas_id,
+ phys_addr_t mem_phys,
+ size_t mem_size)
+{
+ struct qcom_scm_pas_context *ctx;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ctx->dev = dev;
+ ctx->pas_id = pas_id;
+ ctx->mem_phys = mem_phys;
+ ctx->mem_size = mem_size;
+
+ return ctx;
+}
+EXPORT_SYMBOL_GPL(devm_qcom_scm_pas_context_alloc);
+
+static int __qcom_scm_pas_init_image(u32 pas_id, dma_addr_t mdata_phys,
+ struct qcom_scm_res *res)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
+ .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW),
+ .args[0] = pas_id,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ int ret;
+
+ ret = qcom_scm_clk_enable();
+ if (ret)
+ return ret;
+
+ ret = qcom_scm_bw_enable();
+ if (ret)
+ goto disable_clk;
+
+ desc.args[1] = mdata_phys;
+
+ ret = qcom_scm_call(__scm->dev, &desc, res);
+ qcom_scm_bw_disable();
+
+disable_clk:
+ qcom_scm_clk_disable();
+
+ return ret;
+}
+
+static int qcom_scm_pas_prep_and_init_image(struct qcom_scm_pas_context *ctx,
+ const void *metadata, size_t size)
+{
+ struct qcom_scm_res res;
+ phys_addr_t mdata_phys;
+ void *mdata_buf;
+ int ret;
+
+ mdata_buf = qcom_tzmem_alloc(__scm->mempool, size, GFP_KERNEL);
+ if (!mdata_buf)
+ return -ENOMEM;
+
+ memcpy(mdata_buf, metadata, size);
+ mdata_phys = qcom_tzmem_to_phys(mdata_buf);
+
+ ret = __qcom_scm_pas_init_image(ctx->pas_id, mdata_phys, &res);
+ if (ret < 0)
+ qcom_tzmem_free(mdata_buf);
+ else
+ ctx->ptr = mdata_buf;
+
+ return ret ? : res.result[0];
+}
+
+/**
* qcom_scm_pas_init_image() - Initialize peripheral authentication service
* state machine for a given peripheral, using the
* metadata
- * @peripheral: peripheral id
+ * @pas_id: peripheral authentication service id
* @metadata: pointer to memory containing ELF header, program header table
* and optional blob of data used for authenticating the metadata
* and the rest of the firmware
* @size: size of the metadata
- * @ctx: optional metadata context
+ * @ctx: optional pas context
*
* Return: 0 on success.
*
@@ -575,20 +677,16 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
* track the metadata allocation, this needs to be released by invoking
* qcom_scm_pas_metadata_release() by the caller.
*/
-int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
- struct qcom_scm_pas_metadata *ctx)
+int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
+ struct qcom_scm_pas_context *ctx)
{
+ struct qcom_scm_res res;
dma_addr_t mdata_phys;
void *mdata_buf;
int ret;
- struct qcom_scm_desc desc = {
- .svc = QCOM_SCM_SVC_PIL,
- .cmd = QCOM_SCM_PIL_PAS_INIT_IMAGE,
- .arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_VAL, QCOM_SCM_RW),
- .args[0] = peripheral,
- .owner = ARM_SMCCC_OWNER_SIP,
- };
- struct qcom_scm_res res;
+
+ if (ctx && ctx->use_tzmem)
+ return qcom_scm_pas_prep_and_init_image(ctx, metadata, size);
/*
* During the scm call memory protection will be enabled for the meta
@@ -609,23 +707,7 @@ int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
memcpy(mdata_buf, metadata, size);
- ret = qcom_scm_clk_enable();
- if (ret)
- goto out;
-
- ret = qcom_scm_bw_enable();
- if (ret)
- goto disable_clk;
-
- desc.args[1] = mdata_phys;
-
- ret = qcom_scm_call(__scm->dev, &desc, &res);
- qcom_scm_bw_disable();
-
-disable_clk:
- qcom_scm_clk_disable();
-
-out:
+ ret = __qcom_scm_pas_init_image(pas_id, mdata_phys, &res);
if (ret < 0 || !ctx) {
dma_free_coherent(__scm->dev, size, mdata_buf, mdata_phys);
} else if (ctx) {
@@ -640,38 +722,39 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image);
/**
* qcom_scm_pas_metadata_release() - release metadata context
- * @ctx: metadata context
+ * @ctx: pas context
*/
-void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx)
+void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
{
if (!ctx->ptr)
return;
- dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys);
+ if (ctx->use_tzmem)
+ qcom_tzmem_free(ctx->ptr);
+ else
+ dma_free_coherent(__scm->dev, ctx->size, ctx->ptr, ctx->phys);
ctx->ptr = NULL;
- ctx->phys = 0;
- ctx->size = 0;
}
EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release);
/**
* qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral
* for firmware loading
- * @peripheral: peripheral id
+ * @pas_id: peripheral authentication service id
* @addr: start address of memory area to prepare
* @size: size of the memory area to prepare
*
* Returns 0 on success.
*/
-int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size)
+int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
{
int ret;
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_PIL,
.cmd = QCOM_SCM_PIL_PAS_MEM_SETUP,
.arginfo = QCOM_SCM_ARGS(3),
- .args[0] = peripheral,
+ .args[0] = pas_id,
.args[1] = addr,
.args[2] = size,
.owner = ARM_SMCCC_OWNER_SIP,
@@ -696,21 +779,189 @@ disable_clk:
}
EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup);
+static void *__qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt_tzm,
+ size_t input_rt_size,
+ size_t *output_rt_size)
+{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_PIL,
+ .cmd = QCOM_SCM_PIL_PAS_GET_RSCTABLE,
+ .arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, QCOM_SCM_RO, QCOM_SCM_VAL,
+ QCOM_SCM_RW, QCOM_SCM_VAL),
+ .args[0] = pas_id,
+ .owner = ARM_SMCCC_OWNER_SIP,
+ };
+ struct qcom_scm_res res;
+ void *output_rt_tzm;
+ int ret;
+
+ output_rt_tzm = qcom_tzmem_alloc(__scm->mempool, *output_rt_size, GFP_KERNEL);
+ if (!output_rt_tzm)
+ return ERR_PTR(-ENOMEM);
+
+ desc.args[1] = qcom_tzmem_to_phys(input_rt_tzm);
+ desc.args[2] = input_rt_size;
+ desc.args[3] = qcom_tzmem_to_phys(output_rt_tzm);
+ desc.args[4] = *output_rt_size;
+
+ /*
+ * Whether SMC fail or pass, res.result[2] will hold actual resource table
+ * size.
+ *
+ * If passed 'output_rt_size' buffer size is not sufficient to hold the
+ * resource table TrustZone sends, response code in res.result[1] as
+ * RSCTABLE_BUFFER_NOT_SUFFICIENT so that caller can retry this SMC call
+ * with output_rt_tzm buffer with res.result[2] size however, It should not
+ * be of unresonable size.
+ */
+ ret = qcom_scm_call(__scm->dev, &desc, &res);
+ if (!ret && res.result[2] > SZ_1G) {
+ ret = -E2BIG;
+ goto free_output_rt;
+ }
+
+ *output_rt_size = res.result[2];
+ if (ret && res.result[1] == RSCTABLE_BUFFER_NOT_SUFFICIENT)
+ ret = -EOVERFLOW;
+
+free_output_rt:
+ if (ret)
+ qcom_tzmem_free(output_rt_tzm);
+
+ return ret ? ERR_PTR(ret) : output_rt_tzm;
+}
+
+/**
+ * qcom_scm_pas_get_rsc_table() - Retrieve the resource table in passed output buffer
+ * for a given peripheral.
+ *
+ * Qualcomm remote processor may rely on both static and dynamic resources for
+ * its functionality. Static resources typically refer to memory-mapped addresses
+ * required by the subsystem and are often embedded within the firmware binary
+ * and dynamic resources, such as shared memory in DDR etc., are determined at
+ * runtime during the boot process.
+ *
+ * On Qualcomm Technologies devices, it's possible that static resources are not
+ * embedded in the firmware binary and instead are provided by TrustZone However,
+ * dynamic resources are always expected to come from TrustZone. This indicates
+ * that for Qualcomm devices, all resources (static and dynamic) will be provided
+ * by TrustZone via the SMC call.
+ *
+ * If the remote processor firmware binary does contain static resources, they
+ * should be passed in input_rt. These will be forwarded to TrustZone for
+ * authentication. TrustZone will then append the dynamic resources and return
+ * the complete resource table in output_rt_tzm.
+ *
+ * If the remote processor firmware binary does not include a resource table,
+ * the caller of this function should set input_rt as NULL and input_rt_size
+ * as zero respectively.
+ *
+ * More about documentation on resource table data structures can be found in
+ * include/linux/remoteproc.h
+ *
+ * @ctx: PAS context
+ * @pas_id: peripheral authentication service id
+ * @input_rt: resource table buffer which is present in firmware binary
+ * @input_rt_size: size of the resource table present in firmware binary
+ * @output_rt_size: TrustZone expects caller should pass worst case size for
+ * the output_rt_tzm.
+ *
+ * Return:
+ * On success, returns a pointer to the allocated buffer containing the final
+ * resource table and output_rt_size will have actual resource table size from
+ * TrustZone. The caller is responsible for freeing the buffer. On failure,
+ * returns ERR_PTR(-errno).
+ */
+struct resource_table *qcom_scm_pas_get_rsc_table(struct qcom_scm_pas_context *ctx,
+ void *input_rt,
+ size_t input_rt_size,
+ size_t *output_rt_size)
+{
+ struct resource_table empty_rsc = {};
+ size_t size = SZ_16K;
+ void *output_rt_tzm;
+ void *input_rt_tzm;
+ void *tbl_ptr;
+ int ret;
+
+ ret = qcom_scm_clk_enable();
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = qcom_scm_bw_enable();
+ if (ret)
+ goto disable_clk;
+
+ /*
+ * TrustZone can not accept buffer as NULL value as argument hence,
+ * we need to pass a input buffer indicating that subsystem firmware
+ * does not have resource table by filling resource table structure.
+ */
+ if (!input_rt) {
+ input_rt = &empty_rsc;
+ input_rt_size = sizeof(empty_rsc);
+ }
+
+ input_rt_tzm = qcom_tzmem_alloc(__scm->mempool, input_rt_size, GFP_KERNEL);
+ if (!input_rt_tzm) {
+ ret = -ENOMEM;
+ goto disable_scm_bw;
+ }
+
+ memcpy(input_rt_tzm, input_rt, input_rt_size);
+
+ output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id, input_rt_tzm,
+ input_rt_size, &size);
+ if (PTR_ERR(output_rt_tzm) == -EOVERFLOW)
+ /* Try again with the size requested by the TZ */
+ output_rt_tzm = __qcom_scm_pas_get_rsc_table(ctx->pas_id,
+ input_rt_tzm,
+ input_rt_size,
+ &size);
+ if (IS_ERR(output_rt_tzm)) {
+ ret = PTR_ERR(output_rt_tzm);
+ goto free_input_rt;
+ }
+
+ tbl_ptr = kzalloc(size, GFP_KERNEL);
+ if (!tbl_ptr) {
+ qcom_tzmem_free(output_rt_tzm);
+ ret = -ENOMEM;
+ goto free_input_rt;
+ }
+
+ memcpy(tbl_ptr, output_rt_tzm, size);
+ *output_rt_size = size;
+ qcom_tzmem_free(output_rt_tzm);
+
+free_input_rt:
+ qcom_tzmem_free(input_rt_tzm);
+
+disable_scm_bw:
+ qcom_scm_bw_disable();
+
+disable_clk:
+ qcom_scm_clk_disable();
+
+ return ret ? ERR_PTR(ret) : tbl_ptr;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_get_rsc_table);
+
/**
* qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware
* and reset the remote processor
- * @peripheral: peripheral id
+ * @pas_id: peripheral authentication service id
*
* Return 0 on success.
*/
-int qcom_scm_pas_auth_and_reset(u32 peripheral)
+int qcom_scm_pas_auth_and_reset(u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_PIL,
.cmd = QCOM_SCM_PIL_PAS_AUTH_AND_RESET,
.arginfo = QCOM_SCM_ARGS(1),
- .args[0] = peripheral,
+ .args[0] = pas_id,
.owner = ARM_SMCCC_OWNER_SIP,
};
struct qcom_scm_res res;
@@ -734,19 +985,66 @@ disable_clk:
EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset);
/**
+ * qcom_scm_pas_prepare_and_auth_reset() - Prepare, authenticate, and reset the
+ * remote processor
+ *
+ * @ctx: Context saved during call to qcom_scm_pas_context_init()
+ *
+ * This function performs the necessary steps to prepare a PAS subsystem,
+ * authenticate it using the provided metadata, and initiate a reset sequence.
+ *
+ * It should be used when Linux is in control setting up the IOMMU hardware
+ * for remote subsystem during secure firmware loading processes. The preparation
+ * step sets up a shmbridge over the firmware memory before TrustZone accesses the
+ * firmware memory region for authentication. The authentication step verifies
+ * the integrity and authenticity of the firmware or configuration using secure
+ * metadata. Finally, the reset step ensures the subsystem starts in a clean and
+ * sane state.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
+{
+ u64 handle;
+ int ret;
+
+ /*
+ * When Linux running @ EL1, Gunyah hypervisor running @ EL2 traps the
+ * auth_and_reset call and create an shmbridge on the remote subsystem
+ * memory region and then invokes a call to TrustZone to authenticate.
+ */
+ if (!ctx->use_tzmem)
+ return qcom_scm_pas_auth_and_reset(ctx->pas_id);
+
+ /*
+ * When Linux runs @ EL2 Linux must create the shmbridge itself and then
+ * subsequently call TrustZone for authenticate and reset.
+ */
+ ret = qcom_tzmem_shm_bridge_create(ctx->mem_phys, ctx->mem_size, &handle);
+ if (ret)
+ return ret;
+
+ ret = qcom_scm_pas_auth_and_reset(ctx->pas_id);
+ qcom_tzmem_shm_bridge_delete(handle);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_scm_pas_prepare_and_auth_reset);
+
+/**
* qcom_scm_pas_shutdown() - Shut down the remote processor
- * @peripheral: peripheral id
+ * @pas_id: peripheral authentication service id
*
* Returns 0 on success.
*/
-int qcom_scm_pas_shutdown(u32 peripheral)
+int qcom_scm_pas_shutdown(u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_PIL,
.cmd = QCOM_SCM_PIL_PAS_SHUTDOWN,
.arginfo = QCOM_SCM_ARGS(1),
- .args[0] = peripheral,
+ .args[0] = pas_id,
.owner = ARM_SMCCC_OWNER_SIP,
};
struct qcom_scm_res res;
@@ -772,18 +1070,18 @@ EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown);
/**
* qcom_scm_pas_supported() - Check if the peripheral authentication service is
* available for the given peripherial
- * @peripheral: peripheral id
+ * @pas_id: peripheral authentication service id
*
* Returns true if PAS is supported for this peripheral, otherwise false.
*/
-bool qcom_scm_pas_supported(u32 peripheral)
+bool qcom_scm_pas_supported(u32 pas_id)
{
int ret;
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_PIL,
.cmd = QCOM_SCM_PIL_PAS_IS_SUPPORTED,
.arginfo = QCOM_SCM_ARGS(1),
- .args[0] = peripheral,
+ .args[0] = pas_id,
.owner = ARM_SMCCC_OWNER_SIP,
};
struct qcom_scm_res res;
@@ -2007,6 +2305,7 @@ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = {
{ .compatible = "lenovo,yoga-slim7x" },
{ .compatible = "microsoft,arcata", },
{ .compatible = "microsoft,blackrock" },
+ { .compatible = "microsoft,denali", },
{ .compatible = "microsoft,romulus13", },
{ .compatible = "microsoft,romulus15", },
{ .compatible = "qcom,hamoa-iot-evk" },
@@ -2208,42 +2507,107 @@ bool qcom_scm_is_available(void)
}
EXPORT_SYMBOL_GPL(qcom_scm_is_available);
-static int qcom_scm_assert_valid_wq_ctx(u32 wq_ctx)
+static int qcom_scm_fill_irq_fwspec_params(struct irq_fwspec *fwspec, u32 hwirq)
{
- /* FW currently only supports a single wq_ctx (zero).
- * TODO: Update this logic to include dynamic allocation and lookup of
- * completion structs when FW supports more wq_ctx values.
- */
- if (wq_ctx != 0) {
- dev_err(__scm->dev, "Firmware unexpectedly passed non-zero wq_ctx\n");
- return -EINVAL;
+ if (hwirq >= GIC_SPI_BASE && hwirq <= GIC_MAX_SPI) {
+ fwspec->param[0] = GIC_SPI;
+ fwspec->param[1] = hwirq - GIC_SPI_BASE;
+ } else if (hwirq >= GIC_ESPI_BASE && hwirq <= GIC_MAX_ESPI) {
+ fwspec->param[0] = GIC_ESPI;
+ fwspec->param[1] = hwirq - GIC_ESPI_BASE;
+ } else {
+ WARN(1, "Unexpected hwirq: %d\n", hwirq);
+ return -ENXIO;
}
+ fwspec->param[2] = IRQ_TYPE_EDGE_RISING;
+ fwspec->param_count = 3;
+
return 0;
}
-int qcom_scm_wait_for_wq_completion(u32 wq_ctx)
+static int qcom_scm_query_waitq_count(struct qcom_scm *scm)
{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_WAITQ,
+ .cmd = QCOM_SCM_WAITQ_GET_INFO,
+ .owner = ARM_SMCCC_OWNER_SIP
+ };
+ struct qcom_scm_res res;
int ret;
- ret = qcom_scm_assert_valid_wq_ctx(wq_ctx);
+ ret = qcom_scm_call_atomic(scm->dev, &desc, &res);
if (ret)
return ret;
- wait_for_completion(&__scm->waitq_comp);
-
- return 0;
+ return res.result[0] & GENMASK(7, 0);
}
-static int qcom_scm_waitq_wakeup(unsigned int wq_ctx)
+static int qcom_scm_get_waitq_irq(struct qcom_scm *scm)
{
+ struct qcom_scm_desc desc = {
+ .svc = QCOM_SCM_SVC_WAITQ,
+ .cmd = QCOM_SCM_WAITQ_GET_INFO,
+ .owner = ARM_SMCCC_OWNER_SIP
+ };
+ struct device_node *parent_irq_node;
+ struct irq_fwspec fwspec;
+ struct qcom_scm_res res;
+ u32 hwirq;
int ret;
- ret = qcom_scm_assert_valid_wq_ctx(wq_ctx);
+ ret = qcom_scm_call_atomic(scm->dev, &desc, &res);
+ if (ret)
+ return ret;
+
+ hwirq = res.result[1] & GENMASK(15, 0);
+ ret = qcom_scm_fill_irq_fwspec_params(&fwspec, hwirq);
if (ret)
return ret;
- complete(&__scm->waitq_comp);
+ parent_irq_node = of_irq_find_parent(scm->dev->of_node);
+ if (!parent_irq_node)
+ return -ENODEV;
+
+ fwspec.fwnode = of_fwnode_handle(parent_irq_node);
+
+ return irq_create_fwspec_mapping(&fwspec);
+}
+
+static struct completion *qcom_scm_get_completion(u32 wq_ctx)
+{
+ struct completion *wq;
+
+ if (WARN_ON_ONCE(wq_ctx >= __scm->wq_cnt))
+ return ERR_PTR(-EINVAL);
+
+ wq = &__scm->waitq_comps[wq_ctx];
+
+ return wq;
+}
+
+int qcom_scm_wait_for_wq_completion(u32 wq_ctx)
+{
+ struct completion *wq;
+
+ wq = qcom_scm_get_completion(wq_ctx);
+ if (IS_ERR(wq))
+ return PTR_ERR(wq);
+
+ wait_for_completion_state(wq, TASK_IDLE);
+
+ return 0;
+}
+
+static int qcom_scm_waitq_wakeup(unsigned int wq_ctx)
+{
+ struct completion *wq;
+
+ wq = qcom_scm_get_completion(wq_ctx);
+ if (IS_ERR(wq))
+ return PTR_ERR(wq);
+
+ complete(wq);
return 0;
}
@@ -2319,6 +2683,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
struct qcom_tzmem_pool_config pool_config;
struct qcom_scm *scm;
int irq, ret;
+ int i;
scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL);
if (!scm)
@@ -2329,7 +2694,6 @@ static int qcom_scm_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
- init_completion(&scm->waitq_comp);
mutex_init(&scm->scm_bw_lock);
scm->path = devm_of_icc_get(&pdev->dev, NULL);
@@ -2381,7 +2745,20 @@ static int qcom_scm_probe(struct platform_device *pdev)
return dev_err_probe(scm->dev, PTR_ERR(scm->mempool),
"Failed to create the SCM memory pool\n");
- irq = platform_get_irq_optional(pdev, 0);
+ ret = qcom_scm_query_waitq_count(scm);
+ scm->wq_cnt = ret < 0 ? QCOM_SCM_DEFAULT_WAITQ_COUNT : ret;
+ scm->waitq_comps = devm_kcalloc(&pdev->dev, scm->wq_cnt, sizeof(*scm->waitq_comps),
+ GFP_KERNEL);
+ if (!scm->waitq_comps)
+ return -ENOMEM;
+
+ for (i = 0; i < scm->wq_cnt; i++)
+ init_completion(&scm->waitq_comps[i]);
+
+ irq = qcom_scm_get_waitq_irq(scm);
+ if (irq < 0)
+ irq = platform_get_irq_optional(pdev, 0);
+
if (irq < 0) {
if (irq != -ENXIO)
return irq;
diff --git a/drivers/firmware/qcom/qcom_scm.h b/drivers/firmware/qcom/qcom_scm.h
index a56c8212cc0c..caab80a73e17 100644
--- a/drivers/firmware/qcom/qcom_scm.h
+++ b/drivers/firmware/qcom/qcom_scm.h
@@ -105,6 +105,7 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev);
#define QCOM_SCM_PIL_PAS_SHUTDOWN 0x06
#define QCOM_SCM_PIL_PAS_IS_SUPPORTED 0x07
#define QCOM_SCM_PIL_PAS_MSS_RESET 0x0a
+#define QCOM_SCM_PIL_PAS_GET_RSCTABLE 0x21
#define QCOM_SCM_SVC_IO 0x05
#define QCOM_SCM_IO_READ 0x01
@@ -152,6 +153,7 @@ int qcom_scm_shm_bridge_enable(struct device *scm_dev);
#define QCOM_SCM_SVC_WAITQ 0x24
#define QCOM_SCM_WAITQ_RESUME 0x02
#define QCOM_SCM_WAITQ_GET_WQ_CTX 0x03
+#define QCOM_SCM_WAITQ_GET_INFO 0x04
#define QCOM_SCM_SVC_GPU 0x28
#define QCOM_SCM_SVC_GPU_INIT_REGS 0x01
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
index 91f234550c43..4616127e33ff 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -580,13 +580,13 @@ struct ti_sci_msg_resp_get_clock_freq {
} __packed;
/**
- * struct tisci_msg_req_prepare_sleep - Request for TISCI_MSG_PREPARE_SLEEP.
+ * struct ti_sci_msg_req_prepare_sleep - Request for TISCI_MSG_PREPARE_SLEEP.
*
- * @hdr TISCI header to provide ACK/NAK flags to the host.
- * @mode Low power mode to enter.
- * @ctx_lo Low 32-bits of physical pointer to address to use for context save.
- * @ctx_hi High 32-bits of physical pointer to address to use for context save.
- * @debug_flags Flags that can be set to halt the sequence during suspend or
+ * @hdr: TISCI header to provide ACK/NAK flags to the host.
+ * @mode: Low power mode to enter.
+ * @ctx_lo: Low 32-bits of physical pointer to address to use for context save.
+ * @ctx_hi: High 32-bits of physical pointer to address to use for context save.
+ * @debug_flags: Flags that can be set to halt the sequence during suspend or
* resume to allow JTAG connection and debug.
*
* This message is used as the first step of entering a low power mode. It
@@ -610,7 +610,7 @@ struct ti_sci_msg_req_prepare_sleep {
} __packed;
/**
- * struct tisci_msg_set_io_isolation_req - Request for TI_SCI_MSG_SET_IO_ISOLATION.
+ * struct ti_sci_msg_req_set_io_isolation - Request for TI_SCI_MSG_SET_IO_ISOLATION.
*
* @hdr: Generic header
* @state: The deseared state of the IO isolation.
@@ -676,7 +676,7 @@ struct ti_sci_msg_req_lpm_set_device_constraint {
* TISCI_MSG_LPM_SET_LATENCY_CONSTRAINT.
*
* @hdr: TISCI header to provide ACK/NAK flags to the host.
- * @wkup_latency: The maximum acceptable latency to wake up from low power mode
+ * @latency: The maximum acceptable latency to wake up from low power mode
* in milliseconds. The deeper the state, the higher the latency.
* @state: The desired state of wakeup latency constraint: set or clear.
* @rsvd: Reserved for future use.
@@ -855,7 +855,7 @@ struct ti_sci_msg_rm_ring_cfg_req {
* UDMAP transmit channels mapped to source threads will have their
* TCHAN_THRD_ID register programmed with the destination thread if the pairing
* is successful.
-
+ *
* @dst_thread: PSI-L destination thread ID within the PSI-L System thread map.
* PSI-L destination threads start at index 0x8000. The request is NACK'd if
* the destination thread is not greater than or equal to 0x8000.
@@ -1000,7 +1000,8 @@ struct rm_ti_sci_msg_udmap_rx_flow_opt_cfg {
} __packed;
/**
- * Configures a Navigator Subsystem UDMAP transmit channel
+ * struct ti_sci_msg_rm_udmap_tx_ch_cfg_req - Configures a
+ * Navigator Subsystem UDMAP transmit channel
*
* Configures the non-real-time registers of a Navigator Subsystem UDMAP
* transmit channel. The channel index must be assigned to the host defined
@@ -1128,7 +1129,8 @@ struct ti_sci_msg_rm_udmap_tx_ch_cfg_req {
} __packed;
/**
- * Configures a Navigator Subsystem UDMAP receive channel
+ * struct ti_sci_msg_rm_udmap_rx_ch_cfg_req - Configures a
+ * Navigator Subsystem UDMAP receive channel
*
* Configures the non-real-time registers of a Navigator Subsystem UDMAP
* receive channel. The channel index must be assigned to the host defined
@@ -1247,7 +1249,8 @@ struct ti_sci_msg_rm_udmap_rx_ch_cfg_req {
} __packed;
/**
- * Configures a Navigator Subsystem UDMAP receive flow
+ * struct ti_sci_msg_rm_udmap_flow_cfg_req - Configures a
+ * Navigator Subsystem UDMAP receive flow
*
* Configures a Navigator Subsystem UDMAP receive flow's registers.
* Configuration does not include the flow registers which handle size-based
@@ -1258,7 +1261,7 @@ struct ti_sci_msg_rm_udmap_rx_ch_cfg_req {
*
* @hdr: Standard TISCI header
*
- * @valid_params
+ * @valid_params:
* Bitfield defining validity of rx flow configuration parameters. The
* rx flow configuration fields are not valid, and will not be used for flow
* configuration, if their corresponding valid bit is zero. Valid bit usage: