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