struct ps3fb_par {
u32 pseudo_palette[16];
int mode_id, new_mode_id;
- int res_index;
unsigned int num_frames; /* num of frame buffers */
unsigned int width;
unsigned int height;
- unsigned long full_offset; /* start of fullscreen DDR fb */
- unsigned long fb_offset; /* start of actual DDR fb */
- unsigned long pan_offset;
+ unsigned int ddr_line_length;
+ unsigned int ddr_frame_size;
+ unsigned int xdr_frame_size;
+ unsigned int full_offset; /* start of fullscreen DDR fb */
+ unsigned int fb_offset; /* start of actual DDR fb */
+ unsigned int pan_offset;
};
-struct ps3fb_res_table {
- u32 xres;
- u32 yres;
- u32 xoff;
- u32 yoff;
- u32 type;
-};
-#define PS3FB_RES_FULL 1
-static const struct ps3fb_res_table ps3fb_res[] = {
- /* res_x,y margin_x,y full */
- { 720, 480, 72, 48 , 0},
- { 720, 576, 72, 58 , 0},
- { 1280, 720, 78, 38 , 0},
- { 1920, 1080, 116, 58 , 0},
- /* full mode */
- { 720, 480, 0, 0 , PS3FB_RES_FULL},
- { 720, 576, 0, 0 , PS3FB_RES_FULL},
- { 1280, 720, 0, 0 , PS3FB_RES_FULL},
- { 1920, 1080, 0, 0 , PS3FB_RES_FULL},
- /* vesa: normally full mode */
- { 1280, 768, 0, 0 , 0},
- { 1280, 1024, 0, 0 , 0},
- { 1920, 1200, 0, 0 , 0},
- { 0, 0, 0, 0 , 0} };
-
-/* default resolution */
-#define GPU_RES_INDEX 0 /* 720 x 480 */
+
+#define FIRST_NATIVE_MODE_INDEX 10
static const struct fb_videomode ps3fb_modedb[] = {
/* 60 Hz broadcast modes (modes "1" to "5") */
FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
},
- /* VESA modes (modes "11" to "13") */
- {
- /* WXGA */
- "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
- 0, FB_VMODE_NONINTERLACED,
- FB_MODE_IS_VESA
- }, {
- /* SXGA */
- "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
- FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
- FB_MODE_IS_VESA
- }, {
- /* WUXGA */
- "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
- FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
- FB_MODE_IS_VESA
- },
-
+ [FIRST_NATIVE_MODE_INDEX] =
/* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */
{
/* 480if */
/* 1080pf */
"1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5,
FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
+ },
+
+ /* VESA modes (modes "11" to "13") */
+ {
+ /* WXGA */
+ "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
+ }, {
+ /* SXGA */
+ "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
+ }, {
+ /* WUXGA */
+ "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
+ FB_MODE_IS_VESA
}
};
#define HEAD_A
#define HEAD_B
-#define X_OFF(i) (ps3fb_res[i].xoff) /* left/right margin (pixel) */
-#define Y_OFF(i) (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */
-#define WIDTH(i) (ps3fb_res[i].xres) /* width of FB */
-#define HEIGHT(i) (ps3fb_res[i].yres) /* height of FB */
#define BPP 4 /* number of bytes per pixel */
-/* Start of the virtual frame buffer (relative to fullscreen ) */
-#define VP_OFF(i) ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP)
-
static int ps3fb_mode;
module_param(ps3fb_mode, int, 0);
static char *mode_option __devinitdata;
-static int ps3fb_get_res_table(u32 xres, u32 yres, int mode)
+static int ps3fb_cmp_mode(const struct fb_videomode *vmode,
+ const struct fb_var_screeninfo *var)
{
- int full_mode;
- unsigned int i;
- u32 x, y, f;
-
- full_mode = (mode & PS3AV_MODE_FULL) ? PS3FB_RES_FULL : 0;
- for (i = 0;; i++) {
- x = ps3fb_res[i].xres;
- y = ps3fb_res[i].yres;
- f = ps3fb_res[i].type;
-
- if (!x) {
- pr_debug("ERROR: ps3fb_get_res_table()\n");
- return -1;
- }
+ /* resolution + black border must match a native resolution */
+ if (vmode->left_margin + vmode->xres + vmode->right_margin !=
+ var->left_margin + var->xres + var->right_margin ||
+ vmode->upper_margin + vmode->yres + vmode->lower_margin !=
+ var->upper_margin + var->yres + var->lower_margin)
+ return -1;
- if (full_mode == PS3FB_RES_FULL && f != PS3FB_RES_FULL)
- continue;
+ /* minimum limits for margins */
+ if (vmode->left_margin > var->left_margin ||
+ vmode->right_margin > var->right_margin ||
+ vmode->upper_margin > var->upper_margin ||
+ vmode->lower_margin > var->lower_margin)
+ return -1;
- if (x == xres && (yres == 0 || y == yres))
- break;
+ /* these fields must match exactly */
+ if (vmode->pixclock != var->pixclock ||
+ vmode->hsync_len != var->hsync_len ||
+ vmode->vsync_len != var->vsync_len ||
+ vmode->sync != var->sync ||
+ vmode->vmode != (var->vmode & FB_VMODE_MASK))
+ return -1;
- x = x - 2 * ps3fb_res[i].xoff;
- y = y - 2 * ps3fb_res[i].yoff;
- if (x == xres && (yres == 0 || y == yres))
- break;
+ return 0;
+}
+
+static const struct fb_videomode *ps3fb_native_vmode(enum ps3av_mode_num id)
+{
+ return &ps3fb_modedb[FIRST_NATIVE_MODE_INDEX + id - 1];
+}
+
+static const struct fb_videomode *ps3fb_vmode(int id)
+{
+ u32 mode = id & PS3AV_MODE_MASK;
+
+ if (mode < PS3AV_MODE_480I || mode > PS3AV_MODE_WUXGA)
+ return NULL;
+
+ if (mode <= PS3AV_MODE_1080P50 && !(id & PS3AV_MODE_FULL)) {
+ /* Non-fullscreen broadcast mode */
+ return &ps3fb_modedb[mode - 1];
}
- return i;
+
+ return ps3fb_native_vmode(mode);
}
-static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
+static unsigned int ps3fb_find_mode(struct fb_var_screeninfo *var,
u32 *ddr_line_length, u32 *xdr_line_length)
{
- unsigned int i, fi, mode;
-
- for (i = 0; i < ARRAY_SIZE(ps3fb_modedb); i++)
- if (var->xres == ps3fb_modedb[i].xres &&
- var->yres == ps3fb_modedb[i].yres &&
- var->pixclock == ps3fb_modedb[i].pixclock &&
- var->hsync_len == ps3fb_modedb[i].hsync_len &&
- var->vsync_len == ps3fb_modedb[i].vsync_len &&
- var->left_margin == ps3fb_modedb[i].left_margin &&
- var->right_margin == ps3fb_modedb[i].right_margin &&
- var->upper_margin == ps3fb_modedb[i].upper_margin &&
- var->lower_margin == ps3fb_modedb[i].lower_margin &&
- var->sync == ps3fb_modedb[i].sync &&
- (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode)
+ unsigned int id;
+ const struct fb_videomode *vmode;
+
+ for (id = PS3AV_MODE_480I; id <= PS3AV_MODE_WUXGA; id++) {
+ vmode = ps3fb_native_vmode(id);
+ if (!ps3fb_cmp_mode(vmode, var))
goto found;
+ }
- pr_debug("ps3fb_find_mode: mode not found\n");
+ pr_debug("%s: mode not found\n", __func__);
return 0;
found:
- /* Cropped broadcast modes use the full line length */
- fi = i < PS3AV_MODE_1080P50 ? i + PS3AV_MODE_WUXGA : i;
- *ddr_line_length = ps3fb_modedb[fi].xres * BPP;
+ *ddr_line_length = vmode->xres * BPP;
+
+ if (!var->xres) {
+ var->xres = 1;
+ var->right_margin--;
+ }
+ if (!var->yres) {
+ var->yres = 1;
+ var->lower_margin--;
+ }
if (ps3_compare_firmware_version(1, 9, 0) >= 0) {
*xdr_line_length = GPU_ALIGN_UP(max(var->xres,
} else
*xdr_line_length = *ddr_line_length;
- /* Full broadcast modes have the full mode bit set */
- mode = i+1;
- if (mode > PS3AV_MODE_WUXGA)
- mode = (mode - PS3AV_MODE_WUXGA) | PS3AV_MODE_FULL;
-
- pr_debug("ps3fb_find_mode: mode %u\n", mode);
-
- return mode;
-}
-
-static const struct fb_videomode *ps3fb_default_mode(int id)
-{
- u32 mode = id & PS3AV_MODE_MASK;
- u32 flags;
-
- if (mode < PS3AV_MODE_480I || mode > PS3AV_MODE_WUXGA)
- return NULL;
-
- flags = id & ~PS3AV_MODE_MASK;
-
- if (mode <= PS3AV_MODE_1080P50 && flags & PS3AV_MODE_FULL) {
- /* Full broadcast mode */
- return &ps3fb_modedb[mode + PS3AV_MODE_WUXGA - 1];
+ if (vmode->sync & FB_SYNC_BROADCAST) {
+ /* Full broadcast modes have the full mode bit set */
+ if (vmode->xres == var->xres && vmode->yres == var->yres)
+ id |= PS3AV_MODE_FULL;
}
- return &ps3fb_modedb[mode - 1];
+ pr_debug("%s: mode %u\n", __func__, id);
+ return id;
}
static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
static int ps3fb_sync(struct fb_info *info, u32 frame)
{
struct ps3fb_par *par = info->par;
- int i, error = 0;
- u32 ddr_line_length, xdr_line_length;
+ int error = 0;
u64 ddr_base, xdr_base;
if (frame > par->num_frames - 1) {
goto out;
}
- i = par->res_index;
- xdr_line_length = info->fix.line_length;
- ddr_line_length = ps3fb_res[i].xres * BPP;
- xdr_base = frame * info->var.yres_virtual * xdr_line_length;
- ddr_base = frame * ps3fb_res[i].yres * ddr_line_length;
+ xdr_base = frame * par->xdr_frame_size;
+ ddr_base = frame * par->ddr_frame_size;
ps3fb_sync_image(info->device, ddr_base + par->full_offset,
ddr_base + par->fb_offset, xdr_base + par->pan_offset,
- par->width, par->height, ddr_line_length,
- xdr_line_length);
+ par->width, par->height, par->ddr_line_length,
+ info->fix.line_length);
out:
return error;
{
struct ps3fb_par *par = info->par;
unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines;
- int i;
- unsigned long offset;
+ unsigned int ddr_xoff, ddr_yoff, offset;
+ const struct fb_videomode *vmode;
u64 dst;
dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n",
if (!mode)
return -EINVAL;
- i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);
- par->res_index = i;
+ vmode = ps3fb_native_vmode(mode & PS3AV_MODE_MASK);
info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
info->fix.smem_len = ps3fb.xdr_size;
info->screen_base = (char __iomem *)ps3fb.xdr_ea;
+ par->ddr_line_length = ddr_line_length;
+ par->ddr_frame_size = vmode->yres * ddr_line_length;
+ par->xdr_frame_size = info->var.yres_virtual * xdr_line_length;
+
par->num_frames = ps3fb.xdr_size /
- max(ps3fb_res[i].yres * ddr_line_length,
- info->var.yres_virtual * xdr_line_length);
+ max(par->ddr_frame_size, par->xdr_frame_size);
/* Keep the special bits we cannot set using fb_var_screeninfo */
par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
par->width = info->var.xres;
par->height = info->var.yres;
- offset = VP_OFF(i);
+
+ /* Start of the virtual frame buffer (relative to fullscreen) */
+ ddr_xoff = info->var.left_margin - vmode->left_margin;
+ ddr_yoff = info->var.upper_margin - vmode->upper_margin;
+ offset = ddr_yoff * ddr_line_length + ddr_xoff * BPP;
+
par->fb_offset = GPU_ALIGN_UP(offset);
par->full_offset = par->fb_offset - offset;
par->pan_offset = info->var.yoffset * xdr_line_length +
memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
/* Clear DDR frame buffer memory */
- lines = ps3fb_res[i].yres * par->num_frames;
+ lines = vmode->yres * par->num_frames;
if (par->full_offset)
lines++;
maxlines = ps3fb.xdr_size / ddr_line_length;
for (dst = 0; lines; dst += maxlines * ddr_line_length) {
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, vmode->xres, l,
ddr_line_length, ddr_line_length);
lines -= l;
}
case PS3FB_IOCTL_SETMODE:
{
struct ps3fb_par *par = info->par;
- const struct fb_videomode *mode;
+ const struct fb_videomode *vmode;
struct fb_var_screeninfo var;
if (copy_from_user(&val, argp, sizeof(val)))
}
dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);
retval = -EINVAL;
- mode = ps3fb_default_mode(val);
- if (mode) {
+ vmode = ps3fb_vmode(val);
+ if (vmode) {
var = info->var;
- fb_videomode_to_var(&var, mode);
+ fb_videomode_to_var(&var, vmode);
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
/* Force, in case only special bits changed */
struct fb_info *info;
struct ps3fb_par *par;
int retval = -ENOMEM;
- u32 xres, yres;
u64 ddr_lpar = 0;
u64 lpar_dma_control = 0;
u64 lpar_driver_info = 0;
u64 lpar_reports = 0;
u64 lpar_reports_size = 0;
u64 xdr_lpar;
- int status, res_index;
+ int status;
struct task_struct *task;
unsigned long max_ps3fb_size;
ps3fb_mode = ps3av_get_mode();
dev_dbg(&dev->core, "ps3fb_mode: %d\n", ps3fb_mode);
- if (ps3fb_mode > 0 &&
- !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
- res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode);
- dev_dbg(&dev->core, "res_index:%d\n", res_index);
- } else
- 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);
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;
info->screen_base = (char __iomem *)ps3fb.xdr_ea;
if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
ARRAY_SIZE(ps3fb_modedb),
- ps3fb_default_mode(par->new_mode_id), 32)) {
+ ps3fb_vmode(par->new_mode_id), 32)) {
retval = -EINVAL;
goto err_fb_dealloc;
}