summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm/omap_drv.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-05-03 11:44:24 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-05-03 11:44:24 -0700
commit2f34c1231bfc9f2550f934acb268ac7315fb3837 (patch)
treeff8114b3b4ec4723a11b041c6b74c389e9f0eeb9 /drivers/gpu/drm/omapdrm/omap_drv.c
parenta3719f34fdb664ffcfaec2160ef20fca7becf2ee (diff)
parent8b03d1ed2c43a2ba5ef3381322ee4515b97381bf (diff)
downloadtalos-op-linux-2f34c1231bfc9f2550f934acb268ac7315fb3837.tar.gz
talos-op-linux-2f34c1231bfc9f2550f934acb268ac7315fb3837.zip
Merge tag 'drm-for-v4.12' of git://people.freedesktop.org/~airlied/linux
Pull drm u pdates from Dave Airlie: "This is the main drm pull request for v4.12. Apart from two fixes pulls, everything should have been in drm-next for at least 2 weeks. The biggest thing in here is AMD released the public headers for their upcoming VEGA GPUs. These as always are quite a sizeable chunk of header files. They've also added initial non-display support for those GPUs, though they aren't available in production yet. Otherwise it's pretty much normal. New bridge drivers: - megachips-stdpxxxx-ge-b850v3-fw LVDS->DP++ - generic LVDS bridge support. Core: - Displayport link train failure reporting to userspace - debugfs interface cleaned up - subsystem TODO in kerneldoc now - Extended fbdev support (flipping and vblank wait) - drm_platform removed - EDP CRC support in helper - HF-VSDB SCDC support in EDID parser - Lots of code cleanups and header extraction - Thunderbolt external GPU awareness - Atomic helper improvements - Documentation improvements panel: - Sitronix and Samsung new panel support amdgpu: - Preliminary vega10 support - Multi-level page table support - GPU sensor support for userspace - PRT support for sparse buffers - SR-IOV improvements - Non-contig VRAM CPU mapping i915: - Atomic modesetting enabled by default on Gen5+ - LSPCON improvements - Atomic state handling for cdclk - GPU reset improvements - In-kernel unit tests - Geminilake improvements and color manager support - Designware i2c fixes - vblank evasion improvements - Hotplug safe connector iterators - GVT scheduler QoS support - GVT Kabylake support nouveau: - Acceleration support for Pascal (GP10x). - Rearchitecture of code handling proprietary signed firmware - Fix GTX 970 with odd MMU configuration - GP10B support - GP107 acceleration support vmwgfx: - Atomic modesetting support for vmwgfx omapdrm: - Support for render nodes - Refactor omapdss code - Fix some probe ordering issues - Fix too dark RGB565 rendering sunxi: - prelim rework for multiple pipes. mali-dp: - Color management support - Plane scaling - Power management improvements imx-drm: - Prefetch Resolve Engine/Gasket on i.MX6QP - Deferred plane disabling - Separate alpha support mediatek: - Mediatek SoC MT2701 support rcar-du: - Gen3 HDMI support msm: - 4k support for newer chips - OPP bindings for gpu - prep work for per-process pagetables vc4: - HDMI audio support - fixes qxl: - minor fixes. dw-hdmi: - PHY improvements - CSC fixes - Amlogic GX SoC support" * tag 'drm-for-v4.12' of git://people.freedesktop.org/~airlied/linux: (1778 commits) drm/nouveau/fb/gf100-: Fix 32 bit wraparound in new ram detection drm/nouveau/secboot/gm20b: fix the error return code in gm20b_secboot_tegra_read_wpr() drm/nouveau/kms: Increase max retries in scanout position queries. drm/nouveau/bios/bitP: check that table is long enough for optional pointers drm/nouveau/fifo/nv40: no ctxsw for pre-nv44 mpeg engine drm: mali-dp: use div_u64 for expensive 64-bit divisions drm/i915: Confirm the request is still active before adding it to the await drm/i915: Avoid busy-spinning on VLV_GLTC_PW_STATUS mmio drm/i915/selftests: Allocate inode/file dynamically drm/i915: Fix system hang with EI UP masked on Haswell drm/i915: checking for NULL instead of IS_ERR() in mock selftests drm/i915: Perform link quality check unconditionally during long pulse drm/i915: Fix use after free in lpe_audio_platdev_destroy() drm/i915: Use the right mapping_gfp_mask for final shmem allocation drm/i915: Make legacy cursor updates more unsynced drm/i915: Apply a cond_resched() to the saturated signaler drm/i915: Park the signaler before sleeping drm: mali-dp: Check the mclk rate and allow up/down scaling drm: mali-dp: Enable image enhancement when scaling drm: mali-dp: Add plane upscaling support ...
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);
OpenPOWER on IntegriCloud