Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8be48d92 authored by Dave Airlie's avatar Dave Airlie
Browse files

drm/kms/fb: move to using fb helper crtc grouping instead of core crtc list



This move to using the list of crtcs in the fb helper and cleans up the
whole picking code, now we store the crtc/connectors we want directly
into the modeset and we use the modeset directly to set the mode.

Fixes from James Simmons and Ben Skeggs.

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 38651674
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -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) {
+139 −190
Original line number Diff line number Diff line
@@ -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,19 +300,16 @@ 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)
		if (!crtc->enabled)
			continue;

			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) {
@@ -319,13 +317,11 @@ static void drm_fb_helper_on(struct fb_info *info)
				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);
				}
			}
		}
	}
	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,14 +337,12 @@ 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)
		if (!crtc->enabled)
			continue;

		/* Found a CRTC on this fb, now find encoders */
@@ -356,16 +351,12 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
				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);
			}
		}
			mutex_lock(&dev->mode_config.mutex);
		crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
			mutex_unlock(&dev->mode_config.mutex);
		}
	}
	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;
		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;
		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) {

	mutex_lock(&dev->mode_config.mutex);
	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;
		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);

			if (ret) {
				mutex_unlock(&dev->mode_config.mutex);
			if (ret)
				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) {
	mutex_lock(&dev->mode_config.mutex);
	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;
		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,6 +848,7 @@ EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);

void drm_fb_helper_free(struct drm_fb_helper *helper)
{
	if (!list_empty(&helper->kernel_fb_list)) {
		list_del(&helper->kernel_fb_list);
		if (list_empty(&kernel_fb_helper_list)) {
			printk(KERN_INFO "unregistered panic notifier\n");
@@ -913,7 +856,9 @@ void drm_fb_helper_free(struct drm_fb_helper *helper)
							 &paniced);
			unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
		}
	}
	drm_fb_helper_crtc_free(helper);
	if (helper->fbdev->cmap.len)
		fb_dealloc_cmap(&helper->fbdev->cmap);
}
EXPORT_SYMBOL(drm_fb_helper_free);
@@ -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;
}
+3 −2
Original line number Diff line number Diff line
@@ -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 */
+43 −50
Original line number Diff line number Diff line
@@ -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,7 +172,7 @@ 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,
		      fb->width, fb->height,
		      obj_priv->gtt_offset, fbo);


@@ -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;

	if (ifbdev->helper.fbdev) {
		info = ifbdev->helper.fbdev;

		unregister_framebuffer(info);
		iounmap(info->screen_base);
		framebuffer_release(info);
	}

	drm_fb_helper_free(&ifbdev->helper);

	drm_framebuffer_cleanup(&ifb->base);
	if (ifb->obj)
		drm_gem_object_unreference_unlocked(ifb->obj);

	framebuffer_release(info);

	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");
+1 −1
Original line number Diff line number Diff line
@@ -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 *
Loading