void omap_crtc_pre_init(void)
 {
+       memset(omap_crtcs, 0, sizeof(omap_crtcs));
+
        dss_install_mgr_ops(&mgr_ops);
 }
 
 
 /* initialize crtc */
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
-               struct drm_plane *plane, enum omap_channel channel, int id)
+               struct drm_plane *plane, struct omap_dss_device *dssdev)
 {
        struct omap_drm_private *priv = dev->dev_private;
        struct drm_crtc *crtc = NULL;
        struct omap_crtc *omap_crtc;
+       enum omap_channel channel;
+       struct omap_dss_device *out;
        int ret;
 
+       out = omapdss_find_output_from_display(dssdev);
+       channel = out->dispc_channel;
+       omap_dss_put_device(out);
+
        DBG("%s", channel_names[channel]);
 
+       /* Multiple displays on same channel is not allowed */
+       if (WARN_ON(omap_crtcs[channel] != NULL))
+               return ERR_PTR(-EINVAL);
+
        omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
        if (!omap_crtc)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        crtc = &omap_crtc->base;
 
        ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
                                        &omap_crtc_funcs, NULL);
        if (ret < 0) {
+               dev_err(dev->dev, "%s(): could not init crtc for: %s\n",
+                       __func__, dssdev->name);
                kfree(omap_crtc);
-               return NULL;
+               return ERR_PTR(ret);
        }
 
        drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 
        }
 }
 
-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;
        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;
        struct omap_dss_device *dssdev = NULL;
        int num_ovls = priv->dispc_ops->get_num_ovls();
        int num_mgrs = priv->dispc_ops->get_num_mgrs();
-       int num_crtcs = 0;
-       int i, id = 0;
+       int num_crtcs, crtc_idx, plane_idx;
        int ret;
-       u32 possible_crtcs;
+       u32 plane_crtc_mask;
 
        drm_mode_config_init(dev);
 
                return ret;
 
        /*
-        * Let's create one CRTC for each connected DSS device if we
-        * have display managers and overlays (for primary planes) for
-        * them.
+        * 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 = 0;
        for_each_dss_dev(dssdev)
                if (omapdss_device_is_connected(dssdev))
                        num_crtcs++;
 
-       num_crtcs = min3(num_crtcs, num_mgrs, num_ovls);
-       possible_crtcs = (1 << num_crtcs) - 1;
+       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 can
-                * create, let's not try to create a crtc for this
-                * panel/encoder and onwards.
-                */
-               if (id == num_crtcs)
-                       continue;
+               priv->crtcs[priv->num_crtcs++] = crtc;
+               priv->planes[priv->num_planes++] = plane;
+               priv->encoders[priv->num_encoders++] = encoder;
+               priv->connectors[priv->num_connectors++] = connector;
 
-               /*
-                * 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++;
-               }
+               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;
        }
 
-       /*
-        * populate the the possible_crtcs field for all the encoders
-        * we created.
-        */
-       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);
 
        .atomic_get_property = omap_plane_atomic_get_property,
 };
 
-static const char *plane_names[] = {
+static const char *plane_id_to_name[] = {
        [OMAP_DSS_GFX] = "gfx",
        [OMAP_DSS_VIDEO1] = "vid1",
        [OMAP_DSS_VIDEO2] = "vid2",
        [OMAP_DSS_VIDEO3] = "vid3",
 };
 
+static const enum omap_plane_id plane_idx_to_id[] = {
+       OMAP_DSS_GFX,
+       OMAP_DSS_VIDEO1,
+       OMAP_DSS_VIDEO2,
+       OMAP_DSS_VIDEO3,
+};
+
 /* initialize plane */
 struct drm_plane *omap_plane_init(struct drm_device *dev,
-               int id, enum drm_plane_type type,
+               int idx, enum drm_plane_type type,
                u32 possible_crtcs)
 {
        struct omap_drm_private *priv = dev->dev_private;
        struct drm_plane *plane;
        struct omap_plane *omap_plane;
+       enum omap_plane_id id;
        int ret;
 
-       DBG("%s: type=%d", plane_names[id], type);
+       if (WARN_ON(idx >= ARRAY_SIZE(plane_idx_to_id)))
+               return ERR_PTR(-EINVAL);
+
+       id = plane_idx_to_id[idx];
+
+       DBG("%s: type=%d", plane_id_to_name[id], type);
 
        omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
        if (!omap_plane)
                        omap_plane->formats, ARRAY_SIZE(omap_plane->formats),
                        priv->dispc_ops->ovl_get_color_modes(id));
        omap_plane->id = id;
-       omap_plane->name = plane_names[id];
+       omap_plane->name = plane_id_to_name[id];
 
        plane = &omap_plane->base;
 
        return plane;
 
 error:
+       dev_err(dev->dev, "%s(): could not create plane: %s\n",
+               __func__, plane_id_to_name[id]);
+
        kfree(omap_plane);
        return NULL;
 }