blob: e9b622ab6bc0ba3bb175b4239887b0fb860f0f7a [file] [log] [blame]
#include <pthread.h>
#include "modepolicyfunc.h"
#include "DisplayAdapter.h"
#include "modepolicy_aml.h"
weston_ctx_list *gCtx_list = NULL;
static int g_activeLevel = 3;
/* if prop set need change mode, add it to this */
static char *prop_changed_and_mode[] = {
"color_space",
"color_depth",
"dv_mode",
"FRAC_RATE_POLICY"
};
static int weston_set_property(int id, const char *name, int value);
static weston_ctx_list *weston_get_ctx_list()
{
if (!gCtx_list) {
gCtx_list = (weston_ctx_list *)calloc(1, sizeof(*gCtx_list));
wl_list_init(&gCtx_list->ctx_list);
}
return gCtx_list;
}
static weston_ctx *weston_get_ctx_for_head(struct weston_head *head)
{
weston_ctx_list *ctx_list = weston_get_ctx_list();
weston_ctx *ctx, *tmp;
wl_list_for_each(ctx, &ctx_list->ctx_list, link) {
if (ctx->head == head)
return ctx;
}
return NULL;
}
weston_ctx *weston_get_ctx()
{
weston_ctx_list *ctx_list = weston_get_ctx_list();
return weston_get_ctx_for_head(ctx_list->head);
}
static void weston_prop_list_init(weston_ctx *ctx)
{
prop_info *info, *tmp;
if (!wl_list_empty(&ctx->prop_list)) {
wl_list_for_each_safe(info, tmp, &ctx->prop_list, link) {
wl_list_remove(&info->link);
free(info);
}
}
wl_list_init(&ctx->prop_list);
}
static int weston_add_property_item(weston_ctx *ctx,
const char *name, int id, int prop_id)
{
prop_info *info;
wl_list_for_each(info, &ctx->prop_list, link) {
if (!strcmp(name, info->name) && info->item_id == id)
return 0;
}
info = (prop_info *)calloc(1, sizeof(*info));
memcpy(info->name, name, sizeof(info->name));
info->item_id = id;
info->prop_id = prop_id;
info->need_change = 0;
MESON_LOGD("ctx: %p, name: %s, id: %d, prop_id: %d\n", ctx, name, id, prop_id);
wl_list_insert(&ctx->prop_list, &info->link);
return 0;
}
static int weston_add_property(weston_ctx *ctx, int id, int type)
{
int i, len;
int value = 0;
drmModePropertyRes *propRes;
drmModeObjectProperties *props;
props = drmModeObjectGetProperties( ctx->drm_fd, id, type );
if ( props ) {
for ( i= 0; i < props->count_props; ++i ) {
propRes = drmModeGetProperty( ctx->drm_fd, props->props[i] );
if ( propRes ) {
weston_add_property_item(ctx, propRes->name, id, props->props[i]);
drmModeFreeProperty( propRes );
propRes = 0;
}
}
drmModeFreeObjectProperties( props );
props = 0;
}
return value;
}
static int weston_get_property_value(weston_ctx *ctx, const char * key, int id, int type)
{
int i, len;
int value = 0;
drmModePropertyRes *propRes;
drmModeObjectProperties *props;
props = drmModeObjectGetProperties( ctx->drm_fd, id, type );
if ( props ) {
for ( i= 0; i < props->count_props; ++i ) {
propRes = drmModeGetProperty( ctx->drm_fd, props->props[i] );
if ( propRes ) {
len = strlen(propRes->name);
if ( !strncmp( propRes->name, key, len) ) {
MESON_LOGD("property %d name (%s) value (%lld)",
props->props[i], propRes->name, props->prop_values[i] );
value = props->prop_values[i];
drmModeFreeProperty( propRes );
propRes = 0;
break;
}
drmModeFreeProperty( propRes );
propRes = 0;
}
}
drmModeFreeObjectProperties( props );
props = 0;
}
return value;
}
static int weston_get_connector_property(const char * key)
{
weston_ctx *ctx = weston_get_ctx();
if (!ctx)
return 0;
return weston_get_property_value(ctx, key, ctx->conn->connector_id, DRM_MODE_OBJECT_CONNECTOR);
}
static int weston_get_crtc_property(const char * key)
{
weston_ctx *ctx = weston_get_ctx();
if (!ctx)
return 0;
return weston_get_property_value(ctx, key, ctx->crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
}
static bool weston_get_mode_for_env(weston_ctx *ctx, char *out)
{
const char *value = NULL;
if (!ctx || !ctx->conn)
return false;
switch (ctx->conn->connector_type) {
case DRM_MODE_CONNECTOR_HDMIA:
value = bootenv_get("hdmimode");
break;
case DRM_MODE_CONNECTOR_LVDS:
value = bootenv_get("outputmode");
break;
default:
break;
}
if (value)
strcpy(out, value);
else
strcpy(out, "none");
return true;
}
static bool get_mode_name_for_weston_mode(
weston_ctx *ctx,
struct weston_mode *mode,
char *out)
{
int i;
int current_interlaced;
const char *value;
if (mode && getModeNameForPix(out, mode->width, mode->height, mode->refresh, mode->flags))
return true;
weston_get_mode_for_env(ctx, out);
MESON_LOGD("out: %s", out);
return false;
}
static bool weston_get_mode(char *mode)
{
weston_ctx *ctx = weston_get_ctx();
struct weston_mode *wmode = NULL;
if (!wmode && ctx && ctx->current_mode.width != 0)
wmode = &ctx->current_mode;
return get_mode_name_for_weston_mode(ctx, wmode, mode);
}
bool WestonGetUbootIsBestmode()
{
const char *isbestmode = bootenv_get("is.bestmode");
if ( isbestmode != NULL ) {
if (strcmp("false", isbestmode) == 0)
return false;
else
return true;
} else
return true;
}
bool westonGetDrmModeInfoByName( weston_ctx *ctx, const char *mode, drmModeModeInfo *out_mode )
{
bool result= false;
if ( ctx && mode && out_mode ) {
int width = -1, height = -1, rate = -1;
bool interlaced = false;
bool haveTarget = false;
bool useBestRate = true;
MESON_LOGD("%s: mode (%s)", __func__, mode);
if ( sscanf( mode, "%dx%dp%d", &width, &height, &rate ) == 3 ) {
interlaced = false;
} else if ( sscanf( mode, "%dx%di%d", &width, &height, &rate ) == 3 ) {
interlaced = true;
} else if ( sscanf( mode, "%dx%dx%d", &width, &height, &rate ) == 3 ) {
interlaced = false;
} else if ( sscanf( mode, "%dx%d", &width, &height ) == 2 ) {
int len = strlen(mode);
interlaced = (mode[len - 1] == 'i');
} else if (sscanf( mode, "%dp%dhz", &height,&rate ) == 2) {
interlaced = false;
width = -1;
} else if (sscanf( mode, "%di%dhz", &height,&rate ) == 2) {
interlaced = true;
width = -1;
} else if ( sscanf( mode, "%dp", &height ) == 1 ) {
int len = strlen(mode);
interlaced = (mode[len - 1] == 'i');
width = -1;
} else if (sscanf( mode, "smpte%dhz", &rate ) == 1) {
interlaced = false;
height = 2160;
width = 4096;
}
if ( height > 0 ) {
if ( width < 0 ) {
switch ( height ) {
case 480:
case 576:
width = 720;
break;
case 720:
width = 1280;
break;
case 1080:
width = 1920;
break;
case 1440:
width = 2560;
break;
case 2160:
width = 3840;
break;
case 2880:
width = 5120;
break;
case 4320:
width = 7680;
break;
default:
break;
}
}
}
MESON_LOGD("%s w %d h %d rate %d", __func__, width, height, rate);
if ( rate >= 0 )
useBestRate = false;
if ( (width > 0) && (height > 0) ) {
if ( ctx->drm_fd >= 0 ) {
drmModeRes *res = 0;
drmModeConnector *conn = 0;
res = drmModeGetResources( ctx->drm_fd );
if ( res ) {
int i;
for ( i = 0; i < res->count_connectors; ++i ) {
conn = drmModeGetConnector( ctx->drm_fd, res->connectors[i] );
if ( conn ) {
if ( conn->count_modes && (conn->connection == DRM_MODE_CONNECTED) )
break;
drmModeFreeConnector(conn);
conn = 0;
}
}
if ( conn ) {
uint32_t rateBest = 0;
int miBest = -1;
MESON_LOGD("%s: want %dx%dx%d interlaced %d use best rate %d",
__func__, width, height, rate, interlaced, useBestRate);
for ( i = 0; i < conn->count_modes; ++i ) {
MESON_LOGD("%s: consider mode %d: %dx%dx%d (%s) type 0x%x flags 0x%x",
__func__, i, conn->modes[i].hdisplay, conn->modes[i].vdisplay,
conn->modes[i].vrefresh, conn->modes[i].name,
conn->modes[i].type, conn->modes[i].flags );
if (!strcmp(conn->modes[i].name, mode))
miBest = i;
if ( (conn->modes[i].hdisplay == width) &&
(conn->modes[i].vdisplay == height) ) {
bool modeIsInterlaced = (conn->modes[i].flags & DRM_MODE_FLAG_INTERLACE);
if ( modeIsInterlaced != interlaced )
continue;
if ( useBestRate ) {
if ( conn->modes[i].vrefresh > rateBest ) {
rateBest = conn->modes[i].vrefresh;
miBest = i;
}
} else if ( conn->modes[i].vrefresh == rate ) {
miBest = i;
break;
}
}
}
if ( miBest >= 0 ) {
*out_mode = conn->modes[miBest];
MESON_LOGI("%s: choosing output mode: %dx%dx%d (%s) flags 0x%x",
__func__,
out_mode->hdisplay,
out_mode->vdisplay,
out_mode->vrefresh,
out_mode->name,
out_mode->flags );
result= true;
} else {
MESON_LOGE("%s: failed to find a mode matching (%s)", __func__, mode);
}
drmModeFreeConnector( conn );
} else {
MESON_LOGE("%s: unable to get connector for card", __func__);
}
drmModeFreeResources(res);
} else {
MESON_LOGE("%s: unable to get card resources", __func__);
}
} else {
MESON_LOGE("%s: no open device", __func__);
}
} else {
MESON_LOGE("%s: unable to parse mode (%s)", __func__, mode);
}
}
return result;
}
static bool weston_set_mode(const char *mode)
{
weston_ctx *ctx = weston_get_ctx();
drmModeModeInfo info = {0};
if (!ctx)
return false;
if (westonGetDrmModeInfoByName(ctx, mode, &info)) {
ctx->next_mode.width = info.hdisplay;
ctx->next_mode.height = info.vdisplay;
ctx->next_mode.refresh = info.vrefresh * 1000;
ctx->next_mode.flags = info.flags;
setBootConfig(info.name, WestonGetUbootIsBestmode());
ctx->mode_update = true;
ctx->mode_changed = true;
}
return 0;
}
static int weston_get_property(int id, const char *name, char *buf)
{
weston_ctx *ctx = weston_get_ctx();
int value = 0;
if (!ctx)
return 0;
if (!ctx->crtc || !ctx->conn)
return 0;
if (ctx->crtc->crtc_id == id)
value = weston_get_crtc_property(name);
if (ctx->conn->connector_id == id)
value = weston_get_connector_property(name);
snprintf(buf, MAX_BUF_LEN, "%d", value);
return 0;
}
static int weston_set_property(int id, const char *name, int value)
{
prop_info *info;
weston_ctx *ctx = weston_get_ctx();
if (!ctx)
return 0;
wl_list_for_each(info, &ctx->prop_list, link) {
if (!strcmp(name, info->name) && info->item_id == id) {
MESON_LOGD("name: %s, id: %d, prop: %d, value: %d\n",
name, id, info->prop_id, value);
info->value = value;
info->need_change = 1;
ctx->prop_changed = true;
break;
}
}
return 0;
}
static bool weston_set_colorattribute(const char *attr)
{
weston_ctx *ctx = weston_get_ctx();
int depth = -1, value = -1; // default none
if ( attr && strlen(attr) > 3 ) {
if ( strstr (attr, "rgb") )
value = 0;
else if ( strstr (attr, "422") )
value = 1;
else if ( strstr (attr, "444") )
value = 2;
else if ( strstr (attr, "420") )
value = 3;
sscanf(attr + 4, "%dbit", &depth);
}
if (ctx && ctx->conn && ctx->conn->connector_type == DRM_MODE_CONNECTOR_HDMIA) {
weston_set_property(ctx->conn->connector_id, "color_space", value);
weston_set_property(ctx->conn->connector_id, "color_depth", depth);
}
return 0;
}
void weston_set_scaling_position(int x, int y, int w, int h)
{
weston_ctx *ctx = weston_get_ctx();
const char *value = bootenv_get("scaling");
int scaling = -1;
if (value)
scaling = atoi(value);
if (ctx && ctx->scaling != scaling)
ctx->scaling = scaling;
}
CompositorFunctionCallBack callback = {
.get_mode = weston_get_mode,
.set_mode = weston_set_mode,
.set_colorattribute = weston_set_colorattribute,
.get_property = weston_get_property,
.set_property = weston_set_property,
.set_scaling_position = weston_set_scaling_position,
};
static char *get_color_space_by_value(int value)
{
char *str;
switch ( value ) {
case 0:
str = "rgb";
break;
case 1:
str = "422";
break;
case 2:
str = "444";
break;
case 3:
default:
str = "420";
break;
}
return str;
}
static int get_property_value(char *name)
{
prop_info *info;
weston_ctx *ctx = weston_get_ctx();
if (!ctx)
return 0;
wl_list_for_each(info, &ctx->prop_list, link) {
if (!strcmp(name, info->name)) {
if (info->need_change == 1)
return info->value;
}
}
return -1;
}
static int get_id_by_name(const char *name)
{
prop_info *info;
weston_ctx *ctx = weston_get_ctx();
if (!ctx)
return -1;
wl_list_for_each(info, &ctx->prop_list, link) {
if (!strcmp(name, info->name))
return info->item_id;
}
return -1;
}
static int mode_policy_parse_other(weston_ctx *ctx, const char *name, int value)
{
char attrvalue[32] = { 0 };
if (STRCMPS(name, "scaling") == 0) {
if (ctx && ctx->scaling != value)
ctx->scaling = value;
sprintf(attrvalue, "%d", value);
bootenv_update("scaling", attrvalue);
return 0;
}
return -1;
}
static void set_color_attribute(char *space, int depth)
{
char attrvalue[32] = { 0 };
char mode[] = { 0 };
sprintf(attrvalue, "%s,%dbit", space, depth);
setColorSpace(attrvalue);
weston_get_mode(mode);
setBootConfig(mode, false);
}
int mode_policy_set_property(const char *name, int value)
{
char attrvalue[32] = { 0 };
int color_space = 0;
int color_depth = 0;
int id = get_id_by_name(name);
weston_ctx *ctx = weston_get_ctx();
MESON_LOGI("id: %d, name: %s, value: %d", id, name, value);
if (!ctx)
return 0;
if (!ctx->conn || ctx->conn->connector_type != DRM_MODE_CONNECTOR_HDMIA) {
MESON_LOGW("isn't hdmi, don't set property");
return 0;
}
initModePolicyFun(ctx->crtc, ctx->conn, callback);
if (value < 0 || id < 0)
return mode_policy_parse_other(ctx, name, value);
if (strncmp(name, "dv_mode", sizeof("dv_mode")) == 0) {
setDvMode(value == 0 ? 1 : (value == 1 ? 2 : 0));
return 0;
} else if (strncmp(name, "color_depth", sizeof("color_depth")) == 0) {
color_space = get_property_value("color_space");
if (color_space >= 0) {
set_color_attribute(get_color_space_by_value(color_space), value);
return 0;
}
} else if (strncmp(name, "color_space", sizeof("color_space")) == 0) {
color_depth = get_property_value("color_depth");
if (color_depth >= 0) {
set_color_attribute(get_color_space_by_value(value), color_depth);
return 0;
}
} else if (strncmp(name, "meson.crtc.hdr_policy", sizeof("meson.crtc.hdr_policy")) == 0) {
sprintf(attrvalue, "%d", value);
bootenv_update("hdr_policy", attrvalue);
}
return weston_set_property(id, name, value);
}
int mode_policy_get_scaling()
{
const char *env = bootenv_get("scaling");
int scaling = DRM_MAX_SCALING;
if (env)
scaling = atoi(env);
if (scaling < DRM_MIN_SCALING)
scaling = DRM_MIN_SCALING;
if (scaling > DRM_MAX_SCALING)
scaling = DRM_MAX_SCALING;
return scaling;
}
int mode_policy_set_scaling(int scaling)
{
weston_ctx *ctx = weston_get_ctx();
char attrvalue[32] = { 0 };
if (!ctx)
return -1;
if (scaling != ctx->scaling) {
ctx->scaling = scaling;
sprintf(attrvalue, "%d", scaling);
bootenv_update("scaling", attrvalue);
}
return 0;
}
static struct weston_mode
drm_mode_to_weston_mode(drmModeModeInfoPtr info)
{
struct weston_mode m;
m.width = info->hdisplay;
m.height = info->vdisplay;
//mhz:refresh * 1000
m.refresh = info->vrefresh * 1000;
//hack: use weston_mode's flags as drm_mode's flags.
m.flags = info->flags;
m.aspect_ratio = WESTON_MODE_PIC_AR_NONE;
return m;
}
drmModeCrtc *weston_get_crtc_for_conn(int drm_fd, drmModeConnector *conn)
{
drmModeEncoder *encoder;
drmModeCrtc *crtc = NULL;
drmModeRes *res = 0;
int i, j, k;
/* Get the current mode on the crtc that's currently driving
* this connector. */
res = drmModeGetResources(drm_fd);
if ( res ) {
for (i= 0; i < res->count_encoders; ++i ) {
uint32_t crtcId= 0;
bool found= false;
encoder = drmModeGetEncoder(drm_fd, res->encoders[i]);
if (encoder && conn && (encoder->encoder_id == conn->encoder_id)) {
found = true;
break;
}
for (j = 0; j < res->count_crtcs; j++) {
if (encoder->possible_crtcs & (1 << j)) {
crtcId= res->crtcs[j];
for (k = 0; k < res->count_crtcs; k++) {
if (res->crtcs[k] == crtcId) {
drmModeFreeEncoder(encoder);
encoder= drmModeGetEncoder(drm_fd, res->encoders[k]);
encoder->crtc_id= crtcId;
MESON_LOGD("got enc %p crtc id %d, conn id: %d", drm_fd, crtcId, conn->connector_id);
found = true;
break;
}
}
if (found) {
break;
}
}
}
if (!found) {
drmModeFreeEncoder(encoder);
encoder= 0;
}
if (found) {
break;
}
}
if (encoder != NULL) {
crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
drmModeFreeEncoder(encoder);
}
drmModeFreeResources( res );
res = 0;
} else {
MESON_LOGD("unable to get card resources");
}
return crtc;
}
void mode_policy_set_head(struct weston_head *head)
{
weston_ctx_list *ctx_list = weston_get_ctx_list();
ctx_list->head = head;
}
void mode_policy_set_output(struct weston_output *output)
{
weston_ctx_list *ctx_list = weston_get_ctx_list();
weston_ctx *ctx, *tmp;
wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
if (ctx->head && ctx->head->output == output) {
mode_policy_set_head(ctx->head);
break;
}
}
}
static void mode_policy_update_ctx(weston_ctx *ctx,
struct weston_head *head, int fd, drmModeConnector *conn)
{
drmModeCrtc *crtc = NULL;
bool changed = false;
if (!ctx)
return;
crtc = weston_get_crtc_for_conn(fd, conn);
if (!crtc)
return;
if ((ctx->crtc && ctx->crtc->crtc_id != crtc->crtc_id) || !ctx->crtc)
changed = true;
if (ctx->crtc)
drmModeFreeCrtc(ctx->crtc);
ctx->drm_fd = fd;
ctx->crtc = crtc;
ctx->conn = conn;
ctx->head = head;
if (changed) {
ctx->current_mode = drm_mode_to_weston_mode(&ctx->crtc->mode);
weston_prop_list_init(ctx);
weston_add_property(ctx, ctx->crtc->crtc_id, DRM_MODE_OBJECT_CRTC);
weston_add_property(ctx, ctx->conn->connector_id, DRM_MODE_OBJECT_CONNECTOR);
}
}
void init_mode_policy_without_mode(struct weston_head *head, int fd, drmModeConnector *conn)
{
weston_ctx_list *ctx_list = weston_get_ctx_list();
weston_ctx *ctx;
mode_policy_set_head(head);
ctx = weston_get_ctx();
if (!ctx) {
ctx = (weston_ctx *)calloc(1, sizeof(*ctx));
ctx->scaling = -1;
ctx->enableVrr = true;
ctx->state = ctx_list->state;
ctx->drm_fd = fd;
MESON_LOGD("\n init_mode_policy_without_mode :%d\n", fd);
wl_list_init(&ctx->prop_list);
wl_list_insert(&ctx_list->ctx_list, &ctx->link);
}
mode_policy_update_ctx(ctx, head, fd, conn);
}
static bool need_mode_changed(char *name)
{
int size = sizeof(prop_changed_and_mode) / sizeof(prop_changed_and_mode[0]);
int i;
for (i = 0; i < size; i++) {
if (STRCMPS(name, prop_changed_and_mode[i]) == 0)
return true;
}
return false;
}
static void mode_policy_add_mode(weston_ctx_list * ctx_list, bool mode_changed)
{
weston_ctx *ctx, *tmp;
wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
if (ctx->mode_changed && mode_changed)
ctx->need_update_hdmi_param = true;
}
}
int mode_policy_add_prop(drmModeAtomicReq *req, bool mode_changed)
{
prop_info *info;
int err = 0, ret = 0;
int count = 0;
weston_ctx_list * ctx_list = weston_get_ctx_list();
weston_ctx *ctx, *tmp;
mode_policy_add_mode(ctx_list, mode_changed);
wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
wl_list_for_each(info, &ctx->prop_list, link) {
if (info->need_change) {
if (need_mode_changed(info->name))
count++;
err = drmModeAtomicAddProperty(req, info->item_id, info->prop_id, info->value);
if (!err)
MESON_LOGE("drmModeAtomicAddProperty %s fail: %d(%d)\n",
info->name, err, errno);
weston_log("mode_policy_add_prop name %s value %lld\n",info->name,info->value);
info->need_change = 0;
ret |= (err <= 0) ? -1 : 0;
ctx->need_update_hdmi_param = true;
}
}
}
return ret >= 0 ? count : ret;
}
static void weston_set_state_for_ctx(weston_ctx *ctx, int state, bool force)
{
if (!ctx)
return;
if (force) {
ctx->state = state;
} else {
if (ctx->state & state)
ctx->state = state;
}
}
void mode_policy_set_hotplug(int plug, bool force)
{
weston_ctx_list *ctx_list = weston_get_ctx_list();
weston_ctx *ctx, *tmp;
ctx_list->state = plug;
wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
if (ctx->conn && ctx->conn->connector_type == DRM_MODE_CONNECTOR_HDMIA)
weston_set_state_for_ctx(ctx, plug, force);
}
}
void mode_policy_set_state(struct weston_head *head, int state, bool force)
{
weston_ctx_list *ctx_list;
weston_ctx *ctx, *tmp;
if (head) {
ctx = weston_get_ctx_for_head(head);
weston_set_state_for_ctx(ctx, state, force);
return;
}
ctx_list = weston_get_ctx_list();
ctx_list->state = state;
wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link)
weston_set_state_for_ctx(ctx, state, force);
}
void mode_policy_update_mode_state(struct weston_head *head, int state)
{
weston_ctx_list *ctx_list;
weston_ctx *ctx, *tmp;
if (head) {
ctx = weston_get_ctx_for_head(head);
ctx->mode_state = state;
return;
}
ctx_list = weston_get_ctx_list();
wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link)
ctx->mode_state = state;
}
void mode_policy_update_mode(struct weston_mode *mode)
{
weston_ctx *ctx = weston_get_ctx();
if (!ctx)
return;
if (mode)
ctx->current_mode = *mode;
else if (ctx->mode_changed)
ctx->current_mode = ctx->next_mode;
MESON_LOGD("curr: %dx%d@%d",
ctx->current_mode.width,
ctx->current_mode.height,
ctx->current_mode.refresh);
}
struct weston_mode *mode_policy_choose_mode(struct weston_mode *mode)
{
weston_ctx_list * ctx_list = weston_get_ctx_list();
weston_ctx *ctx = weston_get_ctx();
char name[32] = { 0 };
if (!ctx)
return NULL;
initModePolicyFun(ctx->crtc, ctx->conn, callback);
updateDrmfd(ctx->drm_fd);
seamlessSwitchEnabled(ctx->enableVrr);
if (mode) {
if (get_mode_name_for_weston_mode(ctx, mode, name))
setActiveConfig(name);
} else {
if (ctx->state & (AML_WESTON_HOTPLUG_PLUG | AML_WESTON_HOTPLUG_UNPLUG))
onHotplug(ctx->state & AML_WESTON_HOTPLUG_PLUG);
else if (ctx->state & (AML_WESTON_HOTPLUG_BOOT | AML_WESTON_HOTPLUG_SET))
initModePolicy(NULL, NULL, callback);
ctx->state = AML_WESTON_HOTPLUG_INIT;
}
if (ctx->mode_update)
return &ctx->next_mode;
return &ctx->current_mode;
}
void mode_policy_update_bestmode(bool bestmode)
{
bootenv_update("is.bestmode", bestmode ? "true" : "false");
}
static int get_possible_by_connector(weston_ctx *ctx)
{
drmModeEncoder *encoder;
int possible = 0;
if (!ctx || !ctx->conn)
return 0;
encoder = drmModeGetEncoder(ctx->drm_fd, ctx->conn->encoder_id);
if (encoder) {
possible = encoder->possible_crtcs;
drmModeFreeEncoder(encoder);
}
return possible;
}
void mode_policy_update_modeset(int *possible)
{
weston_ctx_list * ctx_list = weston_get_ctx_list();
weston_ctx *ctx, *tmp;
wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
if (ctx->mode_changed) {
*possible |= get_possible_by_connector(ctx);
}
if (ctx->mode_state == AML_WESTON_EXIT_SET_MODE)
ctx->mode_state = AML_WESTON_NORMAL;
}
MESON_LOGV("*possible : %d", *possible);
}
void mode_policy_resume()
{
weston_ctx *ctx = weston_get_ctx();
int flag;
if (!ctx)
return;
flag = (ctx->conn &&
ctx->conn->connector_type == DRM_MODE_CONNECTOR_HDMIA) ?
AML_WESTON_HOTPLUG_PLUG : AML_WESTON_HOTPLUG_SET;
weston_set_state_for_ctx(ctx, flag, true);
}
static int get_priority_strategy(int prio)
{
return (prio >> 28) & 0xf;
}
static int switch_strategy1_to_strategy2(int prio)
{
int ret = prio;
if (get_priority_strategy(prio) == 0) {
switch (prio) {
case MESON_DOLBY_VISION_PRIORITY:
ret = MESON_G_DV_HDR10_HLG;
break;
case MESON_HDR10_PRIORITY:
ret = MESON_G_HDR10_HLG;
break;
case MESON_SDR_PRIORITY:
ret = MESON_G_SDR;
break;
default:
ret = prio;
break;
}
}
return ret;
}
static int switch_strategy2_to_strategy1(int prio)
{
int ret = prio;
if (get_priority_strategy(prio) == 1) {
switch (prio) {
case MESON_G_DV_HDR10_HLG:
case MESON_G_DV_HDR10:
case MESON_G_DV_HLG:
case MESON_G_DV:
ret = MESON_DOLBY_VISION_PRIORITY;
break;
case MESON_G_HDR10_HLG:
case MESON_G_HDR10:
case MESON_G_HLG:
ret = MESON_HDR10_PRIORITY;
break;
case MESON_G_SDR:
ret = MESON_SDR_PRIORITY;
break;
default:
ret = prio;
break;
}
}
return ret;
}
int mode_policy_set_priority(int priority)
{
weston_ctx_list * ctx_list = weston_get_ctx_list();
weston_ctx *ctx = weston_get_ctx();
if (!ctx)
return NULL;
initModePolicyFun(ctx->crtc, ctx->conn, callback);
updateDrmfd(ctx->drm_fd);
seamlessSwitchEnabled(ctx->enableVrr);
return setPriority(switch_strategy2_to_strategy1(priority));
}
int mode_policy_get_priority()
{
int priority = getPriority();
return switch_strategy2_to_strategy1(priority);
}
static void * wstUpdatenvThread(void *arg )
{
long long delay = 16667LL;
weston_ctx_list *ctx_list = (weston_ctx_list *)arg;
weston_ctx *ctx, *tmp;
while (!ctx_list->update_env_thread_stop_requested)
{
wl_list_for_each_safe(ctx, tmp, &ctx_list->ctx_list, link) {
if ((ctx->mode_changed && !ctx->prop_changed && ctx->need_update_hdmi_param) ||
(ctx->prop_changed && ctx->need_update_hdmi_param))
{
weston_log("%s[%d]: mode state: %d\n", __func__, __LINE__, ctx->mode_state);
if (ctx->mode_state)
continue;
mode_policy_set_head(ctx->head);
initModePolicyFun(ctx->crtc, ctx->conn, callback);
updateEnv();
ctx->need_update_hdmi_param = false;
ctx->mode_changed = false;
ctx->prop_changed = false;
}
}
usleep( delay );
}
MESON_LOGD("update env thread exit");
return NULL;
}
void weston_start_update_env_thread()
{
int rc;
weston_ctx_list *ctx_list = weston_get_ctx_list();
ctx_list->update_env_thread_stop_requested = false;
rc = pthread_create(&ctx_list->update_env_thread_id, NULL, wstUpdatenvThread, ctx_list);
if ( rc )
MESON_LOGE("unable to start updatenv thread: rc %d errno %d", rc, errno);
}
bool set_policy_by_appName(const char *name, int state) {
return setPolicyByAppName( name, state);
}
bool get_next_mode(struct weston_mode* mode)
{
bool ret = false;
weston_ctx *ctx = weston_get_ctx();
if (!ctx) {
MESON_LOGE("invalid ctx,return\n");
return ret;
}
if (ctx->mode_changed) {
*mode = ctx->next_mode;
ret = true;
}
return ret;
}