1 /* $Id: atyfb.c,v 1.142 2000/04/12 01:39:41 davem Exp $
2 * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
4 * Copyright (C) 1997-1998 Geert Uytterhoeven
5 * Copyright (C) 1998 Bernd Harries
6 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
8 * This driver is partly based on the PowerMac console driver:
10 * Copyright (C) 1996 Paul Mackerras
12 * and on the PowerMac ATI/mach64 display driver:
14 * Copyright (C) 1997 Michael AK Tesch
16 * with work by Jon Howell
18 * Anthony Tong <atong@uiuc.edu>
20 * This file is subject to the terms and conditions of the GNU General Public
21 * License. See the file COPYING in the main directory of this archive for
25 /******************************************************************************
29 - cursor support on all cards and all ramdacs.
30 - cursor parameters controlable via ioctl()s.
31 - guess PLL and MCLK based on the original PLL register values initialized
32 by the BIOS or Open Firmware (if they are initialized).
34 (Anyone to help with this?)
36 ******************************************************************************/
39 #include <linux/config.h>
40 #include <linux/module.h>
41 #include <linux/kernel.h>
42 #include <linux/errno.h>
43 #include <linux/string.h>
45 #include <linux/tty.h>
46 #include <linux/malloc.h>
47 #include <linux/vmalloc.h>
48 #include <linux/delay.h>
49 #include <linux/interrupt.h>
51 #include <linux/selection.h>
52 #include <linux/console.h>
53 #include <linux/init.h>
54 #include <linux/pci.h>
56 #include <linux/vt_kern.h>
58 #ifdef CONFIG_FB_COMPAT_XPMAC
59 #include <asm/vc_ioctl.h>
65 #include <linux/adb.h>
67 #include <asm/pci-bridge.h>
68 #include <video/macmodes.h>
71 #include <linux/pmu.h>
74 #include <linux/nvram.h>
80 #include <asm/uaccess.h>
82 #include <video/fbcon.h>
83 #include <video/fbcon-cfb8.h>
84 #include <video/fbcon-cfb16.h>
85 #include <video/fbcon-cfb24.h>
86 #include <video/fbcon-cfb32.h>
96 /* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */
98 #define REF_FREQ_2595 1432 /* 14.33 MHz (exact 14.31818) */
99 #define REF_DIV_2595 46 /* really 43 on ICS 2595 !!! */
101 #define MAX_FREQ_2595 15938 /* 159.38 MHz (really 170.486) */
102 #define MIN_FREQ_2595 8000 /* 80.00 MHz ( 85.565) */
103 /* mit Prescaler 2, 4, 8 */
104 #define ABS_MIN_FREQ_2595 1000 /* 10.00 MHz (really 10.697) */
105 #define N_ADJ_2595 257
107 #define STOP_BITS_2595 0x1800
120 /* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */
121 /* - must be large enough to catch all GUI-Regs */
122 /* - must be aligned to a PAGE boundary */
123 #define GUI_RESERVE (1 * PAGE_SIZE)
126 /* FIXME: remove the FAIL definition */
127 #define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
131 * Elements of the Hardware specific atyfb_par structure
146 u32 dp_pix_width
; /* acceleration */
147 u32 dp_chain_mask
; /* acceleration */
171 u32 dsp_config
; /* Mach64 GTB DSP */
172 u32 dsp_on_off
; /* Mach64 GTB DSP */
173 u8 mclk_post_div_real
;
174 u8 vclk_post_div_real
;
179 * The Hardware parameters for each card
187 struct pll_18818 ics2595
;
192 struct aty_cmap_regs
{
200 struct pci_mmap_map
{
204 unsigned long prot_flag
;
205 unsigned long prot_mask
;
208 #define DEFAULT_CURSOR_BLINK_RATE (20)
209 #define CURSOR_DRAW_DELAY (2)
224 struct timer_list
*timer
;
228 struct fb_info fb_info
;
229 struct fb_info_aty
*next
;
230 unsigned long ati_regbase_phys
;
231 unsigned long ati_regbase
;
232 unsigned long frame_buffer_phys
;
233 unsigned long frame_buffer
;
234 unsigned long clk_wr_offset
;
235 struct pci_mmap_map
*mmap_map
;
236 struct aty_cursor
*cursor
;
237 struct aty_cmap_regs
*aty_cmap_regs
;
238 struct { u8 red
, green
, blue
, pad
; } palette
[256];
239 struct atyfb_par default_par
;
240 struct atyfb_par current_par
;
246 #define Gx info->chip_type
248 #define Rev info->chip_rev
256 struct display_switch dispsw
;
258 #ifdef FBCON_HAS_CFB16
261 #ifdef FBCON_HAS_CFB24
264 #ifdef FBCON_HAS_CFB32
268 u8 blitter_may_be_busy
;
275 #ifdef CONFIG_PMAC_PBOOK
276 unsigned char *save_framebuffer
;
277 unsigned long save_pll
[64];
281 #ifdef CONFIG_PMAC_PBOOK
282 int aty_sleep_notify(struct pmu_sleep_notifier
*self
, int when
);
283 static struct pmu_sleep_notifier aty_sleep_notifier
= {
284 aty_sleep_notify
, SLEEP_LEVEL_VIDEO
,
286 static struct fb_info_aty
* first_display
= NULL
;
291 * Frame buffer device API
294 static int atyfb_open(struct fb_info
*info
, int user
);
295 static int atyfb_release(struct fb_info
*info
, int user
);
296 static int atyfb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
298 static int atyfb_get_var(struct fb_var_screeninfo
*var
, int con
,
300 static int atyfb_set_var(struct fb_var_screeninfo
*var
, int con
,
302 static int atyfb_pan_display(struct fb_var_screeninfo
*var
, int con
,
304 static int atyfb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
305 struct fb_info
*info
);
306 static int atyfb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
307 struct fb_info
*info
);
308 static int atyfb_ioctl(struct inode
*inode
, struct file
*file
, u_int cmd
,
309 u_long arg
, int con
, struct fb_info
*info
);
311 static int atyfb_mmap(struct fb_info
*info
, struct file
*file
,
312 struct vm_area_struct
*vma
);
314 static int atyfb_rasterimg(struct fb_info
*info
, int start
);
318 * Interface to the low level console driver
321 static int atyfbcon_switch(int con
, struct fb_info
*fb
);
322 static int atyfbcon_updatevar(int con
, struct fb_info
*fb
);
323 static void atyfbcon_blank(int blank
, struct fb_info
*fb
);
327 * Text console acceleration
330 static void fbcon_aty_bmove(struct display
*p
, int sy
, int sx
, int dy
, int dx
,
331 int height
, int width
);
332 static void fbcon_aty_clear(struct vc_data
*conp
, struct display
*p
, int sy
,
333 int sx
, int height
, int width
);
334 #ifdef FBCON_HAS_CFB8
335 static struct display_switch fbcon_aty8
;
336 static void fbcon_aty8_putc(struct vc_data
*conp
, struct display
*p
, int c
,
338 static void fbcon_aty8_putcs(struct vc_data
*conp
, struct display
*p
,
339 const unsigned short *s
, int count
, int yy
,
342 #ifdef FBCON_HAS_CFB16
343 static struct display_switch fbcon_aty16
;
344 static void fbcon_aty16_putc(struct vc_data
*conp
, struct display
*p
, int c
,
346 static void fbcon_aty16_putcs(struct vc_data
*conp
, struct display
*p
,
347 const unsigned short *s
, int count
, int yy
,
350 #ifdef FBCON_HAS_CFB24
351 static struct display_switch fbcon_aty24
;
352 static void fbcon_aty24_putc(struct vc_data
*conp
, struct display
*p
, int c
,
354 static void fbcon_aty24_putcs(struct vc_data
*conp
, struct display
*p
,
355 const unsigned short *s
, int count
, int yy
,
358 #ifdef FBCON_HAS_CFB32
359 static struct display_switch fbcon_aty32
;
360 static void fbcon_aty32_putc(struct vc_data
*conp
, struct display
*p
, int c
,
362 static void fbcon_aty32_putcs(struct vc_data
*conp
, struct display
*p
,
363 const unsigned short *s
, int count
, int yy
,
372 static int aty_init(struct fb_info_aty
*info
, const char *name
);
373 static struct aty_cursor
*aty_init_cursor(struct fb_info_aty
*fb
);
375 static int store_video_par(char *videopar
, unsigned char m64_num
);
376 static char *strtoke(char *s
, const char *ct
);
379 static void reset_engine(const struct fb_info_aty
*info
);
380 static void init_engine(const struct atyfb_par
*par
, struct fb_info_aty
*info
);
382 static void aty_st_514(int offset
, u8 val
, const struct fb_info_aty
*info
);
383 static void aty_st_pll(int offset
, u8 val
, const struct fb_info_aty
*info
);
384 static u8
aty_ld_pll(int offset
, const struct fb_info_aty
*info
);
385 static void aty_set_crtc(const struct fb_info_aty
*info
,
386 const struct crtc
*crtc
);
387 static int aty_var_to_crtc(const struct fb_info_aty
*info
,
388 const struct fb_var_screeninfo
*var
,
390 static void aty_set_dac_514(const struct fb_info_aty
*info
, u32 bpp
);
391 static int aty_crtc_to_var(const struct crtc
*crtc
,
392 struct fb_var_screeninfo
*var
);
393 static void aty_set_pll_gx(const struct fb_info_aty
*info
,
394 const struct pll_gx
*pll
);
396 static int aty_set_dac_ATI68860_B(const struct fb_info_aty
*info
, u32 bpp
,
398 static int aty_set_dac_ATT21C498(const struct fb_info_aty
*info
,
399 const struct pll_18818
*pll
, u32 bpp
);
400 void aty_dac_waste4(const struct fb_info_aty
*info
);
402 static int aty_var_to_pll_18818(u32 period_in_ps
, struct pll_18818
*pll
);
403 static u32
aty_pll_18818_to_var(const struct pll_18818
*pll
);
404 static void aty_set_pll18818(const struct fb_info_aty
*info
,
405 const struct pll_18818
*pll
);
407 static void aty_StrobeClock(const struct fb_info_aty
*info
);
409 static void aty_ICS2595_put1bit(u8 data
, const struct fb_info_aty
*info
);
411 static int aty_var_to_pll_408(u32 period_in_ps
, struct pll_18818
*pll
);
412 static u32
aty_pll_408_to_var(const struct pll_18818
*pll
);
413 static void aty_set_pll_408(const struct fb_info_aty
*info
,
414 const struct pll_18818
*pll
);
416 static int aty_var_to_pll_1703(u32 period_in_ps
, struct pll_18818
*pll
);
417 static u32
aty_pll_1703_to_var(const struct pll_18818
*pll
);
418 static void aty_set_pll_1703(const struct fb_info_aty
*info
,
419 const struct pll_18818
*pll
);
421 static int aty_var_to_pll_8398(u32 period_in_ps
, struct pll_18818
*pll
);
422 static u32
aty_pll_8398_to_var(const struct pll_18818
*pll
);
423 static void aty_set_pll_8398(const struct fb_info_aty
*info
,
424 const struct pll_18818
*pll
);
426 static int aty_var_to_pll_514(u32 vclk_per
, struct pll_gx
*pll
);
427 static u32
aty_pll_gx_to_var(const struct pll_gx
*pll
,
428 const struct fb_info_aty
*info
);
429 static void aty_set_pll_ct(const struct fb_info_aty
*info
,
430 const struct pll_ct
*pll
);
431 static int aty_valid_pll_ct(const struct fb_info_aty
*info
, u32 vclk_per
,
433 static int aty_dsp_gt(const struct fb_info_aty
*info
, u8 bpp
,
435 static void aty_calc_pll_ct(const struct fb_info_aty
*info
,
437 static int aty_var_to_pll_ct(const struct fb_info_aty
*info
, u32 vclk_per
,
438 u8 bpp
, struct pll_ct
*pll
);
439 static u32
aty_pll_ct_to_var(const struct pll_ct
*pll
,
440 const struct fb_info_aty
*info
);
441 static void atyfb_set_par(const struct atyfb_par
*par
,
442 struct fb_info_aty
*info
);
443 static int atyfb_decode_var(const struct fb_var_screeninfo
*var
,
444 struct atyfb_par
*par
,
445 const struct fb_info_aty
*info
);
446 static int atyfb_encode_var(struct fb_var_screeninfo
*var
,
447 const struct atyfb_par
*par
,
448 const struct fb_info_aty
*info
);
449 static void set_off_pitch(struct atyfb_par
*par
,
450 const struct fb_info_aty
*info
);
451 static int encode_fix(struct fb_fix_screeninfo
*fix
,
452 const struct atyfb_par
*par
,
453 const struct fb_info_aty
*info
);
454 static void atyfb_set_disp(struct display
*disp
, struct fb_info_aty
*info
,
456 static int atyfb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
457 u_int
*transp
, struct fb_info
*fb
);
458 static int atyfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
459 u_int transp
, struct fb_info
*fb
);
460 static void do_install_cmap(int con
, struct fb_info
*info
);
462 static int read_aty_sense(const struct fb_info_aty
*info
);
467 * Interface used by the world
470 int atyfb_init(void);
472 int atyfb_setup(char*);
475 static int currcon
= 0;
477 static struct fb_ops atyfb_ops
= {
480 fb_release
: atyfb_release
,
481 fb_get_fix
: atyfb_get_fix
,
482 fb_get_var
: atyfb_get_var
,
483 fb_set_var
: atyfb_set_var
,
484 fb_get_cmap
: atyfb_get_cmap
,
485 fb_set_cmap
: atyfb_set_cmap
,
486 fb_pan_display
: atyfb_pan_display
,
487 fb_ioctl
: atyfb_ioctl
,
491 fb_rasterimg
: atyfb_rasterimg
,
494 static char atyfb_name
[16] = "ATY Mach64";
495 static char fontname
[40] __initdata
= { 0 };
496 static char curblink __initdata
= 1;
497 static char noaccel __initdata
= 0;
498 static u32 default_vram __initdata
= 0;
499 static int default_pll __initdata
= 0;
500 static int default_mclk __initdata
= 0;
503 static const char *mode_option __initdata
= NULL
;
507 #ifdef CONFIG_NVRAM_NOT_DEFINED
508 static int default_vmode __initdata
= VMODE_NVRAM
;
509 static int default_cmode __initdata
= CMODE_NVRAM
;
511 static int default_vmode __initdata
= VMODE_CHOOSE
;
512 static int default_cmode __initdata
= CMODE_CHOOSE
;
517 static unsigned int mach64_count __initdata
= 0;
518 static unsigned long phys_vmembase
[FB_MAX
] __initdata
= { 0, };
519 static unsigned long phys_size
[FB_MAX
] __initdata
= { 0, };
520 static unsigned long phys_guiregbase
[FB_MAX
] __initdata
= { 0, };
524 static struct aty_features
{
528 } aty_features
[] __initdata
= {
529 /* mach64GX family */
530 { 0x4758, 0x00d7, "mach64GX (ATI888GX00)" },
531 { 0x4358, 0x0057, "mach64CX (ATI888CX00)" },
533 /* mach64CT family */
534 { 0x4354, 0x4354, "mach64CT (ATI264CT)" },
535 { 0x4554, 0x4554, "mach64ET (ATI264ET)" },
537 /* mach64CT family / mach64VT class */
538 { 0x5654, 0x5654, "mach64VT (ATI264VT)" },
539 { 0x5655, 0x5655, "mach64VTB (ATI264VTB)" },
540 { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" },
542 /* mach64CT family / mach64GT (3D RAGE) class */
543 { 0x4c42, 0x4c42, "3D RAGE LT PRO (AGP)" },
544 { 0x4c44, 0x4c44, "3D RAGE LT PRO" },
545 { 0x4c47, 0x4c47, "3D RAGE LT-G" },
546 { 0x4c49, 0x4c49, "3D RAGE LT PRO" },
547 { 0x4c50, 0x4c50, "3D RAGE LT PRO" },
548 { 0x4c54, 0x4c54, "3D RAGE LT" },
549 { 0x4754, 0x4754, "3D RAGE (GT)" },
550 { 0x4755, 0x4755, "3D RAGE II+ (GTB)" },
551 { 0x4756, 0x4756, "3D RAGE IIC (PCI)" },
552 { 0x4757, 0x4757, "3D RAGE IIC (AGP)" },
553 { 0x475a, 0x475a, "3D RAGE IIC (AGP)" },
554 { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)" },
555 { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)" },
556 { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" },
557 { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)" },
558 { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" },
561 static const char *aty_gx_ram
[8] __initdata
= {
562 "DRAM", "VRAM", "VRAM", "DRAM", "DRAM", "VRAM", "VRAM", "RESV"
565 static const char *aty_ct_ram
[8] __initdata
= {
566 "OFF", "DRAM", "EDO", "EDO", "SDRAM", "SGRAM", "WRAM", "RESV"
570 static inline u32
aty_ld_le32(unsigned int regindex
,
571 const struct fb_info_aty
*info
)
573 #if defined(__powerpc__)
577 temp
= info
->ati_regbase
;
578 asm volatile("lwbrx %0,%1,%2;eieio" : "=r"(val
) : "b" (regindex
), "r" (temp
));
580 #elif defined(__mc68000__)
581 return le32_to_cpu(*((volatile u32
*)(info
->ati_regbase
+regindex
)));
583 return readl (info
->ati_regbase
+ regindex
);
587 static inline void aty_st_le32(unsigned int regindex
, u32 val
,
588 const struct fb_info_aty
*info
)
590 #if defined(__powerpc__)
593 temp
= info
->ati_regbase
;
594 asm volatile("stwbrx %0,%1,%2;eieio" : : "r" (val
), "b" (regindex
), "r" (temp
) :
596 #elif defined(__mc68000__)
597 *((volatile u32
*)(info
->ati_regbase
+regindex
)) = cpu_to_le32(val
);
599 writel (val
, info
->ati_regbase
+ regindex
);
603 static inline u8
aty_ld_8(unsigned int regindex
,
604 const struct fb_info_aty
*info
)
606 return readb (info
->ati_regbase
+ regindex
);
609 static inline void aty_st_8(unsigned int regindex
, u8 val
,
610 const struct fb_info_aty
*info
)
612 writeb (val
, info
->ati_regbase
+ regindex
);
615 #if defined(CONFIG_PPC) || defined(CONFIG_PMAC_PBOOK)
616 static void aty_st_lcd(int index
, u32 val
, const struct fb_info_aty
*info
)
620 /* write addr byte */
621 temp
= aty_ld_le32(LCD_INDEX
, info
);
622 aty_st_le32(LCD_INDEX
, (temp
& ~LCD_INDEX_MASK
) | index
, info
);
623 /* write the register value */
624 aty_st_le32(LCD_DATA
, val
, info
);
627 static u32
aty_ld_lcd(int index
, const struct fb_info_aty
*info
)
631 /* write addr byte */
632 temp
= aty_ld_le32(LCD_INDEX
, info
);
633 aty_st_le32(LCD_INDEX
, (temp
& ~LCD_INDEX_MASK
) | index
, info
);
634 /* read the register value */
635 return aty_ld_le32(LCD_DATA
, info
);
640 * Generic Mach64 routines
644 * All writes to draw engine registers are automatically routed through a
645 * 32-bit-wide, 16-entry-deep command FIFO ...
646 * Register writes to registers with DWORD offsets less than 40h are not
648 * (from Chapter 5 of the Mach64 Programmer's Guide)
651 static inline void wait_for_fifo(u16 entries
, const struct fb_info_aty
*info
)
653 while ((aty_ld_le32(FIFO_STAT
, info
) & 0xffff) >
654 ((u32
)(0x8000 >> entries
)));
657 static inline void wait_for_idle(struct fb_info_aty
*info
)
659 wait_for_fifo(16, info
);
660 while ((aty_ld_le32(GUI_STAT
, info
) & 1)!= 0);
661 info
->blitter_may_be_busy
= 0;
664 static void reset_engine(const struct fb_info_aty
*info
)
667 aty_st_le32(GEN_TEST_CNTL
,
668 aty_ld_le32(GEN_TEST_CNTL
, info
) & ~GUI_ENGINE_ENABLE
, info
);
670 aty_st_le32(GEN_TEST_CNTL
,
671 aty_ld_le32(GEN_TEST_CNTL
, info
) | GUI_ENGINE_ENABLE
, info
);
672 /* ensure engine is not locked up by clearing any FIFO or */
674 aty_st_le32(BUS_CNTL
, aty_ld_le32(BUS_CNTL
, info
) | BUS_HOST_ERR_ACK
|
675 BUS_FIFO_ERR_ACK
, info
);
678 static void init_engine(const struct atyfb_par
*par
, struct fb_info_aty
*info
)
682 /* determine modal information from global mode structure */
683 pitch_value
= par
->crtc
.vxres
;
685 if (par
->crtc
.bpp
== 24) {
686 /* In 24 bpp, the engine is in 8 bpp - this requires that all */
687 /* horizontal coordinates and widths must be adjusted */
688 pitch_value
= pitch_value
* 3;
691 /* Reset engine, enable, and clear any engine errors */
693 /* Ensure that vga page pointers are set to zero - the upper */
694 /* page pointers are set to 1 to handle overflows in the */
696 aty_st_le32(MEM_VGA_WP_SEL
, 0x00010000, info
);
697 aty_st_le32(MEM_VGA_RP_SEL
, 0x00010000, info
);
699 /* ---- Setup standard engine context ---- */
701 /* All GUI registers here are FIFOed - therefore, wait for */
702 /* the appropriate number of empty FIFO entries */
703 wait_for_fifo(14, info
);
705 /* enable all registers to be loaded for context loads */
706 aty_st_le32(CONTEXT_MASK
, 0xFFFFFFFF, info
);
708 /* set destination pitch to modal pitch, set offset to zero */
709 aty_st_le32(DST_OFF_PITCH
, (pitch_value
/ 8) << 22, info
);
711 /* zero these registers (set them to a known state) */
712 aty_st_le32(DST_Y_X
, 0, info
);
713 aty_st_le32(DST_HEIGHT
, 0, info
);
714 aty_st_le32(DST_BRES_ERR
, 0, info
);
715 aty_st_le32(DST_BRES_INC
, 0, info
);
716 aty_st_le32(DST_BRES_DEC
, 0, info
);
718 /* set destination drawing attributes */
719 aty_st_le32(DST_CNTL
, DST_LAST_PEL
| DST_Y_TOP_TO_BOTTOM
|
720 DST_X_LEFT_TO_RIGHT
, info
);
722 /* set source pitch to modal pitch, set offset to zero */
723 aty_st_le32(SRC_OFF_PITCH
, (pitch_value
/ 8) << 22, info
);
725 /* set these registers to a known state */
726 aty_st_le32(SRC_Y_X
, 0, info
);
727 aty_st_le32(SRC_HEIGHT1_WIDTH1
, 1, info
);
728 aty_st_le32(SRC_Y_X_START
, 0, info
);
729 aty_st_le32(SRC_HEIGHT2_WIDTH2
, 1, info
);
731 /* set source pixel retrieving attributes */
732 aty_st_le32(SRC_CNTL
, SRC_LINE_X_LEFT_TO_RIGHT
, info
);
734 /* set host attributes */
735 wait_for_fifo(13, info
);
736 aty_st_le32(HOST_CNTL
, 0, info
);
738 /* set pattern attributes */
739 aty_st_le32(PAT_REG0
, 0, info
);
740 aty_st_le32(PAT_REG1
, 0, info
);
741 aty_st_le32(PAT_CNTL
, 0, info
);
743 /* set scissors to modal size */
744 aty_st_le32(SC_LEFT
, 0, info
);
745 aty_st_le32(SC_TOP
, 0, info
);
746 aty_st_le32(SC_BOTTOM
, par
->crtc
.vyres
-1, info
);
747 aty_st_le32(SC_RIGHT
, pitch_value
-1, info
);
749 /* set background color to minimum value (usually BLACK) */
750 aty_st_le32(DP_BKGD_CLR
, 0, info
);
752 /* set foreground color to maximum value (usually WHITE) */
753 aty_st_le32(DP_FRGD_CLR
, 0xFFFFFFFF, info
);
755 /* set write mask to effect all pixel bits */
756 aty_st_le32(DP_WRITE_MASK
, 0xFFFFFFFF, info
);
758 /* set foreground mix to overpaint and background mix to */
760 aty_st_le32(DP_MIX
, FRGD_MIX_S
| BKGD_MIX_D
, info
);
762 /* set primary source pixel channel to foreground color */
764 aty_st_le32(DP_SRC
, FRGD_SRC_FRGD_CLR
, info
);
766 /* set compare functionality to false (no-effect on */
768 wait_for_fifo(3, info
);
769 aty_st_le32(CLR_CMP_CLR
, 0, info
);
770 aty_st_le32(CLR_CMP_MASK
, 0xFFFFFFFF, info
);
771 aty_st_le32(CLR_CMP_CNTL
, 0, info
);
773 /* set pixel depth */
774 wait_for_fifo(2, info
);
775 aty_st_le32(DP_PIX_WIDTH
, par
->crtc
.dp_pix_width
, info
);
776 aty_st_le32(DP_CHAIN_MASK
, par
->crtc
.dp_chain_mask
, info
);
778 wait_for_fifo(5, info
);
779 aty_st_le32(SCALE_3D_CNTL
, 0, info
);
780 aty_st_le32(Z_CNTL
, 0, info
);
781 aty_st_le32(CRTC_INT_CNTL
, aty_ld_le32(CRTC_INT_CNTL
, info
) & ~0x20, info
);
782 aty_st_le32(GUI_TRAJ_CNTL
, 0x100023, info
);
784 /* insure engine is idle before leaving */
788 static void aty_st_514(int offset
, u8 val
, const struct fb_info_aty
*info
)
790 aty_st_8(DAC_CNTL
, 1, info
);
791 /* right addr byte */
792 aty_st_8(DAC_W_INDEX
, offset
& 0xff, info
);
794 aty_st_8(DAC_DATA
, (offset
>> 8) & 0xff, info
);
795 aty_st_8(DAC_MASK
, val
, info
);
796 aty_st_8(DAC_CNTL
, 0, info
);
799 static void aty_st_pll(int offset
, u8 val
, const struct fb_info_aty
*info
)
801 /* write addr byte */
802 aty_st_8(CLOCK_CNTL
+ 1, (offset
<< 2) | PLL_WR_EN
, info
);
803 /* write the register value */
804 aty_st_8(CLOCK_CNTL
+ 2, val
, info
);
805 aty_st_8(CLOCK_CNTL
+ 1, (offset
<< 2) & ~PLL_WR_EN
, info
);
808 static u8
aty_ld_pll(int offset
, const struct fb_info_aty
*info
)
812 /* write addr byte */
813 aty_st_8(CLOCK_CNTL
+ 1, (offset
<< 2), info
);
814 /* read the register value */
815 res
= aty_ld_8(CLOCK_CNTL
+ 2, info
);
819 #if defined(CONFIG_PPC)
822 * Apple monitor sense
825 static int read_aty_sense(const struct fb_info_aty
*info
)
829 aty_st_le32(GP_IO
, 0x31003100, info
); /* drive outputs high */
831 aty_st_le32(GP_IO
, 0, info
); /* turn off outputs */
833 i
= aty_ld_le32(GP_IO
, info
); /* get primary sense value */
834 sense
= ((i
& 0x3000) >> 3) | (i
& 0x100);
836 /* drive each sense line low in turn and collect the other 2 */
837 aty_st_le32(GP_IO
, 0x20000000, info
); /* drive A low */
839 i
= aty_ld_le32(GP_IO
, info
);
840 sense
|= ((i
& 0x1000) >> 7) | ((i
& 0x100) >> 4);
841 aty_st_le32(GP_IO
, 0x20002000, info
); /* drive A high again */
844 aty_st_le32(GP_IO
, 0x10000000, info
); /* drive B low */
846 i
= aty_ld_le32(GP_IO
, info
);
847 sense
|= ((i
& 0x2000) >> 10) | ((i
& 0x100) >> 6);
848 aty_st_le32(GP_IO
, 0x10001000, info
); /* drive B high again */
851 aty_st_le32(GP_IO
, 0x01000000, info
); /* drive C low */
853 sense
|= (aty_ld_le32(GP_IO
, info
) & 0x3000) >> 12;
854 aty_st_le32(GP_IO
, 0, info
); /* turn off outputs */
859 #endif /* defined(CONFIG_PPC) */
861 /* ------------------------------------------------------------------------- */
864 * Hardware Cursor support.
867 static u8 cursor_pixel_map
[2] = { 0, 15 };
868 static u8 cursor_color_map
[2] = { 0, 0xff };
870 static u8 cursor_bits_lookup
[16] =
872 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
873 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
876 static u8 cursor_mask_lookup
[16] =
878 0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02,
879 0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
883 aty_set_cursor_color(struct fb_info_aty
*fb
, u8
*pixel
,
884 u8
*red
, u8
*green
, u8
*blue
)
886 struct aty_cursor
*c
= fb
->cursor
;
893 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
894 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
898 for (i
= 0; i
< 2; i
++) {
899 c
->color
[i
] = (u32
)red
[i
] << 24;
900 c
->color
[i
] |= (u32
)green
[i
] << 16;
901 c
->color
[i
] |= (u32
)blue
[i
] << 8;
902 c
->color
[i
] |= (u32
)pixel
[i
];
905 wait_for_fifo(2, fb
);
906 aty_st_le32(CUR_CLR0
, c
->color
[0], fb
);
907 aty_st_le32(CUR_CLR1
, c
->color
[1], fb
);
911 aty_set_cursor_shape(struct fb_info_aty
*fb
)
913 struct aty_cursor
*c
= fb
->cursor
;
921 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
922 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
927 for (y
= 0; y
< c
->size
.y
; y
++) {
928 for (x
= 0; x
< c
->size
.x
>> 2; x
++) {
931 fb_writeb (cursor_mask_lookup
[m
>> 4] |
932 cursor_bits_lookup
[(b
& m
) >> 4],
934 fb_writeb (cursor_mask_lookup
[m
& 0x0f] |
935 cursor_bits_lookup
[(b
& m
) & 0x0f],
938 for ( ; x
< 8; x
++) {
939 fb_writeb (0xaa, ram
++);
940 fb_writeb (0xaa, ram
++);
943 fb_memset (ram
, 0xaa, (64 - c
->size
.y
) * 16);
947 aty_set_cursor(struct fb_info_aty
*fb
, int on
)
949 struct atyfb_par
*par
= &fb
->current_par
;
950 struct aty_cursor
*c
= fb
->cursor
;
958 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
959 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
964 x
= c
->pos
.x
- c
->hot
.x
- par
->crtc
.xoffset
;
972 y
= c
->pos
.y
- c
->hot
.y
- par
->crtc
.yoffset
;
980 wait_for_fifo(4, fb
);
981 aty_st_le32(CUR_OFFSET
, (c
->offset
>> 3) + (yoff
<< 1), fb
);
982 aty_st_le32(CUR_HORZ_VERT_OFF
,
983 ((u32
)(64 - c
->size
.y
+ yoff
) << 16) | xoff
, fb
);
984 aty_st_le32(CUR_HORZ_VERT_POSN
, ((u32
)y
<< 16) | x
, fb
);
985 aty_st_le32(GEN_TEST_CNTL
, aty_ld_le32(GEN_TEST_CNTL
, fb
)
986 | HWCURSOR_ENABLE
, fb
);
988 wait_for_fifo(1, fb
);
989 aty_st_le32(GEN_TEST_CNTL
,
990 aty_ld_le32(GEN_TEST_CNTL
, fb
) & ~HWCURSOR_ENABLE
,
993 if (fb
->blitter_may_be_busy
)
998 aty_cursor_timer_handler(unsigned long dev_addr
)
1000 struct fb_info_aty
*fb
= (struct fb_info_aty
*)dev_addr
;
1005 if (!fb
->cursor
->enable
)
1008 if (fb
->cursor
->vbl_cnt
&& --fb
->cursor
->vbl_cnt
== 0) {
1009 fb
->cursor
->on
^= 1;
1010 aty_set_cursor(fb
, fb
->cursor
->on
);
1011 fb
->cursor
->vbl_cnt
= fb
->cursor
->blink_rate
;
1015 fb
->cursor
->timer
->expires
= jiffies
+ (HZ
/ 50);
1016 add_timer(fb
->cursor
->timer
);
1020 atyfb_cursor(struct display
*p
, int mode
, int x
, int y
)
1022 struct fb_info_aty
*fb
= (struct fb_info_aty
*)p
->fb_info
;
1023 struct aty_cursor
*c
= fb
->cursor
;
1029 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
1030 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
1036 if (c
->pos
.x
== x
&& c
->pos
.y
== y
&& (mode
== CM_ERASE
) == !c
->enable
)
1041 aty_set_cursor(fb
, 0);
1053 aty_set_cursor(fb
, 1);
1055 c
->vbl_cnt
= CURSOR_DRAW_DELAY
;
1061 static struct fb_info_aty
*fb_list
= NULL
;
1063 static struct aty_cursor
* __init
1064 aty_init_cursor(struct fb_info_aty
*fb
)
1066 struct aty_cursor
*cursor
;
1069 cursor
= kmalloc(sizeof(struct aty_cursor
), GFP_ATOMIC
);
1072 memset(cursor
, 0, sizeof(*cursor
));
1074 cursor
->timer
= kmalloc(sizeof(*cursor
->timer
), GFP_KERNEL
);
1075 if (!cursor
->timer
) {
1079 memset(cursor
->timer
, 0, sizeof(*cursor
->timer
));
1081 cursor
->blink_rate
= DEFAULT_CURSOR_BLINK_RATE
;
1082 fb
->total_vram
-= PAGE_SIZE
;
1083 cursor
->offset
= fb
->total_vram
;
1086 addr
= fb
->frame_buffer
- 0x800000 + cursor
->offset
;
1087 cursor
->ram
= (u8
*)addr
;
1090 addr
= fb
->frame_buffer_phys
- 0x800000 + cursor
->offset
;
1091 cursor
->ram
= (u8
*)ioremap(addr
, 1024);
1093 addr
= fb
->frame_buffer
+ cursor
->offset
;
1094 cursor
->ram
= (u8
*)addr
;
1098 if (! cursor
->ram
) {
1104 init_timer(cursor
->timer
);
1105 cursor
->timer
->expires
= jiffies
+ (HZ
/ 50);
1106 cursor
->timer
->data
= (unsigned long)fb
;
1107 cursor
->timer
->function
= aty_cursor_timer_handler
;
1108 add_timer(cursor
->timer
);
1115 atyfb_set_font(struct display
*d
, int width
, int height
)
1117 struct fb_info_aty
*fb
= (struct fb_info_aty
*)d
->fb_info
;
1118 struct aty_cursor
*c
= fb
->cursor
;
1122 if (!width
|| !height
) {
1132 memset(c
->bits
, 0xff, sizeof(c
->bits
));
1133 memset(c
->mask
, 0, sizeof(c
->mask
));
1135 for (i
= 0, j
= width
; j
>= 0; j
-= 8, i
++) {
1136 c
->mask
[i
][height
-2] = (j
>= 8) ? 0xff : (0xff << (8 - j
));
1137 c
->mask
[i
][height
-1] = (j
>= 8) ? 0xff : (0xff << (8 - j
));
1140 aty_set_cursor_color(fb
, cursor_pixel_map
, cursor_color_map
,
1141 cursor_color_map
, cursor_color_map
);
1142 aty_set_cursor_shape(fb
);
1150 /* ------------------------------------------------------------------------- */
1156 static void aty_set_crtc(const struct fb_info_aty
*info
,
1157 const struct crtc
*crtc
)
1159 aty_st_le32(CRTC_H_TOTAL_DISP
, crtc
->h_tot_disp
, info
);
1160 aty_st_le32(CRTC_H_SYNC_STRT_WID
, crtc
->h_sync_strt_wid
, info
);
1161 aty_st_le32(CRTC_V_TOTAL_DISP
, crtc
->v_tot_disp
, info
);
1162 aty_st_le32(CRTC_V_SYNC_STRT_WID
, crtc
->v_sync_strt_wid
, info
);
1163 aty_st_le32(CRTC_VLINE_CRNT_VLINE
, 0, info
);
1164 aty_st_le32(CRTC_OFF_PITCH
, crtc
->off_pitch
, info
);
1165 aty_st_le32(CRTC_GEN_CNTL
, crtc
->gen_cntl
, info
);
1168 static int aty_var_to_crtc(const struct fb_info_aty
*info
,
1169 const struct fb_var_screeninfo
*var
,
1172 u32 xres
, yres
, vxres
, vyres
, xoffset
, yoffset
, bpp
;
1173 u32 left
, right
, upper
, lower
, hslen
, vslen
, sync
, vmode
;
1174 u32 h_total
, h_disp
, h_sync_strt
, h_sync_dly
, h_sync_wid
, h_sync_pol
;
1175 u32 v_total
, v_disp
, v_sync_strt
, v_sync_wid
, v_sync_pol
, c_sync
;
1176 u32 pix_width
, dp_pix_width
, dp_chain_mask
;
1181 vxres
= var
->xres_virtual
;
1182 vyres
= var
->yres_virtual
;
1183 xoffset
= var
->xoffset
;
1184 yoffset
= var
->yoffset
;
1185 bpp
= var
->bits_per_pixel
;
1186 left
= var
->left_margin
;
1187 right
= var
->right_margin
;
1188 upper
= var
->upper_margin
;
1189 lower
= var
->lower_margin
;
1190 hslen
= var
->hsync_len
;
1191 vslen
= var
->vsync_len
;
1195 /* convert (and round up) and validate */
1196 xres
= (xres
+7) & ~7;
1197 xoffset
= (xoffset
+7) & ~7;
1198 vxres
= (vxres
+7) & ~7;
1199 if (vxres
< xres
+xoffset
)
1200 vxres
= xres
+xoffset
;
1203 FAIL("h_disp too large");
1204 h_sync_strt
= h_disp
+(right
/8);
1205 if (h_sync_strt
> 0x1ff)
1206 FAIL("h_sync_start too large");
1207 h_sync_dly
= right
& 7;
1208 h_sync_wid
= (hslen
+7)/8;
1209 if (h_sync_wid
> 0x1f)
1210 FAIL("h_sync_wid too large");
1211 h_total
= h_sync_strt
+h_sync_wid
+(h_sync_dly
+left
+7)/8;
1212 if (h_total
> 0x1ff)
1213 FAIL("h_total too large");
1214 h_sync_pol
= sync
& FB_SYNC_HOR_HIGH_ACT
? 0 : 1;
1216 if (vyres
< yres
+yoffset
)
1217 vyres
= yres
+yoffset
;
1220 FAIL("v_disp too large");
1221 v_sync_strt
= v_disp
+lower
;
1222 if (v_sync_strt
> 0x7ff)
1223 FAIL("v_sync_strt too large");
1225 if (v_sync_wid
> 0x1f)
1226 FAIL("v_sync_wid too large");
1227 v_total
= v_sync_strt
+v_sync_wid
+upper
;
1228 if (v_total
> 0x7ff)
1229 FAIL("v_total too large");
1230 v_sync_pol
= sync
& FB_SYNC_VERT_HIGH_ACT
? 0 : 1;
1232 c_sync
= sync
& FB_SYNC_COMP_HIGH_ACT
? CRTC_CSYNC_EN
: 0;
1236 pix_width
= CRTC_PIX_WIDTH_8BPP
;
1237 dp_pix_width
= HOST_8BPP
| SRC_8BPP
| DST_8BPP
| BYTE_ORDER_LSB_TO_MSB
;
1238 dp_chain_mask
= 0x8080;
1239 } else if (bpp
<= 16) {
1241 pix_width
= CRTC_PIX_WIDTH_15BPP
;
1242 dp_pix_width
= HOST_15BPP
| SRC_15BPP
| DST_15BPP
|
1243 BYTE_ORDER_LSB_TO_MSB
;
1244 dp_chain_mask
= 0x4210;
1245 } else if ((bpp
<= 24) && (Gx
!= GX_CHIP_ID
) && (Gx
!= CX_CHIP_ID
)) {
1247 pix_width
= CRTC_PIX_WIDTH_24BPP
;
1248 dp_pix_width
= HOST_8BPP
| SRC_8BPP
| DST_8BPP
| BYTE_ORDER_LSB_TO_MSB
;
1249 dp_chain_mask
= 0x8080;
1250 } else if (bpp
<= 32) {
1252 pix_width
= CRTC_PIX_WIDTH_32BPP
;
1253 dp_pix_width
= HOST_32BPP
| SRC_32BPP
| DST_32BPP
|
1254 BYTE_ORDER_LSB_TO_MSB
;
1255 dp_chain_mask
= 0x8080;
1257 FAIL("invalid bpp");
1259 if (vxres
*vyres
*bpp
/8 > info
->total_vram
)
1260 FAIL("not enough video RAM");
1262 if ((vmode
& FB_VMODE_MASK
) != FB_VMODE_NONINTERLACED
)
1263 FAIL("invalid vmode");
1266 crtc
->vxres
= vxres
;
1267 crtc
->vyres
= vyres
;
1268 crtc
->xoffset
= xoffset
;
1269 crtc
->yoffset
= yoffset
;
1271 crtc
->h_tot_disp
= h_total
| (h_disp
<<16);
1272 crtc
->h_sync_strt_wid
= (h_sync_strt
& 0xff) | (h_sync_dly
<<8) |
1273 ((h_sync_strt
& 0x100)<<4) | (h_sync_wid
<<16) |
1275 crtc
->v_tot_disp
= v_total
| (v_disp
<<16);
1276 crtc
->v_sync_strt_wid
= v_sync_strt
| (v_sync_wid
<<16) | (v_sync_pol
<<21);
1277 crtc
->off_pitch
= ((yoffset
*vxres
+xoffset
)*bpp
/64) | (vxres
<<19);
1278 crtc
->gen_cntl
= pix_width
| c_sync
| CRTC_EXT_DISP_EN
| CRTC_ENABLE
;
1279 if ((Gx
== CT_CHIP_ID
) || (Gx
== ET_CHIP_ID
) ||
1280 ((Gx
== VT_CHIP_ID
|| Gx
== GT_CHIP_ID
) && !(Rev
& 0x07))) {
1282 /* FIXME: magic FIFO values */
1283 crtc
->gen_cntl
|= aty_ld_le32(CRTC_GEN_CNTL
, info
) & 0x000e0000;
1285 crtc
->dp_pix_width
= dp_pix_width
;
1286 crtc
->dp_chain_mask
= dp_chain_mask
;
1292 static int aty_set_dac_ATI68860_B(const struct fb_info_aty
*info
, u32 bpp
,
1295 u32 gModeReg
, devSetupRegA
, temp
, mask
;
1303 devSetupRegA
= 0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */;
1307 devSetupRegA
= 0x60;
1311 devSetupRegA
= 0x60;
1315 devSetupRegA
= 0x60;
1319 devSetupRegA
= 0x60;
1325 devSetupRegA
= 0x61;
1328 temp
= aty_ld_8(DAC_CNTL
, info
);
1329 aty_st_8(DAC_CNTL
, (temp
& ~DAC_EXT_SEL_RS2
) | DAC_EXT_SEL_RS3
, info
);
1331 aty_st_8(DAC_REGS
+ 2, 0x1D, info
);
1332 aty_st_8(DAC_REGS
+ 3, gModeReg
, info
);
1333 aty_st_8(DAC_REGS
, 0x02, info
);
1335 temp
= aty_ld_8(DAC_CNTL
, info
);
1336 aty_st_8(DAC_CNTL
, temp
| DAC_EXT_SEL_RS2
| DAC_EXT_SEL_RS3
, info
);
1338 if (info
->total_vram
< MEM_SIZE_1M
)
1340 else if (info
->total_vram
== MEM_SIZE_1M
)
1345 /* The following assumes that the BIOS has correctly set R7 of the
1346 * Device Setup Register A at boot time.
1348 #define A860_DELAY_L 0x80
1350 temp
= aty_ld_8(DAC_REGS
, info
);
1351 aty_st_8(DAC_REGS
, (devSetupRegA
| mask
) | (temp
& A860_DELAY_L
), info
);
1352 temp
= aty_ld_8(DAC_CNTL
, info
);
1353 aty_st_8(DAC_CNTL
, (temp
& ~(DAC_EXT_SEL_RS2
| DAC_EXT_SEL_RS3
)), info
);
1358 static int aty_set_dac_ATT21C498(const struct fb_info_aty
*info
,
1359 const struct pll_18818
*pll
, u32 bpp
)
1365 dotClock
= 100000000 / pll
->period_in_ps
;
1369 if (dotClock
> 8000) {
1389 if (1 /* info->mach64DAC8Bit */)
1392 aty_dac_waste4(info
);
1393 aty_st_8(DAC_REGS
+ 2, DACMask
, info
);
1398 void aty_dac_waste4(const struct fb_info_aty
*info
)
1400 (void)aty_ld_8(DAC_REGS
, info
);
1402 (void)aty_ld_8(DAC_REGS
+ 2, info
);
1403 (void)aty_ld_8(DAC_REGS
+ 2, info
);
1404 (void)aty_ld_8(DAC_REGS
+ 2, info
);
1405 (void)aty_ld_8(DAC_REGS
+ 2, info
);
1409 static void aty_set_dac_514(const struct fb_info_aty
*info
, u32 bpp
)
1415 u8 pixel_cntl_index
;
1418 { 0, 0x41, 0x03, 0x71, 0x45 }, /* 8 bpp */
1419 { 0, 0x45, 0x04, 0x0c, 0x01 }, /* 555 */
1420 { 0, 0x45, 0x06, 0x0e, 0x00 }, /* XRGB */
1436 aty_st_514(0x90, 0x00, info
); /* VRAM Mask Low */
1437 aty_st_514(0x04, tab
[i
].pixel_dly
, info
); /* Horizontal Sync Control */
1438 aty_st_514(0x05, 0x00, info
); /* Power Management */
1439 aty_st_514(0x02, 0x01, info
); /* Misc Clock Control */
1440 aty_st_514(0x71, tab
[i
].misc2_cntl
, info
); /* Misc Control 2 */
1441 aty_st_514(0x0a, tab
[i
].pixel_rep
, info
); /* Pixel Format */
1442 aty_st_514(tab
[i
].pixel_cntl_index
, tab
[i
].pixel_cntl_v1
, info
);
1443 /* Misc Control 2 / 16 BPP Control / 32 BPP Control */
1446 static int aty_crtc_to_var(const struct crtc
*crtc
,
1447 struct fb_var_screeninfo
*var
)
1449 u32 xres
, yres
, bpp
, left
, right
, upper
, lower
, hslen
, vslen
, sync
;
1450 u32 h_total
, h_disp
, h_sync_strt
, h_sync_dly
, h_sync_wid
, h_sync_pol
;
1451 u32 v_total
, v_disp
, v_sync_strt
, v_sync_wid
, v_sync_pol
, c_sync
;
1455 h_total
= crtc
->h_tot_disp
& 0x1ff;
1456 h_disp
= (crtc
->h_tot_disp
>>16) & 0xff;
1457 h_sync_strt
= (crtc
->h_sync_strt_wid
& 0xff) |
1458 ((crtc
->h_sync_strt_wid
>>4) & 0x100);
1459 h_sync_dly
= (crtc
->h_sync_strt_wid
>>8) & 0x7;
1460 h_sync_wid
= (crtc
->h_sync_strt_wid
>>16) & 0x1f;
1461 h_sync_pol
= (crtc
->h_sync_strt_wid
>>21) & 0x1;
1462 v_total
= crtc
->v_tot_disp
& 0x7ff;
1463 v_disp
= (crtc
->v_tot_disp
>>16) & 0x7ff;
1464 v_sync_strt
= crtc
->v_sync_strt_wid
& 0x7ff;
1465 v_sync_wid
= (crtc
->v_sync_strt_wid
>>16) & 0x1f;
1466 v_sync_pol
= (crtc
->v_sync_strt_wid
>>21) & 0x1;
1467 c_sync
= crtc
->gen_cntl
& CRTC_CSYNC_EN
? 1 : 0;
1468 pix_width
= crtc
->gen_cntl
& CRTC_PIX_WIDTH_MASK
;
1471 xres
= (h_disp
+1)*8;
1473 left
= (h_total
-h_sync_strt
-h_sync_wid
)*8-h_sync_dly
;
1474 right
= (h_sync_strt
-h_disp
)*8+h_sync_dly
;
1475 hslen
= h_sync_wid
*8;
1476 upper
= v_total
-v_sync_strt
-v_sync_wid
;
1477 lower
= v_sync_strt
-v_disp
;
1479 sync
= (h_sync_pol
? 0 : FB_SYNC_HOR_HIGH_ACT
) |
1480 (v_sync_pol
? 0 : FB_SYNC_VERT_HIGH_ACT
) |
1481 (c_sync
? FB_SYNC_COMP_HIGH_ACT
: 0);
1483 switch (pix_width
) {
1485 case CRTC_PIX_WIDTH_4BPP
:
1487 var
->red
.offset
= 0;
1488 var
->red
.length
= 8;
1489 var
->green
.offset
= 0;
1490 var
->green
.length
= 8;
1491 var
->blue
.offset
= 0;
1492 var
->blue
.length
= 8;
1493 var
->transp
.offset
= 0;
1494 var
->transp
.length
= 0;
1497 case CRTC_PIX_WIDTH_8BPP
:
1499 var
->red
.offset
= 0;
1500 var
->red
.length
= 8;
1501 var
->green
.offset
= 0;
1502 var
->green
.length
= 8;
1503 var
->blue
.offset
= 0;
1504 var
->blue
.length
= 8;
1505 var
->transp
.offset
= 0;
1506 var
->transp
.length
= 0;
1508 case CRTC_PIX_WIDTH_15BPP
: /* RGB 555 */
1510 var
->red
.offset
= 10;
1511 var
->red
.length
= 5;
1512 var
->green
.offset
= 5;
1513 var
->green
.length
= 5;
1514 var
->blue
.offset
= 0;
1515 var
->blue
.length
= 5;
1516 var
->transp
.offset
= 0;
1517 var
->transp
.length
= 0;
1520 case CRTC_PIX_WIDTH_16BPP
: /* RGB 565 */
1522 var
->red
.offset
= 11;
1523 var
->red
.length
= 5;
1524 var
->green
.offset
= 5;
1525 var
->green
.length
= 6;
1526 var
->blue
.offset
= 0;
1527 var
->blue
.length
= 5;
1528 var
->transp
.offset
= 0;
1529 var
->transp
.length
= 0;
1532 case CRTC_PIX_WIDTH_24BPP
: /* RGB 888 */
1534 var
->red
.offset
= 16;
1535 var
->red
.length
= 8;
1536 var
->green
.offset
= 8;
1537 var
->green
.length
= 8;
1538 var
->blue
.offset
= 0;
1539 var
->blue
.length
= 8;
1540 var
->transp
.offset
= 0;
1541 var
->transp
.length
= 0;
1543 case CRTC_PIX_WIDTH_32BPP
: /* ARGB 8888 */
1545 var
->red
.offset
= 16;
1546 var
->red
.length
= 8;
1547 var
->green
.offset
= 8;
1548 var
->green
.length
= 8;
1549 var
->blue
.offset
= 0;
1550 var
->blue
.length
= 8;
1551 var
->transp
.offset
= 24;
1552 var
->transp
.length
= 8;
1555 FAIL("Invalid pixel width");
1561 var
->xres_virtual
= crtc
->vxres
;
1562 var
->yres_virtual
= crtc
->vyres
;
1563 var
->bits_per_pixel
= bpp
;
1564 var
->xoffset
= crtc
->xoffset
;
1565 var
->yoffset
= crtc
->yoffset
;
1566 var
->left_margin
= left
;
1567 var
->right_margin
= right
;
1568 var
->upper_margin
= upper
;
1569 var
->lower_margin
= lower
;
1570 var
->hsync_len
= hslen
;
1571 var
->vsync_len
= vslen
;
1573 var
->vmode
= FB_VMODE_NONINTERLACED
;
1578 /* ------------------------------------------------------------------------- */
1581 * PLL programming (Mach64 GX family)
1583 * FIXME: use function pointer tables instead of switch statements
1586 static void aty_set_pll_gx(const struct fb_info_aty
*info
,
1587 const struct pll_gx
*pll
)
1589 switch (info
->clk_type
) {
1590 case CLK_ATI18818_1
:
1591 aty_st_8(CLOCK_CNTL
, pll
->m
, info
);
1594 aty_st_514(0x06, 0x02, info
); /* DAC Operation */
1595 aty_st_514(0x10, 0x01, info
); /* PLL Control 1 */
1596 aty_st_514(0x70, 0x01, info
); /* Misc Control 1 */
1597 aty_st_514(0x8f, 0x1f, info
); /* PLL Ref. Divider Input */
1598 aty_st_514(0x03, 0x00, info
); /* Sync Control */
1599 aty_st_514(0x05, 0x00, info
); /* Power Management */
1600 aty_st_514(0x20, pll
->m
, info
); /* F0 / M0 */
1601 aty_st_514(0x21, pll
->n
, info
); /* F1 / N0 */
1607 static int aty_var_to_pll_18818(u32 period_in_ps
, struct pll_18818
*pll
)
1609 u32 MHz100
; /* in 0.01 MHz */
1613 /* Calculate the programming word */
1614 MHz100
= 100000000 / period_in_ps
;
1619 if (MHz100
> MAX_FREQ_2595
) {
1620 MHz100
= MAX_FREQ_2595
;
1622 } else if (MHz100
< ABS_MIN_FREQ_2595
) {
1623 program_bits
= 0; /* MHz100 = 257 */
1626 while (MHz100
< MIN_FREQ_2595
) {
1632 MHz100
= (REF_DIV_2595
* MHz100
) / REF_FREQ_2595
;
1634 MHz100
+= 500; /* + 0.5 round */
1637 if (program_bits
== -1) {
1638 program_bits
= MHz100
- N_ADJ_2595
;
1639 switch (post_divider
) {
1641 program_bits
|= 0x0600;
1644 program_bits
|= 0x0400;
1647 program_bits
|= 0x0200;
1655 program_bits
|= STOP_BITS_2595
;
1657 pll
->program_bits
= program_bits
;
1658 pll
->locationAddr
= 0;
1659 pll
->post_divider
= post_divider
;
1660 pll
->period_in_ps
= period_in_ps
;
1665 static u32
aty_pll_18818_to_var(const struct pll_18818
*pll
)
1667 return(pll
->period_in_ps
); /* default for now */
1670 static void aty_set_pll18818(const struct fb_info_aty
*info
,
1671 const struct pll_18818
*pll
)
1679 u8 old_crtc_ext_disp
;
1681 old_clock_cntl
= aty_ld_8(CLOCK_CNTL
, info
);
1682 aty_st_8(CLOCK_CNTL
+ info
->clk_wr_offset
, 0, info
);
1684 old_crtc_ext_disp
= aty_ld_8(CRTC_GEN_CNTL
+ 3, info
);
1685 aty_st_8(CRTC_GEN_CNTL
+ 3, old_crtc_ext_disp
| (CRTC_EXT_DISP_EN
>> 24),
1688 udelay(15000); /* delay for 50 (15) ms */
1690 program_bits
= pll
->program_bits
;
1691 locationAddr
= pll
->locationAddr
;
1693 /* Program the clock chip */
1694 aty_st_8(CLOCK_CNTL
+ info
->clk_wr_offset
, 0, info
); /* Strobe = 0 */
1695 aty_StrobeClock(info
);
1696 aty_st_8(CLOCK_CNTL
+ info
->clk_wr_offset
, 1, info
); /* Strobe = 0 */
1697 aty_StrobeClock(info
);
1699 aty_ICS2595_put1bit(1, info
); /* Send start bits */
1700 aty_ICS2595_put1bit(0, info
); /* Start bit */
1701 aty_ICS2595_put1bit(0, info
); /* Read / ~Write */
1703 for (i
= 0; i
< 5; i
++) { /* Location 0..4 */
1704 aty_ICS2595_put1bit(locationAddr
& 1, info
);
1708 for (i
= 0; i
< 8 + 1 + 2 + 2; i
++) {
1709 aty_ICS2595_put1bit(program_bits
& 1, info
);
1713 udelay(1000); /* delay for 1 ms */
1715 (void)aty_ld_8(DAC_REGS
, info
); /* Clear DAC Counter */
1716 aty_st_8(CRTC_GEN_CNTL
+ 3, old_crtc_ext_disp
, info
);
1717 aty_st_8(CLOCK_CNTL
+ info
->clk_wr_offset
, old_clock_cntl
| CLOCK_STROBE
,
1720 udelay(50000); /* delay for 50 (15) ms */
1721 aty_st_8(CLOCK_CNTL
+ info
->clk_wr_offset
,
1722 ((pll
->locationAddr
& 0x0F) | CLOCK_STROBE
), info
);
1728 static int aty_var_to_pll_408(u32 period_in_ps
, struct pll_18818
*pll
)
1730 u32 mhz100
; /* in 0.01 MHz */
1732 /* u32 post_divider; */
1733 u32 mach64MinFreq
, mach64MaxFreq
, mach64RefFreq
;
1735 u16 remainder
, preRemainder
;
1736 short divider
= 0, tempA
;
1738 /* Calculate the programming word */
1739 mhz100
= 100000000 / period_in_ps
;
1740 mach64MinFreq
= MIN_FREQ_2595
;
1741 mach64MaxFreq
= MAX_FREQ_2595
;
1742 mach64RefFreq
= REF_FREQ_2595
; /* 14.32 MHz */
1744 /* Calculate program word */
1746 program_bits
= 0xFF;
1748 if (mhz100
< mach64MinFreq
)
1749 mhz100
= mach64MinFreq
;
1750 if (mhz100
> mach64MaxFreq
)
1751 mhz100
= mach64MaxFreq
;
1753 while (mhz100
< (mach64MinFreq
<< 3)) {
1758 temp
= (unsigned int)mhz100
;
1759 temp
= (unsigned int)(temp
* (MIN_N_408
+ 2));
1760 temp
-= ((short)(mach64RefFreq
<< 1));
1763 preRemainder
= 0xFFFF;
1767 remainder
= tempB
% mach64RefFreq
;
1768 tempB
= tempB
/ mach64RefFreq
;
1769 if (((tempB
& 0xFFFF) <= 255) && (remainder
<= preRemainder
)) {
1770 preRemainder
= remainder
;
1773 divider
= (divider
& 0x00FF) + ((tempB
& 0xFF) << 8);
1777 } while(tempA
<= 32);
1779 program_bits
= divider
;
1782 pll
->program_bits
= program_bits
;
1783 pll
->locationAddr
= 0;
1784 pll
->post_divider
= divider
; /* fuer nix */
1785 pll
->period_in_ps
= period_in_ps
;
1790 static u32
aty_pll_408_to_var(const struct pll_18818
*pll
)
1792 return(pll
->period_in_ps
); /* default for now */
1795 static void aty_set_pll_408(const struct fb_info_aty
*info
,
1796 const struct pll_18818
*pll
)
1801 u8 tmpA
, tmpB
, tmpC
;
1802 char old_crtc_ext_disp
;
1804 old_crtc_ext_disp
= aty_ld_8(CRTC_GEN_CNTL
+ 3, info
);
1805 aty_st_8(CRTC_GEN_CNTL
+ 3, old_crtc_ext_disp
| (CRTC_EXT_DISP_EN
>> 24),
1808 program_bits
= pll
->program_bits
;
1809 locationAddr
= pll
->locationAddr
;
1812 aty_dac_waste4(info
);
1813 tmpB
= aty_ld_8(DAC_REGS
+ 2, info
) | 1;
1814 aty_dac_waste4(info
);
1815 aty_st_8(DAC_REGS
+ 2, tmpB
, info
);
1822 aty_st_8(DAC_REGS
, tmpB
, info
);
1823 aty_st_8(DAC_REGS
+ 2, tmpA
, info
);
1825 udelay(400); /* delay for 400 us */
1827 locationAddr
= (locationAddr
<< 2) + 0x40;
1828 tmpB
= locationAddr
;
1829 tmpA
= program_bits
>> 8;
1831 aty_st_8(DAC_REGS
, tmpB
, info
);
1832 aty_st_8(DAC_REGS
+ 2, tmpA
, info
);
1834 tmpB
= locationAddr
+ 1;
1835 tmpA
= (u8
)program_bits
;
1837 aty_st_8(DAC_REGS
, tmpB
, info
);
1838 aty_st_8(DAC_REGS
+ 2, tmpA
, info
);
1840 tmpB
= locationAddr
+ 2;
1843 aty_st_8(DAC_REGS
, tmpB
, info
);
1844 aty_st_8(DAC_REGS
+ 2, tmpA
, info
);
1846 udelay(400); /* delay for 400 us */
1847 tmpA
= tmpC
& (~(1 | 8));
1850 aty_st_8(DAC_REGS
, tmpB
, info
);
1851 aty_st_8(DAC_REGS
+ 2, tmpA
, info
);
1853 (void)aty_ld_8(DAC_REGS
, info
); /* Clear DAC Counter */
1854 aty_st_8(CRTC_GEN_CNTL
+ 3, old_crtc_ext_disp
, info
);
1860 static int aty_var_to_pll_1703(u32 period_in_ps
, struct pll_18818
*pll
)
1862 u32 mhz100
; /* in 0.01 MHz */
1864 /* u32 post_divider; */
1865 u32 mach64MinFreq
, mach64MaxFreq
, mach64RefFreq
;
1867 u16 remainder
, preRemainder
;
1868 short divider
= 0, tempA
;
1870 /* Calculate the programming word */
1871 mhz100
= 100000000 / period_in_ps
;
1872 mach64MinFreq
= MIN_FREQ_2595
;
1873 mach64MaxFreq
= MAX_FREQ_2595
;
1874 mach64RefFreq
= REF_FREQ_2595
; /* 14.32 MHz */
1876 /* Calculate program word */
1878 program_bits
= 0xE0;
1880 if (mhz100
< mach64MinFreq
)
1881 mhz100
= mach64MinFreq
;
1882 if (mhz100
> mach64MaxFreq
)
1883 mhz100
= mach64MaxFreq
;
1886 while (mhz100
< (mach64MinFreq
<< 3)) {
1891 temp
= (unsigned int)(mhz100
);
1892 temp
= (unsigned int)(temp
* (MIN_N_1703
+ 2));
1893 temp
-= (short)(mach64RefFreq
<< 1);
1896 preRemainder
= 0xffff;
1900 remainder
= tempB
% mach64RefFreq
;
1901 tempB
= tempB
/ mach64RefFreq
;
1903 if ((tempB
& 0xffff) <= 127 && (remainder
<= preRemainder
)) {
1904 preRemainder
= remainder
;
1907 divider
= (divider
& 0x00ff) + ((tempB
& 0xff) << 8);
1912 } while (tempA
<= (MIN_N_1703
<< 1));
1914 program_bits
= divider
;
1917 pll
->program_bits
= program_bits
;
1918 pll
->locationAddr
= 0;
1919 pll
->post_divider
= divider
; /* fuer nix */
1920 pll
->period_in_ps
= period_in_ps
;
1925 static u32
aty_pll_1703_to_var(const struct pll_18818
*pll
)
1927 return(pll
->period_in_ps
); /* default for now */
1930 static void aty_set_pll_1703(const struct fb_info_aty
*info
,
1931 const struct pll_18818
*pll
)
1936 char old_crtc_ext_disp
;
1938 old_crtc_ext_disp
= aty_ld_8(CRTC_GEN_CNTL
+ 3, info
);
1939 aty_st_8(CRTC_GEN_CNTL
+ 3, old_crtc_ext_disp
| (CRTC_EXT_DISP_EN
>> 24),
1942 program_bits
= pll
->program_bits
;
1943 locationAddr
= pll
->locationAddr
;
1946 aty_dac_waste4(info
);
1948 (void)aty_ld_8(DAC_REGS
+ 2, info
);
1949 aty_st_8(DAC_REGS
+2, (locationAddr
<< 1) + 0x20, info
);
1950 aty_st_8(DAC_REGS
+2, 0, info
);
1951 aty_st_8(DAC_REGS
+2, (program_bits
& 0xFF00) >> 8, info
);
1952 aty_st_8(DAC_REGS
+2, (program_bits
& 0xFF), info
);
1954 (void)aty_ld_8(DAC_REGS
, info
); /* Clear DAC Counter */
1955 aty_st_8(CRTC_GEN_CNTL
+ 3, old_crtc_ext_disp
, info
);
1961 static int aty_var_to_pll_8398(u32 period_in_ps
, struct pll_18818
*pll
)
1964 u32 tempA
, tempB
, fOut
, longMHz100
, diff
, preDiff
;
1966 u32 mhz100
; /* in 0.01 MHz */
1968 /* u32 post_divider; */
1969 u32 mach64MinFreq
, mach64MaxFreq
, mach64RefFreq
;
1970 u16 m
, n
, k
=0, save_m
, save_n
, twoToKth
;
1972 /* Calculate the programming word */
1973 mhz100
= 100000000 / period_in_ps
;
1974 mach64MinFreq
= MIN_FREQ_2595
;
1975 mach64MaxFreq
= MAX_FREQ_2595
;
1976 mach64RefFreq
= REF_FREQ_2595
; /* 14.32 MHz */
1981 /* Calculate program word */
1983 program_bits
= 0xE0;
1986 if (mhz100
< mach64MinFreq
)
1987 mhz100
= mach64MinFreq
;
1988 if (mhz100
> mach64MaxFreq
)
1989 mhz100
= mach64MaxFreq
;
1991 longMHz100
= mhz100
* 256 / 100; /* 8 bit scale this */
1993 while (mhz100
< (mach64MinFreq
<< 3))
2001 preDiff
= 0xFFFFFFFF;
2003 for (m
= MIN_M
; m
<= MAX_M
; m
++)
2005 for (n
= MIN_N
; n
<= MAX_N
; n
++)
2007 tempA
= (14.31818 * 65536);
2008 tempA
*= (n
+ 8); /* 43..256 */
2009 tempB
= twoToKth
* 256;
2010 tempB
*= (m
+ 2); /* 4..32 */
2011 fOut
= tempA
/ tempB
; /* 8 bit scale */
2013 if (longMHz100
> fOut
)
2014 diff
= longMHz100
- fOut
;
2016 diff
= fOut
- longMHz100
;
2027 program_bits
= (k
<< 6) + (save_m
) + (save_n
<< 8);
2030 pll
->program_bits
= program_bits
;
2031 pll
->locationAddr
= 0;
2032 pll
->post_divider
= 0;
2033 pll
->period_in_ps
= period_in_ps
;
2038 static u32
aty_pll_8398_to_var(const struct pll_18818
*pll
)
2040 return(pll
->period_in_ps
); /* default for now */
2043 static void aty_set_pll_8398(const struct fb_info_aty
*info
,
2044 const struct pll_18818
*pll
)
2049 char old_crtc_ext_disp
;
2052 old_crtc_ext_disp
= aty_ld_8(CRTC_GEN_CNTL
+ 3, info
);
2053 aty_st_8(CRTC_GEN_CNTL
+ 3, old_crtc_ext_disp
| (CRTC_EXT_DISP_EN
>> 24),
2056 program_bits
= pll
->program_bits
;
2057 locationAddr
= pll
->locationAddr
;
2060 tmp
= aty_ld_8(DAC_CNTL
, info
);
2061 aty_st_8(DAC_CNTL
, tmp
| DAC_EXT_SEL_RS2
| DAC_EXT_SEL_RS3
, info
);
2063 aty_st_8(DAC_REGS
, locationAddr
, info
);
2064 aty_st_8(DAC_REGS
+1, (program_bits
& 0xff00) >> 8, info
);
2065 aty_st_8(DAC_REGS
+1, (program_bits
& 0xff), info
);
2067 tmp
= aty_ld_8(DAC_CNTL
, info
);
2068 aty_st_8(DAC_CNTL
, (tmp
& ~DAC_EXT_SEL_RS2
) | DAC_EXT_SEL_RS3
, info
);
2070 (void)aty_ld_8(DAC_REGS
, info
); /* Clear DAC Counter */
2071 aty_st_8(CRTC_GEN_CNTL
+ 3, old_crtc_ext_disp
, info
);
2077 static int aty_var_to_pll_514(u32 vclk_per
, struct pll_gx
*pll
)
2080 * FIXME: use real calculations instead of using fixed values from the old
2084 u32 limit
; /* pixlock rounding limit (arbitrary) */
2085 u8 m
; /* (df<<6) | vco_div_count */
2086 u8 n
; /* ref_div_count */
2087 } RGB514_clocks
[7] = {
2088 { 8000, (3<<6) | 20, 9 }, /* 7395 ps / 135.2273 MHz */
2089 { 10000, (1<<6) | 19, 3 }, /* 9977 ps / 100.2273 MHz */
2090 { 13000, (1<<6) | 2, 3 }, /* 12509 ps / 79.9432 MHz */
2091 { 14000, (2<<6) | 8, 7 }, /* 13394 ps / 74.6591 MHz */
2092 { 16000, (1<<6) | 44, 6 }, /* 15378 ps / 65.0284 MHz */
2093 { 25000, (1<<6) | 15, 5 }, /* 17460 ps / 57.2727 MHz */
2094 { 50000, (0<<6) | 53, 7 }, /* 33145 ps / 30.1705 MHz */
2098 for (i
= 0; i
< sizeof(RGB514_clocks
)/sizeof(*RGB514_clocks
); i
++)
2099 if (vclk_per
<= RGB514_clocks
[i
].limit
) {
2100 pll
->m
= RGB514_clocks
[i
].m
;
2101 pll
->n
= RGB514_clocks
[i
].n
;
2108 static void aty_StrobeClock(const struct fb_info_aty
*info
)
2114 tmp
= aty_ld_8(CLOCK_CNTL
, info
);
2115 aty_st_8(CLOCK_CNTL
+ info
->clk_wr_offset
, tmp
| CLOCK_STROBE
, info
);
2121 static void aty_ICS2595_put1bit(u8 data
, const struct fb_info_aty
*info
)
2126 tmp
= aty_ld_8(CLOCK_CNTL
, info
);
2127 aty_st_8(CLOCK_CNTL
+ info
->clk_wr_offset
, (tmp
& ~0x04) | (data
<< 2),
2130 tmp
= aty_ld_8(CLOCK_CNTL
, info
);
2131 aty_st_8(CLOCK_CNTL
+ info
->clk_wr_offset
, (tmp
& ~0x08) | (0 << 3), info
);
2133 aty_StrobeClock(info
);
2135 tmp
= aty_ld_8(CLOCK_CNTL
, info
);
2136 aty_st_8(CLOCK_CNTL
+ info
->clk_wr_offset
, (tmp
& ~0x08) | (1 << 3), info
);
2138 aty_StrobeClock(info
);
2144 static u32
aty_pll_gx_to_var(const struct pll_gx
*pll
,
2145 const struct fb_info_aty
*info
)
2147 u8 df
, vco_div_count
, ref_div_count
;
2150 vco_div_count
= pll
->m
& 0x3f;
2151 ref_div_count
= pll
->n
;
2153 return ((info
->ref_clk_per
*ref_div_count
)<<(3-df
))/(vco_div_count
+65);
2158 * PLL programming (Mach64 CT family)
2161 static void aty_set_pll_ct(const struct fb_info_aty
*info
,
2162 const struct pll_ct
*pll
)
2164 aty_st_pll(PLL_REF_DIV
, pll
->pll_ref_div
, info
);
2165 aty_st_pll(PLL_GEN_CNTL
, pll
->pll_gen_cntl
, info
);
2166 aty_st_pll(MCLK_FB_DIV
, pll
->mclk_fb_div
, info
);
2167 aty_st_pll(PLL_VCLK_CNTL
, pll
->pll_vclk_cntl
, info
);
2168 aty_st_pll(VCLK_POST_DIV
, pll
->vclk_post_div
, info
);
2169 aty_st_pll(VCLK0_FB_DIV
, pll
->vclk_fb_div
, info
);
2170 aty_st_pll(PLL_EXT_CNTL
, pll
->pll_ext_cntl
, info
);
2172 if (!(Gx
== GX_CHIP_ID
|| Gx
== CX_CHIP_ID
|| Gx
== CT_CHIP_ID
||
2174 ((Gx
== VT_CHIP_ID
|| Gx
== GT_CHIP_ID
) && !(Rev
& 0x07)))) {
2175 if (info
->ram_type
>= SDRAM
)
2176 aty_st_pll(DLL_CNTL
, 0xa6, info
);
2178 aty_st_pll(DLL_CNTL
, 0xa0, info
);
2179 aty_st_pll(VFC_CNTL
, 0x1b, info
);
2180 aty_st_le32(DSP_CONFIG
, pll
->dsp_config
, info
);
2181 aty_st_le32(DSP_ON_OFF
, pll
->dsp_on_off
, info
);
2185 static int aty_dsp_gt(const struct fb_info_aty
*info
, u8 bpp
,
2188 u32 dsp_xclks_per_row
, dsp_loop_latency
, dsp_precision
, dsp_off
, dsp_on
;
2189 u32 xclks_per_row
, fifo_off
, fifo_on
, y
, fifo_size
, page_size
;
2191 /* xclocks_per_row<<11 */
2192 xclks_per_row
= (pll
->mclk_fb_div
*pll
->vclk_post_div_real
*64<<11)/
2193 (pll
->vclk_fb_div
*pll
->mclk_post_div_real
*bpp
);
2194 if (xclks_per_row
< (1<<11))
2195 FAIL("Dotclock to high");
2196 if (Gx
== GT_CHIP_ID
|| Gx
== GU_CHIP_ID
|| Gx
== VT_CHIP_ID
||
2197 Gx
== VU_CHIP_ID
|| Gx
== GV_CHIP_ID
|| Gx
== GW_CHIP_ID
||
2200 dsp_loop_latency
= 0;
2203 dsp_loop_latency
= 2;
2206 y
= (xclks_per_row
*fifo_size
)>>11;
2213 fifo_off
= ((xclks_per_row
*(fifo_size
-1))>>5)+(3<<6);
2215 if (info
->total_vram
> 1*1024*1024) {
2216 if (info
->ram_type
>= SDRAM
) {
2218 dsp_loop_latency
+= 8;
2222 dsp_loop_latency
+= 6;
2226 if (info
->ram_type
>= SDRAM
) {
2228 dsp_loop_latency
+= 9;
2232 dsp_loop_latency
+= 8;
2237 if (xclks_per_row
>= (page_size
<<11))
2238 fifo_on
= ((2*page_size
+1)<<6)+(xclks_per_row
>>5);
2240 fifo_on
= (3*page_size
+2)<<6;
2242 dsp_xclks_per_row
= xclks_per_row
>>dsp_precision
;
2243 dsp_on
= fifo_on
>>dsp_precision
;
2244 dsp_off
= fifo_off
>>dsp_precision
;
2246 pll
->dsp_config
= (dsp_xclks_per_row
& 0x3fff) |
2247 ((dsp_loop_latency
& 0xf)<<16) |
2248 ((dsp_precision
& 7)<<20);
2249 pll
->dsp_on_off
= (dsp_on
& 0x7ff) | ((dsp_off
& 0x7ff)<<16);
2253 static int aty_valid_pll_ct(const struct fb_info_aty
*info
, u32 vclk_per
,
2256 u32 q
, x
; /* x is a workaround for sparc64-linux-gcc */
2257 x
= x
; /* x is a workaround for sparc64-linux-gcc */
2259 pll
->pll_ref_div
= info
->pll_per
*2*255/info
->ref_clk_per
;
2261 /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
2262 q
= info
->ref_clk_per
*pll
->pll_ref_div
*4/info
->mclk_per
; /* actually 8*q */
2263 if (q
< 16*8 || q
> 255*8)
2264 FAIL("mclk out of range");
2266 pll
->mclk_post_div_real
= 8;
2268 pll
->mclk_post_div_real
= 4;
2270 pll
->mclk_post_div_real
= 2;
2272 pll
->mclk_post_div_real
= 1;
2273 pll
->mclk_fb_div
= q
*pll
->mclk_post_div_real
/8;
2275 /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
2276 q
= info
->ref_clk_per
*pll
->pll_ref_div
*4/vclk_per
; /* actually 8*q */
2277 if (q
< 16*8 || q
> 255*8)
2278 FAIL("vclk out of range");
2280 pll
->vclk_post_div_real
= 8;
2282 pll
->vclk_post_div_real
= 4;
2284 pll
->vclk_post_div_real
= 2;
2286 pll
->vclk_post_div_real
= 1;
2287 pll
->vclk_fb_div
= q
*pll
->vclk_post_div_real
/8;
2291 static void aty_calc_pll_ct(const struct fb_info_aty
*info
, struct pll_ct
*pll
)
2296 if ((((Gx
== GT_CHIP_ID
) && (Rev
& 0x03)) || (Gx
== GU_CHIP_ID
) ||
2297 (Gx
== GV_CHIP_ID
) || (Gx
== GW_CHIP_ID
) || (Gx
== GZ_CHIP_ID
) ||
2298 (Gx
== LG_CHIP_ID
) || (Gx
== GB_CHIP_ID
) || (Gx
== GD_CHIP_ID
) ||
2299 (Gx
== GI_CHIP_ID
) || (Gx
== GP_CHIP_ID
) || (Gx
== GQ_CHIP_ID
) ||
2300 (Gx
== VU_CHIP_ID
)) && (info
->ram_type
>= SDRAM
))
2301 pll
->pll_gen_cntl
= 0x04;
2303 pll
->pll_gen_cntl
= 0x84;
2305 switch (pll
->mclk_post_div_real
) {
2322 pll
->pll_gen_cntl
|= mpostdiv
<<4; /* mclk */
2324 if (Gx
== VT_CHIP_ID
&& (Rev
== 0x40 || Rev
== 0x48))
2325 pll
->pll_ext_cntl
= 0;
2327 pll
->pll_ext_cntl
= mpostdiv
; /* xclk == mclk */
2329 switch (pll
->vclk_post_div_real
) {
2334 pll
->pll_ext_cntl
|= 0x10;
2339 pll
->pll_ext_cntl
|= 0x10;
2344 pll
->pll_ext_cntl
|= 0x10;
2350 pll
->pll_vclk_cntl
= 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
2351 pll
->vclk_post_div
= vpostdiv
;
2354 static int aty_var_to_pll_ct(const struct fb_info_aty
*info
, u32 vclk_per
,
2355 u8 bpp
, struct pll_ct
*pll
)
2359 if ((err
= aty_valid_pll_ct(info
, vclk_per
, pll
)))
2361 if (!(Gx
== GX_CHIP_ID
|| Gx
== CX_CHIP_ID
|| Gx
== CT_CHIP_ID
||
2363 ((Gx
== VT_CHIP_ID
|| Gx
== GT_CHIP_ID
) && !(Rev
& 0x07)))) {
2364 if ((err
= aty_dsp_gt(info
, bpp
, pll
)))
2367 aty_calc_pll_ct(info
, pll
);
2371 static u32
aty_pll_ct_to_var(const struct pll_ct
*pll
,
2372 const struct fb_info_aty
*info
)
2374 u32 ref_clk_per
= info
->ref_clk_per
;
2375 u8 pll_ref_div
= pll
->pll_ref_div
;
2376 u8 vclk_fb_div
= pll
->vclk_fb_div
;
2377 u8 vclk_post_div
= pll
->vclk_post_div_real
;
2379 return ref_clk_per
*pll_ref_div
*vclk_post_div
/vclk_fb_div
/2;
2382 /* ------------------------------------------------------------------------- */
2384 static void atyfb_set_par(const struct atyfb_par
*par
,
2385 struct fb_info_aty
*info
)
2392 accelmode
= par
->accel_flags
; /* hack */
2394 info
->current_par
= *par
;
2396 if (info
->blitter_may_be_busy
)
2397 wait_for_idle(info
);
2398 tmp
= aty_ld_8(CRTC_GEN_CNTL
+ 3, info
);
2399 aty_set_crtc(info
, &par
->crtc
);
2400 aty_st_8(CLOCK_CNTL
+ info
->clk_wr_offset
, 0, info
);
2401 /* better call aty_StrobeClock ?? */
2402 aty_st_8(CLOCK_CNTL
+ info
->clk_wr_offset
, CLOCK_STROBE
, info
);
2404 if ((Gx
== GX_CHIP_ID
) || (Gx
== CX_CHIP_ID
)) {
2405 switch (info
->dac_subtype
) {
2407 aty_set_dac_514(info
, par
->crtc
.bpp
);
2409 case DAC_ATI68860_B
:
2410 case DAC_ATI68860_C
:
2411 muxmode
= aty_set_dac_ATI68860_B(info
, par
->crtc
.bpp
,
2413 aty_st_le32(BUS_CNTL
, 0x890e20f1, info
);
2414 aty_st_le32(DAC_CNTL
, 0x47052100, info
);
2417 muxmode
= aty_set_dac_ATT21C498(info
, &par
->pll
.ics2595
,
2419 aty_st_le32(BUS_CNTL
, 0x890e20f1, info
);
2420 aty_st_le32(DAC_CNTL
, 0x00072000, info
);
2423 muxmode
= aty_set_dac_ATT21C498(info
, &par
->pll
.ics2595
,
2425 aty_st_le32(BUS_CNTL
, 0x890e20f1, info
);
2426 aty_st_le32(DAC_CNTL
, 0x00072000, info
);
2429 printk(" atyfb_set_par: DAC type not implemented yet!\n");
2430 aty_st_le32(BUS_CNTL
, 0x890e20f1, info
);
2431 aty_st_le32(DAC_CNTL
, 0x47052100, info
);
2432 /* new in 2.2.3p1 from Geert. ???????? */
2433 aty_st_le32(BUS_CNTL
, 0x590e10ff, info
);
2434 aty_st_le32(DAC_CNTL
, 0x47012100, info
);
2438 switch (info
->clk_type
) {
2439 case CLK_ATI18818_1
:
2440 aty_set_pll18818(info
, &par
->pll
.ics2595
);
2443 aty_set_pll_1703(info
, &par
->pll
.ics2595
);
2446 aty_set_pll_8398(info
, &par
->pll
.ics2595
);
2449 aty_set_pll_408(info
, &par
->pll
.ics2595
);
2452 aty_set_pll_gx(info
, &par
->pll
.gx
);
2455 printk(" atyfb_set_par: CLK type not implemented yet!");
2459 /* Don't forget MEM_CNTL */
2460 i
= aty_ld_le32(MEM_CNTL
, info
) & 0xf0ffffff;
2461 switch (par
->crtc
.bpp
) {
2472 aty_st_le32(MEM_CNTL
, i
, info
);
2475 aty_set_pll_ct(info
, &par
->pll
.ct
);
2476 i
= aty_ld_le32(MEM_CNTL
, info
) & 0xf00fffff;
2477 if (!(Gx
== VT_CHIP_ID
&& (Rev
== 0x40 || Rev
== 0x48)))
2478 i
|= info
->mem_refresh_rate
<< 20;
2479 switch (par
->crtc
.bpp
) {
2491 if ((Gx
== CT_CHIP_ID
) || (Gx
== ET_CHIP_ID
)) {
2492 aty_st_le32(DAC_CNTL
, 0x87010184, info
);
2493 aty_st_le32(BUS_CNTL
, 0x680000f9, info
);
2494 } else if ((Gx
== VT_CHIP_ID
) || (Gx
== VU_CHIP_ID
)) {
2495 aty_st_le32(DAC_CNTL
, 0x87010184, info
);
2496 aty_st_le32(BUS_CNTL
, 0x680000f9, info
);
2499 aty_st_le32(DAC_CNTL
, 0x86010102, info
);
2500 aty_st_le32(BUS_CNTL
, 0x7b23a040, info
);
2501 aty_st_le32(EXT_MEM_CNTL
,
2502 aty_ld_le32(EXT_MEM_CNTL
, info
) | 0x5000001, info
);
2504 aty_st_le32(MEM_CNTL
, i
, info
);
2506 aty_st_8(DAC_MASK
, 0xff, info
);
2508 /* Initialize the graphics engine */
2509 if (par
->accel_flags
& FB_ACCELF_TEXT
)
2510 init_engine(par
, info
);
2512 #ifdef CONFIG_FB_COMPAT_XPMAC
2513 if (!console_fb_info
|| console_fb_info
== &info
->fb_info
) {
2514 struct fb_var_screeninfo var
;
2516 display_info
.height
= ((par
->crtc
.v_tot_disp
>>16) & 0x7ff)+1;
2517 display_info
.width
= (((par
->crtc
.h_tot_disp
>>16) & 0xff)+1)*8;
2518 display_info
.depth
= par
->crtc
.bpp
;
2519 display_info
.pitch
= par
->crtc
.vxres
*par
->crtc
.bpp
/8;
2520 atyfb_encode_var(&var
, par
, info
);
2521 if (mac_var_to_vmode(&var
, &vmode
, &cmode
))
2522 display_info
.mode
= 0;
2524 display_info
.mode
= vmode
;
2525 strcpy(display_info
.name
, atyfb_name
);
2526 display_info
.fb_address
= info
->frame_buffer_phys
;
2527 display_info
.cmap_adr_address
= info
->ati_regbase_phys
+0xc0;
2528 display_info
.cmap_data_address
= info
->ati_regbase_phys
+0xc1;
2529 display_info
.disp_reg_address
= info
->ati_regbase_phys
;
2531 #endif /* CONFIG_FB_COMPAT_XPMAC */
2534 static int atyfb_decode_var(const struct fb_var_screeninfo
*var
,
2535 struct atyfb_par
*par
,
2536 const struct fb_info_aty
*info
)
2540 if ((err
= aty_var_to_crtc(info
, var
, &par
->crtc
)))
2542 if ((Gx
== GX_CHIP_ID
) || (Gx
== CX_CHIP_ID
))
2543 switch (info
->clk_type
) {
2544 case CLK_ATI18818_1
:
2545 err
= aty_var_to_pll_18818(var
->pixclock
, &par
->pll
.ics2595
);
2548 err
= aty_var_to_pll_1703(var
->pixclock
, &par
->pll
.ics2595
);
2551 err
= aty_var_to_pll_8398(var
->pixclock
, &par
->pll
.ics2595
);
2554 err
= aty_var_to_pll_408(var
->pixclock
, &par
->pll
.ics2595
);
2557 err
= aty_var_to_pll_514(var
->pixclock
, &par
->pll
.gx
);
2561 err
= aty_var_to_pll_ct(info
, var
->pixclock
, par
->crtc
.bpp
,
2566 if (var
->accel_flags
& FB_ACCELF_TEXT
)
2567 par
->accel_flags
= FB_ACCELF_TEXT
;
2569 par
->accel_flags
= 0;
2571 #if 0 /* fbmon is not done. uncomment for 2.5.x -brad */
2572 if (!fbmon_valid_timings(var
->pixclock
, htotal
, vtotal
, info
))
2579 static int atyfb_encode_var(struct fb_var_screeninfo
*var
,
2580 const struct atyfb_par
*par
,
2581 const struct fb_info_aty
*info
)
2585 memset(var
, 0, sizeof(struct fb_var_screeninfo
));
2587 if ((err
= aty_crtc_to_var(&par
->crtc
, var
)))
2589 if ((Gx
== GX_CHIP_ID
) || (Gx
== CX_CHIP_ID
))
2590 switch (info
->clk_type
) {
2591 case CLK_ATI18818_1
:
2592 var
->pixclock
= aty_pll_18818_to_var(&par
->pll
.ics2595
);
2595 var
->pixclock
= aty_pll_1703_to_var(&par
->pll
.ics2595
);
2598 var
->pixclock
= aty_pll_8398_to_var(&par
->pll
.ics2595
);
2601 var
->pixclock
= aty_pll_408_to_var(&par
->pll
.ics2595
);
2604 var
->pixclock
= aty_pll_gx_to_var(&par
->pll
.gx
, info
);
2608 var
->pixclock
= aty_pll_ct_to_var(&par
->pll
.ct
, info
);
2612 var
->accel_flags
= par
->accel_flags
;
2619 static void set_off_pitch(struct atyfb_par
*par
,
2620 const struct fb_info_aty
*info
)
2622 u32 xoffset
= par
->crtc
.xoffset
;
2623 u32 yoffset
= par
->crtc
.yoffset
;
2624 u32 vxres
= par
->crtc
.vxres
;
2625 u32 bpp
= par
->crtc
.bpp
;
2627 par
->crtc
.off_pitch
= ((yoffset
*vxres
+xoffset
)*bpp
/64) | (vxres
<<19);
2628 aty_st_le32(CRTC_OFF_PITCH
, par
->crtc
.off_pitch
, info
);
2633 * Open/Release the frame buffer device
2636 static int atyfb_open(struct fb_info
*info
, int user
)
2640 struct fb_info_aty
*fb
= (struct fb_info_aty
*)info
;
2653 struct fb_var_screeninfo default_var
= {
2654 /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
2655 640, 480, 640, 480, 0, 0, 8, 0,
2656 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
2657 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
2658 0, FB_VMODE_NONINTERLACED
2661 static int atyfb_release(struct fb_info
*info
, int user
)
2664 struct fb_info_aty
*fb
= (struct fb_info_aty
*)info
;
2671 int was_mmaped
= fb
->mmaped
;
2674 if (fb
->vtconsole
!= -1)
2675 vt_cons
[fb
->vtconsole
]->vc_mode
= KD_TEXT
;
2679 struct fb_var_screeninfo var
;
2681 /* Now reset the default display config, we have no
2682 * idea what the program(s) which mmap'd the chip did
2683 * to the configuration, nor whether it restored it
2688 var
.accel_flags
&= ~FB_ACCELF_TEXT
;
2690 var
.accel_flags
|= FB_ACCELF_TEXT
;
2691 if (var
.yres
== var
.yres_virtual
) {
2692 u32 vram
= (fb
->total_vram
- (PAGE_SIZE
<< 2));
2693 var
.yres_virtual
= ((vram
* 8) / var
.bits_per_pixel
) /
2695 if (var
.yres_virtual
< var
.yres
)
2696 var
.yres_virtual
= var
.yres
;
2698 atyfb_set_var(&var
, -1, &fb
->fb_info
);
2709 static int encode_fix(struct fb_fix_screeninfo
*fix
,
2710 const struct atyfb_par
*par
,
2711 const struct fb_info_aty
*info
)
2713 memset(fix
, 0, sizeof(struct fb_fix_screeninfo
));
2715 strcpy(fix
->id
, atyfb_name
);
2716 fix
->smem_start
= info
->frame_buffer_phys
;
2717 fix
->smem_len
= (u32
)info
->total_vram
;
2720 * Reg Block 0 (CT-compatible block) is at ati_regbase_phys
2721 * Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400
2723 if (Gx
== GX_CHIP_ID
|| Gx
== CX_CHIP_ID
) {
2724 fix
->mmio_start
= info
->ati_regbase_phys
;
2725 fix
->mmio_len
= 0x400;
2726 fix
->accel
= FB_ACCEL_ATI_MACH64GX
;
2727 } else if (Gx
== CT_CHIP_ID
|| Gx
== ET_CHIP_ID
) {
2728 fix
->mmio_start
= info
->ati_regbase_phys
;
2729 fix
->mmio_len
= 0x400;
2730 fix
->accel
= FB_ACCEL_ATI_MACH64CT
;
2731 } else if (Gx
== VT_CHIP_ID
|| Gx
== VU_CHIP_ID
|| Gx
== VV_CHIP_ID
) {
2732 fix
->mmio_start
= info
->ati_regbase_phys
-0x400;
2733 fix
->mmio_len
= 0x800;
2734 fix
->accel
= FB_ACCEL_ATI_MACH64VT
;
2736 fix
->mmio_start
= info
->ati_regbase_phys
-0x400;
2737 fix
->mmio_len
= 0x800;
2738 fix
->accel
= FB_ACCEL_ATI_MACH64GT
;
2740 fix
->type
= FB_TYPE_PACKED_PIXELS
;
2742 fix
->line_length
= par
->crtc
.vxres
*par
->crtc
.bpp
/8;
2743 fix
->visual
= par
->crtc
.bpp
<= 8 ? FB_VISUAL_PSEUDOCOLOR
2744 : FB_VISUAL_DIRECTCOLOR
;
2754 * Get the Fixed Part of the Display
2757 static int atyfb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
2760 const struct fb_info_aty
*info
= (struct fb_info_aty
*)fb
;
2761 struct atyfb_par par
;
2764 par
= info
->default_par
;
2766 atyfb_decode_var(&fb_display
[con
].var
, &par
, info
);
2767 encode_fix(fix
, &par
, info
);
2773 * Get the User Defined Part of the Display
2776 static int atyfb_get_var(struct fb_var_screeninfo
*var
, int con
,
2779 const struct fb_info_aty
*info
= (struct fb_info_aty
*)fb
;
2782 atyfb_encode_var(var
, &info
->default_par
, info
);
2784 *var
= fb_display
[con
].var
;
2789 static void atyfb_set_disp(struct display
*disp
, struct fb_info_aty
*info
,
2793 #ifdef FBCON_HAS_CFB8
2795 info
->dispsw
= accel
? fbcon_aty8
: fbcon_cfb8
;
2796 disp
->dispsw
= &info
->dispsw
;
2799 #ifdef FBCON_HAS_CFB16
2801 info
->dispsw
= accel
? fbcon_aty16
: fbcon_cfb16
;
2802 disp
->dispsw
= &info
->dispsw
;
2803 disp
->dispsw_data
= info
->fbcon_cmap
.cfb16
;
2806 #ifdef FBCON_HAS_CFB24
2808 info
->dispsw
= accel
? fbcon_aty24
: fbcon_cfb24
;
2809 disp
->dispsw
= &info
->dispsw
;
2810 disp
->dispsw_data
= info
->fbcon_cmap
.cfb24
;
2813 #ifdef FBCON_HAS_CFB32
2815 info
->dispsw
= accel
? fbcon_aty32
: fbcon_cfb32
;
2816 disp
->dispsw
= &info
->dispsw
;
2817 disp
->dispsw_data
= info
->fbcon_cmap
.cfb32
;
2821 disp
->dispsw
= &fbcon_dummy
;
2824 info
->dispsw
.cursor
= atyfb_cursor
;
2825 info
->dispsw
.set_font
= atyfb_set_font
;
2831 * Set the User Defined Part of the Display
2834 static int atyfb_set_var(struct fb_var_screeninfo
*var
, int con
,
2837 struct fb_info_aty
*info
= (struct fb_info_aty
*)fb
;
2838 struct atyfb_par par
;
2839 struct display
*display
;
2840 int oldxres
, oldyres
, oldvxres
, oldvyres
, oldbpp
, oldaccel
, accel
, err
;
2841 int activate
= var
->activate
;
2844 display
= &fb_display
[con
];
2846 display
= fb
->disp
; /* used during initialization */
2848 if ((err
= atyfb_decode_var(var
, &par
, info
)))
2851 atyfb_encode_var(var
, &par
, (struct fb_info_aty
*)info
);
2853 if ((activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) {
2854 oldxres
= display
->var
.xres
;
2855 oldyres
= display
->var
.yres
;
2856 oldvxres
= display
->var
.xres_virtual
;
2857 oldvyres
= display
->var
.yres_virtual
;
2858 oldbpp
= display
->var
.bits_per_pixel
;
2859 oldaccel
= display
->var
.accel_flags
;
2860 display
->var
= *var
;
2861 if (oldxres
!= var
->xres
|| oldyres
!= var
->yres
||
2862 oldvxres
!= var
->xres_virtual
|| oldvyres
!= var
->yres_virtual
||
2863 oldbpp
!= var
->bits_per_pixel
|| oldaccel
!= var
->accel_flags
) {
2864 struct fb_fix_screeninfo fix
;
2866 encode_fix(&fix
, &par
, info
);
2867 display
->screen_base
= (char *)info
->frame_buffer
;
2868 display
->visual
= fix
.visual
;
2869 display
->type
= fix
.type
;
2870 display
->type_aux
= fix
.type_aux
;
2871 display
->ypanstep
= fix
.ypanstep
;
2872 display
->ywrapstep
= fix
.ywrapstep
;
2873 display
->line_length
= fix
.line_length
;
2874 display
->can_soft_blank
= 1;
2875 display
->inverse
= 0;
2876 accel
= var
->accel_flags
& FB_ACCELF_TEXT
;
2877 atyfb_set_disp(display
, info
, par
.crtc
.bpp
, accel
);
2879 display
->scrollmode
= (info
->bus_type
== PCI
) ? SCROLL_YNOMOVE
: 0;
2881 display
->scrollmode
= SCROLL_YREDRAW
;
2882 if (info
->fb_info
.changevar
)
2883 (*info
->fb_info
.changevar
)(con
);
2885 if (!info
->fb_info
.display_fg
||
2886 info
->fb_info
.display_fg
->vc_num
== con
)
2887 atyfb_set_par(&par
, info
);
2888 if (oldbpp
!= var
->bits_per_pixel
) {
2889 if ((err
= fb_alloc_cmap(&display
->cmap
, 0, 0)))
2891 do_install_cmap(con
, &info
->fb_info
);
2900 * Pan or Wrap the Display
2902 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
2905 static int atyfb_pan_display(struct fb_var_screeninfo
*var
, int con
,
2908 struct fb_info_aty
*info
= (struct fb_info_aty
*)fb
;
2909 u32 xres
, yres
, xoffset
, yoffset
;
2910 struct atyfb_par
*par
= &info
->current_par
;
2912 xres
= (((par
->crtc
.h_tot_disp
>>16) & 0xff)+1)*8;
2913 yres
= ((par
->crtc
.v_tot_disp
>>16) & 0x7ff)+1;
2914 xoffset
= (var
->xoffset
+7) & ~7;
2915 yoffset
= var
->yoffset
;
2916 if (xoffset
+xres
> par
->crtc
.vxres
|| yoffset
+yres
> par
->crtc
.vyres
)
2918 par
->crtc
.xoffset
= xoffset
;
2919 par
->crtc
.yoffset
= yoffset
;
2920 set_off_pitch(par
, info
);
2928 static int atyfb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
2929 struct fb_info
*info
)
2931 if (!info
->display_fg
|| con
== info
->display_fg
->vc_num
) /* current console? */
2932 return fb_get_cmap(cmap
, kspc
, atyfb_getcolreg
, info
);
2933 else if (fb_display
[con
].cmap
.len
) /* non default colormap? */
2934 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
2936 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
2937 fb_copy_cmap(fb_default_cmap(size
), cmap
, kspc
? 0 : 2);
2946 static int atyfb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
2947 struct fb_info
*info
)
2950 struct display
*disp
;
2953 disp
= &fb_display
[con
];
2956 if (!disp
->cmap
.len
) { /* no colormap allocated? */
2957 int size
= disp
->var
.bits_per_pixel
== 16 ? 32 : 256;
2958 if ((err
= fb_alloc_cmap(&disp
->cmap
, size
, 0)))
2961 if (!info
->display_fg
|| con
== info
->display_fg
->vc_num
) /* current console? */
2962 return fb_set_cmap(cmap
, kspc
, atyfb_setcolreg
, info
);
2964 fb_copy_cmap(cmap
, &disp
->cmap
, kspc
? 0 : 1);
2970 #define ATYIO_CLKR 0x41545900 /* ATY\00 */
2971 #define ATYIO_CLKW 0x41545901 /* ATY\01 */
2977 u8 mclk_post_div
; /* 1,2,3,4,8 */
2979 u8 vclk_post_div
; /* 1,2,3,4,6,8,12 */
2980 u32 dsp_xclks_per_row
; /* 0-16383 */
2981 u32 dsp_loop_latency
; /* 0-15 */
2982 u32 dsp_precision
; /* 0-7 */
2983 u32 dsp_on
; /* 0-2047 */
2984 u32 dsp_off
; /* 0-2047 */
2988 static int atyfb_ioctl(struct inode
*inode
, struct file
*file
, u_int cmd
,
2989 u_long arg
, int con
, struct fb_info
*info2
)
2991 #if defined(__sparc__) || defined(DEBUG)
2992 struct fb_info_aty
*info
= (struct fb_info_aty
*)info2
;
2993 #endif /* __sparc__ || DEBUG */
2995 struct fbtype fbtyp
;
2996 struct display
*disp
;
2999 disp
= &fb_display
[con
];
3007 fbtyp
.fb_type
= FBTYPE_PCI_GENERIC
;
3008 fbtyp
.fb_width
= info
->current_par
.crtc
.vxres
;
3009 fbtyp
.fb_height
= info
->current_par
.crtc
.vyres
;
3010 fbtyp
.fb_depth
= info
->current_par
.crtc
.bpp
;
3011 fbtyp
.fb_cmsize
= disp
->cmap
.len
;
3012 fbtyp
.fb_size
= info
->total_vram
;
3013 copy_to_user_ret((struct fbtype
*)arg
, &fbtyp
, sizeof(fbtyp
), -EFAULT
);
3015 #endif /* __sparc__ */
3018 if ((Gx
!= GX_CHIP_ID
) && (Gx
!= CX_CHIP_ID
)) {
3020 struct pll_ct
*pll
= &info
->current_par
.pll
.ct
;
3021 u32 dsp_config
= pll
->dsp_config
;
3022 u32 dsp_on_off
= pll
->dsp_on_off
;
3023 clk
.ref_clk_per
= info
->ref_clk_per
;
3024 clk
.pll_ref_div
= pll
->pll_ref_div
;
3025 clk
.mclk_fb_div
= pll
->mclk_fb_div
;
3026 clk
.mclk_post_div
= pll
->mclk_post_div_real
;
3027 clk
.vclk_fb_div
= pll
->vclk_fb_div
;
3028 clk
.vclk_post_div
= pll
->vclk_post_div_real
;
3029 clk
.dsp_xclks_per_row
= dsp_config
& 0x3fff;
3030 clk
.dsp_loop_latency
= (dsp_config
>>16) & 0xf;
3031 clk
.dsp_precision
= (dsp_config
>>20) & 7;
3032 clk
.dsp_on
= dsp_on_off
& 0x7ff;
3033 clk
.dsp_off
= (dsp_on_off
>>16) & 0x7ff;
3034 copy_to_user_ret((struct atyclk
*)arg
, &clk
, sizeof(clk
),
3040 if ((Gx
!= GX_CHIP_ID
) && (Gx
!= CX_CHIP_ID
)) {
3042 struct pll_ct
*pll
= &info
->current_par
.pll
.ct
;
3043 copy_from_user_ret(&clk
, (struct atyclk
*)arg
, sizeof(clk
),
3045 info
->ref_clk_per
= clk
.ref_clk_per
;
3046 pll
->pll_ref_div
= clk
.pll_ref_div
;
3047 pll
->mclk_fb_div
= clk
.mclk_fb_div
;
3048 pll
->mclk_post_div_real
= clk
.mclk_post_div
;
3049 pll
->vclk_fb_div
= clk
.vclk_fb_div
;
3050 pll
->vclk_post_div_real
= clk
.vclk_post_div
;
3051 pll
->dsp_config
= (clk
.dsp_xclks_per_row
& 0x3fff) |
3052 ((clk
.dsp_loop_latency
& 0xf)<<16) |
3053 ((clk
.dsp_precision
& 7)<<20);
3054 pll
->dsp_on_off
= (clk
.dsp_on
& 0x7ff) |
3055 ((clk
.dsp_off
& 0x7ff)<<16);
3056 aty_calc_pll_ct(info
, pll
);
3057 aty_set_pll_ct(info
, pll
);
3068 static int atyfb_rasterimg(struct fb_info
*info
, int start
)
3070 struct fb_info_aty
*fb
= (struct fb_info_aty
*)info
;
3072 if (fb
->blitter_may_be_busy
)
3078 static int atyfb_mmap(struct fb_info
*info
, struct file
*file
,
3079 struct vm_area_struct
*vma
)
3081 struct fb_info_aty
*fb
= (struct fb_info_aty
*)info
;
3082 unsigned int size
, page
, map_size
= 0;
3083 unsigned long map_offset
= 0;
3090 if (vma
->vm_pgoff
> (~0UL >> PAGE_SHIFT
))
3093 off
= vma
->vm_pgoff
<< PAGE_SHIFT
;
3094 size
= vma
->vm_end
- vma
->vm_start
;
3096 /* To stop the swapper from even considering these pages. */
3097 vma
->vm_flags
|= (VM_SHM
| VM_LOCKED
);
3099 if (((vma
->vm_pgoff
== 0) && (size
== fb
->total_vram
)) ||
3100 ((off
== fb
->total_vram
) && (size
== PAGE_SIZE
)))
3101 off
+= 0x8000000000000000UL
;
3103 vma
->vm_pgoff
= off
>> PAGE_SHIFT
; /* propagate off changes */
3106 /* Align it as much as desirable */
3108 unsigned long j
, align
;
3111 map_offset
= off
+ size
;
3112 for (i
= 0; fb
->mmap_map
[i
].size
; i
++) {
3113 if (fb
->mmap_map
[i
].voff
< off
)
3115 if (fb
->mmap_map
[i
].voff
>= map_offset
)
3118 fb
->mmap_map
[i
].size
> fb
->mmap_map
[max
].size
)
3122 j
= fb
->mmap_map
[max
].size
;
3123 if (fb
->mmap_map
[max
].voff
+ j
> map_offset
)
3124 j
= map_offset
- fb
->mmap_map
[max
].voff
;
3125 for (align
= 0x400000; align
> PAGE_SIZE
; align
>>= 3)
3127 !(fb
->mmap_map
[max
].poff
& (align
- 1)))
3129 if (align
> PAGE_SIZE
) {
3131 align
= j
- ((vma
->vm_start
3132 + fb
->mmap_map
[max
].voff
3135 struct vm_area_struct
*vmm
;
3137 vmm
= find_vma(current
->mm
,
3139 if (!vmm
|| vmm
->vm_start
3140 >= vma
->vm_end
+ align
) {
3141 vma
->vm_start
+= align
;
3142 vma
->vm_end
+= align
;
3150 /* Each page, see which map applies */
3151 for (page
= 0; page
< size
; ) {
3153 for (i
= 0; fb
->mmap_map
[i
].size
; i
++) {
3154 unsigned long start
= fb
->mmap_map
[i
].voff
;
3155 unsigned long end
= start
+ fb
->mmap_map
[i
].size
;
3156 unsigned long offset
= off
+ page
;
3163 map_size
= fb
->mmap_map
[i
].size
- (offset
- start
);
3164 map_offset
= fb
->mmap_map
[i
].poff
+ (offset
- start
);
3171 if (page
+ map_size
> size
)
3172 map_size
= size
- page
;
3174 pgprot_val(vma
->vm_page_prot
) &= ~(fb
->mmap_map
[i
].prot_mask
);
3175 pgprot_val(vma
->vm_page_prot
) |= fb
->mmap_map
[i
].prot_flag
;
3177 if (remap_page_range(vma
->vm_start
+ page
, map_offset
,
3178 map_size
, vma
->vm_page_prot
))
3187 vma
->vm_flags
|= VM_IO
;
3190 int lastconsole
= 0;
3192 if (info
->display_fg
)
3193 lastconsole
= info
->display_fg
->vc_num
;
3195 if (fb
->consolecnt
&& fb_display
[lastconsole
].fb_info
== info
) {
3196 fb
->vtconsole
= lastconsole
;
3197 vt_cons
[lastconsole
]->vc_mode
= KD_GRAPHICS
;
3210 static void atyfb_save_palette(struct fb_info
*fb
, int enter
)
3212 struct fb_info_aty
*info
= (struct fb_info_aty
*)fb
;
3215 for (i
= 0; i
< 256; i
++) {
3216 tmp
= aty_ld_8(DAC_CNTL
, info
) & 0xfc;
3217 if (Gx
== GT_CHIP_ID
|| Gx
== GU_CHIP_ID
|| Gx
== GV_CHIP_ID
||
3218 Gx
== GW_CHIP_ID
|| Gx
== GZ_CHIP_ID
|| Gx
== LG_CHIP_ID
||
3219 Gx
== GB_CHIP_ID
|| Gx
== GD_CHIP_ID
|| Gx
== GI_CHIP_ID
||
3220 Gx
== GP_CHIP_ID
|| Gx
== GQ_CHIP_ID
)
3222 aty_st_8(DAC_CNTL
, tmp
, info
);
3223 aty_st_8(DAC_MASK
, 0xff, info
);
3225 scale
= ((Gx
!= GX_CHIP_ID
) && (Gx
!= CX_CHIP_ID
) &&
3226 (info
->current_par
.crtc
.bpp
== 16)) ? 3 : 0;
3227 writeb(i
<< scale
, &info
->aty_cmap_regs
->rindex
);
3229 atyfb_save
.r
[enter
][i
] = readb(&info
->aty_cmap_regs
->lut
);
3230 atyfb_save
.g
[enter
][i
] = readb(&info
->aty_cmap_regs
->lut
);
3231 atyfb_save
.b
[enter
][i
] = readb(&info
->aty_cmap_regs
->lut
);
3232 writeb(i
<< scale
, &info
->aty_cmap_regs
->windex
);
3233 writeb(atyfb_save
.r
[1-enter
][i
], &info
->aty_cmap_regs
->lut
);
3234 writeb(atyfb_save
.g
[1-enter
][i
], &info
->aty_cmap_regs
->lut
);
3235 writeb(atyfb_save
.b
[1-enter
][i
], &info
->aty_cmap_regs
->lut
);
3239 static void atyfb_palette(int enter
)
3241 struct fb_info_aty
*info
;
3242 struct atyfb_par
*par
;
3246 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++) {
3249 d
->fb_info
->fbops
== &atyfb_ops
&&
3250 d
->fb_info
->display_fg
&&
3251 d
->fb_info
->display_fg
->vc_num
== i
) {
3252 atyfb_save_palette(d
->fb_info
, enter
);
3253 info
= (struct fb_info_aty
*)d
->fb_info
;
3254 par
= &info
->current_par
;
3256 atyfb_save
.yoffset
= par
->crtc
.yoffset
;
3257 par
->crtc
.yoffset
= 0;
3258 set_off_pitch(par
, info
);
3260 par
->crtc
.yoffset
= atyfb_save
.yoffset
;
3261 set_off_pitch(par
, info
);
3267 #endif /* __sparc__ */
3273 static int __init
aty_init(struct fb_info_aty
*info
, const char *name
)
3278 struct fb_var_screeninfo var
;
3279 struct display
*disp
;
3280 const char *chipname
= NULL
, *ramname
= NULL
, *xtal
;
3281 int pll
, mclk
, gtb_memsize
;
3282 #if defined(CONFIG_PPC)
3287 info
->aty_cmap_regs
= (struct aty_cmap_regs
*)(info
->ati_regbase
+0xc0);
3288 chip_id
= aty_ld_le32(CONFIG_CHIP_ID
, info
);
3289 Gx
= chip_id
& CFG_CHIP_TYPE
;
3290 Rev
= (chip_id
& CFG_CHIP_REV
)>>24;
3291 for (j
= 0; j
< (sizeof(aty_features
)/sizeof(*aty_features
)); j
++)
3292 if (aty_features
[j
].chip_type
== Gx
) {
3293 chipname
= aty_features
[j
].name
;
3294 info
->dac_type
= (aty_ld_le32(DAC_CNTL
, info
) >> 16) & 0x07;
3298 printk("atyfb: Unknown mach64 0x%04x\n", Gx
);
3301 printk("atyfb: %s [0x%04x rev 0x%02x] ", chipname
, Gx
, Rev
);
3302 if ((Gx
== GX_CHIP_ID
) || (Gx
== CX_CHIP_ID
)) {
3303 info
->bus_type
= (aty_ld_le32(CONFIG_STAT0
, info
) >> 0) & 0x07;
3304 info
->ram_type
= (aty_ld_le32(CONFIG_STAT0
, info
) >> 3) & 0x07;
3305 ramname
= aty_gx_ram
[info
->ram_type
];
3306 /* FIXME: clockchip/RAMDAC probing? */
3308 info
->clk_type
= CLK_ATI18818_1
;
3309 info
->dac_type
= (aty_ld_le32(CONFIG_STAT0
, info
) >> 9) & 0x07;
3310 if (info
->dac_type
== 0x07)
3311 info
->dac_subtype
= DAC_ATT20C408
;
3313 info
->dac_subtype
= (aty_ld_8(SCRATCH_REG1
+ 1, info
) & 0xF0) |
3316 info
->dac_type
= DAC_IBMRGB514
;
3317 info
->dac_subtype
= DAC_IBMRGB514
;
3318 info
->clk_type
= CLK_IBMRGB514
;
3324 info
->bus_type
= PCI
;
3325 info
->ram_type
= (aty_ld_le32(CONFIG_STAT0
, info
) & 0x07);
3326 ramname
= aty_ct_ram
[info
->ram_type
];
3327 info
->dac_type
= DAC_INTERNAL
;
3328 info
->dac_subtype
= DAC_INTERNAL
;
3329 info
->clk_type
= CLK_INTERNAL
;
3330 if ((Gx
== CT_CHIP_ID
) || (Gx
== ET_CHIP_ID
)) {
3334 mclk
= info
->ram_type
>= SDRAM
? 67 : 63;
3335 if ((Gx
== VT_CHIP_ID
) && (Rev
== 0x08)) {
3338 } else if (((Gx
== VT_CHIP_ID
) && ((Rev
== 0x40) ||
3340 ((Gx
== VT_CHIP_ID
) && ((Rev
== 0x01) ||
3345 } else if (Gx
== VV_CHIP_ID
) {
3349 } else if (Gx
== VT_CHIP_ID
) {
3353 } else if ((Gx
== GT_CHIP_ID
) && (Rev
& 0x01)) {
3356 } else if (((Gx
== GT_CHIP_ID
) && (Rev
& 0x02)) ||
3357 (Gx
== GU_CHIP_ID
)) {
3360 } else if (Gx
== GV_CHIP_ID
|| Gx
== GW_CHIP_ID
||
3365 } else if (Gx
== GB_CHIP_ID
|| Gx
== GD_CHIP_ID
||
3366 Gx
== GI_CHIP_ID
|| Gx
== GP_CHIP_ID
||
3367 Gx
== GQ_CHIP_ID
|| Gx
== LB_CHIP_ID
||
3369 Gx
== LI_CHIP_ID
|| Gx
== LP_CHIP_ID
) {
3370 /* RAGE PRO or LT PRO */
3373 } else if (Gx
== LG_CHIP_ID
) {
3385 info
->ref_clk_per
= 1000000000000ULL/14318180;
3387 if (!(Gx
== GX_CHIP_ID
|| Gx
== CX_CHIP_ID
|| Gx
== CT_CHIP_ID
||
3389 ((Gx
== VT_CHIP_ID
|| Gx
== GT_CHIP_ID
) && !(Rev
& 0x07))) &&
3390 (pll_ref_div
= aty_ld_pll(PLL_REF_DIV
, info
))) {
3392 diff1
= 510*14/pll_ref_div
-pll
;
3393 diff2
= 510*29/pll_ref_div
-pll
;
3398 if (diff2
< diff1
) {
3399 info
->ref_clk_per
= 1000000000000ULL/29498928;
3404 i
= aty_ld_le32(MEM_CNTL
, info
);
3405 gtb_memsize
= !(Gx
== GX_CHIP_ID
|| Gx
== CX_CHIP_ID
|| Gx
== CT_CHIP_ID
||
3407 ((Gx
== VT_CHIP_ID
|| Gx
== GT_CHIP_ID
) && !(Rev
& 0x07)));
3409 switch (i
& 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
3411 info
->total_vram
= 0x80000;
3414 info
->total_vram
= 0x100000;
3416 case MEM_SIZE_2M_GTB
:
3417 info
->total_vram
= 0x200000;
3419 case MEM_SIZE_4M_GTB
:
3420 info
->total_vram
= 0x400000;
3422 case MEM_SIZE_6M_GTB
:
3423 info
->total_vram
= 0x600000;
3425 case MEM_SIZE_8M_GTB
:
3426 info
->total_vram
= 0x800000;
3429 info
->total_vram
= 0x80000;
3432 switch (i
& MEM_SIZE_ALIAS
) {
3434 info
->total_vram
= 0x80000;
3437 info
->total_vram
= 0x100000;
3440 info
->total_vram
= 0x200000;
3443 info
->total_vram
= 0x400000;
3446 info
->total_vram
= 0x600000;
3449 info
->total_vram
= 0x800000;
3452 info
->total_vram
= 0x80000;
3455 if (Gx
== GI_CHIP_ID
) {
3456 if (aty_ld_le32(CONFIG_STAT1
, info
) & 0x40000000)
3457 info
->total_vram
+= 0x400000;
3461 info
->total_vram
= default_vram
*1024;
3462 i
= i
& ~(gtb_memsize
? 0xF : MEM_SIZE_ALIAS
);
3463 if (info
->total_vram
<= 0x80000)
3465 else if (info
->total_vram
<= 0x100000)
3467 else if (info
->total_vram
<= 0x200000)
3468 i
|= gtb_memsize
? MEM_SIZE_2M_GTB
: MEM_SIZE_2M
;
3469 else if (info
->total_vram
<= 0x400000)
3470 i
|= gtb_memsize
? MEM_SIZE_4M_GTB
: MEM_SIZE_4M
;
3471 else if (info
->total_vram
<= 0x600000)
3472 i
|= gtb_memsize
? MEM_SIZE_6M_GTB
: MEM_SIZE_6M
;
3474 i
|= gtb_memsize
? MEM_SIZE_8M_GTB
: MEM_SIZE_8M
;
3475 aty_st_le32(MEM_CNTL
, i
, info
);
3480 mclk
= default_mclk
;
3482 printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n",
3483 info
->total_vram
== 0x80000 ? 512 : (info
->total_vram
>> 20),
3484 info
->total_vram
== 0x80000 ? 'K' : 'M', ramname
, xtal
, pll
, mclk
);
3487 info
->mem_refresh_rate
= 0; /* 000 = 10 Mhz - 43 Mhz */
3489 info
->mem_refresh_rate
= 1; /* 001 = 44 Mhz - 49 Mhz */
3491 info
->mem_refresh_rate
= 2; /* 010 = 50 Mhz - 54 Mhz */
3493 info
->mem_refresh_rate
= 3; /* 011 = 55 Mhz - 65 Mhz */
3495 info
->mem_refresh_rate
= 4; /* 100 = 66 Mhz - 74 Mhz */
3497 info
->mem_refresh_rate
= 5; /* 101 = 75 Mhz - 79 Mhz */
3498 else if (mclk
< 100)
3499 info
->mem_refresh_rate
= 6; /* 110 = 80 Mhz - 100 Mhz */
3501 info
->mem_refresh_rate
= 7; /* 111 = 100 Mhz and above */
3502 info
->pll_per
= 1000000/pll
;
3503 info
->mclk_per
= 1000000/mclk
;
3506 if ((Gx
!= GX_CHIP_ID
) && (Gx
!= CX_CHIP_ID
)) {
3508 printk("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL "
3509 "DSP_CONFIG DSP_ON_OFF\n"
3510 "%08x %08x %08x %08x %08x %08x %08x\n"
3512 aty_ld_le32(BUS_CNTL
, info
), aty_ld_le32(DAC_CNTL
, info
),
3513 aty_ld_le32(MEM_CNTL
, info
), aty_ld_le32(EXT_MEM_CNTL
, info
),
3514 aty_ld_le32(CRTC_GEN_CNTL
, info
), aty_ld_le32(DSP_CONFIG
, info
),
3515 aty_ld_le32(DSP_ON_OFF
, info
));
3516 for (i
= 0; i
< 16; i
++)
3517 printk(" %02x", aty_ld_pll(i
, info
));
3523 * Last page of 8 MB (4 MB on ISA) aperture is MMIO
3524 * FIXME: we should use the auxiliary aperture instead so we can acces the
3525 * full 8 MB of video RAM on 8 MB boards
3527 if (info
->total_vram
== 0x800000 ||
3528 (info
->bus_type
== ISA
&& info
->total_vram
== 0x400000))
3529 info
->total_vram
-= GUI_RESERVE
;
3531 /* Clear the video memory */
3532 fb_memset((void *)info
->frame_buffer
, 0, info
->total_vram
);
3536 strcpy(info
->fb_info
.modename
, atyfb_name
);
3537 info
->fb_info
.node
= -1;
3538 info
->fb_info
.fbops
= &atyfb_ops
;
3539 info
->fb_info
.disp
= disp
;
3540 strcpy(info
->fb_info
.fontname
, fontname
);
3541 info
->fb_info
.changevar
= NULL
;
3542 info
->fb_info
.switch_con
= &atyfbcon_switch
;
3543 info
->fb_info
.updatevar
= &atyfbcon_updatevar
;
3544 info
->fb_info
.blank
= &atyfbcon_blank
;
3545 info
->fb_info
.flags
= FBINFO_FLAG_DEFAULT
;
3548 if (Gx
== LI_CHIP_ID
&& machine_is_compatible("PowerBook1,1")) {
3549 /* these bits let the 101 powerbook wake up from sleep -- paulus */
3550 aty_st_lcd(LCD_POWER_MANAGEMENT
, aty_ld_lcd(LCD_POWER_MANAGEMENT
, info
)
3551 | (USE_F32KHZ
| TRISTATE_MEM_EN
), info
);
3553 #endif /* CONFIG_PPC */
3558 memset(&var
, 0, sizeof(var
));
3560 if (_machine
== _MACH_Pmac
) {
3562 * FIXME: The NVRAM stuff should be put in a Mac-specific file, as it
3563 * applies to all Mac video cards
3566 if (!mac_find_mode(&var
, &info
->fb_info
, mode_option
, 8))
3570 if (default_vmode
== VMODE_NVRAM
) {
3571 default_vmode
= nvram_read_byte(NV_VMODE
);
3572 if (default_vmode
<= 0 || default_vmode
> VMODE_MAX
)
3573 default_vmode
= VMODE_CHOOSE
;
3576 if (default_vmode
== VMODE_CHOOSE
) {
3577 if (Gx
== LG_CHIP_ID
|| Gx
== LI_CHIP_ID
)
3578 /* G3 PowerBook with 1024x768 LCD */
3579 default_vmode
= VMODE_1024_768_60
;
3580 else if (machine_is_compatible("iMac"))
3581 default_vmode
= VMODE_1024_768_75
;
3583 default_vmode
= VMODE_640_480_67
;
3584 sense
= read_aty_sense(info
);
3585 printk(KERN_INFO
"atyfb: monitor sense=%x, mode %d\n",
3586 sense
, mac_map_monitor_sense(sense
));
3588 if (default_vmode
<= 0 || default_vmode
> VMODE_MAX
)
3589 default_vmode
= VMODE_640_480_60
;
3591 if (default_cmode
== CMODE_NVRAM
)
3592 default_cmode
= nvram_read_byte(NV_CMODE
);
3594 if (default_cmode
< CMODE_8
|| default_cmode
> CMODE_32
)
3595 default_cmode
= CMODE_8
;
3596 if (mac_vmode_to_var(default_vmode
, default_cmode
, &var
))
3600 else if (!fb_find_mode(&var
, &info
->fb_info
, mode_option
, NULL
, 0, NULL
, 8))
3602 #else /* !CONFIG_PPC */
3605 if (!fb_find_mode(&var
, &info
->fb_info
, mode_option
, NULL
, 0, NULL
, 8))
3610 if (!fb_find_mode(&var
, &info
->fb_info
, mode_option
, NULL
, 0, NULL
, 8))
3612 #endif /* !__sparc__ */
3613 #endif /* !CONFIG_PPC */
3614 #endif /* !MODULE */
3616 var
.accel_flags
&= ~FB_ACCELF_TEXT
;
3618 var
.accel_flags
|= FB_ACCELF_TEXT
;
3620 if (var
.yres
== var
.yres_virtual
) {
3621 u32 vram
= (info
->total_vram
- (PAGE_SIZE
<< 2));
3622 var
.yres_virtual
= ((vram
* 8) / var
.bits_per_pixel
) / var
.xres_virtual
;
3623 if (var
.yres_virtual
< var
.yres
)
3624 var
.yres_virtual
= var
.yres
;
3627 if (atyfb_decode_var(&var
, &info
->default_par
, info
)) {
3628 printk("atyfb: can't set default video mode\n");
3633 atyfb_save_palette(&info
->fb_info
, 0);
3635 for (j
= 0; j
< 16; j
++) {
3637 info
->palette
[j
].red
= default_red
[k
];
3638 info
->palette
[j
].green
= default_grn
[k
];
3639 info
->palette
[j
].blue
= default_blu
[k
];
3642 if (Gx
!= GX_CHIP_ID
&& Gx
!= CX_CHIP_ID
) {
3643 info
->cursor
= aty_init_cursor(info
);
3645 info
->dispsw
.cursor
= atyfb_cursor
;
3646 info
->dispsw
.set_font
= atyfb_set_font
;
3650 atyfb_set_var(&var
, -1, &info
->fb_info
);
3652 if (register_framebuffer(&info
->fb_info
) < 0)
3655 info
->next
= fb_list
;
3658 printk("fb%d: %s frame buffer device on %s\n",
3659 GET_FB_IDX(info
->fb_info
.node
), atyfb_name
, name
);
3663 int __init
atyfb_init(void)
3665 #if defined(CONFIG_PCI)
3666 struct pci_dev
*pdev
= NULL
;
3667 struct fb_info_aty
*info
;
3668 unsigned long addr
, res_start
, res_size
;
3671 extern void (*prom_palette
) (int);
3672 extern int con_is_present(void);
3673 struct pcidev_cookie
*pcp
;
3678 /* Do not attach when we have a serial console. */
3679 if (!con_is_present())
3685 while ((pdev
= pci_find_device(PCI_VENDOR_ID_ATI
, PCI_ANY_ID
, pdev
))) {
3686 if ((pdev
->class >> 16) == PCI_BASE_CLASS_DISPLAY
) {
3687 struct resource
*rp
;
3689 for (i
= sizeof(aty_features
)/sizeof(*aty_features
)-1; i
>= 0; i
--)
3690 if (pdev
->device
== aty_features
[i
].pci_id
)
3695 info
= kmalloc(sizeof(struct fb_info_aty
), GFP_ATOMIC
);
3697 printk("atyfb_init: can't alloc fb_info_aty\n");
3700 memset(info
, 0, sizeof(struct fb_info_aty
));
3702 rp
= &pdev
->resource
[0];
3703 if (rp
->flags
& IORESOURCE_IO
)
3704 rp
= &pdev
->resource
[1];
3709 res_start
= rp
->start
;
3710 res_size
= rp
->end
-rp
->start
+1;
3711 if (!request_mem_region(res_start
, res_size
, "atyfb"))
3716 * Map memory-mapped registers.
3718 info
->ati_regbase
= addr
+ 0x7ffc00UL
;
3719 info
->ati_regbase_phys
= addr
+ 0x7ffc00UL
;
3722 * Map in big-endian aperture.
3724 info
->frame_buffer
= (unsigned long) addr
+ 0x800000UL
;
3725 info
->frame_buffer_phys
= addr
+ 0x800000UL
;
3728 * Figure mmap addresses from PCI config space.
3729 * Split Framebuffer in big- and little-endian halfs.
3731 for (i
= 0; i
< 6 && pdev
->resource
[i
].start
; i
++)
3735 info
->mmap_map
= kmalloc(j
* sizeof(*info
->mmap_map
), GFP_ATOMIC
);
3736 if (!info
->mmap_map
) {
3737 printk("atyfb_init: can't alloc mmap_map\n");
3739 release_mem_region(res_start
, res_size
);
3742 memset(info
->mmap_map
, 0, j
* sizeof(*info
->mmap_map
));
3744 for (i
= 0, j
= 2; i
< 6 && pdev
->resource
[i
].start
; i
++) {
3745 struct resource
*rp
= &pdev
->resource
[i
];
3746 int io
, breg
= PCI_BASE_ADDRESS_0
+ (i
<< 2);
3752 io
= (rp
->flags
& IORESOURCE_IO
);
3754 size
= rp
->end
- base
+ 1;
3756 pci_read_config_dword(pdev
, breg
, &pbase
);
3762 * Map the framebuffer a second time, this time without
3763 * the braindead _PAGE_IE setting. This is used by the
3764 * fixed Xserver, but we need to maintain the old mapping
3765 * to stay compatible with older ones...
3768 info
->mmap_map
[j
].voff
= (pbase
+ 0x10000000) & PAGE_MASK
;
3769 info
->mmap_map
[j
].poff
= base
& PAGE_MASK
;
3770 info
->mmap_map
[j
].size
= (size
+ ~PAGE_MASK
) & PAGE_MASK
;
3771 info
->mmap_map
[j
].prot_mask
= _PAGE_CACHE
;
3772 info
->mmap_map
[j
].prot_flag
= _PAGE_E
;
3777 * Here comes the old framebuffer mapping with _PAGE_IE
3778 * set for the big endian half of the framebuffer...
3781 info
->mmap_map
[j
].voff
= (pbase
+ 0x800000) & PAGE_MASK
;
3782 info
->mmap_map
[j
].poff
= (base
+0x800000) & PAGE_MASK
;
3783 info
->mmap_map
[j
].size
= 0x800000;
3784 info
->mmap_map
[j
].prot_mask
= _PAGE_CACHE
;
3785 info
->mmap_map
[j
].prot_flag
= _PAGE_E
|_PAGE_IE
;
3790 info
->mmap_map
[j
].voff
= pbase
& PAGE_MASK
;
3791 info
->mmap_map
[j
].poff
= base
& PAGE_MASK
;
3792 info
->mmap_map
[j
].size
= (size
+ ~PAGE_MASK
) & PAGE_MASK
;
3793 info
->mmap_map
[j
].prot_mask
= _PAGE_CACHE
;
3794 info
->mmap_map
[j
].prot_flag
= _PAGE_E
;
3799 * Fix PROMs idea of MEM_CNTL settings...
3801 mem
= aty_ld_le32(MEM_CNTL
, info
);
3802 chip_id
= aty_ld_le32(CONFIG_CHIP_ID
, info
);
3803 if (((chip_id
& CFG_CHIP_TYPE
) == VT_CHIP_ID
) &&
3804 !((chip_id
>> 24) & 1)) {
3805 switch (mem
& 0x0f) {
3807 mem
= (mem
& ~(0x0f)) | 2;
3810 mem
= (mem
& ~(0x0f)) | 3;
3813 mem
= (mem
& ~(0x0f)) | 4;
3816 mem
= (mem
& ~(0x0f)) | 5;
3821 if ((aty_ld_le32(CONFIG_STAT0
, info
) & 7) >= SDRAM
)
3822 mem
&= ~(0x00700000);
3824 mem
&= ~(0xcf80e000); /* Turn off all undocumented bits. */
3825 aty_st_le32(MEM_CNTL
, mem
, info
);
3828 * If this is the console device, we will set default video
3829 * settings to what the PROM left us with.
3831 node
= prom_getchild(prom_root_node
);
3832 node
= prom_searchsiblings(node
, "aliases");
3834 len
= prom_getproperty(node
, "screen", prop
, sizeof(prop
));
3837 node
= prom_finddevice(prop
);
3843 pcp
= pdev
->sysdata
;
3844 if (node
== pcp
->prom_node
) {
3846 struct fb_var_screeninfo
*var
= &default_var
;
3847 unsigned int N
, P
, Q
, M
, T
;
3848 u32 v_total
, h_total
;
3853 crtc
.vxres
= prom_getintdefault(node
, "width", 1024);
3854 crtc
.vyres
= prom_getintdefault(node
, "height", 768);
3855 crtc
.bpp
= prom_getintdefault(node
, "depth", 8);
3856 crtc
.xoffset
= crtc
.yoffset
= 0;
3857 crtc
.h_tot_disp
= aty_ld_le32(CRTC_H_TOTAL_DISP
, info
);
3858 crtc
.h_sync_strt_wid
= aty_ld_le32(CRTC_H_SYNC_STRT_WID
, info
);
3859 crtc
.v_tot_disp
= aty_ld_le32(CRTC_V_TOTAL_DISP
, info
);
3860 crtc
.v_sync_strt_wid
= aty_ld_le32(CRTC_V_SYNC_STRT_WID
, info
);
3861 crtc
.gen_cntl
= aty_ld_le32(CRTC_GEN_CNTL
, info
);
3862 aty_crtc_to_var(&crtc
, var
);
3864 h_total
= var
->xres
+ var
->right_margin
+
3865 var
->hsync_len
+ var
->left_margin
;
3866 v_total
= var
->yres
+ var
->lower_margin
+
3867 var
->vsync_len
+ var
->upper_margin
;
3870 * Read the PLL to figure actual Refresh Rate.
3872 clock_cntl
= aty_ld_8(CLOCK_CNTL
, info
);
3873 /* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */
3874 for (i
= 0; i
< 16; i
++)
3875 pll_regs
[i
] = aty_ld_pll(i
, info
);
3878 * PLL Reference Devider M:
3883 * PLL Feedback Devider N (Dependant on CLOCK_CNTL):
3885 N
= pll_regs
[7 + (clock_cntl
& 3)];
3888 * PLL Post Devider P (Dependant on CLOCK_CNTL):
3890 P
= 1 << (pll_regs
[6] >> ((clock_cntl
& 3) << 1));
3904 * where R is XTALIN (= 14318 kHz).
3906 T
= 2 * Q
* 14318 / M
;
3908 default_var
.pixclock
= 1000000000 / T
;
3911 #else /* __sparc__ */
3913 info
->ati_regbase_phys
= 0x7ff000 + addr
;
3914 info
->ati_regbase
= (unsigned long)
3915 ioremap(info
->ati_regbase_phys
, 0x1000);
3917 if(!info
->ati_regbase
) {
3919 release_mem_region(res_start
, res_size
);
3923 info
->ati_regbase_phys
+= 0xc00;
3924 info
->ati_regbase
+= 0xc00;
3927 * Enable memory-space accesses using config-space
3930 pci_read_config_word(pdev
, PCI_COMMAND
, &tmp
);
3931 if (!(tmp
& PCI_COMMAND_MEMORY
)) {
3932 tmp
|= PCI_COMMAND_MEMORY
;
3933 pci_write_config_word(pdev
, PCI_COMMAND
, tmp
);
3937 /* Use the big-endian aperture */
3941 /* Map in frame buffer */
3942 info
->frame_buffer_phys
= addr
;
3943 info
->frame_buffer
= (unsigned long)ioremap(addr
, 0x800000);
3945 if(!info
->frame_buffer
) {
3947 release_mem_region(res_start
, res_size
);
3951 #endif /* __sparc__ */
3953 if (!aty_init(info
, "PCI")) {
3955 kfree(info
->mmap_map
);
3957 release_mem_region(res_start
, res_size
);
3963 prom_palette
= atyfb_palette
;
3966 * Add /dev/fb mmap values.
3968 info
->mmap_map
[0].voff
= 0x8000000000000000UL
;
3969 info
->mmap_map
[0].poff
= info
->frame_buffer
& PAGE_MASK
;
3970 info
->mmap_map
[0].size
= info
->total_vram
;
3971 info
->mmap_map
[0].prot_mask
= _PAGE_CACHE
;
3972 info
->mmap_map
[0].prot_flag
= _PAGE_E
;
3973 info
->mmap_map
[1].voff
= info
->mmap_map
[0].voff
+ info
->total_vram
;
3974 info
->mmap_map
[1].poff
= info
->ati_regbase
& PAGE_MASK
;
3975 info
->mmap_map
[1].size
= PAGE_SIZE
;
3976 info
->mmap_map
[1].prot_mask
= _PAGE_CACHE
;
3977 info
->mmap_map
[1].prot_flag
= _PAGE_E
;
3978 #endif /* __sparc__ */
3980 #ifdef CONFIG_PMAC_PBOOK
3981 if (first_display
== NULL
)
3982 pmu_register_sleep_notifier(&aty_sleep_notifier
);
3983 info
->next
= first_display
;
3984 first_display
= info
;
3987 #ifdef CONFIG_FB_COMPAT_XPMAC
3988 if (!console_fb_info
)
3989 console_fb_info
= &info
->fb_info
;
3990 #endif /* CONFIG_FB_COMPAT_XPMAC */
3994 #elif defined(CONFIG_ATARI)
3997 struct fb_info_aty
*info
;
3999 for (m64_num
= 0; m64_num
< mach64_count
; m64_num
++) {
4000 if (!phys_vmembase
[m64_num
] || !phys_size
[m64_num
] ||
4001 !phys_guiregbase
[m64_num
]) {
4002 printk(" phys_*[%d] parameters not set => returning early. \n",
4007 info
= kmalloc(sizeof(struct fb_info_aty
), GFP_ATOMIC
);
4009 printk("atyfb_init: can't alloc fb_info_aty\n");
4012 memset(info
, 0, sizeof(struct fb_info_aty
));
4015 * Map the video memory (physical address given) to somewhere in the
4016 * kernel address space.
4018 info
->frame_buffer
= ioremap(phys_vmembase
[m64_num
], phys_size
[m64_num
]);
4019 info
->frame_buffer_phys
= info
->frame_buffer
; /* Fake! */
4020 info
->ati_regbase
= ioremap(phys_guiregbase
[m64_num
], 0x10000)+0xFC00ul
;
4021 info
->ati_regbase_phys
= info
->ati_regbase
; /* Fake! */
4023 aty_st_le32(CLOCK_CNTL
, 0x12345678, info
);
4024 clock_r
= aty_ld_le32(CLOCK_CNTL
, info
);
4026 switch (clock_r
& 0x003F) {
4028 info
->clk_wr_offset
= 3; /* */
4031 info
->clk_wr_offset
= 2; /* Medusa ST-IO ISA Adapter etc. */
4034 info
->clk_wr_offset
= 1; /* */
4037 info
->clk_wr_offset
= 0; /* Panther 1 ISA Adapter (Gerald) */
4041 if (!aty_init(info
, "ISA bus")) {
4043 /* This is insufficient! kernel_map has added two large chunks!! */
4047 #endif /* CONFIG_ATARI */
4052 int __init
atyfb_setup(char *options
)
4056 if (!options
|| !*options
)
4059 for (this_opt
= strtok(options
, ","); this_opt
;
4060 this_opt
= strtok(NULL
, ",")) {
4061 if (!strncmp(this_opt
, "font:", 5)) {
4066 for (i
= 0; i
< sizeof(fontname
) - 1; i
++)
4067 if (!*p
|| *p
== ' ' || *p
== ',')
4069 memcpy(fontname
, this_opt
+ 5, i
);
4071 } else if (!strncmp(this_opt
, "noblink", 7)) {
4073 } else if (!strncmp(this_opt
, "noaccel", 7)) {
4075 } else if (!strncmp(this_opt
, "vram:", 5))
4076 default_vram
= simple_strtoul(this_opt
+5, NULL
, 0);
4077 else if (!strncmp(this_opt
, "pll:", 4))
4078 default_pll
= simple_strtoul(this_opt
+4, NULL
, 0);
4079 else if (!strncmp(this_opt
, "mclk:", 5))
4080 default_mclk
= simple_strtoul(this_opt
+5, NULL
, 0);
4082 else if (!strncmp(this_opt
, "vmode:", 6)) {
4083 unsigned int vmode
= simple_strtoul(this_opt
+6, NULL
, 0);
4084 if (vmode
> 0 && vmode
<= VMODE_MAX
)
4085 default_vmode
= vmode
;
4086 } else if (!strncmp(this_opt
, "cmode:", 6)) {
4087 unsigned int cmode
= simple_strtoul(this_opt
+6, NULL
, 0);
4091 default_cmode
= CMODE_8
;
4095 default_cmode
= CMODE_16
;
4099 default_cmode
= CMODE_32
;
4106 * Why do we need this silly Mach64 argument?
4107 * We are already here because of mach64= so its redundant.
4109 else if (MACH_IS_ATARI
&& (!strncmp(this_opt
, "Mach64:", 7))) {
4110 static unsigned char m64_num
;
4111 static char mach64_str
[80];
4112 strncpy(mach64_str
, this_opt
+7, 80);
4113 if (!store_video_par(mach64_str
, m64_num
)) {
4115 mach64_count
= m64_num
;
4120 mode_option
= this_opt
;
4124 #endif /* !MODULE */
4127 static int __init
store_video_par(char *video_str
, unsigned char m64_num
)
4130 unsigned long vmembase
, size
, guiregbase
;
4132 printk("store_video_par() '%s' \n", video_str
);
4134 if (!(p
= strtoke(video_str
, ";")) || !*p
)
4135 goto mach64_invalid
;
4136 vmembase
= simple_strtoul(p
, NULL
, 0);
4137 if (!(p
= strtoke(NULL
, ";")) || !*p
)
4138 goto mach64_invalid
;
4139 size
= simple_strtoul(p
, NULL
, 0);
4140 if (!(p
= strtoke(NULL
, ";")) || !*p
)
4141 goto mach64_invalid
;
4142 guiregbase
= simple_strtoul(p
, NULL
, 0);
4144 phys_vmembase
[m64_num
] = vmembase
;
4145 phys_size
[m64_num
] = size
;
4146 phys_guiregbase
[m64_num
] = guiregbase
;
4147 printk(" stored them all: $%08lX $%08lX $%08lX \n", vmembase
, size
,
4152 phys_vmembase
[m64_num
] = 0;
4156 static char __init
*strtoke(char *s
, const char *ct
)
4158 static char *ssave
= NULL
;
4159 char *sbegin
, *send
;
4161 sbegin
= s
? s
: ssave
;
4164 if (*sbegin
== '\0') {
4168 send
= strpbrk(sbegin
, ct
);
4169 if (send
&& *send
!= '\0')
4174 #endif /* CONFIG_ATARI */
4176 static int atyfbcon_switch(int con
, struct fb_info
*fb
)
4178 struct fb_info_aty
*info
= (struct fb_info_aty
*)fb
;
4179 struct atyfb_par par
;
4181 /* Do we have to save the colormap? */
4182 if (fb_display
[currcon
].cmap
.len
)
4183 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, atyfb_getcolreg
, fb
);
4185 /* Erase HW Cursor */
4187 atyfb_cursor(&fb_display
[currcon
], CM_ERASE
,
4188 info
->cursor
->pos
.x
, info
->cursor
->pos
.y
);
4192 atyfb_decode_var(&fb_display
[con
].var
, &par
, info
);
4193 atyfb_set_par(&par
, info
);
4194 atyfb_set_disp(&fb_display
[con
], info
, par
.crtc
.bpp
,
4195 par
.accel_flags
& FB_ACCELF_TEXT
);
4197 /* Install new colormap */
4198 do_install_cmap(con
, fb
);
4200 /* Install hw cursor */
4202 aty_set_cursor_color(info
, cursor_pixel_map
, cursor_color_map
,
4203 cursor_color_map
, cursor_color_map
);
4204 aty_set_cursor_shape(info
);
4210 * Blank the display.
4213 static void atyfbcon_blank(int blank
, struct fb_info
*fb
)
4215 struct fb_info_aty
*info
= (struct fb_info_aty
*)fb
;
4218 #ifdef CONFIG_ADB_PMU
4219 if ((_machine
== _MACH_Pmac
) && blank
)
4220 pmu_enable_backlight(0);
4223 gen_cntl
= aty_ld_8(CRTC_GEN_CNTL
, info
);
4226 case VESA_NO_BLANKING
:
4229 case VESA_VSYNC_SUSPEND
:
4232 case VESA_HSYNC_SUSPEND
:
4235 case VESA_POWERDOWN
:
4240 gen_cntl
&= ~(0x4c);
4241 aty_st_8(CRTC_GEN_CNTL
, gen_cntl
, info
);
4243 #ifdef CONFIG_ADB_PMU
4244 if ((_machine
== _MACH_Pmac
) && !blank
)
4245 pmu_enable_backlight(1);
4251 * Read a single color register and split it into
4252 * colors/transparent. Return != 0 for invalid regno.
4255 static int atyfb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
4256 u_int
*transp
, struct fb_info
*fb
)
4258 struct fb_info_aty
*info
= (struct fb_info_aty
*)fb
;
4262 *red
= (info
->palette
[regno
].red
<<8) | info
->palette
[regno
].red
;
4263 *green
= (info
->palette
[regno
].green
<<8) | info
->palette
[regno
].green
;
4264 *blue
= (info
->palette
[regno
].blue
<<8) | info
->palette
[regno
].blue
;
4271 * Set a single color register. The values supplied are already
4272 * rounded down to the hardware's capabilities (according to the
4273 * entries in the var structure). Return != 0 for invalid regno.
4276 static int atyfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
4277 u_int transp
, struct fb_info
*fb
)
4279 struct fb_info_aty
*info
= (struct fb_info_aty
*)fb
;
4287 info
->palette
[regno
].red
= red
;
4288 info
->palette
[regno
].green
= green
;
4289 info
->palette
[regno
].blue
= blue
;
4290 i
= aty_ld_8(DAC_CNTL
, info
) & 0xfc;
4291 if (Gx
== GT_CHIP_ID
|| Gx
== GU_CHIP_ID
|| Gx
== GV_CHIP_ID
||
4292 Gx
== GW_CHIP_ID
|| Gx
== GZ_CHIP_ID
|| Gx
== LG_CHIP_ID
||
4293 Gx
== GB_CHIP_ID
|| Gx
== GD_CHIP_ID
|| Gx
== GI_CHIP_ID
||
4294 Gx
== GP_CHIP_ID
|| Gx
== GQ_CHIP_ID
|| Gx
== LI_CHIP_ID
)
4295 i
|= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/
4296 aty_st_8(DAC_CNTL
, i
, info
);
4297 aty_st_8(DAC_MASK
, 0xff, info
);
4298 scale
= ((Gx
!= GX_CHIP_ID
) && (Gx
!= CX_CHIP_ID
) &&
4299 (info
->current_par
.crtc
.bpp
== 16)) ? 3 : 0;
4300 writeb(regno
<< scale
, &info
->aty_cmap_regs
->windex
);
4301 writeb(red
, &info
->aty_cmap_regs
->lut
);
4302 writeb(green
, &info
->aty_cmap_regs
->lut
);
4303 writeb(blue
, &info
->aty_cmap_regs
->lut
);
4305 switch (info
->current_par
.crtc
.bpp
) {
4306 #ifdef FBCON_HAS_CFB16
4308 info
->fbcon_cmap
.cfb16
[regno
] = (regno
<< 10) | (regno
<< 5) |
4312 #ifdef FBCON_HAS_CFB24
4314 info
->fbcon_cmap
.cfb24
[regno
] = (regno
<< 16) | (regno
<< 8) |
4318 #ifdef FBCON_HAS_CFB32
4320 i
= (regno
<< 8) | regno
;
4321 info
->fbcon_cmap
.cfb32
[regno
] = (i
<< 16) | i
;
4329 static void do_install_cmap(int con
, struct fb_info
*info
)
4333 if (fb_display
[con
].cmap
.len
)
4334 fb_set_cmap(&fb_display
[con
].cmap
, 1, atyfb_setcolreg
, info
);
4336 int size
= fb_display
[con
].var
.bits_per_pixel
== 16 ? 32 : 256;
4337 fb_set_cmap(fb_default_cmap(size
), 1, atyfb_setcolreg
, info
);
4343 * Accelerated functions
4346 static inline void draw_rect(s16 x
, s16 y
, u16 width
, u16 height
,
4347 struct fb_info_aty
*info
)
4349 /* perform rectangle fill */
4350 wait_for_fifo(2, info
);
4351 aty_st_le32(DST_Y_X
, (x
<< 16) | y
, info
);
4352 aty_st_le32(DST_HEIGHT_WIDTH
, (width
<< 16) | height
, info
);
4353 info
->blitter_may_be_busy
= 1;
4356 static inline void aty_rectcopy(int srcx
, int srcy
, int dstx
, int dsty
,
4357 u_int width
, u_int height
,
4358 struct fb_info_aty
*info
)
4360 u32 direction
= DST_LAST_PEL
;
4363 if (!width
|| !height
)
4366 pitch_value
= info
->current_par
.crtc
.vxres
;
4367 if (info
->current_par
.crtc
.bpp
== 24) {
4368 /* In 24 bpp, the engine is in 8 bpp - this requires that all */
4369 /* horizontal coordinates and widths must be adjusted */
4380 direction
|= DST_Y_TOP_TO_BOTTOM
;
4386 direction
|= DST_X_LEFT_TO_RIGHT
;
4388 wait_for_fifo(4, info
);
4389 aty_st_le32(DP_SRC
, FRGD_SRC_BLIT
, info
);
4390 aty_st_le32(SRC_Y_X
, (srcx
<< 16) | srcy
, info
);
4391 aty_st_le32(SRC_HEIGHT1_WIDTH1
, (width
<< 16) | height
, info
);
4392 aty_st_le32(DST_CNTL
, direction
, info
);
4393 draw_rect(dstx
, dsty
, width
, height
, info
);
4396 static inline void aty_rectfill(int dstx
, int dsty
, u_int width
, u_int height
,
4397 u_int color
, struct fb_info_aty
*info
)
4399 if (!width
|| !height
)
4402 if (info
->current_par
.crtc
.bpp
== 24) {
4403 /* In 24 bpp, the engine is in 8 bpp - this requires that all */
4404 /* horizontal coordinates and widths must be adjusted */
4409 wait_for_fifo(3, info
);
4410 aty_st_le32(DP_FRGD_CLR
, color
, info
);
4411 aty_st_le32(DP_SRC
, BKGD_SRC_BKGD_CLR
| FRGD_SRC_FRGD_CLR
| MONO_SRC_ONE
,
4413 aty_st_le32(DST_CNTL
, DST_LAST_PEL
| DST_Y_TOP_TO_BOTTOM
|
4414 DST_X_LEFT_TO_RIGHT
, info
);
4415 draw_rect(dstx
, dsty
, width
, height
, info
);
4419 * Update the `var' structure (called by fbcon.c)
4422 static int atyfbcon_updatevar(int con
, struct fb_info
*fb
)
4424 struct fb_info_aty
*info
= (struct fb_info_aty
*)fb
;
4425 struct atyfb_par
*par
= &info
->current_par
;
4426 struct display
*p
= &fb_display
[con
];
4427 struct vc_data
*conp
= p
->conp
;
4428 u32 yres
, yoffset
, sy
, height
;
4430 yres
= ((par
->crtc
.v_tot_disp
>> 16) & 0x7ff) + 1;
4431 yoffset
= fb_display
[con
].var
.yoffset
;
4433 sy
= (conp
->vc_rows
+ p
->yscroll
) * fontheight(p
);
4434 height
= yres
- conp
->vc_rows
* fontheight(p
);
4436 if (height
&& (yoffset
+ yres
> sy
)) {
4440 xres
= (((par
->crtc
.h_tot_disp
>> 16) & 0xff) + 1) * 8;
4441 xoffset
= fb_display
[con
].var
.xoffset
;
4444 bgx
= attr_bgcol_ec(p
, conp
);
4448 if (sy
+ height
> par
->crtc
.vyres
) {
4449 wait_for_fifo(1, info
);
4450 aty_st_le32(SC_BOTTOM
, sy
+ height
- 1, info
);
4452 aty_rectfill(xoffset
, sy
, xres
, height
, bgx
, info
);
4455 if (info
->cursor
&& (yoffset
+ yres
<= sy
))
4456 atyfb_cursor(p
, CM_ERASE
, info
->cursor
->pos
.x
, info
->cursor
->pos
.y
);
4458 info
->current_par
.crtc
.yoffset
= yoffset
;
4459 set_off_pitch(&info
->current_par
, info
);
4464 * Text console acceleration
4467 static void fbcon_aty_bmove(struct display
*p
, int sy
, int sx
, int dy
, int dx
,
4468 int height
, int width
)
4471 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4473 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4474 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4479 sy
*= fontheight(p
);
4481 dy
*= fontheight(p
);
4482 width
*= fontwidth(p
);
4483 height
*= fontheight(p
);
4485 aty_rectcopy(sx
, sy
, dx
, dy
, width
, height
,
4486 (struct fb_info_aty
*)p
->fb_info
);
4489 static void fbcon_aty_clear(struct vc_data
*conp
, struct display
*p
, int sy
,
4490 int sx
, int height
, int width
)
4494 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4496 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4497 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4501 bgx
= attr_bgcol_ec(p
, conp
);
4506 sy
*= fontheight(p
);
4507 width
*= fontwidth(p
);
4508 height
*= fontheight(p
);
4510 aty_rectfill(sx
, sy
, width
, height
, bgx
,
4511 (struct fb_info_aty
*)p
->fb_info
);
4514 #ifdef FBCON_HAS_CFB8
4515 static void fbcon_aty8_putc(struct vc_data
*conp
, struct display
*p
, int c
,
4518 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4521 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4522 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4526 if (fb
->blitter_may_be_busy
)
4527 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4528 fbcon_cfb8_putc(conp
, p
, c
, yy
, xx
);
4531 static void fbcon_aty8_putcs(struct vc_data
*conp
, struct display
*p
,
4532 const unsigned short *s
, int count
, int yy
,
4535 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4538 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4539 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4543 if (fb
->blitter_may_be_busy
)
4544 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4545 fbcon_cfb8_putcs(conp
, p
, s
, count
, yy
, xx
);
4548 static void fbcon_aty8_clear_margins(struct vc_data
*conp
, struct display
*p
,
4551 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4554 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4555 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4559 if (fb
->blitter_may_be_busy
)
4560 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4561 fbcon_cfb8_clear_margins(conp
, p
, bottom_only
);
4564 static struct display_switch fbcon_aty8
= {
4565 fbcon_cfb8_setup
, fbcon_aty_bmove
, fbcon_aty_clear
, fbcon_aty8_putc
,
4566 fbcon_aty8_putcs
, fbcon_cfb8_revc
, NULL
, NULL
, fbcon_aty8_clear_margins
,
4567 FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
4571 #ifdef FBCON_HAS_CFB16
4572 static void fbcon_aty16_putc(struct vc_data
*conp
, struct display
*p
, int c
,
4575 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4578 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4579 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4583 if (fb
->blitter_may_be_busy
)
4584 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4585 fbcon_cfb16_putc(conp
, p
, c
, yy
, xx
);
4588 static void fbcon_aty16_putcs(struct vc_data
*conp
, struct display
*p
,
4589 const unsigned short *s
, int count
, int yy
,
4592 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4595 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4596 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4600 if (fb
->blitter_may_be_busy
)
4601 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4602 fbcon_cfb16_putcs(conp
, p
, s
, count
, yy
, xx
);
4605 static void fbcon_aty16_clear_margins(struct vc_data
*conp
, struct display
*p
,
4608 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4611 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4612 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4616 if (fb
->blitter_may_be_busy
)
4617 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4618 fbcon_cfb16_clear_margins(conp
, p
, bottom_only
);
4621 static struct display_switch fbcon_aty16
= {
4622 fbcon_cfb16_setup
, fbcon_aty_bmove
, fbcon_aty_clear
, fbcon_aty16_putc
,
4623 fbcon_aty16_putcs
, fbcon_cfb16_revc
, NULL
, NULL
, fbcon_aty16_clear_margins
,
4624 FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
4628 #ifdef FBCON_HAS_CFB24
4629 static void fbcon_aty24_putc(struct vc_data
*conp
, struct display
*p
, int c
,
4632 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4635 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4636 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4640 if (fb
->blitter_may_be_busy
)
4641 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4642 fbcon_cfb24_putc(conp
, p
, c
, yy
, xx
);
4645 static void fbcon_aty24_putcs(struct vc_data
*conp
, struct display
*p
,
4646 const unsigned short *s
, int count
, int yy
,
4649 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4652 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4653 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4657 if (fb
->blitter_may_be_busy
)
4658 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4659 fbcon_cfb24_putcs(conp
, p
, s
, count
, yy
, xx
);
4662 static void fbcon_aty24_clear_margins(struct vc_data
*conp
, struct display
*p
,
4665 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4668 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4669 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4673 if (fb
->blitter_may_be_busy
)
4674 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4675 fbcon_cfb24_clear_margins(conp
, p
, bottom_only
);
4678 static struct display_switch fbcon_aty24
= {
4679 fbcon_cfb24_setup
, fbcon_aty_bmove
, fbcon_aty_clear
, fbcon_aty24_putc
,
4680 fbcon_aty24_putcs
, fbcon_cfb24_revc
, NULL
, NULL
, fbcon_aty24_clear_margins
,
4681 FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
4685 #ifdef FBCON_HAS_CFB32
4686 static void fbcon_aty32_putc(struct vc_data
*conp
, struct display
*p
, int c
,
4689 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4692 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4693 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4697 if (fb
->blitter_may_be_busy
)
4698 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4699 fbcon_cfb32_putc(conp
, p
, c
, yy
, xx
);
4702 static void fbcon_aty32_putcs(struct vc_data
*conp
, struct display
*p
,
4703 const unsigned short *s
, int count
, int yy
,
4706 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4709 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4710 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4714 if (fb
->blitter_may_be_busy
)
4715 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4716 fbcon_cfb32_putcs(conp
, p
, s
, count
, yy
, xx
);
4719 static void fbcon_aty32_clear_margins(struct vc_data
*conp
, struct display
*p
,
4722 struct fb_info_aty
*fb
= (struct fb_info_aty
*)(p
->fb_info
);
4725 if (fb
->mmaped
&& (!fb
->fb_info
.display_fg
4726 || fb
->fb_info
.display_fg
->vc_num
== fb
->vtconsole
))
4730 if (fb
->blitter_may_be_busy
)
4731 wait_for_idle((struct fb_info_aty
*)p
->fb_info
);
4732 fbcon_cfb32_clear_margins(conp
, p
, bottom_only
);
4735 static struct display_switch fbcon_aty32
= {
4736 fbcon_cfb32_setup
, fbcon_aty_bmove
, fbcon_aty_clear
, fbcon_aty32_putc
,
4737 fbcon_aty32_putcs
, fbcon_cfb32_revc
, NULL
, NULL
, fbcon_aty32_clear_margins
,
4738 FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
4742 #ifdef CONFIG_PMAC_PBOOK
4744 /* Power management routines. Those are used for PowerBook sleep.
4746 * It appears that Rage LT and Rage LT Pro have different power
4747 * management registers. There's is some confusion about which
4748 * chipID is a Rage LT or LT pro :(
4751 aty_power_mgmt_LT(int sleep
, struct fb_info_aty
*info
)
4756 pm
= aty_ld_le32(POWER_MANAGEMENT_LG
, info
);
4757 pm
= (pm
& ~PWR_MGT_MODE_MASK
) | PWR_MGT_MODE_REG
;
4758 aty_st_le32(POWER_MANAGEMENT_LG
, pm
, info
);
4759 pm
= aty_ld_le32(POWER_MANAGEMENT_LG
, info
);
4765 aty_st_le32(POWER_MANAGEMENT_LG
, pm
, info
);
4766 pm
= aty_ld_le32(POWER_MANAGEMENT_LG
, info
);
4768 pm
&= ~(PWR_BLON
| AUTO_PWR_UP
);
4770 aty_st_le32(POWER_MANAGEMENT_LG
, pm
, info
);
4771 pm
= aty_ld_le32(POWER_MANAGEMENT_LG
, info
);
4774 aty_st_le32(POWER_MANAGEMENT_LG
, pm
, info
);
4776 pm
= aty_ld_le32(POWER_MANAGEMENT_LG
, info
);
4778 if ((--timeout
) == 0)
4780 } while ((pm
& PWR_MGT_STATUS_MASK
) != PWR_MGT_STATUS_SUSPEND
);
4784 aty_st_le32(POWER_MANAGEMENT_LG
, pm
, info
);
4785 pm
= aty_ld_le32(POWER_MANAGEMENT_LG
, info
);
4787 pm
|= (PWR_BLON
| AUTO_PWR_UP
);
4789 aty_st_le32(POWER_MANAGEMENT_LG
, pm
, info
);
4790 pm
= aty_ld_le32(POWER_MANAGEMENT_LG
, info
);
4793 aty_st_le32(POWER_MANAGEMENT_LG
, pm
, info
);
4795 pm
= aty_ld_le32(POWER_MANAGEMENT_LG
, info
);
4797 if ((--timeout
) == 0)
4799 } while ((pm
& PWR_MGT_STATUS_MASK
) != 0);
4803 return timeout
? PBOOK_SLEEP_OK
: PBOOK_SLEEP_REFUSE
;
4807 aty_power_mgmt_LTPro(int sleep
, struct fb_info_aty
*info
)
4812 pm
= aty_ld_lcd(LCD_POWER_MANAGEMENT
, info
);
4813 pm
= (pm
& ~PWR_MGT_MODE_MASK
) | PWR_MGT_MODE_REG
;
4814 aty_st_lcd(LCD_POWER_MANAGEMENT
, pm
, info
);
4815 pm
= aty_ld_lcd(LCD_POWER_MANAGEMENT
, info
);
4821 aty_st_lcd(LCD_POWER_MANAGEMENT
, pm
, info
);
4822 pm
= aty_ld_lcd(LCD_POWER_MANAGEMENT
, info
);
4824 pm
&= ~(PWR_BLON
| AUTO_PWR_UP
);
4826 aty_st_lcd(LCD_POWER_MANAGEMENT
, pm
, info
);
4827 pm
= aty_ld_lcd(LCD_POWER_MANAGEMENT
, info
);
4830 aty_st_lcd(LCD_POWER_MANAGEMENT
, pm
, info
);
4832 pm
= aty_ld_lcd(LCD_POWER_MANAGEMENT
, info
);
4834 if ((--timeout
) == 0)
4836 } while ((pm
& PWR_MGT_STATUS_MASK
) != PWR_MGT_STATUS_SUSPEND
);
4840 aty_st_lcd(LCD_POWER_MANAGEMENT
, pm
, info
);
4841 pm
= aty_ld_lcd(LCD_POWER_MANAGEMENT
, info
);
4844 pm
|= (PWR_BLON
| AUTO_PWR_UP
);
4845 aty_st_lcd(LCD_POWER_MANAGEMENT
, pm
, info
);
4846 pm
= aty_ld_lcd(LCD_POWER_MANAGEMENT
, info
);
4849 aty_st_lcd(LCD_POWER_MANAGEMENT
, pm
, info
);
4851 pm
= aty_ld_lcd(LCD_POWER_MANAGEMENT
, info
);
4853 if ((--timeout
) == 0)
4855 } while ((pm
& PWR_MGT_STATUS_MASK
) != 0);
4858 return timeout
? PBOOK_SLEEP_OK
: PBOOK_SLEEP_REFUSE
;
4862 * Save the contents of the frame buffer when we go to sleep,
4863 * and restore it when we wake up again.
4866 aty_sleep_notify(struct pmu_sleep_notifier
*self
, int when
)
4868 struct fb_info_aty
*info
;
4871 result
= PBOOK_SLEEP_OK
;
4873 for (info
= first_display
; info
!= NULL
; info
= info
->next
) {
4874 struct fb_fix_screeninfo fix
;
4877 atyfb_get_fix(&fix
, fg_console
, (struct fb_info
*)info
);
4878 nb
= fb_display
[fg_console
].var
.yres
* fix
.line_length
;
4881 case PBOOK_SLEEP_REQUEST
:
4882 info
->save_framebuffer
= vmalloc(nb
);
4883 if (info
->save_framebuffer
== NULL
)
4884 return PBOOK_SLEEP_REFUSE
;
4886 case PBOOK_SLEEP_REJECT
:
4887 if (info
->save_framebuffer
) {
4888 vfree(info
->save_framebuffer
);
4889 info
->save_framebuffer
= 0;
4892 case PBOOK_SLEEP_NOW
:
4893 if (info
->blitter_may_be_busy
)
4894 wait_for_idle(info
);
4895 /* Stop accel engine (stop bus mastering) */
4896 if (info
->current_par
.accel_flags
& FB_ACCELF_TEXT
)
4899 /* Backup fb content */
4900 if (info
->save_framebuffer
)
4901 memcpy_fromio(info
->save_framebuffer
,
4902 (void *)info
->frame_buffer
, nb
);
4904 /* Blank display and LCD */
4905 atyfbcon_blank(VESA_POWERDOWN
+1, (struct fb_info
*)info
);
4907 /* Set chip to "suspend" mode */
4908 if (Gx
== LG_CHIP_ID
)
4909 result
= aty_power_mgmt_LT(1, info
);
4911 result
= aty_power_mgmt_LTPro(1, info
);
4915 if (Gx
== LG_CHIP_ID
)
4916 result
= aty_power_mgmt_LT(0, info
);
4918 result
= aty_power_mgmt_LTPro(0, info
);
4920 /* Restore fb content */
4921 if (info
->save_framebuffer
) {
4922 memcpy_toio((void *)info
->frame_buffer
,
4923 info
->save_framebuffer
, nb
);
4924 vfree(info
->save_framebuffer
);
4925 info
->save_framebuffer
= 0;
4927 /* Restore display */
4928 atyfb_set_par(&info
->current_par
, info
);
4929 atyfbcon_blank(0, (struct fb_info
*)info
);
4935 #endif /* CONFIG_PMAC_PBOOK */
4938 int __init
init_module(void)
4941 return fb_list
? 0 : -ENXIO
;
4944 void cleanup_module(void)
4947 struct fb_info_aty
*info
= fb_list
;
4948 fb_list
= info
->next
;
4950 unregister_framebuffer(&info
->fb_info
);
4953 if (info
->ati_regbase
)
4954 iounmap((void *)info
->ati_regbase
);
4955 if (info
->frame_buffer
)
4956 iounmap((void *)info
->frame_buffer
);
4958 if (info
->cursor
&& info
->cursor
->ram
)
4959 iounmap(info
->cursor
->ram
);
4964 if (info
->cursor
->timer
)
4965 kfree(info
->cursor
->timer
);
4966 kfree(info
->cursor
);
4970 kfree(info
->mmap_map
);