aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorGeert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>2007-06-15 18:05:38 -0400
committerPaul Mackerras <paulus@samba.org>2007-06-28 05:16:42 -0400
commit9e6b99bd4494dadebb189d2db4d1f55ae726b0bb (patch)
tree327eed606e5ff03d898d516f8728cbfb79672724 /drivers/video
parent13a5e30cf7407415387b5592b15ef4b352d28283 (diff)
[POWERPC] PS3: Frame buffer system-bus rework
Convert the ps3fb device from a platform device to a PS3 system bus device. Fix the remove and shutdown methods to support kexec and to make ps3fb a loadable module. Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com> Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig4
-rw-r--r--drivers/video/ps3fb.c290
2 files changed, 129 insertions, 165 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 403dac787ebf..9b7a76be36a0 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1790,8 +1790,8 @@ config FB_IBM_GXT4500
1790 adaptor, found on some IBM System P (pSeries) machines. 1790 adaptor, found on some IBM System P (pSeries) machines.
1791 1791
1792config FB_PS3 1792config FB_PS3
1793 bool "PS3 GPU framebuffer driver" 1793 tristate "PS3 GPU framebuffer driver"
1794 depends on (FB = y) && PS3_PS3AV 1794 depends on FB && PS3_PS3AV
1795 select FB_SYS_FILLRECT 1795 select FB_SYS_FILLRECT
1796 select FB_SYS_COPYAREA 1796 select FB_SYS_COPYAREA
1797 select FB_SYS_IMAGEBLIT 1797 select FB_SYS_IMAGEBLIT
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 9cf92ba5d6e3..08b7ffbbbbd8 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -27,7 +27,6 @@
27#include <linux/vmalloc.h> 27#include <linux/vmalloc.h>
28#include <linux/delay.h> 28#include <linux/delay.h>
29#include <linux/interrupt.h> 29#include <linux/interrupt.h>
30#include <linux/platform_device.h>
31#include <linux/console.h> 30#include <linux/console.h>
32#include <linux/ioctl.h> 31#include <linux/ioctl.h>
33#include <linux/notifier.h> 32#include <linux/notifier.h>
@@ -46,6 +45,9 @@
46#include <asm/ps3fb.h> 45#include <asm/ps3fb.h>
47#include <asm/ps3.h> 46#include <asm/ps3.h>
48 47
48
49#define DEVICE_NAME "ps3fb"
50
49#ifdef PS3FB_DEBUG 51#ifdef PS3FB_DEBUG
50#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) 52#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args)
51#else 53#else
@@ -126,7 +128,6 @@ struct gpu_driver_info {
126 128
127struct ps3fb_priv { 129struct ps3fb_priv {
128 unsigned int irq_no; 130 unsigned int irq_no;
129 void *dev;
130 131
131 u64 context_handle, memory_handle; 132 u64 context_handle, memory_handle;
132 void *xdr_ea; 133 void *xdr_ea;
@@ -171,7 +172,7 @@ static const struct ps3fb_res_table ps3fb_res[] = {
171 { 0, 0, 0, 0 , 0} }; 172 { 0, 0, 0, 0 , 0} };
172 173
173/* default resolution */ 174/* default resolution */
174#define GPU_RES_INDEX 0 /* 720 x 480 */ 175#define GPU_RES_INDEX 0 /* 720 x 480 */
175 176
176static const struct fb_videomode ps3fb_modedb[] = { 177static const struct fb_videomode ps3fb_modedb[] = {
177 /* 60 Hz broadcast modes (modes "1" to "5") */ 178 /* 60 Hz broadcast modes (modes "1" to "5") */
@@ -298,10 +299,9 @@ static const struct fb_videomode ps3fb_modedb[] = {
298#define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) 299#define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
299 300
300static int ps3fb_mode; 301static int ps3fb_mode;
301module_param(ps3fb_mode, bool, 0); 302module_param(ps3fb_mode, int, 0);
302
303static char *mode_option __initdata;
304 303
304static char *mode_option __devinitdata;
305 305
306static int ps3fb_get_res_table(u32 xres, u32 yres) 306static int ps3fb_get_res_table(u32 xres, u32 yres)
307{ 307{
@@ -681,15 +681,15 @@ int ps3fb_wait_for_vsync(u32 crtc)
681 681
682EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); 682EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
683 683
684void ps3fb_flip_ctl(int on) 684void ps3fb_flip_ctl(int on, void *data)
685{ 685{
686 struct ps3fb_priv *priv = data;
686 if (on) 687 if (on)
687 atomic_dec_if_positive(&ps3fb.ext_flip); 688 atomic_dec_if_positive(&priv->ext_flip);
688 else 689 else
689 atomic_inc(&ps3fb.ext_flip); 690 atomic_inc(&priv->ext_flip);
690} 691}
691 692
692EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
693 693
694 /* 694 /*
695 * ioctl 695 * ioctl
@@ -851,37 +851,9 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
851 return IRQ_HANDLED; 851 return IRQ_HANDLED;
852} 852}
853 853
854#ifndef MODULE
855static int __init ps3fb_setup(char *options)
856{
857 char *this_opt;
858 int mode = 0;
859
860 if (!options || !*options)
861 return 0; /* no options */
862
863 while ((this_opt = strsep(&options, ",")) != NULL) {
864 if (!*this_opt)
865 continue;
866 if (!strncmp(this_opt, "mode:", 5))
867 mode = simple_strtoul(this_opt + 5, NULL, 0);
868 else
869 mode_option = this_opt;
870 }
871 return mode;
872}
873#endif /* MODULE */
874
875 /*
876 * Initialisation
877 */
878 854
879static void ps3fb_platform_release(struct device *device) 855static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo,
880{ 856 struct ps3_system_bus_device *dev)
881 /* This is called when the reference count goes to zero. */
882}
883
884static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
885{ 857{
886 int error; 858 int error;
887 859
@@ -897,7 +869,6 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
897 return -EINVAL; 869 return -EINVAL;
898 } 870 }
899 871
900 ps3fb.dev = dev;
901 error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, 872 error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
902 &ps3fb.irq_no); 873 &ps3fb.irq_no);
903 if (error) { 874 if (error) {
@@ -907,7 +878,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
907 } 878 }
908 879
909 error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, 880 error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
910 "ps3fb vsync", ps3fb.dev); 881 DEVICE_NAME, dev);
911 if (error) { 882 if (error) {
912 printk(KERN_ERR "%s: request_irq failed %d\n", __func__, 883 printk(KERN_ERR "%s: request_irq failed %d\n", __func__,
913 error); 884 error);
@@ -966,16 +937,45 @@ static struct fb_ops ps3fb_ops = {
966}; 937};
967 938
968static struct fb_fix_screeninfo ps3fb_fix __initdata = { 939static struct fb_fix_screeninfo ps3fb_fix __initdata = {
969 .id = "PS3 FB", 940 .id = DEVICE_NAME,
970 .type = FB_TYPE_PACKED_PIXELS, 941 .type = FB_TYPE_PACKED_PIXELS,
971 .visual = FB_VISUAL_TRUECOLOR, 942 .visual = FB_VISUAL_TRUECOLOR,
972 .accel = FB_ACCEL_NONE, 943 .accel = FB_ACCEL_NONE,
973}; 944};
974 945
975static int __init ps3fb_probe(struct platform_device *dev) 946static int ps3fb_set_sync(void)
947{
948 int status;
949
950#ifdef HEAD_A
951 status = lv1_gpu_context_attribute(0x0,
952 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
953 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
954 if (status) {
955 printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC "
956 "failed: %d\n", __func__, status);
957 return -1;
958 }
959#endif
960#ifdef HEAD_B
961 status = lv1_gpu_context_attribute(0x0,
962 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
963 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
964
965 if (status) {
966 printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE "
967 "failed: %d\n", __func__, status);
968 return -1;
969 }
970#endif
971 return 0;
972}
973
974static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
976{ 975{
977 struct fb_info *info; 976 struct fb_info *info;
978 int retval = -ENOMEM; 977 int retval = -ENOMEM;
978 u32 xres, yres;
979 u64 ddr_lpar = 0; 979 u64 ddr_lpar = 0;
980 u64 lpar_dma_control = 0; 980 u64 lpar_dma_control = 0;
981 u64 lpar_driver_info = 0; 981 u64 lpar_driver_info = 0;
@@ -986,6 +986,30 @@ static int __init ps3fb_probe(struct platform_device *dev)
986 unsigned long offset; 986 unsigned long offset;
987 struct task_struct *task; 987 struct task_struct *task;
988 988
989 status = ps3_open_hv_device(dev);
990 if (status) {
991 printk(KERN_ERR "%s: ps3_open_hv_device failed\n", __func__);
992 goto err;
993 }
994
995 if (!ps3fb_mode)
996 ps3fb_mode = ps3av_get_mode();
997 DPRINTK("ps3av_mode:%d\n", ps3fb_mode);
998
999 if (ps3fb_mode > 0 &&
1000 !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
1001 ps3fb.res_index = ps3fb_get_res_table(xres, yres);
1002 DPRINTK("res_index:%d\n", ps3fb.res_index);
1003 } else
1004 ps3fb.res_index = GPU_RES_INDEX;
1005
1006 atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
1007 atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
1008 init_waitqueue_head(&ps3fb.wait_vsync);
1009 ps3fb.num_frames = 1;
1010
1011 ps3fb_set_sync();
1012
989 /* get gpu context handle */ 1013 /* get gpu context handle */
990 status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, 1014 status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
991 &ps3fb.memory_handle, &ddr_lpar); 1015 &ps3fb.memory_handle, &ddr_lpar);
@@ -1029,7 +1053,7 @@ static int __init ps3fb_probe(struct platform_device *dev)
1029 * leakage into userspace 1053 * leakage into userspace
1030 */ 1054 */
1031 memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); 1055 memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
1032 info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); 1056 info = framebuffer_alloc(sizeof(u32) * 16, &dev->core);
1033 if (!info) 1057 if (!info)
1034 goto err_free_irq; 1058 goto err_free_irq;
1035 1059
@@ -1061,19 +1085,20 @@ static int __init ps3fb_probe(struct platform_device *dev)
1061 if (retval < 0) 1085 if (retval < 0)
1062 goto err_fb_dealloc; 1086 goto err_fb_dealloc;
1063 1087
1064 platform_set_drvdata(dev, info); 1088 dev->core.driver_data = info;
1065 1089
1066 printk(KERN_INFO 1090 printk(KERN_INFO
1067 "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", 1091 "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
1068 info->node, ps3fb_videomemory.size >> 10); 1092 info->node, ps3fb_videomemory.size >> 10);
1069 1093
1070 task = kthread_run(ps3fbd, info, "ps3fbd"); 1094 task = kthread_run(ps3fbd, info, DEVICE_NAME);
1071 if (IS_ERR(task)) { 1095 if (IS_ERR(task)) {
1072 retval = PTR_ERR(task); 1096 retval = PTR_ERR(task);
1073 goto err_unregister_framebuffer; 1097 goto err_unregister_framebuffer;
1074 } 1098 }
1075 1099
1076 ps3fb.task = task; 1100 ps3fb.task = task;
1101 ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb);
1077 1102
1078 return 0; 1103 return 0;
1079 1104
@@ -1084,7 +1109,7 @@ err_fb_dealloc:
1084err_framebuffer_release: 1109err_framebuffer_release:
1085 framebuffer_release(info); 1110 framebuffer_release(info);
1086err_free_irq: 1111err_free_irq:
1087 free_irq(ps3fb.irq_no, ps3fb.dev); 1112 free_irq(ps3fb.irq_no, dev);
1088 ps3_irq_plug_destroy(ps3fb.irq_no); 1113 ps3_irq_plug_destroy(ps3fb.irq_no);
1089err_iounmap_dinfo: 1114err_iounmap_dinfo:
1090 iounmap((u8 __iomem *)ps3fb.dinfo); 1115 iounmap((u8 __iomem *)ps3fb.dinfo);
@@ -1096,26 +1121,30 @@ err:
1096 return retval; 1121 return retval;
1097} 1122}
1098 1123
1099static void ps3fb_shutdown(struct platform_device *dev) 1124static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
1100{ 1125{
1101 ps3fb_flip_ctl(0); /* flip off */ 1126 int status;
1127 struct fb_info *info = dev->core.driver_data;
1128
1129 DPRINTK(" -> %s:%d\n", __func__, __LINE__);
1130
1131 ps3fb_flip_ctl(0, &ps3fb); /* flip off */
1102 ps3fb.dinfo->irq.mask = 0; 1132 ps3fb.dinfo->irq.mask = 0;
1103 free_irq(ps3fb.irq_no, ps3fb.dev);
1104 ps3_irq_plug_destroy(ps3fb.irq_no);
1105 iounmap((u8 __iomem *)ps3fb.dinfo);
1106}
1107 1133
1108void ps3fb_cleanup(void) 1134 if (info) {
1109{ 1135 unregister_framebuffer(info);
1110 int status; 1136 fb_dealloc_cmap(&info->cmap);
1137 framebuffer_release(info);
1138 }
1111 1139
1140 ps3av_register_flip_ctl(NULL, NULL);
1112 if (ps3fb.task) { 1141 if (ps3fb.task) {
1113 struct task_struct *task = ps3fb.task; 1142 struct task_struct *task = ps3fb.task;
1114 ps3fb.task = NULL; 1143 ps3fb.task = NULL;
1115 kthread_stop(task); 1144 kthread_stop(task);
1116 } 1145 }
1117 if (ps3fb.irq_no) { 1146 if (ps3fb.irq_no) {
1118 free_irq(ps3fb.irq_no, ps3fb.dev); 1147 free_irq(ps3fb.irq_no, dev);
1119 ps3_irq_plug_destroy(ps3fb.irq_no); 1148 ps3_irq_plug_destroy(ps3fb.irq_no);
1120 } 1149 }
1121 iounmap((u8 __iomem *)ps3fb.dinfo); 1150 iounmap((u8 __iomem *)ps3fb.dinfo);
@@ -1128,134 +1157,69 @@ void ps3fb_cleanup(void)
1128 if (status) 1157 if (status)
1129 DPRINTK("lv1_gpu_memory_free failed: %d\n", status); 1158 DPRINTK("lv1_gpu_memory_free failed: %d\n", status);
1130 1159
1131 ps3av_dev_close(); 1160 ps3_close_hv_device(dev);
1132} 1161 DPRINTK(" <- %s:%d\n", __func__, __LINE__);
1133 1162
1134EXPORT_SYMBOL_GPL(ps3fb_cleanup);
1135
1136static int ps3fb_remove(struct platform_device *dev)
1137{
1138 struct fb_info *info = platform_get_drvdata(dev);
1139
1140 if (info) {
1141 unregister_framebuffer(info);
1142 fb_dealloc_cmap(&info->cmap);
1143 framebuffer_release(info);
1144 }
1145 ps3fb_cleanup();
1146 return 0; 1163 return 0;
1147} 1164}
1148 1165
1149static struct platform_driver ps3fb_driver = { 1166static struct ps3_system_bus_driver ps3fb_driver = {
1150 .probe = ps3fb_probe, 1167 .match_id = PS3_MATCH_ID_GRAPHICS,
1151 .remove = ps3fb_remove, 1168 .core.name = DEVICE_NAME,
1152 .shutdown = ps3fb_shutdown, 1169 .core.owner = THIS_MODULE,
1153 .driver = { .name = "ps3fb" } 1170 .probe = ps3fb_probe,
1154}; 1171 .remove = ps3fb_shutdown,
1155 1172 .shutdown = ps3fb_shutdown,
1156static struct platform_device ps3fb_device = {
1157 .name = "ps3fb",
1158 .id = 0,
1159 .dev = { .release = ps3fb_platform_release }
1160}; 1173};
1161 1174
1162int ps3fb_set_sync(void) 1175static int __init ps3fb_setup(void)
1163{ 1176{
1164 int status; 1177 char *options;
1165 1178
1166#ifdef HEAD_A 1179#ifdef MODULE
1167 status = lv1_gpu_context_attribute(0x0,
1168 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
1169 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
1170 if (status) {
1171 printk(KERN_ERR
1172 "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
1173 __func__, status);
1174 return -1;
1175 }
1176#endif
1177#ifdef HEAD_B
1178 status = lv1_gpu_context_attribute(0x0,
1179 L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
1180 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
1181
1182 if (status) {
1183 printk(KERN_ERR
1184 "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
1185 __func__, status);
1186 return -1;
1187 }
1188#endif
1189 return 0; 1180 return 0;
1190}
1191
1192EXPORT_SYMBOL_GPL(ps3fb_set_sync);
1193
1194static int __init ps3fb_init(void)
1195{
1196 int error;
1197#ifndef MODULE
1198 int mode;
1199 char *option = NULL;
1200
1201 if (fb_get_options("ps3fb", &option))
1202 goto err;
1203#endif 1181#endif
1204 1182
1205 if (!ps3fb_videomemory.address) 1183 if (fb_get_options(DEVICE_NAME, &options))
1206 goto err; 1184 return -ENXIO;
1207
1208 error = ps3av_dev_open();
1209 if (error) {
1210 printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__);
1211 goto err;
1212 }
1213 1185
1214 ps3fb_mode = ps3av_get_mode(); 1186 if (!options || !*options)
1215 DPRINTK("ps3av_mode:%d\n", ps3fb_mode); 1187 return 0;
1216#ifndef MODULE
1217 mode = ps3fb_setup(option); /* check boot option */
1218 if (mode)
1219 ps3fb_mode = mode;
1220#endif
1221 if (ps3fb_mode > 0) {
1222 u32 xres, yres;
1223 ps3av_video_mode2res(ps3fb_mode, &xres, &yres);
1224 ps3fb.res_index = ps3fb_get_res_table(xres, yres);
1225 DPRINTK("res_index:%d\n", ps3fb.res_index);
1226 } else
1227 ps3fb.res_index = GPU_RES_INDEX;
1228 1188
1229 atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ 1189 while (1) {
1230 atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ 1190 char *this_opt = strsep(&options, ",");
1231 init_waitqueue_head(&ps3fb.wait_vsync);
1232 ps3fb.num_frames = 1;
1233 1191
1234 error = platform_driver_register(&ps3fb_driver); 1192 if (!this_opt)
1235 if (!error) { 1193 break;
1236 error = platform_device_register(&ps3fb_device); 1194 if (!*this_opt)
1237 if (error) 1195 continue;
1238 platform_driver_unregister(&ps3fb_driver); 1196 if (!strncmp(this_opt, "mode:", 5))
1197 ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0);
1198 else
1199 mode_option = this_opt;
1239 } 1200 }
1201 return 0;
1202}
1240 1203
1241 ps3fb_set_sync(); 1204static int __init ps3fb_init(void)
1242 1205{
1243 return error; 1206 if (!ps3fb_videomemory.address || ps3fb_setup())
1207 return -ENXIO;
1244 1208
1245err: 1209 return ps3_system_bus_driver_register(&ps3fb_driver);
1246 return -ENXIO;
1247} 1210}
1248 1211
1249module_init(ps3fb_init);
1250
1251#ifdef MODULE
1252static void __exit ps3fb_exit(void) 1212static void __exit ps3fb_exit(void)
1253{ 1213{
1254 platform_device_unregister(&ps3fb_device); 1214 DPRINTK(" -> %s:%d\n", __func__, __LINE__);
1255 platform_driver_unregister(&ps3fb_driver); 1215 ps3_system_bus_driver_unregister(&ps3fb_driver);
1216 DPRINTK(" <- %s:%d\n", __func__, __LINE__);
1256} 1217}
1257 1218
1219module_init(ps3fb_init);
1258module_exit(ps3fb_exit); 1220module_exit(ps3fb_exit);
1259 1221
1260MODULE_LICENSE("GPL"); 1222MODULE_LICENSE("GPL");
1261#endif /* MODULE */ 1223MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver");
1224MODULE_AUTHOR("Sony Computer Entertainment Inc.");
1225MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS);