From: Rob Clark <rob@xxxxxx> Start breaking out the mutable state of the CRTC into it's own structure. Plus add _check_state() and _set_property() helpers. This only moves the state that is related to scanout fb, which is needed for nuclear-pageflip. The rest of the mutable state should be moved from drm_crtc to drm_crtc_state as part of the atomic-modeset implementation. --- drivers/gpu/drm/drm_crtc.c | 112 ++++++++++++++++++++++++++++------- drivers/gpu/drm/drm_crtc_helper.c | 51 ++++++++-------- drivers/gpu/drm/drm_fb_helper.c | 11 ++-- drivers/staging/omapdrm/omap_crtc.c | 16 ++--- drivers/staging/omapdrm/omap_fb.c | 10 ++-- include/drm/drm_crtc.h | 49 +++++++++++---- 6 files changed, 173 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index bcdd6be..7337fd8 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -397,7 +397,7 @@ static void drm_framebuffer_remove_legacy(struct drm_framebuffer *fb) /* remove from any CRTC */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->fb == fb) { + if (crtc->state->fb == fb) { /* should turn off the crtc */ memset(&set, 0, sizeof(struct drm_mode_set)); set.crtc = crtc; @@ -456,7 +456,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) /* remove from any CRTC */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->fb == fb) { + if (crtc->state->fb == fb) { /* should turn off the crtc */ drm_mode_crtc_set_obj_prop(crtc, state, config->prop_fb_id, 0); } @@ -506,16 +506,25 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, crtc->dev = dev; crtc->funcs = funcs; - crtc->invert_dimensions = false; + crtc->state->invert_dimensions = false; mutex_lock(&dev->mode_config.mutex); + if (!dev_supports_atomic(dev)) { + crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); + if (!crtc->state) { + DRM_DEBUG_KMS("out of memory when allocating state\n"); + ret = -ENOMEM; + goto out; + } + } + ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC); if (ret) goto out; crtc->base.properties = &crtc->properties; - crtc->base.propvals = &crtc->propvals; + crtc->base.propvals = &crtc->state->propvals; list_add_tail(&crtc->head, &dev->mode_config.crtc_list); dev->mode_config.num_crtc++; @@ -559,6 +568,67 @@ void drm_crtc_cleanup(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_crtc_cleanup); +int drm_crtc_check_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct drm_framebuffer *fb = state->fb; + int hdisplay, vdisplay; + + /* disabling the crtc is allowed: */ + if (!fb) + return 0; + + hdisplay = crtc->mode.hdisplay; + vdisplay = crtc->mode.vdisplay; + + if (state->invert_dimensions) + swap(hdisplay, vdisplay); + + if (hdisplay > fb->width || + vdisplay > fb->height || + state->x > fb->width - hdisplay || + state->y > fb->height - vdisplay) { + DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", + fb->width, fb->height, hdisplay, vdisplay, + state->x, state->y, + state->invert_dimensions ? " (inverted)" : ""); + return -ENOSPC; + } + + return 0; +} +EXPORT_SYMBOL(drm_crtc_check_state); + +void drm_crtc_commit_state(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + crtc->state = state; + crtc->base.propvals = &state->propvals; +} +EXPORT_SYMBOL(drm_crtc_commit_state); + +int drm_crtc_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct drm_property *property, uint64_t value) +{ + struct drm_device *dev = crtc->dev; + struct drm_mode_config *config = &dev->mode_config; + + if (property == config->prop_fb_id) { + struct drm_mode_object *obj = drm_property_get_obj(property, value); + state->fb = obj ? obj_to_fb(obj) : NULL; + } else if (property == config->prop_crtc_x) { + state->x = *(int *)&value; + } else if (property == config->prop_crtc_y) { + state->y = *(int32_t *)&value; + } else { + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(drm_crtc_set_property); + /** * drm_mode_probed_add - add a mode to a connector's probed mode list * @connector: connector the new mode @@ -1689,11 +1759,11 @@ int drm_mode_getcrtc(struct drm_device *dev, } crtc = obj_to_crtc(obj); - crtc_resp->x = crtc->x; - crtc_resp->y = crtc->y; + crtc_resp->x = crtc->state->x; + crtc_resp->y = crtc->state->y; crtc_resp->gamma_size = crtc->gamma_size; - if (crtc->fb) - crtc_resp->fb_id = crtc->fb->base.id; + if (crtc->state->fb) + crtc_resp->fb_id = crtc->state->fb->base.id; else crtc_resp->fb_id = 0; @@ -2283,12 +2353,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ if (crtc_req->fb_id == -1) { - if (!crtc->fb) { + if (!crtc->state->fb) { DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); ret = -EINVAL; goto out; } - fb = crtc->fb; + fb = crtc->state->fb; } else { obj = drm_mode_object_find(dev, crtc_req->fb_id, DRM_MODE_OBJECT_FB); @@ -2318,7 +2388,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, hdisplay = mode->hdisplay; vdisplay = mode->vdisplay; - if (crtc->invert_dimensions) + if (crtc->state->invert_dimensions) swap(hdisplay, vdisplay); if (hdisplay > fb->width || @@ -2328,7 +2398,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", fb->width, fb->height, hdisplay, vdisplay, crtc_req->x, crtc_req->y, - crtc->invert_dimensions ? " (inverted)" : ""); + crtc->state->invert_dimensions ? " (inverted)" : ""); ret = -ENOSPC; goto out; } @@ -3639,9 +3709,6 @@ int drm_mode_crtc_set_obj_prop(struct drm_crtc *crtc, if (crtc->funcs->set_property) ret = crtc->funcs->set_property(crtc, state, property, value); - if (!ret) - drm_object_property_set_value(&crtc->base, &crtc->propvals, - property, value); return ret; } @@ -4028,7 +4095,7 @@ static int drm_mode_page_flip_ioctl_legacy(struct drm_device *dev, goto out; crtc = obj_to_crtc(obj); - if (crtc->fb == NULL) { + if (crtc->state->fb == NULL) { /* The framebuffer is currently unbound, presumably * due to a hotplug event, that userspace has not * yet discovered. @@ -4048,16 +4115,17 @@ static int drm_mode_page_flip_ioctl_legacy(struct drm_device *dev, hdisplay = crtc->mode.hdisplay; vdisplay = crtc->mode.vdisplay; - if (crtc->invert_dimensions) + if (crtc->state->invert_dimensions) swap(hdisplay, vdisplay); if (hdisplay > fb->width || vdisplay > fb->height || - crtc->x > fb->width - hdisplay || - crtc->y > fb->height - vdisplay) { + crtc->state->x > fb->width - hdisplay || + crtc->state->y > fb->height - vdisplay) { DRM_DEBUG_KMS("Invalid fb size %ux%u for CRTC viewport %ux%u+%d+%d%s.\n", - fb->width, fb->height, hdisplay, vdisplay, crtc->x, crtc->y, - crtc->invert_dimensions ? " (inverted)" : ""); + fb->width, fb->height, hdisplay, vdisplay, + crtc->state->x, crtc->state->y, + crtc->state->invert_dimensions ? " (inverted)" : ""); ret = -ENOSPC; goto out; } @@ -4114,7 +4182,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, goto out_unlock; } - if (crtc->fb == NULL) { + if (crtc->state->fb == NULL) { /* The framebuffer is currently unbound, presumably * due to a hotplug event, that userspace has not * yet discovered. diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 3252e70..65ed229 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -266,7 +266,7 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) (*crtc_funcs->disable)(crtc); else (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF); - crtc->fb = NULL; + crtc->state->fb = NULL; } } } @@ -363,15 +363,15 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, saved_hwmode = crtc->hwmode; saved_mode = crtc->mode; - saved_x = crtc->x; - saved_y = crtc->y; + saved_x = crtc->state->x; + saved_y = crtc->state->y; /* Update crtc values up front so the driver can rely on them for mode * setting. */ crtc->mode = *mode; - crtc->x = x; - crtc->y = y; + crtc->state->x = x; + crtc->state->y = y; /* Pass our mode to the connectors and the CRTC to give them a chance to * adjust it according to limitations or connector properties, and also @@ -456,8 +456,8 @@ done: if (!ret) { crtc->hwmode = saved_hwmode; crtc->mode = saved_mode; - crtc->x = saved_x; - crtc->y = saved_y; + crtc->state->x = saved_x; + crtc->state->y = saved_y; } return ret; @@ -591,29 +591,29 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) save_set.crtc = set->crtc; save_set.mode = &set->crtc->mode; - save_set.x = set->crtc->x; - save_set.y = set->crtc->y; - save_set.fb = set->crtc->fb; + save_set.x = set->crtc->state->x; + save_set.y = set->crtc->state->y; + save_set.fb = set->crtc->state->fb; /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ - if (set->crtc->fb != set->fb) { + if (set->crtc->state->fb != set->fb) { /* If we have no fb then treat it as a full mode set */ - if (set->crtc->fb == NULL) { + if (set->crtc->state->fb == NULL) { DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); mode_changed = true; } else if (set->fb == NULL) { mode_changed = true; - } else if (set->fb->depth != set->crtc->fb->depth) { + } else if (set->fb->depth != set->crtc->state->fb->depth) { mode_changed = true; } else if (set->fb->bits_per_pixel != - set->crtc->fb->bits_per_pixel) { + set->crtc->state->fb->bits_per_pixel) { mode_changed = true; } else fb_changed = true; } - if (set->x != set->crtc->x || set->y != set->crtc->y) + if (set->x != set->crtc->state->x || set->y != set->crtc->state->y) fb_changed = true; if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { @@ -704,14 +704,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) DRM_DEBUG_KMS("attempting to set mode from" " userspace\n"); drm_mode_debug_printmodeline(set->mode); - old_fb = set->crtc->fb; - set->crtc->fb = set->fb; + old_fb = set->crtc->state->fb; + set->crtc->state->fb = set->fb; if (!drm_crtc_helper_set_mode(set->crtc, set->mode, set->x, set->y, old_fb)) { DRM_ERROR("failed to set mode on [CRTC:%d]\n", set->crtc->base.id); - set->crtc->fb = old_fb; + set->crtc->state->fb = old_fb; ret = -EINVAL; goto fail; } @@ -724,16 +724,16 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) } drm_helper_disable_unused_functions(dev); } else if (fb_changed) { - set->crtc->x = set->x; - set->crtc->y = set->y; + set->crtc->state->x = set->x; + set->crtc->state->y = set->y; - old_fb = set->crtc->fb; - if (set->crtc->fb != set->fb) - set->crtc->fb = set->fb; + old_fb = set->crtc->state->fb; + if (set->crtc->state->fb != set->fb) + set->crtc->state->fb = set->fb; ret = crtc_funcs->mode_set_base(set->crtc, set->x, set->y, old_fb); if (ret != 0) { - set->crtc->fb = old_fb; + set->crtc->state->fb = old_fb; goto fail; } } @@ -888,7 +888,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev) continue; ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); + crtc->state->x, crtc->state->y, + crtc->state->fb); if (ret == false) DRM_ERROR("failed to set mode on crtc %p\n", crtc); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 80bdb59..725ae08 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -185,7 +185,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) list_for_each_entry(c, &dev->mode_config.crtc_list, head) { if (crtc->base.id == c->base.id) - return c->fb; + return c->state->fb; } return NULL; @@ -214,8 +214,9 @@ int drm_fb_helper_debug_leave(struct fb_info *info) } drm_fb_helper_restore_lut_atomic(mode_set->crtc); - funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, - crtc->y, LEAVE_ATOMIC_MODE_SET); + funcs->mode_set_base_atomic(mode_set->crtc, fb, + crtc->state->x, crtc->state->y, + LEAVE_ATOMIC_MODE_SET); } return 0; @@ -1356,9 +1357,9 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) mutex_lock(&dev->mode_config.mutex); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->fb) + if (crtc->state->fb) crtcs_bound++; - if (crtc->fb == fb_helper->fb) + if (crtc->state->fb == fb_helper->fb) bound++; } diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c index 1236d21..b903c63 100644 --- a/drivers/staging/omapdrm/omap_crtc.c +++ b/drivers/staging/omapdrm/omap_crtc.c @@ -206,7 +206,7 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc, } } - return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, + return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->state->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16, @@ -234,7 +234,7 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_plane *plane = omap_crtc->plane; struct drm_display_mode *mode = &crtc->mode; - return omap_plane_mode_set(plane, crtc, crtc->fb, + return omap_plane_mode_set(plane, crtc, crtc->state->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16, @@ -274,14 +274,14 @@ static void page_flip_worker(struct work_struct *work) struct drm_gem_object *bo; mutex_lock(&dev->mode_config.mutex); - omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, + omap_plane_mode_set(omap_crtc->plane, crtc, crtc->state->fb, 0, 0, mode->hdisplay, mode->vdisplay, - crtc->x << 16, crtc->y << 16, + crtc->state->x << 16, crtc->state->y << 16, mode->hdisplay << 16, mode->vdisplay << 16, vblank_cb, crtc); mutex_unlock(&dev->mode_config.mutex); - bo = omap_framebuffer_bo(crtc->fb, 0); + bo = omap_framebuffer_bo(crtc->state->fb, 0); drm_gem_object_unreference_unlocked(bo); } @@ -303,7 +303,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct drm_gem_object *bo; - DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1, + DBG("%d -> %d (event=%p)", crtc->state->fb ? crtc->state->fb->base.id : -1, fb->base.id, event); if (omap_crtc->old_fb) { @@ -312,7 +312,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, } omap_crtc->event = event; - crtc->fb = fb; + crtc->state->fb = fb; /* * Hold a reference temporarily until the crtc is updated @@ -334,7 +334,7 @@ static int omap_crtc_set_property(struct drm_crtc *crtc, void *state, struct omap_drm_private *priv = crtc->dev->dev_private; if (property == priv->rotation_prop) { - crtc->invert_dimensions = + crtc->state->invert_dimensions = !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270))); } diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c index 7fe0345..66c11f9 100644 --- a/drivers/staging/omapdrm/omap_fb.c +++ b/drivers/staging/omapdrm/omap_fb.c @@ -316,7 +316,7 @@ struct drm_connector *omap_framebuffer_get_next_connector( if (connector != from) { struct drm_encoder *encoder = connector->encoder; struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; - if (crtc && crtc->fb == fb) { + if (crtc && crtc->state->fb == fb) { return connector; } } @@ -342,10 +342,10 @@ void omap_framebuffer_flush(struct drm_framebuffer *fb, * could do the coordinate translation.. */ struct drm_crtc *crtc = connector->encoder->crtc; - int cx = max(0, x - crtc->x); - int cy = max(0, y - crtc->y); - int cw = w + (x - crtc->x) - cx; - int ch = h + (y - crtc->y) - cy; + int cx = max(0, x - crtc->state->x); + int cy = max(0, y - crtc->state->y); + int cw = w + (x - crtc->state->x) - cx; + int ch = h + (y - crtc->state->y) - cy; omap_connector_flush(connector, cx, cy, cw, ch); } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index ef558dd..f445135 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -375,18 +375,43 @@ struct drm_crtc_funcs { }; /** + * drm_crtc_state - mutable crtc state + * @fb: the framebuffer that the CRTC is currently bound to + * @invert_dimensions: for purposes of error checking crtc vs fb sizes, + * invert the width/height of the crtc. This is used if the driver + * is performing 90 or 270 degree rotated scanout + * @x: x position on screen + * @y: y position on screen + * @propvals: property values + */ +struct drm_crtc_state { + /* + * NOTE: more should move from 'struct drm_crtc' into here as + * part of the atomic-modeset support: + * + enabled + * + mode + * + hwmode + * + framedur_ns + * + linedur_ns + * + pixeldur_ns + * + * For now, I'm just moving what is needed for atomic-pageflip + */ + struct drm_framebuffer *fb; + bool invert_dimensions; + int x, y; + struct drm_object_property_values propvals; +}; + +/** * drm_crtc - central CRTC control structure * @dev: parent DRM device * @head: list management * @base: base KMS object for ID tracking etc. + * @state: the mutable state * @enabled: is this CRTC enabled? * @mode: current mode timings * @hwmode: mode timings as programmed to hw regs - * @invert_dimensions: for purposes of error checking crtc vs fb sizes, - * invert the width/height of the crtc. This is used if the driver - * is performing 90 or 270 degree rotated scanout - * @x: x position on screen - * @y: y position on screen * @funcs: CRTC control functions * @gamma_size: size of gamma ramp * @gamma_store: gamma ramp values @@ -405,8 +430,7 @@ struct drm_crtc { struct drm_mode_object base; - /* framebuffer the connector is currently bound to */ - struct drm_framebuffer *fb; + struct drm_crtc_state *state; bool enabled; @@ -418,9 +442,6 @@ struct drm_crtc { */ struct drm_display_mode hwmode; - bool invert_dimensions; - - int x, y; const struct drm_crtc_funcs *funcs; /* CRTC gamma size for reporting to userspace */ @@ -434,7 +455,6 @@ struct drm_crtc { void *helper_private; struct drm_object_properties properties; - struct drm_object_property_values propvals; }; @@ -902,6 +922,13 @@ extern int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, const struct drm_crtc_funcs *funcs); extern void drm_crtc_cleanup(struct drm_crtc *crtc); +extern int drm_crtc_check_state(struct drm_crtc *crtc, + struct drm_crtc_state *state); +extern void drm_crtc_commit_state(struct drm_crtc *crtc, + struct drm_crtc_state *state); +extern int drm_crtc_set_property(struct drm_crtc *crtc, + struct drm_crtc_state *state, + struct drm_property *property, uint64_t value); extern int drm_connector_init(struct drm_device *dev, struct drm_connector *connector, -- 1.7.9.5 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel