diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_drv.c')
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.c | 260 |
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); |