soc: qcom: Add RPM SMD Driver

This is a snapshot of the RPM-SMD driver functionality as of
'commit 0453f0e705df8b("move rpm-smd initcall to
postcore_initcall_sync")' on msm-4.14 branch.

Change-Id: Ie70bca9c28ae2339b45715f7d82839f39e733832
Signed-off-by: Raghavendra Kakarla <rkakarla@codeaurora.org>
This commit is contained in:
Raghavendra Kakarla 2019-07-22 17:14:42 +05:30 committed by Gerrit - the friendly Code Review server
parent feef939ed1
commit 1bf666cef4
8 changed files with 2265 additions and 0 deletions

View File

@ -77,4 +77,13 @@ config RPMSG_VIRTIO
select RPMSG
select VIRTIO
config MSM_RPM_SMD
bool "RPM driver using SMD protocol"
help
RPM is the dedicated hardware engine for managing shared SoC
resources. This config adds driver support for using SMD as a
transport layer communication with RPM hardware. It also selects
the MSM_MPM config that programs the MPM module to monitor interrupts
during sleep modes.
endmenu

View File

@ -3,6 +3,7 @@ obj-$(CONFIG_RPMSG) += rpmsg_core.o
obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o
obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o
obj-$(CONFIG_RPMSG_QCOM_GLINK_NATIVE) += qcom_glink_native.o
obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd.o
obj-$(CONFIG_RPMSG_QCOM_GLINK_SMEM) += qcom_glink_smem.o
obj-$(CONFIG_RPMSG_QCOM_GLINK_SPSS) += qcom_glink_spss.o
obj-$(CONFIG_RPMSG_QCOM_GLINK_SPI) += qcom_glink_spi.o

1645
drivers/rpmsg/rpm-smd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -87,6 +87,9 @@ obj-$(CONFIG_QTI_DDR_STATS_LOG) += ddr_stats.o
obj-$(CONFIG_QMP_DEBUGFS_CLIENT) += qmp-debugfs-client.o
obj-$(CONFIG_QCOM_HYP_CORE_CTL) += hyp_core_ctl.o
obj-$(CONFIG_MSM_PERFORMANCE) += msm_performance.o
ifdef CONFIG_DEBUG_FS
obj-$(CONFIG_MSM_RPM_SMD) += rpm-smd-debug.o
endif
obj-$(CONFIG_QCOM_CDSP_RM) += cdsprm.o
obj-$(CONFIG_ICNSS) += icnss.o
obj-$(CONFIG_ICNSS_QMI) += icnss_qmi.o wlan_firmware_service_v01.o

View File

