* Setup fbdev emulation by calling drm_fb_helper_fbdev_setup() and tear it
  * down by calling drm_fb_helper_fbdev_teardown().
  *
- * Drivers that need to handle connector hotplugging (e.g. dp mst) can't use
- * the setup helper and will need to do the whole four-step setup process with
- * drm_fb_helper_prepare(), drm_fb_helper_init(),
- * drm_fb_helper_single_add_all_connectors(), enable hotplugging and
- * drm_fb_helper_initial_config() to avoid a possible race window.
- *
  * At runtime drivers should restore the fbdev console by using
  * drm_fb_helper_lastclose() as their &drm_driver.lastclose callback.
  * They should also notify the fb helper code from updates to the output
  * encoders and connectors. To finish up the fbdev helper initialization, the
  * drm_fb_helper_init() function is called. To probe for all attached displays
  * and set up an initial configuration using the detected hardware, drivers
- * should call drm_fb_helper_single_add_all_connectors() followed by
- * drm_fb_helper_initial_config().
+ * should call drm_fb_helper_initial_config().
  *
  * If &drm_framebuffer_funcs.dirty is set, the
  * drm_fb_helper_{cfb,sys}_{write,fillrect,copyarea,imageblit} functions will
  * deferred I/O (coupled with drm_fb_helper_fbdev_teardown()).
  */
 
-#define drm_fb_helper_for_each_connector(fbh, i__) \
-       for (({ lockdep_assert_held(&(fbh)->lock); }), \
-            i__ = 0; i__ < (fbh)->connector_count; i__++)
-
-static int __drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
-                                            struct drm_connector *connector)
-{
-       struct drm_fb_helper_connector *fb_conn;
-       struct drm_fb_helper_connector **temp;
-       unsigned int count;
-
-       if (!drm_fbdev_emulation)
-               return 0;
-
-       lockdep_assert_held(&fb_helper->lock);
-
-       count = fb_helper->connector_count + 1;
-
-       if (count > fb_helper->connector_info_alloc_count) {
-               size_t size = count * sizeof(fb_conn);
-
-               temp = krealloc(fb_helper->connector_info, size, GFP_KERNEL);
-               if (!temp)
-                       return -ENOMEM;
-
-               fb_helper->connector_info_alloc_count = count;
-               fb_helper->connector_info = temp;
-       }
-
-       fb_conn = kzalloc(sizeof(*fb_conn), GFP_KERNEL);
-       if (!fb_conn)
-               return -ENOMEM;
-
-       drm_connector_get(connector);
-       fb_conn->connector = connector;
-       fb_helper->connector_info[fb_helper->connector_count++] = fb_conn;
-
-       return 0;
-}
-
-int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
-                                   struct drm_connector *connector)
-{
-       int err;
-
-       if (!fb_helper)
-               return 0;
-
-       mutex_lock(&fb_helper->lock);
-       err = __drm_fb_helper_add_one_connector(fb_helper, connector);
-       mutex_unlock(&fb_helper->lock);
-
-       return err;
-}
-EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
-
-/**
- * drm_fb_helper_single_add_all_connectors() - add all connectors to fbdev
- *                                            emulation helper
- * @fb_helper: fbdev initialized with drm_fb_helper_init, can be NULL
- *
- * This functions adds all the available connectors for use with the given
- * fb_helper. This is a separate step to allow drivers to freely assign
- * connectors to the fbdev, e.g. if some are reserved for special purposes or
- * not adequate to be used for the fbcon.
- *
- * This function is protected against concurrent connector hotadds/removals
- * using drm_fb_helper_add_one_connector() and
- * drm_fb_helper_remove_one_connector().
- */
-int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
-{
-       struct drm_device *dev;
-       struct drm_connector *connector;
-       struct drm_connector_list_iter conn_iter;
-       int i, ret = 0;
-
-       if (!drm_fbdev_emulation || !fb_helper)
-               return 0;
-
-       dev = fb_helper->dev;
-
-       mutex_lock(&fb_helper->lock);
-       drm_connector_list_iter_begin(dev, &conn_iter);
-       drm_for_each_connector_iter(connector, &conn_iter) {
-               if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
-                       continue;
-
-               ret = __drm_fb_helper_add_one_connector(fb_helper, connector);
-               if (ret)
-                       goto fail;
-       }
-       goto out;
-
-fail:
-       drm_fb_helper_for_each_connector(fb_helper, i) {
-               struct drm_fb_helper_connector *fb_helper_connector =
-                       fb_helper->connector_info[i];
-
-               drm_connector_put(fb_helper_connector->connector);
-
-               kfree(fb_helper_connector);
-               fb_helper->connector_info[i] = NULL;
-       }
-       fb_helper->connector_count = 0;
-out:
-       drm_connector_list_iter_end(&conn_iter);
-       mutex_unlock(&fb_helper->lock);
-
-       return ret;
-}
-EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
-
-static int __drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
-                                               struct drm_connector *connector)
-{
-       struct drm_fb_helper_connector *fb_helper_connector;
-       int i, j;
-
-       if (!drm_fbdev_emulation)
-               return 0;
-
-       lockdep_assert_held(&fb_helper->lock);
-
-       drm_fb_helper_for_each_connector(fb_helper, i) {
-               if (fb_helper->connector_info[i]->connector == connector)
-                       break;
-       }
-
-       if (i == fb_helper->connector_count)
-               return -EINVAL;
-       fb_helper_connector = fb_helper->connector_info[i];
-       drm_connector_put(fb_helper_connector->connector);
-
-       for (j = i + 1; j < fb_helper->connector_count; j++)
-               fb_helper->connector_info[j - 1] = fb_helper->connector_info[j];
-
-       fb_helper->connector_count--;
-       kfree(fb_helper_connector);
-
-       return 0;
-}
-
-int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
-                                      struct drm_connector *connector)
-{
-       int err;
-
-       if (!fb_helper)
-               return 0;
-
-       mutex_lock(&fb_helper->lock);
-       err = __drm_fb_helper_remove_one_connector(fb_helper, connector);
-       mutex_unlock(&fb_helper->lock);
-
-       return err;
-}
-EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
-
 static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
 {
        uint16_t *r_base, *g_base, *b_base;
                        return ret;
        }
 
-       fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
-       if (!fb_helper->connector_info)
-               goto out_free;
-
-       fb_helper->connector_info_alloc_count = dev->mode_config.num_connector;
-       fb_helper->connector_count = 0;
-
        dev->fb_helper = fb_helper;
 
        return 0;
-out_free:
-       drm_client_release(&fb_helper->client);
-
-       return -ENOMEM;
 }
 EXPORT_SYMBOL(drm_fb_helper_init);
 
 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
 {
        struct fb_info *info;
-       int i;
 
        if (!fb_helper)
                return;
 
        if (!fb_helper->client.funcs)
                drm_client_release(&fb_helper->client);
-
-       for (i = 0; i < fb_helper->connector_count; i++) {
-               drm_connector_put(fb_helper->connector_info[i]->connector);
-               kfree(fb_helper->connector_info[i]);
-       }
-       kfree(fb_helper->connector_info);
 }
 EXPORT_SYMBOL(drm_fb_helper_fini);
 
        struct drm_client_dev *client = &fb_helper->client;
        int ret = 0;
        int crtc_count = 0;
-       int i;
+       struct drm_connector_list_iter conn_iter;
        struct drm_fb_helper_surface_size sizes;
+       struct drm_connector *connector;
        struct drm_mode_set *mode_set;
        int best_depth = 0;
 
        if (preferred_bpp != sizes.surface_bpp)
                sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
 
-       drm_fb_helper_for_each_connector(fb_helper, i) {
-               struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
+       drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
+       drm_client_for_each_connector_iter(connector, &conn_iter) {
                struct drm_cmdline_mode *cmdline_mode;
 
-               cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
+               cmdline_mode = &connector->cmdline_mode;
 
                if (cmdline_mode->bpp_specified) {
                        switch (cmdline_mode->bpp) {
                        break;
                }
        }
+       drm_connector_list_iter_end(&conn_iter);
 
        /*
         * If we run into a situation where, for example, the primary plane
 }
 EXPORT_SYMBOL(drm_fb_helper_fill_info);
 
-static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
-                                               uint32_t maxX,
-                                               uint32_t maxY)
-{
-       struct drm_connector *connector;
-       int i, count = 0;
-
-       drm_fb_helper_for_each_connector(fb_helper, i) {
-               connector = fb_helper->connector_info[i]->connector;
-               count += connector->funcs->fill_modes(connector, maxX, maxY);
-       }
-
-       return count;
-}
-
-struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
+static struct drm_display_mode *
+drm_connector_has_preferred_mode(struct drm_connector *connector, int width, int height)
 {
        struct drm_display_mode *mode;
 
-       list_for_each_entry(mode, &fb_connector->connector->modes, head) {
+       list_for_each_entry(mode, &connector->modes, head) {
                if (mode->hdisplay > width ||
                    mode->vdisplay > height)
                        continue;
        }
        return NULL;
 }
-EXPORT_SYMBOL(drm_has_preferred_mode);
-
-static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
-{
-       return fb_connector->connector->cmdline_mode.specified;
-}
 
-struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn)
+static struct drm_display_mode *
+drm_connector_pick_cmdline_mode(struct drm_connector *connector)
 {
        struct drm_cmdline_mode *cmdline_mode;
        struct drm_display_mode *mode;
        bool prefer_non_interlace;
 
-       cmdline_mode = &fb_helper_conn->connector->cmdline_mode;
+       cmdline_mode = &connector->cmdline_mode;
        if (cmdline_mode->specified == false)
                return NULL;
 
 
        prefer_non_interlace = !cmdline_mode->interlace;
 again:
-       list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
+       list_for_each_entry(mode, &connector->modes, head) {
                /* check width/height */
                if (mode->hdisplay != cmdline_mode->xres ||
                    mode->vdisplay != cmdline_mode->yres)
        }
 
 create_mode:
-       mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
-                                                cmdline_mode);
-       list_add(&mode->head, &fb_helper_conn->connector->modes);
+       mode = drm_mode_create_from_cmdline_mode(connector->dev, cmdline_mode);
+       list_add(&mode->head, &connector->modes);
+
        return mode;
 }
-EXPORT_SYMBOL(drm_pick_cmdline_mode);
 
 static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
 {
        return enable;
 }
 
-static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
-                                 bool *enabled)
+static void drm_client_connectors_enabled(struct drm_connector **connectors,
+                                         unsigned int connector_count,
+                                         bool *enabled)
 {
        bool any_enabled = false;
        struct drm_connector *connector;
        int i = 0;
 
-       drm_fb_helper_for_each_connector(fb_helper, i) {
-               connector = fb_helper->connector_info[i]->connector;
+       for (i = 0; i < connector_count; i++) {
+               connector = connectors[i];
                enabled[i] = drm_connector_enabled(connector, true);
                DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
                              connector->display_info.non_desktop ? "non desktop" : enabled[i] ? "yes" : "no");
        if (any_enabled)
                return;
 
-       drm_fb_helper_for_each_connector(fb_helper, i) {
-               connector = fb_helper->connector_info[i]->connector;
-               enabled[i] = drm_connector_enabled(connector, false);
-       }
+       for (i = 0; i < connector_count; i++)
+               enabled[i] = drm_connector_enabled(connectors[i], false);
 }
 
-static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
-                             struct drm_display_mode **modes,
-                             struct drm_fb_offset *offsets,
-                             bool *enabled, int width, int height)
+static bool drm_client_target_cloned(struct drm_device *dev,
+                                    struct drm_connector **connectors,
+                                    unsigned int connector_count,
+                                    struct drm_display_mode **modes,
+                                    struct drm_fb_offset *offsets,
+                                    bool *enabled, int width, int height)
 {
        int count, i, j;
        bool can_clone = false;
-       struct drm_fb_helper_connector *fb_helper_conn;
        struct drm_display_mode *dmt_mode, *mode;
 
        /* only contemplate cloning in the single crtc case */
-       if (fb_helper->dev->mode_config.num_crtc > 1)
+       if (dev->mode_config.num_crtc > 1)
                return false;
 
        count = 0;
-       drm_fb_helper_for_each_connector(fb_helper, i) {
+       for (i = 0; i < connector_count; i++) {
                if (enabled[i])
                        count++;
        }
 
        /* check the command line or if nothing common pick 1024x768 */
        can_clone = true;
-       drm_fb_helper_for_each_connector(fb_helper, i) {
+       for (i = 0; i < connector_count; i++) {
                if (!enabled[i])
                        continue;
-               fb_helper_conn = fb_helper->connector_info[i];
-               modes[i] = drm_pick_cmdline_mode(fb_helper_conn);
+               modes[i] = drm_connector_pick_cmdline_mode(connectors[i]);
                if (!modes[i]) {
                        can_clone = false;
                        break;
 
        /* try and find a 1024x768 mode on each connector */
        can_clone = true;
-       dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false);
+       dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false);
 
-       drm_fb_helper_for_each_connector(fb_helper, i) {
+       for (i = 0; i < connector_count; i++) {
                if (!enabled[i])
                        continue;
 
-               fb_helper_conn = fb_helper->connector_info[i];
-               list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
+               list_for_each_entry(mode, &connectors[i]->modes, head) {
                        if (drm_mode_match(mode, dmt_mode,
                                           DRM_MODE_MATCH_TIMINGS |
                                           DRM_MODE_MATCH_CLOCK |
        return false;
 }
 
-static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
-                               struct drm_display_mode **modes,
-                               struct drm_fb_offset *offsets,
-                               int idx,
-                               int h_idx, int v_idx)
+static int drm_client_get_tile_offsets(struct drm_connector **connectors,
+                                      unsigned int connector_count,
+                                      struct drm_display_mode **modes,
+                                      struct drm_fb_offset *offsets,
+                                      int idx,
+                                      int h_idx, int v_idx)
 {
-       struct drm_fb_helper_connector *fb_helper_conn;
+       struct drm_connector *connector;
        int i;
        int hoffset = 0, voffset = 0;
 
-       drm_fb_helper_for_each_connector(fb_helper, i) {
-               fb_helper_conn = fb_helper->connector_info[i];
-               if (!fb_helper_conn->connector->has_tile)
+       for (i = 0; i < connector_count; i++) {
+               connector = connectors[i];
+               if (!connector->has_tile)
                        continue;
 
                if (!modes[i] && (h_idx || v_idx)) {
                        DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i,
-                                     fb_helper_conn->connector->base.id);
+                                     connector->base.id);
                        continue;
                }
-               if (fb_helper_conn->connector->tile_h_loc < h_idx)
+               if (connector->tile_h_loc < h_idx)
                        hoffset += modes[i]->hdisplay;
 
-               if (fb_helper_conn->connector->tile_v_loc < v_idx)
+               if (connector->tile_v_loc < v_idx)
                        voffset += modes[i]->vdisplay;
        }
        offsets[idx].x = hoffset;
        return 0;
 }
 
-static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
-                                struct drm_display_mode **modes,
-                                struct drm_fb_offset *offsets,
-                                bool *enabled, int width, int height)
+static bool drm_client_target_preferred(struct drm_connector **connectors,
+                                       unsigned int connector_count,
+                                       struct drm_display_mode **modes,
+                                       struct drm_fb_offset *offsets,
+                                       bool *enabled, int width, int height)
 {
-       struct drm_fb_helper_connector *fb_helper_conn;
-       const u64 mask = BIT_ULL(fb_helper->connector_count) - 1;
+       const u64 mask = BIT_ULL(connector_count) - 1;
+       struct drm_connector *connector;
        u64 conn_configured = 0;
        int tile_pass = 0;
        int i;
 
 retry:
-       drm_fb_helper_for_each_connector(fb_helper, i) {
-               fb_helper_conn = fb_helper->connector_info[i];
+       for (i = 0; i < connector_count; i++) {
+               connector = connectors[i];
 
                if (conn_configured & BIT_ULL(i))
                        continue;
                }
 
                /* first pass over all the untiled connectors */
-               if (tile_pass == 0 && fb_helper_conn->connector->has_tile)
+               if (tile_pass == 0 && connector->has_tile)
                        continue;
 
                if (tile_pass == 1) {
-                       if (fb_helper_conn->connector->tile_h_loc != 0 ||
-                           fb_helper_conn->connector->tile_v_loc != 0)
+                       if (connector->tile_h_loc != 0 ||
+                           connector->tile_v_loc != 0)
                                continue;
 
                } else {
-                       if (fb_helper_conn->connector->tile_h_loc != tile_pass - 1 &&
-                           fb_helper_conn->connector->tile_v_loc != tile_pass - 1)
+                       if (connector->tile_h_loc != tile_pass - 1 &&
+                           connector->tile_v_loc != tile_pass - 1)
                        /* if this tile_pass doesn't cover any of the tiles - keep going */
                                continue;
 
                         * find the tile offsets for this pass - need to find
                         * all tiles left and above
                         */
-                       drm_get_tile_offsets(fb_helper, modes, offsets,
-                                            i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc);
+                       drm_client_get_tile_offsets(connectors, connector_count, modes, offsets, i,
+                                                   connector->tile_h_loc, connector->tile_v_loc);
                }
                DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
-                             fb_helper_conn->connector->base.id);
+                             connector->base.id);
 
                /* got for command line mode first */
-               modes[i] = drm_pick_cmdline_mode(fb_helper_conn);
+               modes[i] = drm_connector_pick_cmdline_mode(connector);
                if (!modes[i]) {
                        DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n",
-                                     fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0);
-                       modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
+                                     connector->base.id, connector->tile_group ? connector->tile_group->id : 0);
+                       modes[i] = drm_connector_has_preferred_mode(connector, width, height);
                }
                /* No preferred modes, pick one off the list */
-               if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
-                       list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
+               if (!modes[i] && !list_empty(&connector->modes)) {
+                       list_for_each_entry(modes[i], &connector->modes, head)
                                break;
                }
                DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
        return false;
 }
 
-static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
-                         struct drm_crtc **best_crtcs,
-                         struct drm_display_mode **modes,
-                         int n, int width, int height)
+static int drm_client_pick_crtcs(struct drm_client_dev *client,
+                                struct drm_connector **connectors,
+                                unsigned int connector_count,
+                                struct drm_crtc **best_crtcs,
+                                struct drm_display_mode **modes,
+                                int n, int width, int height)
 {
-       struct drm_client_dev *client = &fb_helper->client;
+       struct drm_device *dev = client->dev;
        struct drm_connector *connector;
        int my_score, best_score, score;
        struct drm_crtc **crtcs, *crtc;
        struct drm_mode_set *modeset;
-       struct drm_fb_helper_connector *fb_helper_conn;
        int o;
 
-       if (n == fb_helper->connector_count)
+       if (n == connector_count)
                return 0;
 
-       fb_helper_conn = fb_helper->connector_info[n];
-       connector = fb_helper_conn->connector;
+       connector = connectors[n];
 
        best_crtcs[n] = NULL;
-       best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
+       best_score = drm_client_pick_crtcs(client, connectors, connector_count,
+                                          best_crtcs, modes, n + 1, width, height);
        if (modes[n] == NULL)
                return best_score;
 
-       crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
+       crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
        if (!crtcs)
                return best_score;
 
        my_score = 1;
        if (connector->status == connector_status_connected)
                my_score++;
-       if (drm_has_cmdline_mode(fb_helper_conn))
+       if (connector->cmdline_mode.specified)
                my_score++;
-       if (drm_has_preferred_mode(fb_helper_conn, width, height))
+       if (drm_connector_has_preferred_mode(connector, width, height))
                my_score++;
 
        /*
 
                if (o < n) {
                        /* ignore cloning unless only a single crtc */
-                       if (fb_helper->dev->mode_config.num_crtc > 1)
+                       if (dev->mode_config.num_crtc > 1)
                                continue;
 
                        if (!drm_mode_equal(modes[o], modes[n]))
 
                crtcs[n] = crtc;
                memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
-               score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
-                                                 width, height);
+               score = my_score + drm_client_pick_crtcs(client, connectors, connector_count,
+                                                        crtcs, modes, n + 1, width, height);
                if (score > best_score) {
                        best_score = score;
-                       memcpy(best_crtcs, crtcs,
-                              fb_helper->connector_count * sizeof(*crtcs));
+                       memcpy(best_crtcs, crtcs, connector_count * sizeof(*crtcs));
                }
        }
 
 }
 
 /* Try to read the BIOS display configuration and use it for the initial config */
