@@ -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) {
@@ -290,6 +290,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;
@@ -297,33 +298,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)
@@ -331,6 +327,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;
@@ -338,32 +335,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)
@@ -403,17 +394,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++) {
@@ -505,20 +498,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;
@@ -554,22 +542,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)
@@ -684,23 +667,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);
@@ -715,14 +695,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;
@@ -730,34 +705,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;
@@ -773,7 +743,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)
@@ -805,21 +774,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++;
}
}
@@ -831,48 +801,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) {
@@ -904,15 +846,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);
@@ -1166,20 +1111,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) {
@@ -1190,12 +1136,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;
@@ -1212,15 +1158,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;
}
@@ -1230,34 +1173,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;
@@ -1273,7 +1216,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,
@@ -1287,26 +1230,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++;
}
@@ -1330,14 +1277,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,
@@ -1349,20 +1297,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;
}
@@ -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 */
@@ -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");
@@ -531,8 +531,6 @@ struct drm_nouveau_private {
atomic_t validate_sequence;
} ttm;
- // struct fb_info *fbdev_info;
-
int fifo_alloc_count;
struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
@@ -629,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 *
@@ -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;
}
@@ -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;
@@ -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;
@@ -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;
@@ -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;
}
@@ -208,7 +208,7 @@ enum radeon_dvo_chip {
DVO_SIL1178,
};
-struct radeon_kernel_fbdev;
+struct radeon_fbdev;
struct radeon_mode_info {
struct atom_context *atom_context;
@@ -228,7 +228,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
@@ -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 */
@@ -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