@ -0,0 +1,144 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "rpm-smd-debug: %s(): " fmt, __func__
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <soc/qcom/rpm-smd.h>
#define MAX_MSG_BUFFER 350
#define MAX_KEY_VALUE_PAIRS 20
static struct dentry *rpm_debugfs_dir;
static u32 string_to_uint(const u8 *str)
{
int i, len;
u32 output = 0;
len = strnlen(str, sizeof(u32));
for (i = 0; i < len; i++)
output |= str[i] << (i * 8);
return output;
}
static ssize_t rsc_ops_write(struct file *fp, const char __user *user_buffer,
size_t count, loff_t *position)
{
char buf[MAX_MSG_BUFFER], rsc_type_str[6] = {}, rpm_set[8] = {},
key_str[6] = {};
int i, pos = -1, set = -1, nelems = -1;
char *cmp;
uint32_t rsc_type = 0, rsc_id = 0, key = 0, data = 0;
struct msm_rpm_request *req;
count = min(count, sizeof(buf) - 1);
if (copy_from_user(&buf, user_buffer, count))
return -EFAULT;
buf[count] = '\0';
cmp = strstrip(buf);
if (sscanf(cmp, "%7s %5s %u %d %n", rpm_set, rsc_type_str,
&rsc_id, &nelems, &pos) != 4) {
pr_err("Invalid number of arguments passed\n");
goto err;
}
if (strlen(rpm_set) > 6 || strlen(rsc_type_str) > 4) {
pr_err("Invalid value of set or resource type\n");
goto err;
}
if (!strcmp(rpm_set, "active"))
set = 0;
else if (!strcmp(rpm_set, "sleep"))
set = 1;
rsc_type = string_to_uint(rsc_type_str);
if (set < 0 || nelems < 0) {
pr_err("Invalid value of set or nelems\n");
goto err;
}
if (nelems > MAX_KEY_VALUE_PAIRS) {
pr_err("Exceeded max no of key-value entries\n");
goto err;
}
req = msm_rpm_create_request(set, rsc_type, rsc_id, nelems);
if (!req)
return -ENOMEM;
for (i = 0; i < nelems; i++) {
cmp += pos;
if (sscanf(cmp, "%5s %n", key_str, &pos) != 1) {
pr_err("Invalid number of arguments passed\n");
goto err_request;
}
if (strlen(key_str) > 4) {
pr_err("Key value cannot be more than 4 charecters\n");
goto err_request;
}
key = string_to_uint(key_str);
if (!key) {
pr_err("Key values entered incorrectly\n");
goto err_request;
}
cmp += pos;
if (sscanf(cmp, "%u %n", &data, &pos) != 1) {
pr_err("Invalid number of arguments passed\n");
goto err_request;
}
if (msm_rpm_add_kvp_data(req, key,
(void *)&data, sizeof(data)))
goto err_request;
}
if (msm_rpm_wait_for_ack(msm_rpm_send_request(req)))
pr_err("Sending the RPM message failed\n");
err_request:
msm_rpm_free_request(req);
err:
return count;
}
static const struct file_operations rsc_ops = {
.write = rsc_ops_write,
};
static int __init rpm_smd_debugfs_init(void)
{
rpm_debugfs_dir = debugfs_create_dir("rpm_send_msg", NULL);
if (!rpm_debugfs_dir)
return -ENOMEM;
if (!debugfs_create_file("message", 0200, rpm_debugfs_dir, NULL,
&rsc_ops))
return -ENOMEM;
return 0;
}
late_initcall(rpm_smd_debugfs_init);
static void __exit rpm_smd_debugfs_exit(void)
{
debugfs_remove_recursive(rpm_debugfs_dir);
}
module_exit(rpm_smd_debugfs_exit);
MODULE_DESCRIPTION("RPM SMD Debug Driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,56 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef __ARCH_ARM_MACH_MSM_RPM_NOTIF_H
#define __ARCH_ARM_MACH_MSM_RPM_NOTIF_H
struct msm_rpm_notifier_data {
uint32_t rsc_type;
uint32_t rsc_id;
uint32_t key;
uint32_t size;
uint8_t *value;
};
/**
* msm_rpm_register_notifier - Register for sleep set notifications
*
* @nb - notifier block to register
*
* return 0 on success, errno on failure.
*/
int msm_rpm_register_notifier(struct notifier_block *nb);
/**
* msm_rpm_unregister_notifier - Unregister previously registered notifications
*
* @nb - notifier block to unregister
*
* return 0 on success, errno on failure.
*/
int msm_rpm_unregister_notifier(struct notifier_block *nb);
/**
* msm_rpm_enter_sleep - Notify RPM driver to prepare for entering sleep
*
* @bool - flag to enable print contents of sleep buffer.
* @cpumask - cpumask of next wakeup cpu
*
* return 0 on success errno on failure.
*/
int msm_rpm_enter_sleep(bool print, const struct cpumask *cpumask);
/**
* msm_rpm_exit_sleep - Notify RPM driver about resuming from power collapse
*/
void msm_rpm_exit_sleep(void);
/**
* msm_rpm_waiting_for_ack - Indicate if there is RPM message
* pending acknowledgment.
* returns true for pending messages and false otherwise
*/
bool msm_rpm_waiting_for_ack(void);
#endif /*__ARCH_ARM_MACH_MSM_RPM_NOTIF_H */

303
include/soc/qcom/rpm-smd.h Normal file
View File

@ -0,0 +1,303 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/platform_device.h>
#ifndef __ARCH_ARM_MACH_MSM_RPM_SMD_H
#define __ARCH_ARM_MACH_MSM_RPM_SMD_H
/**
* enum msm_rpm_set - RPM enumerations for sleep/active set
* %MSM_RPM_CTX_SET_0: Set resource parameters for active mode.
* %MSM_RPM_CTX_SET_SLEEP: Set resource parameters for sleep.
*/
enum msm_rpm_set {
MSM_RPM_CTX_ACTIVE_SET,
MSM_RPM_CTX_SLEEP_SET,
};
struct msm_rpm_request;
struct msm_rpm_kvp {
uint32_t key;
uint32_t length;
uint8_t *data;
};
#ifdef CONFIG_MSM_RPM_SMD
/**
* msm_rpm_request() - Creates a parent element to identify the
* resource on the RPM, that stores the KVPs for different fields modified
* for a hardware resource
*
* @set: if the device is setting the active/sleep set parameter
* for the resource
* @rsc_type: unsigned 32 bit integer that identifies the type of the resource
* @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
* @num_elements: number of KVPs pairs associated with the resource
*
* returns pointer to a msm_rpm_request on success, NULL on error
*/
struct msm_rpm_request *msm_rpm_create_request(
enum msm_rpm_set set, uint32_t rsc_type,
uint32_t rsc_id, int num_elements);
/**
* msm_rpm_request_noirq() - Creates a parent element to identify the
* resource on the RPM, that stores the KVPs for different fields modified
* for a hardware resource. This function is similar to msm_rpm_create_request
* except that it has to be called with interrupts masked.
*
* @set: if the device is setting the active/sleep set parameter
* for the resource
* @rsc_type: unsigned 32 bit integer that identifies the type of the resource
* @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
* @num_elements: number of KVPs pairs associated with the resource
*
* returns pointer to a msm_rpm_request on success, NULL on error
*/
struct msm_rpm_request *msm_rpm_create_request_noirq(
enum msm_rpm_set set, uint32_t rsc_type,
uint32_t rsc_id, int num_elements);
/**
* msm_rpm_add_kvp_data() - Adds a Key value pair to a existing RPM resource.
*
* @handle: RPM resource handle to which the data should be appended
* @key: unsigned integer identify the parameter modified
* @data: byte array that contains the value corresponding to key.
* @size: size of data in bytes.
*
* returns 0 on success or errno
*/
int msm_rpm_add_kvp_data(struct msm_rpm_request *handle,
uint32_t key, const uint8_t *data, int size);
/**
* msm_rpm_add_kvp_data_noirq() - Adds a Key value pair to a existing RPM
* resource. This function is similar to msm_rpm_add_kvp_data except that it
* has to be called with interrupts masked.
*
* @handle: RPM resource handle to which the data should be appended
* @key: unsigned integer identify the parameter modified
* @data: byte array that contains the value corresponding to key.
* @size: size of data in bytes.
*
* returns 0 on success or errno
*/
int msm_rpm_add_kvp_data_noirq(struct msm_rpm_request *handle,
uint32_t key, const uint8_t *data, int size);
/** msm_rpm_free_request() - clean up the RPM request handle created with
* msm_rpm_create_request
*
* @handle: RPM resource handle to be cleared.
*/
void msm_rpm_free_request(struct msm_rpm_request *handle);
/**
* msm_rpm_send_request() - Send the RPM messages using SMD. The function
* assigns a message id before sending the data out to the RPM. RPM hardware
* uses the message id to acknowledge the messages.
*
* @handle: pointer to the msm_rpm_request for the resource being modified.
*
* returns non-zero message id on success and zero on a failed transaction.
* The drivers use message id to wait for ACK from RPM.
*/
int msm_rpm_send_request(struct msm_rpm_request *handle);
/**
* msm_rpm_send_request_noack() - Send the RPM messages using SMD. The function
* assigns a message id before sending the data out to the RPM. RPM hardware
* uses the message id to acknowledge the messages, but this API does not wait
* on the ACK for this message id and it does not add the message id to the wait
* list.
*
* @handle: pointer to the msm_rpm_request for the resource being modified.
*
* returns NULL on success and PTR_ERR on a failed transaction.
*/
void *msm_rpm_send_request_noack(struct msm_rpm_request *handle);
/**
* msm_rpm_send_request_noirq() - Send the RPM messages using SMD. The
* function assigns a message id before sending the data out to the RPM.
* RPM hardware uses the message id to acknowledge the messages. This function
* is similar to msm_rpm_send_request except that it has to be called with
* interrupts masked.
*
* @handle: pointer to the msm_rpm_request for the resource being modified.
*
* returns non-zero message id on success and zero on a failed transaction.
* The drivers use message id to wait for ACK from RPM.
*/
int msm_rpm_send_request_noirq(struct msm_rpm_request *handle);
/**
* msm_rpm_wait_for_ack() - A blocking call that waits for acknowledgment of
* a message from RPM.
*
* @msg_id: the return from msm_rpm_send_requests
*
* returns 0 on success or errno
*/
int msm_rpm_wait_for_ack(uint32_t msg_id);
/**
* msm_rpm_wait_for_ack_noirq() - A blocking call that waits for acknowledgment
* of a message from RPM. This function is similar to msm_rpm_wait_for_ack
* except that it has to be called with interrupts masked.
*
* @msg_id: the return from msm_rpm_send_request
*
* returns 0 on success or errno
*/
int msm_rpm_wait_for_ack_noirq(uint32_t msg_id);
/**
* msm_rpm_send_message() -Wrapper function for clients to send data given an
* array of key value pairs.
*
* @set: if the device is setting the active/sleep set parameter
* for the resource
* @rsc_type: unsigned 32 bit integer that identifies the type of the resource
* @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
* @kvp: array of KVP data.
* @nelem: number of KVPs pairs associated with the message.
*
* returns 0 on success and errno on failure.
*/
int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type,
uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems);
/**
* msm_rpm_send_message_noack() -Wrapper function for clients to send data
* given an array of key value pairs without waiting for ack.
*
* @set: if the device is setting the active/sleep set parameter
* for the resource
* @rsc_type: unsigned 32 bit integer that identifies the type of the resource
* @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
* @kvp: array of KVP data.
* @nelem: number of KVPs pairs associated with the message.
*
* returns NULL on success and PTR_ERR(errno) on failure.
*/
void *msm_rpm_send_message_noack(enum msm_rpm_set set, uint32_t rsc_type,
uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems);
/**
* msm_rpm_send_message_noirq() -Wrapper function for clients to send data
* given an array of key value pairs. This function is similar to the
* msm_rpm_send_message() except that it has to be called with interrupts
* disabled. Clients should choose the irq version when possible for system
* performance.
*
* @set: if the device is setting the active/sleep set parameter
* for the resource
* @rsc_type: unsigned 32 bit integer that identifies the type of the resource
* @rsc_id: unsigned 32 bit that uniquely identifies a resource within a type
* @kvp: array of KVP data.
* @nelem: number of KVPs pairs associated with the message.
*
* returns 0 on success and errno on failure.
*/
int msm_rpm_send_message_noirq(enum msm_rpm_set set, uint32_t rsc_type,
uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems);
/**
* msm_rpm_driver_init() - Initialization function that registers for a
* rpm platform driver.
*
* returns 0 on success.
*/
int __init msm_rpm_driver_init(void);
#else
static inline struct msm_rpm_request *msm_rpm_create_request(
enum msm_rpm_set set, uint32_t rsc_type,
uint32_t rsc_id, int num_elements)
{
return NULL;
}
static inline struct msm_rpm_request *msm_rpm_create_request_noirq(
enum msm_rpm_set set, uint32_t rsc_type,
uint32_t rsc_id, int num_elements)
{
return NULL;
}
static inline uint32_t msm_rpm_add_kvp_data(struct msm_rpm_request *handle,
uint32_t key, const uint8_t *data, int count)
{
return 0;
}
static inline uint32_t msm_rpm_add_kvp_data_noirq(
struct msm_rpm_request *handle, uint32_t key,
const uint8_t *data, int count)
{
return 0;
}
static inline void msm_rpm_free_request(struct msm_rpm_request *handle)
{
}
static inline int msm_rpm_send_request(struct msm_rpm_request *handle)
{
return 0;
}
static inline int msm_rpm_send_request_noirq(struct msm_rpm_request *handle)
{
return 0;
}
static inline void *msm_rpm_send_request_noack(struct msm_rpm_request *handle)
{
return NULL;
}
static inline int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type,
uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems)
{
return 0;
}
static inline int msm_rpm_send_message_noirq(enum msm_rpm_set set,
uint32_t rsc_type, uint32_t rsc_id, struct msm_rpm_kvp *kvp,
int nelems)
{
return 0;
}
static inline void *msm_rpm_send_message_noack(enum msm_rpm_set set,
uint32_t rsc_type, uint32_t rsc_id, struct msm_rpm_kvp *kvp,
int nelems)
{
return NULL;
}
static inline int msm_rpm_wait_for_ack(uint32_t msg_id)
{
return 0;
}
static inline int msm_rpm_wait_for_ack_noirq(uint32_t msg_id)
{
return 0;
}
static inline int __init msm_rpm_driver_init(void)
{
return 0;
}
#endif
#endif /*__ARCH_ARM_MACH_MSM_RPM_SMD_H*/