-static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
-                                         struct drm_crtc **crtcs,
-                                         struct drm_display_mode **modes,
-                                         struct drm_fb_offset *offsets,
-                                         bool *enabled, int width, int height)
-{
-       struct drm_device *dev = fb_helper->dev;
-       unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
+static bool drm_client_firmware_config(struct drm_client_dev *client,
+                                      struct drm_connector **connectors,
+                                      unsigned int connector_count,
+                                      struct drm_crtc **crtcs,
+                                      struct drm_display_mode **modes,
+                                      struct drm_fb_offset *offsets,
+                                      bool *enabled, int width, int height)
+{
+       unsigned int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
        unsigned long conn_configured, conn_seq, mask;
+       struct drm_device *dev = client->dev;
        int i, j;
        bool *save_enabled;
        bool fallback = true, ret = true;
 retry:
        conn_seq = conn_configured;
        for (i = 0; i < count; i++) {
-               struct drm_fb_helper_connector *fb_conn;
                struct drm_connector *connector;
                struct drm_encoder *encoder;
                struct drm_crtc *new_crtc;
 
-               fb_conn = fb_helper->connector_info[i];
-               connector = fb_conn->connector;
+               connector = connectors[i];
 
                if (conn_configured & BIT(i))
                        continue;
                              connector->name);
 
                /* go for command line mode first */
-               modes[i] = drm_pick_cmdline_mode(fb_conn);
+               modes[i] = drm_connector_pick_cmdline_mode(connector);
 
                /* try for preferred next */
                if (!modes[i]) {
                        DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n",
                                      connector->name, connector->has_tile);
-                       modes[i] = drm_has_preferred_mode(fb_conn, width,
-                                                         height);
+                       modes[i] = drm_connector_has_preferred_mode(connector, width, height);
                }
 
                /* No preferred mode marked by the EDID? Are there any modes? */
 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
                            u32 width, u32 height)
 {
+       struct drm_connector *connector, **connectors = NULL;
        struct drm_client_dev *client = &fb_helper->client;
+       struct drm_connector_list_iter conn_iter;
        struct drm_device *dev = fb_helper->dev;
+       unsigned int total_modes_count = 0;
+       unsigned int connector_count = 0;
        struct drm_display_mode **modes;
        struct drm_fb_offset *offsets;
        struct drm_crtc **crtcs;
        int i;
 
        DRM_DEBUG_KMS("\n");
-       /* prevent concurrent modification of connector_count by hotplug */
-       lockdep_assert_held(&fb_helper->lock);
-
-       crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL);
-       modes = kcalloc(fb_helper->connector_count,
-                       sizeof(struct drm_display_mode *), GFP_KERNEL);
-       offsets = kcalloc(fb_helper->connector_count,
-                         sizeof(struct drm_fb_offset), GFP_KERNEL);
-       enabled = kcalloc(fb_helper->connector_count,
-                         sizeof(bool), GFP_KERNEL);
+
+       drm_connector_list_iter_begin(dev, &conn_iter);
+       drm_client_for_each_connector_iter(connector, &conn_iter) {
+               struct drm_connector **tmp;
+
+               tmp = krealloc(connectors, (connector_count + 1) * sizeof(*connectors), GFP_KERNEL);
+               if (!tmp)
+                       goto free_connectors;
+
+               connectors = tmp;
+               drm_connector_get(connector);
+               connectors[connector_count++] = connector;
+       }
+       drm_connector_list_iter_end(&conn_iter);
+
+       if (!connector_count)
+               return;
+
+       crtcs = kcalloc(connector_count, sizeof(*crtcs), GFP_KERNEL);
+       modes = kcalloc(connector_count, sizeof(*modes), GFP_KERNEL);
+       offsets = kcalloc(connector_count, sizeof(*offsets), GFP_KERNEL);
+       enabled = kcalloc(connector_count, sizeof(bool), GFP_KERNEL);
        if (!crtcs || !modes || !enabled || !offsets) {
                DRM_ERROR("Memory allocation failed\n");
                goto out;
        mutex_lock(&client->modeset_mutex);
 
        mutex_lock(&fb_helper->dev->mode_config.mutex);
-       if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0)
+       for (i = 0; i < connector_count; i++)
+               total_modes_count += connectors[i]->funcs->fill_modes(connectors[i], width, height);
+       if (!total_modes_count)
                DRM_DEBUG_KMS("No connectors reported connected with modes\n");
