aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/ps3fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/ps3fb.c')
-rw-r--r--drivers/video/ps3fb.c116
1 files changed, 73 insertions, 43 deletions
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 81e43cda7d8b..07d1979bc23e 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -32,6 +32,8 @@
32#include <linux/ioctl.h> 32#include <linux/ioctl.h>
33#include <linux/notifier.h> 33#include <linux/notifier.h>
34#include <linux/reboot.h> 34#include <linux/reboot.h>
35#include <linux/kthread.h>
36#include <linux/freezer.h>
35 37
36#include <asm/uaccess.h> 38#include <asm/uaccess.h>
37#include <linux/fb.h> 39#include <linux/fb.h>
@@ -45,7 +47,7 @@
45#include <asm/ps3.h> 47#include <asm/ps3.h>
46 48
47#ifdef PS3FB_DEBUG 49#ifdef PS3FB_DEBUG
48#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args) 50#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args)
49#else 51#else
50#define DPRINTK(fmt, args...) 52#define DPRINTK(fmt, args...)
51#endif 53#endif
@@ -129,7 +131,6 @@ struct ps3fb_priv {
129 u64 context_handle, memory_handle; 131 u64 context_handle, memory_handle;
130 void *xdr_ea; 132 void *xdr_ea;
131 struct gpu_driver_info *dinfo; 133 struct gpu_driver_info *dinfo;
132 struct semaphore sem;
133 u32 res_index; 134 u32 res_index;
134 135
135 u64 vblank_count; /* frame count */ 136 u64 vblank_count; /* frame count */
@@ -139,6 +140,8 @@ struct ps3fb_priv {
139 atomic_t ext_flip; /* on/off flip with vsync */ 140 atomic_t ext_flip; /* on/off flip with vsync */
140 atomic_t f_count; /* fb_open count */ 141 atomic_t f_count; /* fb_open count */
141 int is_blanked; 142 int is_blanked;
143 int is_kicked;
144 struct task_struct *task;
142}; 145};
143static struct ps3fb_priv ps3fb; 146static struct ps3fb_priv ps3fb;
144 147
@@ -294,10 +297,10 @@ static const struct fb_videomode ps3fb_modedb[] = {
294#define VP_OFF(i) (WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP) 297#define VP_OFF(i) (WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP)
295#define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) 298#define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
296 299
297static int ps3fb_mode = 0; 300static int ps3fb_mode;
298module_param(ps3fb_mode, bool, 0); 301module_param(ps3fb_mode, bool, 0);
299 302
300static char *mode_option __initdata = NULL; 303static char *mode_option __initdata;
301 304
302 305
303static int ps3fb_get_res_table(u32 xres, u32 yres) 306static int ps3fb_get_res_table(u32 xres, u32 yres)
@@ -393,7 +396,7 @@ static int ps3fb_sync(u32 frame)
393 396
394 if (frame > ps3fb.num_frames - 1) { 397 if (frame > ps3fb.num_frames - 1) {
395 printk(KERN_WARNING "%s: invalid frame number (%u)\n", 398 printk(KERN_WARNING "%s: invalid frame number (%u)\n",
396 __FUNCTION__, frame); 399 __func__, frame);
397 return -EINVAL; 400 return -EINVAL;
398 } 401 }
399 offset = xres * yres * BPP * frame; 402 offset = xres * yres * BPP * frame;
@@ -406,23 +409,26 @@ static int ps3fb_sync(u32 frame)
406 (xres << 16) | yres, 409 (xres << 16) | yres,
407 xres * BPP); /* line_length */ 410 xres * BPP); /* line_length */
408 if (status) 411 if (status)
409 printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", 412 printk(KERN_ERR
410 __FUNCTION__, status); 413 "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
414 __func__, status);
411#ifdef HEAD_A 415#ifdef HEAD_A
412 status = lv1_gpu_context_attribute(ps3fb.context_handle, 416 status = lv1_gpu_context_attribute(ps3fb.context_handle,
413 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 417 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
414 0, offset, 0, 0); 418 0, offset, 0, 0);
415 if (status) 419 if (status)
416 printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n", 420 printk(KERN_ERR
417 __FUNCTION__, status); 421 "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
422 __func__, status);
418#endif 423#endif
419#ifdef HEAD_B 424#ifdef HEAD_B
420 status = lv1_gpu_context_attribute(ps3fb.context_handle, 425 status = lv1_gpu_context_attribute(ps3fb.context_handle,
421 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 426 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
422 1, offset, 0, 0); 427 1, offset, 0, 0);
423 if (status) 428 if (status)
424 printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n", 429 printk(KERN_ERR
425 __FUNCTION__, status); 430 "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
431 __func__, status);
426#endif 432#endif
427 return 0; 433 return 0;
428} 434}
@@ -631,7 +637,7 @@ static int ps3fb_blank(int blank, struct fb_info *info)
631{ 637{
632 int retval; 638 int retval;
633 639
634 DPRINTK("%s: blank:%d\n", __FUNCTION__, blank); 640 DPRINTK("%s: blank:%d\n", __func__, blank);
635 switch (blank) { 641 switch (blank) {
636 case FB_BLANK_POWERDOWN: 642 case FB_BLANK_POWERDOWN:
637 case FB_BLANK_HSYNC_SUSPEND: 643 case FB_BLANK_HSYNC_SUSPEND:
@@ -677,13 +683,10 @@ EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
677 683
678void ps3fb_flip_ctl(int on) 684void ps3fb_flip_ctl(int on)
679{ 685{
680 if (on) { 686 if (on)
681 if (atomic_read(&ps3fb.ext_flip) > 0) { 687 atomic_dec_if_positive(&ps3fb.ext_flip);
682 atomic_dec(&ps3fb.ext_flip); 688 else
683 }
684 } else {
685 atomic_inc(&ps3fb.ext_flip); 689 atomic_inc(&ps3fb.ext_flip);
686 }
687} 690}
688 691
689EXPORT_SYMBOL_GPL(ps3fb_flip_ctl); 692EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
@@ -732,6 +735,11 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
732 if (copy_from_user(&val, argp, sizeof(val))) 735 if (copy_from_user(&val, argp, sizeof(val)))
733 break; 736 break;
734 737
738 if (!(val & PS3AV_MODE_MASK)) {
739 u32 id = ps3av_get_auto_mode(0);
740 if (id > 0)
741 val = (val & ~PS3AV_MODE_MASK) | id;
742 }
735 DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val); 743 DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val);
736 retval = -EINVAL; 744 retval = -EINVAL;
737 old_mode = ps3fb_mode; 745 old_mode = ps3fb_mode;
@@ -783,8 +791,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
783 791
784 case PS3FB_IOCTL_OFF: 792 case PS3FB_IOCTL_OFF:
785 DPRINTK("PS3FB_IOCTL_OFF:\n"); 793 DPRINTK("PS3FB_IOCTL_OFF:\n");
786 if (atomic_read(&ps3fb.ext_flip) > 0) 794 atomic_dec_if_positive(&ps3fb.ext_flip);
787 atomic_dec(&ps3fb.ext_flip);
788 retval = 0; 795 retval = 0;
789 break; 796 break;
790 797
@@ -805,11 +812,14 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
805 812
806static int ps3fbd(void *arg) 813static int ps3fbd(void *arg)
807{ 814{
808 daemonize("ps3fbd"); 815 while (!kthread_should_stop()) {
809 for (;;) { 816 try_to_freeze();
810 down(&ps3fb.sem); 817 set_current_state(TASK_INTERRUPTIBLE);
811 if (atomic_read(&ps3fb.ext_flip) == 0) 818 if (ps3fb.is_kicked) {
819 ps3fb.is_kicked = 0;
812 ps3fb_sync(0); /* single buffer */ 820 ps3fb_sync(0); /* single buffer */
821 }
822 schedule();
813 } 823 }
814 return 0; 824 return 0;
815} 825}
@@ -823,15 +833,18 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
823 status = lv1_gpu_context_intr(ps3fb.context_handle, &v1); 833 status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
824 if (status) { 834 if (status) {
825 printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n", 835 printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n",
826 __FUNCTION__, status); 836 __func__, status);
827 return IRQ_NONE; 837 return IRQ_NONE;
828 } 838 }
829 839
830 if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) { 840 if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) {
831 /* VSYNC */ 841 /* VSYNC */
832 ps3fb.vblank_count = head->vblank_count; 842 ps3fb.vblank_count = head->vblank_count;
833 if (!ps3fb.is_blanked) 843 if (ps3fb.task && !ps3fb.is_blanked &&
834 up(&ps3fb.sem); 844 !atomic_read(&ps3fb.ext_flip)) {
845 ps3fb.is_kicked = 1;
846 wake_up_process(ps3fb.task);
847 }
835 wake_up_interruptible(&ps3fb.wait_vsync); 848 wake_up_interruptible(&ps3fb.wait_vsync);
836 } 849 }
837 850
@@ -879,7 +892,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
879 dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); 892 dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
880 893
881 if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { 894 if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
882 printk(KERN_ERR "%s: version_driver err:%x\n", __FUNCTION__, 895 printk(KERN_ERR "%s: version_driver err:%x\n", __func__,
883 dinfo->version_driver); 896 dinfo->version_driver);
884 return -EINVAL; 897 return -EINVAL;
885 } 898 }
@@ -888,7 +901,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
888 error = ps3_alloc_irq(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, 901 error = ps3_alloc_irq(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
889 &ps3fb.irq_no); 902 &ps3fb.irq_no);
890 if (error) { 903 if (error) {
891 printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __FUNCTION__, 904 printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __func__,
892 error); 905 error);
893 return error; 906 return error;
894 } 907 }
@@ -896,7 +909,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
896 error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, 909 error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
897 "ps3fb vsync", ps3fb.dev); 910 "ps3fb vsync", ps3fb.dev);
898 if (error) { 911 if (error) {
899 printk(KERN_ERR "%s: request_irq failed %d\n", __FUNCTION__, 912 printk(KERN_ERR "%s: request_irq failed %d\n", __func__,
900 error); 913 error);
901 ps3_free_irq(ps3fb.irq_no); 914 ps3_free_irq(ps3fb.irq_no);
902 return error; 915 return error;
@@ -915,7 +928,7 @@ static int ps3fb_xdr_settings(u64 xdr_lpar)
915 xdr_lpar, ps3fb_videomemory.size, 0); 928 xdr_lpar, ps3fb_videomemory.size, 0);
916 if (status) { 929 if (status) {
917 printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n", 930 printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n",
918 __FUNCTION__, status); 931 __func__, status);
919 return -ENXIO; 932 return -ENXIO;
920 } 933 }
921 DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n", 934 DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
@@ -927,8 +940,9 @@ static int ps3fb_xdr_settings(u64 xdr_lpar)
927 xdr_lpar, ps3fb_videomemory.size, 940 xdr_lpar, ps3fb_videomemory.size,
928 GPU_IOIF, 0); 941 GPU_IOIF, 0);
929 if (status) { 942 if (status) {
930 printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", 943 printk(KERN_ERR
931 __FUNCTION__, status); 944 "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
945 __func__, status);
932 return -ENXIO; 946 return -ENXIO;
933 } 947 }
934 return 0; 948 return 0;
@@ -968,13 +982,14 @@ static int __init ps3fb_probe(struct platform_device *dev)
968 u64 xdr_lpar; 982 u64 xdr_lpar;
969 int status; 983 int status;
970 unsigned long offset; 984 unsigned long offset;
985 struct task_struct *task;
971 986
972 /* get gpu context handle */ 987 /* get gpu context handle */
973 status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, 988 status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
974 &ps3fb.memory_handle, &ddr_lpar); 989 &ps3fb.memory_handle, &ddr_lpar);
975 if (status) { 990 if (status) {
976 printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n", 991 printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n",
977 __FUNCTION__, status); 992 __func__, status);
978 goto err; 993 goto err;
979 } 994 }
980 DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar); 995 DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar);
@@ -985,14 +1000,14 @@ static int __init ps3fb_probe(struct platform_device *dev)
985 &lpar_reports, &lpar_reports_size); 1000 &lpar_reports, &lpar_reports_size);
986 if (status) { 1001 if (status) {
987 printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n", 1002 printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n",
988 __FUNCTION__, status); 1003 __func__, status);
989 goto err_gpu_memory_free; 1004 goto err_gpu_memory_free;
990 } 1005 }
991 1006
992 /* vsync interrupt */ 1007 /* vsync interrupt */
993 ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024); 1008 ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
994 if (!ps3fb.dinfo) { 1009 if (!ps3fb.dinfo) {
995 printk(KERN_ERR "%s: ioremap failed\n", __FUNCTION__); 1010 printk(KERN_ERR "%s: ioremap failed\n", __func__);
996 goto err_gpu_context_free; 1011 goto err_gpu_context_free;
997 } 1012 }
998 1013
@@ -1050,9 +1065,18 @@ static int __init ps3fb_probe(struct platform_device *dev)
1050 "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", 1065 "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
1051 info->node, ps3fb_videomemory.size >> 10); 1066 info->node, ps3fb_videomemory.size >> 10);
1052 1067
1053 kernel_thread(ps3fbd, info, CLONE_KERNEL); 1068 task = kthread_run(ps3fbd, info, "ps3fbd");
1069 if (IS_ERR(task)) {
1070 retval = PTR_ERR(task);
1071 goto err_unregister_framebuffer;
1072 }
1073
1074 ps3fb.task = task;
1075
1054 return 0; 1076 return 0;
1055 1077
1078err_unregister_framebuffer:
1079 unregister_framebuffer(info);
1056err_fb_dealloc: 1080err_fb_dealloc:
1057 fb_dealloc_cmap(&info->cmap); 1081 fb_dealloc_cmap(&info->cmap);
1058err_framebuffer_release: 1082err_framebuffer_release:
@@ -1083,6 +1107,11 @@ void ps3fb_cleanup(void)
1083{ 1107{
1084 int status; 1108 int status;
1085 1109
1110 if (ps3fb.task) {
1111 struct task_struct *task = ps3fb.task;
1112 ps3fb.task = NULL;
1113 kthread_stop(task);
1114 }
1086 if (ps3fb.irq_no) { 1115 if (ps3fb.irq_no) {
1087 free_irq(ps3fb.irq_no, ps3fb.dev); 1116 free_irq(ps3fb.irq_no, ps3fb.dev);
1088 ps3_free_irq(ps3fb.irq_no); 1117 ps3_free_irq(ps3fb.irq_no);
@@ -1137,8 +1166,9 @@ int ps3fb_set_sync(void)
1137 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, 1166 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
1138 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); 1167 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
1139 if (status) { 1168 if (status) {
1140 printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n", 1169 printk(KERN_ERR
1141 __FUNCTION__, status); 1170 "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
1171 __func__, status);
1142 return -1; 1172 return -1;
1143 } 1173 }
1144#endif 1174#endif
@@ -1148,8 +1178,9 @@ int ps3fb_set_sync(void)
1148 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); 1178 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
1149 1179
1150 if (status) { 1180 if (status) {
1151 printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n", 1181 printk(KERN_ERR
1152 __FUNCTION__, status); 1182 "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
1183 __func__, status);
1153 return -1; 1184 return -1;
1154 } 1185 }
1155#endif 1186#endif
@@ -1174,7 +1205,7 @@ static int __init ps3fb_init(void)
1174 1205
1175 error = ps3av_dev_open(); 1206 error = ps3av_dev_open();
1176 if (error) { 1207 if (error) {
1177 printk(KERN_ERR "%s: ps3av_dev_open failed\n", __FUNCTION__); 1208 printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__);
1178 goto err; 1209 goto err;
1179 } 1210 }
1180 1211
@@ -1195,7 +1226,6 @@ static int __init ps3fb_init(void)
1195 1226
1196 atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ 1227 atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
1197 atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ 1228 atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
1198 init_MUTEX(&ps3fb.sem);
1199 init_waitqueue_head(&ps3fb.wait_vsync); 1229 init_waitqueue_head(&ps3fb.wait_vsync);
1200 ps3fb.num_frames = 1; 1230 ps3fb.num_frames = 1;
1201 1231