@@ -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.
@@ -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);
@@ -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++;
}
@@ -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,
From: Rob Clark <rob@ti.com> 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(-)