Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,50 @@
# SPDX-License-Identifier: GPL-2.0-only
menu "ARM SCMI NXP i.MX Vendor Protocols"
config IMX_SCMI_BBM_EXT
tristate "i.MX SCMI BBM EXTENSION"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
default y if ARCH_MXC
help
This enables i.MX System BBM control logic which supports RTC
and BUTTON.
To compile this driver as a module, choose M here: the
module will be called imx-sm-bbm.
config IMX_SCMI_CPU_EXT
tristate "i.MX SCMI CPU EXTENSION"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
depends on IMX_SCMI_CPU_DRV
default y if ARCH_MXC
help
This enables i.MX System CPU Protocol to manage cpu
start, stop and etc.
To compile this driver as a module, choose M here: the
module will be called imx-sm-cpu.
config IMX_SCMI_LMM_EXT
tristate "i.MX SCMI LMM EXTENSION"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
depends on IMX_SCMI_LMM_DRV
default y if ARCH_MXC
help
This enables i.MX System Logical Machine Protocol to
manage Logical Machines boot, shutdown and etc.
To compile this driver as a module, choose M here: the
module will be called imx-sm-lmm.
config IMX_SCMI_MISC_EXT
tristate "i.MX SCMI MISC EXTENSION"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
depends on IMX_SCMI_MISC_DRV
default y if ARCH_MXC
help
This enables i.MX System MISC control logic such as gpio expander
wakeup
To compile this driver as a module, choose M here: the
module will be called imx-sm-misc.
endmenu
@@ -0,0 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_IMX_SCMI_BBM_EXT) += imx-sm-bbm.o
obj-$(CONFIG_IMX_SCMI_CPU_EXT) += imx-sm-cpu.o
obj-$(CONFIG_IMX_SCMI_LMM_EXT) += imx-sm-lmm.o
obj-$(CONFIG_IMX_SCMI_MISC_EXT) += imx-sm-misc.o
@@ -0,0 +1,378 @@
// SPDX-License-Identifier: GPL-2.0
/*
* System Control and Management Interface (SCMI) NXP BBM Protocol
*
* Copyright 2024 NXP
*/
#define pr_fmt(fmt) "SCMI Notifications BBM - " fmt
#include <linux/bits.h>
#include <linux/io.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 "../../protocols.h"
#include "../../notify.h"
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
enum scmi_imx_bbm_protocol_cmd {
IMX_BBM_GPR_SET = 0x3,
IMX_BBM_GPR_GET = 0x4,
IMX_BBM_RTC_ATTRIBUTES = 0x5,
IMX_BBM_RTC_TIME_SET = 0x6,
IMX_BBM_RTC_TIME_GET = 0x7,
IMX_BBM_RTC_ALARM_SET = 0x8,
IMX_BBM_BUTTON_GET = 0x9,
IMX_BBM_RTC_NOTIFY = 0xA,
IMX_BBM_BUTTON_NOTIFY = 0xB,
};
#define GET_RTCS_NR(x) le32_get_bits((x), GENMASK(23, 16))
#define GET_GPRS_NR(x) le32_get_bits((x), GENMASK(15, 0))
#define SCMI_IMX_BBM_NOTIFY_RTC_UPDATED BIT(2)
#define SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER BIT(1)
#define SCMI_IMX_BBM_NOTIFY_RTC_ALARM BIT(0)
#define SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG BIT(0)
#define SCMI_IMX_BBM_NOTIFY_RTC_FLAG \
(SCMI_IMX_BBM_NOTIFY_RTC_UPDATED | SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER | \
SCMI_IMX_BBM_NOTIFY_RTC_ALARM)
#define SCMI_IMX_BBM_EVENT_RTC_MASK GENMASK(31, 24)
struct scmi_imx_bbm_info {
int nr_rtc;
int nr_gpr;
};
struct scmi_msg_imx_bbm_protocol_attributes {
__le32 attributes;
};
struct scmi_imx_bbm_set_time {
__le32 id;
__le32 flags;
__le32 value_low;
__le32 value_high;
};
struct scmi_imx_bbm_get_time {
__le32 id;
__le32 flags;
};
struct scmi_imx_bbm_alarm_time {
__le32 id;
__le32 flags;
__le32 value_low;
__le32 value_high;
};
struct scmi_msg_imx_bbm_rtc_notify {
__le32 rtc_id;
__le32 flags;
};
struct scmi_msg_imx_bbm_button_notify {
__le32 flags;
};
struct scmi_imx_bbm_notify_payld {
__le32 flags;
};
static int scmi_imx_bbm_attributes_get(const struct scmi_protocol_handle *ph,
struct scmi_imx_bbm_info *pi)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_imx_bbm_protocol_attributes *attr;
ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, sizeof(*attr), &t);
if (ret)
return ret;
attr = t->rx.buf;
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
pi->nr_rtc = GET_RTCS_NR(attr->attributes);
pi->nr_gpr = GET_GPRS_NR(attr->attributes);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_bbm_notify(const struct scmi_protocol_handle *ph,
u32 src_id, int message_id, bool enable)
{
int ret;
struct scmi_xfer *t;
if (message_id == IMX_BBM_RTC_NOTIFY) {
struct scmi_msg_imx_bbm_rtc_notify *rtc_notify;
ret = ph->xops->xfer_get_init(ph, message_id,
sizeof(*rtc_notify), 0, &t);
if (ret)
return ret;
rtc_notify = t->tx.buf;
rtc_notify->rtc_id = cpu_to_le32(0);
rtc_notify->flags =
cpu_to_le32(enable ? SCMI_IMX_BBM_NOTIFY_RTC_FLAG : 0);
} else if (message_id == IMX_BBM_BUTTON_NOTIFY) {
struct scmi_msg_imx_bbm_button_notify *button_notify;
ret = ph->xops->xfer_get_init(ph, message_id,
sizeof(*button_notify), 0, &t);
if (ret)
return ret;
button_notify = t->tx.buf;
button_notify->flags = cpu_to_le32(enable ? 1 : 0);
} else {
return -EINVAL;
}
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static enum scmi_imx_bbm_protocol_cmd evt_2_cmd[] = {
IMX_BBM_RTC_NOTIFY,
IMX_BBM_BUTTON_NOTIFY
};
static int scmi_imx_bbm_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret, cmd_id;
if (evt_id >= ARRAY_SIZE(evt_2_cmd))
return -EINVAL;
cmd_id = evt_2_cmd[evt_id];
ret = scmi_imx_bbm_notify(ph, src_id, cmd_id, enable);
if (ret)
pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
evt_id, src_id, ret);
return ret;
}
static void *scmi_imx_bbm_fill_custom_report(const struct scmi_protocol_handle *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
{
const struct scmi_imx_bbm_notify_payld *p = payld;
struct scmi_imx_bbm_notif_report *r = report;
if (sizeof(*p) != payld_sz)
return NULL;
if (evt_id == SCMI_EVENT_IMX_BBM_RTC) {
r->is_rtc = true;
r->is_button = false;
r->timestamp = timestamp;
r->rtc_id = le32_get_bits(p->flags, SCMI_IMX_BBM_EVENT_RTC_MASK);
r->rtc_evt = le32_get_bits(p->flags, SCMI_IMX_BBM_NOTIFY_RTC_FLAG);
dev_dbg(ph->dev, "RTC: %d evt: %x\n", r->rtc_id, r->rtc_evt);
*src_id = r->rtc_evt;
} else if (evt_id == SCMI_EVENT_IMX_BBM_BUTTON) {
r->is_rtc = false;
r->is_button = true;
r->timestamp = timestamp;
dev_dbg(ph->dev, "BBM Button\n");
*src_id = 0;
} else {
WARN_ON_ONCE(1);
return NULL;
}
return r;
}
static const struct scmi_event scmi_imx_bbm_events[] = {
{
.id = SCMI_EVENT_IMX_BBM_RTC,
.max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),
.max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),
},
{
.id = SCMI_EVENT_IMX_BBM_BUTTON,
.max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),
.max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),
},
};
static const struct scmi_event_ops scmi_imx_bbm_event_ops = {
.set_notify_enabled = scmi_imx_bbm_set_notify_enabled,
.fill_custom_report = scmi_imx_bbm_fill_custom_report,
};
static const struct scmi_protocol_events scmi_imx_bbm_protocol_events = {
.queue_sz = SCMI_PROTO_QUEUE_SZ,
.ops = &scmi_imx_bbm_event_ops,
.evts = scmi_imx_bbm_events,
.num_events = ARRAY_SIZE(scmi_imx_bbm_events),
.num_sources = 1,
};
static int scmi_imx_bbm_rtc_time_set(const struct scmi_protocol_handle *ph,
u32 rtc_id, u64 sec)
{
struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
struct scmi_imx_bbm_set_time *cfg;
struct scmi_xfer *t;
int ret;
if (rtc_id >= pi->nr_rtc)
return -EINVAL;
ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_SET, sizeof(*cfg), 0, &t);
if (ret)
return ret;
cfg = t->tx.buf;
cfg->id = cpu_to_le32(rtc_id);
cfg->flags = 0;
cfg->value_low = cpu_to_le32(lower_32_bits(sec));
cfg->value_high = cpu_to_le32(upper_32_bits(sec));
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_bbm_rtc_time_get(const struct scmi_protocol_handle *ph,
u32 rtc_id, u64 *value)
{
struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
struct scmi_imx_bbm_get_time *cfg;
struct scmi_xfer *t;
int ret;
if (rtc_id >= pi->nr_rtc)
return -EINVAL;
ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_GET, sizeof(*cfg),
sizeof(u64), &t);
if (ret)
return ret;
cfg = t->tx.buf;
cfg->id = cpu_to_le32(rtc_id);
cfg->flags = 0;
ret = ph->xops->do_xfer(ph, t);
if (!ret)
*value = get_unaligned_le64(t->rx.buf);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_bbm_rtc_alarm_set(const struct scmi_protocol_handle *ph,
u32 rtc_id, bool enable, u64 sec)
{
struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
struct scmi_imx_bbm_alarm_time *cfg;
struct scmi_xfer *t;
int ret;
if (rtc_id >= pi->nr_rtc)
return -EINVAL;
ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_ALARM_SET, sizeof(*cfg), 0, &t);
if (ret)
return ret;
cfg = t->tx.buf;
cfg->id = cpu_to_le32(rtc_id);
cfg->flags = enable ?
cpu_to_le32(SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG) : 0;
cfg->value_low = cpu_to_le32(lower_32_bits(sec));
cfg->value_high = cpu_to_le32(upper_32_bits(sec));
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_bbm_button_get(const struct scmi_protocol_handle *ph, u32 *state)
{
struct scmi_xfer *t;
int ret;
ret = ph->xops->xfer_get_init(ph, IMX_BBM_BUTTON_GET, 0, sizeof(u32), &t);
if (ret)
return ret;
ret = ph->xops->do_xfer(ph, t);
if (!ret)
*state = get_unaligned_le32(t->rx.buf);
ph->xops->xfer_put(ph, t);
return ret;
}
static const struct scmi_imx_bbm_proto_ops scmi_imx_bbm_proto_ops = {
.rtc_time_get = scmi_imx_bbm_rtc_time_get,
.rtc_time_set = scmi_imx_bbm_rtc_time_set,
.rtc_alarm_set = scmi_imx_bbm_rtc_alarm_set,
.button_get = scmi_imx_bbm_button_get,
};
static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph)
{
int ret;
struct scmi_imx_bbm_info *binfo;
dev_info(ph->dev, "NXP SM BBM Version %d.%d\n",
PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
binfo = devm_kzalloc(ph->dev, sizeof(*binfo), GFP_KERNEL);
if (!binfo)
return -ENOMEM;
ret = scmi_imx_bbm_attributes_get(ph, binfo);
if (ret)
return ret;
return ph->set_priv(ph, binfo);
}
static const struct scmi_protocol scmi_imx_bbm = {
.id = SCMI_PROTOCOL_IMX_BBM,
.owner = THIS_MODULE,
.instance_init = &scmi_imx_bbm_protocol_init,
.ops = &scmi_imx_bbm_proto_ops,
.events = &scmi_imx_bbm_protocol_events,
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
.vendor_id = SCMI_IMX_VENDOR,
.sub_vendor_id = SCMI_IMX_SUBVENDOR,
};
module_scmi_protocol(scmi_imx_bbm);
MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_BBM) "-" SCMI_IMX_VENDOR);
MODULE_DESCRIPTION("i.MX SCMI BBM driver");
MODULE_LICENSE("GPL");
@@ -0,0 +1,271 @@
// SPDX-License-Identifier: GPL-2.0
/*
* System control and Management Interface (SCMI) NXP CPU Protocol
*
* Copyright 2025 NXP
*/
#include <linux/bits.h>
#include <linux/io.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 "../../protocols.h"
#include "../../notify.h"
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
enum scmi_imx_cpu_protocol_cmd {
SCMI_IMX_CPU_ATTRIBUTES = 0x3,
SCMI_IMX_CPU_START = 0x4,
SCMI_IMX_CPU_STOP = 0x5,
SCMI_IMX_CPU_RESET_VECTOR_SET = 0x6,
SCMI_IMX_CPU_INFO_GET = 0xC,
};
struct scmi_imx_cpu_info {
u32 nr_cpu;
};
#define SCMI_IMX_CPU_NR_CPU_MASK GENMASK(15, 0)
struct scmi_msg_imx_cpu_protocol_attributes {
__le32 attributes;
};
struct scmi_msg_imx_cpu_attributes_out {
__le32 attributes;
#define CPU_MAX_NAME 16
u8 name[CPU_MAX_NAME];
};
struct scmi_imx_cpu_reset_vector_set_in {
__le32 cpuid;
#define CPU_VEC_FLAGS_RESUME BIT(31)
#define CPU_VEC_FLAGS_START BIT(30)
#define CPU_VEC_FLAGS_BOOT BIT(29)
__le32 flags;
__le32 resetvectorlow;
__le32 resetvectorhigh;
};
struct scmi_imx_cpu_info_get_out {
#define CPU_RUN_MODE_START 0
#define CPU_RUN_MODE_HOLD 1
#define CPU_RUN_MODE_STOP 2
#define CPU_RUN_MODE_SLEEP 3
__le32 runmode;
__le32 sleepmode;
__le32 resetvectorlow;
__le32 resetvectorhigh;
};
static int scmi_imx_cpu_validate_cpuid(const struct scmi_protocol_handle *ph,
u32 cpuid)
{
struct scmi_imx_cpu_info *info = ph->get_priv(ph);
if (cpuid >= info->nr_cpu)
return -EINVAL;
return 0;
}
static int scmi_imx_cpu_start(const struct scmi_protocol_handle *ph,
u32 cpuid, bool start)
{
struct scmi_xfer *t;
u8 msg_id;
int ret;
ret = scmi_imx_cpu_validate_cpuid(ph, cpuid);
if (ret)
return ret;
if (start)
msg_id = SCMI_IMX_CPU_START;
else
msg_id = SCMI_IMX_CPU_STOP;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(u32), 0, &t);
if (ret)
return ret;
put_unaligned_le32(cpuid, t->tx.buf);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_cpu_reset_vector_set(const struct scmi_protocol_handle *ph,
u32 cpuid, u64 vector, bool start,
bool boot, bool resume)
{
struct scmi_imx_cpu_reset_vector_set_in *in;
struct scmi_xfer *t;
int ret;
ret = scmi_imx_cpu_validate_cpuid(ph, cpuid);
if (ret)
return ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_CPU_RESET_VECTOR_SET, sizeof(*in),
0, &t);
if (ret)
return ret;
in = t->tx.buf;
in->cpuid = cpu_to_le32(cpuid);
in->flags = cpu_to_le32(0);
if (start)
in->flags |= le32_encode_bits(1, CPU_VEC_FLAGS_START);
if (boot)
in->flags |= le32_encode_bits(1, CPU_VEC_FLAGS_BOOT);
if (resume)
in->flags |= le32_encode_bits(1, CPU_VEC_FLAGS_RESUME);
in->resetvectorlow = cpu_to_le32(lower_32_bits(vector));
in->resetvectorhigh = cpu_to_le32(upper_32_bits(vector));
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_cpu_started(const struct scmi_protocol_handle *ph, u32 cpuid,
bool *started)
{
struct scmi_imx_cpu_info_get_out *out;
struct scmi_xfer *t;
u32 mode;
int ret;
if (!started)
return -EINVAL;
*started = false;
ret = scmi_imx_cpu_validate_cpuid(ph, cpuid);
if (ret)
return ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_CPU_INFO_GET, sizeof(u32),
0, &t);
if (ret)
return ret;
put_unaligned_le32(cpuid, t->tx.buf);
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
out = t->rx.buf;
mode = le32_to_cpu(out->runmode);
if (mode == CPU_RUN_MODE_START || mode == CPU_RUN_MODE_SLEEP)
*started = true;
}
ph->xops->xfer_put(ph, t);
return ret;
}
static const struct scmi_imx_cpu_proto_ops scmi_imx_cpu_proto_ops = {
.cpu_reset_vector_set = scmi_imx_cpu_reset_vector_set,
.cpu_start = scmi_imx_cpu_start,
.cpu_started = scmi_imx_cpu_started,
};
static int scmi_imx_cpu_protocol_attributes_get(const struct scmi_protocol_handle *ph,
struct scmi_imx_cpu_info *info)
{
struct scmi_msg_imx_cpu_protocol_attributes *attr;
struct scmi_xfer *t;
int ret;
ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
sizeof(*attr), &t);
if (ret)
return ret;
attr = t->rx.buf;
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
info->nr_cpu = le32_get_bits(attr->attributes, SCMI_IMX_CPU_NR_CPU_MASK);
dev_info(ph->dev, "i.MX SM CPU: %d cpus\n",
info->nr_cpu);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_cpu_attributes_get(const struct scmi_protocol_handle *ph,
u32 cpuid)
{
struct scmi_msg_imx_cpu_attributes_out *out;
char name[SCMI_SHORT_NAME_MAX_SIZE] = {'\0'};
struct scmi_xfer *t;
int ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_CPU_ATTRIBUTES, sizeof(u32), 0, &t);
if (ret)
return ret;
put_unaligned_le32(cpuid, t->tx.buf);
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
out = t->rx.buf;
strscpy(name, out->name, SCMI_SHORT_NAME_MAX_SIZE);
dev_info(ph->dev, "i.MX CPU: name: %s\n", name);
} else {
dev_err(ph->dev, "i.MX cpu: Failed to get info of cpu(%u)\n", cpuid);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_cpu_protocol_init(const struct scmi_protocol_handle *ph)
{
struct scmi_imx_cpu_info *info;
int ret, i;
dev_info(ph->dev, "NXP SM CPU Protocol Version %d.%d\n",
PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
info = devm_kzalloc(ph->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
ret = scmi_imx_cpu_protocol_attributes_get(ph, info);
if (ret)
return ret;
for (i = 0; i < info->nr_cpu; i++) {
ret = scmi_imx_cpu_attributes_get(ph, i);
if (ret)
return ret;
}
return ph->set_priv(ph, info);
}
static const struct scmi_protocol scmi_imx_cpu = {
.id = SCMI_PROTOCOL_IMX_CPU,
.owner = THIS_MODULE,
.instance_init = &scmi_imx_cpu_protocol_init,
.ops = &scmi_imx_cpu_proto_ops,
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
.vendor_id = SCMI_IMX_VENDOR,
.sub_vendor_id = SCMI_IMX_SUBVENDOR,
};
module_scmi_protocol(scmi_imx_cpu);
MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_CPU) "-" SCMI_IMX_VENDOR);
MODULE_DESCRIPTION("i.MX SCMI CPU driver");
MODULE_LICENSE("GPL");
@@ -0,0 +1,258 @@
// SPDX-License-Identifier: GPL-2.0
/*
* System control and Management Interface (SCMI) NXP LMM Protocol
*
* Copyright 2025 NXP
*/
#include <linux/bits.h>
#include <linux/io.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 "../../protocols.h"
#include "../../notify.h"
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
enum scmi_imx_lmm_protocol_cmd {
SCMI_IMX_LMM_ATTRIBUTES = 0x3,
SCMI_IMX_LMM_BOOT = 0x4,
SCMI_IMX_LMM_RESET = 0x5,
SCMI_IMX_LMM_SHUTDOWN = 0x6,
SCMI_IMX_LMM_WAKE = 0x7,
SCMI_IMX_LMM_SUSPEND = 0x8,
SCMI_IMX_LMM_NOTIFY = 0x9,
SCMI_IMX_LMM_RESET_REASON = 0xA,
SCMI_IMX_LMM_POWER_ON = 0xB,
SCMI_IMX_LMM_RESET_VECTOR_SET = 0xC,
};
struct scmi_imx_lmm_priv {
u32 nr_lmm;
};
#define SCMI_IMX_LMM_NR_LM_MASK GENMASK(5, 0)
#define SCMI_IMX_LMM_NR_MAX 16
struct scmi_msg_imx_lmm_protocol_attributes {
__le32 attributes;
};
struct scmi_msg_imx_lmm_attributes_out {
__le32 lmid;
__le32 attributes;
__le32 state;
__le32 errstatus;
u8 name[LMM_MAX_NAME];
};
struct scmi_imx_lmm_reset_vector_set_in {
__le32 lmid;
__le32 cpuid;
__le32 flags; /* reserved for future extension */
__le32 resetvectorlow;
__le32 resetvectorhigh;
};
struct scmi_imx_lmm_shutdown_in {
__le32 lmid;
#define SCMI_IMX_LMM_SHUTDOWN_GRACEFUL BIT(0)
__le32 flags;
};
static int scmi_imx_lmm_validate_lmid(const struct scmi_protocol_handle *ph, u32 lmid)
{
struct scmi_imx_lmm_priv *priv = ph->get_priv(ph);
if (lmid >= priv->nr_lmm)
return -EINVAL;
return 0;
}
static int scmi_imx_lmm_attributes(const struct scmi_protocol_handle *ph,
u32 lmid, struct scmi_imx_lmm_info *info)
{
struct scmi_msg_imx_lmm_attributes_out *out;
struct scmi_xfer *t;
int ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_ATTRIBUTES, sizeof(u32), 0, &t);
if (ret)
return ret;
put_unaligned_le32(lmid, t->tx.buf);
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
out = t->rx.buf;
info->lmid = le32_to_cpu(out->lmid);
info->state = le32_to_cpu(out->state);
info->errstatus = le32_to_cpu(out->errstatus);
strscpy(info->name, out->name);
dev_dbg(ph->dev, "i.MX LMM: Logical Machine(%d), name: %s\n",
info->lmid, info->name);
} else {
dev_err(ph->dev, "i.MX LMM: Failed to get info of Logical Machine(%u)\n", lmid);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int
scmi_imx_lmm_power_boot(const struct scmi_protocol_handle *ph, u32 lmid, bool boot)
{
struct scmi_xfer *t;
u8 msg_id;
int ret;
ret = scmi_imx_lmm_validate_lmid(ph, lmid);
if (ret)
return ret;
if (boot)
msg_id = SCMI_IMX_LMM_BOOT;
else
msg_id = SCMI_IMX_LMM_POWER_ON;
ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(u32), 0, &t);
if (ret)
return ret;
put_unaligned_le32(lmid, t->tx.buf);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_lmm_reset_vector_set(const struct scmi_protocol_handle *ph,
u32 lmid, u32 cpuid, u32 flags, u64 vector)
{
struct scmi_imx_lmm_reset_vector_set_in *in;
struct scmi_xfer *t;
int ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_RESET_VECTOR_SET, sizeof(*in),
0, &t);
if (ret)
return ret;
in = t->tx.buf;
in->lmid = cpu_to_le32(lmid);
in->cpuid = cpu_to_le32(cpuid);
in->flags = cpu_to_le32(0);
in->resetvectorlow = cpu_to_le32(lower_32_bits(vector));
in->resetvectorhigh = cpu_to_le32(upper_32_bits(vector));
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_lmm_shutdown(const struct scmi_protocol_handle *ph, u32 lmid,
u32 flags)
{
struct scmi_imx_lmm_shutdown_in *in;
struct scmi_xfer *t;
int ret;
ret = scmi_imx_lmm_validate_lmid(ph, lmid);
if (ret)
return ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_SHUTDOWN, sizeof(*in),
0, &t);
if (ret)
return ret;
in = t->tx.buf;
in->lmid = cpu_to_le32(lmid);
if (flags & SCMI_IMX_LMM_SHUTDOWN_GRACEFUL)
in->flags = cpu_to_le32(SCMI_IMX_LMM_SHUTDOWN_GRACEFUL);
else
in->flags = cpu_to_le32(0);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static const struct scmi_imx_lmm_proto_ops scmi_imx_lmm_proto_ops = {
.lmm_power_boot = scmi_imx_lmm_power_boot,
.lmm_info = scmi_imx_lmm_attributes,
.lmm_reset_vector_set = scmi_imx_lmm_reset_vector_set,
.lmm_shutdown = scmi_imx_lmm_shutdown,
};
static int scmi_imx_lmm_protocol_attributes_get(const struct scmi_protocol_handle *ph,
struct scmi_imx_lmm_priv *priv)
{
struct scmi_msg_imx_lmm_protocol_attributes *attr;
struct scmi_xfer *t;
int ret;
ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
sizeof(*attr), &t);
if (ret)
return ret;
attr = t->rx.buf;
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
priv->nr_lmm = le32_get_bits(attr->attributes, SCMI_IMX_LMM_NR_LM_MASK);
if (priv->nr_lmm > SCMI_IMX_LMM_NR_MAX) {
dev_err(ph->dev, "i.MX LMM: %d:Exceed max supported Logical Machines\n",
priv->nr_lmm);
ret = -EINVAL;
} else {
dev_info(ph->dev, "i.MX LMM: %d Logical Machines\n", priv->nr_lmm);
}
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_lmm_protocol_init(const struct scmi_protocol_handle *ph)
{
struct scmi_imx_lmm_priv *info;
int ret;
dev_info(ph->dev, "NXP SM LMM Version %d.%d\n",
PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
info = devm_kzalloc(ph->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
ret = scmi_imx_lmm_protocol_attributes_get(ph, info);
if (ret)
return ret;
return ph->set_priv(ph, info);
}
static const struct scmi_protocol scmi_imx_lmm = {
.id = SCMI_PROTOCOL_IMX_LMM,
.owner = THIS_MODULE,
.instance_init = &scmi_imx_lmm_protocol_init,
.ops = &scmi_imx_lmm_proto_ops,
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
.vendor_id = SCMI_IMX_VENDOR,
.sub_vendor_id = SCMI_IMX_SUBVENDOR,
};
module_scmi_protocol(scmi_imx_lmm);
MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_LMM) "-" SCMI_IMX_VENDOR);
MODULE_DESCRIPTION("i.MX SCMI LMM driver");
MODULE_LICENSE("GPL");
@@ -0,0 +1,593 @@
// SPDX-License-Identifier: GPL-2.0
/*
* System control and Management Interface (SCMI) NXP MISC Protocol
*
* Copyright 2024 NXP
*/
#define pr_fmt(fmt) "SCMI Notifications MISC - " fmt
#include <linux/bits.h>
#include <linux/io.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 "../../protocols.h"
#include "../../notify.h"
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
#define MAX_MISC_CTRL_SOURCES GENMASK(15, 0)
enum scmi_imx_misc_protocol_cmd {
SCMI_IMX_MISC_CTRL_SET = 0x3,
SCMI_IMX_MISC_CTRL_GET = 0x4,
SCMI_IMX_MISC_DISCOVER_BUILD_INFO = 0x6,
SCMI_IMX_MISC_CTRL_NOTIFY = 0x8,
SCMI_IMX_MISC_RESET_REASON_GET = 0xA,
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 nr_dev_ctrl;
u32 nr_brd_ctrl;
u32 nr_reason;
};
struct scmi_msg_imx_misc_protocol_attributes {
__le32 attributes;
};
#define GET_BRD_CTRLS_NR(x) le32_get_bits((x), GENMASK(31, 24))
#define GET_REASONS_NR(x) le32_get_bits((x), GENMASK(23, 16))
#define GET_DEV_CTRLS_NR(x) le32_get_bits((x), GENMASK(15, 0))
#define BRD_CTRL_START_ID BIT(15)
struct scmi_imx_misc_ctrl_set_in {
__le32 id;
__le32 num;
__le32 value[];
};
struct scmi_imx_misc_ctrl_notify_in {
__le32 ctrl_id;
__le32 flags;
};
struct scmi_imx_misc_ctrl_notify_payld {
__le32 ctrl_id;
__le32 flags;
};
struct scmi_imx_misc_ctrl_get_out {
__le32 num;
__le32 val[];
};
struct scmi_imx_misc_buildinfo_out {
__le32 buildnum;
__le32 buildcommit;
#define MISC_MAX_BUILDDATE 16
u8 builddate[MISC_MAX_BUILDDATE];
#define MISC_MAX_BUILDTIME 16
u8 buildtime[MISC_MAX_BUILDTIME];
};
struct scmi_imx_misc_board_info_out {
__le32 attributes;
#define MISC_MAX_BRDNAME 16
u8 brdname[MISC_MAX_BRDNAME];
};
struct scmi_imx_misc_cfg_info_out {
__le32 msel;
#define MISC_MAX_CFGNAME 16
u8 cfgname[MISC_MAX_CFGNAME];
};
struct scmi_imx_misc_reset_reason_in {
#define MISC_REASON_FLAG_SYSTEM BIT(0)
__le32 flags;
};
struct scmi_imx_misc_reset_reason_out {
/* Boot reason flags */
#define MISC_BOOT_FLAG_VLD BIT(31)
#define MISC_BOOT_FLAG_ORG_VLD BIT(28)
#define MISC_BOOT_FLAG_ORIGIN GENMASK(27, 24)
#define MISC_BOOT_FLAG_O_SHIFT 24
#define MISC_BOOT_FLAG_ERR_VLD BIT(23)
#define MISC_BOOT_FLAG_ERR_ID GENMASK(22, 8)
#define MISC_BOOT_FLAG_E_SHIFT 8
#define MISC_BOOT_FLAG_REASON GENMASK(7, 0)
__le32 b_flags;
/* Shutdown reason flags */
#define MISC_SHUTDOWN_FLAG_VLD BIT(31)
#define MISC_SHUTDOWN_FLAG_EXT_LEN GENMASK(30, 29)
#define MISC_SHUTDOWN_FLAG_ORG_VLD BIT(28)
#define MISC_SHUTDOWN_FLAG_ORIGIN GENMASK(27, 24)
#define MISC_SHUTDOWN_FLAG_O_SHIFT 24
#define MISC_SHUTDOWN_FLAG_ERR_VLD BIT(23)
#define MISC_SHUTDOWN_FLAG_ERR_ID GENMASK(22, 8)
#define MISC_SHUTDOWN_FLAG_E_SHIFT 8
#define MISC_SHUTDOWN_FLAG_REASON GENMASK(7, 0)
__le32 s_flags;
/* Array of extended info words */
__le32 extinfo[MISC_EXT_INFO_LEN_MAX];
};
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)
{
int ret;
struct scmi_xfer *t;
struct scmi_msg_imx_misc_protocol_attributes *attr;
ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
sizeof(*attr), &t);
if (ret)
return ret;
attr = t->rx.buf;
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
mi->nr_dev_ctrl = GET_DEV_CTRLS_NR(attr->attributes);
mi->nr_brd_ctrl = GET_BRD_CTRLS_NR(attr->attributes);
mi->nr_reason = GET_REASONS_NR(attr->attributes);
dev_info(ph->dev, "i.MX MISC NUM DEV CTRL: %d, NUM BRD CTRL: %d,NUM Reason: %d\n",
mi->nr_dev_ctrl, mi->nr_brd_ctrl, mi->nr_reason);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_misc_ctrl_validate_id(const struct scmi_protocol_handle *ph,
u32 ctrl_id)
{
struct scmi_imx_misc_info *mi = ph->get_priv(ph);
/*
* [0, BRD_CTRL_START_ID) is for Dev Ctrl which is SOC related
* [BRD_CTRL_START_ID, 0xffff) is for Board Ctrl which is board related
*/
if (ctrl_id < BRD_CTRL_START_ID && ctrl_id > mi->nr_dev_ctrl)
return -EINVAL;
if (ctrl_id >= BRD_CTRL_START_ID + mi->nr_brd_ctrl)
return -EINVAL;
return 0;
}
static int scmi_imx_misc_ctrl_notify(const struct scmi_protocol_handle *ph,
u32 ctrl_id, u32 evt_id, u32 flags)
{
struct scmi_imx_misc_ctrl_notify_in *in;
struct scmi_xfer *t;
int ret;
ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);
if (ret)
return ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_NOTIFY,
sizeof(*in), 0, &t);
if (ret)
return ret;
in = t->tx.buf;
in->ctrl_id = cpu_to_le32(ctrl_id);
in->flags = cpu_to_le32(flags);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int
scmi_imx_misc_ctrl_set_notify_enabled(const struct scmi_protocol_handle *ph,
u8 evt_id, u32 src_id, bool enable)
{
int ret;
/* misc_ctrl_req_notify is for enablement */
if (enable)
return 0;
ret = scmi_imx_misc_ctrl_notify(ph, src_id, evt_id, 0);
if (ret)
dev_err(ph->dev, "FAIL_ENABLED - evt[%X] src[%d] - ret:%d\n",
evt_id, src_id, ret);
return ret;
}
static void *
scmi_imx_misc_ctrl_fill_custom_report(const struct scmi_protocol_handle *ph,
u8 evt_id, ktime_t timestamp,
const void *payld, size_t payld_sz,
void *report, u32 *src_id)
{
const struct scmi_imx_misc_ctrl_notify_payld *p = payld;
struct scmi_imx_misc_ctrl_notify_report *r = report;
if (sizeof(*p) != payld_sz)
return NULL;
r->timestamp = timestamp;
r->ctrl_id = le32_to_cpu(p->ctrl_id);
r->flags = le32_to_cpu(p->flags);
if (src_id)
*src_id = r->ctrl_id;
dev_dbg(ph->dev, "%s: ctrl_id: %d flags: %d\n", __func__,
r->ctrl_id, r->flags);
return r;
}
static const struct scmi_event_ops scmi_imx_misc_event_ops = {
.set_notify_enabled = scmi_imx_misc_ctrl_set_notify_enabled,
.fill_custom_report = scmi_imx_misc_ctrl_fill_custom_report,
};
static const struct scmi_event scmi_imx_misc_events[] = {
{
.id = SCMI_EVENT_IMX_MISC_CONTROL,
.max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld),
.max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report),
},
};
static struct scmi_protocol_events scmi_imx_misc_protocol_events = {
.queue_sz = SCMI_PROTO_QUEUE_SZ,
.ops = &scmi_imx_misc_event_ops,
.evts = scmi_imx_misc_events,
.num_events = ARRAY_SIZE(scmi_imx_misc_events),
.num_sources = MAX_MISC_CTRL_SOURCES,
};
static int scmi_imx_misc_ctrl_get(const struct scmi_protocol_handle *ph,
u32 ctrl_id, u32 *num, u32 *val)
{
struct scmi_imx_misc_ctrl_get_out *out;
struct scmi_xfer *t;
int ret, i;
int max_msg_size = ph->hops->get_max_msg_size(ph);
int max_num = (max_msg_size - sizeof(*out)) / sizeof(__le32);
ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);
if (ret)
return ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_GET, sizeof(u32),
0, &t);
if (ret)
return ret;
put_unaligned_le32(ctrl_id, t->tx.buf);
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
out = t->rx.buf;
*num = le32_to_cpu(out->num);
if (*num >= max_num ||
*num * sizeof(__le32) > t->rx.len - sizeof(__le32)) {
ph->xops->xfer_put(ph, t);
return -EINVAL;
}
for (i = 0; i < *num; i++)
val[i] = le32_to_cpu(out->val[i]);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_misc_ctrl_set(const struct scmi_protocol_handle *ph,
u32 ctrl_id, u32 num, u32 *val)
{
struct scmi_imx_misc_ctrl_set_in *in;
struct scmi_xfer *t;
int ret, i;
int max_msg_size = ph->hops->get_max_msg_size(ph);
int max_num = (max_msg_size - sizeof(*in)) / sizeof(__le32);
ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);
if (ret)
return ret;
if (num > max_num)
return -EINVAL;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET,
sizeof(*in) + num * sizeof(__le32), 0, &t);
if (ret)
return ret;
in = t->tx.buf;
in->id = cpu_to_le32(ctrl_id);
in->num = cpu_to_le32(num);
for (i = 0; i < num; i++)
in->value[i] = cpu_to_le32(val[i]);
ret = ph->xops->do_xfer(ph, t);
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_misc_build_info_discover(const struct scmi_protocol_handle *ph)
{
char date[MISC_MAX_BUILDDATE], time[MISC_MAX_BUILDTIME];
struct scmi_imx_misc_buildinfo_out *out;
struct scmi_xfer *t;
int ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_DISCOVER_BUILD_INFO, 0,
sizeof(*out), &t);
if (ret)
return ret;
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
out = t->rx.buf;
strscpy(date, out->builddate, MISC_MAX_BUILDDATE);
strscpy(time, out->buildtime, MISC_MAX_BUILDTIME);
dev_info(ph->dev, "SM Version\t= Build %u, Commit %08x %s %s\n",
le32_to_cpu(out->buildnum), le32_to_cpu(out->buildcommit),
date, time);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_misc_board_info(const struct scmi_protocol_handle *ph)
{
struct scmi_imx_misc_board_info_out *out;
char name[MISC_MAX_BRDNAME];
struct scmi_xfer *t;
int ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_BOARD_INFO, 0, sizeof(*out), &t);
if (ret)
return ret;
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
out = t->rx.buf;
strscpy(name, out->brdname, MISC_MAX_BRDNAME);
dev_info(ph->dev, "Board\t\t= %s, attr=0x%08x\n",
name, le32_to_cpu(out->attributes));
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_imx_misc_cfg_info_get(const struct scmi_protocol_handle *ph)
{
struct scmi_imx_misc_cfg_info_out *out;
char name[MISC_MAX_CFGNAME];
struct scmi_xfer *t;
int ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CFG_INFO_GET, 0, sizeof(*out), &t);
if (ret)
return ret;
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
out = t->rx.buf;
strscpy(name, out->cfgname, MISC_MAX_CFGNAME);
dev_info(ph->dev, "SM Config\t= %s, mSel = %u\n",
name, le32_to_cpu(out->msel));
}
ph->xops->xfer_put(ph, t);
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 int scmi_imx_misc_reset_reason(const struct scmi_protocol_handle *ph, bool system,
struct scmi_imx_misc_reset_reason *boot_r,
struct scmi_imx_misc_reset_reason *shut_r,
u32 *extinfo)
{
struct scmi_imx_misc_reset_reason_in *in;
struct scmi_imx_misc_reset_reason_out *out;
struct scmi_xfer *t;
int ret;
ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_RESET_REASON_GET, sizeof(*in),
sizeof(*out), &t);
if (ret)
return ret;
in = t->tx.buf;
if (system)
in->flags = le32_encode_bits(1, MISC_REASON_FLAG_SYSTEM);
else
in->flags = cpu_to_le32(0);
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
out = t->rx.buf;
if (boot_r) {
boot_r->valid = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_VLD);
boot_r->orig_valid = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_ORG_VLD);
boot_r->err_valid = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_ERR_VLD);
boot_r->reason = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_REASON);
boot_r->origin = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_ORIGIN);
boot_r->errid = le32_get_bits(out->b_flags, MISC_BOOT_FLAG_ERR_ID);
}
if (shut_r) {
shut_r->valid = le32_get_bits(out->s_flags, MISC_SHUTDOWN_FLAG_VLD);
shut_r->orig_valid = le32_get_bits(out->s_flags,
MISC_SHUTDOWN_FLAG_ORG_VLD);
shut_r->err_valid = le32_get_bits(out->s_flags,
MISC_SHUTDOWN_FLAG_ERR_VLD);
shut_r->reason = le32_get_bits(out->s_flags, MISC_SHUTDOWN_FLAG_REASON);
shut_r->origin = le32_get_bits(out->s_flags, MISC_SHUTDOWN_FLAG_ORIGIN);
shut_r->errid = le32_get_bits(out->s_flags, MISC_SHUTDOWN_FLAG_ERR_ID);
}
if (extinfo)
memcpy_from_le32(extinfo, out->extinfo, MISC_EXT_INFO_LEN_MAX);
}
ph->xops->xfer_put(ph, t);
return ret;
}
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,
.misc_reset_reason = scmi_imx_misc_reset_reason,
};
static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph)
{
struct scmi_imx_misc_info *minfo;
int ret;
dev_info(ph->dev, "NXP SM MISC Version %d.%d\n",
PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));
minfo = devm_kzalloc(ph->dev, sizeof(*minfo), GFP_KERNEL);
if (!minfo)
return -ENOMEM;
ret = scmi_imx_misc_attributes_get(ph, minfo);
if (ret)
return ret;
ret = scmi_imx_misc_build_info_discover(ph);
if (ret && ret != -EOPNOTSUPP)
return ret;
ret = scmi_imx_misc_board_info(ph);
if (ret && ret != -EOPNOTSUPP)
return ret;
ret = scmi_imx_misc_cfg_info_get(ph);
if (ret && ret != -EOPNOTSUPP)
return ret;
return ph->set_priv(ph, minfo);
}
static const struct scmi_protocol scmi_imx_misc = {
.id = SCMI_PROTOCOL_IMX_MISC,
.owner = THIS_MODULE,
.instance_init = &scmi_imx_misc_protocol_init,
.ops = &scmi_imx_misc_proto_ops,
.events = &scmi_imx_misc_protocol_events,
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
.vendor_id = SCMI_IMX_VENDOR,
.sub_vendor_id = SCMI_IMX_SUBVENDOR,
};
module_scmi_protocol(scmi_imx_misc);
MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_MISC) "-" SCMI_IMX_VENDOR);
MODULE_DESCRIPTION("i.MX SCMI MISC driver");
MODULE_LICENSE("GPL");
File diff suppressed because it is too large Load Diff