?? ps3fb.c
字號:
ps3fb_sync(info, 0); /* single buffer */ release_console_sem(); } schedule(); } return 0;}static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr){ struct device *dev = ptr; u64 v1; int status; struct display_head *head = &ps3fb.dinfo->display_head[1]; status = lv1_gpu_context_intr(ps3fb.context_handle, &v1); if (status) { dev_err(dev, "%s: lv1_gpu_context_intr failed: %d\n", __func__, status); return IRQ_NONE; } if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) { /* VSYNC */ ps3fb.vblank_count = head->vblank_count; if (ps3fb.task && !ps3fb.is_blanked && !atomic_read(&ps3fb.ext_flip)) { ps3fb.is_kicked = 1; wake_up_process(ps3fb.task); } wake_up_interruptible(&ps3fb.wait_vsync); } return IRQ_HANDLED;}static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, struct device *dev){ int error; dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver); dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet); dev_dbg(dev, "version_gpu: %x memory_size: %x ch: %x core_freq: %d " "mem_freq:%d\n", dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel, dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { dev_err(dev, "%s: version_driver err:%x\n", __func__, dinfo->version_driver); return -EINVAL; } error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, &ps3fb.irq_no); if (error) { dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error); return error; } error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, DEVICE_NAME, dev); if (error) { dev_err(dev, "%s: request_irq failed %d\n", __func__, error); ps3_irq_plug_destroy(ps3fb.irq_no); return error; } dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | (1 << GPU_INTR_STATUS_FLIP_1); return 0;}static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev){ int status; status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, ps3fb_videomemory.size, 0); if (status) { dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n", __func__, status); return -ENXIO; } dev_dbg(dev, "video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n", ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar, virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size); status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, xdr_lpar, GPU_CMD_BUF_SIZE, GPU_IOIF, 0); if (status) { dev_err(dev, "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", __func__, status); return -ENXIO; } return 0;}static struct fb_ops ps3fb_ops = { .fb_open = ps3fb_open, .fb_release = ps3fb_release, .fb_read = fb_sys_read, .fb_write = fb_sys_write, .fb_check_var = ps3fb_check_var, .fb_set_par = ps3fb_set_par, .fb_setcolreg = ps3fb_setcolreg, .fb_pan_display = ps3fb_pan_display, .fb_fillrect = sys_fillrect, .fb_copyarea = sys_copyarea, .fb_imageblit = sys_imageblit, .fb_mmap = ps3fb_mmap, .fb_blank = ps3fb_blank, .fb_ioctl = ps3fb_ioctl, .fb_compat_ioctl = ps3fb_ioctl};static struct fb_fix_screeninfo ps3fb_fix __initdata = { .id = DEVICE_NAME, .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, .accel = FB_ACCEL_NONE,};static int ps3fb_set_sync(struct device *dev){ int status;#ifdef HEAD_A status = lv1_gpu_context_attribute(0x0, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); if (status) { dev_err(dev, "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " "%d\n", __func__, status); return -1; }#endif#ifdef HEAD_B status = lv1_gpu_context_attribute(0x0, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); if (status) { dev_err(dev, "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " "%d\n", __func__, status); return -1; }#endif return 0;}static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev){ struct fb_info *info; struct ps3fb_par *par; int retval = -ENOMEM; u32 xres, yres; u64 ddr_lpar = 0; u64 lpar_dma_control = 0; u64 lpar_driver_info = 0; u64 lpar_reports = 0; u64 lpar_reports_size = 0; u64 xdr_lpar; int status, res_index; struct task_struct *task; unsigned long max_ps3fb_size; if (ps3fb_videomemory.size < GPU_CMD_BUF_SIZE) { dev_err(&dev->core, "%s: Not enough video memory\n", __func__); return -ENOMEM; } status = ps3_open_hv_device(dev); if (status) { dev_err(&dev->core, "%s: ps3_open_hv_device failed\n", __func__); goto err; } if (!ps3fb_mode) ps3fb_mode = ps3av_get_mode(); dev_dbg(&dev->core, "ps3av_mode:%d\n", ps3fb_mode); if (ps3fb_mode > 0 && !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode); dev_dbg(&dev->core, "res_index:%d\n", res_index); } else res_index = GPU_RES_INDEX; atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ init_waitqueue_head(&ps3fb.wait_vsync); ps3fb_set_sync(&dev->core); max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF; if (ps3fb_videomemory.size > max_ps3fb_size) { dev_info(&dev->core, "Limiting ps3fb mem size to %lu bytes\n", max_ps3fb_size); ps3fb_videomemory.size = max_ps3fb_size; } /* get gpu context handle */ status = lv1_gpu_memory_allocate(ps3fb_videomemory.size, 0, 0, 0, 0, &ps3fb.memory_handle, &ddr_lpar); if (status) { dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", __func__, status); goto err; } dev_dbg(&dev->core, "ddr:lpar:0x%lx\n", ddr_lpar); status = lv1_gpu_context_allocate(ps3fb.memory_handle, 0, &ps3fb.context_handle, &lpar_dma_control, &lpar_driver_info, &lpar_reports, &lpar_reports_size); if (status) { dev_err(&dev->core, "%s: lv1_gpu_context_attribute failed: %d\n", __func__, status); goto err_gpu_memory_free; } /* vsync interrupt */ ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024); if (!ps3fb.dinfo) { dev_err(&dev->core, "%s: ioremap failed\n", __func__); goto err_gpu_context_free; } retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core); if (retval) goto err_iounmap_dinfo; /* XDR frame buffer */ ps3fb.xdr_ea = ps3fb_videomemory.address; xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea)); /* Clear memory to prevent kernel info leakage into userspace */ memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); /* * The GPU command buffer is at the start of video memory * As we don't use the full command buffer, we can put the actual * frame buffer at offset GPU_FB_START and save some precious XDR * memory */ ps3fb.xdr_ea += GPU_FB_START; ps3fb.xdr_size = ps3fb_videomemory.size - GPU_FB_START; retval = ps3fb_xdr_settings(xdr_lpar, &dev->core); if (retval) goto err_free_irq; info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); if (!info) goto err_free_irq; par = info->par; par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ par->new_mode_id = ps3fb_mode; par->res_index = res_index; par->num_frames = 1; info->screen_base = (char __iomem *)ps3fb.xdr_ea; info->fbops = &ps3fb_ops; info->fix = ps3fb_fix; info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); info->fix.smem_len = ps3fb.xdr_size; info->pseudo_palette = par->pseudo_palette; info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; retval = fb_alloc_cmap(&info->cmap, 256, 0); if (retval < 0) goto err_framebuffer_release; if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb, ARRAY_SIZE(ps3fb_modedb), ps3fb_default_mode(par->new_mode_id), 32)) { retval = -EINVAL; goto err_fb_dealloc; } fb_videomode_to_modelist(ps3fb_modedb, ARRAY_SIZE(ps3fb_modedb), &info->modelist); retval = register_framebuffer(info); if (retval < 0) goto err_fb_dealloc; dev->core.driver_data = info; dev_info(info->device, "%s %s, using %lu KiB of video memory\n", dev_driver_string(info->dev), info->dev->bus_id, ps3fb.xdr_size >> 10); task = kthread_run(ps3fbd, info, DEVICE_NAME); if (IS_ERR(task)) { retval = PTR_ERR(task); goto err_unregister_framebuffer; } ps3fb.task = task; ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb); return 0;err_unregister_framebuffer: unregister_framebuffer(info);err_fb_dealloc: fb_dealloc_cmap(&info->cmap);err_framebuffer_release: framebuffer_release(info);err_free_irq: free_irq(ps3fb.irq_no, &dev->core); ps3_irq_plug_destroy(ps3fb.irq_no);err_iounmap_dinfo: iounmap((u8 __iomem *)ps3fb.dinfo);err_gpu_context_free: lv1_gpu_context_free(ps3fb.context_handle);err_gpu_memory_free: lv1_gpu_memory_free(ps3fb.memory_handle);err: return retval;}static int ps3fb_shutdown(struct ps3_system_bus_device *dev){ int status; struct fb_info *info = dev->core.driver_data; dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); ps3fb_flip_ctl(0, &ps3fb); /* flip off */ ps3fb.dinfo->irq.mask = 0; ps3av_register_flip_ctl(NULL, NULL); if (ps3fb.task) { struct task_struct *task = ps3fb.task; ps3fb.task = NULL; kthread_stop(task); } if (ps3fb.irq_no) { free_irq(ps3fb.irq_no, &dev->core); ps3_irq_plug_destroy(ps3fb.irq_no); } if (info) { unregister_framebuffer(info); fb_dealloc_cmap(&info->cmap); framebuffer_release(info); info = dev->core.driver_data = NULL; } iounmap((u8 __iomem *)ps3fb.dinfo); status = lv1_gpu_context_free(ps3fb.context_handle); if (status) dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n", status); status = lv1_gpu_memory_free(ps3fb.memory_handle); if (status) dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n", status); ps3_close_hv_device(dev); dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); return 0;}static struct ps3_system_bus_driver ps3fb_driver = { .match_id = PS3_MATCH_ID_GRAPHICS, .core.name = DEVICE_NAME, .core.owner = THIS_MODULE, .probe = ps3fb_probe, .remove = ps3fb_shutdown, .shutdown = ps3fb_shutdown,};static int __init ps3fb_setup(void){ char *options;#ifdef MODULE return 0;#endif if (fb_get_options(DEVICE_NAME, &options)) return -ENXIO; if (!options || !*options) return 0; while (1) { char *this_opt = strsep(&options, ","); if (!this_opt) break; if (!*this_opt) continue; if (!strncmp(this_opt, "mode:", 5)) ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0); else mode_option = this_opt; } return 0;}static int __init ps3fb_init(void){ if (!ps3fb_videomemory.address || ps3fb_setup()) return -ENXIO; return ps3_system_bus_driver_register(&ps3fb_driver);}static void __exit ps3fb_exit(void){ pr_debug(" -> %s:%d\n", __func__, __LINE__); ps3_system_bus_driver_unregister(&ps3fb_driver); pr_debug(" <- %s:%d\n", __func__, __LINE__);}module_init(ps3fb_init);module_exit(ps3fb_exit);MODULE_LICENSE("GPL");MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver");MODULE_AUTHOR("Sony Computer Entertainment Inc.");MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -