aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm/omap_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_drv.c')
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c260
1 files changed, 77 insertions, 183 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 3f2554235225..e1f47f0b3ccf 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -34,11 +34,6 @@
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 0
-static int num_crtc = CONFIG_DRM_OMAP_NUM_CRTCS;
-
-MODULE_PARM_DESC(num_crtc, "Number of overlays to use as CRTCs");
-module_param(num_crtc, int, 0600);
-
/*
* mode config funcs
*/
@@ -93,7 +88,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit)
struct drm_atomic_state *old_state = commit->state;
/* Apply the atomic update. */
- dispc_runtime_get();
+ priv->dispc_ops->runtime_get();
drm_atomic_helper_commit_modeset_disables(dev, old_state);
@@ -117,7 +112,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit)
drm_atomic_helper_cleanup_planes(dev, old_state);
- dispc_runtime_put();
+ priv->dispc_ops->runtime_put();
drm_atomic_state_put(old_state);
@@ -224,20 +219,6 @@ static int get_connector_type(struct omap_dss_device *dssdev)
}
}
-static bool channel_used(struct drm_device *dev, enum omap_channel channel)
-{
- struct omap_drm_private *priv = dev->dev_private;
- int i;
-
- for (i = 0; i < priv->num_crtcs; i++) {
- struct drm_crtc *crtc = priv->crtcs[i];
-
- if (omap_crtc_channel(crtc) == channel)
- return true;
- }
-
- return false;
-}
static void omap_disconnect_dssdevs(void)
{
struct omap_dss_device *dssdev = NULL;
@@ -250,7 +231,9 @@ static int omap_connect_dssdevs(void)
{
int r;
struct omap_dss_device *dssdev = NULL;
- bool no_displays = true;
+
+ if (!omapdss_stack_is_ready())
+ return -EPROBE_DEFER;
for_each_dss_dev(dssdev) {
r = dssdev->driver->connect(dssdev);
@@ -260,14 +243,9 @@ static int omap_connect_dssdevs(void)
} else if (r) {
dev_warn(dssdev->dev, "could not connect display: %s\n",
dssdev->name);
- } else {
- no_displays = false;
}
}
- if (no_displays)
- return -EPROBE_DEFER;
-
return 0;
cleanup:
@@ -280,31 +258,6 @@ cleanup:
return r;
}
-static int omap_modeset_create_crtc(struct drm_device *dev, int id,
- enum omap_channel channel,
- u32 possible_crtcs)
-{
- struct omap_drm_private *priv = dev->dev_private;
- struct drm_plane *plane;
- struct drm_crtc *crtc;
-
- plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_PRIMARY,
- possible_crtcs);
- if (IS_ERR(plane))
- return PTR_ERR(plane);
-
- crtc = omap_crtc_init(dev, plane, channel, id);
-
- BUG_ON(priv->num_crtcs >= ARRAY_SIZE(priv->crtcs));
- priv->crtcs[id] = crtc;
- priv->num_crtcs++;
-
- priv->planes[id] = plane;
- priv->num_planes++;
-
- return 0;
-}
-
static int omap_modeset_init_properties(struct drm_device *dev)
{
struct omap_drm_private *priv = dev->dev_private;
@@ -320,12 +273,11 @@ static int omap_modeset_init(struct drm_device *dev)
{
struct omap_drm_private *priv = dev->dev_private;
struct omap_dss_device *dssdev = NULL;
- int num_ovls = dss_feat_get_num_ovls();
- int num_mgrs = dss_feat_get_num_mgrs();
- int num_crtcs;
- int i, id = 0;
+ int num_ovls = priv->dispc_ops->get_num_ovls();
+ int num_mgrs = priv->dispc_ops->get_num_mgrs();
+ int num_crtcs, crtc_idx, plane_idx;
int ret;
- u32 possible_crtcs;
+ u32 plane_crtc_mask;
drm_mode_config_init(dev);
@@ -334,162 +286,97 @@ static int omap_modeset_init(struct drm_device *dev)
return ret;
/*
- * We usually don't want to create a CRTC for each manager, at least
- * not until we have a way to expose private planes to userspace.
- * Otherwise there would not be enough video pipes left for drm planes.
- * We use the num_crtc argument to limit the number of crtcs we create.
+ * This function creates exactly one connector, encoder, crtc,
+ * and primary plane per each connected dss-device. Each
+ * connector->encoder->crtc chain is expected to be separate
+ * and each crtc is connect to a single dss-channel. If the
+ * configuration does not match the expectations or exceeds
+ * the available resources, the configuration is rejected.
*/
- num_crtcs = min3(num_crtc, num_mgrs, num_ovls);
- possible_crtcs = (1 << num_crtcs) - 1;
+ num_crtcs = 0;
+ for_each_dss_dev(dssdev)
+ if (omapdss_device_is_connected(dssdev))
+ num_crtcs++;
+
+ if (num_crtcs > num_mgrs || num_crtcs > num_ovls ||
+ num_crtcs > ARRAY_SIZE(priv->crtcs) ||
+ num_crtcs > ARRAY_SIZE(priv->planes) ||
+ num_crtcs > ARRAY_SIZE(priv->encoders) ||
+ num_crtcs > ARRAY_SIZE(priv->connectors)) {
+ dev_err(dev->dev, "%s(): Too many connected displays\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* All planes can be put to any CRTC */
+ plane_crtc_mask = (1 << num_crtcs) - 1;
dssdev = NULL;
+ crtc_idx = 0;
+ plane_idx = 0;
for_each_dss_dev(dssdev) {
struct drm_connector *connector;
struct drm_encoder *encoder;
- enum omap_channel channel;
- struct omap_dss_device *out;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
if (!omapdss_device_is_connected(dssdev))
continue;
encoder = omap_encoder_init(dev, dssdev);
-
- if (!encoder) {
- dev_err(dev->dev, "could not create encoder: %s\n",
- dssdev->name);
+ if (!encoder)
return -ENOMEM;
- }
connector = omap_connector_init(dev,
get_connector_type(dssdev), dssdev, encoder);
-
- if (!connector) {
- dev_err(dev->dev, "could not create connector: %s\n",
- dssdev->name);
+ if (!connector)
return -ENOMEM;
- }
- BUG_ON(priv->num_encoders >= ARRAY_SIZE(priv->encoders));
- BUG_ON(priv->num_connectors >= ARRAY_SIZE(priv->connectors));
+ plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_PRIMARY,
+ plane_crtc_mask);
+ if (IS_ERR(plane))
+ return PTR_ERR(plane);
- priv->encoders[priv->num_encoders++] = encoder;
- priv->connectors[priv->num_connectors++] = connector;
+ crtc = omap_crtc_init(dev, plane, dssdev);
+ if (IS_ERR(crtc))
+ return PTR_ERR(crtc);
drm_mode_connector_attach_encoder(connector, encoder);
+ encoder->possible_crtcs = (1 << crtc_idx);
- /*
- * if we have reached the limit of the crtcs we are allowed to
- * create, let's not try to look for a crtc for this
- * panel/encoder and onwards, we will, of course, populate the
- * the possible_crtcs field for all the encoders with the final
- * set of crtcs we create
- */
- if (id == num_crtcs)
- continue;
-
- /*
- * get the recommended DISPC channel for this encoder. For now,
- * we only try to get create a crtc out of the recommended, the
- * other possible channels to which the encoder can connect are
- * not considered.
- */
-
- out = omapdss_find_output_from_display(dssdev);
- channel = out->dispc_channel;
- omap_dss_put_device(out);
-
- /*
- * if this channel hasn't already been taken by a previously
- * allocated crtc, we create a new crtc for it
- */
- if (!channel_used(dev, channel)) {
- ret = omap_modeset_create_crtc(dev, id, channel,
- possible_crtcs);
- if (ret < 0) {
- dev_err(dev->dev,
- "could not create CRTC (channel %u)\n",
- channel);
- return ret;
- }
-
- id++;
- }
- }
-
- /*
- * we have allocated crtcs according to the need of the panels/encoders,
- * adding more crtcs here if needed
- */
- for (; id < num_crtcs; id++) {
-
- /* find a free manager for this crtc */
- for (i = 0; i < num_mgrs; i++) {
- if (!channel_used(dev, i))
- break;
- }
-
- if (i == num_mgrs) {
- /* this shouldn't really happen */
- dev_err(dev->dev, "no managers left for crtc\n");
- return -ENOMEM;
- }
+ priv->crtcs[priv->num_crtcs++] = crtc;
+ priv->planes[priv->num_planes++] = plane;
+ priv->encoders[priv->num_encoders++] = encoder;
+ priv->connectors[priv->num_connectors++] = connector;
- ret = omap_modeset_create_crtc(dev, id, i,
- possible_crtcs);
- if (ret < 0) {
- dev_err(dev->dev,
- "could not create CRTC (channel %u)\n", i);
- return ret;
- }
+ plane_idx++;
+ crtc_idx++;
}
/*
* Create normal planes for the remaining overlays:
*/
- for (; id < num_ovls; id++) {
+ for (; plane_idx < num_ovls; plane_idx++) {
struct drm_plane *plane;
- plane = omap_plane_init(dev, id, DRM_PLANE_TYPE_OVERLAY,
- possible_crtcs);
+ if (WARN_ON(priv->num_planes >= ARRAY_SIZE(priv->planes)))
+ return -EINVAL;
+
+ plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_OVERLAY,
+ plane_crtc_mask);
if (IS_ERR(plane))
return PTR_ERR(plane);
- BUG_ON(priv->num_planes >= ARRAY_SIZE(priv->planes));
priv->planes[priv->num_planes++] = plane;
}
- for (i = 0; i < priv->num_encoders; i++) {
- struct drm_encoder *encoder = priv->encoders[i];
- struct omap_dss_device *dssdev =
- omap_encoder_get_dssdev(encoder);
- struct omap_dss_device *output;
-
- output = omapdss_find_output_from_display(dssdev);
-
- /* figure out which crtc's we can connect the encoder to: */
- encoder->possible_crtcs = 0;
- for (id = 0; id < priv->num_crtcs; id++) {
- struct drm_crtc *crtc = priv->crtcs[id];
- enum omap_channel crtc_channel;
-
- crtc_channel = omap_crtc_channel(crtc);
-
- if (output->dispc_channel == crtc_channel) {
- encoder->possible_crtcs |= (1 << id);
- break;
- }
- }
-
- omap_dss_put_device(output);
- }
-
DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n",
priv->num_planes, priv->num_crtcs, priv->num_encoders,
priv->num_connectors);
- dev->mode_config.min_width = 32;
- dev->mode_config.min_height = 32;
+ dev->mode_config.min_width = 8;
+ dev->mode_config.min_height = 2;
/* note: eventually will need some cpu_is_omapXYZ() type stuff here
* to fill in these limits properly on different OMAP generations..
@@ -629,12 +516,18 @@ static int ioctl_gem_info(struct drm_device *dev, void *data,
}
static const struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] = {
- DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_PREP, ioctl_gem_cpu_prep, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_FINI, ioctl_gem_cpu_fini, DRM_AUTH),
- DRM_IOCTL_DEF_DRV(OMAP_GEM_INFO, ioctl_gem_info, DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(OMAP_GET_PARAM, ioctl_get_param,
+ DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(OMAP_SET_PARAM, ioctl_set_param,
+ DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(OMAP_GEM_NEW, ioctl_gem_new,
+ DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_PREP, ioctl_gem_cpu_prep,
+ DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(OMAP_GEM_CPU_FINI, ioctl_gem_cpu_fini,
+ DRM_AUTH | DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(OMAP_GEM_INFO, ioctl_gem_info,
+ DRM_AUTH | DRM_RENDER_ALLOW),
};
/*
@@ -724,12 +617,9 @@ static const struct file_operations omapdriver_fops = {
static struct drm_driver omap_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
- DRIVER_ATOMIC,
+ DRIVER_ATOMIC | DRIVER_RENDER,
.open = dev_open,
.lastclose = dev_lastclose,
- .get_vblank_counter = drm_vblank_no_hw_counter,
- .enable_vblank = omap_irq_enable_vblank,
- .disable_vblank = omap_irq_disable_vblank,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = omap_debugfs_init,
#endif
@@ -779,6 +669,8 @@ static int pdev_probe(struct platform_device *pdev)
goto err_disconnect_dssdevs;
}
+ priv->dispc_ops = dispc_get_ops();
+
priv->omaprev = pdata->omaprev;
priv->wq = alloc_ordered_workqueue("omapdrm", 0);
@@ -863,6 +755,8 @@ static int pdev_remove(struct platform_device *pdev)
if (priv->fbdev)
omap_fbdev_free(ddev);
+ drm_atomic_helper_shutdown(ddev);
+
drm_mode_config_cleanup(ddev);
omap_drm_irq_uninstall(ddev);