1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * ATI Frame Buffer Device Driver Core
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2004 Alex Kern <alex.kern@gmx.de>
5*4882a593Smuzhiyun * Copyright (C) 1997-2001 Geert Uytterhoeven
6*4882a593Smuzhiyun * Copyright (C) 1998 Bernd Harries
7*4882a593Smuzhiyun * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This driver supports the following ATI graphics chips:
10*4882a593Smuzhiyun * - ATI Mach64
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * To do: add support for
13*4882a593Smuzhiyun * - ATI Rage128 (from aty128fb.c)
14*4882a593Smuzhiyun * - ATI Radeon (from radeonfb.c)
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * This driver is partly based on the PowerMac console driver:
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * Copyright (C) 1996 Paul Mackerras
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * and on the PowerMac ATI/mach64 display driver:
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * Copyright (C) 1997 Michael AK Tesch
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * with work by Jon Howell
25*4882a593Smuzhiyun * Harry AC Eaton
26*4882a593Smuzhiyun * Anthony Tong <atong@uiuc.edu>
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun * Generic LCD support written by Daniel Mantione, ported from 2.4.20 by Alex Kern
29*4882a593Smuzhiyun * Many Thanks to Ville Syrjälä for patches and fixing nasting 16 bit color bug.
30*4882a593Smuzhiyun *
31*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
32*4882a593Smuzhiyun * License. See the file COPYING in the main directory of this archive for
33*4882a593Smuzhiyun * more details.
34*4882a593Smuzhiyun *
35*4882a593Smuzhiyun * Many thanks to Nitya from ATI devrel for support and patience !
36*4882a593Smuzhiyun */
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /******************************************************************************
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun TODO:
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun - cursor support on all cards and all ramdacs.
43*4882a593Smuzhiyun - cursor parameters controlable via ioctl()s.
44*4882a593Smuzhiyun - guess PLL and MCLK based on the original PLL register values initialized
45*4882a593Smuzhiyun by Open Firmware (if they are initialized). BIOS is done
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun (Anyone with Mac to help with this?)
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun ******************************************************************************/
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun #include <linux/compat.h>
52*4882a593Smuzhiyun #include <linux/module.h>
53*4882a593Smuzhiyun #include <linux/moduleparam.h>
54*4882a593Smuzhiyun #include <linux/kernel.h>
55*4882a593Smuzhiyun #include <linux/errno.h>
56*4882a593Smuzhiyun #include <linux/string.h>
57*4882a593Smuzhiyun #include <linux/mm.h>
58*4882a593Smuzhiyun #include <linux/slab.h>
59*4882a593Smuzhiyun #include <linux/vmalloc.h>
60*4882a593Smuzhiyun #include <linux/delay.h>
61*4882a593Smuzhiyun #include <linux/compiler.h>
62*4882a593Smuzhiyun #include <linux/console.h>
63*4882a593Smuzhiyun #include <linux/fb.h>
64*4882a593Smuzhiyun #include <linux/init.h>
65*4882a593Smuzhiyun #include <linux/pci.h>
66*4882a593Smuzhiyun #include <linux/interrupt.h>
67*4882a593Smuzhiyun #include <linux/spinlock.h>
68*4882a593Smuzhiyun #include <linux/wait.h>
69*4882a593Smuzhiyun #include <linux/backlight.h>
70*4882a593Smuzhiyun #include <linux/reboot.h>
71*4882a593Smuzhiyun #include <linux/dmi.h>
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun #include <asm/io.h>
74*4882a593Smuzhiyun #include <linux/uaccess.h>
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun #include <video/mach64.h>
77*4882a593Smuzhiyun #include "atyfb.h"
78*4882a593Smuzhiyun #include "ati_ids.h"
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun #ifdef __powerpc__
81*4882a593Smuzhiyun #include <asm/machdep.h>
82*4882a593Smuzhiyun #include <asm/prom.h>
83*4882a593Smuzhiyun #include "../macmodes.h"
84*4882a593Smuzhiyun #endif
85*4882a593Smuzhiyun #ifdef __sparc__
86*4882a593Smuzhiyun #include <asm/fbio.h>
87*4882a593Smuzhiyun #include <asm/oplib.h>
88*4882a593Smuzhiyun #include <asm/prom.h>
89*4882a593Smuzhiyun #endif
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun #ifdef CONFIG_ADB_PMU
92*4882a593Smuzhiyun #include <linux/adb.h>
93*4882a593Smuzhiyun #include <linux/pmu.h>
94*4882a593Smuzhiyun #endif
95*4882a593Smuzhiyun #ifdef CONFIG_BOOTX_TEXT
96*4882a593Smuzhiyun #include <asm/btext.h>
97*4882a593Smuzhiyun #endif
98*4882a593Smuzhiyun #ifdef CONFIG_PMAC_BACKLIGHT
99*4882a593Smuzhiyun #include <asm/backlight.h>
100*4882a593Smuzhiyun #endif
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun /*
103*4882a593Smuzhiyun * Debug flags.
104*4882a593Smuzhiyun */
105*4882a593Smuzhiyun #undef DEBUG
106*4882a593Smuzhiyun /*#define DEBUG*/
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun /* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */
109*4882a593Smuzhiyun /* - must be large enough to catch all GUI-Regs */
110*4882a593Smuzhiyun /* - must be aligned to a PAGE boundary */
111*4882a593Smuzhiyun #define GUI_RESERVE (1 * PAGE_SIZE)
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun /* FIXME: remove the FAIL definition */
114*4882a593Smuzhiyun #define FAIL(msg) do { \
115*4882a593Smuzhiyun if (!(var->activate & FB_ACTIVATE_TEST)) \
116*4882a593Smuzhiyun printk(KERN_CRIT "atyfb: " msg "\n"); \
117*4882a593Smuzhiyun return -EINVAL; \
118*4882a593Smuzhiyun } while (0)
119*4882a593Smuzhiyun #define FAIL_MAX(msg, x, _max_) do { \
120*4882a593Smuzhiyun if (x > _max_) { \
121*4882a593Smuzhiyun if (!(var->activate & FB_ACTIVATE_TEST)) \
122*4882a593Smuzhiyun printk(KERN_CRIT "atyfb: " msg " %x(%x)\n", x, _max_); \
123*4882a593Smuzhiyun return -EINVAL; \
124*4882a593Smuzhiyun } \
125*4882a593Smuzhiyun } while (0)
126*4882a593Smuzhiyun #ifdef DEBUG
127*4882a593Smuzhiyun #define DPRINTK(fmt, args...) printk(KERN_DEBUG "atyfb: " fmt, ## args)
128*4882a593Smuzhiyun #else
129*4882a593Smuzhiyun #define DPRINTK(fmt, args...) no_printk(fmt, ##args)
130*4882a593Smuzhiyun #endif
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun #define PRINTKI(fmt, args...) printk(KERN_INFO "atyfb: " fmt, ## args)
133*4882a593Smuzhiyun #define PRINTKE(fmt, args...) printk(KERN_ERR "atyfb: " fmt, ## args)
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun #if defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_GENERIC_LCD) || \
136*4882a593Smuzhiyun defined(CONFIG_FB_ATY_BACKLIGHT)
137*4882a593Smuzhiyun static const u32 lt_lcd_regs[] = {
138*4882a593Smuzhiyun CNFG_PANEL_LG,
139*4882a593Smuzhiyun LCD_GEN_CNTL_LG,
140*4882a593Smuzhiyun DSTN_CONTROL_LG,
141*4882a593Smuzhiyun HFB_PITCH_ADDR_LG,
142*4882a593Smuzhiyun HORZ_STRETCHING_LG,
143*4882a593Smuzhiyun VERT_STRETCHING_LG,
144*4882a593Smuzhiyun 0, /* EXT_VERT_STRETCH */
145*4882a593Smuzhiyun LT_GIO_LG,
146*4882a593Smuzhiyun POWER_MANAGEMENT_LG
147*4882a593Smuzhiyun };
148*4882a593Smuzhiyun
aty_st_lcd(int index,u32 val,const struct atyfb_par * par)149*4882a593Smuzhiyun void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun if (M64_HAS(LT_LCD_REGS)) {
152*4882a593Smuzhiyun aty_st_le32(lt_lcd_regs[index], val, par);
153*4882a593Smuzhiyun } else {
154*4882a593Smuzhiyun unsigned long temp;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /* write addr byte */
157*4882a593Smuzhiyun temp = aty_ld_le32(LCD_INDEX, par);
158*4882a593Smuzhiyun aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
159*4882a593Smuzhiyun /* write the register value */
160*4882a593Smuzhiyun aty_st_le32(LCD_DATA, val, par);
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
aty_ld_lcd(int index,const struct atyfb_par * par)164*4882a593Smuzhiyun u32 aty_ld_lcd(int index, const struct atyfb_par *par)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun if (M64_HAS(LT_LCD_REGS)) {
167*4882a593Smuzhiyun return aty_ld_le32(lt_lcd_regs[index], par);
168*4882a593Smuzhiyun } else {
169*4882a593Smuzhiyun unsigned long temp;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* write addr byte */
172*4882a593Smuzhiyun temp = aty_ld_le32(LCD_INDEX, par);
173*4882a593Smuzhiyun aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
174*4882a593Smuzhiyun /* read the register value */
175*4882a593Smuzhiyun return aty_ld_le32(LCD_DATA, par);
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun #endif /* defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) */
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
181*4882a593Smuzhiyun /*
182*4882a593Smuzhiyun * ATIReduceRatio --
183*4882a593Smuzhiyun *
184*4882a593Smuzhiyun * Reduce a fraction by factoring out the largest common divider of the
185*4882a593Smuzhiyun * fraction's numerator and denominator.
186*4882a593Smuzhiyun */
ATIReduceRatio(int * Numerator,int * Denominator)187*4882a593Smuzhiyun static void ATIReduceRatio(int *Numerator, int *Denominator)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun int Multiplier, Divider, Remainder;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun Multiplier = *Numerator;
192*4882a593Smuzhiyun Divider = *Denominator;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun while ((Remainder = Multiplier % Divider)) {
195*4882a593Smuzhiyun Multiplier = Divider;
196*4882a593Smuzhiyun Divider = Remainder;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun *Numerator /= Divider;
200*4882a593Smuzhiyun *Denominator /= Divider;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun #endif
203*4882a593Smuzhiyun /*
204*4882a593Smuzhiyun * The Hardware parameters for each card
205*4882a593Smuzhiyun */
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun struct pci_mmap_map {
208*4882a593Smuzhiyun unsigned long voff;
209*4882a593Smuzhiyun unsigned long poff;
210*4882a593Smuzhiyun unsigned long size;
211*4882a593Smuzhiyun unsigned long prot_flag;
212*4882a593Smuzhiyun unsigned long prot_mask;
213*4882a593Smuzhiyun };
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun static const struct fb_fix_screeninfo atyfb_fix = {
216*4882a593Smuzhiyun .id = "ATY Mach64",
217*4882a593Smuzhiyun .type = FB_TYPE_PACKED_PIXELS,
218*4882a593Smuzhiyun .visual = FB_VISUAL_PSEUDOCOLOR,
219*4882a593Smuzhiyun .xpanstep = 8,
220*4882a593Smuzhiyun .ypanstep = 1,
221*4882a593Smuzhiyun };
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /*
224*4882a593Smuzhiyun * Frame buffer device API
225*4882a593Smuzhiyun */
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun static int atyfb_open(struct fb_info *info, int user);
228*4882a593Smuzhiyun static int atyfb_release(struct fb_info *info, int user);
229*4882a593Smuzhiyun static int atyfb_check_var(struct fb_var_screeninfo *var,
230*4882a593Smuzhiyun struct fb_info *info);
231*4882a593Smuzhiyun static int atyfb_set_par(struct fb_info *info);
232*4882a593Smuzhiyun static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
233*4882a593Smuzhiyun u_int transp, struct fb_info *info);
234*4882a593Smuzhiyun static int atyfb_pan_display(struct fb_var_screeninfo *var,
235*4882a593Smuzhiyun struct fb_info *info);
236*4882a593Smuzhiyun static int atyfb_blank(int blank, struct fb_info *info);
237*4882a593Smuzhiyun static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
238*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
atyfb_compat_ioctl(struct fb_info * info,u_int cmd,u_long arg)239*4882a593Smuzhiyun static int atyfb_compat_ioctl(struct fb_info *info, u_int cmd, u_long arg)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun return atyfb_ioctl(info, cmd, (u_long)compat_ptr(arg));
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun #endif
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun #ifdef __sparc__
246*4882a593Smuzhiyun static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma);
247*4882a593Smuzhiyun #endif
248*4882a593Smuzhiyun static int atyfb_sync(struct fb_info *info);
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /*
251*4882a593Smuzhiyun * Internal routines
252*4882a593Smuzhiyun */
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun static int aty_init(struct fb_info *info);
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc);
259*4882a593Smuzhiyun static int aty_var_to_crtc(const struct fb_info *info,
260*4882a593Smuzhiyun const struct fb_var_screeninfo *var,
261*4882a593Smuzhiyun struct crtc *crtc);
262*4882a593Smuzhiyun static int aty_crtc_to_var(const struct crtc *crtc,
263*4882a593Smuzhiyun struct fb_var_screeninfo *var);
264*4882a593Smuzhiyun static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info);
265*4882a593Smuzhiyun #ifdef CONFIG_PPC
266*4882a593Smuzhiyun static int read_aty_sense(const struct atyfb_par *par);
267*4882a593Smuzhiyun #endif
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun static DEFINE_MUTEX(reboot_lock);
270*4882a593Smuzhiyun static struct fb_info *reboot_info;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun /*
273*4882a593Smuzhiyun * Interface used by the world
274*4882a593Smuzhiyun */
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun static struct fb_var_screeninfo default_var = {
277*4882a593Smuzhiyun /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
278*4882a593Smuzhiyun 640, 480, 640, 480, 0, 0, 8, 0,
279*4882a593Smuzhiyun {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
280*4882a593Smuzhiyun 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
281*4882a593Smuzhiyun 0, FB_VMODE_NONINTERLACED
282*4882a593Smuzhiyun };
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun static const struct fb_videomode defmode = {
285*4882a593Smuzhiyun /* 640x480 @ 60 Hz, 31.5 kHz hsync */
286*4882a593Smuzhiyun NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
287*4882a593Smuzhiyun 0, FB_VMODE_NONINTERLACED
288*4882a593Smuzhiyun };
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun static struct fb_ops atyfb_ops = {
291*4882a593Smuzhiyun .owner = THIS_MODULE,
292*4882a593Smuzhiyun .fb_open = atyfb_open,
293*4882a593Smuzhiyun .fb_release = atyfb_release,
294*4882a593Smuzhiyun .fb_check_var = atyfb_check_var,
295*4882a593Smuzhiyun .fb_set_par = atyfb_set_par,
296*4882a593Smuzhiyun .fb_setcolreg = atyfb_setcolreg,
297*4882a593Smuzhiyun .fb_pan_display = atyfb_pan_display,
298*4882a593Smuzhiyun .fb_blank = atyfb_blank,
299*4882a593Smuzhiyun .fb_ioctl = atyfb_ioctl,
300*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
301*4882a593Smuzhiyun .fb_compat_ioctl = atyfb_compat_ioctl,
302*4882a593Smuzhiyun #endif
303*4882a593Smuzhiyun .fb_fillrect = atyfb_fillrect,
304*4882a593Smuzhiyun .fb_copyarea = atyfb_copyarea,
305*4882a593Smuzhiyun .fb_imageblit = atyfb_imageblit,
306*4882a593Smuzhiyun #ifdef __sparc__
307*4882a593Smuzhiyun .fb_mmap = atyfb_mmap,
308*4882a593Smuzhiyun #endif
309*4882a593Smuzhiyun .fb_sync = atyfb_sync,
310*4882a593Smuzhiyun };
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun static bool noaccel;
313*4882a593Smuzhiyun static bool nomtrr;
314*4882a593Smuzhiyun static int vram;
315*4882a593Smuzhiyun static int pll;
316*4882a593Smuzhiyun static int mclk;
317*4882a593Smuzhiyun static int xclk;
318*4882a593Smuzhiyun static int comp_sync = -1;
319*4882a593Smuzhiyun static char *mode;
320*4882a593Smuzhiyun static int backlight = IS_BUILTIN(CONFIG_PMAC_BACKLIGHT);
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun #ifdef CONFIG_PPC
323*4882a593Smuzhiyun static int default_vmode = VMODE_CHOOSE;
324*4882a593Smuzhiyun static int default_cmode = CMODE_CHOOSE;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun module_param_named(vmode, default_vmode, int, 0);
327*4882a593Smuzhiyun MODULE_PARM_DESC(vmode, "int: video mode for mac");
328*4882a593Smuzhiyun module_param_named(cmode, default_cmode, int, 0);
329*4882a593Smuzhiyun MODULE_PARM_DESC(cmode, "int: color mode for mac");
330*4882a593Smuzhiyun #endif
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun #ifdef CONFIG_ATARI
333*4882a593Smuzhiyun static unsigned int mach64_count = 0;
334*4882a593Smuzhiyun static unsigned long phys_vmembase[FB_MAX] = { 0, };
335*4882a593Smuzhiyun static unsigned long phys_size[FB_MAX] = { 0, };
336*4882a593Smuzhiyun static unsigned long phys_guiregbase[FB_MAX] = { 0, };
337*4882a593Smuzhiyun #endif
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun /* top -> down is an evolution of mach64 chipset, any corrections? */
340*4882a593Smuzhiyun #define ATI_CHIP_88800GX (M64F_GX)
341*4882a593Smuzhiyun #define ATI_CHIP_88800CX (M64F_GX)
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun #define ATI_CHIP_264CT (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO)
344*4882a593Smuzhiyun #define ATI_CHIP_264ET (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO)
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun #define ATI_CHIP_264VT (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO)
347*4882a593Smuzhiyun #define ATI_CHIP_264GT (M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO | M64F_EXTRA_BRIGHT)
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun #define ATI_CHIP_264VTB (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP)
350*4882a593Smuzhiyun #define ATI_CHIP_264VT3 (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL)
351*4882a593Smuzhiyun #define ATI_CHIP_264VT4 (M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP)
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun /* FIXME what is this chip? */
354*4882a593Smuzhiyun #define ATI_CHIP_264LT (M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP)
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* make sets shorter */
357*4882a593Smuzhiyun #define ATI_MODERN_SET (M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_EXTRA_BRIGHT)
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun #define ATI_CHIP_264GTB (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL)
360*4882a593Smuzhiyun /*#define ATI_CHIP_264GTDVD ?*/
361*4882a593Smuzhiyun #define ATI_CHIP_264LTG (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL)
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun #define ATI_CHIP_264GT2C (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE)
364*4882a593Smuzhiyun #define ATI_CHIP_264GTPRO (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
365*4882a593Smuzhiyun #define ATI_CHIP_264LTPRO (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun #define ATI_CHIP_264XL (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM)
368*4882a593Smuzhiyun #define ATI_CHIP_MOBILITY (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_XL_MEM | M64F_MOBIL_BUS)
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun static struct {
371*4882a593Smuzhiyun u16 pci_id;
372*4882a593Smuzhiyun const char *name;
373*4882a593Smuzhiyun int pll, mclk, xclk, ecp_max;
374*4882a593Smuzhiyun u32 features;
375*4882a593Smuzhiyun } aty_chips[] = {
376*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GX
377*4882a593Smuzhiyun /* Mach64 GX */
378*4882a593Smuzhiyun { PCI_CHIP_MACH64GX, "ATI888GX00 (Mach64 GX)", 135, 50, 50, 0, ATI_CHIP_88800GX },
379*4882a593Smuzhiyun { PCI_CHIP_MACH64CX, "ATI888CX00 (Mach64 CX)", 135, 50, 50, 0, ATI_CHIP_88800CX },
380*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_GX */
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_CT
383*4882a593Smuzhiyun { PCI_CHIP_MACH64CT, "ATI264CT (Mach64 CT)", 135, 60, 60, 0, ATI_CHIP_264CT },
384*4882a593Smuzhiyun { PCI_CHIP_MACH64ET, "ATI264ET (Mach64 ET)", 135, 60, 60, 0, ATI_CHIP_264ET },
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun /* FIXME what is this chip? */
387*4882a593Smuzhiyun { PCI_CHIP_MACH64LT, "ATI264LT (Mach64 LT)", 135, 63, 63, 0, ATI_CHIP_264LT },
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun { PCI_CHIP_MACH64VT, "ATI264VT (Mach64 VT)", 170, 67, 67, 80, ATI_CHIP_264VT },
390*4882a593Smuzhiyun { PCI_CHIP_MACH64GT, "3D RAGE (Mach64 GT)", 135, 63, 63, 80, ATI_CHIP_264GT },
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun { PCI_CHIP_MACH64VU, "ATI264VT3 (Mach64 VU)", 200, 67, 67, 80, ATI_CHIP_264VT3 },
393*4882a593Smuzhiyun { PCI_CHIP_MACH64GU, "3D RAGE II+ (Mach64 GU)", 200, 67, 67, 100, ATI_CHIP_264GTB },
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun { PCI_CHIP_MACH64LG, "3D RAGE LT (Mach64 LG)", 230, 63, 63, 100, ATI_CHIP_264LTG | M64F_LT_LCD_REGS | M64F_G3_PB_1024x768 },
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun { PCI_CHIP_MACH64VV, "ATI264VT4 (Mach64 VV)", 230, 83, 83, 100, ATI_CHIP_264VT4 },
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun { PCI_CHIP_MACH64GV, "3D RAGE IIC (Mach64 GV, PCI)", 230, 83, 83, 100, ATI_CHIP_264GT2C },
400*4882a593Smuzhiyun { PCI_CHIP_MACH64GW, "3D RAGE IIC (Mach64 GW, AGP)", 230, 83, 83, 100, ATI_CHIP_264GT2C },
401*4882a593Smuzhiyun { PCI_CHIP_MACH64GY, "3D RAGE IIC (Mach64 GY, PCI)", 230, 83, 83, 100, ATI_CHIP_264GT2C },
402*4882a593Smuzhiyun { PCI_CHIP_MACH64GZ, "3D RAGE IIC (Mach64 GZ, AGP)", 230, 83, 83, 100, ATI_CHIP_264GT2C },
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun { PCI_CHIP_MACH64GB, "3D RAGE PRO (Mach64 GB, BGA, AGP)", 230, 100, 100, 125, ATI_CHIP_264GTPRO },
405*4882a593Smuzhiyun { PCI_CHIP_MACH64GD, "3D RAGE PRO (Mach64 GD, BGA, AGP 1x)", 230, 100, 100, 125, ATI_CHIP_264GTPRO },
406*4882a593Smuzhiyun { PCI_CHIP_MACH64GI, "3D RAGE PRO (Mach64 GI, BGA, PCI)", 230, 100, 100, 125, ATI_CHIP_264GTPRO | M64F_MAGIC_VRAM_SIZE },
407*4882a593Smuzhiyun { PCI_CHIP_MACH64GP, "3D RAGE PRO (Mach64 GP, PQFP, PCI)", 230, 100, 100, 125, ATI_CHIP_264GTPRO },
408*4882a593Smuzhiyun { PCI_CHIP_MACH64GQ, "3D RAGE PRO (Mach64 GQ, PQFP, PCI, limited 3D)", 230, 100, 100, 125, ATI_CHIP_264GTPRO },
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun { PCI_CHIP_MACH64LB, "3D RAGE LT PRO (Mach64 LB, AGP)", 236, 75, 100, 135, ATI_CHIP_264LTPRO },
411*4882a593Smuzhiyun { PCI_CHIP_MACH64LD, "3D RAGE LT PRO (Mach64 LD, AGP)", 230, 100, 100, 135, ATI_CHIP_264LTPRO },
412*4882a593Smuzhiyun { PCI_CHIP_MACH64LI, "3D RAGE LT PRO (Mach64 LI, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 },
413*4882a593Smuzhiyun { PCI_CHIP_MACH64LP, "3D RAGE LT PRO (Mach64 LP, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO | M64F_G3_PB_1024x768 },
414*4882a593Smuzhiyun { PCI_CHIP_MACH64LQ, "3D RAGE LT PRO (Mach64 LQ, PCI)", 230, 100, 100, 135, ATI_CHIP_264LTPRO },
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun { PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP 2x)", 230, 83, 63, 135, ATI_CHIP_264XL },
417*4882a593Smuzhiyun { PCI_CHIP_MACH64GN, "3D RAGE XC (Mach64 GN, AGP 2x)", 230, 83, 63, 135, ATI_CHIP_264XL },
418*4882a593Smuzhiyun { PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66)", 230, 83, 63, 135, ATI_CHIP_264XL },
419*4882a593Smuzhiyun { PCI_CHIP_MACH64GL, "3D RAGE XC (Mach64 GL, PCI-66)", 230, 83, 63, 135, ATI_CHIP_264XL },
420*4882a593Smuzhiyun { PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33)", 230, 83, 63, 135, ATI_CHIP_264XL | M64F_SDRAM_MAGIC_PLL },
421*4882a593Smuzhiyun { PCI_CHIP_MACH64GS, "3D RAGE XC (Mach64 GS, PCI-33)", 230, 83, 63, 135, ATI_CHIP_264XL },
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun { PCI_CHIP_MACH64LM, "3D RAGE Mobility P/M (Mach64 LM, AGP 2x)", 230, 83, 125, 135, ATI_CHIP_MOBILITY },
424*4882a593Smuzhiyun { PCI_CHIP_MACH64LN, "3D RAGE Mobility L (Mach64 LN, AGP 2x)", 230, 83, 125, 135, ATI_CHIP_MOBILITY },
425*4882a593Smuzhiyun { PCI_CHIP_MACH64LR, "3D RAGE Mobility P/M (Mach64 LR, PCI)", 230, 83, 125, 135, ATI_CHIP_MOBILITY },
426*4882a593Smuzhiyun { PCI_CHIP_MACH64LS, "3D RAGE Mobility L (Mach64 LS, PCI)", 230, 83, 125, 135, ATI_CHIP_MOBILITY },
427*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_CT */
428*4882a593Smuzhiyun };
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun /*
431*4882a593Smuzhiyun * Last page of 8 MB (4 MB on ISA) aperture is MMIO,
432*4882a593Smuzhiyun * unless the auxiliary register aperture is used.
433*4882a593Smuzhiyun */
aty_fudge_framebuffer_len(struct fb_info * info)434*4882a593Smuzhiyun static void aty_fudge_framebuffer_len(struct fb_info *info)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun if (!par->aux_start &&
439*4882a593Smuzhiyun (info->fix.smem_len == 0x800000 ||
440*4882a593Smuzhiyun (par->bus_type == ISA && info->fix.smem_len == 0x400000)))
441*4882a593Smuzhiyun info->fix.smem_len -= GUI_RESERVE;
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
correct_chipset(struct atyfb_par * par)444*4882a593Smuzhiyun static int correct_chipset(struct atyfb_par *par)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun u8 rev;
447*4882a593Smuzhiyun u16 type;
448*4882a593Smuzhiyun u32 chip_id;
449*4882a593Smuzhiyun const char *name;
450*4882a593Smuzhiyun int i;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun for (i = (int)ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)
453*4882a593Smuzhiyun if (par->pci_id == aty_chips[i].pci_id)
454*4882a593Smuzhiyun break;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun if (i < 0)
457*4882a593Smuzhiyun return -ENODEV;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun name = aty_chips[i].name;
460*4882a593Smuzhiyun par->pll_limits.pll_max = aty_chips[i].pll;
461*4882a593Smuzhiyun par->pll_limits.mclk = aty_chips[i].mclk;
462*4882a593Smuzhiyun par->pll_limits.xclk = aty_chips[i].xclk;
463*4882a593Smuzhiyun par->pll_limits.ecp_max = aty_chips[i].ecp_max;
464*4882a593Smuzhiyun par->features = aty_chips[i].features;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun chip_id = aty_ld_le32(CNFG_CHIP_ID, par);
467*4882a593Smuzhiyun type = chip_id & CFG_CHIP_TYPE;
468*4882a593Smuzhiyun rev = (chip_id & CFG_CHIP_REV) >> 24;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun switch (par->pci_id) {
471*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GX
472*4882a593Smuzhiyun case PCI_CHIP_MACH64GX:
473*4882a593Smuzhiyun if (type != 0x00d7)
474*4882a593Smuzhiyun return -ENODEV;
475*4882a593Smuzhiyun break;
476*4882a593Smuzhiyun case PCI_CHIP_MACH64CX:
477*4882a593Smuzhiyun if (type != 0x0057)
478*4882a593Smuzhiyun return -ENODEV;
479*4882a593Smuzhiyun break;
480*4882a593Smuzhiyun #endif
481*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_CT
482*4882a593Smuzhiyun case PCI_CHIP_MACH64VT:
483*4882a593Smuzhiyun switch (rev & 0x07) {
484*4882a593Smuzhiyun case 0x00:
485*4882a593Smuzhiyun switch (rev & 0xc0) {
486*4882a593Smuzhiyun case 0x00:
487*4882a593Smuzhiyun name = "ATI264VT (A3) (Mach64 VT)";
488*4882a593Smuzhiyun par->pll_limits.pll_max = 170;
489*4882a593Smuzhiyun par->pll_limits.mclk = 67;
490*4882a593Smuzhiyun par->pll_limits.xclk = 67;
491*4882a593Smuzhiyun par->pll_limits.ecp_max = 80;
492*4882a593Smuzhiyun par->features = ATI_CHIP_264VT;
493*4882a593Smuzhiyun break;
494*4882a593Smuzhiyun case 0x40:
495*4882a593Smuzhiyun name = "ATI264VT2 (A4) (Mach64 VT)";
496*4882a593Smuzhiyun par->pll_limits.pll_max = 200;
497*4882a593Smuzhiyun par->pll_limits.mclk = 67;
498*4882a593Smuzhiyun par->pll_limits.xclk = 67;
499*4882a593Smuzhiyun par->pll_limits.ecp_max = 80;
500*4882a593Smuzhiyun par->features = ATI_CHIP_264VT | M64F_MAGIC_POSTDIV;
501*4882a593Smuzhiyun break;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun break;
504*4882a593Smuzhiyun case 0x01:
505*4882a593Smuzhiyun name = "ATI264VT3 (B1) (Mach64 VT)";
506*4882a593Smuzhiyun par->pll_limits.pll_max = 200;
507*4882a593Smuzhiyun par->pll_limits.mclk = 67;
508*4882a593Smuzhiyun par->pll_limits.xclk = 67;
509*4882a593Smuzhiyun par->pll_limits.ecp_max = 80;
510*4882a593Smuzhiyun par->features = ATI_CHIP_264VTB;
511*4882a593Smuzhiyun break;
512*4882a593Smuzhiyun case 0x02:
513*4882a593Smuzhiyun name = "ATI264VT3 (B2) (Mach64 VT)";
514*4882a593Smuzhiyun par->pll_limits.pll_max = 200;
515*4882a593Smuzhiyun par->pll_limits.mclk = 67;
516*4882a593Smuzhiyun par->pll_limits.xclk = 67;
517*4882a593Smuzhiyun par->pll_limits.ecp_max = 80;
518*4882a593Smuzhiyun par->features = ATI_CHIP_264VT3;
519*4882a593Smuzhiyun break;
520*4882a593Smuzhiyun }
521*4882a593Smuzhiyun break;
522*4882a593Smuzhiyun case PCI_CHIP_MACH64GT:
523*4882a593Smuzhiyun switch (rev & 0x07) {
524*4882a593Smuzhiyun case 0x01:
525*4882a593Smuzhiyun name = "3D RAGE II (Mach64 GT)";
526*4882a593Smuzhiyun par->pll_limits.pll_max = 170;
527*4882a593Smuzhiyun par->pll_limits.mclk = 67;
528*4882a593Smuzhiyun par->pll_limits.xclk = 67;
529*4882a593Smuzhiyun par->pll_limits.ecp_max = 80;
530*4882a593Smuzhiyun par->features = ATI_CHIP_264GTB;
531*4882a593Smuzhiyun break;
532*4882a593Smuzhiyun case 0x02:
533*4882a593Smuzhiyun name = "3D RAGE II+ (Mach64 GT)";
534*4882a593Smuzhiyun par->pll_limits.pll_max = 200;
535*4882a593Smuzhiyun par->pll_limits.mclk = 67;
536*4882a593Smuzhiyun par->pll_limits.xclk = 67;
537*4882a593Smuzhiyun par->pll_limits.ecp_max = 100;
538*4882a593Smuzhiyun par->features = ATI_CHIP_264GTB;
539*4882a593Smuzhiyun break;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun break;
542*4882a593Smuzhiyun #endif
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun PRINTKI("%s [0x%04x rev 0x%02x]\n", name, type, rev);
546*4882a593Smuzhiyun return 0;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun static char ram_dram[] __maybe_unused = "DRAM";
550*4882a593Smuzhiyun static char ram_resv[] __maybe_unused = "RESV";
551*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GX
552*4882a593Smuzhiyun static char ram_vram[] = "VRAM";
553*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_GX */
554*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_CT
555*4882a593Smuzhiyun static char ram_edo[] = "EDO";
556*4882a593Smuzhiyun static char ram_sdram[] = "SDRAM (1:1)";
557*4882a593Smuzhiyun static char ram_sgram[] = "SGRAM (1:1)";
558*4882a593Smuzhiyun static char ram_sdram32[] = "SDRAM (2:1) (32-bit)";
559*4882a593Smuzhiyun static char ram_wram[] = "WRAM";
560*4882a593Smuzhiyun static char ram_off[] = "OFF";
561*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_CT */
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GX
565*4882a593Smuzhiyun static char *aty_gx_ram[8] = {
566*4882a593Smuzhiyun ram_dram, ram_vram, ram_vram, ram_dram,
567*4882a593Smuzhiyun ram_dram, ram_vram, ram_vram, ram_resv
568*4882a593Smuzhiyun };
569*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_GX */
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_CT
572*4882a593Smuzhiyun static char *aty_ct_ram[8] = {
573*4882a593Smuzhiyun ram_off, ram_dram, ram_edo, ram_edo,
574*4882a593Smuzhiyun ram_sdram, ram_sgram, ram_wram, ram_resv
575*4882a593Smuzhiyun };
576*4882a593Smuzhiyun static char *aty_xl_ram[8] = {
577*4882a593Smuzhiyun ram_off, ram_dram, ram_edo, ram_edo,
578*4882a593Smuzhiyun ram_sdram, ram_sgram, ram_sdram32, ram_resv
579*4882a593Smuzhiyun };
580*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_CT */
581*4882a593Smuzhiyun
atyfb_get_pixclock(struct fb_var_screeninfo * var,struct atyfb_par * par)582*4882a593Smuzhiyun static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var,
583*4882a593Smuzhiyun struct atyfb_par *par)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun u32 pixclock = var->pixclock;
586*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
587*4882a593Smuzhiyun u32 lcd_on_off;
588*4882a593Smuzhiyun par->pll.ct.xres = 0;
589*4882a593Smuzhiyun if (par->lcd_table != 0) {
590*4882a593Smuzhiyun lcd_on_off = aty_ld_lcd(LCD_GEN_CNTL, par);
591*4882a593Smuzhiyun if (lcd_on_off & LCD_ON) {
592*4882a593Smuzhiyun par->pll.ct.xres = var->xres;
593*4882a593Smuzhiyun pixclock = par->lcd_pixclock;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun #endif
597*4882a593Smuzhiyun return pixclock;
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun #if defined(CONFIG_PPC)
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun /*
603*4882a593Smuzhiyun * Apple monitor sense
604*4882a593Smuzhiyun */
605*4882a593Smuzhiyun
read_aty_sense(const struct atyfb_par * par)606*4882a593Smuzhiyun static int read_aty_sense(const struct atyfb_par *par)
607*4882a593Smuzhiyun {
608*4882a593Smuzhiyun int sense, i;
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun aty_st_le32(GP_IO, 0x31003100, par); /* drive outputs high */
611*4882a593Smuzhiyun __delay(200);
612*4882a593Smuzhiyun aty_st_le32(GP_IO, 0, par); /* turn off outputs */
613*4882a593Smuzhiyun __delay(2000);
614*4882a593Smuzhiyun i = aty_ld_le32(GP_IO, par); /* get primary sense value */
615*4882a593Smuzhiyun sense = ((i & 0x3000) >> 3) | (i & 0x100);
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /* drive each sense line low in turn and collect the other 2 */
618*4882a593Smuzhiyun aty_st_le32(GP_IO, 0x20000000, par); /* drive A low */
619*4882a593Smuzhiyun __delay(2000);
620*4882a593Smuzhiyun i = aty_ld_le32(GP_IO, par);
621*4882a593Smuzhiyun sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);
622*4882a593Smuzhiyun aty_st_le32(GP_IO, 0x20002000, par); /* drive A high again */
623*4882a593Smuzhiyun __delay(200);
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun aty_st_le32(GP_IO, 0x10000000, par); /* drive B low */
626*4882a593Smuzhiyun __delay(2000);
627*4882a593Smuzhiyun i = aty_ld_le32(GP_IO, par);
628*4882a593Smuzhiyun sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);
629*4882a593Smuzhiyun aty_st_le32(GP_IO, 0x10001000, par); /* drive B high again */
630*4882a593Smuzhiyun __delay(200);
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun aty_st_le32(GP_IO, 0x01000000, par); /* drive C low */
633*4882a593Smuzhiyun __delay(2000);
634*4882a593Smuzhiyun sense |= (aty_ld_le32(GP_IO, par) & 0x3000) >> 12;
635*4882a593Smuzhiyun aty_st_le32(GP_IO, 0, par); /* turn off outputs */
636*4882a593Smuzhiyun return sense;
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun #endif /* defined(CONFIG_PPC) */
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun /*
644*4882a593Smuzhiyun * CRTC programming
645*4882a593Smuzhiyun */
646*4882a593Smuzhiyun
aty_get_crtc(const struct atyfb_par * par,struct crtc * crtc)647*4882a593Smuzhiyun static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc)
648*4882a593Smuzhiyun {
649*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
650*4882a593Smuzhiyun if (par->lcd_table != 0) {
651*4882a593Smuzhiyun if (!M64_HAS(LT_LCD_REGS)) {
652*4882a593Smuzhiyun crtc->lcd_index = aty_ld_le32(LCD_INDEX, par);
653*4882a593Smuzhiyun aty_st_le32(LCD_INDEX, crtc->lcd_index, par);
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun crtc->lcd_config_panel = aty_ld_lcd(CNFG_PANEL, par);
656*4882a593Smuzhiyun crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par);
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun /* switch to non shadow registers */
660*4882a593Smuzhiyun aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl &
661*4882a593Smuzhiyun ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par);
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun /* save stretching */
664*4882a593Smuzhiyun crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par);
665*4882a593Smuzhiyun crtc->vert_stretching = aty_ld_lcd(VERT_STRETCHING, par);
666*4882a593Smuzhiyun if (!M64_HAS(LT_LCD_REGS))
667*4882a593Smuzhiyun crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par);
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun #endif
670*4882a593Smuzhiyun crtc->h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
671*4882a593Smuzhiyun crtc->h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
672*4882a593Smuzhiyun crtc->v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
673*4882a593Smuzhiyun crtc->v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);
674*4882a593Smuzhiyun crtc->vline_crnt_vline = aty_ld_le32(CRTC_VLINE_CRNT_VLINE, par);
675*4882a593Smuzhiyun crtc->off_pitch = aty_ld_le32(CRTC_OFF_PITCH, par);
676*4882a593Smuzhiyun crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
679*4882a593Smuzhiyun if (par->lcd_table != 0) {
680*4882a593Smuzhiyun /* switch to shadow registers */
681*4882a593Smuzhiyun aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) |
682*4882a593Smuzhiyun SHADOW_EN | SHADOW_RW_EN, par);
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun crtc->shadow_h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
685*4882a593Smuzhiyun crtc->shadow_h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
686*4882a593Smuzhiyun crtc->shadow_v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
687*4882a593Smuzhiyun crtc->shadow_v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun aty_st_le32(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_GENERIC_LCD */
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun
aty_set_crtc(const struct atyfb_par * par,const struct crtc * crtc)694*4882a593Smuzhiyun static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc)
695*4882a593Smuzhiyun {
696*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
697*4882a593Smuzhiyun if (par->lcd_table != 0) {
698*4882a593Smuzhiyun /* stop CRTC */
699*4882a593Smuzhiyun aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl &
700*4882a593Smuzhiyun ~(CRTC_EXT_DISP_EN | CRTC_EN), par);
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun /* update non-shadow registers first */
703*4882a593Smuzhiyun aty_st_lcd(CNFG_PANEL, crtc->lcd_config_panel, par);
704*4882a593Smuzhiyun aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl &
705*4882a593Smuzhiyun ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par);
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun /* temporarily disable stretching */
708*4882a593Smuzhiyun aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching &
709*4882a593Smuzhiyun ~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN), par);
710*4882a593Smuzhiyun aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching &
711*4882a593Smuzhiyun ~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 |
712*4882a593Smuzhiyun VERT_STRETCH_USE0 | VERT_STRETCH_EN), par);
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun #endif
715*4882a593Smuzhiyun /* turn off CRT */
716*4882a593Smuzhiyun aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~CRTC_EN, par);
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun DPRINTK("setting up CRTC\n");
719*4882a593Smuzhiyun DPRINTK("set primary CRT to %ix%i %c%c composite %c\n",
720*4882a593Smuzhiyun ((((crtc->h_tot_disp >> 16) & 0xff) + 1) << 3),
721*4882a593Smuzhiyun (((crtc->v_tot_disp >> 16) & 0x7ff) + 1),
722*4882a593Smuzhiyun (crtc->h_sync_strt_wid & 0x200000) ? 'N' : 'P',
723*4882a593Smuzhiyun (crtc->v_sync_strt_wid & 0x200000) ? 'N' : 'P',
724*4882a593Smuzhiyun (crtc->gen_cntl & CRTC_CSYNC_EN) ? 'P' : 'N');
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun DPRINTK("CRTC_H_TOTAL_DISP: %x\n", crtc->h_tot_disp);
727*4882a593Smuzhiyun DPRINTK("CRTC_H_SYNC_STRT_WID: %x\n", crtc->h_sync_strt_wid);
728*4882a593Smuzhiyun DPRINTK("CRTC_V_TOTAL_DISP: %x\n", crtc->v_tot_disp);
729*4882a593Smuzhiyun DPRINTK("CRTC_V_SYNC_STRT_WID: %x\n", crtc->v_sync_strt_wid);
730*4882a593Smuzhiyun DPRINTK("CRTC_OFF_PITCH: %x\n", crtc->off_pitch);
731*4882a593Smuzhiyun DPRINTK("CRTC_VLINE_CRNT_VLINE: %x\n", crtc->vline_crnt_vline);
732*4882a593Smuzhiyun DPRINTK("CRTC_GEN_CNTL: %x\n", crtc->gen_cntl);
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, par);
735*4882a593Smuzhiyun aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, par);
736*4882a593Smuzhiyun aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, par);
737*4882a593Smuzhiyun aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, par);
738*4882a593Smuzhiyun aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, par);
739*4882a593Smuzhiyun aty_st_le32(CRTC_VLINE_CRNT_VLINE, crtc->vline_crnt_vline, par);
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, par);
742*4882a593Smuzhiyun #if 0
743*4882a593Smuzhiyun FIXME
744*4882a593Smuzhiyun if (par->accel_flags & FB_ACCELF_TEXT)
745*4882a593Smuzhiyun aty_init_engine(par, info);
746*4882a593Smuzhiyun #endif
747*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
748*4882a593Smuzhiyun /* after setting the CRTC registers we should set the LCD registers. */
749*4882a593Smuzhiyun if (par->lcd_table != 0) {
750*4882a593Smuzhiyun /* switch to shadow registers */
751*4882a593Smuzhiyun aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) |
752*4882a593Smuzhiyun SHADOW_EN | SHADOW_RW_EN, par);
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun DPRINTK("set shadow CRT to %ix%i %c%c\n",
755*4882a593Smuzhiyun ((((crtc->shadow_h_tot_disp >> 16) & 0xff) + 1) << 3),
756*4882a593Smuzhiyun (((crtc->shadow_v_tot_disp >> 16) & 0x7ff) + 1),
757*4882a593Smuzhiyun (crtc->shadow_h_sync_strt_wid & 0x200000) ? 'N' : 'P',
758*4882a593Smuzhiyun (crtc->shadow_v_sync_strt_wid & 0x200000) ? 'N' : 'P');
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun DPRINTK("SHADOW CRTC_H_TOTAL_DISP: %x\n",
761*4882a593Smuzhiyun crtc->shadow_h_tot_disp);
762*4882a593Smuzhiyun DPRINTK("SHADOW CRTC_H_SYNC_STRT_WID: %x\n",
763*4882a593Smuzhiyun crtc->shadow_h_sync_strt_wid);
764*4882a593Smuzhiyun DPRINTK("SHADOW CRTC_V_TOTAL_DISP: %x\n",
765*4882a593Smuzhiyun crtc->shadow_v_tot_disp);
766*4882a593Smuzhiyun DPRINTK("SHADOW CRTC_V_SYNC_STRT_WID: %x\n",
767*4882a593Smuzhiyun crtc->shadow_v_sync_strt_wid);
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun aty_st_le32(CRTC_H_TOTAL_DISP, crtc->shadow_h_tot_disp, par);
770*4882a593Smuzhiyun aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->shadow_h_sync_strt_wid, par);
771*4882a593Smuzhiyun aty_st_le32(CRTC_V_TOTAL_DISP, crtc->shadow_v_tot_disp, par);
772*4882a593Smuzhiyun aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->shadow_v_sync_strt_wid, par);
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun /* restore CRTC selection & shadow state and enable stretching */
775*4882a593Smuzhiyun DPRINTK("LCD_GEN_CNTL: %x\n", crtc->lcd_gen_cntl);
776*4882a593Smuzhiyun DPRINTK("HORZ_STRETCHING: %x\n", crtc->horz_stretching);
777*4882a593Smuzhiyun DPRINTK("VERT_STRETCHING: %x\n", crtc->vert_stretching);
778*4882a593Smuzhiyun if (!M64_HAS(LT_LCD_REGS))
779*4882a593Smuzhiyun DPRINTK("EXT_VERT_STRETCH: %x\n", crtc->ext_vert_stretch);
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);
782*4882a593Smuzhiyun aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching, par);
783*4882a593Smuzhiyun aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching, par);
784*4882a593Smuzhiyun if (!M64_HAS(LT_LCD_REGS)) {
785*4882a593Smuzhiyun aty_st_lcd(EXT_VERT_STRETCH, crtc->ext_vert_stretch, par);
786*4882a593Smuzhiyun aty_ld_le32(LCD_INDEX, par);
787*4882a593Smuzhiyun aty_st_le32(LCD_INDEX, crtc->lcd_index, par);
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_GENERIC_LCD */
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun
calc_line_length(struct atyfb_par * par,u32 vxres,u32 bpp)793*4882a593Smuzhiyun static u32 calc_line_length(struct atyfb_par *par, u32 vxres, u32 bpp)
794*4882a593Smuzhiyun {
795*4882a593Smuzhiyun u32 line_length = vxres * bpp / 8;
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun if (par->ram_type == SGRAM ||
798*4882a593Smuzhiyun (!M64_HAS(XL_MEM) && par->ram_type == WRAM))
799*4882a593Smuzhiyun line_length = (line_length + 63) & ~63;
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun return line_length;
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun
aty_var_to_crtc(const struct fb_info * info,const struct fb_var_screeninfo * var,struct crtc * crtc)804*4882a593Smuzhiyun static int aty_var_to_crtc(const struct fb_info *info,
805*4882a593Smuzhiyun const struct fb_var_screeninfo *var,
806*4882a593Smuzhiyun struct crtc *crtc)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
809*4882a593Smuzhiyun u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
810*4882a593Smuzhiyun u32 sync, vmode;
811*4882a593Smuzhiyun u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol;
812*4882a593Smuzhiyun u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync;
813*4882a593Smuzhiyun u32 pix_width, dp_pix_width, dp_chain_mask;
814*4882a593Smuzhiyun u32 line_length;
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun /* input */
817*4882a593Smuzhiyun xres = (var->xres + 7) & ~7;
818*4882a593Smuzhiyun yres = var->yres;
819*4882a593Smuzhiyun vxres = (var->xres_virtual + 7) & ~7;
820*4882a593Smuzhiyun vyres = var->yres_virtual;
821*4882a593Smuzhiyun xoffset = (var->xoffset + 7) & ~7;
822*4882a593Smuzhiyun yoffset = var->yoffset;
823*4882a593Smuzhiyun bpp = var->bits_per_pixel;
824*4882a593Smuzhiyun if (bpp == 16)
825*4882a593Smuzhiyun bpp = (var->green.length == 5) ? 15 : 16;
826*4882a593Smuzhiyun sync = var->sync;
827*4882a593Smuzhiyun vmode = var->vmode;
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun /* convert (and round up) and validate */
830*4882a593Smuzhiyun if (vxres < xres + xoffset)
831*4882a593Smuzhiyun vxres = xres + xoffset;
832*4882a593Smuzhiyun h_disp = xres;
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun if (vyres < yres + yoffset)
835*4882a593Smuzhiyun vyres = yres + yoffset;
836*4882a593Smuzhiyun v_disp = yres;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun if (bpp <= 8) {
839*4882a593Smuzhiyun bpp = 8;
840*4882a593Smuzhiyun pix_width = CRTC_PIX_WIDTH_8BPP;
841*4882a593Smuzhiyun dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP |
842*4882a593Smuzhiyun BYTE_ORDER_LSB_TO_MSB;
843*4882a593Smuzhiyun dp_chain_mask = DP_CHAIN_8BPP;
844*4882a593Smuzhiyun } else if (bpp <= 15) {
845*4882a593Smuzhiyun bpp = 16;
846*4882a593Smuzhiyun pix_width = CRTC_PIX_WIDTH_15BPP;
847*4882a593Smuzhiyun dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |
848*4882a593Smuzhiyun BYTE_ORDER_LSB_TO_MSB;
849*4882a593Smuzhiyun dp_chain_mask = DP_CHAIN_15BPP;
850*4882a593Smuzhiyun } else if (bpp <= 16) {
851*4882a593Smuzhiyun bpp = 16;
852*4882a593Smuzhiyun pix_width = CRTC_PIX_WIDTH_16BPP;
853*4882a593Smuzhiyun dp_pix_width = HOST_16BPP | SRC_16BPP | DST_16BPP |
854*4882a593Smuzhiyun BYTE_ORDER_LSB_TO_MSB;
855*4882a593Smuzhiyun dp_chain_mask = DP_CHAIN_16BPP;
856*4882a593Smuzhiyun } else if (bpp <= 24 && M64_HAS(INTEGRATED)) {
857*4882a593Smuzhiyun bpp = 24;
858*4882a593Smuzhiyun pix_width = CRTC_PIX_WIDTH_24BPP;
859*4882a593Smuzhiyun dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP |
860*4882a593Smuzhiyun BYTE_ORDER_LSB_TO_MSB;
861*4882a593Smuzhiyun dp_chain_mask = DP_CHAIN_24BPP;
862*4882a593Smuzhiyun } else if (bpp <= 32) {
863*4882a593Smuzhiyun bpp = 32;
864*4882a593Smuzhiyun pix_width = CRTC_PIX_WIDTH_32BPP;
865*4882a593Smuzhiyun dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP |
866*4882a593Smuzhiyun BYTE_ORDER_LSB_TO_MSB;
867*4882a593Smuzhiyun dp_chain_mask = DP_CHAIN_32BPP;
868*4882a593Smuzhiyun } else
869*4882a593Smuzhiyun FAIL("invalid bpp");
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun line_length = calc_line_length(par, vxres, bpp);
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun if (vyres * line_length > info->fix.smem_len)
874*4882a593Smuzhiyun FAIL("not enough video RAM");
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
877*4882a593Smuzhiyun v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun if ((xres > 1920) || (yres > 1200)) {
880*4882a593Smuzhiyun FAIL("MACH64 chips are designed for max 1920x1200\n"
881*4882a593Smuzhiyun "select another resolution.");
882*4882a593Smuzhiyun }
883*4882a593Smuzhiyun h_sync_strt = h_disp + var->right_margin;
884*4882a593Smuzhiyun h_sync_end = h_sync_strt + var->hsync_len;
885*4882a593Smuzhiyun h_sync_dly = var->right_margin & 7;
886*4882a593Smuzhiyun h_total = h_sync_end + h_sync_dly + var->left_margin;
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun v_sync_strt = v_disp + var->lower_margin;
889*4882a593Smuzhiyun v_sync_end = v_sync_strt + var->vsync_len;
890*4882a593Smuzhiyun v_total = v_sync_end + var->upper_margin;
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
893*4882a593Smuzhiyun if (par->lcd_table != 0) {
894*4882a593Smuzhiyun if (!M64_HAS(LT_LCD_REGS)) {
895*4882a593Smuzhiyun u32 lcd_index = aty_ld_le32(LCD_INDEX, par);
896*4882a593Smuzhiyun crtc->lcd_index = lcd_index &
897*4882a593Smuzhiyun ~(LCD_INDEX_MASK | LCD_DISPLAY_DIS |
898*4882a593Smuzhiyun LCD_SRC_SEL | CRTC2_DISPLAY_DIS);
899*4882a593Smuzhiyun aty_st_le32(LCD_INDEX, lcd_index, par);
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun if (!M64_HAS(MOBIL_BUS))
903*4882a593Smuzhiyun crtc->lcd_index |= CRTC2_DISPLAY_DIS;
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun crtc->lcd_config_panel = aty_ld_lcd(CNFG_PANEL, par) | 0x4000;
906*4882a593Smuzhiyun crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par) & ~CRTC_RW_SELECT;
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun crtc->lcd_gen_cntl &=
909*4882a593Smuzhiyun ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | TVCLK_PM_EN |
910*4882a593Smuzhiyun /*VCLK_DAC_PM_EN | USE_SHADOWED_VEND |*/
911*4882a593Smuzhiyun USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN);
912*4882a593Smuzhiyun crtc->lcd_gen_cntl |= DONT_SHADOW_VPAR | LOCK_8DOT;
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun if ((crtc->lcd_gen_cntl & LCD_ON) &&
915*4882a593Smuzhiyun ((xres > par->lcd_width) || (yres > par->lcd_height))) {
916*4882a593Smuzhiyun /*
917*4882a593Smuzhiyun * We cannot display the mode on the LCD. If the CRT is
918*4882a593Smuzhiyun * enabled we can turn off the LCD.
919*4882a593Smuzhiyun * If the CRT is off, it isn't a good idea to switch it
920*4882a593Smuzhiyun * on; we don't know if one is connected. So it's better
921*4882a593Smuzhiyun * to fail then.
922*4882a593Smuzhiyun */
923*4882a593Smuzhiyun if (crtc->lcd_gen_cntl & CRT_ON) {
924*4882a593Smuzhiyun if (!(var->activate & FB_ACTIVATE_TEST))
925*4882a593Smuzhiyun PRINTKI("Disable LCD panel, because video mode does not fit.\n");
926*4882a593Smuzhiyun crtc->lcd_gen_cntl &= ~LCD_ON;
927*4882a593Smuzhiyun /*aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);*/
928*4882a593Smuzhiyun } else {
929*4882a593Smuzhiyun if (!(var->activate & FB_ACTIVATE_TEST))
930*4882a593Smuzhiyun PRINTKE("Video mode exceeds size of LCD panel.\nConnect this computer to a conventional monitor if you really need this mode.\n");
931*4882a593Smuzhiyun return -EINVAL;
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun }
934*4882a593Smuzhiyun }
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON)) {
937*4882a593Smuzhiyun int VScan = 1;
938*4882a593Smuzhiyun /* bpp -> bytespp, 1,4 -> 0; 8 -> 2; 15,16 -> 1; 24 -> 6; 32 -> 5
939*4882a593Smuzhiyun const u8 DFP_h_sync_dly_LT[] = { 0, 2, 1, 6, 5 };
940*4882a593Smuzhiyun const u8 ADD_to_strt_wid_and_dly_LT_DAC[] = { 0, 5, 6, 9, 9, 12, 12 }; */
941*4882a593Smuzhiyun
942*4882a593Smuzhiyun vmode &= ~(FB_VMODE_DOUBLE | FB_VMODE_INTERLACED);
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun /*
945*4882a593Smuzhiyun * This is horror! When we simulate, say 640x480 on an 800x600
946*4882a593Smuzhiyun * LCD monitor, the CRTC should be programmed 800x600 values for
947*4882a593Smuzhiyun * the non visible part, but 640x480 for the visible part.
948*4882a593Smuzhiyun * This code has been tested on a laptop with it's 1400x1050 LCD
949*4882a593Smuzhiyun * monitor and a conventional monitor both switched on.
950*4882a593Smuzhiyun * Tested modes: 1280x1024, 1152x864, 1024x768, 800x600,
951*4882a593Smuzhiyun * works with little glitches also with DOUBLESCAN modes
952*4882a593Smuzhiyun */
953*4882a593Smuzhiyun if (yres < par->lcd_height) {
954*4882a593Smuzhiyun VScan = par->lcd_height / yres;
955*4882a593Smuzhiyun if (VScan > 1) {
956*4882a593Smuzhiyun VScan = 2;
957*4882a593Smuzhiyun vmode |= FB_VMODE_DOUBLE;
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun
961*4882a593Smuzhiyun h_sync_strt = h_disp + par->lcd_right_margin;
962*4882a593Smuzhiyun h_sync_end = h_sync_strt + par->lcd_hsync_len;
963*4882a593Smuzhiyun h_sync_dly = /*DFP_h_sync_dly[ ( bpp + 1 ) / 3 ]; */par->lcd_hsync_dly;
964*4882a593Smuzhiyun h_total = h_disp + par->lcd_hblank_len;
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun v_sync_strt = v_disp + par->lcd_lower_margin / VScan;
967*4882a593Smuzhiyun v_sync_end = v_sync_strt + par->lcd_vsync_len / VScan;
968*4882a593Smuzhiyun v_total = v_disp + par->lcd_vblank_len / VScan;
969*4882a593Smuzhiyun }
970*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_GENERIC_LCD */
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun h_disp = (h_disp >> 3) - 1;
973*4882a593Smuzhiyun h_sync_strt = (h_sync_strt >> 3) - 1;
974*4882a593Smuzhiyun h_sync_end = (h_sync_end >> 3) - 1;
975*4882a593Smuzhiyun h_total = (h_total >> 3) - 1;
976*4882a593Smuzhiyun h_sync_wid = h_sync_end - h_sync_strt;
977*4882a593Smuzhiyun
978*4882a593Smuzhiyun FAIL_MAX("h_disp too large", h_disp, 0xff);
979*4882a593Smuzhiyun FAIL_MAX("h_sync_strt too large", h_sync_strt, 0x1ff);
980*4882a593Smuzhiyun /*FAIL_MAX("h_sync_wid too large", h_sync_wid, 0x1f);*/
981*4882a593Smuzhiyun if (h_sync_wid > 0x1f)
982*4882a593Smuzhiyun h_sync_wid = 0x1f;
983*4882a593Smuzhiyun FAIL_MAX("h_total too large", h_total, 0x1ff);
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun if (vmode & FB_VMODE_DOUBLE) {
986*4882a593Smuzhiyun v_disp <<= 1;
987*4882a593Smuzhiyun v_sync_strt <<= 1;
988*4882a593Smuzhiyun v_sync_end <<= 1;
989*4882a593Smuzhiyun v_total <<= 1;
990*4882a593Smuzhiyun }
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun v_disp--;
993*4882a593Smuzhiyun v_sync_strt--;
994*4882a593Smuzhiyun v_sync_end--;
995*4882a593Smuzhiyun v_total--;
996*4882a593Smuzhiyun v_sync_wid = v_sync_end - v_sync_strt;
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun FAIL_MAX("v_disp too large", v_disp, 0x7ff);
999*4882a593Smuzhiyun FAIL_MAX("v_sync_stsrt too large", v_sync_strt, 0x7ff);
1000*4882a593Smuzhiyun /*FAIL_MAX("v_sync_wid too large", v_sync_wid, 0x1f);*/
1001*4882a593Smuzhiyun if (v_sync_wid > 0x1f)
1002*4882a593Smuzhiyun v_sync_wid = 0x1f;
1003*4882a593Smuzhiyun FAIL_MAX("v_total too large", v_total, 0x7ff);
1004*4882a593Smuzhiyun
1005*4882a593Smuzhiyun c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0;
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun /* output */
1008*4882a593Smuzhiyun crtc->vxres = vxres;
1009*4882a593Smuzhiyun crtc->vyres = vyres;
1010*4882a593Smuzhiyun crtc->xoffset = xoffset;
1011*4882a593Smuzhiyun crtc->yoffset = yoffset;
1012*4882a593Smuzhiyun crtc->bpp = bpp;
1013*4882a593Smuzhiyun crtc->off_pitch =
1014*4882a593Smuzhiyun ((yoffset * line_length + xoffset * bpp / 8) / 8) |
1015*4882a593Smuzhiyun ((line_length / bpp) << 22);
1016*4882a593Smuzhiyun crtc->vline_crnt_vline = 0;
1017*4882a593Smuzhiyun
1018*4882a593Smuzhiyun crtc->h_tot_disp = h_total | (h_disp << 16);
1019*4882a593Smuzhiyun crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly << 8) |
1020*4882a593Smuzhiyun ((h_sync_strt & 0x100) << 4) | (h_sync_wid << 16) |
1021*4882a593Smuzhiyun (h_sync_pol << 21);
1022*4882a593Smuzhiyun crtc->v_tot_disp = v_total | (v_disp << 16);
1023*4882a593Smuzhiyun crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid << 16) |
1024*4882a593Smuzhiyun (v_sync_pol << 21);
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun /* crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_PRESERVED_MASK; */
1027*4882a593Smuzhiyun crtc->gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | pix_width | c_sync;
1028*4882a593Smuzhiyun crtc->gen_cntl |= CRTC_VGA_LINEAR;
1029*4882a593Smuzhiyun
1030*4882a593Smuzhiyun /* Enable doublescan mode if requested */
1031*4882a593Smuzhiyun if (vmode & FB_VMODE_DOUBLE)
1032*4882a593Smuzhiyun crtc->gen_cntl |= CRTC_DBL_SCAN_EN;
1033*4882a593Smuzhiyun /* Enable interlaced mode if requested */
1034*4882a593Smuzhiyun if (vmode & FB_VMODE_INTERLACED)
1035*4882a593Smuzhiyun crtc->gen_cntl |= CRTC_INTERLACE_EN;
1036*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
1037*4882a593Smuzhiyun if (par->lcd_table != 0) {
1038*4882a593Smuzhiyun u32 vdisplay = yres;
1039*4882a593Smuzhiyun if (vmode & FB_VMODE_DOUBLE)
1040*4882a593Smuzhiyun vdisplay <<= 1;
1041*4882a593Smuzhiyun crtc->gen_cntl &= ~(CRTC2_EN | CRTC2_PIX_WIDTH);
1042*4882a593Smuzhiyun crtc->lcd_gen_cntl &= ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 |
1043*4882a593Smuzhiyun /*TVCLK_PM_EN | VCLK_DAC_PM_EN |*/
1044*4882a593Smuzhiyun USE_SHADOWED_VEND |
1045*4882a593Smuzhiyun USE_SHADOWED_ROWCUR |
1046*4882a593Smuzhiyun SHADOW_EN | SHADOW_RW_EN);
1047*4882a593Smuzhiyun crtc->lcd_gen_cntl |= DONT_SHADOW_VPAR/* | LOCK_8DOT*/;
1048*4882a593Smuzhiyun
1049*4882a593Smuzhiyun /* MOBILITY M1 tested, FIXME: LT */
1050*4882a593Smuzhiyun crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par);
1051*4882a593Smuzhiyun if (!M64_HAS(LT_LCD_REGS))
1052*4882a593Smuzhiyun crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par) &
1053*4882a593Smuzhiyun ~(AUTO_VERT_RATIO | VERT_STRETCH_MODE | VERT_STRETCH_RATIO3);
1054*4882a593Smuzhiyun
1055*4882a593Smuzhiyun crtc->horz_stretching &= ~(HORZ_STRETCH_RATIO |
1056*4882a593Smuzhiyun HORZ_STRETCH_LOOP | AUTO_HORZ_RATIO |
1057*4882a593Smuzhiyun HORZ_STRETCH_MODE | HORZ_STRETCH_EN);
1058*4882a593Smuzhiyun if (xres < par->lcd_width && crtc->lcd_gen_cntl & LCD_ON) {
1059*4882a593Smuzhiyun do {
1060*4882a593Smuzhiyun /*
1061*4882a593Smuzhiyun * The horizontal blender misbehaves when
1062*4882a593Smuzhiyun * HDisplay is less than a certain threshold
1063*4882a593Smuzhiyun * (440 for a 1024-wide panel). It doesn't
1064*4882a593Smuzhiyun * stretch such modes enough. Use pixel
1065*4882a593Smuzhiyun * replication instead of blending to stretch
1066*4882a593Smuzhiyun * modes that can be made to exactly fit the
1067*4882a593Smuzhiyun * panel width. The undocumented "NoLCDBlend"
1068*4882a593Smuzhiyun * option allows the pixel-replicated mode to
1069*4882a593Smuzhiyun * be slightly wider or narrower than the
1070*4882a593Smuzhiyun * panel width. It also causes a mode that is
1071*4882a593Smuzhiyun * exactly half as wide as the panel to be
1072*4882a593Smuzhiyun * pixel-replicated, rather than blended.
1073*4882a593Smuzhiyun */
1074*4882a593Smuzhiyun int HDisplay = xres & ~7;
1075*4882a593Smuzhiyun int nStretch = par->lcd_width / HDisplay;
1076*4882a593Smuzhiyun int Remainder = par->lcd_width % HDisplay;
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun if ((!Remainder && ((nStretch > 2))) ||
1079*4882a593Smuzhiyun (((HDisplay * 16) / par->lcd_width) < 7)) {
1080*4882a593Smuzhiyun static const char StretchLoops[] = { 10, 12, 13, 15, 16 };
1081*4882a593Smuzhiyun int horz_stretch_loop = -1, BestRemainder;
1082*4882a593Smuzhiyun int Numerator = HDisplay, Denominator = par->lcd_width;
1083*4882a593Smuzhiyun int Index = 5;
1084*4882a593Smuzhiyun ATIReduceRatio(&Numerator, &Denominator);
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun BestRemainder = (Numerator * 16) / Denominator;
1087*4882a593Smuzhiyun while (--Index >= 0) {
1088*4882a593Smuzhiyun Remainder = ((Denominator - Numerator) * StretchLoops[Index]) %
1089*4882a593Smuzhiyun Denominator;
1090*4882a593Smuzhiyun if (Remainder < BestRemainder) {
1091*4882a593Smuzhiyun horz_stretch_loop = Index;
1092*4882a593Smuzhiyun if (!(BestRemainder = Remainder))
1093*4882a593Smuzhiyun break;
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun }
1096*4882a593Smuzhiyun
1097*4882a593Smuzhiyun if ((horz_stretch_loop >= 0) && !BestRemainder) {
1098*4882a593Smuzhiyun int horz_stretch_ratio = 0, Accumulator = 0;
1099*4882a593Smuzhiyun int reuse_previous = 1;
1100*4882a593Smuzhiyun
1101*4882a593Smuzhiyun Index = StretchLoops[horz_stretch_loop];
1102*4882a593Smuzhiyun
1103*4882a593Smuzhiyun while (--Index >= 0) {
1104*4882a593Smuzhiyun if (Accumulator > 0)
1105*4882a593Smuzhiyun horz_stretch_ratio |= reuse_previous;
1106*4882a593Smuzhiyun else
1107*4882a593Smuzhiyun Accumulator += Denominator;
1108*4882a593Smuzhiyun Accumulator -= Numerator;
1109*4882a593Smuzhiyun reuse_previous <<= 1;
1110*4882a593Smuzhiyun }
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun crtc->horz_stretching |= (HORZ_STRETCH_EN |
1113*4882a593Smuzhiyun ((horz_stretch_loop & HORZ_STRETCH_LOOP) << 16) |
1114*4882a593Smuzhiyun (horz_stretch_ratio & HORZ_STRETCH_RATIO));
1115*4882a593Smuzhiyun break; /* Out of the do { ... } while (0) */
1116*4882a593Smuzhiyun }
1117*4882a593Smuzhiyun }
1118*4882a593Smuzhiyun
1119*4882a593Smuzhiyun crtc->horz_stretching |= (HORZ_STRETCH_MODE | HORZ_STRETCH_EN |
1120*4882a593Smuzhiyun (((HDisplay * (HORZ_STRETCH_BLEND + 1)) / par->lcd_width) & HORZ_STRETCH_BLEND));
1121*4882a593Smuzhiyun } while (0);
1122*4882a593Smuzhiyun }
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun if (vdisplay < par->lcd_height && crtc->lcd_gen_cntl & LCD_ON) {
1125*4882a593Smuzhiyun crtc->vert_stretching = (VERT_STRETCH_USE0 | VERT_STRETCH_EN |
1126*4882a593Smuzhiyun (((vdisplay * (VERT_STRETCH_RATIO0 + 1)) / par->lcd_height) & VERT_STRETCH_RATIO0));
1127*4882a593Smuzhiyun
1128*4882a593Smuzhiyun if (!M64_HAS(LT_LCD_REGS) &&
1129*4882a593Smuzhiyun xres <= (M64_HAS(MOBIL_BUS) ? 1024 : 800))
1130*4882a593Smuzhiyun crtc->ext_vert_stretch |= VERT_STRETCH_MODE;
1131*4882a593Smuzhiyun } else {
1132*4882a593Smuzhiyun /*
1133*4882a593Smuzhiyun * Don't use vertical blending if the mode is too wide
1134*4882a593Smuzhiyun * or not vertically stretched.
1135*4882a593Smuzhiyun */
1136*4882a593Smuzhiyun crtc->vert_stretching = 0;
1137*4882a593Smuzhiyun }
1138*4882a593Smuzhiyun /* copy to shadow crtc */
1139*4882a593Smuzhiyun crtc->shadow_h_tot_disp = crtc->h_tot_disp;
1140*4882a593Smuzhiyun crtc->shadow_h_sync_strt_wid = crtc->h_sync_strt_wid;
1141*4882a593Smuzhiyun crtc->shadow_v_tot_disp = crtc->v_tot_disp;
1142*4882a593Smuzhiyun crtc->shadow_v_sync_strt_wid = crtc->v_sync_strt_wid;
1143*4882a593Smuzhiyun }
1144*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_GENERIC_LCD */
1145*4882a593Smuzhiyun
1146*4882a593Smuzhiyun if (M64_HAS(MAGIC_FIFO)) {
1147*4882a593Smuzhiyun /* FIXME: display FIFO low watermark values */
1148*4882a593Smuzhiyun crtc->gen_cntl |= (aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_FIFO_LWM);
1149*4882a593Smuzhiyun }
1150*4882a593Smuzhiyun crtc->dp_pix_width = dp_pix_width;
1151*4882a593Smuzhiyun crtc->dp_chain_mask = dp_chain_mask;
1152*4882a593Smuzhiyun
1153*4882a593Smuzhiyun return 0;
1154*4882a593Smuzhiyun }
1155*4882a593Smuzhiyun
aty_crtc_to_var(const struct crtc * crtc,struct fb_var_screeninfo * var)1156*4882a593Smuzhiyun static int aty_crtc_to_var(const struct crtc *crtc,
1157*4882a593Smuzhiyun struct fb_var_screeninfo *var)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;
1160*4882a593Smuzhiyun u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
1161*4882a593Smuzhiyun u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
1162*4882a593Smuzhiyun u32 pix_width;
1163*4882a593Smuzhiyun u32 double_scan, interlace;
1164*4882a593Smuzhiyun
1165*4882a593Smuzhiyun /* input */
1166*4882a593Smuzhiyun h_total = crtc->h_tot_disp & 0x1ff;
1167*4882a593Smuzhiyun h_disp = (crtc->h_tot_disp >> 16) & 0xff;
1168*4882a593Smuzhiyun h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | ((crtc->h_sync_strt_wid >> 4) & 0x100);
1169*4882a593Smuzhiyun h_sync_dly = (crtc->h_sync_strt_wid >> 8) & 0x7;
1170*4882a593Smuzhiyun h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x1f;
1171*4882a593Smuzhiyun h_sync_pol = (crtc->h_sync_strt_wid >> 21) & 0x1;
1172*4882a593Smuzhiyun v_total = crtc->v_tot_disp & 0x7ff;
1173*4882a593Smuzhiyun v_disp = (crtc->v_tot_disp >> 16) & 0x7ff;
1174*4882a593Smuzhiyun v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
1175*4882a593Smuzhiyun v_sync_wid = (crtc->v_sync_strt_wid >> 16) & 0x1f;
1176*4882a593Smuzhiyun v_sync_pol = (crtc->v_sync_strt_wid >> 21) & 0x1;
1177*4882a593Smuzhiyun c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;
1178*4882a593Smuzhiyun pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
1179*4882a593Smuzhiyun double_scan = crtc->gen_cntl & CRTC_DBL_SCAN_EN;
1180*4882a593Smuzhiyun interlace = crtc->gen_cntl & CRTC_INTERLACE_EN;
1181*4882a593Smuzhiyun
1182*4882a593Smuzhiyun /* convert */
1183*4882a593Smuzhiyun xres = (h_disp + 1) * 8;
1184*4882a593Smuzhiyun yres = v_disp + 1;
1185*4882a593Smuzhiyun left = (h_total - h_sync_strt - h_sync_wid) * 8 - h_sync_dly;
1186*4882a593Smuzhiyun right = (h_sync_strt - h_disp) * 8 + h_sync_dly;
1187*4882a593Smuzhiyun hslen = h_sync_wid * 8;
1188*4882a593Smuzhiyun upper = v_total - v_sync_strt - v_sync_wid;
1189*4882a593Smuzhiyun lower = v_sync_strt - v_disp;
1190*4882a593Smuzhiyun vslen = v_sync_wid;
1191*4882a593Smuzhiyun sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
1192*4882a593Smuzhiyun (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
1193*4882a593Smuzhiyun (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);
1194*4882a593Smuzhiyun
1195*4882a593Smuzhiyun switch (pix_width) {
1196*4882a593Smuzhiyun case CRTC_PIX_WIDTH_8BPP:
1197*4882a593Smuzhiyun bpp = 8;
1198*4882a593Smuzhiyun var->red.offset = 0;
1199*4882a593Smuzhiyun var->red.length = 8;
1200*4882a593Smuzhiyun var->green.offset = 0;
1201*4882a593Smuzhiyun var->green.length = 8;
1202*4882a593Smuzhiyun var->blue.offset = 0;
1203*4882a593Smuzhiyun var->blue.length = 8;
1204*4882a593Smuzhiyun var->transp.offset = 0;
1205*4882a593Smuzhiyun var->transp.length = 0;
1206*4882a593Smuzhiyun break;
1207*4882a593Smuzhiyun case CRTC_PIX_WIDTH_15BPP: /* RGB 555 */
1208*4882a593Smuzhiyun bpp = 16;
1209*4882a593Smuzhiyun var->red.offset = 10;
1210*4882a593Smuzhiyun var->red.length = 5;
1211*4882a593Smuzhiyun var->green.offset = 5;
1212*4882a593Smuzhiyun var->green.length = 5;
1213*4882a593Smuzhiyun var->blue.offset = 0;
1214*4882a593Smuzhiyun var->blue.length = 5;
1215*4882a593Smuzhiyun var->transp.offset = 0;
1216*4882a593Smuzhiyun var->transp.length = 0;
1217*4882a593Smuzhiyun break;
1218*4882a593Smuzhiyun case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */
1219*4882a593Smuzhiyun bpp = 16;
1220*4882a593Smuzhiyun var->red.offset = 11;
1221*4882a593Smuzhiyun var->red.length = 5;
1222*4882a593Smuzhiyun var->green.offset = 5;
1223*4882a593Smuzhiyun var->green.length = 6;
1224*4882a593Smuzhiyun var->blue.offset = 0;
1225*4882a593Smuzhiyun var->blue.length = 5;
1226*4882a593Smuzhiyun var->transp.offset = 0;
1227*4882a593Smuzhiyun var->transp.length = 0;
1228*4882a593Smuzhiyun break;
1229*4882a593Smuzhiyun case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */
1230*4882a593Smuzhiyun bpp = 24;
1231*4882a593Smuzhiyun var->red.offset = 16;
1232*4882a593Smuzhiyun var->red.length = 8;
1233*4882a593Smuzhiyun var->green.offset = 8;
1234*4882a593Smuzhiyun var->green.length = 8;
1235*4882a593Smuzhiyun var->blue.offset = 0;
1236*4882a593Smuzhiyun var->blue.length = 8;
1237*4882a593Smuzhiyun var->transp.offset = 0;
1238*4882a593Smuzhiyun var->transp.length = 0;
1239*4882a593Smuzhiyun break;
1240*4882a593Smuzhiyun case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */
1241*4882a593Smuzhiyun bpp = 32;
1242*4882a593Smuzhiyun var->red.offset = 16;
1243*4882a593Smuzhiyun var->red.length = 8;
1244*4882a593Smuzhiyun var->green.offset = 8;
1245*4882a593Smuzhiyun var->green.length = 8;
1246*4882a593Smuzhiyun var->blue.offset = 0;
1247*4882a593Smuzhiyun var->blue.length = 8;
1248*4882a593Smuzhiyun var->transp.offset = 24;
1249*4882a593Smuzhiyun var->transp.length = 8;
1250*4882a593Smuzhiyun break;
1251*4882a593Smuzhiyun default:
1252*4882a593Smuzhiyun PRINTKE("Invalid pixel width\n");
1253*4882a593Smuzhiyun return -EINVAL;
1254*4882a593Smuzhiyun }
1255*4882a593Smuzhiyun
1256*4882a593Smuzhiyun /* output */
1257*4882a593Smuzhiyun var->xres = xres;
1258*4882a593Smuzhiyun var->yres = yres;
1259*4882a593Smuzhiyun var->xres_virtual = crtc->vxres;
1260*4882a593Smuzhiyun var->yres_virtual = crtc->vyres;
1261*4882a593Smuzhiyun var->bits_per_pixel = bpp;
1262*4882a593Smuzhiyun var->left_margin = left;
1263*4882a593Smuzhiyun var->right_margin = right;
1264*4882a593Smuzhiyun var->upper_margin = upper;
1265*4882a593Smuzhiyun var->lower_margin = lower;
1266*4882a593Smuzhiyun var->hsync_len = hslen;
1267*4882a593Smuzhiyun var->vsync_len = vslen;
1268*4882a593Smuzhiyun var->sync = sync;
1269*4882a593Smuzhiyun var->vmode = FB_VMODE_NONINTERLACED;
1270*4882a593Smuzhiyun /*
1271*4882a593Smuzhiyun * In double scan mode, the vertical parameters are doubled,
1272*4882a593Smuzhiyun * so we need to halve them to get the right values.
1273*4882a593Smuzhiyun * In interlaced mode the values are already correct,
1274*4882a593Smuzhiyun * so no correction is necessary.
1275*4882a593Smuzhiyun */
1276*4882a593Smuzhiyun if (interlace)
1277*4882a593Smuzhiyun var->vmode = FB_VMODE_INTERLACED;
1278*4882a593Smuzhiyun
1279*4882a593Smuzhiyun if (double_scan) {
1280*4882a593Smuzhiyun var->vmode = FB_VMODE_DOUBLE;
1281*4882a593Smuzhiyun var->yres >>= 1;
1282*4882a593Smuzhiyun var->upper_margin >>= 1;
1283*4882a593Smuzhiyun var->lower_margin >>= 1;
1284*4882a593Smuzhiyun var->vsync_len >>= 1;
1285*4882a593Smuzhiyun }
1286*4882a593Smuzhiyun
1287*4882a593Smuzhiyun return 0;
1288*4882a593Smuzhiyun }
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
1291*4882a593Smuzhiyun
atyfb_set_par(struct fb_info * info)1292*4882a593Smuzhiyun static int atyfb_set_par(struct fb_info *info)
1293*4882a593Smuzhiyun {
1294*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
1295*4882a593Smuzhiyun struct fb_var_screeninfo *var = &info->var;
1296*4882a593Smuzhiyun u32 tmp, pixclock;
1297*4882a593Smuzhiyun int err;
1298*4882a593Smuzhiyun #ifdef DEBUG
1299*4882a593Smuzhiyun struct fb_var_screeninfo debug;
1300*4882a593Smuzhiyun u32 pixclock_in_ps;
1301*4882a593Smuzhiyun #endif
1302*4882a593Smuzhiyun if (par->asleep)
1303*4882a593Smuzhiyun return 0;
1304*4882a593Smuzhiyun
1305*4882a593Smuzhiyun err = aty_var_to_crtc(info, var, &par->crtc);
1306*4882a593Smuzhiyun if (err)
1307*4882a593Smuzhiyun return err;
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun pixclock = atyfb_get_pixclock(var, par);
1310*4882a593Smuzhiyun
1311*4882a593Smuzhiyun if (pixclock == 0) {
1312*4882a593Smuzhiyun PRINTKE("Invalid pixclock\n");
1313*4882a593Smuzhiyun return -EINVAL;
1314*4882a593Smuzhiyun } else {
1315*4882a593Smuzhiyun err = par->pll_ops->var_to_pll(info, pixclock,
1316*4882a593Smuzhiyun var->bits_per_pixel, &par->pll);
1317*4882a593Smuzhiyun if (err)
1318*4882a593Smuzhiyun return err;
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun par->accel_flags = var->accel_flags; /* hack */
1322*4882a593Smuzhiyun
1323*4882a593Smuzhiyun if (var->accel_flags) {
1324*4882a593Smuzhiyun atyfb_ops.fb_sync = atyfb_sync;
1325*4882a593Smuzhiyun info->flags &= ~FBINFO_HWACCEL_DISABLED;
1326*4882a593Smuzhiyun } else {
1327*4882a593Smuzhiyun atyfb_ops.fb_sync = NULL;
1328*4882a593Smuzhiyun info->flags |= FBINFO_HWACCEL_DISABLED;
1329*4882a593Smuzhiyun }
1330*4882a593Smuzhiyun
1331*4882a593Smuzhiyun if (par->blitter_may_be_busy)
1332*4882a593Smuzhiyun wait_for_idle(par);
1333*4882a593Smuzhiyun
1334*4882a593Smuzhiyun aty_set_crtc(par, &par->crtc);
1335*4882a593Smuzhiyun par->dac_ops->set_dac(info, &par->pll,
1336*4882a593Smuzhiyun var->bits_per_pixel, par->accel_flags);
1337*4882a593Smuzhiyun par->pll_ops->set_pll(info, &par->pll);
1338*4882a593Smuzhiyun
1339*4882a593Smuzhiyun #ifdef DEBUG
1340*4882a593Smuzhiyun if (par->pll_ops && par->pll_ops->pll_to_var)
1341*4882a593Smuzhiyun pixclock_in_ps = par->pll_ops->pll_to_var(info, &par->pll);
1342*4882a593Smuzhiyun else
1343*4882a593Smuzhiyun pixclock_in_ps = 0;
1344*4882a593Smuzhiyun
1345*4882a593Smuzhiyun if (0 == pixclock_in_ps) {
1346*4882a593Smuzhiyun PRINTKE("ALERT ops->pll_to_var get 0\n");
1347*4882a593Smuzhiyun pixclock_in_ps = pixclock;
1348*4882a593Smuzhiyun }
1349*4882a593Smuzhiyun
1350*4882a593Smuzhiyun memset(&debug, 0, sizeof(debug));
1351*4882a593Smuzhiyun if (!aty_crtc_to_var(&par->crtc, &debug)) {
1352*4882a593Smuzhiyun u32 hSync, vRefresh;
1353*4882a593Smuzhiyun u32 h_disp, h_sync_strt, h_sync_end, h_total;
1354*4882a593Smuzhiyun u32 v_disp, v_sync_strt, v_sync_end, v_total;
1355*4882a593Smuzhiyun
1356*4882a593Smuzhiyun h_disp = debug.xres;
1357*4882a593Smuzhiyun h_sync_strt = h_disp + debug.right_margin;
1358*4882a593Smuzhiyun h_sync_end = h_sync_strt + debug.hsync_len;
1359*4882a593Smuzhiyun h_total = h_sync_end + debug.left_margin;
1360*4882a593Smuzhiyun v_disp = debug.yres;
1361*4882a593Smuzhiyun v_sync_strt = v_disp + debug.lower_margin;
1362*4882a593Smuzhiyun v_sync_end = v_sync_strt + debug.vsync_len;
1363*4882a593Smuzhiyun v_total = v_sync_end + debug.upper_margin;
1364*4882a593Smuzhiyun
1365*4882a593Smuzhiyun hSync = 1000000000 / (pixclock_in_ps * h_total);
1366*4882a593Smuzhiyun vRefresh = (hSync * 1000) / v_total;
1367*4882a593Smuzhiyun if (par->crtc.gen_cntl & CRTC_INTERLACE_EN)
1368*4882a593Smuzhiyun vRefresh *= 2;
1369*4882a593Smuzhiyun if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN)
1370*4882a593Smuzhiyun vRefresh /= 2;
1371*4882a593Smuzhiyun
1372*4882a593Smuzhiyun DPRINTK("atyfb_set_par\n");
1373*4882a593Smuzhiyun DPRINTK(" Set Visible Mode to %ix%i-%i\n",
1374*4882a593Smuzhiyun var->xres, var->yres, var->bits_per_pixel);
1375*4882a593Smuzhiyun DPRINTK(" Virtual resolution %ix%i, "
1376*4882a593Smuzhiyun "pixclock_in_ps %i (calculated %i)\n",
1377*4882a593Smuzhiyun var->xres_virtual, var->yres_virtual,
1378*4882a593Smuzhiyun pixclock, pixclock_in_ps);
1379*4882a593Smuzhiyun DPRINTK(" Dot clock: %i MHz\n",
1380*4882a593Smuzhiyun 1000000 / pixclock_in_ps);
1381*4882a593Smuzhiyun DPRINTK(" Horizontal sync: %i kHz\n", hSync);
1382*4882a593Smuzhiyun DPRINTK(" Vertical refresh: %i Hz\n", vRefresh);
1383*4882a593Smuzhiyun DPRINTK(" x style: %i.%03i %i %i %i %i %i %i %i %i\n",
1384*4882a593Smuzhiyun 1000000 / pixclock_in_ps, 1000000 % pixclock_in_ps,
1385*4882a593Smuzhiyun h_disp, h_sync_strt, h_sync_end, h_total,
1386*4882a593Smuzhiyun v_disp, v_sync_strt, v_sync_end, v_total);
1387*4882a593Smuzhiyun DPRINTK(" fb style: %i %i %i %i %i %i %i %i %i\n",
1388*4882a593Smuzhiyun pixclock_in_ps,
1389*4882a593Smuzhiyun debug.left_margin, h_disp, debug.right_margin, debug.hsync_len,
1390*4882a593Smuzhiyun debug.upper_margin, v_disp, debug.lower_margin, debug.vsync_len);
1391*4882a593Smuzhiyun }
1392*4882a593Smuzhiyun #endif /* DEBUG */
1393*4882a593Smuzhiyun
1394*4882a593Smuzhiyun if (!M64_HAS(INTEGRATED)) {
1395*4882a593Smuzhiyun /* Don't forget MEM_CNTL */
1396*4882a593Smuzhiyun tmp = aty_ld_le32(MEM_CNTL, par) & 0xf0ffffff;
1397*4882a593Smuzhiyun switch (var->bits_per_pixel) {
1398*4882a593Smuzhiyun case 8:
1399*4882a593Smuzhiyun tmp |= 0x02000000;
1400*4882a593Smuzhiyun break;
1401*4882a593Smuzhiyun case 16:
1402*4882a593Smuzhiyun tmp |= 0x03000000;
1403*4882a593Smuzhiyun break;
1404*4882a593Smuzhiyun case 32:
1405*4882a593Smuzhiyun tmp |= 0x06000000;
1406*4882a593Smuzhiyun break;
1407*4882a593Smuzhiyun }
1408*4882a593Smuzhiyun aty_st_le32(MEM_CNTL, tmp, par);
1409*4882a593Smuzhiyun } else {
1410*4882a593Smuzhiyun tmp = aty_ld_le32(MEM_CNTL, par) & 0xf00fffff;
1411*4882a593Smuzhiyun if (!M64_HAS(MAGIC_POSTDIV))
1412*4882a593Smuzhiyun tmp |= par->mem_refresh_rate << 20;
1413*4882a593Smuzhiyun switch (var->bits_per_pixel) {
1414*4882a593Smuzhiyun case 8:
1415*4882a593Smuzhiyun case 24:
1416*4882a593Smuzhiyun tmp |= 0x00000000;
1417*4882a593Smuzhiyun break;
1418*4882a593Smuzhiyun case 16:
1419*4882a593Smuzhiyun tmp |= 0x04000000;
1420*4882a593Smuzhiyun break;
1421*4882a593Smuzhiyun case 32:
1422*4882a593Smuzhiyun tmp |= 0x08000000;
1423*4882a593Smuzhiyun break;
1424*4882a593Smuzhiyun }
1425*4882a593Smuzhiyun if (M64_HAS(CT_BUS)) {
1426*4882a593Smuzhiyun aty_st_le32(DAC_CNTL, 0x87010184, par);
1427*4882a593Smuzhiyun aty_st_le32(BUS_CNTL, 0x680000f9, par);
1428*4882a593Smuzhiyun } else if (M64_HAS(VT_BUS)) {
1429*4882a593Smuzhiyun aty_st_le32(DAC_CNTL, 0x87010184, par);
1430*4882a593Smuzhiyun aty_st_le32(BUS_CNTL, 0x680000f9, par);
1431*4882a593Smuzhiyun } else if (M64_HAS(MOBIL_BUS)) {
1432*4882a593Smuzhiyun aty_st_le32(DAC_CNTL, 0x80010102, par);
1433*4882a593Smuzhiyun aty_st_le32(BUS_CNTL, 0x7b33a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par);
1434*4882a593Smuzhiyun } else {
1435*4882a593Smuzhiyun /* GT */
1436*4882a593Smuzhiyun aty_st_le32(DAC_CNTL, 0x86010102, par);
1437*4882a593Smuzhiyun aty_st_le32(BUS_CNTL, 0x7b23a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par);
1438*4882a593Smuzhiyun aty_st_le32(EXT_MEM_CNTL, aty_ld_le32(EXT_MEM_CNTL, par) | 0x5000001, par);
1439*4882a593Smuzhiyun }
1440*4882a593Smuzhiyun aty_st_le32(MEM_CNTL, tmp, par);
1441*4882a593Smuzhiyun }
1442*4882a593Smuzhiyun aty_st_8(DAC_MASK, 0xff, par);
1443*4882a593Smuzhiyun
1444*4882a593Smuzhiyun info->fix.line_length = calc_line_length(par, var->xres_virtual,
1445*4882a593Smuzhiyun var->bits_per_pixel);
1446*4882a593Smuzhiyun
1447*4882a593Smuzhiyun info->fix.visual = var->bits_per_pixel <= 8 ?
1448*4882a593Smuzhiyun FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
1449*4882a593Smuzhiyun
1450*4882a593Smuzhiyun /* Initialize the graphics engine */
1451*4882a593Smuzhiyun if (par->accel_flags & FB_ACCELF_TEXT)
1452*4882a593Smuzhiyun aty_init_engine(par, info);
1453*4882a593Smuzhiyun
1454*4882a593Smuzhiyun #ifdef CONFIG_BOOTX_TEXT
1455*4882a593Smuzhiyun btext_update_display(info->fix.smem_start,
1456*4882a593Smuzhiyun (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8,
1457*4882a593Smuzhiyun ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1,
1458*4882a593Smuzhiyun var->bits_per_pixel,
1459*4882a593Smuzhiyun par->crtc.vxres * var->bits_per_pixel / 8);
1460*4882a593Smuzhiyun #endif /* CONFIG_BOOTX_TEXT */
1461*4882a593Smuzhiyun #ifdef DEBUG
1462*4882a593Smuzhiyun {
1463*4882a593Smuzhiyun /* dump non shadow CRTC, pll, LCD registers */
1464*4882a593Smuzhiyun int i; u32 base;
1465*4882a593Smuzhiyun
1466*4882a593Smuzhiyun /* CRTC registers */
1467*4882a593Smuzhiyun base = 0x2000;
1468*4882a593Smuzhiyun printk("debug atyfb: Mach64 non-shadow register values:");
1469*4882a593Smuzhiyun for (i = 0; i < 256; i = i+4) {
1470*4882a593Smuzhiyun if (i % 16 == 0) {
1471*4882a593Smuzhiyun pr_cont("\n");
1472*4882a593Smuzhiyun printk("debug atyfb: 0x%04X: ", base + i);
1473*4882a593Smuzhiyun }
1474*4882a593Smuzhiyun pr_cont(" %08X", aty_ld_le32(i, par));
1475*4882a593Smuzhiyun }
1476*4882a593Smuzhiyun pr_cont("\n\n");
1477*4882a593Smuzhiyun
1478*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_CT
1479*4882a593Smuzhiyun /* PLL registers */
1480*4882a593Smuzhiyun base = 0x00;
1481*4882a593Smuzhiyun printk("debug atyfb: Mach64 PLL register values:");
1482*4882a593Smuzhiyun for (i = 0; i < 64; i++) {
1483*4882a593Smuzhiyun if (i % 16 == 0) {
1484*4882a593Smuzhiyun pr_cont("\n");
1485*4882a593Smuzhiyun printk("debug atyfb: 0x%02X: ", base + i);
1486*4882a593Smuzhiyun }
1487*4882a593Smuzhiyun if (i % 4 == 0)
1488*4882a593Smuzhiyun pr_cont(" ");
1489*4882a593Smuzhiyun pr_cont("%02X", aty_ld_pll_ct(i, par));
1490*4882a593Smuzhiyun }
1491*4882a593Smuzhiyun pr_cont("\n\n");
1492*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_CT */
1493*4882a593Smuzhiyun
1494*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
1495*4882a593Smuzhiyun if (par->lcd_table != 0) {
1496*4882a593Smuzhiyun /* LCD registers */
1497*4882a593Smuzhiyun base = 0x00;
1498*4882a593Smuzhiyun printk("debug atyfb: LCD register values:");
1499*4882a593Smuzhiyun if (M64_HAS(LT_LCD_REGS)) {
1500*4882a593Smuzhiyun for (i = 0; i <= POWER_MANAGEMENT; i++) {
1501*4882a593Smuzhiyun if (i == EXT_VERT_STRETCH)
1502*4882a593Smuzhiyun continue;
1503*4882a593Smuzhiyun pr_cont("\ndebug atyfb: 0x%04X: ",
1504*4882a593Smuzhiyun lt_lcd_regs[i]);
1505*4882a593Smuzhiyun pr_cont(" %08X", aty_ld_lcd(i, par));
1506*4882a593Smuzhiyun }
1507*4882a593Smuzhiyun } else {
1508*4882a593Smuzhiyun for (i = 0; i < 64; i++) {
1509*4882a593Smuzhiyun if (i % 4 == 0)
1510*4882a593Smuzhiyun pr_cont("\ndebug atyfb: 0x%02X: ",
1511*4882a593Smuzhiyun base + i);
1512*4882a593Smuzhiyun pr_cont(" %08X", aty_ld_lcd(i, par));
1513*4882a593Smuzhiyun }
1514*4882a593Smuzhiyun }
1515*4882a593Smuzhiyun pr_cont("\n\n");
1516*4882a593Smuzhiyun }
1517*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_GENERIC_LCD */
1518*4882a593Smuzhiyun }
1519*4882a593Smuzhiyun #endif /* DEBUG */
1520*4882a593Smuzhiyun return 0;
1521*4882a593Smuzhiyun }
1522*4882a593Smuzhiyun
atyfb_check_var(struct fb_var_screeninfo * var,struct fb_info * info)1523*4882a593Smuzhiyun static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1524*4882a593Smuzhiyun {
1525*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
1526*4882a593Smuzhiyun int err;
1527*4882a593Smuzhiyun struct crtc crtc;
1528*4882a593Smuzhiyun union aty_pll pll;
1529*4882a593Smuzhiyun u32 pixclock;
1530*4882a593Smuzhiyun
1531*4882a593Smuzhiyun memcpy(&pll, &par->pll, sizeof(pll));
1532*4882a593Smuzhiyun
1533*4882a593Smuzhiyun err = aty_var_to_crtc(info, var, &crtc);
1534*4882a593Smuzhiyun if (err)
1535*4882a593Smuzhiyun return err;
1536*4882a593Smuzhiyun
1537*4882a593Smuzhiyun pixclock = atyfb_get_pixclock(var, par);
1538*4882a593Smuzhiyun
1539*4882a593Smuzhiyun if (pixclock == 0) {
1540*4882a593Smuzhiyun if (!(var->activate & FB_ACTIVATE_TEST))
1541*4882a593Smuzhiyun PRINTKE("Invalid pixclock\n");
1542*4882a593Smuzhiyun return -EINVAL;
1543*4882a593Smuzhiyun } else {
1544*4882a593Smuzhiyun err = par->pll_ops->var_to_pll(info, pixclock,
1545*4882a593Smuzhiyun var->bits_per_pixel, &pll);
1546*4882a593Smuzhiyun if (err)
1547*4882a593Smuzhiyun return err;
1548*4882a593Smuzhiyun }
1549*4882a593Smuzhiyun
1550*4882a593Smuzhiyun if (var->accel_flags & FB_ACCELF_TEXT)
1551*4882a593Smuzhiyun info->var.accel_flags = FB_ACCELF_TEXT;
1552*4882a593Smuzhiyun else
1553*4882a593Smuzhiyun info->var.accel_flags = 0;
1554*4882a593Smuzhiyun
1555*4882a593Smuzhiyun aty_crtc_to_var(&crtc, var);
1556*4882a593Smuzhiyun var->pixclock = par->pll_ops->pll_to_var(info, &pll);
1557*4882a593Smuzhiyun return 0;
1558*4882a593Smuzhiyun }
1559*4882a593Smuzhiyun
set_off_pitch(struct atyfb_par * par,const struct fb_info * info)1560*4882a593Smuzhiyun static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info)
1561*4882a593Smuzhiyun {
1562*4882a593Smuzhiyun u32 xoffset = info->var.xoffset;
1563*4882a593Smuzhiyun u32 yoffset = info->var.yoffset;
1564*4882a593Smuzhiyun u32 line_length = info->fix.line_length;
1565*4882a593Smuzhiyun u32 bpp = info->var.bits_per_pixel;
1566*4882a593Smuzhiyun
1567*4882a593Smuzhiyun par->crtc.off_pitch =
1568*4882a593Smuzhiyun ((yoffset * line_length + xoffset * bpp / 8) / 8) |
1569*4882a593Smuzhiyun ((line_length / bpp) << 22);
1570*4882a593Smuzhiyun }
1571*4882a593Smuzhiyun
1572*4882a593Smuzhiyun
1573*4882a593Smuzhiyun /*
1574*4882a593Smuzhiyun * Open/Release the frame buffer device
1575*4882a593Smuzhiyun */
1576*4882a593Smuzhiyun
atyfb_open(struct fb_info * info,int user)1577*4882a593Smuzhiyun static int atyfb_open(struct fb_info *info, int user)
1578*4882a593Smuzhiyun {
1579*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
1580*4882a593Smuzhiyun
1581*4882a593Smuzhiyun if (user) {
1582*4882a593Smuzhiyun par->open++;
1583*4882a593Smuzhiyun #ifdef __sparc__
1584*4882a593Smuzhiyun par->mmaped = 0;
1585*4882a593Smuzhiyun #endif
1586*4882a593Smuzhiyun }
1587*4882a593Smuzhiyun return 0;
1588*4882a593Smuzhiyun }
1589*4882a593Smuzhiyun
aty_irq(int irq,void * dev_id)1590*4882a593Smuzhiyun static irqreturn_t aty_irq(int irq, void *dev_id)
1591*4882a593Smuzhiyun {
1592*4882a593Smuzhiyun struct atyfb_par *par = dev_id;
1593*4882a593Smuzhiyun int handled = 0;
1594*4882a593Smuzhiyun u32 int_cntl;
1595*4882a593Smuzhiyun
1596*4882a593Smuzhiyun spin_lock(&par->int_lock);
1597*4882a593Smuzhiyun
1598*4882a593Smuzhiyun int_cntl = aty_ld_le32(CRTC_INT_CNTL, par);
1599*4882a593Smuzhiyun
1600*4882a593Smuzhiyun if (int_cntl & CRTC_VBLANK_INT) {
1601*4882a593Smuzhiyun /* clear interrupt */
1602*4882a593Smuzhiyun aty_st_le32(CRTC_INT_CNTL, (int_cntl & CRTC_INT_EN_MASK) |
1603*4882a593Smuzhiyun CRTC_VBLANK_INT_AK, par);
1604*4882a593Smuzhiyun par->vblank.count++;
1605*4882a593Smuzhiyun if (par->vblank.pan_display) {
1606*4882a593Smuzhiyun par->vblank.pan_display = 0;
1607*4882a593Smuzhiyun aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
1608*4882a593Smuzhiyun }
1609*4882a593Smuzhiyun wake_up_interruptible(&par->vblank.wait);
1610*4882a593Smuzhiyun handled = 1;
1611*4882a593Smuzhiyun }
1612*4882a593Smuzhiyun
1613*4882a593Smuzhiyun spin_unlock(&par->int_lock);
1614*4882a593Smuzhiyun
1615*4882a593Smuzhiyun return IRQ_RETVAL(handled);
1616*4882a593Smuzhiyun }
1617*4882a593Smuzhiyun
aty_enable_irq(struct atyfb_par * par,int reenable)1618*4882a593Smuzhiyun static int aty_enable_irq(struct atyfb_par *par, int reenable)
1619*4882a593Smuzhiyun {
1620*4882a593Smuzhiyun u32 int_cntl;
1621*4882a593Smuzhiyun
1622*4882a593Smuzhiyun if (!test_and_set_bit(0, &par->irq_flags)) {
1623*4882a593Smuzhiyun if (request_irq(par->irq, aty_irq, IRQF_SHARED, "atyfb", par)) {
1624*4882a593Smuzhiyun clear_bit(0, &par->irq_flags);
1625*4882a593Smuzhiyun return -EINVAL;
1626*4882a593Smuzhiyun }
1627*4882a593Smuzhiyun spin_lock_irq(&par->int_lock);
1628*4882a593Smuzhiyun int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
1629*4882a593Smuzhiyun /* clear interrupt */
1630*4882a593Smuzhiyun aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_AK, par);
1631*4882a593Smuzhiyun /* enable interrupt */
1632*4882a593Smuzhiyun aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par);
1633*4882a593Smuzhiyun spin_unlock_irq(&par->int_lock);
1634*4882a593Smuzhiyun } else if (reenable) {
1635*4882a593Smuzhiyun spin_lock_irq(&par->int_lock);
1636*4882a593Smuzhiyun int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
1637*4882a593Smuzhiyun if (!(int_cntl & CRTC_VBLANK_INT_EN)) {
1638*4882a593Smuzhiyun printk("atyfb: someone disabled IRQ [%08x]\n",
1639*4882a593Smuzhiyun int_cntl);
1640*4882a593Smuzhiyun /* re-enable interrupt */
1641*4882a593Smuzhiyun aty_st_le32(CRTC_INT_CNTL, int_cntl |
1642*4882a593Smuzhiyun CRTC_VBLANK_INT_EN, par);
1643*4882a593Smuzhiyun }
1644*4882a593Smuzhiyun spin_unlock_irq(&par->int_lock);
1645*4882a593Smuzhiyun }
1646*4882a593Smuzhiyun
1647*4882a593Smuzhiyun return 0;
1648*4882a593Smuzhiyun }
1649*4882a593Smuzhiyun
aty_disable_irq(struct atyfb_par * par)1650*4882a593Smuzhiyun static int aty_disable_irq(struct atyfb_par *par)
1651*4882a593Smuzhiyun {
1652*4882a593Smuzhiyun u32 int_cntl;
1653*4882a593Smuzhiyun
1654*4882a593Smuzhiyun if (test_and_clear_bit(0, &par->irq_flags)) {
1655*4882a593Smuzhiyun if (par->vblank.pan_display) {
1656*4882a593Smuzhiyun par->vblank.pan_display = 0;
1657*4882a593Smuzhiyun aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
1658*4882a593Smuzhiyun }
1659*4882a593Smuzhiyun spin_lock_irq(&par->int_lock);
1660*4882a593Smuzhiyun int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
1661*4882a593Smuzhiyun /* disable interrupt */
1662*4882a593Smuzhiyun aty_st_le32(CRTC_INT_CNTL, int_cntl & ~CRTC_VBLANK_INT_EN, par);
1663*4882a593Smuzhiyun spin_unlock_irq(&par->int_lock);
1664*4882a593Smuzhiyun free_irq(par->irq, par);
1665*4882a593Smuzhiyun }
1666*4882a593Smuzhiyun
1667*4882a593Smuzhiyun return 0;
1668*4882a593Smuzhiyun }
1669*4882a593Smuzhiyun
atyfb_release(struct fb_info * info,int user)1670*4882a593Smuzhiyun static int atyfb_release(struct fb_info *info, int user)
1671*4882a593Smuzhiyun {
1672*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
1673*4882a593Smuzhiyun #ifdef __sparc__
1674*4882a593Smuzhiyun int was_mmaped;
1675*4882a593Smuzhiyun #endif
1676*4882a593Smuzhiyun
1677*4882a593Smuzhiyun if (!user)
1678*4882a593Smuzhiyun return 0;
1679*4882a593Smuzhiyun
1680*4882a593Smuzhiyun par->open--;
1681*4882a593Smuzhiyun mdelay(1);
1682*4882a593Smuzhiyun wait_for_idle(par);
1683*4882a593Smuzhiyun
1684*4882a593Smuzhiyun if (par->open)
1685*4882a593Smuzhiyun return 0;
1686*4882a593Smuzhiyun
1687*4882a593Smuzhiyun #ifdef __sparc__
1688*4882a593Smuzhiyun was_mmaped = par->mmaped;
1689*4882a593Smuzhiyun
1690*4882a593Smuzhiyun par->mmaped = 0;
1691*4882a593Smuzhiyun
1692*4882a593Smuzhiyun if (was_mmaped) {
1693*4882a593Smuzhiyun struct fb_var_screeninfo var;
1694*4882a593Smuzhiyun
1695*4882a593Smuzhiyun /*
1696*4882a593Smuzhiyun * Now reset the default display config, we have
1697*4882a593Smuzhiyun * no idea what the program(s) which mmap'd the
1698*4882a593Smuzhiyun * chip did to the configuration, nor whether it
1699*4882a593Smuzhiyun * restored it correctly.
1700*4882a593Smuzhiyun */
1701*4882a593Smuzhiyun var = default_var;
1702*4882a593Smuzhiyun if (noaccel)
1703*4882a593Smuzhiyun var.accel_flags &= ~FB_ACCELF_TEXT;
1704*4882a593Smuzhiyun else
1705*4882a593Smuzhiyun var.accel_flags |= FB_ACCELF_TEXT;
1706*4882a593Smuzhiyun if (var.yres == var.yres_virtual) {
1707*4882a593Smuzhiyun u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2));
1708*4882a593Smuzhiyun var.yres_virtual =
1709*4882a593Smuzhiyun ((videoram * 8) / var.bits_per_pixel) /
1710*4882a593Smuzhiyun var.xres_virtual;
1711*4882a593Smuzhiyun if (var.yres_virtual < var.yres)
1712*4882a593Smuzhiyun var.yres_virtual = var.yres;
1713*4882a593Smuzhiyun }
1714*4882a593Smuzhiyun }
1715*4882a593Smuzhiyun #endif
1716*4882a593Smuzhiyun aty_disable_irq(par);
1717*4882a593Smuzhiyun
1718*4882a593Smuzhiyun return 0;
1719*4882a593Smuzhiyun }
1720*4882a593Smuzhiyun
1721*4882a593Smuzhiyun /*
1722*4882a593Smuzhiyun * Pan or Wrap the Display
1723*4882a593Smuzhiyun *
1724*4882a593Smuzhiyun * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
1725*4882a593Smuzhiyun */
1726*4882a593Smuzhiyun
atyfb_pan_display(struct fb_var_screeninfo * var,struct fb_info * info)1727*4882a593Smuzhiyun static int atyfb_pan_display(struct fb_var_screeninfo *var,
1728*4882a593Smuzhiyun struct fb_info *info)
1729*4882a593Smuzhiyun {
1730*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
1731*4882a593Smuzhiyun u32 xres, yres, xoffset, yoffset;
1732*4882a593Smuzhiyun
1733*4882a593Smuzhiyun xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8;
1734*4882a593Smuzhiyun yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1;
1735*4882a593Smuzhiyun if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN)
1736*4882a593Smuzhiyun yres >>= 1;
1737*4882a593Smuzhiyun xoffset = (var->xoffset + 7) & ~7;
1738*4882a593Smuzhiyun yoffset = var->yoffset;
1739*4882a593Smuzhiyun if (xoffset + xres > par->crtc.vxres ||
1740*4882a593Smuzhiyun yoffset + yres > par->crtc.vyres)
1741*4882a593Smuzhiyun return -EINVAL;
1742*4882a593Smuzhiyun info->var.xoffset = xoffset;
1743*4882a593Smuzhiyun info->var.yoffset = yoffset;
1744*4882a593Smuzhiyun if (par->asleep)
1745*4882a593Smuzhiyun return 0;
1746*4882a593Smuzhiyun
1747*4882a593Smuzhiyun set_off_pitch(par, info);
1748*4882a593Smuzhiyun if ((var->activate & FB_ACTIVATE_VBL) && !aty_enable_irq(par, 0)) {
1749*4882a593Smuzhiyun par->vblank.pan_display = 1;
1750*4882a593Smuzhiyun } else {
1751*4882a593Smuzhiyun par->vblank.pan_display = 0;
1752*4882a593Smuzhiyun aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
1753*4882a593Smuzhiyun }
1754*4882a593Smuzhiyun
1755*4882a593Smuzhiyun return 0;
1756*4882a593Smuzhiyun }
1757*4882a593Smuzhiyun
aty_waitforvblank(struct atyfb_par * par,u32 crtc)1758*4882a593Smuzhiyun static int aty_waitforvblank(struct atyfb_par *par, u32 crtc)
1759*4882a593Smuzhiyun {
1760*4882a593Smuzhiyun struct aty_interrupt *vbl;
1761*4882a593Smuzhiyun unsigned int count;
1762*4882a593Smuzhiyun int ret;
1763*4882a593Smuzhiyun
1764*4882a593Smuzhiyun switch (crtc) {
1765*4882a593Smuzhiyun case 0:
1766*4882a593Smuzhiyun vbl = &par->vblank;
1767*4882a593Smuzhiyun break;
1768*4882a593Smuzhiyun default:
1769*4882a593Smuzhiyun return -ENODEV;
1770*4882a593Smuzhiyun }
1771*4882a593Smuzhiyun
1772*4882a593Smuzhiyun ret = aty_enable_irq(par, 0);
1773*4882a593Smuzhiyun if (ret)
1774*4882a593Smuzhiyun return ret;
1775*4882a593Smuzhiyun
1776*4882a593Smuzhiyun count = vbl->count;
1777*4882a593Smuzhiyun ret = wait_event_interruptible_timeout(vbl->wait,
1778*4882a593Smuzhiyun count != vbl->count, HZ/10);
1779*4882a593Smuzhiyun if (ret < 0)
1780*4882a593Smuzhiyun return ret;
1781*4882a593Smuzhiyun if (ret == 0) {
1782*4882a593Smuzhiyun aty_enable_irq(par, 1);
1783*4882a593Smuzhiyun return -ETIMEDOUT;
1784*4882a593Smuzhiyun }
1785*4882a593Smuzhiyun
1786*4882a593Smuzhiyun return 0;
1787*4882a593Smuzhiyun }
1788*4882a593Smuzhiyun
1789*4882a593Smuzhiyun
1790*4882a593Smuzhiyun #ifdef DEBUG
1791*4882a593Smuzhiyun #define ATYIO_CLKR 0x41545900 /* ATY\00 */
1792*4882a593Smuzhiyun #define ATYIO_CLKW 0x41545901 /* ATY\01 */
1793*4882a593Smuzhiyun
1794*4882a593Smuzhiyun struct atyclk {
1795*4882a593Smuzhiyun u32 ref_clk_per;
1796*4882a593Smuzhiyun u8 pll_ref_div;
1797*4882a593Smuzhiyun u8 mclk_fb_div;
1798*4882a593Smuzhiyun u8 mclk_post_div; /* 1,2,3,4,8 */
1799*4882a593Smuzhiyun u8 mclk_fb_mult; /* 2 or 4 */
1800*4882a593Smuzhiyun u8 xclk_post_div; /* 1,2,3,4,8 */
1801*4882a593Smuzhiyun u8 vclk_fb_div;
1802*4882a593Smuzhiyun u8 vclk_post_div; /* 1,2,3,4,6,8,12 */
1803*4882a593Smuzhiyun u32 dsp_xclks_per_row; /* 0-16383 */
1804*4882a593Smuzhiyun u32 dsp_loop_latency; /* 0-15 */
1805*4882a593Smuzhiyun u32 dsp_precision; /* 0-7 */
1806*4882a593Smuzhiyun u32 dsp_on; /* 0-2047 */
1807*4882a593Smuzhiyun u32 dsp_off; /* 0-2047 */
1808*4882a593Smuzhiyun };
1809*4882a593Smuzhiyun
1810*4882a593Smuzhiyun #define ATYIO_FEATR 0x41545902 /* ATY\02 */
1811*4882a593Smuzhiyun #define ATYIO_FEATW 0x41545903 /* ATY\03 */
1812*4882a593Smuzhiyun #endif
1813*4882a593Smuzhiyun
atyfb_ioctl(struct fb_info * info,u_int cmd,u_long arg)1814*4882a593Smuzhiyun static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
1815*4882a593Smuzhiyun {
1816*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
1817*4882a593Smuzhiyun #ifdef __sparc__
1818*4882a593Smuzhiyun struct fbtype fbtyp;
1819*4882a593Smuzhiyun #endif
1820*4882a593Smuzhiyun
1821*4882a593Smuzhiyun switch (cmd) {
1822*4882a593Smuzhiyun #ifdef __sparc__
1823*4882a593Smuzhiyun case FBIOGTYPE:
1824*4882a593Smuzhiyun fbtyp.fb_type = FBTYPE_PCI_GENERIC;
1825*4882a593Smuzhiyun fbtyp.fb_width = par->crtc.vxres;
1826*4882a593Smuzhiyun fbtyp.fb_height = par->crtc.vyres;
1827*4882a593Smuzhiyun fbtyp.fb_depth = info->var.bits_per_pixel;
1828*4882a593Smuzhiyun fbtyp.fb_cmsize = info->cmap.len;
1829*4882a593Smuzhiyun fbtyp.fb_size = info->fix.smem_len;
1830*4882a593Smuzhiyun if (copy_to_user((struct fbtype __user *) arg, &fbtyp,
1831*4882a593Smuzhiyun sizeof(fbtyp)))
1832*4882a593Smuzhiyun return -EFAULT;
1833*4882a593Smuzhiyun break;
1834*4882a593Smuzhiyun #endif /* __sparc__ */
1835*4882a593Smuzhiyun
1836*4882a593Smuzhiyun case FBIO_WAITFORVSYNC:
1837*4882a593Smuzhiyun {
1838*4882a593Smuzhiyun u32 crtc;
1839*4882a593Smuzhiyun
1840*4882a593Smuzhiyun if (get_user(crtc, (__u32 __user *) arg))
1841*4882a593Smuzhiyun return -EFAULT;
1842*4882a593Smuzhiyun
1843*4882a593Smuzhiyun return aty_waitforvblank(par, crtc);
1844*4882a593Smuzhiyun }
1845*4882a593Smuzhiyun
1846*4882a593Smuzhiyun #if defined(DEBUG) && defined(CONFIG_FB_ATY_CT)
1847*4882a593Smuzhiyun case ATYIO_CLKR:
1848*4882a593Smuzhiyun if (M64_HAS(INTEGRATED)) {
1849*4882a593Smuzhiyun struct atyclk clk = { 0 };
1850*4882a593Smuzhiyun union aty_pll *pll = &par->pll;
1851*4882a593Smuzhiyun u32 dsp_config = pll->ct.dsp_config;
1852*4882a593Smuzhiyun u32 dsp_on_off = pll->ct.dsp_on_off;
1853*4882a593Smuzhiyun clk.ref_clk_per = par->ref_clk_per;
1854*4882a593Smuzhiyun clk.pll_ref_div = pll->ct.pll_ref_div;
1855*4882a593Smuzhiyun clk.mclk_fb_div = pll->ct.mclk_fb_div;
1856*4882a593Smuzhiyun clk.mclk_post_div = pll->ct.mclk_post_div_real;
1857*4882a593Smuzhiyun clk.mclk_fb_mult = pll->ct.mclk_fb_mult;
1858*4882a593Smuzhiyun clk.xclk_post_div = pll->ct.xclk_post_div_real;
1859*4882a593Smuzhiyun clk.vclk_fb_div = pll->ct.vclk_fb_div;
1860*4882a593Smuzhiyun clk.vclk_post_div = pll->ct.vclk_post_div_real;
1861*4882a593Smuzhiyun clk.dsp_xclks_per_row = dsp_config & 0x3fff;
1862*4882a593Smuzhiyun clk.dsp_loop_latency = (dsp_config >> 16) & 0xf;
1863*4882a593Smuzhiyun clk.dsp_precision = (dsp_config >> 20) & 7;
1864*4882a593Smuzhiyun clk.dsp_off = dsp_on_off & 0x7ff;
1865*4882a593Smuzhiyun clk.dsp_on = (dsp_on_off >> 16) & 0x7ff;
1866*4882a593Smuzhiyun if (copy_to_user((struct atyclk __user *) arg, &clk,
1867*4882a593Smuzhiyun sizeof(clk)))
1868*4882a593Smuzhiyun return -EFAULT;
1869*4882a593Smuzhiyun } else
1870*4882a593Smuzhiyun return -EINVAL;
1871*4882a593Smuzhiyun break;
1872*4882a593Smuzhiyun case ATYIO_CLKW:
1873*4882a593Smuzhiyun if (M64_HAS(INTEGRATED)) {
1874*4882a593Smuzhiyun struct atyclk clk;
1875*4882a593Smuzhiyun union aty_pll *pll = &par->pll;
1876*4882a593Smuzhiyun if (copy_from_user(&clk, (struct atyclk __user *) arg,
1877*4882a593Smuzhiyun sizeof(clk)))
1878*4882a593Smuzhiyun return -EFAULT;
1879*4882a593Smuzhiyun par->ref_clk_per = clk.ref_clk_per;
1880*4882a593Smuzhiyun pll->ct.pll_ref_div = clk.pll_ref_div;
1881*4882a593Smuzhiyun pll->ct.mclk_fb_div = clk.mclk_fb_div;
1882*4882a593Smuzhiyun pll->ct.mclk_post_div_real = clk.mclk_post_div;
1883*4882a593Smuzhiyun pll->ct.mclk_fb_mult = clk.mclk_fb_mult;
1884*4882a593Smuzhiyun pll->ct.xclk_post_div_real = clk.xclk_post_div;
1885*4882a593Smuzhiyun pll->ct.vclk_fb_div = clk.vclk_fb_div;
1886*4882a593Smuzhiyun pll->ct.vclk_post_div_real = clk.vclk_post_div;
1887*4882a593Smuzhiyun pll->ct.dsp_config = (clk.dsp_xclks_per_row & 0x3fff) |
1888*4882a593Smuzhiyun ((clk.dsp_loop_latency & 0xf) << 16) |
1889*4882a593Smuzhiyun ((clk.dsp_precision & 7) << 20);
1890*4882a593Smuzhiyun pll->ct.dsp_on_off = (clk.dsp_off & 0x7ff) |
1891*4882a593Smuzhiyun ((clk.dsp_on & 0x7ff) << 16);
1892*4882a593Smuzhiyun /*aty_calc_pll_ct(info, &pll->ct);*/
1893*4882a593Smuzhiyun aty_set_pll_ct(info, pll);
1894*4882a593Smuzhiyun } else
1895*4882a593Smuzhiyun return -EINVAL;
1896*4882a593Smuzhiyun break;
1897*4882a593Smuzhiyun case ATYIO_FEATR:
1898*4882a593Smuzhiyun if (get_user(par->features, (u32 __user *) arg))
1899*4882a593Smuzhiyun return -EFAULT;
1900*4882a593Smuzhiyun break;
1901*4882a593Smuzhiyun case ATYIO_FEATW:
1902*4882a593Smuzhiyun if (put_user(par->features, (u32 __user *) arg))
1903*4882a593Smuzhiyun return -EFAULT;
1904*4882a593Smuzhiyun break;
1905*4882a593Smuzhiyun #endif /* DEBUG && CONFIG_FB_ATY_CT */
1906*4882a593Smuzhiyun default:
1907*4882a593Smuzhiyun return -EINVAL;
1908*4882a593Smuzhiyun }
1909*4882a593Smuzhiyun return 0;
1910*4882a593Smuzhiyun }
1911*4882a593Smuzhiyun
atyfb_sync(struct fb_info * info)1912*4882a593Smuzhiyun static int atyfb_sync(struct fb_info *info)
1913*4882a593Smuzhiyun {
1914*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
1915*4882a593Smuzhiyun
1916*4882a593Smuzhiyun if (par->blitter_may_be_busy)
1917*4882a593Smuzhiyun wait_for_idle(par);
1918*4882a593Smuzhiyun return 0;
1919*4882a593Smuzhiyun }
1920*4882a593Smuzhiyun
1921*4882a593Smuzhiyun #ifdef __sparc__
atyfb_mmap(struct fb_info * info,struct vm_area_struct * vma)1922*4882a593Smuzhiyun static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
1923*4882a593Smuzhiyun {
1924*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
1925*4882a593Smuzhiyun unsigned int size, page, map_size = 0;
1926*4882a593Smuzhiyun unsigned long map_offset = 0;
1927*4882a593Smuzhiyun unsigned long off;
1928*4882a593Smuzhiyun int i;
1929*4882a593Smuzhiyun
1930*4882a593Smuzhiyun if (!par->mmap_map)
1931*4882a593Smuzhiyun return -ENXIO;
1932*4882a593Smuzhiyun
1933*4882a593Smuzhiyun if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1934*4882a593Smuzhiyun return -EINVAL;
1935*4882a593Smuzhiyun
1936*4882a593Smuzhiyun off = vma->vm_pgoff << PAGE_SHIFT;
1937*4882a593Smuzhiyun size = vma->vm_end - vma->vm_start;
1938*4882a593Smuzhiyun
1939*4882a593Smuzhiyun /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */
1940*4882a593Smuzhiyun
1941*4882a593Smuzhiyun if (((vma->vm_pgoff == 0) && (size == info->fix.smem_len)) ||
1942*4882a593Smuzhiyun ((off == info->fix.smem_len) && (size == PAGE_SIZE)))
1943*4882a593Smuzhiyun off += 0x8000000000000000UL;
1944*4882a593Smuzhiyun
1945*4882a593Smuzhiyun vma->vm_pgoff = off >> PAGE_SHIFT; /* propagate off changes */
1946*4882a593Smuzhiyun
1947*4882a593Smuzhiyun /* Each page, see which map applies */
1948*4882a593Smuzhiyun for (page = 0; page < size;) {
1949*4882a593Smuzhiyun map_size = 0;
1950*4882a593Smuzhiyun for (i = 0; par->mmap_map[i].size; i++) {
1951*4882a593Smuzhiyun unsigned long start = par->mmap_map[i].voff;
1952*4882a593Smuzhiyun unsigned long end = start + par->mmap_map[i].size;
1953*4882a593Smuzhiyun unsigned long offset = off + page;
1954*4882a593Smuzhiyun
1955*4882a593Smuzhiyun if (start > offset)
1956*4882a593Smuzhiyun continue;
1957*4882a593Smuzhiyun if (offset >= end)
1958*4882a593Smuzhiyun continue;
1959*4882a593Smuzhiyun
1960*4882a593Smuzhiyun map_size = par->mmap_map[i].size - (offset - start);
1961*4882a593Smuzhiyun map_offset = par->mmap_map[i].poff + (offset - start);
1962*4882a593Smuzhiyun break;
1963*4882a593Smuzhiyun }
1964*4882a593Smuzhiyun if (!map_size) {
1965*4882a593Smuzhiyun page += PAGE_SIZE;
1966*4882a593Smuzhiyun continue;
1967*4882a593Smuzhiyun }
1968*4882a593Smuzhiyun if (page + map_size > size)
1969*4882a593Smuzhiyun map_size = size - page;
1970*4882a593Smuzhiyun
1971*4882a593Smuzhiyun pgprot_val(vma->vm_page_prot) &= ~(par->mmap_map[i].prot_mask);
1972*4882a593Smuzhiyun pgprot_val(vma->vm_page_prot) |= par->mmap_map[i].prot_flag;
1973*4882a593Smuzhiyun
1974*4882a593Smuzhiyun if (remap_pfn_range(vma, vma->vm_start + page,
1975*4882a593Smuzhiyun map_offset >> PAGE_SHIFT, map_size, vma->vm_page_prot))
1976*4882a593Smuzhiyun return -EAGAIN;
1977*4882a593Smuzhiyun
1978*4882a593Smuzhiyun page += map_size;
1979*4882a593Smuzhiyun }
1980*4882a593Smuzhiyun
1981*4882a593Smuzhiyun if (!map_size)
1982*4882a593Smuzhiyun return -EINVAL;
1983*4882a593Smuzhiyun
1984*4882a593Smuzhiyun if (!par->mmaped)
1985*4882a593Smuzhiyun par->mmaped = 1;
1986*4882a593Smuzhiyun return 0;
1987*4882a593Smuzhiyun }
1988*4882a593Smuzhiyun #endif /* __sparc__ */
1989*4882a593Smuzhiyun
1990*4882a593Smuzhiyun
1991*4882a593Smuzhiyun
1992*4882a593Smuzhiyun #if defined(CONFIG_PCI)
1993*4882a593Smuzhiyun
1994*4882a593Smuzhiyun #ifdef CONFIG_PPC_PMAC
1995*4882a593Smuzhiyun /* Power management routines. Those are used for PowerBook sleep.
1996*4882a593Smuzhiyun */
aty_power_mgmt(int sleep,struct atyfb_par * par)1997*4882a593Smuzhiyun static int aty_power_mgmt(int sleep, struct atyfb_par *par)
1998*4882a593Smuzhiyun {
1999*4882a593Smuzhiyun u32 pm;
2000*4882a593Smuzhiyun int timeout;
2001*4882a593Smuzhiyun
2002*4882a593Smuzhiyun pm = aty_ld_lcd(POWER_MANAGEMENT, par);
2003*4882a593Smuzhiyun pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
2004*4882a593Smuzhiyun aty_st_lcd(POWER_MANAGEMENT, pm, par);
2005*4882a593Smuzhiyun pm = aty_ld_lcd(POWER_MANAGEMENT, par);
2006*4882a593Smuzhiyun
2007*4882a593Smuzhiyun timeout = 2000;
2008*4882a593Smuzhiyun if (sleep) {
2009*4882a593Smuzhiyun /* Sleep */
2010*4882a593Smuzhiyun pm &= ~PWR_MGT_ON;
2011*4882a593Smuzhiyun aty_st_lcd(POWER_MANAGEMENT, pm, par);
2012*4882a593Smuzhiyun pm = aty_ld_lcd(POWER_MANAGEMENT, par);
2013*4882a593Smuzhiyun udelay(10);
2014*4882a593Smuzhiyun pm &= ~(PWR_BLON | AUTO_PWR_UP);
2015*4882a593Smuzhiyun pm |= SUSPEND_NOW;
2016*4882a593Smuzhiyun aty_st_lcd(POWER_MANAGEMENT, pm, par);
2017*4882a593Smuzhiyun pm = aty_ld_lcd(POWER_MANAGEMENT, par);
2018*4882a593Smuzhiyun udelay(10);
2019*4882a593Smuzhiyun pm |= PWR_MGT_ON;
2020*4882a593Smuzhiyun aty_st_lcd(POWER_MANAGEMENT, pm, par);
2021*4882a593Smuzhiyun do {
2022*4882a593Smuzhiyun pm = aty_ld_lcd(POWER_MANAGEMENT, par);
2023*4882a593Smuzhiyun mdelay(1);
2024*4882a593Smuzhiyun if ((--timeout) == 0)
2025*4882a593Smuzhiyun break;
2026*4882a593Smuzhiyun } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
2027*4882a593Smuzhiyun } else {
2028*4882a593Smuzhiyun /* Wakeup */
2029*4882a593Smuzhiyun pm &= ~PWR_MGT_ON;
2030*4882a593Smuzhiyun aty_st_lcd(POWER_MANAGEMENT, pm, par);
2031*4882a593Smuzhiyun pm = aty_ld_lcd(POWER_MANAGEMENT, par);
2032*4882a593Smuzhiyun udelay(10);
2033*4882a593Smuzhiyun pm &= ~SUSPEND_NOW;
2034*4882a593Smuzhiyun pm |= (PWR_BLON | AUTO_PWR_UP);
2035*4882a593Smuzhiyun aty_st_lcd(POWER_MANAGEMENT, pm, par);
2036*4882a593Smuzhiyun pm = aty_ld_lcd(POWER_MANAGEMENT, par);
2037*4882a593Smuzhiyun udelay(10);
2038*4882a593Smuzhiyun pm |= PWR_MGT_ON;
2039*4882a593Smuzhiyun aty_st_lcd(POWER_MANAGEMENT, pm, par);
2040*4882a593Smuzhiyun do {
2041*4882a593Smuzhiyun pm = aty_ld_lcd(POWER_MANAGEMENT, par);
2042*4882a593Smuzhiyun mdelay(1);
2043*4882a593Smuzhiyun if ((--timeout) == 0)
2044*4882a593Smuzhiyun break;
2045*4882a593Smuzhiyun } while ((pm & PWR_MGT_STATUS_MASK) != 0);
2046*4882a593Smuzhiyun }
2047*4882a593Smuzhiyun mdelay(500);
2048*4882a593Smuzhiyun
2049*4882a593Smuzhiyun return timeout ? 0 : -EIO;
2050*4882a593Smuzhiyun }
2051*4882a593Smuzhiyun #endif /* CONFIG_PPC_PMAC */
2052*4882a593Smuzhiyun
atyfb_pci_suspend_late(struct device * dev,pm_message_t state)2053*4882a593Smuzhiyun static int atyfb_pci_suspend_late(struct device *dev, pm_message_t state)
2054*4882a593Smuzhiyun {
2055*4882a593Smuzhiyun struct pci_dev *pdev = to_pci_dev(dev);
2056*4882a593Smuzhiyun struct fb_info *info = pci_get_drvdata(pdev);
2057*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
2058*4882a593Smuzhiyun
2059*4882a593Smuzhiyun if (state.event == pdev->dev.power.power_state.event)
2060*4882a593Smuzhiyun return 0;
2061*4882a593Smuzhiyun
2062*4882a593Smuzhiyun console_lock();
2063*4882a593Smuzhiyun
2064*4882a593Smuzhiyun fb_set_suspend(info, 1);
2065*4882a593Smuzhiyun
2066*4882a593Smuzhiyun /* Idle & reset engine */
2067*4882a593Smuzhiyun wait_for_idle(par);
2068*4882a593Smuzhiyun aty_reset_engine(par);
2069*4882a593Smuzhiyun
2070*4882a593Smuzhiyun /* Blank display and LCD */
2071*4882a593Smuzhiyun atyfb_blank(FB_BLANK_POWERDOWN, info);
2072*4882a593Smuzhiyun
2073*4882a593Smuzhiyun par->asleep = 1;
2074*4882a593Smuzhiyun par->lock_blank = 1;
2075*4882a593Smuzhiyun
2076*4882a593Smuzhiyun /*
2077*4882a593Smuzhiyun * Because we may change PCI D state ourselves, we need to
2078*4882a593Smuzhiyun * first save the config space content so the core can
2079*4882a593Smuzhiyun * restore it properly on resume.
2080*4882a593Smuzhiyun */
2081*4882a593Smuzhiyun
2082*4882a593Smuzhiyun #ifdef CONFIG_PPC_PMAC
2083*4882a593Smuzhiyun /* Set chip to "suspend" mode */
2084*4882a593Smuzhiyun if (machine_is(powermac) && aty_power_mgmt(1, par)) {
2085*4882a593Smuzhiyun par->asleep = 0;
2086*4882a593Smuzhiyun par->lock_blank = 0;
2087*4882a593Smuzhiyun atyfb_blank(FB_BLANK_UNBLANK, info);
2088*4882a593Smuzhiyun fb_set_suspend(info, 0);
2089*4882a593Smuzhiyun console_unlock();
2090*4882a593Smuzhiyun return -EIO;
2091*4882a593Smuzhiyun }
2092*4882a593Smuzhiyun #endif
2093*4882a593Smuzhiyun
2094*4882a593Smuzhiyun console_unlock();
2095*4882a593Smuzhiyun
2096*4882a593Smuzhiyun pdev->dev.power.power_state = state;
2097*4882a593Smuzhiyun
2098*4882a593Smuzhiyun return 0;
2099*4882a593Smuzhiyun }
2100*4882a593Smuzhiyun
atyfb_pci_suspend(struct device * dev)2101*4882a593Smuzhiyun static int __maybe_unused atyfb_pci_suspend(struct device *dev)
2102*4882a593Smuzhiyun {
2103*4882a593Smuzhiyun return atyfb_pci_suspend_late(dev, PMSG_SUSPEND);
2104*4882a593Smuzhiyun }
2105*4882a593Smuzhiyun
atyfb_pci_hibernate(struct device * dev)2106*4882a593Smuzhiyun static int __maybe_unused atyfb_pci_hibernate(struct device *dev)
2107*4882a593Smuzhiyun {
2108*4882a593Smuzhiyun return atyfb_pci_suspend_late(dev, PMSG_HIBERNATE);
2109*4882a593Smuzhiyun }
2110*4882a593Smuzhiyun
atyfb_pci_freeze(struct device * dev)2111*4882a593Smuzhiyun static int __maybe_unused atyfb_pci_freeze(struct device *dev)
2112*4882a593Smuzhiyun {
2113*4882a593Smuzhiyun return atyfb_pci_suspend_late(dev, PMSG_FREEZE);
2114*4882a593Smuzhiyun }
2115*4882a593Smuzhiyun
aty_resume_chip(struct fb_info * info)2116*4882a593Smuzhiyun static void aty_resume_chip(struct fb_info *info)
2117*4882a593Smuzhiyun {
2118*4882a593Smuzhiyun struct atyfb_par *par = info->par;
2119*4882a593Smuzhiyun
2120*4882a593Smuzhiyun aty_st_le32(MEM_CNTL, par->mem_cntl, par);
2121*4882a593Smuzhiyun
2122*4882a593Smuzhiyun if (par->pll_ops->resume_pll)
2123*4882a593Smuzhiyun par->pll_ops->resume_pll(info, &par->pll);
2124*4882a593Smuzhiyun
2125*4882a593Smuzhiyun if (par->aux_start)
2126*4882a593Smuzhiyun aty_st_le32(BUS_CNTL,
2127*4882a593Smuzhiyun aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);
2128*4882a593Smuzhiyun }
2129*4882a593Smuzhiyun
atyfb_pci_resume(struct device * dev)2130*4882a593Smuzhiyun static int __maybe_unused atyfb_pci_resume(struct device *dev)
2131*4882a593Smuzhiyun {
2132*4882a593Smuzhiyun struct pci_dev *pdev = to_pci_dev(dev);
2133*4882a593Smuzhiyun struct fb_info *info = pci_get_drvdata(pdev);
2134*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
2135*4882a593Smuzhiyun
2136*4882a593Smuzhiyun if (pdev->dev.power.power_state.event == PM_EVENT_ON)
2137*4882a593Smuzhiyun return 0;
2138*4882a593Smuzhiyun
2139*4882a593Smuzhiyun console_lock();
2140*4882a593Smuzhiyun
2141*4882a593Smuzhiyun /*
2142*4882a593Smuzhiyun * PCI state will have been restored by the core, so
2143*4882a593Smuzhiyun * we should be in D0 now with our config space fully
2144*4882a593Smuzhiyun * restored
2145*4882a593Smuzhiyun */
2146*4882a593Smuzhiyun
2147*4882a593Smuzhiyun #ifdef CONFIG_PPC_PMAC
2148*4882a593Smuzhiyun if (machine_is(powermac) &&
2149*4882a593Smuzhiyun pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
2150*4882a593Smuzhiyun aty_power_mgmt(0, par);
2151*4882a593Smuzhiyun #endif
2152*4882a593Smuzhiyun
2153*4882a593Smuzhiyun aty_resume_chip(info);
2154*4882a593Smuzhiyun
2155*4882a593Smuzhiyun par->asleep = 0;
2156*4882a593Smuzhiyun
2157*4882a593Smuzhiyun /* Restore display */
2158*4882a593Smuzhiyun atyfb_set_par(info);
2159*4882a593Smuzhiyun
2160*4882a593Smuzhiyun /* Refresh */
2161*4882a593Smuzhiyun fb_set_suspend(info, 0);
2162*4882a593Smuzhiyun
2163*4882a593Smuzhiyun /* Unblank */
2164*4882a593Smuzhiyun par->lock_blank = 0;
2165*4882a593Smuzhiyun atyfb_blank(FB_BLANK_UNBLANK, info);
2166*4882a593Smuzhiyun
2167*4882a593Smuzhiyun console_unlock();
2168*4882a593Smuzhiyun
2169*4882a593Smuzhiyun pdev->dev.power.power_state = PMSG_ON;
2170*4882a593Smuzhiyun
2171*4882a593Smuzhiyun return 0;
2172*4882a593Smuzhiyun }
2173*4882a593Smuzhiyun
2174*4882a593Smuzhiyun static const struct dev_pm_ops atyfb_pci_pm_ops = {
2175*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
2176*4882a593Smuzhiyun .suspend = atyfb_pci_suspend,
2177*4882a593Smuzhiyun .resume = atyfb_pci_resume,
2178*4882a593Smuzhiyun .freeze = atyfb_pci_freeze,
2179*4882a593Smuzhiyun .thaw = atyfb_pci_resume,
2180*4882a593Smuzhiyun .poweroff = atyfb_pci_hibernate,
2181*4882a593Smuzhiyun .restore = atyfb_pci_resume,
2182*4882a593Smuzhiyun #endif /* CONFIG_PM_SLEEP */
2183*4882a593Smuzhiyun };
2184*4882a593Smuzhiyun
2185*4882a593Smuzhiyun #endif /* defined(CONFIG_PCI) */
2186*4882a593Smuzhiyun
2187*4882a593Smuzhiyun /* Backlight */
2188*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_BACKLIGHT
2189*4882a593Smuzhiyun #define MAX_LEVEL 0xFF
2190*4882a593Smuzhiyun
aty_bl_get_level_brightness(struct atyfb_par * par,int level)2191*4882a593Smuzhiyun static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
2192*4882a593Smuzhiyun {
2193*4882a593Smuzhiyun struct fb_info *info = pci_get_drvdata(par->pdev);
2194*4882a593Smuzhiyun int atylevel;
2195*4882a593Smuzhiyun
2196*4882a593Smuzhiyun /* Get and convert the value */
2197*4882a593Smuzhiyun /* No locking of bl_curve since we read a single value */
2198*4882a593Smuzhiyun atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
2199*4882a593Smuzhiyun
2200*4882a593Smuzhiyun if (atylevel < 0)
2201*4882a593Smuzhiyun atylevel = 0;
2202*4882a593Smuzhiyun else if (atylevel > MAX_LEVEL)
2203*4882a593Smuzhiyun atylevel = MAX_LEVEL;
2204*4882a593Smuzhiyun
2205*4882a593Smuzhiyun return atylevel;
2206*4882a593Smuzhiyun }
2207*4882a593Smuzhiyun
aty_bl_update_status(struct backlight_device * bd)2208*4882a593Smuzhiyun static int aty_bl_update_status(struct backlight_device *bd)
2209*4882a593Smuzhiyun {
2210*4882a593Smuzhiyun struct atyfb_par *par = bl_get_data(bd);
2211*4882a593Smuzhiyun unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
2212*4882a593Smuzhiyun int level;
2213*4882a593Smuzhiyun
2214*4882a593Smuzhiyun if (bd->props.power != FB_BLANK_UNBLANK ||
2215*4882a593Smuzhiyun bd->props.fb_blank != FB_BLANK_UNBLANK)
2216*4882a593Smuzhiyun level = 0;
2217*4882a593Smuzhiyun else
2218*4882a593Smuzhiyun level = bd->props.brightness;
2219*4882a593Smuzhiyun
2220*4882a593Smuzhiyun reg |= (BLMOD_EN | BIASMOD_EN);
2221*4882a593Smuzhiyun if (level > 0) {
2222*4882a593Smuzhiyun reg &= ~BIAS_MOD_LEVEL_MASK;
2223*4882a593Smuzhiyun reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT);
2224*4882a593Smuzhiyun } else {
2225*4882a593Smuzhiyun reg &= ~BIAS_MOD_LEVEL_MASK;
2226*4882a593Smuzhiyun reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT);
2227*4882a593Smuzhiyun }
2228*4882a593Smuzhiyun aty_st_lcd(LCD_MISC_CNTL, reg, par);
2229*4882a593Smuzhiyun
2230*4882a593Smuzhiyun return 0;
2231*4882a593Smuzhiyun }
2232*4882a593Smuzhiyun
2233*4882a593Smuzhiyun static const struct backlight_ops aty_bl_data = {
2234*4882a593Smuzhiyun .update_status = aty_bl_update_status,
2235*4882a593Smuzhiyun };
2236*4882a593Smuzhiyun
aty_bl_init(struct atyfb_par * par)2237*4882a593Smuzhiyun static void aty_bl_init(struct atyfb_par *par)
2238*4882a593Smuzhiyun {
2239*4882a593Smuzhiyun struct backlight_properties props;
2240*4882a593Smuzhiyun struct fb_info *info = pci_get_drvdata(par->pdev);
2241*4882a593Smuzhiyun struct backlight_device *bd;
2242*4882a593Smuzhiyun char name[12];
2243*4882a593Smuzhiyun
2244*4882a593Smuzhiyun #ifdef CONFIG_PMAC_BACKLIGHT
2245*4882a593Smuzhiyun if (!pmac_has_backlight_type("ati"))
2246*4882a593Smuzhiyun return;
2247*4882a593Smuzhiyun #endif
2248*4882a593Smuzhiyun
2249*4882a593Smuzhiyun snprintf(name, sizeof(name), "atybl%d", info->node);
2250*4882a593Smuzhiyun
2251*4882a593Smuzhiyun memset(&props, 0, sizeof(struct backlight_properties));
2252*4882a593Smuzhiyun props.type = BACKLIGHT_RAW;
2253*4882a593Smuzhiyun props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
2254*4882a593Smuzhiyun bd = backlight_device_register(name, info->dev, par, &aty_bl_data,
2255*4882a593Smuzhiyun &props);
2256*4882a593Smuzhiyun if (IS_ERR(bd)) {
2257*4882a593Smuzhiyun info->bl_dev = NULL;
2258*4882a593Smuzhiyun printk(KERN_WARNING "aty: Backlight registration failed\n");
2259*4882a593Smuzhiyun goto error;
2260*4882a593Smuzhiyun }
2261*4882a593Smuzhiyun
2262*4882a593Smuzhiyun info->bl_dev = bd;
2263*4882a593Smuzhiyun fb_bl_default_curve(info, 0,
2264*4882a593Smuzhiyun 0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,
2265*4882a593Smuzhiyun 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
2266*4882a593Smuzhiyun
2267*4882a593Smuzhiyun bd->props.brightness = bd->props.max_brightness;
2268*4882a593Smuzhiyun bd->props.power = FB_BLANK_UNBLANK;
2269*4882a593Smuzhiyun backlight_update_status(bd);
2270*4882a593Smuzhiyun
2271*4882a593Smuzhiyun printk("aty: Backlight initialized (%s)\n", name);
2272*4882a593Smuzhiyun
2273*4882a593Smuzhiyun return;
2274*4882a593Smuzhiyun
2275*4882a593Smuzhiyun error:
2276*4882a593Smuzhiyun return;
2277*4882a593Smuzhiyun }
2278*4882a593Smuzhiyun
2279*4882a593Smuzhiyun #ifdef CONFIG_PCI
aty_bl_exit(struct backlight_device * bd)2280*4882a593Smuzhiyun static void aty_bl_exit(struct backlight_device *bd)
2281*4882a593Smuzhiyun {
2282*4882a593Smuzhiyun backlight_device_unregister(bd);
2283*4882a593Smuzhiyun printk("aty: Backlight unloaded\n");
2284*4882a593Smuzhiyun }
2285*4882a593Smuzhiyun #endif /* CONFIG_PCI */
2286*4882a593Smuzhiyun
2287*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_BACKLIGHT */
2288*4882a593Smuzhiyun
aty_calc_mem_refresh(struct atyfb_par * par,int xclk)2289*4882a593Smuzhiyun static void aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
2290*4882a593Smuzhiyun {
2291*4882a593Smuzhiyun static const int ragepro_tbl[] = {
2292*4882a593Smuzhiyun 44, 50, 55, 66, 75, 80, 100
2293*4882a593Smuzhiyun };
2294*4882a593Smuzhiyun static const int ragexl_tbl[] = {
2295*4882a593Smuzhiyun 50, 66, 75, 83, 90, 95, 100, 105,
2296*4882a593Smuzhiyun 110, 115, 120, 125, 133, 143, 166
2297*4882a593Smuzhiyun };
2298*4882a593Smuzhiyun const int *refresh_tbl;
2299*4882a593Smuzhiyun int i, size;
2300*4882a593Smuzhiyun
2301*4882a593Smuzhiyun if (M64_HAS(XL_MEM)) {
2302*4882a593Smuzhiyun refresh_tbl = ragexl_tbl;
2303*4882a593Smuzhiyun size = ARRAY_SIZE(ragexl_tbl);
2304*4882a593Smuzhiyun } else {
2305*4882a593Smuzhiyun refresh_tbl = ragepro_tbl;
2306*4882a593Smuzhiyun size = ARRAY_SIZE(ragepro_tbl);
2307*4882a593Smuzhiyun }
2308*4882a593Smuzhiyun
2309*4882a593Smuzhiyun for (i = 0; i < size; i++) {
2310*4882a593Smuzhiyun if (xclk < refresh_tbl[i])
2311*4882a593Smuzhiyun break;
2312*4882a593Smuzhiyun }
2313*4882a593Smuzhiyun par->mem_refresh_rate = i;
2314*4882a593Smuzhiyun }
2315*4882a593Smuzhiyun
2316*4882a593Smuzhiyun /*
2317*4882a593Smuzhiyun * Initialisation
2318*4882a593Smuzhiyun */
2319*4882a593Smuzhiyun
2320*4882a593Smuzhiyun static struct fb_info *fb_list = NULL;
2321*4882a593Smuzhiyun
2322*4882a593Smuzhiyun #if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD)
atyfb_get_timings_from_lcd(struct atyfb_par * par,struct fb_var_screeninfo * var)2323*4882a593Smuzhiyun static int atyfb_get_timings_from_lcd(struct atyfb_par *par,
2324*4882a593Smuzhiyun struct fb_var_screeninfo *var)
2325*4882a593Smuzhiyun {
2326*4882a593Smuzhiyun int ret = -EINVAL;
2327*4882a593Smuzhiyun
2328*4882a593Smuzhiyun if (par->lcd_table != 0 && (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
2329*4882a593Smuzhiyun *var = default_var;
2330*4882a593Smuzhiyun var->xres = var->xres_virtual = par->lcd_hdisp;
2331*4882a593Smuzhiyun var->right_margin = par->lcd_right_margin;
2332*4882a593Smuzhiyun var->left_margin = par->lcd_hblank_len -
2333*4882a593Smuzhiyun (par->lcd_right_margin + par->lcd_hsync_dly +
2334*4882a593Smuzhiyun par->lcd_hsync_len);
2335*4882a593Smuzhiyun var->hsync_len = par->lcd_hsync_len + par->lcd_hsync_dly;
2336*4882a593Smuzhiyun var->yres = var->yres_virtual = par->lcd_vdisp;
2337*4882a593Smuzhiyun var->lower_margin = par->lcd_lower_margin;
2338*4882a593Smuzhiyun var->upper_margin = par->lcd_vblank_len -
2339*4882a593Smuzhiyun (par->lcd_lower_margin + par->lcd_vsync_len);
2340*4882a593Smuzhiyun var->vsync_len = par->lcd_vsync_len;
2341*4882a593Smuzhiyun var->pixclock = par->lcd_pixclock;
2342*4882a593Smuzhiyun ret = 0;
2343*4882a593Smuzhiyun }
2344*4882a593Smuzhiyun
2345*4882a593Smuzhiyun return ret;
2346*4882a593Smuzhiyun }
2347*4882a593Smuzhiyun #endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */
2348*4882a593Smuzhiyun
aty_init(struct fb_info * info)2349*4882a593Smuzhiyun static int aty_init(struct fb_info *info)
2350*4882a593Smuzhiyun {
2351*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
2352*4882a593Smuzhiyun const char *ramname = NULL, *xtal;
2353*4882a593Smuzhiyun int gtb_memsize, has_var = 0;
2354*4882a593Smuzhiyun struct fb_var_screeninfo var;
2355*4882a593Smuzhiyun int ret;
2356*4882a593Smuzhiyun
2357*4882a593Smuzhiyun init_waitqueue_head(&par->vblank.wait);
2358*4882a593Smuzhiyun spin_lock_init(&par->int_lock);
2359*4882a593Smuzhiyun
2360*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GX
2361*4882a593Smuzhiyun if (!M64_HAS(INTEGRATED)) {
2362*4882a593Smuzhiyun u32 stat0;
2363*4882a593Smuzhiyun u8 dac_type, dac_subtype, clk_type;
2364*4882a593Smuzhiyun stat0 = aty_ld_le32(CNFG_STAT0, par);
2365*4882a593Smuzhiyun par->bus_type = (stat0 >> 0) & 0x07;
2366*4882a593Smuzhiyun par->ram_type = (stat0 >> 3) & 0x07;
2367*4882a593Smuzhiyun ramname = aty_gx_ram[par->ram_type];
2368*4882a593Smuzhiyun /* FIXME: clockchip/RAMDAC probing? */
2369*4882a593Smuzhiyun dac_type = (aty_ld_le32(DAC_CNTL, par) >> 16) & 0x07;
2370*4882a593Smuzhiyun #ifdef CONFIG_ATARI
2371*4882a593Smuzhiyun clk_type = CLK_ATI18818_1;
2372*4882a593Smuzhiyun dac_type = (stat0 >> 9) & 0x07;
2373*4882a593Smuzhiyun if (dac_type == 0x07)
2374*4882a593Smuzhiyun dac_subtype = DAC_ATT20C408;
2375*4882a593Smuzhiyun else
2376*4882a593Smuzhiyun dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, par) & 0xF0) | dac_type;
2377*4882a593Smuzhiyun #else
2378*4882a593Smuzhiyun dac_type = DAC_IBMRGB514;
2379*4882a593Smuzhiyun dac_subtype = DAC_IBMRGB514;
2380*4882a593Smuzhiyun clk_type = CLK_IBMRGB514;
2381*4882a593Smuzhiyun #endif
2382*4882a593Smuzhiyun switch (dac_subtype) {
2383*4882a593Smuzhiyun case DAC_IBMRGB514:
2384*4882a593Smuzhiyun par->dac_ops = &aty_dac_ibm514;
2385*4882a593Smuzhiyun break;
2386*4882a593Smuzhiyun #ifdef CONFIG_ATARI
2387*4882a593Smuzhiyun case DAC_ATI68860_B:
2388*4882a593Smuzhiyun case DAC_ATI68860_C:
2389*4882a593Smuzhiyun par->dac_ops = &aty_dac_ati68860b;
2390*4882a593Smuzhiyun break;
2391*4882a593Smuzhiyun case DAC_ATT20C408:
2392*4882a593Smuzhiyun case DAC_ATT21C498:
2393*4882a593Smuzhiyun par->dac_ops = &aty_dac_att21c498;
2394*4882a593Smuzhiyun break;
2395*4882a593Smuzhiyun #endif
2396*4882a593Smuzhiyun default:
2397*4882a593Smuzhiyun PRINTKI("aty_init: DAC type not implemented yet!\n");
2398*4882a593Smuzhiyun par->dac_ops = &aty_dac_unsupported;
2399*4882a593Smuzhiyun break;
2400*4882a593Smuzhiyun }
2401*4882a593Smuzhiyun switch (clk_type) {
2402*4882a593Smuzhiyun #ifdef CONFIG_ATARI
2403*4882a593Smuzhiyun case CLK_ATI18818_1:
2404*4882a593Smuzhiyun par->pll_ops = &aty_pll_ati18818_1;
2405*4882a593Smuzhiyun break;
2406*4882a593Smuzhiyun #else
2407*4882a593Smuzhiyun case CLK_IBMRGB514:
2408*4882a593Smuzhiyun par->pll_ops = &aty_pll_ibm514;
2409*4882a593Smuzhiyun break;
2410*4882a593Smuzhiyun #endif
2411*4882a593Smuzhiyun default:
2412*4882a593Smuzhiyun PRINTKI("aty_init: CLK type not implemented yet!");
2413*4882a593Smuzhiyun par->pll_ops = &aty_pll_unsupported;
2414*4882a593Smuzhiyun break;
2415*4882a593Smuzhiyun }
2416*4882a593Smuzhiyun }
2417*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_GX */
2418*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_CT
2419*4882a593Smuzhiyun if (M64_HAS(INTEGRATED)) {
2420*4882a593Smuzhiyun par->dac_ops = &aty_dac_ct;
2421*4882a593Smuzhiyun par->pll_ops = &aty_pll_ct;
2422*4882a593Smuzhiyun par->bus_type = PCI;
2423*4882a593Smuzhiyun par->ram_type = (aty_ld_le32(CNFG_STAT0, par) & 0x07);
2424*4882a593Smuzhiyun if (M64_HAS(XL_MEM))
2425*4882a593Smuzhiyun ramname = aty_xl_ram[par->ram_type];
2426*4882a593Smuzhiyun else
2427*4882a593Smuzhiyun ramname = aty_ct_ram[par->ram_type];
2428*4882a593Smuzhiyun /* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */
2429*4882a593Smuzhiyun if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM)
2430*4882a593Smuzhiyun par->pll_limits.mclk = 63;
2431*4882a593Smuzhiyun /* Mobility + 32bit memory interface need halved XCLK. */
2432*4882a593Smuzhiyun if (M64_HAS(MOBIL_BUS) && par->ram_type == SDRAM32)
2433*4882a593Smuzhiyun par->pll_limits.xclk = (par->pll_limits.xclk + 1) >> 1;
2434*4882a593Smuzhiyun }
2435*4882a593Smuzhiyun #endif
2436*4882a593Smuzhiyun #ifdef CONFIG_PPC_PMAC
2437*4882a593Smuzhiyun /*
2438*4882a593Smuzhiyun * The Apple iBook1 uses non-standard memory frequencies.
2439*4882a593Smuzhiyun * We detect it and set the frequency manually.
2440*4882a593Smuzhiyun */
2441*4882a593Smuzhiyun if (of_machine_is_compatible("PowerBook2,1")) {
2442*4882a593Smuzhiyun par->pll_limits.mclk = 70;
2443*4882a593Smuzhiyun par->pll_limits.xclk = 53;
2444*4882a593Smuzhiyun }
2445*4882a593Smuzhiyun #endif
2446*4882a593Smuzhiyun
2447*4882a593Smuzhiyun /* Allow command line to override clocks. */
2448*4882a593Smuzhiyun if (pll)
2449*4882a593Smuzhiyun par->pll_limits.pll_max = pll;
2450*4882a593Smuzhiyun if (mclk)
2451*4882a593Smuzhiyun par->pll_limits.mclk = mclk;
2452*4882a593Smuzhiyun if (xclk)
2453*4882a593Smuzhiyun par->pll_limits.xclk = xclk;
2454*4882a593Smuzhiyun
2455*4882a593Smuzhiyun aty_calc_mem_refresh(par, par->pll_limits.xclk);
2456*4882a593Smuzhiyun par->pll_per = 1000000/par->pll_limits.pll_max;
2457*4882a593Smuzhiyun par->mclk_per = 1000000/par->pll_limits.mclk;
2458*4882a593Smuzhiyun par->xclk_per = 1000000/par->pll_limits.xclk;
2459*4882a593Smuzhiyun
2460*4882a593Smuzhiyun par->ref_clk_per = 1000000000000ULL / 14318180;
2461*4882a593Smuzhiyun xtal = "14.31818";
2462*4882a593Smuzhiyun
2463*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_CT
2464*4882a593Smuzhiyun if (M64_HAS(GTB_DSP)) {
2465*4882a593Smuzhiyun u8 pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
2466*4882a593Smuzhiyun
2467*4882a593Smuzhiyun if (pll_ref_div) {
2468*4882a593Smuzhiyun int diff1, diff2;
2469*4882a593Smuzhiyun diff1 = 510 * 14 / pll_ref_div - par->pll_limits.pll_max;
2470*4882a593Smuzhiyun diff2 = 510 * 29 / pll_ref_div - par->pll_limits.pll_max;
2471*4882a593Smuzhiyun if (diff1 < 0)
2472*4882a593Smuzhiyun diff1 = -diff1;
2473*4882a593Smuzhiyun if (diff2 < 0)
2474*4882a593Smuzhiyun diff2 = -diff2;
2475*4882a593Smuzhiyun if (diff2 < diff1) {
2476*4882a593Smuzhiyun par->ref_clk_per = 1000000000000ULL / 29498928;
2477*4882a593Smuzhiyun xtal = "29.498928";
2478*4882a593Smuzhiyun }
2479*4882a593Smuzhiyun }
2480*4882a593Smuzhiyun }
2481*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_CT */
2482*4882a593Smuzhiyun
2483*4882a593Smuzhiyun /* save previous video mode */
2484*4882a593Smuzhiyun aty_get_crtc(par, &par->saved_crtc);
2485*4882a593Smuzhiyun if (par->pll_ops->get_pll)
2486*4882a593Smuzhiyun par->pll_ops->get_pll(info, &par->saved_pll);
2487*4882a593Smuzhiyun
2488*4882a593Smuzhiyun par->mem_cntl = aty_ld_le32(MEM_CNTL, par);
2489*4882a593Smuzhiyun gtb_memsize = M64_HAS(GTB_DSP);
2490*4882a593Smuzhiyun if (gtb_memsize)
2491*4882a593Smuzhiyun /* 0xF used instead of MEM_SIZE_ALIAS */
2492*4882a593Smuzhiyun switch (par->mem_cntl & 0xF) {
2493*4882a593Smuzhiyun case MEM_SIZE_512K:
2494*4882a593Smuzhiyun info->fix.smem_len = 0x80000;
2495*4882a593Smuzhiyun break;
2496*4882a593Smuzhiyun case MEM_SIZE_1M:
2497*4882a593Smuzhiyun info->fix.smem_len = 0x100000;
2498*4882a593Smuzhiyun break;
2499*4882a593Smuzhiyun case MEM_SIZE_2M_GTB:
2500*4882a593Smuzhiyun info->fix.smem_len = 0x200000;
2501*4882a593Smuzhiyun break;
2502*4882a593Smuzhiyun case MEM_SIZE_4M_GTB:
2503*4882a593Smuzhiyun info->fix.smem_len = 0x400000;
2504*4882a593Smuzhiyun break;
2505*4882a593Smuzhiyun case MEM_SIZE_6M_GTB:
2506*4882a593Smuzhiyun info->fix.smem_len = 0x600000;
2507*4882a593Smuzhiyun break;
2508*4882a593Smuzhiyun case MEM_SIZE_8M_GTB:
2509*4882a593Smuzhiyun info->fix.smem_len = 0x800000;
2510*4882a593Smuzhiyun break;
2511*4882a593Smuzhiyun default:
2512*4882a593Smuzhiyun info->fix.smem_len = 0x80000;
2513*4882a593Smuzhiyun } else
2514*4882a593Smuzhiyun switch (par->mem_cntl & MEM_SIZE_ALIAS) {
2515*4882a593Smuzhiyun case MEM_SIZE_512K:
2516*4882a593Smuzhiyun info->fix.smem_len = 0x80000;
2517*4882a593Smuzhiyun break;
2518*4882a593Smuzhiyun case MEM_SIZE_1M:
2519*4882a593Smuzhiyun info->fix.smem_len = 0x100000;
2520*4882a593Smuzhiyun break;
2521*4882a593Smuzhiyun case MEM_SIZE_2M:
2522*4882a593Smuzhiyun info->fix.smem_len = 0x200000;
2523*4882a593Smuzhiyun break;
2524*4882a593Smuzhiyun case MEM_SIZE_4M:
2525*4882a593Smuzhiyun info->fix.smem_len = 0x400000;
2526*4882a593Smuzhiyun break;
2527*4882a593Smuzhiyun case MEM_SIZE_6M:
2528*4882a593Smuzhiyun info->fix.smem_len = 0x600000;
2529*4882a593Smuzhiyun break;
2530*4882a593Smuzhiyun case MEM_SIZE_8M:
2531*4882a593Smuzhiyun info->fix.smem_len = 0x800000;
2532*4882a593Smuzhiyun break;
2533*4882a593Smuzhiyun default:
2534*4882a593Smuzhiyun info->fix.smem_len = 0x80000;
2535*4882a593Smuzhiyun }
2536*4882a593Smuzhiyun
2537*4882a593Smuzhiyun if (M64_HAS(MAGIC_VRAM_SIZE)) {
2538*4882a593Smuzhiyun if (aty_ld_le32(CNFG_STAT1, par) & 0x40000000)
2539*4882a593Smuzhiyun info->fix.smem_len += 0x400000;
2540*4882a593Smuzhiyun }
2541*4882a593Smuzhiyun
2542*4882a593Smuzhiyun if (vram) {
2543*4882a593Smuzhiyun info->fix.smem_len = vram * 1024;
2544*4882a593Smuzhiyun par->mem_cntl &= ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
2545*4882a593Smuzhiyun if (info->fix.smem_len <= 0x80000)
2546*4882a593Smuzhiyun par->mem_cntl |= MEM_SIZE_512K;
2547*4882a593Smuzhiyun else if (info->fix.smem_len <= 0x100000)
2548*4882a593Smuzhiyun par->mem_cntl |= MEM_SIZE_1M;
2549*4882a593Smuzhiyun else if (info->fix.smem_len <= 0x200000)
2550*4882a593Smuzhiyun par->mem_cntl |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
2551*4882a593Smuzhiyun else if (info->fix.smem_len <= 0x400000)
2552*4882a593Smuzhiyun par->mem_cntl |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
2553*4882a593Smuzhiyun else if (info->fix.smem_len <= 0x600000)
2554*4882a593Smuzhiyun par->mem_cntl |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
2555*4882a593Smuzhiyun else
2556*4882a593Smuzhiyun par->mem_cntl |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
2557*4882a593Smuzhiyun aty_st_le32(MEM_CNTL, par->mem_cntl, par);
2558*4882a593Smuzhiyun }
2559*4882a593Smuzhiyun
2560*4882a593Smuzhiyun /*
2561*4882a593Smuzhiyun * Reg Block 0 (CT-compatible block) is at mmio_start
2562*4882a593Smuzhiyun * Reg Block 1 (multimedia extensions) is at mmio_start - 0x400
2563*4882a593Smuzhiyun */
2564*4882a593Smuzhiyun if (M64_HAS(GX)) {
2565*4882a593Smuzhiyun info->fix.mmio_len = 0x400;
2566*4882a593Smuzhiyun info->fix.accel = FB_ACCEL_ATI_MACH64GX;
2567*4882a593Smuzhiyun } else if (M64_HAS(CT)) {
2568*4882a593Smuzhiyun info->fix.mmio_len = 0x400;
2569*4882a593Smuzhiyun info->fix.accel = FB_ACCEL_ATI_MACH64CT;
2570*4882a593Smuzhiyun } else if (M64_HAS(VT)) {
2571*4882a593Smuzhiyun info->fix.mmio_start -= 0x400;
2572*4882a593Smuzhiyun info->fix.mmio_len = 0x800;
2573*4882a593Smuzhiyun info->fix.accel = FB_ACCEL_ATI_MACH64VT;
2574*4882a593Smuzhiyun } else {/* GT */
2575*4882a593Smuzhiyun info->fix.mmio_start -= 0x400;
2576*4882a593Smuzhiyun info->fix.mmio_len = 0x800;
2577*4882a593Smuzhiyun info->fix.accel = FB_ACCEL_ATI_MACH64GT;
2578*4882a593Smuzhiyun }
2579*4882a593Smuzhiyun
2580*4882a593Smuzhiyun PRINTKI("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK, %d MHz XCLK\n",
2581*4882a593Smuzhiyun info->fix.smem_len == 0x80000 ? 512 : (info->fix.smem_len>>20),
2582*4882a593Smuzhiyun info->fix.smem_len == 0x80000 ? 'K' : 'M', ramname, xtal,
2583*4882a593Smuzhiyun par->pll_limits.pll_max, par->pll_limits.mclk,
2584*4882a593Smuzhiyun par->pll_limits.xclk);
2585*4882a593Smuzhiyun
2586*4882a593Smuzhiyun #if defined(DEBUG) && defined(CONFIG_FB_ATY_CT)
2587*4882a593Smuzhiyun if (M64_HAS(INTEGRATED)) {
2588*4882a593Smuzhiyun int i;
2589*4882a593Smuzhiyun printk("debug atyfb: BUS_CNTL DAC_CNTL MEM_CNTL "
2590*4882a593Smuzhiyun "EXT_MEM_CNTL CRTC_GEN_CNTL DSP_CONFIG "
2591*4882a593Smuzhiyun "DSP_ON_OFF CLOCK_CNTL\n"
2592*4882a593Smuzhiyun "debug atyfb: %08x %08x %08x "
2593*4882a593Smuzhiyun "%08x %08x %08x "
2594*4882a593Smuzhiyun "%08x %08x\n"
2595*4882a593Smuzhiyun "debug atyfb: PLL",
2596*4882a593Smuzhiyun aty_ld_le32(BUS_CNTL, par),
2597*4882a593Smuzhiyun aty_ld_le32(DAC_CNTL, par),
2598*4882a593Smuzhiyun aty_ld_le32(MEM_CNTL, par),
2599*4882a593Smuzhiyun aty_ld_le32(EXT_MEM_CNTL, par),
2600*4882a593Smuzhiyun aty_ld_le32(CRTC_GEN_CNTL, par),
2601*4882a593Smuzhiyun aty_ld_le32(DSP_CONFIG, par),
2602*4882a593Smuzhiyun aty_ld_le32(DSP_ON_OFF, par),
2603*4882a593Smuzhiyun aty_ld_le32(CLOCK_CNTL, par));
2604*4882a593Smuzhiyun for (i = 0; i < 40; i++)
2605*4882a593Smuzhiyun pr_cont(" %02x", aty_ld_pll_ct(i, par));
2606*4882a593Smuzhiyun pr_cont("\n");
2607*4882a593Smuzhiyun }
2608*4882a593Smuzhiyun #endif
2609*4882a593Smuzhiyun if (par->pll_ops->init_pll)
2610*4882a593Smuzhiyun par->pll_ops->init_pll(info, &par->pll);
2611*4882a593Smuzhiyun if (par->pll_ops->resume_pll)
2612*4882a593Smuzhiyun par->pll_ops->resume_pll(info, &par->pll);
2613*4882a593Smuzhiyun
2614*4882a593Smuzhiyun aty_fudge_framebuffer_len(info);
2615*4882a593Smuzhiyun
2616*4882a593Smuzhiyun /*
2617*4882a593Smuzhiyun * Disable register access through the linear aperture
2618*4882a593Smuzhiyun * if the auxiliary aperture is used so we can access
2619*4882a593Smuzhiyun * the full 8 MB of video RAM on 8 MB boards.
2620*4882a593Smuzhiyun */
2621*4882a593Smuzhiyun if (par->aux_start)
2622*4882a593Smuzhiyun aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) |
2623*4882a593Smuzhiyun BUS_APER_REG_DIS, par);
2624*4882a593Smuzhiyun
2625*4882a593Smuzhiyun if (!nomtrr)
2626*4882a593Smuzhiyun /*
2627*4882a593Smuzhiyun * Only the ioremap_wc()'d area will get WC here
2628*4882a593Smuzhiyun * since ioremap_uc() was used on the entire PCI BAR.
2629*4882a593Smuzhiyun */
2630*4882a593Smuzhiyun par->wc_cookie = arch_phys_wc_add(par->res_start,
2631*4882a593Smuzhiyun par->res_size);
2632*4882a593Smuzhiyun
2633*4882a593Smuzhiyun info->fbops = &atyfb_ops;
2634*4882a593Smuzhiyun info->pseudo_palette = par->pseudo_palette;
2635*4882a593Smuzhiyun info->flags = FBINFO_DEFAULT |
2636*4882a593Smuzhiyun FBINFO_HWACCEL_IMAGEBLIT |
2637*4882a593Smuzhiyun FBINFO_HWACCEL_FILLRECT |
2638*4882a593Smuzhiyun FBINFO_HWACCEL_COPYAREA |
2639*4882a593Smuzhiyun FBINFO_HWACCEL_YPAN |
2640*4882a593Smuzhiyun FBINFO_READS_FAST;
2641*4882a593Smuzhiyun
2642*4882a593Smuzhiyun #ifdef CONFIG_PMAC_BACKLIGHT
2643*4882a593Smuzhiyun if (M64_HAS(G3_PB_1_1) && of_machine_is_compatible("PowerBook1,1")) {
2644*4882a593Smuzhiyun /*
2645*4882a593Smuzhiyun * these bits let the 101 powerbook
2646*4882a593Smuzhiyun * wake up from sleep -- paulus
2647*4882a593Smuzhiyun */
2648*4882a593Smuzhiyun aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par) |
2649*4882a593Smuzhiyun USE_F32KHZ | TRISTATE_MEM_EN, par);
2650*4882a593Smuzhiyun } else
2651*4882a593Smuzhiyun #endif
2652*4882a593Smuzhiyun if (M64_HAS(MOBIL_BUS) && backlight) {
2653*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_BACKLIGHT
2654*4882a593Smuzhiyun aty_bl_init(par);
2655*4882a593Smuzhiyun #endif
2656*4882a593Smuzhiyun }
2657*4882a593Smuzhiyun
2658*4882a593Smuzhiyun memset(&var, 0, sizeof(var));
2659*4882a593Smuzhiyun #ifdef CONFIG_PPC
2660*4882a593Smuzhiyun if (machine_is(powermac)) {
2661*4882a593Smuzhiyun /*
2662*4882a593Smuzhiyun * FIXME: The NVRAM stuff should be put in a Mac-specific file,
2663*4882a593Smuzhiyun * as it applies to all Mac video cards
2664*4882a593Smuzhiyun */
2665*4882a593Smuzhiyun if (mode) {
2666*4882a593Smuzhiyun if (mac_find_mode(&var, info, mode, 8))
2667*4882a593Smuzhiyun has_var = 1;
2668*4882a593Smuzhiyun } else {
2669*4882a593Smuzhiyun if (default_vmode == VMODE_CHOOSE) {
2670*4882a593Smuzhiyun int sense;
2671*4882a593Smuzhiyun if (M64_HAS(G3_PB_1024x768))
2672*4882a593Smuzhiyun /* G3 PowerBook with 1024x768 LCD */
2673*4882a593Smuzhiyun default_vmode = VMODE_1024_768_60;
2674*4882a593Smuzhiyun else if (of_machine_is_compatible("iMac"))
2675*4882a593Smuzhiyun default_vmode = VMODE_1024_768_75;
2676*4882a593Smuzhiyun else if (of_machine_is_compatible("PowerBook2,1"))
2677*4882a593Smuzhiyun /* iBook with 800x600 LCD */
2678*4882a593Smuzhiyun default_vmode = VMODE_800_600_60;
2679*4882a593Smuzhiyun else
2680*4882a593Smuzhiyun default_vmode = VMODE_640_480_67;
2681*4882a593Smuzhiyun sense = read_aty_sense(par);
2682*4882a593Smuzhiyun PRINTKI("monitor sense=%x, mode %d\n",
2683*4882a593Smuzhiyun sense, mac_map_monitor_sense(sense));
2684*4882a593Smuzhiyun }
2685*4882a593Smuzhiyun if (default_vmode <= 0 || default_vmode > VMODE_MAX)
2686*4882a593Smuzhiyun default_vmode = VMODE_640_480_60;
2687*4882a593Smuzhiyun if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
2688*4882a593Smuzhiyun default_cmode = CMODE_8;
2689*4882a593Smuzhiyun if (!mac_vmode_to_var(default_vmode, default_cmode,
2690*4882a593Smuzhiyun &var))
2691*4882a593Smuzhiyun has_var = 1;
2692*4882a593Smuzhiyun }
2693*4882a593Smuzhiyun }
2694*4882a593Smuzhiyun
2695*4882a593Smuzhiyun #endif /* !CONFIG_PPC */
2696*4882a593Smuzhiyun
2697*4882a593Smuzhiyun #if defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD)
2698*4882a593Smuzhiyun if (!atyfb_get_timings_from_lcd(par, &var))
2699*4882a593Smuzhiyun has_var = 1;
2700*4882a593Smuzhiyun #endif
2701*4882a593Smuzhiyun
2702*4882a593Smuzhiyun if (mode && fb_find_mode(&var, info, mode, NULL, 0, &defmode, 8))
2703*4882a593Smuzhiyun has_var = 1;
2704*4882a593Smuzhiyun
2705*4882a593Smuzhiyun if (!has_var)
2706*4882a593Smuzhiyun var = default_var;
2707*4882a593Smuzhiyun
2708*4882a593Smuzhiyun if (noaccel)
2709*4882a593Smuzhiyun var.accel_flags &= ~FB_ACCELF_TEXT;
2710*4882a593Smuzhiyun else
2711*4882a593Smuzhiyun var.accel_flags |= FB_ACCELF_TEXT;
2712*4882a593Smuzhiyun
2713*4882a593Smuzhiyun if (comp_sync != -1) {
2714*4882a593Smuzhiyun if (!comp_sync)
2715*4882a593Smuzhiyun var.sync &= ~FB_SYNC_COMP_HIGH_ACT;
2716*4882a593Smuzhiyun else
2717*4882a593Smuzhiyun var.sync |= FB_SYNC_COMP_HIGH_ACT;
2718*4882a593Smuzhiyun }
2719*4882a593Smuzhiyun
2720*4882a593Smuzhiyun if (var.yres == var.yres_virtual) {
2721*4882a593Smuzhiyun u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2));
2722*4882a593Smuzhiyun var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual;
2723*4882a593Smuzhiyun if (var.yres_virtual < var.yres)
2724*4882a593Smuzhiyun var.yres_virtual = var.yres;
2725*4882a593Smuzhiyun }
2726*4882a593Smuzhiyun
2727*4882a593Smuzhiyun ret = atyfb_check_var(&var, info);
2728*4882a593Smuzhiyun if (ret) {
2729*4882a593Smuzhiyun PRINTKE("can't set default video mode\n");
2730*4882a593Smuzhiyun goto aty_init_exit;
2731*4882a593Smuzhiyun }
2732*4882a593Smuzhiyun
2733*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_CT
2734*4882a593Smuzhiyun if (!noaccel && M64_HAS(INTEGRATED))
2735*4882a593Smuzhiyun aty_init_cursor(info, &atyfb_ops);
2736*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_CT */
2737*4882a593Smuzhiyun info->var = var;
2738*4882a593Smuzhiyun
2739*4882a593Smuzhiyun ret = fb_alloc_cmap(&info->cmap, 256, 0);
2740*4882a593Smuzhiyun if (ret < 0)
2741*4882a593Smuzhiyun goto aty_init_exit;
2742*4882a593Smuzhiyun
2743*4882a593Smuzhiyun ret = register_framebuffer(info);
2744*4882a593Smuzhiyun if (ret < 0) {
2745*4882a593Smuzhiyun fb_dealloc_cmap(&info->cmap);
2746*4882a593Smuzhiyun goto aty_init_exit;
2747*4882a593Smuzhiyun }
2748*4882a593Smuzhiyun
2749*4882a593Smuzhiyun fb_list = info;
2750*4882a593Smuzhiyun
2751*4882a593Smuzhiyun PRINTKI("fb%d: %s frame buffer device on %s\n",
2752*4882a593Smuzhiyun info->node, info->fix.id, par->bus_type == ISA ? "ISA" : "PCI");
2753*4882a593Smuzhiyun return 0;
2754*4882a593Smuzhiyun
2755*4882a593Smuzhiyun aty_init_exit:
2756*4882a593Smuzhiyun /* restore video mode */
2757*4882a593Smuzhiyun aty_set_crtc(par, &par->saved_crtc);
2758*4882a593Smuzhiyun par->pll_ops->set_pll(info, &par->saved_pll);
2759*4882a593Smuzhiyun arch_phys_wc_del(par->wc_cookie);
2760*4882a593Smuzhiyun
2761*4882a593Smuzhiyun return ret;
2762*4882a593Smuzhiyun }
2763*4882a593Smuzhiyun
2764*4882a593Smuzhiyun #if defined(CONFIG_ATARI) && !defined(MODULE)
store_video_par(char * video_str,unsigned char m64_num)2765*4882a593Smuzhiyun static int store_video_par(char *video_str, unsigned char m64_num)
2766*4882a593Smuzhiyun {
2767*4882a593Smuzhiyun char *p;
2768*4882a593Smuzhiyun unsigned long vmembase, size, guiregbase;
2769*4882a593Smuzhiyun
2770*4882a593Smuzhiyun PRINTKI("store_video_par() '%s' \n", video_str);
2771*4882a593Smuzhiyun
2772*4882a593Smuzhiyun if (!(p = strsep(&video_str, ";")) || !*p)
2773*4882a593Smuzhiyun goto mach64_invalid;
2774*4882a593Smuzhiyun vmembase = simple_strtoul(p, NULL, 0);
2775*4882a593Smuzhiyun if (!(p = strsep(&video_str, ";")) || !*p)
2776*4882a593Smuzhiyun goto mach64_invalid;
2777*4882a593Smuzhiyun size = simple_strtoul(p, NULL, 0);
2778*4882a593Smuzhiyun if (!(p = strsep(&video_str, ";")) || !*p)
2779*4882a593Smuzhiyun goto mach64_invalid;
2780*4882a593Smuzhiyun guiregbase = simple_strtoul(p, NULL, 0);
2781*4882a593Smuzhiyun
2782*4882a593Smuzhiyun phys_vmembase[m64_num] = vmembase;
2783*4882a593Smuzhiyun phys_size[m64_num] = size;
2784*4882a593Smuzhiyun phys_guiregbase[m64_num] = guiregbase;
2785*4882a593Smuzhiyun PRINTKI("stored them all: $%08lX $%08lX $%08lX \n", vmembase, size,
2786*4882a593Smuzhiyun guiregbase);
2787*4882a593Smuzhiyun return 0;
2788*4882a593Smuzhiyun
2789*4882a593Smuzhiyun mach64_invalid:
2790*4882a593Smuzhiyun phys_vmembase[m64_num] = 0;
2791*4882a593Smuzhiyun return -1;
2792*4882a593Smuzhiyun }
2793*4882a593Smuzhiyun #endif /* CONFIG_ATARI && !MODULE */
2794*4882a593Smuzhiyun
2795*4882a593Smuzhiyun /*
2796*4882a593Smuzhiyun * Blank the display.
2797*4882a593Smuzhiyun */
2798*4882a593Smuzhiyun
atyfb_blank(int blank,struct fb_info * info)2799*4882a593Smuzhiyun static int atyfb_blank(int blank, struct fb_info *info)
2800*4882a593Smuzhiyun {
2801*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
2802*4882a593Smuzhiyun u32 gen_cntl;
2803*4882a593Smuzhiyun
2804*4882a593Smuzhiyun if (par->lock_blank || par->asleep)
2805*4882a593Smuzhiyun return 0;
2806*4882a593Smuzhiyun
2807*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
2808*4882a593Smuzhiyun if (par->lcd_table && blank > FB_BLANK_NORMAL &&
2809*4882a593Smuzhiyun (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
2810*4882a593Smuzhiyun u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
2811*4882a593Smuzhiyun pm &= ~PWR_BLON;
2812*4882a593Smuzhiyun aty_st_lcd(POWER_MANAGEMENT, pm, par);
2813*4882a593Smuzhiyun }
2814*4882a593Smuzhiyun #endif
2815*4882a593Smuzhiyun
2816*4882a593Smuzhiyun gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
2817*4882a593Smuzhiyun gen_cntl &= ~0x400004c;
2818*4882a593Smuzhiyun switch (blank) {
2819*4882a593Smuzhiyun case FB_BLANK_UNBLANK:
2820*4882a593Smuzhiyun break;
2821*4882a593Smuzhiyun case FB_BLANK_NORMAL:
2822*4882a593Smuzhiyun gen_cntl |= 0x4000040;
2823*4882a593Smuzhiyun break;
2824*4882a593Smuzhiyun case FB_BLANK_VSYNC_SUSPEND:
2825*4882a593Smuzhiyun gen_cntl |= 0x4000048;
2826*4882a593Smuzhiyun break;
2827*4882a593Smuzhiyun case FB_BLANK_HSYNC_SUSPEND:
2828*4882a593Smuzhiyun gen_cntl |= 0x4000044;
2829*4882a593Smuzhiyun break;
2830*4882a593Smuzhiyun case FB_BLANK_POWERDOWN:
2831*4882a593Smuzhiyun gen_cntl |= 0x400004c;
2832*4882a593Smuzhiyun break;
2833*4882a593Smuzhiyun }
2834*4882a593Smuzhiyun aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
2835*4882a593Smuzhiyun
2836*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
2837*4882a593Smuzhiyun if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
2838*4882a593Smuzhiyun (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
2839*4882a593Smuzhiyun u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
2840*4882a593Smuzhiyun pm |= PWR_BLON;
2841*4882a593Smuzhiyun aty_st_lcd(POWER_MANAGEMENT, pm, par);
2842*4882a593Smuzhiyun }
2843*4882a593Smuzhiyun #endif
2844*4882a593Smuzhiyun
2845*4882a593Smuzhiyun return 0;
2846*4882a593Smuzhiyun }
2847*4882a593Smuzhiyun
aty_st_pal(u_int regno,u_int red,u_int green,u_int blue,const struct atyfb_par * par)2848*4882a593Smuzhiyun static void aty_st_pal(u_int regno, u_int red, u_int green, u_int blue,
2849*4882a593Smuzhiyun const struct atyfb_par *par)
2850*4882a593Smuzhiyun {
2851*4882a593Smuzhiyun aty_st_8(DAC_W_INDEX, regno, par);
2852*4882a593Smuzhiyun aty_st_8(DAC_DATA, red, par);
2853*4882a593Smuzhiyun aty_st_8(DAC_DATA, green, par);
2854*4882a593Smuzhiyun aty_st_8(DAC_DATA, blue, par);
2855*4882a593Smuzhiyun }
2856*4882a593Smuzhiyun
2857*4882a593Smuzhiyun /*
2858*4882a593Smuzhiyun * Set a single color register. The values supplied are already
2859*4882a593Smuzhiyun * rounded down to the hardware's capabilities (according to the
2860*4882a593Smuzhiyun * entries in the var structure). Return != 0 for invalid regno.
2861*4882a593Smuzhiyun * !! 4 & 8 = PSEUDO, > 8 = DIRECTCOLOR
2862*4882a593Smuzhiyun */
2863*4882a593Smuzhiyun
atyfb_setcolreg(u_int regno,u_int red,u_int green,u_int blue,u_int transp,struct fb_info * info)2864*4882a593Smuzhiyun static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
2865*4882a593Smuzhiyun u_int transp, struct fb_info *info)
2866*4882a593Smuzhiyun {
2867*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
2868*4882a593Smuzhiyun int i, depth;
2869*4882a593Smuzhiyun u32 *pal = info->pseudo_palette;
2870*4882a593Smuzhiyun
2871*4882a593Smuzhiyun depth = info->var.bits_per_pixel;
2872*4882a593Smuzhiyun if (depth == 16)
2873*4882a593Smuzhiyun depth = (info->var.green.length == 5) ? 15 : 16;
2874*4882a593Smuzhiyun
2875*4882a593Smuzhiyun if (par->asleep)
2876*4882a593Smuzhiyun return 0;
2877*4882a593Smuzhiyun
2878*4882a593Smuzhiyun if (regno > 255 ||
2879*4882a593Smuzhiyun (depth == 16 && regno > 63) ||
2880*4882a593Smuzhiyun (depth == 15 && regno > 31))
2881*4882a593Smuzhiyun return 1;
2882*4882a593Smuzhiyun
2883*4882a593Smuzhiyun red >>= 8;
2884*4882a593Smuzhiyun green >>= 8;
2885*4882a593Smuzhiyun blue >>= 8;
2886*4882a593Smuzhiyun
2887*4882a593Smuzhiyun par->palette[regno].red = red;
2888*4882a593Smuzhiyun par->palette[regno].green = green;
2889*4882a593Smuzhiyun par->palette[regno].blue = blue;
2890*4882a593Smuzhiyun
2891*4882a593Smuzhiyun if (regno < 16) {
2892*4882a593Smuzhiyun switch (depth) {
2893*4882a593Smuzhiyun case 15:
2894*4882a593Smuzhiyun pal[regno] = (regno << 10) | (regno << 5) | regno;
2895*4882a593Smuzhiyun break;
2896*4882a593Smuzhiyun case 16:
2897*4882a593Smuzhiyun pal[regno] = (regno << 11) | (regno << 5) | regno;
2898*4882a593Smuzhiyun break;
2899*4882a593Smuzhiyun case 24:
2900*4882a593Smuzhiyun pal[regno] = (regno << 16) | (regno << 8) | regno;
2901*4882a593Smuzhiyun break;
2902*4882a593Smuzhiyun case 32:
2903*4882a593Smuzhiyun i = (regno << 8) | regno;
2904*4882a593Smuzhiyun pal[regno] = (i << 16) | i;
2905*4882a593Smuzhiyun break;
2906*4882a593Smuzhiyun }
2907*4882a593Smuzhiyun }
2908*4882a593Smuzhiyun
2909*4882a593Smuzhiyun i = aty_ld_8(DAC_CNTL, par) & 0xfc;
2910*4882a593Smuzhiyun if (M64_HAS(EXTRA_BRIGHT))
2911*4882a593Smuzhiyun i |= 0x2; /* DAC_CNTL | 0x2 turns off the extra brightness for gt */
2912*4882a593Smuzhiyun aty_st_8(DAC_CNTL, i, par);
2913*4882a593Smuzhiyun aty_st_8(DAC_MASK, 0xff, par);
2914*4882a593Smuzhiyun
2915*4882a593Smuzhiyun if (M64_HAS(INTEGRATED)) {
2916*4882a593Smuzhiyun if (depth == 16) {
2917*4882a593Smuzhiyun if (regno < 32)
2918*4882a593Smuzhiyun aty_st_pal(regno << 3, red,
2919*4882a593Smuzhiyun par->palette[regno << 1].green,
2920*4882a593Smuzhiyun blue, par);
2921*4882a593Smuzhiyun red = par->palette[regno >> 1].red;
2922*4882a593Smuzhiyun blue = par->palette[regno >> 1].blue;
2923*4882a593Smuzhiyun regno <<= 2;
2924*4882a593Smuzhiyun } else if (depth == 15) {
2925*4882a593Smuzhiyun regno <<= 3;
2926*4882a593Smuzhiyun for (i = 0; i < 8; i++)
2927*4882a593Smuzhiyun aty_st_pal(regno + i, red, green, blue, par);
2928*4882a593Smuzhiyun }
2929*4882a593Smuzhiyun }
2930*4882a593Smuzhiyun aty_st_pal(regno, red, green, blue, par);
2931*4882a593Smuzhiyun
2932*4882a593Smuzhiyun return 0;
2933*4882a593Smuzhiyun }
2934*4882a593Smuzhiyun
2935*4882a593Smuzhiyun #ifdef CONFIG_PCI
2936*4882a593Smuzhiyun
2937*4882a593Smuzhiyun #ifdef __sparc__
2938*4882a593Smuzhiyun
atyfb_setup_sparc(struct pci_dev * pdev,struct fb_info * info,unsigned long addr)2939*4882a593Smuzhiyun static int atyfb_setup_sparc(struct pci_dev *pdev, struct fb_info *info,
2940*4882a593Smuzhiyun unsigned long addr)
2941*4882a593Smuzhiyun {
2942*4882a593Smuzhiyun struct atyfb_par *par = info->par;
2943*4882a593Smuzhiyun struct device_node *dp;
2944*4882a593Smuzhiyun u32 mem, chip_id;
2945*4882a593Smuzhiyun int i, j, ret;
2946*4882a593Smuzhiyun
2947*4882a593Smuzhiyun /*
2948*4882a593Smuzhiyun * Map memory-mapped registers.
2949*4882a593Smuzhiyun */
2950*4882a593Smuzhiyun par->ati_regbase = (void *)addr + 0x7ffc00UL;
2951*4882a593Smuzhiyun info->fix.mmio_start = addr + 0x7ffc00UL;
2952*4882a593Smuzhiyun
2953*4882a593Smuzhiyun /*
2954*4882a593Smuzhiyun * Map in big-endian aperture.
2955*4882a593Smuzhiyun */
2956*4882a593Smuzhiyun info->screen_base = (char *) (addr + 0x800000UL);
2957*4882a593Smuzhiyun info->fix.smem_start = addr + 0x800000UL;
2958*4882a593Smuzhiyun
2959*4882a593Smuzhiyun /*
2960*4882a593Smuzhiyun * Figure mmap addresses from PCI config space.
2961*4882a593Smuzhiyun * Split Framebuffer in big- and little-endian halfs.
2962*4882a593Smuzhiyun */
2963*4882a593Smuzhiyun for (i = 0; i < 6 && pdev->resource[i].start; i++)
2964*4882a593Smuzhiyun /* nothing */ ;
2965*4882a593Smuzhiyun j = i + 4;
2966*4882a593Smuzhiyun
2967*4882a593Smuzhiyun par->mmap_map = kcalloc(j, sizeof(*par->mmap_map), GFP_ATOMIC);
2968*4882a593Smuzhiyun if (!par->mmap_map) {
2969*4882a593Smuzhiyun PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");
2970*4882a593Smuzhiyun return -ENOMEM;
2971*4882a593Smuzhiyun }
2972*4882a593Smuzhiyun
2973*4882a593Smuzhiyun for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
2974*4882a593Smuzhiyun struct resource *rp = &pdev->resource[i];
2975*4882a593Smuzhiyun int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
2976*4882a593Smuzhiyun unsigned long base;
2977*4882a593Smuzhiyun u32 size, pbase;
2978*4882a593Smuzhiyun
2979*4882a593Smuzhiyun base = rp->start;
2980*4882a593Smuzhiyun
2981*4882a593Smuzhiyun io = (rp->flags & IORESOURCE_IO);
2982*4882a593Smuzhiyun
2983*4882a593Smuzhiyun size = rp->end - base + 1;
2984*4882a593Smuzhiyun
2985*4882a593Smuzhiyun pci_read_config_dword(pdev, breg, &pbase);
2986*4882a593Smuzhiyun
2987*4882a593Smuzhiyun if (io)
2988*4882a593Smuzhiyun size &= ~1;
2989*4882a593Smuzhiyun
2990*4882a593Smuzhiyun /*
2991*4882a593Smuzhiyun * Map the framebuffer a second time, this time without
2992*4882a593Smuzhiyun * the braindead _PAGE_IE setting. This is used by the
2993*4882a593Smuzhiyun * fixed Xserver, but we need to maintain the old mapping
2994*4882a593Smuzhiyun * to stay compatible with older ones...
2995*4882a593Smuzhiyun */
2996*4882a593Smuzhiyun if (base == addr) {
2997*4882a593Smuzhiyun par->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK;
2998*4882a593Smuzhiyun par->mmap_map[j].poff = base & PAGE_MASK;
2999*4882a593Smuzhiyun par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
3000*4882a593Smuzhiyun par->mmap_map[j].prot_mask = _PAGE_CACHE;
3001*4882a593Smuzhiyun par->mmap_map[j].prot_flag = _PAGE_E;
3002*4882a593Smuzhiyun j++;
3003*4882a593Smuzhiyun }
3004*4882a593Smuzhiyun
3005*4882a593Smuzhiyun /*
3006*4882a593Smuzhiyun * Here comes the old framebuffer mapping with _PAGE_IE
3007*4882a593Smuzhiyun * set for the big endian half of the framebuffer...
3008*4882a593Smuzhiyun */
3009*4882a593Smuzhiyun if (base == addr) {
3010*4882a593Smuzhiyun par->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK;
3011*4882a593Smuzhiyun par->mmap_map[j].poff = (base + 0x800000) & PAGE_MASK;
3012*4882a593Smuzhiyun par->mmap_map[j].size = 0x800000;
3013*4882a593Smuzhiyun par->mmap_map[j].prot_mask = _PAGE_CACHE;
3014*4882a593Smuzhiyun par->mmap_map[j].prot_flag = _PAGE_E | _PAGE_IE;
3015*4882a593Smuzhiyun size -= 0x800000;
3016*4882a593Smuzhiyun j++;
3017*4882a593Smuzhiyun }
3018*4882a593Smuzhiyun
3019*4882a593Smuzhiyun par->mmap_map[j].voff = pbase & PAGE_MASK;
3020*4882a593Smuzhiyun par->mmap_map[j].poff = base & PAGE_MASK;
3021*4882a593Smuzhiyun par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
3022*4882a593Smuzhiyun par->mmap_map[j].prot_mask = _PAGE_CACHE;
3023*4882a593Smuzhiyun par->mmap_map[j].prot_flag = _PAGE_E;
3024*4882a593Smuzhiyun j++;
3025*4882a593Smuzhiyun }
3026*4882a593Smuzhiyun
3027*4882a593Smuzhiyun ret = correct_chipset(par);
3028*4882a593Smuzhiyun if (ret)
3029*4882a593Smuzhiyun return ret;
3030*4882a593Smuzhiyun
3031*4882a593Smuzhiyun if (IS_XL(pdev->device)) {
3032*4882a593Smuzhiyun /*
3033*4882a593Smuzhiyun * Fix PROMs idea of MEM_CNTL settings...
3034*4882a593Smuzhiyun */
3035*4882a593Smuzhiyun mem = aty_ld_le32(MEM_CNTL, par);
3036*4882a593Smuzhiyun chip_id = aty_ld_le32(CNFG_CHIP_ID, par);
3037*4882a593Smuzhiyun if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && !((chip_id >> 24) & 1)) {
3038*4882a593Smuzhiyun switch (mem & 0x0f) {
3039*4882a593Smuzhiyun case 3:
3040*4882a593Smuzhiyun mem = (mem & ~(0x0f)) | 2;
3041*4882a593Smuzhiyun break;
3042*4882a593Smuzhiyun case 7:
3043*4882a593Smuzhiyun mem = (mem & ~(0x0f)) | 3;
3044*4882a593Smuzhiyun break;
3045*4882a593Smuzhiyun case 9:
3046*4882a593Smuzhiyun mem = (mem & ~(0x0f)) | 4;
3047*4882a593Smuzhiyun break;
3048*4882a593Smuzhiyun case 11:
3049*4882a593Smuzhiyun mem = (mem & ~(0x0f)) | 5;
3050*4882a593Smuzhiyun break;
3051*4882a593Smuzhiyun default:
3052*4882a593Smuzhiyun break;
3053*4882a593Smuzhiyun }
3054*4882a593Smuzhiyun if ((aty_ld_le32(CNFG_STAT0, par) & 7) >= SDRAM)
3055*4882a593Smuzhiyun mem &= ~(0x00700000);
3056*4882a593Smuzhiyun }
3057*4882a593Smuzhiyun mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */
3058*4882a593Smuzhiyun aty_st_le32(MEM_CNTL, mem, par);
3059*4882a593Smuzhiyun }
3060*4882a593Smuzhiyun
3061*4882a593Smuzhiyun dp = pci_device_to_OF_node(pdev);
3062*4882a593Smuzhiyun if (dp == of_console_device) {
3063*4882a593Smuzhiyun struct fb_var_screeninfo *var = &default_var;
3064*4882a593Smuzhiyun unsigned int N, P, Q, M, T, R;
3065*4882a593Smuzhiyun u32 v_total, h_total;
3066*4882a593Smuzhiyun struct crtc crtc;
3067*4882a593Smuzhiyun u8 pll_regs[16];
3068*4882a593Smuzhiyun u8 clock_cntl;
3069*4882a593Smuzhiyun
3070*4882a593Smuzhiyun crtc.vxres = of_getintprop_default(dp, "width", 1024);
3071*4882a593Smuzhiyun crtc.vyres = of_getintprop_default(dp, "height", 768);
3072*4882a593Smuzhiyun var->bits_per_pixel = of_getintprop_default(dp, "depth", 8);
3073*4882a593Smuzhiyun var->xoffset = var->yoffset = 0;
3074*4882a593Smuzhiyun crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
3075*4882a593Smuzhiyun crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
3076*4882a593Smuzhiyun crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
3077*4882a593Smuzhiyun crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);
3078*4882a593Smuzhiyun crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
3079*4882a593Smuzhiyun aty_crtc_to_var(&crtc, var);
3080*4882a593Smuzhiyun
3081*4882a593Smuzhiyun h_total = var->xres + var->right_margin + var->hsync_len + var->left_margin;
3082*4882a593Smuzhiyun v_total = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
3083*4882a593Smuzhiyun
3084*4882a593Smuzhiyun /*
3085*4882a593Smuzhiyun * Read the PLL to figure actual Refresh Rate.
3086*4882a593Smuzhiyun */
3087*4882a593Smuzhiyun clock_cntl = aty_ld_8(CLOCK_CNTL, par);
3088*4882a593Smuzhiyun /* DPRINTK("CLOCK_CNTL %02x\n", clock_cntl); */
3089*4882a593Smuzhiyun for (i = 0; i < 16; i++)
3090*4882a593Smuzhiyun pll_regs[i] = aty_ld_pll_ct(i, par);
3091*4882a593Smuzhiyun
3092*4882a593Smuzhiyun /*
3093*4882a593Smuzhiyun * PLL Reference Divider M:
3094*4882a593Smuzhiyun */
3095*4882a593Smuzhiyun M = pll_regs[PLL_REF_DIV];
3096*4882a593Smuzhiyun
3097*4882a593Smuzhiyun /*
3098*4882a593Smuzhiyun * PLL Feedback Divider N (Dependent on CLOCK_CNTL):
3099*4882a593Smuzhiyun */
3100*4882a593Smuzhiyun N = pll_regs[VCLK0_FB_DIV + (clock_cntl & 3)];
3101*4882a593Smuzhiyun
3102*4882a593Smuzhiyun /*
3103*4882a593Smuzhiyun * PLL Post Divider P (Dependent on CLOCK_CNTL):
3104*4882a593Smuzhiyun */
3105*4882a593Smuzhiyun P = aty_postdividers[((pll_regs[VCLK_POST_DIV] >> ((clock_cntl & 3) << 1)) & 3) |
3106*4882a593Smuzhiyun ((pll_regs[PLL_EXT_CNTL] >> (2 + (clock_cntl & 3))) & 4)];
3107*4882a593Smuzhiyun
3108*4882a593Smuzhiyun /*
3109*4882a593Smuzhiyun * PLL Divider Q:
3110*4882a593Smuzhiyun */
3111*4882a593Smuzhiyun Q = N / P;
3112*4882a593Smuzhiyun
3113*4882a593Smuzhiyun /*
3114*4882a593Smuzhiyun * Target Frequency:
3115*4882a593Smuzhiyun *
3116*4882a593Smuzhiyun * T * M
3117*4882a593Smuzhiyun * Q = -------
3118*4882a593Smuzhiyun * 2 * R
3119*4882a593Smuzhiyun *
3120*4882a593Smuzhiyun * where R is XTALIN (= 14318 or 29498 kHz).
3121*4882a593Smuzhiyun */
3122*4882a593Smuzhiyun if (IS_XL(pdev->device))
3123*4882a593Smuzhiyun R = 29498;
3124*4882a593Smuzhiyun else
3125*4882a593Smuzhiyun R = 14318;
3126*4882a593Smuzhiyun
3127*4882a593Smuzhiyun T = 2 * Q * R / M;
3128*4882a593Smuzhiyun
3129*4882a593Smuzhiyun default_var.pixclock = 1000000000 / T;
3130*4882a593Smuzhiyun }
3131*4882a593Smuzhiyun
3132*4882a593Smuzhiyun return 0;
3133*4882a593Smuzhiyun }
3134*4882a593Smuzhiyun
3135*4882a593Smuzhiyun #else /* __sparc__ */
3136*4882a593Smuzhiyun
3137*4882a593Smuzhiyun #ifdef __i386__
3138*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
aty_init_lcd(struct atyfb_par * par,u32 bios_base)3139*4882a593Smuzhiyun static void aty_init_lcd(struct atyfb_par *par, u32 bios_base)
3140*4882a593Smuzhiyun {
3141*4882a593Smuzhiyun u32 driv_inf_tab, sig;
3142*4882a593Smuzhiyun u16 lcd_ofs;
3143*4882a593Smuzhiyun
3144*4882a593Smuzhiyun /*
3145*4882a593Smuzhiyun * To support an LCD panel, we should know it's dimensions and
3146*4882a593Smuzhiyun * it's desired pixel clock.
3147*4882a593Smuzhiyun * There are two ways to do it:
3148*4882a593Smuzhiyun * - Check the startup video mode and calculate the panel
3149*4882a593Smuzhiyun * size from it. This is unreliable.
3150*4882a593Smuzhiyun * - Read it from the driver information table in the video BIOS.
3151*4882a593Smuzhiyun */
3152*4882a593Smuzhiyun /* Address of driver information table is at offset 0x78. */
3153*4882a593Smuzhiyun driv_inf_tab = bios_base + *((u16 *)(bios_base+0x78));
3154*4882a593Smuzhiyun
3155*4882a593Smuzhiyun /* Check for the driver information table signature. */
3156*4882a593Smuzhiyun sig = *(u32 *)driv_inf_tab;
3157*4882a593Smuzhiyun if ((sig == 0x54504c24) || /* Rage LT pro */
3158*4882a593Smuzhiyun (sig == 0x544d5224) || /* Rage mobility */
3159*4882a593Smuzhiyun (sig == 0x54435824) || /* Rage XC */
3160*4882a593Smuzhiyun (sig == 0x544c5824)) { /* Rage XL */
3161*4882a593Smuzhiyun PRINTKI("BIOS contains driver information table.\n");
3162*4882a593Smuzhiyun lcd_ofs = *(u16 *)(driv_inf_tab + 10);
3163*4882a593Smuzhiyun par->lcd_table = 0;
3164*4882a593Smuzhiyun if (lcd_ofs != 0)
3165*4882a593Smuzhiyun par->lcd_table = bios_base + lcd_ofs;
3166*4882a593Smuzhiyun }
3167*4882a593Smuzhiyun
3168*4882a593Smuzhiyun if (par->lcd_table != 0) {
3169*4882a593Smuzhiyun char model[24];
3170*4882a593Smuzhiyun char strbuf[16];
3171*4882a593Smuzhiyun char refresh_rates_buf[100];
3172*4882a593Smuzhiyun int id, tech, f, i, m, default_refresh_rate;
3173*4882a593Smuzhiyun char *txtcolour;
3174*4882a593Smuzhiyun char *txtmonitor;
3175*4882a593Smuzhiyun char *txtdual;
3176*4882a593Smuzhiyun char *txtformat;
3177*4882a593Smuzhiyun u16 width, height, panel_type, refresh_rates;
3178*4882a593Smuzhiyun u16 *lcdmodeptr;
3179*4882a593Smuzhiyun u32 format;
3180*4882a593Smuzhiyun u8 lcd_refresh_rates[16] = { 50, 56, 60, 67, 70, 72, 75, 76, 85,
3181*4882a593Smuzhiyun 90, 100, 120, 140, 150, 160, 200 };
3182*4882a593Smuzhiyun /*
3183*4882a593Smuzhiyun * The most important information is the panel size at
3184*4882a593Smuzhiyun * offset 25 and 27, but there's some other nice information
3185*4882a593Smuzhiyun * which we print to the screen.
3186*4882a593Smuzhiyun */
3187*4882a593Smuzhiyun id = *(u8 *)par->lcd_table;
3188*4882a593Smuzhiyun strncpy(model, (char *)par->lcd_table+1, 24);
3189*4882a593Smuzhiyun model[23] = 0;
3190*4882a593Smuzhiyun
3191*4882a593Smuzhiyun width = par->lcd_width = *(u16 *)(par->lcd_table+25);
3192*4882a593Smuzhiyun height = par->lcd_height = *(u16 *)(par->lcd_table+27);
3193*4882a593Smuzhiyun panel_type = *(u16 *)(par->lcd_table+29);
3194*4882a593Smuzhiyun if (panel_type & 1)
3195*4882a593Smuzhiyun txtcolour = "colour";
3196*4882a593Smuzhiyun else
3197*4882a593Smuzhiyun txtcolour = "monochrome";
3198*4882a593Smuzhiyun if (panel_type & 2)
3199*4882a593Smuzhiyun txtdual = "dual (split) ";
3200*4882a593Smuzhiyun else
3201*4882a593Smuzhiyun txtdual = "";
3202*4882a593Smuzhiyun tech = (panel_type >> 2) & 63;
3203*4882a593Smuzhiyun switch (tech) {
3204*4882a593Smuzhiyun case 0:
3205*4882a593Smuzhiyun txtmonitor = "passive matrix";
3206*4882a593Smuzhiyun break;
3207*4882a593Smuzhiyun case 1:
3208*4882a593Smuzhiyun txtmonitor = "active matrix";
3209*4882a593Smuzhiyun break;
3210*4882a593Smuzhiyun case 2:
3211*4882a593Smuzhiyun txtmonitor = "active addressed STN";
3212*4882a593Smuzhiyun break;
3213*4882a593Smuzhiyun case 3:
3214*4882a593Smuzhiyun txtmonitor = "EL";
3215*4882a593Smuzhiyun break;
3216*4882a593Smuzhiyun case 4:
3217*4882a593Smuzhiyun txtmonitor = "plasma";
3218*4882a593Smuzhiyun break;
3219*4882a593Smuzhiyun default:
3220*4882a593Smuzhiyun txtmonitor = "unknown";
3221*4882a593Smuzhiyun }
3222*4882a593Smuzhiyun format = *(u32 *)(par->lcd_table+57);
3223*4882a593Smuzhiyun if (tech == 0 || tech == 2) {
3224*4882a593Smuzhiyun switch (format & 7) {
3225*4882a593Smuzhiyun case 0:
3226*4882a593Smuzhiyun txtformat = "12 bit interface";
3227*4882a593Smuzhiyun break;
3228*4882a593Smuzhiyun case 1:
3229*4882a593Smuzhiyun txtformat = "16 bit interface";
3230*4882a593Smuzhiyun break;
3231*4882a593Smuzhiyun case 2:
3232*4882a593Smuzhiyun txtformat = "24 bit interface";
3233*4882a593Smuzhiyun break;
3234*4882a593Smuzhiyun default:
3235*4882a593Smuzhiyun txtformat = "unknown format";
3236*4882a593Smuzhiyun }
3237*4882a593Smuzhiyun } else {
3238*4882a593Smuzhiyun switch (format & 7) {
3239*4882a593Smuzhiyun case 0:
3240*4882a593Smuzhiyun txtformat = "8 colours";
3241*4882a593Smuzhiyun break;
3242*4882a593Smuzhiyun case 1:
3243*4882a593Smuzhiyun txtformat = "512 colours";
3244*4882a593Smuzhiyun break;
3245*4882a593Smuzhiyun case 2:
3246*4882a593Smuzhiyun txtformat = "4096 colours";
3247*4882a593Smuzhiyun break;
3248*4882a593Smuzhiyun case 4:
3249*4882a593Smuzhiyun txtformat = "262144 colours (LT mode)";
3250*4882a593Smuzhiyun break;
3251*4882a593Smuzhiyun case 5:
3252*4882a593Smuzhiyun txtformat = "16777216 colours";
3253*4882a593Smuzhiyun break;
3254*4882a593Smuzhiyun case 6:
3255*4882a593Smuzhiyun txtformat = "262144 colours (FDPI-2 mode)";
3256*4882a593Smuzhiyun break;
3257*4882a593Smuzhiyun default:
3258*4882a593Smuzhiyun txtformat = "unknown format";
3259*4882a593Smuzhiyun }
3260*4882a593Smuzhiyun }
3261*4882a593Smuzhiyun PRINTKI("%s%s %s monitor detected: %s\n",
3262*4882a593Smuzhiyun txtdual, txtcolour, txtmonitor, model);
3263*4882a593Smuzhiyun PRINTKI(" id=%d, %dx%d pixels, %s\n",
3264*4882a593Smuzhiyun id, width, height, txtformat);
3265*4882a593Smuzhiyun refresh_rates_buf[0] = 0;
3266*4882a593Smuzhiyun refresh_rates = *(u16 *)(par->lcd_table+62);
3267*4882a593Smuzhiyun m = 1;
3268*4882a593Smuzhiyun f = 0;
3269*4882a593Smuzhiyun for (i = 0; i < 16; i++) {
3270*4882a593Smuzhiyun if (refresh_rates & m) {
3271*4882a593Smuzhiyun if (f == 0) {
3272*4882a593Smuzhiyun sprintf(strbuf, "%d",
3273*4882a593Smuzhiyun lcd_refresh_rates[i]);
3274*4882a593Smuzhiyun f++;
3275*4882a593Smuzhiyun } else {
3276*4882a593Smuzhiyun sprintf(strbuf, ",%d",
3277*4882a593Smuzhiyun lcd_refresh_rates[i]);
3278*4882a593Smuzhiyun }
3279*4882a593Smuzhiyun strcat(refresh_rates_buf, strbuf);
3280*4882a593Smuzhiyun }
3281*4882a593Smuzhiyun m = m << 1;
3282*4882a593Smuzhiyun }
3283*4882a593Smuzhiyun default_refresh_rate = (*(u8 *)(par->lcd_table+61) & 0xf0) >> 4;
3284*4882a593Smuzhiyun PRINTKI(" supports refresh rates [%s], default %d Hz\n",
3285*4882a593Smuzhiyun refresh_rates_buf, lcd_refresh_rates[default_refresh_rate]);
3286*4882a593Smuzhiyun par->lcd_refreshrate = lcd_refresh_rates[default_refresh_rate];
3287*4882a593Smuzhiyun /*
3288*4882a593Smuzhiyun * We now need to determine the crtc parameters for the
3289*4882a593Smuzhiyun * LCD monitor. This is tricky, because they are not stored
3290*4882a593Smuzhiyun * individually in the BIOS. Instead, the BIOS contains a
3291*4882a593Smuzhiyun * table of display modes that work for this monitor.
3292*4882a593Smuzhiyun *
3293*4882a593Smuzhiyun * The idea is that we search for a mode of the same dimensions
3294*4882a593Smuzhiyun * as the dimensions of the LCD monitor. Say our LCD monitor
3295*4882a593Smuzhiyun * is 800x600 pixels, we search for a 800x600 monitor.
3296*4882a593Smuzhiyun * The CRTC parameters we find here are the ones that we need
3297*4882a593Smuzhiyun * to use to simulate other resolutions on the LCD screen.
3298*4882a593Smuzhiyun */
3299*4882a593Smuzhiyun lcdmodeptr = (u16 *)(par->lcd_table + 64);
3300*4882a593Smuzhiyun while (*lcdmodeptr != 0) {
3301*4882a593Smuzhiyun u32 modeptr;
3302*4882a593Smuzhiyun u16 mwidth, mheight, lcd_hsync_start, lcd_vsync_start;
3303*4882a593Smuzhiyun modeptr = bios_base + *lcdmodeptr;
3304*4882a593Smuzhiyun
3305*4882a593Smuzhiyun mwidth = *((u16 *)(modeptr+0));
3306*4882a593Smuzhiyun mheight = *((u16 *)(modeptr+2));
3307*4882a593Smuzhiyun
3308*4882a593Smuzhiyun if (mwidth == width && mheight == height) {
3309*4882a593Smuzhiyun par->lcd_pixclock = 100000000 / *((u16 *)(modeptr+9));
3310*4882a593Smuzhiyun par->lcd_htotal = *((u16 *)(modeptr+17)) & 511;
3311*4882a593Smuzhiyun par->lcd_hdisp = *((u16 *)(modeptr+19)) & 511;
3312*4882a593Smuzhiyun lcd_hsync_start = *((u16 *)(modeptr+21)) & 511;
3313*4882a593Smuzhiyun par->lcd_hsync_dly = (*((u16 *)(modeptr+21)) >> 9) & 7;
3314*4882a593Smuzhiyun par->lcd_hsync_len = *((u8 *)(modeptr+23)) & 63;
3315*4882a593Smuzhiyun
3316*4882a593Smuzhiyun par->lcd_vtotal = *((u16 *)(modeptr+24)) & 2047;
3317*4882a593Smuzhiyun par->lcd_vdisp = *((u16 *)(modeptr+26)) & 2047;
3318*4882a593Smuzhiyun lcd_vsync_start = *((u16 *)(modeptr+28)) & 2047;
3319*4882a593Smuzhiyun par->lcd_vsync_len = (*((u16 *)(modeptr+28)) >> 11) & 31;
3320*4882a593Smuzhiyun
3321*4882a593Smuzhiyun par->lcd_htotal = (par->lcd_htotal + 1) * 8;
3322*4882a593Smuzhiyun par->lcd_hdisp = (par->lcd_hdisp + 1) * 8;
3323*4882a593Smuzhiyun lcd_hsync_start = (lcd_hsync_start + 1) * 8;
3324*4882a593Smuzhiyun par->lcd_hsync_len = par->lcd_hsync_len * 8;
3325*4882a593Smuzhiyun
3326*4882a593Smuzhiyun par->lcd_vtotal++;
3327*4882a593Smuzhiyun par->lcd_vdisp++;
3328*4882a593Smuzhiyun lcd_vsync_start++;
3329*4882a593Smuzhiyun
3330*4882a593Smuzhiyun par->lcd_right_margin = lcd_hsync_start - par->lcd_hdisp;
3331*4882a593Smuzhiyun par->lcd_lower_margin = lcd_vsync_start - par->lcd_vdisp;
3332*4882a593Smuzhiyun par->lcd_hblank_len = par->lcd_htotal - par->lcd_hdisp;
3333*4882a593Smuzhiyun par->lcd_vblank_len = par->lcd_vtotal - par->lcd_vdisp;
3334*4882a593Smuzhiyun break;
3335*4882a593Smuzhiyun }
3336*4882a593Smuzhiyun
3337*4882a593Smuzhiyun lcdmodeptr++;
3338*4882a593Smuzhiyun }
3339*4882a593Smuzhiyun if (*lcdmodeptr == 0) {
3340*4882a593Smuzhiyun PRINTKE("LCD monitor CRTC parameters not found!!!\n");
3341*4882a593Smuzhiyun /* To do: Switch to CRT if possible. */
3342*4882a593Smuzhiyun } else {
3343*4882a593Smuzhiyun PRINTKI(" LCD CRTC parameters: %d.%d %d %d %d %d %d %d %d %d\n",
3344*4882a593Smuzhiyun 1000000 / par->lcd_pixclock, 1000000 % par->lcd_pixclock,
3345*4882a593Smuzhiyun par->lcd_hdisp,
3346*4882a593Smuzhiyun par->lcd_hdisp + par->lcd_right_margin,
3347*4882a593Smuzhiyun par->lcd_hdisp + par->lcd_right_margin
3348*4882a593Smuzhiyun + par->lcd_hsync_dly + par->lcd_hsync_len,
3349*4882a593Smuzhiyun par->lcd_htotal,
3350*4882a593Smuzhiyun par->lcd_vdisp,
3351*4882a593Smuzhiyun par->lcd_vdisp + par->lcd_lower_margin,
3352*4882a593Smuzhiyun par->lcd_vdisp + par->lcd_lower_margin + par->lcd_vsync_len,
3353*4882a593Smuzhiyun par->lcd_vtotal);
3354*4882a593Smuzhiyun PRINTKI(" : %d %d %d %d %d %d %d %d %d\n",
3355*4882a593Smuzhiyun par->lcd_pixclock,
3356*4882a593Smuzhiyun par->lcd_hblank_len - (par->lcd_right_margin +
3357*4882a593Smuzhiyun par->lcd_hsync_dly + par->lcd_hsync_len),
3358*4882a593Smuzhiyun par->lcd_hdisp,
3359*4882a593Smuzhiyun par->lcd_right_margin,
3360*4882a593Smuzhiyun par->lcd_hsync_len,
3361*4882a593Smuzhiyun par->lcd_vblank_len - (par->lcd_lower_margin + par->lcd_vsync_len),
3362*4882a593Smuzhiyun par->lcd_vdisp,
3363*4882a593Smuzhiyun par->lcd_lower_margin,
3364*4882a593Smuzhiyun par->lcd_vsync_len);
3365*4882a593Smuzhiyun }
3366*4882a593Smuzhiyun }
3367*4882a593Smuzhiyun }
3368*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_GENERIC_LCD */
3369*4882a593Smuzhiyun
init_from_bios(struct atyfb_par * par)3370*4882a593Smuzhiyun static int init_from_bios(struct atyfb_par *par)
3371*4882a593Smuzhiyun {
3372*4882a593Smuzhiyun u32 bios_base, rom_addr;
3373*4882a593Smuzhiyun int ret;
3374*4882a593Smuzhiyun
3375*4882a593Smuzhiyun rom_addr = 0xc0000 + ((aty_ld_le32(SCRATCH_REG1, par) & 0x7f) << 11);
3376*4882a593Smuzhiyun bios_base = (unsigned long)ioremap(rom_addr, 0x10000);
3377*4882a593Smuzhiyun
3378*4882a593Smuzhiyun /* The BIOS starts with 0xaa55. */
3379*4882a593Smuzhiyun if (*((u16 *)bios_base) == 0xaa55) {
3380*4882a593Smuzhiyun
3381*4882a593Smuzhiyun u8 *bios_ptr;
3382*4882a593Smuzhiyun u16 rom_table_offset, freq_table_offset;
3383*4882a593Smuzhiyun PLL_BLOCK_MACH64 pll_block;
3384*4882a593Smuzhiyun
3385*4882a593Smuzhiyun PRINTKI("Mach64 BIOS is located at %x, mapped at %x.\n", rom_addr, bios_base);
3386*4882a593Smuzhiyun
3387*4882a593Smuzhiyun /* check for frequncy table */
3388*4882a593Smuzhiyun bios_ptr = (u8*)bios_base;
3389*4882a593Smuzhiyun rom_table_offset = (u16)(bios_ptr[0x48] | (bios_ptr[0x49] << 8));
3390*4882a593Smuzhiyun freq_table_offset = bios_ptr[rom_table_offset + 16] | (bios_ptr[rom_table_offset + 17] << 8);
3391*4882a593Smuzhiyun memcpy(&pll_block, bios_ptr + freq_table_offset, sizeof(PLL_BLOCK_MACH64));
3392*4882a593Smuzhiyun
3393*4882a593Smuzhiyun PRINTKI("BIOS frequency table:\n");
3394*4882a593Smuzhiyun PRINTKI("PCLK_min_freq %d, PCLK_max_freq %d, ref_freq %d, ref_divider %d\n",
3395*4882a593Smuzhiyun pll_block.PCLK_min_freq, pll_block.PCLK_max_freq,
3396*4882a593Smuzhiyun pll_block.ref_freq, pll_block.ref_divider);
3397*4882a593Smuzhiyun PRINTKI("MCLK_pwd %d, MCLK_max_freq %d, XCLK_max_freq %d, SCLK_freq %d\n",
3398*4882a593Smuzhiyun pll_block.MCLK_pwd, pll_block.MCLK_max_freq,
3399*4882a593Smuzhiyun pll_block.XCLK_max_freq, pll_block.SCLK_freq);
3400*4882a593Smuzhiyun
3401*4882a593Smuzhiyun par->pll_limits.pll_min = pll_block.PCLK_min_freq/100;
3402*4882a593Smuzhiyun par->pll_limits.pll_max = pll_block.PCLK_max_freq/100;
3403*4882a593Smuzhiyun par->pll_limits.ref_clk = pll_block.ref_freq/100;
3404*4882a593Smuzhiyun par->pll_limits.ref_div = pll_block.ref_divider;
3405*4882a593Smuzhiyun par->pll_limits.sclk = pll_block.SCLK_freq/100;
3406*4882a593Smuzhiyun par->pll_limits.mclk = pll_block.MCLK_max_freq/100;
3407*4882a593Smuzhiyun par->pll_limits.mclk_pm = pll_block.MCLK_pwd/100;
3408*4882a593Smuzhiyun par->pll_limits.xclk = pll_block.XCLK_max_freq/100;
3409*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GENERIC_LCD
3410*4882a593Smuzhiyun aty_init_lcd(par, bios_base);
3411*4882a593Smuzhiyun #endif
3412*4882a593Smuzhiyun ret = 0;
3413*4882a593Smuzhiyun } else {
3414*4882a593Smuzhiyun PRINTKE("no BIOS frequency table found, use parameters\n");
3415*4882a593Smuzhiyun ret = -ENXIO;
3416*4882a593Smuzhiyun }
3417*4882a593Smuzhiyun iounmap((void __iomem *)bios_base);
3418*4882a593Smuzhiyun
3419*4882a593Smuzhiyun return ret;
3420*4882a593Smuzhiyun }
3421*4882a593Smuzhiyun #endif /* __i386__ */
3422*4882a593Smuzhiyun
atyfb_setup_generic(struct pci_dev * pdev,struct fb_info * info,unsigned long addr)3423*4882a593Smuzhiyun static int atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info,
3424*4882a593Smuzhiyun unsigned long addr)
3425*4882a593Smuzhiyun {
3426*4882a593Smuzhiyun struct atyfb_par *par = info->par;
3427*4882a593Smuzhiyun u16 tmp;
3428*4882a593Smuzhiyun unsigned long raddr;
3429*4882a593Smuzhiyun struct resource *rrp;
3430*4882a593Smuzhiyun int ret = 0;
3431*4882a593Smuzhiyun
3432*4882a593Smuzhiyun raddr = addr + 0x7ff000UL;
3433*4882a593Smuzhiyun rrp = &pdev->resource[2];
3434*4882a593Smuzhiyun if ((rrp->flags & IORESOURCE_MEM) &&
3435*4882a593Smuzhiyun request_mem_region(rrp->start, resource_size(rrp), "atyfb")) {
3436*4882a593Smuzhiyun par->aux_start = rrp->start;
3437*4882a593Smuzhiyun par->aux_size = resource_size(rrp);
3438*4882a593Smuzhiyun raddr = rrp->start;
3439*4882a593Smuzhiyun PRINTKI("using auxiliary register aperture\n");
3440*4882a593Smuzhiyun }
3441*4882a593Smuzhiyun
3442*4882a593Smuzhiyun info->fix.mmio_start = raddr;
3443*4882a593Smuzhiyun /*
3444*4882a593Smuzhiyun * By using strong UC we force the MTRR to never have an
3445*4882a593Smuzhiyun * effect on the MMIO region on both non-PAT and PAT systems.
3446*4882a593Smuzhiyun */
3447*4882a593Smuzhiyun par->ati_regbase = ioremap_uc(info->fix.mmio_start, 0x1000);
3448*4882a593Smuzhiyun if (par->ati_regbase == NULL)
3449*4882a593Smuzhiyun return -ENOMEM;
3450*4882a593Smuzhiyun
3451*4882a593Smuzhiyun info->fix.mmio_start += par->aux_start ? 0x400 : 0xc00;
3452*4882a593Smuzhiyun par->ati_regbase += par->aux_start ? 0x400 : 0xc00;
3453*4882a593Smuzhiyun
3454*4882a593Smuzhiyun /*
3455*4882a593Smuzhiyun * Enable memory-space accesses using config-space
3456*4882a593Smuzhiyun * command register.
3457*4882a593Smuzhiyun */
3458*4882a593Smuzhiyun pci_read_config_word(pdev, PCI_COMMAND, &tmp);
3459*4882a593Smuzhiyun if (!(tmp & PCI_COMMAND_MEMORY)) {
3460*4882a593Smuzhiyun tmp |= PCI_COMMAND_MEMORY;
3461*4882a593Smuzhiyun pci_write_config_word(pdev, PCI_COMMAND, tmp);
3462*4882a593Smuzhiyun }
3463*4882a593Smuzhiyun #ifdef __BIG_ENDIAN
3464*4882a593Smuzhiyun /* Use the big-endian aperture */
3465*4882a593Smuzhiyun addr += 0x800000;
3466*4882a593Smuzhiyun #endif
3467*4882a593Smuzhiyun
3468*4882a593Smuzhiyun /* Map in frame buffer */
3469*4882a593Smuzhiyun info->fix.smem_start = addr;
3470*4882a593Smuzhiyun
3471*4882a593Smuzhiyun /*
3472*4882a593Smuzhiyun * The framebuffer is not always 8 MiB, that's just the size of the
3473*4882a593Smuzhiyun * PCI BAR. We temporarily abuse smem_len here to store the size
3474*4882a593Smuzhiyun * of the BAR. aty_init() will later correct it to match the actual
3475*4882a593Smuzhiyun * framebuffer size.
3476*4882a593Smuzhiyun *
3477*4882a593Smuzhiyun * On devices that don't have the auxiliary register aperture, the
3478*4882a593Smuzhiyun * registers are housed at the top end of the framebuffer PCI BAR.
3479*4882a593Smuzhiyun * aty_fudge_framebuffer_len() is used to reduce smem_len to not
3480*4882a593Smuzhiyun * overlap with the registers.
3481*4882a593Smuzhiyun */
3482*4882a593Smuzhiyun info->fix.smem_len = 0x800000;
3483*4882a593Smuzhiyun
3484*4882a593Smuzhiyun aty_fudge_framebuffer_len(info);
3485*4882a593Smuzhiyun
3486*4882a593Smuzhiyun info->screen_base = ioremap_wc(info->fix.smem_start,
3487*4882a593Smuzhiyun info->fix.smem_len);
3488*4882a593Smuzhiyun if (info->screen_base == NULL) {
3489*4882a593Smuzhiyun ret = -ENOMEM;
3490*4882a593Smuzhiyun goto atyfb_setup_generic_fail;
3491*4882a593Smuzhiyun }
3492*4882a593Smuzhiyun
3493*4882a593Smuzhiyun ret = correct_chipset(par);
3494*4882a593Smuzhiyun if (ret)
3495*4882a593Smuzhiyun goto atyfb_setup_generic_fail;
3496*4882a593Smuzhiyun #ifdef __i386__
3497*4882a593Smuzhiyun ret = init_from_bios(par);
3498*4882a593Smuzhiyun if (ret)
3499*4882a593Smuzhiyun goto atyfb_setup_generic_fail;
3500*4882a593Smuzhiyun #endif
3501*4882a593Smuzhiyun if (!(aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_EXT_DISP_EN))
3502*4882a593Smuzhiyun par->clk_wr_offset = (inb(R_GENMO) & 0x0CU) >> 2;
3503*4882a593Smuzhiyun else
3504*4882a593Smuzhiyun par->clk_wr_offset = aty_ld_8(CLOCK_CNTL, par) & 0x03U;
3505*4882a593Smuzhiyun
3506*4882a593Smuzhiyun /* according to ATI, we should use clock 3 for acelerated mode */
3507*4882a593Smuzhiyun par->clk_wr_offset = 3;
3508*4882a593Smuzhiyun
3509*4882a593Smuzhiyun return 0;
3510*4882a593Smuzhiyun
3511*4882a593Smuzhiyun atyfb_setup_generic_fail:
3512*4882a593Smuzhiyun iounmap(par->ati_regbase);
3513*4882a593Smuzhiyun par->ati_regbase = NULL;
3514*4882a593Smuzhiyun if (info->screen_base) {
3515*4882a593Smuzhiyun iounmap(info->screen_base);
3516*4882a593Smuzhiyun info->screen_base = NULL;
3517*4882a593Smuzhiyun }
3518*4882a593Smuzhiyun return ret;
3519*4882a593Smuzhiyun }
3520*4882a593Smuzhiyun
3521*4882a593Smuzhiyun #endif /* !__sparc__ */
3522*4882a593Smuzhiyun
atyfb_pci_probe(struct pci_dev * pdev,const struct pci_device_id * ent)3523*4882a593Smuzhiyun static int atyfb_pci_probe(struct pci_dev *pdev,
3524*4882a593Smuzhiyun const struct pci_device_id *ent)
3525*4882a593Smuzhiyun {
3526*4882a593Smuzhiyun unsigned long addr, res_start, res_size;
3527*4882a593Smuzhiyun struct fb_info *info;
3528*4882a593Smuzhiyun struct resource *rp;
3529*4882a593Smuzhiyun struct atyfb_par *par;
3530*4882a593Smuzhiyun int rc = -ENOMEM;
3531*4882a593Smuzhiyun
3532*4882a593Smuzhiyun /* Enable device in PCI config */
3533*4882a593Smuzhiyun if (pci_enable_device(pdev)) {
3534*4882a593Smuzhiyun PRINTKE("Cannot enable PCI device\n");
3535*4882a593Smuzhiyun return -ENXIO;
3536*4882a593Smuzhiyun }
3537*4882a593Smuzhiyun
3538*4882a593Smuzhiyun /* Find which resource to use */
3539*4882a593Smuzhiyun rp = &pdev->resource[0];
3540*4882a593Smuzhiyun if (rp->flags & IORESOURCE_IO)
3541*4882a593Smuzhiyun rp = &pdev->resource[1];
3542*4882a593Smuzhiyun addr = rp->start;
3543*4882a593Smuzhiyun if (!addr)
3544*4882a593Smuzhiyun return -ENXIO;
3545*4882a593Smuzhiyun
3546*4882a593Smuzhiyun /* Reserve space */
3547*4882a593Smuzhiyun res_start = rp->start;
3548*4882a593Smuzhiyun res_size = resource_size(rp);
3549*4882a593Smuzhiyun if (!request_mem_region(res_start, res_size, "atyfb"))
3550*4882a593Smuzhiyun return -EBUSY;
3551*4882a593Smuzhiyun
3552*4882a593Smuzhiyun /* Allocate framebuffer */
3553*4882a593Smuzhiyun info = framebuffer_alloc(sizeof(struct atyfb_par), &pdev->dev);
3554*4882a593Smuzhiyun if (!info)
3555*4882a593Smuzhiyun return -ENOMEM;
3556*4882a593Smuzhiyun
3557*4882a593Smuzhiyun par = info->par;
3558*4882a593Smuzhiyun par->bus_type = PCI;
3559*4882a593Smuzhiyun info->fix = atyfb_fix;
3560*4882a593Smuzhiyun info->device = &pdev->dev;
3561*4882a593Smuzhiyun par->pci_id = pdev->device;
3562*4882a593Smuzhiyun par->res_start = res_start;
3563*4882a593Smuzhiyun par->res_size = res_size;
3564*4882a593Smuzhiyun par->irq = pdev->irq;
3565*4882a593Smuzhiyun par->pdev = pdev;
3566*4882a593Smuzhiyun
3567*4882a593Smuzhiyun /* Setup "info" structure */
3568*4882a593Smuzhiyun #ifdef __sparc__
3569*4882a593Smuzhiyun rc = atyfb_setup_sparc(pdev, info, addr);
3570*4882a593Smuzhiyun #else
3571*4882a593Smuzhiyun rc = atyfb_setup_generic(pdev, info, addr);
3572*4882a593Smuzhiyun #endif
3573*4882a593Smuzhiyun if (rc)
3574*4882a593Smuzhiyun goto err_release_mem;
3575*4882a593Smuzhiyun
3576*4882a593Smuzhiyun pci_set_drvdata(pdev, info);
3577*4882a593Smuzhiyun
3578*4882a593Smuzhiyun /* Init chip & register framebuffer */
3579*4882a593Smuzhiyun rc = aty_init(info);
3580*4882a593Smuzhiyun if (rc)
3581*4882a593Smuzhiyun goto err_release_io;
3582*4882a593Smuzhiyun
3583*4882a593Smuzhiyun #ifdef __sparc__
3584*4882a593Smuzhiyun /*
3585*4882a593Smuzhiyun * Add /dev/fb mmap values.
3586*4882a593Smuzhiyun */
3587*4882a593Smuzhiyun par->mmap_map[0].voff = 0x8000000000000000UL;
3588*4882a593Smuzhiyun par->mmap_map[0].poff = (unsigned long) info->screen_base & PAGE_MASK;
3589*4882a593Smuzhiyun par->mmap_map[0].size = info->fix.smem_len;
3590*4882a593Smuzhiyun par->mmap_map[0].prot_mask = _PAGE_CACHE;
3591*4882a593Smuzhiyun par->mmap_map[0].prot_flag = _PAGE_E;
3592*4882a593Smuzhiyun par->mmap_map[1].voff = par->mmap_map[0].voff + info->fix.smem_len;
3593*4882a593Smuzhiyun par->mmap_map[1].poff = (long)par->ati_regbase & PAGE_MASK;
3594*4882a593Smuzhiyun par->mmap_map[1].size = PAGE_SIZE;
3595*4882a593Smuzhiyun par->mmap_map[1].prot_mask = _PAGE_CACHE;
3596*4882a593Smuzhiyun par->mmap_map[1].prot_flag = _PAGE_E;
3597*4882a593Smuzhiyun #endif /* __sparc__ */
3598*4882a593Smuzhiyun
3599*4882a593Smuzhiyun mutex_lock(&reboot_lock);
3600*4882a593Smuzhiyun if (!reboot_info)
3601*4882a593Smuzhiyun reboot_info = info;
3602*4882a593Smuzhiyun mutex_unlock(&reboot_lock);
3603*4882a593Smuzhiyun
3604*4882a593Smuzhiyun return 0;
3605*4882a593Smuzhiyun
3606*4882a593Smuzhiyun err_release_io:
3607*4882a593Smuzhiyun #ifdef __sparc__
3608*4882a593Smuzhiyun kfree(par->mmap_map);
3609*4882a593Smuzhiyun #else
3610*4882a593Smuzhiyun if (par->ati_regbase)
3611*4882a593Smuzhiyun iounmap(par->ati_regbase);
3612*4882a593Smuzhiyun if (info->screen_base)
3613*4882a593Smuzhiyun iounmap(info->screen_base);
3614*4882a593Smuzhiyun #endif
3615*4882a593Smuzhiyun err_release_mem:
3616*4882a593Smuzhiyun if (par->aux_start)
3617*4882a593Smuzhiyun release_mem_region(par->aux_start, par->aux_size);
3618*4882a593Smuzhiyun
3619*4882a593Smuzhiyun release_mem_region(par->res_start, par->res_size);
3620*4882a593Smuzhiyun framebuffer_release(info);
3621*4882a593Smuzhiyun
3622*4882a593Smuzhiyun return rc;
3623*4882a593Smuzhiyun }
3624*4882a593Smuzhiyun
3625*4882a593Smuzhiyun #endif /* CONFIG_PCI */
3626*4882a593Smuzhiyun
3627*4882a593Smuzhiyun #ifdef CONFIG_ATARI
3628*4882a593Smuzhiyun
atyfb_atari_probe(void)3629*4882a593Smuzhiyun static int __init atyfb_atari_probe(void)
3630*4882a593Smuzhiyun {
3631*4882a593Smuzhiyun struct atyfb_par *par;
3632*4882a593Smuzhiyun struct fb_info *info;
3633*4882a593Smuzhiyun int m64_num;
3634*4882a593Smuzhiyun u32 clock_r;
3635*4882a593Smuzhiyun int num_found = 0;
3636*4882a593Smuzhiyun
3637*4882a593Smuzhiyun for (m64_num = 0; m64_num < mach64_count; m64_num++) {
3638*4882a593Smuzhiyun if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
3639*4882a593Smuzhiyun !phys_guiregbase[m64_num]) {
3640*4882a593Smuzhiyun PRINTKI("phys_*[%d] parameters not set => "
3641*4882a593Smuzhiyun "returning early. \n", m64_num);
3642*4882a593Smuzhiyun continue;
3643*4882a593Smuzhiyun }
3644*4882a593Smuzhiyun
3645*4882a593Smuzhiyun info = framebuffer_alloc(sizeof(struct atyfb_par), NULL);
3646*4882a593Smuzhiyun if (!info)
3647*4882a593Smuzhiyun return -ENOMEM;
3648*4882a593Smuzhiyun
3649*4882a593Smuzhiyun par = info->par;
3650*4882a593Smuzhiyun
3651*4882a593Smuzhiyun info->fix = atyfb_fix;
3652*4882a593Smuzhiyun
3653*4882a593Smuzhiyun par->irq = (unsigned int) -1; /* something invalid */
3654*4882a593Smuzhiyun
3655*4882a593Smuzhiyun /*
3656*4882a593Smuzhiyun * Map the video memory (physical address given)
3657*4882a593Smuzhiyun * to somewhere in the kernel address space.
3658*4882a593Smuzhiyun */
3659*4882a593Smuzhiyun info->screen_base = ioremap_wc(phys_vmembase[m64_num],
3660*4882a593Smuzhiyun phys_size[m64_num]);
3661*4882a593Smuzhiyun info->fix.smem_start = (unsigned long)info->screen_base; /* Fake! */
3662*4882a593Smuzhiyun par->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000) +
3663*4882a593Smuzhiyun 0xFC00ul;
3664*4882a593Smuzhiyun info->fix.mmio_start = (unsigned long)par->ati_regbase; /* Fake! */
3665*4882a593Smuzhiyun
3666*4882a593Smuzhiyun aty_st_le32(CLOCK_CNTL, 0x12345678, par);
3667*4882a593Smuzhiyun clock_r = aty_ld_le32(CLOCK_CNTL, par);
3668*4882a593Smuzhiyun
3669*4882a593Smuzhiyun switch (clock_r & 0x003F) {
3670*4882a593Smuzhiyun case 0x12:
3671*4882a593Smuzhiyun par->clk_wr_offset = 3; /* */
3672*4882a593Smuzhiyun break;
3673*4882a593Smuzhiyun case 0x34:
3674*4882a593Smuzhiyun par->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */
3675*4882a593Smuzhiyun break;
3676*4882a593Smuzhiyun case 0x16:
3677*4882a593Smuzhiyun par->clk_wr_offset = 1; /* */
3678*4882a593Smuzhiyun break;
3679*4882a593Smuzhiyun case 0x38:
3680*4882a593Smuzhiyun par->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */
3681*4882a593Smuzhiyun break;
3682*4882a593Smuzhiyun }
3683*4882a593Smuzhiyun
3684*4882a593Smuzhiyun /* Fake pci_id for correct_chipset() */
3685*4882a593Smuzhiyun switch (aty_ld_le32(CNFG_CHIP_ID, par) & CFG_CHIP_TYPE) {
3686*4882a593Smuzhiyun case 0x00d7:
3687*4882a593Smuzhiyun par->pci_id = PCI_CHIP_MACH64GX;
3688*4882a593Smuzhiyun break;
3689*4882a593Smuzhiyun case 0x0057:
3690*4882a593Smuzhiyun par->pci_id = PCI_CHIP_MACH64CX;
3691*4882a593Smuzhiyun break;
3692*4882a593Smuzhiyun default:
3693*4882a593Smuzhiyun break;
3694*4882a593Smuzhiyun }
3695*4882a593Smuzhiyun
3696*4882a593Smuzhiyun if (correct_chipset(par) || aty_init(info)) {
3697*4882a593Smuzhiyun iounmap(info->screen_base);
3698*4882a593Smuzhiyun iounmap(par->ati_regbase);
3699*4882a593Smuzhiyun framebuffer_release(info);
3700*4882a593Smuzhiyun } else {
3701*4882a593Smuzhiyun num_found++;
3702*4882a593Smuzhiyun }
3703*4882a593Smuzhiyun }
3704*4882a593Smuzhiyun
3705*4882a593Smuzhiyun return num_found ? 0 : -ENXIO;
3706*4882a593Smuzhiyun }
3707*4882a593Smuzhiyun
3708*4882a593Smuzhiyun #endif /* CONFIG_ATARI */
3709*4882a593Smuzhiyun
3710*4882a593Smuzhiyun #ifdef CONFIG_PCI
3711*4882a593Smuzhiyun
atyfb_remove(struct fb_info * info)3712*4882a593Smuzhiyun static void atyfb_remove(struct fb_info *info)
3713*4882a593Smuzhiyun {
3714*4882a593Smuzhiyun struct atyfb_par *par = (struct atyfb_par *) info->par;
3715*4882a593Smuzhiyun
3716*4882a593Smuzhiyun /* restore video mode */
3717*4882a593Smuzhiyun aty_set_crtc(par, &par->saved_crtc);
3718*4882a593Smuzhiyun par->pll_ops->set_pll(info, &par->saved_pll);
3719*4882a593Smuzhiyun
3720*4882a593Smuzhiyun unregister_framebuffer(info);
3721*4882a593Smuzhiyun
3722*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_BACKLIGHT
3723*4882a593Smuzhiyun if (M64_HAS(MOBIL_BUS))
3724*4882a593Smuzhiyun aty_bl_exit(info->bl_dev);
3725*4882a593Smuzhiyun #endif
3726*4882a593Smuzhiyun arch_phys_wc_del(par->wc_cookie);
3727*4882a593Smuzhiyun
3728*4882a593Smuzhiyun #ifndef __sparc__
3729*4882a593Smuzhiyun if (par->ati_regbase)
3730*4882a593Smuzhiyun iounmap(par->ati_regbase);
3731*4882a593Smuzhiyun if (info->screen_base)
3732*4882a593Smuzhiyun iounmap(info->screen_base);
3733*4882a593Smuzhiyun #ifdef __BIG_ENDIAN
3734*4882a593Smuzhiyun if (info->sprite.addr)
3735*4882a593Smuzhiyun iounmap(info->sprite.addr);
3736*4882a593Smuzhiyun #endif
3737*4882a593Smuzhiyun #endif
3738*4882a593Smuzhiyun #ifdef __sparc__
3739*4882a593Smuzhiyun kfree(par->mmap_map);
3740*4882a593Smuzhiyun #endif
3741*4882a593Smuzhiyun if (par->aux_start)
3742*4882a593Smuzhiyun release_mem_region(par->aux_start, par->aux_size);
3743*4882a593Smuzhiyun
3744*4882a593Smuzhiyun if (par->res_start)
3745*4882a593Smuzhiyun release_mem_region(par->res_start, par->res_size);
3746*4882a593Smuzhiyun
3747*4882a593Smuzhiyun framebuffer_release(info);
3748*4882a593Smuzhiyun }
3749*4882a593Smuzhiyun
3750*4882a593Smuzhiyun
atyfb_pci_remove(struct pci_dev * pdev)3751*4882a593Smuzhiyun static void atyfb_pci_remove(struct pci_dev *pdev)
3752*4882a593Smuzhiyun {
3753*4882a593Smuzhiyun struct fb_info *info = pci_get_drvdata(pdev);
3754*4882a593Smuzhiyun
3755*4882a593Smuzhiyun mutex_lock(&reboot_lock);
3756*4882a593Smuzhiyun if (reboot_info == info)
3757*4882a593Smuzhiyun reboot_info = NULL;
3758*4882a593Smuzhiyun mutex_unlock(&reboot_lock);
3759*4882a593Smuzhiyun
3760*4882a593Smuzhiyun atyfb_remove(info);
3761*4882a593Smuzhiyun }
3762*4882a593Smuzhiyun
3763*4882a593Smuzhiyun static const struct pci_device_id atyfb_pci_tbl[] = {
3764*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_GX
3765*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GX) },
3766*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64CX) },
3767*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_GX */
3768*4882a593Smuzhiyun
3769*4882a593Smuzhiyun #ifdef CONFIG_FB_ATY_CT
3770*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64CT) },
3771*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64ET) },
3772*4882a593Smuzhiyun
3773*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LT) },
3774*4882a593Smuzhiyun
3775*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VT) },
3776*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GT) },
3777*4882a593Smuzhiyun
3778*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VU) },
3779*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GU) },
3780*4882a593Smuzhiyun
3781*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LG) },
3782*4882a593Smuzhiyun
3783*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64VV) },
3784*4882a593Smuzhiyun
3785*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GV) },
3786*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GW) },
3787*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GY) },
3788*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GZ) },
3789*4882a593Smuzhiyun
3790*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GB) },
3791*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GD) },
3792*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GI) },
3793*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GP) },
3794*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GQ) },
3795*4882a593Smuzhiyun
3796*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LB) },
3797*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LD) },
3798*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LI) },
3799*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LP) },
3800*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LQ) },
3801*4882a593Smuzhiyun
3802*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GM) },
3803*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GN) },
3804*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GO) },
3805*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GL) },
3806*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GR) },
3807*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64GS) },
3808*4882a593Smuzhiyun
3809*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LM) },
3810*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LN) },
3811*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LR) },
3812*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_CHIP_MACH64LS) },
3813*4882a593Smuzhiyun #endif /* CONFIG_FB_ATY_CT */
3814*4882a593Smuzhiyun { }
3815*4882a593Smuzhiyun };
3816*4882a593Smuzhiyun
3817*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, atyfb_pci_tbl);
3818*4882a593Smuzhiyun
3819*4882a593Smuzhiyun static struct pci_driver atyfb_driver = {
3820*4882a593Smuzhiyun .name = "atyfb",
3821*4882a593Smuzhiyun .id_table = atyfb_pci_tbl,
3822*4882a593Smuzhiyun .probe = atyfb_pci_probe,
3823*4882a593Smuzhiyun .remove = atyfb_pci_remove,
3824*4882a593Smuzhiyun .driver.pm = &atyfb_pci_pm_ops,
3825*4882a593Smuzhiyun };
3826*4882a593Smuzhiyun
3827*4882a593Smuzhiyun #endif /* CONFIG_PCI */
3828*4882a593Smuzhiyun
3829*4882a593Smuzhiyun #ifndef MODULE
atyfb_setup(char * options)3830*4882a593Smuzhiyun static int __init atyfb_setup(char *options)
3831*4882a593Smuzhiyun {
3832*4882a593Smuzhiyun char *this_opt;
3833*4882a593Smuzhiyun
3834*4882a593Smuzhiyun if (!options || !*options)
3835*4882a593Smuzhiyun return 0;
3836*4882a593Smuzhiyun
3837*4882a593Smuzhiyun while ((this_opt = strsep(&options, ",")) != NULL) {
3838*4882a593Smuzhiyun if (!strncmp(this_opt, "noaccel", 7)) {
3839*4882a593Smuzhiyun noaccel = true;
3840*4882a593Smuzhiyun } else if (!strncmp(this_opt, "nomtrr", 6)) {
3841*4882a593Smuzhiyun nomtrr = true;
3842*4882a593Smuzhiyun } else if (!strncmp(this_opt, "vram:", 5))
3843*4882a593Smuzhiyun vram = simple_strtoul(this_opt + 5, NULL, 0);
3844*4882a593Smuzhiyun else if (!strncmp(this_opt, "pll:", 4))
3845*4882a593Smuzhiyun pll = simple_strtoul(this_opt + 4, NULL, 0);
3846*4882a593Smuzhiyun else if (!strncmp(this_opt, "mclk:", 5))
3847*4882a593Smuzhiyun mclk = simple_strtoul(this_opt + 5, NULL, 0);
3848*4882a593Smuzhiyun else if (!strncmp(this_opt, "xclk:", 5))
3849*4882a593Smuzhiyun xclk = simple_strtoul(this_opt+5, NULL, 0);
3850*4882a593Smuzhiyun else if (!strncmp(this_opt, "comp_sync:", 10))
3851*4882a593Smuzhiyun comp_sync = simple_strtoul(this_opt+10, NULL, 0);
3852*4882a593Smuzhiyun else if (!strncmp(this_opt, "backlight:", 10))
3853*4882a593Smuzhiyun backlight = simple_strtoul(this_opt+10, NULL, 0);
3854*4882a593Smuzhiyun #ifdef CONFIG_PPC
3855*4882a593Smuzhiyun else if (!strncmp(this_opt, "vmode:", 6)) {
3856*4882a593Smuzhiyun unsigned int vmode =
3857*4882a593Smuzhiyun simple_strtoul(this_opt + 6, NULL, 0);
3858*4882a593Smuzhiyun if (vmode > 0 && vmode <= VMODE_MAX)
3859*4882a593Smuzhiyun default_vmode = vmode;
3860*4882a593Smuzhiyun } else if (!strncmp(this_opt, "cmode:", 6)) {
3861*4882a593Smuzhiyun unsigned int cmode =
3862*4882a593Smuzhiyun simple_strtoul(this_opt + 6, NULL, 0);
3863*4882a593Smuzhiyun switch (cmode) {
3864*4882a593Smuzhiyun case 0:
3865*4882a593Smuzhiyun case 8:
3866*4882a593Smuzhiyun default_cmode = CMODE_8;
3867*4882a593Smuzhiyun break;
3868*4882a593Smuzhiyun case 15:
3869*4882a593Smuzhiyun case 16:
3870*4882a593Smuzhiyun default_cmode = CMODE_16;
3871*4882a593Smuzhiyun break;
3872*4882a593Smuzhiyun case 24:
3873*4882a593Smuzhiyun case 32:
3874*4882a593Smuzhiyun default_cmode = CMODE_32;
3875*4882a593Smuzhiyun break;
3876*4882a593Smuzhiyun }
3877*4882a593Smuzhiyun }
3878*4882a593Smuzhiyun #endif
3879*4882a593Smuzhiyun #ifdef CONFIG_ATARI
3880*4882a593Smuzhiyun /*
3881*4882a593Smuzhiyun * Why do we need this silly Mach64 argument?
3882*4882a593Smuzhiyun * We are already here because of mach64= so its redundant.
3883*4882a593Smuzhiyun */
3884*4882a593Smuzhiyun else if (MACH_IS_ATARI
3885*4882a593Smuzhiyun && (!strncmp(this_opt, "Mach64:", 7))) {
3886*4882a593Smuzhiyun static unsigned char m64_num;
3887*4882a593Smuzhiyun static char mach64_str[80];
3888*4882a593Smuzhiyun strlcpy(mach64_str, this_opt + 7, sizeof(mach64_str));
3889*4882a593Smuzhiyun if (!store_video_par(mach64_str, m64_num)) {
3890*4882a593Smuzhiyun m64_num++;
3891*4882a593Smuzhiyun mach64_count = m64_num;
3892*4882a593Smuzhiyun }
3893*4882a593Smuzhiyun }
3894*4882a593Smuzhiyun #endif
3895*4882a593Smuzhiyun else
3896*4882a593Smuzhiyun mode = this_opt;
3897*4882a593Smuzhiyun }
3898*4882a593Smuzhiyun return 0;
3899*4882a593Smuzhiyun }
3900*4882a593Smuzhiyun #endif /* MODULE */
3901*4882a593Smuzhiyun
atyfb_reboot_notify(struct notifier_block * nb,unsigned long code,void * unused)3902*4882a593Smuzhiyun static int atyfb_reboot_notify(struct notifier_block *nb,
3903*4882a593Smuzhiyun unsigned long code, void *unused)
3904*4882a593Smuzhiyun {
3905*4882a593Smuzhiyun struct atyfb_par *par;
3906*4882a593Smuzhiyun
3907*4882a593Smuzhiyun if (code != SYS_RESTART)
3908*4882a593Smuzhiyun return NOTIFY_DONE;
3909*4882a593Smuzhiyun
3910*4882a593Smuzhiyun mutex_lock(&reboot_lock);
3911*4882a593Smuzhiyun
3912*4882a593Smuzhiyun if (!reboot_info)
3913*4882a593Smuzhiyun goto out;
3914*4882a593Smuzhiyun
3915*4882a593Smuzhiyun lock_fb_info(reboot_info);
3916*4882a593Smuzhiyun
3917*4882a593Smuzhiyun par = reboot_info->par;
3918*4882a593Smuzhiyun
3919*4882a593Smuzhiyun /*
3920*4882a593Smuzhiyun * HP OmniBook 500's BIOS doesn't like the state of the
3921*4882a593Smuzhiyun * hardware after atyfb has been used. Restore the hardware
3922*4882a593Smuzhiyun * to the original state to allow successful reboots.
3923*4882a593Smuzhiyun */
3924*4882a593Smuzhiyun aty_set_crtc(par, &par->saved_crtc);
3925*4882a593Smuzhiyun par->pll_ops->set_pll(reboot_info, &par->saved_pll);
3926*4882a593Smuzhiyun
3927*4882a593Smuzhiyun unlock_fb_info(reboot_info);
3928*4882a593Smuzhiyun out:
3929*4882a593Smuzhiyun mutex_unlock(&reboot_lock);
3930*4882a593Smuzhiyun
3931*4882a593Smuzhiyun return NOTIFY_DONE;
3932*4882a593Smuzhiyun }
3933*4882a593Smuzhiyun
3934*4882a593Smuzhiyun static struct notifier_block atyfb_reboot_notifier = {
3935*4882a593Smuzhiyun .notifier_call = atyfb_reboot_notify,
3936*4882a593Smuzhiyun };
3937*4882a593Smuzhiyun
3938*4882a593Smuzhiyun static const struct dmi_system_id atyfb_reboot_ids[] __initconst = {
3939*4882a593Smuzhiyun {
3940*4882a593Smuzhiyun .ident = "HP OmniBook 500",
3941*4882a593Smuzhiyun .matches = {
3942*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
3943*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "HP OmniBook PC"),
3944*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_VERSION, "HP OmniBook 500 FA"),
3945*4882a593Smuzhiyun },
3946*4882a593Smuzhiyun },
3947*4882a593Smuzhiyun
3948*4882a593Smuzhiyun { }
3949*4882a593Smuzhiyun };
3950*4882a593Smuzhiyun static bool registered_notifier = false;
3951*4882a593Smuzhiyun
atyfb_init(void)3952*4882a593Smuzhiyun static int __init atyfb_init(void)
3953*4882a593Smuzhiyun {
3954*4882a593Smuzhiyun int err1 = 1, err2 = 1;
3955*4882a593Smuzhiyun #ifndef MODULE
3956*4882a593Smuzhiyun char *option = NULL;
3957*4882a593Smuzhiyun
3958*4882a593Smuzhiyun if (fb_get_options("atyfb", &option))
3959*4882a593Smuzhiyun return -ENODEV;
3960*4882a593Smuzhiyun atyfb_setup(option);
3961*4882a593Smuzhiyun #endif
3962*4882a593Smuzhiyun
3963*4882a593Smuzhiyun #ifdef CONFIG_PCI
3964*4882a593Smuzhiyun err1 = pci_register_driver(&atyfb_driver);
3965*4882a593Smuzhiyun #endif
3966*4882a593Smuzhiyun #ifdef CONFIG_ATARI
3967*4882a593Smuzhiyun err2 = atyfb_atari_probe();
3968*4882a593Smuzhiyun #endif
3969*4882a593Smuzhiyun
3970*4882a593Smuzhiyun if (err1 && err2)
3971*4882a593Smuzhiyun return -ENODEV;
3972*4882a593Smuzhiyun
3973*4882a593Smuzhiyun if (dmi_check_system(atyfb_reboot_ids)) {
3974*4882a593Smuzhiyun register_reboot_notifier(&atyfb_reboot_notifier);
3975*4882a593Smuzhiyun registered_notifier = true;
3976*4882a593Smuzhiyun }
3977*4882a593Smuzhiyun
3978*4882a593Smuzhiyun return 0;
3979*4882a593Smuzhiyun }
3980*4882a593Smuzhiyun
atyfb_exit(void)3981*4882a593Smuzhiyun static void __exit atyfb_exit(void)
3982*4882a593Smuzhiyun {
3983*4882a593Smuzhiyun if (registered_notifier)
3984*4882a593Smuzhiyun unregister_reboot_notifier(&atyfb_reboot_notifier);
3985*4882a593Smuzhiyun
3986*4882a593Smuzhiyun #ifdef CONFIG_PCI
3987*4882a593Smuzhiyun pci_unregister_driver(&atyfb_driver);
3988*4882a593Smuzhiyun #endif
3989*4882a593Smuzhiyun }
3990*4882a593Smuzhiyun
3991*4882a593Smuzhiyun module_init(atyfb_init);
3992*4882a593Smuzhiyun module_exit(atyfb_exit);
3993*4882a593Smuzhiyun
3994*4882a593Smuzhiyun MODULE_DESCRIPTION("FBDev driver for ATI Mach64 cards");
3995*4882a593Smuzhiyun MODULE_LICENSE("GPL");
3996*4882a593Smuzhiyun module_param(noaccel, bool, 0);
3997*4882a593Smuzhiyun MODULE_PARM_DESC(noaccel, "bool: disable acceleration");
3998*4882a593Smuzhiyun module_param(vram, int, 0);
3999*4882a593Smuzhiyun MODULE_PARM_DESC(vram, "int: override size of video ram");
4000*4882a593Smuzhiyun module_param(pll, int, 0);
4001*4882a593Smuzhiyun MODULE_PARM_DESC(pll, "int: override video clock");
4002*4882a593Smuzhiyun module_param(mclk, int, 0);
4003*4882a593Smuzhiyun MODULE_PARM_DESC(mclk, "int: override memory clock");
4004*4882a593Smuzhiyun module_param(xclk, int, 0);
4005*4882a593Smuzhiyun MODULE_PARM_DESC(xclk, "int: override accelerated engine clock");
4006*4882a593Smuzhiyun module_param(comp_sync, int, 0);
4007*4882a593Smuzhiyun MODULE_PARM_DESC(comp_sync, "Set composite sync signal to low (0) or high (1)");
4008*4882a593Smuzhiyun module_param(mode, charp, 0);
4009*4882a593Smuzhiyun MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
4010*4882a593Smuzhiyun module_param(nomtrr, bool, 0);
4011*4882a593Smuzhiyun MODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers");
4012