View File

@ -0,0 +1,104 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM rpm_smd
#if !defined(_TRACE_RPM_SMD_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_RPM_SMD_H
#include <linux/tracepoint.h>
TRACE_EVENT(rpm_smd_ack_recvd,
TP_PROTO(unsigned int irq, unsigned int msg_id, int errno),
TP_ARGS(irq, msg_id, errno),
TP_STRUCT__entry(
__field(int, irq)
__field(int, msg_id)
__field(int, errno)
),
TP_fast_assign(
__entry->irq = irq;
__entry->msg_id = msg_id;
__entry->errno = errno;
),
TP_printk("ctx:%s msg_id:%d errno:%08x",
__entry->irq ? "noslp" : "sleep",
__entry->msg_id,
__entry->errno)
);
TRACE_EVENT(rpm_smd_interrupt_notify,
TP_PROTO(char *dummy),
TP_ARGS(dummy),
TP_STRUCT__entry(
__field(char *, dummy)
),
TP_fast_assign(
__entry->dummy = dummy;
),
TP_printk("%s", __entry->dummy)
);
DECLARE_EVENT_CLASS(rpm_send_msg,
TP_PROTO(unsigned int msg_id, unsigned int rsc_type,
unsigned int rsc_id),
TP_ARGS(msg_id, rsc_type, rsc_id),
TP_STRUCT__entry(
__field(u32, msg_id)
__field(u32, rsc_type)
__field(u32, rsc_id)
__array(char, name, 5)
),
TP_fast_assign(
__entry->msg_id = msg_id;
__entry->name[4] = 0;
__entry->rsc_type = rsc_type;
__entry->rsc_id = rsc_id;
memcpy(__entry->name, &rsc_type, sizeof(uint32_t));
),
TP_printk("msg_id:%d, rsc_type:0x%08x(%s), rsc_id:0x%08x",
__entry->msg_id,
__entry->rsc_type, __entry->name,
__entry->rsc_id)
);
DEFINE_EVENT(rpm_send_msg, rpm_smd_sleep_set,
TP_PROTO(unsigned int msg_id, unsigned int rsc_type,
unsigned int rsc_id),
TP_ARGS(msg_id, rsc_type, rsc_id)
);
DEFINE_EVENT(rpm_send_msg, rpm_smd_send_sleep_set,
TP_PROTO(unsigned int msg_id, unsigned int rsc_type,
unsigned int rsc_id),
TP_ARGS(msg_id, rsc_type, rsc_id)
);
DEFINE_EVENT(rpm_send_msg, rpm_smd_send_active_set,
TP_PROTO(unsigned int msg_id, unsigned int rsc_type,
unsigned int rsc_id),
TP_ARGS(msg_id, rsc_type, rsc_id)
);
#endif
#define TRACE_INCLUDE_FILE trace_rpm_smd
#include <trace/define_trace.h>