이 장에서는 DRM core에서 drm_connector_helper_funcs의 get_modes를 여러번 호출했을때 중복 저장되는 display mode가 어떻게 처리되는지 확인해 보기로 한다.
DRM core는 drm_connector_helper_funcs의 get_modes api를 호출해서 현재 연결된 connector의 display mode정보를
가져온다.
struct drm_connector_helper_funcs {
...
int (*get_modes)(struct drm_connector *connector);
...
};
이 get_modes는 보통 다음과 같이 구현되어 있다.
static int imx_ldb_connector_get_modes(struct drm_connector *connector)
{
struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
...
if (imx_ldb_ch->edid) {
drm_mode_connector_update_edid_property(connector,
imx_ldb_ch->edid);
num_modes = drm_add_edid_modes(connector, imx_ldb_ch->edid);
}
if (imx_ldb_ch->mode_valid) {
struct drm_display_mode *mode;
mode = drm_mode_create(connector->dev);
if (!mode)
return -EINVAL;
drm_mode_copy(mode, &imx_ldb_ch->mode);
mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector, mode);
num_modes++;
}
return num_modes;
}
HDMI나 DP처럼 edid를 읽어온 경우 drm_add_edid_modes를 그렇지 않고 LVDS panel처럼 display mode를 제공하는 경우는 drm_mode_probed_add를 호출하고 이 두함수는 최종적으로 다음 함수를 호출해서 display mode정보fmf connector에 저장한다.
void drm_mode_probed_add(struct drm_connector *connector,
struct drm_display_mode *mode)
{
WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
list_add_tail(&mode->head, &connector->probed_modes);
}
EXPORT_SYMBOL(drm_mode_probed_add);
그런데 get_modes은 부팅시나 부팅후 상황에 따라 여러번 호출되는 것을 볼수 있다. 그래서 connecto의 probed_mods에 display mode를 매번 추가 하는것처럼 보이는데 여러번 호출되어도 문제 없는지 확인해 보기로 했다.
확인 결과 drm_helper_probe_single_connector_modes가 호출될때마다 drm_mode_connector_list_update 함수가 호출되면서 아래와 같이 중복되는 display mode를 제거해주고 있는것을 알게되었다.
void drm_mode_connector_list_update(struct drm_connector *connector)
{
struct drm_display_mode *pmode, *pt;
WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
list_for_each_entry_safe(pmode, pt, &connector->probed_modes, head) {
struct drm_display_mode *mode;
bool found_it = false;
/* go through current modes checking for the new probed mode */
list_for_each_entry(mode, &connector->modes, head) {
if (!drm_mode_equal(pmode, mode))
continue;
found_it = true;
/*
* If the old matching mode is stale (ie. left over
* from a previous probe) just replace it outright.
* Otherwise just merge the type bits between all
* equal probed modes.
*
* If two probed modes are considered equal, pick the
* actual timings from the one that's marked as
* preferred (in case the match isn't 100%). If
* multiple or zero preferred modes are present, favor
* the mode added to the probed_modes list first.
*/
if (mode->status == MODE_STALE) {
drm_mode_copy(mode, pmode);
} else if ((mode->type & DRM_MODE_TYPE_PREFERRED) == 0 &&
(pmode->type & DRM_MODE_TYPE_PREFERRED) != 0) {
pmode->type |= mode->type;
drm_mode_copy(mode, pmode);
} else {
mode->type |= pmode->type;
}
pr_err("%s remove duplicated list", __func__);
list_del(&pmode->head);
drm_mode_destroy(connector->dev, pmode);
break;
}
if (!found_it) {
list_move_tail(&pmode->head, &connector->modes);
}
}
}
EXPORT_SYMBOL(drm_mode_connector_list_update);
'Linux > DRM' 카테고리의 다른 글
DRM flip-work (0) | 2022.01.24 |
---|---|
drm_atomic_helper_commit_planes (0) | 2021.11.08 |