-       drm_enable_connectors(fb_helper, enabled);
-
-       if (!drm_fb_helper_firmware_config(fb_helper, crtcs, modes, offsets,
-                                          enabled, width, height)) {
-               memset(modes, 0, fb_helper->connector_count*sizeof(modes[0]));
-               memset(crtcs, 0, fb_helper->connector_count*sizeof(crtcs[0]));
-               memset(offsets, 0, fb_helper->connector_count*sizeof(offsets[0]));
-
-               if (!drm_target_cloned(fb_helper, modes, offsets,
-                                      enabled, width, height) &&
-                   !drm_target_preferred(fb_helper, modes, offsets,
-                                         enabled, width, height))
+       drm_client_connectors_enabled(connectors, connector_count, enabled);
+
+       if (!drm_client_firmware_config(client, connectors, connector_count, crtcs,
+                                       modes, offsets, enabled, width, height)) {
+               memset(modes, 0, connector_count * sizeof(*modes));
+               memset(crtcs, 0, connector_count * sizeof(*crtcs));
+               memset(offsets, 0, connector_count * sizeof(*offsets));
+
+               if (!drm_client_target_cloned(dev, connectors, connector_count, modes,
+                                             offsets, enabled, width, height) &&
+                   !drm_client_target_preferred(connectors, connector_count, modes,
+                                                offsets, enabled, width, height))
                        DRM_ERROR("Unable to find initial modes\n");
 
                DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n",
                              width, height);
 
-               drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
+               drm_client_pick_crtcs(client, connectors, connector_count,
+                                     crtcs, modes, 0, width, height);
        }
        mutex_unlock(&fb_helper->dev->mode_config.mutex);
 
        drm_client_modeset_release(client);
 
