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

Commit fc7028b7 authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Linus Torvalds
Browse files

ps3fb: add virtual screen and panning support



ps3fb: Add virtual screen and panning support:
  - The vertical virtual screen size is limited by the amount of memory
    reserved for ps3fb,
  - The horizontal virtual screen size is limited to the fullscreen width,
  - Advertise that we support panning, so fbcon will use it if the virtual
    screen is enabled.
    Enabling a virtual screen (using `fbset -vyres nnn') can speed up text
    console scrolling by a factor of 10-15, depending on the video mode.

Signed-off-by: default avatarGeert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent f1664ed8
Loading
Loading
Loading
Loading
+40 −25
Original line number Original line Diff line number Diff line
@@ -141,6 +141,7 @@ struct ps3fb_par {
	unsigned int height;
	unsigned int height;
	unsigned long full_offset;	/* start of fullscreen DDR fb */
	unsigned long full_offset;	/* start of fullscreen DDR fb */
	unsigned long fb_offset;	/* start of actual DDR fb */
	unsigned long fb_offset;	/* start of actual DDR fb */
	unsigned long pan_offset;
};
};


struct ps3fb_res_table {
struct ps3fb_res_table {
@@ -440,8 +441,8 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
	base = frame * yres * line_length;
	base = frame * yres * line_length;


	ps3fb_sync_image(info->device, base + par->full_offset,
	ps3fb_sync_image(info->device, base + par->full_offset,
			 base + par->fb_offset, base, par->width, par->height,
			 base + par->fb_offset, base + par->pan_offset,
			 line_length);
			 par->width, par->height, line_length);


out:
out:
	release_console_sem();
	release_console_sem();
@@ -488,27 +489,23 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
	if (!mode)
	if (!mode)
		return -EINVAL;
		return -EINVAL;


	/*
	/* Virtual screen */
	 *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
	if (var->xres_virtual < var->xres)
	 *  as FB_VMODE_SMOOTH_XPAN is only used internally
		var->xres_virtual = var->xres;
	 */
	if (var->yres_virtual < var->yres)

		var->yres_virtual = var->yres;
	if (var->vmode & FB_VMODE_CONUPDATE) {
		var->vmode |= FB_VMODE_YWRAP;
		var->xoffset = info->var.xoffset;
		var->yoffset = info->var.yoffset;
	}


	/* Virtual screen and panning are not supported */
	if (var->xres_virtual > line_length / BPP) {
	if (var->xres_virtual > var->xres || var->yres_virtual > var->yres ||
	    var->xoffset || var->yoffset) {
		dev_dbg(info->device,
		dev_dbg(info->device,
			"Virtual screen and panning are not supported\n");
			"Horizontal virtual screen size too large\n");
		return -EINVAL;
		return -EINVAL;
	}
	}


	var->xres_virtual = var->xres;
	if (var->xoffset + var->xres > var->xres_virtual ||
	var->yres_virtual = var->yres;
	    var->yoffset + var->yres > var->yres_virtual) {
		dev_dbg(info->device, "panning out-of-range\n");
		return -EINVAL;
	}


	/* We support ARGB8888 only */
	/* We support ARGB8888 only */
	if (var->bits_per_pixel > 32 || var->grayscale ||
	if (var->bits_per_pixel > 32 || var->grayscale ||
@@ -543,7 +540,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
	}
	}


	/* Memory limit */
	/* Memory limit */
	if (var->yres * line_length > ps3fb.xdr_size) {
	if (var->yres_virtual * line_length > ps3fb.xdr_size) {
		dev_dbg(info->device, "Not enough memory\n");
		dev_dbg(info->device, "Not enough memory\n");
		return -ENOMEM;
		return -ENOMEM;
	}
	}
@@ -561,7 +558,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
static int ps3fb_set_par(struct fb_info *info)
static int ps3fb_set_par(struct fb_info *info)
{
{
	struct ps3fb_par *par = info->par;
	struct ps3fb_par *par = info->par;
	unsigned int mode, lines, maxlines;
	unsigned int mode, line_length, lines, maxlines;
	int i;
	int i;
	unsigned long offset, dst;
	unsigned long offset, dst;


@@ -569,7 +566,7 @@ static int ps3fb_set_par(struct fb_info *info)
		info->var.xres, info->var.xres_virtual,
		info->var.xres, info->var.xres_virtual,
		info->var.yres, info->var.yres_virtual, info->var.pixclock);
		info->var.yres, info->var.yres_virtual, info->var.pixclock);


	mode = ps3fb_find_mode(&info->var, &info->fix.line_length);
	mode = ps3fb_find_mode(&info->var, &line_length);
	if (!mode)
	if (!mode)
		return -EINVAL;
		return -EINVAL;


@@ -578,6 +575,10 @@ static int ps3fb_set_par(struct fb_info *info)


	info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
	info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
	info->fix.smem_len = ps3fb.xdr_size;
	info->fix.smem_len = ps3fb.xdr_size;
	info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
	info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
	info->fix.line_length = line_length;

	info->screen_base = (char __iomem *)ps3fb.xdr_ea;
	info->screen_base = (char __iomem *)ps3fb.xdr_ea;


	par->num_frames = info->fix.smem_len/
	par->num_frames = info->fix.smem_len/
@@ -591,6 +592,8 @@ static int ps3fb_set_par(struct fb_info *info)
	offset = VP_OFF(i);
	offset = VP_OFF(i);
	par->fb_offset = GPU_ALIGN_UP(offset);
	par->fb_offset = GPU_ALIGN_UP(offset);
	par->full_offset = par->fb_offset - offset;
	par->full_offset = par->fb_offset - offset;
	par->pan_offset = info->var.yoffset * line_length +
			  info->var.xoffset * BPP;


	if (par->new_mode_id != par->mode_id) {
	if (par->new_mode_id != par->mode_id) {
		if (ps3av_set_video_mode(par->new_mode_id)) {
		if (ps3av_set_video_mode(par->new_mode_id)) {
@@ -607,11 +610,11 @@ static int ps3fb_set_par(struct fb_info *info)
	lines = ps3fb_res[i].yres * par->num_frames;
	lines = ps3fb_res[i].yres * par->num_frames;
	if (par->full_offset)
	if (par->full_offset)
		lines++;
		lines++;
	maxlines = ps3fb.xdr_size / info->fix.line_length;
	maxlines = ps3fb.xdr_size / line_length;
	for (dst = 0; lines; dst += maxlines * info->fix.line_length) {
	for (dst = 0; lines; dst += maxlines * line_length) {
		unsigned int l = min(lines, maxlines);
		unsigned int l = min(lines, maxlines);
		ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,
		ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,
				 info->fix.line_length);
				 line_length);
		lines -= l;
		lines -= l;
	}
	}


@@ -641,6 +644,16 @@ static int ps3fb_setcolreg(unsigned int regno, unsigned int red,
	return 0;
	return 0;
}
}


static int ps3fb_pan_display(struct fb_var_screeninfo *var,
			     struct fb_info *info)
{
	struct ps3fb_par *par = info->par;

	par->pan_offset = var->yoffset * info->fix.line_length +
			  var->xoffset * BPP;
	return 0;
}

    /*
    /*
     *  As we have a virtual frame buffer, we need our own mmap function
     *  As we have a virtual frame buffer, we need our own mmap function
     */
     */
@@ -965,6 +978,7 @@ static struct fb_ops ps3fb_ops = {
	.fb_check_var	= ps3fb_check_var,
	.fb_check_var	= ps3fb_check_var,
	.fb_set_par	= ps3fb_set_par,
	.fb_set_par	= ps3fb_set_par,
	.fb_setcolreg	= ps3fb_setcolreg,
	.fb_setcolreg	= ps3fb_setcolreg,
	.fb_pan_display	= ps3fb_pan_display,
	.fb_fillrect	= sys_fillrect,
	.fb_fillrect	= sys_fillrect,
	.fb_copyarea	= sys_copyarea,
	.fb_copyarea	= sys_copyarea,
	.fb_imageblit	= sys_imageblit,
	.fb_imageblit	= sys_imageblit,
@@ -1115,7 +1129,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
	info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
	info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
	info->fix.smem_len = ps3fb.xdr_size;
	info->fix.smem_len = ps3fb.xdr_size;
	info->pseudo_palette = par->pseudo_palette;
	info->pseudo_palette = par->pseudo_palette;
	info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
	info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
		      FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;


	retval = fb_alloc_cmap(&info->cmap, 256, 0);
	retval = fb_alloc_cmap(&info->cmap, 256, 0);
	if (retval < 0)
	if (retval < 0)