Message ID | 20240405-imx95-bbm-misc-v2-v2-4-9fc9186856c2@nxp.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | firmware: support i.MX95 SCMI BBM/MISC Extenstion | expand |
Hi Peng, On 24-04-05, Peng Fan (OSS) wrote: > From: Peng Fan <peng.fan@nxp.com> > > The i.MX MISC protocol is for misc settings, such as gpio expander > wakeup. Can you elaborate a bit more please? Regards, Marco > > Signed-off-by: Peng Fan <peng.fan@nxp.com> > --- > drivers/firmware/arm_scmi/Kconfig | 10 ++ > drivers/firmware/arm_scmi/Makefile | 1 + > drivers/firmware/arm_scmi/imx-sm-misc.c | 305 ++++++++++++++++++++++++++++++++ > include/linux/scmi_imx_protocol.h | 17 ++ > 4 files changed, 333 insertions(+) > > diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig > index 56d11c9d9f47..bfeae92f6420 100644 > --- a/drivers/firmware/arm_scmi/Kconfig > +++ b/drivers/firmware/arm_scmi/Kconfig > @@ -191,3 +191,13 @@ config IMX_SCMI_BBM_EXT > and BUTTON. > > This driver can also be built as a module. > + > +config IMX_SCMI_MISC_EXT > + tristate "i.MX SCMI MISC EXTENSION" > + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) > + default y if ARCH_MXC > + help > + This enables i.MX System MISC control logic such as gpio expander > + wakeup > + > + This driver can also be built as a module. > diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile > index 327687acf857..a23fde721222 100644 > --- a/drivers/firmware/arm_scmi/Makefile > +++ b/drivers/firmware/arm_scmi/Makefile > @@ -12,6 +12,7 @@ scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o > scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o > scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o powercap.o > scmi-protocols-$(CONFIG_IMX_SCMI_BBM_EXT) += imx-sm-bbm.o > +scmi-protocols-$(CONFIG_IMX_SCMI_MISC_EXT) += imx-sm-misc.o > scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y) > > obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o > diff --git a/drivers/firmware/arm_scmi/imx-sm-misc.c b/drivers/firmware/arm_scmi/imx-sm-misc.c > new file mode 100644 > index 000000000000..1b0ec2281518 > --- /dev/null > +++ b/drivers/firmware/arm_scmi/imx-sm-misc.c > @@ -0,0 +1,305 @@ > +// 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 > + > +enum scmi_imx_misc_protocol_cmd { > + SCMI_IMX_MISC_CTRL_SET = 0x3, > + SCMI_IMX_MISC_CTRL_GET = 0x4, > + SCMI_IMX_MISC_CTRL_NOTIFY = 0x8, > +}; > + > +struct scmi_imx_misc_info { > + u32 version; > + 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[MISC_MAX_VAL]; > +}; > + > +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; > +}; > + > +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); > + > + 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 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; > + > + ret = scmi_imx_misc_ctrl_notify(ph, src_id, enable ? 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 int scmi_imx_misc_ctrl_get_num_sources(const struct scmi_protocol_handle *ph) > +{ > + return GENMASK(15, 0); > +} > + > +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 = p->ctrl_id; > + r->flags = p->flags; > + *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 = { > + .get_num_sources = scmi_imx_misc_ctrl_get_num_sources, > + .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_DISABLED, > + .max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld), > + .max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report), > + }, > + { > + .id = SCMI_EVENT_IMX_MISC_CONTROL_FALLING_EDGE, > + .max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld), > + .max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report), > + }, > + { > + .id = SCMI_EVENT_IMX_MISC_CONTROL_RISING_EDGE, > + .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), > +}; > + > +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)); > + > + 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; > + > + return ph->set_priv(ph, minfo, version); > +} > + > +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; > + > + 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); > + for (i = 0; i < *num && i < MISC_MAX_VAL; 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; > + > + ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id); > + if (ret) > + return ret; > + > + if (num > MISC_MAX_VAL) > + return -EINVAL; > + > + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET, sizeof(*in), > + 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 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, > +}; > + > +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, > +}; > +module_scmi_protocol(scmi_imx_misc); > diff --git a/include/linux/scmi_imx_protocol.h b/include/linux/scmi_imx_protocol.h > index 90ce011a4429..a69bd4a20f0f 100644 > --- a/include/linux/scmi_imx_protocol.h > +++ b/include/linux/scmi_imx_protocol.h > @@ -13,8 +13,14 @@ > #include <linux/notifier.h> > #include <linux/types.h> > > +#define SCMI_PAYLOAD_LEN 100 > + > +#define SCMI_ARRAY(X, Y) ((SCMI_PAYLOAD_LEN - (X)) / sizeof(Y)) > +#define MISC_MAX_VAL SCMI_ARRAY(8, uint32_t) > + > enum scmi_nxp_protocol { > SCMI_PROTOCOL_IMX_BBM = 0x81, > + SCMI_PROTOCOL_IMX_MISC = 0x84, > }; > > struct scmi_imx_bbm_proto_ops { > @@ -42,4 +48,15 @@ struct scmi_imx_bbm_notif_report { > unsigned int rtc_id; > unsigned int rtc_evt; > }; > + > +struct scmi_imx_misc_ctrl_notify_report { > + ktime_t timestamp; > + unsigned int ctrl_id; > + unsigned int flags; > +}; > + > +struct scmi_imx_misc_proto_ops { > + int (*misc_ctrl_set)(const struct scmi_protocol_handle *ph, u32 id, u32 num, u32 *val); > + int (*misc_ctrl_get)(const struct scmi_protocol_handle *ph, u32 id, u32 *num, u32 *val); > +}; > #endif > > -- > 2.37.1 > > >
> Subject: Re: [PATCH v2 4/6] firmware: arm_scmi: add initial support for i.MX > MISC protocol > > Hi Peng, > > On 24-04-05, Peng Fan (OSS) wrote: > > From: Peng Fan <peng.fan@nxp.com> > > > > The i.MX MISC protocol is for misc settings, such as gpio expander > > wakeup. > > Can you elaborate a bit more please? The gpio expander is under M33(SCMI firmware used core) I2C control, But the gpio expander supports board function such as PCIE_WAKEUP, BTN_WAKEUP. So these are managed by MISC protocol. SAI_CLK_MSEL in WAKEUP BLK CTRL is also managed by MISC Protocol. And etc... I will add more info in commit log in next version later, after I get more reviews on the patchset. Thanks, Peng. > > Regards, > Marco > > > > > > Signed-off-by: Peng Fan <peng.fan@nxp.com> > > --- > > drivers/firmware/arm_scmi/Kconfig | 10 ++ > > drivers/firmware/arm_scmi/Makefile | 1 + > > drivers/firmware/arm_scmi/imx-sm-misc.c | 305 > ++++++++++++++++++++++++++++++++ > > include/linux/scmi_imx_protocol.h | 17 ++ > > 4 files changed, 333 insertions(+) > > > > diff --git a/drivers/firmware/arm_scmi/Kconfig > > b/drivers/firmware/arm_scmi/Kconfig > > index 56d11c9d9f47..bfeae92f6420 100644 > > --- a/drivers/firmware/arm_scmi/Kconfig > > +++ b/drivers/firmware/arm_scmi/Kconfig > > @@ -191,3 +191,13 @@ config IMX_SCMI_BBM_EXT > > and BUTTON. > > > > This driver can also be built as a module. > > + > > +config IMX_SCMI_MISC_EXT > > + tristate "i.MX SCMI MISC EXTENSION" > > + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) > > + default y if ARCH_MXC > > + help > > + This enables i.MX System MISC control logic such as gpio expander > > + wakeup > > + > > + This driver can also be built as a module. > > diff --git a/drivers/firmware/arm_scmi/Makefile > > b/drivers/firmware/arm_scmi/Makefile > > index 327687acf857..a23fde721222 100644 > > --- a/drivers/firmware/arm_scmi/Makefile > > +++ b/drivers/firmware/arm_scmi/Makefile > > @@ -12,6 +12,7 @@ scmi-transport- > $(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) > > += virtio.o > > scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o > > scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o > > system.o voltage.o powercap.o > > scmi-protocols-$(CONFIG_IMX_SCMI_BBM_EXT) += imx-sm-bbm.o > > +scmi-protocols-$(CONFIG_IMX_SCMI_MISC_EXT) += imx-sm-misc.o > > scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) > > $(scmi-transport-y) > > > > obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o diff --git > > a/drivers/firmware/arm_scmi/imx-sm-misc.c > > b/drivers/firmware/arm_scmi/imx-sm-misc.c > > new file mode 100644 > > index 000000000000..1b0ec2281518 > > --- /dev/null > > +++ b/drivers/firmware/arm_scmi/imx-sm-misc.c > > @@ -0,0 +1,305 @@ > > +// 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 > > + > > +enum scmi_imx_misc_protocol_cmd { > > + SCMI_IMX_MISC_CTRL_SET = 0x3, > > + SCMI_IMX_MISC_CTRL_GET = 0x4, > > + SCMI_IMX_MISC_CTRL_NOTIFY = 0x8, > > +}; > > + > > +struct scmi_imx_misc_info { > > + u32 version; > > + 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[MISC_MAX_VAL]; > > +}; > > + > > +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; > > +}; > > + > > +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); > > + > > + 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 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; > > + > > + ret = scmi_imx_misc_ctrl_notify(ph, src_id, enable ? 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 int scmi_imx_misc_ctrl_get_num_sources(const struct > > +scmi_protocol_handle *ph) { > > + return GENMASK(15, 0); > > +} > > + > > +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 = p->ctrl_id; > > + r->flags = p->flags; > > + *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 = { > > + .get_num_sources = scmi_imx_misc_ctrl_get_num_sources, > > + .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_DISABLED, > > + .max_payld_sz = sizeof(struct > scmi_imx_misc_ctrl_notify_payld), > > + .max_report_sz = sizeof(struct > scmi_imx_misc_ctrl_notify_report), > > + }, > > + { > > + .id = SCMI_EVENT_IMX_MISC_CONTROL_FALLING_EDGE, > > + .max_payld_sz = sizeof(struct > scmi_imx_misc_ctrl_notify_payld), > > + .max_report_sz = sizeof(struct > scmi_imx_misc_ctrl_notify_report), > > + }, > > + { > > + .id = SCMI_EVENT_IMX_MISC_CONTROL_RISING_EDGE, > > + .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), }; > > + > > +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)); > > + > > + 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; > > + > > + return ph->set_priv(ph, minfo, version); } > > + > > +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; > > + > > + 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); > > + for (i = 0; i < *num && i < MISC_MAX_VAL; 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; > > + > > + ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id); > > + if (ret) > > + return ret; > > + > > + if (num > MISC_MAX_VAL) > > + return -EINVAL; > > + > > + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET, > sizeof(*in), > > + 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 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, }; > > + > > +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, }; > > +module_scmi_protocol(scmi_imx_misc); > > diff --git a/include/linux/scmi_imx_protocol.h > > b/include/linux/scmi_imx_protocol.h > > index 90ce011a4429..a69bd4a20f0f 100644 > > --- a/include/linux/scmi_imx_protocol.h > > +++ b/include/linux/scmi_imx_protocol.h > > @@ -13,8 +13,14 @@ > > #include <linux/notifier.h> > > #include <linux/types.h> > > > > +#define SCMI_PAYLOAD_LEN 100 > > + > > +#define SCMI_ARRAY(X, Y) ((SCMI_PAYLOAD_LEN - (X)) / sizeof(Y)) > > +#define MISC_MAX_VAL SCMI_ARRAY(8, uint32_t) > > + > > enum scmi_nxp_protocol { > > SCMI_PROTOCOL_IMX_BBM = 0x81, > > + SCMI_PROTOCOL_IMX_MISC = 0x84, > > }; > > > > struct scmi_imx_bbm_proto_ops { > > @@ -42,4 +48,15 @@ struct scmi_imx_bbm_notif_report { > > unsigned int rtc_id; > > unsigned int rtc_evt; > > }; > > + > > +struct scmi_imx_misc_ctrl_notify_report { > > + ktime_t timestamp; > > + unsigned int ctrl_id; > > + unsigned int flags; > > +}; > > + > > +struct scmi_imx_misc_proto_ops { > > + int (*misc_ctrl_set)(const struct scmi_protocol_handle *ph, u32 id, > u32 num, u32 *val); > > + int (*misc_ctrl_get)(const struct scmi_protocol_handle *ph, u32 id, > > +u32 *num, u32 *val); }; > > #endif > > > > -- > > 2.37.1 > > > > > >
Hi Peng, On 24-04-07, Peng Fan wrote: > > Subject: Re: [PATCH v2 4/6] firmware: arm_scmi: add initial support for i.MX > > MISC protocol > > > > Hi Peng, > > > > On 24-04-05, Peng Fan (OSS) wrote: > > > From: Peng Fan <peng.fan@nxp.com> > > > > > > The i.MX MISC protocol is for misc settings, such as gpio expander > > > wakeup. > > > > Can you elaborate a bit more please? > > The gpio expander is under M33(SCMI firmware used core) I2C control, Due to missing technical references I guess that your specific EVK has an i2c-expander connected to the system-critical-i2c bus? The system-critical-i2c should be only used for system critical topics like PMIC control. > But the gpio expander supports board function such as PCIE_WAKEUP, > BTN_WAKEUP. So these are managed by MISC protocol. This seems more like an specific i.MX95-EVK problem too me since you have conneccted the i2c-gpio-expander to the system-critical-i2c bus instead of using an bus available within Linux. Also can you please provide me a link with the propsoal for the MISC protocol? I can't find any references within the SCMI v3.2 https://developer.arm.com/documentation/den0056/e/ nor within the SCP firmware git: https://github.com/ARM-software/SCP-firmware. > SAI_CLK_MSEL in WAKEUP BLK CTRL is also managed by MISC Protocol. You recently said that we need blk-ctrl drivers for managing/controlling the GPR stuff within Linux since the SCMI firmware does not support this. Now blk-ctrl GPR control is supported by the firmware? Regards, Marco > > And etc... > > I will add more info in commit log in next version later, after I get more > reviews on the patchset. > > Thanks, > Peng. > > > > > Regards, > > Marco > > > > > > > > > > Signed-off-by: Peng Fan <peng.fan@nxp.com> > > > --- > > > drivers/firmware/arm_scmi/Kconfig | 10 ++ > > > drivers/firmware/arm_scmi/Makefile | 1 + > > > drivers/firmware/arm_scmi/imx-sm-misc.c | 305 > > ++++++++++++++++++++++++++++++++ > > > include/linux/scmi_imx_protocol.h | 17 ++ > > > 4 files changed, 333 insertions(+) > > > > > > diff --git a/drivers/firmware/arm_scmi/Kconfig > > > b/drivers/firmware/arm_scmi/Kconfig > > > index 56d11c9d9f47..bfeae92f6420 100644 > > > --- a/drivers/firmware/arm_scmi/Kconfig > > > +++ b/drivers/firmware/arm_scmi/Kconfig > > > @@ -191,3 +191,13 @@ config IMX_SCMI_BBM_EXT > > > and BUTTON. > > > > > > This driver can also be built as a module. > > > + > > > +config IMX_SCMI_MISC_EXT > > > + tristate "i.MX SCMI MISC EXTENSION" > > > + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) > > > + default y if ARCH_MXC > > > + help > > > + This enables i.MX System MISC control logic such as gpio expander > > > + wakeup > > > + > > > + This driver can also be built as a module. > > > diff --git a/drivers/firmware/arm_scmi/Makefile > > > b/drivers/firmware/arm_scmi/Makefile > > > index 327687acf857..a23fde721222 100644 > > > --- a/drivers/firmware/arm_scmi/Makefile > > > +++ b/drivers/firmware/arm_scmi/Makefile > > > @@ -12,6 +12,7 @@ scmi-transport- > > $(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) > > > += virtio.o > > > scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o > > > scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o > > > system.o voltage.o powercap.o > > > scmi-protocols-$(CONFIG_IMX_SCMI_BBM_EXT) += imx-sm-bbm.o > > > +scmi-protocols-$(CONFIG_IMX_SCMI_MISC_EXT) += imx-sm-misc.o > > > scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) > > > $(scmi-transport-y) > > > > > > obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o diff --git > > > a/drivers/firmware/arm_scmi/imx-sm-misc.c > > > b/drivers/firmware/arm_scmi/imx-sm-misc.c > > > new file mode 100644 > > > index 000000000000..1b0ec2281518 > > > --- /dev/null > > > +++ b/drivers/firmware/arm_scmi/imx-sm-misc.c > > > @@ -0,0 +1,305 @@ > > > +// 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 > > > + > > > +enum scmi_imx_misc_protocol_cmd { > > > + SCMI_IMX_MISC_CTRL_SET = 0x3, > > > + SCMI_IMX_MISC_CTRL_GET = 0x4, > > > + SCMI_IMX_MISC_CTRL_NOTIFY = 0x8, > > > +}; > > > + > > > +struct scmi_imx_misc_info { > > > + u32 version; > > > + 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[MISC_MAX_VAL]; > > > +}; > > > + > > > +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; > > > +}; > > > + > > > +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); > > > + > > > + 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 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; > > > + > > > + ret = scmi_imx_misc_ctrl_notify(ph, src_id, enable ? 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 int scmi_imx_misc_ctrl_get_num_sources(const struct > > > +scmi_protocol_handle *ph) { > > > + return GENMASK(15, 0); > > > +} > > > + > > > +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 = p->ctrl_id; > > > + r->flags = p->flags; > > > + *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 = { > > > + .get_num_sources = scmi_imx_misc_ctrl_get_num_sources, > > > + .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_DISABLED, > > > + .max_payld_sz = sizeof(struct > > scmi_imx_misc_ctrl_notify_payld), > > > + .max_report_sz = sizeof(struct > > scmi_imx_misc_ctrl_notify_report), > > > + }, > > > + { > > > + .id = SCMI_EVENT_IMX_MISC_CONTROL_FALLING_EDGE, > > > + .max_payld_sz = sizeof(struct > > scmi_imx_misc_ctrl_notify_payld), > > > + .max_report_sz = sizeof(struct > > scmi_imx_misc_ctrl_notify_report), > > > + }, > > > + { > > > + .id = SCMI_EVENT_IMX_MISC_CONTROL_RISING_EDGE, > > > + .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), }; > > > + > > > +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)); > > > + > > > + 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; > > > + > > > + return ph->set_priv(ph, minfo, version); } > > > + > > > +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; > > > + > > > + 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); > > > + for (i = 0; i < *num && i < MISC_MAX_VAL; 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; > > > + > > > + ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id); > > > + if (ret) > > > + return ret; > > > + > > > + if (num > MISC_MAX_VAL) > > > + return -EINVAL; > > > + > > > + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET, > > sizeof(*in), > > > + 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 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, }; > > > + > > > +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, }; > > > +module_scmi_protocol(scmi_imx_misc); > > > diff --git a/include/linux/scmi_imx_protocol.h > > > b/include/linux/scmi_imx_protocol.h > > > index 90ce011a4429..a69bd4a20f0f 100644 > > > --- a/include/linux/scmi_imx_protocol.h > > > +++ b/include/linux/scmi_imx_protocol.h > > > @@ -13,8 +13,14 @@ > > > #include <linux/notifier.h> > > > #include <linux/types.h> > > > > > > +#define SCMI_PAYLOAD_LEN 100 > > > + > > > +#define SCMI_ARRAY(X, Y) ((SCMI_PAYLOAD_LEN - (X)) / sizeof(Y)) > > > +#define MISC_MAX_VAL SCMI_ARRAY(8, uint32_t) > > > + > > > enum scmi_nxp_protocol { > > > SCMI_PROTOCOL_IMX_BBM = 0x81, > > > + SCMI_PROTOCOL_IMX_MISC = 0x84, > > > }; > > > > > > struct scmi_imx_bbm_proto_ops { > > > @@ -42,4 +48,15 @@ struct scmi_imx_bbm_notif_report { > > > unsigned int rtc_id; > > > unsigned int rtc_evt; > > > }; > > > + > > > +struct scmi_imx_misc_ctrl_notify_report { > > > + ktime_t timestamp; > > > + unsigned int ctrl_id; > > > + unsigned int flags; > > > +}; > > > + > > > +struct scmi_imx_misc_proto_ops { > > > + int (*misc_ctrl_set)(const struct scmi_protocol_handle *ph, u32 id, > > u32 num, u32 *val); > > > + int (*misc_ctrl_get)(const struct scmi_protocol_handle *ph, u32 id, > > > +u32 *num, u32 *val); }; > > > #endif > > > > > > -- > > > 2.37.1 > > > > > > > > > >
> Subject: Re: [PATCH v2 4/6] firmware: arm_scmi: add initial support for i.MX > MISC protocol > > Hi Peng, > > On 24-04-07, Peng Fan wrote: > > > Subject: Re: [PATCH v2 4/6] firmware: arm_scmi: add initial support > > > for i.MX MISC protocol > > > > > > Hi Peng, > > > > > > On 24-04-05, Peng Fan (OSS) wrote: > > > > From: Peng Fan <peng.fan@nxp.com> > > > > > > > > The i.MX MISC protocol is for misc settings, such as gpio expander > > > > wakeup. > > > > > > Can you elaborate a bit more please? > > > > The gpio expander is under M33(SCMI firmware used core) I2C control, > > Due to missing technical references I guess that your specific EVK has an i2c- > expander connected to the system-critical-i2c bus? The system-critical-i2c > should be only used for system critical topics like PMIC control. Right. > > > But the gpio expander supports board function such as PCIE_WAKEUP, > > BTN_WAKEUP. So these are managed by MISC protocol. > > This seems more like an specific i.MX95-EVK problem too me since you have > conneccted the i2c-gpio-expander to the system-critical-i2c bus instead of > using an bus available within Linux. Also can you please provide me a link > with the propsoal for the MISC protocol? I can't find any references within the > SCMI v3.2 It is i.MX VENDOR Extension, not a standard one in Spec. > https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdevelo > per.arm.com%2Fdocumentation%2Fden0056%2Fe%2F&data=05%7C02%7Cp > eng.fan%40nxp.com%7C6120357a772045a0618808dc56f22c95%7C686ea1d > 3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C638480845336536607%7CUnk > nown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik > 1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=NI%2F8WMPuGzJwD74 > 1jcuknHZUR5uI2me9iEeWbeDKshE%3D&reserved=0 nor within the SCP > firmware git: > https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub > .com%2FARM-software%2FSCP- > firmware&data=05%7C02%7Cpeng.fan%40nxp.com%7C6120357a772045a06 > 18808dc56f22c95%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C > 638480845336550459%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAw > MDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C > &sdata=N3bT9ItgvL4Z9xP1oxlmDTG%2FFjsXkuhJIA9wooJWfcM%3D&reserve > d=0. > > > SAI_CLK_MSEL in WAKEUP BLK CTRL is also managed by MISC Protocol. > > You recently said that we need blk-ctrl drivers for managing/controlling the > GPR stuff within Linux since the SCMI firmware does not support this. Now > blk-ctrl GPR control is supported by the firmware? AONMIX/WAKEUPMIX BLK CTRL is managed by SCMI firmware, for other non system critical BLK CTRLs, they are managed by Linux directly, such as GPU/VPU BLK CTRL and etc. Regards, Peng. > > Regards, > Marco > > > > > And etc... > > > > I will add more info in commit log in next version later, after I get > > more reviews on the patchset. > > > > Thanks, > > Peng. > > > > > > > > Regards, > > > Marco > > > > > > > > > > > > > > Signed-off-by: Peng Fan <peng.fan@nxp.com> > > > > --- > > > > drivers/firmware/arm_scmi/Kconfig | 10 ++ > > > > drivers/firmware/arm_scmi/Makefile | 1 + > > > > drivers/firmware/arm_scmi/imx-sm-misc.c | 305 > > > ++++++++++++++++++++++++++++++++ > > > > include/linux/scmi_imx_protocol.h | 17 ++ > > > > 4 files changed, 333 insertions(+) > > > > > > > > diff --git a/drivers/firmware/arm_scmi/Kconfig > > > > b/drivers/firmware/arm_scmi/Kconfig > > > > index 56d11c9d9f47..bfeae92f6420 100644 > > > > --- a/drivers/firmware/arm_scmi/Kconfig > > > > +++ b/drivers/firmware/arm_scmi/Kconfig > > > > @@ -191,3 +191,13 @@ config IMX_SCMI_BBM_EXT > > > > and BUTTON. > > > > > > > > This driver can also be built as a module. > > > > + > > > > +config IMX_SCMI_MISC_EXT > > > > + tristate "i.MX SCMI MISC EXTENSION" > > > > + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) > > > > + default y if ARCH_MXC > > > > + help > > > > + This enables i.MX System MISC control logic such as gpio expander > > > > + wakeup > > > > + > > > > + This driver can also be built as a module. > > > > diff --git a/drivers/firmware/arm_scmi/Makefile > > > > b/drivers/firmware/arm_scmi/Makefile > > > > index 327687acf857..a23fde721222 100644 > > > > --- a/drivers/firmware/arm_scmi/Makefile > > > > +++ b/drivers/firmware/arm_scmi/Makefile > > > > @@ -12,6 +12,7 @@ scmi-transport- > > > $(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) > > > > += virtio.o > > > > scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o > > > > scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o > > > > system.o voltage.o powercap.o > > > > scmi-protocols-$(CONFIG_IMX_SCMI_BBM_EXT) += imx-sm-bbm.o > > > > +scmi-protocols-$(CONFIG_IMX_SCMI_MISC_EXT) += imx-sm-misc.o > > > > scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) > > > > $(scmi-transport-y) > > > > > > > > obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o diff --git > > > > a/drivers/firmware/arm_scmi/imx-sm-misc.c > > > > b/drivers/firmware/arm_scmi/imx-sm-misc.c > > > > new file mode 100644 > > > > index 000000000000..1b0ec2281518 > > > > --- /dev/null > > > > +++ b/drivers/firmware/arm_scmi/imx-sm-misc.c > > > > @@ -0,0 +1,305 @@ > > > > +// 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 > > > > + > > > > +enum scmi_imx_misc_protocol_cmd { > > > > + SCMI_IMX_MISC_CTRL_SET = 0x3, > > > > + SCMI_IMX_MISC_CTRL_GET = 0x4, > > > > + SCMI_IMX_MISC_CTRL_NOTIFY = 0x8, }; > > > > + > > > > +struct scmi_imx_misc_info { > > > > + u32 version; > > > > + 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[MISC_MAX_VAL]; > > > > +}; > > > > + > > > > +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; > > > > +}; > > > > + > > > > +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); > > > > + > > > > + 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 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; > > > > + > > > > + ret = scmi_imx_misc_ctrl_notify(ph, src_id, enable ? 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 int scmi_imx_misc_ctrl_get_num_sources(const struct > > > > +scmi_protocol_handle *ph) { > > > > + return GENMASK(15, 0); > > > > +} > > > > + > > > > +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 = p->ctrl_id; > > > > + r->flags = p->flags; > > > > + *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 = { > > > > + .get_num_sources = scmi_imx_misc_ctrl_get_num_sources, > > > > + .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_DISABLED, > > > > + .max_payld_sz = sizeof(struct > > > scmi_imx_misc_ctrl_notify_payld), > > > > + .max_report_sz = sizeof(struct > > > scmi_imx_misc_ctrl_notify_report), > > > > + }, > > > > + { > > > > + .id = SCMI_EVENT_IMX_MISC_CONTROL_FALLING_EDGE, > > > > + .max_payld_sz = sizeof(struct > > > scmi_imx_misc_ctrl_notify_payld), > > > > + .max_report_sz = sizeof(struct > > > scmi_imx_misc_ctrl_notify_report), > > > > + }, > > > > + { > > > > + .id = SCMI_EVENT_IMX_MISC_CONTROL_RISING_EDGE, > > > > + .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), }; > > > > + > > > > +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)); > > > > + > > > > + 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; > > > > + > > > > + return ph->set_priv(ph, minfo, version); } > > > > + > > > > +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; > > > > + > > > > + 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); > > > > + for (i = 0; i < *num && i < MISC_MAX_VAL; 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; > > > > + > > > > + ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id); > > > > + if (ret) > > > > + return ret; > > > > + > > > > + if (num > MISC_MAX_VAL) > > > > + return -EINVAL; > > > > + > > > > + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET, > > > sizeof(*in), > > > > + 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 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, }; > > > > + > > > > +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, }; > > > > +module_scmi_protocol(scmi_imx_misc); > > > > diff --git a/include/linux/scmi_imx_protocol.h > > > > b/include/linux/scmi_imx_protocol.h > > > > index 90ce011a4429..a69bd4a20f0f 100644 > > > > --- a/include/linux/scmi_imx_protocol.h > > > > +++ b/include/linux/scmi_imx_protocol.h > > > > @@ -13,8 +13,14 @@ > > > > #include <linux/notifier.h> > > > > #include <linux/types.h> > > > > > > > > +#define SCMI_PAYLOAD_LEN 100 > > > > + > > > > +#define SCMI_ARRAY(X, Y) ((SCMI_PAYLOAD_LEN - (X)) / sizeof(Y)) > > > > +#define MISC_MAX_VAL SCMI_ARRAY(8, uint32_t) > > > > + > > > > enum scmi_nxp_protocol { > > > > SCMI_PROTOCOL_IMX_BBM = 0x81, > > > > + SCMI_PROTOCOL_IMX_MISC = 0x84, > > > > }; > > > > > > > > struct scmi_imx_bbm_proto_ops { > > > > @@ -42,4 +48,15 @@ struct scmi_imx_bbm_notif_report { > > > > unsigned int rtc_id; > > > > unsigned int rtc_evt; > > > > }; > > > > + > > > > +struct scmi_imx_misc_ctrl_notify_report { > > > > + ktime_t timestamp; > > > > + unsigned int ctrl_id; > > > > + unsigned int flags; > > > > +}; > > > > + > > > > +struct scmi_imx_misc_proto_ops { > > > > + int (*misc_ctrl_set)(const struct scmi_protocol_handle *ph, u32 > > > > +id, > > > u32 num, u32 *val); > > > > + int (*misc_ctrl_get)(const struct scmi_protocol_handle *ph, u32 > > > > +id, > > > > +u32 *num, u32 *val); }; > > > > #endif > > > > > > > > -- > > > > 2.37.1 > > > > > > > > > > > > > >
diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index 56d11c9d9f47..bfeae92f6420 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -191,3 +191,13 @@ config IMX_SCMI_BBM_EXT and BUTTON. This driver can also be built as a module. + +config IMX_SCMI_MISC_EXT + tristate "i.MX SCMI MISC EXTENSION" + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) + default y if ARCH_MXC + help + This enables i.MX System MISC control logic such as gpio expander + wakeup + + This driver can also be built as a module. diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 327687acf857..a23fde721222 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -12,6 +12,7 @@ scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_VIRTIO) += virtio.o scmi-transport-$(CONFIG_ARM_SCMI_TRANSPORT_OPTEE) += optee.o scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o voltage.o powercap.o scmi-protocols-$(CONFIG_IMX_SCMI_BBM_EXT) += imx-sm-bbm.o +scmi-protocols-$(CONFIG_IMX_SCMI_MISC_EXT) += imx-sm-misc.o scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y) obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o diff --git a/drivers/firmware/arm_scmi/imx-sm-misc.c b/drivers/firmware/arm_scmi/imx-sm-misc.c new file mode 100644 index 000000000000..1b0ec2281518 --- /dev/null +++ b/drivers/firmware/arm_scmi/imx-sm-misc.c @@ -0,0 +1,305 @@ +// 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 + +enum scmi_imx_misc_protocol_cmd { + SCMI_IMX_MISC_CTRL_SET = 0x3, + SCMI_IMX_MISC_CTRL_GET = 0x4, + SCMI_IMX_MISC_CTRL_NOTIFY = 0x8, +}; + +struct scmi_imx_misc_info { + u32 version; + 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[MISC_MAX_VAL]; +}; + +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; +}; + +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); + + 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 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; + + ret = scmi_imx_misc_ctrl_notify(ph, src_id, enable ? 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 int scmi_imx_misc_ctrl_get_num_sources(const struct scmi_protocol_handle *ph) +{ + return GENMASK(15, 0); +} + +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 = p->ctrl_id; + r->flags = p->flags; + *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 = { + .get_num_sources = scmi_imx_misc_ctrl_get_num_sources, + .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_DISABLED, + .max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld), + .max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report), + }, + { + .id = SCMI_EVENT_IMX_MISC_CONTROL_FALLING_EDGE, + .max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld), + .max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report), + }, + { + .id = SCMI_EVENT_IMX_MISC_CONTROL_RISING_EDGE, + .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), +}; + +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)); + + 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; + + return ph->set_priv(ph, minfo, version); +} + +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; + + 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); + for (i = 0; i < *num && i < MISC_MAX_VAL; 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; + + ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id); + if (ret) + return ret; + + if (num > MISC_MAX_VAL) + return -EINVAL; + + ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET, sizeof(*in), + 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 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, +}; + +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, +}; +module_scmi_protocol(scmi_imx_misc); diff --git a/include/linux/scmi_imx_protocol.h b/include/linux/scmi_imx_protocol.h index 90ce011a4429..a69bd4a20f0f 100644 --- a/include/linux/scmi_imx_protocol.h +++ b/include/linux/scmi_imx_protocol.h @@ -13,8 +13,14 @@ #include <linux/notifier.h> #include <linux/types.h> +#define SCMI_PAYLOAD_LEN 100 + +#define SCMI_ARRAY(X, Y) ((SCMI_PAYLOAD_LEN - (X)) / sizeof(Y)) +#define MISC_MAX_VAL SCMI_ARRAY(8, uint32_t) + enum scmi_nxp_protocol { SCMI_PROTOCOL_IMX_BBM = 0x81, + SCMI_PROTOCOL_IMX_MISC = 0x84, }; struct scmi_imx_bbm_proto_ops { @@ -42,4 +48,15 @@ struct scmi_imx_bbm_notif_report { unsigned int rtc_id; unsigned int rtc_evt; }; + +struct scmi_imx_misc_ctrl_notify_report { + ktime_t timestamp; + unsigned int ctrl_id; + unsigned int flags; +}; + +struct scmi_imx_misc_proto_ops { + int (*misc_ctrl_set)(const struct scmi_protocol_handle *ph, u32 id, u32 num, u32 *val); + int (*misc_ctrl_get)(const struct scmi_protocol_handle *ph, u32 id, u32 *num, u32 *val); +}; #endif