diff options
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/ps3fb.c | 108 |
1 files changed, 22 insertions, 86 deletions
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 229727a5bc75..b9c5b4e122c7 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c | |||
@@ -134,42 +134,17 @@ static struct ps3fb_priv ps3fb; | |||
134 | struct ps3fb_par { | 134 | struct ps3fb_par { |
135 | u32 pseudo_palette[16]; | 135 | u32 pseudo_palette[16]; |
136 | int mode_id, new_mode_id; | 136 | int mode_id, new_mode_id; |
137 | int res_index; | ||
138 | unsigned int num_frames; /* num of frame buffers */ | 137 | unsigned int num_frames; /* num of frame buffers */ |
139 | unsigned int width; | 138 | unsigned int width; |
140 | unsigned int height; | 139 | unsigned int height; |
140 | unsigned int ddr_line_length; | ||
141 | unsigned int ddr_frame_size; | ||
142 | unsigned int xdr_frame_size; | ||
141 | unsigned long full_offset; /* start of fullscreen DDR fb */ | 143 | unsigned long full_offset; /* start of fullscreen DDR fb */ |
142 | unsigned long fb_offset; /* start of actual DDR fb */ | 144 | unsigned long fb_offset; /* start of actual DDR fb */ |
143 | unsigned long pan_offset; | 145 | unsigned long pan_offset; |
144 | }; | 146 | }; |
145 | 147 | ||
146 | struct ps3fb_res_table { | ||
147 | u32 xres; | ||
148 | u32 yres; | ||
149 | u32 xoff; | ||
150 | u32 yoff; | ||
151 | u32 type; | ||
152 | }; | ||
153 | #define PS3FB_RES_FULL 1 | ||
154 | static const struct ps3fb_res_table ps3fb_res[] = { | ||
155 | /* res_x,y margin_x,y full */ | ||
156 | { 720, 480, 72, 48 , 0}, | ||
157 | { 720, 576, 72, 58 , 0}, | ||
158 | { 1280, 720, 78, 38 , 0}, | ||
159 | { 1920, 1080, 116, 58 , 0}, | ||
160 | /* full mode */ | ||
161 | { 720, 480, 0, 0 , PS3FB_RES_FULL}, | ||
162 | { 720, 576, 0, 0 , PS3FB_RES_FULL}, | ||
163 | { 1280, 720, 0, 0 , PS3FB_RES_FULL}, | ||
164 | { 1920, 1080, 0, 0 , PS3FB_RES_FULL}, | ||
165 | /* vesa: normally full mode */ | ||
166 | { 1280, 768, 0, 0 , 0}, | ||
167 | { 1280, 1024, 0, 0 , 0}, | ||
168 | { 1920, 1200, 0, 0 , 0}, | ||
169 | { 0, 0, 0, 0 , 0} }; | ||
170 | |||
171 | /* default resolution */ | ||
172 | #define GPU_RES_INDEX 0 /* 720 x 480 */ | ||
173 | 148 | ||
174 | static const struct fb_videomode ps3fb_modedb[] = { | 149 | static const struct fb_videomode ps3fb_modedb[] = { |
175 | /* 60 Hz broadcast modes (modes "1" to "5") */ | 150 | /* 60 Hz broadcast modes (modes "1" to "5") */ |
@@ -295,37 +270,6 @@ module_param(ps3fb_mode, int, 0); | |||
295 | 270 | ||
296 | static char *mode_option __devinitdata; | 271 | static char *mode_option __devinitdata; |
297 | 272 | ||
298 | static int ps3fb_get_res_table(u32 xres, u32 yres, int mode) | ||
299 | { | ||
300 | int full_mode; | ||
301 | unsigned int i; | ||
302 | u32 x, y, f; | ||
303 | |||
304 | full_mode = (mode & PS3AV_MODE_FULL) ? PS3FB_RES_FULL : 0; | ||
305 | for (i = 0;; i++) { | ||
306 | x = ps3fb_res[i].xres; | ||
307 | y = ps3fb_res[i].yres; | ||
308 | f = ps3fb_res[i].type; | ||
309 | |||
310 | if (!x) { | ||
311 | pr_debug("ERROR: ps3fb_get_res_table()\n"); | ||
312 | return -1; | ||
313 | } | ||
314 | |||
315 | if (full_mode == PS3FB_RES_FULL && f != PS3FB_RES_FULL) | ||
316 | continue; | ||
317 | |||
318 | if (x == xres && (yres == 0 || y == yres)) | ||
319 | break; | ||
320 | |||
321 | x = x - 2 * ps3fb_res[i].xoff; | ||
322 | y = y - 2 * ps3fb_res[i].yoff; | ||
323 | if (x == xres && (yres == 0 || y == yres)) | ||
324 | break; | ||
325 | } | ||
326 | return i; | ||
327 | } | ||
328 | |||
329 | static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var, | 273 | static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var, |
330 | u32 *ddr_line_length, u32 *xdr_line_length) | 274 | u32 *ddr_line_length, u32 *xdr_line_length) |
331 | { | 275 | { |
@@ -433,8 +377,7 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset, | |||
433 | static int ps3fb_sync(struct fb_info *info, u32 frame) | 377 | static int ps3fb_sync(struct fb_info *info, u32 frame) |
434 | { | 378 | { |
435 | struct ps3fb_par *par = info->par; | 379 | struct ps3fb_par *par = info->par; |
436 | int i, error = 0; | 380 | int error = 0; |
437 | u32 ddr_line_length, xdr_line_length; | ||
438 | u64 ddr_base, xdr_base; | 381 | u64 ddr_base, xdr_base; |
439 | 382 | ||
440 | if (frame > par->num_frames - 1) { | 383 | if (frame > par->num_frames - 1) { |
@@ -444,16 +387,13 @@ static int ps3fb_sync(struct fb_info *info, u32 frame) | |||
444 | goto out; | 387 | goto out; |
445 | } | 388 | } |
446 | 389 | ||
447 | i = par->res_index; | 390 | xdr_base = frame * par->xdr_frame_size; |
448 | xdr_line_length = info->fix.line_length; | 391 | ddr_base = frame * par->ddr_frame_size; |
449 | ddr_line_length = ps3fb_res[i].xres * BPP; | ||
450 | xdr_base = frame * info->var.yres_virtual * xdr_line_length; | ||
451 | ddr_base = frame * ps3fb_res[i].yres * ddr_line_length; | ||
452 | 392 | ||
453 | ps3fb_sync_image(info->device, ddr_base + par->full_offset, | 393 | ps3fb_sync_image(info->device, ddr_base + par->full_offset, |
454 | ddr_base + par->fb_offset, xdr_base + par->pan_offset, | 394 | ddr_base + par->fb_offset, xdr_base + par->pan_offset, |
455 | par->width, par->height, ddr_line_length, | 395 | par->width, par->height, par->ddr_line_length, |
456 | xdr_line_length); | 396 | info->fix.line_length); |
457 | 397 | ||
458 | out: | 398 | out: |
459 | return error; | 399 | return error; |
@@ -572,8 +512,9 @@ static int ps3fb_set_par(struct fb_info *info) | |||
572 | { | 512 | { |
573 | struct ps3fb_par *par = info->par; | 513 | struct ps3fb_par *par = info->par; |
574 | unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines; | 514 | unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines; |
575 | int i; | 515 | unsigned int ddr_xoff, ddr_yoff; |
576 | unsigned long offset; | 516 | unsigned long offset; |
517 | const struct fb_videomode *vmode; | ||
577 | u64 dst; | 518 | u64 dst; |
578 | 519 | ||
579 | dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n", | 520 | dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n", |
@@ -584,8 +525,7 @@ static int ps3fb_set_par(struct fb_info *info) | |||
584 | if (!mode) | 525 | if (!mode) |
585 | return -EINVAL; | 526 | return -EINVAL; |
586 | 527 | ||
587 | i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode); | 528 | vmode = ps3fb_default_mode(mode | PS3AV_MODE_FULL); |
588 | par->res_index = i; | ||
589 | 529 | ||
590 | info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); | 530 | info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); |
591 | info->fix.smem_len = ps3fb.xdr_size; | 531 | info->fix.smem_len = ps3fb.xdr_size; |
@@ -595,9 +535,12 @@ static int ps3fb_set_par(struct fb_info *info) | |||
595 | 535 | ||
596 | info->screen_base = (char __iomem *)ps3fb.xdr_ea; | 536 | info->screen_base = (char __iomem *)ps3fb.xdr_ea; |
597 | 537 | ||
538 | par->ddr_line_length = ddr_line_length; | ||
539 | par->ddr_frame_size = vmode->yres * ddr_line_length; | ||
540 | par->xdr_frame_size = info->var.yres_virtual * xdr_line_length; | ||
541 | |||
598 | par->num_frames = ps3fb.xdr_size / | 542 | par->num_frames = ps3fb.xdr_size / |
599 | max(ps3fb_res[i].yres * ddr_line_length, | 543 | max(par->ddr_frame_size, par->xdr_frame_size); |
600 | info->var.yres_virtual * xdr_line_length); | ||
601 | 544 | ||
602 | /* Keep the special bits we cannot set using fb_var_screeninfo */ | 545 | /* Keep the special bits we cannot set using fb_var_screeninfo */ |
603 | par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode; | 546 | par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode; |
@@ -606,7 +549,9 @@ static int ps3fb_set_par(struct fb_info *info) | |||
606 | par->height = info->var.yres; | 549 | par->height = info->var.yres; |
607 | 550 | ||
608 | /* Start of the virtual frame buffer (relative to fullscreen) */ | 551 | /* Start of the virtual frame buffer (relative to fullscreen) */ |
609 | offset = ps3fb_res[i].yoff * ddr_line_length + ps3fb_res[i].xoff * BPP; | 552 | ddr_xoff = info->var.left_margin - vmode->left_margin; |
553 | ddr_yoff = info->var.upper_margin - vmode->upper_margin; | ||
554 | offset = ddr_yoff * ddr_line_length + ddr_xoff * BPP; | ||
610 | 555 | ||
611 | par->fb_offset = GPU_ALIGN_UP(offset); | 556 | par->fb_offset = GPU_ALIGN_UP(offset); |
612 | par->full_offset = par->fb_offset - offset; | 557 | par->full_offset = par->fb_offset - offset; |
@@ -625,13 +570,13 @@ static int ps3fb_set_par(struct fb_info *info) | |||
625 | memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size); | 570 | memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size); |
626 | 571 | ||
627 | /* Clear DDR frame buffer memory */ | 572 | /* Clear DDR frame buffer memory */ |
628 | lines = ps3fb_res[i].yres * par->num_frames; | 573 | lines = vmode->yres * par->num_frames; |
629 | if (par->full_offset) | 574 | if (par->full_offset) |
630 | lines++; | 575 | lines++; |
631 | maxlines = ps3fb.xdr_size / ddr_line_length; | 576 | maxlines = ps3fb.xdr_size / ddr_line_length; |
632 | for (dst = 0; lines; dst += maxlines * ddr_line_length) { | 577 | for (dst = 0; lines; dst += maxlines * ddr_line_length) { |
633 | unsigned int l = min(lines, maxlines); | 578 | unsigned int l = min(lines, maxlines); |
634 | ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l, | 579 | ps3fb_sync_image(info->device, 0, dst, 0, vmode->xres, l, |
635 | ddr_line_length, ddr_line_length); | 580 | ddr_line_length, ddr_line_length); |
636 | lines -= l; | 581 | lines -= l; |
637 | } | 582 | } |
@@ -1052,14 +997,13 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
1052 | struct fb_info *info; | 997 | struct fb_info *info; |
1053 | struct ps3fb_par *par; | 998 | struct ps3fb_par *par; |
1054 | int retval = -ENOMEM; | 999 | int retval = -ENOMEM; |
1055 | u32 xres, yres; | ||
1056 | u64 ddr_lpar = 0; | 1000 | u64 ddr_lpar = 0; |
1057 | u64 lpar_dma_control = 0; | 1001 | u64 lpar_dma_control = 0; |
1058 | u64 lpar_driver_info = 0; | 1002 | u64 lpar_driver_info = 0; |
1059 | u64 lpar_reports = 0; | 1003 | u64 lpar_reports = 0; |
1060 | u64 lpar_reports_size = 0; | 1004 | u64 lpar_reports_size = 0; |
1061 | u64 xdr_lpar; | 1005 | u64 xdr_lpar; |
1062 | int status, res_index; | 1006 | int status; |
1063 | struct task_struct *task; | 1007 | struct task_struct *task; |
1064 | unsigned long max_ps3fb_size; | 1008 | unsigned long max_ps3fb_size; |
1065 | 1009 | ||
@@ -1079,13 +1023,6 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
1079 | ps3fb_mode = ps3av_get_mode(); | 1023 | ps3fb_mode = ps3av_get_mode(); |
1080 | dev_dbg(&dev->core, "ps3fb_mode: %d\n", ps3fb_mode); | 1024 | dev_dbg(&dev->core, "ps3fb_mode: %d\n", ps3fb_mode); |
1081 | 1025 | ||
1082 | if (ps3fb_mode > 0 && | ||
1083 | !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { | ||
1084 | res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode); | ||
1085 | dev_dbg(&dev->core, "res_index:%d\n", res_index); | ||
1086 | } else | ||
1087 | res_index = GPU_RES_INDEX; | ||
1088 | |||
1089 | atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ | 1026 | atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ |
1090 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ | 1027 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ |
1091 | init_waitqueue_head(&ps3fb.wait_vsync); | 1028 | init_waitqueue_head(&ps3fb.wait_vsync); |
@@ -1158,7 +1095,6 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
1158 | par = info->par; | 1095 | par = info->par; |
1159 | par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ | 1096 | par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ |
1160 | par->new_mode_id = ps3fb_mode; | 1097 | par->new_mode_id = ps3fb_mode; |
1161 | par->res_index = res_index; | ||
1162 | par->num_frames = 1; | 1098 | par->num_frames = 1; |
1163 | 1099 | ||
1164 | info->screen_base = (char __iomem *)ps3fb.xdr_ea; | 1100 | info->screen_base = (char __iomem *)ps3fb.xdr_ea; |