1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/debug/mipi_stp_decoder.h>
7 #include <string.h>
8
9 #if defined(CONFIG_CPU_CORTEX_M) && \
10 !defined(CONFIG_CPU_CORTEX_M0) && \
11 !defined(CONFIG_CPU_CORTEX_M0PLUS)
12 #define UNALIGNED_ACCESS_SUPPORTED 1
13 #else
14 #define UNALIGNED_ACCESS_SUPPORTED 0
15 #endif
16
17 enum stp_state {
18 STP_STATE_OP,
19 STP_STATE_DATA,
20 STP_STATE_TS,
21 STP_STATE_OUT_OF_SYNC,
22 };
23
24 enum stp_id {
25 STP_NULL,
26 STP_M8,
27 STP_MERR,
28 STP_C8,
29 STP_D8,
30 STP_D16,
31 STP_D32,
32 STP_D64,
33 STP_D8MTS,
34 STP_D16MTS,
35 STP_D32MTS,
36 STP_D64MTS,
37 STP_D4,
38 STP_D4MTS,
39 STP_FLAG_TS,
40 STP_VERSION,
41 STP_TAG_3NIBBLE_OP = STP_VERSION,
42 STP_NULL_TS,
43 STP_USER,
44 STP_USER_TS,
45 STP_TIME,
46 STP_TIME_TS,
47 STP_TRIG,
48 STP_TRIG_TS,
49 STP_FREQ,
50 STP_FREQ_TS,
51 STP_XSYNC,
52 STP_XSYNC_TS,
53 STP_FREQ_40,
54 STP_TAG_4NIBBLE_OP = STP_FREQ_40,
55 STP_FREQ_40_TS,
56 STP_DIP,
57 STP_M16,
58 STP_TAG_2NIBBLE_OP = STP_M16,
59 STP_GERR,
60 STP_C16,
61 STP_D8TS,
62 STP_D16TS,
63 STP_D32TS,
64 STP_D64TS,
65 STP_D8M,
66 STP_D16M,
67 STP_D32M,
68 STP_D64M,
69 STP_D4TS,
70 STP_D4M,
71 STP_FLAG,
72 STP_ASYNC,
73 STP_INVALID,
74 STP_OP_MAX
75 };
76
77 #define STP_LONG_OP_ID 0xF
78 #define STP_2B_OP_ID 0xF0
79
80 #define STP_VAR_DATA 0xff
81
82 typedef void (*stp_cb)(uint64_t data, uint64_t ts);
83
84 struct stp_item {
85 const char *name;
86 enum stp_id type;
87 uint8_t id[3];
88 uint8_t id_ncnt;
89 uint8_t d_ncnt;
90 bool has_ts;
91 stp_cb cb;
92 };
93
94 #define STP_ITEM(_type, _id, _id_ncnt, _d_ncnt, _has_ts, _cb) \
95 { \
96 .name = STRINGIFY(_type), .type = _type, .id = {__DEBRACKET _id}, \
97 .id_ncnt = _id_ncnt, .d_ncnt = _d_ncnt, \
98 .has_ts = _has_ts, .cb = (stp_cb)_cb \
99 }
100
101 static struct mipi_stp_decoder_config cfg;
102 static uint64_t prev_ts;
103 static uint64_t base_ts;
104 static enum stp_state state;
105 static size_t ntotal;
106 static size_t ncnt;
107 static size_t noff;
108 static uint16_t curr_ch;
109
data4_cb(uint64_t data,uint64_t ts)110 static void data4_cb(uint64_t data, uint64_t ts)
111 {
112 ARG_UNUSED(ts);
113 union mipi_stp_decoder_data d = {.data = data};
114
115 cfg.cb(STP_DATA4, d, NULL, false);
116 }
117
data8_cb(uint64_t data,uint64_t ts)118 static void data8_cb(uint64_t data, uint64_t ts)
119 {
120 ARG_UNUSED(ts);
121 union mipi_stp_decoder_data d = {.data = data};
122
123 cfg.cb(STP_DATA8, d, NULL, false);
124 }
125
data16_cb(uint64_t data,uint64_t ts)126 static void data16_cb(uint64_t data, uint64_t ts)
127 {
128 ARG_UNUSED(ts);
129 union mipi_stp_decoder_data d = {.data = data};
130
131 cfg.cb(STP_DATA16, d, NULL, false);
132 }
133
data32_cb(uint64_t data,uint64_t ts)134 static void data32_cb(uint64_t data, uint64_t ts)
135 {
136 ARG_UNUSED(ts);
137 union mipi_stp_decoder_data d = {.data = data};
138
139 cfg.cb(STP_DATA32, d, NULL, false);
140 }
141
data64_cb(uint64_t data,uint64_t ts)142 static void data64_cb(uint64_t data, uint64_t ts)
143 {
144 ARG_UNUSED(ts);
145 union mipi_stp_decoder_data d = {.data = data};
146
147 cfg.cb(STP_DATA64, d, NULL, false);
148 }
149
data4_m_cb(uint64_t data,uint64_t ts)150 static void data4_m_cb(uint64_t data, uint64_t ts)
151 {
152 ARG_UNUSED(ts);
153 union mipi_stp_decoder_data d = {.data = data};
154
155 cfg.cb(STP_DATA4, d, NULL, true);
156 }
157
data8_m_cb(uint64_t data,uint64_t ts)158 static void data8_m_cb(uint64_t data, uint64_t ts)
159 {
160 ARG_UNUSED(ts);
161 union mipi_stp_decoder_data d = {.data = data};
162
163 cfg.cb(STP_DATA8, d, NULL, true);
164 }
165
data16_m_cb(uint64_t data,uint64_t ts)166 static void data16_m_cb(uint64_t data, uint64_t ts)
167 {
168 ARG_UNUSED(ts);
169 union mipi_stp_decoder_data d = {.data = data};
170
171 cfg.cb(STP_DATA16, d, NULL, true);
172 }
173
data32_m_cb(uint64_t data,uint64_t ts)174 static void data32_m_cb(uint64_t data, uint64_t ts)
175 {
176 ARG_UNUSED(ts);
177 union mipi_stp_decoder_data d = {.data = data};
178
179 cfg.cb(STP_DATA32, d, NULL, true);
180 }
181
data64_m_cb(uint64_t data,uint64_t ts)182 static void data64_m_cb(uint64_t data, uint64_t ts)
183 {
184 ARG_UNUSED(ts);
185 union mipi_stp_decoder_data d = {.data = data};
186
187 cfg.cb(STP_DATA64, d, NULL, true);
188 }
189
data4_ts_cb(uint64_t data,uint64_t ts)190 static void data4_ts_cb(uint64_t data, uint64_t ts)
191 {
192 union mipi_stp_decoder_data d = {.data = data};
193
194 cfg.cb(STP_DATA4, d, &ts, false);
195 }
196
data8_ts_cb(uint64_t data,uint64_t ts)197 static void data8_ts_cb(uint64_t data, uint64_t ts)
198 {
199 union mipi_stp_decoder_data d = {.data = data};
200
201 cfg.cb(STP_DATA8, d, &ts, false);
202 }
203
data16_ts_cb(uint64_t data,uint64_t ts)204 static void data16_ts_cb(uint64_t data, uint64_t ts)
205 {
206 union mipi_stp_decoder_data d = {.data = data};
207
208 cfg.cb(STP_DATA16, d, &ts, false);
209 }
210
data32_ts_cb(uint64_t data,uint64_t ts)211 static void data32_ts_cb(uint64_t data, uint64_t ts)
212 {
213 union mipi_stp_decoder_data d = {.data = data};
214
215 cfg.cb(STP_DATA32, d, &ts, false);
216 }
217
data64_ts_cb(uint64_t data,uint64_t ts)218 static void data64_ts_cb(uint64_t data, uint64_t ts)
219 {
220 union mipi_stp_decoder_data d = {.data = data};
221
222 cfg.cb(STP_DATA64, d, &ts, false);
223 }
224
data4_mts_cb(uint64_t data,uint64_t ts)225 static void data4_mts_cb(uint64_t data, uint64_t ts)
226 {
227 union mipi_stp_decoder_data d = {.data = data};
228
229 cfg.cb(STP_DATA4, d, &ts, true);
230 }
231
data8_mts_cb(uint64_t data,uint64_t ts)232 static void data8_mts_cb(uint64_t data, uint64_t ts)
233 {
234 union mipi_stp_decoder_data d = {.data = data};
235
236 cfg.cb(STP_DATA8, d, &ts, true);
237 }
238
data16_mts_cb(uint64_t data,uint64_t ts)239 static void data16_mts_cb(uint64_t data, uint64_t ts)
240 {
241 union mipi_stp_decoder_data d = {.data = data};
242
243 cfg.cb(STP_DATA16, d, &ts, true);
244 }
245
data32_mts_cb(uint64_t data,uint64_t ts)246 static void data32_mts_cb(uint64_t data, uint64_t ts)
247 {
248 union mipi_stp_decoder_data d = {.data = data};
249
250 cfg.cb(STP_DATA32, d, &ts, true);
251 }
252
data64_mts_cb(uint64_t data,uint64_t ts)253 static void data64_mts_cb(uint64_t data, uint64_t ts)
254 {
255 union mipi_stp_decoder_data d = {.data = data};
256
257 cfg.cb(STP_DATA64, d, &ts, true);
258 }
259
master_cb(uint64_t id,uint64_t ts)260 static void master_cb(uint64_t id, uint64_t ts)
261 {
262 ARG_UNUSED(ts);
263 uint16_t m_id = (uint16_t)id;
264 union mipi_stp_decoder_data data = {.id = m_id};
265
266 curr_ch = 0;
267
268 cfg.cb(STP_DECODER_MASTER, data, NULL, false);
269 }
270
channel16_cb(uint64_t id,uint64_t ts)271 static void channel16_cb(uint64_t id, uint64_t ts)
272 {
273 uint16_t ch = (uint16_t)id;
274
275 curr_ch = 0xFF00 & ch;
276
277 ARG_UNUSED(ts);
278 union mipi_stp_decoder_data data = {.id = ch};
279
280 cfg.cb(STP_DECODER_CHANNEL, data, NULL, false);
281 }
channel_cb(uint64_t id,uint64_t ts)282 static void channel_cb(uint64_t id, uint64_t ts)
283 {
284 uint16_t ch = (uint16_t)id;
285
286 ch |= curr_ch;
287
288 ARG_UNUSED(ts);
289 union mipi_stp_decoder_data data = {.id = ch};
290
291 cfg.cb(STP_DECODER_CHANNEL, data, NULL, false);
292 }
293
merror_cb(uint64_t err,uint64_t ts)294 static void merror_cb(uint64_t err, uint64_t ts)
295 {
296 ARG_UNUSED(ts);
297 union mipi_stp_decoder_data data = {.err = (uint32_t)err};
298
299 cfg.cb(STP_DECODER_MERROR, data, NULL, false);
300 }
301
gerror_cb(uint64_t err,uint64_t ts)302 static void gerror_cb(uint64_t err, uint64_t ts)
303 {
304 ARG_UNUSED(ts);
305 union mipi_stp_decoder_data data = {.err = (uint32_t)err};
306
307 cfg.cb(STP_DECODER_GERROR, data, NULL, false);
308 }
309
flag_cb(uint64_t data,uint64_t ts)310 static void flag_cb(uint64_t data, uint64_t ts)
311 {
312 ARG_UNUSED(ts);
313 ARG_UNUSED(data);
314 union mipi_stp_decoder_data dummy = {.dummy = 0};
315
316 cfg.cb(STP_DECODER_FLAG, dummy, NULL, false);
317 }
318
flag_ts_cb(uint64_t unused,uint64_t ts)319 static void flag_ts_cb(uint64_t unused, uint64_t ts)
320 {
321 ARG_UNUSED(unused);
322 union mipi_stp_decoder_data data = {.dummy = 0};
323
324 cfg.cb(STP_DECODER_FLAG, data, &ts, false);
325 }
326
version_cb(uint64_t version,uint64_t ts)327 static void version_cb(uint64_t version, uint64_t ts)
328 {
329 ARG_UNUSED(ts);
330
331 curr_ch = 0;
332
333 union mipi_stp_decoder_data data = {.ver = version};
334
335 cfg.cb(STP_DECODER_VERSION, data, NULL, false);
336 }
337
notsup_cb(uint64_t data,uint64_t ts)338 static void notsup_cb(uint64_t data, uint64_t ts)
339 {
340 ARG_UNUSED(ts);
341 ARG_UNUSED(data);
342
343 union mipi_stp_decoder_data dummy = {.dummy = 0};
344
345 cfg.cb(STP_DECODER_NOT_SUPPORTED, dummy, NULL, false);
346 }
347
freq_cb(uint64_t freq,uint64_t ts)348 static void freq_cb(uint64_t freq, uint64_t ts)
349 {
350 ARG_UNUSED(ts);
351
352 union mipi_stp_decoder_data data = {.freq = freq};
353
354 cfg.cb(STP_DECODER_FREQ, data, NULL, false);
355 }
356
freq_ts_cb(uint64_t freq,uint64_t ts)357 static void freq_ts_cb(uint64_t freq, uint64_t ts)
358 {
359 union mipi_stp_decoder_data data = {.freq = freq};
360
361 cfg.cb(STP_DECODER_FREQ, data, &ts, false);
362 }
363
null_cb(uint64_t data,uint64_t ts)364 static void null_cb(uint64_t data, uint64_t ts)
365 {
366 ARG_UNUSED(ts);
367 ARG_UNUSED(data);
368
369 union mipi_stp_decoder_data dummy = {.dummy = 0};
370
371 cfg.cb(STP_DECODER_NULL, dummy, NULL, false);
372 }
373
async_cb(uint64_t data,uint64_t ts)374 static void async_cb(uint64_t data, uint64_t ts)
375 {
376 ARG_UNUSED(ts);
377 ARG_UNUSED(data);
378
379 union mipi_stp_decoder_data dummy = {.dummy = 0};
380
381 cfg.cb(STP_DECODER_ASYNC, dummy, NULL, false);
382 }
383
384 static const struct stp_item items[] = {
385 STP_ITEM(STP_NULL, (0x0), 1, 0, false, null_cb),
386 STP_ITEM(STP_M8, (0x1), 1, 2, false, master_cb),
387 STP_ITEM(STP_MERR, (0x2), 1, 2, false, merror_cb),
388 STP_ITEM(STP_C8, (0x3), 1, 2, false, channel_cb),
389 STP_ITEM(STP_D8, (0x4), 1, 2, false, data8_cb),
390 STP_ITEM(STP_D16, (0x5), 1, 4, false, data16_cb),
391 STP_ITEM(STP_D32, (0x6), 1, 8, false, data32_cb),
392 STP_ITEM(STP_D64, (0x7), 1, 16, false, data64_cb),
393 STP_ITEM(STP_D8MTS, (0x8), 1, 2, true, data8_mts_cb),
394 STP_ITEM(STP_D16MTS, (0x9), 1, 4, true, data16_mts_cb),
395 STP_ITEM(STP_D32MTS, (0xa), 1, 8, true, data32_mts_cb),
396 STP_ITEM(STP_D64MTS, (0xb), 1, 16, true, data64_mts_cb),
397 STP_ITEM(STP_D4, (0xc), 1, 1, false, data4_cb),
398 STP_ITEM(STP_D4MTS, (0xd), 1, 1, true, data4_mts_cb),
399 STP_ITEM(STP_FLAG_TS, (0xe), 1, 0, true, flag_ts_cb),
400 STP_ITEM(STP_VERSION, (0xf0, 0x00), 3, 1, false, version_cb),
401 STP_ITEM(STP_NULL_TS, (0xf0, 0x01), 3, 0, true, notsup_cb),
402 STP_ITEM(STP_USER, (0xf0, 0x02), 3, 0, false, notsup_cb),
403 STP_ITEM(STP_USER_TS, (0xf0, 0x03), 3, 0, true, notsup_cb),
404 STP_ITEM(STP_TIME, (0xf0, 0x04), 3, 0, false, notsup_cb),
405 STP_ITEM(STP_TIME_TS, (0xf0, 0x05), 3, 0, true, notsup_cb),
406 STP_ITEM(STP_TRIG, (0xf0, 0x06), 3, 0, false, notsup_cb),
407 STP_ITEM(STP_TRIG_TS, (0xf0, 0x07), 3, 0, true, notsup_cb),
408 STP_ITEM(STP_FREQ, (0xf0, 0x08), 3, 8, false, freq_cb),
409 STP_ITEM(STP_FREQ_TS, (0xf0, 0x09), 3, 8, true, freq_ts_cb),
410 STP_ITEM(STP_XSYNC, (0xf0, 0x0a), 3, 0, false, notsup_cb),
411 STP_ITEM(STP_XSYNC_TS, (0xf0, 0x0b), 3, 0, true, notsup_cb),
412 STP_ITEM(STP_FREQ_40, (0xf0, 0xf0), 4, 10, false, freq_cb),
413 STP_ITEM(STP_FREQ_40_TS, (0xf0, 0xf1), 4, 0, true, notsup_cb),
414 STP_ITEM(STP_DIP, (0xf0, 0xf2), 4, 0, false, notsup_cb),
415 STP_ITEM(STP_M16, (0xf1), 2, 4, false, master_cb),
416 STP_ITEM(STP_GERR, (0xf2), 2, 2, false, gerror_cb),
417 STP_ITEM(STP_C16, (0xf3), 2, 4, false, channel16_cb),
418 STP_ITEM(STP_D8TS, (0xf4), 2, 2, true, data8_ts_cb),
419 STP_ITEM(STP_D16TS, (0xf5), 2, 4, true, data16_ts_cb),
420 STP_ITEM(STP_D32TS, (0xf6), 2, 8, true, data32_ts_cb),
421 STP_ITEM(STP_D64TS, (0xf7), 2, 16, true, data64_ts_cb),
422 STP_ITEM(STP_D8M, (0xf8), 2, 2, false, data8_m_cb),
423 STP_ITEM(STP_D16M, (0xf9), 2, 4, false, data16_m_cb),
424 STP_ITEM(STP_D32M, (0xfa), 2, 8, false, data32_m_cb),
425 STP_ITEM(STP_D64M, (0xfb), 2, 16, false, data64_m_cb),
426 STP_ITEM(STP_D4TS, (0xfc), 2, 1, true, data4_ts_cb),
427 STP_ITEM(STP_D4M, (0xfd), 2, 1, false, data4_m_cb),
428 STP_ITEM(STP_FLAG, (0xfe), 2, 0, false, flag_cb),
429 STP_ITEM(STP_ASYNC, (0xff, 0xff, 0xff), 6, 16, false, async_cb),
430 STP_ITEM(STP_INVALID, (0x0), 0, 0, false, NULL),
431 };
432
433 /** @brief Decode a nibble and read opcode from the stream.
434 *
435 * Function reads a nibble and continues or starts decoding of a STP opcode.
436 *
437 * @param data Pointer to the stream.
438 * @param[in,out] noff Offset (in nibbles).
439 * @param nlen Length (in nibbles).
440 * @param[in,out] ncnt Current number of nibbles
441 * @param[in,out] ntotal Number of nibbles in the opcode.
442 *
443 * @retval STP_INVALID Opcode decoding is in progress.
444 * @retval opcode Decoded opcode.
445 */
get_nibble(const uint8_t * data,size_t noff)446 static inline uint8_t get_nibble(const uint8_t *data, size_t noff)
447 {
448 uint8_t ret = data[noff / 2];
449
450 if (noff & 0x1UL) {
451 ret >>= 4;
452 }
453
454 ret &= 0x0F;
455
456 return ret;
457 }
458
get_nibbles64(const uint8_t * src,size_t src_noff,uint8_t * dst,size_t dst_noff,size_t nlen)459 static inline void get_nibbles64(const uint8_t *src, size_t src_noff, uint8_t *dst, size_t dst_noff,
460 size_t nlen)
461 {
462 bool src_ba = (src_noff & 0x1UL) == 0;
463 bool dst_ba = (dst_noff & 0x1UL) == 0;
464 uint64_t *src64 = (uint64_t *)&src[src_noff / 2];
465 uint64_t *dst64 = (uint64_t *)&dst[dst_noff / 2];
466
467 if (nlen == 16) {
468 /* dst must be aligned. */
469 if (src_ba) {
470 uint32_t *s32 = (uint32_t *)src64;
471 uint32_t *d32 = (uint32_t *)dst64;
472
473 d32[0] = s32[0];
474 d32[1] = s32[1];
475 } else {
476 uint64_t part_a = src64[0] >> 4;
477 uint64_t part_b = src64[1] << 60;
478
479 dst64[0] = part_a | part_b;
480 }
481 return;
482 }
483
484 uint64_t mask = BIT64_MASK(nlen * 4) << (src_ba ? 0 : 4);
485 uint64_t src_d = src64[0] & mask;
486
487 if (((src_noff ^ dst_noff) & 0x1UL) == 0) {
488 dst64[0] |= src_d;
489 } else if (dst_ba) {
490 dst64[0] |= (src_d >> 4);
491 } else {
492 dst64[0] |= (src_d << 4);
493 }
494 }
495
496 /* Function performs getting nibbles in less efficient way but does not use unaligned
497 * access which may not be supported by some platforms.
498 */
get_nibbles_unaligned(const uint8_t * src,size_t src_noff,uint8_t * dst,size_t dst_noff,size_t nlen)499 static void get_nibbles_unaligned(const uint8_t *src, size_t src_noff, uint8_t *dst,
500 size_t dst_noff, size_t nlen)
501 {
502 for (size_t i = 0; i < nlen; i++) {
503 size_t idx = (src_noff + i) / 2;
504 size_t ni = (src_noff + i) & 0x1;
505 uint8_t n = src[idx] >> (ni ? 4 : 0);
506 size_t d_idx = (dst_noff + i) / 2;
507 size_t dni = (dst_noff + i) & 0x1;
508
509 if (dni == 0) {
510 dst[d_idx] = n;
511 } else {
512 dst[d_idx] |= n << 4;
513 }
514 }
515 }
516
get_nibbles(const uint8_t * src,size_t src_noff,uint8_t * dst,size_t dst_noff,size_t nlen)517 static inline void get_nibbles(const uint8_t *src, size_t src_noff, uint8_t *dst, size_t dst_noff,
518 size_t nlen)
519 {
520 if (!UNALIGNED_ACCESS_SUPPORTED) {
521 get_nibbles_unaligned(src, src_noff, dst, dst_noff, nlen);
522 return;
523 }
524
525 bool src_ba = (src_noff & 0x1UL) == 0;
526 bool dst_ba = (dst_noff & 0x1UL) == 0;
527 uint32_t *src32 = (uint32_t *)&src[src_noff / 2];
528 uint32_t *dst32 = (uint32_t *)&dst[dst_noff / 2];
529
530 if (nlen > 8) {
531 get_nibbles64(src, src_noff, dst, dst_noff, nlen);
532 return;
533 } else if (nlen == 8) {
534 /* dst must be aligned. */
535 if (src_ba) {
536 dst32[0] = src32[0];
537 } else {
538 uint32_t part_a = src32[0] >> 4;
539 uint32_t part_b = src32[1] << 28;
540
541 dst32[0] = part_a | part_b;
542 }
543 return;
544 }
545
546 uint32_t mask = BIT_MASK(nlen * 4) << (src_ba ? 0 : 4);
547 uint32_t src_d = src32[0] & mask;
548
549 if (((src_noff ^ dst_noff) & 0x1UL) == 0) {
550 dst32[0] |= src_d;
551 } else if (dst_ba) {
552 dst32[0] |= (src_d >> 4);
553 } else {
554 dst32[0] |= (src_d << 4);
555 }
556 }
557
558 /* Function swaps nibbles in a byte. */
swap8(uint8_t byte)559 static uint8_t swap8(uint8_t byte)
560 {
561 return (byte << 4) | (byte >> 4);
562 }
563
564 /* Function swaps nibbles in a 16 bit variable. */
swap16(uint16_t halfword)565 static uint16_t swap16(uint16_t halfword)
566 {
567 halfword = __builtin_bswap16(halfword);
568 uint16_t d1 = (halfword & 0xf0f0) >> 4;
569 uint16_t d2 = (halfword & 0x0f0f) << 4;
570
571 return d1 | d2;
572 }
573
574 /* Function swaps nibbles in a 32 bit word. */
swap32(uint32_t word)575 static uint32_t swap32(uint32_t word)
576 {
577 word = __builtin_bswap32(word);
578 uint32_t d1 = (word & 0xf0f0f0f0) >> 4;
579 uint32_t d2 = (word & 0x0f0f0f0f) << 4;
580
581 return d1 | d2;
582 }
583
584 /* Function swaps nibbles in a 64 bit word. */
swap64(uint64_t dword)585 static uint64_t swap64(uint64_t dword)
586 {
587 uint32_t l = (uint32_t)dword;
588 uint32_t u = (uint32_t)(dword >> 32);
589
590 return ((uint64_t)swap32(l) << 32) | (uint64_t)swap32(u);
591 }
592
swap_n(uint8_t * data,uint32_t n)593 static void swap_n(uint8_t *data, uint32_t n)
594 {
595 switch (n) {
596 case 2:
597 *data = swap8(*data);
598 break;
599 case 4:
600 *(uint16_t *)data = swap16(*(uint16_t *)data);
601 break;
602 case 8:
603 *(uint32_t *)data = swap32(*(uint32_t *)data);
604 break;
605 case 16:
606 *(uint64_t *)data = swap64(*(uint64_t *)data);
607 break;
608 default:
609 *(uint64_t *)data = swap64(*(uint64_t *)data);
610 *(uint64_t *)data >>= (4 * (16 - n));
611 break;
612 }
613 }
614
get_op(const uint8_t * data,size_t * noff,size_t * nlen,size_t * ncnt,size_t * ntotal)615 static enum stp_id get_op(const uint8_t *data, size_t *noff, size_t *nlen, size_t *ncnt,
616 size_t *ntotal)
617 {
618 uint8_t op = 0;
619
620 op = get_nibble(data, *noff);
621
622 *noff += 1;
623 *ncnt += 1;
624 if (*ntotal == 0 && *ncnt == 1) {
625 /* Starting to read op. */
626 /* op code has only 1 nibble. */
627 if (op != 0xF) {
628 return (enum stp_id)op;
629 }
630 } else if (*ncnt == 2) {
631 if (op == 0xF) {
632 /* ASYNC*/
633 *ntotal = 6;
634 } else if (op != 0) {
635 return (enum stp_id)(STP_TAG_2NIBBLE_OP - 1 + op);
636 }
637 } else if (*ncnt == 3) {
638 if (op != 0xf) {
639 return (enum stp_id)(STP_TAG_3NIBBLE_OP + op);
640 } else if (*ntotal == 0) {
641 *ntotal = 4;
642 }
643 } else if (*ncnt == *ntotal) {
644 if (*ntotal == 4) {
645 return (enum stp_id)(STP_TAG_4NIBBLE_OP + op);
646 } else {
647 return STP_ASYNC;
648 }
649 }
650
651 return STP_INVALID;
652 }
653
mipi_stp_decoder_sync_loss(void)654 void mipi_stp_decoder_sync_loss(void)
655 {
656 state = STP_STATE_OUT_OF_SYNC;
657 ncnt = 0;
658 ntotal = 0;
659 }
660
mipi_stp_decoder_decode(const uint8_t * data,size_t len)661 int mipi_stp_decoder_decode(const uint8_t *data, size_t len)
662 {
663 static enum stp_id curr_id = STP_INVALID;
664 static uint8_t data_buf[8] __aligned(sizeof(uint64_t));
665 static uint8_t ts_buf[8] __aligned(sizeof(uint64_t));
666 uint64_t *data64 = (uint64_t *)data_buf;
667 uint64_t *ts64 = (uint64_t *)ts_buf;
668 size_t nlen = 2 * len;
669
670 do {
671 switch (state) {
672 case STP_STATE_OUT_OF_SYNC: {
673 uint8_t b = get_nibble(data, noff);
674
675 noff++;
676 if (ncnt < 21 && b == 0xF) {
677 ncnt++;
678 } else if (ncnt == 21 && b == 0) {
679 curr_id = STP_INVALID;
680 ncnt = 0;
681
682 items[STP_ASYNC].cb(0, 0);
683 state = STP_STATE_OP;
684 } else {
685 ncnt = 0;
686 }
687 break;
688 }
689 case STP_STATE_OP: {
690 curr_id = get_op(data, &noff, &nlen, &ncnt, &ntotal);
691 if (curr_id != STP_INVALID) {
692 ntotal = items[curr_id].d_ncnt;
693 ncnt = 0;
694 if (ntotal > 0) {
695 state = STP_STATE_DATA;
696 data64[0] = 0;
697 } else if (items[curr_id].has_ts) {
698 state = STP_STATE_TS;
699 } else {
700 /* item without data and ts, notify. */
701 items[curr_id].cb(0, 0);
702 curr_id = STP_INVALID;
703 }
704 }
705 break;
706 }
707 case STP_STATE_DATA: {
708 size_t ncpy = MIN(ntotal - ncnt, nlen - noff);
709
710 get_nibbles(data, noff, data_buf, ncnt, ncpy);
711
712 ncnt += ncpy;
713 noff += ncpy;
714 if (ncnt == ntotal) {
715 swap_n(data_buf, ntotal);
716 ncnt = 0;
717 if (items[curr_id].has_ts) {
718 ncnt = 0;
719 ntotal = 0;
720 state = STP_STATE_TS;
721 } else {
722 items[curr_id].cb(*data64, 0);
723 curr_id = STP_INVALID;
724 state = STP_STATE_OP;
725 ntotal = 0;
726 ncnt = 0;
727 }
728 }
729 break;
730 }
731 case STP_STATE_TS:
732 if (ntotal == 0 && ncnt == 0) {
733 /* TS to be read but length is unknown yet */
734 *ts64 = 0;
735 ntotal = get_nibble(data, noff);
736 noff++;
737 /* Values up to 12 represents number of nibbles on which
738 * timestamp is encoded. Above are the exceptions:
739 * - 13 => 14 nibbles
740 * - 14 => 16 nibbles
741 */
742 if (ntotal > 12) {
743 if (ntotal == 13) {
744 ntotal = 14;
745 base_ts = ~BIT64_MASK(4 * ntotal) & prev_ts;
746 } else {
747 ntotal = 16;
748 base_ts = 0;
749 }
750 } else {
751 base_ts = ~BIT64_MASK(4 * ntotal) & prev_ts;
752 }
753
754 } else {
755 size_t ncpy = MIN(ntotal - ncnt, nlen - noff);
756
757 get_nibbles(data, noff, ts_buf, ncnt, ncpy);
758 ncnt += ncpy;
759 noff += ncpy;
760 if (ncnt == ntotal) {
761 swap_n(ts_buf, ntotal);
762 prev_ts = base_ts | *ts64;
763 items[curr_id].cb(*data64, prev_ts);
764 curr_id = STP_INVALID;
765 state = STP_STATE_OP;
766 ntotal = 0;
767 ncnt = 0;
768 }
769 }
770 break;
771
772 default:
773 break;
774 }
775 } while (noff < nlen);
776
777 noff = 0;
778
779 return 0;
780 }
781
mipi_stp_decoder_init(const struct mipi_stp_decoder_config * config)782 int mipi_stp_decoder_init(const struct mipi_stp_decoder_config *config)
783 {
784 state = config->start_out_of_sync ? STP_STATE_OUT_OF_SYNC : STP_STATE_OP;
785 ntotal = 0;
786 ncnt = 0;
787 cfg = *config;
788 prev_ts = 0;
789 base_ts = 0;
790 noff = 0;
791
792 return 0;
793 }
794