blob: 5c1e26a256ccdd433a77c5fa935ceb75f0618c95 [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};
limin.tiana9a091a2024-09-23 07:54:32 +000015static int weston_set_property(int id, const char *name, int value);
leng.fang13fd3982024-07-03 19:09:58 +080016
leng.fang3e8a4b52024-07-24 14:51:30 +080017static weston_ctx_list *weston_get_ctx_list()
18{
19 if (!gCtx_list) {
20 gCtx_list = (weston_ctx_list *)calloc(1, sizeof(*gCtx_list));
21 wl_list_init(&gCtx_list->ctx_list);
22 }
23 return gCtx_list;
24}
25
leng.fang69a93e32024-08-08 16:31:01 +080026static weston_ctx *weston_get_ctx_for_head(struct weston_head *head)
leng.fang91856072024-06-07 14:12:54 +080027{
leng.fang3e8a4b52024-07-24 14:51:30 +080028 weston_ctx_list *ctx_list = weston_get_ctx_list();
29 weston_ctx *ctx, *tmp;
30
31 wl_list_for_each(ctx, &ctx_list->ctx_list, link) {
leng.fang69a93e32024-08-08 16:31:01 +080032 if (ctx->head == head)
leng.fang3e8a4b52024-07-24 14:51:30 +080033 return ctx;
leng.fang91856072024-06-07 14:12:54 +080034 }
leng.fang3e8a4b52024-07-24 14:51:30 +080035 return NULL;
leng.fang91856072024-06-07 14:12:54 +080036}
37
leng.fang69a93e32024-08-08 16:31:01 +080038weston_ctx *weston_get_ctx()
39{
40 weston_ctx_list *ctx_list = weston_get_ctx_list();
41
42 return weston_get_ctx_for_head(ctx_list->head);
43}
44
leng.fang91856072024-06-07 14:12:54 +080045static void weston_prop_list_init(weston_ctx *ctx)
46{
47 prop_info *info, *tmp;
48 if (!wl_list_empty(&ctx->prop_list)) {
49 wl_list_for_each_safe(info, tmp, &ctx->prop_list, link) {
50 wl_list_remove(&info->link);
51 free(info);
52 }
53 }
54 wl_list_init(&ctx->prop_list);
55}
56
57static int weston_add_property_item(weston_ctx *ctx,
58 const char *name, int id, int prop_id)
59{
60 prop_info *info;
61
62 wl_list_for_each(info, &ctx->prop_list, link) {
63 if (!strcmp(name, info->name) && info->item_id == id)
64 return 0;
65 }
66
67 info = (prop_info *)calloc(1, sizeof(*info));
68 memcpy(info->name, name, sizeof(info->name));
69 info->item_id = id;
70 info->prop_id = prop_id;
71 info->need_change = 0;
72 MESON_LOGD("ctx: %p, name: %s, id: %d, prop_id: %d\n", ctx, name, id, prop_id);
73 wl_list_insert(&ctx->prop_list, &info->link);
74 return 0;
75}
76
77static int weston_add_property(weston_ctx *ctx, int id, int type)
78{
79 int i, len;
80 int value = 0;
81 drmModePropertyRes *propRes;
82 drmModeObjectProperties *props;
83
84 props = drmModeObjectGetProperties( ctx->drm_fd, id, type );
85 if ( props ) {
86 for ( i= 0; i < props->count_props; ++i ) {
87 propRes = drmModeGetProperty( ctx->drm_fd, props->props[i] );
88 if ( propRes ) {
89 weston_add_property_item(ctx, propRes->name, id, props->props[i]);
90 drmModeFreeProperty( propRes );
91 propRes = 0;
92 }
93 }
94 drmModeFreeObjectProperties( props );
95 props = 0;
96 }
97 return value;
98}
99
100static int weston_get_property_value(weston_ctx *ctx, const char * key, int id, int type)
101{
102 int i, len;
103 int value = 0;
104 drmModePropertyRes *propRes;
105 drmModeObjectProperties *props;
106
107 props = drmModeObjectGetProperties( ctx->drm_fd, id, type );
108 if ( props ) {
109 for ( i= 0; i < props->count_props; ++i ) {
110 propRes = drmModeGetProperty( ctx->drm_fd, props->props[i] );
111 if ( propRes ) {
112 len = strlen(propRes->name);
113 if ( !strncmp( propRes->name, key, len) ) {
114 MESON_LOGD("property %d name (%s) value (%lld)",
115 props->props[i], propRes->name, props->prop_values[i] );
116 value = props->prop_values[i];
117 drmModeFreeProperty( propRes );
118 propRes = 0;
119 break;
120 }
121 drmModeFreeProperty( propRes );
122 propRes = 0;
123 }
124 }
125 drmModeFreeObjectProperties( props );
126 props = 0;
127 }
128 return value;
129}
130
131static int weston_get_connector_property(const char * key)
132{
133 weston_ctx *ctx = weston_get_ctx();
134
leng.fang3e8a4b52024-07-24 14:51:30 +0800135 if (!ctx)
136 return 0;
137
leng.fang91856072024-06-07 14:12:54 +0800138 return weston_get_property_value(ctx, key, ctx->conn->connector_id, DRM_MODE_OBJECT_CONNECTOR);
139}
140
141static int weston_get_crtc_property(const char * key)
142{
143 weston_ctx *ctx = weston_get_ctx();
144
leng.fang3e8a4b52024-07-24 14:51:30 +0800145 if (!ctx)
146 return 0;
147
leng.fang91856072024-06-07 14:12:54 +0800148 return weston_get_property_value(ctx, key, ctx->crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
149}
150
leng.fang69a93e32024-08-08 16:31:01 +0800151static bool weston_get_mode_for_env(weston_ctx *ctx, char *out)
152{
153 const char *value = NULL;
154
155 if (!ctx || !ctx->conn)
156 return false;
157
158 switch (ctx->conn->connector_type) {
159 case DRM_MODE_CONNECTOR_HDMIA:
160 value = bootenv_get("hdmimode");
161 break;
162 case DRM_MODE_CONNECTOR_LVDS:
163 value = bootenv_get("outputmode");
164 break;
165 default:
166 break;
167 }
168 if (value)
169 strcpy(out, value);
170 else
171 strcpy(out, "none");
172 return true;
173}
174
leng.fang91856072024-06-07 14:12:54 +0800175static bool get_mode_name_for_weston_mode(
176 weston_ctx *ctx,
177 struct weston_mode *mode,
178 char *out)
179{
180 int i;
181 int current_interlaced;
182 const char *value;
183
184 if (mode && getModeNameForPix(out, mode->width, mode->height, mode->refresh, mode->flags))
185 return true;
186
leng.fang69a93e32024-08-08 16:31:01 +0800187 weston_get_mode_for_env(ctx, out);
leng.fang91856072024-06-07 14:12:54 +0800188 MESON_LOGD("out: %s", out);
189 return false;
190}
191
192static bool weston_get_mode(char *mode)
193{
194 weston_ctx *ctx = weston_get_ctx();
195 struct weston_mode *wmode = NULL;
196
leng.fang3e8a4b52024-07-24 14:51:30 +0800197 if (!wmode && ctx && ctx->current_mode.width != 0)
leng.fang91856072024-06-07 14:12:54 +0800198 wmode = &ctx->current_mode;
199
200 return get_mode_name_for_weston_mode(ctx, wmode, mode);
201}
202
leng.fang9cf09e22024-07-17 20:01:11 +0800203bool WestonGetUbootIsBestmode()
leng.fang91856072024-06-07 14:12:54 +0800204{
205 const char *isbestmode = bootenv_get("is.bestmode");
206 if ( isbestmode != NULL ) {
207 if (strcmp("false", isbestmode) == 0)
208 return false;
209 else
210 return true;
211 } else
212 return true;
213}
214
215bool westonGetDrmModeInfoByName( weston_ctx *ctx, const char *mode, drmModeModeInfo *out_mode )
216{
217 bool result= false;
218
219 if ( ctx && mode && out_mode ) {
220 int width = -1, height = -1, rate = -1;
221 bool interlaced = false;
222 bool haveTarget = false;
223 bool useBestRate = true;
224
225 MESON_LOGD("%s: mode (%s)", __func__, mode);
226
227 if ( sscanf( mode, "%dx%dp%d", &width, &height, &rate ) == 3 ) {
228 interlaced = false;
229 } else if ( sscanf( mode, "%dx%di%d", &width, &height, &rate ) == 3 ) {
230 interlaced = true;
231 } else if ( sscanf( mode, "%dx%dx%d", &width, &height, &rate ) == 3 ) {
232 interlaced = false;
233 } else if ( sscanf( mode, "%dx%d", &width, &height ) == 2 ) {
234 int len = strlen(mode);
235 interlaced = (mode[len - 1] == 'i');
236 } else if (sscanf( mode, "%dp%dhz", &height,&rate ) == 2) {
237 interlaced = false;
238 width = -1;
239 } else if (sscanf( mode, "%di%dhz", &height,&rate ) == 2) {
240 interlaced = true;
241 width = -1;
242 } else if ( sscanf( mode, "%dp", &height ) == 1 ) {
243 int len = strlen(mode);
244 interlaced = (mode[len - 1] == 'i');
245 width = -1;
246 } else if (sscanf( mode, "smpte%dhz", &rate ) == 1) {
247 interlaced = false;
248 height = 2160;
249 width = 4096;
250 }
251
252 if ( height > 0 ) {
253 if ( width < 0 ) {
254 switch ( height ) {
255 case 480:
256 case 576:
257 width = 720;
258 break;
259 case 720:
260 width = 1280;
261 break;
262 case 1080:
263 width = 1920;
264 break;
265 case 1440:
266 width = 2560;
267 break;
268 case 2160:
269 width = 3840;
270 break;
271 case 2880:
272 width = 5120;
273 break;
274 case 4320:
275 width = 7680;
276 break;
277 default:
278 break;
279 }
280 }
281 }
282 MESON_LOGD("%s w %d h %d rate %d", __func__, width, height, rate);
283 if ( rate >= 0 )
284 useBestRate = false;
285
286 if ( (width > 0) && (height > 0) ) {
287 if ( ctx->drm_fd >= 0 ) {
288 drmModeRes *res = 0;
289 drmModeConnector *conn = 0;
290
291 res = drmModeGetResources( ctx->drm_fd );
292 if ( res ) {
293 int i;
294 for ( i = 0; i < res->count_connectors; ++i ) {
295 conn = drmModeGetConnector( ctx->drm_fd, res->connectors[i] );
296 if ( conn ) {
297 if ( conn->count_modes && (conn->connection == DRM_MODE_CONNECTED) )
298 break;
299 drmModeFreeConnector(conn);
300 conn = 0;
301 }
302 }
303 if ( conn ) {
304 uint32_t rateBest = 0;
305 int miBest = -1;
306
307 MESON_LOGD("%s: want %dx%dx%d interlaced %d use best rate %d",
308 __func__, width, height, rate, interlaced, useBestRate);
309 for ( i = 0; i < conn->count_modes; ++i ) {
310 MESON_LOGD("%s: consider mode %d: %dx%dx%d (%s) type 0x%x flags 0x%x",
311 __func__, i, conn->modes[i].hdisplay, conn->modes[i].vdisplay,
312 conn->modes[i].vrefresh, conn->modes[i].name,
313 conn->modes[i].type, conn->modes[i].flags );
314
leng.fang3c0ab6d2024-08-01 16:29:00 +0800315 if (!strcmp(conn->modes[i].name, mode))
316 miBest = i;
317
leng.fang91856072024-06-07 14:12:54 +0800318 if ( (conn->modes[i].hdisplay == width) &&
319 (conn->modes[i].vdisplay == height) ) {
320 bool modeIsInterlaced = (conn->modes[i].flags & DRM_MODE_FLAG_INTERLACE);
321 if ( modeIsInterlaced != interlaced )
322 continue;
323
324 if ( useBestRate ) {
325 if ( conn->modes[i].vrefresh > rateBest ) {
326 rateBest = conn->modes[i].vrefresh;
327 miBest = i;
328 }
329 } else if ( conn->modes[i].vrefresh == rate ) {
330 miBest = i;
331 break;
332 }
333 }
334 }
335
336 if ( miBest >= 0 ) {
337 *out_mode = conn->modes[miBest];
338
339 MESON_LOGI("%s: choosing output mode: %dx%dx%d (%s) flags 0x%x",
340 __func__,
341 out_mode->hdisplay,
342 out_mode->vdisplay,
343 out_mode->vrefresh,
344 out_mode->name,
345 out_mode->flags );
346
347 result= true;
348 } else {
349 MESON_LOGE("%s: failed to find a mode matching (%s)", __func__, mode);
350 }
351
352 drmModeFreeConnector( conn );
353 } else {
354 MESON_LOGE("%s: unable to get connector for card", __func__);
355 }
356 drmModeFreeResources(res);
357 } else {
358 MESON_LOGE("%s: unable to get card resources", __func__);
359 }
360 } else {
361 MESON_LOGE("%s: no open device", __func__);
362 }
363 } else {
364 MESON_LOGE("%s: unable to parse mode (%s)", __func__, mode);
365 }
366 }
367
368 return result;
369}
370
371static bool weston_set_mode(const char *mode)
372{
373 weston_ctx *ctx = weston_get_ctx();
374 drmModeModeInfo info = {0};
375
leng.fang3e8a4b52024-07-24 14:51:30 +0800376 if (!ctx)
377 return false;
378
leng.fang91856072024-06-07 14:12:54 +0800379 if (westonGetDrmModeInfoByName(ctx, mode, &info)) {
380 ctx->next_mode.width = info.hdisplay;
381 ctx->next_mode.height = info.vdisplay;
382 ctx->next_mode.refresh = info.vrefresh * 1000;
383 ctx->next_mode.flags = info.flags;
384 setBootConfig(info.name, WestonGetUbootIsBestmode());
385 ctx->mode_update = true;
386 ctx->mode_changed = true;
387 }
388 return 0;
389}
390
391static int weston_get_property(int id, const char *name, char *buf)
392{
393 weston_ctx *ctx = weston_get_ctx();
394 int value = 0;
395
leng.fang3e8a4b52024-07-24 14:51:30 +0800396 if (!ctx)
397 return 0;
398
leng.fang91856072024-06-07 14:12:54 +0800399 if (!ctx->crtc || !ctx->conn)
400 return 0;
401
402 if (ctx->crtc->crtc_id == id)
403 value = weston_get_crtc_property(name);
404
405 if (ctx->conn->connector_id == id)
406 value = weston_get_connector_property(name);
407
408 snprintf(buf, MAX_BUF_LEN, "%d", value);
409 return 0;
410}
411
412static int weston_set_property(int id, const char *name, int value)
413{
414 prop_info *info;
415 weston_ctx *ctx = weston_get_ctx();
416
leng.fang3e8a4b52024-07-24 14:51:30 +0800417 if (!ctx)
418 return 0;
419
leng.fang91856072024-06-07 14:12:54 +0800420 wl_list_for_each(info, &ctx->prop_list, link) {
421 if (!strcmp(name, info->name) && info->item_id == id) {
422 MESON_LOGD("name: %s, id: %d, prop: %d, value: %d\n",
423 name, id, info->prop_id, value);
424 info->value = value;
425 info->need_change = 1;
426 ctx->prop_changed = true;
427 break;
428 }
429 }
430
431 return 0;
432}
433
434static bool weston_set_colorattribute(const char *attr)
435{
436 weston_ctx *ctx = weston_get_ctx();
437 int depth = -1, value = -1; // default none
438
439 if ( attr && strlen(attr) > 3 ) {
440 if ( strstr (attr, "rgb") )
441 value = 0;
442 else if ( strstr (attr, "422") )
443 value = 1;
444 else if ( strstr (attr, "444") )
445 value = 2;
446 else if ( strstr (attr, "420") )
447 value = 3;
448 sscanf(attr + 4, "%dbit", &depth);
449 }
450 if (ctx && ctx->conn && ctx->conn->connector_type == DRM_MODE_CONNECTOR_HDMIA) {
451 weston_set_property(ctx->conn->connector_id, "color_space", value);
452 weston_set_property(ctx->conn->connector_id, "color_depth", depth);
453 }
454 return 0;
455}
456
457void weston_set_scaling_position(int x, int y, int w, int h)
458{
459 weston_ctx *ctx = weston_get_ctx();
460 const char *value = bootenv_get("scaling");
leng.fang3e8a4b52024-07-24 14:51:30 +0800461 int scaling = -1;
leng.fang91856072024-06-07 14:12:54 +0800462
463 if (value)
464 scaling = atoi(value);
465
leng.fangb1081a32024-06-25 14:41:37 +0800466 if (ctx && ctx->scaling != scaling)
467 ctx->scaling = scaling;
leng.fang91856072024-06-07 14:12:54 +0800468}
469
470CompositorFunctionCallBack callback = {
471 .get_mode = weston_get_mode,
472 .set_mode = weston_set_mode,
473 .set_colorattribute = weston_set_colorattribute,
474 .get_property = weston_get_property,
475 .set_property = weston_set_property,
476 .set_scaling_position = weston_set_scaling_position,
477};
478
leng.fangb1081a32024-06-25 14:41:37 +0800479static char *get_color_space_by_value(int value)
480{
481 char *str;
482
483 switch ( value ) {
484 case 0:
485 str = "rgb";
486 break;
487 case 1:
488 str = "422";
489 break;
490 case 2:
491 str = "444";
492 break;
493 case 3:
494 default:
495 str = "420";
496 break;
497 }
498 return str;
499}
500
501static int get_property_value(char *name)
502{
503 prop_info *info;
504 weston_ctx *ctx = weston_get_ctx();
505
leng.fang3e8a4b52024-07-24 14:51:30 +0800506 if (!ctx)
507 return 0;
508
leng.fangb1081a32024-06-25 14:41:37 +0800509 wl_list_for_each(info, &ctx->prop_list, link) {
510 if (!strcmp(name, info->name)) {
511 if (info->need_change == 1)
512 return info->value;
513 }
514 }
515 return -1;
516}
517
518static int get_id_by_name(const char *name)
519{
520 prop_info *info;
521 weston_ctx *ctx = weston_get_ctx();
522
leng.fang3e8a4b52024-07-24 14:51:30 +0800523 if (!ctx)
524 return -1;
525
leng.fangb1081a32024-06-25 14:41:37 +0800526 wl_list_for_each(info, &ctx->prop_list, link) {
527 if (!strcmp(name, info->name))
528 return info->item_id;
529 }
530 return -1;
531}
532
leng.fang3e8a4b52024-07-24 14:51:30 +0800533static int mode_policy_parse_other(weston_ctx *ctx, const char *name, int value)
leng.fangb1081a32024-06-25 14:41:37 +0800534{
leng.fangb1081a32024-06-25 14:41:37 +0800535 char attrvalue[32] = { 0 };
536
537 if (STRCMPS(name, "scaling") == 0) {
538 if (ctx && ctx->scaling != value)
539 ctx->scaling = value;
540
541 sprintf(attrvalue, "%d", value);
542 bootenv_update("scaling", attrvalue);
543 return 0;
544 }
545 return -1;
546}
547
leng.fang13fd3982024-07-03 19:09:58 +0800548static void set_color_attribute(char *space, int depth)
549{
leng.fang13fd3982024-07-03 19:09:58 +0800550 char attrvalue[32] = { 0 };
551 char mode[] = { 0 };
552
553 sprintf(attrvalue, "%s,%dbit", space, depth);
554 setColorSpace(attrvalue);
555 weston_get_mode(mode);
556 setBootConfig(mode, false);
557}
558
leng.fangb1081a32024-06-25 14:41:37 +0800559int mode_policy_set_property(const char *name, int value)
560{
561 char attrvalue[32] = { 0 };
562 int color_space = 0;
563 int color_depth = 0;
564 int id = get_id_by_name(name);
leng.fang3e8a4b52024-07-24 14:51:30 +0800565 weston_ctx *ctx = weston_get_ctx();
leng.fangb1081a32024-06-25 14:41:37 +0800566 MESON_LOGI("id: %d, name: %s, value: %d", id, name, value);
567
leng.fang3e8a4b52024-07-24 14:51:30 +0800568 if (!ctx)
569 return 0;
570
leng.fang3c0ab6d2024-08-01 16:29:00 +0800571 if (!ctx->conn || ctx->conn->connector_type != DRM_MODE_CONNECTOR_HDMIA) {
572 MESON_LOGW("isn't hdmi, don't set property");
573 return 0;
574 }
575
leng.fang3e8a4b52024-07-24 14:51:30 +0800576 initModePolicyFun(ctx->crtc, ctx->conn, callback);
leng.fangb1081a32024-06-25 14:41:37 +0800577 if (value < 0 || id < 0)
leng.fang3e8a4b52024-07-24 14:51:30 +0800578 return mode_policy_parse_other(ctx, name, value);
leng.fangb1081a32024-06-25 14:41:37 +0800579
580 if (strncmp(name, "dv_mode", sizeof("dv_mode")) == 0) {
581 setDvMode(value == 0 ? 1 : (value == 1 ? 2 : 0));
582 return 0;
583 } else if (strncmp(name, "color_depth", sizeof("color_depth")) == 0) {
584 color_space = get_property_value("color_space");
585 if (color_space >= 0) {
leng.fang13fd3982024-07-03 19:09:58 +0800586 set_color_attribute(get_color_space_by_value(color_space), value);
leng.fangb1081a32024-06-25 14:41:37 +0800587 return 0;
588 }
589 } else if (strncmp(name, "color_space", sizeof("color_space")) == 0) {
590 color_depth = get_property_value("color_depth");
591 if (color_depth >= 0) {
leng.fang13fd3982024-07-03 19:09:58 +0800592 set_color_attribute(get_color_space_by_value(value), color_depth);
leng.fangb1081a32024-06-25 14:41:37 +0800593 return 0;
594 }
595 } else if (strncmp(name, "meson.crtc.hdr_policy", sizeof("meson.crtc.hdr_policy")) == 0) {
596 sprintf(attrvalue, "%d", value);
597 bootenv_update("hdr_policy", attrvalue);
598 }
599
600 return weston_set_property(id, name, value);
601}
602
603int mode_policy_get_scaling()
604{
leng.fangc0af1fa2024-08-13 17:54:42 +0800605 const char *env = bootenv_get("scaling");
606 int scaling = DRM_MAX_SCALING;
607
608 if (env)
609 scaling = atoi(env);
610
611 if (scaling < DRM_MIN_SCALING)
612 scaling = DRM_MIN_SCALING;
613
614 if (scaling > DRM_MAX_SCALING)
615 scaling = DRM_MAX_SCALING;
616
617 return scaling;
618}
619
620int mode_policy_set_scaling(int scaling)
621{
leng.fangb1081a32024-06-25 14:41:37 +0800622 weston_ctx *ctx = weston_get_ctx();
leng.fangc0af1fa2024-08-13 17:54:42 +0800623 char attrvalue[32] = { 0 };
leng.fangb1081a32024-06-25 14:41:37 +0800624
leng.fang3e8a4b52024-07-24 14:51:30 +0800625 if (!ctx)
leng.fangc0af1fa2024-08-13 17:54:42 +0800626 return -1;
leng.fang3e8a4b52024-07-24 14:51:30 +0800627
leng.fangc0af1fa2024-08-13 17:54:42 +0800628 if (scaling != ctx->scaling) {
629 ctx->scaling = scaling;
630 sprintf(attrvalue, "%d", scaling);
631 bootenv_update("scaling", attrvalue);
632 }
633 return 0;
leng.fangb1081a32024-06-25 14:41:37 +0800634}
635
leng.fang13fd3982024-07-03 19:09:58 +0800636static struct weston_mode
637drm_mode_to_weston_mode(drmModeModeInfoPtr info)
638{
639 struct weston_mode m;
640
641 m.width = info->hdisplay;
642 m.height = info->vdisplay;
643 //mhz:refresh * 1000
644 m.refresh = info->vrefresh * 1000;
645 //hack: use weston_mode's flags as drm_mode's flags.
646 m.flags = info->flags;
647 m.aspect_ratio = WESTON_MODE_PIC_AR_NONE;
648
649 return m;
650}
651
leng.fang5ec9b6c2024-07-29 14:25:00 +0800652drmModeCrtc *weston_get_crtc_for_conn(int drm_fd, drmModeConnector *conn)
leng.fang91856072024-06-07 14:12:54 +0800653{
654 drmModeEncoder *encoder;
655 drmModeCrtc *crtc = NULL;
chen.wang19f2f82b2024-07-16 11:43:59 +0000656 drmModeRes *res = 0;
657 int i, j, k;
leng.fang91856072024-06-07 14:12:54 +0800658 /* Get the current mode on the crtc that's currently driving
659 * this connector. */
chen.wang19f2f82b2024-07-16 11:43:59 +0000660 res = drmModeGetResources(drm_fd);
661 if ( res ) {
662 for (i= 0; i < res->count_encoders; ++i ) {
663 uint32_t crtcId= 0;
664 bool found= false;
665 encoder = drmModeGetEncoder(drm_fd, res->encoders[i]);
666 if (encoder && conn && (encoder->encoder_id == conn->encoder_id)) {
667 found = true;
668 break;
669 }
670 for (j = 0; j < res->count_crtcs; j++) {
671 if (encoder->possible_crtcs & (1 << j)) {
672 crtcId= res->crtcs[j];
673 for (k = 0; k < res->count_crtcs; k++) {
674 if (res->crtcs[k] == crtcId) {
675 drmModeFreeEncoder(encoder);
676 encoder= drmModeGetEncoder(drm_fd, res->encoders[k]);
677 encoder->crtc_id= crtcId;
leng.fang69a93e32024-08-08 16:31:01 +0800678 MESON_LOGD("got enc %p crtc id %d, conn id: %d", drm_fd, crtcId, conn->connector_id);
chen.wang19f2f82b2024-07-16 11:43:59 +0000679 found = true;
680 break;
681 }
682 }
683 if (found) {
684 break;
685 }
686 }
687 }
688 if (!found) {
689 drmModeFreeEncoder(encoder);
690 encoder= 0;
691 }
692 if (found) {
693 break;
694 }
695 }
696 if (encoder != NULL) {
697 crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
698 drmModeFreeEncoder(encoder);
699 }
700 drmModeFreeResources( res );
701 res = 0;
702 } else {
703 MESON_LOGD("unable to get card resources");
leng.fang91856072024-06-07 14:12:54 +0800704 }
705 return crtc;
706}
707
leng.fang3e8a4b52024-07-24 14:51:30 +0800708void mode_policy_set_head(struct weston_head *head)
leng.fang91856072024-06-07 14:12:54 +0800709{
leng.fang3e8a4b52024-07-24 14:51:30 +0800710 weston_ctx_list *ctx_list = weston_get_ctx_list();
711 ctx_list->head = head;
712}
leng.fang91856072024-06-07 14:12:54 +0800713
leng.fang3e8a4b52024-07-24 14:51:30 +0800714void mode_policy_set_output(struct weston_output *output)
715{
716 weston_ctx_list *ctx_list = weston_get_ctx_list();
717 weston_ctx *ctx, *tmp;
leng.fang91856072024-06-07 14:12:54 +0800718
leng.fang3e8a4b52024-07-24 14:51:30 +0800719 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
720 if (ctx->head && ctx->head->output == output) {
721 mode_policy_set_head(ctx->head);
722 break;
leng.fange9d800e2024-07-12 13:31:59 +0800723 }
leng.fang91856072024-06-07 14:12:54 +0800724 }
725}
726
leng.fang3e8a4b52024-07-24 14:51:30 +0800727static void mode_policy_update_ctx(weston_ctx *ctx,
728 struct weston_head *head, int fd, drmModeConnector *conn)
leng.fang91856072024-06-07 14:12:54 +0800729{
leng.fang3e8a4b52024-07-24 14:51:30 +0800730 drmModeCrtc *crtc = NULL;
731 bool changed = false;
732
733 if (!ctx)
734 return;
735
736 crtc = weston_get_crtc_for_conn(fd, conn);
737 if (!crtc)
738 return;
739
740 if ((ctx->crtc && ctx->crtc->crtc_id != crtc->crtc_id) || !ctx->crtc)
741 changed = true;
742
leng.fang91856072024-06-07 14:12:54 +0800743 if (ctx->crtc)
744 drmModeFreeCrtc(ctx->crtc);
745 ctx->drm_fd = fd;
746 ctx->crtc = crtc;
747 ctx->conn = conn;
leng.fang3e8a4b52024-07-24 14:51:30 +0800748 ctx->head = head;
749 if (changed) {
750 ctx->current_mode = drm_mode_to_weston_mode(&ctx->crtc->mode);
751 weston_prop_list_init(ctx);
752 weston_add_property(ctx, ctx->crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
753 weston_add_property(ctx, ctx->conn->connector_id, DRM_MODE_OBJECT_CONNECTOR);
754 }
755}
756
757void init_mode_policy_without_mode(struct weston_head *head, int fd, drmModeConnector *conn)
758{
759 weston_ctx_list *ctx_list = weston_get_ctx_list();
760 weston_ctx *ctx;
761
762 mode_policy_set_head(head);
763 ctx = weston_get_ctx();
764 if (!ctx) {
765 ctx = (weston_ctx *)calloc(1, sizeof(*ctx));
766 ctx->scaling = -1;
limin.tiana9a091a2024-09-23 07:54:32 +0000767 ctx->enableVrr = true;
leng.fang69a93e32024-08-08 16:31:01 +0800768 ctx->state = ctx_list->state;
limin.tiana9a091a2024-09-23 07:54:32 +0000769 ctx->drm_fd = fd;
770 MESON_LOGD("\n init_mode_policy_without_mode :%d\n", fd);
leng.fang3e8a4b52024-07-24 14:51:30 +0800771 wl_list_init(&ctx->prop_list);
772 wl_list_insert(&ctx_list->ctx_list, &ctx->link);
773 }
774 mode_policy_update_ctx(ctx, head, fd, conn);
leng.fang91856072024-06-07 14:12:54 +0800775}
776
leng.fang13fd3982024-07-03 19:09:58 +0800777static bool need_mode_changed(char *name)
778{
779 int size = sizeof(prop_changed_and_mode) / sizeof(prop_changed_and_mode[0]);
780 int i;
781
782 for (i = 0; i < size; i++) {
783 if (STRCMPS(name, prop_changed_and_mode[i]) == 0)
784 return true;
785 }
786 return false;
787}
788
leng.fang3c0ab6d2024-08-01 16:29:00 +0800789static void mode_policy_add_mode(weston_ctx_list * ctx_list, bool mode_changed)
790{
791 weston_ctx *ctx, *tmp;
792
793 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
794 if (ctx->mode_changed && mode_changed)
795 ctx->need_update_hdmi_param = true;
796 }
797}
798
leng.fang13fd3982024-07-03 19:09:58 +0800799int mode_policy_add_prop(drmModeAtomicReq *req, bool mode_changed)
leng.fang91856072024-06-07 14:12:54 +0800800{
leng.fang91856072024-06-07 14:12:54 +0800801 prop_info *info;
802 int err = 0, ret = 0;
leng.fangb1081a32024-06-25 14:41:37 +0800803 int count = 0;
leng.fang3e8a4b52024-07-24 14:51:30 +0800804 weston_ctx_list * ctx_list = weston_get_ctx_list();
805 weston_ctx *ctx, *tmp;
leng.fang91856072024-06-07 14:12:54 +0800806
leng.fang3c0ab6d2024-08-01 16:29:00 +0800807 mode_policy_add_mode(ctx_list, mode_changed);
leng.fang3e8a4b52024-07-24 14:51:30 +0800808 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
809 wl_list_for_each(info, &ctx->prop_list, link) {
810 if (info->need_change) {
811 if (need_mode_changed(info->name) && !mode_changed)
812 continue;
leng.fang13fd3982024-07-03 19:09:58 +0800813
leng.fang3e8a4b52024-07-24 14:51:30 +0800814 err = drmModeAtomicAddProperty(req, info->item_id, info->prop_id, info->value);
815 if (!err)
816 MESON_LOGE("drmModeAtomicAddProperty %s fail: %d(%d)\n",
817 info->name, err, errno);
818 info->need_change = 0;
819 ret |= (err <= 0) ? -1 : 0;
820 if (!ret)
821 count++;
822 ctx->need_update_hdmi_param = true;
823 }
leng.fang91856072024-06-07 14:12:54 +0800824 }
825 }
leng.fangb1081a32024-06-25 14:41:37 +0800826 return ret >= 0 ? count : ret;
leng.fang91856072024-06-07 14:12:54 +0800827}
828
leng.fang69a93e32024-08-08 16:31:01 +0800829static void weston_set_state_for_ctx(weston_ctx *ctx, int state, bool force)
830{
831 if (!ctx)
832 return;
833
834 if (force) {
835 ctx->state = state;
836 } else {
837 if (ctx->state & state)
838 ctx->state = state;
839 }
840}
841
leng.fang13fd3982024-07-03 19:09:58 +0800842void mode_policy_set_hotplug(int plug, bool force)
leng.fang91856072024-06-07 14:12:54 +0800843{
leng.fang3e8a4b52024-07-24 14:51:30 +0800844 weston_ctx_list *ctx_list = weston_get_ctx_list();
leng.fang69a93e32024-08-08 16:31:01 +0800845 weston_ctx *ctx, *tmp;
leng.fang13fd3982024-07-03 19:09:58 +0800846
leng.fang69a93e32024-08-08 16:31:01 +0800847 ctx_list->state = plug;
848 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
849 if (ctx->conn && ctx->conn->connector_type == DRM_MODE_CONNECTOR_HDMIA)
850 weston_set_state_for_ctx(ctx, plug, force);
leng.fang13fd3982024-07-03 19:09:58 +0800851 }
leng.fang91856072024-06-07 14:12:54 +0800852}
853
leng.fang69a93e32024-08-08 16:31:01 +0800854void mode_policy_set_state(struct weston_head *head, int state, bool force)
855{
856 weston_ctx_list *ctx_list;
857 weston_ctx *ctx, *tmp;
858
859 if (head) {
860 ctx = weston_get_ctx_for_head(head);
861 weston_set_state_for_ctx(ctx, state, force);
862 return;
863 }
864
865 ctx_list = weston_get_ctx_list();
866 ctx_list->state = state;
867 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link)
868 weston_set_state_for_ctx(ctx, state, force);
869}
870
leng.fang91856072024-06-07 14:12:54 +0800871void mode_policy_update_mode(struct weston_mode *mode)
872{
873 weston_ctx *ctx = weston_get_ctx();
leng.fang3e8a4b52024-07-24 14:51:30 +0800874
875 if (!ctx)
876 return;
877
leng.fang91856072024-06-07 14:12:54 +0800878 if (mode)
879 ctx->current_mode = *mode;
leng.fang13fd3982024-07-03 19:09:58 +0800880 else if (ctx->mode_changed)
leng.fang91856072024-06-07 14:12:54 +0800881 ctx->current_mode = ctx->next_mode;
882 MESON_LOGD("curr: %dx%d@%d",
883 ctx->current_mode.width,
884 ctx->current_mode.height,
885 ctx->current_mode.refresh);
886}
887
888struct weston_mode *mode_policy_choose_mode(struct weston_mode *mode)
889{
leng.fang3e8a4b52024-07-24 14:51:30 +0800890 weston_ctx_list * ctx_list = weston_get_ctx_list();
leng.fang91856072024-06-07 14:12:54 +0800891 weston_ctx *ctx = weston_get_ctx();
892 char name[32] = { 0 };
leng.fang91856072024-06-07 14:12:54 +0800893
leng.fang3e8a4b52024-07-24 14:51:30 +0800894 if (!ctx)
895 return NULL;
896
897 initModePolicyFun(ctx->crtc, ctx->conn, callback);
limin.tiana9a091a2024-09-23 07:54:32 +0000898 updateDrmfd(ctx->drm_fd);
899 seamlessSwitchEnabled(ctx->enableVrr);
leng.fang91856072024-06-07 14:12:54 +0800900 if (mode) {
901 if (get_mode_name_for_weston_mode(ctx, mode, name))
902 setActiveConfig(name);
903 } else {
leng.fang69a93e32024-08-08 16:31:01 +0800904 if (ctx->state & (AML_WESTON_HOTPLUG_PLUG | AML_WESTON_HOTPLUG_UNPLUG))
905 onHotplug(ctx->state & AML_WESTON_HOTPLUG_PLUG);
906 else if (ctx->state & (AML_WESTON_HOTPLUG_BOOT | AML_WESTON_HOTPLUG_SET))
leng.fang91856072024-06-07 14:12:54 +0800907 initModePolicy(NULL, NULL, callback);
leng.fang69a93e32024-08-08 16:31:01 +0800908 ctx->state = AML_WESTON_HOTPLUG_INIT;
leng.fang91856072024-06-07 14:12:54 +0800909 }
910 if (ctx->mode_update)
911 return &ctx->next_mode;
leng.fang13fd3982024-07-03 19:09:58 +0800912 return &ctx->current_mode;
leng.fang91856072024-06-07 14:12:54 +0800913}
914
leng.fangb1081a32024-06-25 14:41:37 +0800915void mode_policy_update_bestmode(bool bestmode)
916{
917 bootenv_update("is.bestmode", bestmode ? "true" : "false");
918}
919
leng.fang69a93e32024-08-08 16:31:01 +0800920static int get_possible_by_connector(weston_ctx *ctx)
921{
922 drmModeEncoder *encoder;
923 int possible = 0;
924
925 if (!ctx || !ctx->conn)
926 return 0;
927
928 encoder = drmModeGetEncoder(ctx->drm_fd, ctx->conn->encoder_id);
929 if (encoder) {
930 possible = encoder->possible_crtcs;
931 drmModeFreeEncoder(encoder);
932 }
933 return possible;
934}
935
936void mode_policy_update_modeset(bool *state, bool *modeset, int *possible)
leng.fang13fd3982024-07-03 19:09:58 +0800937{
leng.fang3e8a4b52024-07-24 14:51:30 +0800938 weston_ctx_list * ctx_list = weston_get_ctx_list();
939 weston_ctx *ctx, *tmp;
940 bool mode_changed = false;
leng.fang13fd3982024-07-03 19:09:58 +0800941
leng.fang3e8a4b52024-07-24 14:51:30 +0800942 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
leng.fang69a93e32024-08-08 16:31:01 +0800943 if (ctx->mode_changed) {
leng.fang3e8a4b52024-07-24 14:51:30 +0800944 mode_changed = true;
leng.fang69a93e32024-08-08 16:31:01 +0800945 *possible |= get_possible_by_connector(ctx);
946 }
leng.fang3e8a4b52024-07-24 14:51:30 +0800947 }
948
949 MESON_LOGV("state: %d, modeset: %d, mode_changed: %d", *state, *modeset, mode_changed);
950 if (mode_changed) {
leng.fang13fd3982024-07-03 19:09:58 +0800951 if (!*state)
952 *state = true;
953 if (!*modeset)
954 *modeset = true;
955 }
956}
957
leng.fange9d800e2024-07-12 13:31:59 +0800958void mode_policy_resume()
959{
960 weston_ctx *ctx = weston_get_ctx();
961 int flag;
962
leng.fang3e8a4b52024-07-24 14:51:30 +0800963 if (!ctx)
964 return;
965
leng.fange9d800e2024-07-12 13:31:59 +0800966 flag = (ctx->conn &&
leng.fang5ec9b6c2024-07-29 14:25:00 +0800967 ctx->conn->connector_type == DRM_MODE_CONNECTOR_HDMIA) ?
leng.fange9d800e2024-07-12 13:31:59 +0800968 AML_WESTON_HOTPLUG_PLUG : AML_WESTON_HOTPLUG_SET;
969
leng.fang69a93e32024-08-08 16:31:01 +0800970 weston_set_state_for_ctx(ctx, flag, true);
leng.fange9d800e2024-07-12 13:31:59 +0800971}
972
leng.fang91856072024-06-07 14:12:54 +0800973static void * wstUpdatenvThread(void *arg )
974{
975 long long delay = 16667LL;
leng.fang3e8a4b52024-07-24 14:51:30 +0800976 weston_ctx_list *ctx_list = (weston_ctx_list *)arg;
977 weston_ctx *ctx, *tmp;
leng.fang13fd3982024-07-03 19:09:58 +0800978
leng.fang3e8a4b52024-07-24 14:51:30 +0800979 while (!ctx_list->update_env_thread_stop_requested)
leng.fang91856072024-06-07 14:12:54 +0800980 {
leng.fang3e8a4b52024-07-24 14:51:30 +0800981 wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
leng.fang3c0ab6d2024-08-01 16:29:00 +0800982 if ((ctx->mode_changed && !ctx->prop_changed && ctx->need_update_hdmi_param) ||
leng.fang3e8a4b52024-07-24 14:51:30 +0800983 (ctx->prop_changed && ctx->need_update_hdmi_param))
984 {
985 weston_log("%s[%d]\n", __func__, __LINE__);
leng.fang69a93e32024-08-08 16:31:01 +0800986 mode_policy_set_head(ctx->head);
leng.fang3e8a4b52024-07-24 14:51:30 +0800987 initModePolicyFun(ctx->crtc, ctx->conn, callback);
988 updateEnv();
989 ctx->need_update_hdmi_param = false;
990 ctx->mode_changed = false;
991 ctx->prop_changed = false;
992 }
leng.fang91856072024-06-07 14:12:54 +0800993 }
994 usleep( delay );
995 }
996 MESON_LOGD("update env thread exit");
997 return NULL;
998}
999
1000void weston_start_update_env_thread()
1001{
1002 int rc;
leng.fang3e8a4b52024-07-24 14:51:30 +08001003 weston_ctx_list *ctx_list = weston_get_ctx_list();
leng.fang91856072024-06-07 14:12:54 +08001004
leng.fang3e8a4b52024-07-24 14:51:30 +08001005 ctx_list->update_env_thread_stop_requested = false;
1006 rc = pthread_create(&ctx_list->update_env_thread_id, NULL, wstUpdatenvThread, ctx_list);
leng.fang91856072024-06-07 14:12:54 +08001007 if ( rc )
1008 MESON_LOGE("unable to start updatenv thread: rc %d errno %d", rc, errno);
1009}