aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/ps3fb.c131
1 files changed, 75 insertions, 56 deletions
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index d6160e016b33..88e15d4b5684 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -54,6 +54,7 @@
54#define DDR_SIZE (0) /* used no ddr */ 54#define DDR_SIZE (0) /* used no ddr */
55#define GPU_CMD_BUF_SIZE (64 * 1024) 55#define GPU_CMD_BUF_SIZE (64 * 1024)
56#define GPU_IOIF (0x0d000000UL) 56#define GPU_IOIF (0x0d000000UL)
57#define GPU_ALIGN_UP(x) _ALIGN_UP((x), 64)
57 58
58#define PS3FB_FULL_MODE_BIT 0x80 59#define PS3FB_FULL_MODE_BIT 0x80
59 60
@@ -136,6 +137,10 @@ struct ps3fb_par {
136 int mode_id, new_mode_id; 137 int mode_id, new_mode_id;
137 int res_index; 138 int res_index;
138 unsigned int num_frames; /* num of frame buffers */ 139 unsigned int num_frames; /* num of frame buffers */
140 unsigned int width;
141 unsigned int height;
142 unsigned long full_offset; /* start of fullscreen DDR fb */
143 unsigned long fb_offset; /* start of actual DDR fb */
139}; 144};
140 145
141struct ps3fb_res_table { 146struct ps3fb_res_table {
@@ -291,15 +296,6 @@ static const struct fb_videomode ps3fb_modedb[] = {
291/* Start of the virtual frame buffer (relative to fullscreen ) */ 296/* Start of the virtual frame buffer (relative to fullscreen ) */
292#define VP_OFF(i) ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP) 297#define VP_OFF(i) ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP)
293 298
294/*
295 * Start of the virtual frame buffer (relative to start of video memory)
296 * This is PAGE_SIZE aligned for easier mmap()
297 */
298#define VFB_OFF(i) PAGE_ALIGN(VP_OFF(i))
299
300/* Start of the fullscreen frame buffer (relative to start of video memory) */
301#define FB_OFF(i) (-VP_OFF(i) & ~PAGE_MASK)
302
303 299
304static int ps3fb_mode; 300static int ps3fb_mode;
305module_param(ps3fb_mode, int, 0); 301module_param(ps3fb_mode, int, 0);
@@ -386,63 +382,72 @@ static const struct fb_videomode *ps3fb_default_mode(int id)
386 return &ps3fb_modedb[mode - 1]; 382 return &ps3fb_modedb[mode - 1];
387} 383}
388 384
389static int ps3fb_sync(struct fb_info *info, u32 frame) 385static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
386 u64 dst_offset, u64 src_offset, u32 width,
387 u32 height, u64 line_length)
390{ 388{
391 struct ps3fb_par *par = info->par; 389 int status;
392 int i, status, error = 0;
393 u32 xres, yres;
394 u64 fb_ioif, offset;
395
396 acquire_console_sem();
397
398 i = par->res_index;
399 xres = ps3fb_res[i].xres;
400 yres = ps3fb_res[i].yres;
401
402 if (frame > par->num_frames - 1) {
403 dev_dbg(info->device, "%s: invalid frame number (%u)\n",
404 __func__, frame);
405 error = -EINVAL;
406 goto out;
407 }
408 offset = xres * yres * BPP * frame;
409 390
410 fb_ioif = GPU_IOIF + FB_OFF(i) + offset;
411 status = lv1_gpu_context_attribute(ps3fb.context_handle, 391 status = lv1_gpu_context_attribute(ps3fb.context_handle,
412 L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 392 L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
413 offset, fb_ioif, 393 dst_offset, GPU_IOIF + src_offset,
414 L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | 394 L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
415 (xres << 16) | yres, 395 (width << 16) | height,
416 xres * BPP); /* line_length */ 396 line_length);
417 if (status) 397 if (status)
418 dev_err(info->device, 398 dev_err(dev,
419 "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", 399 "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
420 __func__, status); 400 __func__, status);
421#ifdef HEAD_A 401#ifdef HEAD_A
422 status = lv1_gpu_context_attribute(ps3fb.context_handle, 402 status = lv1_gpu_context_attribute(ps3fb.context_handle,
423 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 403 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
424 0, offset, 0, 0); 404 0, frame_offset, 0, 0);
425 if (status) 405 if (status)
426 dev_err(info->device, 406 dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
427 "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
428 __func__, status); 407 __func__, status);
429#endif 408#endif
430#ifdef HEAD_B 409#ifdef HEAD_B
431 status = lv1_gpu_context_attribute(ps3fb.context_handle, 410 status = lv1_gpu_context_attribute(ps3fb.context_handle,
432 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 411 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
433 1, offset, 0, 0); 412 1, frame_offset, 0, 0);
434 if (status) 413 if (status)
435 dev_err(info->device, 414 dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
436 "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
437 __func__, status); 415 __func__, status);
438#endif 416#endif
417}
418
419static int ps3fb_sync(struct fb_info *info, u32 frame)
420{
421 struct ps3fb_par *par = info->par;
422 int i, error = 0;
423 u32 xres, yres;
424 u64 line_length, base;
425
426 acquire_console_sem();
427
428 if (frame > par->num_frames - 1) {
429 dev_dbg(info->device, "%s: invalid frame number (%u)\n",
430 __func__, frame);
431 error = -EINVAL;
432 goto out;
433 }
434
435 i = par->res_index;
436 xres = ps3fb_res[i].xres;
437 yres = ps3fb_res[i].yres;
438
439 line_length = xres * BPP;
440 base = frame * yres * line_length;
441
442 ps3fb_sync_image(info->device, base + par->full_offset,
443 base + par->fb_offset, base, par->width, par->height,
444 line_length);
439 445
440out: 446out:
441 release_console_sem(); 447 release_console_sem();
442 return error; 448 return error;
443} 449}
444 450
445
446static int ps3fb_open(struct fb_info *info, int user) 451static int ps3fb_open(struct fb_info *info, int user)
447{ 452{
448 atomic_inc(&ps3fb.f_count); 453 atomic_inc(&ps3fb.f_count);
@@ -472,7 +477,6 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
472{ 477{
473 u32 line_length; 478 u32 line_length;
474 int mode; 479 int mode;
475 int i;
476 480
477 dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres, 481 dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres,
478 info->var.xres); 482 info->var.xres);
@@ -539,9 +543,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
539 } 543 }
540 544
541 /* Memory limit */ 545 /* Memory limit */
542 i = ps3fb_get_res_table(var->xres, var->yres, mode); 546 if (var->yres * line_length > ps3fb.xdr_size) {
543 if (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP >
544 ps3fb.xdr_size - VFB_OFF(i)) {
545 dev_dbg(info->device, "Not enough memory\n"); 547 dev_dbg(info->device, "Not enough memory\n");
546 return -ENOMEM; 548 return -ENOMEM;
547 } 549 }
@@ -559,9 +561,9 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
559static int ps3fb_set_par(struct fb_info *info) 561static int ps3fb_set_par(struct fb_info *info)
560{ 562{
561 struct ps3fb_par *par = info->par; 563 struct ps3fb_par *par = info->par;
562 unsigned int mode; 564 unsigned int mode, lines, maxlines;
563 int i; 565 int i;
564 unsigned long offset; 566 unsigned long offset, dst;
565 567
566 dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n", 568 dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n",
567 info->var.xres, info->var.xres_virtual, 569 info->var.xres, info->var.xres_virtual,
@@ -574,11 +576,9 @@ static int ps3fb_set_par(struct fb_info *info)
574 i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode); 576 i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);
575 par->res_index = i; 577 par->res_index = i;
576 578
577 offset = VFB_OFF(i); 579 info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
578 info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea) + offset; 580 info->fix.smem_len = ps3fb.xdr_size;
579 info->fix.smem_len = ps3fb.xdr_size - offset; 581 info->screen_base = (char __iomem *)ps3fb.xdr_ea;
580 info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
581 memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
582 582
583 par->num_frames = info->fix.smem_len/ 583 par->num_frames = info->fix.smem_len/
584 (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP); 584 (ps3fb_res[i].xres*ps3fb_res[i].yres*BPP);
@@ -586,6 +586,12 @@ static int ps3fb_set_par(struct fb_info *info)
586 /* Keep the special bits we cannot set using fb_var_screeninfo */ 586 /* Keep the special bits we cannot set using fb_var_screeninfo */
587 par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode; 587 par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
588 588
589 par->width = info->var.xres;
590 par->height = info->var.yres;
591 offset = VP_OFF(i);
592 par->fb_offset = GPU_ALIGN_UP(offset);
593 par->full_offset = par->fb_offset - offset;
594
589 if (par->new_mode_id != par->mode_id) { 595 if (par->new_mode_id != par->mode_id) {
590 if (ps3av_set_video_mode(par->new_mode_id)) { 596 if (ps3av_set_video_mode(par->new_mode_id)) {
591 par->new_mode_id = par->mode_id; 597 par->new_mode_id = par->mode_id;
@@ -594,6 +600,21 @@ static int ps3fb_set_par(struct fb_info *info)
594 par->mode_id = par->new_mode_id; 600 par->mode_id = par->new_mode_id;
595 } 601 }
596 602
603 /* Clear XDR frame buffer memory */
604 memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
605
606 /* Clear DDR frame buffer memory */
607 lines = ps3fb_res[i].yres * par->num_frames;
608 if (par->full_offset)
609 lines++;
610 maxlines = ps3fb.xdr_size / info->fix.line_length;
611 for (dst = 0; lines; dst += maxlines * info->fix.line_length) {
612 unsigned int l = min(lines, maxlines);
613 ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,
614 info->fix.line_length);
615 lines -= l;
616 }
617
597 return 0; 618 return 0;
598} 619}
599 620
@@ -1005,7 +1026,6 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
1005 u64 lpar_reports_size = 0; 1026 u64 lpar_reports_size = 0;
1006 u64 xdr_lpar; 1027 u64 xdr_lpar;
1007 int status, res_index; 1028 int status, res_index;
1008 unsigned long offset;
1009 struct task_struct *task; 1029 struct task_struct *task;
1010 1030
1011 status = ps3_open_hv_device(dev); 1031 status = ps3_open_hv_device(dev);
@@ -1088,13 +1108,12 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
1088 par->res_index = res_index; 1108 par->res_index = res_index;
1089 par->num_frames = 1; 1109 par->num_frames = 1;
1090 1110
1091 offset = VFB_OFF(res_index); 1111 info->screen_base = (char __iomem *)ps3fb.xdr_ea;
1092 info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
1093 info->fbops = &ps3fb_ops; 1112 info->fbops = &ps3fb_ops;
1094 1113
1095 info->fix = ps3fb_fix; 1114 info->fix = ps3fb_fix;
1096 info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea) + offset; 1115 info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
1097 info->fix.smem_len = ps3fb.xdr_size - offset; 1116 info->fix.smem_len = ps3fb.xdr_size;
1098 info->pseudo_palette = par->pseudo_palette; 1117 info->pseudo_palette = par->pseudo_palette;
1099 info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST; 1118 info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
1100 1119