1310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven/* 2310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * linux/drivers/video/ps3fb.c -- PS3 GPU frame buffer device 3310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * 4310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * Copyright (C) 2006 Sony Computer Entertainment Inc. 5310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * Copyright 2006, 2007 Sony Corporation 6310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * 7310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * This file is based on : 8310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * 9310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * linux/drivers/video/vfb.c -- Virtual frame buffer device 10310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * 11310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * Copyright (C) 2002 James Simmons 12310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * 13310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * Copyright (C) 1997 Geert Uytterhoeven 14310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * 15310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * This file is subject to the terms and conditions of the GNU General Public 16310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * License. See the file COPYING in the main directory of this archive for 17310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * more details. 18310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven */ 19310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 20310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <linux/module.h> 21310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <linux/kernel.h> 22310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <linux/errno.h> 23310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <linux/string.h> 24310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <linux/mm.h> 25310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <linux/interrupt.h> 26310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <linux/console.h> 27310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <linux/ioctl.h> 281c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven#include <linux/kthread.h> 291c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven#include <linux/freezer.h> 3084902b7af642c86a518c17629c0dbe705a4b6d14Krzysztof Helt#include <linux/uaccess.h> 31310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <linux/fb.h> 32310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <linux/init.h> 33310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 349413c8836a16e9d034928a7f9d3ad81bebd71ce9Geert Uytterhoeven#include <asm/cell-regs.h> 35310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <asm/lv1call.h> 36310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <asm/ps3av.h> 37310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <asm/ps3fb.h> 38310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#include <asm/ps3.h> 39d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven#include <asm/ps3gpu.h> 40310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 419e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven 429e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven#define DEVICE_NAME "ps3fb" 439e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven 449ac67a35827ee03d71f2f1c656a725e263b14a7eGeert Uytterhoeven#define GPU_CMD_BUF_SIZE (2 * 1024 * 1024) 459ac67a35827ee03d71f2f1c656a725e263b14a7eGeert Uytterhoeven#define GPU_FB_START (64 * 1024) 46310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#define GPU_IOIF (0x0d000000UL) 47f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven#define GPU_ALIGN_UP(x) _ALIGN_UP((x), 64) 4861e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven#define GPU_MAX_LINE_LENGTH (65536 - 64) 49310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 50310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#define GPU_INTR_STATUS_VSYNC_0 0 /* vsync on head A */ 51310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#define GPU_INTR_STATUS_VSYNC_1 1 /* vsync on head B */ 52310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#define GPU_INTR_STATUS_FLIP_0 3 /* flip head A */ 53310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#define GPU_INTR_STATUS_FLIP_1 4 /* flip head B */ 54310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#define GPU_INTR_STATUS_QUEUE_0 5 /* queue head A */ 55310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#define GPU_INTR_STATUS_QUEUE_1 6 /* queue head B */ 56310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 57310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#define GPU_DRIVER_INFO_VERSION 0x211 58310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 59310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven/* gpu internals */ 60310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstruct display_head { 61310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 be_time_stamp; 62310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 status; 63310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 offset; 64310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 res1; 65310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 res2; 66310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 field; 67310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 reserved1; 68310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 69310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 res3; 70310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 raster; 71310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 72310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 vblank_count; 73310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 field_vsync; 74310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 reserved2; 75310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven}; 76310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 77310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstruct gpu_irq { 78310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 irq_outlet; 79310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 status; 80310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 mask; 81310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 video_cause; 82310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 graph_cause; 83310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 user_cause; 84310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 85310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 res1; 86310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 res2; 87310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 88310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 reserved[4]; 89310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven}; 90310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 91310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstruct gpu_driver_info { 92310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 version_driver; 93310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 version_gpu; 94310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 memory_size; 95310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 hardware_channel; 96310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 97310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 nvcore_frequency; 98310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 memory_frequency; 99310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 100310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 reserved[1063]; 101310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven struct display_head display_head[8]; 102310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven struct gpu_irq irq; 103310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven}; 104310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 105310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstruct ps3fb_priv { 106310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven unsigned int irq_no; 107310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 108310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 context_handle, memory_handle; 109310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven struct gpu_driver_info *dinfo; 110310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 111310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 vblank_count; /* frame count */ 112310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven wait_queue_head_t wait_vsync; 113310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 114310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven atomic_t ext_flip; /* on/off flip with vsync */ 115310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven atomic_t f_count; /* fb_open count */ 116310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven int is_blanked; 1171c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven int is_kicked; 1181c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven struct task_struct *task; 119310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven}; 120310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic struct ps3fb_priv ps3fb; 121310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1220333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoevenstruct ps3fb_par { 1230333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven u32 pseudo_palette[16]; 1240333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven int mode_id, new_mode_id; 1250333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven unsigned int num_frames; /* num of frame buffers */ 126f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven unsigned int width; 127f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven unsigned int height; 1289f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven unsigned int ddr_line_length; 1299f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven unsigned int ddr_frame_size; 1309f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven unsigned int xdr_frame_size; 1317974f72a21a246051b3dd84d7158974fc4785150Geert Uytterhoeven unsigned int full_offset; /* start of fullscreen DDR fb */ 1327974f72a21a246051b3dd84d7158974fc4785150Geert Uytterhoeven unsigned int fb_offset; /* start of actual DDR fb */ 1337974f72a21a246051b3dd84d7158974fc4785150Geert Uytterhoeven unsigned int pan_offset; 1340333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven}; 1350333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven 136310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 13734c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven#define FIRST_NATIVE_MODE_INDEX 10 13834c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven 139310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic const struct fb_videomode ps3fb_modedb[] = { 140310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 60 Hz broadcast modes (modes "1" to "5") */ 141310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven { 142310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 480i */ 143310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "480i", 60, 576, 384, 74074, 130, 89, 78, 57, 63, 6, 144310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_INTERLACED 145310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 146310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 480p */ 147310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "480p", 60, 576, 384, 37037, 130, 89, 78, 57, 63, 6, 148310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 149310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 150310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 720p */ 151310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "720p", 60, 1124, 644, 13481, 298, 148, 57, 44, 80, 5, 152310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 153310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 154310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 1080i */ 155310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "1080i", 60, 1688, 964, 13481, 264, 160, 94, 62, 88, 5, 156310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_INTERLACED 157310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 158310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 1080p */ 159310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "1080p", 60, 1688, 964, 6741, 264, 160, 94, 62, 88, 5, 160310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 161310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, 162310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 163310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 50 Hz broadcast modes (modes "6" to "10") */ 164310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven { 165310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 576i */ 166310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "576i", 50, 576, 460, 74074, 142, 83, 97, 63, 63, 5, 167310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_INTERLACED 168310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 169310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 576p */ 170310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "576p", 50, 576, 460, 37037, 142, 83, 97, 63, 63, 5, 171310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 172310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 173310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 720p */ 174310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "720p", 50, 1124, 644, 13468, 298, 478, 57, 44, 80, 5, 175310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 176310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 177a782eed655de49faa4895ae6143c3891985e4d98Geoff Levand /* 1080i */ 178310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "1080i", 50, 1688, 964, 13468, 264, 600, 94, 62, 88, 5, 179310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_INTERLACED 180310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 181310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 1080p */ 182310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "1080p", 50, 1688, 964, 6734, 264, 600, 94, 62, 88, 5, 183310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 184310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, 185310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 18634c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven [FIRST_NATIVE_MODE_INDEX] = 187310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */ 188310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven { 189310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 480if */ 190310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "480if", 60, 720, 480, 74074, 58, 17, 30, 9, 63, 6, 191310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_INTERLACED 192310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 193310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 480pf */ 194310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "480pf", 60, 720, 480, 37037, 58, 17, 30, 9, 63, 6, 195310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 196310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 197310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 720pf */ 198310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "720pf", 60, 1280, 720, 13481, 220, 70, 19, 6, 80, 5, 199310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 200310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 201310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 1080if */ 202310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "1080if", 60, 1920, 1080, 13481, 148, 44, 36, 4, 88, 5, 203310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_INTERLACED 204310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 205310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 1080pf */ 206310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "1080pf", 60, 1920, 1080, 6741, 148, 44, 36, 4, 88, 5, 207310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 208310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, 209310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 210310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 50 Hz broadcast modes (full resolution versions of modes "6" to "10") */ 211310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven { 212310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 576if */ 213310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "576if", 50, 720, 576, 74074, 70, 11, 39, 5, 63, 5, 214310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_INTERLACED 215310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 216310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 576pf */ 217310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "576pf", 50, 720, 576, 37037, 70, 11, 39, 5, 63, 5, 218310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 219310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 220310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 720pf */ 221310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "720pf", 50, 1280, 720, 13468, 220, 400, 19, 6, 80, 5, 222310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 223310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 224310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 1080if */ 225a782eed655de49faa4895ae6143c3891985e4d98Geoff Levand "1080if", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5, 226310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_INTERLACED 227310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven }, { 228310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 1080pf */ 229310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven "1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5, 230310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED 23134c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven }, 23234c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven 23334c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven /* VESA modes (modes "11" to "13") */ 23434c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven { 23534c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven /* WXGA */ 23634c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6, 23734c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven 0, FB_VMODE_NONINTERLACED, 23834c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven FB_MODE_IS_VESA 23934c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven }, { 24034c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven /* SXGA */ 24134c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, 24234c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, 24334c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven FB_MODE_IS_VESA 24434c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven }, { 24534c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven /* WUXGA */ 24634c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6, 24734c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, 24834c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven FB_MODE_IS_VESA 249310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 250310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven}; 251310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 252310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 253310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#define HEAD_A 254310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#define HEAD_B 255310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 2562ce32e15a16312d2c29c8bb188bf95bc821fdab6Geert Uytterhoeven#define BPP 4 /* number of bytes per pixel */ 2572ce32e15a16312d2c29c8bb188bf95bc821fdab6Geert Uytterhoeven 258310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 259bd685ac8e78b9bfd4a0145be22a7ff11ab11adefGeert Uytterhoevenstatic int ps3fb_mode; 2609e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoevenmodule_param(ps3fb_mode, int, 0); 261310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 26248c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic char *mode_option; 263310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 264633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoevenstatic int ps3fb_cmp_mode(const struct fb_videomode *vmode, 265633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven const struct fb_var_screeninfo *var) 266633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven{ 267a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven long xres, yres, left_margin, right_margin, upper_margin, lower_margin; 268a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven long dx, dy; 269a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven 270a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* maximum values */ 271a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (var->xres > vmode->xres || var->yres > vmode->yres || 272a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->pixclock > vmode->pixclock || 273a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->hsync_len > vmode->hsync_len || 274a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->vsync_len > vmode->vsync_len) 275633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven return -1; 276633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven 277a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* progressive/interlaced must match */ 278a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if ((var->vmode & FB_VMODE_MASK) != vmode->vmode) 279633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven return -1; 280633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven 281a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* minimum resolution */ 282a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven xres = max(var->xres, 1U); 283a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven yres = max(var->yres, 1U); 284a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven 285a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* minimum margins */ 286a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven left_margin = max(var->left_margin, vmode->left_margin); 287a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven right_margin = max(var->right_margin, vmode->right_margin); 288a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven upper_margin = max(var->upper_margin, vmode->upper_margin); 289a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven lower_margin = max(var->lower_margin, vmode->lower_margin); 290a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven 291a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* resolution + margins may not exceed native parameters */ 292a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven dx = ((long)vmode->left_margin + (long)vmode->xres + 293a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven (long)vmode->right_margin) - 294a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven (left_margin + xres + right_margin); 295a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (dx < 0) 296633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven return -1; 297633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven 298a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven dy = ((long)vmode->upper_margin + (long)vmode->yres + 299a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven (long)vmode->lower_margin) - 300a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven (upper_margin + yres + lower_margin); 301a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (dy < 0) 302a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven return -1; 303a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven 304a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* exact match */ 305a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (!dx && !dy) 306a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven return 0; 307a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven 308a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* resolution difference */ 309a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven return (vmode->xres - xres) * (vmode->yres - yres); 310633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven} 311633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven 31234c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoevenstatic const struct fb_videomode *ps3fb_native_vmode(enum ps3av_mode_num id) 31334c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven{ 31434c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven return &ps3fb_modedb[FIRST_NATIVE_MODE_INDEX + id - 1]; 31534c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven} 31634c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven 31734c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoevenstatic const struct fb_videomode *ps3fb_vmode(int id) 31834c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven{ 31934c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven u32 mode = id & PS3AV_MODE_MASK; 32034c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven 32134c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven if (mode < PS3AV_MODE_480I || mode > PS3AV_MODE_WUXGA) 32234c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven return NULL; 32334c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven 32434c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven if (mode <= PS3AV_MODE_1080P50 && !(id & PS3AV_MODE_FULL)) { 32534c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven /* Non-fullscreen broadcast mode */ 32634c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven return &ps3fb_modedb[mode - 1]; 32734c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven } 32834c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven 32934c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven return ps3fb_native_vmode(mode); 33034c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven} 33134c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven 332633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoevenstatic unsigned int ps3fb_find_mode(struct fb_var_screeninfo *var, 33361e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven u32 *ddr_line_length, u32 *xdr_line_length) 334310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 335a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven unsigned int id, best_id; 336a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven int diff, best_diff; 33734c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven const struct fb_videomode *vmode; 338a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven long gap; 339633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven 340a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven best_id = 0; 341a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven best_diff = INT_MAX; 342a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven pr_debug("%s: wanted %u [%u] %u x %u [%u] %u\n", __func__, 343a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->left_margin, var->xres, var->right_margin, 344a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->upper_margin, var->yres, var->lower_margin); 34534c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven for (id = PS3AV_MODE_480I; id <= PS3AV_MODE_WUXGA; id++) { 34634c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven vmode = ps3fb_native_vmode(id); 347a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven diff = ps3fb_cmp_mode(vmode, var); 348a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven pr_debug("%s: mode %u: %u [%u] %u x %u [%u] %u: diff = %d\n", 349a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven __func__, id, vmode->left_margin, vmode->xres, 350a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven vmode->right_margin, vmode->upper_margin, 351a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven vmode->yres, vmode->lower_margin, diff); 352a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (diff < 0) 353a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven continue; 354a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (diff < best_diff) { 355a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven best_id = id; 356a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (!diff) 357a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven break; 358a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven best_diff = diff; 359a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven } 36034c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven } 361310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 362a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (!best_id) { 363a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven pr_debug("%s: no suitable mode found\n", __func__); 364a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven return 0; 365a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven } 366a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven 367a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven id = best_id; 368a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven vmode = ps3fb_native_vmode(id); 36961e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven 37034c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven *ddr_line_length = vmode->xres * BPP; 371633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven 372a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* minimum resolution */ 373a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (!var->xres) 374633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven var->xres = 1; 375a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (!var->yres) 376633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven var->yres = 1; 377a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven 378a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* minimum virtual resolution */ 379a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (var->xres_virtual < var->xres) 380a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->xres_virtual = var->xres; 381a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (var->yres_virtual < var->yres) 382a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->yres_virtual = var->yres; 383a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven 384a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* minimum margins */ 385a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (var->left_margin < vmode->left_margin) 386a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->left_margin = vmode->left_margin; 387a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (var->right_margin < vmode->right_margin) 388a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->right_margin = vmode->right_margin; 389a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (var->upper_margin < vmode->upper_margin) 390a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->upper_margin = vmode->upper_margin; 391a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (var->lower_margin < vmode->lower_margin) 392a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->lower_margin = vmode->lower_margin; 393a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven 394a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* extra margins */ 395a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven gap = ((long)vmode->left_margin + (long)vmode->xres + 396a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven (long)vmode->right_margin) - 397a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven ((long)var->left_margin + (long)var->xres + 398a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven (long)var->right_margin); 399a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (gap > 0) { 400a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->left_margin += gap/2; 401a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->right_margin += (gap+1)/2; 402a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven pr_debug("%s: rounded up H to %u [%u] %u\n", __func__, 403a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->left_margin, var->xres, var->right_margin); 404a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven } 405a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven 406a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven gap = ((long)vmode->upper_margin + (long)vmode->yres + 407a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven (long)vmode->lower_margin) - 408a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven ((long)var->upper_margin + (long)var->yres + 409a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven (long)var->lower_margin); 410a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven if (gap > 0) { 411a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->upper_margin += gap/2; 412a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->lower_margin += (gap+1)/2; 413a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven pr_debug("%s: rounded up V to %u [%u] %u\n", __func__, 414a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->upper_margin, var->yres, var->lower_margin); 415633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven } 41661e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven 417a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven /* fixed fields */ 418a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->pixclock = vmode->pixclock; 419a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->hsync_len = vmode->hsync_len; 420a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->vsync_len = vmode->vsync_len; 421a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven var->sync = vmode->sync; 422a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven 42361e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven if (ps3_compare_firmware_version(1, 9, 0) >= 0) { 424a3665366b0cbf3af1e0949bb9ada9ce63eaaaac1Geert Uytterhoeven *xdr_line_length = GPU_ALIGN_UP(var->xres_virtual * BPP); 42561e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven if (*xdr_line_length > GPU_MAX_LINE_LENGTH) 42661e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven *xdr_line_length = GPU_MAX_LINE_LENGTH; 42761e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven } else 42861e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven *xdr_line_length = *ddr_line_length; 42961e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven 43034c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven if (vmode->sync & FB_SYNC_BROADCAST) { 431633bd111bafa346d0bb5137bd1e71b92cf1ca594Geert Uytterhoeven /* Full broadcast modes have the full mode bit set */ 43234c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven if (vmode->xres == var->xres && vmode->yres == var->yres) 43334c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven id |= PS3AV_MODE_FULL; 434310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 435310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 43634c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven pr_debug("%s: mode %u\n", __func__, id); 43734c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven return id; 438310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 439310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 440f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoevenstatic void ps3fb_sync_image(struct device *dev, u64 frame_offset, 441f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven u64 dst_offset, u64 src_offset, u32 width, 44261e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven u32 height, u32 dst_line_length, 44361e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven u32 src_line_length) 444310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 445f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven int status; 44661e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven u64 line_length; 44761e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven 44861e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven line_length = dst_line_length; 44961e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven if (src_line_length != dst_line_length) 45061e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven line_length |= (u64)src_line_length << 32; 451310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 4529ac67a35827ee03d71f2f1c656a725e263b14a7eGeert Uytterhoeven src_offset += GPU_FB_START; 4539b82f3e61758ed897200f0244b63a77c1791bcbaGeert Uytterhoeven 4549b82f3e61758ed897200f0244b63a77c1791bcbaGeert Uytterhoeven mutex_lock(&ps3_gpu_mutex); 455d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset, 456d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven GPU_IOIF + src_offset, 457d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | 458d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven (width << 16) | height, 459d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven line_length); 4609b82f3e61758ed897200f0244b63a77c1791bcbaGeert Uytterhoeven mutex_unlock(&ps3_gpu_mutex); 4619b82f3e61758ed897200f0244b63a77c1791bcbaGeert Uytterhoeven 462310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (status) 463d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__, 464d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven status); 465310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#ifdef HEAD_A 466d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset); 467310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (status) 468d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, 469d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven status); 470310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#endif 471310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#ifdef HEAD_B 472d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven status = lv1_gpu_display_flip(ps3fb.context_handle, 1, frame_offset); 473310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (status) 474d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, 475d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven status); 476310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#endif 477f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven} 478f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven 479f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoevenstatic int ps3fb_sync(struct fb_info *info, u32 frame) 480f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven{ 481f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven struct ps3fb_par *par = info->par; 4829f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven int error = 0; 48361e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven u64 ddr_base, xdr_base; 484f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven 485f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven if (frame > par->num_frames - 1) { 486f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven dev_dbg(info->device, "%s: invalid frame number (%u)\n", 487f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven __func__, frame); 488f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven error = -EINVAL; 489f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven goto out; 490f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven } 491f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven 4929f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven xdr_base = frame * par->xdr_frame_size; 4939f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven ddr_base = frame * par->ddr_frame_size; 494f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven 49561e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven ps3fb_sync_image(info->device, ddr_base + par->full_offset, 49661e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven ddr_base + par->fb_offset, xdr_base + par->pan_offset, 4979f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven par->width, par->height, par->ddr_line_length, 4989f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven info->fix.line_length); 4990333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven 5000333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoevenout: 5010333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven return error; 502310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 503310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 504310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic int ps3fb_open(struct fb_info *info, int user) 505310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 506310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven atomic_inc(&ps3fb.f_count); 507310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 0; 508310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 509310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 510310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic int ps3fb_release(struct fb_info *info, int user) 511310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 512310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (atomic_dec_and_test(&ps3fb.f_count)) { 513310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (atomic_read(&ps3fb.ext_flip)) { 514310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven atomic_set(&ps3fb.ext_flip, 0); 515ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn if (console_trylock()) { 5168dab63761219d7bc6a7d7d3b5f0fca76af5533a5Jeremy Kerr ps3fb_sync(info, 0); /* single buffer */ 517ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 5188dab63761219d7bc6a7d7d3b5f0fca76af5533a5Jeremy Kerr } 519310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 520310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 521310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 0; 522310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 523310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 524310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 525310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * Setting the video mode has been split into two parts. 526310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * First part, xxxfb_check_var, must not write anything 527310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * to hardware, it should only verify and adjust var. 528310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * This means it doesn't alter par but it does use hardware 529310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * data from it to check this var. 530310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven */ 531310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 532310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 533310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 53461e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven u32 xdr_line_length, ddr_line_length; 535310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven int mode; 536310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 53761e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length); 538310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (!mode) 539310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return -EINVAL; 540310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 541fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven /* Virtual screen */ 54261e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven if (var->xres_virtual > xdr_line_length / BPP) { 543535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, 544fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven "Horizontal virtual screen size too large\n"); 545310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return -EINVAL; 546310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 547310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 548fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven if (var->xoffset + var->xres > var->xres_virtual || 549fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven var->yoffset + var->yres > var->yres_virtual) { 550fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven dev_dbg(info->device, "panning out-of-range\n"); 551fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven return -EINVAL; 552fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven } 553310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 554310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* We support ARGB8888 only */ 555310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (var->bits_per_pixel > 32 || var->grayscale || 556310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->red.offset > 16 || var->green.offset > 8 || 557310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->blue.offset > 0 || var->transp.offset > 24 || 558310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->red.length > 8 || var->green.length > 8 || 559310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->blue.length > 8 || var->transp.length > 8 || 560310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->red.msb_right || var->green.msb_right || 561310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->blue.msb_right || var->transp.msb_right || var->nonstd) { 562535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "We support ARGB8888 only\n"); 563310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return -EINVAL; 564310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 565310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 566310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->bits_per_pixel = 32; 567310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->red.offset = 16; 568310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->green.offset = 8; 569310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->blue.offset = 0; 570310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->transp.offset = 24; 571310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->red.length = 8; 572310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->green.length = 8; 573310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->blue.length = 8; 574310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->transp.length = 8; 575310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->red.msb_right = 0; 576310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->green.msb_right = 0; 577310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->blue.msb_right = 0; 578310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->transp.msb_right = 0; 579310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 580310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* Rotation is not supported */ 581310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (var->rotate) { 582535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "Rotation is not supported\n"); 583310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return -EINVAL; 584310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 585310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 586310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* Memory limit */ 587a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven if (var->yres_virtual * xdr_line_length > info->fix.smem_len) { 588535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "Not enough memory\n"); 589310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return -ENOMEM; 590310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 591310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 592310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->height = -1; 593310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var->width = -1; 594310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 595310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 0; 596310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 597310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 598310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 599310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * This routine actually sets the video mode. 600310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven */ 601310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 602310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic int ps3fb_set_par(struct fb_info *info) 603310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 6040333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven struct ps3fb_par *par = info->par; 60561e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines; 6067974f72a21a246051b3dd84d7158974fc4785150Geert Uytterhoeven unsigned int ddr_xoff, ddr_yoff, offset; 6079f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven const struct fb_videomode *vmode; 60861e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven u64 dst; 609310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 61061e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length); 611310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (!mode) 612310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return -EINVAL; 613310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 61434c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven vmode = ps3fb_native_vmode(mode & PS3AV_MODE_MASK); 615c95344a557099f4e4a9fd05b6145a72541b2158aGeert Uytterhoeven 616fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; 617fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; 61861e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven info->fix.line_length = xdr_line_length; 619fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven 6209f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven par->ddr_line_length = ddr_line_length; 6219f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven par->ddr_frame_size = vmode->yres * ddr_line_length; 6229f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven par->xdr_frame_size = info->var.yres_virtual * xdr_line_length; 6239f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven 624a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven par->num_frames = info->fix.smem_len / 6259f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven max(par->ddr_frame_size, par->xdr_frame_size); 626310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 627310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* Keep the special bits we cannot set using fb_var_screeninfo */ 6280333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode; 629310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 630f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven par->width = info->var.xres; 631f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven par->height = info->var.yres; 632d9a4ba6a28f6cdd291ce2ee85bc91a85ff2c4a38Geert Uytterhoeven 633d9a4ba6a28f6cdd291ce2ee85bc91a85ff2c4a38Geert Uytterhoeven /* Start of the virtual frame buffer (relative to fullscreen) */ 6349f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven ddr_xoff = info->var.left_margin - vmode->left_margin; 6359f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven ddr_yoff = info->var.upper_margin - vmode->upper_margin; 6369f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven offset = ddr_yoff * ddr_line_length + ddr_xoff * BPP; 637d9a4ba6a28f6cdd291ce2ee85bc91a85ff2c4a38Geert Uytterhoeven 638f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven par->fb_offset = GPU_ALIGN_UP(offset); 639f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven par->full_offset = par->fb_offset - offset; 64061e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven par->pan_offset = info->var.yoffset * xdr_line_length + 641fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven info->var.xoffset * BPP; 642f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven 6430333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven if (par->new_mode_id != par->mode_id) { 6440333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven if (ps3av_set_video_mode(par->new_mode_id)) { 6450333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven par->new_mode_id = par->mode_id; 6460333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven return -EINVAL; 6470333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven } 6480333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven par->mode_id = par->new_mode_id; 6490333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven } 650310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 651f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven /* Clear XDR frame buffer memory */ 652a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven memset((void __force *)info->screen_base, 0, info->fix.smem_len); 653f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven 654f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven /* Clear DDR frame buffer memory */ 6559f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven lines = vmode->yres * par->num_frames; 656f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven if (par->full_offset) 657f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven lines++; 658a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven maxlines = info->fix.smem_len / ddr_line_length; 65961e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven for (dst = 0; lines; dst += maxlines * ddr_line_length) { 660f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven unsigned int l = min(lines, maxlines); 6619f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven ps3fb_sync_image(info->device, 0, dst, 0, vmode->xres, l, 66261e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven ddr_line_length, ddr_line_length); 663f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven lines -= l; 664f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven } 665f1664ed8ae98d17b294e01a5a0220f635f207824Geert Uytterhoeven 666310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 0; 667310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 668310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 669310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 670310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * Set a single color register. The values supplied are already 671310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * rounded down to the hardware's capabilities (according to the 672310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * entries in the var structure). Return != 0 for invalid regno. 673310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven */ 674310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 675310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic int ps3fb_setcolreg(unsigned int regno, unsigned int red, 676310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven unsigned int green, unsigned int blue, 677310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven unsigned int transp, struct fb_info *info) 678310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 679310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (regno >= 16) 680310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 1; 681310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 682310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven red >>= 8; 683310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven green >>= 8; 684310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven blue >>= 8; 685310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven transp >>= 8; 686310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 687310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven ((u32 *)info->pseudo_palette)[regno] = transp << 24 | red << 16 | 688310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven green << 8 | blue; 689310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 0; 690310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 691310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 692fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoevenstatic int ps3fb_pan_display(struct fb_var_screeninfo *var, 693fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven struct fb_info *info) 694fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven{ 695fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven struct ps3fb_par *par = info->par; 696fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven 697fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven par->pan_offset = var->yoffset * info->fix.line_length + 698fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven var->xoffset * BPP; 699fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven return 0; 700fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven} 701fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven 702310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 703310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * As we have a virtual frame buffer, we need our own mmap function 704310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven */ 705310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 706310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma) 707310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 70811bd5933abe033fb7a3a0d1f1bd2cb4b6df8143fTomi Valkeinen int r; 709310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 71011bd5933abe033fb7a3a0d1f1bd2cb4b6df8143fTomi Valkeinen r = vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len); 711310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 712535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n", 713b358c6cf029cb67b3ed9cc367fb46f1fa3228c5bTomi Valkeinen info->fix.smem_start + (vma->vm_pgoff << PAGE_SHIFT), 71411bd5933abe033fb7a3a0d1f1bd2cb4b6df8143fTomi Valkeinen vma->vm_start); 71511bd5933abe033fb7a3a0d1f1bd2cb4b6df8143fTomi Valkeinen 71611bd5933abe033fb7a3a0d1f1bd2cb4b6df8143fTomi Valkeinen return r; 717310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 718310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 719310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 720310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * Blank the display 721310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven */ 722310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 723310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic int ps3fb_blank(int blank, struct fb_info *info) 724310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 725310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven int retval; 726310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 727535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "%s: blank:%d\n", __func__, blank); 728310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven switch (blank) { 729310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case FB_BLANK_POWERDOWN: 730310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case FB_BLANK_HSYNC_SUSPEND: 731310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case FB_BLANK_VSYNC_SUSPEND: 732310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case FB_BLANK_NORMAL: 733310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = ps3av_video_mute(1); /* mute on */ 734310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (!retval) 735310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven ps3fb.is_blanked = 1; 736310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 737310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 738310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven default: /* unblank */ 739310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = ps3av_video_mute(0); /* mute off */ 740310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (!retval) 741310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven ps3fb.is_blanked = 0; 742310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 743310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 744310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return retval; 745310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 746310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 747310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic int ps3fb_get_vblank(struct fb_vblank *vblank) 748310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 7493cc2c17700c98b0af778566b0af6292b23b01430Li Zefan memset(vblank, 0, sizeof(*vblank)); 750310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven vblank->flags = FB_VBLANK_HAVE_VSYNC; 751310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 0; 752310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 753310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 75415e4d001ef5b14f56fa51665952cbffc0001762fGeert Uytterhoevenstatic int ps3fb_wait_for_vsync(u32 crtc) 755310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 756310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven int ret; 757310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 count; 758310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 759310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven count = ps3fb.vblank_count; 760310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven ret = wait_event_interruptible_timeout(ps3fb.wait_vsync, 761310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven count != ps3fb.vblank_count, 762310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven HZ / 10); 763310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (!ret) 764310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return -ETIMEDOUT; 765310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 766310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 0; 767310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 768310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 769310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 770310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* 771310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven * ioctl 772310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven */ 773310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 774310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, 775310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven unsigned long arg) 776310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 777310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven void __user *argp = (void __user *)arg; 7780333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven u32 val; 779310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven int retval = -EFAULT; 780310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 781310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven switch (cmd) { 782310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case FBIOGET_VBLANK: 783310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven { 784310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven struct fb_vblank vblank; 785535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "FBIOGET_VBLANK:\n"); 786310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = ps3fb_get_vblank(&vblank); 787310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (retval) 788310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 789310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 790310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (copy_to_user(argp, &vblank, sizeof(vblank))) 791310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = -EFAULT; 792310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 793310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 794310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 795310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case FBIO_WAITFORVSYNC: 796310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven { 797310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u32 crt; 798535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "FBIO_WAITFORVSYNC:\n"); 799310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (get_user(crt, (u32 __user *) arg)) 800310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 801310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 802310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = ps3fb_wait_for_vsync(crt); 803310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 804310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 805310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 806310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case PS3FB_IOCTL_SETMODE: 807310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven { 8080333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven struct ps3fb_par *par = info->par; 80934c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven const struct fb_videomode *vmode; 810310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven struct fb_var_screeninfo var; 811310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 812310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (copy_from_user(&val, argp, sizeof(val))) 813310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 814310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 815640729014e073e6e2de1f513b2856b81aa7d84e9Masashi Kimoto if (!(val & PS3AV_MODE_MASK)) { 816ce4c371a9de1f5b9e1d15f9d59c5f7d079bcd6d7Geert Uytterhoeven u32 id = ps3av_get_auto_mode(); 817640729014e073e6e2de1f513b2856b81aa7d84e9Masashi Kimoto if (id > 0) 818640729014e073e6e2de1f513b2856b81aa7d84e9Masashi Kimoto val = (val & ~PS3AV_MODE_MASK) | id; 819640729014e073e6e2de1f513b2856b81aa7d84e9Masashi Kimoto } 820535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val); 821310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = -EINVAL; 82234c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven vmode = ps3fb_vmode(val); 82334c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven if (vmode) { 824310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var = info->var; 82534c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven fb_videomode_to_var(&var, vmode); 826ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 827310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven info->flags |= FBINFO_MISC_USEREVENT; 828310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* Force, in case only special bits changed */ 829310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven var.activate |= FB_ACTIVATE_FORCE; 8300333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven par->new_mode_id = val; 831310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = fb_set_var(info, &var); 832310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven info->flags &= ~FBINFO_MISC_USEREVENT; 833ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 834310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 835310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 836310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 837310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 838310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case PS3FB_IOCTL_GETMODE: 839310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven val = ps3av_get_mode(); 840535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "PS3FB_IOCTL_GETMODE:%x\n", val); 841310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (!copy_to_user(argp, &val, sizeof(val))) 842310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = 0; 843310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 844310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 845310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case PS3FB_IOCTL_SCREENINFO: 846310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven { 8470333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven struct ps3fb_par *par = info->par; 848310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven struct ps3fb_ioctl_res res; 849535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n"); 85061e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven res.xres = info->fix.line_length / BPP; 85161e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven res.yres = info->var.yres_virtual; 85261e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven res.xoff = (res.xres - info->var.xres) / 2; 85361e0b28e5435ac3010746bcf24fe8a16425d0343Geert Uytterhoeven res.yoff = (res.yres - info->var.yres) / 2; 8540333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven res.num_frames = par->num_frames; 855310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (!copy_to_user(argp, &res, sizeof(res))) 856310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = 0; 857310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 858310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 859310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 860310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case PS3FB_IOCTL_ON: 861535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "PS3FB_IOCTL_ON:\n"); 862310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven atomic_inc(&ps3fb.ext_flip); 863310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = 0; 864310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 865310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 866310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case PS3FB_IOCTL_OFF: 867535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "PS3FB_IOCTL_OFF:\n"); 868eca28743b74736456bd75e0dabeb7d2df09fc03eGeert Uytterhoeven atomic_dec_if_positive(&ps3fb.ext_flip); 869310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = 0; 870310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 871310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 872310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven case PS3FB_IOCTL_FSEL: 873310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (copy_from_user(&val, argp, sizeof(val))) 874310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 875310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 876535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val); 877ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 878535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven retval = ps3fb_sync(info, val); 879ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 880310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 881310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 882310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven default: 883310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = -ENOIOCTLCMD; 884310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven break; 885310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 886310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return retval; 887310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 888310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 889310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic int ps3fbd(void *arg) 890310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 891535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven struct fb_info *info = arg; 892535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven 893831441862956fffa17b9801db37e6ea1650b0f69Rafael J. Wysocki set_freezable(); 8941c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven while (!kthread_should_stop()) { 8951c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven try_to_freeze(); 8961c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven set_current_state(TASK_INTERRUPTIBLE); 8971c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven if (ps3fb.is_kicked) { 8981c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven ps3fb.is_kicked = 0; 899ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 900535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven ps3fb_sync(info, 0); /* single buffer */ 901ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 9021c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven } 9031c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven schedule(); 904310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 905310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 0; 906310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 907310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 908310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) 909310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 910535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven struct device *dev = ptr; 911310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 v1; 912310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven int status; 913310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven struct display_head *head = &ps3fb.dinfo->display_head[1]; 914310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 915310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven status = lv1_gpu_context_intr(ps3fb.context_handle, &v1); 916310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (status) { 917535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_err(dev, "%s: lv1_gpu_context_intr failed: %d\n", __func__, 918535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven status); 919310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return IRQ_NONE; 920310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 921310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 922310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) { 923310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* VSYNC */ 924310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven ps3fb.vblank_count = head->vblank_count; 9251c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven if (ps3fb.task && !ps3fb.is_blanked && 9261c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven !atomic_read(&ps3fb.ext_flip)) { 9271c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven ps3fb.is_kicked = 1; 9281c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven wake_up_process(ps3fb.task); 9291c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven } 930310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven wake_up_interruptible(&ps3fb.wait_vsync); 931310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 932310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 933310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return IRQ_HANDLED; 934310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 935310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 936310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 937310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic struct fb_ops ps3fb_ops = { 938310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .fb_open = ps3fb_open, 939310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .fb_release = ps3fb_release, 94092c4579dbb3bc70bd397e272258c69f88de189b8Geert Uytterhoeven .fb_read = fb_sys_read, 94192c4579dbb3bc70bd397e272258c69f88de189b8Geert Uytterhoeven .fb_write = fb_sys_write, 942310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .fb_check_var = ps3fb_check_var, 943310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .fb_set_par = ps3fb_set_par, 944310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .fb_setcolreg = ps3fb_setcolreg, 945fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven .fb_pan_display = ps3fb_pan_display, 94692c4579dbb3bc70bd397e272258c69f88de189b8Geert Uytterhoeven .fb_fillrect = sys_fillrect, 94792c4579dbb3bc70bd397e272258c69f88de189b8Geert Uytterhoeven .fb_copyarea = sys_copyarea, 94892c4579dbb3bc70bd397e272258c69f88de189b8Geert Uytterhoeven .fb_imageblit = sys_imageblit, 949310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .fb_mmap = ps3fb_mmap, 950310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .fb_blank = ps3fb_blank, 951310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .fb_ioctl = ps3fb_ioctl, 952310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .fb_compat_ioctl = ps3fb_ioctl 953310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven}; 954310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 95588c2d0b6fa753c63047fad92eac94c376ee4e568Vladimir Murzinstatic struct fb_fix_screeninfo ps3fb_fix = { 9569e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven .id = DEVICE_NAME, 957310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .type = FB_TYPE_PACKED_PIXELS, 958310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .visual = FB_VISUAL_TRUECOLOR, 959310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven .accel = FB_ACCEL_NONE, 960310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven}; 961310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 96248c68c4f1b542444f175a9e136febcecf3e704d8Greg Kroah-Hartmanstatic int ps3fb_probe(struct ps3_system_bus_device *dev) 963310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 964310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven struct fb_info *info; 9650333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven struct ps3fb_par *par; 966ca971ea39fa92add0fa596ad80affd7db781d762Geert Uytterhoeven int retval; 967310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 ddr_lpar = 0; 968310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 lpar_dma_control = 0; 969310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 lpar_driver_info = 0; 970310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 lpar_reports = 0; 971310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 lpar_reports_size = 0; 972310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven u64 xdr_lpar; 973bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven struct gpu_driver_info *dinfo; 974a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven void *fb_start; 9759f4f21b453f2f51c9d1f22638eae306c07c95b42Geert Uytterhoeven int status; 9761c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven struct task_struct *task; 977ee592a5bd5180cc1ffaf5acd7bf1e91e0d854a08Geert Uytterhoeven unsigned long max_ps3fb_size; 978310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 9799ac67a35827ee03d71f2f1c656a725e263b14a7eGeert Uytterhoeven if (ps3fb_videomemory.size < GPU_CMD_BUF_SIZE) { 9809ac67a35827ee03d71f2f1c656a725e263b14a7eGeert Uytterhoeven dev_err(&dev->core, "%s: Not enough video memory\n", __func__); 9819ac67a35827ee03d71f2f1c656a725e263b14a7eGeert Uytterhoeven return -ENOMEM; 9829ac67a35827ee03d71f2f1c656a725e263b14a7eGeert Uytterhoeven } 9839ac67a35827ee03d71f2f1c656a725e263b14a7eGeert Uytterhoeven 984ca971ea39fa92add0fa596ad80affd7db781d762Geert Uytterhoeven retval = ps3_open_hv_device(dev); 985ca971ea39fa92add0fa596ad80affd7db781d762Geert Uytterhoeven if (retval) { 986535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_err(&dev->core, "%s: ps3_open_hv_device failed\n", 987535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven __func__); 9889e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven goto err; 9899e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven } 9909e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven 9919e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven if (!ps3fb_mode) 9929e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven ps3fb_mode = ps3av_get_mode(); 993084ffff29844a4bce69999d67809e6c00309ba58Geert Uytterhoeven dev_dbg(&dev->core, "ps3fb_mode: %d\n", ps3fb_mode); 9949e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven 9959e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ 9969e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ 9979e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven init_waitqueue_head(&ps3fb.wait_vsync); 9989e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven 999bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven#ifdef HEAD_A 1000d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven status = lv1_gpu_display_sync(0x0, 0, L1GPU_DISPLAY_SYNC_VSYNC); 1001bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven if (status) { 1002d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", 1003bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven __func__, status); 1004ca971ea39fa92add0fa596ad80affd7db781d762Geert Uytterhoeven retval = -ENODEV; 1005ca971ea39fa92add0fa596ad80affd7db781d762Geert Uytterhoeven goto err_close_device; 1006bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven } 1007bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven#endif 1008bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven#ifdef HEAD_B 1009d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven status = lv1_gpu_display_sync(0x0, 1, L1GPU_DISPLAY_SYNC_VSYNC); 1010bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven if (status) { 1011d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", 1012bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven __func__, status); 1013ca971ea39fa92add0fa596ad80affd7db781d762Geert Uytterhoeven retval = -ENODEV; 1014ca971ea39fa92add0fa596ad80affd7db781d762Geert Uytterhoeven goto err_close_device; 1015bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven } 1016bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven#endif 10179e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven 1018ee592a5bd5180cc1ffaf5acd7bf1e91e0d854a08Geert Uytterhoeven max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF; 1019ee592a5bd5180cc1ffaf5acd7bf1e91e0d854a08Geert Uytterhoeven if (ps3fb_videomemory.size > max_ps3fb_size) { 1020ee592a5bd5180cc1ffaf5acd7bf1e91e0d854a08Geert Uytterhoeven dev_info(&dev->core, "Limiting ps3fb mem size to %lu bytes\n", 1021ee592a5bd5180cc1ffaf5acd7bf1e91e0d854a08Geert Uytterhoeven max_ps3fb_size); 1022ee592a5bd5180cc1ffaf5acd7bf1e91e0d854a08Geert Uytterhoeven ps3fb_videomemory.size = max_ps3fb_size; 1023ee592a5bd5180cc1ffaf5acd7bf1e91e0d854a08Geert Uytterhoeven } 1024ee592a5bd5180cc1ffaf5acd7bf1e91e0d854a08Geert Uytterhoeven 1025310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* get gpu context handle */ 1026ee592a5bd5180cc1ffaf5acd7bf1e91e0d854a08Geert Uytterhoeven status = lv1_gpu_memory_allocate(ps3fb_videomemory.size, 0, 0, 0, 0, 1027310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven &ps3fb.memory_handle, &ddr_lpar); 1028310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (status) { 1029535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", 1030535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven __func__, status); 10318ead8a2e943ac4101f2dc5a806042fe34db976a1Peter Senna Tschudin retval = -ENOMEM; 1032ca971ea39fa92add0fa596ad80affd7db781d762Geert Uytterhoeven goto err_close_device; 1033310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 10345d9ee3ff3dbf815cd9ee18c166bb9b538e8057d2Stephen Rothwell dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar); 1035310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1036310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven status = lv1_gpu_context_allocate(ps3fb.memory_handle, 0, 1037310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven &ps3fb.context_handle, 1038310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven &lpar_dma_control, &lpar_driver_info, 1039310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven &lpar_reports, &lpar_reports_size); 1040310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (status) { 1041535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_err(&dev->core, 1042d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven "%s: lv1_gpu_context_allocate failed: %d\n", __func__, 1043535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven status); 10448ead8a2e943ac4101f2dc5a806042fe34db976a1Peter Senna Tschudin retval = -ENOMEM; 1045310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven goto err_gpu_memory_free; 1046310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 1047310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1048310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven /* vsync interrupt */ 1049bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); 1050bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven if (!dinfo) { 1051535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_err(&dev->core, "%s: ioremap failed\n", __func__); 10528ead8a2e943ac4101f2dc5a806042fe34db976a1Peter Senna Tschudin retval = -ENOMEM; 1053310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven goto err_gpu_context_free; 1054310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 1055310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1056bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven ps3fb.dinfo = dinfo; 1057bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dev_dbg(&dev->core, "version_driver:%x\n", dinfo->version_driver); 1058bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dev_dbg(&dev->core, "irq outlet:%x\n", dinfo->irq.irq_outlet); 1059bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dev_dbg(&dev->core, "version_gpu: %x memory_size: %x ch: %x " 1060bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven "core_freq: %d mem_freq:%d\n", dinfo->version_gpu, 1061bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dinfo->memory_size, dinfo->hardware_channel, 1062bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dinfo->nvcore_frequency/1000000, 1063bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dinfo->memory_frequency/1000000); 1064bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven 1065bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { 1066bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dev_err(&dev->core, "%s: version_driver err:%x\n", __func__, 1067bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dinfo->version_driver); 1068bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven retval = -EINVAL; 1069bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven goto err_iounmap_dinfo; 1070bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven } 1071bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven 1072bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven retval = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, 1073bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven &ps3fb.irq_no); 1074bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven if (retval) { 1075bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dev_err(&dev->core, "%s: ps3_alloc_irq failed %d\n", __func__, 1076bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven retval); 1077310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven goto err_iounmap_dinfo; 1078bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven } 1079bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven 1080bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, 1081f8798ccbefc0e4ef7438c080b7ba0410738c8cfaYong Zhang 0, DEVICE_NAME, &dev->core); 1082bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven if (retval) { 1083bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dev_err(&dev->core, "%s: request_irq failed %d\n", __func__, 1084bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven retval); 1085bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven goto err_destroy_plug; 1086bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven } 1087bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven 1088bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | 1089bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven (1 << GPU_INTR_STATUS_FLIP_1); 1090310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 10912ce32e15a16312d2c29c8bb188bf95bc821fdab6Geert Uytterhoeven /* Clear memory to prevent kernel info leakage into userspace */ 1092a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size); 10932ce32e15a16312d2c29c8bb188bf95bc821fdab6Geert Uytterhoeven 1094a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); 1095bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven 1096bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, 1097e78d0c5c14ab91648274b2c5e6c4c35f072cea64Geert Uytterhoeven xdr_lpar, ps3fb_videomemory.size, 1098e78d0c5c14ab91648274b2c5e6c4c35f072cea64Geert Uytterhoeven CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | 1099e78d0c5c14ab91648274b2c5e6c4c35f072cea64Geert Uytterhoeven CBE_IOPTE_M); 1100bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven if (status) { 1101bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dev_err(&dev->core, "%s: lv1_gpu_context_iomap failed: %d\n", 1102bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven __func__, status); 1103bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven retval = -ENXIO; 1104bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven goto err_free_irq; 1105bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven } 1106bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven 1107bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven dev_dbg(&dev->core, "video:%p ioif:%lx lpar:%llx size:%lx\n", 1108bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, 1109bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven ps3fb_videomemory.size); 1110bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven 1111d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven status = lv1_gpu_fb_setup(ps3fb.context_handle, xdr_lpar, 1112d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven GPU_CMD_BUF_SIZE, GPU_IOIF); 1113bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven if (status) { 1114d3352c9f1e8e2f2989d9686c8aa8acb4842fe75eGeert Uytterhoeven dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n", 1115bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven __func__, status); 1116bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven retval = -ENXIO; 1117e78d0c5c14ab91648274b2c5e6c4c35f072cea64Geert Uytterhoeven goto err_context_unmap; 1118bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoeven } 1119310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 11200333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); 11218ead8a2e943ac4101f2dc5a806042fe34db976a1Peter Senna Tschudin if (!info) { 11228ead8a2e943ac4101f2dc5a806042fe34db976a1Peter Senna Tschudin retval = -ENOMEM; 1123c204ff65590837e6a9c50ca549497b4682682ec6Geert Uytterhoeven goto err_context_fb_close; 11248ead8a2e943ac4101f2dc5a806042fe34db976a1Peter Senna Tschudin } 1125310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 11260333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven par = info->par; 11270333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ 11280333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven par->new_mode_id = ps3fb_mode; 11290333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven par->num_frames = 1; 11300333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven 1131310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven info->fbops = &ps3fb_ops; 1132310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven info->fix = ps3fb_fix; 1133a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven 1134a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven /* 1135a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven * The GPU command buffer is at the start of video memory 1136a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven * As we don't use the full command buffer, we can put the actual 1137a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven * frame buffer at offset GPU_FB_START and save some precious XDR 1138a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven * memory 1139a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven */ 1140a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven fb_start = ps3fb_videomemory.address + GPU_FB_START; 1141a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven info->screen_base = (char __force __iomem *)fb_start; 1142f6b3df625ab8285398b4acf02942a8e742e72efcMichael Ellerman info->fix.smem_start = __pa(fb_start); 1143a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven info->fix.smem_len = ps3fb_videomemory.size - GPU_FB_START; 1144a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven 11450333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven info->pseudo_palette = par->pseudo_palette; 1146fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST | 1147fc7028b7487cc57ef44c7efc5e286f06bef8fc13Geert Uytterhoeven FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; 1148310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1149310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = fb_alloc_cmap(&info->cmap, 256, 0); 1150310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (retval < 0) 1151310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven goto err_framebuffer_release; 1152310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1153310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb, 11540333d83509c7d8496c8965b5ba9bc0c98e83c259Geert Uytterhoeven ARRAY_SIZE(ps3fb_modedb), 115534c422fb2435b1e18b7c36c3310e4f57e21d7ddfGeert Uytterhoeven ps3fb_vmode(par->new_mode_id), 32)) { 1156310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = -EINVAL; 1157310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven goto err_fb_dealloc; 1158310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 1159310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1160310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven fb_videomode_to_modelist(ps3fb_modedb, ARRAY_SIZE(ps3fb_modedb), 1161310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven &info->modelist); 1162310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1163310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven retval = register_framebuffer(info); 1164310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (retval < 0) 1165310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven goto err_fb_dealloc; 1166310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1167cd4a157d769311964717d5c7cfc0c34426d090b4Geert Uytterhoeven ps3_system_bus_set_drvdata(dev, info); 1168310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1169a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven dev_info(info->device, "%s %s, using %u KiB of video memory\n", 11707ad33e74857f16f1202cbc5746faf52e88e8b376Kay Sievers dev_driver_string(info->dev), dev_name(info->dev), 1171a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven info->fix.smem_len >> 10); 1172310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 11739e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven task = kthread_run(ps3fbd, info, DEVICE_NAME); 11741c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven if (IS_ERR(task)) { 11751c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven retval = PTR_ERR(task); 11761c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven goto err_unregister_framebuffer; 11771c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven } 11781c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven 11791c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven ps3fb.task = task; 11801c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven 1181310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 0; 1182310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 11831c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoevenerr_unregister_framebuffer: 11841c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven unregister_framebuffer(info); 1185310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenerr_fb_dealloc: 1186310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven fb_dealloc_cmap(&info->cmap); 1187310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenerr_framebuffer_release: 1188310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven framebuffer_release(info); 1189c204ff65590837e6a9c50ca549497b4682682ec6Geert Uytterhoevenerr_context_fb_close: 1190c204ff65590837e6a9c50ca549497b4682682ec6Geert Uytterhoeven lv1_gpu_fb_close(ps3fb.context_handle); 1191e78d0c5c14ab91648274b2c5e6c4c35f072cea64Geert Uytterhoevenerr_context_unmap: 1192e78d0c5c14ab91648274b2c5e6c4c35f072cea64Geert Uytterhoeven lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, 1193e78d0c5c14ab91648274b2c5e6c4c35f072cea64Geert Uytterhoeven ps3fb_videomemory.size, CBE_IOPTE_M); 1194310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenerr_free_irq: 1195fcbe6e9709f90fd83cfa614a4e0efe83174018eaGeoff Levand free_irq(ps3fb.irq_no, &dev->core); 1196bb94f077e5c1d3276fe656665c2574fdd3483e75Geert Uytterhoevenerr_destroy_plug: 1197dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand ps3_irq_plug_destroy(ps3fb.irq_no); 1198310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenerr_iounmap_dinfo: 1199a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven iounmap((u8 __force __iomem *)ps3fb.dinfo); 1200310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenerr_gpu_context_free: 1201310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven lv1_gpu_context_free(ps3fb.context_handle); 1202310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenerr_gpu_memory_free: 1203310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven lv1_gpu_memory_free(ps3fb.memory_handle); 1204ca971ea39fa92add0fa596ad80affd7db781d762Geert Uytterhoevenerr_close_device: 1205ca971ea39fa92add0fa596ad80affd7db781d762Geert Uytterhoeven ps3_close_hv_device(dev); 1206310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenerr: 1207310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return retval; 1208310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 1209310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 12109e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoevenstatic int ps3fb_shutdown(struct ps3_system_bus_device *dev) 1211310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 1212cd4a157d769311964717d5c7cfc0c34426d090b4Geert Uytterhoeven struct fb_info *info = ps3_system_bus_get_drvdata(dev); 1213e78d0c5c14ab91648274b2c5e6c4c35f072cea64Geert Uytterhoeven u64 xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); 12149e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven 1215535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); 12169e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven 12179b82f3e61758ed897200f0244b63a77c1791bcbaGeert Uytterhoeven atomic_inc(&ps3fb.ext_flip); /* flip off */ 1218310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven ps3fb.dinfo->irq.mask = 0; 1219310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 12201c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven if (ps3fb.task) { 12211c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven struct task_struct *task = ps3fb.task; 12221c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven ps3fb.task = NULL; 12231c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven kthread_stop(task); 12241c0c8461191d6d74926397abe2aa5f7cc9fd5a67Geert Uytterhoeven } 1225310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven if (ps3fb.irq_no) { 1226fcbe6e9709f90fd83cfa614a4e0efe83174018eaGeoff Levand free_irq(ps3fb.irq_no, &dev->core); 1227dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand ps3_irq_plug_destroy(ps3fb.irq_no); 1228310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 1229ba21611c9c0031ca8388cae5e43b38c29c8b595dJeremy Kerr if (info) { 1230ba21611c9c0031ca8388cae5e43b38c29c8b595dJeremy Kerr unregister_framebuffer(info); 1231ba21611c9c0031ca8388cae5e43b38c29c8b595dJeremy Kerr fb_dealloc_cmap(&info->cmap); 1232ba21611c9c0031ca8388cae5e43b38c29c8b595dJeremy Kerr framebuffer_release(info); 1233cd4a157d769311964717d5c7cfc0c34426d090b4Geert Uytterhoeven ps3_system_bus_set_drvdata(dev, NULL); 1234ba21611c9c0031ca8388cae5e43b38c29c8b595dJeremy Kerr } 1235a286408c702cad43ae9046f4ed4928495848ea51Geert Uytterhoeven iounmap((u8 __force __iomem *)ps3fb.dinfo); 1236c204ff65590837e6a9c50ca549497b4682682ec6Geert Uytterhoeven lv1_gpu_fb_close(ps3fb.context_handle); 1237e78d0c5c14ab91648274b2c5e6c4c35f072cea64Geert Uytterhoeven lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, 1238e78d0c5c14ab91648274b2c5e6c4c35f072cea64Geert Uytterhoeven ps3fb_videomemory.size, CBE_IOPTE_M); 123902aad32c32691b63a47d8e7c098c1822faf88c35Geert Uytterhoeven lv1_gpu_context_free(ps3fb.context_handle); 124002aad32c32691b63a47d8e7c098c1822faf88c35Geert Uytterhoeven lv1_gpu_memory_free(ps3fb.memory_handle); 12419e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven ps3_close_hv_device(dev); 1242535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); 1243310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1244310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 0; 1245310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 1246310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 12479e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoevenstatic struct ps3_system_bus_driver ps3fb_driver = { 124846d01492b2c50791b9b66f9b9154ac8d25acaeb9Geert Uytterhoeven .match_id = PS3_MATCH_ID_GPU, 124946d01492b2c50791b9b66f9b9154ac8d25acaeb9Geert Uytterhoeven .match_sub_id = PS3_MATCH_SUB_ID_GPU_FB, 12509e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven .core.name = DEVICE_NAME, 12519e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven .core.owner = THIS_MODULE, 12529e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven .probe = ps3fb_probe, 12539e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven .remove = ps3fb_shutdown, 12549e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven .shutdown = ps3fb_shutdown, 1255310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven}; 1256310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 12579e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoevenstatic int __init ps3fb_setup(void) 1258310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 12599e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven char *options; 1260310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 12619e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven#ifdef MODULE 1262310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven return 0; 1263310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven#endif 1264310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 12659e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven if (fb_get_options(DEVICE_NAME, &options)) 12669e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven return -ENXIO; 1267310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 12689e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven if (!options || !*options) 12699e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven return 0; 1270310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 12719e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven while (1) { 12729e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven char *this_opt = strsep(&options, ","); 1273310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 12749e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven if (!this_opt) 12759e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven break; 12769e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven if (!*this_opt) 12779e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven continue; 12789e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven if (!strncmp(this_opt, "mode:", 5)) 12799e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0); 12809e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven else 12819e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven mode_option = this_opt; 1282310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven } 12839e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven return 0; 12849e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven} 1285310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 12869e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoevenstatic int __init ps3fb_init(void) 12879e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven{ 12889e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven if (!ps3fb_videomemory.address || ps3fb_setup()) 12899e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven return -ENXIO; 1290310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 12919e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven return ps3_system_bus_driver_register(&ps3fb_driver); 1292310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 1293310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1294310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenstatic void __exit ps3fb_exit(void) 1295310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven{ 1296535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven pr_debug(" -> %s:%d\n", __func__, __LINE__); 12979e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoeven ps3_system_bus_driver_unregister(&ps3fb_driver); 1298535da7ffe68dfdf70c7aecade21864a573035b75Geert Uytterhoeven pr_debug(" <- %s:%d\n", __func__, __LINE__); 1299310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven} 1300310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 13019e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert Uytterhoevenmodule_init(ps3fb_init); 1302310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoevenmodule_exit(ps3fb_exit); 1303310d8c11126d21e417206c874c6382c44ece1baaGeert Uytterhoeven 1304310d8c11126d21e417206c874c6382c44ece1baaGeert UytterhoevenMODULE_LICENSE("GPL"); 13059e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert UytterhoevenMODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver"); 13069e6b99bd4494dadebb189d2db4d1f55ae726b0bbGeert UytterhoevenMODULE_AUTHOR("Sony Computer Entertainment Inc."); 130746d01492b2c50791b9b66f9b9154ac8d25acaeb9Geert UytterhoevenMODULE_ALIAS(PS3_MODULE_ALIAS_GPU_FB); 1308