xref: /OK3568_Linux_fs/kernel/drivers/video/fbdev/aty/aty128fb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /* $Id: aty128fb.c,v 1.1.1.1.36.1 1999/12/11 09:03:05 Exp $
3*4882a593Smuzhiyun  *  linux/drivers/video/aty128fb.c -- Frame buffer device for ATI Rage128
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (C) 1999-2003, Brad Douglas <brad@neruo.com>
6*4882a593Smuzhiyun  *  Copyright (C) 1999, Anthony Tong <atong@uiuc.edu>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *                Ani Joshi / Jeff Garzik
9*4882a593Smuzhiyun  *                      - Code cleanup
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  *                Michel Danzer <michdaen@iiic.ethz.ch>
12*4882a593Smuzhiyun  *                      - 15/16 bit cleanup
13*4882a593Smuzhiyun  *                      - fix panning
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  *                Benjamin Herrenschmidt
16*4882a593Smuzhiyun  *                      - pmac-specific PM stuff
17*4882a593Smuzhiyun  *			- various fixes & cleanups
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  *                Andreas Hundt <andi@convergence.de>
20*4882a593Smuzhiyun  *                      - FB_ACTIVATE fixes
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  *		  Paul Mackerras <paulus@samba.org>
23*4882a593Smuzhiyun  *			- Convert to new framebuffer API,
24*4882a593Smuzhiyun  *			  fix colormap setting at 16 bits/pixel (565)
25*4882a593Smuzhiyun  *
26*4882a593Smuzhiyun  *		  Paul Mundt
27*4882a593Smuzhiyun  *		  	- PCI hotplug
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  *		  Jon Smirl <jonsmirl@yahoo.com>
30*4882a593Smuzhiyun  * 			- PCI ID update
31*4882a593Smuzhiyun  * 			- replace ROM BIOS search
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  *  Based off of Geert's atyfb.c and vfb.c.
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  *  TODO:
36*4882a593Smuzhiyun  *		- monitor sensing (DDC)
37*4882a593Smuzhiyun  *              - virtual display
38*4882a593Smuzhiyun  *		- other platform support (only ppc/x86 supported)
39*4882a593Smuzhiyun  *		- hardware cursor support
40*4882a593Smuzhiyun  *
41*4882a593Smuzhiyun  *    Please cc: your patches to brad@neruo.com.
42*4882a593Smuzhiyun  */
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun /*
45*4882a593Smuzhiyun  * A special note of gratitude to ATI's devrel for providing documentation,
46*4882a593Smuzhiyun  * example code and hardware. Thanks Nitya.	-atong and brad
47*4882a593Smuzhiyun  */
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #include <linux/module.h>
51*4882a593Smuzhiyun #include <linux/moduleparam.h>
52*4882a593Smuzhiyun #include <linux/kernel.h>
53*4882a593Smuzhiyun #include <linux/errno.h>
54*4882a593Smuzhiyun #include <linux/string.h>
55*4882a593Smuzhiyun #include <linux/mm.h>
56*4882a593Smuzhiyun #include <linux/vmalloc.h>
57*4882a593Smuzhiyun #include <linux/delay.h>
58*4882a593Smuzhiyun #include <linux/interrupt.h>
59*4882a593Smuzhiyun #include <linux/uaccess.h>
60*4882a593Smuzhiyun #include <linux/fb.h>
61*4882a593Smuzhiyun #include <linux/init.h>
62*4882a593Smuzhiyun #include <linux/pci.h>
63*4882a593Smuzhiyun #include <linux/ioport.h>
64*4882a593Smuzhiyun #include <linux/console.h>
65*4882a593Smuzhiyun #include <linux/backlight.h>
66*4882a593Smuzhiyun #include <asm/io.h>
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #ifdef CONFIG_PPC_PMAC
69*4882a593Smuzhiyun #include <asm/machdep.h>
70*4882a593Smuzhiyun #include <asm/pmac_feature.h>
71*4882a593Smuzhiyun #include <asm/prom.h>
72*4882a593Smuzhiyun #include "../macmodes.h"
73*4882a593Smuzhiyun #endif
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun #ifdef CONFIG_PMAC_BACKLIGHT
76*4882a593Smuzhiyun #include <asm/backlight.h>
77*4882a593Smuzhiyun #endif
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #ifdef CONFIG_BOOTX_TEXT
80*4882a593Smuzhiyun #include <asm/btext.h>
81*4882a593Smuzhiyun #endif /* CONFIG_BOOTX_TEXT */
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun #include <video/aty128.h>
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /* Debug flag */
86*4882a593Smuzhiyun #undef DEBUG
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun #ifdef DEBUG
89*4882a593Smuzhiyun #define DBG(fmt, args...) \
90*4882a593Smuzhiyun 	printk(KERN_DEBUG "aty128fb: %s " fmt, __func__, ##args);
91*4882a593Smuzhiyun #else
92*4882a593Smuzhiyun #define DBG(fmt, args...)
93*4882a593Smuzhiyun #endif
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun #ifndef CONFIG_PPC_PMAC
96*4882a593Smuzhiyun /* default mode */
97*4882a593Smuzhiyun static const struct fb_var_screeninfo default_var = {
98*4882a593Smuzhiyun 	/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
99*4882a593Smuzhiyun 	640, 480, 640, 480, 0, 0, 8, 0,
100*4882a593Smuzhiyun 	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
101*4882a593Smuzhiyun 	0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
102*4882a593Smuzhiyun 	0, FB_VMODE_NONINTERLACED
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun #else /* CONFIG_PPC_PMAC */
106*4882a593Smuzhiyun /* default to 1024x768 at 75Hz on PPC - this will work
107*4882a593Smuzhiyun  * on the iMac, the usual 640x480 @ 60Hz doesn't. */
108*4882a593Smuzhiyun static const struct fb_var_screeninfo default_var = {
109*4882a593Smuzhiyun 	/* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
110*4882a593Smuzhiyun 	1024, 768, 1024, 768, 0, 0, 8, 0,
111*4882a593Smuzhiyun 	{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
112*4882a593Smuzhiyun 	0, 0, -1, -1, 0, 12699, 160, 32, 28, 1, 96, 3,
113*4882a593Smuzhiyun 	FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
114*4882a593Smuzhiyun 	FB_VMODE_NONINTERLACED
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun #endif /* CONFIG_PPC_PMAC */
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun /* default modedb mode */
119*4882a593Smuzhiyun /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
120*4882a593Smuzhiyun static const struct fb_videomode defaultmode = {
121*4882a593Smuzhiyun 	.refresh =	60,
122*4882a593Smuzhiyun 	.xres =		640,
123*4882a593Smuzhiyun 	.yres =		480,
124*4882a593Smuzhiyun 	.pixclock =	39722,
125*4882a593Smuzhiyun 	.left_margin =	48,
126*4882a593Smuzhiyun 	.right_margin =	16,
127*4882a593Smuzhiyun 	.upper_margin =	33,
128*4882a593Smuzhiyun 	.lower_margin =	10,
129*4882a593Smuzhiyun 	.hsync_len =	96,
130*4882a593Smuzhiyun 	.vsync_len =	2,
131*4882a593Smuzhiyun 	.sync =		0,
132*4882a593Smuzhiyun 	.vmode =	FB_VMODE_NONINTERLACED
133*4882a593Smuzhiyun };
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun /* Chip generations */
136*4882a593Smuzhiyun enum {
137*4882a593Smuzhiyun 	rage_128,
138*4882a593Smuzhiyun 	rage_128_pci,
139*4882a593Smuzhiyun 	rage_128_pro,
140*4882a593Smuzhiyun 	rage_128_pro_pci,
141*4882a593Smuzhiyun 	rage_M3,
142*4882a593Smuzhiyun 	rage_M3_pci,
143*4882a593Smuzhiyun 	rage_M4,
144*4882a593Smuzhiyun 	rage_128_ultra,
145*4882a593Smuzhiyun };
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun /* Must match above enum */
148*4882a593Smuzhiyun static char * const r128_family[] = {
149*4882a593Smuzhiyun 	"AGP",
150*4882a593Smuzhiyun 	"PCI",
151*4882a593Smuzhiyun 	"PRO AGP",
152*4882a593Smuzhiyun 	"PRO PCI",
153*4882a593Smuzhiyun 	"M3 AGP",
154*4882a593Smuzhiyun 	"M3 PCI",
155*4882a593Smuzhiyun 	"M4 AGP",
156*4882a593Smuzhiyun 	"Ultra AGP",
157*4882a593Smuzhiyun };
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun /*
160*4882a593Smuzhiyun  * PCI driver prototypes
161*4882a593Smuzhiyun  */
162*4882a593Smuzhiyun static int aty128_probe(struct pci_dev *pdev,
163*4882a593Smuzhiyun                                const struct pci_device_id *ent);
164*4882a593Smuzhiyun static void aty128_remove(struct pci_dev *pdev);
165*4882a593Smuzhiyun static int aty128_pci_suspend_late(struct device *dev, pm_message_t state);
166*4882a593Smuzhiyun static int __maybe_unused aty128_pci_suspend(struct device *dev);
167*4882a593Smuzhiyun static int __maybe_unused aty128_pci_hibernate(struct device *dev);
168*4882a593Smuzhiyun static int __maybe_unused aty128_pci_freeze(struct device *dev);
169*4882a593Smuzhiyun static int __maybe_unused aty128_pci_resume(struct device *dev);
170*4882a593Smuzhiyun static int aty128_do_resume(struct pci_dev *pdev);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun static const struct dev_pm_ops aty128_pci_pm_ops = {
173*4882a593Smuzhiyun 	.suspend	= aty128_pci_suspend,
174*4882a593Smuzhiyun 	.resume		= aty128_pci_resume,
175*4882a593Smuzhiyun 	.freeze		= aty128_pci_freeze,
176*4882a593Smuzhiyun 	.thaw		= aty128_pci_resume,
177*4882a593Smuzhiyun 	.poweroff	= aty128_pci_hibernate,
178*4882a593Smuzhiyun 	.restore	= aty128_pci_resume,
179*4882a593Smuzhiyun };
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun /* supported Rage128 chipsets */
182*4882a593Smuzhiyun static const struct pci_device_id aty128_pci_tbl[] = {
183*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LE,
184*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3_pci },
185*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_LF,
186*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M3 },
187*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_MF,
188*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
189*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_ML,
190*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_M4 },
191*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PA,
192*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
193*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PB,
194*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
195*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PC,
196*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
197*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PD,
198*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
199*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PE,
200*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
201*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PF,
202*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
203*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PG,
204*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
205*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PH,
206*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
207*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PI,
208*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
209*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PJ,
210*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
211*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PK,
212*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
213*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PL,
214*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
215*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PM,
216*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
217*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PN,
218*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
219*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PO,
220*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
221*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PP,
222*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
223*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PQ,
224*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
225*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PR,
226*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro_pci },
227*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PS,
228*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
229*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PT,
230*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
231*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PU,
232*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
233*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PV,
234*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
235*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PW,
236*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
237*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_PX,
238*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pro },
239*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RE,
240*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
241*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RF,
242*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
243*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RG,
244*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
245*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RK,
246*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
247*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_RL,
248*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
249*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SE,
250*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
251*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SF,
252*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_pci },
253*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SG,
254*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
255*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SH,
256*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
257*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SK,
258*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
259*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SL,
260*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
261*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SM,
262*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
263*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_SN,
264*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128 },
265*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TF,
266*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
267*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TL,
268*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
269*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TR,
270*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
271*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TS,
272*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
273*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TT,
274*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
275*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RAGE128_TU,
276*4882a593Smuzhiyun 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, rage_128_ultra },
277*4882a593Smuzhiyun 	{ 0, }
278*4882a593Smuzhiyun };
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, aty128_pci_tbl);
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun static struct pci_driver aty128fb_driver = {
283*4882a593Smuzhiyun 	.name		= "aty128fb",
284*4882a593Smuzhiyun 	.id_table	= aty128_pci_tbl,
285*4882a593Smuzhiyun 	.probe		= aty128_probe,
286*4882a593Smuzhiyun 	.remove		= aty128_remove,
287*4882a593Smuzhiyun 	.driver.pm	= &aty128_pci_pm_ops,
288*4882a593Smuzhiyun };
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun /* packed BIOS settings */
291*4882a593Smuzhiyun #ifndef CONFIG_PPC
292*4882a593Smuzhiyun typedef struct {
293*4882a593Smuzhiyun 	u8 clock_chip_type;
294*4882a593Smuzhiyun 	u8 struct_size;
295*4882a593Smuzhiyun 	u8 accelerator_entry;
296*4882a593Smuzhiyun 	u8 VGA_entry;
297*4882a593Smuzhiyun 	u16 VGA_table_offset;
298*4882a593Smuzhiyun 	u16 POST_table_offset;
299*4882a593Smuzhiyun 	u16 XCLK;
300*4882a593Smuzhiyun 	u16 MCLK;
301*4882a593Smuzhiyun 	u8 num_PLL_blocks;
302*4882a593Smuzhiyun 	u8 size_PLL_blocks;
303*4882a593Smuzhiyun 	u16 PCLK_ref_freq;
304*4882a593Smuzhiyun 	u16 PCLK_ref_divider;
305*4882a593Smuzhiyun 	u32 PCLK_min_freq;
306*4882a593Smuzhiyun 	u32 PCLK_max_freq;
307*4882a593Smuzhiyun 	u16 MCLK_ref_freq;
308*4882a593Smuzhiyun 	u16 MCLK_ref_divider;
309*4882a593Smuzhiyun 	u32 MCLK_min_freq;
310*4882a593Smuzhiyun 	u32 MCLK_max_freq;
311*4882a593Smuzhiyun 	u16 XCLK_ref_freq;
312*4882a593Smuzhiyun 	u16 XCLK_ref_divider;
313*4882a593Smuzhiyun 	u32 XCLK_min_freq;
314*4882a593Smuzhiyun 	u32 XCLK_max_freq;
315*4882a593Smuzhiyun } __attribute__ ((packed)) PLL_BLOCK;
316*4882a593Smuzhiyun #endif /* !CONFIG_PPC */
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun /* onboard memory information */
319*4882a593Smuzhiyun struct aty128_meminfo {
320*4882a593Smuzhiyun 	u8 ML;
321*4882a593Smuzhiyun 	u8 MB;
322*4882a593Smuzhiyun 	u8 Trcd;
323*4882a593Smuzhiyun 	u8 Trp;
324*4882a593Smuzhiyun 	u8 Twr;
325*4882a593Smuzhiyun 	u8 CL;
326*4882a593Smuzhiyun 	u8 Tr2w;
327*4882a593Smuzhiyun 	u8 LoopLatency;
328*4882a593Smuzhiyun 	u8 DspOn;
329*4882a593Smuzhiyun 	u8 Rloop;
330*4882a593Smuzhiyun 	const char *name;
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun /* various memory configurations */
334*4882a593Smuzhiyun static const struct aty128_meminfo sdr_128 = {
335*4882a593Smuzhiyun 	.ML = 4,
336*4882a593Smuzhiyun 	.MB = 4,
337*4882a593Smuzhiyun 	.Trcd = 3,
338*4882a593Smuzhiyun 	.Trp = 3,
339*4882a593Smuzhiyun 	.Twr = 1,
340*4882a593Smuzhiyun 	.CL = 3,
341*4882a593Smuzhiyun 	.Tr2w = 1,
342*4882a593Smuzhiyun 	.LoopLatency = 16,
343*4882a593Smuzhiyun 	.DspOn = 30,
344*4882a593Smuzhiyun 	.Rloop = 16,
345*4882a593Smuzhiyun 	.name = "128-bit SDR SGRAM (1:1)",
346*4882a593Smuzhiyun };
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun static const struct aty128_meminfo sdr_sgram = {
349*4882a593Smuzhiyun 	.ML = 4,
350*4882a593Smuzhiyun 	.MB = 4,
351*4882a593Smuzhiyun 	.Trcd = 1,
352*4882a593Smuzhiyun 	.Trp = 2,
353*4882a593Smuzhiyun 	.Twr = 1,
354*4882a593Smuzhiyun 	.CL = 2,
355*4882a593Smuzhiyun 	.Tr2w = 1,
356*4882a593Smuzhiyun 	.LoopLatency = 16,
357*4882a593Smuzhiyun 	.DspOn = 24,
358*4882a593Smuzhiyun 	.Rloop = 16,
359*4882a593Smuzhiyun 	.name = "64-bit SDR SGRAM (2:1)",
360*4882a593Smuzhiyun };
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun static const struct aty128_meminfo ddr_sgram = {
363*4882a593Smuzhiyun 	.ML = 4,
364*4882a593Smuzhiyun 	.MB = 4,
365*4882a593Smuzhiyun 	.Trcd = 3,
366*4882a593Smuzhiyun 	.Trp = 3,
367*4882a593Smuzhiyun 	.Twr = 2,
368*4882a593Smuzhiyun 	.CL = 3,
369*4882a593Smuzhiyun 	.Tr2w = 1,
370*4882a593Smuzhiyun 	.LoopLatency = 16,
371*4882a593Smuzhiyun 	.DspOn = 31,
372*4882a593Smuzhiyun 	.Rloop = 16,
373*4882a593Smuzhiyun 	.name = "64-bit DDR SGRAM",
374*4882a593Smuzhiyun };
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun static const struct fb_fix_screeninfo aty128fb_fix = {
377*4882a593Smuzhiyun 	.id		= "ATY Rage128",
378*4882a593Smuzhiyun 	.type		= FB_TYPE_PACKED_PIXELS,
379*4882a593Smuzhiyun 	.visual		= FB_VISUAL_PSEUDOCOLOR,
380*4882a593Smuzhiyun 	.xpanstep	= 8,
381*4882a593Smuzhiyun 	.ypanstep	= 1,
382*4882a593Smuzhiyun 	.mmio_len	= 0x2000,
383*4882a593Smuzhiyun 	.accel		= FB_ACCEL_ATI_RAGE128,
384*4882a593Smuzhiyun };
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun static char *mode_option = NULL;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun #ifdef CONFIG_PPC_PMAC
389*4882a593Smuzhiyun static int default_vmode = VMODE_1024_768_60;
390*4882a593Smuzhiyun static int default_cmode = CMODE_8;
391*4882a593Smuzhiyun #endif
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun static int default_crt_on = 0;
394*4882a593Smuzhiyun static int default_lcd_on = 1;
395*4882a593Smuzhiyun static bool mtrr = true;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY128_BACKLIGHT
398*4882a593Smuzhiyun static int backlight = IS_BUILTIN(CONFIG_PMAC_BACKLIGHT);
399*4882a593Smuzhiyun #endif
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun /* PLL constants */
402*4882a593Smuzhiyun struct aty128_constants {
403*4882a593Smuzhiyun 	u32 ref_clk;
404*4882a593Smuzhiyun 	u32 ppll_min;
405*4882a593Smuzhiyun 	u32 ppll_max;
406*4882a593Smuzhiyun 	u32 ref_divider;
407*4882a593Smuzhiyun 	u32 xclk;
408*4882a593Smuzhiyun 	u32 fifo_width;
409*4882a593Smuzhiyun 	u32 fifo_depth;
410*4882a593Smuzhiyun };
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun struct aty128_crtc {
413*4882a593Smuzhiyun 	u32 gen_cntl;
414*4882a593Smuzhiyun 	u32 h_total, h_sync_strt_wid;
415*4882a593Smuzhiyun 	u32 v_total, v_sync_strt_wid;
416*4882a593Smuzhiyun 	u32 pitch;
417*4882a593Smuzhiyun 	u32 offset, offset_cntl;
418*4882a593Smuzhiyun 	u32 xoffset, yoffset;
419*4882a593Smuzhiyun 	u32 vxres, vyres;
420*4882a593Smuzhiyun 	u32 depth, bpp;
421*4882a593Smuzhiyun };
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun struct aty128_pll {
424*4882a593Smuzhiyun 	u32 post_divider;
425*4882a593Smuzhiyun 	u32 feedback_divider;
426*4882a593Smuzhiyun 	u32 vclk;
427*4882a593Smuzhiyun };
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun struct aty128_ddafifo {
430*4882a593Smuzhiyun 	u32 dda_config;
431*4882a593Smuzhiyun 	u32 dda_on_off;
432*4882a593Smuzhiyun };
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun /* register values for a specific mode */
435*4882a593Smuzhiyun struct aty128fb_par {
436*4882a593Smuzhiyun 	struct aty128_crtc crtc;
437*4882a593Smuzhiyun 	struct aty128_pll pll;
438*4882a593Smuzhiyun 	struct aty128_ddafifo fifo_reg;
439*4882a593Smuzhiyun 	u32 accel_flags;
440*4882a593Smuzhiyun 	struct aty128_constants constants;  /* PLL and others      */
441*4882a593Smuzhiyun 	void __iomem *regbase;              /* remapped mmio       */
442*4882a593Smuzhiyun 	u32 vram_size;                      /* onboard video ram   */
443*4882a593Smuzhiyun 	int chip_gen;
444*4882a593Smuzhiyun 	const struct aty128_meminfo *mem;   /* onboard mem info    */
445*4882a593Smuzhiyun 	int wc_cookie;
446*4882a593Smuzhiyun 	int blitter_may_be_busy;
447*4882a593Smuzhiyun 	int fifo_slots;                 /* free slots in FIFO (64 max) */
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	int crt_on, lcd_on;
450*4882a593Smuzhiyun 	struct pci_dev *pdev;
451*4882a593Smuzhiyun 	struct fb_info *next;
452*4882a593Smuzhiyun 	int	asleep;
453*4882a593Smuzhiyun 	int	lock_blank;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	u8	red[32];		/* see aty128fb_setcolreg */
456*4882a593Smuzhiyun 	u8	green[64];
457*4882a593Smuzhiyun 	u8	blue[32];
458*4882a593Smuzhiyun 	u32	pseudo_palette[16];	/* used for TRUECOLOR */
459*4882a593Smuzhiyun };
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun #define round_div(n, d) ((n+(d/2))/d)
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun static int aty128fb_check_var(struct fb_var_screeninfo *var,
465*4882a593Smuzhiyun 			      struct fb_info *info);
466*4882a593Smuzhiyun static int aty128fb_set_par(struct fb_info *info);
467*4882a593Smuzhiyun static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
468*4882a593Smuzhiyun 			      u_int transp, struct fb_info *info);
469*4882a593Smuzhiyun static int aty128fb_pan_display(struct fb_var_screeninfo *var,
470*4882a593Smuzhiyun 			   struct fb_info *fb);
471*4882a593Smuzhiyun static int aty128fb_blank(int blank, struct fb_info *fb);
472*4882a593Smuzhiyun static int aty128fb_ioctl(struct fb_info *info, u_int cmd, unsigned long arg);
473*4882a593Smuzhiyun static int aty128fb_sync(struct fb_info *info);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun     /*
476*4882a593Smuzhiyun      *  Internal routines
477*4882a593Smuzhiyun      */
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun static int aty128_encode_var(struct fb_var_screeninfo *var,
480*4882a593Smuzhiyun                              const struct aty128fb_par *par);
481*4882a593Smuzhiyun static int aty128_decode_var(struct fb_var_screeninfo *var,
482*4882a593Smuzhiyun                              struct aty128fb_par *par);
483*4882a593Smuzhiyun static void aty128_timings(struct aty128fb_par *par);
484*4882a593Smuzhiyun static void aty128_init_engine(struct aty128fb_par *par);
485*4882a593Smuzhiyun static void aty128_reset_engine(const struct aty128fb_par *par);
486*4882a593Smuzhiyun static void aty128_flush_pixel_cache(const struct aty128fb_par *par);
487*4882a593Smuzhiyun static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par);
488*4882a593Smuzhiyun static void wait_for_fifo(u16 entries, struct aty128fb_par *par);
489*4882a593Smuzhiyun static void wait_for_idle(struct aty128fb_par *par);
490*4882a593Smuzhiyun static u32 depth_to_dst(u32 depth);
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY128_BACKLIGHT
493*4882a593Smuzhiyun static void aty128_bl_set_power(struct fb_info *info, int power);
494*4882a593Smuzhiyun #endif
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun #define BIOS_IN8(v)  	(readb(bios + (v)))
497*4882a593Smuzhiyun #define BIOS_IN16(v) 	(readb(bios + (v)) | \
498*4882a593Smuzhiyun 			  (readb(bios + (v) + 1) << 8))
499*4882a593Smuzhiyun #define BIOS_IN32(v) 	(readb(bios + (v)) | \
500*4882a593Smuzhiyun 			  (readb(bios + (v) + 1) << 8) | \
501*4882a593Smuzhiyun 			  (readb(bios + (v) + 2) << 16) | \
502*4882a593Smuzhiyun 			  (readb(bios + (v) + 3) << 24))
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun static const struct fb_ops aty128fb_ops = {
506*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
507*4882a593Smuzhiyun 	.fb_check_var	= aty128fb_check_var,
508*4882a593Smuzhiyun 	.fb_set_par	= aty128fb_set_par,
509*4882a593Smuzhiyun 	.fb_setcolreg	= aty128fb_setcolreg,
510*4882a593Smuzhiyun 	.fb_pan_display = aty128fb_pan_display,
511*4882a593Smuzhiyun 	.fb_blank	= aty128fb_blank,
512*4882a593Smuzhiyun 	.fb_ioctl	= aty128fb_ioctl,
513*4882a593Smuzhiyun 	.fb_sync	= aty128fb_sync,
514*4882a593Smuzhiyun 	.fb_fillrect	= cfb_fillrect,
515*4882a593Smuzhiyun 	.fb_copyarea	= cfb_copyarea,
516*4882a593Smuzhiyun 	.fb_imageblit	= cfb_imageblit,
517*4882a593Smuzhiyun };
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun     /*
520*4882a593Smuzhiyun      * Functions to read from/write to the mmio registers
521*4882a593Smuzhiyun      *	- endian conversions may possibly be avoided by
522*4882a593Smuzhiyun      *    using the other register aperture. TODO.
523*4882a593Smuzhiyun      */
_aty_ld_le32(volatile unsigned int regindex,const struct aty128fb_par * par)524*4882a593Smuzhiyun static inline u32 _aty_ld_le32(volatile unsigned int regindex,
525*4882a593Smuzhiyun 			       const struct aty128fb_par *par)
526*4882a593Smuzhiyun {
527*4882a593Smuzhiyun 	return readl (par->regbase + regindex);
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun 
_aty_st_le32(volatile unsigned int regindex,u32 val,const struct aty128fb_par * par)530*4882a593Smuzhiyun static inline void _aty_st_le32(volatile unsigned int regindex, u32 val,
531*4882a593Smuzhiyun 				const struct aty128fb_par *par)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun 	writel (val, par->regbase + regindex);
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun 
_aty_ld_8(unsigned int regindex,const struct aty128fb_par * par)536*4882a593Smuzhiyun static inline u8 _aty_ld_8(unsigned int regindex,
537*4882a593Smuzhiyun 			   const struct aty128fb_par *par)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun 	return readb (par->regbase + regindex);
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun 
_aty_st_8(unsigned int regindex,u8 val,const struct aty128fb_par * par)542*4882a593Smuzhiyun static inline void _aty_st_8(unsigned int regindex, u8 val,
543*4882a593Smuzhiyun 			     const struct aty128fb_par *par)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun 	writeb (val, par->regbase + regindex);
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun #define aty_ld_le32(regindex)		_aty_ld_le32(regindex, par)
549*4882a593Smuzhiyun #define aty_st_le32(regindex, val)	_aty_st_le32(regindex, val, par)
550*4882a593Smuzhiyun #define aty_ld_8(regindex)		_aty_ld_8(regindex, par)
551*4882a593Smuzhiyun #define aty_st_8(regindex, val)		_aty_st_8(regindex, val, par)
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun     /*
554*4882a593Smuzhiyun      * Functions to read from/write to the pll registers
555*4882a593Smuzhiyun      */
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun #define aty_ld_pll(pll_index)		_aty_ld_pll(pll_index, par)
558*4882a593Smuzhiyun #define aty_st_pll(pll_index, val)	_aty_st_pll(pll_index, val, par)
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 
_aty_ld_pll(unsigned int pll_index,const struct aty128fb_par * par)561*4882a593Smuzhiyun static u32 _aty_ld_pll(unsigned int pll_index,
562*4882a593Smuzhiyun 		       const struct aty128fb_par *par)
563*4882a593Smuzhiyun {
564*4882a593Smuzhiyun 	aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F);
565*4882a593Smuzhiyun 	return aty_ld_le32(CLOCK_CNTL_DATA);
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 
_aty_st_pll(unsigned int pll_index,u32 val,const struct aty128fb_par * par)569*4882a593Smuzhiyun static void _aty_st_pll(unsigned int pll_index, u32 val,
570*4882a593Smuzhiyun 			const struct aty128fb_par *par)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun 	aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x3F) | PLL_WR_EN);
573*4882a593Smuzhiyun 	aty_st_le32(CLOCK_CNTL_DATA, val);
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun /* return true when the PLL has completed an atomic update */
aty_pll_readupdate(const struct aty128fb_par * par)578*4882a593Smuzhiyun static int aty_pll_readupdate(const struct aty128fb_par *par)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun 	return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R);
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 
aty_pll_wait_readupdate(const struct aty128fb_par * par)584*4882a593Smuzhiyun static void aty_pll_wait_readupdate(const struct aty128fb_par *par)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun 	unsigned long timeout = jiffies + HZ/100; // should be more than enough
587*4882a593Smuzhiyun 	int reset = 1;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	while (time_before(jiffies, timeout))
590*4882a593Smuzhiyun 		if (aty_pll_readupdate(par)) {
591*4882a593Smuzhiyun 			reset = 0;
592*4882a593Smuzhiyun 			break;
593*4882a593Smuzhiyun 		}
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	if (reset)	/* reset engine?? */
596*4882a593Smuzhiyun 		printk(KERN_DEBUG "aty128fb: PLL write timeout!\n");
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun /* tell PLL to update */
aty_pll_writeupdate(const struct aty128fb_par * par)601*4882a593Smuzhiyun static void aty_pll_writeupdate(const struct aty128fb_par *par)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun 	aty_pll_wait_readupdate(par);
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	aty_st_pll(PPLL_REF_DIV,
606*4882a593Smuzhiyun 		   aty_ld_pll(PPLL_REF_DIV) | PPLL_ATOMIC_UPDATE_W);
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun /* write to the scratch register to test r/w functionality */
register_test(const struct aty128fb_par * par)611*4882a593Smuzhiyun static int register_test(const struct aty128fb_par *par)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun 	u32 val;
614*4882a593Smuzhiyun 	int flag = 0;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	val = aty_ld_le32(BIOS_0_SCRATCH);
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	aty_st_le32(BIOS_0_SCRATCH, 0x55555555);
619*4882a593Smuzhiyun 	if (aty_ld_le32(BIOS_0_SCRATCH) == 0x55555555) {
620*4882a593Smuzhiyun 		aty_st_le32(BIOS_0_SCRATCH, 0xAAAAAAAA);
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 		if (aty_ld_le32(BIOS_0_SCRATCH) == 0xAAAAAAAA)
623*4882a593Smuzhiyun 			flag = 1;
624*4882a593Smuzhiyun 	}
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	aty_st_le32(BIOS_0_SCRATCH, val);	// restore value
627*4882a593Smuzhiyun 	return flag;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun /*
632*4882a593Smuzhiyun  * Accelerator engine functions
633*4882a593Smuzhiyun  */
do_wait_for_fifo(u16 entries,struct aty128fb_par * par)634*4882a593Smuzhiyun static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun 	int i;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	for (;;) {
639*4882a593Smuzhiyun 		for (i = 0; i < 2000000; i++) {
640*4882a593Smuzhiyun 			par->fifo_slots = aty_ld_le32(GUI_STAT) & 0x0fff;
641*4882a593Smuzhiyun 			if (par->fifo_slots >= entries)
642*4882a593Smuzhiyun 				return;
643*4882a593Smuzhiyun 		}
644*4882a593Smuzhiyun 		aty128_reset_engine(par);
645*4882a593Smuzhiyun 	}
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 
wait_for_idle(struct aty128fb_par * par)649*4882a593Smuzhiyun static void wait_for_idle(struct aty128fb_par *par)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun 	int i;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 	do_wait_for_fifo(64, par);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	for (;;) {
656*4882a593Smuzhiyun 		for (i = 0; i < 2000000; i++) {
657*4882a593Smuzhiyun 			if (!(aty_ld_le32(GUI_STAT) & (1 << 31))) {
658*4882a593Smuzhiyun 				aty128_flush_pixel_cache(par);
659*4882a593Smuzhiyun 				par->blitter_may_be_busy = 0;
660*4882a593Smuzhiyun 				return;
661*4882a593Smuzhiyun 			}
662*4882a593Smuzhiyun 		}
663*4882a593Smuzhiyun 		aty128_reset_engine(par);
664*4882a593Smuzhiyun 	}
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 
wait_for_fifo(u16 entries,struct aty128fb_par * par)668*4882a593Smuzhiyun static void wait_for_fifo(u16 entries, struct aty128fb_par *par)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun 	if (par->fifo_slots < entries)
671*4882a593Smuzhiyun 		do_wait_for_fifo(64, par);
672*4882a593Smuzhiyun 	par->fifo_slots -= entries;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 
aty128_flush_pixel_cache(const struct aty128fb_par * par)676*4882a593Smuzhiyun static void aty128_flush_pixel_cache(const struct aty128fb_par *par)
677*4882a593Smuzhiyun {
678*4882a593Smuzhiyun 	int i;
679*4882a593Smuzhiyun 	u32 tmp;
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 	tmp = aty_ld_le32(PC_NGUI_CTLSTAT);
682*4882a593Smuzhiyun 	tmp &= ~(0x00ff);
683*4882a593Smuzhiyun 	tmp |= 0x00ff;
684*4882a593Smuzhiyun 	aty_st_le32(PC_NGUI_CTLSTAT, tmp);
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	for (i = 0; i < 2000000; i++)
687*4882a593Smuzhiyun 		if (!(aty_ld_le32(PC_NGUI_CTLSTAT) & PC_BUSY))
688*4882a593Smuzhiyun 			break;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 
aty128_reset_engine(const struct aty128fb_par * par)692*4882a593Smuzhiyun static void aty128_reset_engine(const struct aty128fb_par *par)
693*4882a593Smuzhiyun {
694*4882a593Smuzhiyun 	u32 gen_reset_cntl, clock_cntl_index, mclk_cntl;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	aty128_flush_pixel_cache(par);
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	clock_cntl_index = aty_ld_le32(CLOCK_CNTL_INDEX);
699*4882a593Smuzhiyun 	mclk_cntl = aty_ld_pll(MCLK_CNTL);
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	aty_st_pll(MCLK_CNTL, mclk_cntl | 0x00030000);
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	gen_reset_cntl = aty_ld_le32(GEN_RESET_CNTL);
704*4882a593Smuzhiyun 	aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl | SOFT_RESET_GUI);
705*4882a593Smuzhiyun 	aty_ld_le32(GEN_RESET_CNTL);
706*4882a593Smuzhiyun 	aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl & ~(SOFT_RESET_GUI));
707*4882a593Smuzhiyun 	aty_ld_le32(GEN_RESET_CNTL);
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	aty_st_pll(MCLK_CNTL, mclk_cntl);
710*4882a593Smuzhiyun 	aty_st_le32(CLOCK_CNTL_INDEX, clock_cntl_index);
711*4882a593Smuzhiyun 	aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl);
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	/* use old pio mode */
714*4882a593Smuzhiyun 	aty_st_le32(PM4_BUFFER_CNTL, PM4_BUFFER_CNTL_NONPM4);
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	DBG("engine reset");
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 
aty128_init_engine(struct aty128fb_par * par)720*4882a593Smuzhiyun static void aty128_init_engine(struct aty128fb_par *par)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun 	u32 pitch_value;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	wait_for_idle(par);
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	/* 3D scaler not spoken here */
727*4882a593Smuzhiyun 	wait_for_fifo(1, par);
728*4882a593Smuzhiyun 	aty_st_le32(SCALE_3D_CNTL, 0x00000000);
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	aty128_reset_engine(par);
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	pitch_value = par->crtc.pitch;
733*4882a593Smuzhiyun 	if (par->crtc.bpp == 24) {
734*4882a593Smuzhiyun 		pitch_value = pitch_value * 3;
735*4882a593Smuzhiyun 	}
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	wait_for_fifo(4, par);
738*4882a593Smuzhiyun 	/* setup engine offset registers */
739*4882a593Smuzhiyun 	aty_st_le32(DEFAULT_OFFSET, 0x00000000);
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	/* setup engine pitch registers */
742*4882a593Smuzhiyun 	aty_st_le32(DEFAULT_PITCH, pitch_value);
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	/* set the default scissor register to max dimensions */
745*4882a593Smuzhiyun 	aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF);
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	/* set the drawing controls registers */
748*4882a593Smuzhiyun 	aty_st_le32(DP_GUI_MASTER_CNTL,
749*4882a593Smuzhiyun 		    GMC_SRC_PITCH_OFFSET_DEFAULT		|
750*4882a593Smuzhiyun 		    GMC_DST_PITCH_OFFSET_DEFAULT		|
751*4882a593Smuzhiyun 		    GMC_SRC_CLIP_DEFAULT			|
752*4882a593Smuzhiyun 		    GMC_DST_CLIP_DEFAULT			|
753*4882a593Smuzhiyun 		    GMC_BRUSH_SOLIDCOLOR			|
754*4882a593Smuzhiyun 		    (depth_to_dst(par->crtc.depth) << 8)	|
755*4882a593Smuzhiyun 		    GMC_SRC_DSTCOLOR			|
756*4882a593Smuzhiyun 		    GMC_BYTE_ORDER_MSB_TO_LSB		|
757*4882a593Smuzhiyun 		    GMC_DP_CONVERSION_TEMP_6500		|
758*4882a593Smuzhiyun 		    ROP3_PATCOPY				|
759*4882a593Smuzhiyun 		    GMC_DP_SRC_RECT				|
760*4882a593Smuzhiyun 		    GMC_3D_FCN_EN_CLR			|
761*4882a593Smuzhiyun 		    GMC_DST_CLR_CMP_FCN_CLEAR		|
762*4882a593Smuzhiyun 		    GMC_AUX_CLIP_CLEAR			|
763*4882a593Smuzhiyun 		    GMC_WRITE_MASK_SET);
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 	wait_for_fifo(8, par);
766*4882a593Smuzhiyun 	/* clear the line drawing registers */
767*4882a593Smuzhiyun 	aty_st_le32(DST_BRES_ERR, 0);
768*4882a593Smuzhiyun 	aty_st_le32(DST_BRES_INC, 0);
769*4882a593Smuzhiyun 	aty_st_le32(DST_BRES_DEC, 0);
770*4882a593Smuzhiyun 
771*4882a593Smuzhiyun 	/* set brush color registers */
772*4882a593Smuzhiyun 	aty_st_le32(DP_BRUSH_FRGD_CLR, 0xFFFFFFFF); /* white */
773*4882a593Smuzhiyun 	aty_st_le32(DP_BRUSH_BKGD_CLR, 0x00000000); /* black */
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	/* set source color registers */
776*4882a593Smuzhiyun 	aty_st_le32(DP_SRC_FRGD_CLR, 0xFFFFFFFF);   /* white */
777*4882a593Smuzhiyun 	aty_st_le32(DP_SRC_BKGD_CLR, 0x00000000);   /* black */
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	/* default write mask */
780*4882a593Smuzhiyun 	aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF);
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	/* Wait for all the writes to be completed before returning */
783*4882a593Smuzhiyun 	wait_for_idle(par);
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun /* convert depth values to their register representation */
depth_to_dst(u32 depth)788*4882a593Smuzhiyun static u32 depth_to_dst(u32 depth)
789*4882a593Smuzhiyun {
790*4882a593Smuzhiyun 	if (depth <= 8)
791*4882a593Smuzhiyun 		return DST_8BPP;
792*4882a593Smuzhiyun 	else if (depth <= 15)
793*4882a593Smuzhiyun 		return DST_15BPP;
794*4882a593Smuzhiyun 	else if (depth == 16)
795*4882a593Smuzhiyun 		return DST_16BPP;
796*4882a593Smuzhiyun 	else if (depth <= 24)
797*4882a593Smuzhiyun 		return DST_24BPP;
798*4882a593Smuzhiyun 	else if (depth <= 32)
799*4882a593Smuzhiyun 		return DST_32BPP;
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun 	return -EINVAL;
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun /*
805*4882a593Smuzhiyun  * PLL informations retreival
806*4882a593Smuzhiyun  */
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun #ifndef __sparc__
aty128_map_ROM(const struct aty128fb_par * par,struct pci_dev * dev)810*4882a593Smuzhiyun static void __iomem *aty128_map_ROM(const struct aty128fb_par *par,
811*4882a593Smuzhiyun 				    struct pci_dev *dev)
812*4882a593Smuzhiyun {
813*4882a593Smuzhiyun 	u16 dptr;
814*4882a593Smuzhiyun 	u8 rom_type;
815*4882a593Smuzhiyun 	void __iomem *bios;
816*4882a593Smuzhiyun 	size_t rom_size;
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun     	/* Fix from ATI for problem with Rage128 hardware not leaving ROM enabled */
819*4882a593Smuzhiyun     	unsigned int temp;
820*4882a593Smuzhiyun 	temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);
821*4882a593Smuzhiyun 	temp &= 0x00ffffffu;
822*4882a593Smuzhiyun 	temp |= 0x04 << 24;
823*4882a593Smuzhiyun 	aty_st_le32(RAGE128_MPP_TB_CONFIG, temp);
824*4882a593Smuzhiyun 	temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	bios = pci_map_rom(dev, &rom_size);
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	if (!bios) {
829*4882a593Smuzhiyun 		printk(KERN_ERR "aty128fb: ROM failed to map\n");
830*4882a593Smuzhiyun 		return NULL;
831*4882a593Smuzhiyun 	}
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	/* Very simple test to make sure it appeared */
834*4882a593Smuzhiyun 	if (BIOS_IN16(0) != 0xaa55) {
835*4882a593Smuzhiyun 		printk(KERN_DEBUG "aty128fb: Invalid ROM signature %x should "
836*4882a593Smuzhiyun 			" be 0xaa55\n", BIOS_IN16(0));
837*4882a593Smuzhiyun 		goto failed;
838*4882a593Smuzhiyun 	}
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 	/* Look for the PCI data to check the ROM type */
841*4882a593Smuzhiyun 	dptr = BIOS_IN16(0x18);
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	/* Check the PCI data signature. If it's wrong, we still assume a normal
844*4882a593Smuzhiyun 	 * x86 ROM for now, until I've verified this works everywhere.
845*4882a593Smuzhiyun 	 * The goal here is more to phase out Open Firmware images.
846*4882a593Smuzhiyun 	 *
847*4882a593Smuzhiyun 	 * Currently, we only look at the first PCI data, we could iteratre and
848*4882a593Smuzhiyun 	 * deal with them all, and we should use fb_bios_start relative to start
849*4882a593Smuzhiyun 	 * of image and not relative start of ROM, but so far, I never found a
850*4882a593Smuzhiyun 	 * dual-image ATI card.
851*4882a593Smuzhiyun 	 *
852*4882a593Smuzhiyun 	 * typedef struct {
853*4882a593Smuzhiyun 	 * 	u32	signature;	+ 0x00
854*4882a593Smuzhiyun 	 * 	u16	vendor;		+ 0x04
855*4882a593Smuzhiyun 	 * 	u16	device;		+ 0x06
856*4882a593Smuzhiyun 	 * 	u16	reserved_1;	+ 0x08
857*4882a593Smuzhiyun 	 * 	u16	dlen;		+ 0x0a
858*4882a593Smuzhiyun 	 * 	u8	drevision;	+ 0x0c
859*4882a593Smuzhiyun 	 * 	u8	class_hi;	+ 0x0d
860*4882a593Smuzhiyun 	 * 	u16	class_lo;	+ 0x0e
861*4882a593Smuzhiyun 	 * 	u16	ilen;		+ 0x10
862*4882a593Smuzhiyun 	 * 	u16	irevision;	+ 0x12
863*4882a593Smuzhiyun 	 * 	u8	type;		+ 0x14
864*4882a593Smuzhiyun 	 * 	u8	indicator;	+ 0x15
865*4882a593Smuzhiyun 	 * 	u16	reserved_2;	+ 0x16
866*4882a593Smuzhiyun 	 * } pci_data_t;
867*4882a593Smuzhiyun 	 */
868*4882a593Smuzhiyun 	if (BIOS_IN32(dptr) !=  (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {
869*4882a593Smuzhiyun 		printk(KERN_WARNING "aty128fb: PCI DATA signature in ROM incorrect: %08x\n",
870*4882a593Smuzhiyun 		       BIOS_IN32(dptr));
871*4882a593Smuzhiyun 		goto anyway;
872*4882a593Smuzhiyun 	}
873*4882a593Smuzhiyun 	rom_type = BIOS_IN8(dptr + 0x14);
874*4882a593Smuzhiyun 	switch(rom_type) {
875*4882a593Smuzhiyun 	case 0:
876*4882a593Smuzhiyun 		printk(KERN_INFO "aty128fb: Found Intel x86 BIOS ROM Image\n");
877*4882a593Smuzhiyun 		break;
878*4882a593Smuzhiyun 	case 1:
879*4882a593Smuzhiyun 		printk(KERN_INFO "aty128fb: Found Open Firmware ROM Image\n");
880*4882a593Smuzhiyun 		goto failed;
881*4882a593Smuzhiyun 	case 2:
882*4882a593Smuzhiyun 		printk(KERN_INFO "aty128fb: Found HP PA-RISC ROM Image\n");
883*4882a593Smuzhiyun 		goto failed;
884*4882a593Smuzhiyun 	default:
885*4882a593Smuzhiyun 		printk(KERN_INFO "aty128fb: Found unknown type %d ROM Image\n",
886*4882a593Smuzhiyun 		       rom_type);
887*4882a593Smuzhiyun 		goto failed;
888*4882a593Smuzhiyun 	}
889*4882a593Smuzhiyun  anyway:
890*4882a593Smuzhiyun 	return bios;
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun  failed:
893*4882a593Smuzhiyun 	pci_unmap_rom(dev, bios);
894*4882a593Smuzhiyun 	return NULL;
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun 
aty128_get_pllinfo(struct aty128fb_par * par,unsigned char __iomem * bios)897*4882a593Smuzhiyun static void aty128_get_pllinfo(struct aty128fb_par *par,
898*4882a593Smuzhiyun 			       unsigned char __iomem *bios)
899*4882a593Smuzhiyun {
900*4882a593Smuzhiyun 	unsigned int bios_hdr;
901*4882a593Smuzhiyun 	unsigned int bios_pll;
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 	bios_hdr = BIOS_IN16(0x48);
904*4882a593Smuzhiyun 	bios_pll = BIOS_IN16(bios_hdr + 0x30);
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 	par->constants.ppll_max = BIOS_IN32(bios_pll + 0x16);
907*4882a593Smuzhiyun 	par->constants.ppll_min = BIOS_IN32(bios_pll + 0x12);
908*4882a593Smuzhiyun 	par->constants.xclk = BIOS_IN16(bios_pll + 0x08);
909*4882a593Smuzhiyun 	par->constants.ref_divider = BIOS_IN16(bios_pll + 0x10);
910*4882a593Smuzhiyun 	par->constants.ref_clk = BIOS_IN16(bios_pll + 0x0e);
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d ref clock %d\n",
913*4882a593Smuzhiyun 			par->constants.ppll_max, par->constants.ppll_min,
914*4882a593Smuzhiyun 			par->constants.xclk, par->constants.ref_divider,
915*4882a593Smuzhiyun 			par->constants.ref_clk);
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun #ifdef CONFIG_X86
aty128_find_mem_vbios(struct aty128fb_par * par)920*4882a593Smuzhiyun static void __iomem *aty128_find_mem_vbios(struct aty128fb_par *par)
921*4882a593Smuzhiyun {
922*4882a593Smuzhiyun 	/* I simplified this code as we used to miss the signatures in
923*4882a593Smuzhiyun 	 * a lot of case. It's now closer to XFree, we just don't check
924*4882a593Smuzhiyun 	 * for signatures at all... Something better will have to be done
925*4882a593Smuzhiyun 	 * if we end up having conflicts
926*4882a593Smuzhiyun 	 */
927*4882a593Smuzhiyun         u32  segstart;
928*4882a593Smuzhiyun         unsigned char __iomem *rom_base = NULL;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun         for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {
931*4882a593Smuzhiyun                 rom_base = ioremap(segstart, 0x10000);
932*4882a593Smuzhiyun 		if (rom_base == NULL)
933*4882a593Smuzhiyun 			return NULL;
934*4882a593Smuzhiyun 		if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa)
935*4882a593Smuzhiyun 	                break;
936*4882a593Smuzhiyun                 iounmap(rom_base);
937*4882a593Smuzhiyun 		rom_base = NULL;
938*4882a593Smuzhiyun         }
939*4882a593Smuzhiyun 	return rom_base;
940*4882a593Smuzhiyun }
941*4882a593Smuzhiyun #endif
942*4882a593Smuzhiyun #endif /* ndef(__sparc__) */
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun /* fill in known card constants if pll_block is not available */
aty128_timings(struct aty128fb_par * par)945*4882a593Smuzhiyun static void aty128_timings(struct aty128fb_par *par)
946*4882a593Smuzhiyun {
947*4882a593Smuzhiyun #ifdef CONFIG_PPC
948*4882a593Smuzhiyun 	/* instead of a table lookup, assume OF has properly
949*4882a593Smuzhiyun 	 * setup the PLL registers and use their values
950*4882a593Smuzhiyun 	 * to set the XCLK values and reference divider values */
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 	u32 x_mpll_ref_fb_div;
953*4882a593Smuzhiyun 	u32 xclk_cntl;
954*4882a593Smuzhiyun 	u32 Nx, M;
955*4882a593Smuzhiyun 	unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 };
956*4882a593Smuzhiyun #endif
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	if (!par->constants.ref_clk)
959*4882a593Smuzhiyun 		par->constants.ref_clk = 2950;
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun #ifdef CONFIG_PPC
962*4882a593Smuzhiyun 	x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);
963*4882a593Smuzhiyun 	xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7;
964*4882a593Smuzhiyun 	Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;
965*4882a593Smuzhiyun 	M  = x_mpll_ref_fb_div & 0x0000ff;
966*4882a593Smuzhiyun 
967*4882a593Smuzhiyun 	par->constants.xclk = round_div((2 * Nx * par->constants.ref_clk),
968*4882a593Smuzhiyun 					(M * PostDivSet[xclk_cntl]));
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun 	par->constants.ref_divider =
971*4882a593Smuzhiyun 		aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;
972*4882a593Smuzhiyun #endif
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	if (!par->constants.ref_divider) {
975*4882a593Smuzhiyun 		par->constants.ref_divider = 0x3b;
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 		aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);
978*4882a593Smuzhiyun 		aty_pll_writeupdate(par);
979*4882a593Smuzhiyun 	}
980*4882a593Smuzhiyun 	aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider);
981*4882a593Smuzhiyun 	aty_pll_writeupdate(par);
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	/* from documentation */
984*4882a593Smuzhiyun 	if (!par->constants.ppll_min)
985*4882a593Smuzhiyun 		par->constants.ppll_min = 12500;
986*4882a593Smuzhiyun 	if (!par->constants.ppll_max)
987*4882a593Smuzhiyun 		par->constants.ppll_max = 25000;    /* 23000 on some cards? */
988*4882a593Smuzhiyun 	if (!par->constants.xclk)
989*4882a593Smuzhiyun 		par->constants.xclk = 0x1d4d;	     /* same as mclk */
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun 	par->constants.fifo_width = 128;
992*4882a593Smuzhiyun 	par->constants.fifo_depth = 32;
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 	switch (aty_ld_le32(MEM_CNTL) & 0x3) {
995*4882a593Smuzhiyun 	case 0:
996*4882a593Smuzhiyun 		par->mem = &sdr_128;
997*4882a593Smuzhiyun 		break;
998*4882a593Smuzhiyun 	case 1:
999*4882a593Smuzhiyun 		par->mem = &sdr_sgram;
1000*4882a593Smuzhiyun 		break;
1001*4882a593Smuzhiyun 	case 2:
1002*4882a593Smuzhiyun 		par->mem = &ddr_sgram;
1003*4882a593Smuzhiyun 		break;
1004*4882a593Smuzhiyun 	default:
1005*4882a593Smuzhiyun 		par->mem = &sdr_sgram;
1006*4882a593Smuzhiyun 	}
1007*4882a593Smuzhiyun }
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun /*
1012*4882a593Smuzhiyun  * CRTC programming
1013*4882a593Smuzhiyun  */
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun /* Program the CRTC registers */
aty128_set_crtc(const struct aty128_crtc * crtc,const struct aty128fb_par * par)1016*4882a593Smuzhiyun static void aty128_set_crtc(const struct aty128_crtc *crtc,
1017*4882a593Smuzhiyun 			    const struct aty128fb_par *par)
1018*4882a593Smuzhiyun {
1019*4882a593Smuzhiyun 	aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl);
1020*4882a593Smuzhiyun 	aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_total);
1021*4882a593Smuzhiyun 	aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid);
1022*4882a593Smuzhiyun 	aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_total);
1023*4882a593Smuzhiyun 	aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid);
1024*4882a593Smuzhiyun 	aty_st_le32(CRTC_PITCH, crtc->pitch);
1025*4882a593Smuzhiyun 	aty_st_le32(CRTC_OFFSET, crtc->offset);
1026*4882a593Smuzhiyun 	aty_st_le32(CRTC_OFFSET_CNTL, crtc->offset_cntl);
1027*4882a593Smuzhiyun 	/* Disable ATOMIC updating.  Is this the right place? */
1028*4882a593Smuzhiyun 	aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~(0x00030000));
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 
aty128_var_to_crtc(const struct fb_var_screeninfo * var,struct aty128_crtc * crtc,const struct aty128fb_par * par)1032*4882a593Smuzhiyun static int aty128_var_to_crtc(const struct fb_var_screeninfo *var,
1033*4882a593Smuzhiyun 			      struct aty128_crtc *crtc,
1034*4882a593Smuzhiyun 			      const struct aty128fb_par *par)
1035*4882a593Smuzhiyun {
1036*4882a593Smuzhiyun 	u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp, dst;
1037*4882a593Smuzhiyun 	u32 left, right, upper, lower, hslen, vslen, sync, vmode;
1038*4882a593Smuzhiyun 	u32 h_total, h_disp, h_sync_strt, h_sync_wid, h_sync_pol;
1039*4882a593Smuzhiyun 	u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
1040*4882a593Smuzhiyun 	u32 depth, bytpp;
1041*4882a593Smuzhiyun 	u8 mode_bytpp[7] = { 0, 0, 1, 2, 2, 3, 4 };
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 	/* input */
1044*4882a593Smuzhiyun 	xres = var->xres;
1045*4882a593Smuzhiyun 	yres = var->yres;
1046*4882a593Smuzhiyun 	vxres   = var->xres_virtual;
1047*4882a593Smuzhiyun 	vyres   = var->yres_virtual;
1048*4882a593Smuzhiyun 	xoffset = var->xoffset;
1049*4882a593Smuzhiyun 	yoffset = var->yoffset;
1050*4882a593Smuzhiyun 	bpp   = var->bits_per_pixel;
1051*4882a593Smuzhiyun 	left  = var->left_margin;
1052*4882a593Smuzhiyun 	right = var->right_margin;
1053*4882a593Smuzhiyun 	upper = var->upper_margin;
1054*4882a593Smuzhiyun 	lower = var->lower_margin;
1055*4882a593Smuzhiyun 	hslen = var->hsync_len;
1056*4882a593Smuzhiyun 	vslen = var->vsync_len;
1057*4882a593Smuzhiyun 	sync  = var->sync;
1058*4882a593Smuzhiyun 	vmode = var->vmode;
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	if (bpp != 16)
1061*4882a593Smuzhiyun 		depth = bpp;
1062*4882a593Smuzhiyun 	else
1063*4882a593Smuzhiyun 		depth = (var->green.length == 6) ? 16 : 15;
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun 	/* check for mode eligibility
1066*4882a593Smuzhiyun 	 * accept only non interlaced modes */
1067*4882a593Smuzhiyun 	if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
1068*4882a593Smuzhiyun 		return -EINVAL;
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	/* convert (and round up) and validate */
1071*4882a593Smuzhiyun 	xres = (xres + 7) & ~7;
1072*4882a593Smuzhiyun 	xoffset = (xoffset + 7) & ~7;
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun 	if (vxres < xres + xoffset)
1075*4882a593Smuzhiyun 		vxres = xres + xoffset;
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 	if (vyres < yres + yoffset)
1078*4882a593Smuzhiyun 		vyres = yres + yoffset;
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun 	/* convert depth into ATI register depth */
1081*4882a593Smuzhiyun 	dst = depth_to_dst(depth);
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	if (dst == -EINVAL) {
1084*4882a593Smuzhiyun 		printk(KERN_ERR "aty128fb: Invalid depth or RGBA\n");
1085*4882a593Smuzhiyun 		return -EINVAL;
1086*4882a593Smuzhiyun 	}
1087*4882a593Smuzhiyun 
1088*4882a593Smuzhiyun 	/* convert register depth to bytes per pixel */
1089*4882a593Smuzhiyun 	bytpp = mode_bytpp[dst];
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 	/* make sure there is enough video ram for the mode */
1092*4882a593Smuzhiyun 	if ((u32)(vxres * vyres * bytpp) > par->vram_size) {
1093*4882a593Smuzhiyun 		printk(KERN_ERR "aty128fb: Not enough memory for mode\n");
1094*4882a593Smuzhiyun 		return -EINVAL;
1095*4882a593Smuzhiyun 	}
1096*4882a593Smuzhiyun 
1097*4882a593Smuzhiyun 	h_disp = (xres >> 3) - 1;
1098*4882a593Smuzhiyun 	h_total = (((xres + right + hslen + left) >> 3) - 1) & 0xFFFFL;
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	v_disp = yres - 1;
1101*4882a593Smuzhiyun 	v_total = (yres + upper + vslen + lower - 1) & 0xFFFFL;
1102*4882a593Smuzhiyun 
1103*4882a593Smuzhiyun 	/* check to make sure h_total and v_total are in range */
1104*4882a593Smuzhiyun 	if (((h_total >> 3) - 1) > 0x1ff || (v_total - 1) > 0x7FF) {
1105*4882a593Smuzhiyun 		printk(KERN_ERR "aty128fb: invalid width ranges\n");
1106*4882a593Smuzhiyun 		return -EINVAL;
1107*4882a593Smuzhiyun 	}
1108*4882a593Smuzhiyun 
1109*4882a593Smuzhiyun 	h_sync_wid = (hslen + 7) >> 3;
1110*4882a593Smuzhiyun 	if (h_sync_wid == 0)
1111*4882a593Smuzhiyun 		h_sync_wid = 1;
1112*4882a593Smuzhiyun 	else if (h_sync_wid > 0x3f)        /* 0x3f = max hwidth */
1113*4882a593Smuzhiyun 		h_sync_wid = 0x3f;
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 	h_sync_strt = (h_disp << 3) + right;
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun 	v_sync_wid = vslen;
1118*4882a593Smuzhiyun 	if (v_sync_wid == 0)
1119*4882a593Smuzhiyun 		v_sync_wid = 1;
1120*4882a593Smuzhiyun 	else if (v_sync_wid > 0x1f)        /* 0x1f = max vwidth */
1121*4882a593Smuzhiyun 		v_sync_wid = 0x1f;
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 	v_sync_strt = v_disp + lower;
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun 	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
1126*4882a593Smuzhiyun 	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun 	c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0;
1129*4882a593Smuzhiyun 
1130*4882a593Smuzhiyun 	crtc->gen_cntl = 0x3000000L | c_sync | (dst << 8);
1131*4882a593Smuzhiyun 
1132*4882a593Smuzhiyun 	crtc->h_total = h_total | (h_disp << 16);
1133*4882a593Smuzhiyun 	crtc->v_total = v_total | (v_disp << 16);
1134*4882a593Smuzhiyun 
1135*4882a593Smuzhiyun 	crtc->h_sync_strt_wid = h_sync_strt | (h_sync_wid << 16) |
1136*4882a593Smuzhiyun 	        (h_sync_pol << 23);
1137*4882a593Smuzhiyun 	crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) |
1138*4882a593Smuzhiyun                 (v_sync_pol << 23);
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	crtc->pitch = vxres >> 3;
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	crtc->offset = 0;
1143*4882a593Smuzhiyun 
1144*4882a593Smuzhiyun 	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
1145*4882a593Smuzhiyun 		crtc->offset_cntl = 0x00010000;
1146*4882a593Smuzhiyun 	else
1147*4882a593Smuzhiyun 		crtc->offset_cntl = 0;
1148*4882a593Smuzhiyun 
1149*4882a593Smuzhiyun 	crtc->vxres = vxres;
1150*4882a593Smuzhiyun 	crtc->vyres = vyres;
1151*4882a593Smuzhiyun 	crtc->xoffset = xoffset;
1152*4882a593Smuzhiyun 	crtc->yoffset = yoffset;
1153*4882a593Smuzhiyun 	crtc->depth = depth;
1154*4882a593Smuzhiyun 	crtc->bpp = bpp;
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	return 0;
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun 
1159*4882a593Smuzhiyun 
aty128_pix_width_to_var(int pix_width,struct fb_var_screeninfo * var)1160*4882a593Smuzhiyun static int aty128_pix_width_to_var(int pix_width, struct fb_var_screeninfo *var)
1161*4882a593Smuzhiyun {
1162*4882a593Smuzhiyun 
1163*4882a593Smuzhiyun 	/* fill in pixel info */
1164*4882a593Smuzhiyun 	var->red.msb_right = 0;
1165*4882a593Smuzhiyun 	var->green.msb_right = 0;
1166*4882a593Smuzhiyun 	var->blue.offset = 0;
1167*4882a593Smuzhiyun 	var->blue.msb_right = 0;
1168*4882a593Smuzhiyun 	var->transp.offset = 0;
1169*4882a593Smuzhiyun 	var->transp.length = 0;
1170*4882a593Smuzhiyun 	var->transp.msb_right = 0;
1171*4882a593Smuzhiyun 	switch (pix_width) {
1172*4882a593Smuzhiyun 	case CRTC_PIX_WIDTH_8BPP:
1173*4882a593Smuzhiyun 		var->bits_per_pixel = 8;
1174*4882a593Smuzhiyun 		var->red.offset = 0;
1175*4882a593Smuzhiyun 		var->red.length = 8;
1176*4882a593Smuzhiyun 		var->green.offset = 0;
1177*4882a593Smuzhiyun 		var->green.length = 8;
1178*4882a593Smuzhiyun 		var->blue.length = 8;
1179*4882a593Smuzhiyun 		break;
1180*4882a593Smuzhiyun 	case CRTC_PIX_WIDTH_15BPP:
1181*4882a593Smuzhiyun 		var->bits_per_pixel = 16;
1182*4882a593Smuzhiyun 		var->red.offset = 10;
1183*4882a593Smuzhiyun 		var->red.length = 5;
1184*4882a593Smuzhiyun 		var->green.offset = 5;
1185*4882a593Smuzhiyun 		var->green.length = 5;
1186*4882a593Smuzhiyun 		var->blue.length = 5;
1187*4882a593Smuzhiyun 		break;
1188*4882a593Smuzhiyun 	case CRTC_PIX_WIDTH_16BPP:
1189*4882a593Smuzhiyun 		var->bits_per_pixel = 16;
1190*4882a593Smuzhiyun 		var->red.offset = 11;
1191*4882a593Smuzhiyun 		var->red.length = 5;
1192*4882a593Smuzhiyun 		var->green.offset = 5;
1193*4882a593Smuzhiyun 		var->green.length = 6;
1194*4882a593Smuzhiyun 		var->blue.length = 5;
1195*4882a593Smuzhiyun 		break;
1196*4882a593Smuzhiyun 	case CRTC_PIX_WIDTH_24BPP:
1197*4882a593Smuzhiyun 		var->bits_per_pixel = 24;
1198*4882a593Smuzhiyun 		var->red.offset = 16;
1199*4882a593Smuzhiyun 		var->red.length = 8;
1200*4882a593Smuzhiyun 		var->green.offset = 8;
1201*4882a593Smuzhiyun 		var->green.length = 8;
1202*4882a593Smuzhiyun 		var->blue.length = 8;
1203*4882a593Smuzhiyun 		break;
1204*4882a593Smuzhiyun 	case CRTC_PIX_WIDTH_32BPP:
1205*4882a593Smuzhiyun 		var->bits_per_pixel = 32;
1206*4882a593Smuzhiyun 		var->red.offset = 16;
1207*4882a593Smuzhiyun 		var->red.length = 8;
1208*4882a593Smuzhiyun 		var->green.offset = 8;
1209*4882a593Smuzhiyun 		var->green.length = 8;
1210*4882a593Smuzhiyun 		var->blue.length = 8;
1211*4882a593Smuzhiyun 		var->transp.offset = 24;
1212*4882a593Smuzhiyun 		var->transp.length = 8;
1213*4882a593Smuzhiyun 		break;
1214*4882a593Smuzhiyun 	default:
1215*4882a593Smuzhiyun 		printk(KERN_ERR "aty128fb: Invalid pixel width\n");
1216*4882a593Smuzhiyun 		return -EINVAL;
1217*4882a593Smuzhiyun 	}
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 	return 0;
1220*4882a593Smuzhiyun }
1221*4882a593Smuzhiyun 
1222*4882a593Smuzhiyun 
aty128_crtc_to_var(const struct aty128_crtc * crtc,struct fb_var_screeninfo * var)1223*4882a593Smuzhiyun static int aty128_crtc_to_var(const struct aty128_crtc *crtc,
1224*4882a593Smuzhiyun 			      struct fb_var_screeninfo *var)
1225*4882a593Smuzhiyun {
1226*4882a593Smuzhiyun 	u32 xres, yres, left, right, upper, lower, hslen, vslen, sync;
1227*4882a593Smuzhiyun 	u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
1228*4882a593Smuzhiyun 	u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
1229*4882a593Smuzhiyun 	u32 pix_width;
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun 	/* fun with masking */
1232*4882a593Smuzhiyun 	h_total     = crtc->h_total & 0x1ff;
1233*4882a593Smuzhiyun 	h_disp      = (crtc->h_total >> 16) & 0xff;
1234*4882a593Smuzhiyun 	h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff;
1235*4882a593Smuzhiyun 	h_sync_dly  = crtc->h_sync_strt_wid & 0x7;
1236*4882a593Smuzhiyun 	h_sync_wid  = (crtc->h_sync_strt_wid >> 16) & 0x3f;
1237*4882a593Smuzhiyun 	h_sync_pol  = (crtc->h_sync_strt_wid >> 23) & 0x1;
1238*4882a593Smuzhiyun 	v_total     = crtc->v_total & 0x7ff;
1239*4882a593Smuzhiyun 	v_disp      = (crtc->v_total >> 16) & 0x7ff;
1240*4882a593Smuzhiyun 	v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
1241*4882a593Smuzhiyun 	v_sync_wid  = (crtc->v_sync_strt_wid >> 16) & 0x1f;
1242*4882a593Smuzhiyun 	v_sync_pol  = (crtc->v_sync_strt_wid >> 23) & 0x1;
1243*4882a593Smuzhiyun 	c_sync      = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;
1244*4882a593Smuzhiyun 	pix_width   = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 	/* do conversions */
1247*4882a593Smuzhiyun 	xres  = (h_disp + 1) << 3;
1248*4882a593Smuzhiyun 	yres  = v_disp + 1;
1249*4882a593Smuzhiyun 	left  = ((h_total - h_sync_strt - h_sync_wid) << 3) - h_sync_dly;
1250*4882a593Smuzhiyun 	right = ((h_sync_strt - h_disp) << 3) + h_sync_dly;
1251*4882a593Smuzhiyun 	hslen = h_sync_wid << 3;
1252*4882a593Smuzhiyun 	upper = v_total - v_sync_strt - v_sync_wid;
1253*4882a593Smuzhiyun 	lower = v_sync_strt - v_disp;
1254*4882a593Smuzhiyun 	vslen = v_sync_wid;
1255*4882a593Smuzhiyun 	sync  = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
1256*4882a593Smuzhiyun 		(v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
1257*4882a593Smuzhiyun 		(c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 	aty128_pix_width_to_var(pix_width, var);
1260*4882a593Smuzhiyun 
1261*4882a593Smuzhiyun 	var->xres = xres;
1262*4882a593Smuzhiyun 	var->yres = yres;
1263*4882a593Smuzhiyun 	var->xres_virtual = crtc->vxres;
1264*4882a593Smuzhiyun 	var->yres_virtual = crtc->vyres;
1265*4882a593Smuzhiyun 	var->xoffset = crtc->xoffset;
1266*4882a593Smuzhiyun 	var->yoffset = crtc->yoffset;
1267*4882a593Smuzhiyun 	var->left_margin  = left;
1268*4882a593Smuzhiyun 	var->right_margin = right;
1269*4882a593Smuzhiyun 	var->upper_margin = upper;
1270*4882a593Smuzhiyun 	var->lower_margin = lower;
1271*4882a593Smuzhiyun 	var->hsync_len = hslen;
1272*4882a593Smuzhiyun 	var->vsync_len = vslen;
1273*4882a593Smuzhiyun 	var->sync  = sync;
1274*4882a593Smuzhiyun 	var->vmode = FB_VMODE_NONINTERLACED;
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	return 0;
1277*4882a593Smuzhiyun }
1278*4882a593Smuzhiyun 
aty128_set_crt_enable(struct aty128fb_par * par,int on)1279*4882a593Smuzhiyun static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
1280*4882a593Smuzhiyun {
1281*4882a593Smuzhiyun 	if (on) {
1282*4882a593Smuzhiyun 		aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) |
1283*4882a593Smuzhiyun 			    CRT_CRTC_ON);
1284*4882a593Smuzhiyun 		aty_st_le32(DAC_CNTL, (aty_ld_le32(DAC_CNTL) |
1285*4882a593Smuzhiyun 			    DAC_PALETTE2_SNOOP_EN));
1286*4882a593Smuzhiyun 	} else
1287*4882a593Smuzhiyun 		aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) &
1288*4882a593Smuzhiyun 			    ~CRT_CRTC_ON);
1289*4882a593Smuzhiyun }
1290*4882a593Smuzhiyun 
aty128_set_lcd_enable(struct aty128fb_par * par,int on)1291*4882a593Smuzhiyun static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
1292*4882a593Smuzhiyun {
1293*4882a593Smuzhiyun 	u32 reg;
1294*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY128_BACKLIGHT
1295*4882a593Smuzhiyun 	struct fb_info *info = pci_get_drvdata(par->pdev);
1296*4882a593Smuzhiyun #endif
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun 	if (on) {
1299*4882a593Smuzhiyun 		reg = aty_ld_le32(LVDS_GEN_CNTL);
1300*4882a593Smuzhiyun 		reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION;
1301*4882a593Smuzhiyun 		reg &= ~LVDS_DISPLAY_DIS;
1302*4882a593Smuzhiyun 		aty_st_le32(LVDS_GEN_CNTL, reg);
1303*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY128_BACKLIGHT
1304*4882a593Smuzhiyun 		aty128_bl_set_power(info, FB_BLANK_UNBLANK);
1305*4882a593Smuzhiyun #endif
1306*4882a593Smuzhiyun 	} else {
1307*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY128_BACKLIGHT
1308*4882a593Smuzhiyun 		aty128_bl_set_power(info, FB_BLANK_POWERDOWN);
1309*4882a593Smuzhiyun #endif
1310*4882a593Smuzhiyun 		reg = aty_ld_le32(LVDS_GEN_CNTL);
1311*4882a593Smuzhiyun 		reg |= LVDS_DISPLAY_DIS;
1312*4882a593Smuzhiyun 		aty_st_le32(LVDS_GEN_CNTL, reg);
1313*4882a593Smuzhiyun 		mdelay(100);
1314*4882a593Smuzhiyun 		reg &= ~(LVDS_ON /*| LVDS_EN*/);
1315*4882a593Smuzhiyun 		aty_st_le32(LVDS_GEN_CNTL, reg);
1316*4882a593Smuzhiyun 	}
1317*4882a593Smuzhiyun }
1318*4882a593Smuzhiyun 
aty128_set_pll(struct aty128_pll * pll,const struct aty128fb_par * par)1319*4882a593Smuzhiyun static void aty128_set_pll(struct aty128_pll *pll,
1320*4882a593Smuzhiyun 			   const struct aty128fb_par *par)
1321*4882a593Smuzhiyun {
1322*4882a593Smuzhiyun 	u32 div3;
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 	unsigned char post_conv[] =	/* register values for post dividers */
1325*4882a593Smuzhiyun         { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 };
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun 	/* select PPLL_DIV_3 */
1328*4882a593Smuzhiyun 	aty_st_le32(CLOCK_CNTL_INDEX, aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8));
1329*4882a593Smuzhiyun 
1330*4882a593Smuzhiyun 	/* reset PLL */
1331*4882a593Smuzhiyun 	aty_st_pll(PPLL_CNTL,
1332*4882a593Smuzhiyun 		   aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN);
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 	/* write the reference divider */
1335*4882a593Smuzhiyun 	aty_pll_wait_readupdate(par);
1336*4882a593Smuzhiyun 	aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider & 0x3ff);
1337*4882a593Smuzhiyun 	aty_pll_writeupdate(par);
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun 	div3 = aty_ld_pll(PPLL_DIV_3);
1340*4882a593Smuzhiyun 	div3 &= ~PPLL_FB3_DIV_MASK;
1341*4882a593Smuzhiyun 	div3 |= pll->feedback_divider;
1342*4882a593Smuzhiyun 	div3 &= ~PPLL_POST3_DIV_MASK;
1343*4882a593Smuzhiyun 	div3 |= post_conv[pll->post_divider] << 16;
1344*4882a593Smuzhiyun 
1345*4882a593Smuzhiyun 	/* write feedback and post dividers */
1346*4882a593Smuzhiyun 	aty_pll_wait_readupdate(par);
1347*4882a593Smuzhiyun 	aty_st_pll(PPLL_DIV_3, div3);
1348*4882a593Smuzhiyun 	aty_pll_writeupdate(par);
1349*4882a593Smuzhiyun 
1350*4882a593Smuzhiyun 	aty_pll_wait_readupdate(par);
1351*4882a593Smuzhiyun 	aty_st_pll(HTOTAL_CNTL, 0);	/* no horiz crtc adjustment */
1352*4882a593Smuzhiyun 	aty_pll_writeupdate(par);
1353*4882a593Smuzhiyun 
1354*4882a593Smuzhiyun 	/* clear the reset, just in case */
1355*4882a593Smuzhiyun 	aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET);
1356*4882a593Smuzhiyun }
1357*4882a593Smuzhiyun 
1358*4882a593Smuzhiyun 
aty128_var_to_pll(u32 period_in_ps,struct aty128_pll * pll,const struct aty128fb_par * par)1359*4882a593Smuzhiyun static int aty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll,
1360*4882a593Smuzhiyun 			     const struct aty128fb_par *par)
1361*4882a593Smuzhiyun {
1362*4882a593Smuzhiyun 	const struct aty128_constants c = par->constants;
1363*4882a593Smuzhiyun 	unsigned char post_dividers[] = {1,2,4,8,3,6,12};
1364*4882a593Smuzhiyun 	u32 output_freq;
1365*4882a593Smuzhiyun 	u32 vclk;        /* in .01 MHz */
1366*4882a593Smuzhiyun 	int i = 0;
1367*4882a593Smuzhiyun 	u32 n, d;
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun 	vclk = 100000000 / period_in_ps;	/* convert units to 10 kHz */
1370*4882a593Smuzhiyun 
1371*4882a593Smuzhiyun 	/* adjust pixel clock if necessary */
1372*4882a593Smuzhiyun 	if (vclk > c.ppll_max)
1373*4882a593Smuzhiyun 		vclk = c.ppll_max;
1374*4882a593Smuzhiyun 	if (vclk * 12 < c.ppll_min)
1375*4882a593Smuzhiyun 		vclk = c.ppll_min/12;
1376*4882a593Smuzhiyun 
1377*4882a593Smuzhiyun 	/* now, find an acceptable divider */
1378*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(post_dividers); i++) {
1379*4882a593Smuzhiyun 		output_freq = post_dividers[i] * vclk;
1380*4882a593Smuzhiyun 		if (output_freq >= c.ppll_min && output_freq <= c.ppll_max) {
1381*4882a593Smuzhiyun 			pll->post_divider = post_dividers[i];
1382*4882a593Smuzhiyun 			break;
1383*4882a593Smuzhiyun 		}
1384*4882a593Smuzhiyun 	}
1385*4882a593Smuzhiyun 
1386*4882a593Smuzhiyun 	if (i == ARRAY_SIZE(post_dividers))
1387*4882a593Smuzhiyun 		return -EINVAL;
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun 	/* calculate feedback divider */
1390*4882a593Smuzhiyun 	n = c.ref_divider * output_freq;
1391*4882a593Smuzhiyun 	d = c.ref_clk;
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun 	pll->feedback_divider = round_div(n, d);
1394*4882a593Smuzhiyun 	pll->vclk = vclk;
1395*4882a593Smuzhiyun 
1396*4882a593Smuzhiyun 	DBG("post %d feedback %d vlck %d output %d ref_divider %d "
1397*4882a593Smuzhiyun 	    "vclk_per: %d\n", pll->post_divider,
1398*4882a593Smuzhiyun 	    pll->feedback_divider, vclk, output_freq,
1399*4882a593Smuzhiyun 	    c.ref_divider, period_in_ps);
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun 	return 0;
1402*4882a593Smuzhiyun }
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 
aty128_pll_to_var(const struct aty128_pll * pll,struct fb_var_screeninfo * var)1405*4882a593Smuzhiyun static int aty128_pll_to_var(const struct aty128_pll *pll,
1406*4882a593Smuzhiyun 			     struct fb_var_screeninfo *var)
1407*4882a593Smuzhiyun {
1408*4882a593Smuzhiyun 	var->pixclock = 100000000 / pll->vclk;
1409*4882a593Smuzhiyun 
1410*4882a593Smuzhiyun 	return 0;
1411*4882a593Smuzhiyun }
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun 
aty128_set_fifo(const struct aty128_ddafifo * dsp,const struct aty128fb_par * par)1414*4882a593Smuzhiyun static void aty128_set_fifo(const struct aty128_ddafifo *dsp,
1415*4882a593Smuzhiyun 			    const struct aty128fb_par *par)
1416*4882a593Smuzhiyun {
1417*4882a593Smuzhiyun 	aty_st_le32(DDA_CONFIG, dsp->dda_config);
1418*4882a593Smuzhiyun 	aty_st_le32(DDA_ON_OFF, dsp->dda_on_off);
1419*4882a593Smuzhiyun }
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 
aty128_ddafifo(struct aty128_ddafifo * dsp,const struct aty128_pll * pll,u32 depth,const struct aty128fb_par * par)1422*4882a593Smuzhiyun static int aty128_ddafifo(struct aty128_ddafifo *dsp,
1423*4882a593Smuzhiyun 			  const struct aty128_pll *pll,
1424*4882a593Smuzhiyun 			  u32 depth,
1425*4882a593Smuzhiyun 			  const struct aty128fb_par *par)
1426*4882a593Smuzhiyun {
1427*4882a593Smuzhiyun 	const struct aty128_meminfo *m = par->mem;
1428*4882a593Smuzhiyun 	u32 xclk = par->constants.xclk;
1429*4882a593Smuzhiyun 	u32 fifo_width = par->constants.fifo_width;
1430*4882a593Smuzhiyun 	u32 fifo_depth = par->constants.fifo_depth;
1431*4882a593Smuzhiyun 	s32 x, b, p, ron, roff;
1432*4882a593Smuzhiyun 	u32 n, d, bpp;
1433*4882a593Smuzhiyun 
1434*4882a593Smuzhiyun 	/* round up to multiple of 8 */
1435*4882a593Smuzhiyun 	bpp = (depth+7) & ~7;
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 	n = xclk * fifo_width;
1438*4882a593Smuzhiyun 	d = pll->vclk * bpp;
1439*4882a593Smuzhiyun 	x = round_div(n, d);
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun 	ron = 4 * m->MB +
1442*4882a593Smuzhiyun 		3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) +
1443*4882a593Smuzhiyun 		2 * m->Trp +
1444*4882a593Smuzhiyun 		m->Twr +
1445*4882a593Smuzhiyun 		m->CL +
1446*4882a593Smuzhiyun 		m->Tr2w +
1447*4882a593Smuzhiyun 		x;
1448*4882a593Smuzhiyun 
1449*4882a593Smuzhiyun 	DBG("x %x\n", x);
1450*4882a593Smuzhiyun 
1451*4882a593Smuzhiyun 	b = 0;
1452*4882a593Smuzhiyun 	while (x) {
1453*4882a593Smuzhiyun 		x >>= 1;
1454*4882a593Smuzhiyun 		b++;
1455*4882a593Smuzhiyun 	}
1456*4882a593Smuzhiyun 	p = b + 1;
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 	ron <<= (11 - p);
1459*4882a593Smuzhiyun 
1460*4882a593Smuzhiyun 	n <<= (11 - p);
1461*4882a593Smuzhiyun 	x = round_div(n, d);
1462*4882a593Smuzhiyun 	roff = x * (fifo_depth - 4);
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun 	if ((ron + m->Rloop) >= roff) {
1465*4882a593Smuzhiyun 		printk(KERN_ERR "aty128fb: Mode out of range!\n");
1466*4882a593Smuzhiyun 		return -EINVAL;
1467*4882a593Smuzhiyun 	}
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 	DBG("p: %x rloop: %x x: %x ron: %x roff: %x\n",
1470*4882a593Smuzhiyun 	    p, m->Rloop, x, ron, roff);
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun 	dsp->dda_config = p << 16 | m->Rloop << 20 | x;
1473*4882a593Smuzhiyun 	dsp->dda_on_off = ron << 16 | roff;
1474*4882a593Smuzhiyun 
1475*4882a593Smuzhiyun 	return 0;
1476*4882a593Smuzhiyun }
1477*4882a593Smuzhiyun 
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun /*
1480*4882a593Smuzhiyun  * This actually sets the video mode.
1481*4882a593Smuzhiyun  */
aty128fb_set_par(struct fb_info * info)1482*4882a593Smuzhiyun static int aty128fb_set_par(struct fb_info *info)
1483*4882a593Smuzhiyun {
1484*4882a593Smuzhiyun 	struct aty128fb_par *par = info->par;
1485*4882a593Smuzhiyun 	u32 config;
1486*4882a593Smuzhiyun 	int err;
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun 	if ((err = aty128_decode_var(&info->var, par)) != 0)
1489*4882a593Smuzhiyun 		return err;
1490*4882a593Smuzhiyun 
1491*4882a593Smuzhiyun 	if (par->blitter_may_be_busy)
1492*4882a593Smuzhiyun 		wait_for_idle(par);
1493*4882a593Smuzhiyun 
1494*4882a593Smuzhiyun 	/* clear all registers that may interfere with mode setting */
1495*4882a593Smuzhiyun 	aty_st_le32(OVR_CLR, 0);
1496*4882a593Smuzhiyun 	aty_st_le32(OVR_WID_LEFT_RIGHT, 0);
1497*4882a593Smuzhiyun 	aty_st_le32(OVR_WID_TOP_BOTTOM, 0);
1498*4882a593Smuzhiyun 	aty_st_le32(OV0_SCALE_CNTL, 0);
1499*4882a593Smuzhiyun 	aty_st_le32(MPP_TB_CONFIG, 0);
1500*4882a593Smuzhiyun 	aty_st_le32(MPP_GP_CONFIG, 0);
1501*4882a593Smuzhiyun 	aty_st_le32(SUBPIC_CNTL, 0);
1502*4882a593Smuzhiyun 	aty_st_le32(VIPH_CONTROL, 0);
1503*4882a593Smuzhiyun 	aty_st_le32(I2C_CNTL_1, 0);         /* turn off i2c */
1504*4882a593Smuzhiyun 	aty_st_le32(GEN_INT_CNTL, 0);	/* turn off interrupts */
1505*4882a593Smuzhiyun 	aty_st_le32(CAP0_TRIG_CNTL, 0);
1506*4882a593Smuzhiyun 	aty_st_le32(CAP1_TRIG_CNTL, 0);
1507*4882a593Smuzhiyun 
1508*4882a593Smuzhiyun 	aty_st_8(CRTC_EXT_CNTL + 1, 4);	/* turn video off */
1509*4882a593Smuzhiyun 
1510*4882a593Smuzhiyun 	aty128_set_crtc(&par->crtc, par);
1511*4882a593Smuzhiyun 	aty128_set_pll(&par->pll, par);
1512*4882a593Smuzhiyun 	aty128_set_fifo(&par->fifo_reg, par);
1513*4882a593Smuzhiyun 
1514*4882a593Smuzhiyun 	config = aty_ld_le32(CNFG_CNTL) & ~3;
1515*4882a593Smuzhiyun 
1516*4882a593Smuzhiyun #if defined(__BIG_ENDIAN)
1517*4882a593Smuzhiyun 	if (par->crtc.bpp == 32)
1518*4882a593Smuzhiyun 		config |= 2;	/* make aperture do 32 bit swapping */
1519*4882a593Smuzhiyun 	else if (par->crtc.bpp == 16)
1520*4882a593Smuzhiyun 		config |= 1;	/* make aperture do 16 bit swapping */
1521*4882a593Smuzhiyun #endif
1522*4882a593Smuzhiyun 
1523*4882a593Smuzhiyun 	aty_st_le32(CNFG_CNTL, config);
1524*4882a593Smuzhiyun 	aty_st_8(CRTC_EXT_CNTL + 1, 0);	/* turn the video back on */
1525*4882a593Smuzhiyun 
1526*4882a593Smuzhiyun 	info->fix.line_length = (par->crtc.vxres * par->crtc.bpp) >> 3;
1527*4882a593Smuzhiyun 	info->fix.visual = par->crtc.bpp == 8 ? FB_VISUAL_PSEUDOCOLOR
1528*4882a593Smuzhiyun 		: FB_VISUAL_DIRECTCOLOR;
1529*4882a593Smuzhiyun 
1530*4882a593Smuzhiyun 	if (par->chip_gen == rage_M3) {
1531*4882a593Smuzhiyun 		aty128_set_crt_enable(par, par->crt_on);
1532*4882a593Smuzhiyun 		aty128_set_lcd_enable(par, par->lcd_on);
1533*4882a593Smuzhiyun 	}
1534*4882a593Smuzhiyun 	if (par->accel_flags & FB_ACCELF_TEXT)
1535*4882a593Smuzhiyun 		aty128_init_engine(par);
1536*4882a593Smuzhiyun 
1537*4882a593Smuzhiyun #ifdef CONFIG_BOOTX_TEXT
1538*4882a593Smuzhiyun 	btext_update_display(info->fix.smem_start,
1539*4882a593Smuzhiyun 			     (((par->crtc.h_total>>16) & 0xff)+1)*8,
1540*4882a593Smuzhiyun 			     ((par->crtc.v_total>>16) & 0x7ff)+1,
1541*4882a593Smuzhiyun 			     par->crtc.bpp,
1542*4882a593Smuzhiyun 			     par->crtc.vxres*par->crtc.bpp/8);
1543*4882a593Smuzhiyun #endif /* CONFIG_BOOTX_TEXT */
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun 	return 0;
1546*4882a593Smuzhiyun }
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun /*
1549*4882a593Smuzhiyun  *  encode/decode the User Defined Part of the Display
1550*4882a593Smuzhiyun  */
1551*4882a593Smuzhiyun 
aty128_decode_var(struct fb_var_screeninfo * var,struct aty128fb_par * par)1552*4882a593Smuzhiyun static int aty128_decode_var(struct fb_var_screeninfo *var,
1553*4882a593Smuzhiyun 			     struct aty128fb_par *par)
1554*4882a593Smuzhiyun {
1555*4882a593Smuzhiyun 	int err;
1556*4882a593Smuzhiyun 	struct aty128_crtc crtc;
1557*4882a593Smuzhiyun 	struct aty128_pll pll;
1558*4882a593Smuzhiyun 	struct aty128_ddafifo fifo_reg;
1559*4882a593Smuzhiyun 
1560*4882a593Smuzhiyun 	if ((err = aty128_var_to_crtc(var, &crtc, par)))
1561*4882a593Smuzhiyun 		return err;
1562*4882a593Smuzhiyun 
1563*4882a593Smuzhiyun 	if ((err = aty128_var_to_pll(var->pixclock, &pll, par)))
1564*4882a593Smuzhiyun 		return err;
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun 	if ((err = aty128_ddafifo(&fifo_reg, &pll, crtc.depth, par)))
1567*4882a593Smuzhiyun 		return err;
1568*4882a593Smuzhiyun 
1569*4882a593Smuzhiyun 	par->crtc = crtc;
1570*4882a593Smuzhiyun 	par->pll = pll;
1571*4882a593Smuzhiyun 	par->fifo_reg = fifo_reg;
1572*4882a593Smuzhiyun 	par->accel_flags = var->accel_flags;
1573*4882a593Smuzhiyun 
1574*4882a593Smuzhiyun 	return 0;
1575*4882a593Smuzhiyun }
1576*4882a593Smuzhiyun 
1577*4882a593Smuzhiyun 
aty128_encode_var(struct fb_var_screeninfo * var,const struct aty128fb_par * par)1578*4882a593Smuzhiyun static int aty128_encode_var(struct fb_var_screeninfo *var,
1579*4882a593Smuzhiyun 			     const struct aty128fb_par *par)
1580*4882a593Smuzhiyun {
1581*4882a593Smuzhiyun 	int err;
1582*4882a593Smuzhiyun 
1583*4882a593Smuzhiyun 	if ((err = aty128_crtc_to_var(&par->crtc, var)))
1584*4882a593Smuzhiyun 		return err;
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 	if ((err = aty128_pll_to_var(&par->pll, var)))
1587*4882a593Smuzhiyun 		return err;
1588*4882a593Smuzhiyun 
1589*4882a593Smuzhiyun 	var->nonstd = 0;
1590*4882a593Smuzhiyun 	var->activate = 0;
1591*4882a593Smuzhiyun 
1592*4882a593Smuzhiyun 	var->height = -1;
1593*4882a593Smuzhiyun 	var->width = -1;
1594*4882a593Smuzhiyun 	var->accel_flags = par->accel_flags;
1595*4882a593Smuzhiyun 
1596*4882a593Smuzhiyun 	return 0;
1597*4882a593Smuzhiyun }
1598*4882a593Smuzhiyun 
1599*4882a593Smuzhiyun 
aty128fb_check_var(struct fb_var_screeninfo * var,struct fb_info * info)1600*4882a593Smuzhiyun static int aty128fb_check_var(struct fb_var_screeninfo *var,
1601*4882a593Smuzhiyun 			      struct fb_info *info)
1602*4882a593Smuzhiyun {
1603*4882a593Smuzhiyun 	struct aty128fb_par par;
1604*4882a593Smuzhiyun 	int err;
1605*4882a593Smuzhiyun 
1606*4882a593Smuzhiyun 	par = *(struct aty128fb_par *)info->par;
1607*4882a593Smuzhiyun 	if ((err = aty128_decode_var(var, &par)) != 0)
1608*4882a593Smuzhiyun 		return err;
1609*4882a593Smuzhiyun 	aty128_encode_var(var, &par);
1610*4882a593Smuzhiyun 	return 0;
1611*4882a593Smuzhiyun }
1612*4882a593Smuzhiyun 
1613*4882a593Smuzhiyun 
1614*4882a593Smuzhiyun /*
1615*4882a593Smuzhiyun  *  Pan or Wrap the Display
1616*4882a593Smuzhiyun  */
aty128fb_pan_display(struct fb_var_screeninfo * var,struct fb_info * fb)1617*4882a593Smuzhiyun static int aty128fb_pan_display(struct fb_var_screeninfo *var,
1618*4882a593Smuzhiyun 				struct fb_info *fb)
1619*4882a593Smuzhiyun {
1620*4882a593Smuzhiyun 	struct aty128fb_par *par = fb->par;
1621*4882a593Smuzhiyun 	u32 xoffset, yoffset;
1622*4882a593Smuzhiyun 	u32 offset;
1623*4882a593Smuzhiyun 	u32 xres, yres;
1624*4882a593Smuzhiyun 
1625*4882a593Smuzhiyun 	xres = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3;
1626*4882a593Smuzhiyun 	yres = ((par->crtc.v_total >> 16) & 0x7ff) + 1;
1627*4882a593Smuzhiyun 
1628*4882a593Smuzhiyun 	xoffset = (var->xoffset +7) & ~7;
1629*4882a593Smuzhiyun 	yoffset = var->yoffset;
1630*4882a593Smuzhiyun 
1631*4882a593Smuzhiyun 	if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres)
1632*4882a593Smuzhiyun 		return -EINVAL;
1633*4882a593Smuzhiyun 
1634*4882a593Smuzhiyun 	par->crtc.xoffset = xoffset;
1635*4882a593Smuzhiyun 	par->crtc.yoffset = yoffset;
1636*4882a593Smuzhiyun 
1637*4882a593Smuzhiyun 	offset = ((yoffset * par->crtc.vxres + xoffset) * (par->crtc.bpp >> 3))
1638*4882a593Smuzhiyun 									  & ~7;
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 	if (par->crtc.bpp == 24)
1641*4882a593Smuzhiyun 		offset += 8 * (offset % 3); /* Must be multiple of 8 and 3 */
1642*4882a593Smuzhiyun 
1643*4882a593Smuzhiyun 	aty_st_le32(CRTC_OFFSET, offset);
1644*4882a593Smuzhiyun 
1645*4882a593Smuzhiyun 	return 0;
1646*4882a593Smuzhiyun }
1647*4882a593Smuzhiyun 
1648*4882a593Smuzhiyun 
1649*4882a593Smuzhiyun /*
1650*4882a593Smuzhiyun  *  Helper function to store a single palette register
1651*4882a593Smuzhiyun  */
aty128_st_pal(u_int regno,u_int red,u_int green,u_int blue,struct aty128fb_par * par)1652*4882a593Smuzhiyun static void aty128_st_pal(u_int regno, u_int red, u_int green, u_int blue,
1653*4882a593Smuzhiyun 			  struct aty128fb_par *par)
1654*4882a593Smuzhiyun {
1655*4882a593Smuzhiyun 	if (par->chip_gen == rage_M3) {
1656*4882a593Smuzhiyun 		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) &
1657*4882a593Smuzhiyun 			    ~DAC_PALETTE_ACCESS_CNTL);
1658*4882a593Smuzhiyun 	}
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun 	aty_st_8(PALETTE_INDEX, regno);
1661*4882a593Smuzhiyun 	aty_st_le32(PALETTE_DATA, (red<<16)|(green<<8)|blue);
1662*4882a593Smuzhiyun }
1663*4882a593Smuzhiyun 
aty128fb_sync(struct fb_info * info)1664*4882a593Smuzhiyun static int aty128fb_sync(struct fb_info *info)
1665*4882a593Smuzhiyun {
1666*4882a593Smuzhiyun 	struct aty128fb_par *par = info->par;
1667*4882a593Smuzhiyun 
1668*4882a593Smuzhiyun 	if (par->blitter_may_be_busy)
1669*4882a593Smuzhiyun 		wait_for_idle(par);
1670*4882a593Smuzhiyun 	return 0;
1671*4882a593Smuzhiyun }
1672*4882a593Smuzhiyun 
1673*4882a593Smuzhiyun #ifndef MODULE
aty128fb_setup(char * options)1674*4882a593Smuzhiyun static int aty128fb_setup(char *options)
1675*4882a593Smuzhiyun {
1676*4882a593Smuzhiyun 	char *this_opt;
1677*4882a593Smuzhiyun 
1678*4882a593Smuzhiyun 	if (!options || !*options)
1679*4882a593Smuzhiyun 		return 0;
1680*4882a593Smuzhiyun 
1681*4882a593Smuzhiyun 	while ((this_opt = strsep(&options, ",")) != NULL) {
1682*4882a593Smuzhiyun 		if (!strncmp(this_opt, "lcd:", 4)) {
1683*4882a593Smuzhiyun 			default_lcd_on = simple_strtoul(this_opt+4, NULL, 0);
1684*4882a593Smuzhiyun 			continue;
1685*4882a593Smuzhiyun 		} else if (!strncmp(this_opt, "crt:", 4)) {
1686*4882a593Smuzhiyun 			default_crt_on = simple_strtoul(this_opt+4, NULL, 0);
1687*4882a593Smuzhiyun 			continue;
1688*4882a593Smuzhiyun 		} else if (!strncmp(this_opt, "backlight:", 10)) {
1689*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY128_BACKLIGHT
1690*4882a593Smuzhiyun 			backlight = simple_strtoul(this_opt+10, NULL, 0);
1691*4882a593Smuzhiyun #endif
1692*4882a593Smuzhiyun 			continue;
1693*4882a593Smuzhiyun 		}
1694*4882a593Smuzhiyun 		if(!strncmp(this_opt, "nomtrr", 6)) {
1695*4882a593Smuzhiyun 			mtrr = false;
1696*4882a593Smuzhiyun 			continue;
1697*4882a593Smuzhiyun 		}
1698*4882a593Smuzhiyun #ifdef CONFIG_PPC_PMAC
1699*4882a593Smuzhiyun 		/* vmode and cmode deprecated */
1700*4882a593Smuzhiyun 		if (!strncmp(this_opt, "vmode:", 6)) {
1701*4882a593Smuzhiyun 			unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
1702*4882a593Smuzhiyun 			if (vmode > 0 && vmode <= VMODE_MAX)
1703*4882a593Smuzhiyun 				default_vmode = vmode;
1704*4882a593Smuzhiyun 			continue;
1705*4882a593Smuzhiyun 		} else if (!strncmp(this_opt, "cmode:", 6)) {
1706*4882a593Smuzhiyun 			unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
1707*4882a593Smuzhiyun 			switch (cmode) {
1708*4882a593Smuzhiyun 			case 0:
1709*4882a593Smuzhiyun 			case 8:
1710*4882a593Smuzhiyun 				default_cmode = CMODE_8;
1711*4882a593Smuzhiyun 				break;
1712*4882a593Smuzhiyun 			case 15:
1713*4882a593Smuzhiyun 			case 16:
1714*4882a593Smuzhiyun 				default_cmode = CMODE_16;
1715*4882a593Smuzhiyun 				break;
1716*4882a593Smuzhiyun 			case 24:
1717*4882a593Smuzhiyun 			case 32:
1718*4882a593Smuzhiyun 				default_cmode = CMODE_32;
1719*4882a593Smuzhiyun 				break;
1720*4882a593Smuzhiyun 			}
1721*4882a593Smuzhiyun 			continue;
1722*4882a593Smuzhiyun 		}
1723*4882a593Smuzhiyun #endif /* CONFIG_PPC_PMAC */
1724*4882a593Smuzhiyun 		mode_option = this_opt;
1725*4882a593Smuzhiyun 	}
1726*4882a593Smuzhiyun 	return 0;
1727*4882a593Smuzhiyun }
1728*4882a593Smuzhiyun #endif  /*  MODULE  */
1729*4882a593Smuzhiyun 
1730*4882a593Smuzhiyun /* Backlight */
1731*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY128_BACKLIGHT
1732*4882a593Smuzhiyun #define MAX_LEVEL 0xFF
1733*4882a593Smuzhiyun 
aty128_bl_get_level_brightness(struct aty128fb_par * par,int level)1734*4882a593Smuzhiyun static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
1735*4882a593Smuzhiyun 		int level)
1736*4882a593Smuzhiyun {
1737*4882a593Smuzhiyun 	struct fb_info *info = pci_get_drvdata(par->pdev);
1738*4882a593Smuzhiyun 	int atylevel;
1739*4882a593Smuzhiyun 
1740*4882a593Smuzhiyun 	/* Get and convert the value */
1741*4882a593Smuzhiyun 	/* No locking of bl_curve since we read a single value */
1742*4882a593Smuzhiyun 	atylevel = MAX_LEVEL -
1743*4882a593Smuzhiyun 		(info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
1744*4882a593Smuzhiyun 
1745*4882a593Smuzhiyun 	if (atylevel < 0)
1746*4882a593Smuzhiyun 		atylevel = 0;
1747*4882a593Smuzhiyun 	else if (atylevel > MAX_LEVEL)
1748*4882a593Smuzhiyun 		atylevel = MAX_LEVEL;
1749*4882a593Smuzhiyun 
1750*4882a593Smuzhiyun 	return atylevel;
1751*4882a593Smuzhiyun }
1752*4882a593Smuzhiyun 
1753*4882a593Smuzhiyun /* We turn off the LCD completely instead of just dimming the backlight.
1754*4882a593Smuzhiyun  * This provides greater power saving and the display is useless without
1755*4882a593Smuzhiyun  * backlight anyway
1756*4882a593Smuzhiyun  */
1757*4882a593Smuzhiyun #define BACKLIGHT_LVDS_OFF
1758*4882a593Smuzhiyun /* That one prevents proper CRT output with LCD off */
1759*4882a593Smuzhiyun #undef BACKLIGHT_DAC_OFF
1760*4882a593Smuzhiyun 
aty128_bl_update_status(struct backlight_device * bd)1761*4882a593Smuzhiyun static int aty128_bl_update_status(struct backlight_device *bd)
1762*4882a593Smuzhiyun {
1763*4882a593Smuzhiyun 	struct aty128fb_par *par = bl_get_data(bd);
1764*4882a593Smuzhiyun 	unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
1765*4882a593Smuzhiyun 	int level;
1766*4882a593Smuzhiyun 
1767*4882a593Smuzhiyun 	if (bd->props.power != FB_BLANK_UNBLANK ||
1768*4882a593Smuzhiyun 	    bd->props.fb_blank != FB_BLANK_UNBLANK ||
1769*4882a593Smuzhiyun 	    !par->lcd_on)
1770*4882a593Smuzhiyun 		level = 0;
1771*4882a593Smuzhiyun 	else
1772*4882a593Smuzhiyun 		level = bd->props.brightness;
1773*4882a593Smuzhiyun 
1774*4882a593Smuzhiyun 	reg |= LVDS_BL_MOD_EN | LVDS_BLON;
1775*4882a593Smuzhiyun 	if (level > 0) {
1776*4882a593Smuzhiyun 		reg |= LVDS_DIGION;
1777*4882a593Smuzhiyun 		if (!(reg & LVDS_ON)) {
1778*4882a593Smuzhiyun 			reg &= ~LVDS_BLON;
1779*4882a593Smuzhiyun 			aty_st_le32(LVDS_GEN_CNTL, reg);
1780*4882a593Smuzhiyun 			aty_ld_le32(LVDS_GEN_CNTL);
1781*4882a593Smuzhiyun 			mdelay(10);
1782*4882a593Smuzhiyun 			reg |= LVDS_BLON;
1783*4882a593Smuzhiyun 			aty_st_le32(LVDS_GEN_CNTL, reg);
1784*4882a593Smuzhiyun 		}
1785*4882a593Smuzhiyun 		reg &= ~LVDS_BL_MOD_LEVEL_MASK;
1786*4882a593Smuzhiyun 		reg |= (aty128_bl_get_level_brightness(par, level) <<
1787*4882a593Smuzhiyun 			LVDS_BL_MOD_LEVEL_SHIFT);
1788*4882a593Smuzhiyun #ifdef BACKLIGHT_LVDS_OFF
1789*4882a593Smuzhiyun 		reg |= LVDS_ON | LVDS_EN;
1790*4882a593Smuzhiyun 		reg &= ~LVDS_DISPLAY_DIS;
1791*4882a593Smuzhiyun #endif
1792*4882a593Smuzhiyun 		aty_st_le32(LVDS_GEN_CNTL, reg);
1793*4882a593Smuzhiyun #ifdef BACKLIGHT_DAC_OFF
1794*4882a593Smuzhiyun 		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
1795*4882a593Smuzhiyun #endif
1796*4882a593Smuzhiyun 	} else {
1797*4882a593Smuzhiyun 		reg &= ~LVDS_BL_MOD_LEVEL_MASK;
1798*4882a593Smuzhiyun 		reg |= (aty128_bl_get_level_brightness(par, 0) <<
1799*4882a593Smuzhiyun 			LVDS_BL_MOD_LEVEL_SHIFT);
1800*4882a593Smuzhiyun #ifdef BACKLIGHT_LVDS_OFF
1801*4882a593Smuzhiyun 		reg |= LVDS_DISPLAY_DIS;
1802*4882a593Smuzhiyun 		aty_st_le32(LVDS_GEN_CNTL, reg);
1803*4882a593Smuzhiyun 		aty_ld_le32(LVDS_GEN_CNTL);
1804*4882a593Smuzhiyun 		udelay(10);
1805*4882a593Smuzhiyun 		reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
1806*4882a593Smuzhiyun #endif
1807*4882a593Smuzhiyun 		aty_st_le32(LVDS_GEN_CNTL, reg);
1808*4882a593Smuzhiyun #ifdef BACKLIGHT_DAC_OFF
1809*4882a593Smuzhiyun 		aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
1810*4882a593Smuzhiyun #endif
1811*4882a593Smuzhiyun 	}
1812*4882a593Smuzhiyun 
1813*4882a593Smuzhiyun 	return 0;
1814*4882a593Smuzhiyun }
1815*4882a593Smuzhiyun 
1816*4882a593Smuzhiyun static const struct backlight_ops aty128_bl_data = {
1817*4882a593Smuzhiyun 	.update_status	= aty128_bl_update_status,
1818*4882a593Smuzhiyun };
1819*4882a593Smuzhiyun 
aty128_bl_set_power(struct fb_info * info,int power)1820*4882a593Smuzhiyun static void aty128_bl_set_power(struct fb_info *info, int power)
1821*4882a593Smuzhiyun {
1822*4882a593Smuzhiyun 	if (info->bl_dev) {
1823*4882a593Smuzhiyun 		info->bl_dev->props.power = power;
1824*4882a593Smuzhiyun 		backlight_update_status(info->bl_dev);
1825*4882a593Smuzhiyun 	}
1826*4882a593Smuzhiyun }
1827*4882a593Smuzhiyun 
aty128_bl_init(struct aty128fb_par * par)1828*4882a593Smuzhiyun static void aty128_bl_init(struct aty128fb_par *par)
1829*4882a593Smuzhiyun {
1830*4882a593Smuzhiyun 	struct backlight_properties props;
1831*4882a593Smuzhiyun 	struct fb_info *info = pci_get_drvdata(par->pdev);
1832*4882a593Smuzhiyun 	struct backlight_device *bd;
1833*4882a593Smuzhiyun 	char name[12];
1834*4882a593Smuzhiyun 
1835*4882a593Smuzhiyun 	/* Could be extended to Rage128Pro LVDS output too */
1836*4882a593Smuzhiyun 	if (par->chip_gen != rage_M3)
1837*4882a593Smuzhiyun 		return;
1838*4882a593Smuzhiyun 
1839*4882a593Smuzhiyun #ifdef CONFIG_PMAC_BACKLIGHT
1840*4882a593Smuzhiyun 	if (!pmac_has_backlight_type("ati"))
1841*4882a593Smuzhiyun 		return;
1842*4882a593Smuzhiyun #endif
1843*4882a593Smuzhiyun 
1844*4882a593Smuzhiyun 	snprintf(name, sizeof(name), "aty128bl%d", info->node);
1845*4882a593Smuzhiyun 
1846*4882a593Smuzhiyun 	memset(&props, 0, sizeof(struct backlight_properties));
1847*4882a593Smuzhiyun 	props.type = BACKLIGHT_RAW;
1848*4882a593Smuzhiyun 	props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
1849*4882a593Smuzhiyun 	bd = backlight_device_register(name, info->dev, par, &aty128_bl_data,
1850*4882a593Smuzhiyun 				       &props);
1851*4882a593Smuzhiyun 	if (IS_ERR(bd)) {
1852*4882a593Smuzhiyun 		info->bl_dev = NULL;
1853*4882a593Smuzhiyun 		printk(KERN_WARNING "aty128: Backlight registration failed\n");
1854*4882a593Smuzhiyun 		goto error;
1855*4882a593Smuzhiyun 	}
1856*4882a593Smuzhiyun 
1857*4882a593Smuzhiyun 	info->bl_dev = bd;
1858*4882a593Smuzhiyun 	fb_bl_default_curve(info, 0,
1859*4882a593Smuzhiyun 		 63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
1860*4882a593Smuzhiyun 		219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
1861*4882a593Smuzhiyun 
1862*4882a593Smuzhiyun 	bd->props.brightness = bd->props.max_brightness;
1863*4882a593Smuzhiyun 	bd->props.power = FB_BLANK_UNBLANK;
1864*4882a593Smuzhiyun 	backlight_update_status(bd);
1865*4882a593Smuzhiyun 
1866*4882a593Smuzhiyun 	printk("aty128: Backlight initialized (%s)\n", name);
1867*4882a593Smuzhiyun 
1868*4882a593Smuzhiyun 	return;
1869*4882a593Smuzhiyun 
1870*4882a593Smuzhiyun error:
1871*4882a593Smuzhiyun 	return;
1872*4882a593Smuzhiyun }
1873*4882a593Smuzhiyun 
aty128_bl_exit(struct backlight_device * bd)1874*4882a593Smuzhiyun static void aty128_bl_exit(struct backlight_device *bd)
1875*4882a593Smuzhiyun {
1876*4882a593Smuzhiyun 	backlight_device_unregister(bd);
1877*4882a593Smuzhiyun 	printk("aty128: Backlight unloaded\n");
1878*4882a593Smuzhiyun }
1879*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY128_BACKLIGHT */
1880*4882a593Smuzhiyun 
1881*4882a593Smuzhiyun /*
1882*4882a593Smuzhiyun  *  Initialisation
1883*4882a593Smuzhiyun  */
1884*4882a593Smuzhiyun 
1885*4882a593Smuzhiyun #ifdef CONFIG_PPC_PMAC__disabled
aty128_early_resume(void * data)1886*4882a593Smuzhiyun static void aty128_early_resume(void *data)
1887*4882a593Smuzhiyun {
1888*4882a593Smuzhiyun         struct aty128fb_par *par = data;
1889*4882a593Smuzhiyun 
1890*4882a593Smuzhiyun 	if (!console_trylock())
1891*4882a593Smuzhiyun 		return;
1892*4882a593Smuzhiyun 	pci_restore_state(par->pdev);
1893*4882a593Smuzhiyun 	aty128_do_resume(par->pdev);
1894*4882a593Smuzhiyun 	console_unlock();
1895*4882a593Smuzhiyun }
1896*4882a593Smuzhiyun #endif /* CONFIG_PPC_PMAC */
1897*4882a593Smuzhiyun 
aty128_init(struct pci_dev * pdev,const struct pci_device_id * ent)1898*4882a593Smuzhiyun static int aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
1899*4882a593Smuzhiyun {
1900*4882a593Smuzhiyun 	struct fb_info *info = pci_get_drvdata(pdev);
1901*4882a593Smuzhiyun 	struct aty128fb_par *par = info->par;
1902*4882a593Smuzhiyun 	struct fb_var_screeninfo var;
1903*4882a593Smuzhiyun 	char video_card[50];
1904*4882a593Smuzhiyun 	u8 chip_rev;
1905*4882a593Smuzhiyun 	u32 dac;
1906*4882a593Smuzhiyun 
1907*4882a593Smuzhiyun 	/* Get the chip revision */
1908*4882a593Smuzhiyun 	chip_rev = (aty_ld_le32(CNFG_CNTL) >> 16) & 0x1F;
1909*4882a593Smuzhiyun 
1910*4882a593Smuzhiyun 	strcpy(video_card, "Rage128 XX ");
1911*4882a593Smuzhiyun 	video_card[8] = ent->device >> 8;
1912*4882a593Smuzhiyun 	video_card[9] = ent->device & 0xFF;
1913*4882a593Smuzhiyun 
1914*4882a593Smuzhiyun 	/* range check to make sure */
1915*4882a593Smuzhiyun 	if (ent->driver_data < ARRAY_SIZE(r128_family))
1916*4882a593Smuzhiyun 		strlcat(video_card, r128_family[ent->driver_data],
1917*4882a593Smuzhiyun 			sizeof(video_card));
1918*4882a593Smuzhiyun 
1919*4882a593Smuzhiyun 	printk(KERN_INFO "aty128fb: %s [chip rev 0x%x] ", video_card, chip_rev);
1920*4882a593Smuzhiyun 
1921*4882a593Smuzhiyun 	if (par->vram_size % (1024 * 1024) == 0)
1922*4882a593Smuzhiyun 		printk("%dM %s\n", par->vram_size / (1024*1024), par->mem->name);
1923*4882a593Smuzhiyun 	else
1924*4882a593Smuzhiyun 		printk("%dk %s\n", par->vram_size / 1024, par->mem->name);
1925*4882a593Smuzhiyun 
1926*4882a593Smuzhiyun 	par->chip_gen = ent->driver_data;
1927*4882a593Smuzhiyun 
1928*4882a593Smuzhiyun 	/* fill in info */
1929*4882a593Smuzhiyun 	info->fbops = &aty128fb_ops;
1930*4882a593Smuzhiyun 	info->flags = FBINFO_FLAG_DEFAULT;
1931*4882a593Smuzhiyun 
1932*4882a593Smuzhiyun 	par->lcd_on = default_lcd_on;
1933*4882a593Smuzhiyun 	par->crt_on = default_crt_on;
1934*4882a593Smuzhiyun 
1935*4882a593Smuzhiyun 	var = default_var;
1936*4882a593Smuzhiyun #ifdef CONFIG_PPC_PMAC
1937*4882a593Smuzhiyun 	if (machine_is(powermac)) {
1938*4882a593Smuzhiyun 		/* Indicate sleep capability */
1939*4882a593Smuzhiyun 		if (par->chip_gen == rage_M3) {
1940*4882a593Smuzhiyun 			pmac_call_feature(PMAC_FTR_DEVICE_CAN_WAKE, NULL, 0, 1);
1941*4882a593Smuzhiyun #if 0 /* Disable the early video resume hack for now as it's causing problems,
1942*4882a593Smuzhiyun        * among others we now rely on the PCI core restoring the config space
1943*4882a593Smuzhiyun        * for us, which isn't the case with that hack, and that code path causes
1944*4882a593Smuzhiyun        * various things to be called with interrupts off while they shouldn't.
1945*4882a593Smuzhiyun        * I'm leaving the code in as it can be useful for debugging purposes
1946*4882a593Smuzhiyun        */
1947*4882a593Smuzhiyun 			pmac_set_early_video_resume(aty128_early_resume, par);
1948*4882a593Smuzhiyun #endif
1949*4882a593Smuzhiyun 		}
1950*4882a593Smuzhiyun 
1951*4882a593Smuzhiyun 		/* Find default mode */
1952*4882a593Smuzhiyun 		if (mode_option) {
1953*4882a593Smuzhiyun 			if (!mac_find_mode(&var, info, mode_option, 8))
1954*4882a593Smuzhiyun 				var = default_var;
1955*4882a593Smuzhiyun 		} else {
1956*4882a593Smuzhiyun 			if (default_vmode <= 0 || default_vmode > VMODE_MAX)
1957*4882a593Smuzhiyun 				default_vmode = VMODE_1024_768_60;
1958*4882a593Smuzhiyun 
1959*4882a593Smuzhiyun 			/* iMacs need that resolution
1960*4882a593Smuzhiyun 			 * PowerMac2,1 first r128 iMacs
1961*4882a593Smuzhiyun 			 * PowerMac2,2 summer 2000 iMacs
1962*4882a593Smuzhiyun 			 * PowerMac4,1 january 2001 iMacs "flower power"
1963*4882a593Smuzhiyun 			 */
1964*4882a593Smuzhiyun 			if (of_machine_is_compatible("PowerMac2,1") ||
1965*4882a593Smuzhiyun 			    of_machine_is_compatible("PowerMac2,2") ||
1966*4882a593Smuzhiyun 			    of_machine_is_compatible("PowerMac4,1"))
1967*4882a593Smuzhiyun 				default_vmode = VMODE_1024_768_75;
1968*4882a593Smuzhiyun 
1969*4882a593Smuzhiyun 			/* iBook SE */
1970*4882a593Smuzhiyun 			if (of_machine_is_compatible("PowerBook2,2"))
1971*4882a593Smuzhiyun 				default_vmode = VMODE_800_600_60;
1972*4882a593Smuzhiyun 
1973*4882a593Smuzhiyun 			/* PowerBook Firewire (Pismo), iBook Dual USB */
1974*4882a593Smuzhiyun 			if (of_machine_is_compatible("PowerBook3,1") ||
1975*4882a593Smuzhiyun 			    of_machine_is_compatible("PowerBook4,1"))
1976*4882a593Smuzhiyun 				default_vmode = VMODE_1024_768_60;
1977*4882a593Smuzhiyun 
1978*4882a593Smuzhiyun 			/* PowerBook Titanium */
1979*4882a593Smuzhiyun 			if (of_machine_is_compatible("PowerBook3,2"))
1980*4882a593Smuzhiyun 				default_vmode = VMODE_1152_768_60;
1981*4882a593Smuzhiyun 
1982*4882a593Smuzhiyun 			if (default_cmode > 16)
1983*4882a593Smuzhiyun 				default_cmode = CMODE_32;
1984*4882a593Smuzhiyun 			else if (default_cmode > 8)
1985*4882a593Smuzhiyun 				default_cmode = CMODE_16;
1986*4882a593Smuzhiyun 			else
1987*4882a593Smuzhiyun 				default_cmode = CMODE_8;
1988*4882a593Smuzhiyun 
1989*4882a593Smuzhiyun 			if (mac_vmode_to_var(default_vmode, default_cmode, &var))
1990*4882a593Smuzhiyun 				var = default_var;
1991*4882a593Smuzhiyun 		}
1992*4882a593Smuzhiyun 	} else
1993*4882a593Smuzhiyun #endif /* CONFIG_PPC_PMAC */
1994*4882a593Smuzhiyun 	{
1995*4882a593Smuzhiyun 		if (mode_option)
1996*4882a593Smuzhiyun 			if (fb_find_mode(&var, info, mode_option, NULL,
1997*4882a593Smuzhiyun 					 0, &defaultmode, 8) == 0)
1998*4882a593Smuzhiyun 				var = default_var;
1999*4882a593Smuzhiyun 	}
2000*4882a593Smuzhiyun 
2001*4882a593Smuzhiyun 	var.accel_flags &= ~FB_ACCELF_TEXT;
2002*4882a593Smuzhiyun //	var.accel_flags |= FB_ACCELF_TEXT;/* FIXME Will add accel later */
2003*4882a593Smuzhiyun 
2004*4882a593Smuzhiyun 	if (aty128fb_check_var(&var, info)) {
2005*4882a593Smuzhiyun 		printk(KERN_ERR "aty128fb: Cannot set default mode.\n");
2006*4882a593Smuzhiyun 		return 0;
2007*4882a593Smuzhiyun 	}
2008*4882a593Smuzhiyun 
2009*4882a593Smuzhiyun 	/* setup the DAC the way we like it */
2010*4882a593Smuzhiyun 	dac = aty_ld_le32(DAC_CNTL);
2011*4882a593Smuzhiyun 	dac |= (DAC_8BIT_EN | DAC_RANGE_CNTL);
2012*4882a593Smuzhiyun 	dac |= DAC_MASK;
2013*4882a593Smuzhiyun 	if (par->chip_gen == rage_M3)
2014*4882a593Smuzhiyun 		dac |= DAC_PALETTE2_SNOOP_EN;
2015*4882a593Smuzhiyun 	aty_st_le32(DAC_CNTL, dac);
2016*4882a593Smuzhiyun 
2017*4882a593Smuzhiyun 	/* turn off bus mastering, just in case */
2018*4882a593Smuzhiyun 	aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_MASTER_DIS);
2019*4882a593Smuzhiyun 
2020*4882a593Smuzhiyun 	info->var = var;
2021*4882a593Smuzhiyun 	fb_alloc_cmap(&info->cmap, 256, 0);
2022*4882a593Smuzhiyun 
2023*4882a593Smuzhiyun 	var.activate = FB_ACTIVATE_NOW;
2024*4882a593Smuzhiyun 
2025*4882a593Smuzhiyun 	aty128_init_engine(par);
2026*4882a593Smuzhiyun 
2027*4882a593Smuzhiyun 	par->pdev = pdev;
2028*4882a593Smuzhiyun 	par->asleep = 0;
2029*4882a593Smuzhiyun 	par->lock_blank = 0;
2030*4882a593Smuzhiyun 
2031*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY128_BACKLIGHT
2032*4882a593Smuzhiyun 	if (backlight)
2033*4882a593Smuzhiyun 		aty128_bl_init(par);
2034*4882a593Smuzhiyun #endif
2035*4882a593Smuzhiyun 
2036*4882a593Smuzhiyun 	if (register_framebuffer(info) < 0)
2037*4882a593Smuzhiyun 		return 0;
2038*4882a593Smuzhiyun 
2039*4882a593Smuzhiyun 	fb_info(info, "%s frame buffer device on %s\n",
2040*4882a593Smuzhiyun 		info->fix.id, video_card);
2041*4882a593Smuzhiyun 
2042*4882a593Smuzhiyun 	return 1;	/* success! */
2043*4882a593Smuzhiyun }
2044*4882a593Smuzhiyun 
2045*4882a593Smuzhiyun #ifdef CONFIG_PCI
2046*4882a593Smuzhiyun /* register a card    ++ajoshi */
aty128_probe(struct pci_dev * pdev,const struct pci_device_id * ent)2047*4882a593Smuzhiyun static int aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
2048*4882a593Smuzhiyun {
2049*4882a593Smuzhiyun 	unsigned long fb_addr, reg_addr;
2050*4882a593Smuzhiyun 	struct aty128fb_par *par;
2051*4882a593Smuzhiyun 	struct fb_info *info;
2052*4882a593Smuzhiyun 	int err;
2053*4882a593Smuzhiyun #ifndef __sparc__
2054*4882a593Smuzhiyun 	void __iomem *bios = NULL;
2055*4882a593Smuzhiyun #endif
2056*4882a593Smuzhiyun 
2057*4882a593Smuzhiyun 	/* Enable device in PCI config */
2058*4882a593Smuzhiyun 	if ((err = pci_enable_device(pdev))) {
2059*4882a593Smuzhiyun 		printk(KERN_ERR "aty128fb: Cannot enable PCI device: %d\n",
2060*4882a593Smuzhiyun 				err);
2061*4882a593Smuzhiyun 		return -ENODEV;
2062*4882a593Smuzhiyun 	}
2063*4882a593Smuzhiyun 
2064*4882a593Smuzhiyun 	fb_addr = pci_resource_start(pdev, 0);
2065*4882a593Smuzhiyun 	if (!request_mem_region(fb_addr, pci_resource_len(pdev, 0),
2066*4882a593Smuzhiyun 				"aty128fb FB")) {
2067*4882a593Smuzhiyun 		printk(KERN_ERR "aty128fb: cannot reserve frame "
2068*4882a593Smuzhiyun 				"buffer memory\n");
2069*4882a593Smuzhiyun 		return -ENODEV;
2070*4882a593Smuzhiyun 	}
2071*4882a593Smuzhiyun 
2072*4882a593Smuzhiyun 	reg_addr = pci_resource_start(pdev, 2);
2073*4882a593Smuzhiyun 	if (!request_mem_region(reg_addr, pci_resource_len(pdev, 2),
2074*4882a593Smuzhiyun 				"aty128fb MMIO")) {
2075*4882a593Smuzhiyun 		printk(KERN_ERR "aty128fb: cannot reserve MMIO region\n");
2076*4882a593Smuzhiyun 		goto err_free_fb;
2077*4882a593Smuzhiyun 	}
2078*4882a593Smuzhiyun 
2079*4882a593Smuzhiyun 	/* We have the resources. Now virtualize them */
2080*4882a593Smuzhiyun 	info = framebuffer_alloc(sizeof(struct aty128fb_par), &pdev->dev);
2081*4882a593Smuzhiyun 	if (!info)
2082*4882a593Smuzhiyun 		goto err_free_mmio;
2083*4882a593Smuzhiyun 
2084*4882a593Smuzhiyun 	par = info->par;
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun 	info->pseudo_palette = par->pseudo_palette;
2087*4882a593Smuzhiyun 
2088*4882a593Smuzhiyun 	/* Virtualize mmio region */
2089*4882a593Smuzhiyun 	info->fix.mmio_start = reg_addr;
2090*4882a593Smuzhiyun 	par->regbase = pci_ioremap_bar(pdev, 2);
2091*4882a593Smuzhiyun 	if (!par->regbase)
2092*4882a593Smuzhiyun 		goto err_free_info;
2093*4882a593Smuzhiyun 
2094*4882a593Smuzhiyun 	/* Grab memory size from the card */
2095*4882a593Smuzhiyun 	// How does this relate to the resource length from the PCI hardware?
2096*4882a593Smuzhiyun 	par->vram_size = aty_ld_le32(CNFG_MEMSIZE) & 0x03FFFFFF;
2097*4882a593Smuzhiyun 
2098*4882a593Smuzhiyun 	/* Virtualize the framebuffer */
2099*4882a593Smuzhiyun 	info->screen_base = ioremap_wc(fb_addr, par->vram_size);
2100*4882a593Smuzhiyun 	if (!info->screen_base)
2101*4882a593Smuzhiyun 		goto err_unmap_out;
2102*4882a593Smuzhiyun 
2103*4882a593Smuzhiyun 	/* Set up info->fix */
2104*4882a593Smuzhiyun 	info->fix = aty128fb_fix;
2105*4882a593Smuzhiyun 	info->fix.smem_start = fb_addr;
2106*4882a593Smuzhiyun 	info->fix.smem_len = par->vram_size;
2107*4882a593Smuzhiyun 	info->fix.mmio_start = reg_addr;
2108*4882a593Smuzhiyun 
2109*4882a593Smuzhiyun 	/* If we can't test scratch registers, something is seriously wrong */
2110*4882a593Smuzhiyun 	if (!register_test(par)) {
2111*4882a593Smuzhiyun 		printk(KERN_ERR "aty128fb: Can't write to video register!\n");
2112*4882a593Smuzhiyun 		goto err_out;
2113*4882a593Smuzhiyun 	}
2114*4882a593Smuzhiyun 
2115*4882a593Smuzhiyun #ifndef __sparc__
2116*4882a593Smuzhiyun 	bios = aty128_map_ROM(par, pdev);
2117*4882a593Smuzhiyun #ifdef CONFIG_X86
2118*4882a593Smuzhiyun 	if (bios == NULL)
2119*4882a593Smuzhiyun 		bios = aty128_find_mem_vbios(par);
2120*4882a593Smuzhiyun #endif
2121*4882a593Smuzhiyun 	if (bios == NULL)
2122*4882a593Smuzhiyun 		printk(KERN_INFO "aty128fb: BIOS not located, guessing timings.\n");
2123*4882a593Smuzhiyun 	else {
2124*4882a593Smuzhiyun 		printk(KERN_INFO "aty128fb: Rage128 BIOS located\n");
2125*4882a593Smuzhiyun 		aty128_get_pllinfo(par, bios);
2126*4882a593Smuzhiyun 		pci_unmap_rom(pdev, bios);
2127*4882a593Smuzhiyun 	}
2128*4882a593Smuzhiyun #endif /* __sparc__ */
2129*4882a593Smuzhiyun 
2130*4882a593Smuzhiyun 	aty128_timings(par);
2131*4882a593Smuzhiyun 	pci_set_drvdata(pdev, info);
2132*4882a593Smuzhiyun 
2133*4882a593Smuzhiyun 	if (!aty128_init(pdev, ent))
2134*4882a593Smuzhiyun 		goto err_out;
2135*4882a593Smuzhiyun 
2136*4882a593Smuzhiyun 	if (mtrr)
2137*4882a593Smuzhiyun 		par->wc_cookie = arch_phys_wc_add(info->fix.smem_start,
2138*4882a593Smuzhiyun 						  par->vram_size);
2139*4882a593Smuzhiyun 	return 0;
2140*4882a593Smuzhiyun 
2141*4882a593Smuzhiyun err_out:
2142*4882a593Smuzhiyun 	iounmap(info->screen_base);
2143*4882a593Smuzhiyun err_unmap_out:
2144*4882a593Smuzhiyun 	iounmap(par->regbase);
2145*4882a593Smuzhiyun err_free_info:
2146*4882a593Smuzhiyun 	framebuffer_release(info);
2147*4882a593Smuzhiyun err_free_mmio:
2148*4882a593Smuzhiyun 	release_mem_region(pci_resource_start(pdev, 2),
2149*4882a593Smuzhiyun 			pci_resource_len(pdev, 2));
2150*4882a593Smuzhiyun err_free_fb:
2151*4882a593Smuzhiyun 	release_mem_region(pci_resource_start(pdev, 0),
2152*4882a593Smuzhiyun 			pci_resource_len(pdev, 0));
2153*4882a593Smuzhiyun 	return -ENODEV;
2154*4882a593Smuzhiyun }
2155*4882a593Smuzhiyun 
aty128_remove(struct pci_dev * pdev)2156*4882a593Smuzhiyun static void aty128_remove(struct pci_dev *pdev)
2157*4882a593Smuzhiyun {
2158*4882a593Smuzhiyun 	struct fb_info *info = pci_get_drvdata(pdev);
2159*4882a593Smuzhiyun 	struct aty128fb_par *par;
2160*4882a593Smuzhiyun 
2161*4882a593Smuzhiyun 	if (!info)
2162*4882a593Smuzhiyun 		return;
2163*4882a593Smuzhiyun 
2164*4882a593Smuzhiyun 	par = info->par;
2165*4882a593Smuzhiyun 
2166*4882a593Smuzhiyun 	unregister_framebuffer(info);
2167*4882a593Smuzhiyun 
2168*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY128_BACKLIGHT
2169*4882a593Smuzhiyun 	aty128_bl_exit(info->bl_dev);
2170*4882a593Smuzhiyun #endif
2171*4882a593Smuzhiyun 
2172*4882a593Smuzhiyun 	arch_phys_wc_del(par->wc_cookie);
2173*4882a593Smuzhiyun 	iounmap(par->regbase);
2174*4882a593Smuzhiyun 	iounmap(info->screen_base);
2175*4882a593Smuzhiyun 
2176*4882a593Smuzhiyun 	release_mem_region(pci_resource_start(pdev, 0),
2177*4882a593Smuzhiyun 			   pci_resource_len(pdev, 0));
2178*4882a593Smuzhiyun 	release_mem_region(pci_resource_start(pdev, 2),
2179*4882a593Smuzhiyun 			   pci_resource_len(pdev, 2));
2180*4882a593Smuzhiyun 	framebuffer_release(info);
2181*4882a593Smuzhiyun }
2182*4882a593Smuzhiyun #endif /* CONFIG_PCI */
2183*4882a593Smuzhiyun 
2184*4882a593Smuzhiyun 
2185*4882a593Smuzhiyun 
2186*4882a593Smuzhiyun     /*
2187*4882a593Smuzhiyun      *  Blank the display.
2188*4882a593Smuzhiyun      */
aty128fb_blank(int blank,struct fb_info * fb)2189*4882a593Smuzhiyun static int aty128fb_blank(int blank, struct fb_info *fb)
2190*4882a593Smuzhiyun {
2191*4882a593Smuzhiyun 	struct aty128fb_par *par = fb->par;
2192*4882a593Smuzhiyun 	u8 state;
2193*4882a593Smuzhiyun 
2194*4882a593Smuzhiyun 	if (par->lock_blank || par->asleep)
2195*4882a593Smuzhiyun 		return 0;
2196*4882a593Smuzhiyun 
2197*4882a593Smuzhiyun 	switch (blank) {
2198*4882a593Smuzhiyun 	case FB_BLANK_NORMAL:
2199*4882a593Smuzhiyun 		state = 4;
2200*4882a593Smuzhiyun 		break;
2201*4882a593Smuzhiyun 	case FB_BLANK_VSYNC_SUSPEND:
2202*4882a593Smuzhiyun 		state = 6;
2203*4882a593Smuzhiyun 		break;
2204*4882a593Smuzhiyun 	case FB_BLANK_HSYNC_SUSPEND:
2205*4882a593Smuzhiyun 		state = 5;
2206*4882a593Smuzhiyun 		break;
2207*4882a593Smuzhiyun 	case FB_BLANK_POWERDOWN:
2208*4882a593Smuzhiyun 		state = 7;
2209*4882a593Smuzhiyun 		break;
2210*4882a593Smuzhiyun 	case FB_BLANK_UNBLANK:
2211*4882a593Smuzhiyun 	default:
2212*4882a593Smuzhiyun 		state = 0;
2213*4882a593Smuzhiyun 		break;
2214*4882a593Smuzhiyun 	}
2215*4882a593Smuzhiyun 	aty_st_8(CRTC_EXT_CNTL+1, state);
2216*4882a593Smuzhiyun 
2217*4882a593Smuzhiyun 	if (par->chip_gen == rage_M3) {
2218*4882a593Smuzhiyun 		aty128_set_crt_enable(par, par->crt_on && !blank);
2219*4882a593Smuzhiyun 		aty128_set_lcd_enable(par, par->lcd_on && !blank);
2220*4882a593Smuzhiyun 	}
2221*4882a593Smuzhiyun 
2222*4882a593Smuzhiyun 	return 0;
2223*4882a593Smuzhiyun }
2224*4882a593Smuzhiyun 
2225*4882a593Smuzhiyun /*
2226*4882a593Smuzhiyun  *  Set a single color register. The values supplied are already
2227*4882a593Smuzhiyun  *  rounded down to the hardware's capabilities (according to the
2228*4882a593Smuzhiyun  *  entries in the var structure). Return != 0 for invalid regno.
2229*4882a593Smuzhiyun  */
aty128fb_setcolreg(u_int regno,u_int red,u_int green,u_int blue,u_int transp,struct fb_info * info)2230*4882a593Smuzhiyun static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
2231*4882a593Smuzhiyun 			      u_int transp, struct fb_info *info)
2232*4882a593Smuzhiyun {
2233*4882a593Smuzhiyun 	struct aty128fb_par *par = info->par;
2234*4882a593Smuzhiyun 
2235*4882a593Smuzhiyun 	if (regno > 255
2236*4882a593Smuzhiyun 	    || (par->crtc.depth == 16 && regno > 63)
2237*4882a593Smuzhiyun 	    || (par->crtc.depth == 15 && regno > 31))
2238*4882a593Smuzhiyun 		return 1;
2239*4882a593Smuzhiyun 
2240*4882a593Smuzhiyun 	red >>= 8;
2241*4882a593Smuzhiyun 	green >>= 8;
2242*4882a593Smuzhiyun 	blue >>= 8;
2243*4882a593Smuzhiyun 
2244*4882a593Smuzhiyun 	if (regno < 16) {
2245*4882a593Smuzhiyun 		int i;
2246*4882a593Smuzhiyun 		u32 *pal = info->pseudo_palette;
2247*4882a593Smuzhiyun 
2248*4882a593Smuzhiyun 		switch (par->crtc.depth) {
2249*4882a593Smuzhiyun 		case 15:
2250*4882a593Smuzhiyun 			pal[regno] = (regno << 10) | (regno << 5) | regno;
2251*4882a593Smuzhiyun 			break;
2252*4882a593Smuzhiyun 		case 16:
2253*4882a593Smuzhiyun 			pal[regno] = (regno << 11) | (regno << 6) | regno;
2254*4882a593Smuzhiyun 			break;
2255*4882a593Smuzhiyun 		case 24:
2256*4882a593Smuzhiyun 			pal[regno] = (regno << 16) | (regno << 8) | regno;
2257*4882a593Smuzhiyun 			break;
2258*4882a593Smuzhiyun 		case 32:
2259*4882a593Smuzhiyun 			i = (regno << 8) | regno;
2260*4882a593Smuzhiyun 			pal[regno] = (i << 16) | i;
2261*4882a593Smuzhiyun 			break;
2262*4882a593Smuzhiyun 		}
2263*4882a593Smuzhiyun 	}
2264*4882a593Smuzhiyun 
2265*4882a593Smuzhiyun 	if (par->crtc.depth == 16 && regno > 0) {
2266*4882a593Smuzhiyun 		/*
2267*4882a593Smuzhiyun 		 * With the 5-6-5 split of bits for RGB at 16 bits/pixel, we
2268*4882a593Smuzhiyun 		 * have 32 slots for R and B values but 64 slots for G values.
2269*4882a593Smuzhiyun 		 * Thus the R and B values go in one slot but the G value
2270*4882a593Smuzhiyun 		 * goes in a different slot, and we have to avoid disturbing
2271*4882a593Smuzhiyun 		 * the other fields in the slots we touch.
2272*4882a593Smuzhiyun 		 */
2273*4882a593Smuzhiyun 		par->green[regno] = green;
2274*4882a593Smuzhiyun 		if (regno < 32) {
2275*4882a593Smuzhiyun 			par->red[regno] = red;
2276*4882a593Smuzhiyun 			par->blue[regno] = blue;
2277*4882a593Smuzhiyun 			aty128_st_pal(regno * 8, red, par->green[regno*2],
2278*4882a593Smuzhiyun 				      blue, par);
2279*4882a593Smuzhiyun 		}
2280*4882a593Smuzhiyun 		red = par->red[regno/2];
2281*4882a593Smuzhiyun 		blue = par->blue[regno/2];
2282*4882a593Smuzhiyun 		regno <<= 2;
2283*4882a593Smuzhiyun 	} else if (par->crtc.bpp == 16)
2284*4882a593Smuzhiyun 		regno <<= 3;
2285*4882a593Smuzhiyun 	aty128_st_pal(regno, red, green, blue, par);
2286*4882a593Smuzhiyun 
2287*4882a593Smuzhiyun 	return 0;
2288*4882a593Smuzhiyun }
2289*4882a593Smuzhiyun 
2290*4882a593Smuzhiyun #define ATY_MIRROR_LCD_ON	0x00000001
2291*4882a593Smuzhiyun #define ATY_MIRROR_CRT_ON	0x00000002
2292*4882a593Smuzhiyun 
2293*4882a593Smuzhiyun /* out param: u32*	backlight value: 0 to 15 */
2294*4882a593Smuzhiyun #define FBIO_ATY128_GET_MIRROR	_IOR('@', 1, __u32)
2295*4882a593Smuzhiyun /* in param: u32*	backlight value: 0 to 15 */
2296*4882a593Smuzhiyun #define FBIO_ATY128_SET_MIRROR	_IOW('@', 2, __u32)
2297*4882a593Smuzhiyun 
aty128fb_ioctl(struct fb_info * info,u_int cmd,u_long arg)2298*4882a593Smuzhiyun static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
2299*4882a593Smuzhiyun {
2300*4882a593Smuzhiyun 	struct aty128fb_par *par = info->par;
2301*4882a593Smuzhiyun 	u32 value;
2302*4882a593Smuzhiyun 	int rc;
2303*4882a593Smuzhiyun 
2304*4882a593Smuzhiyun 	switch (cmd) {
2305*4882a593Smuzhiyun 	case FBIO_ATY128_SET_MIRROR:
2306*4882a593Smuzhiyun 		if (par->chip_gen != rage_M3)
2307*4882a593Smuzhiyun 			return -EINVAL;
2308*4882a593Smuzhiyun 		rc = get_user(value, (__u32 __user *)arg);
2309*4882a593Smuzhiyun 		if (rc)
2310*4882a593Smuzhiyun 			return rc;
2311*4882a593Smuzhiyun 		par->lcd_on = (value & 0x01) != 0;
2312*4882a593Smuzhiyun 		par->crt_on = (value & 0x02) != 0;
2313*4882a593Smuzhiyun 		if (!par->crt_on && !par->lcd_on)
2314*4882a593Smuzhiyun 			par->lcd_on = 1;
2315*4882a593Smuzhiyun 		aty128_set_crt_enable(par, par->crt_on);
2316*4882a593Smuzhiyun 		aty128_set_lcd_enable(par, par->lcd_on);
2317*4882a593Smuzhiyun 		return 0;
2318*4882a593Smuzhiyun 	case FBIO_ATY128_GET_MIRROR:
2319*4882a593Smuzhiyun 		if (par->chip_gen != rage_M3)
2320*4882a593Smuzhiyun 			return -EINVAL;
2321*4882a593Smuzhiyun 		value = (par->crt_on << 1) | par->lcd_on;
2322*4882a593Smuzhiyun 		return put_user(value, (__u32 __user *)arg);
2323*4882a593Smuzhiyun 	}
2324*4882a593Smuzhiyun 	return -EINVAL;
2325*4882a593Smuzhiyun }
2326*4882a593Smuzhiyun 
aty128_set_suspend(struct aty128fb_par * par,int suspend)2327*4882a593Smuzhiyun static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
2328*4882a593Smuzhiyun {
2329*4882a593Smuzhiyun 	u32	pmgt;
2330*4882a593Smuzhiyun 
2331*4882a593Smuzhiyun 	if (!par->pdev->pm_cap)
2332*4882a593Smuzhiyun 		return;
2333*4882a593Smuzhiyun 
2334*4882a593Smuzhiyun 	/* Set the chip into the appropriate suspend mode (we use D2,
2335*4882a593Smuzhiyun 	 * D3 would require a complete re-initialisation of the chip,
2336*4882a593Smuzhiyun 	 * including PCI config registers, clocks, AGP configuration, ...)
2337*4882a593Smuzhiyun 	 *
2338*4882a593Smuzhiyun 	 * For resume, the core will have already brought us back to D0
2339*4882a593Smuzhiyun 	 */
2340*4882a593Smuzhiyun 	if (suspend) {
2341*4882a593Smuzhiyun 		/* Make sure CRTC2 is reset. Remove that the day we decide to
2342*4882a593Smuzhiyun 		 * actually use CRTC2 and replace it with real code for disabling
2343*4882a593Smuzhiyun 		 * the CRTC2 output during sleep
2344*4882a593Smuzhiyun 		 */
2345*4882a593Smuzhiyun 		aty_st_le32(CRTC2_GEN_CNTL, aty_ld_le32(CRTC2_GEN_CNTL) &
2346*4882a593Smuzhiyun 			~(CRTC2_EN));
2347*4882a593Smuzhiyun 
2348*4882a593Smuzhiyun 		/* Set the power management mode to be PCI based */
2349*4882a593Smuzhiyun 		/* Use this magic value for now */
2350*4882a593Smuzhiyun 		pmgt = 0x0c005407;
2351*4882a593Smuzhiyun 		aty_st_pll(POWER_MANAGEMENT, pmgt);
2352*4882a593Smuzhiyun 		(void)aty_ld_pll(POWER_MANAGEMENT);
2353*4882a593Smuzhiyun 		aty_st_le32(BUS_CNTL1, 0x00000010);
2354*4882a593Smuzhiyun 		aty_st_le32(MEM_POWER_MISC, 0x0c830000);
2355*4882a593Smuzhiyun 		msleep(100);
2356*4882a593Smuzhiyun 	}
2357*4882a593Smuzhiyun }
2358*4882a593Smuzhiyun 
aty128_pci_suspend_late(struct device * dev,pm_message_t state)2359*4882a593Smuzhiyun static int aty128_pci_suspend_late(struct device *dev, pm_message_t state)
2360*4882a593Smuzhiyun {
2361*4882a593Smuzhiyun 	struct pci_dev *pdev = to_pci_dev(dev);
2362*4882a593Smuzhiyun 	struct fb_info *info = pci_get_drvdata(pdev);
2363*4882a593Smuzhiyun 	struct aty128fb_par *par = info->par;
2364*4882a593Smuzhiyun 
2365*4882a593Smuzhiyun 	/* We don't do anything but D2, for now we return 0, but
2366*4882a593Smuzhiyun 	 * we may want to change that. How do we know if the BIOS
2367*4882a593Smuzhiyun 	 * can properly take care of D3 ? Also, with swsusp, we
2368*4882a593Smuzhiyun 	 * know we'll be rebooted, ...
2369*4882a593Smuzhiyun 	 */
2370*4882a593Smuzhiyun #ifndef CONFIG_PPC_PMAC
2371*4882a593Smuzhiyun 	/* HACK ALERT ! Once I find a proper way to say to each driver
2372*4882a593Smuzhiyun 	 * individually what will happen with it's PCI slot, I'll change
2373*4882a593Smuzhiyun 	 * that. On laptops, the AGP slot is just unclocked, so D2 is
2374*4882a593Smuzhiyun 	 * expected, while on desktops, the card is powered off
2375*4882a593Smuzhiyun 	 */
2376*4882a593Smuzhiyun 	return 0;
2377*4882a593Smuzhiyun #endif /* CONFIG_PPC_PMAC */
2378*4882a593Smuzhiyun 
2379*4882a593Smuzhiyun 	if (state.event == pdev->dev.power.power_state.event)
2380*4882a593Smuzhiyun 		return 0;
2381*4882a593Smuzhiyun 
2382*4882a593Smuzhiyun 	printk(KERN_DEBUG "aty128fb: suspending...\n");
2383*4882a593Smuzhiyun 
2384*4882a593Smuzhiyun 	console_lock();
2385*4882a593Smuzhiyun 
2386*4882a593Smuzhiyun 	fb_set_suspend(info, 1);
2387*4882a593Smuzhiyun 
2388*4882a593Smuzhiyun 	/* Make sure engine is reset */
2389*4882a593Smuzhiyun 	wait_for_idle(par);
2390*4882a593Smuzhiyun 	aty128_reset_engine(par);
2391*4882a593Smuzhiyun 	wait_for_idle(par);
2392*4882a593Smuzhiyun 
2393*4882a593Smuzhiyun 	/* Blank display and LCD */
2394*4882a593Smuzhiyun 	aty128fb_blank(FB_BLANK_POWERDOWN, info);
2395*4882a593Smuzhiyun 
2396*4882a593Smuzhiyun 	/* Sleep */
2397*4882a593Smuzhiyun 	par->asleep = 1;
2398*4882a593Smuzhiyun 	par->lock_blank = 1;
2399*4882a593Smuzhiyun 
2400*4882a593Smuzhiyun #ifdef CONFIG_PPC_PMAC
2401*4882a593Smuzhiyun 	/* On powermac, we have hooks to properly suspend/resume AGP now,
2402*4882a593Smuzhiyun 	 * use them here. We'll ultimately need some generic support here,
2403*4882a593Smuzhiyun 	 * but the generic code isn't quite ready for that yet
2404*4882a593Smuzhiyun 	 */
2405*4882a593Smuzhiyun 	pmac_suspend_agp_for_card(pdev);
2406*4882a593Smuzhiyun #endif /* CONFIG_PPC_PMAC */
2407*4882a593Smuzhiyun 
2408*4882a593Smuzhiyun 	/* We need a way to make sure the fbdev layer will _not_ touch the
2409*4882a593Smuzhiyun 	 * framebuffer before we put the chip to suspend state. On 2.4, I
2410*4882a593Smuzhiyun 	 * used dummy fb ops, 2.5 need proper support for this at the
2411*4882a593Smuzhiyun 	 * fbdev level
2412*4882a593Smuzhiyun 	 */
2413*4882a593Smuzhiyun 	if (state.event != PM_EVENT_ON)
2414*4882a593Smuzhiyun 		aty128_set_suspend(par, 1);
2415*4882a593Smuzhiyun 
2416*4882a593Smuzhiyun 	console_unlock();
2417*4882a593Smuzhiyun 
2418*4882a593Smuzhiyun 	pdev->dev.power.power_state = state;
2419*4882a593Smuzhiyun 
2420*4882a593Smuzhiyun 	return 0;
2421*4882a593Smuzhiyun }
2422*4882a593Smuzhiyun 
aty128_pci_suspend(struct device * dev)2423*4882a593Smuzhiyun static int __maybe_unused aty128_pci_suspend(struct device *dev)
2424*4882a593Smuzhiyun {
2425*4882a593Smuzhiyun 	return aty128_pci_suspend_late(dev, PMSG_SUSPEND);
2426*4882a593Smuzhiyun }
2427*4882a593Smuzhiyun 
aty128_pci_hibernate(struct device * dev)2428*4882a593Smuzhiyun static int __maybe_unused aty128_pci_hibernate(struct device *dev)
2429*4882a593Smuzhiyun {
2430*4882a593Smuzhiyun 	return aty128_pci_suspend_late(dev, PMSG_HIBERNATE);
2431*4882a593Smuzhiyun }
2432*4882a593Smuzhiyun 
aty128_pci_freeze(struct device * dev)2433*4882a593Smuzhiyun static int __maybe_unused aty128_pci_freeze(struct device *dev)
2434*4882a593Smuzhiyun {
2435*4882a593Smuzhiyun 	return aty128_pci_suspend_late(dev, PMSG_FREEZE);
2436*4882a593Smuzhiyun }
2437*4882a593Smuzhiyun 
aty128_do_resume(struct pci_dev * pdev)2438*4882a593Smuzhiyun static int aty128_do_resume(struct pci_dev *pdev)
2439*4882a593Smuzhiyun {
2440*4882a593Smuzhiyun 	struct fb_info *info = pci_get_drvdata(pdev);
2441*4882a593Smuzhiyun 	struct aty128fb_par *par = info->par;
2442*4882a593Smuzhiyun 
2443*4882a593Smuzhiyun 	if (pdev->dev.power.power_state.event == PM_EVENT_ON)
2444*4882a593Smuzhiyun 		return 0;
2445*4882a593Smuzhiyun 
2446*4882a593Smuzhiyun 	/* PCI state will have been restored by the core, so
2447*4882a593Smuzhiyun 	 * we should be in D0 now with our config space fully
2448*4882a593Smuzhiyun 	 * restored
2449*4882a593Smuzhiyun 	 */
2450*4882a593Smuzhiyun 
2451*4882a593Smuzhiyun 	/* Wakeup chip */
2452*4882a593Smuzhiyun 	aty128_set_suspend(par, 0);
2453*4882a593Smuzhiyun 	par->asleep = 0;
2454*4882a593Smuzhiyun 
2455*4882a593Smuzhiyun 	/* Restore display & engine */
2456*4882a593Smuzhiyun 	aty128_reset_engine(par);
2457*4882a593Smuzhiyun 	wait_for_idle(par);
2458*4882a593Smuzhiyun 	aty128fb_set_par(info);
2459*4882a593Smuzhiyun 	fb_pan_display(info, &info->var);
2460*4882a593Smuzhiyun 	fb_set_cmap(&info->cmap, info);
2461*4882a593Smuzhiyun 
2462*4882a593Smuzhiyun 	/* Refresh */
2463*4882a593Smuzhiyun 	fb_set_suspend(info, 0);
2464*4882a593Smuzhiyun 
2465*4882a593Smuzhiyun 	/* Unblank */
2466*4882a593Smuzhiyun 	par->lock_blank = 0;
2467*4882a593Smuzhiyun 	aty128fb_blank(0, info);
2468*4882a593Smuzhiyun 
2469*4882a593Smuzhiyun #ifdef CONFIG_PPC_PMAC
2470*4882a593Smuzhiyun 	/* On powermac, we have hooks to properly suspend/resume AGP now,
2471*4882a593Smuzhiyun 	 * use them here. We'll ultimately need some generic support here,
2472*4882a593Smuzhiyun 	 * but the generic code isn't quite ready for that yet
2473*4882a593Smuzhiyun 	 */
2474*4882a593Smuzhiyun 	pmac_resume_agp_for_card(pdev);
2475*4882a593Smuzhiyun #endif /* CONFIG_PPC_PMAC */
2476*4882a593Smuzhiyun 
2477*4882a593Smuzhiyun 	pdev->dev.power.power_state = PMSG_ON;
2478*4882a593Smuzhiyun 
2479*4882a593Smuzhiyun 	printk(KERN_DEBUG "aty128fb: resumed !\n");
2480*4882a593Smuzhiyun 
2481*4882a593Smuzhiyun 	return 0;
2482*4882a593Smuzhiyun }
2483*4882a593Smuzhiyun 
aty128_pci_resume(struct device * dev)2484*4882a593Smuzhiyun static int __maybe_unused aty128_pci_resume(struct device *dev)
2485*4882a593Smuzhiyun {
2486*4882a593Smuzhiyun 	int rc;
2487*4882a593Smuzhiyun 
2488*4882a593Smuzhiyun 	console_lock();
2489*4882a593Smuzhiyun 	rc = aty128_do_resume(to_pci_dev(dev));
2490*4882a593Smuzhiyun 	console_unlock();
2491*4882a593Smuzhiyun 
2492*4882a593Smuzhiyun 	return rc;
2493*4882a593Smuzhiyun }
2494*4882a593Smuzhiyun 
2495*4882a593Smuzhiyun 
aty128fb_init(void)2496*4882a593Smuzhiyun static int aty128fb_init(void)
2497*4882a593Smuzhiyun {
2498*4882a593Smuzhiyun #ifndef MODULE
2499*4882a593Smuzhiyun 	char *option = NULL;
2500*4882a593Smuzhiyun 
2501*4882a593Smuzhiyun 	if (fb_get_options("aty128fb", &option))
2502*4882a593Smuzhiyun 		return -ENODEV;
2503*4882a593Smuzhiyun 	aty128fb_setup(option);
2504*4882a593Smuzhiyun #endif
2505*4882a593Smuzhiyun 
2506*4882a593Smuzhiyun 	return pci_register_driver(&aty128fb_driver);
2507*4882a593Smuzhiyun }
2508*4882a593Smuzhiyun 
aty128fb_exit(void)2509*4882a593Smuzhiyun static void __exit aty128fb_exit(void)
2510*4882a593Smuzhiyun {
2511*4882a593Smuzhiyun 	pci_unregister_driver(&aty128fb_driver);
2512*4882a593Smuzhiyun }
2513*4882a593Smuzhiyun 
2514*4882a593Smuzhiyun module_init(aty128fb_init);
2515*4882a593Smuzhiyun 
2516*4882a593Smuzhiyun module_exit(aty128fb_exit);
2517*4882a593Smuzhiyun 
2518*4882a593Smuzhiyun MODULE_AUTHOR("(c)1999-2003 Brad Douglas <brad@neruo.com>");
2519*4882a593Smuzhiyun MODULE_DESCRIPTION("FBDev driver for ATI Rage128 / Pro cards");
2520*4882a593Smuzhiyun MODULE_LICENSE("GPL");
2521*4882a593Smuzhiyun module_param(mode_option, charp, 0);
2522*4882a593Smuzhiyun MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
2523*4882a593Smuzhiyun module_param_named(nomtrr, mtrr, invbool, 0);
2524*4882a593Smuzhiyun MODULE_PARM_DESC(nomtrr, "bool: Disable MTRR support (0 or 1=disabled) (default=0)");
2525