diff options
-rw-r--r-- | drivers/gpu/drm/drm_crtc_helper.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 329 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_fb.c | 93 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.c | 121 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_fbcon.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_fbcon.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_fb.c | 240 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 4 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 5 | ||||
-rw-r--r-- | include/drm/drm_fb_helper.h | 21 |
13 files changed, 411 insertions, 447 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 9d23f54673d..b142ac260d9 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -625,10 +625,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ret = -EINVAL; goto fail; } - /* TODO are these needed? */ - set->crtc->desired_x = set->x; - set->crtc->desired_y = set->y; - set->crtc->desired_mode = set->mode; } drm_helper_disable_unused_functions(dev); } else if (fb_changed) { diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 055b5be7887..2515563063c 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -292,6 +292,7 @@ static void drm_fb_helper_on(struct fb_info *info) struct drm_fb_helper *fb_helper = info->par; struct drm_device *dev = fb_helper->dev; struct drm_crtc *crtc; + struct drm_crtc_helper_funcs *crtc_funcs; struct drm_encoder *encoder; int i; @@ -299,33 +300,28 @@ static void drm_fb_helper_on(struct fb_info *info) * For each CRTC in this fb, turn the crtc on then, * find all associated encoders and turn them on. */ + mutex_lock(&dev->mode_config.mutex); for (i = 0; i < fb_helper->crtc_count; i++) { - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_crtc_helper_funcs *crtc_funcs = - crtc->helper_private; + crtc = fb_helper->crtc_info[i].mode_set.crtc; + crtc_funcs = crtc->helper_private; - /* Only mess with CRTCs in this fb */ - if (crtc->base.id != fb_helper->crtc_info[i].crtc_id || - !crtc->enabled) - continue; + if (!crtc->enabled) + continue; + + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); - mutex_lock(&dev->mode_config.mutex); - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); - mutex_unlock(&dev->mode_config.mutex); - /* Found a CRTC on this fb, now find encoders */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - struct drm_encoder_helper_funcs *encoder_funcs; + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; - encoder_funcs = encoder->helper_private; - mutex_lock(&dev->mode_config.mutex); - encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); - mutex_unlock(&dev->mode_config.mutex); - } + encoder_funcs = encoder->helper_private; + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); } } } + mutex_unlock(&dev->mode_config.mutex); } static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) @@ -333,6 +329,7 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) struct drm_fb_helper *fb_helper = info->par; struct drm_device *dev = fb_helper->dev; struct drm_crtc *crtc; + struct drm_crtc_helper_funcs *crtc_funcs; struct drm_encoder *encoder; int i; @@ -340,32 +337,26 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) * For each CRTC in this fb, find all associated encoders * and turn them off, then turn off the CRTC. */ + mutex_lock(&dev->mode_config.mutex); for (i = 0; i < fb_helper->crtc_count; i++) { - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_crtc_helper_funcs *crtc_funcs = - crtc->helper_private; + crtc = fb_helper->crtc_info[i].mode_set.crtc; + crtc_funcs = crtc->helper_private; - /* Only mess with CRTCs in this fb */ - if (crtc->base.id != fb_helper->crtc_info[i].crtc_id || - !crtc->enabled) - continue; + if (!crtc->enabled) + continue; - /* Found a CRTC on this fb, now find encoders */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - struct drm_encoder_helper_funcs *encoder_funcs; + /* Found a CRTC on this fb, now find encoders */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + struct drm_encoder_helper_funcs *encoder_funcs; - encoder_funcs = encoder->helper_private; - mutex_lock(&dev->mode_config.mutex); - encoder_funcs->dpms(encoder, dpms_mode); - mutex_unlock(&dev->mode_config.mutex); - } + encoder_funcs = encoder->helper_private; + encoder_funcs->dpms(encoder, dpms_mode); } - mutex_lock(&dev->mode_config.mutex); - crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); - mutex_unlock(&dev->mode_config.mutex); } + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); } + mutex_unlock(&dev->mode_config.mutex); } int drm_fb_helper_blank(int blank, struct fb_info *info) @@ -405,17 +396,19 @@ 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_fb_helper *helper, int crtc_count, int max_conn_count) +int drm_fb_helper_init_crtc_count(struct drm_device *dev, + struct drm_fb_helper *helper, + int crtc_count, int max_conn_count) { - struct drm_device *dev = helper->dev; 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) return -ENOMEM; - helper->crtc_count = crtc_count; for (i = 0; i < crtc_count; i++) { @@ -507,20 +500,15 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; - struct drm_device *dev = fb_helper->dev; + struct drm_crtc_helper_funcs *crtc_funcs; u16 *red, *green, *blue, *transp; struct drm_crtc *crtc; int i, rc = 0; int start; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - for (i = 0; i < fb_helper->crtc_count; i++) { - if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) - break; - } - if (i == fb_helper->crtc_count) - continue; + for (i = 0; i < fb_helper->crtc_count; i++) { + crtc = fb_helper->crtc_info[i].mode_set.crtc; + crtc_funcs = crtc->helper_private; red = cmap->red; green = cmap->green; @@ -556,22 +544,17 @@ int drm_fb_helper_setcolreg(unsigned regno, struct fb_info *info) { struct drm_fb_helper *fb_helper = info->par; - struct drm_device *dev = fb_helper->dev; struct drm_crtc *crtc; + struct drm_crtc_helper_funcs *crtc_funcs; int i; int ret; if (regno > 255) return 1; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - for (i = 0; i < fb_helper->crtc_count; i++) { - if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) - break; - } - if (i == fb_helper->crtc_count) - continue; + 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) @@ -686,23 +669,20 @@ int drm_fb_helper_set_par(struct fb_info *info) return -EINVAL; } - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - - for (i = 0; i < fb_helper->crtc_count; i++) { - if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) - break; - } - if (i == fb_helper->crtc_count) - continue; + mutex_lock(&dev->mode_config.mutex); + for (i = 0; i < fb_helper->crtc_count; i++) { + crtc = fb_helper->crtc_info[i].mode_set.crtc; - if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) { - mutex_lock(&dev->mode_config.mutex); + if (crtc->fb != fb_helper->crtc_info[i].mode_set.fb) { ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); - mutex_unlock(&dev->mode_config.mutex); - if (ret) + + if (ret) { + mutex_unlock(&dev->mode_config.mutex); return ret; + } } } + mutex_unlock(&dev->mode_config.mutex); return 0; } EXPORT_SYMBOL(drm_fb_helper_set_par); @@ -717,14 +697,9 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, int ret = 0; int i; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - for (i = 0; i < fb_helper->crtc_count; i++) { - if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) - break; - } - - if (i == fb_helper->crtc_count) - continue; + mutex_lock(&dev->mode_config.mutex); + for (i = 0; i < fb_helper->crtc_count; i++) { + crtc = fb_helper->crtc_info[i].mode_set.crtc; modeset = &fb_helper->crtc_info[i].mode_set; @@ -732,34 +707,29 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, modeset->y = var->yoffset; if (modeset->num_connectors) { - mutex_lock(&dev->mode_config.mutex); ret = crtc->funcs->set_config(modeset); - mutex_unlock(&dev->mode_config.mutex); if (!ret) { info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; } } } + mutex_unlock(&dev->mode_config.mutex); return ret; } EXPORT_SYMBOL(drm_fb_helper_pan_display); -int drm_fb_helper_single_fb_probe(struct drm_device *dev, - int preferred_bpp, - int (*fb_find_or_create)(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct drm_fb_helper **fb_ptr)) +int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, + int preferred_bpp) { - struct drm_crtc *crtc; + struct drm_device *dev = fb_helper->dev; struct drm_connector *connector; int new_fb = 0; int crtc_count = 0; - int ret, i, conn_count = 0; + int ret, i; struct fb_info *info; - struct drm_mode_set *modeset = NULL; - struct drm_fb_helper *fb_helper; struct drm_fb_helper_surface_size sizes; + int gamma_size = 0; memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); sizes.surface_depth = 24; @@ -775,7 +745,6 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, /* first up get a count of crtcs now in use and new min/maxes width/heights */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; - struct drm_fb_helper_cmdline_mode *cmdline_mode; if (!fb_help_conn) @@ -807,21 +776,22 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, } } - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (drm_helper_crtc_in_use(crtc)) { - if (crtc->desired_mode) { - if (crtc->desired_mode->hdisplay < sizes.fb_width) - sizes.fb_width = crtc->desired_mode->hdisplay; - - if (crtc->desired_mode->vdisplay < sizes.fb_height) - sizes.fb_height = crtc->desired_mode->vdisplay; - - if (crtc->desired_mode->hdisplay > sizes.surface_width) - sizes.surface_width = crtc->desired_mode->hdisplay; - - if (crtc->desired_mode->vdisplay > sizes.surface_height) - sizes.surface_height = crtc->desired_mode->vdisplay; - } + crtc_count = 0; + for (i = 0; i < fb_helper->crtc_count; i++) { + struct drm_display_mode *desired_mode; + desired_mode = fb_helper->crtc_info[i].desired_mode; + + if (desired_mode) { + if (gamma_size == 0) + gamma_size = fb_helper->crtc_info[i].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) + sizes.fb_height = desired_mode->vdisplay; + if (desired_mode->hdisplay > sizes.surface_width) + sizes.surface_width = desired_mode->hdisplay; + if (desired_mode->vdisplay > sizes.surface_height) + sizes.surface_height = desired_mode->vdisplay; crtc_count++; } } @@ -833,48 +803,20 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev, } /* push down into drivers */ - new_fb = (*fb_find_or_create)(dev, &sizes, - &fb_helper); + new_fb = (*fb_helper->fb_probe)(fb_helper, &sizes); if (new_fb < 0) return new_fb; info = fb_helper->fbdev; - crtc_count = 0; - /* okay we need to setup new connector sets in the crtcs */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - modeset = &fb_helper->crtc_info[crtc_count].mode_set; - modeset->fb = fb_helper->fb; - conn_count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder) - if (connector->encoder->crtc == modeset->crtc) { - modeset->connectors[conn_count] = connector; - conn_count++; - if (conn_count > fb_helper->conn_limit) - BUG(); - } - } - - for (i = conn_count; i < fb_helper->conn_limit; i++) - modeset->connectors[i] = NULL; - - modeset->crtc = crtc; - crtc_count++; - - modeset->num_connectors = conn_count; - if (modeset->crtc->desired_mode) { - if (modeset->mode) - drm_mode_destroy(dev, modeset->mode); - modeset->mode = drm_mode_duplicate(dev, - modeset->crtc->desired_mode); - } + /* set the fb pointer */ + for (i = 0; i < fb_helper->crtc_count; i++) { + fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb; } - fb_helper->crtc_count = crtc_count; if (new_fb) { info->var.pixclock = 0; - ret = fb_alloc_cmap(&info->cmap, modeset->crtc->gamma_size, 0); + ret = fb_alloc_cmap(&info->cmap, gamma_size, 0); if (ret) return ret; if (register_framebuffer(info) < 0) { @@ -906,15 +848,18 @@ EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); void drm_fb_helper_free(struct drm_fb_helper *helper) { - 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); + 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); - fb_dealloc_cmap(&helper->fbdev->cmap); + if (helper->fbdev->cmap.len) + fb_dealloc_cmap(&helper->fbdev->cmap); } EXPORT_SYMBOL(drm_fb_helper_free); @@ -1168,20 +1113,21 @@ static bool drm_target_preferred(struct drm_device *dev, return true; } -static int drm_pick_crtcs(struct drm_device *dev, - struct drm_crtc **best_crtcs, +static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, + struct drm_fb_helper_crtc **best_crtcs, struct drm_display_mode **modes, int n, int width, int height) { int c, o; + struct drm_device *dev = fb_helper->dev; struct drm_connector *connector; struct drm_connector_helper_funcs *connector_funcs; struct drm_encoder *encoder; - struct drm_crtc *best_crtc; + struct drm_fb_helper_crtc *best_crtc; int my_score, best_score, score; - struct drm_crtc **crtcs, *crtc; + struct drm_fb_helper_crtc **crtcs, *crtc; - if (n == dev->mode_config.num_connector) + if (n == fb_helper->dev->mode_config.num_connector) return 0; c = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -1192,12 +1138,12 @@ static int drm_pick_crtcs(struct drm_device *dev, best_crtcs[n] = NULL; best_crtc = NULL; - best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); + best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height); if (modes[n] == NULL) return best_score; - crtcs = kmalloc(dev->mode_config.num_connector * - sizeof(struct drm_crtc *), GFP_KERNEL); + crtcs = kzalloc(dev->mode_config.num_connector * + sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); if (!crtcs) return best_score; @@ -1214,15 +1160,12 @@ static int drm_pick_crtcs(struct drm_device *dev, if (!encoder) goto out; - connector->encoder = encoder; - /* select a crtc for this connector and then attempt to configure remaining connectors */ - c = 0; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + for (c = 0; c < fb_helper->crtc_count; c++) { + crtc = &fb_helper->crtc_info[c]; if ((encoder->possible_crtcs & (1 << c)) == 0) { - c++; continue; } @@ -1232,34 +1175,34 @@ static int drm_pick_crtcs(struct drm_device *dev, if (o < n) { /* ignore cloning for now */ - c++; continue; } crtcs[n] = crtc; - memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *)); - score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1, + memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *)); + score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1, width, height); if (score > best_score) { best_crtc = crtc; best_score = score; memcpy(best_crtcs, crtcs, dev->mode_config.num_connector * - sizeof(struct drm_crtc *)); + sizeof(struct drm_fb_helper_crtc *)); } - c++; } out: kfree(crtcs); return best_score; } -static void drm_setup_crtcs(struct drm_device *dev) +static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) { - struct drm_crtc **crtcs; + struct drm_device *dev = fb_helper->dev; + struct drm_fb_helper_crtc **crtcs; struct drm_display_mode **modes; struct drm_encoder *encoder; struct drm_connector *connector; + struct drm_mode_set *modeset; bool *enabled; int width, height; int i, ret; @@ -1275,7 +1218,7 @@ static void drm_setup_crtcs(struct drm_device *dev) } crtcs = kcalloc(dev->mode_config.num_connector, - sizeof(struct drm_crtc *), GFP_KERNEL); + sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); modes = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_display_mode *), GFP_KERNEL); enabled = kcalloc(dev->mode_config.num_connector, @@ -1289,26 +1232,30 @@ static void drm_setup_crtcs(struct drm_device *dev) DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); - drm_pick_crtcs(dev, crtcs, modes, 0, width, height); + drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height); + + /* 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; + } i = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct drm_display_mode *mode = modes[i]; - struct drm_crtc *crtc = crtcs[i]; - - if (connector->encoder == NULL) { - i++; - continue; - } + struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; + modeset = &fb_crtc->mode_set; - if (mode && crtc) { + if (mode && fb_crtc) { DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", - mode->name, crtc->base.id); - crtc->desired_mode = mode; - connector->encoder->crtc = crtc; - } else { - connector->encoder->crtc = NULL; - connector->encoder = NULL; + mode->name, fb_crtc->mode_set.crtc->base.id); + fb_crtc->desired_mode = mode; + if (modeset->mode) + drm_mode_destroy(dev, modeset->mode); + modeset->mode = drm_mode_duplicate(dev, + fb_crtc->desired_mode); + modeset->connectors[modeset->num_connectors++] = connector; } i++; } @@ -1332,14 +1279,15 @@ static void drm_setup_crtcs(struct drm_device *dev) * RETURNS: * Zero if everything went ok, nonzero otherwise. */ -bool drm_helper_initial_config(struct drm_device *dev) +bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) { + struct drm_device *dev = fb_helper->dev; int count = 0; /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); + drm_helper_disable_unused_functions(fb_helper->dev); - drm_fb_helper_parse_command_line(dev); + drm_fb_helper_parse_command_line(fb_helper->dev); count = drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, @@ -1351,20 +1299,21 @@ bool drm_helper_initial_config(struct drm_device *dev) if (count == 0) printk(KERN_INFO "No connectors reported connected with modes\n"); - drm_setup_crtcs(dev); + drm_setup_crtcs(fb_helper); return 0; } -EXPORT_SYMBOL(drm_helper_initial_config); +EXPORT_SYMBOL(drm_fb_helper_initial_config); -bool drm_helper_fb_hotplug_event(struct drm_device *dev) +bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, + u32 max_width, u32 max_height) { DRM_DEBUG_KMS("\n"); - drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, - dev->mode_config.max_height); + drm_helper_probe_connector_modes(fb_helper->dev, max_width, + max_height); - drm_setup_crtcs(dev); + drm_setup_crtcs(fb_helper); return true; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 601f354e467..0405a746059 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -220,7 +220,7 @@ enum no_fbc_reason { FBC_NOT_TILED, /* buffer not tiled */ }; -struct intel_kernel_fbdev; +struct intel_fbdev; typedef struct drm_i915_private { struct drm_device *dev; @@ -630,7 +630,8 @@ typedef struct drm_i915_private { enum no_fbc_reason no_fbc_reason; - struct intel_kernel_fbdev *fbdev; + /* list of fbdev register on this device */ + struct intel_fbdev *fbdev; } drm_i915_private_t; /** driver private structure attached to each drm_gem_object */ diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index b0de9bbde34..ff6912edf0c 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -45,7 +45,7 @@ #include "i915_drm.h" #include "i915_drv.h" -struct intel_kernel_fbdev { +struct intel_fbdev { struct drm_fb_helper helper; struct intel_framebuffer ifb; struct list_head fbdev_list; @@ -71,14 +71,12 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = { }; -static int intelfb_create(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct intel_kernel_fbdev **ifbdev_p) +static int intelfb_create(struct intel_fbdev *ifbdev, + struct drm_fb_helper_surface_size *sizes) { + struct drm_device *dev = ifbdev->helper.dev; struct fb_info *info; - struct intel_kernel_fbdev *ifbdev; struct drm_framebuffer *fb; - struct intel_framebuffer *intel_fb; struct drm_mode_fb_cmd mode_cmd; struct drm_gem_object *fbo = NULL; struct drm_i915_gem_object *obj_priv; @@ -117,13 +115,14 @@ static int intelfb_create(struct drm_device *dev, /* Flush everything out, we'll be doing GTT only from now on */ i915_gem_object_set_to_gtt_domain(fbo, 1); - info = framebuffer_alloc(sizeof(struct intel_kernel_fbdev), device); + info = framebuffer_alloc(0, device); if (!info) { ret = -ENOMEM; goto out_unpin; } - ifbdev = info->par; + info->par = ifbdev; + intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo); fb = &ifbdev->ifb.base; @@ -131,22 +130,12 @@ static int intelfb_create(struct drm_device *dev, ifbdev->helper.fb = fb; ifbdev->helper.fbdev = info; ifbdev->helper.funcs = &intel_fb_helper_funcs; - ifbdev->helper.dev = dev; - - *ifbdev_p = ifbdev; - - ret = drm_fb_helper_init_crtc_count(&ifbdev->helper, 2, - INTELFB_CONN_LIMIT); - if (ret) - goto out_unref; strcpy(info->fix.id, "inteldrmfb"); info->flags = FBINFO_DEFAULT; - info->fbops = &intelfb_ops; - /* setup aperture base/size for vesafb takeover */ info->aperture_base = dev->mode_config.fb_base; if (IS_I9XX(dev)) @@ -183,8 +172,8 @@ static int intelfb_create(struct drm_device *dev, info->pixmap.scan_align = 1; DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", - intel_fb->base.width, intel_fb->base.height, - obj_priv->gtt_offset, fbo); + fb->width, fb->height, + obj_priv->gtt_offset, fbo); mutex_unlock(&dev->struct_mutex); @@ -200,76 +189,80 @@ out: return ret; } -static int intel_fb_find_or_create_single(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct drm_fb_helper **fb_ptr) +static int intel_fb_find_or_create_single(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) { - drm_i915_private_t *dev_priv = dev->dev_private; - struct intel_kernel_fbdev *ifbdev = NULL; + struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper; int new_fb = 0; int ret; - if (!dev_priv->fbdev) { - ret = intelfb_create(dev, sizes, - &ifbdev); + if (!helper->fb) { + ret = intelfb_create(ifbdev, sizes); if (ret) return ret; - - dev_priv->fbdev = ifbdev; new_fb = 1; - } else { - ifbdev = dev_priv->fbdev; - if (ifbdev->ifb.base.width < sizes->surface_width || - ifbdev->ifb.base.height < sizes->surface_height) { - DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); - return -EINVAL; - } } - - *fb_ptr = &ifbdev->helper; return new_fb; } -static int intelfb_probe(struct drm_device *dev) +static int intelfb_probe(struct intel_fbdev *ifbdev) { int ret; DRM_DEBUG_KMS("\n"); - ret = drm_fb_helper_single_fb_probe(dev, 32, intel_fb_find_or_create_single); + ret = drm_fb_helper_single_fb_probe(&ifbdev->helper, 32); return ret; } int intel_fbdev_destroy(struct drm_device *dev, - struct intel_kernel_fbdev *ifbdev) + struct intel_fbdev *ifbdev) { struct fb_info *info; struct intel_framebuffer *ifb = &ifbdev->ifb; - info = ifbdev->helper.fbdev; + if (ifbdev->helper.fbdev) { + info = ifbdev->helper.fbdev; + unregister_framebuffer(info); + iounmap(info->screen_base); + framebuffer_release(info); + } - unregister_framebuffer(info); - iounmap(info->screen_base); drm_fb_helper_free(&ifbdev->helper); drm_framebuffer_cleanup(&ifb->base); - drm_gem_object_unreference_unlocked(ifb->obj); - - framebuffer_release(info); + if (ifb->obj) + drm_gem_object_unreference_unlocked(ifb->obj); return 0; } int intel_fbdev_init(struct drm_device *dev) { - drm_helper_initial_config(dev); - intelfb_probe(dev); + struct intel_fbdev *ifbdev; + drm_i915_private_t *dev_priv = dev->dev_private; + + ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL); + if (!ifbdev) + return -ENOMEM; + + dev_priv->fbdev = ifbdev; + + drm_fb_helper_init_crtc_count(dev, &ifbdev->helper, 2, + INTELFB_CONN_LIMIT); + ifbdev->helper.fb_probe = intel_fb_find_or_create_single; + drm_fb_helper_initial_config(&ifbdev->helper); + intelfb_probe(ifbdev); return 0; } void intel_fbdev_fini(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; + if (!dev_priv->fbdev) + return; + intel_fbdev_destroy(dev, dev_priv->fbdev); + kfree(dev_priv->fbdev); dev_priv->fbdev = NULL; } MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 93459e07e82..941339cb8d8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -627,7 +627,7 @@ struct drm_nouveau_private { struct dentry *channel_root; } debugfs; - struct nouveau_fbcon_par *nfbdev; + struct nouveau_fbdev *nfbdev; }; static inline struct drm_nouveau_private * diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 712ee42e3cf..90843b62d9b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -53,8 +53,8 @@ static int nouveau_fbcon_sync(struct fb_info *info) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; int ret, i; @@ -200,9 +200,9 @@ not_fb: #endif static void -nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) +nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *nfbdev) { - struct fb_info *info = fbpar->helper.fbdev; + struct fb_info *info = nfbdev->helper.fbdev; struct fb_fillrect rect; /* Clear the entire fbcon. The drm will program every connector @@ -218,13 +218,12 @@ nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) } static int -nouveau_fbcon_create(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct nouveau_fbcon_par **fbpar_p) +nouveau_fbcon_create(struct nouveau_fbdev *nfbdev, + struct drm_fb_helper_surface_size *sizes) { + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct fb_info *info; - struct nouveau_fbcon_par *par; struct drm_framebuffer *fb; struct nouveau_framebuffer *nouveau_fb; struct nouveau_bo *nvbo; @@ -267,27 +266,23 @@ nouveau_fbcon_create(struct drm_device *dev, mutex_lock(&dev->struct_mutex); - info = framebuffer_alloc(sizeof(struct nouveau_fbcon_par), device); + info = framebuffer_alloc(0, device); if (!info) { ret = -ENOMEM; goto out_unref; } - par = info->par; - nouveau_framebuffer_init(dev, &par->nouveau_fb, &mode_cmd, nvbo); + info->par = nfbdev; - fb = &par->nouveau_fb.base; - /* setup helper */ - par->helper.fb = fb; - par->helper.fbdev = info; - par->helper.funcs = &nouveau_fbcon_helper_funcs; - par->helper.dev = dev; + nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo); - *fbpar_p = par; + nouveau_fb = &nfbdev->nouveau_fb; + fb = &nouveau_fb->base; - ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 4); - if (ret) - goto out_unref; + /* setup helper */ + nfbdev->helper.fb = fb; + nfbdev->helper.fbdev = info; + nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs; strcpy(info->fix.id, "nouveaufb"); if (nouveau_nofbaccel) @@ -305,7 +300,7 @@ nouveau_fbcon_create(struct drm_device *dev, info->screen_size = size; drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); - drm_fb_helper_fill_var(info, &par->helper, sizes->fb_width, sizes->fb_height); + drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height); /* FIXME: we really shouldn't expose mmio space at all */ info->fix.mmio_start = pci_resource_start(dev->pdev, 1); @@ -338,8 +333,6 @@ nouveau_fbcon_create(struct drm_device *dev, info->pixmap.flags = FB_PIXMAP_SYSTEM; info->pixmap.scan_align = 1; - par->dev = dev; - if (dev_priv->channel && !nouveau_nofbaccel) { switch (dev_priv->card_type) { case NV_50: @@ -353,7 +346,7 @@ nouveau_fbcon_create(struct drm_device *dev, }; } - nouveau_fbcon_zfill(dev, par); + nouveau_fbcon_zfill(dev, nfbdev); /* To allow resizeing without swapping buffers */ NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n", @@ -372,66 +365,56 @@ out: } static int -nouveau_fbcon_find_or_create_single(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct drm_fb_helper **fb_ptr) +nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_fbcon_par *fbpar; + struct nouveau_fbdev *nfbdev = (struct nouveau_fbdev *)helper; int new_fb = 0; int ret; - if (!dev_priv->nfbdev) { - ret = nouveau_fbcon_create(dev, sizes, - &fbpar); + if (!helper->fb) { + ret = nouveau_fbcon_create(nfbdev, sizes); if (ret) return ret; - dev_priv->nfbdev = fbpar; new_fb = 1; - } else { - fbpar = dev_priv->nfbdev; - if (fbpar->nouveau_fb.base.width < sizes->surface_width || - fbpar->nouveau_fb.base.height < sizes->surface_height) { - DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); - return -EINVAL; - } } - *fb_ptr = &fbpar->helper; return new_fb; } static int -nouveau_fbcon_probe(struct drm_device *dev) +nouveau_fbcon_probe(struct nouveau_fbdev *nfbdev) { - NV_DEBUG_KMS(dev, "\n"); + NV_DEBUG_KMS(nfbdev->dev, "\n"); - return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_find_or_create_single); + return drm_fb_helper_single_fb_probe(&nfbdev->helper, 32); } int -nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) +nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev) { - struct nouveau_framebuffer *nouveau_fb = &fbpar->nouveau_fb; + struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb; struct fb_info *info; - info = fbpar->helper.fbdev; - - unregister_framebuffer(info); - nouveau_bo_unmap(nouveau_fb->nvbo); - drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); - nouveau_fb->nvbo = NULL; - drm_fb_helper_free(&fbpar->helper); + if (nfbdev->helper.fbdev) { + info = nfbdev->helper.fbdev; + unregister_framebuffer(info); + framebuffer_release(info); + } + if (nouveau_fb->nvbo) { + nouveau_bo_unmap(nouveau_fb->nvbo); + drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); + nouveau_fb->nvbo = NULL; + } + drm_fb_helper_free(&nfbdev->helper); drm_framebuffer_cleanup(&nouveau_fb->base); - framebuffer_release(info); - return 0; } void nouveau_fbcon_gpu_lockup(struct fb_info *info) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); info->flags |= FBINFO_HWACCEL_DISABLED; @@ -439,15 +422,33 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info) int nouveau_fbcon_init(struct drm_device *dev) { - drm_helper_initial_config(dev); - nouveau_fbcon_probe(dev); + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fbdev *nfbdev; + + nfbdev = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL); + if (!nfbdev) + return -ENOMEM; + + nfbdev->dev = dev; + dev_priv->nfbdev = nfbdev; + + drm_fb_helper_init_crtc_count(dev, &nfbdev->helper, + 2, 4); + nfbdev->helper.fb_probe = nouveau_fbcon_find_or_create_single; + drm_fb_helper_initial_config(&nfbdev->helper); + nouveau_fbcon_probe(nfbdev); return 0; } void nouveau_fbcon_fini(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (!dev_priv->nfbdev) + return; + nouveau_fbcon_destroy(dev, dev_priv->nfbdev); + kfree(dev_priv->nfbdev); dev_priv->nfbdev = NULL; } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index fa66cb9fa4d..7835b568555 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -30,7 +30,7 @@ #include "drm_fb_helper.h" #include "nouveau_fb.h" -struct nouveau_fbcon_par { +struct nouveau_fbdev { struct drm_fb_helper helper; struct nouveau_framebuffer nouveau_fb; struct list_head fbdev_list; diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index 813b25cec72..603090ee6ac 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -30,8 +30,8 @@ void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; @@ -57,8 +57,8 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; @@ -91,8 +91,8 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; uint32_t fg; @@ -179,8 +179,8 @@ nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle) int nv04_fbcon_accel_init(struct fb_info *info) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; const int sub = NvSubCtxSurf2D; diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 25a3cd8794f..f2410489cd3 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -6,8 +6,8 @@ void nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; @@ -49,8 +49,8 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) void nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; @@ -84,8 +84,8 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; uint32_t width, dwords, *data = (uint32_t *)image->data; @@ -152,8 +152,8 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) int nv50_fbcon_accel_init(struct fb_info *info) { - struct nouveau_fbcon_par *par = info->par; - struct drm_device *dev = par->dev; + struct nouveau_fbdev *nfbdev = info->par; + struct drm_device *dev = nfbdev->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->channel; struct nouveau_gpuobj *eng2d = NULL; diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index a7e4c2a89ee..705425defba 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -23,10 +23,6 @@ * Authors: * David Airlie */ - /* - * Modularization - */ - #include <linux/module.h> #include <linux/fb.h> @@ -45,7 +41,7 @@ this contains a helper + a radeon fb the helper contains a pointer to radeon framebuffer baseclass. */ -struct radeon_kernel_fbdev { +struct radeon_fbdev { struct drm_fb_helper helper; struct radeon_framebuffer rfb; struct list_head fbdev_list; @@ -95,49 +91,44 @@ static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { .gamma_get = radeon_crtc_fb_gamma_get, }; -static int radeonfb_create(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct radeon_kernel_fbdev **rfbdev_p) +static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj) { - struct radeon_device *rdev = dev->dev_private; - struct fb_info *info; - struct radeon_kernel_fbdev *rfbdev; - struct drm_framebuffer *fb = NULL; - struct drm_mode_fb_cmd mode_cmd; + struct radeon_bo *rbo = gobj->driver_private; + int ret; + + ret = radeon_bo_reserve(rbo, false); + if (likely(ret == 0)) { + radeon_bo_kunmap(rbo); + radeon_bo_unreserve(rbo); + } + drm_gem_object_unreference_unlocked(gobj); +} + +static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev, + struct drm_mode_fb_cmd *mode_cmd, + struct drm_gem_object **gobj_p) +{ + struct radeon_device *rdev = rfbdev->rdev; struct drm_gem_object *gobj = NULL; struct radeon_bo *rbo = NULL; - struct device *device = &rdev->pdev->dev; - int size, aligned_size, ret; - u64 fb_gpuaddr; - void *fbptr = NULL; - unsigned long tmp; bool fb_tiled = false; /* useful for testing */ u32 tiling_flags = 0; + int ret; + int aligned_size, size; - mode_cmd.width = sizes->surface_width; - mode_cmd.height = sizes->surface_height; - - /* avivo can't scanout real 24bpp */ - if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev)) - sizes->surface_bpp = 32; - - mode_cmd.bpp = sizes->surface_bpp; /* need to align pitch with crtc limits */ - mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8); - mode_cmd.depth = sizes->surface_depth; + mode_cmd->pitch = radeon_align_pitch(rdev, mode_cmd->width, mode_cmd->bpp, fb_tiled) * ((mode_cmd->bpp + 1) / 8); - size = mode_cmd.pitch * mode_cmd.height; + size = mode_cmd->pitch * mode_cmd->height; aligned_size = ALIGN(size, PAGE_SIZE); - ret = radeon_gem_object_create(rdev, aligned_size, 0, - RADEON_GEM_DOMAIN_VRAM, - false, ttm_bo_type_kernel, - &gobj); + RADEON_GEM_DOMAIN_VRAM, + false, ttm_bo_type_kernel, + &gobj); if (ret) { - printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n", - sizes->surface_width, sizes->surface_height); - ret = -ENOMEM; - goto out; + printk(KERN_ERR "failed to allocate framebuffer (%d)\n", + aligned_size); + return -ENOMEM; } rbo = gobj->driver_private; @@ -145,7 +136,7 @@ static int radeonfb_create(struct drm_device *dev, tiling_flags = RADEON_TILING_MACRO; #ifdef __BIG_ENDIAN - switch (mode_cmd.bpp) { + switch (mode_cmd->bpp) { case 32: tiling_flags |= RADEON_TILING_SWAP_32BIT; break; @@ -158,54 +149,82 @@ static int radeonfb_create(struct drm_device *dev, if (tiling_flags) { ret = radeon_bo_set_tiling_flags(rbo, - tiling_flags | RADEON_TILING_SURFACE, - mode_cmd.pitch); + tiling_flags | RADEON_TILING_SURFACE, + mode_cmd->pitch); if (ret) dev_err(rdev->dev, "FB failed to set tiling flags\n"); } - mutex_lock(&rdev->ddev->struct_mutex); + ret = radeon_bo_reserve(rbo, false); if (unlikely(ret != 0)) goto out_unref; - ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr); + ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, NULL); if (ret) { radeon_bo_unreserve(rbo); goto out_unref; } if (fb_tiled) radeon_bo_check_tiling(rbo, 0, 0); - ret = radeon_bo_kmap(rbo, &fbptr); + ret = radeon_bo_kmap(rbo, NULL); radeon_bo_unreserve(rbo); if (ret) { goto out_unref; } - info = framebuffer_alloc(sizeof(struct radeon_kernel_fbdev), device); + *gobj_p = gobj; + return 0; +out_unref: + radeonfb_destroy_pinned_object(gobj); + *gobj_p = NULL; + return ret; +} + +static int radeonfb_create(struct radeon_fbdev *rfbdev, + struct drm_fb_helper_surface_size *sizes) +{ + struct radeon_device *rdev = rfbdev->rdev; + struct fb_info *info; + struct drm_framebuffer *fb = NULL; + struct drm_mode_fb_cmd mode_cmd; + struct drm_gem_object *gobj = NULL; + struct radeon_bo *rbo = NULL; + struct device *device = &rdev->pdev->dev; + int ret; + unsigned long tmp; + + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; + + /* avivo can't scanout real 24bpp */ + if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev)) + sizes->surface_bpp = 32; + + mode_cmd.bpp = sizes->surface_bpp; + mode_cmd.depth = sizes->surface_depth; + + ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj); + rbo = gobj->driver_private; + + /* okay we have an object now allocate the framebuffer */ + info = framebuffer_alloc(0, device); if (info == NULL) { ret = -ENOMEM; goto out_unref; } - rfbdev = info->par; - rfbdev->rdev = rdev; - radeon_framebuffer_init(dev, &rfbdev->rfb, &mode_cmd, gobj); + info->par = rfbdev; + + radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj); + fb = &rfbdev->rfb.base; /* setup helper */ rfbdev->helper.fb = fb; rfbdev->helper.fbdev = info; rfbdev->helper.funcs = &radeon_fb_helper_funcs; - rfbdev->helper.dev = dev; - - *rfbdev_p = rfbdev; - ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc, - RADEONFB_CONN_LIMIT); - if (ret) - goto out_unref; - - memset_io(fbptr, 0x0, aligned_size); + memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo)); strcpy(info->fix.id, "radeondrmfb"); @@ -214,11 +233,11 @@ static int radeonfb_create(struct drm_device *dev, info->flags = FBINFO_DEFAULT; info->fbops = &radeonfb_ops; - tmp = fb_gpuaddr - rdev->mc.vram_start; + tmp = radeon_bo_gpu_offset(rbo) - rdev->mc.vram_start; info->fix.smem_start = rdev->mc.aper_base + tmp; - info->fix.smem_len = size; - info->screen_base = fbptr; - info->screen_size = size; + info->fix.smem_len = radeon_bo_size(rbo); + info->screen_base = rbo->kptr; + info->screen_size = radeon_bo_size(rbo); drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height); @@ -239,60 +258,40 @@ static int radeonfb_create(struct drm_device *dev, } DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); - DRM_INFO("size %lu\n", (unsigned long)size); + DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo)); DRM_INFO("fb depth is %d\n", fb->depth); DRM_INFO(" pitch is %d\n", fb->pitch); - - mutex_unlock(&rdev->ddev->struct_mutex); vga_switcheroo_client_fb_set(rdev->ddev->pdev, info); return 0; out_unref: if (rbo) { - ret = radeon_bo_reserve(rbo, false); - if (likely(ret == 0)) { - radeon_bo_kunmap(rbo); - radeon_bo_unreserve(rbo); - } + } if (fb && ret) { drm_gem_object_unreference(gobj); drm_framebuffer_cleanup(fb); kfree(fb); } - drm_gem_object_unreference(gobj); - mutex_unlock(&rdev->ddev->struct_mutex); + out: return ret; } -static int radeon_fb_find_or_create_single(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct drm_fb_helper **fb_ptr) +static int radeon_fb_find_or_create_single(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) { - struct radeon_device *rdev = dev->dev_private; - struct radeon_kernel_fbdev *rfbdev = NULL; + struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper; int new_fb = 0; int ret; - if (!rdev->mode_info.rfbdev) { - ret = radeonfb_create(dev, sizes, - &rfbdev); + if (!helper->fb) { + ret = radeonfb_create(rfbdev, sizes); if (ret) return ret; - rdev->mode_info.rfbdev = rfbdev; new_fb = 1; - } else { - rfbdev = rdev->mode_info.rfbdev; - if (rfbdev->rfb.base.width < sizes->surface_width || - rfbdev->rfb.base.height < sizes->surface_height) { - DRM_ERROR("Framebuffer not large enough to scale console onto.\n"); - return -EINVAL; - } } - - *fb_ptr = &rfbdev->helper; return new_fb; } @@ -312,48 +311,55 @@ int radeon_parse_options(char *options) return 0; } -static int radeonfb_probe(struct drm_device *dev) +static int radeonfb_probe(struct radeon_fbdev *rfbdev) { - struct radeon_device *rdev = dev->dev_private; + struct radeon_device *rdev = rfbdev->rdev; int bpp_sel = 32; /* select 8 bpp console on RN50 or 16MB cards */ if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) bpp_sel = 8; - return drm_fb_helper_single_fb_probe(dev, bpp_sel, &radeon_fb_find_or_create_single); + return drm_fb_helper_single_fb_probe(&rfbdev->helper, bpp_sel); } void radeonfb_hotplug(struct drm_device *dev) { - drm_helper_fb_hotplug_event(dev); + struct radeon_device *rdev = dev->dev_private; + int max_width, max_height; + + max_width = rdev->mode_info.rfbdev->rfb.base.width; + max_height = rdev->mode_info.rfbdev->rfb.base.height; + drm_helper_fb_hotplug_event(&rdev->mode_info.rfbdev->helper, max_width, max_height); - radeonfb_probe(dev); + radeonfb_probe(rdev->mode_info.rfbdev); } -static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_kernel_fbdev *rfbdev) +static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) { struct fb_info *info; struct radeon_framebuffer *rfb = &rfbdev->rfb; struct radeon_bo *rbo; int r; - rbo = rfb->obj->driver_private; - info = rfbdev->helper.fbdev; - unregister_framebuffer(info); - r = radeon_bo_reserve(rbo, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rbo); - radeon_bo_unpin(rbo); - radeon_bo_unreserve(rbo); + if (rfbdev->helper.fbdev) { + info = rfbdev->helper.fbdev; + unregister_framebuffer(info); + framebuffer_release(info); } + if (rfb->obj) { + rbo = rfb->obj->driver_private; + r = radeon_bo_reserve(rbo, false); + if (likely(r == 0)) { + radeon_bo_kunmap(rbo); + radeon_bo_unpin(rbo); + radeon_bo_unreserve(rbo); + } + drm_gem_object_unreference_unlocked(rfb->obj); + } drm_fb_helper_free(&rfbdev->helper); drm_framebuffer_cleanup(&rfb->base); - if (rfb->obj) - drm_gem_object_unreference_unlocked(rfb->obj); - - framebuffer_release(info); return 0; } @@ -361,14 +367,32 @@ MODULE_LICENSE("GPL"); int radeon_fbdev_init(struct radeon_device *rdev) { - drm_helper_initial_config(rdev->ddev); - radeonfb_probe(rdev->ddev); + struct radeon_fbdev *rfbdev; + + rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL); + if (!rfbdev) + return -ENOMEM; + + rfbdev->rdev = rdev; + rdev->mode_info.rfbdev = rfbdev; + + drm_fb_helper_init_crtc_count(rdev->ddev, &rfbdev->helper, + rdev->num_crtc, + RADEONFB_CONN_LIMIT); + rfbdev->helper.fb_probe = radeon_fb_find_or_create_single; + drm_fb_helper_initial_config(&rfbdev->helper); + radeonfb_probe(rfbdev); return 0; + } void radeon_fbdev_fini(struct radeon_device *rdev) { + if (!rdev->mode_info.rfbdev) + return; + radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev); + kfree(rdev->mode_info.rfbdev); rdev->mode_info.rfbdev = NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 1e9138bf559..165f6025a3b 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -203,7 +203,7 @@ enum radeon_dvo_chip { DVO_SIL1178, }; -struct radeon_kernel_fbdev; +struct radeon_fbdev; struct radeon_mode_info { struct atom_context *atom_context; @@ -223,7 +223,7 @@ struct radeon_mode_info { struct edid *bios_hardcoded_edid; /* pointer to fbdev info structure */ - struct radeon_kernel_fbdev *rfbdev; + struct radeon_fbdev *rfbdev; }; #define MAX_H_CODE_TIMING_LEN 32 diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c70814b184e..e4e34bae22c 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -367,9 +367,6 @@ struct drm_crtc_funcs { * @enabled: is this CRTC enabled? * @x: x position on screen * @y: y position on screen - * @desired_mode: new desired mode - * @desired_x: desired x for desired_mode - * @desired_y: desired y for desired_mode * @funcs: CRTC control functions * * Each CRTC may have one or more connectors associated with it. This structure @@ -389,8 +386,6 @@ struct drm_crtc { struct drm_display_mode mode; int x, y; - struct drm_display_mode *desired_mode; - int desired_x, desired_y; const struct drm_crtc_funcs *funcs; /* CRTC gamma size for reporting to userspace */ diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index 38ab0daffd1..b1ea66f11de 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h @@ -33,6 +33,7 @@ struct drm_fb_helper_crtc { uint32_t crtc_id; struct drm_mode_set mode_set; + struct drm_display_mode *desired_mode; }; @@ -81,14 +82,16 @@ struct drm_fb_helper { struct fb_info *fbdev; u32 pseudo_palette[17]; struct list_head kernel_fb_list; + + int (*fb_probe)(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes); }; -int drm_fb_helper_single_fb_probe(struct drm_device *dev, - int preferred_bpp, - int (*fb_create)(struct drm_device *dev, - struct drm_fb_helper_surface_size *sizes, - struct drm_fb_helper **fb_ptr)); -int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, +int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper, + int preferred_bpp); + +int drm_fb_helper_init_crtc_count(struct drm_device *dev, + struct drm_fb_helper *helper, int crtc_count, int max_conn); void drm_fb_helper_free(struct drm_fb_helper *helper); int drm_fb_helper_blank(int blank, struct fb_info *info); @@ -114,6 +117,8 @@ int drm_fb_helper_add_connector(struct drm_connector *connector); int drm_fb_helper_parse_command_line(struct drm_device *dev); int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); -bool drm_helper_fb_hotplug_event(struct drm_device *dev); -bool drm_helper_initial_config(struct drm_device *dev); +bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, u32 max_width, + u32 max_height); +bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); + #endif |