Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Geert Uytterhoeven and committed by
Paul Mackerras
9e6b99bd 13a5e30c

+137 -184
+5 -4
arch/powerpc/platforms/ps3/setup.c
··· 107 107 while(1); 108 108 } 109 109 110 - #ifdef CONFIG_FB_PS3 110 + #if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) 111 111 static void prealloc(struct ps3_prealloc *p) 112 112 { 113 113 if (!p->size) ··· 125 125 } 126 126 127 127 struct ps3_prealloc ps3fb_videomemory = { 128 - .name = "ps3fb videomemory", 129 - .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024, 130 - .align = 1024*1024 /* the GPU requires 1 MiB alignment */ 128 + .name = "ps3fb videomemory", 129 + .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024, 130 + .align = 1024*1024 /* the GPU requires 1 MiB alignment */ 131 131 }; 132 + EXPORT_SYMBOL_GPL(ps3fb_videomemory); 132 133 #define prealloc_ps3fb_videomemory() prealloc(&ps3fb_videomemory) 133 134 134 135 static int __init early_parse_ps3fb(char *p)
+2 -2
drivers/video/Kconfig
··· 1790 1790 adaptor, found on some IBM System P (pSeries) machines. 1791 1791 1792 1792 config FB_PS3 1793 - bool "PS3 GPU framebuffer driver" 1794 - depends on (FB = y) && PS3_PS3AV 1793 + tristate "PS3 GPU framebuffer driver" 1794 + depends on FB && PS3_PS3AV 1795 1795 select FB_SYS_FILLRECT 1796 1796 select FB_SYS_COPYAREA 1797 1797 select FB_SYS_IMAGEBLIT
+130 -166
drivers/video/ps3fb.c
··· 27 27 #include <linux/vmalloc.h> 28 28 #include <linux/delay.h> 29 29 #include <linux/interrupt.h> 30 - #include <linux/platform_device.h> 31 30 #include <linux/console.h> 32 31 #include <linux/ioctl.h> 33 32 #include <linux/notifier.h> ··· 44 45 #include <asm/ps3av.h> 45 46 #include <asm/ps3fb.h> 46 47 #include <asm/ps3.h> 48 + 49 + 50 + #define DEVICE_NAME "ps3fb" 47 51 48 52 #ifdef PS3FB_DEBUG 49 53 #define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) ··· 128 126 129 127 struct ps3fb_priv { 130 128 unsigned int irq_no; 131 - void *dev; 132 129 133 130 u64 context_handle, memory_handle; 134 131 void *xdr_ea; ··· 172 171 { 0, 0, 0, 0 , 0} }; 173 172 174 173 /* default resolution */ 175 - #define GPU_RES_INDEX 0 /* 720 x 480 */ 174 + #define GPU_RES_INDEX 0 /* 720 x 480 */ 176 175 177 176 static const struct fb_videomode ps3fb_modedb[] = { 178 177 /* 60 Hz broadcast modes (modes "1" to "5") */ ··· 299 298 #define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) 300 299 301 300 static int ps3fb_mode; 302 - module_param(ps3fb_mode, bool, 0); 301 + module_param(ps3fb_mode, int, 0); 303 302 304 - static char *mode_option __initdata; 305 - 303 + static char *mode_option __devinitdata; 306 304 307 305 static int ps3fb_get_res_table(u32 xres, u32 yres) 308 306 { ··· 681 681 682 682 EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); 683 683 684 - void ps3fb_flip_ctl(int on) 684 + void ps3fb_flip_ctl(int on, void *data) 685 685 { 686 + struct ps3fb_priv *priv = data; 686 687 if (on) 687 - atomic_dec_if_positive(&ps3fb.ext_flip); 688 + atomic_dec_if_positive(&priv->ext_flip); 688 689 else 689 - atomic_inc(&ps3fb.ext_flip); 690 + atomic_inc(&priv->ext_flip); 690 691 } 691 692 692 - EXPORT_SYMBOL_GPL(ps3fb_flip_ctl); 693 693 694 694 /* 695 695 * ioctl ··· 851 851 return IRQ_HANDLED; 852 852 } 853 853 854 - #ifndef MODULE 855 - static int __init ps3fb_setup(char *options) 856 - { 857 - char *this_opt; 858 - int mode = 0; 859 854 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 - 879 - static void ps3fb_platform_release(struct device *device) 880 - { 881 - /* This is called when the reference count goes to zero. */ 882 - } 883 - 884 - static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) 855 + static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, 856 + struct ps3_system_bus_device *dev) 885 857 { 886 858 int error; 887 859 ··· 869 897 return -EINVAL; 870 898 } 871 899 872 - ps3fb.dev = dev; 873 900 error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, 874 901 &ps3fb.irq_no); 875 902 if (error) { ··· 878 907 } 879 908 880 909 error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, 881 - "ps3fb vsync", ps3fb.dev); 910 + DEVICE_NAME, dev); 882 911 if (error) { 883 912 printk(KERN_ERR "%s: request_irq failed %d\n", __func__, 884 913 error); ··· 937 966 }; 938 967 939 968 static struct fb_fix_screeninfo ps3fb_fix __initdata = { 940 - .id = "PS3 FB", 969 + .id = DEVICE_NAME, 941 970 .type = FB_TYPE_PACKED_PIXELS, 942 971 .visual = FB_VISUAL_TRUECOLOR, 943 972 .accel = FB_ACCEL_NONE, 944 973 }; 945 974 946 - static int __init ps3fb_probe(struct platform_device *dev) 975 + static int ps3fb_set_sync(void) 976 + { 977 + int status; 978 + 979 + #ifdef HEAD_A 980 + status = lv1_gpu_context_attribute(0x0, 981 + L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, 982 + 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); 983 + if (status) { 984 + printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC " 985 + "failed: %d\n", __func__, status); 986 + return -1; 987 + } 988 + #endif 989 + #ifdef HEAD_B 990 + status = lv1_gpu_context_attribute(0x0, 991 + L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, 992 + 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); 993 + 994 + if (status) { 995 + printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE " 996 + "failed: %d\n", __func__, status); 997 + return -1; 998 + } 999 + #endif 1000 + return 0; 1001 + } 1002 + 1003 + static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) 947 1004 { 948 1005 struct fb_info *info; 949 1006 int retval = -ENOMEM; 1007 + u32 xres, yres; 950 1008 u64 ddr_lpar = 0; 951 1009 u64 lpar_dma_control = 0; 952 1010 u64 lpar_driver_info = 0; ··· 985 985 int status; 986 986 unsigned long offset; 987 987 struct task_struct *task; 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(); 988 1012 989 1013 /* get gpu context handle */ 990 1014 status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, ··· 1053 1029 * leakage into userspace 1054 1030 */ 1055 1031 memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); 1056 - info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); 1032 + info = framebuffer_alloc(sizeof(u32) * 16, &dev->core); 1057 1033 if (!info) 1058 1034 goto err_free_irq; 1059 1035 ··· 1085 1061 if (retval < 0) 1086 1062 goto err_fb_dealloc; 1087 1063 1088 - platform_set_drvdata(dev, info); 1064 + dev->core.driver_data = info; 1089 1065 1090 1066 printk(KERN_INFO 1091 1067 "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", 1092 1068 info->node, ps3fb_videomemory.size >> 10); 1093 1069 1094 - task = kthread_run(ps3fbd, info, "ps3fbd"); 1070 + task = kthread_run(ps3fbd, info, DEVICE_NAME); 1095 1071 if (IS_ERR(task)) { 1096 1072 retval = PTR_ERR(task); 1097 1073 goto err_unregister_framebuffer; 1098 1074 } 1099 1075 1100 1076 ps3fb.task = task; 1077 + ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb); 1101 1078 1102 1079 return 0; 1103 1080 ··· 1109 1084 err_framebuffer_release: 1110 1085 framebuffer_release(info); 1111 1086 err_free_irq: 1112 - free_irq(ps3fb.irq_no, ps3fb.dev); 1087 + free_irq(ps3fb.irq_no, dev); 1113 1088 ps3_irq_plug_destroy(ps3fb.irq_no); 1114 1089 err_iounmap_dinfo: 1115 1090 iounmap((u8 __iomem *)ps3fb.dinfo); ··· 1121 1096 return retval; 1122 1097 } 1123 1098 1124 - static void ps3fb_shutdown(struct platform_device *dev) 1125 - { 1126 - ps3fb_flip_ctl(0); /* flip off */ 1127 - ps3fb.dinfo->irq.mask = 0; 1128 - free_irq(ps3fb.irq_no, ps3fb.dev); 1129 - ps3_irq_plug_destroy(ps3fb.irq_no); 1130 - iounmap((u8 __iomem *)ps3fb.dinfo); 1131 - } 1132 - 1133 - void ps3fb_cleanup(void) 1099 + static int ps3fb_shutdown(struct ps3_system_bus_device *dev) 1134 1100 { 1135 1101 int status; 1102 + struct fb_info *info = dev->core.driver_data; 1136 1103 1104 + DPRINTK(" -> %s:%d\n", __func__, __LINE__); 1105 + 1106 + ps3fb_flip_ctl(0, &ps3fb); /* flip off */ 1107 + ps3fb.dinfo->irq.mask = 0; 1108 + 1109 + if (info) { 1110 + unregister_framebuffer(info); 1111 + fb_dealloc_cmap(&info->cmap); 1112 + framebuffer_release(info); 1113 + } 1114 + 1115 + ps3av_register_flip_ctl(NULL, NULL); 1137 1116 if (ps3fb.task) { 1138 1117 struct task_struct *task = ps3fb.task; 1139 1118 ps3fb.task = NULL; 1140 1119 kthread_stop(task); 1141 1120 } 1142 1121 if (ps3fb.irq_no) { 1143 - free_irq(ps3fb.irq_no, ps3fb.dev); 1122 + free_irq(ps3fb.irq_no, dev); 1144 1123 ps3_irq_plug_destroy(ps3fb.irq_no); 1145 1124 } 1146 1125 iounmap((u8 __iomem *)ps3fb.dinfo); ··· 1157 1128 if (status) 1158 1129 DPRINTK("lv1_gpu_memory_free failed: %d\n", status); 1159 1130 1160 - ps3av_dev_close(); 1161 - } 1131 + ps3_close_hv_device(dev); 1132 + DPRINTK(" <- %s:%d\n", __func__, __LINE__); 1162 1133 1163 - EXPORT_SYMBOL_GPL(ps3fb_cleanup); 1164 - 1165 - static int ps3fb_remove(struct platform_device *dev) 1166 - { 1167 - struct fb_info *info = platform_get_drvdata(dev); 1168 - 1169 - if (info) { 1170 - unregister_framebuffer(info); 1171 - fb_dealloc_cmap(&info->cmap); 1172 - framebuffer_release(info); 1173 - } 1174 - ps3fb_cleanup(); 1175 1134 return 0; 1176 1135 } 1177 1136 1178 - static struct platform_driver ps3fb_driver = { 1179 - .probe = ps3fb_probe, 1180 - .remove = ps3fb_remove, 1181 - .shutdown = ps3fb_shutdown, 1182 - .driver = { .name = "ps3fb" } 1137 + static struct ps3_system_bus_driver ps3fb_driver = { 1138 + .match_id = PS3_MATCH_ID_GRAPHICS, 1139 + .core.name = DEVICE_NAME, 1140 + .core.owner = THIS_MODULE, 1141 + .probe = ps3fb_probe, 1142 + .remove = ps3fb_shutdown, 1143 + .shutdown = ps3fb_shutdown, 1183 1144 }; 1184 1145 1185 - static struct platform_device ps3fb_device = { 1186 - .name = "ps3fb", 1187 - .id = 0, 1188 - .dev = { .release = ps3fb_platform_release } 1189 - }; 1190 - 1191 - int ps3fb_set_sync(void) 1146 + static int __init ps3fb_setup(void) 1192 1147 { 1193 - int status; 1148 + char *options; 1194 1149 1195 - #ifdef HEAD_A 1196 - status = lv1_gpu_context_attribute(0x0, 1197 - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, 1198 - 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); 1199 - if (status) { 1200 - printk(KERN_ERR 1201 - "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n", 1202 - __func__, status); 1203 - return -1; 1204 - } 1150 + #ifdef MODULE 1151 + return 0; 1205 1152 #endif 1206 - #ifdef HEAD_B 1207 - status = lv1_gpu_context_attribute(0x0, 1208 - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, 1209 - 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); 1210 1153 1211 - if (status) { 1212 - printk(KERN_ERR 1213 - "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n", 1214 - __func__, status); 1215 - return -1; 1154 + if (fb_get_options(DEVICE_NAME, &options)) 1155 + return -ENXIO; 1156 + 1157 + if (!options || !*options) 1158 + return 0; 1159 + 1160 + while (1) { 1161 + char *this_opt = strsep(&options, ","); 1162 + 1163 + if (!this_opt) 1164 + break; 1165 + if (!*this_opt) 1166 + continue; 1167 + if (!strncmp(this_opt, "mode:", 5)) 1168 + ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0); 1169 + else 1170 + mode_option = this_opt; 1216 1171 } 1217 - #endif 1218 1172 return 0; 1219 1173 } 1220 - 1221 - EXPORT_SYMBOL_GPL(ps3fb_set_sync); 1222 1174 1223 1175 static int __init ps3fb_init(void) 1224 1176 { 1225 - int error; 1226 - #ifndef MODULE 1227 - int mode; 1228 - char *option = NULL; 1177 + if (!ps3fb_videomemory.address || ps3fb_setup()) 1178 + return -ENXIO; 1229 1179 1230 - if (fb_get_options("ps3fb", &option)) 1231 - goto err; 1232 - #endif 1180 + return ps3_system_bus_driver_register(&ps3fb_driver); 1181 + } 1233 1182 1234 - if (!ps3fb_videomemory.address) 1235 - goto err; 1236 - 1237 - error = ps3av_dev_open(); 1238 - if (error) { 1239 - printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__); 1240 - goto err; 1241 - } 1242 - 1243 - ps3fb_mode = ps3av_get_mode(); 1244 - DPRINTK("ps3av_mode:%d\n", ps3fb_mode); 1245 - #ifndef MODULE 1246 - mode = ps3fb_setup(option); /* check boot option */ 1247 - if (mode) 1248 - ps3fb_mode = mode; 1249 - #endif 1250 - if (ps3fb_mode > 0) { 1251 - u32 xres, yres; 1252 - ps3av_video_mode2res(ps3fb_mode, &xres, &yres); 1253 - ps3fb.res_index = ps3fb_get_res_table(xres, yres); 1254 - DPRINTK("res_index:%d\n", ps3fb.res_index); 1255 - } else 1256 - ps3fb.res_index = GPU_RES_INDEX; 1257 - 1258 - atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ 1259 - atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ 1260 - init_waitqueue_head(&ps3fb.wait_vsync); 1261 - ps3fb.num_frames = 1; 1262 - 1263 - error = platform_driver_register(&ps3fb_driver); 1264 - if (!error) { 1265 - error = platform_device_register(&ps3fb_device); 1266 - if (error) 1267 - platform_driver_unregister(&ps3fb_driver); 1268 - } 1269 - 1270 - ps3fb_set_sync(); 1271 - 1272 - return error; 1273 - 1274 - err: 1275 - return -ENXIO; 1183 + static void __exit ps3fb_exit(void) 1184 + { 1185 + DPRINTK(" -> %s:%d\n", __func__, __LINE__); 1186 + ps3_system_bus_driver_unregister(&ps3fb_driver); 1187 + DPRINTK(" <- %s:%d\n", __func__, __LINE__); 1276 1188 } 1277 1189 1278 1190 module_init(ps3fb_init); 1279 - 1280 - #ifdef MODULE 1281 - static void __exit ps3fb_exit(void) 1282 - { 1283 - platform_device_unregister(&ps3fb_device); 1284 - platform_driver_unregister(&ps3fb_driver); 1285 - } 1286 - 1287 1191 module_exit(ps3fb_exit); 1288 1192 1289 1193 MODULE_LICENSE("GPL"); 1290 - #endif /* MODULE */ 1194 + MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver"); 1195 + MODULE_AUTHOR("Sony Computer Entertainment Inc."); 1196 + MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS);
-12
include/asm-powerpc/ps3fb.h
··· 41 41 __u32 num_frames; /* num of frame buffers */ 42 42 }; 43 43 44 - #ifdef __KERNEL__ 45 - 46 - #ifdef CONFIG_FB_PS3 47 - extern void ps3fb_flip_ctl(int on); 48 - extern void ps3fb_cleanup(void); 49 - #else 50 - static inline void ps3fb_flip_ctl(int on) {} 51 - static inline void ps3fb_cleanup(void) {} 52 - #endif 53 - 54 - #endif /* __KERNEL__ */ 55 - 56 44 #endif /* _ASM_POWERPC_PS3FB_H_ */