?? 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 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; 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; unsigned int num_frames; /* num of frame buffers */ unsigned int width; unsigned int height; unsigned int ddr_line_length; unsigned int ddr_frame_size; unsigned int xdr_frame_size; unsigned int full_offset; /* start of fullscreen DDR fb */ unsigned int fb_offset; /* start of actual DDR fb */ unsigned int pan_offset;};#define FIRST_NATIVE_MODE_INDEX 10static 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 }, { /* 1080i */ "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 }, [FIRST_NATIVE_MODE_INDEX] = /* 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 */ "1080if", 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 }, /* 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 }};#define HEAD_A#define HEAD_B#define BPP 4 /* number of bytes per pixel */static int ps3fb_mode;module_param(ps3fb_mode, int, 0);static char *mode_option __devinitdata;static int ps3fb_cmp_mode(const struct fb_videomode *vmode, const struct fb_var_screeninfo *var){ long xres, yres, left_margin, right_margin, upper_margin, lower_margin; long dx, dy; /* maximum values */ if (var->xres > vmode->xres || var->yres > vmode->yres || var->pixclock > vmode->pixclock || var->hsync_len > vmode->hsync_len || var->vsync_len > vmode->vsync_len) return -1; /* progressive/interlaced must match */ if ((var->vmode & FB_VMODE_MASK) != vmode->vmode) return -1; /* minimum resolution */ xres = max(var->xres, 1U); yres = max(var->yres, 1U); /* minimum margins */ left_margin = max(var->left_margin, vmode->left_margin); right_margin = max(var->right_margin, vmode->right_margin); upper_margin = max(var->upper_margin, vmode->upper_margin); lower_margin = max(var->lower_margin, vmode->lower_margin); /* resolution + margins may not exceed native parameters */ dx = ((long)vmode->left_margin + (long)vmode->xres + (long)vmode->right_margin) - (left_margin + xres + right_margin); if (dx < 0) return -1; dy = ((long)vmode->upper_margin + (long)vmode->yres + (long)vmode->lower_margin) - (upper_margin + yres + lower_margin); if (dy < 0) return -1; /* exact match */ if (!dx && !dy) return 0; /* resolution difference */ return (vmode->xres - xres) * (vmode->yres - yres);}static const struct fb_videomode *ps3fb_native_vmode(enum ps3av_mode_num id){ return &ps3fb_modedb[FIRST_NATIVE_MODE_INDEX + id - 1];}static const struct fb_videomode *ps3fb_vmode(int id){ u32 mode = id & PS3AV_MODE_MASK; if (mode < PS3AV_MODE_480I || mode > PS3AV_MODE_WUXGA) return NULL; if (mode <= PS3AV_MODE_1080P50 && !(id & PS3AV_MODE_FULL)) { /* Non-fullscreen broadcast mode */ return &ps3fb_modedb[mode - 1]; } return ps3fb_native_vmode(mode);}static unsigned int ps3fb_find_mode(struct fb_var_screeninfo *var, u32 *ddr_line_length, u32 *xdr_line_length){ unsigned int id, best_id; int diff, best_diff; const struct fb_videomode *vmode; long gap; best_id = 0; best_diff = INT_MAX; pr_debug("%s: wanted %u [%u] %u x %u [%u] %u\n", __func__, var->left_margin, var->xres, var->right_margin, var->upper_margin, var->yres, var->lower_margin); for (id = PS3AV_MODE_480I; id <= PS3AV_MODE_WUXGA; id++) { vmode = ps3fb_native_vmode(id); diff = ps3fb_cmp_mode(vmode, var); pr_debug("%s: mode %u: %u [%u] %u x %u [%u] %u: diff = %d\n", __func__, id, vmode->left_margin, vmode->xres, vmode->right_margin, vmode->upper_margin, vmode->yres, vmode->lower_margin, diff); if (diff < 0) continue; if (diff < best_diff) { best_id = id; if (!diff) break; best_diff = diff; } } if (!best_id) { pr_debug("%s: no suitable mode found\n", __func__); return 0; } id = best_id; vmode = ps3fb_native_vmode(id); *ddr_line_length = vmode->xres * BPP; /* minimum resolution */ if (!var->xres) var->xres = 1; if (!var->yres) var->yres = 1; /* minimum virtual resolution */ if (var->xres_virtual < var->xres) var->xres_virtual = var->xres; if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; /* minimum margins */ if (var->left_margin < vmode->left_margin) var->left_margin = vmode->left_margin; if (var->right_margin < vmode->right_margin) var->right_margin = vmode->right_margin; if (var->upper_margin < vmode->upper_margin) var->upper_margin = vmode->upper_margin; if (var->lower_margin < vmode->lower_margin) var->lower_margin = vmode->lower_margin; /* extra margins */ gap = ((long)vmode->left_margin + (long)vmode->xres + (long)vmode->right_margin) - ((long)var->left_margin + (long)var->xres + (long)var->right_margin); if (gap > 0) { var->left_margin += gap/2; var->right_margin += (gap+1)/2; pr_debug("%s: rounded up H to %u [%u] %u\n", __func__, var->left_margin, var->xres, var->right_margin); } gap = ((long)vmode->upper_margin + (long)vmode->yres + (long)vmode->lower_margin) - ((long)var->upper_margin + (long)var->yres + (long)var->lower_margin); if (gap > 0) { var->upper_margin += gap/2; var->lower_margin += (gap+1)/2; pr_debug("%s: rounded up V to %u [%u] %u\n", __func__, var->upper_margin, var->yres, var->lower_margin); } /* fixed fields */ var->pixclock = vmode->pixclock; var->hsync_len = vmode->hsync_len; var->vsync_len = vmode->vsync_len; var->sync = vmode->sync; if (ps3_compare_firmware_version(1, 9, 0) >= 0) { *xdr_line_length = GPU_ALIGN_UP(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; if (vmode->sync & FB_SYNC_BROADCAST) { /* Full broadcast modes have the full mode bit set */ if (vmode->xres == var->xres && vmode->yres == var->yres) id |= PS3AV_MODE_FULL; } pr_debug("%s: mode %u\n", __func__, id); return id;}static void ps3fb_sync_image(struct device *dev, u64 frame_offset, u64 dst_offset, u64 src_offset, u32 width,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -