@@ -306,6 +306,9 @@ drm_fb_helper cleanup tasks
- The max connector argument for drm_fb_helper_init() and
drm_fb_helper_fbdev_setup() isn't used anymore and can be removed.
+- The helper doesn't keep an array of connectors anymore so these can be
+ removed: drm_fb_helper_single_add_all_connectors(),
+ drm_fb_helper_add_one_connector() and drm_fb_helper_remove_one_connector().
Core refactorings
=================
@@ -92,12 +92,6 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
* 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
@@ -120,8 +114,7 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
* 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
@@ -134,165 +127,6 @@ static DEFINE_MUTEX(kernel_fb_helper_lock);
* 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;
@@ -651,20 +485,9 @@ int drm_fb_helper_init(struct drm_device *dev,
if (IS_ERR(fb_helper->modesets))
return -ENOMEM;
- 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_modesets_release(fb_helper->modesets);
-
- return -ENOMEM;
}
EXPORT_SYMBOL(drm_fb_helper_init);
@@ -738,7 +561,6 @@ EXPORT_SYMBOL(drm_fb_helper_unregister_fbi);
void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
{
struct fb_info *info;
- int i;
if (!fb_helper)
return;
@@ -769,12 +591,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
mutex_destroy(&fb_helper->lock);
drm_client_modesets_release(fb_helper->modesets);
-
- 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);
@@ -1638,8 +1454,9 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
{
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;
@@ -1656,11 +1473,11 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
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) {
@@ -1685,6 +1502,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
break;
}
}
+ drm_connector_list_iter_end(&conn_iter);
/*
* If we run into a situation where, for example, the primary plane
@@ -1865,26 +1683,12 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helpe
}
EXPORT_SYMBOL(drm_fb_helper_fill_var);
-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;
@@ -1893,20 +1697,15 @@ struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *
}
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;
@@ -1918,7 +1717,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
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)
@@ -1945,12 +1744,10 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
}
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)
{
@@ -1967,15 +1764,16 @@ 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");
@@ -1986,28 +1784,27 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
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++;
}
@@ -2018,11 +1815,10 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
/* 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;
@@ -2046,14 +1842,13 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
/* 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 |
@@ -2073,30 +1868,31 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
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;
@@ -2105,20 +1901,21 @@ static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper,
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;
@@ -2129,17 +1926,17 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
}
/* 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;
@@ -2147,22 +1944,22 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
* 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 :
@@ -2191,40 +1988,41 @@ static bool connector_has_possible_crtc(struct drm_connector *connector,
return false;
}
-static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
- struct drm_mode_set *modesets,
- struct drm_crtc **best_crtcs,
- struct drm_display_mode **modes,
- int n, int width, int height)
+static int drm_client_pick_crtcs(struct drm_device *dev,
+ struct drm_mode_set *modesets,
+ 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_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, modesets, best_crtcs, modes, n + 1, width, height);
+ best_score = drm_client_pick_crtcs(dev, modesets, 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++;
/*
@@ -2243,7 +2041,7 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
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]))
@@ -2252,12 +2050,11 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
crtcs[n] = crtc;
memcpy(crtcs, best_crtcs, n * sizeof(*crtcs));
- score = my_score + drm_pick_crtcs(fb_helper, modesets, crtcs, modes, n + 1,
- width, height);
+ score = my_score + drm_client_pick_crtcs(dev, modesets, 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));
}
}
@@ -2266,14 +2063,15 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
}
/* 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)
+static bool drm_client_firmware_config(struct drm_device *dev,
+ 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)
{
- struct drm_device *dev = fb_helper->dev;
- unsigned int count = min(fb_helper->connector_count, BITS_PER_LONG);
+ unsigned int count = min_t(unsigned int, connector_count, BITS_PER_LONG);
unsigned long conn_configured, conn_seq;
int i, j;
bool *save_enabled;
@@ -2296,13 +2094,11 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
conn_configured = 0;
retry:
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;
@@ -2360,14 +2156,13 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
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? */
@@ -2444,10 +2239,14 @@ static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper,
static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
u32 width, u32 height)
{
+ struct drm_connector *connector, **connectors = NULL;
+ struct drm_connector_list_iter conn_iter;
struct drm_device *dev = fb_helper->dev;
+ struct drm_mode_set *modesets = NULL;
+ unsigned int total_modes_count = 0;
+ unsigned int connector_count = 0;
struct drm_display_mode **modes;
struct drm_fb_offset *offsets;
- struct drm_mode_set *modesets;
struct drm_crtc **crtcs;
bool *enabled;
int i;
@@ -2456,52 +2255,68 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
/* prevent concurrent modification of connector_count by hotplug */
lockdep_assert_held(&fb_helper->lock);
+ 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;
+
modesets = drm_client_modesets_create(dev);
- 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);
+ 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 (IS_ERR(modesets) || !crtcs || !modes || !enabled || !offsets) {
DRM_ERROR("Memory allocation failed\n");
goto out;
}
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);
+ drm_client_connectors_enabled(connectors, connector_count, 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_client_firmware_config(dev, 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_target_cloned(fb_helper, modes, offsets,
- enabled, width, height) &&
- !drm_target_preferred(fb_helper, modes, offsets,
- enabled, width, height))
+ 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, modesets, crtcs, modes, 0, width, height);
+ drm_client_pick_crtcs(dev, modesets, connectors, connector_count,
+ crtcs, modes, 0, width, height);
}
mutex_unlock(&fb_helper->dev->mode_config.mutex);
- 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(modesets, 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);
@@ -2524,6 +2339,13 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
kfree(modes);
kfree(offsets);
kfree(enabled);
+free_connectors:
+ if (connectors) {
+ for (i = 0; i < connector_count; i++)
+ drm_connector_put(connectors[i]);
+ kfree(connectors);
+ }
+
drm_client_modesets_release(modesets);
}
@@ -2536,10 +2358,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper,
*/
static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
{
+ 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;
drm_client_for_each_modeset(modeset, fb_helper->modesets) {
if (!modeset->num_connectors)
@@ -2554,10 +2377,8 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
sw_rotations |= rotation;
}
- 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) {
@@ -2566,7 +2387,7 @@ static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper)
break;
}
}
- mutex_unlock(&fb_helper->dev->mode_config.mutex);
+ drm_connector_list_iter_end(&conn_iter);
switch (sw_rotations) {
case DRM_MODE_ROTATE_0:
@@ -2803,12 +2624,6 @@ int drm_fb_helper_fbdev_setup(struct drm_device *dev,
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);
@@ -3118,10 +2933,6 @@ static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
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);
@@ -5,6 +5,7 @@
#include <linux/types.h>
+#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
struct drm_client_dev;
@@ -146,6 +147,20 @@ bool drm_client_panel_rotation(struct drm_mode_set *modeset, unsigned int *rotat
int drm_client_modesets_commit(struct drm_device *dev, struct drm_mode_set *modesets);
void drm_client_modesets_dpms(struct drm_device *dev, struct drm_mode_set *modesets, int mode);
+/**
+ * drm_client_for_each_connector_iter - connector_list iterator macro
+ * @connector: &struct drm_connector pointer used as cursor
+ * @iter: &struct drm_connector_list_iter
+ *
+ * This iterates the connectors that are useable for internal clients (excludes
+ * writeback connectors).
+ *
+ * For more info see drm_for_each_connector_iter().
+ */
+#define drm_client_for_each_connector_iter(connector, iter) \
+ drm_for_each_connector_iter(connector, iter) \
+ if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK)
+
/**
* drm_client_for_each_modeset() - Iterate over modesets
* @modeset: &drm_mode_set loop cursor
@@ -98,16 +98,10 @@ struct drm_fb_helper_funcs {
struct drm_fb_helper_surface_size *sizes);
};
-struct drm_fb_helper_connector {
- struct drm_connector *connector;
-};
-
/**
* struct drm_fb_helper - main structure to emulate fbdev on top of KMS
* @fb: Scanout framebuffer object
* @dev: DRM device
- * @connector_count: number of connected connectors
- * @connector_info_alloc_count: size of connector_info
* @funcs: driver callbacks for fb helper
* @fbdev: emulated fbdev device info struct
* @pseudo_palette: fake palette of 16 colors
@@ -145,15 +139,6 @@ struct drm_fb_helper {
*/
struct drm_mode_set *modesets;
- int connector_count;
- int connector_info_alloc_count;
- /**
- * @connector_info:
- *
- * Array of per-connector information. Do not iterate directly, but use
- * drm_fb_helper_for_each_connector.
- */
- struct drm_fb_helper_connector **connector_info;
const struct drm_fb_helper_funcs *funcs;
struct fb_info *fbdev;
u32 pseudo_palette[17];
@@ -294,18 +279,8 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
-int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
int drm_fb_helper_debug_enter(struct fb_info *info);
int drm_fb_helper_debug_leave(struct fb_info *info);
-struct drm_display_mode *
-drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector,
- int width, int height);
-struct drm_display_mode *
-drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn);
-
-int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_connector *connector);
-int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
- struct drm_connector *connector);
int drm_fb_helper_fbdev_setup(struct drm_device *dev,
struct drm_fb_helper *fb_helper,
@@ -484,12 +459,6 @@ static inline int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper,
return 0;
}
-static inline int
-drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
-{
- return 0;
-}
-
static inline int drm_fb_helper_debug_enter(struct fb_info *info)
{
return 0;
@@ -500,34 +469,6 @@ static inline int drm_fb_helper_debug_leave(struct fb_info *info)
return 0;
}
-static inline struct drm_display_mode *
-drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector,
- int width, int height)
-{
- return NULL;
-}
-
-static inline struct drm_display_mode *
-drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
- int width, int height)
-{
- return NULL;
-}
-
-static inline int
-drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
- struct drm_connector *connector)
-{
- return 0;
-}
-
-static inline int
-drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
- struct drm_connector *connector)
-{
- return 0;
-}
-
static inline int
drm_fb_helper_fbdev_setup(struct drm_device *dev,
struct drm_fb_helper *fb_helper,
@@ -569,6 +510,27 @@ drm_fbdev_generic_setup(struct drm_device *dev, unsigned int preferred_bpp)
#endif
+/* TODO: There's a todo entry to remove these three */
+static inline int
+drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
+{
+ return 0;
+}
+
+static inline int
+drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper,
+ struct drm_connector *connector)
+{
+ return 0;
+}
+
+static inline int
+drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
+ struct drm_connector *connector)
+{
+ return 0;
+}
+
/**
* drm_fb_helper_remove_conflicting_framebuffers - remove firmware-configured framebuffers
* @a: memory range, users of which are to be removed
All drivers add all their connectors so there's no need to keep around an array of available connectors. Rename functions which signature is changed since they will be moved to drm_client in a later patch. Signed-off-by: Noralf Trønnes <noralf@tronnes.org> --- checkpatch complains, but I'm unable to satisfy it: ERROR: Macros with complex values should be enclosed in parentheses #939: FILE: include/drm/drm_client.h:160: +#define drm_client_for_each_connector_iter(connector, iter) \ + drm_for_each_connector_iter(connector, iter) \ + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) Documentation/gpu/todo.rst | 3 + drivers/gpu/drm/drm_fb_helper.c | 499 ++++++++++---------------------- include/drm/drm_client.h | 15 + include/drm/drm_fb_helper.h | 80 ++--- 4 files changed, 194 insertions(+), 403 deletions(-)