1 // SPDX-License-Identifier: GPL-2.0
3 * MIPI SyS-T framing protocol for STM devices.
4 * Copyright (c) 2018, Intel Corporation.
7 #include <linux/configfs.h>
8 #include <linux/module.h>
9 #include <linux/device.h>
10 #include <linux/slab.h>
11 #include <linux/uuid.h>
12 #include <linux/stm.h>
15 enum sys_t_message_type
{
16 MIPI_SYST_TYPE_BUILD
= 0,
17 MIPI_SYST_TYPE_SHORT32
,
18 MIPI_SYST_TYPE_STRING
,
19 MIPI_SYST_TYPE_CATALOG
,
20 MIPI_SYST_TYPE_RAW
= 6,
21 MIPI_SYST_TYPE_SHORT64
,
25 enum sys_t_message_severity
{
26 MIPI_SYST_SEVERITY_MAX
= 0,
27 MIPI_SYST_SEVERITY_FATAL
,
28 MIPI_SYST_SEVERITY_ERROR
,
29 MIPI_SYST_SEVERITY_WARNING
,
30 MIPI_SYST_SEVERITY_INFO
,
31 MIPI_SYST_SEVERITY_USER1
,
32 MIPI_SYST_SEVERITY_USER2
,
33 MIPI_SYST_SEVERITY_DEBUG
,
36 enum sys_t_message_build_subtype
{
37 MIPI_SYST_BUILD_ID_COMPACT32
= 0,
38 MIPI_SYST_BUILD_ID_COMPACT64
,
39 MIPI_SYST_BUILD_ID_LONG
,
42 enum sys_t_message_clock_subtype
{
43 MIPI_SYST_CLOCK_TRANSPORT_SYNC
= 1,
46 enum sys_t_message_string_subtype
{
47 MIPI_SYST_STRING_GENERIC
= 1,
48 MIPI_SYST_STRING_FUNCTIONENTER
,
49 MIPI_SYST_STRING_FUNCTIONEXIT
,
50 MIPI_SYST_STRING_INVALIDPARAM
= 5,
51 MIPI_SYST_STRING_ASSERT
= 7,
52 MIPI_SYST_STRING_PRINTF_32
= 11,
53 MIPI_SYST_STRING_PRINTF_64
= 12,
56 #define MIPI_SYST_TYPE(t) ((u32)(MIPI_SYST_TYPE_ ## t))
57 #define MIPI_SYST_SEVERITY(s) ((u32)(MIPI_SYST_SEVERITY_ ## s) << 4)
58 #define MIPI_SYST_OPT_LOC BIT(8)
59 #define MIPI_SYST_OPT_LEN BIT(9)
60 #define MIPI_SYST_OPT_CHK BIT(10)
61 #define MIPI_SYST_OPT_TS BIT(11)
62 #define MIPI_SYST_UNIT(u) ((u32)(u) << 12)
63 #define MIPI_SYST_ORIGIN(o) ((u32)(o) << 16)
64 #define MIPI_SYST_OPT_GUID BIT(23)
65 #define MIPI_SYST_SUBTYPE(s) ((u32)(MIPI_SYST_ ## s) << 24)
66 #define MIPI_SYST_UNITLARGE(u) (MIPI_SYST_UNIT(u & 0xf) | \
67 MIPI_SYST_ORIGIN(u >> 4))
68 #define MIPI_SYST_TYPES(t, s) (MIPI_SYST_TYPE(t) | \
69 MIPI_SYST_SUBTYPE(t ## _ ## s))
71 #define DATA_HEADER (MIPI_SYST_TYPES(STRING, GENERIC) | \
72 MIPI_SYST_SEVERITY(INFO) | \
75 #define CLOCK_SYNC_HEADER (MIPI_SYST_TYPES(CLOCK, TRANSPORT_SYNC) | \
76 MIPI_SYST_SEVERITY(MAX))
78 struct sys_t_policy_node
{
81 unsigned long ts_interval
;
82 unsigned long clocksync_interval
;
86 struct sys_t_policy_node node
;
87 unsigned long ts_jiffies
;
88 unsigned long clocksync_jiffies
;
91 static void sys_t_policy_node_init(void *priv
)
93 struct sys_t_policy_node
*pn
= priv
;
95 generate_random_uuid(pn
->uuid
.b
);
98 static int sys_t_output_open(void *priv
, struct stm_output
*output
)
100 struct sys_t_policy_node
*pn
= priv
;
101 struct sys_t_output
*opriv
;
103 opriv
= kzalloc(sizeof(*opriv
), GFP_ATOMIC
);
107 memcpy(&opriv
->node
, pn
, sizeof(opriv
->node
));
108 output
->pdrv_private
= opriv
;
113 static void sys_t_output_close(struct stm_output
*output
)
115 kfree(output
->pdrv_private
);
118 static ssize_t
sys_t_policy_uuid_show(struct config_item
*item
,
121 struct sys_t_policy_node
*pn
= to_pdrv_policy_node(item
);
123 return sprintf(page
, "%pU\n", &pn
->uuid
);
127 sys_t_policy_uuid_store(struct config_item
*item
, const char *page
,
130 struct mutex
*mutexp
= &item
->ci_group
->cg_subsys
->su_mutex
;
131 struct sys_t_policy_node
*pn
= to_pdrv_policy_node(item
);
135 ret
= uuid_parse(page
, &pn
->uuid
);
136 mutex_unlock(mutexp
);
138 return ret
< 0 ? ret
: count
;
141 CONFIGFS_ATTR(sys_t_policy_
, uuid
);
143 static ssize_t
sys_t_policy_do_len_show(struct config_item
*item
,
146 struct sys_t_policy_node
*pn
= to_pdrv_policy_node(item
);
148 return sprintf(page
, "%d\n", pn
->do_len
);
152 sys_t_policy_do_len_store(struct config_item
*item
, const char *page
,
155 struct mutex
*mutexp
= &item
->ci_group
->cg_subsys
->su_mutex
;
156 struct sys_t_policy_node
*pn
= to_pdrv_policy_node(item
);
160 ret
= kstrtobool(page
, &pn
->do_len
);
161 mutex_unlock(mutexp
);
163 return ret
? ret
: count
;
166 CONFIGFS_ATTR(sys_t_policy_
, do_len
);
168 static ssize_t
sys_t_policy_ts_interval_show(struct config_item
*item
,
171 struct sys_t_policy_node
*pn
= to_pdrv_policy_node(item
);
173 return sprintf(page
, "%u\n", jiffies_to_msecs(pn
->ts_interval
));
177 sys_t_policy_ts_interval_store(struct config_item
*item
, const char *page
,
180 struct mutex
*mutexp
= &item
->ci_group
->cg_subsys
->su_mutex
;
181 struct sys_t_policy_node
*pn
= to_pdrv_policy_node(item
);
186 ret
= kstrtouint(page
, 10, &ms
);
187 mutex_unlock(mutexp
);
190 pn
->ts_interval
= msecs_to_jiffies(ms
);
197 CONFIGFS_ATTR(sys_t_policy_
, ts_interval
);
199 static ssize_t
sys_t_policy_clocksync_interval_show(struct config_item
*item
,
202 struct sys_t_policy_node
*pn
= to_pdrv_policy_node(item
);
204 return sprintf(page
, "%u\n", jiffies_to_msecs(pn
->clocksync_interval
));
208 sys_t_policy_clocksync_interval_store(struct config_item
*item
,
209 const char *page
, size_t count
)
211 struct mutex
*mutexp
= &item
->ci_group
->cg_subsys
->su_mutex
;
212 struct sys_t_policy_node
*pn
= to_pdrv_policy_node(item
);
217 ret
= kstrtouint(page
, 10, &ms
);
218 mutex_unlock(mutexp
);
221 pn
->clocksync_interval
= msecs_to_jiffies(ms
);
228 CONFIGFS_ATTR(sys_t_policy_
, clocksync_interval
);
230 static struct configfs_attribute
*sys_t_policy_attrs
[] = {
231 &sys_t_policy_attr_uuid
,
232 &sys_t_policy_attr_do_len
,
233 &sys_t_policy_attr_ts_interval
,
234 &sys_t_policy_attr_clocksync_interval
,
238 static inline bool sys_t_need_ts(struct sys_t_output
*op
)
240 if (op
->node
.ts_interval
&&
241 time_after(jiffies
, op
->ts_jiffies
+ op
->node
.ts_interval
)) {
242 op
->ts_jiffies
= jiffies
;
250 static bool sys_t_need_clock_sync(struct sys_t_output
*op
)
252 if (op
->node
.clocksync_interval
&&
254 op
->clocksync_jiffies
+ op
->node
.clocksync_interval
)) {
255 op
->clocksync_jiffies
= jiffies
;
264 sys_t_clock_sync(struct stm_data
*data
, unsigned int m
, unsigned int c
)
266 u32 header
= CLOCK_SYNC_HEADER
;
267 const unsigned char nil
= 0;
268 u64 payload
[2]; /* Clock value and frequency */
271 sz
= data
->packet(data
, m
, c
, STP_PACKET_DATA
, STP_PACKET_TIMESTAMPED
,
276 payload
[0] = ktime_get_real_ns();
277 payload
[1] = NSEC_PER_SEC
;
278 sz
= stm_data_write(data
, m
, c
, false, &payload
, sizeof(payload
));
282 data
->packet(data
, m
, c
, STP_PACKET_FLAG
, 0, 0, &nil
);
284 return sizeof(header
) + sizeof(payload
);
287 static ssize_t
sys_t_write(struct stm_data
*data
, struct stm_output
*output
,
288 unsigned int chan
, const char *buf
, size_t count
)
290 struct sys_t_output
*op
= output
->pdrv_private
;
291 unsigned int c
= output
->channel
+ chan
;
292 unsigned int m
= output
->master
;
293 const unsigned char nil
= 0;
294 u32 header
= DATA_HEADER
;
297 /* We require an existing policy node to proceed */
301 if (sys_t_need_clock_sync(op
)) {
302 sz
= sys_t_clock_sync(data
, m
, c
);
308 header
|= MIPI_SYST_OPT_LEN
;
309 if (sys_t_need_ts(op
))
310 header
|= MIPI_SYST_OPT_TS
;
313 * STP framing rules for SyS-T frames:
314 * * the first packet of the SyS-T frame is timestamped;
315 * * the last packet is a FLAG.
317 /* Message layout: HEADER / GUID / [LENGTH /][TIMESTAMP /] DATA */
319 sz
= data
->packet(data
, m
, c
, STP_PACKET_DATA
, STP_PACKET_TIMESTAMPED
,
325 sz
= stm_data_write(data
, m
, c
, false, op
->node
.uuid
.b
, UUID_SIZE
);
330 if (op
->node
.do_len
) {
333 sz
= data
->packet(data
, m
, c
, STP_PACKET_DATA
, 0, 2,
340 if (header
& MIPI_SYST_OPT_TS
) {
341 u64 ts
= ktime_get_real_ns();
343 sz
= stm_data_write(data
, m
, c
, false, &ts
, sizeof(ts
));
349 sz
= stm_data_write(data
, m
, c
, false, buf
, count
);
351 data
->packet(data
, m
, c
, STP_PACKET_FLAG
, 0, 0, &nil
);
356 static const struct stm_protocol_driver sys_t_pdrv
= {
357 .owner
= THIS_MODULE
,
359 .priv_sz
= sizeof(struct sys_t_policy_node
),
360 .write
= sys_t_write
,
361 .policy_attr
= sys_t_policy_attrs
,
362 .policy_node_init
= sys_t_policy_node_init
,
363 .output_open
= sys_t_output_open
,
364 .output_close
= sys_t_output_close
,
367 static int sys_t_stm_init(void)
369 return stm_register_protocol(&sys_t_pdrv
);
372 static void sys_t_stm_exit(void)
374 stm_unregister_protocol(&sys_t_pdrv
);
377 module_init(sys_t_stm_init
);
378 module_exit(sys_t_stm_exit
);
380 MODULE_LICENSE("GPL v2");
381 MODULE_DESCRIPTION("MIPI SyS-T STM framing protocol driver");
382 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");