Merge tag 'drm-misc-fixes-2016-10-27' of git://anongit.freedesktop.org/git/drm-misc into drm-fixes
Set of drm core fixes. Hopefully fixes a bug in MST unplugs in fbdev. * tag 'drm-misc-fixes-2016-10-27' of git://anongit.freedesktop.org/git/drm-misc: drm/dp/mst: Check peer device type before attempting EDID read drm/dp/mst: Clear port->pdt when tearing down the i2c adapter drm/fb-helper: Keep references for the current set of used connectors drm: Don't force all planes to be added to the state due to zpos drm/fb-helper: Fix connector ref leak on error drm/fb-helper: Don't call dirty callback for untouched clips drm: Release reference from blob lookup after replacing property
This commit is contained in:
Коммит
aa72c26c2b
|
@ -420,18 +420,21 @@ drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc,
|
|||
ssize_t expected_size,
|
||||
bool *replaced)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_property_blob *new_blob = NULL;
|
||||
|
||||
if (blob_id != 0) {
|
||||
new_blob = drm_property_lookup_blob(dev, blob_id);
|
||||
new_blob = drm_property_lookup_blob(crtc->dev, blob_id);
|
||||
if (new_blob == NULL)
|
||||
return -EINVAL;
|
||||
if (expected_size > 0 && expected_size != new_blob->length)
|
||||
|
||||
if (expected_size > 0 && expected_size != new_blob->length) {
|
||||
drm_property_unreference_blob(new_blob);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
drm_atomic_replace_property_blob(blob, new_blob, replaced);
|
||||
drm_property_unreference_blob(new_blob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -594,10 +594,6 @@ drm_atomic_helper_check_planes(struct drm_device *dev,
|
|||
struct drm_plane_state *plane_state;
|
||||
int i, ret = 0;
|
||||
|
||||
ret = drm_atomic_normalize_zpos(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for_each_plane_in_state(state, plane, plane_state, i) {
|
||||
const struct drm_plane_helper_funcs *funcs;
|
||||
|
||||
|
|
|
@ -914,6 +914,7 @@ static void drm_dp_destroy_port(struct kref *kref)
|
|||
/* no need to clean up vcpi
|
||||
* as if we have no connector we never setup a vcpi */
|
||||
drm_dp_port_teardown_pdt(port, port->pdt);
|
||||
port->pdt = DP_PEER_DEVICE_NONE;
|
||||
}
|
||||
kfree(port);
|
||||
}
|
||||
|
@ -1159,7 +1160,9 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
|
|||
drm_dp_put_port(port);
|
||||
goto out;
|
||||
}
|
||||
if (port->port_num >= DP_MST_LOGICAL_PORT_0) {
|
||||
if ((port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV ||
|
||||
port->pdt == DP_PEER_DEVICE_SST_SINK) &&
|
||||
port->port_num >= DP_MST_LOGICAL_PORT_0) {
|
||||
port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
|
||||
drm_mode_connector_set_tile_property(port->connector);
|
||||
}
|
||||
|
@ -2919,6 +2922,7 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
|
|||
mgr->cbs->destroy_connector(mgr, port->connector);
|
||||
|
||||
drm_dp_port_teardown_pdt(port, port->pdt);
|
||||
port->pdt = DP_PEER_DEVICE_NONE;
|
||||
|
||||
if (!port->input && port->vcpi.vcpi > 0) {
|
||||
drm_dp_mst_reset_vcpi_slots(mgr, port);
|
||||
|
|
|
@ -131,7 +131,12 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
|
|||
return 0;
|
||||
fail:
|
||||
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
kfree(fb_helper->connector_info[i]);
|
||||
struct drm_fb_helper_connector *fb_helper_connector =
|
||||
fb_helper->connector_info[i];
|
||||
|
||||
drm_connector_unreference(fb_helper_connector->connector);
|
||||
|
||||
kfree(fb_helper_connector);
|
||||
fb_helper->connector_info[i] = NULL;
|
||||
}
|
||||
fb_helper->connector_count = 0;
|
||||
|
@ -603,6 +608,24 @@ int drm_fb_helper_blank(int blank, struct fb_info *info)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_fb_helper_blank);
|
||||
|
||||
static void drm_fb_helper_modeset_release(struct drm_fb_helper *helper,
|
||||
struct drm_mode_set *modeset)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < modeset->num_connectors; i++) {
|
||||
drm_connector_unreference(modeset->connectors[i]);
|
||||
modeset->connectors[i] = NULL;
|
||||
}
|
||||
modeset->num_connectors = 0;
|
||||
|
||||
drm_mode_destroy(helper->dev, modeset->mode);
|
||||
modeset->mode = NULL;
|
||||
|
||||
/* FIXME should hold a ref? */
|
||||
modeset->fb = NULL;
|
||||
}
|
||||
|
||||
static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
|
||||
{
|
||||
int i;
|
||||
|
@ -612,10 +635,12 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
|
|||
kfree(helper->connector_info[i]);
|
||||
}
|
||||
kfree(helper->connector_info);
|
||||
|
||||
for (i = 0; i < helper->crtc_count; i++) {
|
||||
kfree(helper->crtc_info[i].mode_set.connectors);
|
||||
if (helper->crtc_info[i].mode_set.mode)
|
||||
drm_mode_destroy(helper->dev, helper->crtc_info[i].mode_set.mode);
|
||||
struct drm_mode_set *modeset = &helper->crtc_info[i].mode_set;
|
||||
|
||||
drm_fb_helper_modeset_release(helper, modeset);
|
||||
kfree(modeset->connectors);
|
||||
}
|
||||
kfree(helper->crtc_info);
|
||||
}
|
||||
|
@ -644,7 +669,9 @@ static void drm_fb_helper_dirty_work(struct work_struct *work)
|
|||
clip->x2 = clip->y2 = 0;
|
||||
spin_unlock_irqrestore(&helper->dirty_lock, flags);
|
||||
|
||||
helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
|
||||
/* call dirty callback only when it has been really touched */
|
||||
if (clip_copy.x1 < clip_copy.x2 && clip_copy.y1 < clip_copy.y2)
|
||||
helper->fb->funcs->dirty(helper->fb, NULL, 0, 0, &clip_copy, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2088,7 +2115,6 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
|||
struct drm_fb_helper_crtc **crtcs;
|
||||
struct drm_display_mode **modes;
|
||||
struct drm_fb_offset *offsets;
|
||||
struct drm_mode_set *modeset;
|
||||
bool *enabled;
|
||||
int width, height;
|
||||
int i;
|
||||
|
@ -2136,45 +2162,35 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
|
|||
|
||||
/* need to set the modesets up here for use later */
|
||||
/* fill out the connector<->crtc mappings into the modesets */
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
modeset = &fb_helper->crtc_info[i].mode_set;
|
||||
modeset->num_connectors = 0;
|
||||
modeset->fb = NULL;
|
||||
}
|
||||
for (i = 0; i < fb_helper->crtc_count; i++)
|
||||
drm_fb_helper_modeset_release(fb_helper,
|
||||
&fb_helper->crtc_info[i].mode_set);
|
||||
|
||||
for (i = 0; i < fb_helper->connector_count; i++) {
|
||||
struct drm_display_mode *mode = modes[i];
|
||||
struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
|
||||
struct drm_fb_offset *offset = &offsets[i];
|
||||
modeset = &fb_crtc->mode_set;
|
||||
struct drm_mode_set *modeset = &fb_crtc->mode_set;
|
||||
|
||||
if (mode && fb_crtc) {
|
||||
struct drm_connector *connector =
|
||||
fb_helper->connector_info[i]->connector;
|
||||
|
||||
DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
|
||||
mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y);
|
||||
|
||||
fb_crtc->desired_mode = mode;
|
||||
fb_crtc->x = offset->x;
|
||||
fb_crtc->y = offset->y;
|
||||
if (modeset->mode)
|
||||
drm_mode_destroy(dev, modeset->mode);
|
||||
modeset->mode = drm_mode_duplicate(dev,
|
||||
fb_crtc->desired_mode);
|
||||
modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
|
||||
drm_connector_reference(connector);
|
||||
modeset->connectors[modeset->num_connectors++] = connector;
|
||||
modeset->fb = fb_helper->fb;
|
||||
modeset->x = offset->x;
|
||||
modeset->y = offset->y;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear out any old modes if there are no more connected outputs. */
|
||||
for (i = 0; i < fb_helper->crtc_count; i++) {
|
||||
modeset = &fb_helper->crtc_info[i].mode_set;
|
||||
if (modeset->num_connectors == 0) {
|
||||
BUG_ON(modeset->fb);
|
||||
if (modeset->mode)
|
||||
drm_mode_destroy(dev, modeset->mode);
|
||||
modeset->mode = NULL;
|
||||
}
|
||||
}
|
||||
out:
|
||||
kfree(crtcs);
|
||||
kfree(modes);
|
||||
|
|
|
@ -262,6 +262,26 @@ int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int exynos_atomic_check(struct drm_device *dev,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = drm_atomic_helper_check_modeset(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_normalize_zpos(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_helper_check_planes(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
|
||||
{
|
||||
struct drm_exynos_file_private *file_priv;
|
||||
|
|
|
@ -301,6 +301,7 @@ static inline int exynos_dpi_bind(struct drm_device *dev,
|
|||
|
||||
int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state,
|
||||
bool nonblock);
|
||||
int exynos_atomic_check(struct drm_device *dev, struct drm_atomic_state *state);
|
||||
|
||||
|
||||
extern struct platform_driver fimd_driver;
|
||||
|
|
|
@ -190,7 +190,7 @@ dma_addr_t exynos_drm_fb_dma_addr(struct drm_framebuffer *fb, int index)
|
|||
static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
|
||||
.fb_create = exynos_user_fb_create,
|
||||
.output_poll_changed = exynos_drm_output_poll_changed,
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_check = exynos_atomic_check,
|
||||
.atomic_commit = exynos_atomic_commit,
|
||||
};
|
||||
|
||||
|
|
|
@ -231,8 +231,16 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
|||
struct rcar_du_device *rcdu = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
ret = drm_atomic_helper_check(dev, state);
|
||||
if (ret < 0)
|
||||
ret = drm_atomic_helper_check_modeset(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_normalize_zpos(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_helper_check_planes(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE))
|
||||
|
|
|
@ -195,6 +195,26 @@ static void sti_atomic_work(struct work_struct *work)
|
|||
sti_atomic_complete(private, private->commit.state);
|
||||
}
|
||||
|
||||
static int sti_atomic_check(struct drm_device *dev,
|
||||
struct drm_atomic_state *state)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = drm_atomic_helper_check_modeset(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_normalize_zpos(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = drm_atomic_helper_check_planes(dev, state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sti_atomic_commit(struct drm_device *drm,
|
||||
struct drm_atomic_state *state, bool nonblock)
|
||||
{
|
||||
|
@ -248,7 +268,7 @@ static void sti_output_poll_changed(struct drm_device *ddev)
|
|||
static const struct drm_mode_config_funcs sti_mode_config_funcs = {
|
||||
.fb_create = drm_fb_cma_create,
|
||||
.output_poll_changed = sti_output_poll_changed,
|
||||
.atomic_check = drm_atomic_helper_check,
|
||||
.atomic_check = sti_atomic_check,
|
||||
.atomic_commit = sti_atomic_commit,
|
||||
};
|
||||
|
||||
|
|
|
@ -47,8 +47,14 @@ struct drm_crtc;
|
|||
* @src_h: height of visible portion of plane (in 16.16)
|
||||
* @rotation: rotation of the plane
|
||||
* @zpos: priority of the given plane on crtc (optional)
|
||||
* Note that multiple active planes on the same crtc can have an identical
|
||||
* zpos value. The rule to solving the conflict is to compare the plane
|
||||
* object IDs; the plane with a higher ID must be stacked on top of a
|
||||
* plane with a lower ID.
|
||||
* @normalized_zpos: normalized value of zpos: unique, range from 0 to N-1
|
||||
* where N is the number of active planes for given crtc
|
||||
* where N is the number of active planes for given crtc. Note that
|
||||
* the driver must call drm_atomic_normalize_zpos() to update this before
|
||||
* it can be trusted.
|
||||
* @src: clipped source coordinates of the plane (in 16.16)
|
||||
* @dst: clipped destination coordinates of the plane
|
||||
* @visible: visibility of the plane
|
||||
|
|
Загрузка…
Ссылка в новой задаче