-       drm_fb_helper_for_each_connector(fb_helper, i) {
+       for (i = 0; i < connector_count; i++) {
                struct drm_display_mode *mode = modes[i];
                struct drm_crtc *crtc = crtcs[i];
                struct drm_fb_offset *offset = &offsets[i];
 
                if (mode && crtc) {
                        struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc);
-                       struct drm_connector *connector =
-                               fb_helper->connector_info[i]->connector;
+                       struct drm_connector *connector = connectors[i];
 
                        DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n",
                                      mode->name, crtc->base.id, offset->x, offset->y);
        kfree(modes);
        kfree(offsets);
        kfree(enabled);
+free_connectors:
+       for (i = 0; i < connector_count; i++)
+               drm_connector_put(connectors[i]);
+       kfree(connectors);
 }
 
 /*
 static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
 {
        struct drm_client_dev *client = &fb_helper->client;
+       struct drm_connector_list_iter conn_iter;
        struct fb_info *info = fb_helper->fbdev;
        unsigned int rotation, sw_rotations = 0;
+       struct drm_connector *connector;
        struct drm_mode_set *modeset;
-       int i;
 
        mutex_lock(&client->modeset_mutex);
        drm_client_for_each_modeset(modeset, client) {
        }
        mutex_unlock(&client->modeset_mutex);
 
-       mutex_lock(&fb_helper->dev->mode_config.mutex);
-       drm_fb_helper_for_each_connector(fb_helper, i) {
-               struct drm_connector *connector =
-                                       fb_helper->connector_info[i]->connector;
+       drm_connector_list_iter_begin(fb_helper->dev, &conn_iter);
+       drm_client_for_each_connector_iter(connector, &conn_iter) {
 
                /* use first connected connector for the physical dimensions */
                if (connector->status == connector_status_connected) {
                        break;
                }
        }
-       mutex_unlock(&fb_helper->dev->mode_config.mutex);
+       drm_connector_list_iter_end(&conn_iter);
 
        switch (sw_rotations) {
        case DRM_MODE_ROTATE_0:
                return ret;
        }
 
-       ret = drm_fb_helper_single_add_all_connectors(fb_helper);
-       if (ret < 0) {
-               DRM_DEV_ERROR(dev->dev, "fbdev: Failed to add connectors (ret=%d)\n", ret);
-               goto err_drm_fb_helper_fini;
-       }
-
        if (!drm_drv_uses_atomic_modeset(dev))
                drm_helper_disable_unused_functions(dev);
 
        if (ret)
                goto err;
 
-       ret = drm_fb_helper_single_add_all_connectors(fb_helper);
-       if (ret)
-               goto err_cleanup;
-
        if (!drm_drv_uses_atomic_modeset(dev))
                drm_helper_disable_unused_functions(dev);