|
@@ -119,12 +119,10 @@ struct ps3fb_priv {
|
|
|
void *xdr_ea;
|
|
|
size_t xdr_size;
|
|
|
struct gpu_driver_info *dinfo;
|
|
|
- u32 res_index;
|
|
|
|
|
|
u64 vblank_count; /* frame count */
|
|
|
wait_queue_head_t wait_vsync;
|
|
|
|
|
|
- u32 num_frames; /* num of frame buffers */
|
|
|
atomic_t ext_flip; /* on/off flip with vsync */
|
|
|
atomic_t f_count; /* fb_open count */
|
|
|
int is_blanked;
|
|
@@ -133,6 +131,13 @@ struct ps3fb_priv {
|
|
|
};
|
|
|
static struct ps3fb_priv ps3fb;
|
|
|
|
|
|
+struct ps3fb_par {
|
|
|
+ u32 pseudo_palette[16];
|
|
|
+ int mode_id, new_mode_id;
|
|
|
+ int res_index;
|
|
|
+ unsigned int num_frames; /* num of frame buffers */
|
|
|
+};
|
|
|
+
|
|
|
struct ps3fb_res_table {
|
|
|
u32 xres;
|
|
|
u32 yres;
|
|
@@ -361,18 +366,17 @@ static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
|
|
|
|
|
|
pr_debug("ps3fb_find_mode: mode not found\n");
|
|
|
return 0;
|
|
|
-
|
|
|
}
|
|
|
|
|
|
-static const struct fb_videomode *ps3fb_default_mode(void)
|
|
|
+static const struct fb_videomode *ps3fb_default_mode(int id)
|
|
|
{
|
|
|
- u32 mode = ps3fb_mode & PS3AV_MODE_MASK;
|
|
|
+ u32 mode = id & PS3AV_MODE_MASK;
|
|
|
u32 flags;
|
|
|
|
|
|
if (mode < 1 || mode > 13)
|
|
|
return NULL;
|
|
|
|
|
|
- flags = ps3fb_mode & ~PS3AV_MODE_MASK;
|
|
|
+ flags = id & ~PS3AV_MODE_MASK;
|
|
|
|
|
|
if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) {
|
|
|
/* Full broadcast mode */
|
|
@@ -384,18 +388,22 @@ static const struct fb_videomode *ps3fb_default_mode(void)
|
|
|
|
|
|
static int ps3fb_sync(struct fb_info *info, u32 frame)
|
|
|
{
|
|
|
- int i, status;
|
|
|
+ struct ps3fb_par *par = info->par;
|
|
|
+ int i, status, error = 0;
|
|
|
u32 xres, yres;
|
|
|
u64 fb_ioif, offset;
|
|
|
|
|
|
- i = ps3fb.res_index;
|
|
|
+ acquire_console_sem();
|
|
|
+
|
|
|
+ i = par->res_index;
|
|
|
xres = ps3fb_res[i].xres;
|
|
|
yres = ps3fb_res[i].yres;
|
|
|
|
|
|
- if (frame > ps3fb.num_frames - 1) {
|
|
|
+ if (frame > par->num_frames - 1) {
|
|
|
dev_dbg(info->device, "%s: invalid frame number (%u)\n",
|
|
|
__func__, frame);
|
|
|
- return -EINVAL;
|
|
|
+ error = -EINVAL;
|
|
|
+ goto out;
|
|
|
}
|
|
|
offset = xres * yres * BPP * frame;
|
|
|
|
|
@@ -428,7 +436,10 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
|
|
|
"%s: lv1_gpu_context_attribute FLIP failed: %d\n",
|
|
|
__func__, status);
|
|
|
#endif
|
|
|
- return 0;
|
|
|
+
|
|
|
+out:
|
|
|
+ release_console_sem();
|
|
|
+ return error;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -547,6 +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)
|
|
|
{
|
|
|
+ struct ps3fb_par *par = info->par;
|
|
|
unsigned int mode;
|
|
|
int i;
|
|
|
unsigned long offset;
|
|
@@ -560,7 +572,7 @@ static int ps3fb_set_par(struct fb_info *info)
|
|
|
return -EINVAL;
|
|
|
|
|
|
i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);
|
|
|
- ps3fb.res_index = i;
|
|
|
+ par->res_index = i;
|
|
|
|
|
|
offset = VFB_OFF(i);
|
|
|
info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea) + offset;
|
|
@@ -568,14 +580,19 @@ static int ps3fb_set_par(struct fb_info *info)
|
|
|
info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
|
|
|
memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
|
|
|
|
|
|
- ps3fb.num_frames = info->fix.smem_len/
|
|
|
- (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP);
|
|
|
+ par->num_frames = info->fix.smem_len/
|
|
|
+ (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP);
|
|
|
|
|
|
/* Keep the special bits we cannot set using fb_var_screeninfo */
|
|
|
- ps3fb_mode = (ps3fb_mode & ~PS3AV_MODE_MASK) | mode;
|
|
|
+ par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
|
|
|
|
|
|
- if (ps3av_set_video_mode(ps3fb_mode))
|
|
|
- return -EINVAL;
|
|
|
+ if (par->new_mode_id != par->mode_id) {
|
|
|
+ if (ps3av_set_video_mode(par->new_mode_id)) {
|
|
|
+ par->new_mode_id = par->mode_id;
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ par->mode_id = par->new_mode_id;
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -694,7 +711,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
|
|
|
unsigned long arg)
|
|
|
{
|
|
|
void __user *argp = (void __user *)arg;
|
|
|
- u32 val, old_mode;
|
|
|
+ u32 val;
|
|
|
int retval = -EFAULT;
|
|
|
|
|
|
switch (cmd) {
|
|
@@ -724,6 +741,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
|
|
|
|
|
|
case PS3FB_IOCTL_SETMODE:
|
|
|
{
|
|
|
+ struct ps3fb_par *par = info->par;
|
|
|
const struct fb_videomode *mode;
|
|
|
struct fb_var_screeninfo var;
|
|
|
|
|
@@ -737,9 +755,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
|
|
|
}
|
|
|
dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);
|
|
|
retval = -EINVAL;
|
|
|
- old_mode = ps3fb_mode;
|
|
|
- ps3fb_mode = val;
|
|
|
- mode = ps3fb_default_mode();
|
|
|
+ mode = ps3fb_default_mode(val);
|
|
|
if (mode) {
|
|
|
var = info->var;
|
|
|
fb_videomode_to_var(&var, mode);
|
|
@@ -747,12 +763,11 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
|
|
|
info->flags |= FBINFO_MISC_USEREVENT;
|
|
|
/* Force, in case only special bits changed */
|
|
|
var.activate |= FB_ACTIVATE_FORCE;
|
|
|
+ par->new_mode_id = val;
|
|
|
retval = fb_set_var(info, &var);
|
|
|
info->flags &= ~FBINFO_MISC_USEREVENT;
|
|
|
release_console_sem();
|
|
|
}
|
|
|
- if (retval)
|
|
|
- ps3fb_mode = old_mode;
|
|
|
break;
|
|
|
}
|
|
|
|
|
@@ -765,14 +780,15 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
|
|
|
|
|
|
case PS3FB_IOCTL_SCREENINFO:
|
|
|
{
|
|
|
+ struct ps3fb_par *par = info->par;
|
|
|
struct ps3fb_ioctl_res res;
|
|
|
- int i = ps3fb.res_index;
|
|
|
+ int i = par->res_index;
|
|
|
dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n");
|
|
|
res.xres = ps3fb_res[i].xres;
|
|
|
res.yres = ps3fb_res[i].yres;
|
|
|
res.xoff = ps3fb_res[i].xoff;
|
|
|
res.yoff = ps3fb_res[i].yoff;
|
|
|
- res.num_frames = ps3fb.num_frames;
|
|
|
+ res.num_frames = par->num_frames;
|
|
|
if (!copy_to_user(argp, &res, sizeof(res)))
|
|
|
retval = 0;
|
|
|
break;
|
|
@@ -979,6 +995,7 @@ static int ps3fb_set_sync(struct device *dev)
|
|
|
static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
|
|
|
{
|
|
|
struct fb_info *info;
|
|
|
+ struct ps3fb_par *par;
|
|
|
int retval = -ENOMEM;
|
|
|
u32 xres, yres;
|
|
|
u64 ddr_lpar = 0;
|
|
@@ -987,7 +1004,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
|
|
|
u64 lpar_reports = 0;
|
|
|
u64 lpar_reports_size = 0;
|
|
|
u64 xdr_lpar;
|
|
|
- int status;
|
|
|
+ int status, res_index;
|
|
|
unsigned long offset;
|
|
|
struct task_struct *task;
|
|
|
|
|
@@ -1004,15 +1021,14 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
|
|
|
|
|
|
if (ps3fb_mode > 0 &&
|
|
|
!ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
|
|
|
- ps3fb.res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode);
|
|
|
- dev_dbg(&dev->core, "res_index:%d\n", ps3fb.res_index);
|
|
|
+ res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode);
|
|
|
+ dev_dbg(&dev->core, "res_index:%d\n", res_index);
|
|
|
} else
|
|
|
- ps3fb.res_index = GPU_RES_INDEX;
|
|
|
+ res_index = GPU_RES_INDEX;
|
|
|
|
|
|
atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
|
|
|
atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
|
|
|
init_waitqueue_head(&ps3fb.wait_vsync);
|
|
|
- ps3fb.num_frames = 1;
|
|
|
|
|
|
ps3fb_set_sync(&dev->core);
|
|
|
|
|
@@ -1062,19 +1078,24 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
|
|
|
if (retval)
|
|
|
goto err_free_irq;
|
|
|
|
|
|
- info = framebuffer_alloc(sizeof(u32) * 16, &dev->core);
|
|
|
+ info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
|
|
|
if (!info)
|
|
|
goto err_free_irq;
|
|
|
|
|
|
- offset = VFB_OFF(ps3fb.res_index);
|
|
|
+ par = info->par;
|
|
|
+ par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */
|
|
|
+ par->new_mode_id = ps3fb_mode;
|
|
|
+ par->res_index = res_index;
|
|
|
+ par->num_frames = 1;
|
|
|
+
|
|
|
+ offset = VFB_OFF(res_index);
|
|
|
info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
|
|
|
info->fbops = &ps3fb_ops;
|
|
|
|
|
|
info->fix = ps3fb_fix;
|
|
|
info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea) + offset;
|
|
|
info->fix.smem_len = ps3fb.xdr_size - offset;
|
|
|
- info->pseudo_palette = info->par;
|
|
|
- info->par = NULL;
|
|
|
+ info->pseudo_palette = par->pseudo_palette;
|
|
|
info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
|
|
|
|
|
|
retval = fb_alloc_cmap(&info->cmap, 256, 0);
|
|
@@ -1082,7 +1103,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
|
|
|
goto err_framebuffer_release;
|
|
|
|
|
|
if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
|
|
|
- ARRAY_SIZE(ps3fb_modedb), ps3fb_default_mode(), 32)) {
|
|
|
+ ARRAY_SIZE(ps3fb_modedb),
|
|
|
+ ps3fb_default_mode(par->new_mode_id), 32)) {
|
|
|
retval = -EINVAL;
|
|
|
goto err_fb_dealloc;
|
|
|
}
|