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