1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) COPYRIGHT 2019 ARM Limited. All rights reserved.
4  * Author: James.Qian.Wang <james.qian.wang@arm.com>
5  *
6  */
7 #include <drm/drm_print.h>
8 
9 #include "komeda_dev.h"
10 
11 struct komeda_str {
12 	char *str;
13 	u32 sz;
14 	u32 len;
15 };
16 
17 /* return 0 on success,  < 0 on no space.
18  */
19 static int komeda_sprintf(struct komeda_str *str, const char *fmt, ...)
20 {
21 	va_list args;
22 	int num, free_sz;
23 	int err;
24 
25 	free_sz = str->sz - str->len - 1;
26 	if (free_sz <= 0)
27 		return -ENOSPC;
28 
29 	va_start(args, fmt);
30 
31 	num = vsnprintf(str->str + str->len, free_sz, fmt, args);
32 
33 	va_end(args);
34 
35 	if (num < free_sz) {
36 		str->len += num;
37 		err = 0;
38 	} else {
39 		str->len = str->sz - 1;
40 		err = -ENOSPC;
41 	}
42 
43 	return err;
44 }
45 
46 static void evt_sprintf(struct komeda_str *str, u64 evt, const char *msg)
47 {
48 	if (evt)
49 		komeda_sprintf(str, msg);
50 }
51 
52 static void evt_str(struct komeda_str *str, u64 events)
53 {
54 	if (events == 0ULL) {
55 		komeda_sprintf(str, "None");
56 		return;
57 	}
58 
59 	evt_sprintf(str, events & KOMEDA_EVENT_VSYNC, "VSYNC|");
60 	evt_sprintf(str, events & KOMEDA_EVENT_FLIP, "FLIP|");
61 	evt_sprintf(str, events & KOMEDA_EVENT_EOW, "EOW|");
62 	evt_sprintf(str, events & KOMEDA_EVENT_MODE, "OP-MODE|");
63 
64 	evt_sprintf(str, events & KOMEDA_EVENT_URUN, "UNDERRUN|");
65 	evt_sprintf(str, events & KOMEDA_EVENT_OVR, "OVERRUN|");
66 
67 	/* GLB error */
68 	evt_sprintf(str, events & KOMEDA_ERR_MERR, "MERR|");
69 	evt_sprintf(str, events & KOMEDA_ERR_FRAMETO, "FRAMETO|");
70 
71 	/* DOU error */
72 	evt_sprintf(str, events & KOMEDA_ERR_DRIFTTO, "DRIFTTO|");
73 	evt_sprintf(str, events & KOMEDA_ERR_FRAMETO, "FRAMETO|");
74 	evt_sprintf(str, events & KOMEDA_ERR_TETO, "TETO|");
75 	evt_sprintf(str, events & KOMEDA_ERR_CSCE, "CSCE|");
76 
77 	/* LPU errors or events */
78 	evt_sprintf(str, events & KOMEDA_EVENT_IBSY, "IBSY|");
79 	evt_sprintf(str, events & KOMEDA_ERR_AXIE, "AXIE|");
80 	evt_sprintf(str, events & KOMEDA_ERR_ACE0, "ACE0|");
81 	evt_sprintf(str, events & KOMEDA_ERR_ACE1, "ACE1|");
82 	evt_sprintf(str, events & KOMEDA_ERR_ACE2, "ACE2|");
83 	evt_sprintf(str, events & KOMEDA_ERR_ACE3, "ACE3|");
84 
85 	/* LPU TBU errors*/
86 	evt_sprintf(str, events & KOMEDA_ERR_TCF, "TCF|");
87 	evt_sprintf(str, events & KOMEDA_ERR_TTNG, "TTNG|");
88 	evt_sprintf(str, events & KOMEDA_ERR_TITR, "TITR|");
89 	evt_sprintf(str, events & KOMEDA_ERR_TEMR, "TEMR|");
90 	evt_sprintf(str, events & KOMEDA_ERR_TTF, "TTF|");
91 
92 	/* CU errors*/
93 	evt_sprintf(str, events & KOMEDA_ERR_CPE, "COPROC|");
94 	evt_sprintf(str, events & KOMEDA_ERR_ZME, "ZME|");
95 	evt_sprintf(str, events & KOMEDA_ERR_CFGE, "CFGE|");
96 	evt_sprintf(str, events & KOMEDA_ERR_TEMR, "TEMR|");
97 
98 	if (str->len > 0 && (str->str[str->len - 1] == '|')) {
99 		str->str[str->len - 1] = 0;
100 		str->len--;
101 	}
102 }
103 
104 static bool is_new_frame(struct komeda_events *a)
105 {
106 	return (a->pipes[0] | a->pipes[1]) &
107 	       (KOMEDA_EVENT_FLIP | KOMEDA_EVENT_EOW);
108 }
109 
110 void komeda_print_events(struct komeda_events *evts)
111 {
112 	u64 print_evts = KOMEDA_ERR_EVENTS;
113 	static bool en_print = true;
114 
115 	/* reduce the same msg print, only print the first evt for one frame */
116 	if (evts->global || is_new_frame(evts))
117 		en_print = true;
118 	if (!en_print)
119 		return;
120 
121 	if ((evts->global | evts->pipes[0] | evts->pipes[1]) & print_evts) {
122 		char msg[256];
123 		struct komeda_str str;
124 
125 		str.str = msg;
126 		str.sz  = sizeof(msg);
127 		str.len = 0;
128 
129 		komeda_sprintf(&str, "gcu: ");
130 		evt_str(&str, evts->global);
131 		komeda_sprintf(&str, ", pipes[0]: ");
132 		evt_str(&str, evts->pipes[0]);
133 		komeda_sprintf(&str, ", pipes[1]: ");
134 		evt_str(&str, evts->pipes[1]);
135 
136 		DRM_ERROR("err detect: %s\n", msg);
137 
138 		en_print = false;
139 	}
140 }
141