The fb helper uses fixed size arrays for the associated crtcs.
This is an unnecessary limitation, so instead use a list to
store the crtcs and allocate them dynamically.

Signed-off-by: Sascha Hauer <s.ha...@pengutronix.de>
---
 drivers/gpu/drm/drm_fb_helper.c |  129 ++++++++++++++++++++-------------------
 include/drm/drm_fb_helper.h     |    3 +-
 2 files changed, 68 insertions(+), 64 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 7740dd2..f292a78 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -147,15 +147,14 @@ int drm_fb_helper_debug_enter(struct fb_info *info)
 {
        struct drm_fb_helper *helper = info->par;
        struct drm_crtc_helper_funcs *funcs;
-       int i;
 
        if (list_empty(&kernel_fb_helper_list))
                return false;
 
        list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) {
-               for (i = 0; i < helper->crtc_count; i++) {
-                       struct drm_mode_set *mode_set =
-                               &helper->crtc_info[i].mode_set;
+               struct drm_fb_helper_crtc *helper_crtc;
+               list_for_each_entry(helper_crtc, &helper->crtc_list, list) {
+                       struct drm_mode_set *mode_set = &helper_crtc->mode_set;
 
                        if (!mode_set->crtc->enabled)
                                continue;
@@ -194,10 +193,10 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
        struct drm_crtc *crtc;
        struct drm_crtc_helper_funcs *funcs;
        struct drm_framebuffer *fb;
-       int i;
+       struct drm_fb_helper_crtc *helper_crtc;
 
-       for (i = 0; i < helper->crtc_count; i++) {
-               struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set;
+       list_for_each_entry(helper_crtc, &helper->crtc_list, list) {
+               struct drm_mode_set *mode_set = &helper_crtc->mode_set;
                crtc = mode_set->crtc;
                funcs = crtc->helper_private;
                fb = drm_mode_config_fb(crtc);
@@ -221,10 +220,12 @@ EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
 bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
 {
+       struct drm_fb_helper_crtc *helper_crtc;
        bool error = false;
-       int i, ret;
-       for (i = 0; i < fb_helper->crtc_count; i++) {
-               struct drm_mode_set *mode_set = 
&fb_helper->crtc_info[i].mode_set;
+       int ret;
+
+       list_for_each_entry(helper_crtc, &fb_helper->crtc_list, list) {
+               struct drm_mode_set *mode_set = &helper_crtc->mode_set;
                ret = drm_crtc_helper_set_config(mode_set);
                if (ret)
                        error = true;
@@ -312,14 +313,15 @@ static void drm_fb_helper_dpms(struct fb_info *info, int 
dpms_mode)
        struct drm_device *dev = fb_helper->dev;
        struct drm_crtc *crtc;
        struct drm_connector *connector;
-       int i, j;
+       struct drm_fb_helper_crtc *helper_crtc;
+       int j;
 
        /*
         * For each CRTC in this fb, turn the connectors on/off.
         */
        mutex_lock(&dev->mode_config.mutex);
-       for (i = 0; i < fb_helper->crtc_count; i++) {
-               crtc = fb_helper->crtc_info[i].mode_set.crtc;
+       list_for_each_entry(helper_crtc, &fb_helper->crtc_list, list) {
+               crtc = helper_crtc->mode_set.crtc;
 
                if (!crtc->enabled)
                        continue;
@@ -365,17 +367,20 @@ EXPORT_SYMBOL(drm_fb_helper_blank);
 
 static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
 {
+       struct drm_fb_helper_crtc *helper_crtc, *tmp;
        int i;
 
        for (i = 0; i < helper->connector_count; i++)
                kfree(helper->connector_info[i]);
+
        kfree(helper->connector_info);
-       for (i = 0; i < helper->crtc_count; i++) {
-               kfree(helper->crtc_info[i].mode_set.connectors);
-               if (helper->crtc_info[i].mode_set.mode)
-                       drm_mode_destroy(helper->dev, 
helper->crtc_info[i].mode_set.mode);
+
+       list_for_each_entry_safe(helper_crtc, tmp, &helper->crtc_list, list) {
+               kfree(helper_crtc->mode_set.connectors);
+               if (helper_crtc->mode_set.mode)
+                       drm_mode_destroy(helper->dev, 
helper_crtc->mode_set.mode);
+               kfree(helper_crtc);
        }
-       kfree(helper->crtc_info);
 }
 
 int drm_fb_helper_init(struct drm_device *dev,
@@ -383,42 +388,40 @@ int drm_fb_helper_init(struct drm_device *dev,
                       int crtc_count, int max_conn_count)
 {
        struct drm_crtc *crtc;
+       struct drm_fb_helper_crtc *helper_crtc;
        int ret = 0;
-       int i;
 
        fb_helper->dev = dev;
 
        INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
+       INIT_LIST_HEAD(&fb_helper->crtc_list);
 
-       fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct 
drm_fb_helper_crtc), GFP_KERNEL);
-       if (!fb_helper->crtc_info)
+       fb_helper->crtc_count = 0;
+       fb_helper->connector_info = kcalloc(dev->mode_config.num_connector,
+                       sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
+       if (!fb_helper->connector_info)
                return -ENOMEM;
 
-       fb_helper->crtc_count = crtc_count;
-       fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, 
sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
-       if (!fb_helper->connector_info) {
-               kfree(fb_helper->crtc_info);
-               return -ENOMEM;
-       }
        fb_helper->connector_count = 0;
 
-       for (i = 0; i < crtc_count; i++) {
-               fb_helper->crtc_info[i].mode_set.connectors =
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               helper_crtc = kzalloc(sizeof(*helper_crtc), GFP_KERNEL);
+               if (!helper_crtc)
+                       goto out_free;
+
+               helper_crtc->mode_set.crtc = crtc;
+               helper_crtc->mode_set.connectors =
                        kcalloc(max_conn_count,
                                sizeof(struct drm_connector *),
                                GFP_KERNEL);
 
-               if (!fb_helper->crtc_info[i].mode_set.connectors) {
+               if (!helper_crtc->mode_set.connectors) {
                        ret = -ENOMEM;
                        goto out_free;
                }
-               fb_helper->crtc_info[i].mode_set.num_connectors = 0;
-       }
-
-       i = 0;
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               fb_helper->crtc_info[i].mode_set.crtc = crtc;
-               i++;
+               helper_crtc->mode_set.num_connectors = 0;
+               list_add_tail(&helper_crtc->list, &fb_helper->crtc_list);
+               fb_helper->crtc_count++;
        }
 
        return 0;
@@ -515,11 +518,12 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct 
fb_info *info)
        struct drm_crtc_helper_funcs *crtc_funcs;
        u16 *red, *green, *blue, *transp;
        struct drm_crtc *crtc;
-       int i, j, rc = 0;
+       struct drm_fb_helper_crtc *helper_crtc;
+       int j, rc = 0;
        int start;
 
-       for (i = 0; i < fb_helper->crtc_count; i++) {
-               crtc = fb_helper->crtc_info[i].mode_set.crtc;
+       list_for_each_entry(helper_crtc, &fb_helper->crtc_list, list) {
+               crtc = helper_crtc->mode_set.crtc;
                crtc_funcs = crtc->helper_private;
 
                red = cmap->red;
@@ -642,9 +646,9 @@ int drm_fb_helper_set_par(struct fb_info *info)
        struct drm_fb_helper *fb_helper = info->par;
        struct drm_device *dev = fb_helper->dev;
        struct fb_var_screeninfo *var = &info->var;
+       struct drm_fb_helper_crtc *helper_crtc;
        struct drm_crtc *crtc;
        int ret;
-       int i;
 
        if (var->pixclock != 0) {
                DRM_ERROR("PIXEL CLOCK SET\n");
@@ -652,9 +656,9 @@ int drm_fb_helper_set_par(struct fb_info *info)
        }
 
        mutex_lock(&dev->mode_config.mutex);
-       for (i = 0; i < fb_helper->crtc_count; i++) {
-               crtc = fb_helper->crtc_info[i].mode_set.crtc;
-               ret = 
crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
+       list_for_each_entry(helper_crtc, &fb_helper->crtc_list, list) {
+               crtc = helper_crtc->mode_set.crtc;
+               ret = crtc->funcs->set_config(&helper_crtc->mode_set);
                if (ret) {
                        mutex_unlock(&dev->mode_config.mutex);
                        return ret;
@@ -676,15 +680,15 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo 
*var,
        struct drm_fb_helper *fb_helper = info->par;
        struct drm_device *dev = fb_helper->dev;
        struct drm_mode_set *modeset;
+       struct drm_fb_helper_crtc *helper_crtc;
        struct drm_crtc *crtc;
        int ret = 0;
-       int i;
 
        mutex_lock(&dev->mode_config.mutex);
-       for (i = 0; i < fb_helper->crtc_count; i++) {
-               crtc = fb_helper->crtc_info[i].mode_set.crtc;
+       list_for_each_entry(helper_crtc, &fb_helper->crtc_list, list) {
+               modeset = &helper_crtc->mode_set;
+               crtc = modeset->crtc;
 
-               modeset = &fb_helper->crtc_info[i].mode_set;
 
                modeset->x = var->xoffset;
                modeset->y = var->yoffset;
@@ -705,6 +709,7 @@ EXPORT_SYMBOL(drm_fb_helper_pan_display);
 int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
                                  int preferred_bpp)
 {
+       struct drm_fb_helper_crtc *helper_crtc;
        int new_fb = 0;
        int crtc_count = 0;
        int i;
@@ -755,13 +760,13 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper 
*fb_helper,
        }
 
        crtc_count = 0;
-       for (i = 0; i < fb_helper->crtc_count; i++) {
+       list_for_each_entry(helper_crtc, &fb_helper->crtc_list, list) {
                struct drm_display_mode *desired_mode;
-               desired_mode = fb_helper->crtc_info[i].desired_mode;
+               desired_mode = helper_crtc->desired_mode;
 
                if (desired_mode) {
                        if (gamma_size == 0)
-                               gamma_size = 
fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
+                               gamma_size = 
helper_crtc->mode_set.crtc->gamma_size;
                        if (desired_mode->hdisplay < sizes.fb_width)
                                sizes.fb_width = desired_mode->hdisplay;
                        if (desired_mode->vdisplay < sizes.fb_height)
@@ -790,16 +795,15 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper 
*fb_helper,
        info = fb_helper->fbdev;
 
        /* set the fb pointer */
-       for (i = 0; i < fb_helper->crtc_count; i++) {
-               fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
-       }
+       list_for_each_entry(helper_crtc, &fb_helper->crtc_list, list)
+               helper_crtc->mode_set.fb = fb_helper->fb;
 
        if (new_fb) {
                info->var.pixclock = 0;
                if (register_framebuffer(info) < 0) {
                        return -EINVAL;
                }
-
+               drm_fb_helper_blank(FB_BLANK_UNBLANK, info);
                printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
                       info->fix.id);
 
@@ -1184,12 +1188,13 @@ static int drm_pick_crtcs(struct drm_fb_helper 
*fb_helper,
 
        /* select a crtc for this connector and then attempt to configure
           remaining connectors */
-       for (c = 0; c < fb_helper->crtc_count; c++) {
-               crtc = &fb_helper->crtc_info[c];
-
+       c = 0;
+       list_for_each_entry(crtc, &fb_helper->crtc_list, list) {
                if ((encoder->possible_crtcs & (1 << c)) == 0) {
+                       c++;
                        continue;
                }
+               c++;
 
                for (o = 0; o < n; o++)
                        if (best_crtcs[o] == crtc)
@@ -1224,7 +1229,7 @@ out:
 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
 {
        struct drm_device *dev = fb_helper->dev;
-       struct drm_fb_helper_crtc **crtcs;
+       struct drm_fb_helper_crtc **crtcs, *helper_crtc;
        struct drm_display_mode **modes;
        struct drm_encoder *encoder;
        struct drm_mode_set *modeset;
@@ -1264,10 +1269,8 @@ static void drm_setup_crtcs(struct drm_fb_helper 
*fb_helper)
 
        /* need to set the modesets up here for use later */
        /* fill out the connector<->crtc mappings into the modesets */
-       for (i = 0; i < fb_helper->crtc_count; i++) {
-               modeset = &fb_helper->crtc_info[i].mode_set;
-               modeset->num_connectors = 0;
-       }
+       list_for_each_entry(helper_crtc, &fb_helper->crtc_list, list)
+               helper_crtc->mode_set.num_connectors = 0;
 
        for (i = 0; i < fb_helper->connector_count; i++) {
                struct drm_display_mode *mode = modes[i];
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 5120b01..e1e1c02 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -37,6 +37,7 @@ struct drm_fb_helper;
 struct drm_fb_helper_crtc {
        struct drm_mode_set mode_set;
        struct drm_display_mode *desired_mode;
+       struct list_head list;
 };
 
 struct drm_fb_helper_surface_size {
@@ -69,7 +70,7 @@ struct drm_fb_helper {
        struct drm_device *dev;
        struct drm_display_mode *mode;
        int crtc_count;
-       struct drm_fb_helper_crtc *crtc_info;
+       struct list_head crtc_list;
        int connector_count;
        struct drm_fb_helper_connector **connector_info;
        struct drm_fb_helper_funcs *funcs;
-- 
1.7.8.3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to