137 lines
3.1 KiB
C
137 lines
3.1 KiB
C
|
// SPDX-License-Identifier: GPL-2.0-only
|
||
|
/*
|
||
|
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||
|
*/
|
||
|
|
||
|
#include "common.h"
|
||
|
|
||
|
#define SCMI_VENDOR_MSG_MAX_TX_SIZE (100) /* in bytes */
|
||
|
#define SCMI_VENDOR_MSG_START (3)
|
||
|
#define SCMI_VENDOR_MSG_PLH_START (16)
|
||
|
|
||
|
enum scmi_plh_protocol_cmd {
|
||
|
PERF_LOCK_SET_LOG_LEVEL = SCMI_VENDOR_MSG_START,
|
||
|
PERF_LOCK_SCROLL_INIT_IPC_FREQ_TBL_MSG_ID = SCMI_VENDOR_MSG_PLH_START,
|
||
|
PERF_LOCK_SCROLL_START_MSG_ID,
|
||
|
PERF_LOCK_SCROLL_STOP_MSG_ID,
|
||
|
PERF_LOCK_MAX_MSG_ID,
|
||
|
};
|
||
|
|
||
|
|
||
|
static int scmi_plh_scroll_init_ipc_freq_tbl(const struct scmi_handle *handle,
|
||
|
u16 *p_init_args, u16 init_len)
|
||
|
{
|
||
|
int ret, i = 0;
|
||
|
struct scmi_xfer *t;
|
||
|
uint32_t *msg, msg_size, msg_val, align_init_len = init_len;
|
||
|
|
||
|
if (init_len % 2)
|
||
|
align_init_len += 1; /* align in multiple of u32 */
|
||
|
|
||
|
msg_size = align_init_len * sizeof(*p_init_args);
|
||
|
|
||
|
if (msg_size > SCMI_VENDOR_MSG_MAX_TX_SIZE)
|
||
|
return -EINVAL;
|
||
|
|
||
|
ret = scmi_xfer_get_init(handle, PERF_LOCK_SCROLL_INIT_IPC_FREQ_TBL_MSG_ID,
|
||
|
SCMI_PROTOCOL_PLH,
|
||
|
(msg_size), sizeof(uint32_t), &t);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
|
||
|
msg = t->tx.buf;
|
||
|
|
||
|
for (i = 0; i < init_len/2 ; i++) {
|
||
|
msg_val = *p_init_args++;
|
||
|
msg_val |= ((*p_init_args++) << 16);
|
||
|
*msg++ = cpu_to_le32(msg_val);
|
||
|
}
|
||
|
|
||
|
if (init_len % 2)
|
||
|
*msg = cpu_to_le32(*p_init_args);
|
||
|
|
||
|
ret = scmi_do_xfer(handle, t);
|
||
|
scmi_xfer_put(handle, t);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
static int scmi_send_start_stop(const struct scmi_handle *handle,
|
||
|
u16 fps, u32 msg_id)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
struct scmi_xfer *t;
|
||
|
uint32_t *msg;
|
||
|
|
||
|
ret = scmi_xfer_get_init(handle, msg_id,
|
||
|
SCMI_PROTOCOL_PLH,
|
||
|
sizeof(*msg), sizeof(uint32_t), &t);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
|
||
|
msg = t->tx.buf;
|
||
|
*msg = cpu_to_le32(fps);
|
||
|
ret = scmi_do_xfer(handle, t);
|
||
|
scmi_xfer_put(handle, t);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int scmi_plh_scroll_start_cmd(const struct scmi_handle *handle,
|
||
|
u16 fps)
|
||
|
{
|
||
|
return scmi_send_start_stop(handle, fps, PERF_LOCK_SCROLL_START_MSG_ID);
|
||
|
}
|
||
|
|
||
|
static int scmi_plh_scroll_stop_cmd(const struct scmi_handle *handle)
|
||
|
{
|
||
|
return scmi_send_start_stop(handle, 0, PERF_LOCK_SCROLL_STOP_MSG_ID);
|
||
|
}
|
||
|
|
||
|
static int scmi_plh_set_log_level(const struct scmi_handle *handle,
|
||
|
u16 val)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
struct scmi_xfer *t;
|
||
|
uint32_t *msg;
|
||
|
|
||
|
ret = scmi_xfer_get_init(handle, PERF_LOCK_SET_LOG_LEVEL,
|
||
|
SCMI_PROTOCOL_PLH, sizeof(*msg),
|
||
|
sizeof(uint32_t), &t);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
|
||
|
msg = t->tx.buf;
|
||
|
*msg = cpu_to_le32(val);
|
||
|
ret = scmi_do_xfer(handle, t);
|
||
|
scmi_xfer_put(handle, t);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static struct scmi_plh_vendor_ops plh_ops = {
|
||
|
.init_splh_ipc_freq_tbl = scmi_plh_scroll_init_ipc_freq_tbl,
|
||
|
.start_splh = scmi_plh_scroll_start_cmd,
|
||
|
.stop_splh = scmi_plh_scroll_stop_cmd,
|
||
|
.set_plh_log_level = scmi_plh_set_log_level,
|
||
|
};
|
||
|
|
||
|
static int scmi_plh_vendor_protocol_init(struct scmi_handle *handle)
|
||
|
{
|
||
|
u32 version;
|
||
|
|
||
|
scmi_version_get(handle, SCMI_PROTOCOL_PLH, &version);
|
||
|
|
||
|
dev_dbg(handle->dev, "PLH version %d.%d\n",
|
||
|
PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
|
||
|
|
||
|
handle->plh_ops = &plh_ops;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int __init scmi_plh_init(void)
|
||
|
{
|
||
|
return scmi_protocol_register(SCMI_PROTOCOL_PLH,
|
||
|
&scmi_plh_vendor_protocol_init);
|
||
|
}
|
||
|
subsys_initcall(scmi_plh_init);
|