drivers: firmware: arm_scmi: Add qcom vendor protocol

Add Qcom vendor consolidated protocol.
This change adds client and vendor driver for
Qcom SCMI consolidated protocol.

Change-Id: I8100d9487fd5da706004f6090a25a271a482b2fe
Signed-off-by: Shivnandan Kumar <quic_kshivnan@quicinc.com>
This commit is contained in:
Shivnandan Kumar 2022-12-14 13:27:34 +05:30
parent 93288c2477
commit 1db77b7094
7 changed files with 269 additions and 2 deletions

View file

@ -143,7 +143,18 @@ config QTI_SCMI_PMU_PROTOCOL
This protocol provides interface to communicate with micro controller
which maintains the PMU configuration for multiple clients.
This driver defines the comands or message ID's used for this
This driver defines the commands or message ID's used for this
communication and also exposes the ops used by clients.
config QTI_SCMI_VENDOR_PROTOCOL
tristate "Qualcomm Technologies, Inc. Qcom SCMI vendor Protocol"
depends on ARM || ARM64 || COMPILE_TEST
depends on ARM_SCMI_PROTOCOL && QCOM_CPUCP
help
System Control and Management Interface (SCMI) Qcom vendor protocol.
This protocol provides interface to communicate with micro controller.
This driver defines the commands or message ID's used for this
communication and also exposes the ops used by clients.
config QTI_SCMI_C1DCVS_PROTOCOL

View file

@ -16,6 +16,7 @@ obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o
obj-$(CONFIG_QTI_SCMI_PMU_PROTOCOL) += pmu_vendor.o
obj-$(CONFIG_QTI_SCMI_C1DCVS_PROTOCOL) += c1dcvs_vendor.o
obj-$(CONFIG_QTI_SCMI_MEMLAT_PROTOCOL) += memlat_vendor.o
obj-$(CONFIG_QTI_SCMI_VENDOR_PROTOCOL) += qcom_scmi_vendor.o
ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy)
# The use of R7 in the SMCCC conflicts with the compiler's use of R7 as a frame

View file

