[go: nahoru, domu]

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