1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/kernel.h>
7 #include <zephyr/logging/log_frontend.h>
8 #include <zephyr/logging/log_frontend_stmesp.h>
9 #include <zephyr/logging/log_frontend_stmesp_demux.h>
10 #include <zephyr/logging/log_output_dict.h>
11 #include <zephyr/logging/log_ctrl.h>
12 #include <zephyr/logging/log_msg.h>
13 #include <zephyr/sys/cbprintf.h>
14 #ifdef CONFIG_NRF_ETR
15 #include <zephyr/drivers/misc/coresight/nrf_etr.h>
16 #endif
17
18 /* Only 32 bit platforms supported. */
19 BUILD_ASSERT(sizeof(void *) == sizeof(uint32_t));
20
21 #define LOG_FRONTEND_STM_NO_SOURCE 0xFFFF
22
23 #define EARLY_BUF_SIZE CONFIG_LOG_FRONTEND_STMESP_EARLY_BUF_SIZE
24
25 #define LEN_SZ sizeof(uint32_t)
26
27 #define STMESP_FLUSH_WORD 0xaabbccdd
28
29 #define STM_FLAG(reg) \
30 stmesp_flag(reg, 1, false, IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_GUARANTEED_ACCESS))
31
32 #define STM_D8(reg, data, timestamp, marked) \
33 stmesp_data8(reg, data, timestamp, marked, \
34 IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_GUARANTEED_ACCESS))
35
36 #define STM_D16(reg, data, timestamp, marked) \
37 stmesp_data16(reg, data, timestamp, marked, \
38 IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_GUARANTEED_ACCESS))
39
40 #define STM_D32(reg, data, timestamp, marked) \
41 stmesp_data32(reg, data, timestamp, marked, \
42 IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_GUARANTEED_ACCESS))
43
44 /* Buffer for storing frontend data before STM/ETR is ready for usage.
45 * When notification about ETR readiness is received content of this buffer is
46 * written to the STM stimulus port.
47 */
48 static atomic_t stmesp_chan_cnt;
49
50 static uint8_t early_buf[EARLY_BUF_SIZE] __aligned(sizeof(uint32_t));
51 static uint32_t early_buf_idx;
52 static struct k_spinlock lock;
53
54 /* Flag indicating that STM/ETR is ready for use. */
55 static bool etr_rdy;
56
57 /* Number of messages dropped due to too small early buffer. */
58 static uint32_t dropped;
59
60 /* Flag indicating that logging is in the panic mode. */
61 static bool in_panic;
62
63 static atomic_t new_data;
64
65 /* Enum used for type bit field in the message. */
66 enum stm_msg_type_log_dict {
67 /* Dictionary-based log message */
68 STM_MSG_TYPE_LOG_DICT = 0,
69 /* Reserved for future use. */
70 STM_MSG_TYPE_RESERVED = 1,
71 };
72
73 /* Descriptor of the dictionary based logging message. */
74 struct stm_log_dict_msg_desc {
75 /* Structure version. Current version 0. */
76 uint32_t ver: 2;
77
78 /* Type. Set 0 as this is a logging message descriptor. */
79 uint32_t type: 1;
80
81 /* Severity level. */
82 uint32_t level: 3;
83
84 /* Data length, non-zero fox hexdump message. */
85 uint32_t data_len: 12;
86
87 /* Source ID. Source index as ordered in the memory section. */
88 uint32_t source_id: 12;
89
90 /* Reserved for future use. */
91 uint32_t reserved: 2;
92 };
93
94 union stm_log_dict_hdr {
95 struct stm_log_dict_msg_desc hdr;
96 uint32_t raw;
97 };
98
99 /* Dictionary header initializer. */
100 #define DICT_HDR_INITIALIZER(_level, _source_id, _data_len) \
101 { \
102 .hdr = {.ver = CONFIG_LOG_FRONTEND_STMESP_DICT_VER, \
103 .type = STM_MSG_TYPE_LOG_DICT, \
104 .level = _level, \
105 .data_len = _data_len, \
106 .source_id = _source_id, \
107 .reserved = 0 } \
108 }
109
110 /* Align early buffer index to a 32 bit word. */
early_buf_align_idx(void)111 static inline void early_buf_align_idx(void)
112 {
113 uint32_t rem = early_buf_idx & 0x3;
114
115 if (rem) {
116 early_buf_idx += (sizeof(uint32_t) - rem);
117 }
118 }
119
120 /* Get address where length is written. Location is used in the dictionary mode
121 * where length of the message is only known once whole message is written.
122 * Calculated length is written to the length field location.
123 */
early_buf_len_loc(void)124 static inline uint32_t *early_buf_len_loc(void)
125 {
126 early_buf_align_idx();
127
128 uint32_t *loc = (uint32_t *)&early_buf[early_buf_idx];
129
130 early_buf_idx += LEN_SZ;
131
132 return loc;
133 }
134
135 /* Check if there is space for requested amount of data. */
early_buf_has_space(uint32_t len)136 static inline bool early_buf_has_space(uint32_t len)
137 {
138 return (EARLY_BUF_SIZE - early_buf_idx) >= len;
139 }
140
141 /* Calculate length of the message. It is calculated by taking current write
142 * location and length location (which is at the beginning of the current message.
143 * Used in dictionary mode.
144 */
early_buf_get_len(uint32_t * len_loc)145 static inline uint32_t early_buf_get_len(uint32_t *len_loc)
146 {
147 if (early_buf_idx == EARLY_BUF_SIZE) {
148 return 0;
149 }
150
151 return (uint32_t)((uintptr_t)&early_buf[early_buf_idx] - (uintptr_t)len_loc - LEN_SZ);
152 }
153
154 /* Check if there is available space for the message. If yes, write length field
155 * and return true. If allocation fails it sets next length field to 0 to indicate
156 * that the buffer is full.
157 */
early_buf_alloc(uint32_t len)158 static inline bool early_buf_alloc(uint32_t len)
159 {
160 early_buf_align_idx();
161
162 if (early_buf_has_space(len + LEN_SZ)) {
163 *(uint32_t *)&early_buf[early_buf_idx] = len;
164 early_buf_idx += LEN_SZ;
165 return true;
166 }
167
168 if (early_buf_has_space(LEN_SZ)) {
169 *(uint32_t *)&early_buf[early_buf_idx] = 0;
170 }
171
172 return false;
173 }
174
175 /* Switch to read mode. Start reading from the beginning. */
early_buf_read_mode(void)176 static inline void early_buf_read_mode(void)
177 {
178 early_buf_idx = 0;
179 }
180
181 /* Get message. Returns 0 if no messages. */
early_buf_get_data(void ** buf)182 static inline uint32_t early_buf_get_data(void **buf)
183 {
184 early_buf_align_idx();
185
186 if (early_buf_has_space(LEN_SZ)) {
187 uint32_t len = *(uint32_t *)&early_buf[early_buf_idx];
188
189 *buf = &early_buf[early_buf_idx + LEN_SZ];
190 early_buf_idx += len + LEN_SZ;
191 return len;
192 }
193
194 return 0;
195 }
196
early_buf_put_data(const void * buf,size_t len)197 static void early_buf_put_data(const void *buf, size_t len)
198 {
199 if (early_buf_has_space(len)) {
200 memcpy(&early_buf[early_buf_idx], buf, len);
201 early_buf_idx += len;
202 } else {
203 early_buf_idx = EARLY_BUF_SIZE;
204 }
205 }
206
early_package_cb(const void * buf,size_t len,void * ctx)207 static int early_package_cb(const void *buf, size_t len, void *ctx)
208 {
209 ARG_UNUSED(ctx);
210
211 early_buf_put_data(buf, len);
212
213 return 0;
214 }
215
write_data(const void * data,size_t len,STMESP_Type * const stm_esp)216 static inline void write_data(const void *data, size_t len, STMESP_Type *const stm_esp)
217 {
218 const uint8_t *p8 = data;
219 const uint32_t *p32;
220 uint32_t unaligned;
221
222 if (!len) {
223 return;
224 }
225
226 /* Start by writing using D8 or D16 until pointer is word aligned. */
227 unaligned = (uintptr_t)data & 0x00000003UL;
228 if (unaligned != 0) {
229 unaligned = 4 - unaligned;
230 unaligned = MIN(len, unaligned);
231
232 len -= unaligned;
233
234 switch (unaligned) {
235 case 3:
236 STM_D8(stm_esp, *p8++, false, false);
237 STM_D16(stm_esp, *(uint16_t *)p8, false, false);
238 p8 += sizeof(uint16_t);
239 break;
240 case 2:
241 if (len) {
242 STM_D16(stm_esp, *(uint16_t *)p8, false, false);
243 p8 += sizeof(uint16_t);
244 } else {
245 /* If len 0 then it means that even though 2 bytes are
246 * to be copied we can have address which is not aligned
247 * to 2 bytes.
248 */
249 STM_D8(stm_esp, *p8++, false, false);
250 STM_D8(stm_esp, *p8++, false, false);
251 }
252 break;
253 default:
254 /* 1 byte to align. */
255 STM_D8(stm_esp, *p8++, false, false);
256 }
257 }
258
259 p32 = (const uint32_t *)p8;
260
261 /* Use D32 to write as much data as possible. */
262 while (len >= sizeof(uint32_t)) {
263 STM_D32(stm_esp, *p32++, false, false);
264 len -= sizeof(uint32_t);
265 }
266
267 /* Write tail using D16 or D8. Address is word aligned at that point. */
268 if (len) {
269 p8 = (const uint8_t *)p32;
270 switch (len) {
271 case 2:
272 STM_D16(stm_esp, *(uint16_t *)p8, false, false);
273 p8 += sizeof(uint16_t);
274 break;
275 case 3:
276 STM_D16(stm_esp, *(uint16_t *)p8, false, false);
277 p8 += sizeof(uint16_t);
278 /* fallthrough */
279 default:
280 /* 1 byte to align. */
281 STM_D8(stm_esp, *p8++, false, false);
282 break;
283 }
284 }
285 }
286
package_cb(const void * buf,size_t len,void * ctx)287 static int package_cb(const void *buf, size_t len, void *ctx)
288 {
289 write_data(buf, len, (STMESP_Type *const)ctx);
290
291 return len;
292 }
293
294 /* Get STM channel to use. Ensure that channel is unique for given priority level.
295 * This way we know that writing to that channel will not be interrupted by
296 * another log message writing to the same channel.
297 */
get_channel(void)298 static inline uint16_t get_channel(void)
299 {
300 return (atomic_inc(&stmesp_chan_cnt) & 0x7F) + 1;
301 }
302
303 /* Convert pointer to the source structure to the source ID. */
get_source_id(const void * source)304 static inline int16_t get_source_id(const void *source)
305 {
306 if (source != NULL) {
307 return log_source_id(source);
308 }
309
310 return LOG_FRONTEND_STM_NO_SOURCE;
311 }
312
packet_end(STMESP_Type * stm_esp)313 static void packet_end(STMESP_Type *stm_esp)
314 {
315 if (IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_MSG_END_TIMESTAMP)) {
316 STM_D8(stm_esp, 0, true, true);
317 } else {
318 STM_FLAG(stm_esp);
319 }
320 atomic_set(&new_data, 1);
321 }
322
323 /* Common function to end the message when STMESP is not ready. */
early_msg_end(uint32_t * len_loc)324 static inline void early_msg_end(uint32_t *len_loc)
325 {
326 *len_loc = early_buf_get_len(len_loc);
327 if (*len_loc == 0) {
328 dropped++;
329 }
330 }
331
332 #if CONFIG_LOG_FRONTEND_STMESP_FSC
log_frontend_msg(const void * source,const struct log_msg_desc desc,uint8_t * package,const void * data)333 void log_frontend_msg(const void *source, const struct log_msg_desc desc, uint8_t *package,
334 const void *data)
335 {
336 uint16_t strl[4];
337 union log_frontend_stmesp_demux_header hdr = {.log = {.level = desc.level}};
338 bool use_timestamp = desc.level != LOG_LEVEL_INTERNAL_RAW_STRING;
339 const char *sname;
340 static const char null_c = '\0';
341 size_t sname_len;
342 int package_len;
343 int total_len;
344 static const uint32_t flags =
345 CBPRINTF_PACKAGE_CONVERT_RW_STR | CBPRINTF_PACKAGE_CONVERT_RO_STR;
346
347 sname = log_source_name_get(0, get_source_id(source));
348 if (sname) {
349 sname_len = strlen(sname) + 1;
350 } else {
351 sname = &null_c;
352 sname_len = 1;
353 }
354 total_len = desc.data_len + sname_len /* null terminator */;
355
356 package_len = cbprintf_package_convert(package, desc.package_len, NULL, NULL, flags, strl,
357 ARRAY_SIZE(strl));
358 hdr.log.total_len = total_len + package_len;
359 hdr.log.package_len = package_len;
360
361 if ((EARLY_BUF_SIZE == 0) || etr_rdy) {
362 STMESP_Type *stm_esp;
363 int err;
364
365 err = stmesp_get_port(get_channel(), &stm_esp);
366 if (err < 0) {
367 return;
368 }
369
370 if (IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_MSG_END_TIMESTAMP)) {
371 STM_D32(stm_esp, hdr.raw, false, false);
372 } else {
373 STM_D32(stm_esp, hdr.raw, use_timestamp, true);
374 }
375 (void)cbprintf_package_convert(package, desc.package_len, package_cb, stm_esp,
376 flags, strl, ARRAY_SIZE(strl));
377 write_data(sname, sname_len, stm_esp);
378 if (data) {
379 write_data(data, desc.data_len, stm_esp);
380 }
381 packet_end(stm_esp);
382
383 } else {
384 k_spinlock_key_t key = k_spin_lock(&lock);
385
386 if ((EARLY_BUF_SIZE == 0) ||
387 (early_buf_alloc(hdr.log.total_len + sizeof(hdr)) == false)) {
388 dropped++;
389 k_spin_unlock(&lock, key);
390 return;
391 }
392
393 early_buf_put_data((const uint8_t *)&hdr, sizeof(hdr));
394 (void)cbprintf_package_convert(package, desc.package_len, early_package_cb, NULL,
395 flags, strl, ARRAY_SIZE(strl));
396 early_buf_put_data(sname, sname_len);
397 if (data) {
398 early_buf_put_data(data, desc.data_len);
399 }
400
401 k_spin_unlock(&lock, key);
402 }
403 }
404
405 #else /* CONFIG_LOG_FRONTEND_STMESP_FSC */
406
log_frontend_msg(const void * source,const struct log_msg_desc desc,uint8_t * package,const void * data)407 void log_frontend_msg(const void *source, const struct log_msg_desc desc, uint8_t *package,
408 const void *data)
409 {
410 static const uint32_t flags = CBPRINTF_PACKAGE_CONVERT_RW_STR;
411 union stm_log_dict_hdr dict_desc =
412 DICT_HDR_INITIALIZER(desc.level, get_source_id(source), 0);
413
414 if ((EARLY_BUF_SIZE == 0) || etr_rdy) {
415 STMESP_Type *stm_esp;
416 int err;
417
418 err = stmesp_get_port(get_channel(), &stm_esp);
419 if (err < 0) {
420 return;
421 }
422
423 if (IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_MSG_END_TIMESTAMP)) {
424 STM_D32(stm_esp, dict_desc.raw, false, false);
425 } else {
426 STM_D32(stm_esp, dict_desc.raw, true, true);
427 }
428 (void)cbprintf_package_convert(package, desc.package_len, package_cb, stm_esp,
429 flags, NULL, 0);
430 if (data) {
431 package_cb(data, desc.data_len, stm_esp);
432 }
433 packet_end(stm_esp);
434 } else {
435 k_spinlock_key_t key;
436 uint32_t *len_loc;
437
438 key = k_spin_lock(&lock);
439 len_loc = early_buf_len_loc();
440 early_package_cb(&dict_desc.raw, sizeof(dict_desc.raw), NULL);
441 (void)cbprintf_package_convert(package, desc.package_len, early_package_cb, NULL,
442 flags, NULL, 0);
443 if (data) {
444 early_package_cb(data, desc.data_len, NULL);
445 }
446 early_msg_end(len_loc);
447 k_spin_unlock(&lock, key);
448 }
449 }
450
451 /* Common function for optimized message (log with 0-2 arguments) which is used in
452 * case when STMESP is not yet ready.
453 */
early_msg_start(uint32_t level,const void * source,uint32_t package_hdr,const char * fmt)454 static inline uint32_t *early_msg_start(uint32_t level, const void *source, uint32_t package_hdr,
455 const char *fmt)
456 {
457 union stm_log_dict_hdr dict_desc = DICT_HDR_INITIALIZER(level, get_source_id(source), 0);
458 uint32_t fmt32 = (uint32_t)fmt;
459 uint32_t *len_loc = early_buf_len_loc();
460
461 early_package_cb(&dict_desc.raw, sizeof(dict_desc.raw), NULL);
462 early_package_cb(&package_hdr, sizeof(package_hdr), NULL);
463 early_package_cb(&fmt32, sizeof(fmt32), NULL);
464
465 return len_loc;
466 }
467
468 /* Common function for optimized message (log with 0-2 arguments) which writes to STMESP */
msg_start(STMESP_Type * stm_esp,uint32_t level,const void * source,uint32_t package_hdr,const char * fmt)469 static inline void msg_start(STMESP_Type *stm_esp, uint32_t level, const void *source,
470 uint32_t package_hdr, const char *fmt)
471
472 {
473 union stm_log_dict_hdr dict_desc = DICT_HDR_INITIALIZER(level, get_source_id(source), 0);
474
475 if (IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_MSG_END_TIMESTAMP)) {
476 STM_D32(stm_esp, dict_desc.raw, false, false);
477 } else {
478 STM_D32(stm_esp, dict_desc.raw, true, true);
479 }
480 STM_D32(stm_esp, package_hdr, false, false);
481 STM_D32(stm_esp, (uint32_t)fmt, false, false);
482 }
483
log_frontend_simple_0(const void * source,uint32_t level,const char * fmt)484 void log_frontend_simple_0(const void *source, uint32_t level, const char *fmt)
485 {
486 static const union cbprintf_package_hdr package_hdr = {.desc = {.len = 2}};
487
488 if ((EARLY_BUF_SIZE == 0) || etr_rdy) {
489 STMESP_Type *stm_esp;
490 int err;
491
492 err = stmesp_get_port(get_channel(), &stm_esp);
493 if (err < 0) {
494 return;
495 }
496
497 msg_start(stm_esp, level, source, (uint32_t)package_hdr.raw, fmt);
498 packet_end(stm_esp);
499 return;
500 }
501
502 uint32_t *len_loc;
503 k_spinlock_key_t key;
504
505 key = k_spin_lock(&lock);
506 len_loc = early_msg_start(level, source, (uint32_t)package_hdr.raw, fmt);
507 early_msg_end(len_loc);
508 k_spin_unlock(&lock, key);
509 }
510
log_frontend_simple_1(const void * source,uint32_t level,const char * fmt,uint32_t arg)511 void log_frontend_simple_1(const void *source, uint32_t level, const char *fmt, uint32_t arg)
512 {
513 static const union cbprintf_package_hdr package_hdr = {.desc = {.len = 2 + 1}};
514
515 if ((EARLY_BUF_SIZE == 0) || etr_rdy) {
516 STMESP_Type *stm_esp;
517 int err;
518
519 err = stmesp_get_port(get_channel(), &stm_esp);
520 if (err < 0) {
521 return;
522 }
523
524 msg_start(stm_esp, level, source, (uint32_t)package_hdr.raw, fmt);
525 STM_D32(stm_esp, arg, false, false);
526 packet_end(stm_esp);
527 return;
528 }
529
530 uint32_t *len_loc;
531 k_spinlock_key_t key;
532
533 key = k_spin_lock(&lock);
534 len_loc = early_msg_start(level, source, (uint32_t)package_hdr.raw, fmt);
535 early_package_cb(&arg, sizeof(arg), NULL);
536 early_msg_end(len_loc);
537 k_spin_unlock(&lock, key);
538 }
539
log_frontend_simple_2(const void * source,uint32_t level,const char * fmt,uint32_t arg0,uint32_t arg1)540 void log_frontend_simple_2(const void *source, uint32_t level, const char *fmt, uint32_t arg0,
541 uint32_t arg1)
542 {
543 static const union cbprintf_package_hdr package_hdr = {.desc = {.len = 2 + 2}};
544
545 if ((EARLY_BUF_SIZE == 0) || etr_rdy) {
546 STMESP_Type *stm_esp;
547 int err;
548
549 err = stmesp_get_port(get_channel(), &stm_esp);
550 if (err < 0) {
551 return;
552 }
553
554 msg_start(stm_esp, level, source, (uint32_t)package_hdr.raw, fmt);
555 STM_D32(stm_esp, arg0, false, false);
556 STM_D32(stm_esp, arg1, false, false);
557 packet_end(stm_esp);
558 return;
559 }
560
561 uint32_t *len_loc;
562 k_spinlock_key_t key;
563
564 key = k_spin_lock(&lock);
565 len_loc = early_msg_start(level, source, (uint32_t)package_hdr.raw, fmt);
566 early_package_cb(&arg0, sizeof(arg0), NULL);
567 early_package_cb(&arg1, sizeof(arg1), NULL);
568 early_msg_end(len_loc);
569 k_spin_unlock(&lock, key);
570 }
571
572 #endif /* CONFIG_LOG_FRONTEND_STMESP_FSC */
573
log_frontend_panic(void)574 void log_frontend_panic(void)
575 {
576 in_panic = true;
577 #ifdef CONFIG_NRF_ETR
578 nrf_etr_flush();
579 #endif
580 }
581
log_frontend_init(void)582 void log_frontend_init(void)
583 {
584 #if defined(CONFIG_LOG_FRONTEND_STPESP_TURBO_SOURCE_PORT_ID) && !defined(CONFIG_NRF_ETR)
585 /* Send location of section with constant source data. It is used by the
586 * application core to retrieve source names of log messages coming from
587 * coprocessors (FLPR and PPR).
588 */
589 TYPE_SECTION_START_EXTERN(struct log_source_const_data, log_const);
590 STMESP_Type *stm_esp;
591 uintptr_t log_const_start;
592
593 (void)stmesp_get_port(CONFIG_LOG_FRONTEND_STPESP_TURBO_SOURCE_PORT_ID, &stm_esp);
594 log_const_start = (uintptr_t)TYPE_SECTION_START(log_const);
595 STM_D32(stm_esp, log_const_start, false, true);
596 #endif
597 }
598
log_frontend_stmesp_dummy_write(void)599 void log_frontend_stmesp_dummy_write(void)
600 {
601 #define STMESP_DUMMY_WORD 0xaabbccdd
602
603 STMESP_Type *stm_esp;
604
605 (void)stmesp_get_port(CONFIG_LOG_FRONTEND_STMESP_FLUSH_PORT_ID, &stm_esp);
606 STM_D32(stm_esp, STMESP_DUMMY_WORD, false, false);
607 }
608
log_frontend_stmesp_pre_sleep(void)609 void log_frontend_stmesp_pre_sleep(void)
610 {
611 bool use_stm = etr_rdy || (EARLY_BUF_SIZE == 0);
612
613 if (!use_stm || new_data == 0) {
614 return;
615 }
616
617 for (uint32_t i = 0; i < CONFIG_LOG_FRONTEND_STMESP_FLUSH_COUNT; i++) {
618 log_frontend_stmesp_dummy_write();
619 }
620
621 atomic_set(&new_data, 0);
622 }
623
624 #if EARLY_BUF_SIZE > 0
log_frontend_stmesp_etr_ready(void)625 int log_frontend_stmesp_etr_ready(void)
626 {
627 STMESP_Type *stm_esp;
628 uint16_t len;
629 uint32_t *buf = NULL;
630 int err;
631
632 err = stmesp_get_port(get_channel(), &stm_esp);
633 if (err < 0) {
634 return -EIO;
635 }
636
637 early_buf_read_mode();
638
639 while ((len = early_buf_get_data((void **)&buf)) > 0) {
640 if (IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_MSG_END_TIMESTAMP)) {
641 STM_D32(stm_esp, *buf, false, false);
642 } else {
643 /* Write first word with Marked and timestamp. */
644 STM_D32(stm_esp, *buf, true, true);
645 }
646 buf++;
647 len -= sizeof(uint32_t);
648
649 /* Write remaining data as raw data. */
650 write_data(buf, len, stm_esp);
651
652 /* Flag the end. */
653 packet_end(stm_esp);
654 }
655
656 etr_rdy = true;
657
658 return 0;
659 }
660 #endif /* EARLY_BUF_SIZE > 0 */
661
log_frontend_stmesp_log0(const void * source,uint32_t x)662 void log_frontend_stmesp_log0(const void *source, uint32_t x)
663 {
664 STMESP_Type *port;
665 int err = stmesp_get_port((uint32_t)x + 0x8000, &port);
666 uint16_t source_id = log_source_id(source);
667
668 __ASSERT_NO_MSG(err == 0);
669 if (err == 0) {
670 stmesp_data16(port, source_id, true, true,
671 IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_GUARANTEED_ACCESS));
672 }
673 }
674
log_frontend_stmesp_log1(const void * source,uint32_t x,uint32_t arg)675 void log_frontend_stmesp_log1(const void *source, uint32_t x, uint32_t arg)
676 {
677 STMESP_Type *port;
678 int err = stmesp_get_port((uint32_t)x + 0x8000, &port);
679 uint16_t source_id = log_source_id(source);
680
681 __ASSERT_NO_MSG(err == 0);
682 if (err == 0) {
683 stmesp_data16(port, source_id, false, true,
684 IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_GUARANTEED_ACCESS));
685 stmesp_data32(port, arg, true, true,
686 IS_ENABLED(CONFIG_LOG_FRONTEND_STMESP_GUARANTEED_ACCESS));
687 }
688 }
689