X-Git-Url: http://ftp.safe.ca/?p=safe%2Fjmp%2Flinux-2.6;a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Fdrm_fb_helper.c;h=08c4c926e65f58e1b28fabcb1bb30c3ac183f7b5;hp=9808f6e37a9d9501efa7a87de97859edd32254bc;hb=fc2362afd5ab9456caab4de317da796cc88944fe;hpb=0b4c0f3f0eceacb691e2b5570d9b16d751ce1b48 diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 9808f6e..08c4c92 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -29,6 +29,7 @@ */ #include #include +#include #include #include "drmP.h" #include "drm_crtc.h" @@ -263,7 +264,7 @@ bool drm_fb_helper_force_kernel_mode(void) int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed, void *panic_str) { - DRM_ERROR("panic occurred, switching back to text console\n"); + printk(KERN_ERR "panic occurred, switching back to text console\n"); return drm_fb_helper_force_kernel_mode(); return 0; } @@ -420,54 +421,73 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) kfree(helper->crtc_info); } -int drm_fb_helper_init_crtc_count(struct drm_device *dev, - struct drm_fb_helper *helper, - int crtc_count, int max_conn_count) +int drm_fb_helper_init(struct drm_device *dev, + struct drm_fb_helper *fb_helper, + int crtc_count, int max_conn_count) { struct drm_crtc *crtc; int ret = 0; int i; - INIT_LIST_HEAD(&helper->kernel_fb_list); - helper->dev = dev; - helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); - if (!helper->crtc_info) + fb_helper->dev = dev; + + INIT_LIST_HEAD(&fb_helper->kernel_fb_list); + + fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); + if (!fb_helper->crtc_info) return -ENOMEM; - helper->crtc_count = crtc_count; - helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); - if (!helper->connector_info) { - kfree(helper->crtc_info); + 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; } - helper->connector_count = 0; + fb_helper->connector_count = 0; for (i = 0; i < crtc_count; i++) { - helper->crtc_info[i].mode_set.connectors = + fb_helper->crtc_info[i].mode_set.connectors = kcalloc(max_conn_count, sizeof(struct drm_connector *), GFP_KERNEL); - if (!helper->crtc_info[i].mode_set.connectors) { + if (!fb_helper->crtc_info[i].mode_set.connectors) { ret = -ENOMEM; goto out_free; } - helper->crtc_info[i].mode_set.num_connectors = 0; + fb_helper->crtc_info[i].mode_set.num_connectors = 0; } i = 0; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - helper->crtc_info[i].crtc_id = crtc->base.id; - helper->crtc_info[i].mode_set.crtc = crtc; + fb_helper->crtc_info[i].crtc_id = crtc->base.id; + fb_helper->crtc_info[i].mode_set.crtc = crtc; i++; } - helper->conn_limit = max_conn_count; + fb_helper->conn_limit = max_conn_count; return 0; out_free: - drm_fb_helper_crtc_free(helper); + drm_fb_helper_crtc_free(fb_helper); return -ENOMEM; } -EXPORT_SYMBOL(drm_fb_helper_init_crtc_count); +EXPORT_SYMBOL(drm_fb_helper_init); + +void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) +{ + if (!list_empty(&fb_helper->kernel_fb_list)) { + list_del(&fb_helper->kernel_fb_list); + if (list_empty(&kernel_fb_helper_list)) { + printk(KERN_INFO "drm: unregistered panic notifier\n"); + atomic_notifier_chain_unregister(&panic_notifier_list, + &paniced); + unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); + } + } + + drm_fb_helper_crtc_free(fb_helper); + +} +EXPORT_SYMBOL(drm_fb_helper_fini); static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, u16 regno, struct fb_info *info) @@ -567,36 +587,6 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) } EXPORT_SYMBOL(drm_fb_helper_setcmap); -int drm_fb_helper_setcolreg(unsigned regno, - unsigned red, - unsigned green, - unsigned blue, - unsigned transp, - struct fb_info *info) -{ - struct drm_fb_helper *fb_helper = info->par; - struct drm_crtc *crtc; - struct drm_crtc_helper_funcs *crtc_funcs; - int i; - int ret; - - if (regno > 255) - return 1; - - for (i = 0; i < fb_helper->crtc_count; i++) { - crtc = fb_helper->crtc_info[i].mode_set.crtc; - crtc_funcs = crtc->helper_private; - - ret = setcolreg(crtc, red, green, blue, regno, info); - if (ret) - return ret; - - crtc_funcs->load_lut(crtc); - } - return 0; -} -EXPORT_SYMBOL(drm_fb_helper_setcolreg); - int drm_fb_helper_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { @@ -710,6 +700,11 @@ int drm_fb_helper_set_par(struct fb_info *info) } } mutex_unlock(&dev->mode_config.mutex); + + if (fb_helper->delayed_hotplug) { + fb_helper->delayed_hotplug = false; + drm_fb_helper_hotplug_event(fb_helper); + } return 0; } EXPORT_SYMBOL(drm_fb_helper_set_par); @@ -751,7 +746,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, { int new_fb = 0; int crtc_count = 0; - int ret, i; + int i; struct fb_info *info; struct drm_fb_helper_surface_size sizes; int gamma_size = 0; @@ -821,11 +816,13 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { /* hmm everyone went away - assume VGA cable just fell out and will come back later. */ - return 0; + DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n"); + sizes.fb_width = sizes.surface_width = 1024; + sizes.fb_height = sizes.surface_height = 768; } /* push down into drivers */ - new_fb = (*fb_helper->fb_probe)(fb_helper, &sizes); + new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes); if (new_fb < 0) return new_fb; @@ -838,11 +835,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, if (new_fb) { info->var.pixclock = 0; - ret = fb_alloc_cmap(&info->cmap, gamma_size, 0); - if (ret) - return ret; if (register_framebuffer(info) < 0) { - fb_dealloc_cmap(&info->cmap); return -EINVAL; } @@ -856,7 +849,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, /* Switch back to kernel console on panic */ /* multi card linked list maybe */ if (list_empty(&kernel_fb_helper_list)) { - printk(KERN_INFO "registered panic notifier\n"); + printk(KERN_INFO "drm: registered panic notifier\n"); atomic_notifier_chain_register(&panic_notifier_list, &paniced); register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); @@ -868,23 +861,6 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, } EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); -void drm_fb_helper_free(struct drm_fb_helper *helper) -{ - if (!list_empty(&helper->kernel_fb_list)) { - list_del(&helper->kernel_fb_list); - if (list_empty(&kernel_fb_helper_list)) { - printk(KERN_INFO "unregistered panic notifier\n"); - atomic_notifier_chain_unregister(&panic_notifier_list, - &paniced); - unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); - } - } - drm_fb_helper_crtc_free(helper); - if (helper->fbdev->cmap.len) - fb_dealloc_cmap(&helper->fbdev->cmap); -} -EXPORT_SYMBOL(drm_fb_helper_free); - void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, uint32_t depth) { @@ -1094,6 +1070,79 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper, } } +static bool drm_target_cloned(struct drm_fb_helper *fb_helper, + struct drm_display_mode **modes, + 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->crtc_count > 1) + return false; + + count = 0; + for (i = 0; i < fb_helper->connector_count; i++) { + if (enabled[i]) + count++; + } + + /* only contemplate cloning if more than one connector is enabled */ + if (count <= 1) + return false; + + /* check the command line or if nothing common pick 1024x768 */ + can_clone = true; + for (i = 0; i < fb_helper->connector_count; i++) { + if (!enabled[i]) + continue; + fb_helper_conn = fb_helper->connector_info[i]; + modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); + if (!modes[i]) { + can_clone = false; + break; + } + for (j = 0; j < i; j++) { + if (!enabled[j]) + continue; + if (!drm_mode_equal(modes[j], modes[i])) + can_clone = false; + } + } + + if (can_clone) { + DRM_DEBUG_KMS("can clone using command line\n"); + return true; + } + + /* try and find a 1024x768 mode on each connector */ + can_clone = true; + dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60); + + for (i = 0; i < fb_helper->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) { + if (drm_mode_equal(mode, dmt_mode)) + modes[i] = mode; + } + if (!modes[i]) + can_clone = false; + } + + if (can_clone) { + DRM_DEBUG_KMS("can clone using 1024x768\n"); + return true; + } + DRM_INFO("kms: can't enable cloning when we probably wanted to.\n"); + return false; +} + static bool drm_target_preferred(struct drm_fb_helper *fb_helper, struct drm_display_mode **modes, bool *enabled, int width, int height) @@ -1187,8 +1236,12 @@ static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, break; if (o < n) { - /* ignore cloning for now */ - continue; + /* ignore cloning unless only a single crtc */ + if (fb_helper->crtc_count > 1) + continue; + + if (!drm_mode_equal(modes[o], modes[n])) + continue; } crtcs[n] = crtc; @@ -1238,9 +1291,12 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) drm_enable_connectors(fb_helper, enabled); - ret = drm_target_preferred(fb_helper, modes, enabled, width, height); - if (!ret) - DRM_ERROR("Unable to find initial modes\n"); + ret = drm_target_cloned(fb_helper, modes, enabled, width, height); + if (!ret) { + ret = drm_target_preferred(fb_helper, modes, enabled, width, height); + if (!ret) + DRM_ERROR("Unable to find initial modes\n"); + } DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); @@ -1289,7 +1345,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) * RETURNS: * Zero if everything went ok, nonzero otherwise. */ -bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) +bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) { struct drm_device *dev = fb_helper->dev; int count = 0; @@ -1302,29 +1358,50 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) count = drm_fb_helper_probe_connector_modes(fb_helper, dev->mode_config.max_width, dev->mode_config.max_height); - /* * we shouldn't end up with no modes here. */ - if (count == 0) + if (count == 0) { printk(KERN_INFO "No connectors reported connected with modes\n"); - + } drm_setup_crtcs(fb_helper); - return 0; + return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); } EXPORT_SYMBOL(drm_fb_helper_initial_config); -bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, - u32 max_width, u32 max_height) +bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) { + int count = 0; + u32 max_width, max_height, bpp_sel; + bool bound = false, crtcs_bound = false; + struct drm_crtc *crtc; + + if (!fb_helper->fb) + return false; + + list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) { + if (crtc->fb) + crtcs_bound = true; + if (crtc->fb == fb_helper->fb) + bound = true; + } + + if (!bound && crtcs_bound) { + fb_helper->delayed_hotplug = true; + return false; + } DRM_DEBUG_KMS("\n"); - drm_fb_helper_probe_connector_modes(fb_helper, max_width, - max_height); + max_width = fb_helper->fb->width; + max_height = fb_helper->fb->height; + bpp_sel = fb_helper->fb->bits_per_pixel; + count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, + max_height); drm_setup_crtcs(fb_helper); - return true; + return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); } -EXPORT_SYMBOL(drm_helper_fb_hotplug_event); +EXPORT_SYMBOL(drm_fb_helper_hotplug_event); +