blob: 216b21edb4d2ce27129ddbee12a34ad1c8440156 [file] [log] [blame]
leng.fang91856072024-06-07 14:12:54 +08001#include <pthread.h>
2
3#include "modepolicyfunc.h"
4#include "DisplayAdapter.h"
5#include "modepolicy_aml.h"
6
leng.fang3e8a4b52024-07-24 14:51:30 +08007weston_ctx_list *gCtx_list = NULL;
leng.fang91856072024-06-07 14:12:54 +08008static int g_activeLevel = 3;
9
leng.fang3e8a4b52024-07-24 14:51:30 +080010/* if prop set need change mode, add it to this */
leng.fang13fd3982024-07-03 19:09:58 +080011static char *prop_changed_and_mode[] = {
12 "color_space",
13 "color_depth"
14};
15
leng.fang3e8a4b52024-07-24 14:51:30 +080016static weston_ctx_list *weston_get_ctx_list()
17{
18 if (!gCtx_list) {
19 gCtx_list = (weston_ctx_list *)calloc(1, sizeof(*gCtx_list));
20 wl_list_init(&gCtx_list->ctx_list);
21 }
22 return gCtx_list;
23}
24
leng.fang69a93e32024-08-08 16:31:01 +080025static weston_ctx *weston_get_ctx_for_head(struct weston_head *head)
leng.fang91856072024-06-07 14:12:54 +080026{
leng.fang3e8a4b52024-07-24 14:51:30 +080027 weston_ctx_list *ctx_list = weston_get_ctx_list();
28 weston_ctx *ctx, *tmp;
29
30 wl_list_for_each(ctx, &ctx_list->ctx_list, link) {
leng.fang69a93e32024-08-08 16:31:01 +080031 if (ctx->head == head)
leng.fang3e8a4b52024-07-24 14:51:30 +080032 return ctx;
leng.fang91856072024-06-07 14:12:54 +080033 }
leng.fang3e8a4b52024-07-24 14:51:30 +080034 return NULL;
leng.fang91856072024-06-07 14:12:54 +080035}
36
leng.fang69a93e32024-08-08 16:31:01 +080037weston_ctx *weston_get_ctx()
38{
39 weston_ctx_list *ctx_list = weston_get_ctx_list();
40
41 return weston_get_ctx_for_head(ctx_list->head);
42}
43
leng.fang91856072024-06-07 14:12:54 +080044static void weston_prop_list_init(weston_ctx *ctx)
45{
46 prop_info *info, *tmp;
47 if (!wl_list_empty(&ctx->prop_list)) {
48 wl_list_for_each_safe(info, tmp, &ctx->prop_list, link) {
49 wl_list_remove(&info->link);
50 free(info);
51 }
52 }
53 wl_list_init(&ctx->prop_list);
54}
55
56static int weston_add_property_item(weston_ctx *ctx,
57 const char *name, int id, int prop_id)
58{
59 prop_info *info;
60
61 wl_list_for_each(info, &ctx->prop_list, link) {
62 if (!strcmp(name, info->name) && info->item_id == id)
63 return 0;
64 }
65
66 info = (prop_info *)calloc(1, sizeof(*info));
67 memcpy(info->name, name, sizeof(info->name));
68 info->item_id = id;
69 info->prop_id = prop_id;
70 info->need_change = 0;
71 MESON_LOGD("ctx: %p, name: %s, id: %d, prop_id: %d\n", ctx, name, id, prop_id);
72 wl_list_insert(&ctx->prop_list, &info->link);
73 return 0;
74}
75
76static int weston_add_property(weston_ctx *ctx, int id, int type)
77{
78 int i, len;
79 int value = 0;
80 drmModePropertyRes *propRes;
81 drmModeObjectProperties *props;
82
83 props = drmModeObjectGetProperties( ctx->drm_fd, id, type );
84 if ( props ) {
85 for ( i= 0; i < props->count_props; ++i ) {
86 propRes = drmModeGetProperty( ctx->drm_fd, props->props[i] );
87 if ( propRes ) {
88 weston_add_property_item(ctx, propRes->name, id, props->props[i]);
89 drmModeFreeProperty( propRes );
90 propRes = 0;
91 }
92 }
93 drmModeFreeObjectProperties( props );
94 props = 0;
95 }
96 return value;
97}
98
99static int weston_get_property_value(weston_ctx *ctx, const char * key, int id, int type)
100{
101 int i, len;
102 int value = 0;
103 drmModePropertyRes *propRes;
104 drmModeObjectProperties *props;
105
106 props = drmModeObjectGetProperties( ctx->drm_fd, id, type );
107 if ( props ) {
108 for ( i= 0; i < props->count_props; ++i ) {
109 propRes = drmModeGetProperty( ctx->drm_fd, props->props[i] );
110 if ( propRes ) {
111 len = strlen(propRes->name);
112 if ( !strncmp( propRes->name, key, len) ) {
113 MESON_LOGD("property %d name (%s) value (%lld)",
114 props->props[i], propRes->name, props->prop_values[i] );
115 value = props->prop_values[i];
116 drmModeFreeProperty( propRes );
117 propRes = 0;
118 break;
119 }
120 drmModeFreeProperty( propRes );
121 propRes = 0;
122 }
123 }
124 drmModeFreeObjectProperties( props );
125 props = 0;
126 }
127 return value;
128}
129
130static int weston_get_connector_property(const char * key)
131{
132 weston_ctx *ctx = weston_get_ctx();
133
leng.fang3e8a4b52024-07-24 14:51:30 +0800134 if (!ctx)
135 return 0;
136
leng.fang91856072024-06-07 14:12:54 +0800137 return weston_get_property_value(ctx, key, ctx->conn->connector_id, DRM_MODE_OBJECT_CONNECTOR);
138}
139
140static int weston_get_crtc_property(const char * key)
141{
142 weston_ctx *ctx = weston_get_ctx();
143
leng.fang3e8a4b52024-07-24 14:51:30 +0800144 if (!ctx)
145 return 0;
146
leng.fang91856072024-06-07 14:12:54 +0800147 return weston_get_property_value(ctx, key, ctx->crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
148}
149
leng.fang69a93e32024-08-08 16:31:01 +0800150static bool weston_get_mode_for_env(weston_ctx *ctx, char *out)
151{
152 const char *value = NULL;
153
154 if (!ctx || !ctx->conn)
155 return false;
156
157 switch (ctx->conn->connector_type) {
158 case DRM_MODE_CONNECTOR_HDMIA:
159 value = bootenv_get("hdmimode");
160 break;
161 case DRM_MODE_CONNECTOR_LVDS:
162 value = bootenv_get("outputmode");
163 break;
164 default:
165 break;
166 }
167 if (value)
168 strcpy(out, value);
169 else
170 strcpy(out, "none");
171 return true;
172}
173
leng.fang91856072024-06-07 14:12:54 +0800174static bool get_mode_name_for_weston_mode(
175 weston_ctx *ctx,
176 struct weston_mode *mode,
177 char *out)
178{
179 int i;
180 int current_interlaced;
181 const char *value;
182
183 if (mode && getModeNameForPix(out, mode->width, mode->height, mode->refresh, mode->flags))
184 return true;
185
leng.fang69a93e32024-08-08 16:31:01 +0800186 weston_get_mode_for_env(ctx, out);
leng.fang91856072024-06-07 14:12:54 +0800187 MESON_LOGD("out: %s", out);
188 return false;
189}
190
191static bool weston_get_mode(char *mode)
192{
193 weston_ctx *ctx = weston_get_ctx();
194 struct weston_mode *wmode = NULL;
195
leng.fang3e8a4b52024-07-24 14:51:30 +0800196 if (!wmode && ctx && ctx->current_mode.width != 0)
leng.fang91856072024-06-07 14:12:54 +0800197 wmode = &ctx->current_mode;
198
199 return get_mode_name_for_weston_mode(ctx, wmode, mode);
200}
201
leng.fang9cf09e22024-07-17 20:01:11 +0800202bool WestonGetUbootIsBestmode()
leng.fang91856072024-06-07 14:12:54 +0800203{
204 const char *isbestmode = bootenv_get("is.bestmode");
205 if ( isbestmode != NULL ) {
206 if (strcmp("false", isbestmode) == 0)
207 return false;
208 else
209 return true;
210 } else
211 return true;
212}
213
214bool westonGetDrmModeInfoByName( weston_ctx *ctx, const char *mode, drmModeModeInfo *out_mode )
215{
216 bool result= false;
217
218 if ( ctx && mode && out_mode ) {
219 int width = -1, height = -1, rate = -1;
220 bool interlaced = false;
221 bool haveTarget = false;
222 bool useBestRate = true;
223
224 MESON_LOGD("%s: mode (%s)", __func__, mode);
225
226 if ( sscanf( mode, "%dx%dp%d", &width, &height, &rate ) == 3 ) {
227 interlaced = false;
228 } else if ( sscanf( mode, "%dx%di%d", &width, &height, &rate ) == 3 ) {
229 interlaced = true;
230 } else if ( sscanf( mode, "%dx%dx%d", &width, &height, &rate ) == 3 ) {
231 interlaced = false;
232 } else if ( sscanf( mode, "%dx%d", &width, &height ) == 2 ) {
233 int len = strlen(mode);
234 interlaced = (mode[len - 1] == 'i');
235 } else if (sscanf( mode, "%dp%dhz", &height,&rate ) == 2) {
236 interlaced = false;
237 width = -1;
238 } else if (sscanf( mode, "%di%dhz", &height,&rate ) == 2) {
239 interlaced = true;
240 width = -1;
241 } else if ( sscanf( mode, "%dp", &height ) == 1 ) {
242 int len = strlen(mode);
243 interlaced = (mode[len - 1] == 'i');
244 width = -1;
245 } else if (sscanf( mode, "smpte%dhz", &rate ) == 1) {
246 interlaced = false;
247 height = 2160;
248 width = 4096;
249 }
250
251 if ( height > 0 ) {
252 if ( width < 0 ) {
253 switch ( height ) {
254 case 480:
255 case 576:
256 width = 720;
257 break;
258 case 720:
259 width = 1280;
260 break;
261 case 1080:
262 width = 1920;
263 break;
264 case 1440:
265 width = 2560;
266 break;
267 case 2160:
268 width = 3840;
269 break;
270 case 2880:
271 width = 5120;
272 break;
273 case 4320:
274 width = 7680;
275 break;
276 default:
277 break;
278 }
279 }
280 }
281 MESON_LOGD("%s w %d h %d rate %d", __func__, width, height, rate);
282 if ( rate >= 0 )
283 useBestRate = false;
284
285 if ( (width > 0) && (height > 0) ) {
286 if ( ctx->drm_fd >= 0 ) {
287 drmModeRes *res = 0;
288 drmModeConnector *conn = 0;
289
290 res = drmModeGetResources( ctx->drm_fd );
291 if ( res ) {
292 int i;
293 for ( i = 0; i < res->count_connectors; ++i ) {
294 conn = drmModeGetConnector( ctx->drm_fd, res->connectors[i] );
295 if ( conn ) {
296 if ( conn->count_modes && (conn->connection == DRM_MODE_CONNECTED) )
297 break;
298 drmModeFreeConnector(conn);
299 conn = 0;
300 }
301 }
302 if ( conn ) {
303 uint32_t rateBest = 0;
304 int miBest = -1;
305
306 MESON_LOGD("%s: want %dx%dx%d interlaced %d use best rate %d",
307 __func__, width, height, rate, interlaced, useBestRate);
308 for ( i = 0; i < conn->count_modes; ++i ) {
309 MESON_LOGD("%s: consider mode %d: %dx%dx%d (%s) type 0x%x flags 0x%x",
310 __func__, i, conn->modes[i].hdisplay, conn->modes[i].vdisplay,
311 conn->modes[i].vrefresh, conn->modes[i].name,
312 conn->modes[i].type, conn->modes[i].flags );
313
leng.fang3c0ab6d2024-08-01 16:29:00 +0800314 if (!strcmp(conn->modes[i].name, mode))
315 miBest = i;
316
leng.fang91856072024-06-07 14:12:54 +0800317 if ( (conn->modes[i].hdisplay == width) &&
318 (conn->modes[i].vdisplay == height) ) {
319 bool modeIsInterlaced = (conn->modes[i].flags & DRM_MODE_FLAG_INTERLACE);
320 if ( modeIsInterlaced != interlaced )
321 continue;
322
323 if ( useBestRate ) {
324 if ( conn->modes[i].vrefresh > rateBest ) {
325 rateBest = conn->modes[i].vrefresh;
326 miBest = i;
327 }
328 } else if ( conn->modes[i].vrefresh == rate ) {
329 miBest = i;
330 break;
331 }
332 }
333 }
334
335 if ( miBest >= 0 ) {
336 *out_mode = conn->modes[miBest];
337
338 MESON_LOGI("%s: choosing output mode: %dx%dx%d (%s) flags 0x%x",
339 __func__,
340 out_mode->hdisplay,
341 out_mode->vdisplay,
342 out_mode->vrefresh,
343 out_mode->name,
344 out_mode->flags );
345
346 result= true;
347 } else {
348 MESON_LOGE("%s: failed to find a mode matching (%s)", __func__, mode);
349 }
350
351 drmModeFreeConnector( conn );
352 } else {
353 MESON_LOGE("%s: unable to get connector for card", __func__);
354 }
355 drmModeFreeResources(res);
356 } else {
357 MESON_LOGE("%s: unable to get card resources", __func__);
358 }
359 } else {
360 MESON_LOGE("%s: no open device", __func__);
361 }
362 } else {
363 MESON_LOGE("%s: unable to parse mode (%s)", __func__, mode);
364 }
365 }
366
367 return result;
368}
369
370static bool weston_set_mode(const char *mode)
371{
372 weston_ctx *ctx = weston_get_ctx();
373 drmModeModeInfo info = {0};
374
leng.fang3e8a4b52024-07-24 14:51:30 +0800375 if (!ctx)
376 return false;
377
leng.fang91856072024-06-07 14:12:54 +0800378 if (westonGetDrmModeInfoByName(ctx, mode, &info)) {
379 ctx->next_mode.width = info.hdisplay;
380 ctx->next_mode.height = info.vdisplay;
381 ctx->next_mode.refresh = info.vrefresh * 1000;
382 ctx->next_mode.flags = info.flags;
383 setBootConfig(info.name, WestonGetUbootIsBestmode());
384 ctx->mode_update = true;
385 ctx->mode_changed = true;
386 }
387 return 0;
388}
389
390static int weston_get_property(int id, const char *name, char *buf)
391{
392 weston_ctx *ctx = weston_get_ctx();
393 int value = 0;
394
leng.fang3e8a4b52024-07-24 14:51:30 +0800395 if (!ctx)
396 return 0;
397
leng.fang91856072024-06-07 14:12:54 +0800398 if (!ctx->crtc || !ctx->conn)
399 return 0;
400
401 if (ctx->crtc->crtc_id == id)
402 value = weston_get_crtc_property(name);
403
404 if (ctx->conn->connector_id == id)
405 value = weston_get_connector_property(name);
406
407 snprintf(buf, MAX_BUF_LEN, "%d", value);
408 return 0;
409}
410
411static int weston_set_property(int id, const char *name, int value)
412{
413 prop_info *info;
414 weston_ctx *ctx = weston_get_ctx();
415
leng.fang3e8a4b52024-07-24 14:51:30 +0800416 if (!ctx)
417 return 0;
418
leng.fang91856072024-06-07 14:12:54 +0800419 wl_list_for_each(info, &ctx->prop_list, link) {
420 if (!strcmp(name, info->name) && info->item_id == id) {
421 MESON_LOGD("name: %s, id: %d, prop: %d, value: %d\n",
422 name, id, info->prop_id, value);
423 info->value = value;
424 info->need_change = 1;
425 ctx->prop_changed = true;
426 break;
427 }
428 }
429
430 return 0;
431}
432
433static bool weston_set_colorattribute(const char *attr)
434{
435 weston_ctx *ctx = weston_get_ctx();
436 int depth = -1, value = -1; // default none
437
438 if ( attr && strlen(attr) > 3 ) {
439 if ( strstr (attr, "rgb") )
440 value = 0;
441 else if ( strstr (attr, "422") )
442 value = 1;
443 else if ( strstr (attr, "444") )
444 value = 2;
445 else if ( strstr (attr, "420") )
446 value = 3;
447 sscanf(attr + 4, "%dbit", &depth);
448 }
449 if (ctx && ctx->conn && ctx->conn->connector_type == DRM_MODE_CONNECTOR_HDMIA) {
450 weston_set_property(ctx->conn->connector_id, "color_space", value);
451 weston_set_property(ctx->conn->connector_id, "color_depth", depth);
452 }
453 return 0;
454}
455
456void weston_set_scaling_position(int x, int y, int w, int h)
457{
458 weston_ctx *ctx = weston_get_ctx();
459 const char *value = bootenv_get("scaling");
leng.fang3e8a4b52024-07-24 14:51:30 +0800460 int scaling = -1;
leng.fang91856072024-06-07 14:12:54 +0800461
462 if (value)
463 scaling = atoi(value);
464
leng.fangb1081a32024-06-25 14:41:37 +0800465 if (ctx && ctx->scaling != scaling)
466 ctx->scaling = scaling;
leng.fang91856072024-06-07 14:12:54 +0800467}
468
469CompositorFunctionCallBack callback = {
470 .get_mode = weston_get_mode,
471 .set_mode = weston_set_mode,
472 .set_colorattribute = weston_set_colorattribute,
473 .get_property = weston_get_property,
474 .set_property = weston_set_property,
475 .set_scaling_position = weston_set_scaling_position,
476};
477
leng.fangb1081a32024-06-25 14:41:37 +0800478static char *get_color_space_by_value(int value)
479{
480 char *str;
481
482 switch ( value ) {
483 case 0:
484 str = "rgb";
485 break;
486 case 1:
487 str = "422";
488 break;
489 case 2:
490 str = "444";
491 break;
492 case 3:
493 default:
494 str = "420";
495 break;
496 }
497 return str;
498}
499
500static int get_property_value(char *name)
501{
502 prop_info *info;
503 weston_ctx *ctx = weston_get_ctx();
504
leng.fang3e8a4b52024-07-24 14:51:30 +0800505 if (!ctx)
506 return 0;
507
leng.fangb1081a32024-06-25 14:41:37 +0800508 wl_list_for_each(info, &ctx->prop_list, link) {
509 if (!strcmp(name, info->name)) {
510 if (info->need_change == 1)
511 return info->value;
512 }
513 }
514 return -1;
515}
516
517static int get_id_by_name(const char *name)
518{
519 prop_info *info;
520 weston_ctx *ctx = weston_get_ctx();
521
leng.fang3e8a4b52024-07-24 14:51:30 +0800522 if (!ctx)
523 return -1;
524
leng.fangb1081a32024-06-25 14:41:37 +0800525 wl_list_for_each(info, &ctx->prop_list, link) {
526 if (!strcmp(name, info->name))
527 return info->item_id;
528 }
529 return -1;
530}
531
leng.fang3e8a4b52024-07-24 14:51:30 +0800532static int mode_policy_parse_other(weston_ctx *ctx, const char *name, int value)
leng.fangb1081a32024-06-25 14:41:37 +0800533{
leng.fangb1081a32024-06-25 14:41:37 +0800534 char attrvalue[32] = { 0 };
535
536 if (STRCMPS(name, "scaling") == 0) {
537 if (ctx && ctx->scaling != value)
538 ctx->scaling = value;
539
540 sprintf(attrvalue, "%d", value);
541 bootenv_update("scaling", attrvalue);
542 return 0;
543 }
544 return -1;
545}
546
leng.fang13fd3982024-07-03 19:09:58 +0800547static void set_color_attribute(char *space, int depth)
548{
leng.fang13fd3982024-07-03 19:09:58 +0800549 char attrvalue[32] = { 0 };
550 char mode[] = { 0 };
551
552 sprintf(attrvalue, "%s,%dbit", space, depth);
553 setColorSpace(attrvalue);
554 weston_get_mode(mode);
555 setBootConfig(mode, false);
556}
557
leng.fangb1081a32024-06-25 14:41:37 +0800558int mode_policy_set_property(const char *name, int value)
559{
560 char attrvalue[32] = { 0 };
561 int color_space = 0;
562 int color_depth = 0;
563 int id = get_id_by_name(name);
leng.fang3e8a4b52024-07-24 14:51:30 +0800564 weston_ctx *ctx = weston_get_ctx();
leng.fangb1081a32024-06-25 14:41:37 +0800565 MESON_LOGI("id: %d, name: %s, value: %d", id, name, value);
566
leng.fang3e8a4b52024-07-24 14:51:30 +0800567 if (!ctx)
568 return 0;
569
leng.fang3c0ab6d2024-08-01 16:29:00 +0800570 if (!ctx->conn || ctx->conn->connector_type != DRM_MODE_CONNECTOR_HDMIA) {
571 MESON_LOGW("isn't hdmi, don't set property");
572 return 0;
573 }
574
leng.fang3e8a4b52024-07-24 14:51:30 +0800575 initModePolicyFun(ctx->crtc, ctx->conn, callback);
leng.fangb1081a32024-06-25 14:41:37 +0800576 if (value < 0 || id < 0)
leng.fang3e8a4b52024-07-24 14:51:30 +0800577 return mode_policy_parse_other(ctx, name, value);
leng.fangb1081a32024-06-25 14:41:37 +0800578
579 if (strncmp(name, "dv_mode", sizeof("dv_mode")) == 0) {
580 setDvMode(value == 0 ? 1 : (value == 1 ? 2 : 0));
581 return 0;
582 } else if (strncmp(name, "color_depth", sizeof("color_depth")) == 0) {
583 color_space = get_property_value("color_space");
584 if (color_space >= 0) {
leng.fang13fd3982024-07-03 19:09:58 +0800585 set_color_attribute(get_color_space_by_value(color_space), value);
leng.fangb1081a32024-06-25 14:41:37 +0800586 return 0;
587 }
588 } else if (strncmp(name, "color_space", sizeof("color_space")) == 0) {
589 color_depth = get_property_value("color_depth");
590 if (color_depth >= 0) {
leng.fang13fd3982024-07-03 19:09:58 +0800591 set_color_attribute(get_color_space_by_value(value), color_depth);
leng.fangb1081a32024-06-25 14:41:37 +0800592 return 0;
593 }
594 } else if (strncmp(name, "meson.crtc.hdr_policy", sizeof("meson.crtc.hdr_policy")) == 0) {
595 sprintf(attrvalue, "%d", value);
596 bootenv_update("hdr_policy", attrvalue);
597 }
598
599 return weston_set_property(id, name, value);
600}
601
602int mode_policy_get_scaling()
603{
604 weston_ctx *ctx = weston_get_ctx();
605
leng.fang3e8a4b52024-07-24 14:51:30 +0800606 if (!ctx)
607 return 100;
608
leng.fangb1081a32024-06-25 14:41:37 +0800609 if (ctx->scaling < 0)
610 return 100;
611
612 return ctx->scaling;
613}
614
leng.fang13fd3982024-07-03 19:09:58 +0800615static struct weston_mode
616drm_mode_to_weston_mode(drmModeModeInfoPtr info)
617{
618 struct weston_mode m;
619
620 m.width = info->hdisplay;
621 m.height = info->vdisplay;
622 //mhz:refresh * 1000
623 m.refresh = info->vrefresh * 1000;
624 //hack: use weston_mode's flags as drm_mode's flags.
625 m.flags = info->flags;
626 m.aspect_ratio = WESTON_MODE_PIC_AR_NONE;
627
628 return m;
629}
630
leng.fang5ec9b6c2024-07-29 14:25:00 +0800631drmModeCrtc *weston_get_crtc_for_conn(int drm_fd, drmModeConnector *conn)
leng.fang91856072024-06-07 14:12:54 +0800632{
633 drmModeEncoder *encoder;
634 drmModeCrtc *crtc = NULL;
chen.wang19f2f82b2024-07-16 11:43:59 +0000635 drmModeRes *res = 0;
636 int i, j, k;
leng.fang91856072024-06-07 14:12:54 +0800637 /* Get the current mode on the crtc that's currently driving
638 * this connector. */
chen.wang19f2f82b2024-07-16 11:43:59 +0000639 res = drmModeGetResources(drm_fd);
640 if ( res ) {
641 for (i= 0; i < res->count_encoders; ++i ) {
642 uint32_t crtcId= 0;
643 bool found= false;
644 encoder = drmModeGetEncoder(drm_fd, res->encoders[i]);
645 if (encoder && conn && (encoder->encoder_id == conn->encoder_id)) {
646 found = true;
647 break;
648 }
649 for (j = 0; j < res->count_crtcs; j++) {
650 if (encoder->possible_crtcs & (1 << j)) {
651 crtcId= res->crtcs[j];
652 for (k = 0; k < res->count_crtcs; k++) {
653 if (res->crtcs[k] == crtcId) {
654 drmModeFreeEncoder(encoder);
655 encoder= drmModeGetEncoder(drm_fd, res->encoders[k]);
656 encoder->crtc_id= crtcId;
leng.fang69a93e32024-08-08 16:31:01 +0800657 MESON_LOGD("got enc %p crtc id %d, conn id: %d", drm_fd, crtcId, conn->connector_id);
chen.wang19f2f82b2024-07-16 11:43:59 +0000658 found = true;
659 break;
660 }
661 }
662 if (found) {
663 break;
664 }
665 }
666 }
667 if (!found) {
668 drmModeFreeEncoder(encoder);
669 encoder= 0;
670 }
671 if (found) {
672 break;
673 }
674 }
675 if (encoder != NULL) {
676 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
677 drmModeFreeEncoder(encoder);
678 }
679 drmModeFreeResources( res );
680 res = 0;
681 } else {
682 MESON_LOGD("unable to get card resources");
leng.fang91856072024-06-07 14:12:54 +0800683 }
684 return crtc;
685}
686
leng.fang3e8a4b52024-07-24 14:51:30 +0800687void mode_policy_set_head(struct weston_head *head)
leng.fang91856072024-06-07 14:12:54 +0800688{
leng.fang3e8a4b52024-07-24 14:51:30 +0800689 weston_ctx_list *ctx_list = weston_get_ctx_list();
690 ctx_list->head = head;
691}
leng.fang91856072024-06-07 14:12:54 +0800692
leng.fang3e8a4b52024-07-24 14:51:30 +0800693void mode_policy_set_output(struct weston_output *output)
694{
695 weston_ctx_list *ctx_list = weston_get_ctx_list();
696 weston_ctx *ctx, *tmp;
leng.fang91856072024-06-07 14:12:54 +0800697
leng.fang3e8a4b52024-07-24 14:51:30 +0800698 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
699 if (ctx->head && ctx->head->output == output) {
700 mode_policy_set_head(ctx->head);
701 break;
leng.fange9d800e2024-07-12 13:31:59 +0800702 }
leng.fang91856072024-06-07 14:12:54 +0800703 }
704}
705
leng.fang3e8a4b52024-07-24 14:51:30 +0800706static void mode_policy_update_ctx(weston_ctx *ctx,
707 struct weston_head *head, int fd, drmModeConnector *conn)
leng.fang91856072024-06-07 14:12:54 +0800708{
leng.fang3e8a4b52024-07-24 14:51:30 +0800709 drmModeCrtc *crtc = NULL;
710 bool changed = false;
711
712 if (!ctx)
713 return;
714
715 crtc = weston_get_crtc_for_conn(fd, conn);
716 if (!crtc)
717 return;
718
719 if ((ctx->crtc && ctx->crtc->crtc_id != crtc->crtc_id) || !ctx->crtc)
720 changed = true;
721
leng.fang91856072024-06-07 14:12:54 +0800722 if (ctx->crtc)
723 drmModeFreeCrtc(ctx->crtc);
724 ctx->drm_fd = fd;
725 ctx->crtc = crtc;
726 ctx->conn = conn;
leng.fang3e8a4b52024-07-24 14:51:30 +0800727 ctx->head = head;
728 if (changed) {
729 ctx->current_mode = drm_mode_to_weston_mode(&ctx->crtc->mode);
730 weston_prop_list_init(ctx);
731 weston_add_property(ctx, ctx->crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
732 weston_add_property(ctx, ctx->conn->connector_id, DRM_MODE_OBJECT_CONNECTOR);
733 }
734}
735
736void init_mode_policy_without_mode(struct weston_head *head, int fd, drmModeConnector *conn)
737{
738 weston_ctx_list *ctx_list = weston_get_ctx_list();
739 weston_ctx *ctx;
740
741 mode_policy_set_head(head);
742 ctx = weston_get_ctx();
743 if (!ctx) {
744 ctx = (weston_ctx *)calloc(1, sizeof(*ctx));
745 ctx->scaling = -1;
leng.fang69a93e32024-08-08 16:31:01 +0800746 ctx->state = ctx_list->state;
leng.fang3e8a4b52024-07-24 14:51:30 +0800747 wl_list_init(&ctx->prop_list);
748 wl_list_insert(&ctx_list->ctx_list, &ctx->link);
749 }
750 mode_policy_update_ctx(ctx, head, fd, conn);
leng.fang91856072024-06-07 14:12:54 +0800751}
752
leng.fang13fd3982024-07-03 19:09:58 +0800753static bool need_mode_changed(char *name)
754{
755 int size = sizeof(prop_changed_and_mode) / sizeof(prop_changed_and_mode[0]);
756 int i;
757
758 for (i = 0; i < size; i++) {
759 if (STRCMPS(name, prop_changed_and_mode[i]) == 0)
760 return true;
761 }
762 return false;
763}
764
leng.fang3c0ab6d2024-08-01 16:29:00 +0800765static void mode_policy_add_mode(weston_ctx_list * ctx_list, bool mode_changed)
766{
767 weston_ctx *ctx, *tmp;
768
769 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
770 if (ctx->mode_changed && mode_changed)
771 ctx->need_update_hdmi_param = true;
772 }
773}
774
leng.fang13fd3982024-07-03 19:09:58 +0800775int mode_policy_add_prop(drmModeAtomicReq *req, bool mode_changed)
leng.fang91856072024-06-07 14:12:54 +0800776{
leng.fang91856072024-06-07 14:12:54 +0800777 prop_info *info;
778 int err = 0, ret = 0;
leng.fangb1081a32024-06-25 14:41:37 +0800779 int count = 0;
leng.fang3e8a4b52024-07-24 14:51:30 +0800780 weston_ctx_list * ctx_list = weston_get_ctx_list();
781 weston_ctx *ctx, *tmp;
leng.fang91856072024-06-07 14:12:54 +0800782
leng.fang3c0ab6d2024-08-01 16:29:00 +0800783 mode_policy_add_mode(ctx_list, mode_changed);
leng.fang3e8a4b52024-07-24 14:51:30 +0800784 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
785 wl_list_for_each(info, &ctx->prop_list, link) {
786 if (info->need_change) {
787 if (need_mode_changed(info->name) && !mode_changed)
788 continue;
leng.fang13fd3982024-07-03 19:09:58 +0800789
leng.fang3e8a4b52024-07-24 14:51:30 +0800790 err = drmModeAtomicAddProperty(req, info->item_id, info->prop_id, info->value);
791 if (!err)
792 MESON_LOGE("drmModeAtomicAddProperty %s fail: %d(%d)\n",
793 info->name, err, errno);
794 info->need_change = 0;
795 ret |= (err <= 0) ? -1 : 0;
796 if (!ret)
797 count++;
798 ctx->need_update_hdmi_param = true;
799 }
leng.fang91856072024-06-07 14:12:54 +0800800 }
801 }
leng.fangb1081a32024-06-25 14:41:37 +0800802 return ret >= 0 ? count : ret;
leng.fang91856072024-06-07 14:12:54 +0800803}
804
leng.fang69a93e32024-08-08 16:31:01 +0800805static void weston_set_state_for_ctx(weston_ctx *ctx, int state, bool force)
806{
807 if (!ctx)
808 return;
809
810 if (force) {
811 ctx->state = state;
812 } else {
813 if (ctx->state & state)
814 ctx->state = state;
815 }
816}
817
leng.fang13fd3982024-07-03 19:09:58 +0800818void mode_policy_set_hotplug(int plug, bool force)
leng.fang91856072024-06-07 14:12:54 +0800819{
leng.fang3e8a4b52024-07-24 14:51:30 +0800820 weston_ctx_list *ctx_list = weston_get_ctx_list();
leng.fang69a93e32024-08-08 16:31:01 +0800821 weston_ctx *ctx, *tmp;
leng.fang13fd3982024-07-03 19:09:58 +0800822
leng.fang69a93e32024-08-08 16:31:01 +0800823 ctx_list->state = plug;
824 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
825 if (ctx->conn && ctx->conn->connector_type == DRM_MODE_CONNECTOR_HDMIA)
826 weston_set_state_for_ctx(ctx, plug, force);
leng.fang13fd3982024-07-03 19:09:58 +0800827 }
leng.fang91856072024-06-07 14:12:54 +0800828}
829
leng.fang69a93e32024-08-08 16:31:01 +0800830void mode_policy_set_state(struct weston_head *head, int state, bool force)
831{
832 weston_ctx_list *ctx_list;
833 weston_ctx *ctx, *tmp;
834
835 if (head) {
836 ctx = weston_get_ctx_for_head(head);
837 weston_set_state_for_ctx(ctx, state, force);
838 return;
839 }
840
841 ctx_list = weston_get_ctx_list();
842 ctx_list->state = state;
843 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link)
844 weston_set_state_for_ctx(ctx, state, force);
845}
846
leng.fang91856072024-06-07 14:12:54 +0800847void mode_policy_update_mode(struct weston_mode *mode)
848{
849 weston_ctx *ctx = weston_get_ctx();
leng.fang3e8a4b52024-07-24 14:51:30 +0800850
851 if (!ctx)
852 return;
853
leng.fang91856072024-06-07 14:12:54 +0800854 if (mode)
855 ctx->current_mode = *mode;
leng.fang13fd3982024-07-03 19:09:58 +0800856 else if (ctx->mode_changed)
leng.fang91856072024-06-07 14:12:54 +0800857 ctx->current_mode = ctx->next_mode;
858 MESON_LOGD("curr: %dx%d@%d",
859 ctx->current_mode.width,
860 ctx->current_mode.height,
861 ctx->current_mode.refresh);
862}
863
864struct weston_mode *mode_policy_choose_mode(struct weston_mode *mode)
865{
leng.fang3e8a4b52024-07-24 14:51:30 +0800866 weston_ctx_list * ctx_list = weston_get_ctx_list();
leng.fang91856072024-06-07 14:12:54 +0800867 weston_ctx *ctx = weston_get_ctx();
868 char name[32] = { 0 };
leng.fang91856072024-06-07 14:12:54 +0800869
leng.fang3e8a4b52024-07-24 14:51:30 +0800870 if (!ctx)
871 return NULL;
872
873 initModePolicyFun(ctx->crtc, ctx->conn, callback);
leng.fang91856072024-06-07 14:12:54 +0800874 if (mode) {
875 if (get_mode_name_for_weston_mode(ctx, mode, name))
876 setActiveConfig(name);
877 } else {
leng.fang69a93e32024-08-08 16:31:01 +0800878 if (ctx->state & (AML_WESTON_HOTPLUG_PLUG | AML_WESTON_HOTPLUG_UNPLUG))
879 onHotplug(ctx->state & AML_WESTON_HOTPLUG_PLUG);
880 else if (ctx->state & (AML_WESTON_HOTPLUG_BOOT | AML_WESTON_HOTPLUG_SET))
leng.fang91856072024-06-07 14:12:54 +0800881 initModePolicy(NULL, NULL, callback);
leng.fang69a93e32024-08-08 16:31:01 +0800882 ctx->state = AML_WESTON_HOTPLUG_INIT;
leng.fang91856072024-06-07 14:12:54 +0800883 }
884 if (ctx->mode_update)
885 return &ctx->next_mode;
leng.fang13fd3982024-07-03 19:09:58 +0800886 return &ctx->current_mode;
leng.fang91856072024-06-07 14:12:54 +0800887}
888
leng.fangb1081a32024-06-25 14:41:37 +0800889void mode_policy_update_bestmode(bool bestmode)
890{
891 bootenv_update("is.bestmode", bestmode ? "true" : "false");
892}
893
leng.fang69a93e32024-08-08 16:31:01 +0800894static int get_possible_by_connector(weston_ctx *ctx)
895{
896 drmModeEncoder *encoder;
897 int possible = 0;
898
899 if (!ctx || !ctx->conn)
900 return 0;
901
902 encoder = drmModeGetEncoder(ctx->drm_fd, ctx->conn->encoder_id);
903 if (encoder) {
904 possible = encoder->possible_crtcs;
905 drmModeFreeEncoder(encoder);
906 }
907 return possible;
908}
909
910void mode_policy_update_modeset(bool *state, bool *modeset, int *possible)
leng.fang13fd3982024-07-03 19:09:58 +0800911{
leng.fang3e8a4b52024-07-24 14:51:30 +0800912 weston_ctx_list * ctx_list = weston_get_ctx_list();
913 weston_ctx *ctx, *tmp;
914 bool mode_changed = false;
leng.fang13fd3982024-07-03 19:09:58 +0800915
leng.fang3e8a4b52024-07-24 14:51:30 +0800916 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
leng.fang69a93e32024-08-08 16:31:01 +0800917 if (ctx->mode_changed) {
leng.fang3e8a4b52024-07-24 14:51:30 +0800918 mode_changed = true;
leng.fang69a93e32024-08-08 16:31:01 +0800919 *possible |= get_possible_by_connector(ctx);
920 }
leng.fang3e8a4b52024-07-24 14:51:30 +0800921 }
922
923 MESON_LOGV("state: %d, modeset: %d, mode_changed: %d", *state, *modeset, mode_changed);
924 if (mode_changed) {
leng.fang13fd3982024-07-03 19:09:58 +0800925 if (!*state)
926 *state = true;
927 if (!*modeset)
928 *modeset = true;
929 }
930}
931
leng.fange9d800e2024-07-12 13:31:59 +0800932void mode_policy_resume()
933{
934 weston_ctx *ctx = weston_get_ctx();
935 int flag;
936
leng.fang3e8a4b52024-07-24 14:51:30 +0800937 if (!ctx)
938 return;
939
leng.fange9d800e2024-07-12 13:31:59 +0800940 flag = (ctx->conn &&
leng.fang5ec9b6c2024-07-29 14:25:00 +0800941 ctx->conn->connector_type == DRM_MODE_CONNECTOR_HDMIA) ?
leng.fange9d800e2024-07-12 13:31:59 +0800942 AML_WESTON_HOTPLUG_PLUG : AML_WESTON_HOTPLUG_SET;
943
leng.fang69a93e32024-08-08 16:31:01 +0800944 weston_set_state_for_ctx(ctx, flag, true);
leng.fange9d800e2024-07-12 13:31:59 +0800945}
946
leng.fang91856072024-06-07 14:12:54 +0800947static void * wstUpdatenvThread(void *arg )
948{
949 long long delay = 16667LL;
leng.fang3e8a4b52024-07-24 14:51:30 +0800950 weston_ctx_list *ctx_list = (weston_ctx_list *)arg;
951 weston_ctx *ctx, *tmp;
leng.fang13fd3982024-07-03 19:09:58 +0800952
leng.fang3e8a4b52024-07-24 14:51:30 +0800953 while (!ctx_list->update_env_thread_stop_requested)
leng.fang91856072024-06-07 14:12:54 +0800954 {
leng.fang3e8a4b52024-07-24 14:51:30 +0800955 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
leng.fang3c0ab6d2024-08-01 16:29:00 +0800956 if ((ctx->mode_changed && !ctx->prop_changed && ctx->need_update_hdmi_param) ||
leng.fang3e8a4b52024-07-24 14:51:30 +0800957 (ctx->prop_changed && ctx->need_update_hdmi_param))
958 {
959 weston_log("%s[%d]\n", __func__, __LINE__);
leng.fang69a93e32024-08-08 16:31:01 +0800960 mode_policy_set_head(ctx->head);
leng.fang3e8a4b52024-07-24 14:51:30 +0800961 initModePolicyFun(ctx->crtc, ctx->conn, callback);
962 updateEnv();
963 ctx->need_update_hdmi_param = false;
964 ctx->mode_changed = false;
965 ctx->prop_changed = false;
966 }
leng.fang91856072024-06-07 14:12:54 +0800967 }
968 usleep( delay );
969 }
970 MESON_LOGD("update env thread exit");
971 return NULL;
972}
973
974void weston_start_update_env_thread()
975{
976 int rc;
leng.fang3e8a4b52024-07-24 14:51:30 +0800977 weston_ctx_list *ctx_list = weston_get_ctx_list();
leng.fang91856072024-06-07 14:12:54 +0800978
leng.fang3e8a4b52024-07-24 14:51:30 +0800979 ctx_list->update_env_thread_stop_requested = false;
980 rc = pthread_create(&ctx_list->update_env_thread_id, NULL, wstUpdatenvThread, ctx_list);
leng.fang91856072024-06-07 14:12:54 +0800981 if ( rc )
982 MESON_LOGE("unable to start updatenv thread: rc %d errno %d", rc, errno);
983}