From 35c52e2194adee6630c3ecfc64c9315c58d57e6d Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Wed, 19 Jun 2019 14:15:08 +0800 Subject: [PATCH] drm/rockchip: driver: add support more property Change-Id: If2cbc617d9346713efaf7dc4dd5c393e8605f91d Signed-off-by: Sandy Huang --- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 157 ++++++++++++++- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 6 + drivers/gpu/drm/rockchip/rockchip_drm_fb.h | 1 - drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 212 +++++++++++++++++++- include/drm/drm_atomic.h | 5 + 5 files changed, 370 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 67d0f9adc66d..0eb3555f945b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -37,6 +37,8 @@ #include "rockchip_drm_fbdev.h" #include "rockchip_drm_gem.h" +#include "../drm_internal.h" + #define DRIVER_NAME "rockchip" #define DRIVER_DESC "RockChip Soc DRM" #define DRIVER_DATE "20140818" @@ -571,6 +573,7 @@ static int update_state(struct drm_device *drm_dev, struct rockchip_drm_mode_set *set, unsigned int *plane_mask) { + struct rockchip_drm_private *priv = drm_dev->dev_private; struct drm_crtc *crtc = set->crtc; struct drm_connector *connector = set->connector; struct drm_display_mode *mode = set->mode; @@ -578,6 +581,7 @@ static int update_state(struct drm_device *drm_dev, struct drm_crtc_state *crtc_state; struct drm_connector_state *conn_state; int ret; + struct rockchip_crtc_state *s; crtc_state = drm_atomic_get_crtc_state(state, crtc); if (IS_ERR(crtc_state)) @@ -585,6 +589,11 @@ static int update_state(struct drm_device *drm_dev, conn_state = drm_atomic_get_connector_state(state, connector); if (IS_ERR(conn_state)) return PTR_ERR(conn_state); + s = to_rockchip_crtc_state(crtc_state); + s->left_margin = set->left_margin; + s->right_margin = set->right_margin; + s->top_margin = set->top_margin; + s->bottom_margin = set->bottom_margin; if (set->mode_changed) { ret = drm_atomic_set_crtc_for_connector(conn_state, crtc); @@ -630,13 +639,17 @@ static int update_state(struct drm_device *drm_dev, drm_framebuffer_put(set->fb); ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); - /* - * TODO: - * some vop maybe not support ymirror, but force use it now. - * drm_atomic_plane_set_property(crtc->primary, primary_state, - * mode_config->rotation_property, - * BIT(DRM_REFLECT_Y)); - */ + if (set->ymirror) { + /* + * TODO: + * some vop maybe not support ymirror, but force use it now. + */ + ret = drm_atomic_set_property(state, + &primary_state->plane->base, + priv->logo_ymirror_prop, true); + if (ret) + DRM_ERROR("Failed to initial logo_ymirror_prop\n"); + } return ret; } @@ -675,7 +688,11 @@ static void show_loader_logo(struct drm_device *drm_dev) } state->acquire_ctx = mode_config->acquire_ctx; + for_each_child_of_node(root, route) { + if (!of_device_is_available(route)) + continue; + set = of_parse_display_resource(drm_dev, route); if (!set) continue; @@ -865,6 +882,50 @@ static void rockchip_iommu_cleanup(struct drm_device *drm_dev) iommu_domain_free(private->domain); } +static int rockchip_drm_create_properties(struct drm_device *dev) +{ + struct drm_property *prop; + struct rockchip_drm_private *private = dev->dev_private; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "EOTF", 0, 5); + if (!prop) + return -ENOMEM; + private->eotf_prop = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "COLOR_SPACE", 0, 12); + if (!prop) + return -ENOMEM; + private->color_space_prop = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "GLOBAL_ALPHA", 0, 255); + if (!prop) + return -ENOMEM; + private->global_alpha_prop = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "BLEND_MODE", 0, 1); + if (!prop) + return -ENOMEM; + private->blend_mode_prop = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "ALPHA_SCALE", 0, 1); + if (!prop) + return -ENOMEM; + private->alpha_scale_prop = prop; + + prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC, + "LOGO_YMIRROR", 0, 1); + if (!prop) + return -ENOMEM; + private->logo_ymirror_prop = prop; + + return drm_mode_create_tv_properties(dev, 0, NULL); +} + static int rockchip_gem_pool_init(struct drm_device *drm) { struct rockchip_drm_private *private = drm->dev_private; @@ -905,6 +966,84 @@ static void rockchip_gem_pool_destroy(struct drm_device *drm) gen_pool_destroy(private->secure_buffer_pool); } +static void rockchip_attach_connector_property(struct drm_device *drm) +{ + struct drm_connector *connector; + struct drm_mode_config *conf = &drm->mode_config; + struct drm_connector_list_iter conn_iter; + + mutex_lock(&drm->mode_config.mutex); + +#define ROCKCHIP_PROP_ATTACH(prop, v) \ + drm_object_attach_property(&connector->base, prop, v) + + drm_connector_list_iter_begin(drm, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + ROCKCHIP_PROP_ATTACH(conf->tv_brightness_property, 100); + ROCKCHIP_PROP_ATTACH(conf->tv_contrast_property, 100); + ROCKCHIP_PROP_ATTACH(conf->tv_saturation_property, 100); + ROCKCHIP_PROP_ATTACH(conf->tv_hue_property, 100); + } + drm_connector_list_iter_end(&conn_iter); +#undef ROCKCHIP_PROP_ATTACH + + mutex_unlock(&drm->mode_config.mutex); +} + +static void rockchip_drm_set_property_default(struct drm_device *drm) +{ + struct drm_connector *connector; + struct drm_mode_config *conf = &drm->mode_config; + struct drm_atomic_state *state; + int ret; + struct drm_connector_list_iter conn_iter; + + drm_modeset_lock_all(drm); + + state = drm_atomic_helper_duplicate_state(drm, conf->acquire_ctx); + if (!state) { + DRM_ERROR("failed to alloc atomic state\n"); + goto err_unlock; + } + state->acquire_ctx = conf->acquire_ctx; + +#define CONNECTOR_SET_PROP(prop, val) \ + do { \ + ret = drm_atomic_set_property(state, &connector->base, \ + prop, \ + val); \ + if (ret) \ + DRM_ERROR("Connector[%d]: Failed to initial %s\n", \ + connector->base.id, #prop); \ + } while (0) + + drm_connector_list_iter_begin(drm, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + struct drm_connector_state *connector_state; + + connector_state = drm_atomic_get_connector_state(state, + connector); + if (IS_ERR(connector_state)) + DRM_ERROR("Connector[%d]: Failed to get state\n", + connector->base.id); + + CONNECTOR_SET_PROP(conf->tv_brightness_property, 50); + CONNECTOR_SET_PROP(conf->tv_contrast_property, 50); + CONNECTOR_SET_PROP(conf->tv_saturation_property, 50); + CONNECTOR_SET_PROP(conf->tv_hue_property, 50); + } + drm_connector_list_iter_end(&conn_iter); +#undef CONNECTOR_SET_PROP + + ret = drm_atomic_commit(state); + WARN_ON(ret == -EDEADLK); + if (ret) + DRM_ERROR("Failed to update properties\n"); + +err_unlock: + drm_modeset_unlock_all(drm); +} + static int rockchip_drm_bind(struct device *dev) { struct drm_device *drm_dev; @@ -935,17 +1074,19 @@ static int rockchip_drm_bind(struct device *dev) drm_mode_config_init(drm_dev); rockchip_drm_mode_config_init(drm_dev); - + rockchip_drm_create_properties(drm_dev); /* Try to bind all sub drivers. */ ret = component_bind_all(dev, drm_dev); if (ret) goto err_mode_config_cleanup; + rockchip_attach_connector_property(drm_dev); ret = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc); if (ret) goto err_unbind_all; drm_mode_config_reset(drm_dev); + rockchip_drm_set_property_default(drm_dev); /* * enable drm irq mode. diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index a20835d60662..d4e3071dbf3d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -119,6 +119,12 @@ struct rockchip_logo { */ struct rockchip_drm_private { struct rockchip_logo *logo; + struct drm_property *logo_ymirror_prop; + struct drm_property *eotf_prop; + struct drm_property *color_space_prop; + struct drm_property *global_alpha_prop; + struct drm_property *blend_mode_prop; + struct drm_property *alpha_scale_prop; struct drm_fb_helper *fbdev_helper; struct drm_gem_object *fbdev_bo; struct drm_atomic_state *state; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h index 86a401d0a545..f3c24edaffed 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h @@ -23,7 +23,6 @@ rockchip_drm_framebuffer_init(struct drm_device *dev, void rockchip_drm_framebuffer_fini(struct drm_framebuffer *fb); void rockchip_drm_mode_config_init(struct drm_device *dev); - struct drm_framebuffer * rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **obj, struct rockchip_logo *logo, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index e797be12d2b0..cff370afdd43 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1678,6 +1678,7 @@ static int vop_atomic_plane_set_property(struct drm_plane *plane, struct drm_property *property, uint64_t val) { + struct rockchip_drm_private *private = plane->dev->dev_private; struct vop_win *win = to_vop_win(plane); struct vop_plane_state *plane_state = &win->state; @@ -1685,8 +1686,35 @@ static int vop_atomic_plane_set_property(struct drm_plane *plane, plane_state->zpos = val; return 0; } + if (property == private->logo_ymirror_prop) { + WARN_ON(!rockchip_fb_is_logo(state->fb)); + plane_state->logo_ymirror = val; + return 0; + } + + if (property == private->eotf_prop) { + plane_state->eotf = val; + return 0; + } + + if (property == private->color_space_prop) { + plane_state->color_space = val; + return 0; + } + + if (property == private->global_alpha_prop) { + plane_state->global_alpha = val; + return 0; + } + + if (property == private->blend_mode_prop) { + plane_state->blend_mode = val; + return 0; + } + + DRM_ERROR("failed to set vop plane property id:%d, name:%s\n", + property->base.id, property->name); - DRM_ERROR("failed to set vop plane property\n"); return -EINVAL; } @@ -1697,13 +1725,41 @@ static int vop_atomic_plane_get_property(struct drm_plane *plane, { struct vop_win *win = to_vop_win(plane); struct vop_plane_state *plane_state = &win->state; + struct rockchip_drm_private *private = plane->dev->dev_private; if (property == win->vop->plane_zpos_prop) { *val = plane_state->zpos; return 0; } - DRM_ERROR("failed to get vop plane property\n"); + if (property == private->logo_ymirror_prop) { + *val = plane_state->logo_ymirror; + return 0; + } + + if (property == private->eotf_prop) { + *val = plane_state->eotf; + return 0; + } + + if (property == private->color_space_prop) { + *val = plane_state->color_space; + return 0; + } + + if (property == private->global_alpha_prop) { + *val = plane_state->global_alpha; + return 0; + } + + if (property == private->blend_mode_prop) { + *val = plane_state->blend_mode; + return 0; + } + + DRM_ERROR("failed to get vop plane property id:%d, name:%s\n", + property->base.id, property->name); + return -EINVAL; } @@ -2785,11 +2841,87 @@ vop_crtc_verify_crc_source(struct drm_crtc *crtc, const char *source_name, } #endif +static int vop_crtc_atomic_get_property(struct drm_crtc *crtc, + const struct drm_crtc_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct drm_device *drm_dev = crtc->dev; + struct rockchip_drm_private *private = drm_dev->dev_private; + struct drm_mode_config *mode_config = &drm_dev->mode_config; + struct rockchip_crtc_state *s = to_rockchip_crtc_state(state); + struct vop *vop = to_vop(crtc); + + if (property == mode_config->tv_left_margin_property) { + *val = s->left_margin; + return 0; + } + + if (property == mode_config->tv_right_margin_property) { + *val = s->right_margin; + return 0; + } + + if (property == mode_config->tv_top_margin_property) { + *val = s->top_margin; + return 0; + } + + if (property == mode_config->tv_bottom_margin_property) { + *val = s->bottom_margin; + return 0; + } + + if (property == private->alpha_scale_prop) { + *val = (vop->data->feature & VOP_FEATURE_ALPHA_SCALE) ? 1 : 0; + return 0; + } + + DRM_ERROR("failed to get vop crtc property\n"); + return -EINVAL; +} + +static int vop_crtc_atomic_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct drm_property *property, + uint64_t val) +{ + struct drm_device *drm_dev = crtc->dev; + struct drm_mode_config *mode_config = &drm_dev->mode_config; + struct rockchip_crtc_state *s = to_rockchip_crtc_state(state); + //struct vop *vop = to_vop(crtc); + + if (property == mode_config->tv_left_margin_property) { + s->left_margin = val; + return 0; + } + + if (property == mode_config->tv_right_margin_property) { + s->right_margin = val; + return 0; + } + + if (property == mode_config->tv_top_margin_property) { + s->top_margin = val; + return 0; + } + + if (property == mode_config->tv_bottom_margin_property) { + s->bottom_margin = val; + return 0; + } + + DRM_ERROR("failed to set vop crtc property\n"); + return -EINVAL; +} + static const struct drm_crtc_funcs vop_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, .destroy = vop_crtc_destroy, .reset = vop_crtc_reset, + .atomic_get_property = vop_crtc_atomic_get_property, + .atomic_set_property = vop_crtc_atomic_set_property, .atomic_duplicate_state = vop_crtc_duplicate_state, .atomic_destroy_state = vop_crtc_destroy_state, .enable_vblank = vop_crtc_enable_vblank, @@ -2933,7 +3065,9 @@ static void vop_plane_add_properties(struct vop *vop, static int vop_plane_init(struct vop *vop, struct vop_win *win, unsigned long possible_crtcs) { + struct rockchip_drm_private *private = vop->drm_dev->dev_private; struct drm_plane *share = NULL; + uint64_t feature = 0; int ret; if (win->parent) @@ -2950,16 +3084,44 @@ static int vop_plane_init(struct vop *vop, struct vop_win *win, drm_object_attach_property(&win->base.base, vop->plane_zpos_prop, win->win_id); + if (VOP_WIN_SUPPORT(vop, win, ymirror)) + drm_object_attach_property(&win->base.base, private->logo_ymirror_prop, 0); + if (win->phy->scl) + feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_SCALE); + if (VOP_WIN_SUPPORT(vop, win, src_alpha_ctl) || + VOP_WIN_SUPPORT(vop, win, alpha_en)) + feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_ALPHA); + if (win->feature & WIN_FEATURE_HDR2SDR) + feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_HDR2SDR); + if (win->feature & WIN_FEATURE_SDR2HDR) + feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_SDR2HDR); + if (win->feature & WIN_FEATURE_AFBDC) + feature |= BIT(ROCKCHIP_DRM_PLANE_FEATURE_AFBDC); + + drm_object_attach_property(&win->base.base, vop->plane_feature_prop, + feature); + drm_object_attach_property(&win->base.base, private->eotf_prop, 0); + drm_object_attach_property(&win->base.base, + private->color_space_prop, 0); + if (VOP_WIN_SUPPORT(vop, win, global_alpha_val)) + drm_object_attach_property(&win->base.base, + private->global_alpha_prop, 0xff); + drm_object_attach_property(&win->base.base, + private->blend_mode_prop, 0); + return 0; } static int vop_create_crtc(struct vop *vop) { struct device *dev = vop->dev; + const struct vop_data *vop_data = vop->data; struct drm_device *drm_dev = vop->drm_dev; + struct rockchip_drm_private *private = drm_dev->dev_private; struct drm_plane *primary = NULL, *cursor = NULL, *plane, *tmp; struct drm_crtc *crtc = &vop->crtc; struct device_node *port; + uint64_t feature = 0; int ret = 0; int i; @@ -3027,6 +3189,20 @@ static int vop_create_crtc(struct vop *vop) init_completion(&vop->line_flag_completion); crtc->port = port; +#define VOP_ATTACH_MODE_CONFIG_PROP(prop, v) \ + drm_object_attach_property(&crtc->base, drm_dev->mode_config.prop, v) + + VOP_ATTACH_MODE_CONFIG_PROP(tv_left_margin_property, 100); + VOP_ATTACH_MODE_CONFIG_PROP(tv_right_margin_property, 100); + VOP_ATTACH_MODE_CONFIG_PROP(tv_top_margin_property, 100); + VOP_ATTACH_MODE_CONFIG_PROP(tv_bottom_margin_property, 100); + +#undef VOP_ATTACH_MODE_CONFIG_PROP + drm_object_attach_property(&crtc->base, private->alpha_scale_prop, 0); + if (vop_data->feature & VOP_FEATURE_AFBDC) + feature |= BIT(ROCKCHIP_DRM_CRTC_FEATURE_AFBDC); + drm_object_attach_property(&crtc->base, vop->feature_prop, + feature); return 0; err_cleanup_crtc: @@ -3075,6 +3251,16 @@ static int vop_win_init(struct vop *vop) unsigned int i, j; unsigned int num_wins = 0; struct drm_property *prop; + static const struct drm_prop_enum_list props[] = { + { ROCKCHIP_DRM_PLANE_FEATURE_SCALE, "scale" }, + { ROCKCHIP_DRM_PLANE_FEATURE_ALPHA, "alpha" }, + { ROCKCHIP_DRM_PLANE_FEATURE_HDR2SDR, "hdr2sdr" }, + { ROCKCHIP_DRM_PLANE_FEATURE_SDR2HDR, "sdr2hdr" }, + { ROCKCHIP_DRM_PLANE_FEATURE_AFBDC, "afbdc" }, + }; + static const struct drm_prop_enum_list crtc_props[] = { + { ROCKCHIP_DRM_CRTC_FEATURE_AFBDC, "afbdc" }, + }; for (i = 0; i < vop_data->win_size; i++) { struct vop_win *vop_win = &vop->win[num_wins]; @@ -3122,6 +3308,28 @@ static int vop_win_init(struct vop *vop) } vop->plane_zpos_prop = prop; + vop->plane_feature_prop = drm_property_create_bitmask(vop->drm_dev, + DRM_MODE_PROP_IMMUTABLE, "FEATURE", + props, ARRAY_SIZE(props), + BIT(ROCKCHIP_DRM_PLANE_FEATURE_SCALE) | + BIT(ROCKCHIP_DRM_PLANE_FEATURE_ALPHA) | + BIT(ROCKCHIP_DRM_PLANE_FEATURE_HDR2SDR) | + BIT(ROCKCHIP_DRM_PLANE_FEATURE_SDR2HDR) | + BIT(ROCKCHIP_DRM_PLANE_FEATURE_AFBDC)); + if (!vop->plane_feature_prop) { + DRM_ERROR("failed to create feature property\n"); + return -EINVAL; + } + + vop->feature_prop = drm_property_create_bitmask(vop->drm_dev, + DRM_MODE_PROP_IMMUTABLE, "FEATURE", + crtc_props, ARRAY_SIZE(crtc_props), + BIT(ROCKCHIP_DRM_CRTC_FEATURE_AFBDC)); + if (!vop->feature_prop) { + DRM_ERROR("failed to create vop feature property\n"); + return -EINVAL; + } + return 0; } diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 1e713154f00e..042ec8f12a30 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -913,4 +913,9 @@ drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state) state->connectors_changed; } +int drm_atomic_set_property(struct drm_atomic_state *state, + struct drm_mode_object *obj, + struct drm_property *prop, + uint64_t prop_value); + #endif /* DRM_ATOMIC_H_ */