@ -0,0 +1,148 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include "common.h"
#include <linux/qcom_scmi_vendor.h>
#define EXTENDED_MSG_ID 0
#define SCMI_MAX_TX_RX_SIZE 128
#define PROTOCOL_PAYLOAD_SIZE 16
#define SET_PARAM 0x10
#define GET_PARAM 0x11
#define START_ACTIVITY 0x12
#define STOP_ACTIVITY 0x13
static int qcom_scmi_set_param(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str,
u32 param_id, size_t size)
{
int ret = -EINVAL;
struct scmi_xfer *t;
uint32_t *msg;
if (!ph || !ph->xops)
return ret;
ret = ph->xops->xfer_get_init(ph, SET_PARAM, size + PROTOCOL_PAYLOAD_SIZE,
SCMI_MAX_TX_RX_SIZE, &t);
if (ret)
return ret;
msg = t->tx.buf;
*msg++ = cpu_to_le32(EXTENDED_MSG_ID);
*msg++ = cpu_to_le32(algo_str & GENMASK(31, 0));
*msg++ = cpu_to_le32((algo_str & GENMASK(63, 32)) >> 32);
*msg++ = cpu_to_le32(param_id);
memcpy(msg, buf, size);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int qcom_scmi_get_param(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str,
u32 param_id, size_t tx_size, size_t rx_size)
{
int ret = -EINVAL;
struct scmi_xfer *t;
uint32_t *msg;
if (!ph || !ph->xops || !buf)
return ret;
ret = ph->xops->xfer_get_init(ph, GET_PARAM, tx_size + PROTOCOL_PAYLOAD_SIZE,
SCMI_MAX_TX_RX_SIZE, &t);
if (ret)
return ret;
msg = t->tx.buf;
*msg++ = cpu_to_le32(EXTENDED_MSG_ID);
*msg++ = cpu_to_le32(algo_str & GENMASK(31, 0));
*msg++ = cpu_to_le32((algo_str & GENMASK(63, 32)) >> 32);
*msg++ = cpu_to_le32(param_id);
memcpy(msg, buf, tx_size);
ret = ph->xops->do_xfer(ph, t);
if (t->rx.len > rx_size) {
pr_err("SCMI received buffer size %d is more than expected size %d\n",
t->rx.len, rx_size);
return -EMSGSIZE;
}
memcpy(buf, t->rx.buf, t->rx.len);
ph->xops->xfer_put(ph, t);
return ret;
}
static int qcom_scmi_start_activity(const struct scmi_protocol_handle *ph,
void *buf, u64 algo_str, u32 param_id, size_t size)
{
int ret = -EINVAL;
struct scmi_xfer *t;
uint32_t *msg;
if (!ph || !ph->xops)
return ret;
ret = ph->xops->xfer_get_init(ph, START_ACTIVITY, size + PROTOCOL_PAYLOAD_SIZE,
SCMI_MAX_TX_RX_SIZE, &t);
if (ret)
return ret;
msg = t->tx.buf;
*msg++ = cpu_to_le32(EXTENDED_MSG_ID);
*msg++ = cpu_to_le32(algo_str & GENMASK(31, 0));
*msg++ = cpu_to_le32((algo_str & GENMASK(63, 32)) >> 32);
*msg++ = cpu_to_le32(param_id);
memcpy(msg, buf, size);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int qcom_scmi_stop_activity(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str,
u32 param_id, size_t size)
{
int ret = -EINVAL;
struct scmi_xfer *t;
uint32_t *msg;
if (!ph || !ph->xops)
return ret;
ret = ph->xops->xfer_get_init(ph, STOP_ACTIVITY, size + PROTOCOL_PAYLOAD_SIZE,
SCMI_MAX_TX_RX_SIZE, &t);
if (ret)
return ret;
msg = t->tx.buf;
*msg++ = cpu_to_le32(EXTENDED_MSG_ID);
*msg++ = cpu_to_le32(algo_str & GENMASK(31, 0));
*msg++ = cpu_to_le32((algo_str & GENMASK(63, 32)) >> 32);
*msg++ = cpu_to_le32(param_id);
memcpy(msg, buf, size);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static struct qcom_scmi_vendor_ops qcom_proto_ops = {
.set_param = qcom_scmi_set_param,
.get_param = qcom_scmi_get_param,
.start_activity = qcom_scmi_start_activity,
.stop_activity = qcom_scmi_stop_activity,
};
static int qcom_scmi_vendor_protocol_init(const struct scmi_protocol_handle *ph)
{
u32 version;
ph->xops->version_get(ph, &version);
dev_dbg(ph->dev, "qcom scmi version %d.%d\n",
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
return 0;
}
static const struct scmi_protocol qcom_scmi_vendor = {
.id = QCOM_SCMI_VENDOR_PROTOCOL,
.owner = THIS_MODULE,
.instance_init = &qcom_scmi_vendor_protocol_init,
.ops = &qcom_proto_ops,
};
module_scmi_protocol(qcom_scmi_vendor);
MODULE_DESCRIPTION("qcom scmi vendor Protocol");
MODULE_LICENSE("GPL");

View file

@ -76,7 +76,18 @@ config QTI_PMU_SCMI_CLIENT
This driver delivers the pmu vendor protocol handle to interface
driver, and interface driver will use this handle to communicate with
rimps.
cpucp.
config QTI_QCOM_SCMI_CLIENT
tristate "Qualcomm Technologies Inc. SCMI client driver"
depends on QTI_SCMI_VENDOR_PROTOCOL
default n
help
SCMI client driver registers for Qcom vendor protocol.
This driver delivers the qcom vendor protocol handle to interface
driver, and interface driver will use this handle to communicate with
cpucp.
config QTI_C1DCVS_SCMI_CLIENT
tristate "Qualcomm Technologies Inc. SCMI client driver for cpudcvs"

View file

@ -9,3 +9,4 @@ obj-$(CONFIG_QCOM_BWMON) += bwmon.o
obj-$(CONFIG_QTI_PMU_SCMI_CLIENT) += pmu_scmi.o
obj-$(CONFIG_QTI_C1DCVS_SCMI_CLIENT) += c1dcvs_scmi.o
obj-$(CONFIG_QTI_HW_MEMLAT_SCMI_CLIENT) += memlat_scmi.o
obj-$(CONFIG_QTI_QCOM_SCMI_CLIENT) += qcom_scmi_client.o

View file

@ -0,0 +1,57 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/scmi_protocol.h>
#include <linux/qcom_scmi_vendor.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
struct scmi_device *scmi_dev;
static int scmi_client_inited;
struct scmi_device *get_qcom_scmi_device(void)
{
if (!scmi_client_inited)
return ERR_PTR(-EPROBE_DEFER);
if (!scmi_dev || !scmi_dev->handle)
return ERR_PTR(-ENODEV);
return scmi_dev;
}
EXPORT_SYMBOL(get_qcom_scmi_device);
static int scmi_client_probe(struct scmi_device *sdev)
{
int ret = 0;
scmi_dev = sdev;
if (!sdev)
ret = -ENODEV;
scmi_client_inited = 1;
return ret;
}
static const struct scmi_device_id scmi_id_table[] = {
{ .protocol_id = QCOM_SCMI_VENDOR_PROTOCOL, .name = "qcom_scmi_vendor_protocol" },
{ },
};
MODULE_DEVICE_TABLE(scmi, scmi_id_table);
static struct scmi_driver qcom_scmi_client_drv = {
.name = "qcom-scmi-driver",
.probe = scmi_client_probe,
.id_table = scmi_id_table,
};
module_scmi_driver(qcom_scmi_client_drv);
MODULE_SOFTDEP("pre: qcom_scmi_vendor");
MODULE_DESCRIPTION("QCOM SCMI client driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Qcom scmi vendor protocol's header
*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _QCOM_SCMI_VENDOR_H
#define _QCOM_SCMI_VENDOR_H
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/types.h>
#define QCOM_SCMI_VENDOR_PROTOCOL 0x80
struct scmi_protocol_handle;
extern struct scmi_device *get_qcom_scmi_device(void);
/**
* struct qcom_scmi_vendor_ops - represents the various operations provided
* by qcom scmi vendor protocol
*/
struct qcom_scmi_vendor_ops {
int (*set_param)(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str,
u32 param_id, size_t size);
int (*get_param)(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str,
u32 param_id, size_t tx_size, size_t rx_size);
int (*start_activity)(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str,
u32 param_id, size_t size);
int (*stop_activity)(const struct scmi_protocol_handle *ph, void *buf, u64 algo_str,
u32 param_id, size_t size);
};
#endif /* _QCOM_SCMI_VENDOR_H */