?? ps3fb.c
字號:
/* * linux/drivers/video/ps3fb.c -- PS3 GPU frame buffer device * * Copyright (C) 2006 Sony Computer Entertainment Inc. * Copyright 2006, 2007 Sony Corporation * * This file is based on : * * linux/drivers/video/vfb.c -- Virtual frame buffer device * * Copyright (C) 2002 James Simmons * * Copyright (C) 1997 Geert Uytterhoeven * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/console.h>#include <linux/ioctl.h>#include <linux/kthread.h>#include <linux/freezer.h>#include <linux/uaccess.h>#include <linux/fb.h>#include <linux/init.h>#include <asm/abs_addr.h>#include <asm/lv1call.h>#include <asm/ps3av.h>#include <asm/ps3fb.h>#include <asm/ps3.h>#define DEVICE_NAME "ps3fb"#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32)#define L1GPU_DISPLAY_SYNC_HSYNC 1#define L1GPU_DISPLAY_SYNC_VSYNC 2#define GPU_CMD_BUF_SIZE (2 * 1024 * 1024)#define GPU_FB_START (64 * 1024)#define GPU_IOIF (0x0d000000UL)#define GPU_ALIGN_UP(x) _ALIGN_UP((x), 64)#define GPU_MAX_LINE_LENGTH (65536 - 64)#define PS3FB_FULL_MODE_BIT 0x80#define GPU_INTR_STATUS_VSYNC_0 0 /* vsync on head A */#define GPU_INTR_STATUS_VSYNC_1 1 /* vsync on head B */#define GPU_INTR_STATUS_FLIP_0 3 /* flip head A */#define GPU_INTR_STATUS_FLIP_1 4 /* flip head B */#define GPU_INTR_STATUS_QUEUE_0 5 /* queue head A */#define GPU_INTR_STATUS_QUEUE_1 6 /* queue head B */#define GPU_DRIVER_INFO_VERSION 0x211/* gpu internals */struct display_head { u64 be_time_stamp; u32 status; u32 offset; u32 res1; u32 res2; u32 field; u32 reserved1; u64 res3; u32 raster; u64 vblank_count; u32 field_vsync; u32 reserved2;};struct gpu_irq { u32 irq_outlet; u32 status; u32 mask; u32 video_cause; u32 graph_cause; u32 user_cause; u32 res1; u64 res2; u32 reserved[4];};struct gpu_driver_info { u32 version_driver; u32 version_gpu; u32 memory_size; u32 hardware_channel; u32 nvcore_frequency; u32 memory_frequency; u32 reserved[1063]; struct display_head display_head[8]; struct gpu_irq irq;};struct ps3fb_priv { unsigned int irq_no; u64 context_handle, memory_handle; void *xdr_ea; size_t xdr_size; struct gpu_driver_info *dinfo; u64 vblank_count; /* frame count */ wait_queue_head_t wait_vsync; atomic_t ext_flip; /* on/off flip with vsync */ atomic_t f_count; /* fb_open count */ int is_blanked; int is_kicked; struct task_struct *task;};static struct ps3fb_priv ps3fb;struct ps3fb_par { u32 pseudo_palette[16]; int mode_id, new_mode_id; int res_index; unsigned int num_frames; /* num of frame buffers */ unsigned int width; unsigned int height; unsigned long full_offset; /* start of fullscreen DDR fb */ unsigned long fb_offset; /* start of actual DDR fb */ unsigned long pan_offset;};struct ps3fb_res_table { u32 xres; u32 yres; u32 xoff; u32 yoff; u32 type;};#define PS3FB_RES_FULL 1static const struct ps3fb_res_table ps3fb_res[] = { /* res_x,y margin_x,y full */ { 720, 480, 72, 48 , 0}, { 720, 576, 72, 58 , 0}, { 1280, 720, 78, 38 , 0}, { 1920, 1080, 116, 58 , 0}, /* full mode */ { 720, 480, 0, 0 , PS3FB_RES_FULL}, { 720, 576, 0, 0 , PS3FB_RES_FULL}, { 1280, 720, 0, 0 , PS3FB_RES_FULL}, { 1920, 1080, 0, 0 , PS3FB_RES_FULL}, /* vesa: normally full mode */ { 1280, 768, 0, 0 , 0}, { 1280, 1024, 0, 0 , 0}, { 1920, 1200, 0, 0 , 0}, { 0, 0, 0, 0 , 0} };/* default resolution */#define GPU_RES_INDEX 0 /* 720 x 480 */static const struct fb_videomode ps3fb_modedb[] = { /* 60 Hz broadcast modes (modes "1" to "5") */ { /* 480i */ "480i", 60, 576, 384, 74074, 130, 89, 78, 57, 63, 6, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { /* 480p */ "480p", 60, 576, 384, 37037, 130, 89, 78, 57, 63, 6, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { /* 720p */ "720p", 60, 1124, 644, 13481, 298, 148, 57, 44, 80, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { /* 1080i */ "1080i", 60, 1688, 964, 13481, 264, 160, 94, 62, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { /* 1080p */ "1080p", 60, 1688, 964, 6741, 264, 160, 94, 62, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, /* 50 Hz broadcast modes (modes "6" to "10") */ { /* 576i */ "576i", 50, 576, 460, 74074, 142, 83, 97, 63, 63, 5, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { /* 576p */ "576p", 50, 576, 460, 37037, 142, 83, 97, 63, 63, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { /* 720p */ "720p", 50, 1124, 644, 13468, 298, 478, 57, 44, 80, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { /* 1080 */ "1080i", 50, 1688, 964, 13468, 264, 600, 94, 62, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { /* 1080p */ "1080p", 50, 1688, 964, 6734, 264, 600, 94, 62, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, /* VESA modes (modes "11" to "13") */ { /* WXGA */ "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6, 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, { /* SXGA */ "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, { /* WUXGA */ "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6, FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */ { /* 480if */ "480if", 60, 720, 480, 74074, 58, 17, 30, 9, 63, 6, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { /* 480pf */ "480pf", 60, 720, 480, 37037, 58, 17, 30, 9, 63, 6, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { /* 720pf */ "720pf", 60, 1280, 720, 13481, 220, 70, 19, 6, 80, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { /* 1080if */ "1080if", 60, 1920, 1080, 13481, 148, 44, 36, 4, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { /* 1080pf */ "1080pf", 60, 1920, 1080, 6741, 148, 44, 36, 4, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, /* 50 Hz broadcast modes (full resolution versions of modes "6" to "10") */ { /* 576if */ "576if", 50, 720, 576, 74074, 70, 11, 39, 5, 63, 5, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { /* 576pf */ "576pf", 50, 720, 576, 37037, 70, 11, 39, 5, 63, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { /* 720pf */ "720pf", 50, 1280, 720, 13468, 220, 400, 19, 6, 80, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { /* 1080if */ "1080f", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { /* 1080pf */ "1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }};#define HEAD_A#define HEAD_B#define X_OFF(i) (ps3fb_res[i].xoff) /* left/right margin (pixel) */#define Y_OFF(i) (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */#define WIDTH(i) (ps3fb_res[i].xres) /* width of FB */#define HEIGHT(i) (ps3fb_res[i].yres) /* height of FB */#define BPP 4 /* number of bytes per pixel *//* Start of the virtual frame buffer (relative to fullscreen ) */#define VP_OFF(i) ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP)static int ps3fb_mode;module_param(ps3fb_mode, int, 0);static char *mode_option __devinitdata;static int ps3fb_get_res_table(u32 xres, u32 yres, int mode){ int full_mode; unsigned int i; u32 x, y, f; full_mode = (mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0; for (i = 0;; i++) { x = ps3fb_res[i].xres; y = ps3fb_res[i].yres; f = ps3fb_res[i].type; if (!x) { pr_debug("ERROR: ps3fb_get_res_table()\n"); return -1; } if (full_mode == PS3FB_RES_FULL && f != PS3FB_RES_FULL) continue; if (x == xres && (yres == 0 || y == yres)) break; x = x - 2 * ps3fb_res[i].xoff; y = y - 2 * ps3fb_res[i].yoff; if (x == xres && (yres == 0 || y == yres)) break; } return i;}static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var, u32 *ddr_line_length, u32 *xdr_line_length){ unsigned int i, mode; for (i = 0; i < ARRAY_SIZE(ps3fb_modedb); i++) if (var->xres == ps3fb_modedb[i].xres && var->yres == ps3fb_modedb[i].yres && var->pixclock == ps3fb_modedb[i].pixclock && var->hsync_len == ps3fb_modedb[i].hsync_len && var->vsync_len == ps3fb_modedb[i].vsync_len && var->left_margin == ps3fb_modedb[i].left_margin && var->right_margin == ps3fb_modedb[i].right_margin && var->upper_margin == ps3fb_modedb[i].upper_margin && var->lower_margin == ps3fb_modedb[i].lower_margin && var->sync == ps3fb_modedb[i].sync && (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode) goto found; pr_debug("ps3fb_find_mode: mode not found\n"); return 0;found: /* Cropped broadcast modes use the full line length */ *ddr_line_length = ps3fb_modedb[i < 10 ? i + 13 : i].xres * BPP; if (ps3_compare_firmware_version(1, 9, 0) >= 0) { *xdr_line_length = GPU_ALIGN_UP(max(var->xres, var->xres_virtual) * BPP); if (*xdr_line_length > GPU_MAX_LINE_LENGTH) *xdr_line_length = GPU_MAX_LINE_LENGTH; } else *xdr_line_length = *ddr_line_length; /* Full broadcast modes have the full mode bit set */ mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1; pr_debug("ps3fb_find_mode: mode %u\n", mode); return mode;}static const struct fb_videomode *ps3fb_default_mode(int id){ u32 mode = id & PS3AV_MODE_MASK; u32 flags; if (mode < 1 || mode > 13) return NULL; flags = id & ~PS3AV_MODE_MASK; if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) { /* Full broadcast mode */ return &ps3fb_modedb[mode + 12]; } return &ps3fb_modedb[mode - 1];}static void ps3fb_sync_image(struct device *dev, u64 frame_offset, u64 dst_offset, u64 src_offset, u32 width, u32 height, u32 dst_line_length, u32 src_line_length){ int status; u64 line_length; line_length = dst_line_length; if (src_line_length != dst_line_length) line_length |= (u64)src_line_length << 32; src_offset += GPU_FB_START; status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, dst_offset, GPU_IOIF + src_offset, L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | (width << 16) | height, line_length); if (status) dev_err(dev, "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", __func__, status);#ifdef HEAD_A status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 0, frame_offset, 0, 0); if (status) dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", __func__, status);#endif#ifdef HEAD_B status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 1, frame_offset, 0, 0); if (status) dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", __func__, status);#endif}static int ps3fb_sync(struct fb_info *info, u32 frame){ struct ps3fb_par *par = info->par; int i, error = 0; u32 ddr_line_length, xdr_line_length; u64 ddr_base, xdr_base;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -