drm/vkms: Add support for ABGR8888 pixel format
[drm/drm-misc.git] / drivers / firmware / arm_scmi / vendors / imx / imx-sm-bbm.c
blob17799eacf06c3036033a9673da3c44de40014684
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * System Control and Management Interface (SCMI) NXP BBM Protocol
5 * Copyright 2024 NXP
6 */
8 #define pr_fmt(fmt) "SCMI Notifications BBM - " fmt
10 #include <linux/bits.h>
11 #include <linux/io.h>
12 #include <linux/module.h>
13 #include <linux/of.h>
14 #include <linux/platform_device.h>
15 #include <linux/scmi_protocol.h>
16 #include <linux/scmi_imx_protocol.h>
18 #include "../../protocols.h"
19 #include "../../notify.h"
21 #define SCMI_PROTOCOL_SUPPORTED_VERSION 0x10000
23 enum scmi_imx_bbm_protocol_cmd {
24 IMX_BBM_GPR_SET = 0x3,
25 IMX_BBM_GPR_GET = 0x4,
26 IMX_BBM_RTC_ATTRIBUTES = 0x5,
27 IMX_BBM_RTC_TIME_SET = 0x6,
28 IMX_BBM_RTC_TIME_GET = 0x7,
29 IMX_BBM_RTC_ALARM_SET = 0x8,
30 IMX_BBM_BUTTON_GET = 0x9,
31 IMX_BBM_RTC_NOTIFY = 0xA,
32 IMX_BBM_BUTTON_NOTIFY = 0xB,
35 #define GET_RTCS_NR(x) le32_get_bits((x), GENMASK(23, 16))
36 #define GET_GPRS_NR(x) le32_get_bits((x), GENMASK(15, 0))
38 #define SCMI_IMX_BBM_NOTIFY_RTC_UPDATED BIT(2)
39 #define SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER BIT(1)
40 #define SCMI_IMX_BBM_NOTIFY_RTC_ALARM BIT(0)
42 #define SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG BIT(0)
44 #define SCMI_IMX_BBM_NOTIFY_RTC_FLAG \
45 (SCMI_IMX_BBM_NOTIFY_RTC_UPDATED | SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER | \
46 SCMI_IMX_BBM_NOTIFY_RTC_ALARM)
48 #define SCMI_IMX_BBM_EVENT_RTC_MASK GENMASK(31, 24)
50 struct scmi_imx_bbm_info {
51 u32 version;
52 int nr_rtc;
53 int nr_gpr;
56 struct scmi_msg_imx_bbm_protocol_attributes {
57 __le32 attributes;
60 struct scmi_imx_bbm_set_time {
61 __le32 id;
62 __le32 flags;
63 __le32 value_low;
64 __le32 value_high;
67 struct scmi_imx_bbm_get_time {
68 __le32 id;
69 __le32 flags;
72 struct scmi_imx_bbm_alarm_time {
73 __le32 id;
74 __le32 flags;
75 __le32 value_low;
76 __le32 value_high;
79 struct scmi_msg_imx_bbm_rtc_notify {
80 __le32 rtc_id;
81 __le32 flags;
84 struct scmi_msg_imx_bbm_button_notify {
85 __le32 flags;
88 struct scmi_imx_bbm_notify_payld {
89 __le32 flags;
92 static int scmi_imx_bbm_attributes_get(const struct scmi_protocol_handle *ph,
93 struct scmi_imx_bbm_info *pi)
95 int ret;
96 struct scmi_xfer *t;
97 struct scmi_msg_imx_bbm_protocol_attributes *attr;
99 ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, sizeof(*attr), &t);
100 if (ret)
101 return ret;
103 attr = t->rx.buf;
105 ret = ph->xops->do_xfer(ph, t);
106 if (!ret) {
107 pi->nr_rtc = GET_RTCS_NR(attr->attributes);
108 pi->nr_gpr = GET_GPRS_NR(attr->attributes);
111 ph->xops->xfer_put(ph, t);
113 return ret;
116 static int scmi_imx_bbm_notify(const struct scmi_protocol_handle *ph,
117 u32 src_id, int message_id, bool enable)
119 int ret;
120 struct scmi_xfer *t;
122 if (message_id == IMX_BBM_RTC_NOTIFY) {
123 struct scmi_msg_imx_bbm_rtc_notify *rtc_notify;
125 ret = ph->xops->xfer_get_init(ph, message_id,
126 sizeof(*rtc_notify), 0, &t);
127 if (ret)
128 return ret;
130 rtc_notify = t->tx.buf;
131 rtc_notify->rtc_id = cpu_to_le32(0);
132 rtc_notify->flags =
133 cpu_to_le32(enable ? SCMI_IMX_BBM_NOTIFY_RTC_FLAG : 0);
134 } else if (message_id == IMX_BBM_BUTTON_NOTIFY) {
135 struct scmi_msg_imx_bbm_button_notify *button_notify;
137 ret = ph->xops->xfer_get_init(ph, message_id,
138 sizeof(*button_notify), 0, &t);
139 if (ret)
140 return ret;
142 button_notify = t->tx.buf;
143 button_notify->flags = cpu_to_le32(enable ? 1 : 0);
144 } else {
145 return -EINVAL;
148 ret = ph->xops->do_xfer(ph, t);
150 ph->xops->xfer_put(ph, t);
151 return ret;
154 static enum scmi_imx_bbm_protocol_cmd evt_2_cmd[] = {
155 IMX_BBM_RTC_NOTIFY,
156 IMX_BBM_BUTTON_NOTIFY
159 static int scmi_imx_bbm_set_notify_enabled(const struct scmi_protocol_handle *ph,
160 u8 evt_id, u32 src_id, bool enable)
162 int ret, cmd_id;
164 if (evt_id >= ARRAY_SIZE(evt_2_cmd))
165 return -EINVAL;
167 cmd_id = evt_2_cmd[evt_id];
168 ret = scmi_imx_bbm_notify(ph, src_id, cmd_id, enable);
169 if (ret)
170 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
171 evt_id, src_id, ret);
173 return ret;
176 static void *scmi_imx_bbm_fill_custom_report(const struct scmi_protocol_handle *ph,
177 u8 evt_id, ktime_t timestamp,
178 const void *payld, size_t payld_sz,
179 void *report, u32 *src_id)
181 const struct scmi_imx_bbm_notify_payld *p = payld;
182 struct scmi_imx_bbm_notif_report *r = report;
184 if (sizeof(*p) != payld_sz)
185 return NULL;
187 if (evt_id == SCMI_EVENT_IMX_BBM_RTC) {
188 r->is_rtc = true;
189 r->is_button = false;
190 r->timestamp = timestamp;
191 r->rtc_id = le32_get_bits(p->flags, SCMI_IMX_BBM_EVENT_RTC_MASK);
192 r->rtc_evt = le32_get_bits(p->flags, SCMI_IMX_BBM_NOTIFY_RTC_FLAG);
193 dev_dbg(ph->dev, "RTC: %d evt: %x\n", r->rtc_id, r->rtc_evt);
194 *src_id = r->rtc_evt;
195 } else if (evt_id == SCMI_EVENT_IMX_BBM_BUTTON) {
196 r->is_rtc = false;
197 r->is_button = true;
198 r->timestamp = timestamp;
199 dev_dbg(ph->dev, "BBM Button\n");
200 *src_id = 0;
201 } else {
202 WARN_ON_ONCE(1);
203 return NULL;
206 return r;
209 static const struct scmi_event scmi_imx_bbm_events[] = {
211 .id = SCMI_EVENT_IMX_BBM_RTC,
212 .max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),
213 .max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),
216 .id = SCMI_EVENT_IMX_BBM_BUTTON,
217 .max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),
218 .max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),
222 static const struct scmi_event_ops scmi_imx_bbm_event_ops = {
223 .set_notify_enabled = scmi_imx_bbm_set_notify_enabled,
224 .fill_custom_report = scmi_imx_bbm_fill_custom_report,
227 static const struct scmi_protocol_events scmi_imx_bbm_protocol_events = {
228 .queue_sz = SCMI_PROTO_QUEUE_SZ,
229 .ops = &scmi_imx_bbm_event_ops,
230 .evts = scmi_imx_bbm_events,
231 .num_events = ARRAY_SIZE(scmi_imx_bbm_events),
232 .num_sources = 1,
235 static int scmi_imx_bbm_rtc_time_set(const struct scmi_protocol_handle *ph,
236 u32 rtc_id, u64 sec)
238 struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
239 struct scmi_imx_bbm_set_time *cfg;
240 struct scmi_xfer *t;
241 int ret;
243 if (rtc_id >= pi->nr_rtc)
244 return -EINVAL;
246 ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_SET, sizeof(*cfg), 0, &t);
247 if (ret)
248 return ret;
250 cfg = t->tx.buf;
251 cfg->id = cpu_to_le32(rtc_id);
252 cfg->flags = 0;
253 cfg->value_low = cpu_to_le32(lower_32_bits(sec));
254 cfg->value_high = cpu_to_le32(upper_32_bits(sec));
256 ret = ph->xops->do_xfer(ph, t);
258 ph->xops->xfer_put(ph, t);
260 return ret;
263 static int scmi_imx_bbm_rtc_time_get(const struct scmi_protocol_handle *ph,
264 u32 rtc_id, u64 *value)
266 struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
267 struct scmi_imx_bbm_get_time *cfg;
268 struct scmi_xfer *t;
269 int ret;
271 if (rtc_id >= pi->nr_rtc)
272 return -EINVAL;
274 ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_GET, sizeof(*cfg),
275 sizeof(u64), &t);
276 if (ret)
277 return ret;
279 cfg = t->tx.buf;
280 cfg->id = cpu_to_le32(rtc_id);
281 cfg->flags = 0;
283 ret = ph->xops->do_xfer(ph, t);
284 if (!ret)
285 *value = get_unaligned_le64(t->rx.buf);
287 ph->xops->xfer_put(ph, t);
289 return ret;
292 static int scmi_imx_bbm_rtc_alarm_set(const struct scmi_protocol_handle *ph,
293 u32 rtc_id, bool enable, u64 sec)
295 struct scmi_imx_bbm_info *pi = ph->get_priv(ph);
296 struct scmi_imx_bbm_alarm_time *cfg;
297 struct scmi_xfer *t;
298 int ret;
300 if (rtc_id >= pi->nr_rtc)
301 return -EINVAL;
303 ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_ALARM_SET, sizeof(*cfg), 0, &t);
304 if (ret)
305 return ret;
307 cfg = t->tx.buf;
308 cfg->id = cpu_to_le32(rtc_id);
309 cfg->flags = enable ?
310 cpu_to_le32(SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG) : 0;
311 cfg->value_low = cpu_to_le32(lower_32_bits(sec));
312 cfg->value_high = cpu_to_le32(upper_32_bits(sec));
314 ret = ph->xops->do_xfer(ph, t);
316 ph->xops->xfer_put(ph, t);
318 return ret;
321 static int scmi_imx_bbm_button_get(const struct scmi_protocol_handle *ph, u32 *state)
323 struct scmi_xfer *t;
324 int ret;
326 ret = ph->xops->xfer_get_init(ph, IMX_BBM_BUTTON_GET, 0, sizeof(u32), &t);
327 if (ret)
328 return ret;
330 ret = ph->xops->do_xfer(ph, t);
331 if (!ret)
332 *state = get_unaligned_le32(t->rx.buf);
334 ph->xops->xfer_put(ph, t);
336 return ret;
339 static const struct scmi_imx_bbm_proto_ops scmi_imx_bbm_proto_ops = {
340 .rtc_time_get = scmi_imx_bbm_rtc_time_get,
341 .rtc_time_set = scmi_imx_bbm_rtc_time_set,
342 .rtc_alarm_set = scmi_imx_bbm_rtc_alarm_set,
343 .button_get = scmi_imx_bbm_button_get,
346 static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph)
348 u32 version;
349 int ret;
350 struct scmi_imx_bbm_info *binfo;
352 ret = ph->xops->version_get(ph, &version);
353 if (ret)
354 return ret;
356 dev_info(ph->dev, "NXP SM BBM Version %d.%d\n",
357 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
359 binfo = devm_kzalloc(ph->dev, sizeof(*binfo), GFP_KERNEL);
360 if (!binfo)
361 return -ENOMEM;
363 ret = scmi_imx_bbm_attributes_get(ph, binfo);
364 if (ret)
365 return ret;
367 return ph->set_priv(ph, binfo, version);
370 static const struct scmi_protocol scmi_imx_bbm = {
371 .id = SCMI_PROTOCOL_IMX_BBM,
372 .owner = THIS_MODULE,
373 .instance_init = &scmi_imx_bbm_protocol_init,
374 .ops = &scmi_imx_bbm_proto_ops,
375 .events = &scmi_imx_bbm_protocol_events,
376 .supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
377 .vendor_id = "NXP",
378 .sub_vendor_id = "IMX",
380 module_scmi_protocol(scmi_imx_bbm);
382 MODULE_DESCRIPTION("i.MX SCMI BBM driver");
383 MODULE_LICENSE("GPL");