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