Path: blob/master/drivers/firmware/arm_scmi/vendors/imx/imx-sm-bbm.c
26498 views
// SPDX-License-Identifier: GPL-2.01/*2* System Control and Management Interface (SCMI) NXP BBM Protocol3*4* Copyright 2024 NXP5*/67#define pr_fmt(fmt) "SCMI Notifications BBM - " fmt89#include <linux/bits.h>10#include <linux/io.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/platform_device.h>14#include <linux/scmi_protocol.h>15#include <linux/scmi_imx_protocol.h>1617#include "../../protocols.h"18#include "../../notify.h"1920#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x100002122enum scmi_imx_bbm_protocol_cmd {23IMX_BBM_GPR_SET = 0x3,24IMX_BBM_GPR_GET = 0x4,25IMX_BBM_RTC_ATTRIBUTES = 0x5,26IMX_BBM_RTC_TIME_SET = 0x6,27IMX_BBM_RTC_TIME_GET = 0x7,28IMX_BBM_RTC_ALARM_SET = 0x8,29IMX_BBM_BUTTON_GET = 0x9,30IMX_BBM_RTC_NOTIFY = 0xA,31IMX_BBM_BUTTON_NOTIFY = 0xB,32};3334#define GET_RTCS_NR(x) le32_get_bits((x), GENMASK(23, 16))35#define GET_GPRS_NR(x) le32_get_bits((x), GENMASK(15, 0))3637#define SCMI_IMX_BBM_NOTIFY_RTC_UPDATED BIT(2)38#define SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER BIT(1)39#define SCMI_IMX_BBM_NOTIFY_RTC_ALARM BIT(0)4041#define SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG BIT(0)4243#define SCMI_IMX_BBM_NOTIFY_RTC_FLAG \44(SCMI_IMX_BBM_NOTIFY_RTC_UPDATED | SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER | \45SCMI_IMX_BBM_NOTIFY_RTC_ALARM)4647#define SCMI_IMX_BBM_EVENT_RTC_MASK GENMASK(31, 24)4849struct scmi_imx_bbm_info {50u32 version;51int nr_rtc;52int nr_gpr;53};5455struct scmi_msg_imx_bbm_protocol_attributes {56__le32 attributes;57};5859struct scmi_imx_bbm_set_time {60__le32 id;61__le32 flags;62__le32 value_low;63__le32 value_high;64};6566struct scmi_imx_bbm_get_time {67__le32 id;68__le32 flags;69};7071struct scmi_imx_bbm_alarm_time {72__le32 id;73__le32 flags;74__le32 value_low;75__le32 value_high;76};7778struct scmi_msg_imx_bbm_rtc_notify {79__le32 rtc_id;80__le32 flags;81};8283struct scmi_msg_imx_bbm_button_notify {84__le32 flags;85};8687struct scmi_imx_bbm_notify_payld {88__le32 flags;89};9091static int scmi_imx_bbm_attributes_get(const struct scmi_protocol_handle *ph,92struct scmi_imx_bbm_info *pi)93{94int ret;95struct scmi_xfer *t;96struct scmi_msg_imx_bbm_protocol_attributes *attr;9798ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, sizeof(*attr), &t);99if (ret)100return ret;101102attr = t->rx.buf;103104ret = ph->xops->do_xfer(ph, t);105if (!ret) {106pi->nr_rtc = GET_RTCS_NR(attr->attributes);107pi->nr_gpr = GET_GPRS_NR(attr->attributes);108}109110ph->xops->xfer_put(ph, t);111112return ret;113}114115static int scmi_imx_bbm_notify(const struct scmi_protocol_handle *ph,116u32 src_id, int message_id, bool enable)117{118int ret;119struct scmi_xfer *t;120121if (message_id == IMX_BBM_RTC_NOTIFY) {122struct scmi_msg_imx_bbm_rtc_notify *rtc_notify;123124ret = ph->xops->xfer_get_init(ph, message_id,125sizeof(*rtc_notify), 0, &t);126if (ret)127return ret;128129rtc_notify = t->tx.buf;130rtc_notify->rtc_id = cpu_to_le32(0);131rtc_notify->flags =132cpu_to_le32(enable ? SCMI_IMX_BBM_NOTIFY_RTC_FLAG : 0);133} else if (message_id == IMX_BBM_BUTTON_NOTIFY) {134struct scmi_msg_imx_bbm_button_notify *button_notify;135136ret = ph->xops->xfer_get_init(ph, message_id,137sizeof(*button_notify), 0, &t);138if (ret)139return ret;140141button_notify = t->tx.buf;142button_notify->flags = cpu_to_le32(enable ? 1 : 0);143} else {144return -EINVAL;145}146147ret = ph->xops->do_xfer(ph, t);148149ph->xops->xfer_put(ph, t);150return ret;151}152153static enum scmi_imx_bbm_protocol_cmd evt_2_cmd[] = {154IMX_BBM_RTC_NOTIFY,155IMX_BBM_BUTTON_NOTIFY156};157158static int scmi_imx_bbm_set_notify_enabled(const struct scmi_protocol_handle *ph,159u8 evt_id, u32 src_id, bool enable)160{161int ret, cmd_id;162163if (evt_id >= ARRAY_SIZE(evt_2_cmd))164return -EINVAL;165166cmd_id = evt_2_cmd[evt_id];167ret = scmi_imx_bbm_notify(ph, src_id, cmd_id, enable);168if (ret)169pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",170evt_id, src_id, ret);171172return ret;173}174175static void *scmi_imx_bbm_fill_custom_report(const struct scmi_protocol_handle *ph,176u8 evt_id, ktime_t timestamp,177const void *payld, size_t payld_sz,178void *report, u32 *src_id)179{180const struct scmi_imx_bbm_notify_payld *p = payld;181struct scmi_imx_bbm_notif_report *r = report;182183if (sizeof(*p) != payld_sz)184return NULL;185186if (evt_id == SCMI_EVENT_IMX_BBM_RTC) {187r->is_rtc = true;188r->is_button = false;189r->timestamp = timestamp;190r->rtc_id = le32_get_bits(p->flags, SCMI_IMX_BBM_EVENT_RTC_MASK);191r->rtc_evt = le32_get_bits(p->flags, SCMI_IMX_BBM_NOTIFY_RTC_FLAG);192dev_dbg(ph->dev, "RTC: %d evt: %x\n", r->rtc_id, r->rtc_evt);193*src_id = r->rtc_evt;194} else if (evt_id == SCMI_EVENT_IMX_BBM_BUTTON) {195r->is_rtc = false;196r->is_button = true;197r->timestamp = timestamp;198dev_dbg(ph->dev, "BBM Button\n");199*src_id = 0;200} else {201WARN_ON_ONCE(1);202return NULL;203}204205return r;206}207208static const struct scmi_event scmi_imx_bbm_events[] = {209{210.id = SCMI_EVENT_IMX_BBM_RTC,211.max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),212.max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),213},214{215.id = SCMI_EVENT_IMX_BBM_BUTTON,216.max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),217.max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),218},219};220221static const struct scmi_event_ops scmi_imx_bbm_event_ops = {222.set_notify_enabled = scmi_imx_bbm_set_notify_enabled,223.fill_custom_report = scmi_imx_bbm_fill_custom_report,224};225226static const struct scmi_protocol_events scmi_imx_bbm_protocol_events = {227.queue_sz = SCMI_PROTO_QUEUE_SZ,228.ops = &scmi_imx_bbm_event_ops,229.evts = scmi_imx_bbm_events,230.num_events = ARRAY_SIZE(scmi_imx_bbm_events),231.num_sources = 1,232};233234static int scmi_imx_bbm_rtc_time_set(const struct scmi_protocol_handle *ph,235u32 rtc_id, u64 sec)236{237struct scmi_imx_bbm_info *pi = ph->get_priv(ph);238struct scmi_imx_bbm_set_time *cfg;239struct scmi_xfer *t;240int ret;241242if (rtc_id >= pi->nr_rtc)243return -EINVAL;244245ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_SET, sizeof(*cfg), 0, &t);246if (ret)247return ret;248249cfg = t->tx.buf;250cfg->id = cpu_to_le32(rtc_id);251cfg->flags = 0;252cfg->value_low = cpu_to_le32(lower_32_bits(sec));253cfg->value_high = cpu_to_le32(upper_32_bits(sec));254255ret = ph->xops->do_xfer(ph, t);256257ph->xops->xfer_put(ph, t);258259return ret;260}261262static int scmi_imx_bbm_rtc_time_get(const struct scmi_protocol_handle *ph,263u32 rtc_id, u64 *value)264{265struct scmi_imx_bbm_info *pi = ph->get_priv(ph);266struct scmi_imx_bbm_get_time *cfg;267struct scmi_xfer *t;268int ret;269270if (rtc_id >= pi->nr_rtc)271return -EINVAL;272273ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_GET, sizeof(*cfg),274sizeof(u64), &t);275if (ret)276return ret;277278cfg = t->tx.buf;279cfg->id = cpu_to_le32(rtc_id);280cfg->flags = 0;281282ret = ph->xops->do_xfer(ph, t);283if (!ret)284*value = get_unaligned_le64(t->rx.buf);285286ph->xops->xfer_put(ph, t);287288return ret;289}290291static int scmi_imx_bbm_rtc_alarm_set(const struct scmi_protocol_handle *ph,292u32 rtc_id, bool enable, u64 sec)293{294struct scmi_imx_bbm_info *pi = ph->get_priv(ph);295struct scmi_imx_bbm_alarm_time *cfg;296struct scmi_xfer *t;297int ret;298299if (rtc_id >= pi->nr_rtc)300return -EINVAL;301302ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_ALARM_SET, sizeof(*cfg), 0, &t);303if (ret)304return ret;305306cfg = t->tx.buf;307cfg->id = cpu_to_le32(rtc_id);308cfg->flags = enable ?309cpu_to_le32(SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG) : 0;310cfg->value_low = cpu_to_le32(lower_32_bits(sec));311cfg->value_high = cpu_to_le32(upper_32_bits(sec));312313ret = ph->xops->do_xfer(ph, t);314315ph->xops->xfer_put(ph, t);316317return ret;318}319320static int scmi_imx_bbm_button_get(const struct scmi_protocol_handle *ph, u32 *state)321{322struct scmi_xfer *t;323int ret;324325ret = ph->xops->xfer_get_init(ph, IMX_BBM_BUTTON_GET, 0, sizeof(u32), &t);326if (ret)327return ret;328329ret = ph->xops->do_xfer(ph, t);330if (!ret)331*state = get_unaligned_le32(t->rx.buf);332333ph->xops->xfer_put(ph, t);334335return ret;336}337338static const struct scmi_imx_bbm_proto_ops scmi_imx_bbm_proto_ops = {339.rtc_time_get = scmi_imx_bbm_rtc_time_get,340.rtc_time_set = scmi_imx_bbm_rtc_time_set,341.rtc_alarm_set = scmi_imx_bbm_rtc_alarm_set,342.button_get = scmi_imx_bbm_button_get,343};344345static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph)346{347u32 version;348int ret;349struct scmi_imx_bbm_info *binfo;350351ret = ph->xops->version_get(ph, &version);352if (ret)353return ret;354355dev_info(ph->dev, "NXP SM BBM Version %d.%d\n",356PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));357358binfo = devm_kzalloc(ph->dev, sizeof(*binfo), GFP_KERNEL);359if (!binfo)360return -ENOMEM;361362ret = scmi_imx_bbm_attributes_get(ph, binfo);363if (ret)364return ret;365366return ph->set_priv(ph, binfo, version);367}368369static const struct scmi_protocol scmi_imx_bbm = {370.id = SCMI_PROTOCOL_IMX_BBM,371.owner = THIS_MODULE,372.instance_init = &scmi_imx_bbm_protocol_init,373.ops = &scmi_imx_bbm_proto_ops,374.events = &scmi_imx_bbm_protocol_events,375.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,376.vendor_id = SCMI_IMX_VENDOR,377.sub_vendor_id = SCMI_IMX_SUBVENDOR,378};379module_scmi_protocol(scmi_imx_bbm);380381MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_BBM) "-" SCMI_IMX_VENDOR);382MODULE_DESCRIPTION("i.MX SCMI BBM driver");383MODULE_LICENSE("GPL");384385386