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 | 70 +++++++++++++++++++++++++++++++------ drivers/gpu/drm/drm_crtc_helper.c | 51 ++++++++++++++------------- drivers/gpu/drm/drm_fb_helper.c | 11 +++--- include/drm/drm_crtc.h | 44 +++++++++++++++++------ 4 files changed, 125 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 8be57e4..0ddd43e 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -397,7 +397,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_crtc_id, 0); } @@ -447,7 +447,7 @@ 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); @@ -496,6 +496,54 @@ 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; + + 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); + +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) { + state->fb = U642VOID(value); + } 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 @@ -1593,11 +1641,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; @@ -2042,12 +2090,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); @@ -2077,7 +2125,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 || @@ -2087,7 +2135,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; } @@ -3773,7 +3821,7 @@ int drm_mode_page_flip_ioctl(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. 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 f546d1e..d70b787 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; @@ -1361,9 +1362,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/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index a0bec04..9417aaa 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -352,18 +352,41 @@ 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 + */ +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 nuclear-pageflip + */ + struct drm_framebuffer *fb; + bool invert_dimensions; + int x, y; +}; + +/** * 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 @@ -382,8 +405,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; @@ -395,9 +417,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 */ @@ -858,6 +877,11 @@ 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 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