* [PATCH 3/5] fbdev: Various mach64 changes
@ 2004-10-20 0:15 Antonino A. Daplas
2004-10-22 7:55 ` Andrew Morton
0 siblings, 1 reply; 3+ messages in thread
From: Antonino A. Daplas @ 2004-10-20 0:15 UTC (permalink / raw)
To: Andrew Morton, Linux Fbdev development list
Cc: Alexander Kern, Arnaud FONTAINE, Geert Uytterhoeven,
James Simmons, Nicolas Souchu, Ville Syrjälä
Alexander Kern <alex.kern@gmx.de>
[PATCH] port Daniel Mantione 2.4 driver to 2.6
[PATCH] add more pci_id number
[PATCH] add accelerated imgblit
[PATCH] revert SDRAM_MAGIC_PLL to old behaviour
[PATCH] do a "from BIOS" initialisation only by __i386__
Arnaud FONTAINE <arnaud.fontaine@free.fr>
[PATCH atyfb] correction for 3D Rage Mobility L
Geert Uytterhoeven <geert@linux-m68k.org>
[PATCH atyfb] Atari Atyfb fixes
[PATCH atyfb] Atyfb on Mach64 GX or Atari
[PATCH 468] m68k sparse floating point
James Simmons <jsimmons@infradead.org>
[PATCH add] port to framebuffer_alloc api
Nicolas Souchu <nsouch@free.fr>
[PATCH] I do not found a copy, but it was incorporated too
Ville Syrjälä <syrjala@sci.fi>
[PATCH] fix pan with doublescan
[PATCH] another double scan fix
[PATCH] disable linear aperture register access
[PATCH] Memory type correction
[PATCH] atyfb (2.6): Fix mmio_start
[PATCH] atyfb (2.6): Fix mem_refresh_rate for Mobility
[PATCH] atyfb (2.6): Add RGB565 support
[PATCH] atyfb: Blank LCD by turning off backlight voltage
[PATCH] atyfb: Rage LT LCD register access
[PATCH] atyfb: vblank irq support
[PATCH] atyfb: MTRR support
Signed-off-by: Antonino Daplas <adaplas@pol.net>
---
drivers/video/Kconfig | 19
drivers/video/aty/ati_ids.h | 1
drivers/video/aty/atyfb.h | 207 +-
drivers/video/aty/atyfb_base.c | 3576 ++++++++++++++++++++++++--------------
drivers/video/aty/mach64_accel.c | 212 ++
drivers/video/aty/mach64_ct.c | 731 +++++--
drivers/video/aty/mach64_cursor.c | 309 +--
drivers/video/aty/mach64_gx.c | 20
drivers/video/aty/xlinit.c | 68
include/video/mach64.h | 351 +++
10 files changed, 3680 insertions(+), 1814 deletions(-)
diff -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig
--- a/drivers/video/Kconfig 2004-10-17 14:02:58 +08:00
+++ b/drivers/video/Kconfig 2004-10-07 06:18:18 +08:00
@@ -750,6 +750,19 @@
framebuffer device. The ATI product support page for these boards
is at <http://support.ati.com/products/pc/mach64/>.
+config FB_ATY_GENERIC_LCD
+ bool "Mach64 generic LCD support (EXPERIMENTAL)"
+ depends on FB_ATY_CT
+ help
+ Say Y if you have a laptop with an ATI Rage LT PRO, Rage Mobility,
+ Rage XC, or Rage XL chipset.
+
+config FB_ATY_XL_INIT
+ bool "Rage XL No-BIOS Init support"
+ depends on FB_ATY_CT
+ help
+ Say Y here to support booting a Rage XL without BIOS support.
+
config FB_ATY_GX
bool "Mach64 GX support" if PCI
depends on FB_ATY
@@ -760,12 +773,6 @@
framebuffer device. The ATI product support page for these boards
is at
<http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
-
-config FB_ATY_XL_INIT
- bool " Rage XL No-BIOS Init support" if FB_ATY_CT
- depends on FB_ATY
- help
- Say Y here to support booting a Rage XL without BIOS support.
config FB_SIS
tristate "SiS acceleration"
diff -Nru a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h
--- a/drivers/video/aty/ati_ids.h 2004-10-19 20:22:38 +08:00
+++ b/drivers/video/aty/ati_ids.h 2004-10-07 06:18:18 +08:00
@@ -64,6 +64,7 @@
#define PCI_CHIP_MACH64LQ 0x4C51
#define PCI_CHIP_MACH64LR 0x4C52
#define PCI_CHIP_MACH64LS 0x4C53
+#define PCI_CHIP_MACH64LT 0x4C54
#define PCI_CHIP_RADEON_LW 0x4C57
#define PCI_CHIP_RADEON_LX 0x4C58
#define PCI_CHIP_RADEON_LY 0x4C59
diff -Nru a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
--- a/drivers/video/aty/atyfb.h 2004-10-19 20:22:40 +08:00
+++ b/drivers/video/aty/atyfb.h 2004-10-11 03:43:16 +08:00
@@ -3,6 +3,8 @@
*/
#include <linux/config.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
/*
* Elements of the hardware specific atyfb_par structure
*/
@@ -10,16 +12,60 @@
struct crtc {
u32 vxres;
u32 vyres;
+ u32 xoffset;
+ u32 yoffset;
+ u32 bpp;
u32 h_tot_disp;
u32 h_sync_strt_wid;
u32 v_tot_disp;
u32 v_sync_strt_wid;
+ u32 vline_crnt_vline;
u32 off_pitch;
u32 gen_cntl;
u32 dp_pix_width; /* acceleration */
u32 dp_chain_mask; /* acceleration */
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ u32 horz_stretching;
+ u32 vert_stretching;
+ u32 ext_vert_stretch;
+ u32 shadow_h_tot_disp;
+ u32 shadow_h_sync_strt_wid;
+ u32 shadow_v_tot_disp;
+ u32 shadow_v_sync_strt_wid;
+ u32 lcd_gen_cntl;
+ u32 lcd_config_panel;
+ u32 lcd_index;
+#endif
+};
+
+struct aty_interrupt {
+ wait_queue_head_t wait;
+ unsigned int count;
+ int pan_display;
+};
+
+struct pll_info {
+ int pll_max;
+ int pll_min;
+ int sclk, mclk, mclk_pm, xclk;
+ int ref_div;
+ int ref_clk;
};
+typedef struct {
+ u16 unknown1;
+ u16 PCLK_min_freq;
+ u16 PCLK_max_freq;
+ u16 unknown2;
+ u16 ref_freq;
+ u16 ref_divider;
+ u16 unknown3;
+ u16 MCLK_pwd;
+ u16 MCLK_max_freq;
+ u16 XCLK_max_freq;
+ u16 SCLK_freq;
+} __attribute__ ((packed)) PLL_BLOCK_MACH64;
+
struct pll_514 {
u8 m;
u8 n;
@@ -36,16 +82,39 @@
u8 pll_ref_div;
u8 pll_gen_cntl;
u8 mclk_fb_div;
+ u8 mclk_fb_mult; /* 2 ro 4 */
+/* u8 sclk_fb_div;*/
u8 pll_vclk_cntl;
u8 vclk_post_div;
u8 vclk_fb_div;
u8 pll_ext_cntl;
- u32 dsp_config; /* Mach64 GTB DSP */
- u32 dsp_on_off; /* Mach64 GTB DSP */
+/* u8 ext_vpll_cntl;
+ u8 spll_cntl2;*/
+ u32 dsp_config; /* Mach64 GTB DSP */
+ u32 dsp_on_off; /* Mach64 GTB DSP */
+ u32 dsp_loop_latency;
+ u32 fifo_size;
+ u32 xclkpagefaultdelay;
+ u32 xclkmaxrasdelay;
+ u8 xclk_ref_div;
+ u8 xclk_post_div;
u8 mclk_post_div_real;
+ u8 xclk_post_div_real;
u8 vclk_post_div_real;
+ u8 features;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ u32 xres; /* use for LCD stretching/scaling */
+#endif
};
+/*
+ for pll_ct.features
+*/
+#define DONT_USE_SPLL 0x1
+#define DONT_USE_XDLL 0x2
+#define USE_CPUCLK 0x4
+#define POWERDOWN_PLL 0x8
+
union aty_pll {
struct pll_ct ct;
struct pll_514 ibm514;
@@ -56,42 +125,68 @@
* The hardware parameters for each card
*/
-struct aty_cursor {
- u8 bits[8][64];
- u8 mask[8][64];
- u8 *ram;
-};
-
struct atyfb_par {
struct aty_cmap_regs *aty_cmap_regs;
+ struct { u8 red, green, blue; } palette[256];
const struct aty_dac_ops *dac_ops;
const struct aty_pll_ops *pll_ops;
- struct aty_cursor *cursor;
- unsigned long ati_regbase;
- unsigned long clk_wr_offset;
+ void *ati_regbase;
+ unsigned long clk_wr_offset; /* meaning overloaded, clock id by CT */
struct crtc crtc;
union aty_pll pll;
+ struct pll_info pll_limits;
u32 features;
u32 ref_clk_per;
u32 pll_per;
u32 mclk_per;
+ u32 xclk_per;
u8 bus_type;
u8 ram_type;
u8 mem_refresh_rate;
- u8 blitter_may_be_busy;
+ u16 pci_id;
u32 accel_flags;
+ int blitter_may_be_busy;
+ int asleep;
+ int lock_blank;
+ unsigned long res_start;
+ unsigned long res_size;
#ifdef __sparc__
struct pci_mmap_map *mmap_map;
u8 mmaped;
+#endif
int open;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ unsigned long bios_base_phys;
+ unsigned long bios_base;
+ unsigned long lcd_table;
+ u16 lcd_width;
+ u16 lcd_height;
+ u32 lcd_pixclock;
+ u16 lcd_refreshrate;
+ u16 lcd_htotal;
+ u16 lcd_hdisp;
+ u16 lcd_hsync_dly;
+ u16 lcd_hsync_len;
+ u16 lcd_vtotal;
+ u16 lcd_vdisp;
+ u16 lcd_vsync_len;
+ u16 lcd_right_margin;
+ u16 lcd_lower_margin;
+ u16 lcd_hblank_len;
+ u16 lcd_vblank_len;
#endif
-#ifdef CONFIG_PMAC_PBOOK
- struct fb_info *next;
- unsigned char *save_framebuffer;
- unsigned long save_pll[64];
+ unsigned long aux_start; /* auxiliary aperture */
+ unsigned long aux_size;
+ struct aty_interrupt vblank;
+ unsigned long irq_flags;
+ unsigned int irq;
+ spinlock_t int_lock;
+#ifdef CONFIG_MTRR
+ int mtrr_aper;
+ int mtrr_reg;
#endif
};
-
+
/*
* ATI Mach64 features
*/
@@ -101,7 +196,7 @@
#define M64F_RESET_3D 0x00000001
#define M64F_MAGIC_FIFO 0x00000002
#define M64F_GTB_DSP 0x00000004
-#define M64F_FIFO_24 0x00000008
+#define M64F_FIFO_32 0x00000008
#define M64F_SDRAM_MAGIC_PLL 0x00000010
#define M64F_MAGIC_POSTDIV 0x00000020
#define M64F_INTEGRATED 0x00000040
@@ -116,9 +211,10 @@
#define M64F_G3_PB_1_1 0x00008000
#define M64F_G3_PB_1024x768 0x00010000
#define M64F_EXTRA_BRIGHT 0x00020000
-#define M64F_LT_SLEEP 0x00040000
+#define M64F_LT_LCD_REGS 0x00040000
#define M64F_XL_DLL 0x00080000
-
+#define M64F_MFB_FORCE_4 0x00100000
+#define M64F_HW_TRIPLE 0x00200000
/*
* Register access
@@ -137,8 +233,7 @@
#endif
}
-static inline void aty_st_le32(int regindex, u32 val,
- const struct atyfb_par *par)
+static inline void aty_st_le32(int regindex, u32 val, const struct atyfb_par *par)
{
/* Hack for bloc 1, should be cleanly optimized by compiler */
if (regindex >= 0x400)
@@ -163,8 +258,7 @@
#endif
}
-static inline void aty_st_8(int regindex, u8 val,
- const struct atyfb_par *par)
+static inline void aty_st_8(int regindex, u8 val, const struct atyfb_par *par)
{
/* Hack for bloc 1, should be cleanly optimized by compiler */
if (regindex >= 0x400)
@@ -177,17 +271,10 @@
#endif
}
-static inline u8 aty_ld_pll(int offset, const struct atyfb_par *par)
-{
- u8 res;
-
- /* write addr byte */
- aty_st_8(CLOCK_CNTL + 1, (offset << 2), par);
- /* read the register value */
- res = aty_ld_8(CLOCK_CNTL + 2, par);
- return res;
-}
-
+#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD)
+extern void aty_st_lcd(int index, u32 val, const struct atyfb_par *par);
+extern u32 aty_ld_lcd(int index, const struct atyfb_par *par);
+#endif
/*
* DAC operations
@@ -195,14 +282,14 @@
struct aty_dac_ops {
int (*set_dac) (const struct fb_info * info,
- const union aty_pll * pll, u32 bpp, u32 accel);
+ const union aty_pll * pll, u32 bpp, u32 accel);
};
-extern const struct aty_dac_ops aty_dac_ibm514; /* IBM RGB514 */
-extern const struct aty_dac_ops aty_dac_ati68860b; /* ATI 68860-B */
-extern const struct aty_dac_ops aty_dac_att21c498; /* AT&T 21C498 */
-extern const struct aty_dac_ops aty_dac_unsupported; /* unsupported */
-extern const struct aty_dac_ops aty_dac_ct; /* Integrated */
+extern const struct aty_dac_ops aty_dac_ibm514; /* IBM RGB514 */
+extern const struct aty_dac_ops aty_dac_ati68860b; /* ATI 68860-B */
+extern const struct aty_dac_ops aty_dac_att21c498; /* AT&T 21C498 */
+extern const struct aty_dac_ops aty_dac_unsupported; /* unsupported */
+extern const struct aty_dac_ops aty_dac_ct; /* Integrated */
/*
@@ -210,37 +297,32 @@
*/
struct aty_pll_ops {
- int (*var_to_pll) (const struct fb_info * info, u32 vclk_per,
- u8 bpp, union aty_pll * pll);
- u32(*pll_to_var) (const struct fb_info * info,
- const union aty_pll * pll);
- void (*set_pll) (const struct fb_info * info,
- const union aty_pll * pll);
+ int (*var_to_pll) (const struct fb_info * info, u32 vclk_per, u32 bpp, union aty_pll * pll);
+ u32 (*pll_to_var) (const struct fb_info * info, const union aty_pll * pll);
+ void (*set_pll) (const struct fb_info * info, const union aty_pll * pll);
+ void (*get_pll) (const struct fb_info *info, union aty_pll * pll);
+ int (*init_pll) (const struct fb_info * info, union aty_pll * pll);
};
-extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */
-extern const struct aty_pll_ops aty_pll_stg1703; /* STG 1703 */
-extern const struct aty_pll_ops aty_pll_ch8398; /* Chrontel 8398 */
-extern const struct aty_pll_ops aty_pll_att20c408; /* AT&T 20C408 */
-extern const struct aty_pll_ops aty_pll_ibm514; /* IBM RGB514 */
-extern const struct aty_pll_ops aty_pll_unsupported; /* unsupported */
-extern const struct aty_pll_ops aty_pll_ct; /* Integrated */
+extern const struct aty_pll_ops aty_pll_ati18818_1; /* ATI 18818 */
+extern const struct aty_pll_ops aty_pll_stg1703; /* STG 1703 */
+extern const struct aty_pll_ops aty_pll_ch8398; /* Chrontel 8398 */
+extern const struct aty_pll_ops aty_pll_att20c408; /* AT&T 20C408 */
+extern const struct aty_pll_ops aty_pll_ibm514; /* IBM RGB514 */
+extern const struct aty_pll_ops aty_pll_unsupported; /* unsupported */
+extern const struct aty_pll_ops aty_pll_ct; /* Integrated */
-extern void aty_set_pll_ct(const struct fb_info *info,
- const union aty_pll *pll);
-extern void aty_calc_pll_ct(const struct fb_info *info,
- struct pll_ct *pll);
+extern void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll);
+extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par);
/*
* Hardware cursor support
*/
-extern struct aty_cursor *aty_init_cursor(struct fb_info *info);
+extern int aty_init_cursor(struct fb_info *info);
extern int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor);
-extern void aty_set_cursor_color(struct fb_info *info);
-extern void aty_set_cursor_shape(struct fb_info *info);
/*
* Hardware acceleration
@@ -260,6 +342,5 @@
}
extern void aty_reset_engine(const struct atyfb_par *par);
-extern void aty_init_engine(struct atyfb_par *par,
- struct fb_info *info);
+extern void aty_init_engine(struct atyfb_par *par, struct fb_info *info);
diff -Nru a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
--- a/drivers/video/aty/atyfb_base.c 2004-10-19 20:22:41 +08:00
+++ b/drivers/video/aty/atyfb_base.c 2004-10-11 04:38:39 +08:00
@@ -1,6 +1,7 @@
/*
* ATI Frame Buffer Device Driver Core
*
+ * Copyright (C) 2004 Alex Kern <alex.kern@gmx.de>
* Copyright (C) 1997-2001 Geert Uytterhoeven
* Copyright (C) 1998 Bernd Harries
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
@@ -24,10 +25,13 @@
* Harry AC Eaton
* Anthony Tong <atong@uiuc.edu>
*
+ * Generic LCD support written by Daniel Mantione, ported from 2.4.20 by Alex Kern
+ * Many Thanks to Ville Syrjälä for patches and fixing nasting 16 bit color bug.
+ *
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
- *
+ *
* Many thanks to Nitya from ATI devrel for support and patience !
*/
@@ -38,15 +42,16 @@
- cursor support on all cards and all ramdacs.
- cursor parameters controlable via ioctl()s.
- guess PLL and MCLK based on the original PLL register values initialized
- by the BIOS or Open Firmware (if they are initialized).
+ by Open Firmware (if they are initialized). BIOS is done
- (Anyone to help with this?)
+ (Anyone with Mac to help with this?)
******************************************************************************/
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
@@ -54,19 +59,20 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
-#include <linux/selection.h>
#include <linux/console.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
-#include <linux/vt_kern.h>
-#include <linux/kd.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <video/mach64.h>
#include "atyfb.h"
+#include "ati_ids.h"
#ifdef __powerpc__
#include <asm/prom.h>
@@ -87,23 +93,102 @@
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif
-
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
/*
* Debug flags.
*/
-#undef DEBUG
+/*#undef DEBUG*/
+#define DEBUG
/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */
/* - must be large enough to catch all GUI-Regs */
/* - must be aligned to a PAGE boundary */
#define GUI_RESERVE (1 * PAGE_SIZE)
-
/* FIXME: remove the FAIL definition */
-#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
+#define FAIL(msg) do { printk(KERN_CRIT "atyfb: " msg "\n"); return -EINVAL; } while (0)
+#define FAIL_MAX(msg, x, _max_) do { if(x > _max_) { printk(KERN_CRIT "atyfb: " msg " %x(%x)\n", x, _max_); return -EINVAL; } } while (0)
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "atyfb: " fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define PRINTKI(fmt, args...) printk(KERN_INFO "atyfb: " fmt, ## args)
+#define PRINTKE(fmt, args...) printk(KERN_ERR "atyfb: " fmt, ## args)
+
+#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD)
+static const u32 lt_lcd_regs[] = {
+ CONFIG_PANEL_LG,
+ LCD_GEN_CNTL_LG,
+ DSTN_CONTROL_LG,
+ HFB_PITCH_ADDR_LG,
+ HORZ_STRETCHING_LG,
+ VERT_STRETCHING_LG,
+ 0, /* EXT_VERT_STRETCH */
+ LT_GIO_LG,
+ POWER_MANAGEMENT_LG
+};
+
+void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)
+{
+ if (M64_HAS(LT_LCD_REGS)) {
+ aty_st_le32(lt_lcd_regs[index], val, par);
+ } else {
+ unsigned long temp;
+
+ /* write addr byte */
+ temp = aty_ld_le32(LCD_INDEX, par);
+ aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
+ /* write the register value */
+ aty_st_le32(LCD_DATA, val, par);
+ }
+}
+
+u32 aty_ld_lcd(int index, const struct atyfb_par *par)
+{
+ if (M64_HAS(LT_LCD_REGS)) {
+ return aty_ld_le32(lt_lcd_regs[index], par);
+ } else {
+ unsigned long temp;
+
+ /* write addr byte */
+ temp = aty_ld_le32(LCD_INDEX, par);
+ aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
+ /* read the register value */
+ return aty_ld_le32(LCD_DATA, par);
+ }
+}
+#endif /* defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) */
+
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+/*
+ * ATIReduceRatio --
+ *
+ * Reduce a fraction by factoring out the largest common divider of the
+ * fraction's numerator and denominator.
+ */
+static void ATIReduceRatio(int *Numerator, int *Denominator)
+{
+ int Multiplier, Divider, Remainder;
+ Multiplier = *Numerator;
+ Divider = *Denominator;
+ while ((Remainder = Multiplier % Divider))
+ {
+ Multiplier = Divider;
+ Divider = Remainder;
+ }
+
+ *Numerator /= Divider;
+ *Denominator /= Divider;
+}
+#endif
/*
* The Hardware parameters for each card
*/
@@ -138,22 +223,19 @@
static int atyfb_open(struct fb_info *info, int user);
static int atyfb_release(struct fb_info *info, int user);
-static int atyfb_check_var(struct fb_var_screeninfo *var,
- struct fb_info *info);
-static int atyfb_set_par(struct fb_info *info);
+static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
+static int atyfb_set_par(struct fb_info *info);
static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
-static int atyfb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info);
+ u_int transp, struct fb_info *info);
+static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
static int atyfb_blank(int blank, struct fb_info *info);
static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, struct fb_info *info);
+ u_long arg, struct fb_info *info);
extern void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
extern void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
extern void atyfb_imageblit(struct fb_info *info, const struct fb_image *image);
#ifdef __sparc__
-static int atyfb_mmap(struct fb_info *info, struct file *file,
- struct vm_area_struct *vma);
+static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
#endif
static int atyfb_sync(struct fb_info *info);
@@ -166,15 +248,14 @@
static int store_video_par(char *videopar, unsigned char m64_num);
#endif
-static void aty_set_crtc(const struct atyfb_par *par,
- const struct crtc *crtc);
-static int aty_var_to_crtc(const struct fb_info *info,
- const struct fb_var_screeninfo *var,
- struct crtc *crtc);
-static int aty_crtc_to_var(const struct crtc *crtc,
- struct fb_var_screeninfo *var);
-static void set_off_pitch(struct atyfb_par *par,
- const struct fb_info *info);
+static struct crtc saved_crtc;
+static union aty_pll saved_pll;
+static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc);
+
+static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc);
+static int aty_var_to_crtc(const struct fb_info *info, const struct fb_var_screeninfo *var, struct crtc *crtc);
+static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screeninfo *var);
+static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info);
#ifdef CONFIG_PPC
static int read_aty_sense(const struct atyfb_par *par);
#endif
@@ -184,10 +265,19 @@
* Interface used by the world
*/
-int atyfb_init(void);
-#ifndef MODULE
-int atyfb_setup(char *);
-#endif
+struct fb_var_screeninfo default_var = {
+ /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+ 640, 480, 640, 480, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+};
+
+static struct fb_videomode defmode = {
+ /* 640x480 @ 60 Hz, 31.5 kHz hsync */
+ NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2,
+ 0, FB_VMODE_NONINTERLACED
+};
static struct fb_ops atyfb_ops = {
.owner = THIS_MODULE,
@@ -202,22 +292,22 @@
.fb_fillrect = atyfb_fillrect,
.fb_copyarea = atyfb_copyarea,
.fb_imageblit = atyfb_imageblit,
- .fb_cursor = soft_cursor,
+ .fb_cursor = atyfb_cursor,
#ifdef __sparc__
.fb_mmap = atyfb_mmap,
#endif
.fb_sync = atyfb_sync,
};
-static char curblink __initdata = 1;
-static char noaccel __initdata = 0;
-static u32 default_vram __initdata = 0;
-static int default_pll __initdata = 0;
-static int default_mclk __initdata = 0;
-
-#ifndef MODULE
-static char *mode_option __initdata = NULL;
-#endif
+static int noaccel;
+#ifdef CONFIG_MTRR
+static int nomtrr;
+#endif
+static int vram;
+static int pll;
+static int mclk;
+static int xclk;
+static char *mode;
#ifdef CONFIG_PPC
static int default_vmode __initdata = VMODE_CHOOSE;
@@ -231,177 +321,185 @@
static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
#endif
-#ifdef CONFIG_FB_ATY_GX
-static char m64n_gx[] __initdata = "mach64GX (ATI888GX00)";
-static char m64n_cx[] __initdata = "mach64CX (ATI888CX00)";
-#endif /* CONFIG_FB_ATY_GX */
-#ifdef CONFIG_FB_ATY_CT
-static char m64n_ct[] __initdata = "mach64CT (ATI264CT)";
-static char m64n_et[] __initdata = "mach64ET (ATI264ET)";
-static char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)";
-static char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)";
-static char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)";
-static char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)";
-static char m64n_gt[] __initdata = "3D RAGE (GT)";
-static char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)";
-static char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)";
-static char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)";
-static char m64n_lt[] __initdata = "3D RAGE LT";
-static char m64n_ltg[] __initdata = "3D RAGE LT-G";
-static char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)";
-static char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)";
-static char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)";
-static char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)";
-static char m64n_gtc_ppl[] __initdata =
- "3D RAGE PRO (PQFP, PCI, limited 3D)";
-static char m64n_xl[] __initdata = "3D RAGE (XL)";
-static char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)";
-static char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)";
-static char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)";
-static char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)";
-#endif /* CONFIG_FB_ATY_CT */
+/* top -> down is an evolution of mach64 chipset, any corrections? */
+#define ATI_CHIP_88800GX (M64F_GX)
+#define ATI_CHIP_88800CX (M64F_GX)
+
+#define ATI_CHIP_264CT (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO)
+#define ATI_CHIP_264ET (M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO)
+
+#define ATI_CHIP_264VT (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO)
+#define ATI_CHIP_264GT (M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO | M64F_EXTRA_BRIGHT)
+
+#define ATI_CHIP_264VTB (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP)
+#define ATI_CHIP_264VT3 (M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL)
+#define ATI_CHIP_264VT4 (M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP)
+
+#define ATI_CHIP_264LT (M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP)
+
+/* make sets shorter */
+#define ATI_MODERN_SET (M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_EXTRA_BRIGHT)
+
+#define ATI_CHIP_264GTB (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL)
+/*#define ATI_CHIP_264GTDVD ?*/
+#define ATI_CHIP_264LTG (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL)
+
+#define ATI_CHIP_264GT2C (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE)
+#define ATI_CHIP_264GTPRO (ATI_MODERN_SET | M64F_SDRAM_MAGIC_PLL | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
+#define ATI_CHIP_264LTPRO (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D)
+
+#define ATI_CHIP_264XL (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4)
+#define ATI_CHIP_MOBILITY (ATI_MODERN_SET | M64F_HW_TRIPLE | M64F_FIFO_32 | M64F_RESET_3D | M64F_XL_DLL | M64F_MFB_FORCE_4 | M64F_MOBIL_BUS)
static struct {
- u16 pci_id, chip_type;
- u8 rev_mask, rev_val;
+ u16 pci_id;
const char *name;
- int pll, mclk;
+ int pll, mclk, xclk;
u32 features;
} aty_chips[] __initdata = {
#ifdef CONFIG_FB_ATY_GX
/* Mach64 GX */
- {
- 0x4758, 0x00d7, 0x00, 0x00, m64n_gx, 135, 50, M64F_GX}, {
- 0x4358, 0x0057, 0x00, 0x00, m64n_cx, 135, 50, M64F_GX},
-#endif /* CONFIG_FB_ATY_GX */
+ { PCI_CHIP_MACH64GX, "ATI888GX00 (Mach64 GX)", 135, 50, 50, ATI_CHIP_88800GX },
+ { PCI_CHIP_MACH64CX, "ATI888CX00 (Mach64 CX)", 135, 50, 50, ATI_CHIP_88800CX },
+#endif /* CONFIG_FB_ATY_GX */
+
#ifdef CONFIG_FB_ATY_CT
- /* Mach64 CT */
- {
- 0x4354, 0x4354, 0x00, 0x00, m64n_ct, 135, 60,
- M64F_CT | M64F_INTEGRATED | M64F_CT_BUS |
- M64F_MAGIC_FIFO}, {
- 0x4554, 0x4554, 0x00, 0x00, m64n_et, 135, 60,
- M64F_CT | M64F_INTEGRATED | M64F_CT_BUS |
- M64F_MAGIC_FIFO},
- /* Mach64 VT */
- {
- 0x5654, 0x5654, 0xc7, 0x00, m64n_vta3, 170, 67,
- M64F_VT | M64F_INTEGRATED | M64F_VT_BUS |
- M64F_MAGIC_FIFO | M64F_FIFO_24}, {
- 0x5654, 0x5654, 0xc7, 0x40, m64n_vta4, 200, 67,
- M64F_VT | M64F_INTEGRATED | M64F_VT_BUS |
- M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_MAGIC_POSTDIV}, {
- 0x5654, 0x5654, 0x00, 0x00, m64n_vtb, 200, 67,
- M64F_VT | M64F_INTEGRATED | M64F_VT_BUS |
- M64F_GTB_DSP | M64F_FIFO_24}, {
- 0x5655, 0x5655, 0x00, 0x00, m64n_vtb, 200, 67,
- M64F_VT | M64F_INTEGRATED | M64F_VT_BUS |
- M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL}, {
- 0x5656, 0x5656, 0x00, 0x00, m64n_vt4, 230, 83,
- M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP},
- /* Mach64 GT (3D RAGE) */
- {
- 0x4754, 0x4754, 0x07, 0x00, m64n_gt, 135, 63,
- M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO |
- M64F_FIFO_24 | M64F_EXTRA_BRIGHT}, {
- 0x4754, 0x4754, 0x07, 0x01, m64n_gt, 170, 67,
- M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
- M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT}, {
- 0x4754, 0x4754, 0x07, 0x02, m64n_gt, 200, 67,
- M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
- M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT}, {
- 0x4755, 0x4755, 0x00, 0x00, m64n_gtb, 200, 67,
- M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
- M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT}, {
- 0x4756, 0x4756, 0x00, 0x00, m64n_iic_p, 230, 83,
- M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
- M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT}, {
- 0x4757, 0x4757, 0x00, 0x00, m64n_iic_a, 230, 83,
- M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
- M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT}, {
- 0x475a, 0x475a, 0x00, 0x00, m64n_iic_a, 230, 83,
- M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
- M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT},
- /* Mach64 LT */
- {
- 0x4c54, 0x4c54, 0x00, 0x00, m64n_lt, 135, 63,
- M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP}, {
- 0x4c47, 0x4c47, 0x00, 0x00, m64n_ltg, 230, 63,
- M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
- M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT |
- M64F_LT_SLEEP | M64F_G3_PB_1024x768},
- /* Mach64 GTC (3D RAGE PRO) */
- {
- 0x4742, 0x4742, 0x00, 0x00, m64n_gtc_ba, 230, 100,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT}, {
- 0x4744, 0x4744, 0x00, 0x00, m64n_gtc_ba1, 230, 100,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT}, {
- 0x4749, 0x4749, 0x00, 0x00, m64n_gtc_bp, 230, 100,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT | M64F_MAGIC_VRAM_SIZE}, {
- 0x4750, 0x4750, 0x00, 0x00, m64n_gtc_pp, 230, 100,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT}, {
- 0x4751, 0x4751, 0x00, 0x00, m64n_gtc_ppl, 230, 100,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT},
- /* 3D RAGE XL */
- {
- 0x4752, 0x4752, 0x00, 0x00, m64n_xl, 230, 100,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
- M64F_EXTRA_BRIGHT | M64F_XL_DLL},
- /* Mach64 LT PRO */
- {
- 0x4c42, 0x4c42, 0x00, 0x00, m64n_ltp_a, 230, 100,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP}, {
- 0x4c44, 0x4c44, 0x00, 0x00, m64n_ltp_p, 230, 100,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP}, {
- 0x4c49, 0x4c49, 0x00, 0x00, m64n_ltp_p, 230, 100,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP | M64F_EXTRA_BRIGHT |
- M64F_G3_PB_1_1 | M64F_G3_PB_1024x768}, {
- 0x4c50, 0x4c50, 0x00, 0x00, m64n_ltp_p, 230, 100,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP},
- /* 3D RAGE Mobility */
- {
- 0x4c4d, 0x4c4d, 0x00, 0x00, m64n_mob_p, 230, 50,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP | M64F_MOBIL_BUS}, {
- 0x4c4e, 0x4c4e, 0x00, 0x00, m64n_mob_a, 230, 50,
- M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
- M64F_GTB_DSP | M64F_MOBIL_BUS},
-#endif /* CONFIG_FB_ATY_CT */
+ { PCI_CHIP_MACH64CT, "ATI264CT (Mach64 CT)", 135, 60, 60, ATI_CHIP_264CT },
+ { PCI_CHIP_MACH64ET, "ATI264ET (Mach64 ET)", 135, 60, 60, ATI_CHIP_264ET },
+ { PCI_CHIP_MACH64VT, "ATI264VT? (Mach64 VT)", 170, 67, 67, ATI_CHIP_264VT },
+ { PCI_CHIP_MACH64GT, "3D RAGE (Mach64 GT)", 135, 63, 63, ATI_CHIP_264GT },
+ /* FIXME { ...ATI_264GU, maybe ATI_CHIP_264GTDVD }, */
+ { PCI_CHIP_MACH64GU, "3D RAGE II+ (Mach64 GTB)", 200, 67, 67, ATI_CHIP_264GTB },
+ { PCI_CHIP_MACH64VU, "ATI264VTB (Mach64 VU)", 200, 67, 67, ATI_CHIP_264VT3 },
+
+ { PCI_CHIP_MACH64LT, "3D RAGE LT (Mach64 LT)", 135, 63, 63, ATI_CHIP_264LT },
+ /* FIXME chipset maybe ATI_CHIP_264LTPRO ? */
+ { PCI_CHIP_MACH64LG, "3D RAGE LT-G (Mach64 LG)", 230, 63, 63, ATI_CHIP_264LTG | M64F_LT_LCD_REGS | M64F_G3_PB_1024x768 },
+
+ { PCI_CHIP_MACH64VV, "ATI264VT4 (Mach64 VV)", 230, 83, 83, ATI_CHIP_264VT4 },
+
+ { PCI_CHIP_MACH64GV, "3D RAGE IIC (Mach64 GV, PCI)", 230, 83, 83, ATI_CHIP_264GT2C },
+ { PCI_CHIP_MACH64GW, "3D RAGE IIC (Mach64 GW, AGP)", 230, 83, 83, ATI_CHIP_264GT2C },
+ { PCI_CHIP_MACH64GY, "3D RAGE IIC (Mach64 GY, PCI)", 230, 83, 83, ATI_CHIP_264GT2C },
+ { PCI_CHIP_MACH64GZ, "3D RAGE IIC (Mach64 GZ, AGP)", 230, 83, 83, ATI_CHIP_264GT2C },
+
+ { PCI_CHIP_MACH64GB, "3D RAGE PRO (Mach64 GB, BGA, AGP)", 230, 100, 100, ATI_CHIP_264GTPRO },
+ { PCI_CHIP_MACH64GD, "3D RAGE PRO (Mach64 GD, BGA, AGP 1x)", 230, 100, 100, ATI_CHIP_264GTPRO },
+ { PCI_CHIP_MACH64GI, "3D RAGE PRO (Mach64 GI, BGA, PCI)", 230, 100, 100, ATI_CHIP_264GTPRO | M64F_MAGIC_VRAM_SIZE },
+ { PCI_CHIP_MACH64GP, "3D RAGE PRO (Mach64 GP, PQFP, PCI)", 230, 100, 100, ATI_CHIP_264GTPRO },
+ { PCI_CHIP_MACH64GQ, "3D RAGE PRO (Mach64 GQ, PQFP, PCI, limited 3D)", 230, 100, 100, ATI_CHIP_264GTPRO },
+
+ { PCI_CHIP_MACH64LB, "3D RAGE LT PRO (Mach64 LB, AGP)", 236, 75, 100, ATI_CHIP_264LTPRO },
+ { PCI_CHIP_MACH64LD, "3D RAGE LT PRO (Mach64 LD, AGP)", 230, 100, 100, ATI_CHIP_264LTPRO },
+ { PCI_CHIP_MACH64LI, "3D RAGE LT PRO (Mach64 LI, PCI)", 230, 100, 100, ATI_CHIP_264LTPRO | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 },
+ { PCI_CHIP_MACH64LP, "3D RAGE LT PRO (Mach64 LP, PCI)", 230, 100, 100, ATI_CHIP_264LTPRO },
+ { PCI_CHIP_MACH64LQ, "3D RAGE LT PRO (Mach64 LQ, PCI)", 230, 100, 100, ATI_CHIP_264LTPRO },
+
+ { PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP)", 230, 83, 63, ATI_CHIP_264XL },
+ { PCI_CHIP_MACH64GN, "3D RAGE XL (Mach64 GN, AGP)", 230, 83, 63, ATI_CHIP_264XL },
+ { PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66/BGA)", 230, 83, 63, ATI_CHIP_264XL },
+ { PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33MHz)", 230, 83, 63, ATI_CHIP_264XL },
+ { PCI_CHIP_MACH64GL, "3D RAGE XL (Mach64 GL, PCI)", 230, 83, 63, ATI_CHIP_264XL },
+ { PCI_CHIP_MACH64GS, "3D RAGE XL (Mach64 GS, PCI)", 230, 83, 63, ATI_CHIP_264XL },
+
+ { PCI_CHIP_MACH64LM, "3D RAGE Mobility P/M (Mach64 LM, AGP 2x)", 230, 83, 125, ATI_CHIP_MOBILITY },
+ { PCI_CHIP_MACH64LN, "3D RAGE Mobility L (Mach64 LN, AGP 2x)", 230, 83, 125, ATI_CHIP_MOBILITY },
+ { PCI_CHIP_MACH64LR, "3D RAGE Mobility P/M (Mach64 LR, PCI)", 230, 83, 125, ATI_CHIP_MOBILITY },
+ { PCI_CHIP_MACH64LS, "3D RAGE Mobility L (Mach64 LS, PCI)", 230, 83, 125, ATI_CHIP_MOBILITY },
+#endif /* CONFIG_FB_ATY_CT */
};
+/* can not fail */
+static int __devinit correct_chipset(struct atyfb_par *par)
+{
+ u8 rev;
+ u16 type;
+ u32 chip_id;
+ const char *name;
+ int i;
+
+ for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--)
+ if (par->pci_id == aty_chips[i].pci_id)
+ break;
+
+ name = aty_chips[i].name;
+ par->pll_limits.pll_max = aty_chips[i].pll;
+ par->pll_limits.mclk = aty_chips[i].mclk;
+ par->pll_limits.xclk = aty_chips[i].xclk;
+ par->features = aty_chips[i].features;
+
+ chip_id = aty_ld_le32(CONFIG_CHIP_ID, par);
+ type = chip_id & CFG_CHIP_TYPE;
+ rev = (chip_id & CFG_CHIP_REV) >> 24;
+
+ switch(par->pci_id) {
+#ifdef CONFIG_FB_ATY_GX
+ case PCI_CHIP_MACH64GX:
+ if(type != 0x00d7);
+ return -ENODEV;
+ break;
+ case PCI_CHIP_MACH64CX:
+ if(type != 0x0057);
+ return -ENODEV;
+ break;
+#endif
+#ifdef CONFIG_FB_ATY_CT
+ case PCI_CHIP_MACH64VT:
+ rev &= 0xc7;
+ if(rev == 0x00) {
+ name = "ATI264VTA3 (Mach64 VT)";
+ par->pll_limits.pll_max = 170;
+ par->pll_limits.mclk = 67;
+ par->pll_limits.xclk = 67;
+ par->features = ATI_CHIP_264VT;
+ } else if(rev == 0x40) {
+ name = "ATI264VTA4 (Mach64 VT)";
+ par->pll_limits.pll_max = 200;
+ par->pll_limits.mclk = 67;
+ par->pll_limits.xclk = 67;
+ par->features = ATI_CHIP_264VT | M64F_MAGIC_POSTDIV;
+ } else {
+ name = "ATI264VTB (Mach64 VT)";
+ par->pll_limits.pll_max = 200;
+ par->pll_limits.mclk = 67;
+ par->pll_limits.xclk = 67;
+ par->features = ATI_CHIP_264VTB;
+ }
+ break;
+ case PCI_CHIP_MACH64GT:
+ rev &= 0x07;
+ if(rev == 0x01) {
+ par->pll_limits.pll_max = 170;
+ par->pll_limits.mclk = 67;
+ par->pll_limits.xclk = 67;
+ par->features = ATI_CHIP_264GTB;
+ } else if(rev == 0x02) {
+ par->pll_limits.pll_max = 200;
+ par->pll_limits.mclk = 67;
+ par->pll_limits.xclk = 67;
+ par->features = ATI_CHIP_264GTB;
+ }
+ break;
+#endif
+ }
+
+ PRINTKI("%s [0x%04x rev 0x%02x]\n", name, type, rev);
+ return 0;
+}
+
static char ram_dram[] __initdata = "DRAM";
+static char ram_resv[] __initdata = "RESV";
#ifdef CONFIG_FB_ATY_GX
static char ram_vram[] __initdata = "VRAM";
#endif /* CONFIG_FB_ATY_GX */
#ifdef CONFIG_FB_ATY_CT
static char ram_edo[] __initdata = "EDO";
-static char ram_sdram[] __initdata = "SDRAM";
-static char ram_sgram[] __initdata = "SGRAM";
-static char ram_wram[] __initdata = "WRAM";
+static char ram_sdram[] __initdata = "SDRAM (1:1)";
+static char ram_sgram[] __initdata = "SGRAM (1:1)";
+static char ram_sdram32[] __initdata = "SDRAM (2:1) (32-bit)";
static char ram_off[] __initdata = "OFF";
#endif /* CONFIG_FB_ATY_CT */
-static char ram_resv[] __initdata = "RESV";
+
static u32 pseudo_palette[17];
@@ -410,109 +508,226 @@
ram_dram, ram_vram, ram_vram, ram_dram,
ram_dram, ram_vram, ram_vram, ram_resv
};
-#endif /* CONFIG_FB_ATY_GX */
+#endif /* CONFIG_FB_ATY_GX */
#ifdef CONFIG_FB_ATY_CT
static char *aty_ct_ram[8] __initdata = {
ram_off, ram_dram, ram_edo, ram_edo,
- ram_sdram, ram_sgram, ram_wram, ram_resv
+ ram_sdram, ram_sgram, ram_sdram32, ram_resv
};
-#endif /* CONFIG_FB_ATY_CT */
+#endif /* CONFIG_FB_ATY_CT */
+static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var, struct atyfb_par *par)
+{
+ u32 pixclock = var->pixclock;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ u32 lcd_on_off;
+ par->pll.ct.xres = 0;
+ if (par->lcd_table != 0) {
+ lcd_on_off = aty_ld_lcd(LCD_GEN_CNTL, par);
+ if(lcd_on_off & LCD_ON) {
+ par->pll.ct.xres = var->xres;
+ pixclock = par->lcd_pixclock;
+ }
+ }
+#endif
+ return pixclock;
+}
#if defined(CONFIG_PPC)
- /*
- * Apple monitor sense
- */
+/*
+ * Apple monitor sense
+ */
static int __init read_aty_sense(const struct atyfb_par *par)
{
int sense, i;
- aty_st_le32(GP_IO, 0x31003100, par); /* drive outputs high */
+ aty_st_le32(GP_IO, 0x31003100, par); /* drive outputs high */
__delay(200);
- aty_st_le32(GP_IO, 0, par); /* turn off outputs */
+ aty_st_le32(GP_IO, 0, par); /* turn off outputs */
__delay(2000);
- i = aty_ld_le32(GP_IO, par); /* get primary sense value */
+ i = aty_ld_le32(GP_IO, par); /* get primary sense value */
sense = ((i & 0x3000) >> 3) | (i & 0x100);
/* drive each sense line low in turn and collect the other 2 */
- aty_st_le32(GP_IO, 0x20000000, par); /* drive A low */
+ aty_st_le32(GP_IO, 0x20000000, par); /* drive A low */
__delay(2000);
i = aty_ld_le32(GP_IO, par);
sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);
- aty_st_le32(GP_IO, 0x20002000, par); /* drive A high again */
+ aty_st_le32(GP_IO, 0x20002000, par); /* drive A high again */
__delay(200);
- aty_st_le32(GP_IO, 0x10000000, par); /* drive B low */
+ aty_st_le32(GP_IO, 0x10000000, par); /* drive B low */
__delay(2000);
i = aty_ld_le32(GP_IO, par);
sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);
- aty_st_le32(GP_IO, 0x10001000, par); /* drive B high again */
+ aty_st_le32(GP_IO, 0x10001000, par); /* drive B high again */
__delay(200);
- aty_st_le32(GP_IO, 0x01000000, par); /* drive C low */
+ aty_st_le32(GP_IO, 0x01000000, par); /* drive C low */
__delay(2000);
sense |= (aty_ld_le32(GP_IO, par) & 0x3000) >> 12;
- aty_st_le32(GP_IO, 0, par); /* turn off outputs */
+ aty_st_le32(GP_IO, 0, par); /* turn off outputs */
return sense;
}
-#endif /* defined(CONFIG_PPC) */
-
-#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT)
-static void aty_st_lcd(int index, u32 val, const struct atyfb_par *par)
-{
- unsigned long temp;
-
- /* write addr byte */
- temp = aty_ld_le32(LCD_INDEX, par);
- aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
- /* write the register value */
- aty_st_le32(LCD_DATA, val, par);
-}
-
-static u32 aty_ld_lcd(int index, const struct atyfb_par *par)
-{
- unsigned long temp;
-
- /* write addr byte */
- temp = aty_ld_le32(LCD_INDEX, par);
- aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, par);
- /* read the register value */
- return aty_ld_le32(LCD_DATA, par);
-}
-#endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT */
+#endif /* defined(CONFIG_PPC) */
/* ------------------------------------------------------------------------- */
- /*
- * CRTC programming
- */
+/*
+ * CRTC programming
+ */
-static void aty_set_crtc(const struct atyfb_par *par,
- const struct crtc *crtc)
+static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc)
{
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ if (par->lcd_table != 0) {
+ if(!M64_HAS(LT_LCD_REGS)) {
+ crtc->lcd_index = aty_ld_le32(LCD_INDEX, par);
+ aty_st_le32(LCD_INDEX, crtc->lcd_index, par);
+ }
+ crtc->lcd_config_panel = aty_ld_lcd(CONFIG_PANEL, par);
+ crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par);
+
+
+ /* switch to non shadow registers */
+ aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl &
+ ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par);
+
+ /* save stretching */
+ crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par);
+ crtc->vert_stretching = aty_ld_lcd(VERT_STRETCHING, par);
+ if (!M64_HAS(LT_LCD_REGS))
+ crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par);
+ }
+#endif
+ crtc->h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
+ crtc->h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
+ crtc->v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
+ crtc->v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);
+ crtc->vline_crnt_vline = aty_ld_le32(CRTC_VLINE_CRNT_VLINE, par);
+ crtc->off_pitch = aty_ld_le32(CRTC_OFF_PITCH, par);
+ crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
+
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ if (par->lcd_table != 0) {
+ /* switch to shadow registers */
+ aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) |
+ SHADOW_EN | SHADOW_RW_EN, par);
+
+ crtc->shadow_h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
+ crtc->shadow_h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
+ crtc->shadow_v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
+ crtc->shadow_v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);
+
+ aty_st_le32(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);
+ }
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
+}
+
+static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc)
+{
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ if (par->lcd_table != 0) {
+ /* stop CRTC */
+ aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~(CRTC_EXT_DISP_EN | CRTC_EN), par);
+
+ /* update non-shadow registers first */
+ aty_st_lcd(CONFIG_PANEL, crtc->lcd_config_panel, par);
+ aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl &
+ ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par);
+
+ /* temporarily disable stretching */
+ aty_st_lcd(HORZ_STRETCHING,
+ crtc->horz_stretching &
+ ~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN), par);
+ aty_st_lcd(VERT_STRETCHING,
+ crtc->vert_stretching &
+ ~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 |
+ VERT_STRETCH_USE0 | VERT_STRETCH_EN), par);
+ }
+#endif
+ /* turn off CRT */
+ aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~CRTC_EN, par);
+
+ DPRINTK("setting up CRTC\n");
+ PRINTKI("set primary CRT to %ix%i %c%c composite %c\n",
+ ((((crtc->h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->v_tot_disp>>16) & 0x7ff) + 1),
+ (crtc->h_sync_strt_wid & 0x200000)?'N':'P', (crtc->v_sync_strt_wid & 0x200000)?'N':'P',
+ (crtc->gen_cntl & CRTC_CSYNC_EN)?'P':'N');
+
+ DPRINTK("CRTC_H_TOTAL_DISP: %x\n",crtc->h_tot_disp);
+ DPRINTK("CRTC_H_SYNC_STRT_WID: %x\n",crtc->h_sync_strt_wid);
+ DPRINTK("CRTC_V_TOTAL_DISP: %x\n",crtc->v_tot_disp);
+ DPRINTK("CRTC_V_SYNC_STRT_WID: %x\n",crtc->v_sync_strt_wid);
+ DPRINTK("CRTC_OFF_PITCH: %x\n", crtc->off_pitch);
+ DPRINTK("CRTC_VLINE_CRNT_VLINE: %x\n", crtc->vline_crnt_vline);
+ DPRINTK("CRTC_GEN_CNTL: %x\n",crtc->gen_cntl);
+
aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, par);
aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, par);
aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, par);
aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, par);
- aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, par);
aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, par);
+ aty_st_le32(CRTC_VLINE_CRNT_VLINE, crtc->vline_crnt_vline, par);
+
aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, par);
+#if 0
+ FIXME
+ if (par->accel_flags & FB_ACCELF_TEXT)
+ aty_init_engine(par, info);
+#endif
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ /* after setting the CRTC registers we should set the LCD registers. */
+ if (par->lcd_table != 0) {
+ /* switch to shadow registers */
+ aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) |
+ (SHADOW_EN | SHADOW_RW_EN), par);
+
+ PRINTKI("set secondary CRT to %ix%i %c%c\n",
+ ((((crtc->shadow_h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->shadow_v_tot_disp>>16) & 0x7ff) + 1),
+ (crtc->shadow_h_sync_strt_wid & 0x200000)?'N':'P', (crtc->shadow_v_sync_strt_wid & 0x200000)?'N':'P');
+
+ DPRINTK("SHADOW CRTC_H_TOTAL_DISP: %x\n", crtc->shadow_h_tot_disp);
+ DPRINTK("SHADOW CRTC_H_SYNC_STRT_WID: %x\n", crtc->shadow_h_sync_strt_wid);
+ DPRINTK("SHADOW CRTC_V_TOTAL_DISP: %x\n", crtc->shadow_v_tot_disp);
+ DPRINTK("SHADOW CRTC_V_SYNC_STRT_WID: %x\n", crtc->shadow_v_sync_strt_wid);
+
+ aty_st_le32(CRTC_H_TOTAL_DISP, crtc->shadow_h_tot_disp, par);
+ aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->shadow_h_sync_strt_wid, par);
+ aty_st_le32(CRTC_V_TOTAL_DISP, crtc->shadow_v_tot_disp, par);
+ aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->shadow_v_sync_strt_wid, par);
+
+ /* restore CRTC selection & shadow state and enable stretching */
+ DPRINTK("LCD_GEN_CNTL: %x\n", crtc->lcd_gen_cntl);
+ DPRINTK("HORZ_STRETCHING: %x\n", crtc->horz_stretching);
+ DPRINTK("VERT_STRETCHING: %x\n", crtc->vert_stretching);
+ if(!M64_HAS(LT_LCD_REGS))
+ DPRINTK("EXT_VERT_STRETCH: %x\n", crtc->ext_vert_stretch);
+
+ aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);
+ aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching, par);
+ aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching, par);
+ if(!M64_HAS(LT_LCD_REGS)) {
+ aty_st_lcd(EXT_VERT_STRETCH, crtc->ext_vert_stretch, par);
+ aty_ld_le32(LCD_INDEX, par);
+ aty_st_le32(LCD_INDEX, crtc->lcd_index, par);
+ }
+ }
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
}
static int aty_var_to_crtc(const struct fb_info *info,
- const struct fb_var_screeninfo *var,
- struct crtc *crtc)
+ const struct fb_var_screeninfo *var, struct crtc *crtc)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
- u32 left, right, upper, lower, hslen, vslen, sync, vmode;
- u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid,
- h_sync_pol;
- u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
+ u32 sync, vmode, vdisplay;
+ u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol;
+ u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync;
u32 pix_width, dp_pix_width, dp_chain_mask;
/* input */
@@ -523,53 +738,19 @@
xoffset = var->xoffset;
yoffset = var->yoffset;
bpp = var->bits_per_pixel;
- left = var->left_margin;
- right = var->right_margin;
- upper = var->upper_margin;
- lower = var->lower_margin;
- hslen = var->hsync_len;
- vslen = var->vsync_len;
+ if (bpp == 16)
+ bpp = (var->green.length == 5) ? 15 : 16;
sync = var->sync;
vmode = var->vmode;
/* convert (and round up) and validate */
- xres = (xres + 7) & ~7;
- xoffset = (xoffset + 7) & ~7;
- vxres = (vxres + 7) & ~7;
if (vxres < xres + xoffset)
vxres = xres + xoffset;
- h_disp = xres / 8 - 1;
- if (h_disp > 0xff)
- FAIL("h_disp too large");
- h_sync_strt = h_disp + (right / 8);
- if (h_sync_strt > 0x1ff)
- FAIL("h_sync_start too large");
- h_sync_dly = right & 7;
- h_sync_wid = (hslen + 7) / 8;
- if (h_sync_wid > 0x1f)
- FAIL("h_sync_wid too large");
- h_total = h_sync_strt + h_sync_wid + (h_sync_dly + left + 7) / 8;
- if (h_total > 0x1ff)
- FAIL("h_total too large");
- h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+ h_disp = xres;
if (vyres < yres + yoffset)
vyres = yres + yoffset;
- v_disp = yres - 1;
- if (v_disp > 0x7ff)
- FAIL("v_disp too large");
- v_sync_strt = v_disp + lower;
- if (v_sync_strt > 0x7ff)
- FAIL("v_sync_strt too large");
- v_sync_wid = vslen;
- if (v_sync_wid > 0x1f)
- FAIL("v_sync_wid too large");
- v_total = v_sync_strt + v_sync_wid + upper;
- if (v_total > 0x7ff)
- FAIL("v_total too large");
- v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
-
- c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0;
+ v_disp = yres;
if (bpp <= 8) {
bpp = 8;
@@ -577,54 +758,325 @@
dp_pix_width =
HOST_8BPP | SRC_8BPP | DST_8BPP |
BYTE_ORDER_LSB_TO_MSB;
- dp_chain_mask = 0x8080;
- } else if (bpp <= 16) {
+ dp_chain_mask = DP_CHAIN_8BPP;
+ } else if (bpp <= 15) {
bpp = 16;
pix_width = CRTC_PIX_WIDTH_15BPP;
dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |
BYTE_ORDER_LSB_TO_MSB;
- dp_chain_mask = 0x4210;
+ dp_chain_mask = DP_CHAIN_15BPP;
+ } else if (bpp <= 16) {
+ bpp = 16;
+ pix_width = CRTC_PIX_WIDTH_16BPP;
+ dp_pix_width = HOST_16BPP | SRC_16BPP | DST_16BPP |
+ BYTE_ORDER_LSB_TO_MSB;
+ dp_chain_mask = DP_CHAIN_16BPP;
} else if (bpp <= 24 && M64_HAS(INTEGRATED)) {
bpp = 24;
pix_width = CRTC_PIX_WIDTH_24BPP;
dp_pix_width =
HOST_8BPP | SRC_8BPP | DST_8BPP |
BYTE_ORDER_LSB_TO_MSB;
- dp_chain_mask = 0x8080;
+ dp_chain_mask = DP_CHAIN_24BPP;
} else if (bpp <= 32) {
bpp = 32;
pix_width = CRTC_PIX_WIDTH_32BPP;
dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP |
BYTE_ORDER_LSB_TO_MSB;
- dp_chain_mask = 0x8080;
+ dp_chain_mask = DP_CHAIN_32BPP;
} else
FAIL("invalid bpp");
if (vxres * vyres * bpp / 8 > info->fix.smem_len)
FAIL("not enough video RAM");
- if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
- FAIL("invalid vmode");
+ h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+ v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+ if((xres > 1600) || (yres > 1200)) {
+ FAIL("MACH64 chips are designed for max 1600x1200\n"
+ "select anoter resolution.");
+ }
+ h_sync_strt = h_disp + var->right_margin;
+ h_sync_end = h_sync_strt + var->hsync_len;
+ h_sync_dly = var->right_margin & 7;
+ h_total = h_sync_end + h_sync_dly + var->left_margin;
+
+ v_sync_strt = v_disp + var->lower_margin;
+ v_sync_end = v_sync_strt + var->vsync_len;
+ v_total = v_sync_end + var->upper_margin;
+
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ if (par->lcd_table != 0) {
+ if(!M64_HAS(LT_LCD_REGS)) {
+ u32 lcd_index = aty_ld_le32(LCD_INDEX, par);
+ crtc->lcd_index = lcd_index &
+ ~(LCD_INDEX_MASK | LCD_DISPLAY_DIS | LCD_SRC_SEL | CRTC2_DISPLAY_DIS);
+ aty_st_le32(LCD_INDEX, lcd_index, par);
+ }
+
+ if (!M64_HAS(MOBIL_BUS))
+ crtc->lcd_index |= CRTC2_DISPLAY_DIS;
+
+ crtc->lcd_config_panel = aty_ld_lcd(CONFIG_PANEL, par) | 0x4000;
+ crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par) & ~CRTC_RW_SELECT;
+
+ crtc->lcd_gen_cntl &=
+ ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | TVCLK_PM_EN |
+ /*VCLK_DAC_PM_EN | USE_SHADOWED_VEND |*/
+ USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN);
+ crtc->lcd_gen_cntl |= DONT_SHADOW_VPAR | LOCK_8DOT;
+
+ if((crtc->lcd_gen_cntl & LCD_ON) &&
+ ((xres > par->lcd_width) || (yres > par->lcd_height))) {
+ /* We cannot display the mode on the LCD. If the CRT is enabled
+ we can turn off the LCD.
+ If the CRT is off, it isn't a good idea to switch it on; we don't
+ know if one is connected. So it's better to fail then.
+ */
+ if (crtc->lcd_gen_cntl & CRT_ON) {
+ PRINTKI("Disable lcd panel, because video mode does not fit.\n");
+ crtc->lcd_gen_cntl &= ~LCD_ON;
+ /*aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);*/
+ } else {
+ FAIL("Video mode exceeds size of lcd panel.\nConnect this computer to a conventional monitor if you really need this mode.");
+ }
+ }
+ }
+
+ if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON)) {
+ int VScan = 1;
+ /* bpp -> bytespp, 1,4 -> 0; 8 -> 2; 15,16 -> 1; 24 -> 6; 32 -> 5
+ const u8 DFP_h_sync_dly_LT[] = { 0, 2, 1, 6, 5 };
+ const u8 ADD_to_strt_wid_and_dly_LT_DAC[] = { 0, 5, 6, 9, 9, 12, 12 }; */
+
+ vmode &= ~(FB_VMODE_DOUBLE | FB_VMODE_INTERLACED);
+
+ /* This is horror! When we simulate, say 640x480 on an 800x600
+ lcd monitor, the CRTC should be programmed 800x600 values for
+ the non visible part, but 640x480 for the visible part.
+ This code has been tested on a laptop with it's 1400x1050 lcd
+ monitor and a conventional monitor both switched on.
+ Tested modes: 1280x1024, 1152x864, 1024x768, 800x600,
+ works with little glitches also with DOUBLESCAN modes
+ */
+ if (yres < par->lcd_height) {
+ VScan = par->lcd_height / yres;
+ if(VScan > 1) {
+ VScan = 2;
+ vmode |= FB_VMODE_DOUBLE;
+ }
+ }
+
+ h_sync_strt = h_disp + par->lcd_right_margin;
+ h_sync_end = h_sync_strt + par->lcd_hsync_len;
+ h_sync_dly = /*DFP_h_sync_dly[ ( bpp + 1 ) / 3 ]; */par->lcd_hsync_dly;
+ h_total = h_disp + par->lcd_hblank_len;
+
+ v_sync_strt = v_disp + par->lcd_lower_margin / VScan;
+ v_sync_end = v_sync_strt + par->lcd_vsync_len / VScan;
+ v_total = v_disp + par->lcd_vblank_len / VScan;
+ }
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
+
+ h_disp = (h_disp >> 3) - 1;
+ h_sync_strt = (h_sync_strt >> 3) - 1;
+ h_sync_end = (h_sync_end >> 3) - 1;
+ h_total = (h_total >> 3) - 1;
+ h_sync_wid = h_sync_end - h_sync_strt;
+
+ FAIL_MAX("h_disp too large", h_disp, 0xff);
+ FAIL_MAX("h_sync_strt too large", h_sync_strt, 0x1ff);
+ /*FAIL_MAX("h_sync_wid too large", h_sync_wid, 0x1f);*/
+ if(h_sync_wid > 0x1f)
+ h_sync_wid = 0x1f;
+ FAIL_MAX("h_total too large", h_total, 0x1ff);
+
+ if (vmode & FB_VMODE_DOUBLE) {
+ v_disp <<= 1;
+ v_sync_strt <<= 1;
+ v_sync_end <<= 1;
+ v_total <<= 1;
+ }
+
+ vdisplay = yres;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON))
+ vdisplay = par->lcd_height;
+#endif
+
+ if(vdisplay < 400) {
+ h_sync_pol = 1;
+ v_sync_pol = 0;
+ } else if(vdisplay < 480) {
+ h_sync_pol = 0;
+ v_sync_pol = 1;
+ } else if(vdisplay < 768) {
+ h_sync_pol = 0;
+ v_sync_pol = 0;
+ } else {
+ h_sync_pol = 1;
+ v_sync_pol = 1;
+ }
+
+ v_disp--;
+ v_sync_strt--;
+ v_sync_end--;
+ v_total--;
+ v_sync_wid = v_sync_end - v_sync_strt;
+
+ FAIL_MAX("v_disp too large", v_disp, 0x7ff);
+ FAIL_MAX("v_sync_stsrt too large", v_sync_strt, 0x7ff);
+ /*FAIL_MAX("v_sync_wid too large", v_sync_wid, 0x1f);*/
+ if(v_sync_wid > 0x1f)
+ v_sync_wid = 0x1f;
+ FAIL_MAX("v_total too large", v_total, 0x7ff);
+
+ c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0;
/* output */
crtc->vxres = vxres;
crtc->vyres = vyres;
- crtc->h_tot_disp = h_total | (h_disp << 16);
- crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly << 8) |
- ((h_sync_strt & 0x100) << 4) | (h_sync_wid << 16) |
- (h_sync_pol << 21);
- crtc->v_tot_disp = v_total | (v_disp << 16);
- crtc->v_sync_strt_wid =
- v_sync_strt | (v_sync_wid << 16) | (v_sync_pol << 21);
- crtc->off_pitch =
- ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19);
- crtc->gen_cntl =
- pix_width | c_sync | CRTC_EXT_DISP_EN | CRTC_ENABLE;
+ crtc->xoffset = xoffset;
+ crtc->yoffset = yoffset;
+ crtc->bpp = bpp;
+ crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+ crtc->vline_crnt_vline = 0;
+
+ crtc->h_tot_disp = h_total | (h_disp<<16);
+ crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) |
+ ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) | (h_sync_pol<<21);
+ crtc->v_tot_disp = v_total | (v_disp<<16);
+ crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21);
+
+ /* crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_PRESERVED_MASK; */
+ crtc->gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | pix_width | c_sync;
+ crtc->gen_cntl |= CRTC_VGA_LINEAR;
+
+ /* Enable doublescan mode if requested */
+ if (vmode & FB_VMODE_DOUBLE)
+ crtc->gen_cntl |= CRTC_DBL_SCAN_EN;
+ /* Enable interlaced mode if requested */
+ if (vmode & FB_VMODE_INTERLACED)
+ crtc->gen_cntl |= CRTC_INTERLACE_EN;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ if (par->lcd_table != 0) {
+ vdisplay = yres;
+ if(vmode & FB_VMODE_DOUBLE)
+ vdisplay <<= 1;
+ if(vmode & FB_VMODE_INTERLACED) {
+ vdisplay >>= 1;
+
+ /* The prefered mode for the lcd is not interlaced, so disable it if
+ it was enabled. For doublescan there is no problem, because we can
+ compensate for it in the hardware stretching (we stretch half as much)
+ */
+ vmode &= ~FB_VMODE_INTERLACED;
+ /*crtc->gen_cntl &= ~CRTC_INTERLACE_EN;*/
+ }
+ crtc->gen_cntl &= ~(CRTC2_EN | CRTC2_PIX_WIDTH);
+ crtc->lcd_gen_cntl &= ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 |
+ /*TVCLK_PM_EN | VCLK_DAC_PM_EN |*/
+ USE_SHADOWED_VEND | USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN);
+ crtc->lcd_gen_cntl |= (DONT_SHADOW_VPAR/* | LOCK_8DOT*/);
+
+ /* MOBILITY M1 tested, FIXME: LT */
+ crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par);
+ if (!M64_HAS(LT_LCD_REGS))
+ crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par) &
+ ~(AUTO_VERT_RATIO | VERT_STRETCH_MODE | VERT_STRETCH_RATIO3);
+
+ crtc->horz_stretching &=
+ ~(HORZ_STRETCH_RATIO | HORZ_STRETCH_LOOP | AUTO_HORZ_RATIO |
+ HORZ_STRETCH_MODE | HORZ_STRETCH_EN);
+ if (xres < par->lcd_width) {
+ do {
+ /*
+ * The horizontal blender misbehaves when HDisplay is less than a
+ * a certain threshold (440 for a 1024-wide panel). It doesn't
+ * stretch such modes enough. Use pixel replication instead of
+ * blending to stretch modes that can be made to exactly fit the
+ * panel width. The undocumented "NoLCDBlend" option allows the
+ * pixel-replicated mode to be slightly wider or narrower than the
+ * panel width. It also causes a mode that is exactly half as wide
+ * as the panel to be pixel-replicated, rather than blended.
+ */
+ int HDisplay = xres & ~7;
+ int nStretch = par->lcd_width / HDisplay;
+ int Remainder = par->lcd_width % HDisplay;
+
+ if ((!Remainder && ((nStretch > 2))) ||
+ (((HDisplay * 16) / par->lcd_width) < 7)) {
+ static const char StretchLoops[] = {10, 12, 13, 15, 16};
+ int horz_stretch_loop = -1, BestRemainder;
+ int Numerator = HDisplay, Denominator = par->lcd_width;
+ int Index = 5;
+ ATIReduceRatio(&Numerator, &Denominator);
+
+ BestRemainder = (Numerator * 16) / Denominator;
+ while (--Index >= 0) {
+ Remainder = ((Denominator - Numerator) * StretchLoops[Index]) %
+ Denominator;
+ if (Remainder < BestRemainder) {
+ horz_stretch_loop = Index;
+ if (!(BestRemainder = Remainder))
+ break;
+ }
+ }
+
+ if ((horz_stretch_loop >= 0) && !BestRemainder) {
+ int horz_stretch_ratio = 0, Accumulator = 0;
+ int reuse_previous = 1;
+
+ Index = StretchLoops[horz_stretch_loop];
+
+ while (--Index >= 0) {
+ if (Accumulator > 0)
+ horz_stretch_ratio |= reuse_previous;
+ else
+ Accumulator += Denominator;
+ Accumulator -= Numerator;
+ reuse_previous <<= 1;
+ }
+
+ crtc->horz_stretching |= (HORZ_STRETCH_EN |
+ ((horz_stretch_loop & HORZ_STRETCH_LOOP) << 16) |
+ (horz_stretch_ratio & HORZ_STRETCH_RATIO));
+ break; /* Out of the do { ... } while (0) */
+ }
+ }
+
+ crtc->horz_stretching |= (HORZ_STRETCH_MODE | HORZ_STRETCH_EN |
+ (((HDisplay * (HORZ_STRETCH_BLEND + 1)) / par->lcd_width) & HORZ_STRETCH_BLEND));
+ } while (0);
+ }
+
+ if (vdisplay < par->lcd_height) {
+ crtc->vert_stretching = (VERT_STRETCH_USE0 | VERT_STRETCH_EN |
+ (((vdisplay * (VERT_STRETCH_RATIO0 + 1)) / par->lcd_height) & VERT_STRETCH_RATIO0));
+
+ if (!M64_HAS(LT_LCD_REGS) &&
+ xres <= (M64_HAS(MOBIL_BUS)?1024:800))
+ crtc->ext_vert_stretch |= VERT_STRETCH_MODE;
+ } else {
+ /*
+ * Don't use vertical blending if the mode is too wide or not
+ * vertically stretched.
+ */
+ crtc->vert_stretching = 0;
+ }
+ /* copy to shadow crtc */
+ crtc->shadow_h_tot_disp = crtc->h_tot_disp;
+ crtc->shadow_h_sync_strt_wid = crtc->h_sync_strt_wid;
+ crtc->shadow_v_tot_disp = crtc->v_tot_disp;
+ crtc->shadow_v_sync_strt_wid = crtc->v_sync_strt_wid;
+ }
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
+
if (M64_HAS(MAGIC_FIFO)) {
/* Not VTB/GTB */
/* FIXME: magic FIFO values */
- crtc->gen_cntl |=
- aty_ld_le32(CRTC_GEN_CNTL, par) & 0x000e0000;
+ crtc->gen_cntl |= (aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC2_PIX_WIDTH);
}
crtc->dp_pix_width = dp_pix_width;
crtc->dp_chain_mask = dp_chain_mask;
@@ -632,21 +1084,19 @@
return 0;
}
-
-static int aty_crtc_to_var(const struct crtc *crtc,
- struct fb_var_screeninfo *var)
+static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screeninfo *var)
{
u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;
u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid,
h_sync_pol;
u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
u32 pix_width;
+ u32 double_scan, interlace;
/* input */
h_total = crtc->h_tot_disp & 0x1ff;
h_disp = (crtc->h_tot_disp >> 16) & 0xff;
- h_sync_strt = (crtc->h_sync_strt_wid & 0xff) |
- ((crtc->h_sync_strt_wid >> 4) & 0x100);
+ h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | ((crtc->h_sync_strt_wid >> 4) & 0x100);
h_sync_dly = (crtc->h_sync_strt_wid >> 8) & 0x7;
h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x1f;
h_sync_pol = (crtc->h_sync_strt_wid >> 21) & 0x1;
@@ -657,6 +1107,8 @@
v_sync_pol = (crtc->v_sync_strt_wid >> 21) & 0x1;
c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;
pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
+ double_scan = crtc->gen_cntl & CRTC_DBL_SCAN_EN;
+ interlace = crtc->gen_cntl & CRTC_INTERLACE_EN;
/* convert */
xres = (h_disp + 1) * 8;
@@ -707,7 +1159,6 @@
var->transp.offset = 0;
var->transp.length = 0;
break;
-#if 0
case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */
bpp = 16;
var->red.offset = 11;
@@ -719,7 +1170,6 @@
var->transp.offset = 0;
var->transp.length = 0;
break;
-#endif
case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */
bpp = 24;
var->red.offset = 16;
@@ -760,6 +1210,21 @@
var->vsync_len = vslen;
var->sync = sync;
var->vmode = FB_VMODE_NONINTERLACED;
+ /* In double scan mode, the vertical parameters are doubled, so we need to
+ half them to get the right values.
+ In interlaced mode the values are already correct, so no correction is
+ necessary.
+ */
+ if (interlace)
+ var->vmode = FB_VMODE_INTERLACED;
+
+ if (double_scan) {
+ var->vmode = FB_VMODE_DOUBLE;
+ var->yres>>=1;
+ var->upper_margin>>=1;
+ var->lower_margin>>=1;
+ var->vsync_len>>=1;
+ }
return 0;
}
@@ -770,58 +1235,116 @@
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
struct fb_var_screeninfo *var = &info->var;
- u8 tmp;
- u32 i;
+ u32 tmp, pixclock;
int err;
+#ifdef DEBUG
+ struct fb_var_screeninfo debug;
+ u32 pixclock_in_ps;
+#endif
+ if (par->asleep)
+ return 0;
- if ((err = aty_var_to_crtc(info, var, &par->crtc)) ||
- (err = par->pll_ops->var_to_pll(info, var->pixclock,
- var->bits_per_pixel, &par->pll)))
+ if ((err = aty_var_to_crtc(info, var, &par->crtc)))
return err;
- par->accel_flags = var->accel_flags; /* hack */
+ pixclock = atyfb_get_pixclock(var, par);
+
+ if (pixclock == 0) {
+ FAIL("Invalid pixclock");
+ } else {
+ if((err = par->pll_ops->var_to_pll(info, pixclock, var->bits_per_pixel, &par->pll)))
+ return err;
+ }
+
+ par->accel_flags = var->accel_flags; /* hack */
if (par->blitter_may_be_busy)
wait_for_idle(par);
- tmp = aty_ld_8(CRTC_GEN_CNTL + 3, par);
- aty_set_crtc(par, &par->crtc);
- aty_st_8(CLOCK_CNTL + par->clk_wr_offset, 0, par);
- /* better call aty_StrobeClock ?? */
- aty_st_8(CLOCK_CNTL + par->clk_wr_offset, CLOCK_STROBE, par);
- par->dac_ops->set_dac(info, &par->pll, var->bits_per_pixel,
- par->accel_flags);
+ aty_set_crtc(par, &par->crtc);
+ par->dac_ops->set_dac(info, &par->pll, var->bits_per_pixel, par->accel_flags);
par->pll_ops->set_pll(info, &par->pll);
+#ifdef DEBUG
+ if(par->pll_ops && par->pll_ops->pll_to_var)
+ pixclock_in_ps = par->pll_ops->pll_to_var(info, &(par->pll));
+ else
+ pixclock_in_ps = 0;
+
+ if(0 == pixclock_in_ps) {
+ PRINTKE("ALERT ops->pll_to_var get 0\n");
+ pixclock_in_ps = pixclock;
+ }
+
+ memset(&debug, 0, sizeof(debug));
+ if(!aty_crtc_to_var(&(par->crtc), &debug)) {
+ u32 hSync, vRefresh;
+ u32 h_disp, h_sync_strt, h_sync_end, h_total;
+ u32 v_disp, v_sync_strt, v_sync_end, v_total;
+
+ h_disp = debug.xres;
+ h_sync_strt = h_disp + debug.right_margin;
+ h_sync_end = h_sync_strt + debug.hsync_len;
+ h_total = h_sync_end + debug.left_margin;
+ v_disp = debug.yres;
+ v_sync_strt = v_disp + debug.lower_margin;
+ v_sync_end = v_sync_strt + debug.vsync_len;
+ v_total = v_sync_end + debug.upper_margin;
+
+ hSync = 1000000000 / (pixclock_in_ps * h_total);
+ vRefresh = (hSync * 1000) / v_total;
+ if (par->crtc.gen_cntl & CRTC_INTERLACE_EN)
+ vRefresh *= 2;
+ if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN)
+ vRefresh /= 2;
+
+ DPRINTK("atyfb_set_par\n");
+ DPRINTK(" Set Visible Mode to %ix%i-%i\n", var->xres, var->yres, var->bits_per_pixel);
+ DPRINTK(" Virtual resolution %ix%i, pixclock_in_ps %i (calculated %i)\n",
+ var->xres_virtual, var->yres_virtual, pixclock, pixclock_in_ps);
+ DPRINTK(" Dot clock: %i MHz\n", 1000000 / pixclock_in_ps);
+ DPRINTK(" Horizontal sync: %i kHz\n", hSync);
+ DPRINTK(" Vertical refresh: %i Hz\n", vRefresh);
+ DPRINTK(" x style: %i.%03i %i %i %i %i %i %i %i %i\n",
+ 1000000 / pixclock_in_ps, 1000000 % pixclock_in_ps,
+ h_disp, h_sync_strt, h_sync_end, h_total,
+ v_disp, v_sync_strt, v_sync_end, v_total);
+ DPRINTK(" fb style: %i %i %i %i %i %i %i %i %i\n",
+ pixclock_in_ps,
+ debug.left_margin, h_disp, debug.right_margin, debug.hsync_len,
+ debug.upper_margin, v_disp, debug.lower_margin, debug.vsync_len);
+ }
+#endif /* DEBUG */
+
if (!M64_HAS(INTEGRATED)) {
/* Don't forget MEM_CNTL */
- i = aty_ld_le32(MEM_CNTL, par) & 0xf0ffffff;
+ tmp = aty_ld_le32(MEM_CNTL, par) & 0xf0ffffff;
switch (var->bits_per_pixel) {
case 8:
- i |= 0x02000000;
+ tmp |= 0x02000000;
break;
case 16:
- i |= 0x03000000;
+ tmp |= 0x03000000;
break;
case 32:
- i |= 0x06000000;
+ tmp |= 0x06000000;
break;
}
- aty_st_le32(MEM_CNTL, i, par);
+ aty_st_le32(MEM_CNTL, tmp, par);
} else {
- i = aty_ld_le32(MEM_CNTL, par) & 0xf00fffff;
+ tmp = aty_ld_le32(MEM_CNTL, par) & 0xf00fffff;
if (!M64_HAS(MAGIC_POSTDIV))
- i |= par->mem_refresh_rate << 20;
+ tmp |= par->mem_refresh_rate << 20;
switch (var->bits_per_pixel) {
case 8:
case 24:
- i |= 0x00000000;
+ tmp |= 0x00000000;
break;
case 16:
- i |= 0x04000000;
+ tmp |= 0x04000000;
break;
case 32:
- i |= 0x08000000;
+ tmp |= 0x08000000;
break;
}
if (M64_HAS(CT_BUS)) {
@@ -832,16 +1355,14 @@
aty_st_le32(BUS_CNTL, 0x680000f9, par);
} else if (M64_HAS(MOBIL_BUS)) {
aty_st_le32(DAC_CNTL, 0x80010102, par);
- aty_st_le32(BUS_CNTL, 0x7b33a040, par);
+ aty_st_le32(BUS_CNTL, 0x7b33a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par);
} else {
/* GT */
aty_st_le32(DAC_CNTL, 0x86010102, par);
- aty_st_le32(BUS_CNTL, 0x7b23a040, par);
- aty_st_le32(EXT_MEM_CNTL,
- aty_ld_le32(EXT_MEM_CNTL,
- par) | 0x5000001, par);
+ aty_st_le32(BUS_CNTL, 0x7b23a040 | (par->aux_start ? BUS_APER_REG_DIS : 0), par);
+ aty_st_le32(EXT_MEM_CNTL, aty_ld_le32(EXT_MEM_CNTL, par) | 0x5000001, par);
}
- aty_st_le32(MEM_CNTL, i, par);
+ aty_st_le32(MEM_CNTL, tmp, par);
}
aty_st_8(DAC_MASK, 0xff, par);
@@ -855,29 +1376,98 @@
#ifdef CONFIG_BOOTX_TEXT
btext_update_display(info->fix.smem_start,
- (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8,
- ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1,
- var->bits_per_pixel,
- par->crtc.vxres * var->bits_per_pixel / 8);
-#endif /* CONFIG_BOOTX_TEXT */
+ (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8,
+ ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1,
+ var->bits_per_pixel,
+ par->crtc.vxres * var->bits_per_pixel / 8);
+#endif /* CONFIG_BOOTX_TEXT */
+#if 0
+ /* switch to accelerator mode */
+ if (!(par->crtc.gen_cntl & CRTC_EXT_DISP_EN))
+ aty_st_le32(CRTC_GEN_CNTL, par->crtc.gen_cntl | CRTC_EXT_DISP_EN, par);
+#endif
+#ifdef DEBUG
+{
+ /* dump non shadow CRTC, pll, LCD registers */
+ int i; u32 base;
+
+ /* CRTC registers */
+ base = 0x2000;
+ printk("debug atyfb: Mach64 non-shadow register values:");
+ for (i = 0; i < 256; i = i+4) {
+ if(i%16 == 0) printk("\ndebug atyfb: 0x%04X: ", base + i);
+ printk(" %08X", aty_ld_le32(i, par));
+ }
+ printk("\n\n");
+
+#ifdef CONFIG_FB_ATY_CT
+ /* PLL registers */
+ base = 0x00;
+ printk("debug atyfb: Mach64 PLL register values:");
+ for (i = 0; i < 64; i++) {
+ if(i%16 == 0) printk("\ndebug atyfb: 0x%02X: ", base + i);
+ if(i%4 == 0) printk(" ");
+ printk("%02X", aty_ld_pll_ct(i, par));
+ }
+ printk("\n\n");
+#endif /* CONFIG_FB_ATY_CT */
+
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ if (par->lcd_table != 0) {
+ /* LCD registers */
+ base = 0x00;
+ printk("debug atyfb: LCD register values:");
+ if(M64_HAS(LT_LCD_REGS)) {
+ for(i = 0; i <= POWER_MANAGEMENT; i++) {
+ if(i == EXT_VERT_STRETCH)
+ continue;
+ printk("\ndebug atyfb: 0x%04X: ", lt_lcd_regs[i]);
+ printk(" %08X", aty_ld_lcd(i, par));
+ }
+
+ } else {
+ for (i = 0; i < 64; i++) {
+ if(i%4 == 0) printk("\ndebug atyfb: 0x%02X: ", base + i);
+ printk(" %08X", aty_ld_lcd(i, par));
+ }
+ }
+ printk("\n\n");
+ }
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
+}
+#endif /* DEBUG */
return 0;
}
-static int atyfb_check_var(struct fb_var_screeninfo *var,
- struct fb_info *info)
+static int atyfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
+ int err;
struct crtc crtc;
union aty_pll pll;
- int err;
+ u32 pixclock;
- if ((err = aty_var_to_crtc(info, var, &crtc)) ||
- (err = par->pll_ops->var_to_pll(info, var->pixclock,
- var->bits_per_pixel, &pll)))
+ memcpy(&pll, &(par->pll), sizeof(pll));
+
+ if((err = aty_var_to_crtc(info, var, &crtc)))
return err;
-#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */
- if (!fbmon_valid_timings(var->pixclock, htotal, vtotal, info))
+ pixclock = atyfb_get_pixclock(var, par);
+
+ if (pixclock == 0) {
+ FAIL("Invalid pixclock");
+ } else {
+ if((err = par->pll_ops->var_to_pll(info, pixclock, var->bits_per_pixel, &pll)))
+ return err;
+ }
+
+ if (var->accel_flags & FB_ACCELF_TEXT)
+ info->var.accel_flags = FB_ACCELF_TEXT;
+ else
+ info->var.accel_flags = 0;
+
+#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */
+ if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
return -EINVAL;
#endif
aty_crtc_to_var(&crtc, var);
@@ -885,17 +1475,14 @@
return 0;
}
-static void set_off_pitch(struct atyfb_par *par,
- const struct fb_info *info)
+static void set_off_pitch(struct atyfb_par *par, const struct fb_info *info)
{
u32 xoffset = info->var.xoffset;
u32 yoffset = info->var.yoffset;
u32 vxres = par->crtc.vxres;
u32 bpp = info->var.bits_per_pixel;
- par->crtc.off_pitch =
- ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19);
- aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
+ par->crtc.off_pitch = ((yoffset * vxres + xoffset) * bpp / 64) | (vxres << 19);
}
@@ -905,35 +1492,103 @@
static int atyfb_open(struct fb_info *info, int user)
{
-#ifdef __sparc__
struct atyfb_par *par = (struct atyfb_par *) info->par;
if (user) {
par->open++;
+#ifdef __sparc__
par->mmaped = 0;
- }
#endif
+ }
return (0);
}
-struct fb_var_screeninfo default_var = {
- /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
- 640, 480, 640, 480, 0, 0, 8, 0,
- {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
- 0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
- 0, FB_VMODE_NONINTERLACED
-};
+static irqreturn_t aty_irq(int irq, void *dev_id, struct pt_regs *fp)
+{
+ struct atyfb_par *par = dev_id;
+ int handled = 0;
+ u32 int_cntl;
-static int atyfb_release(struct fb_info *info, int user)
+ spin_lock(&par->int_lock);
+
+ int_cntl = aty_ld_le32(CRTC_INT_CNTL, par);
+
+ if (int_cntl & CRTC_VBLANK_INT) {
+ /* clear interrupt */
+ aty_st_le32(CRTC_INT_CNTL, (int_cntl & CRTC_INT_EN_MASK) | CRTC_VBLANK_INT_AK, par);
+ par->vblank.count++;
+ if (par->vblank.pan_display) {
+ par->vblank.pan_display = 0;
+ aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
+ }
+ wake_up_interruptible(&par->vblank.wait);
+ handled = 1;
+ }
+
+ spin_unlock(&par->int_lock);
+
+ return IRQ_RETVAL(handled);
+}
+
+static int aty_enable_irq(struct atyfb_par *par, int reenable)
{
-#ifdef __sparc__
- struct atyfb_par *par = (struct atyfb_par *) info->par;
+ u32 int_cntl;
+ if (!test_and_set_bit(0, &par->irq_flags)) {
+ if (request_irq(par->irq, aty_irq, SA_SHIRQ, "atyfb", par)) {
+ clear_bit(0, &par->irq_flags);
+ return -EINVAL;
+ }
+ spin_lock_irq(&par->int_lock);
+ int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
+ /* clear interrupt */
+ aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_AK, par);
+ /* enable interrupt */
+ aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par);
+ spin_unlock_irq(&par->int_lock);
+ } else if (reenable) {
+ spin_lock_irq(&par->int_lock);
+ int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
+ if (!(int_cntl & CRTC_VBLANK_INT_EN)) {
+ printk("atyfb: someone disabled IRQ [%08x]\n", int_cntl);
+ /* re-enable interrupt */
+ aty_st_le32(CRTC_INT_CNTL, int_cntl | CRTC_VBLANK_INT_EN, par );
+ }
+ spin_unlock_irq(&par->int_lock);
+ }
+
+ return 0;
+}
+
+static int aty_disable_irq(struct atyfb_par *par)
+{
+ u32 int_cntl;
+
+ if (test_and_clear_bit(0, &par->irq_flags)) {
+ if (par->vblank.pan_display) {
+ par->vblank.pan_display = 0;
+ aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
+ }
+ spin_lock_irq(&par->int_lock);
+ int_cntl = aty_ld_le32(CRTC_INT_CNTL, par) & CRTC_INT_EN_MASK;
+ /* disable interrupt */
+ aty_st_le32(CRTC_INT_CNTL, int_cntl & ~CRTC_VBLANK_INT_EN, par );
+ spin_unlock_irq(&par->int_lock);
+ free_irq(par->irq, par);
+ }
+
+ return 0;
+}
+
+static int atyfb_release(struct fb_info *info, int user)
+{
+ struct atyfb_par *par = (struct atyfb_par *) info->par;
if (user) {
par->open--;
mdelay(1);
wait_for_idle(par);
if (!par->open) {
+#ifdef __sparc__
int was_mmaped = par->mmaped;
par->mmaped = 0;
@@ -952,21 +1607,16 @@
else
var.accel_flags |= FB_ACCELF_TEXT;
if (var.yres == var.yres_virtual) {
- u32 vram =
- (info->fix.smem_len -
- (PAGE_SIZE << 2));
- var.yres_virtual =
- ((vram * 8) /
- var.bits_per_pixel) /
- var.xres_virtual;
+ u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2));
+ var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual;
if (var.yres_virtual < var.yres)
- var.yres_virtual =
- var.yres;
+ var.yres_virtual = var.yres;
}
}
- }
- }
#endif
+ aty_disable_irq(par);
+ }
+ }
return (0);
}
@@ -976,25 +1626,67 @@
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
*/
-static int atyfb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info)
+static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
u32 xres, yres, xoffset, yoffset;
xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8;
yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1;
+ if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN)
+ yres >>= 1;
xoffset = (var->xoffset + 7) & ~7;
yoffset = var->yoffset;
- if (xoffset + xres > par->crtc.vxres
- || yoffset + yres > par->crtc.vyres)
+ if (xoffset + xres > par->crtc.vxres || yoffset + yres > par->crtc.vyres)
return -EINVAL;
info->var.xoffset = xoffset;
info->var.yoffset = yoffset;
+ if (par->asleep)
+ return 0;
+
set_off_pitch(par, info);
+ if ((var->activate & FB_ACTIVATE_VBL) && !aty_enable_irq(par, 0)) {
+ par->vblank.pan_display = 1;
+ } else {
+ par->vblank.pan_display = 0;
+ aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
+ }
+
return 0;
}
+static int aty_waitforvblank(struct atyfb_par *par, u32 crtc)
+{
+ struct aty_interrupt *vbl;
+ unsigned int count;
+ int ret;
+
+ switch (crtc) {
+ case 0:
+ vbl = &par->vblank;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ ret = aty_enable_irq(par, 0);
+ if (ret)
+ return ret;
+
+ count = vbl->count;
+ ret = wait_event_interruptible_timeout(vbl->wait, count != vbl->count, HZ/10);
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret == 0) {
+ aty_enable_irq(par, 1);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+
#ifdef DEBUG
#define ATYIO_CLKR 0x41545900 /* ATY\00 */
#define ATYIO_CLKW 0x41545901 /* ATY\01 */
@@ -1004,6 +1696,8 @@
u8 pll_ref_div;
u8 mclk_fb_div;
u8 mclk_post_div; /* 1,2,3,4,8 */
+ u8 mclk_fb_mult; /* 2 or 4 */
+ u8 xclk_post_div; /* 1,2,3,4,8 */
u8 vclk_fb_div;
u8 vclk_post_div; /* 1,2,3,4,6,8,12 */
u32 dsp_xclks_per_row; /* 0-16383 */
@@ -1017,12 +1711,14 @@
#define ATYIO_FEATW 0x41545903 /* ATY\03 */
#endif
+#ifndef FBIO_WAITFORVSYNC
+#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
+#endif
+
static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg, struct fb_info *info)
+ u_long arg, struct fb_info *info)
{
-#if defined(__sparc__) || (defined(DEBUG) && defined(CONFIG_FB_ATY_CT))
struct atyfb_par *par = (struct atyfb_par *) info->par;
-#endif /* __sparc__ || DEBUG */
#ifdef __sparc__
struct fbtype fbtyp;
#endif
@@ -1036,31 +1732,43 @@
fbtyp.fb_depth = info->var.bits_per_pixel;
fbtyp.fb_cmsize = info->cmap.len;
fbtyp.fb_size = info->fix.smem_len;
- if (copy_to_user
- ((struct fbtype __user *) arg, &fbtyp, sizeof(fbtyp)))
+ if (copy_to_user((struct fbtype __user *) arg, &fbtyp, sizeof(fbtyp)))
return -EFAULT;
break;
-#endif /* __sparc__ */
+#endif /* __sparc__ */
+
+ case FBIO_WAITFORVSYNC:
+ {
+ u32 crtc;
+
+ if (get_user(crtc, (__u32 *) arg))
+ return -EFAULT;
+
+ return aty_waitforvblank(par, crtc);
+ }
+ break;
+
#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT)
case ATYIO_CLKR:
if (M64_HAS(INTEGRATED)) {
struct atyclk clk;
- union aty_pll *pll = par->pll;
+ union aty_pll *pll = &(par->pll);
u32 dsp_config = pll->ct.dsp_config;
u32 dsp_on_off = pll->ct.dsp_on_off;
clk.ref_clk_per = par->ref_clk_per;
clk.pll_ref_div = pll->ct.pll_ref_div;
clk.mclk_fb_div = pll->ct.mclk_fb_div;
clk.mclk_post_div = pll->ct.mclk_post_div_real;
+ clk.mclk_fb_mult = pll->ct.mclk_fb_mult;
+ clk.xclk_post_div = pll->ct.xclk_post_div_real;
clk.vclk_fb_div = pll->ct.vclk_fb_div;
clk.vclk_post_div = pll->ct.vclk_post_div_real;
clk.dsp_xclks_per_row = dsp_config & 0x3fff;
clk.dsp_loop_latency = (dsp_config >> 16) & 0xf;
clk.dsp_precision = (dsp_config >> 20) & 7;
- clk.dsp_on = dsp_on_off & 0x7ff;
- clk.dsp_off = (dsp_on_off >> 16) & 0x7ff;
- if (copy_to_user
- ((struct atyclk *) arg, &clk, sizeof(clk)))
+ clk.dsp_off = dsp_on_off & 0x7ff;
+ clk.dsp_on = (dsp_on_off >> 16) & 0x7ff;
+ if (copy_to_user((struct atyclk *) arg, &clk, sizeof(clk)))
return -EFAULT;
} else
return -EINVAL;
@@ -1068,27 +1776,21 @@
case ATYIO_CLKW:
if (M64_HAS(INTEGRATED)) {
struct atyclk clk;
- union aty_pll *pll = par->pll;
- if (copy_from_user
- (&clk, (struct atyclk *) arg, sizeof(clk)))
+ union aty_pll *pll = &(par->pll);
+ if (copy_from_user(&clk, (struct atyclk *) arg, sizeof(clk)))
return -EFAULT;
par->ref_clk_per = clk.ref_clk_per;
pll->ct.pll_ref_div = clk.pll_ref_div;
pll->ct.mclk_fb_div = clk.mclk_fb_div;
pll->ct.mclk_post_div_real = clk.mclk_post_div;
+ pll->ct.mclk_fb_mult = clk.mclk_fb_mult;
+ pll->ct.xclk_post_div_real = clk.xclk_post_div;
pll->ct.vclk_fb_div = clk.vclk_fb_div;
pll->ct.vclk_post_div_real = clk.vclk_post_div;
- pll->ct.dsp_config =
- (clk.
- dsp_xclks_per_row & 0x3fff) | ((clk.
- dsp_loop_latency
- & 0xf) << 16)
- | ((clk.dsp_precision & 7) << 20);
- pll->ct.dsp_on_off =
- (clk.
- dsp_on & 0x7ff) | ((clk.
- dsp_off & 0x7ff) << 16);
- aty_calc_pll_ct(info, &pll->ct);
+ pll->ct.dsp_config = (clk.dsp_xclks_per_row & 0x3fff) |
+ ((clk.dsp_loop_latency & 0xf)<<16)| ((clk.dsp_precision & 7)<<20);
+ pll->ct.dsp_on_off = (clk.dsp_off & 0x7ff) | ((clk.dsp_on & 0x7ff)<<16);
+ /*aty_calc_pll_ct(info, &pll->ct);*/
aty_set_pll_ct(info, pll);
} else
return -EINVAL;
@@ -1101,7 +1803,7 @@
if (put_user(par->features, (u32 *) arg))
return -EFAULT;
break;
-#endif /* DEBUG && CONFIG_FB_ATY_CT */
+#endif /* DEBUG && CONFIG_FB_ATY_CT */
default:
return -EINVAL;
}
@@ -1118,8 +1820,7 @@
}
#ifdef __sparc__
-static int atyfb_mmap(struct fb_info *info, struct file *file,
- struct vm_area_struct *vma)
+static int atyfb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
unsigned int size, page, map_size = 0;
@@ -1243,83 +1944,22 @@
info->var.yoffset = atyfb_save.yoffset;
set_off_pitch(par, info);
}
+ aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, par);
break;
}
}
}
-#endif /* __sparc__ */
-
+#endif /* __sparc__ */
-#ifdef CONFIG_PMAC_PBOOK
-static struct fb_info *first_display = NULL;
+#if defined(CONFIG_PM) && defined(CONFIG_PCI)
/* Power management routines. Those are used for PowerBook sleep.
- *
- * It appears that Rage LT and Rage LT Pro have different power
- * management registers. There's is some confusion about which
- * chipID is a Rage LT or LT pro :(
*/
-static int aty_power_mgmt_LT(int sleep, struct atyfb_par *par)
-{
- unsigned int pm;
- int timeout;
-
- pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
- pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
- aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
- pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
-
- timeout = 200000;
- if (sleep) {
- /* Sleep */
- pm &= ~PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
- pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
- udelay(10);
- pm &= ~(PWR_BLON | AUTO_PWR_UP);
- pm |= SUSPEND_NOW;
- aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
- pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
- udelay(10);
- pm |= PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
- do {
- pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
- udelay(10);
- if ((--timeout) == 0)
- break;
- } while ((pm & PWR_MGT_STATUS_MASK) !=
- PWR_MGT_STATUS_SUSPEND);
- } else {
- /* Wakeup */
- pm &= ~PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
- pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
- udelay(10);
- pm |= (PWR_BLON | AUTO_PWR_UP);
- pm &= ~SUSPEND_NOW;
- aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
- pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
- udelay(10);
- pm |= PWR_MGT_ON;
- aty_st_le32(POWER_MANAGEMENT_LG, pm, par);
- do {
- pm = aty_ld_le32(POWER_MANAGEMENT_LG, par);
- udelay(10);
- if ((--timeout) == 0)
- break;
- } while ((pm & PWR_MGT_STATUS_MASK) != 0);
- }
- mdelay(500);
-
- return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
-}
-
-static int aty_power_mgmt_LTPro(int sleep, struct atyfb_par *par)
+static int aty_power_mgmt(int sleep, struct atyfb_par *par)
{
- unsigned int pm;
+ u32 pm;
int timeout;
pm = aty_ld_lcd(POWER_MANAGEMENT, par);
@@ -1327,7 +1967,7 @@
aty_st_lcd(POWER_MANAGEMENT, pm, par);
pm = aty_ld_lcd(POWER_MANAGEMENT, par);
- timeout = 200;
+ timeout = 2000;
if (sleep) {
/* Sleep */
pm &= ~PWR_MGT_ON;
@@ -1346,8 +1986,7 @@
mdelay(1);
if ((--timeout) == 0)
break;
- } while ((pm & PWR_MGT_STATUS_MASK) !=
- PWR_MGT_STATUS_SUSPEND);
+ } while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
} else {
/* Wakeup */
pm &= ~PWR_MGT_ON;
@@ -1368,88 +2007,92 @@
break;
} while ((pm & PWR_MGT_STATUS_MASK) != 0);
}
+ mdelay(500);
- return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
+ return timeout ? -1 : 0;
}
-static int aty_power_mgmt(int sleep, struct atyfb_par *par)
+static int atyfb_pci_suspend(struct pci_dev *pdev, u32 state)
{
- return M64_HAS(LT_SLEEP) ? aty_power_mgmt_LT(sleep, par)
- : aty_power_mgmt_LTPro(sleep, par);
+ struct fb_info *info = pci_get_drvdata(pdev);
+ struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+#ifdef CONFIG_PPC_PMAC
+ /* HACK ALERT ! Once I find a proper way to say to each driver
+ * individually what will happen with it's PCI slot, I'll change
+ * that. On laptops, the AGP slot is just unclocked, so D2 is
+ * expected, while on desktops, the card is powered off
+ */
+ if (state >= 3)
+ state = 2;
+#endif /* CONFIG_PPC_PMAC */
+
+ if (state != 2 || state == pdev->dev.power_state)
+ return 0;
+
+ acquire_console_sem();
+
+ fb_set_suspend(info, 1);
+
+ /* Idle & reset engine */
+ wait_for_idle(par);
+ aty_reset_engine(par);
+
+ /* Blank display and LCD */
+ atyfb_blank(VESA_POWERDOWN + 1, info);
+
+ par->asleep = 1;
+ par->lock_blank = 1;
+
+ /* Set chip to "suspend" mode */
+ if (aty_power_mgmt(1, par)) {
+ par->asleep = 0;
+ par->lock_blank = 0;
+ atyfb_blank(0, info);
+ fb_set_suspend(info, 0);
+ release_console_sem();
+ return -EIO;
+ }
+
+ release_console_sem();
+
+ pdev->dev.power_state = state;
+
+ return 0;
}
-/*
- * Save the contents of the frame buffer when we go to sleep,
- * and restore it when we wake up again.
- */
-static int aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
+static int atyfb_pci_resume(struct pci_dev *pdev)
{
- struct fb_info *info;
- struct atyfb_par *par;
- int result;
+ struct fb_info *info = pci_get_drvdata(pdev);
+ struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+ if (pdev->dev.power_state == 0)
+ return 0;
- result = PBOOK_SLEEP_OK;
+ acquire_console_sem();
- for (info = first_display; info != NULL; info = par->next) {
- int nb;
+ if (pdev->dev.power_state == 2)
+ aty_power_mgmt(0, par);
+ par->asleep = 0;
- par = (struct atyfb_par *) info->par;
- nb = info->var.yres * info->fix.line_length;
-
- switch (when) {
- case PBOOK_SLEEP_REQUEST:
- par->save_framebuffer = vmalloc(nb);
- if (par->save_framebuffer == NULL)
- return PBOOK_SLEEP_REFUSE;
- break;
- case PBOOK_SLEEP_REJECT:
- if (par->save_framebuffer) {
- vfree(par->save_framebuffer);
- par->save_framebuffer = NULL;
- }
- break;
- case PBOOK_SLEEP_NOW:
- if (par->blitter_may_be_busy)
- wait_for_idle(par);
- /* Stop accel engine (stop bus mastering) */
- if (par->accel_flags & FB_ACCELF_TEXT)
- aty_reset_engine(par);
-
- /* Backup fb content */
- if (par->save_framebuffer)
- memcpy_fromio(par->save_framebuffer,
- (void *) info->screen_base, nb);
-
- /* Blank display and LCD */
- atyfb_blank(VESA_POWERDOWN + 1, info);
-
- /* Set chip to "suspend" mode */
- result = aty_power_mgmt(1, par);
- break;
- case PBOOK_WAKE:
- /* Wakeup chip */
- result = aty_power_mgmt(0, par);
-
- /* Restore fb content */
- if (par->save_framebuffer) {
- memcpy_toio((void *) info->screen_base,
- par->save_framebuffer, nb);
- vfree(par->save_framebuffer);
- par->save_framebuffer = NULL;
- }
- /* Restore display */
- atyfb_set_par(info);
- atyfb_blank(0, info);
- break;
- }
- }
- return result;
+ /* Restore display */
+ atyfb_set_par(info);
+
+ /* Refresh */
+ fb_set_suspend(info, 0);
+
+ /* Unblank */
+ par->lock_blank = 0;
+ atyfb_blank(0, info);
+
+ release_console_sem();
+
+ pdev->dev.power_state = 0;
+
+ return 0;
}
-static struct pmu_sleep_notifier aty_sleep_notifier = {
- aty_sleep_notify, SLEEP_LEVEL_VIDEO,
-};
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* defined(CONFIG_PM) && defined(CONFIG_PCI) */
#ifdef CONFIG_PMAC_BACKLIGHT
@@ -1489,9 +2132,34 @@
aty_set_backlight_enable,
aty_set_backlight_level
};
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#endif /* CONFIG_PMAC_BACKLIGHT */
+static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
+{
+ const int ragepro_tbl[] = {
+ 44, 50, 55, 66, 75, 80, 100
+ };
+ const int ragexl_tbl[] = {
+ 50, 66, 75, 83, 90, 95, 100, 105,
+ 110, 115, 120, 125, 133, 143, 166
+ };
+ const int *refresh_tbl;
+ int i, size;
+
+ if (IS_XL(par->pci_id) || IS_MOBILITY(par->pci_id)) {
+ refresh_tbl = ragexl_tbl;
+ size = sizeof(ragexl_tbl)/sizeof(int);
+ } else {
+ refresh_tbl = ragepro_tbl;
+ size = sizeof(ragepro_tbl)/sizeof(int);
+ }
+ for (i=0; i < size; i++) {
+ if (xclk < refresh_tbl[i])
+ break;
+ }
+ par->mem_refresh_rate = i;
+}
/*
* Initialisation
@@ -1502,37 +2170,36 @@
static int __init aty_init(struct fb_info *info, const char *name)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
- const char *chipname = NULL, *ramname = NULL, *xtal;
- int j, pll, mclk, gtb_memsize;
+ const char *ramname = NULL, *xtal;
+ int gtb_memsize;
struct fb_var_screeninfo var;
- u32 chip_id, i;
- u16 type;
- u8 rev;
+ u8 pll_ref_div;
+ u32 i;
#if defined(CONFIG_PPC)
int sense;
#endif
- u8 pll_ref_div;
+
+ init_waitqueue_head(&par->vblank.wait);
+ spin_lock_init(&par->int_lock);
par->aty_cmap_regs =
(struct aty_cmap_regs *) (par->ati_regbase + 0xc0);
- chip_id = aty_ld_le32(CONFIG_CHIP_ID, par);
- type = chip_id & CFG_CHIP_TYPE;
- rev = (chip_id & CFG_CHIP_REV) >> 24;
- for (j = 0; j < (sizeof(aty_chips) / sizeof(*aty_chips)); j++)
- if (type == aty_chips[j].chip_type &&
- (rev & aty_chips[j].rev_mask) ==
- aty_chips[j].rev_val) {
- chipname = aty_chips[j].name;
- pll = aty_chips[j].pll;
- mclk = aty_chips[j].mclk;
- par->features = aty_chips[j].features;
- goto found;
- }
- printk("atyfb: Unknown mach64 0x%04x rev 0x%04x\n", type, rev);
- return 0;
- found:
- printk("atyfb: %s [0x%04x rev 0x%02x] ", chipname, type, rev);
+ if (pll)
+ par->pll_limits.pll_max = pll;
+ if (mclk)
+ par->pll_limits.mclk = mclk;
+ if (xclk)
+ par->pll_limits.xclk = xclk;
+
+ aty_calc_mem_refresh(par, par->pll_limits.xclk);
+ par->pll_per = 1000000/par->pll_limits.pll_max;
+ par->mclk_per = 1000000/par->pll_limits.mclk;
+ par->xclk_per = 1000000/par->pll_limits.xclk;
+
+ par->ref_clk_per = 1000000000000ULL / 14318180;
+ xtal = "14.31818";
+
#ifdef CONFIG_FB_ATY_GX
if (!M64_HAS(INTEGRATED)) {
u32 stat0;
@@ -1549,9 +2216,7 @@
if (dac_type == 0x07)
dac_subtype = DAC_ATT20C408;
else
- dac_subtype =
- (aty_ld_8(SCRATCH_REG1 + 1, par) & 0xF0) |
- dac_type;
+ dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, par) & 0xF0) | dac_type;
#else
dac_type = DAC_IBMRGB514;
dac_subtype = DAC_IBMRGB514;
@@ -1570,8 +2235,7 @@
par->dac_ops = &aty_dac_att21c498;
break;
default:
- printk
- (" atyfb_set_par: DAC type not implemented yet!\n");
+ PRINTKI("aty_init: DAC type not implemented yet!\n");
par->dac_ops = &aty_dac_unsupported;
break;
}
@@ -1592,33 +2256,30 @@
par->pll_ops = &aty_pll_ibm514;
break;
default:
- printk
- (" atyfb_set_par: CLK type not implemented yet!");
+ PRINTKI("aty_init: CLK type not implemented yet!");
par->pll_ops = &aty_pll_unsupported;
break;
}
}
-#endif /* CONFIG_FB_ATY_GX */
+#endif /* CONFIG_FB_ATY_GX */
#ifdef CONFIG_FB_ATY_CT
if (M64_HAS(INTEGRATED)) {
+ par->dac_ops = &aty_dac_ct;
+ par->pll_ops = &aty_pll_ct;
par->bus_type = PCI;
par->ram_type = (aty_ld_le32(CONFIG_STAT0, par) & 0x07);
ramname = aty_ct_ram[par->ram_type];
- par->dac_ops = &aty_dac_ct;
- par->pll_ops = &aty_pll_ct;
+
/* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */
- if (mclk == 67 && par->ram_type < SDRAM)
- mclk = 63;
+ if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM)
+ par->pll_limits.mclk = 63;
}
-#endif /* CONFIG_FB_ATY_CT */
- par->ref_clk_per = 1000000000000ULL / 14318180;
- xtal = "14.31818";
if (M64_HAS(GTB_DSP)
- && (pll_ref_div = aty_ld_pll(PLL_REF_DIV, par))) {
+ && (pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par))) {
int diff1, diff2;
- diff1 = 510 * 14 / pll_ref_div - pll;
- diff2 = 510 * 29 / pll_ref_div - pll;
+ diff1 = 510 * 14 / pll_ref_div - par->pll_limits.pll_max;
+ diff2 = 510 * 29 / pll_ref_div - par->pll_limits.pll_max;
if (diff1 < 0)
diff1 = -diff1;
if (diff2 < 0)
@@ -1628,6 +2289,12 @@
xtal = "29.498928";
}
}
+#endif /* CONFIG_FB_ATY_CT */
+
+ /* save previous video mode */
+ aty_get_crtc(par, &saved_crtc);
+ if(par->pll_ops->get_pll)
+ par->pll_ops->get_pll(info, &saved_pll);
i = aty_ld_le32(MEM_CNTL, par);
gtb_memsize = M64_HAS(GTB_DSP);
@@ -1682,8 +2349,8 @@
info->fix.smem_len += 0x400000;
}
- if (default_vram) {
- info->fix.smem_len = default_vram * 1024;
+ if (vram) {
+ info->fix.smem_len = vram * 1024;
i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
if (info->fix.smem_len <= 0x80000)
i |= MEM_SIZE_512K;
@@ -1701,7 +2368,7 @@
}
/*
- * Reg Block 0 (CT-compatible block) is at mmio_start
+ * Reg Block 0 (CT-compatible block) is at mmio_start
* Reg Block 1 (multimedia extensions) is at mmio_start - 0x400
*/
if (M64_HAS(GX)) {
@@ -1711,79 +2378,77 @@
info->fix.mmio_len = 0x400;
info->fix.accel = FB_ACCEL_ATI_MACH64CT;
} else if (M64_HAS(VT)) {
- info->fix.mmio_start = -0x400;
+ info->fix.mmio_start -= 0x400;
info->fix.mmio_len = 0x800;
info->fix.accel = FB_ACCEL_ATI_MACH64VT;
- } else { /* if (M64_HAS(GT)) */
-
- info->fix.mmio_start = -0x400;
+ } else {/* GT */
+ info->fix.mmio_start -= 0x400;
info->fix.mmio_len = 0x800;
info->fix.accel = FB_ACCEL_ATI_MACH64GT;
}
- if (default_pll)
- pll = default_pll;
- if (default_mclk)
- mclk = default_mclk;
-
- printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n",
- info->fix.smem_len ==
- 0x80000 ? 512 : (info->fix.smem_len >> 20),
- info->fix.smem_len == 0x80000 ? 'K' : 'M', ramname,
- xtal, pll, mclk);
-
- if (mclk < 44)
- par->mem_refresh_rate = 0; /* 000 = 10 Mhz - 43 Mhz */
- else if (mclk < 50)
- par->mem_refresh_rate = 1; /* 001 = 44 Mhz - 49 Mhz */
- else if (mclk < 55)
- par->mem_refresh_rate = 2; /* 010 = 50 Mhz - 54 Mhz */
- else if (mclk < 66)
- par->mem_refresh_rate = 3; /* 011 = 55 Mhz - 65 Mhz */
- else if (mclk < 75)
- par->mem_refresh_rate = 4; /* 100 = 66 Mhz - 74 Mhz */
- else if (mclk < 80)
- par->mem_refresh_rate = 5; /* 101 = 75 Mhz - 79 Mhz */
- else if (mclk < 100)
- par->mem_refresh_rate = 6; /* 110 = 80 Mhz - 100 Mhz */
- else
- par->mem_refresh_rate = 7; /* 111 = 100 Mhz and above */
- par->pll_per = 1000000 / pll;
- par->mclk_per = 1000000 / mclk;
+ PRINTKI("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK, %d MHz XCLK\n",
+ info->fix.smem_len == 0x80000 ? 512 : (info->fix.smem_len >> 20),
+ info->fix.smem_len == 0x80000 ? 'K' : 'M', ramname, xtal, par->pll_limits.pll_max,
+ par->pll_limits.mclk, par->pll_limits.xclk);
-#ifdef DEBUG
+#if defined(DEBUG) && defined(CONFIG_ATY_CT)
if (M64_HAS(INTEGRATED)) {
int i;
- printk
- ("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL "
- "DSP_CONFIG DSP_ON_OFF\n"
- "%08x %08x %08x %08x %08x %08x %08x\n"
- "PLL", aty_ld_le32(BUS_CNTL, par),
- aty_ld_le32(DAC_CNTL, par), aty_ld_le32(MEM_CNTL,
- par),
- aty_ld_le32(EXT_MEM_CNTL, par),
- aty_ld_le32(CRTC_GEN_CNTL, par),
- aty_ld_le32(DSP_CONFIG, par), aty_ld_le32(DSP_ON_OFF,
- par));
- for (i = 0; i < 16; i++)
- printk(" %02x", aty_ld_pll(i, par));
+ printk("debug atyfb: BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL "
+ "DSP_CONFIG DSP_ON_OFF CLOCK_CNTL\n"
+ "debug atyfb: %08x %08x %08x %08x %08x %08x %08x %08x\n"
+ "debug atyfb: PLL",
+ aty_ld_le32(BUS_CNTL, par), aty_ld_le32(DAC_CNTL, par),
+ aty_ld_le32(MEM_CNTL, par), aty_ld_le32(EXT_MEM_CNTL, par),
+ aty_ld_le32(CRTC_GEN_CNTL, par), aty_ld_le32(DSP_CONFIG, par),
+ aty_ld_le32(DSP_ON_OFF, par), aty_ld_le32(CLOCK_CNTL, par));
+ for (i = 0; i < 40; i++)
+ printk(" %02x", aty_ld_pll_ct(i, par));
printk("\n");
}
#endif
+ if(par->pll_ops->init_pll)
+ par->pll_ops->init_pll(info, &par->pll);
/*
* Last page of 8 MB (4 MB on ISA) aperture is MMIO
* FIXME: we should use the auxiliary aperture instead so we can access
* the full 8 MB of video RAM on 8 MB boards
*/
- if (info->fix.smem_len == 0x800000 ||
- (par->bus_type == ISA
- && info->fix.smem_len == 0x400000))
+
+ if (!par->aux_start &&
+ (info->fix.smem_len == 0x800000 || (par->bus_type == ISA && info->fix.smem_len == 0x400000)))
info->fix.smem_len -= GUI_RESERVE;
+ /*
+ * Disable register access through the linear aperture
+ * if the auxiliary aperture is used so we can access
+ * the full 8 MB of video RAM on 8 MB boards.
+ */
+ if (par->aux_start)
+ aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, par) | BUS_APER_REG_DIS, par);
+
+#ifdef CONFIG_MTRR
+ par->mtrr_aper = -1;
+ par->mtrr_reg = -1;
+ if (!nomtrr) {
+ /* Cover the whole resource. */
+ par->mtrr_aper = mtrr_add(par->res_start, par->res_size, MTRR_TYPE_WRCOMB, 1);
+ if (par->mtrr_aper >= 0 && !par->aux_start) {
+ /* Make a hole for mmio. */
+ par->mtrr_reg = mtrr_add(par->res_start + 0x800000 - GUI_RESERVE,
+ GUI_RESERVE, MTRR_TYPE_UNCACHABLE, 1);
+ if (par->mtrr_reg < 0) {
+ mtrr_del(par->mtrr_aper, 0, 0);
+ par->mtrr_aper = -1;
+ }
+ }
+ }
+#endif
+
/* Clear the video memory */
- fb_memset((void *) info->screen_base, 0,
- info->fix.smem_len);
+ fb_memset((void *) info->screen_base, 0, info->fix.smem_len);
info->fbops = &atyfb_ops;
info->pseudo_palette = pseudo_palette;
@@ -1792,18 +2457,12 @@
#ifdef CONFIG_PMAC_BACKLIGHT
if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) {
/* these bits let the 101 powerbook wake up from sleep -- paulus */
- aty_st_lcd(POWER_MANAGEMENT,
- aty_ld_lcd(POWER_MANAGEMENT, par)
+ aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par)
| (USE_F32KHZ | TRISTATE_MEM_EN), par);
- }
- if (M64_HAS(MOBIL_BUS))
- register_backlight_controller(&aty_backlight_controller,
- info, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ } else if (M64_HAS(MOBIL_BUS))
+ register_backlight_controller(&aty_backlight_controller, info, "ati");
+#endif /* CONFIG_PMAC_BACKLIGHT */
-#ifdef MODULE
- var = default_var;
-#else /* !MODULE */
memset(&var, 0, sizeof(var));
#ifdef CONFIG_PPC
if (_machine == _MACH_Pmac) {
@@ -1811,9 +2470,8 @@
* FIXME: The NVRAM stuff should be put in a Mac-specific file, as it
* applies to all Mac video cards
*/
- if (mode_option) {
- if (!mac_find_mode
- (&var, info, mode_option, 8))
+ if (mode) {
+ if (!mac_find_mode(&var, info, mode, 8))
var = default_var;
} else {
if (default_vmode == VMODE_CHOOSE) {
@@ -1829,484 +2487,948 @@
else
default_vmode = VMODE_640_480_67;
sense = read_aty_sense(par);
- printk(KERN_INFO
- "atyfb: monitor sense=%x, mode %d\n",
- sense,
- mac_map_monitor_sense(sense));
+ PRINTKI("monitor sense=%x, mode %d\n",
+ sense, mac_map_monitor_sense(sense));
}
- if (default_vmode <= 0
- || default_vmode > VMODE_MAX)
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_vmode = VMODE_640_480_60;
- if (default_cmode < CMODE_8
- || default_cmode > CMODE_32)
+ if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
default_cmode = CMODE_8;
- if (mac_vmode_to_var
- (default_vmode, default_cmode, &var))
+ if (mac_vmode_to_var(default_vmode, default_cmode, &var))
var = default_var;
}
} else
- if (!fb_find_mode
- (&var, info, mode_option, NULL, 0, NULL, 8))
- var = default_var;
-#else /* !CONFIG_PPC */
-#ifdef __sparc__
- if (mode_option) {
- if (!fb_find_mode
- (&var, info, mode_option, NULL, 0, NULL, 8))
- var = default_var;
- } else
+#endif /* !CONFIG_PPC */
+ if (!fb_find_mode(&var, info, mode, NULL, 0, &defmode, 8))
var = default_var;
-#else
- if (!fb_find_mode
- (&var, info, mode_option, NULL, 0, NULL, 8))
- var = default_var;
-#endif /* !__sparc__ */
-#endif /* !CONFIG_PPC */
-#endif /* !MODULE */
+
if (noaccel)
var.accel_flags &= ~FB_ACCELF_TEXT;
else
var.accel_flags |= FB_ACCELF_TEXT;
if (var.yres == var.yres_virtual) {
- u32 vram = (info->fix.smem_len - (PAGE_SIZE << 2));
- var.yres_virtual =
- ((vram * 8) / var.bits_per_pixel) / var.xres_virtual;
+ u32 videoram = (info->fix.smem_len - (PAGE_SIZE << 2));
+ var.yres_virtual = ((videoram * 8) / var.bits_per_pixel) / var.xres_virtual;
if (var.yres_virtual < var.yres)
var.yres_virtual = var.yres;
}
if (atyfb_check_var(&var, info)) {
- printk("atyfb: can't set default video mode\n");
- return 0;
+ PRINTKE("can't set default video mode\n");
+ goto aty_init_exit;
}
+
#ifdef __sparc__
atyfb_save_palette(par, 0);
#endif
#ifdef CONFIG_FB_ATY_CT
- if (curblink && M64_HAS(INTEGRATED))
- par->cursor = aty_init_cursor(info);
-#endif /* CONFIG_FB_ATY_CT */
+ if (!noaccel && M64_HAS(INTEGRATED))
+ aty_init_cursor(info);
+#endif /* CONFIG_FB_ATY_CT */
info->var = var;
fb_alloc_cmap(&info->cmap, 256, 0);
if (register_framebuffer(info) < 0)
- return 0;
+ goto aty_init_exit;
fb_list = info;
- printk("fb%d: %s frame buffer device on %s\n",
+ PRINTKI("fb%d: %s frame buffer device on %s\n",
info->node, info->fix.id, name);
- return 1;
+ return 0;
+
+aty_init_exit:
+ /* restore video mode */
+ aty_set_crtc(par, &saved_crtc);
+ par->pll_ops->set_pll(info, &saved_pll);
+
+#ifdef CONFIG_MTRR
+ if (par->mtrr_reg >= 0) {
+ mtrr_del(par->mtrr_reg, 0, 0);
+ par->mtrr_reg = -1;
+ }
+ if (par->mtrr_aper >= 0) {
+ mtrr_del(par->mtrr_aper, 0, 0);
+ par->mtrr_aper = -1;
+ }
+#endif
+ return -1;
}
-int __init atyfb_do_init(void)
+#ifdef CONFIG_ATARI
+static int __init store_video_par(char *video_str, unsigned char m64_num)
{
-#if defined(CONFIG_PCI)
- unsigned long addr, res_start, res_size;
- struct atyfb_par *default_par;
- struct pci_dev *pdev = NULL;
- struct fb_info *info;
- int i;
+ char *p;
+ unsigned long vmembase, size, guiregbase;
+
+ PRINTKI("store_video_par() '%s' \n", video_str);
+
+ if (!(p = strsep(&video_str, ";")) || !*p)
+ goto mach64_invalid;
+ vmembase = simple_strtoul(p, NULL, 0);
+ if (!(p = strsep(&video_str, ";")) || !*p)
+ goto mach64_invalid;
+ size = simple_strtoul(p, NULL, 0);
+ if (!(p = strsep(&video_str, ";")) || !*p)
+ goto mach64_invalid;
+ guiregbase = simple_strtoul(p, NULL, 0);
+
+ phys_vmembase[m64_num] = vmembase;
+ phys_size[m64_num] = size;
+ phys_guiregbase[m64_num] = guiregbase;
+ PRINTKI("stored them all: $%08lX $%08lX $%08lX \n", vmembase, size,
+ guiregbase);
+ return 0;
+
+ mach64_invalid:
+ phys_vmembase[m64_num] = 0;
+ return -1;
+}
+#endif /* CONFIG_ATARI */
+
+ /*
+ * Blank the display.
+ */
+
+static int atyfb_blank(int blank, struct fb_info *info)
+{
+ struct atyfb_par *par = (struct atyfb_par *) info->par;
+ u8 gen_cntl;
+
+ if (par->lock_blank || par->asleep)
+ return 0;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if ((_machine == _MACH_Pmac) && blank)
+ set_backlight_enable(0);
+#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
+ if (par->lcd_table && blank &&
+ (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
+ u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+ pm &= ~PWR_BLON;
+ aty_st_lcd(POWER_MANAGEMENT, pm, par);
+ }
+#endif
+
+ gen_cntl = aty_ld_8(CRTC_GEN_CNTL, par);
+ if (blank > 0)
+ switch (blank - 1) {
+ case VESA_NO_BLANKING:
+ gen_cntl |= 0x40;
+ break;
+ case VESA_VSYNC_SUSPEND:
+ gen_cntl |= 0x8;
+ break;
+ case VESA_HSYNC_SUSPEND:
+ gen_cntl |= 0x4;
+ break;
+ case VESA_POWERDOWN:
+ gen_cntl |= 0x4c;
+ break;
+ } else
+ gen_cntl &= ~(0x4c);
+ aty_st_8(CRTC_GEN_CNTL, gen_cntl, par);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if ((_machine == _MACH_Pmac) && !blank)
+ set_backlight_enable(1);
+#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
+ if (par->lcd_table && !blank &&
+ (aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
+ u32 pm = aty_ld_lcd(POWER_MANAGEMENT, par);
+ pm |= PWR_BLON;
+ aty_st_lcd(POWER_MANAGEMENT, pm, par);
+ }
+#endif
+
+ return 0;
+}
+
+static void aty_st_pal(u_int regno, u_int red, u_int green, u_int blue,
+ const struct atyfb_par *par)
+{
+#ifdef CONFIG_ATARI
+ out_8(&par->aty_cmap_regs->windex, regno);
+ out_8(&par->aty_cmap_regs->lut, red);
+ out_8(&par->aty_cmap_regs->lut, green);
+ out_8(&par->aty_cmap_regs->lut, blue);
+#else
+ writeb(regno, &par->aty_cmap_regs->windex);
+ writeb(red, &par->aty_cmap_regs->lut);
+ writeb(green, &par->aty_cmap_regs->lut);
+ writeb(blue, &par->aty_cmap_regs->lut);
+#endif
+}
+
+ /*
+ * Set a single color register. The values supplied are already
+ * rounded down to the hardware's capabilities (according to the
+ * entries in the var structure). Return != 0 for invalid regno.
+ * !! 4 & 8 = PSEUDO, > 8 = DIRECTCOLOR
+ */
+
+static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ struct atyfb_par *par = (struct atyfb_par *) info->par;
+ int i, depth;
+ u32 *pal = info->pseudo_palette;
+
+ depth = info->var.bits_per_pixel;
+ if (depth == 16)
+ depth = (info->var.green.length == 5) ? 15 : 16;
+
+ if (par->asleep)
+ return 0;
+
+ if (regno > 255 ||
+ (depth == 16 && regno > 63) ||
+ (depth == 15 && regno > 31))
+ return 1;
+
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ par->palette[regno].red = red;
+ par->palette[regno].green = green;
+ par->palette[regno].blue = blue;
+
+ if (regno < 16) {
+ switch (depth) {
+ case 15:
+ pal[regno] = (regno << 10) | (regno << 5) | regno;
+ break;
+ case 16:
+ pal[regno] = (regno << 11) | (regno << 5) | regno;
+ break;
+ case 24:
+ pal[regno] = (regno << 16) | (regno << 8) | regno;
+ break;
+ case 32:
+ i = (regno << 8) | regno;
+ pal[regno] = (i << 16) | i;
+ break;
+ }
+ }
+
+ i = aty_ld_8(DAC_CNTL, par) & 0xfc;
+ if (M64_HAS(EXTRA_BRIGHT))
+ i |= 0x2; /* DAC_CNTL | 0x2 turns off the extra brightness for gt */
+ aty_st_8(DAC_CNTL, i, par);
+ aty_st_8(DAC_MASK, 0xff, par);
+
+ if (M64_HAS(INTEGRATED)) {
+ if (depth == 16) {
+ if (regno < 32)
+ aty_st_pal(regno << 3, red,
+ par->palette[regno<<1].green,
+ blue, par);
+ red = par->palette[regno>>1].red;
+ blue = par->palette[regno>>1].blue;
+ regno <<= 2;
+ } else if (depth == 15) {
+ regno <<= 3;
+ for(i = 0; i < 8; i++) {
+ aty_st_pal(regno + i, red, green, blue, par);
+ }
+ }
+ }
+ aty_st_pal(regno, red, green, blue, par);
+
+ return 0;
+}
+
+#ifdef CONFIG_PCI
+
#ifdef __sparc__
+
+static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, struct fb_indo *info, unsigned long addr)
+{
extern void (*prom_palette) (int);
extern int con_is_present(void);
+
+ struct atyfb_par *par = info->par;
struct pcidev_cookie *pcp;
char prop[128];
- int node, len, j;
+ int node, len, i, j, ret;
u32 mem, chip_id;
-#else
- u16 tmp;
-#endif
-#ifdef __sparc__
/* Do not attach when we have a serial console. */
if (!con_is_present())
return -ENXIO;
-#endif
- while ((pdev =
- pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) {
- if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
- struct resource *rp;
-
- for (i =
- sizeof(aty_chips) / sizeof(*aty_chips) - 1;
- i >= 0; i--)
- if (pdev->device == aty_chips[i].pci_id)
- break;
- if (i < 0)
- continue;
+ /*
+ * Map memory-mapped registers.
+ */
+ par->ati_regbase = addr + 0x7ffc00UL;
+ info->fix.mmio_start = addr + 0x7ffc00UL;
- rp = &pdev->resource[0];
- if (rp->flags & IORESOURCE_IO)
- rp = &pdev->resource[1];
- addr = rp->start;
- if (!addr)
- continue;
+ /*
+ * Map in big-endian aperture.
+ */
+ info->screen_base = (char *) (addr + 0x800000UL);
+ info->fix.smem_start = addr + 0x800000UL;
- res_start = rp->start;
- res_size = rp->end - rp->start + 1;
- if (!request_mem_region
- (res_start, res_size, "atyfb"))
- continue;
+ /*
+ * Figure mmap addresses from PCI config space.
+ * Split Framebuffer in big- and little-endian halfs.
+ */
+ for (i = 0; i < 6 && pdev->resource[i].start; i++)
+ /* nothing */ ;
+ j = i + 4;
- info =
- kmalloc(sizeof(struct fb_info), GFP_ATOMIC);
- if (!info) {
- printk
- ("atyfb_init: can't alloc fb_info\n");
- return -ENXIO;
- }
- memset(info, 0, sizeof(struct fb_info));
+ par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC);
+ if (!_par->mmap_map) {
+ PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");
+ return -ENOMEM;
+ }
+ memset(par->mmap_map, 0, j * sizeof(*par->mmap_map));
- default_par =
- kmalloc(sizeof(struct atyfb_par), GFP_ATOMIC);
- if (!default_par) {
- printk
- ("atyfb_init: can't alloc atyfb_par\n");
- kfree(info);
- return -ENXIO;
- }
- memset(default_par, 0, sizeof(struct atyfb_par));
+ for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
+ struct resource *rp = &pdev->resource[i];
+ int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
+ unsigned long base;
+ u32 size, pbase;
- info->fix = atyfb_fix;
- info->par = default_par;
- info->device = &pdev->dev;
-#ifdef __sparc__
- /*
- * Map memory-mapped registers.
- */
- default_par->ati_regbase = addr + 0x7ffc00UL;
- info->fix.mmio_start = addr + 0x7ffc00UL;
+ base = rp->start;
- /*
- * Map in big-endian aperture.
- */
- info->screen_base = (char *) (addr + 0x800000UL);
- info->fix.smem_start = addr + 0x800000UL;
+ io = (rp->flags & IORESOURCE_IO);
- /*
- * Figure mmap addresses from PCI config space.
- * Split Framebuffer in big- and little-endian halfs.
- */
- for (i = 0; i < 6 && pdev->resource[i].start; i++)
- /* nothing */ ;
- j = i + 4;
-
- default_par->mmap_map =
- kmalloc(j * sizeof(*default_par->mmap_map),
- GFP_ATOMIC);
- if (!default_par->mmap_map) {
- printk
- ("atyfb_init: can't alloc mmap_map\n");
- kfree(default_par);
- kfree(info);
- release_mem_region(res_start, res_size);
- return -ENXIO;
+ size = rp->end - base + 1;
+
+ pci_read_config_dword(pdev, breg, &pbase);
+
+ if (io)
+ size &= ~1;
+
+ /*
+ * Map the framebuffer a second time, this time without
+ * the braindead _PAGE_IE setting. This is used by the
+ * fixed Xserver, but we need to maintain the old mapping
+ * to stay compatible with older ones...
+ */
+ if (base == addr) {
+ par->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK;
+ par->mmap_map[j].poff = base & PAGE_MASK;
+ par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
+ par->mmap_map[j].prot_mask = _PAGE_CACHE;
+ par->mmap_map[j].prot_flag = _PAGE_E;
+ j++;
+ }
+
+ /*
+ * Here comes the old framebuffer mapping with _PAGE_IE
+ * set for the big endian half of the framebuffer...
+ */
+ if (base == addr) {
+ par->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK;
+ par->mmap_map[j].poff = (base + 0x800000) & PAGE_MASK;
+ par->mmap_map[j].size = 0x800000;
+ par->mmap_map[j].prot_mask = _PAGE_CACHE;
+ par->mmap_map[j].prot_flag = _PAGE_E | _PAGE_IE;
+ size -= 0x800000;
+ j++;
+ }
+
+ par->mmap_map[j].voff = pbase & PAGE_MASK;
+ par->mmap_map[j].poff = base & PAGE_MASK;
+ par->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
+ par->mmap_map[j].prot_mask = _PAGE_CACHE;
+ par->mmap_map[j].prot_flag = _PAGE_E;
+ j++;
+ }
+
+ if((ret = correct_chipset(par)))
+ return ret;
+
+ if (IS_XL(pdev->device)) {
+ /*
+ * Fix PROMs idea of MEM_CNTL settings...
+ */
+ mem = aty_ld_le32(MEM_CNTL, par);
+ chip_id = aty_ld_le32(CONFIG_CHIP_ID, par);
+ if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) && !((chip_id >> 24) & 1)) {
+ switch (mem & 0x0f) {
+ case 3:
+ mem = (mem & ~(0x0f)) | 2;
+ break;
+ case 7:
+ mem = (mem & ~(0x0f)) | 3;
+ break;
+ case 9:
+ mem = (mem & ~(0x0f)) | 4;
+ break;
+ case 11:
+ mem = (mem & ~(0x0f)) | 5;
+ break;
+ default:
+ break;
}
- memset(default_par->mmap_map, 0,
- j * sizeof(*default_par->mmap_map));
+ if ((aty_ld_le32(CONFIG_STAT0, par) & 7) >= SDRAM)
+ mem &= ~(0x00700000);
+ }
+ mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */
+ aty_st_le32(MEM_CNTL, mem, par);
+ }
- for (i = 0, j = 2;
- i < 6 && pdev->resource[i].start; i++) {
- struct resource *rp = &pdev->resource[i];
- int io, breg =
- PCI_BASE_ADDRESS_0 + (i << 2);
- unsigned long base;
- u32 size, pbase;
+ /*
+ * If this is the console device, we will set default video
+ * settings to what the PROM left us with.
+ */
+ node = prom_getchild(prom_root_node);
+ node = prom_searchsiblings(node, "aliases");
+ if (node) {
+ len = prom_getproperty(node, "screen", prop, sizeof(prop));
+ if (len > 0) {
+ prop[len] = '\0';
+ node = prom_finddevice(prop);
+ } else
+ node = 0;
+ }
- base = rp->start;
+ pcp = pdev->sysdata;
+ if (node == pcp->prom_node) {
+ struct fb_var_screeninfo *var = &default_var;
+ unsigned int N, P, Q, M, T, R;
+ u32 v_total, h_total;
+ struct crtc crtc;
+ u8 pll_regs[16];
+ u8 clock_cntl;
+
+ crtc.vxres = prom_getintdefault(node, "width", 1024);
+ crtc.vyres = prom_getintdefault(node, "height", 768);
+ var->bits_per_pixel = prom_getintdefault(node, "depth", 8);
+ var->xoffset = var->yoffset = 0;
+ crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par);
+ crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par);
+ crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par);
+ crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par);
+ crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
+ aty_crtc_to_var(&crtc, var);
- io = (rp->flags & IORESOURCE_IO);
+ h_total = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+ v_total = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
- size = rp->end - base + 1;
+ /*
+ * Read the PLL to figure actual Refresh Rate.
+ */
+ clock_cntl = aty_ld_8(CLOCK_CNTL, par);
+ /* DPRINTK("CLOCK_CNTL %02x\n", clock_cntl); */
+ for (i = 0; i < 16; i++)
+ pll_regs[i] = aty_ld_pll_ct(i, par);
- pci_read_config_dword(pdev, breg, &pbase);
+ /*
+ * PLL Reference Divider M:
+ */
+ M = pll_regs[2];
- if (io)
- size &= ~1;
+ /*
+ * PLL Feedback Divider N (Dependant on CLOCK_CNTL):
+ */
+ N = pll_regs[7 + (clock_cntl & 3)];
- /*
- * Map the framebuffer a second time, this time without
- * the braindead _PAGE_IE setting. This is used by the
- * fixed Xserver, but we need to maintain the old mapping
- * to stay compatible with older ones...
- */
- if (base == addr) {
- default_par->mmap_map[j].voff =
- (pbase +
- 0x10000000) & PAGE_MASK;
- default_par->mmap_map[j].poff =
- base & PAGE_MASK;
- default_par->mmap_map[j].size =
- (size +
- ~PAGE_MASK) & PAGE_MASK;
- default_par->mmap_map[j].prot_mask =
- _PAGE_CACHE;
- default_par->mmap_map[j].prot_flag =
- _PAGE_E;
- j++;
- }
+ /*
+ * PLL Post Divider P (Dependant on CLOCK_CNTL):
+ */
+ P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1));
- /*
- * Here comes the old framebuffer mapping with _PAGE_IE
- * set for the big endian half of the framebuffer...
- */
- if (base == addr) {
- default_par->mmap_map[j].voff =
- (pbase + 0x800000) & PAGE_MASK;
- default_par->mmap_map[j].poff =
- (base + 0x800000) & PAGE_MASK;
- default_par->mmap_map[j].size = 0x800000;
- default_par->mmap_map[j].prot_mask =
- _PAGE_CACHE;
- default_par->mmap_map[j].prot_flag =
- _PAGE_E | _PAGE_IE;
- size -= 0x800000;
- j++;
- }
+ /*
+ * PLL Divider Q:
+ */
+ Q = N / P;
- default_par->mmap_map[j].voff = pbase & PAGE_MASK;
- default_par->mmap_map[j].poff = base & PAGE_MASK;
- default_par->mmap_map[j].size =
- (size + ~PAGE_MASK) & PAGE_MASK;
- default_par->mmap_map[j].prot_mask = _PAGE_CACHE;
- default_par->mmap_map[j].prot_flag = _PAGE_E;
- j++;
- }
+ /*
+ * Target Frequency:
+ *
+ * T * M
+ * Q = -------
+ * 2 * R
+ *
+ * where R is XTALIN (= 14318 or 29498 kHz).
+ */
+ if (IS_XL(pdev->device))
+ R = 29498;
+ else
+ R = 14318;
- if (pdev->device != XL_CHIP_ID) {
- /*
- * Fix PROMs idea of MEM_CNTL settings...
- */
- mem = aty_ld_le32(MEM_CNTL, default_par);
- chip_id = aty_ld_le32(CONFIG_CHIP_ID, default_par);
- if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID)
- && !((chip_id >> 24) & 1)) {
- switch (mem & 0x0f) {
- case 3:
- mem = (mem & ~(0x0f)) | 2;
- break;
- case 7:
- mem = (mem & ~(0x0f)) | 3;
- break;
- case 9:
- mem = (mem & ~(0x0f)) | 4;
- break;
- case 11:
- mem = (mem & ~(0x0f)) | 5;
- break;
- default:
- break;
- }
- if ((aty_ld_le32(CONFIG_STAT0, default_par) & 7) >= SDRAM)
- mem &= ~(0x00700000);
- }
- mem &= ~(0xcf80e000); /* Turn off all undocumented bits. */
- aty_st_le32(MEM_CNTL, mem, default_par);
- }
+ T = 2 * Q * R / M;
- /*
- * If this is the console device, we will set default video
- * settings to what the PROM left us with.
- */
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(node, "aliases");
- if (node) {
- len =
- prom_getproperty(node, "screen", prop,
- sizeof(prop));
- if (len > 0) {
- prop[len] = '\0';
- node = prom_finddevice(prop);
+ default_var.pixclock = 1000000000 / T;
+ }
+
+ return 0;
+}
+
+#else /* __sparc__ */
+
+#ifdef __i386__
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+void aty_init_lcd(struct atyfb_par *par, u32 bios_base)
+{
+ u32 driv_inf_tab, sig;
+ u16 lcd_ofs;
+
+ /* To support an LCD panel, we should know it's dimensions and
+ * it's desired pixel clock.
+ * There are two ways to do it:
+ * - Check the startup video mode and calculate the panel
+ * size from it. This is unreliable.
+ * - Read it from the driver information table in the video BIOS.
+ */
+ /* Address of driver information table is at offset 0x78. */
+ driv_inf_tab = bios_base + *((u16 *)(bios_base+0x78));
+
+ /* Check for the driver information table signature. */
+ sig = (*(u32 *)driv_inf_tab);
+ if ((sig == 0x54504c24) || /* Rage LT pro */
+ (sig == 0x544d5224) || /* Rage mobility */
+ (sig == 0x54435824) || /* Rage XC */
+ (sig == 0x544c5824)) { /* Rage XL */
+ PRINTKI("BIOS contains driver information table.\n");
+ lcd_ofs = (*(u16 *)(driv_inf_tab + 10));
+ par->lcd_table = 0;
+ if (lcd_ofs != 0) {
+ par->lcd_table = bios_base + lcd_ofs;
+ }
+ }
+
+ if (par->lcd_table != 0) {
+ char model[24];
+ char strbuf[16];
+ char refresh_rates_buf[100];
+ int id, tech, f, i, m, default_refresh_rate;
+ char *txtcolour;
+ char *txtmonitor;
+ char *txtdual;
+ char *txtformat;
+ u16 width, height, panel_type, refresh_rates;
+ u16 *lcdmodeptr;
+ u32 format;
+ u8 lcd_refresh_rates[16] = {50,56,60,67,70,72,75,76,85,90,100,120,140,150,160,200};
+ /* The most important information is the panel size at
+ * offset 25 and 27, but there's some other nice information
+ * which we print to the screen.
+ */
+ id = *(u8 *)par->lcd_table;
+ strncpy(model,(char *)par->lcd_table+1,24);
+ model[23]=0;
+
+ width = par->lcd_width = *(u16 *)(par->lcd_table+25);
+ height = par->lcd_height = *(u16 *)(par->lcd_table+27);
+ panel_type = *(u16 *)(par->lcd_table+29);
+ if (panel_type & 1)
+ txtcolour = "colour";
+ else
+ txtcolour = "monochrome";
+ if (panel_type & 2)
+ txtdual = "dual (split) ";
+ else
+ txtdual = "";
+ tech = (panel_type>>2) & 63;
+ switch (tech) {
+ case 0:
+ txtmonitor = "passive matrix";
+ break;
+ case 1:
+ txtmonitor = "active matrix";
+ break;
+ case 2:
+ txtmonitor = "active addressed STN";
+ break;
+ case 3:
+ txtmonitor = "EL";
+ break;
+ case 4:
+ txtmonitor = "plasma";
+ break;
+ default:
+ txtmonitor = "unknown";
+ }
+ format = *(u32 *)(par->lcd_table+57);
+ if (tech == 0 || tech == 2) {
+ switch (format & 7) {
+ case 0:
+ txtformat = "12 bit interface";
+ break;
+ case 1:
+ txtformat = "16 bit interface";
+ break;
+ case 2:
+ txtformat = "24 bit interface";
+ break;
+ default:
+ txtformat = "unkown format";
+ }
+ } else {
+ switch (format & 7) {
+ case 0:
+ txtformat = "8 colours";
+ break;
+ case 1:
+ txtformat = "512 colours";
+ break;
+ case 2:
+ txtformat = "4096 colours";
+ break;
+ case 4:
+ txtformat = "262144 colours (LT mode)";
+ break;
+ case 5:
+ txtformat = "16777216 colours";
+ break;
+ case 6:
+ txtformat = "262144 colours (FDPI-2 mode)";
+ break;
+ default:
+ txtformat = "unkown format";
+ }
+ }
+ PRINTKI("%s%s %s monitor detected: %s\n",
+ txtdual ,txtcolour, txtmonitor, model);
+ PRINTKI(" id=%d, %dx%d pixels, %s\n",
+ id, width, height, txtformat);
+ refresh_rates_buf[0] = 0;
+ refresh_rates = *(u16 *)(par->lcd_table+62);
+ m = 1;
+ f = 0;
+ for (i=0;i<16;i++) {
+ if (refresh_rates & m) {
+ if (f == 0) {
+ sprintf(strbuf, "%d", lcd_refresh_rates[i]);
+ f++;
} else {
- node = 0;
+ sprintf(strbuf, ",%d", lcd_refresh_rates[i]);
}
+ strcat(refresh_rates_buf,strbuf);
+ }
+ m = m << 1;
+ }
+ default_refresh_rate = (*(u8 *)(par->lcd_table+61) & 0xf0) >> 4;
+ PRINTKI(" supports refresh rates [%s], default %d Hz\n",
+ refresh_rates_buf, lcd_refresh_rates[default_refresh_rate]);
+ par->lcd_refreshrate = lcd_refresh_rates[default_refresh_rate];
+ /* We now need to determine the crtc parameters for the
+ * lcd monitor. This is tricky, because they are not stored
+ * individually in the BIOS. Instead, the BIOS contains a
+ * table of display modes that work for this monitor.
+ *
+ * The idea is that we search for a mode of the same dimensions
+ * as the dimensions of the lcd monitor. Say our lcd monitor
+ * is 800x600 pixels, we search for a 800x600 monitor.
+ * The CRTC parameters we find here are the ones that we need
+ * to use to simulate other resolutions on the lcd screen.
+ */
+ lcdmodeptr = (u16 *)(par->lcd_table + 64);
+ while (*lcdmodeptr != 0) {
+ u32 modeptr;
+ u16 mwidth, mheight, lcd_hsync_start, lcd_vsync_start;
+ modeptr = bios_base + *lcdmodeptr;
+
+ mwidth = *((u16 *)(modeptr+0));
+ mheight = *((u16 *)(modeptr+2));
+
+ if (mwidth == width && mheight == height) {
+ par->lcd_pixclock = 100000000 / *((u16 *)(modeptr+9));
+ par->lcd_htotal = *((u16 *)(modeptr+17)) & 511;
+ par->lcd_hdisp = *((u16 *)(modeptr+19)) & 511;
+ lcd_hsync_start = *((u16 *)(modeptr+21)) & 511;
+ par->lcd_hsync_dly = (*((u16 *)(modeptr+21)) >> 9) & 7;
+ par->lcd_hsync_len = *((u8 *)(modeptr+23)) & 63;
+
+ par->lcd_vtotal = *((u16 *)(modeptr+24)) & 2047;
+ par->lcd_vdisp = *((u16 *)(modeptr+26)) & 2047;
+ lcd_vsync_start = *((u16 *)(modeptr+28)) & 2047;
+ par->lcd_vsync_len = (*((u16 *)(modeptr+28)) >> 11) & 31;
+
+ par->lcd_htotal = (par->lcd_htotal + 1) * 8;
+ par->lcd_hdisp = (par->lcd_hdisp + 1) * 8;
+ lcd_hsync_start = (lcd_hsync_start + 1) * 8;
+ par->lcd_hsync_len = par->lcd_hsync_len * 8;
+
+ par->lcd_vtotal++;
+ par->lcd_vdisp++;
+ lcd_vsync_start++;
+
+ par->lcd_right_margin = lcd_hsync_start - par->lcd_hdisp;
+ par->lcd_lower_margin = lcd_vsync_start - par->lcd_vdisp;
+ par->lcd_hblank_len = par->lcd_htotal - par->lcd_hdisp;
+ par->lcd_vblank_len = par->lcd_vtotal - par->lcd_vdisp;
+ break;
}
- pcp = pdev->sysdata;
- if (node == pcp->prom_node) {
+ lcdmodeptr++;
+ }
+ if (*lcdmodeptr == 0) {
+ PRINTKE("LCD monitor CRTC parameters not found!!!\n");
+ /* To do: Switch to CRT if possible. */
+ } else {
+ PRINTKI(" LCD CRTC parameters: %d.%d %d %d %d %d %d %d %d %d\n",
+ 1000000 / par->lcd_pixclock, 1000000 % par->lcd_pixclock,
+ par->lcd_hdisp,
+ par->lcd_hdisp + par->lcd_right_margin,
+ par->lcd_hdisp + par->lcd_right_margin
+ + par->lcd_hsync_dly + par->lcd_hsync_len,
+ par->lcd_htotal,
+ par->lcd_vdisp,
+ par->lcd_vdisp + par->lcd_lower_margin,
+ par->lcd_vdisp + par->lcd_lower_margin + par->lcd_vsync_len,
+ par->lcd_vtotal);
+ PRINTKI(" : %d %d %d %d %d %d %d %d %d\n",
+ par->lcd_pixclock,
+ par->lcd_hblank_len - (par->lcd_right_margin +
+ par->lcd_hsync_dly + par->lcd_hsync_len),
+ par->lcd_hdisp,
+ par->lcd_right_margin,
+ par->lcd_hsync_len,
+ par->lcd_vblank_len - (par->lcd_lower_margin + par->lcd_vsync_len),
+ par->lcd_vdisp,
+ par->lcd_lower_margin,
+ par->lcd_vsync_len);
+ }
+ }
+}
+#endif /* CONFIG_FB_ATY_GENERIC_LCD */
+
+static int __devinit init_from_bios(struct atyfb_par *par)
+{
+ u32 bios_base, rom_addr;
+ int ret;
+
+ rom_addr = 0xc0000 + ((aty_ld_le32(SCRATCH_REG1, par) & 0x7f) << 11);
+ bios_base = (unsigned long)ioremap(rom_addr, 0x10000);
+
+ /* The BIOS starts with 0xaa55. */
+ if (*((u16 *)bios_base) == 0xaa55) {
+
+ u8 *bios_ptr;
+ u16 rom_table_offset, freq_table_offset;
+ PLL_BLOCK_MACH64 pll_block;
+
+ PRINTKI("Mach64 BIOS is located at %x, mapped at %x.\n", rom_addr, bios_base);
+
+ /* check for frequncy table */
+ bios_ptr = (u8*)bios_base;
+ rom_table_offset = (u16)(bios_ptr[0x48] | (bios_ptr[0x49] << 8));
+ freq_table_offset = bios_ptr[rom_table_offset + 16] | (bios_ptr[rom_table_offset + 17] << 8);
+ memcpy(&pll_block, bios_ptr + freq_table_offset, sizeof(PLL_BLOCK_MACH64));
+
+ PRINTKI("BIOS frequency table:\n");
+ PRINTKI("PCLK_min_freq %d, PCLK_max_freq %d, ref_freq %d, ref_divider %d\n",
+ pll_block.PCLK_min_freq, pll_block.PCLK_max_freq,
+ pll_block.ref_freq, pll_block.ref_divider);
+ PRINTKI("MCLK_pwd %d, MCLK_max_freq %d, XCLK_max_freq %d, SCLK_freq %d\n",
+ pll_block.MCLK_pwd, pll_block.MCLK_max_freq,
+ pll_block.XCLK_max_freq, pll_block.SCLK_freq);
+
+ par->pll_limits.pll_min = pll_block.PCLK_min_freq/100;
+ par->pll_limits.pll_max = pll_block.PCLK_max_freq/100;
+ par->pll_limits.ref_clk = pll_block.ref_freq/100;
+ par->pll_limits.ref_div = pll_block.ref_divider;
+ par->pll_limits.sclk = pll_block.SCLK_freq/100;
+ par->pll_limits.mclk = pll_block.MCLK_max_freq/100;
+ par->pll_limits.mclk_pm = pll_block.MCLK_pwd/100;
+ par->pll_limits.xclk = pll_block.XCLK_max_freq/100;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ aty_init_lcd(par, bios_base);
+#endif
+ ret = 0;
+ } else {
+ PRINTKE("no BIOS frequency table found, use parameters\n");
+ ret = -ENXIO;
+ }
+ iounmap((void*)bios_base);
- struct fb_var_screeninfo *var =
- &default_var;
- unsigned int N, P, Q, M, T, R;
- u32 v_total, h_total;
- struct crtc crtc;
- u8 pll_regs[16];
- u8 clock_cntl;
-
- crtc.vxres =
- prom_getintdefault(node, "width",
- 1024);
- crtc.vyres =
- prom_getintdefault(node, "height",
- 768);
- var->bits_per_pixel =
- prom_getintdefault(node, "depth", 8);
- var->xoffset = var->yoffset = 0;
- crtc.h_tot_disp =
- aty_ld_le32(CRTC_H_TOTAL_DISP, default_par);
- crtc.h_sync_strt_wid =
- aty_ld_le32(CRTC_H_SYNC_STRT_WID,
- default_par);
- crtc.v_tot_disp =
- aty_ld_le32(CRTC_V_TOTAL_DISP, default_par);
- crtc.v_sync_strt_wid =
- aty_ld_le32(CRTC_V_SYNC_STRT_WID,
- default_par);
- crtc.gen_cntl =
- aty_ld_le32(CRTC_GEN_CNTL, default_par);
- aty_crtc_to_var(&crtc, var);
-
- h_total = var->xres + var->right_margin +
- var->hsync_len + var->left_margin;
- v_total = var->yres + var->lower_margin +
- var->vsync_len + var->upper_margin;
+ return ret;
+}
+#endif /* __i386__ */
- /*
- * Read the PLL to figure actual Refresh Rate.
- */
- clock_cntl = aty_ld_8(CLOCK_CNTL, default_par);
- /* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */
- for (i = 0; i < 16; i++)
- pll_regs[i] = aty_ld_pll(i, default_par);
+static int __devinit atyfb_setup_generic(struct pci_dev *pdev, struct fb_info *info, unsigned long addr)
+{
+ struct atyfb_par *par = info->par;
+ u16 tmp;
+ unsigned long raddr;
+ struct resource *rrp;
+ int ret = 0;
+
+ raddr = addr + 0x7ff000UL;
+ rrp = &pdev->resource[2];
+ if ((rrp->flags & IORESOURCE_MEM) && request_mem_region(rrp->start, rrp->end - rrp->start + 1, "atyfb")) {
+ par->aux_start = rrp->start;
+ par->aux_size = rrp->end - rrp->start + 1;
+ raddr = rrp->start;
+ PRINTKI("using auxiliary register aperture\n");
+ }
+
+ info->fix.mmio_start = raddr;
+ par->ati_regbase = ioremap(info->fix.mmio_start, 0x1000);
+ if (par->ati_regbase == 0)
+ return -ENOMEM;
- /*
- * PLL Reference Divider M:
- */
- M = pll_regs[2];
+ info->fix.mmio_start += par->aux_start ? 0x400 : 0xc00;
+ par->ati_regbase += par->aux_start ? 0x400 : 0xc00;
- /*
- * PLL Feedback Divider N (Dependant on CLOCK_CNTL):
- */
- N = pll_regs[7 + (clock_cntl & 3)];
+ /*
+ * Enable memory-space accesses using config-space
+ * command register.
+ */
+ pci_read_config_word(pdev, PCI_COMMAND, &tmp);
+ if (!(tmp & PCI_COMMAND_MEMORY)) {
+ tmp |= PCI_COMMAND_MEMORY;
+ pci_write_config_word(pdev, PCI_COMMAND, tmp);
+ }
+#ifdef __BIG_ENDIAN
+ /* Use the big-endian aperture */
+ addr += 0x800000;
+#endif
- /*
- * PLL Post Divider P (Dependant on CLOCK_CNTL):
- */
- P = 1 << (pll_regs[6] >>
- ((clock_cntl & 3) << 1));
+ /* Map in frame buffer */
+ info->fix.smem_start = addr;
+ info->screen_base = ioremap(addr, 0x800000);
+ if (info->screen_base == NULL) {
+ ret = -ENOMEM;
+ goto atyfb_setup_generic_fail;
+ }
+
+ if((ret = correct_chipset(par)))
+ goto atyfb_setup_generic_fail;
+#ifdef __i386__
+ if((ret = init_from_bios(par)))
+ goto atyfb_setup_generic_fail;
+#endif
+ if (!(aty_ld_le32(CRTC_GEN_CNTL, par) & CRTC_EXT_DISP_EN))
+ par->clk_wr_offset = (inb(R_GENMO) & 0x0CU) >> 2;
+ else
+ par->clk_wr_offset = aty_ld_8(CLOCK_CNTL, par) & 0x03U;
- /*
- * PLL Divider Q:
- */
- Q = N / P;
+ /* according to ATI, we should use clock 3 for acelerated mode */
+ par->clk_wr_offset = 3;
- /*
- * Target Frequency:
- *
- * T * M
- * Q = -------
- * 2 * R
- *
- * where R is XTALIN (= 14318 or 29498 kHz).
- */
- if (pdev->device == XL_CHIP_ID)
- R = 29498;
- else
- R = 14318;
+ return 0;
- T = 2 * Q * R / M;
+atyfb_setup_generic_fail:
+ iounmap(par->ati_regbase);
+ par->ati_regbase = 0;
+ return ret;
+}
- default_var.pixclock = 1000000000 / T;
- }
-#else /* __sparc__ */
+#endif /* !__sparc__ */
- info->fix.mmio_start = 0x7ff000 + addr;
- default_par->ati_regbase = (unsigned long)
- ioremap(info->fix.mmio_start, 0x1000);
+static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ unsigned long addr, res_start, res_size;
+ struct fb_info *info;
+ struct resource *rp;
+ struct atyfb_par *par;
+ int i, rc = -ENOMEM;
- if (!default_par->ati_regbase) {
-#ifdef __sparc__
- kfree(default_par->mmap_map);
-#endif
- kfree(default_par);
- kfree(info);
- release_mem_region(res_start, res_size);
- return -ENOMEM;
- }
+ for (i = sizeof(aty_chips) / sizeof(*aty_chips) - 1; i >= 0; i--)
+ if (pdev->device == aty_chips[i].pci_id)
+ break;
- info->fix.mmio_start += 0xc00;
- default_par->ati_regbase += 0xc00;
+ if (i < 0)
+ return -ENODEV;
- /*
- * Enable memory-space accesses using config-space
- * command register.
- */
- pci_read_config_word(pdev, PCI_COMMAND, &tmp);
- if (!(tmp & PCI_COMMAND_MEMORY)) {
- tmp |= PCI_COMMAND_MEMORY;
- pci_write_config_word(pdev, PCI_COMMAND,
- tmp);
- }
-#ifdef __BIG_ENDIAN
- /* Use the big-endian aperture */
- addr += 0x800000;
-#endif
+ /* Enable device in PCI config */
+ if (pci_enable_device(pdev)) {
+ PRINTKE("Cannot enable PCI device\n");
+ return -ENXIO;
+ }
+
+ /* Find which resource to use */
+ rp = &pdev->resource[0];
+ if (rp->flags & IORESOURCE_IO)
+ rp = &pdev->resource[1];
+ addr = rp->start;
+ if (!addr)
+ return -ENXIO;
- /* Map in frame buffer */
- info->fix.smem_start = addr;
- info->screen_base =
- (char *) ioremap(addr, 0x800000);
+ /* Reserve space */
+ res_start = rp->start;
+ res_size = rp->end - rp->start + 1;
+ if (!request_mem_region (res_start, res_size, "atyfb"))
+ return -EBUSY;
+
+ /* Allocate framebuffer */
+ info = framebuffer_alloc(sizeof(struct atyfb_par), &pdev->dev);
+ if (!info) {
+ PRINTKE("atyfb_pci_probe() can't alloc fb_info\n");
+ return -ENOMEM;
+ }
+ par = info->par;
+ info->fix = atyfb_fix;
+ info->device = &pdev->dev;
+ par->pci_id = aty_chips[i].pci_id;
+ par->res_start = res_start;
+ par->res_size = res_size;
+ par->irq = pdev->irq;
- if (!info->screen_base) {
+ /* Setup "info" structure */
#ifdef __sparc__
- kfree(default_par->mmap_map);
+ rc = atyfb_setup_sparc(pdev, info, addr);
+#else
+ rc = atyfb_setup_generic(pdev, info, addr);
#endif
- kfree(default_par);
- kfree(info);
- release_mem_region(res_start, res_size);
- return -ENXIO;
- }
-#endif /* __sparc__ */
+ if (rc)
+ goto err_release_mem;
+
+ pci_set_drvdata(pdev, info);
+
+ /* Init chip & register framebuffer */
+ if (aty_init(info, "PCI"))
+ goto err_release_io;
- if (!aty_init(info, "PCI")) {
-#ifdef __sparc__
- if (default_par->mmap_map)
- kfree(default_par->mmap_map);
-#endif
- kfree(default_par);
- kfree(info);
- release_mem_region(res_start, res_size);
- return -ENXIO;
- }
#ifdef __sparc__
- if (!prom_palette)
- prom_palette = atyfb_palette;
+ if (!prom_palette)
+ prom_palette = atyfb_palette;
- /*
- * Add /dev/fb mmap values.
- */
- default_par->mmap_map[0].voff = 0x8000000000000000UL;
- default_par->mmap_map[0].poff =
- (unsigned long) info->screen_base & PAGE_MASK;
- default_par->mmap_map[0].size =
- info->fix.smem_len;
- default_par->mmap_map[0].prot_mask = _PAGE_CACHE;
- default_par->mmap_map[0].prot_flag = _PAGE_E;
- default_par->mmap_map[1].voff =
- default_par->mmap_map[0].voff +
- info->fix.smem_len;
- default_par->mmap_map[1].poff =
- default_par->ati_regbase & PAGE_MASK;
- default_par->mmap_map[1].size = PAGE_SIZE;
- default_par->mmap_map[1].prot_mask = _PAGE_CACHE;
- default_par->mmap_map[1].prot_flag = _PAGE_E;
-#endif /* __sparc__ */
-
-#ifdef CONFIG_PMAC_PBOOK
- if (first_display == NULL)
- pmu_register_sleep_notifier(&aty_sleep_notifier);
- default_par->next = first_display;
+ /*
+ * Add /dev/fb mmap values.
+ */
+ par->mmap_map[0].voff = 0x8000000000000000UL;
+ par->mmap_map[0].poff = (unsigned long) info->screen_base & PAGE_MASK;
+ par->mmap_map[0].size = info->fix.smem_len;
+ par->mmap_map[0].prot_mask = _PAGE_CACHE;
+ par->mmap_map[0].prot_flag = _PAGE_E;
+ par->mmap_map[1].voff = par->mmap_map[0].voff + info->fix.smem_len;
+ par->mmap_map[1].poff = par->ati_regbase & PAGE_MASK;
+ par->mmap_map[1].size = PAGE_SIZE;
+ par->mmap_map[1].prot_mask = _PAGE_CACHE;
+ par->mmap_map[1].prot_flag = _PAGE_E;
+#endif /* __sparc__ */
+
+ return 0;
+
+err_release_io:
+#ifdef __sparc__
+ if (par->mmap_map)
+ kfree(par->mmap_map);
+#else
+ if (par->ati_regbase)
+ iounmap(par->ati_regbase);
+ if (info->screen_base)
+ iounmap(info->screen_base);
#endif
- }
- }
+err_release_mem:
+ if(par->aux_start)
+ release_mem_region(par->aux_start, par->aux_size);
+
+ release_mem_region(par->res_start, par->res_size);
+ framebuffer_release(info);
+
+ return rc;
+}
+
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_ATARI
-#elif defined(CONFIG_ATARI)
- struct atyfb_par *default_par;
+static int __devinit atyfb_atari_probe(void)
+{
+ struct aty_par *par;
struct fb_info *info;
int m64_num;
u32 clock_r;
@@ -2314,85 +3436,135 @@
for (m64_num = 0; m64_num < mach64_count; m64_num++) {
if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
!phys_guiregbase[m64_num]) {
- printk
- (" phys_*[%d] parameters not set => returning early. \n",
- m64_num);
+ PRINTKI("phys_*[%d] parameters not set => returning early. \n", m64_num);
continue;
}
- info = kmalloc(sizeof(struct fb_info), GFP_ATOMIC);
+ info = framebuffer_alloc(sizeof(struct atyfb_par), NULL);
if (!info) {
- printk("atyfb_init: can't alloc fb_info\n");
+ PRINTKE("atyfb_atari_probe() can't alloc fb_info\n");
return -ENOMEM;
}
- memset(info, 0, sizeof(struct fb_info));
-
- default_par = kmalloc(sizeof(struct atyfb_par), GFP_ATOMIC);
- if (!default_par) {
- printk
- ("atyfb_init: can't alloc atyfb_par\n");
- kfree(info);
- return -ENXIO;
- }
- memset(default_par, 0, sizeof(struct atyfb_par));
+ par = info->par;
info->fix = atyfb_fix;
- info->par = default_par;
+
+ par->irq = (unsigned int) -1; /* something invalid */
/*
* Map the video memory (physical address given) to somewhere in the
* kernel address space.
*/
- info->screen_base = ioremap(phys_vmembase[m64_num],
- phys_size[m64_num]);
- info->fix.smem_start = (unsigned long)info->screen_base; /* Fake! */
- default_par->ati_regbase = (unsigned long)ioremap(phys_guiregbase[m64_num],
- 0x10000) + 0xFC00ul;
- info->fix.mmio_start = default_par->ati_regbase; /* Fake! */
+ info->screen_base = ioremap(phys_vmembase[m64_num], phys_size[m64_num]);
+ info->fix.smem_start = (unsigned long)info->screen_base; /* Fake! */
+ par->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000) + 0xFC00ul;
+ info->fix.mmio_start = par->ati_regbase; /* Fake! */
- aty_st_le32(CLOCK_CNTL, 0x12345678, default_par);
- clock_r = aty_ld_le32(CLOCK_CNTL, default_par);
+ aty_st_le32(CLOCK_CNTL, 0x12345678, par);
+ clock_r = aty_ld_le32(CLOCK_CNTL, par);
switch (clock_r & 0x003F) {
case 0x12:
- default_par->clk_wr_offset = 3; /* */
+ par->clk_wr_offset = 3; /* */
break;
case 0x34:
- default_par->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */
+ par->clk_wr_offset = 2; /* Medusa ST-IO ISA Adapter etc. */
break;
case 0x16:
- default_par->clk_wr_offset = 1; /* */
+ par->clk_wr_offset = 1; /* */
break;
case 0x38:
- default_par->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */
+ par->clk_wr_offset = 0; /* Panther 1 ISA Adapter (Gerald) */
break;
}
- if (!aty_init(info, "ISA bus")) {
- kfree(default_par);
- kfree(info);
+ if (aty_init(info, "ISA bus")) {
+ framebuffer_release(info);
/* This is insufficient! kernel_map has added two large chunks!! */
return -ENXIO;
}
}
-#endif /* CONFIG_ATARI */
- return 0;
}
-int __init atyfb_init(void)
+#endif /* CONFIG_ATARI */
+
+static void __devexit atyfb_remove(struct fb_info *info)
{
-#ifndef MODULE
- char *option = NULL;
+ struct atyfb_par *par = (struct atyfb_par *) info->par;
- if (fb_get_options("atyfb", &option))
- return -ENODEV;
- atyfb_setup(option);
+ /* restore video mode */
+ aty_set_crtc(par, &saved_crtc);
+ par->pll_ops->set_pll(info, &saved_pll);
+
+ unregister_framebuffer(info);
+
+#ifdef CONFIG_MTRR
+ if (par->mtrr_reg >= 0) {
+ mtrr_del(par->mtrr_reg, 0, 0);
+ par->mtrr_reg = -1;
+ }
+ if (par->mtrr_aper >= 0) {
+ mtrr_del(par->mtrr_aper, 0, 0);
+ par->mtrr_aper = -1;
+ }
#endif
- return atyfb_do_init();
+#ifndef __sparc__
+ if (par->ati_regbase)
+ iounmap(par->ati_regbase);
+ if (info->screen_base)
+ iounmap(info->screen_base);
+#ifdef __BIG_ENDIAN
+ if (info->sprite.addr)
+ iounmap(info->sprite.addr);
+#endif
+#endif
+#ifdef __sparc__
+ if (par->mmap_map)
+ kfree(par->mmap_map);
+#endif
+ if (par->aux_start)
+ release_mem_region(par->aux_start, par->aux_size);
+
+ if (par->res_start)
+ release_mem_region(par->res_start, par->res_size);
+
+ framebuffer_release(info);
}
+#ifdef CONFIG_PCI
+
+static void __devexit atyfb_pci_remove(struct pci_dev *pdev)
+{
+ struct fb_info *info = pci_get_drvdata(pdev);
+
+ atyfb_remove(info);
+}
+
+/*
+ * This driver uses its own matching table. That will be more difficult
+ * to fix, so for now, we just match against any ATI ID and let the
+ * probe() function find out what's up. That also mean we don't have
+ * a module ID table though.
+ */
+static struct pci_device_id atyfb_pci_tbl[] = {
+ { PCI_VENDOR_ID_ATI, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0 },
+ { 0, }
+};
+
+static struct pci_driver atyfb_driver = {
+ .name = "atyfb",
+ .id_table = atyfb_pci_tbl,
+ .probe = atyfb_pci_probe,
+ .remove = __devexit_p(atyfb_pci_remove),
+#ifdef CONFIG_PM
+ .suspend = atyfb_pci_suspend,
+ .resume = atyfb_pci_resume,
+#endif /* CONFIG_PM */
+};
+
+#endif /* CONFIG_PCI */
-#ifndef MODULE
int __init atyfb_setup(char *options)
{
char *this_opt;
@@ -2401,19 +3573,20 @@
return 0;
while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!strncmp(this_opt, "noblink", 7)) {
- curblink = 0;
- } else if (!strncmp(this_opt, "noaccel", 7)) {
+ if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
+#ifdef CONFIG_MTRR
+ } else if (!strncmp(this_opt, "nomtrr", 6)) {
+ nomtrr = 1;
+#endif
} else if (!strncmp(this_opt, "vram:", 5))
- default_vram =
- simple_strtoul(this_opt + 5, NULL, 0);
+ vram = simple_strtoul(this_opt + 5, NULL, 0);
else if (!strncmp(this_opt, "pll:", 4))
- default_pll =
- simple_strtoul(this_opt + 4, NULL, 0);
+ pll = simple_strtoul(this_opt + 4, NULL, 0);
else if (!strncmp(this_opt, "mclk:", 5))
- default_mclk =
- simple_strtoul(this_opt + 5, NULL, 0);
+ mclk = simple_strtoul(this_opt + 5, NULL, 0);
+ else if (!strncmp(this_opt, "xclk:", 5))
+ xclk = simple_strtoul(this_opt+5, NULL, 0);
#ifdef CONFIG_PPC
else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode =
@@ -2456,182 +3629,63 @@
}
#endif
else
- mode_option = this_opt;
+ mode = this_opt;
}
return 0;
}
-module_init(atyfb_init);
-#endif /* !MODULE */
-
-#ifdef CONFIG_ATARI
-static int __init store_video_par(char *video_str, unsigned char m64_num)
-{
- char *p;
- unsigned long vmembase, size, guiregbase;
-
- printk("store_video_par() '%s' \n", video_str);
-
- if (!(p = strsep(&video_str, ";")) || !*p)
- goto mach64_invalid;
- vmembase = simple_strtoul(p, NULL, 0);
- if (!(p = strsep(&video_str, ";")) || !*p)
- goto mach64_invalid;
- size = simple_strtoul(p, NULL, 0);
- if (!(p = strsep(&video_str, ";")) || !*p)
- goto mach64_invalid;
- guiregbase = simple_strtoul(p, NULL, 0);
-
- phys_vmembase[m64_num] = vmembase;
- phys_size[m64_num] = size;
- phys_guiregbase[m64_num] = guiregbase;
- printk(" stored them all: $%08lX $%08lX $%08lX \n", vmembase, size,
- guiregbase);
- return 0;
-
- mach64_invalid:
- phys_vmembase[m64_num] = 0;
- return -1;
-}
-#endif /* CONFIG_ATARI */
-
-/*
-#ifdef CONFIG_FB_ATY_CT
- * Erase HW Cursor *
- if (par->cursor && (info->currcon >= 0))
- atyfb_cursor(&fb_display[par->currcon], CM_ERASE,
- par->cursor->pos.x, par->cursor->pos.y);
-#endif * CONFIG_FB_ATY_CT *
-#ifdef CONFIG_FB_ATY_CT
- * Install hw cursor *
- if (par->cursor) {
- aty_set_cursor_color(info);
- aty_set_cursor_shape(info);
- }
-#endif * CONFIG_FB_ATY_CT */
-
- /*
- * Blank the display.
- */
-
-static int atyfb_blank(int blank, struct fb_info *info)
+int __init atyfb_init(void)
{
- struct atyfb_par *par = (struct atyfb_par *) info->par;
- u8 gen_cntl;
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- if ((_machine == _MACH_Pmac) && blank)
- set_backlight_enable(0);
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
- gen_cntl = aty_ld_8(CRTC_GEN_CNTL, par);
- if (blank > 0)
- switch (blank - 1) {
- case VESA_NO_BLANKING:
- gen_cntl |= 0x40;
- break;
- case VESA_VSYNC_SUSPEND:
- gen_cntl |= 0x8;
- break;
- case VESA_HSYNC_SUSPEND:
- gen_cntl |= 0x4;
- break;
- case VESA_POWERDOWN:
- gen_cntl |= 0x4c;
- break;
- } else
- gen_cntl &= ~(0x4c);
- aty_st_8(CRTC_GEN_CNTL, gen_cntl, par);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- if ((_machine == _MACH_Pmac) && !blank)
- set_backlight_enable(1);
-#endif /* CONFIG_PMAC_BACKLIGHT */
- return 0;
-}
-
- /*
- * Set a single color register. The values supplied are already
- * rounded down to the hardware's capabilities (according to the
- * entries in the var structure). Return != 0 for invalid regno.
- */
+#ifndef MODULE
+ char *option = NULL;
-static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
-{
- struct atyfb_par *par = (struct atyfb_par *) info->par;
- int i, scale;
- u32 *pal = info->pseudo_palette;
+ if (fb_get_options("atyfb", &option))
+ return -ENODEV;
+ atyfb_setup(option);
+#endif
- if (regno > 255)
- return 1;
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- i = aty_ld_8(DAC_CNTL, par) & 0xfc;
- if (M64_HAS(EXTRA_BRIGHT))
- i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt */
- aty_st_8(DAC_CNTL, i, par);
- aty_st_8(DAC_MASK, 0xff, par);
- scale = (M64_HAS(INTEGRATED) && info->var.bits_per_pixel == 16) ? 3 : 0;
+#ifdef CONFIG_PCI
+ pci_module_init(&atyfb_driver);
+#endif
#ifdef CONFIG_ATARI
- out_8(&par->aty_cmap_regs->windex, regno << scale);
- out_8(&par->aty_cmap_regs->lut, red);
- out_8(&par->aty_cmap_regs->lut, green);
- out_8(&par->aty_cmap_regs->lut, blue);
-#else
- writeb(regno << scale, &par->aty_cmap_regs->windex);
- writeb(red, &par->aty_cmap_regs->lut);
- writeb(green, &par->aty_cmap_regs->lut);
- writeb(blue, &par->aty_cmap_regs->lut);
+ atyfb_atari_probe();
#endif
- if (regno < 16)
- switch (info->var.bits_per_pixel) {
- case 16:
- pal[regno] = (regno << 10) | (regno << 5) | regno;
- break;
- case 24:
- pal[regno] = (regno << 16) | (regno << 8) | regno;
- break;
- case 32:
- i = (regno << 8) | regno;
- pal[regno] = (i << 16) | i;
- break;
- }
- return 0;
+ return 0;
}
-#ifdef MODULE
-int __init init_module(void)
+void __exit atyfb_exit(void)
{
- atyfb_init();
- return fb_list ? 0 : -ENXIO;
-}
-
-void cleanup_module(void)
-{
- struct fb_info *info = fb_list;
- struct atyfb_par *par = (struct atyfb_par *) info->par;
- unregister_framebuffer(info);
-
-#ifndef __sparc__
- if (par->ati_regbase)
- iounmap((void *) par->ati_regbase);
- if (info->screen_base)
- iounmap((void *) info->screen_base);
-#ifdef __BIG_ENDIAN
- if (par->cursor && par->cursor->ram)
- iounmap(par->cursor->ram);
-#endif
-#endif
- if (par->cursor)
- kfree(par->cursor);
-#ifdef __sparc__
- if (par->mmap_map)
- kfree(par->mmap_map);
+#ifdef CONFIG_PCI
+ pci_unregister_driver(&atyfb_driver);
#endif
- kfree(info);
}
+module_init(atyfb_init);
+#ifdef MODULE
+module_exit(atyfb_exit);
#endif
+
+MODULE_DESCRIPTION("FBDev driver for ATI Mach64 cards");
MODULE_LICENSE("GPL");
+module_param(noaccel, bool, 0);
+MODULE_PARM_DESC(noaccel, "bool: disable acceleration");
+module_param(vram, int, 0);
+MODULE_PARM_DESC(vram, "int: override size of video ram");
+module_param(pll, int, 0);
+MODULE_PARM_DESC(pll, "int: override video clock");
+module_param(mclk, int, 0);
+MODULE_PARM_DESC(mclk, "int: override memory clock");
+module_param(xclk, int, 0);
+MODULE_PARM_DESC(xclk, "int: override accelerated engine clock");
+#ifdef CONFIG_PPC
+module_param(vmode, int, 0);
+MODULE_PARM_DESC(vmode, "int: video mode for mac");
+module_param(cmode, int, 0);
+MODULE_PARM_DESC(cmode, "int: color mode for mac");
+#endif
+module_param(mode, charp, 0);
+MODULE_PARM_DESC(mode, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
+#ifdef CONFIG_MTRR
+module_param(nomtrr, bool, 0);
+MODULE_PARM_DESC(nomtrr, "bool: disable use of MTRR registers");
+#endif
diff -Nru a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c
--- a/drivers/video/aty/mach64_accel.c 2004-10-19 20:22:42 +08:00
+++ b/drivers/video/aty/mach64_accel.c 2004-10-07 06:18:18 +08:00
@@ -13,22 +13,41 @@
* Generic Mach64 routines
*/
+/* this is for DMA GUI engine! work in progress */
+typedef struct {
+ u32 frame_buf_offset;
+ u32 system_mem_addr;
+ u32 command;
+ u32 reserved;
+} BM_DESCRIPTOR_ENTRY;
+
+#define LAST_DESCRIPTOR (1 << 31)
+#define SYSTEM_TO_FRAME_BUFFER 0
+
+static u32 rotation24bpp(u32 dx, u32 direction)
+{
+ u32 rotation;
+ if (direction & DST_X_LEFT_TO_RIGHT) {
+ rotation = (dx / 4) % 6;
+ } else {
+ rotation = ((dx + 2) / 4) % 6;
+ }
+
+ return ((rotation << 8) | DST_24_ROTATION_ENABLE);
+}
+
void aty_reset_engine(const struct atyfb_par *par)
{
/* reset engine */
aty_st_le32(GEN_TEST_CNTL,
- aty_ld_le32(GEN_TEST_CNTL, par) & ~GUI_ENGINE_ENABLE,
- par);
+ aty_ld_le32(GEN_TEST_CNTL, par) & ~GUI_ENGINE_ENABLE, par);
/* enable engine */
aty_st_le32(GEN_TEST_CNTL,
- aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE,
- par);
+ aty_ld_le32(GEN_TEST_CNTL, par) | GUI_ENGINE_ENABLE, par);
/* ensure engine is not locked up by clearing any FIFO or */
/* HOST errors */
aty_st_le32(BUS_CNTL,
- aty_ld_le32(BUS_CNTL,
- par) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK,
- par);
+ aty_ld_le32(BUS_CNTL, par) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK, par);
}
static void reset_GTC_3D_engine(const struct atyfb_par *par)
@@ -51,7 +70,7 @@
if (info->var.bits_per_pixel == 24) {
/* In 24 bpp, the engine is in 8 bpp - this requires that all */
/* horizontal coordinates and widths must be adjusted */
- pitch_value = pitch_value * 3;
+ pitch_value *= 3;
}
/* On GTC (RagePro), we need to reset the 3D engine before */
@@ -146,7 +165,7 @@
aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, par);
wait_for_fifo(5, par);
- aty_st_le32(SCALE_3D_CNTL, 0, par);
+ aty_st_le32(SCALE_3D_CNTL, 0, par);
aty_st_le32(Z_CNTL, 0, par);
aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, par) & ~0x20,
par);
@@ -174,9 +193,10 @@
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
u32 dy = area->dy, sy = area->sy, direction = DST_LAST_PEL;
- u32 sx = area->sx, dx = area->dx, width = area->width;
- u32 pitch_value;
+ u32 sx = area->sx, dx = area->dx, width = area->width, rotation = 0;
+ if (par->asleep)
+ return;
if (!area->width || !area->height)
return;
if (!par->accel_flags) {
@@ -186,11 +206,9 @@
return;
}
- pitch_value = info->var.xres_virtual;
if (info->var.bits_per_pixel == 24) {
/* In 24 bpp, the engine is in 8 bpp - this requires that all */
/* horizontal coordinates and widths must be adjusted */
- pitch_value *= 3;
sx *= 3;
dx *= 3;
width *= 3;
@@ -208,19 +226,25 @@
} else
direction |= DST_X_LEFT_TO_RIGHT;
+ if (info->var.bits_per_pixel == 24) {
+ rotation = rotation24bpp(dx, direction);
+ }
+
wait_for_fifo(4, par);
aty_st_le32(DP_SRC, FRGD_SRC_BLIT, par);
aty_st_le32(SRC_Y_X, (sx << 16) | sy, par);
aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | area->height, par);
- aty_st_le32(DST_CNTL, direction, par);
+ aty_st_le32(DST_CNTL, direction | rotation, par);
draw_rect(dx, dy, width, area->height, par);
}
void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
- u32 color = rect->color, dx = rect->dx, width = rect->width;
+ u32 color = rect->color, dx = rect->dx, width = rect->width, rotation = 0;
+ if (par->asleep)
+ return;
if (!rect->width || !rect->height)
return;
if (!par->accel_flags) {
@@ -238,6 +262,7 @@
/* horizontal coordinates and widths must be adjusted */
dx *= 3;
width *= 3;
+ rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT);
}
wait_for_fifo(3, par);
@@ -247,15 +272,162 @@
par);
aty_st_le32(DST_CNTL,
DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
- DST_X_LEFT_TO_RIGHT, par);
+ DST_X_LEFT_TO_RIGHT | rotation, par);
draw_rect(dx, rect->dy, width, rect->height, par);
}
void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
-
- if (par->blitter_may_be_busy)
- wait_for_idle(par);
- cfb_imageblit(info, image);
+ u32 src_bytes, dx = image->dx, dy = image->dy, width = image->width;
+ u32 pix_width_save, pix_width, host_cntl, rotation = 0, src, mix;
+
+ if (par->asleep)
+ return;
+ if (!image->width || !image->height)
+ return;
+ if (!par->accel_flags ||
+ (image->depth != 1 && info->var.bits_per_pixel != image->depth)) {
+ if (par->blitter_may_be_busy)
+ wait_for_idle(par);
+
+ cfb_imageblit(info, image);
+ return;
+ }
+
+ wait_for_idle(par);
+ pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par);
+ host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN;
+
+ switch (image->depth) {
+ case 1:
+ pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK);
+ pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_1BPP);
+ break;
+ case 4:
+ pix_width &= ~(BYTE_ORDER_MASK | HOST_MASK);
+ pix_width |= (BYTE_ORDER_MSB_TO_LSB | HOST_4BPP);
+ break;
+ case 8:
+ pix_width &= ~HOST_MASK;
+ pix_width |= HOST_8BPP;
+ break;
+ case 15:
+ pix_width &= ~HOST_MASK;
+ pix_width |= HOST_15BPP;
+ break;
+ case 16:
+ pix_width &= ~HOST_MASK;
+ pix_width |= HOST_16BPP;
+ break;
+ case 24:
+ pix_width &= ~HOST_MASK;
+ pix_width |= HOST_24BPP;
+ break;
+ case 32:
+ pix_width &= ~HOST_MASK;
+ pix_width |= HOST_32BPP;
+ break;
+ }
+
+ if (info->var.bits_per_pixel == 24) {
+ /* In 24 bpp, the engine is in 8 bpp - this requires that all */
+ /* horizontal coordinates and widths must be adjusted */
+ dx *= 3;
+ width *= 3;
+
+ rotation = rotation24bpp(dx, DST_X_LEFT_TO_RIGHT);
+
+ pix_width &= ~DST_MASK;
+ pix_width |= DST_8BPP;
+
+ /*
+ * since Rage 3D IIc we have DP_HOST_TRIPLE_EN bit
+ * this hwaccelerated triple has an issue with not aligned data
+ */
+ if (M64_HAS(HW_TRIPLE) && image->width % 8 == 0)
+ pix_width |= DP_HOST_TRIPLE_EN;
+ }
+
+ if (image->depth == 1) {
+ u32 fg, bg;
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ fg = ((u32*)(info->pseudo_palette))[image->fg_color];
+ bg = ((u32*)(info->pseudo_palette))[image->bg_color];
+ } else {
+ fg = image->fg_color;
+ bg = image->bg_color;
+ }
+
+ wait_for_fifo(2, par);
+ aty_st_le32(DP_BKGD_CLR, bg, par);
+ aty_st_le32(DP_FRGD_CLR, fg, par);
+ src = MONO_SRC_HOST | FRGD_SRC_FRGD_CLR | BKGD_SRC_BKGD_CLR;
+ mix = FRGD_MIX_S | BKGD_MIX_S;
+ } else {
+ src = MONO_SRC_ONE | FRGD_SRC_HOST;
+ mix = FRGD_MIX_D_XOR_S | BKGD_MIX_D;
+ }
+
+ wait_for_fifo(6, par);
+ aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, par);
+ aty_st_le32(DP_PIX_WIDTH, pix_width, par);
+ aty_st_le32(DP_MIX, mix, par);
+ aty_st_le32(DP_SRC, src, par);
+ aty_st_le32(HOST_CNTL, host_cntl, par);
+ aty_st_le32(DST_CNTL, DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT | rotation, par);
+
+ draw_rect(dx, dy, width, image->height, par);
+ src_bytes = (((image->width * image->depth) + 7) / 8) * image->height;
+
+ /* manual triple each pixel */
+ if (info->var.bits_per_pixel == 24 && !(pix_width & DP_HOST_TRIPLE_EN)) {
+ int inbit, outbit, mult24, byte_id_in_dword, width;
+ u8 *pbitmapin = (u8*)image->data, *pbitmapout;
+ u32 hostdword;
+
+ for (width = image->width, inbit = 7, mult24 = 0; src_bytes; ) {
+ for (hostdword = 0, pbitmapout = (u8*)&hostdword, byte_id_in_dword = 0;
+ byte_id_in_dword < 4 && src_bytes;
+ byte_id_in_dword++, pbitmapout++) {
+ for (outbit = 7; outbit >= 0; outbit--) {
+ *pbitmapout |= (((*pbitmapin >> inbit) & 1) << outbit);
+ mult24++;
+ /* next bit */
+ if (mult24 == 3) {
+ mult24 = 0;
+ inbit--;
+ width--;
+ }
+
+ /* next byte */
+ if (inbit < 0 || width == 0) {
+ src_bytes--;
+ pbitmapin++;
+ inbit = 7;
+
+ if (width == 0) {
+ width = image->width;
+ outbit = 0;
+ }
+ }
+ }
+ }
+ wait_for_fifo(1, par);
+ aty_st_le32(HOST_DATA0, hostdword, par);
+ }
+ } else {
+ u32 *pbitmap, dwords = (src_bytes + 3) / 4;
+ for (pbitmap = (u32*)(image->data); dwords; dwords--, pbitmap++) {
+ wait_for_fifo(1, par);
+ aty_st_le32(HOST_DATA0, le32_to_cpup(pbitmap), par);
+ }
+ }
+
+ wait_for_idle(par);
+
+ /* restore pix_width */
+ wait_for_fifo(1, par);
+ aty_st_le32(DP_PIX_WIDTH, pix_width_save, par);
}
diff -Nru a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
--- a/drivers/video/aty/mach64_ct.c 2004-10-19 20:22:43 +08:00
+++ b/drivers/video/aty/mach64_ct.c 2004-10-07 06:18:18 +08:00
@@ -4,214 +4,236 @@
*/
#include <linux/fb.h>
-
+#include <linux/delay.h>
#include <asm/io.h>
-
#include <video/mach64.h>
#include "atyfb.h"
+#undef DEBUG
-/* FIXME: remove the FAIL definition */
-#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
-
-static void aty_st_pll(int offset, u8 val, const struct atyfb_par *par);
-static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per,
- struct pll_ct *pll);
-static int aty_dsp_gt(const struct fb_info *info, u8 bpp,
- struct pll_ct *pll);
-static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per,
- u8 bpp, union aty_pll *pll);
-static u32 aty_pll_ct_to_var(const struct fb_info *info,
- const union aty_pll *pll);
+static int aty_valid_pll_ct (const struct fb_info *info, u32 vclk_per, struct pll_ct *pll);
+static int aty_dsp_gt (const struct fb_info *info, u32 bpp, struct pll_ct *pll);
+static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll);
+static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll);
+u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par)
+{
+ u8 res;
+ /* write addr byte */
+ aty_st_8(CLOCK_CNTL_ADDR, (offset << 2) & PLL_ADDR, par);
+ /* read the register value */
+ res = aty_ld_8(CLOCK_CNTL_DATA, par);
+ return res;
+}
-static void aty_st_pll(int offset, u8 val, const struct atyfb_par *par)
+void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
{
/* write addr byte */
- aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, par);
+ aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) | PLL_WR_EN, par);
/* write the register value */
- aty_st_8(CLOCK_CNTL + 2, val, par);
- aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, par);
+ aty_st_8(CLOCK_CNTL_DATA, val & PLL_DATA, par);
+ aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) & ~PLL_WR_EN, par);
}
+/*
+ * by Daniel Mantione
+ * <daniel.mantione@freepascal.org>
+ *
+ *
+ * ATI Mach64 CT clock synthesis description.
+ *
+ * All clocks on the Mach64 can be calculated using the same principle:
+ *
+ * XTALIN * x * FB_DIV
+ * CLK = ----------------------
+ * PLL_REF_DIV * POST_DIV
+ *
+ * XTALIN is a fixed speed clock. Common speeds are 14.31 MHz and 29.50 MHz.
+ * PLL_REF_DIV can be set by the user, but is the same for all clocks.
+ * FB_DIV can be set by the user for each clock individually, it should be set
+ * between 128 and 255, the chip will generate a bad clock signal for too low
+ * values.
+ * x depends on the type of clock; usually it is 2, but for the MCLK it can also
+ * be set to 4.
+ * POST_DIV can be set by the user for each clock individually, Possible values
+ * are 1,2,4,8 and for some clocks other values are available too.
+ * CLK is of course the clock speed that is generated.
+ *
+ * The Mach64 has these clocks:
+ *
+ * MCLK The clock rate of the chip
+ * XCLK The clock rate of the on-chip memory
+ * VCLK0 First pixel clock of first CRT controller
+ * VCLK1 Second pixel clock of first CRT controller
+ * VCLK2 Third pixel clock of first CRT controller
+ * VCLK3 Fourth pixel clock of first CRT controller
+ * VCLK Selected pixel clock, one of VCLK0, VCLK1, VCLK2, VCLK3
+ * V2CLK Pixel clock of the second CRT controller.
+ * SCLK Multi-purpose clock
+ *
+ * - MCLK and XCLK use the same FB_DIV
+ * - VCLK0 .. VCLK3 use the same FB_DIV
+ * - V2CLK is needed when the second CRTC is used (can be used for dualhead);
+ * i.e. CRT monitor connected to laptop has different resolution than built
+ * in LCD monitor.
+ * - SCLK is not available on all cards; it is know to exist on the Rage LT-PRO,
+ * Rage XL and Rage Mobility. It is know not to exist on the Mach64 VT.
+ * - V2CLK is not available on all cards, most likely only the Rage LT-PRO,
+ * the Rage XL and the Rage Mobility
+ *
+ * SCLK can be used to:
+ * - Clock the chip instead of MCLK
+ * - Replace XTALIN with a user defined frequency
+ * - Generate the pixel clock for the LCD monitor (instead of VCLK)
+ */
+
+ /*
+ * It can be quite hard to calculate XCLK and MCLK if they don't run at the
+ * same frequency. Luckily, until now all cards that need asynchrone clock
+ * speeds seem to have SCLK.
+ * So this driver uses SCLK to clock the chip and XCLK to clock the memory.
+ */
/* ------------------------------------------------------------------------- */
- /*
- * PLL programming (Mach64 CT family)
- */
+/*
+ * PLL programming (Mach64 CT family)
+ *
+ *
+ * This procedure sets the display fifo. The display fifo is a buffer that
+ * contains data read from the video memory that waits to be processed by
+ * the CRT controller.
+ *
+ * On the more modern Mach64 variants, the chip doesn't calculate the
+ * interval after which the display fifo has to be reloaded from memory
+ * automatically, the driver has to do it instead.
+ */
+
+#define Maximum_DSP_PRECISION 7
+static u8 postdividers[] = {1,2,4,8,3};
-static int aty_dsp_gt(const struct fb_info *info, u8 bpp,
- struct pll_ct *pll)
+static int aty_dsp_gt(const struct fb_info *info, u32 bpp, struct pll_ct *pll)
{
- struct atyfb_par *par = (struct atyfb_par *) info->par;
- u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off,
- dsp_on;
- u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size;
-
- /* xclocks_per_row<<11 */
- xclks_per_row =
- (pll->mclk_fb_div * pll->vclk_post_div_real * 64 << 11) /
- (pll->vclk_fb_div * pll->mclk_post_div_real * bpp);
- if (xclks_per_row < (1 << 11))
- FAIL("Dotclock to high");
- if (M64_HAS(FIFO_24)) {
- fifo_size = 24;
- dsp_loop_latency = 0;
- } else {
- fifo_size = 32;
- dsp_loop_latency = 2;
+ u32 dsp_off, dsp_on, dsp_xclks;
+ u32 multiplier, divider, ras_multiplier, ras_divider, tmp;
+ u8 vshift, xshift;
+ s8 dsp_precision;
+
+ multiplier = ((u32)pll->mclk_fb_div) * pll->vclk_post_div_real;
+ divider = ((u32)pll->vclk_fb_div) * pll->xclk_ref_div;
+
+ ras_multiplier = pll->xclkmaxrasdelay;
+ ras_divider = 1;
+
+ if (bpp>=8)
+ divider = divider * (bpp >> 2);
+
+ vshift = (6 - 2) - pll->xclk_post_div; /* FIFO is 64 bits wide in accelerator mode ... */
+
+ if (bpp == 0)
+ vshift--; /* ... but only 32 bits in VGA mode. */
+
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ if (pll->xres != 0) {
+ struct atyfb_par *par = (struct atyfb_par *) info->par;
+
+ multiplier = multiplier * par->lcd_width;
+ divider = divider * pll->xres & ~7;
+
+ ras_multiplier = ras_multiplier * par->lcd_width;
+ ras_divider = ras_divider * pll->xres & ~7;
}
- dsp_precision = 0;
- y = (xclks_per_row * fifo_size) >> 11;
- while (y) {
- y >>= 1;
- dsp_precision++;
- }
- dsp_precision -= 5;
- /* fifo_off<<6 */
- fifo_off = ((xclks_per_row * (fifo_size - 1)) >> 5) + (3 << 6);
-
- if (info->fix.smem_len > 1 * 1024 * 1024) {
- if (par->ram_type >= SDRAM) {
- /* >1 MB SDRAM */
- dsp_loop_latency += 8;
- page_size = 8;
- } else {
- /* >1 MB DRAM */
- dsp_loop_latency += 6;
- page_size = 9;
- }
- } else {
- if (par->ram_type >= SDRAM) {
- /* <2 MB SDRAM */
- dsp_loop_latency += 9;
- page_size = 10;
- } else {
- /* <2 MB DRAM */
- dsp_loop_latency += 8;
- page_size = 10;
- }
+#endif
+ /* If we don't do this, 32 bits for multiplier & divider won't be
+ enough in certain situations! */
+ while (((multiplier | divider) & 1) == 0) {
+ multiplier = multiplier >> 1;
+ divider = divider >> 1;
}
- /* fifo_on<<6 */
- if (xclks_per_row >= (page_size << 11))
- fifo_on =
- ((2 * page_size + 1) << 6) + (xclks_per_row >> 5);
- else
- fifo_on = (3 * page_size + 2) << 6;
- dsp_xclks_per_row = xclks_per_row >> dsp_precision;
- dsp_on = fifo_on >> dsp_precision;
- dsp_off = fifo_off >> dsp_precision;
-
- pll->dsp_config = (dsp_xclks_per_row & 0x3fff) |
- ((dsp_loop_latency & 0xf) << 16) | ((dsp_precision & 7) << 20);
- pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff) << 16);
- return 0;
-}
+ /* Determine DSP precision first */
+ tmp = ((multiplier * pll->fifo_size) << vshift) / divider;
-static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per,
- struct pll_ct *pll)
-{
- struct atyfb_par *par = (struct atyfb_par *) info->par;
- u32 q, x; /* x is a workaround for sparc64-linux-gcc */
- x = x; /* x is a workaround for sparc64-linux-gcc */
+ for (dsp_precision = -5; tmp; dsp_precision++)
+ tmp >>= 1;
+ if (dsp_precision < 0)
+ dsp_precision = 0;
+ else if (dsp_precision > Maximum_DSP_PRECISION)
+ dsp_precision = Maximum_DSP_PRECISION;
+
+ xshift = 6 - dsp_precision;
+ vshift += xshift;
+
+ /* Move on to dsp_off */
+ dsp_off = ((multiplier * (pll->fifo_size - 1)) << vshift) / divider -
+ (1 << (vshift - xshift));
+
+/* if (bpp == 0)
+ dsp_on = ((multiplier * 20 << vshift) + divider) / divider;
+ else */
+ {
+ dsp_on = ((multiplier << vshift) + divider) / divider;
+ tmp = ((ras_multiplier << xshift) + ras_divider) / ras_divider;
+ if (dsp_on < tmp)
+ dsp_on = tmp;
+ dsp_on = dsp_on + (tmp * 2) + (pll->xclkpagefaultdelay << xshift);
+ }
- pll->pll_ref_div = par->pll_per * 2 * 255 / par->ref_clk_per;
+ /* Calculate rounding factor and apply it to dsp_on */
+ tmp = ((1 << (Maximum_DSP_PRECISION - dsp_precision)) - 1) >> 1;
+ dsp_on = ((dsp_on + tmp) / (tmp + 1)) * (tmp + 1);
+
+ if (dsp_on >= ((dsp_off / (tmp + 1)) * (tmp + 1))) {
+ dsp_on = dsp_off - (multiplier << vshift) / divider;
+ dsp_on = (dsp_on / (tmp + 1)) * (tmp + 1);
+ }
- /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
- q = par->ref_clk_per * pll->pll_ref_div * 4 / par->mclk_per; /* actually 8*q */
- if (q < 16 * 8 || q > 255 * 8)
- FAIL("mclk out of range");
- else if (q < 32 * 8)
- pll->mclk_post_div_real = 8;
- else if (q < 64 * 8)
- pll->mclk_post_div_real = 4;
- else if (q < 128 * 8)
- pll->mclk_post_div_real = 2;
- else
- pll->mclk_post_div_real = 1;
- pll->mclk_fb_div = q * pll->mclk_post_div_real / 8;
+ /* Last but not least: dsp_xclks */
+ dsp_xclks = ((multiplier << (vshift + 5)) + divider) / divider;
- /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
- q = par->ref_clk_per * pll->pll_ref_div * 4 / vclk_per; /* actually 8*q */
- if (q < 16 * 8 || q > 255 * 8)
- FAIL("vclk out of range");
- else if (q < 32 * 8)
- pll->vclk_post_div_real = 8;
- else if (q < 64 * 8)
- pll->vclk_post_div_real = 4;
- else if (q < 128 * 8)
- pll->vclk_post_div_real = 2;
- else
- pll->vclk_post_div_real = 1;
- pll->vclk_fb_div = q * pll->vclk_post_div_real / 8;
+ /* Get register values. */
+ pll->dsp_on_off = (dsp_on << 16) + dsp_off;
+ pll->dsp_config = (dsp_precision << 20) | (pll->dsp_loop_latency << 16) | dsp_xclks;
+#ifdef DEBUG
+ printk("atyfb(%s): dsp_config 0x%08x, dsp_on_off 0x%08x\n",
+ __FUNCTION__, pll->dsp_config, pll->dsp_on_off);
+#endif
return 0;
}
-void aty_calc_pll_ct(const struct fb_info *info, struct pll_ct *pll)
+static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per, struct pll_ct *pll)
{
+ u32 q;
struct atyfb_par *par = (struct atyfb_par *) info->par;
- u8 mpostdiv = 0;
- u8 vpostdiv = 0;
-
- if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
- pll->pll_gen_cntl = 0x04;
- else
- pll->pll_gen_cntl = 0x84;
-
- switch (pll->mclk_post_div_real) {
- case 1:
- mpostdiv = 0;
- break;
- case 2:
- mpostdiv = 1;
- break;
- case 3:
- mpostdiv = 4;
- break;
- case 4:
- mpostdiv = 2;
- break;
- case 8:
- mpostdiv = 3;
- break;
- }
- pll->pll_gen_cntl |= mpostdiv << 4; /* mclk */
+#ifdef DEBUG
+ int pllvclk;
+#endif
- if (M64_HAS(MAGIC_POSTDIV))
- pll->pll_ext_cntl = 0;
- else
- pll->pll_ext_cntl = mpostdiv; /* xclk == mclk */
-
- switch (pll->vclk_post_div_real) {
- case 2:
- vpostdiv = 1;
- break;
- case 3:
- pll->pll_ext_cntl |= 0x10;
- case 1:
- vpostdiv = 0;
- break;
- case 6:
- pll->pll_ext_cntl |= 0x10;
- case 4:
- vpostdiv = 2;
- break;
- case 12:
- pll->pll_ext_cntl |= 0x10;
- case 8:
- vpostdiv = 3;
- break;
+ /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
+ q = par->ref_clk_per * pll->pll_ref_div * 4 / vclk_per;
+ if (q < 16*8 || q > 255*8) {
+ printk(KERN_CRIT "atyfb: vclk out of range\n");
+ return -EINVAL;
+ } else {
+ pll->vclk_post_div = (q < 128*8);
+ pll->vclk_post_div += (q < 64*8);
+ pll->vclk_post_div += (q < 32*8);
}
-
- pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
- pll->vclk_post_div = vpostdiv;
+ pll->vclk_post_div_real = postdividers[pll->vclk_post_div];
+ // pll->vclk_post_div <<= 6;
+ pll->vclk_fb_div = q * pll->vclk_post_div_real / 8;
+#ifdef DEBUG
+ pllvclk = (1000000 * 2 * pll->vclk_fb_div) /
+ (par->ref_clk_per * pll->pll_ref_div);
+ printk("atyfb(%s): pllvclk=%d MHz, vclk=%d MHz\n",
+ __FUNCTION__, pllvclk, pllvclk / pll->vclk_post_div_real);
+#endif
+ pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
+ return 0;
}
-static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per,
- u8 bpp, union aty_pll *pll)
+static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per, u32 bpp, union aty_pll *pll)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
int err;
@@ -220,47 +242,358 @@
return err;
if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct)))
return err;
- aty_calc_pll_ct(info, &pll->ct);
+ /*aty_calc_pll_ct(info, &pll->ct);*/
return 0;
}
-static u32 aty_pll_ct_to_var(const struct fb_info *info,
- const union aty_pll *pll)
+static u32 aty_pll_to_var_ct(const struct fb_info *info, const union aty_pll *pll)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
-
- u32 ref_clk_per = par->ref_clk_per;
- u8 pll_ref_div = pll->ct.pll_ref_div;
- u8 vclk_fb_div = pll->ct.vclk_fb_div;
- u8 vclk_post_div = pll->ct.vclk_post_div_real;
-
- return ref_clk_per * pll_ref_div * vclk_post_div / vclk_fb_div / 2;
+ u32 ret;
+ ret = par->ref_clk_per * pll->ct.pll_ref_div * pll->ct.vclk_post_div_real / pll->ct.vclk_fb_div / 2;
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ if(pll->ct.xres > 0) {
+ ret *= par->lcd_width;
+ ret /= pll->ct.xres;
+ }
+#endif
+#ifdef DEBUG
+ printk("atyfb(%s): calculated 0x%08X(%i)\n", __FUNCTION__, ret, ret);
+#endif
+ return ret;
}
-void aty_set_pll_ct(const struct fb_info *info,
- const union aty_pll *pll)
+void aty_set_pll_ct(const struct fb_info *info, const union aty_pll *pll)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
+ u32 crtc_gen_cntl, lcd_gen_cntrl = 0;
+ u8 tmp, tmp2;
+#ifdef DEBUG
+ printk("atyfb(%s): about to program:\n"
+ "pll_ext_cntl=0x%02x pll_gen_cntl=0x%02x pll_vclk_cntl=0x%02x\n",
+ __FUNCTION__,
+ pll->ct.pll_ext_cntl, pll->ct.pll_gen_cntl, pll->ct.pll_vclk_cntl);
+
+ printk("atyfb(%s): setting clock %lu for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i(%i)\n",
+ __FUNCTION__,
+ par->clk_wr_offset, pll->ct.vclk_fb_div,
+ pll->ct.pll_ref_div, pll->ct.vclk_post_div, pll->ct.vclk_post_div_real);
+#endif
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ if (par->lcd_table != 0) {
+ /* turn off LCD */
+ lcd_gen_cntrl = aty_ld_lcd(LCD_GEN_CNTL, par);
+ aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl & ~LCD_ON, par);
+ }
+#endif
+ aty_st_8(CLOCK_CNTL, par->clk_wr_offset | CLOCK_STROBE, par);
- aty_st_pll(PLL_REF_DIV, pll->ct.pll_ref_div, par);
- aty_st_pll(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
- aty_st_pll(MCLK_FB_DIV, pll->ct.mclk_fb_div, par);
- aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
- aty_st_pll(VCLK_POST_DIV, pll->ct.vclk_post_div, par);
- aty_st_pll(VCLK0_FB_DIV, pll->ct.vclk_fb_div, par);
- aty_st_pll(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par);
+ /* Temporarily switch to accelerator mode */
+ crtc_gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
+ if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
+ aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN, par);
+
+ /* Reset VCLK generator */
+ aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
+
+ /* Set post-divider */
+ tmp2 = par->clk_wr_offset << 1;
+ tmp = aty_ld_pll_ct(VCLK_POST_DIV, par);
+ tmp &= ~(0x03U << tmp2);
+ tmp |= ((pll->ct.vclk_post_div & 0x03U) << tmp2);
+ aty_st_pll_ct(VCLK_POST_DIV, tmp, par);
+
+ /* Set extended post-divider */
+ tmp = aty_ld_pll_ct(PLL_EXT_CNTL, par);
+ tmp &= ~(0x10U << par->clk_wr_offset);
+ tmp &= 0xF0U;
+ tmp |= pll->ct.pll_ext_cntl;
+ aty_st_pll_ct(PLL_EXT_CNTL, tmp, par);
+
+ /* Set feedback divider */
+ tmp = VCLK0_FB_DIV + par->clk_wr_offset;
+ aty_st_pll_ct(tmp, (pll->ct.vclk_fb_div & 0xFFU), par);
+
+ aty_st_pll_ct(PLL_GEN_CNTL, (pll->ct.pll_gen_cntl & (~(PLL_OVERRIDE | PLL_MCLK_RST))) | OSC_EN, par);
+
+ /* End VCLK generator reset */
+ aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl & ~(PLL_VCLK_RST), par);
+ mdelay(5);
+
+ aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
+ aty_st_pll_ct(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
+ mdelay(1);
+
+ /* Restore mode register */
+ if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
+ aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl, par);
if (M64_HAS(GTB_DSP)) {
+ u8 dll_cntl;
+
if (M64_HAS(XL_DLL))
- aty_st_pll(DLL_CNTL, 0x80, par);
+ dll_cntl = 0x80;
else if (par->ram_type >= SDRAM)
- aty_st_pll(DLL_CNTL, 0xa6, par);
+ dll_cntl = 0xa6;
else
- aty_st_pll(DLL_CNTL, 0xa0, par);
- aty_st_pll(VFC_CNTL, 0x1b, par);
+ dll_cntl = 0xa0;
+ aty_st_pll_ct(DLL_CNTL, dll_cntl, par);
+ aty_st_pll_ct(VFC_CNTL, 0x1b, par);
aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, par);
aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, par);
+
+ mdelay(10);
+ aty_st_pll_ct(DLL_CNTL, dll_cntl, par);
+ mdelay(10);
+ aty_st_pll_ct(DLL_CNTL, dll_cntl | 0x40, par);
+ mdelay(10);
+ aty_st_pll_ct(DLL_CNTL, dll_cntl & ~0x40, par);
+ }
+#ifdef CONFIG_FB_ATY_GENERIC_LCD
+ if (par->lcd_table != 0) {
+ /* restore LCD */
+ aty_st_lcd(LCD_GEN_CNTL, lcd_gen_cntrl, par);
}
+#endif
+}
+
+void __init aty_get_pll_ct(const struct fb_info *info, union aty_pll *pll)
+{
+ struct atyfb_par *par = (struct atyfb_par *) info->par;
+ u8 tmp, clock;
+
+ clock = aty_ld_8(CLOCK_CNTL, par) & 0x03U;
+ tmp = clock << 1;
+ pll->ct.vclk_post_div = (aty_ld_pll_ct(VCLK_POST_DIV, par) >> tmp) & 0x03U;
+
+ pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par) & 0x0FU;
+ pll->ct.vclk_fb_div = aty_ld_pll_ct(VCLK0_FB_DIV + clock, par) & 0xFFU;
+ pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
+ pll->ct.mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
+
+ pll->ct.pll_gen_cntl = aty_ld_pll_ct(PLL_GEN_CNTL, par);
+ pll->ct.pll_vclk_cntl = aty_ld_pll_ct(PLL_VCLK_CNTL, par);
+
+ if (M64_HAS(GTB_DSP)) {
+ pll->ct.dsp_config = aty_ld_le32(DSP_CONFIG, par);
+ pll->ct.dsp_on_off = aty_ld_le32(DSP_ON_OFF, par);
+ }
+}
+
+int __init aty_init_pll_ct(const struct fb_info *info, union aty_pll *pll) {
+ struct atyfb_par *par = (struct atyfb_par *) info->par;
+ u8 mpost_div, xpost_div, sclk_post_div_real, sclk_fb_div, spll_cntl2;
+ u32 q, i, memcntl, trp;
+ u32 dsp_config, dsp_on_off, vga_dsp_config, vga_dsp_on_off;
+#ifdef DEBUG
+ int pllmclk, pllsclk;
+#endif
+ pll->ct.pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
+ pll->ct.xclk_post_div = pll->ct.pll_ext_cntl & 0x07;
+ pll->ct.xclk_ref_div = 1;
+ switch (pll->ct.xclk_post_div) {
+ case 0: case 1: case 2: case 3:
+ break;
+
+ case 4:
+ pll->ct.xclk_ref_div = 3;
+ pll->ct.xclk_post_div = 0;
+ break;
+
+ default:
+ printk(KERN_CRIT "atyfb: Unsupported xclk source: %d.\n", pll->ct.xclk_post_div);
+ return -EINVAL;
+ }
+ pll->ct.mclk_fb_mult = 2;
+ if(pll->ct.pll_ext_cntl & PLL_MFB_TIMES_4_2B) {
+ pll->ct.mclk_fb_mult = 4;
+ pll->ct.xclk_post_div -= 1;
+ }
+
+#ifdef DEBUG
+ printk("atyfb(%s): mclk_fb_mult=%d, xclk_post_div=%d\n",
+ __FUNCTION__, pll->ct.mclk_fb_mult, pll->ct.xclk_post_div);
+#endif
+
+ memcntl = aty_ld_le32(MEM_CNTL, par);
+ trp = (memcntl & 0x300) >> 8;
+
+ pll->ct.xclkpagefaultdelay = ((memcntl & 0xc00) >> 10) + ((memcntl & 0x1000) >> 12) + trp + 2;
+ pll->ct.xclkmaxrasdelay = ((memcntl & 0x70000) >> 16) + trp + 2;
+
+ if (M64_HAS(FIFO_32)) {
+ pll->ct.fifo_size = 32;
+ } else {
+ pll->ct.fifo_size = 24;
+ pll->ct.xclkpagefaultdelay += 2;
+ pll->ct.xclkmaxrasdelay += 3;
+ }
+
+ switch (par->ram_type) {
+ case DRAM:
+ if (info->fix.smem_len<=ONE_MB) {
+ pll->ct.dsp_loop_latency = 10;
+ } else {
+ pll->ct.dsp_loop_latency = 8;
+ pll->ct.xclkpagefaultdelay += 2;
+ }
+ break;
+ case EDO:
+ case PSEUDO_EDO:
+ if (info->fix.smem_len<=ONE_MB) {
+ pll->ct.dsp_loop_latency = 9;
+ } else {
+ pll->ct.dsp_loop_latency = 8;
+ pll->ct.xclkpagefaultdelay += 1;
+ }
+ break;
+ case SDRAM:
+ if (info->fix.smem_len<=ONE_MB) {
+ pll->ct.dsp_loop_latency = 11;
+ } else {
+ pll->ct.dsp_loop_latency = 10;
+ pll->ct.xclkpagefaultdelay += 1;
+ }
+ break;
+ case SGRAM:
+ pll->ct.dsp_loop_latency = 8;
+ pll->ct.xclkpagefaultdelay += 3;
+ break;
+ default:
+ pll->ct.dsp_loop_latency = 11;
+ pll->ct.xclkpagefaultdelay += 3;
+ break;
+ }
+
+ if (pll->ct.xclkmaxrasdelay <= pll->ct.xclkpagefaultdelay)
+ pll->ct.xclkmaxrasdelay = pll->ct.xclkpagefaultdelay + 1;
+
+ /* Allow BIOS to override */
+ dsp_config = aty_ld_le32(DSP_CONFIG, par);
+ dsp_on_off = aty_ld_le32(DSP_ON_OFF, par);
+ vga_dsp_config = aty_ld_le32(VGA_DSP_CONFIG, par);
+ vga_dsp_on_off = aty_ld_le32(VGA_DSP_ON_OFF, par);
+
+ if (dsp_config)
+ pll->ct.dsp_loop_latency = (dsp_config & DSP_LOOP_LATENCY) >> 16;
+#if 0
+ FIXME: is it relevant for us?
+ if ((!dsp_on_off && !M64_HAS(RESET_3D)) ||
+ ((dsp_on_off == vga_dsp_on_off) &&
+ (!dsp_config || !((dsp_config ^ vga_dsp_config) & DSP_XCLKS_PER_QW)))) {
+ vga_dsp_on_off &= VGA_DSP_OFF;
+ vga_dsp_config &= VGA_DSP_XCLKS_PER_QW;
+ if (ATIDivide(vga_dsp_on_off, vga_dsp_config, 5, 1) > 24)
+ pll->ct.fifo_size = 32;
+ else
+ pll->ct.fifo_size = 24;
+ }
+#endif
+ /* Exit if the user does not want us to tamper with the clock
+ rates of her chip. */
+ if (par->mclk_per == 0) {
+ u8 mclk_fb_div, pll_ext_cntl;
+ pll->ct.pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
+ pll_ext_cntl = aty_ld_pll_ct(PLL_EXT_CNTL, par);
+ pll->ct.xclk_post_div_real = postdividers[pll_ext_cntl & 0x07];
+ mclk_fb_div = aty_ld_pll_ct(MCLK_FB_DIV, par);
+ if (pll_ext_cntl & PLL_MFB_TIMES_4_2B)
+ mclk_fb_div <<= 1;
+ pll->ct.mclk_fb_div = mclk_fb_div;
+ return 0;
+ }
+
+ pll->ct.pll_ref_div = par->pll_per * 2 * 255 / par->ref_clk_per;
+
+ /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
+ q = par->ref_clk_per * pll->ct.pll_ref_div * 8 /
+ (pll->ct.mclk_fb_mult * par->xclk_per);
+
+ if (q < 16*8 || q > 255*8) {
+ printk(KERN_CRIT "atxfb: xclk out of range\n");
+ return -EINVAL;
+ } else {
+ xpost_div = (q < 128*8);
+ xpost_div += (q < 64*8);
+ xpost_div += (q < 32*8);
+ }
+ pll->ct.xclk_post_div_real = postdividers[xpost_div];
+ pll->ct.mclk_fb_div = q * pll->ct.xclk_post_div_real / 8;
+
+#ifdef DEBUG
+ pllmclk = (1000000 * pll->ct.mclk_fb_mult * pll->ct.mclk_fb_div) /
+ (par->ref_clk_per * pll->ct.pll_ref_div);
+ printk("atyfb(%s): pllmclk=%d MHz, xclk=%d MHz\n",
+ __FUNCTION__, pllmclk, pllmclk / pll->ct.xclk_post_div_real);
+#endif
+
+ if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
+ pll->ct.pll_gen_cntl = OSC_EN;
+ else
+ pll->ct.pll_gen_cntl = OSC_EN | DLL_PWDN /* | FORCE_DCLK_TRI_STATE */;
+
+ if (M64_HAS(MAGIC_POSTDIV))
+ pll->ct.pll_ext_cntl = 0;
+ else
+ pll->ct.pll_ext_cntl = xpost_div;
+
+ if (pll->ct.mclk_fb_mult == 4)
+ pll->ct.pll_ext_cntl |= PLL_MFB_TIMES_4_2B;
+
+ if (par->mclk_per == par->xclk_per) {
+ pll->ct.pll_gen_cntl |= (xpost_div << 4); /* mclk == xclk */
+ } else {
+ /*
+ * The chip clock is not equal to the memory clock.
+ * Therefore we will use sclk to clock the chip.
+ */
+ pll->ct.pll_gen_cntl |= (6 << 4); /* mclk == sclk */
+
+ q = par->ref_clk_per * pll->ct.pll_ref_div * 4 / par->mclk_per;
+ if (q < 16*8 || q > 255*8) {
+ printk(KERN_CRIT "atyfb: mclk out of range\n");
+ return -EINVAL;
+ } else {
+ mpost_div = (q < 128*8);
+ mpost_div += (q < 64*8);
+ mpost_div += (q < 32*8);
+ }
+ sclk_post_div_real = postdividers[mpost_div];
+ sclk_fb_div = q * sclk_post_div_real / 8;
+ spll_cntl2 = mpost_div << 4;
+#ifdef DEBUG
+ pllsclk = (1000000 * 2 * sclk_fb_div) /
+ (par->ref_clk_per * pll->ct.pll_ref_div);
+ printk("atyfb(%s): use sclk, pllsclk=%d MHz, sclk=mclk=%d MHz\n",
+ __FUNCTION__, pllsclk, pllsclk / sclk_post_div_real);
+#endif
+ /*
+ * This disables the sclk, crashes the computer as reported:
+ * aty_st_pll_ct(SPLL_CNTL2, 3, info);
+ *
+ * So it seems the sclk must be enabled before it is used;
+ * so PLL_GEN_CNTL must be programmed *after* the sclk.
+ */
+ aty_st_pll_ct(SCLK_FB_DIV, sclk_fb_div, par);
+ aty_st_pll_ct(SPLL_CNTL2, spll_cntl2, par);
+ /*
+ * The sclk has been started. However, I believe the first clock
+ * ticks it generates are not very stable. Hope this primitive loop
+ * helps for Rage Mobilities that sometimes crash when
+ * we switch to sclk. (Daniel Mantione, 13-05-2003)
+ */
+ for (i=0;i<=0x1ffff;i++);
+ }
+
+ aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par);
+ aty_st_pll_ct(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
+ aty_st_pll_ct(MCLK_FB_DIV, pll->ct.mclk_fb_div, par);
+ aty_st_pll_ct(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par);
+ /* Disable the extra precision pixel clock controls since we do not use them. */
+ aty_st_pll_ct(EXT_VPLL_CNTL, aty_ld_pll_ct(EXT_VPLL_CNTL, par) &
+ ~(EXT_VPLL_EN | EXT_VPLL_VGA_EN | EXT_VPLL_INSYNC), par);
+
+ return 0;
}
static int dummy(void)
@@ -274,6 +607,8 @@
const struct aty_pll_ops aty_pll_ct = {
.var_to_pll = aty_var_to_pll_ct,
- .pll_to_var = aty_pll_ct_to_var,
+ .pll_to_var = aty_pll_to_var_ct,
.set_pll = aty_set_pll_ct,
+ .get_pll = aty_get_pll_ct,
+ .init_pll = aty_init_pll_ct
};
diff -Nru a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c
--- a/drivers/video/aty/mach64_cursor.c 2004-10-19 20:22:44 +08:00
+++ b/drivers/video/aty/mach64_cursor.c 2004-10-09 00:22:38 +08:00
@@ -1,12 +1,11 @@
-
/*
* ATI Mach64 CT/VT/GT/LT Cursor Support
*/
#include <linux/slab.h>
-#include <linux/console.h>
#include <linux/fb.h>
#include <linux/init.h>
+#include <linux/string.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -19,13 +18,49 @@
#include <video/mach64.h>
#include "atyfb.h"
+/*
+ * The hardware cursor definition requires 2 bits per pixel. The
+ * Cursor size reguardless of the visible cursor size is 64 pixels
+ * by 64 lines. The total memory required to define the cursor is
+ * 16 bytes / line for 64 lines or 1024 bytes of data. The data
+ * must be in a contigiuos format. The 2 bit cursor code values are
+ * as follows:
+ *
+ * 00 - pixel colour = CURSOR_CLR_0
+ * 01 - pixel colour = CURSOR_CLR_1
+ * 10 - pixel colour = transparent (current display pixel)
+ * 11 - pixel colour = 1's complement of current display pixel
+ *
+ * Cursor Offset 64 pixels Actual Displayed Area
+ * \_________________________/
+ * | | | |
+ * |<--------------->| | |
+ * | CURS_HORZ_OFFSET| | |
+ * | |_______| | 64 Lines
+ * | ^ | |
+ * | | | |
+ * | CURS_VERT_OFFSET| |
+ * | | | |
+ * |____________________|____| |
+ *
+ *
+ * The Screen position of the top left corner of the displayed
+ * cursor is specificed by CURS_HORZ_VERT_POSN. Care must be taken
+ * when the cursor hot spot is not the top left corner and the
+ * physical cursor position becomes negative. It will be be displayed
+ * if either the horizontal or vertical cursor position is negative
+ *
+ * If x becomes negative the cursor manager must adjust the CURS_HORZ_OFFSET
+ * to a larger number and saturate CUR_HORZ_POSN to zero.
+ *
+ * if Y becomes negative, CUR_VERT_OFFSET must be adjusted to a larger number,
+ * CUR_OFFSET must be adjusted to a point to the appropraite line in the cursor
+ * definitation and CUR_VERT_POSN must be saturated to zero.
+ */
+
/*
* Hardware Cursor support.
*/
-
-static const u8 cursor_pixel_map[2] = { 0, 15 };
-static const u8 cursor_color_map[2] = { 0, 0xff };
-
static const u8 cursor_bits_lookup[16] = {
0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
@@ -36,90 +71,39 @@
0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
};
-void aty_set_cursor_color(struct fb_info *info)
-{
- struct atyfb_par *par = (struct atyfb_par *) info->par;
- struct aty_cursor *c = par->cursor;
- const u8 *pixel = cursor_pixel_map; /* ++Geert: Why?? */
- const u8 *red = cursor_color_map;
- const u8 *green = cursor_color_map;
- const u8 *blue = cursor_color_map;
- u32 fg_color, bg_color;
-
- if (!c)
- return;
-
-#ifdef __sparc__
- if (par->mmaped)
- return;
-#endif
- fg_color = (u32) red[0] << 24;
- fg_color |= (u32) green[0] << 16;
- fg_color |= (u32) blue[0] << 8;
- fg_color |= (u32) pixel[0];
-
- bg_color = (u32) red[1] << 24;
- bg_color |= (u32) green[1] << 16;
- bg_color |= (u32) blue[1] << 8;
- bg_color |= (u32) pixel[1];
-
- wait_for_fifo(2, par);
- aty_st_le32(CUR_CLR0, fg_color, par);
- aty_st_le32(CUR_CLR1, bg_color, par);
-}
-
-void aty_set_cursor_shape(struct fb_info *info)
+int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
- struct fb_cursor *cursor = &info->cursor;
- struct aty_cursor *c = par->cursor;
- u8 *ram, m, b;
+ u16 xoff, yoff;
int x, y;
- if (!c)
- return;
#ifdef __sparc__
if (par->mmaped)
- return;
+ return -EPERM;
#endif
+ if (par->asleep)
+ return -EPERM;
- ram = c->ram;
- for (y = 0; y < cursor->image.height; y++) {
- for (x = 0; x < cursor->image.width >> 2; x++) {
- m = c->mask[x][y];
- b = c->bits[x][y];
- fb_writeb(cursor_mask_lookup[m >> 4] |
- cursor_bits_lookup[(b & m) >> 4], ram++);
- fb_writeb(cursor_mask_lookup[m & 0x0f] |
- cursor_bits_lookup[(b & m) & 0x0f],
- ram++);
- }
- for (; x < 8; x++) {
- fb_writeb(0xaa, ram++);
- fb_writeb(0xaa, ram++);
- }
+ /* Hide cursor */
+ wait_for_fifo(1, par);
+ aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) & ~HWCURSOR_ENABLE, par);
+
+ /* Set size */
+ if (cursor->set & FB_CUR_SETSIZE) {
+ info->cursor.image.height = cursor->image.height;
+ info->cursor.image.width = cursor->image.width;
}
- fb_memset(ram, 0xaa, (64 - cursor->image.height) * 16);
-}
-static void aty_set_cursor(struct fb_info *info)
-{
- struct atyfb_par *par = (struct atyfb_par *) info->par;
- struct fb_cursor *cursor = &info->cursor;
- struct aty_cursor *c = par->cursor;
- u16 xoff, yoff;
- int x, y;
+ /* Set hot spot */
+ if (cursor->set & FB_CUR_SETHOT)
+ info->cursor.hot = cursor->hot;
+
+ /* set position */
+ if (cursor->set & FB_CUR_SETPOS) {
+ info->cursor.image.dx = cursor->image.dx;
+ info->cursor.image.dy = cursor->image.dy;
- if (!c)
- return;
-
-#ifdef __sparc__
- if (par->mmaped)
- return;
-#endif
-
- if (cursor->enable) {
- x = cursor->image.dx - cursor->hot.x - info->var.xoffset;
+ x = info->cursor.image.dx - info->cursor.hot.x - info->var.xoffset;
if (x < 0) {
xoff = -x;
x = 0;
@@ -127,7 +111,7 @@
xoff = 0;
}
- y = cursor->image.dy - cursor->hot.y - info->var.yoffset;
+ y = info->cursor.image.dy - info->cursor.hot.y - info->var.yoffset;
if (y < 0) {
yoff = -y;
y = 0;
@@ -135,107 +119,120 @@
yoff = 0;
}
+ /*
+ * In doublescan mode, the cursor location also needs to be
+ * doubled.
+ */
+ if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN)
+ y<<=1;
wait_for_fifo(4, par);
- aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1),
- par);
+ aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1), par);
aty_st_le32(CUR_HORZ_VERT_OFF,
- ((u32) (64 - cursor->image.height + yoff) << 16) | xoff,
+ ((u32) (64 - info->cursor.image.height + yoff) << 16) | xoff,
par);
aty_st_le32(CUR_HORZ_VERT_POSN, ((u32) y << 16) | x, par);
- aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
- | HWCURSOR_ENABLE, par);
- } else {
- wait_for_fifo(1, par);
- aty_st_le32(GEN_TEST_CNTL,
- aty_ld_le32(GEN_TEST_CNTL,
- par) & ~HWCURSOR_ENABLE, par);
}
- if (par->blitter_may_be_busy)
- wait_for_idle(par);
-}
-
-int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
-{
- struct atyfb_par *par = (struct atyfb_par *) info->par;
- struct aty_cursor *c = par->cursor;
- if (!c)
- return -1;
-
-#ifdef __sparc__
- if (par->mmaped)
- return 0;
-#endif
+ /* Set color map */
+ if (cursor->set & FB_CUR_SETCMAP) {
+ u32 fg_idx, bg_idx, fg, bg;
+
+ info->cursor.image.fg_color = cursor->image.fg_color;
+ info->cursor.image.bg_color = cursor->image.bg_color;
+ fg_idx = info->cursor.image.fg_color;
+ bg_idx = info->cursor.image.bg_color;
+
+ fg = (info->cmap.red[fg_idx] << 24) |
+ (info->cmap.green[fg_idx] << 16) |
+ (info->cmap.blue[fg_idx] << 8) | 15;
+
+ bg = (info->cmap.red[bg_idx] << 24) |
+ (info->cmap.green[bg_idx] << 16) |
+ (info->cmap.blue[bg_idx] << 8);
+
+ wait_for_fifo(2, par);
+ aty_st_le32(CUR_CLR0, bg, par);
+ aty_st_le32(CUR_CLR1, fg, par);
+ }
- aty_set_cursor(info);
- cursor->image.dx = info->cursor.image.dx;
- cursor->image.dy = info->cursor.image.dy;
+ if (cursor->set & FB_CUR_SETSHAPE) {
+ u8 *src = (u8 *)cursor->image.data;
+ u8 *msk = (u8 *)info->cursor.mask;
+ u8 *dst = (u8 *)info->sprite.addr;
+ unsigned int width = (info->cursor.image.width + 7) >> 3;
+ unsigned int height = info->cursor.image.height;
+ unsigned int align = info->sprite.scan_align;
+
+ unsigned int i, j, offset;
+ u8 m, b;
+
+ // Clear cursor image with 1010101010...
+ fb_memset(dst, 0xaa, 1024);
+
+ offset = align - width*2;
+
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ b = *src++;
+ m = *msk++;
+ switch (info->cursor.rop) {
+ case ROP_XOR:
+ // Upper 4 bits of mask data
+ fb_writeb(cursor_mask_lookup[m >> 4 ] |
+ cursor_bits_lookup[(b ^ m) >> 4], dst++);
+ // Lower 4 bits of mask
+ fb_writeb(cursor_mask_lookup[m & 0x0f ] |
+ cursor_bits_lookup[(b ^ m) & 0x0f], dst++);
+ break;
+ case ROP_COPY:
+ // Upper 4 bits of mask data
+ fb_writeb(cursor_mask_lookup[m >> 4 ] |
+ cursor_bits_lookup[(b & m) >> 4], dst++);
+ // Lower 4 bits of mask
+ fb_writeb(cursor_mask_lookup[m & 0x0f ] |
+ cursor_bits_lookup[(b & m) & 0x0f], dst++);
+ break;
+ }
+ }
+ dst += offset;
+ }
+ }
- aty_set_cursor(info);
+ if (cursor->enable) {
+ wait_for_fifo(1, par);
+ aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
+ | HWCURSOR_ENABLE, par);
+ }
return 0;
}
-struct aty_cursor *__init aty_init_cursor(struct fb_info *info)
+int __init aty_init_cursor(struct fb_info *info)
{
- struct aty_cursor *cursor;
unsigned long addr;
- cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC);
- if (!cursor)
- return NULL;
- memset(cursor, 0, sizeof(*cursor));
-
info->fix.smem_len -= PAGE_SIZE;
#ifdef __sparc__
addr = (unsigned long) info->screen_base - 0x800000 + info->fix.smem_len;
- cursor->ram = (u8 *) addr;
+ info->sprite.addr = (u8 *) addr;
#else
#ifdef __BIG_ENDIAN
addr = info->fix.smem_start - 0x800000 + info->fix.smem_len;
- cursor->ram = (u8 *) ioremap(addr, 1024);
+ info->sprite.addr = (u8 *) ioremap(addr, 1024);
#else
addr = (unsigned long) info->screen_base + info->fix.smem_len;
- cursor->ram = (u8 *) addr;
+ info->sprite.addr = (u8 *) addr;
#endif
#endif
- if (!cursor->ram) {
- kfree(cursor);
- return NULL;
- }
- return cursor;
-}
+ if (!info->sprite.addr)
+ return -ENXIO;
+ info->sprite.size = PAGE_SIZE;
+ info->sprite.scan_align = 16; /* Scratch pad 64 bytes wide */
+ info->sprite.buf_align = 16; /* and 64 lines tall. */
+ info->sprite.flags = FB_PIXMAP_IO;
-int atyfb_set_font(struct fb_info *info, int width, int height)
-{
- struct atyfb_par *par = (struct atyfb_par *) info->par;
- struct fb_cursor *cursor = &info->cursor;
- struct aty_cursor *c = par->cursor;
- int i, j;
-
- if (c) {
- if (!width || !height) {
- width = 8;
- height = 16;
- }
-
- cursor->hot.x = 0;
- cursor->hot.y = 0;
- cursor->image.width = width;
- cursor->image.height = height;
-
- memset(c->bits, 0xff, sizeof(c->bits));
- memset(c->mask, 0, sizeof(c->mask));
-
- for (i = 0, j = width; j >= 0; j -= 8, i++) {
- c->mask[i][height - 2] =
- (j >= 8) ? 0xff : (0xff << (8 - j));
- c->mask[i][height - 1] =
- (j >= 8) ? 0xff : (0xff << (8 - j));
- }
+ info->fbops->fb_cursor = atyfb_cursor;
- aty_set_cursor_color(info);
- aty_set_cursor_shape(info);
- }
- return 1;
+ return 0;
}
+
diff -Nru a/drivers/video/aty/mach64_gx.c b/drivers/video/aty/mach64_gx.c
--- a/drivers/video/aty/mach64_gx.c 2004-10-19 20:22:45 +08:00
+++ b/drivers/video/aty/mach64_gx.c 2004-10-07 06:18:18 +08:00
@@ -121,7 +121,7 @@
}
static int aty_var_to_pll_514(const struct fb_info *info, u32 vclk_per,
- u8 bpp, union aty_pll *pll)
+ u32 bpp, union aty_pll *pll)
{
/*
* FIXME: use real calculations instead of using fixed values from the old
@@ -253,9 +253,9 @@
temp = aty_ld_8(DAC_CNTL, par);
aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, par);
- if (info->fix.smem_len < MEM_SIZE_1M)
+ if (info->fix.smem_len < ONE_MB)
mask = 0x04;
- else if (info->fix.smem_len == MEM_SIZE_1M)
+ else if (info->fix.smem_len == ONE_MB)
mask = 0x08;
else
mask = 0x0C;
@@ -339,8 +339,8 @@
* ATI 18818 / ICS 2595 Clock Chip
*/
-static int aty_var_to_pll_18818(const struct fb_info *info,
- u32 vclk_per, u8 bpp, union aty_pll *pll)
+static int aty_var_to_pll_18818(const struct fb_info *info, u32 vclk_per,
+ u32 bpp, union aty_pll *pll)
{
u32 MHz100; /* in 0.01 MHz */
u32 program_bits;
@@ -495,8 +495,8 @@
* STG 1703 Clock Chip
*/
-static int aty_var_to_pll_1703(const struct fb_info *info,
- u32 vclk_per, u8 bpp, union aty_pll *pll)
+static int aty_var_to_pll_1703(const struct fb_info *info, u32 vclk_per,
+ u32 bpp, union aty_pll *pll)
{
u32 mhz100; /* in 0.01 MHz */
u32 program_bits;
@@ -611,8 +611,8 @@
* Chrontel 8398 Clock Chip
*/
-static int aty_var_to_pll_8398(const struct fb_info *info,
- u32 vclk_per, u8 bpp, union aty_pll *pll)
+static int aty_var_to_pll_8398(const struct fb_info *info, u32 vclk_per,
+ u32 bpp, union aty_pll *pll)
{
u32 tempA, tempB, fOut, longMHz100, diff, preDiff;
@@ -736,7 +736,7 @@
*/
static int aty_var_to_pll_408(const struct fb_info *info, u32 vclk_per,
- u8 bpp, union aty_pll *pll)
+ u32 bpp, union aty_pll *pll)
{
u32 mhz100; /* in 0.01 MHz */
u32 program_bits;
diff -Nru a/drivers/video/aty/xlinit.c b/drivers/video/aty/xlinit.c
--- a/drivers/video/aty/xlinit.c 2004-10-19 20:22:54 +08:00
+++ b/drivers/video/aty/xlinit.c 2004-10-07 06:18:18 +08:00
@@ -148,15 +148,15 @@
static void init_dll(struct atyfb_par *par)
{
// enable DLL
- aty_st_pll(PLL_GEN_CNTL,
- aty_ld_pll(PLL_GEN_CNTL, par) & 0x7f,
+ aty_st_pll_ct(PLL_GEN_CNTL,
+ aty_ld_pll_ct(PLL_GEN_CNTL, par) & 0x7f,
par);
// reset DLL
- aty_st_pll(DLL_CNTL, 0x82, par);
- aty_st_pll(DLL_CNTL, 0xE2, par);
+ aty_st_pll_ct(DLL_CNTL, 0x82, par);
+ aty_st_pll_ct(DLL_CNTL, 0xE2, par);
mdelay(5);
- aty_st_pll(DLL_CNTL, 0x82, par);
+ aty_st_pll_ct(DLL_CNTL, 0x82, par);
mdelay(6);
}
@@ -164,8 +164,8 @@
int hsync_enb)
{
reset_gui(par);
- aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, par);
- aty_st_pll(SCLK_FB_DIV, pll->sclk_fb_div, par);
+ aty_st_pll_ct(MCLK_FB_DIV, pll->mclk_fb_div, par);
+ aty_st_pll_ct(SCLK_FB_DIV, pll->sclk_fb_div, par);
mdelay(15);
init_dll(par);
@@ -177,9 +177,9 @@
aty_st_8(CRTC_GEN_CNTL+3,
hsync_enb ? 0x00 : 0x04, par);
- aty_st_pll(SPLL_CNTL2, pll->spll_cntl2, par);
- aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, par);
- aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, par);
+ aty_st_pll_ct(SPLL_CNTL2, pll->spll_cntl2, par);
+ aty_st_pll_ct(PLL_GEN_CNTL, pll->pll_gen_cntl, par);
+ aty_st_pll_ct(PLL_VCLK_CNTL, pll->pll_vclk_cntl, par);
}
int atyfb_xl_init(struct fb_info *info)
@@ -216,31 +216,31 @@
if ((err = aty_pll_ct.var_to_pll(info, 39726, 8, &pll)))
return err;
- aty_st_pll(LVDS_CNTL0, 0x00, par);
- aty_st_pll(DLL2_CNTL, card->dll2_cntl, par);
- aty_st_pll(V2PLL_CNTL, 0x10, par);
- aty_st_pll(MPLL_CNTL, MPLL_GAIN, par);
- aty_st_pll(VPLL_CNTL, VPLL_GAIN, par);
- aty_st_pll(PLL_VCLK_CNTL, 0x00, par);
- aty_st_pll(VFC_CNTL, 0x1B, par);
- aty_st_pll(PLL_REF_DIV, pll.ct.pll_ref_div, par);
- aty_st_pll(PLL_EXT_CNTL, pll.ct.pll_ext_cntl, par);
- aty_st_pll(SPLL_CNTL2, 0x03, par);
- aty_st_pll(PLL_GEN_CNTL, 0x44, par);
+ aty_st_pll_ct(LVDS_CNTL0, 0x00, par);
+ aty_st_pll_ct(DLL2_CNTL, card->dll2_cntl, par);
+ aty_st_pll_ct(V2PLL_CNTL, 0x10, par);
+ aty_st_pll_ct(MPLL_CNTL, MPLL_GAIN, par);
+ aty_st_pll_ct(VPLL_CNTL, VPLL_GAIN, par);
+ aty_st_pll_ct(PLL_VCLK_CNTL, 0x00, par);
+ aty_st_pll_ct(VFC_CNTL, 0x1B, par);
+ aty_st_pll_ct(PLL_REF_DIV, pll.ct.pll_ref_div, par);
+ aty_st_pll_ct(PLL_EXT_CNTL, pll.ct.pll_ext_cntl, par);
+ aty_st_pll_ct(SPLL_CNTL2, 0x03, par);
+ aty_st_pll_ct(PLL_GEN_CNTL, 0x44, par);
reset_clocks(par, &pll.ct, 0);
mdelay(10);
- aty_st_pll(VCLK_POST_DIV, 0x03, par);
- aty_st_pll(VCLK0_FB_DIV, 0xDA, par);
- aty_st_pll(VCLK_POST_DIV, 0x0F, par);
- aty_st_pll(VCLK1_FB_DIV, 0xF5, par);
- aty_st_pll(VCLK_POST_DIV, 0x3F, par);
- aty_st_pll(PLL_EXT_CNTL, 0x40 | pll.ct.pll_ext_cntl, par);
- aty_st_pll(VCLK2_FB_DIV, 0x00, par);
- aty_st_pll(VCLK_POST_DIV, 0xFF, par);
- aty_st_pll(PLL_EXT_CNTL, 0xC0 | pll.ct.pll_ext_cntl, par);
- aty_st_pll(VCLK3_FB_DIV, 0x00, par);
+ aty_st_pll_ct(VCLK_POST_DIV, 0x03, par);
+ aty_st_pll_ct(VCLK0_FB_DIV, 0xDA, par);
+ aty_st_pll_ct(VCLK_POST_DIV, 0x0F, par);
+ aty_st_pll_ct(VCLK1_FB_DIV, 0xF5, par);
+ aty_st_pll_ct(VCLK_POST_DIV, 0x3F, par);
+ aty_st_pll_ct(PLL_EXT_CNTL, 0x40 | pll.ct.pll_ext_cntl, par);
+ aty_st_pll_ct(VCLK2_FB_DIV, 0x00, par);
+ aty_st_pll_ct(VCLK_POST_DIV, 0xFF, par);
+ aty_st_pll_ct(PLL_EXT_CNTL, 0xC0 | pll.ct.pll_ext_cntl, par);
+ aty_st_pll_ct(VCLK3_FB_DIV, 0x00, par);
aty_st_8(BUS_CNTL, 0x01, par);
aty_st_le32(BUS_CNTL, card->bus_cntl | 0x08000000, par);
@@ -295,7 +295,7 @@
aty_st_8(CRTC_GEN_CNTL+3, 0x04, par);
mdelay(10);
- aty_st_pll(PLL_YCLK_CNTL, 0x25, par);
+ aty_st_pll_ct(PLL_YCLK_CNTL, 0x25, par);
aty_st_le16(CUSTOM_MACRO_CNTL, 0x0179, par);
aty_st_le16(CUSTOM_MACRO_CNTL+2, 0x005E, par);
@@ -309,9 +309,9 @@
aty_st_8(CONFIG_STAT0, 0xA0 | card->mem_type, par);
- aty_st_pll(PLL_YCLK_CNTL, 0x01, par);
+ aty_st_pll_ct(PLL_YCLK_CNTL, 0x01, par);
mdelay(15);
- aty_st_pll(PLL_YCLK_CNTL, card->pll_yclk_cntl, par);
+ aty_st_pll_ct(PLL_YCLK_CNTL, card->pll_yclk_cntl, par);
mdelay(1);
reset_clocks(par, &pll.ct, 0);
diff -Nru a/include/video/mach64.h b/include/video/mach64.h
--- a/include/video/mach64.h 2004-10-19 22:44:44 +08:00
+++ b/include/video/mach64.h 2004-10-07 06:18:18 +08:00
@@ -68,6 +68,8 @@
#define I2C_CNTL_0 0x003C /* Dword offset 0_0F */
+#define DSTN_CONTROL_LG 0x003C /* Dword offset 0_0F (LG) */
+
/* Overscan */
#define OVR_CLR 0x0040 /* Dword offset 0_10 */
#define OVR2_CLR 0x0040 /* Dword offset 0_10 */
@@ -101,7 +103,7 @@
#define CUR_HORZ_VERT_OFF 0x0070 /* Dword offset 0_1C */
#define CUR2_HORZ_VERT_OFF 0x0070 /* Dword offset 0_1C */
-#define CONFIG_PANEL_LG 0x0074 /* Dword offset 0_1D */
+#define CONFIG_PANEL_LG 0x0074 /* Dword offset 0_1D (LG) */
/* General I/O Control */
#define GP_IO 0x0078 /* Dword offset 0_1E */
@@ -116,7 +118,31 @@
#define SCRATCH_REG3 0x008C /* Dword offset 0_23 */
/* Clock Control */
-#define CLOCK_CNTL 0x0090 /* Dword offset 0_24 */
+#define CLOCK_CNTL 0x0090 /* Dword offset 0_24 */
+/* CLOCK_CNTL register constants CT LAYOUT */
+#define CLOCK_SEL 0x0f
+#define CLOCK_SEL_INTERNAL 0x03
+#define CLOCK_SEL_EXTERNAL 0x0c
+#define CLOCK_DIV 0x30
+#define CLOCK_DIV1 0x00
+#define CLOCK_DIV2 0x10
+#define CLOCK_DIV4 0x20
+#define CLOCK_STROBE 0x40
+/* ? 0x80 */
+/* CLOCK_CNTL register constants GX LAYOUT */
+#define CLOCK_BIT 0x04 /* For ICS2595 */
+#define CLOCK_PULSE 0x08 /* For ICS2595 */
+/*#define CLOCK_STROBE 0x40 dito as CT */
+#define CLOCK_DATA 0x80
+
+/* For internal PLL(CT) start */
+#define CLOCK_CNTL_ADDR CLOCK_CNTL + 1
+#define PLL_WR_EN 0x02
+#define PLL_ADDR 0xfc
+#define CLOCK_CNTL_DATA CLOCK_CNTL + 2
+#define PLL_DATA 0xff
+/* For internal PLL(CT) end */
+
#define CLOCK_SEL_CNTL 0x0090 /* Dword offset 0_24 */
/* Configuration */
@@ -129,6 +155,8 @@
#define LCD_INDEX 0x00A4 /* Dword offset 0_29 */
#define LCD_DATA 0x00A8 /* Dword offset 0_2A */
+#define HFB_PITCH_ADDR_LG 0x00A8 /* Dword offset 0_2A (LG) */
+
/* Memory Control */
#define EXT_MEM_CNTL 0x00AC /* Dword offset 0_2B */
#define MEM_CNTL 0x00B0 /* Dword offset 0_2C */
@@ -137,6 +165,8 @@
#define I2C_CNTL_1 0x00BC /* Dword offset 0_2F */
+#define LT_GIO_LG 0x00BC /* Dword offset 0_2F (LG) */
+
/* DAC Control */
#define DAC_REGS 0x00C0 /* Dword offset 0_30 */
#define DAC_W_INDEX 0x00C0 /* Dword offset 0_30 */
@@ -147,14 +177,16 @@
#define EXT_DAC_REGS 0x00C8 /* Dword offset 0_32 */
+#define HORZ_STRETCHING_LG 0x00C8 /* Dword offset 0_32 (LG) */
+#define VERT_STRETCHING_LG 0x00CC /* Dword offset 0_33 (LG) */
+
/* Test and Debug */
#define GEN_TEST_CNTL 0x00D0 /* Dword offset 0_34 */
/* Custom Macros */
#define CUSTOM_MACRO_CNTL 0x00D4 /* Dword offset 0_35 */
-#define LCD_GEN_CNTL_LG 0x00D4 /* Dword offset 0_35 */
-
+#define LCD_GEN_CNTL_LG 0x00D4 /* Dword offset 0_35 (LG) */
#define POWER_MANAGEMENT_LG 0x00D8 /* Dword offset 0_36 (LG) */
/* Configuration */
@@ -558,7 +590,7 @@
#define CRTC_CSYNC_EN 0x00000010
#define CRTC_PIX_BY_2_EN 0x00000020 /* unused on RAGE */
#define CRTC_DISPLAY_DIS 0x00000040
-#define CRTC_VGA_XOVERSCAN 0x00000040
+#define CRTC_VGA_XOVERSCAN 0x00000080
#define CRTC_PIX_WIDTH_MASK 0x00000700
#define CRTC_PIX_WIDTH_4BPP 0x00000100
@@ -572,25 +604,95 @@
#define CRTC_PIX_ORDER_MSN_LSN 0x00000000
#define CRTC_PIX_ORDER_LSN_MSN 0x00000800
+#define CRTC_VSYNC_INT_EN 0x00001000ul /* XC/XL */
+#define CRTC_VSYNC_INT 0x00002000ul /* XC/XL */
+#define CRTC_FIFO_OVERFILL 0x0000c000ul /* VT/GT */
+#define CRTC2_VSYNC_INT_EN 0x00004000ul /* XC/XL */
+#define CRTC2_VSYNC_INT 0x00008000ul /* XC/XL */
+
#define CRTC_FIFO_LWM 0x000f0000
+#define CRTC_HVSYNC_IO_DRIVE 0x00010000 /* XC/XL */
+#define CRTC2_PIX_WIDTH 0x000e0000 /* LTPro */
-#define VGA_128KAP_PAGING 0x00100000
-#define VFC_SYNC_TRISTATE 0x00200000
+#define CRTC_VGA_128KAP_PAGING 0x00100000
+#define CRTC_VFC_SYNC_TRISTATE 0x00200000 /* VTB/GTB/LT */
+#define CRTC2_EN 0x00200000 /* LTPro */
#define CRTC_LOCK_REGS 0x00400000
#define CRTC_SYNC_TRISTATE 0x00800000
#define CRTC_EXT_DISP_EN 0x01000000
-#define CRTC_ENABLE 0x02000000
-#define CRTC_DISP_REQ_ENB 0x04000000
-#define VGA_ATI_LINEAR 0x08000000
+#define CRTC_EN 0x02000000
+#define CRTC_DISP_REQ_EN 0x04000000
+#define CRTC_VGA_LINEAR 0x08000000
#define CRTC_VSYNC_FALL_EDGE 0x10000000
-#define VGA_TEXT_132 0x20000000
-#define VGA_XCRT_CNT_EN 0x40000000
-#define VGA_CUR_B_TEST 0x80000000
+#define CRTC_VGA_TEXT_132 0x20000000
+#define CRTC_CNT_EN 0x40000000
+#define CRTC_CUR_B_TEST 0x80000000
#define CRTC_CRNT_VLINE 0x07f00000
-#define CRTC_VBLANK 0x00000001
+#define CRTC_PRESERVED_MASK 0x0001f000
+
+#define CRTC_VBLANK 0x00000001
+#define CRTC_VBLANK_INT_EN 0x00000002
+#define CRTC_VBLANK_INT 0x00000004
+#define CRTC_VBLANK_INT_AK CRTC_VBLANK_INT
+#define CRTC_VLINE_INT_EN 0x00000008
+#define CRTC_VLINE_INT 0x00000010
+#define CRTC_VLINE_INT_AK CRTC_VLINE_INT
+#define CRTC_VLINE_SYNC 0x00000020
+#define CRTC_FRAME 0x00000040
+#define SNAPSHOT_INT_EN 0x00000080
+#define SNAPSHOT_INT 0x00000100
+#define SNAPSHOT_INT_AK SNAPSHOT_INT
+#define I2C_INT_EN 0x00000200
+#define I2C_INT 0x00000400
+#define I2C_INT_AK I2C_INT
+#define CRTC2_VBLANK 0x00000800
+#define CRTC2_VBLANK_INT_EN 0x00001000
+#define CRTC2_VBLANK_INT 0x00002000
+#define CRTC2_VBLANK_INT_AK CRTC2_VBLANK_INT
+#define CRTC2_VLINE_INT_EN 0x00004000
+#define CRTC2_VLINE_INT 0x00008000
+#define CRTC2_VLINE_INT_AK CRTC2_VLINE_INT
+#define CAPBUF0_INT_EN 0x00010000
+#define CAPBUF0_INT 0x00020000
+#define CAPBUF0_INT_AK CAPBUF0_INT
+#define CAPBUF1_INT_EN 0x00040000
+#define CAPBUF1_INT 0x00080000
+#define CAPBUF1_INT_AK CAPBUF1_INT
+#define OVERLAY_EOF_INT_EN 0x00100000
+#define OVERLAY_EOF_INT 0x00200000
+#define OVERLAY_EOF_INT_AK OVERLAY_EOF_INT
+#define ONESHOT_CAP_INT_EN 0x00400000
+#define ONESHOT_CAP_INT 0x00800000
+#define ONESHOT_CAP_INT_AK ONESHOT_CAP_INT
+#define BUSMASTER_EOL_INT_EN 0x01000000
+#define BUSMASTER_EOL_INT 0x02000000
+#define BUSMASTER_EOL_INT_AK BUSMASTER_EOL_INT
+#define GP_INT_EN 0x04000000
+#define GP_INT 0x08000000
+#define GP_INT_AK GP_INT
+#define CRTC2_VLINE_SYNC 0x10000000
+#define SNAPSHOT2_INT_EN 0x20000000
+#define SNAPSHOT2_INT 0x40000000
+#define SNAPSHOT2_INT_AK SNAPSHOT2_INT
+#define VBLANK_BIT2_INT 0x80000000
+#define VBLANK_BIT2_INT_AK VBLANK_BIT2_INT
+
+#define CRTC_INT_EN_MASK (CRTC_VBLANK_INT_EN | \
+ CRTC_VLINE_INT_EN | \
+ SNAPSHOT_INT_EN | \
+ I2C_INT_EN | \
+ CRTC2_VBLANK_INT_EN | \
+ CRTC2_VLINE_INT_EN | \
+ CAPBUF0_INT_EN | \
+ CAPBUF1_INT_EN | \
+ OVERLAY_EOF_INT_EN | \
+ ONESHOT_CAP_INT_EN | \
+ BUSMASTER_EOL_INT_EN | \
+ GP_INT_EN | \
+ SNAPSHOT2_INT_EN)
/* DAC control values */
@@ -606,6 +708,24 @@
#define DAC_BLANK_ADJ_1 0x00000800
#define DAC_BLANK_ADJ_2 0x00001000
+/* DAC control values (my source XL/XC Register reference) */
+#define DAC_OUTPUT_MASK 0x00000001 /* 0 - PAL, 1 - NTSC */
+#define DAC_MISTERY_BIT 0x00000002 /* PS2 ? RS343 ?, EXTRA_BRIGHT for GT */
+#define DAC_BLANKING 0x00000004
+#define DAC_CMP_DISABLE 0x00000008
+#define DAC1_CLK_SEL 0x00000010
+#define PALETTE_ACCESS_CNTL 0x00000020
+#define PALETTE2_SNOOP_EN 0x00000040
+#define DAC_CMP_OUTPUT 0x00000080 /* read only */
+/* #define DAC_8BIT_EN is ok */
+#define CRT_SENSE 0x00000800 /* read only */
+#define CRT_DETECTION_ON 0x00001000
+#define DAC_VGA_ADR_EN 0x00002000
+#define DAC_FEA_CON_EN 0x00004000
+#define DAC_PDWN 0x00008000
+#define DAC_TYPE_MASK 0x00070000 /* read only */
+
+
/* Mix control values */
@@ -635,6 +755,7 @@
/* Mach64 engine bit constants - these are typically ORed together */
/* BUS_CNTL register constants */
+#define BUS_APER_REG_DIS 0x00000010
#define BUS_FIFO_ERR_ACK 0x00200000
#define BUS_HOST_ERR_ACK 0x00800000
@@ -652,29 +773,48 @@
/* DSP_ON_OFF register constants */
#define DSP_OFF 0x000007ff
#define DSP_ON 0x07ff0000
+#define VGA_DSP_OFF DSP_OFF
+#define VGA_DSP_ON DSP_ON
+#define VGA_DSP_XCLKS_PER_QW DSP_XCLKS_PER_QW
-/* CLOCK_CNTL register constants */
-#define CLOCK_SEL 0x0f
-#define CLOCK_DIV 0x30
-#define CLOCK_DIV1 0x00
-#define CLOCK_DIV2 0x10
-#define CLOCK_DIV4 0x20
-#define CLOCK_STROBE 0x40
-#define PLL_WR_EN 0x02
-
-/* PLL register indices */
+/* PLL register indices and fields */
#define MPLL_CNTL 0x00
+#define PLL_PC_GAIN 0x07
+#define PLL_VC_GAIN 0x18
+#define PLL_DUTY_CYC 0xE0
#define VPLL_CNTL 0x01
#define PLL_REF_DIV 0x02
#define PLL_GEN_CNTL 0x03
+#define PLL_OVERRIDE 0x01 /* PLL_SLEEP */
+#define PLL_MCLK_RST 0x02 /* PLL_MRESET */
+#define OSC_EN 0x04
+#define EXT_CLK_EN 0x08
+#define FORCE_DCLK_TRI_STATE 0x08 /* VT4 -> */
+#define MCLK_SRC_SEL 0x70
+#define EXT_CLK_CNTL 0x80
+#define DLL_PWDN 0x80 /* VT4 -> */
#define MCLK_FB_DIV 0x04
#define PLL_VCLK_CNTL 0x05
+#define PLL_VCLK_SRC_SEL 0x03
+#define PLL_VCLK_RST 0x04
+#define PLL_VCLK_INVERT 0x08
#define VCLK_POST_DIV 0x06
+#define VCLK0_POST 0x03
+#define VCLK1_POST 0x0C
+#define VCLK2_POST 0x30
+#define VCLK3_POST 0xC0
#define VCLK0_FB_DIV 0x07
#define VCLK1_FB_DIV 0x08
#define VCLK2_FB_DIV 0x09
#define VCLK3_FB_DIV 0x0A
#define PLL_EXT_CNTL 0x0B
+#define PLL_XCLK_MCLK_RATIO 0x03
+#define PLL_XCLK_SRC_SEL 0x07
+#define PLL_MFB_TIMES_4_2B 0x08
+#define PLL_VCLK0_XDIV 0x10
+#define PLL_VCLK1_XDIV 0x20
+#define PLL_VCLK2_XDIV 0x40
+#define PLL_VCLK3_XDIV 0x80
#define DLL_CNTL 0x0C
#define DLL1_CNTL 0x0C
#define VFC_CNTL 0x0D
@@ -690,6 +830,9 @@
#define SPLL_CNTL2 0x17
#define APLL_STRAPS 0x18
#define EXT_VPLL_CNTL 0x19
+#define EXT_VPLL_EN 0x04
+#define EXT_VPLL_VGA_EN 0x08
+#define EXT_VPLL_INSYNC 0x10
#define EXT_VPLL_REF_DIV 0x1A
#define EXT_VPLL_FB_DIV 0x1B
#define EXT_VPLL_MSB 0x1C
@@ -708,24 +851,6 @@
#define PLL_YCLK_CNTL 0x29
#define PM_DYN_CLK_CNTL 0x2A
-/* Fields in PLL registers */
-#define PLL_PC_GAIN 0x07
-#define PLL_VC_GAIN 0x18
-#define PLL_DUTY_CYC 0xE0
-#define PLL_OVERRIDE 0x01
-#define PLL_MCLK_RST 0x02
-#define OSC_EN 0x04
-#define EXT_CLK_EN 0x08
-#define MCLK_SRC_SEL 0x70
-#define EXT_CLK_CNTL 0x80
-#define VCLK_SRC_SEL 0x03
-#define PLL_VCLK_RST 0x04
-#define VCLK_INVERT 0x08
-#define VCLK0_POST 0x03
-#define VCLK1_POST 0x0C
-#define VCLK2_POST 0x30
-#define VCLK3_POST 0xC0
-
/* CONFIG_CNTL register constants */
#define APERTURE_4M_ENABLE 1
#define APERTURE_8M_ENABLE 2
@@ -811,6 +936,7 @@
#define MEM_BNDRY_1M 0x00030000
#define MEM_BNDRY_EN 0x00040000
+#define ONE_MB 0x100000
/* ATI PCI constants */
#define PCI_ATI_VENDOR_ID 0x1002
@@ -849,7 +975,19 @@
#define LI_CHIP_ID 0x4c49 /* RAGE LT PRO */
#define LP_CHIP_ID 0x4c50 /* RAGE LT PRO */
#define LT_CHIP_ID 0x4c54 /* RAGE LT */
-#define XL_CHIP_ID 0x4752 /* RAGE (XL) */
+
+/* mach64CT family / (Rage XL) class */
+#define GR_CHIP_ID 0x4752 /* RAGE XL, BGA, PCI33 */
+#define GS_CHIP_ID 0x4753 /* RAGE XL, PQFP, PCI33 */
+#define GM_CHIP_ID 0x474d /* RAGE XL, BGA, AGP 1x,2x */
+#define GN_CHIP_ID 0x474e /* RAGE XL, PQFP,AGP 1x,2x */
+#define GO_CHIP_ID 0x474f /* RAGE XL, BGA, PCI66 */
+#define GL_CHIP_ID 0x474c /* RAGE XL, PQFP, PCI66 */
+
+#define IS_XL(id) ((id)==GR_CHIP_ID || (id)==GS_CHIP_ID || \
+ (id)==GM_CHIP_ID || (id)==GN_CHIP_ID || \
+ (id)==GO_CHIP_ID || (id)==GL_CHIP_ID)
+
#define GT_CHIP_ID 0x4754 /* RAGE (GT) */
#define GU_CHIP_ID 0x4755 /* RAGE II/II+ (GTB) */
#define GV_CHIP_ID 0x4756 /* RAGE IIC, PCI */
@@ -860,10 +998,14 @@
#define GI_CHIP_ID 0x4749 /* RAGE PRO, BGA, PCI33 only */
#define GP_CHIP_ID 0x4750 /* RAGE PRO, PQFP, PCI33, full 3D */
#define GQ_CHIP_ID 0x4751 /* RAGE PRO, PQFP, PCI33, limited 3D */
-#define LM_CHIP_ID 0x4c4d /* RAGE Mobility PCI */
-#define LN_CHIP_ID 0x4c4e /* RAGE Mobility AGP */
+#define LM_CHIP_ID 0x4c4d /* RAGE Mobility AGP, full function */
+#define LN_CHIP_ID 0x4c4e /* RAGE Mobility AGP */
+#define LR_CHIP_ID 0x4c52 /* RAGE Mobility PCI, full function */
+#define LS_CHIP_ID 0x4c53 /* RAGE Mobility PCI */
+#define IS_MOBILITY(id) ((id)==LM_CHIP_ID || (id)==LN_CHIP_ID || \
+ (id)==LR_CHIP_ID || (id)==LS_CHIP_ID)
/* Mach64 major ASIC revisions */
#define MACH64_ASIC_NEC_VT_A3 0x08
#define MACH64_ASIC_NEC_VT_A4 0x48
@@ -889,7 +1031,7 @@
#define MACH64_UNKNOWN 0
#define MACH64_GX 1
#define MACH64_CX 2
-#define MACH64_CT 3
+#define MACH64_CT 3Restore
#define MACH64_ET 4
#define MACH64_VT 5
#define MACH64_GT 6
@@ -934,26 +1076,34 @@
#define DP_CHAIN_32BPP 0x8080
/* DP_PIX_WIDTH register constants */
-#define DST_1BPP 0
-#define DST_4BPP 1
-#define DST_8BPP 2
-#define DST_15BPP 3
-#define DST_16BPP 4
-#define DST_32BPP 6
-#define SRC_1BPP 0
+#define DST_1BPP 0x0
+#define DST_4BPP 0x1
+#define DST_8BPP 0x2
+#define DST_15BPP 0x3
+#define DST_16BPP 0x4
+#define DST_24BPP 0x5
+#define DST_32BPP 0x6
+#define DST_MASK 0xF
+#define SRC_1BPP 0x000
#define SRC_4BPP 0x100
#define SRC_8BPP 0x200
#define SRC_15BPP 0x300
#define SRC_16BPP 0x400
+#define SRC_24BPP 0x500
#define SRC_32BPP 0x600
-#define HOST_1BPP 0
+#define SRC_MASK 0xF00
+#define DP_HOST_TRIPLE_EN 0x2000
+#define HOST_1BPP 0x00000
#define HOST_4BPP 0x10000
#define HOST_8BPP 0x20000
#define HOST_15BPP 0x30000
#define HOST_16BPP 0x40000
+#define HOST_24BPP 0x50000
#define HOST_32BPP 0x60000
+#define HOST_MASK 0xF0000
#define BYTE_ORDER_MSB_TO_LSB 0
#define BYTE_ORDER_LSB_TO_MSB 0x1000000
+#define BYTE_ORDER_MASK 0x1000000
/* DP_MIX register constants */
#define BKGD_MIX_NOT_D 0
@@ -1027,12 +1177,12 @@
#define CONTEXT_CMD_DISABLE 0x80000000
/* GUI_STAT register constants */
-#define ENGINE_IDLE 0
-#define ENGINE_BUSY 1
-#define SCISSOR_LEFT_FLAG 0x10
-#define SCISSOR_RIGHT_FLAG 0x20
-#define SCISSOR_TOP_FLAG 0x40
-#define SCISSOR_BOTTOM_FLAG 0x80
+#define ENGINE_IDLE 0
+#define ENGINE_BUSY 1
+#define SCISSOR_LEFT_FLAG 0x10
+#define SCISSOR_RIGHT_FLAG 0x20
+#define SCISSOR_TOP_FLAG 0x40
+#define SCISSOR_BOTTOM_FLAG 0x80
/* ATI VGA Extended Regsiters */
#define sioATIEXT 0x1ce
@@ -1043,6 +1193,7 @@
#define ATI36 0xb6
/* VGA Graphics Controller Registers */
+#define R_GENMO 0x3cc
#define VGAGRA 0x3ce
#define GRA06 0x06
@@ -1103,7 +1254,7 @@
/* LCD register indices */
#define CONFIG_PANEL 0x00
-#define LCD_GEN_CTRL 0x01
+#define LCD_GEN_CNTL 0x01
#define DSTN_CONTROL 0x02
#define HFB_PITCH_ADDR 0x03
#define HORZ_STRETCHING 0x04
@@ -1148,11 +1299,79 @@
#define APC_LUT_MN 0x39
#define APC_LUT_OP 0x3A
+/* Values in LCD_GEN_CTRL */
+#define CRT_ON 0x00000001ul
+#define LCD_ON 0x00000002ul
+#define HORZ_DIVBY2_EN 0x00000004ul
+#define DONT_DS_ICON 0x00000008ul
+#define LOCK_8DOT 0x00000010ul
+#define ICON_ENABLE 0x00000020ul
+#define DONT_SHADOW_VPAR 0x00000040ul
+#define V2CLK_PM_EN 0x00000080ul
+#define RST_FM 0x00000100ul
+#define DISABLE_PCLK_RESET 0x00000200ul /* XC/XL */
+#define DIS_HOR_CRT_DIVBY2 0x00000400ul
+#define SCLK_SEL 0x00000800ul
+#define SCLK_DELAY 0x0000f000ul
+#define TVCLK_PM_EN 0x00010000ul
+#define VCLK_DAC_PM_EN 0x00020000ul
+#define VCLK_LCD_OFF 0x00040000ul
+#define SELECT_WAIT_4MS 0x00080000ul
+#define XTALIN_PM_EN 0x00080000ul /* XC/XL */
+#define V2CLK_DAC_PM_EN 0x00100000ul
+#define LVDS_EN 0x00200000ul
+#define LVDS_PLL_EN 0x00400000ul
+#define LVDS_PLL_RESET 0x00800000ul
+#define LVDS_RESERVED_BITS 0x07000000ul
+#define CRTC_RW_SELECT 0x08000000ul /* LTPro */
+#define USE_SHADOWED_VEND 0x10000000ul
+#define USE_SHADOWED_ROWCUR 0x20000000ul
+#define SHADOW_EN 0x40000000ul
+#define SHADOW_RW_EN 0x80000000ul
+
+#define LCD_SET_PRIMARY_MASK 0x07FFFBFBul
+
+/* Values in HORZ_STRETCHING */
+#define HORZ_STRETCH_BLEND 0x00000ffful
+#define HORZ_STRETCH_RATIO 0x0000fffful
+#define HORZ_STRETCH_LOOP 0x00070000ul
+#define HORZ_STRETCH_LOOP09 0x00000000ul
+#define HORZ_STRETCH_LOOP11 0x00010000ul
+#define HORZ_STRETCH_LOOP12 0x00020000ul
+#define HORZ_STRETCH_LOOP14 0x00030000ul
+#define HORZ_STRETCH_LOOP15 0x00040000ul
+/* ? 0x00050000ul */
+/* ? 0x00060000ul */
+/* ? 0x00070000ul */
+/* ? 0x00080000ul */
+#define HORZ_PANEL_SIZE 0x0ff00000ul /* XC/XL */
+/* ? 0x10000000ul */
+#define AUTO_HORZ_RATIO 0x20000000ul /* XC/XL */
+#define HORZ_STRETCH_MODE 0x40000000ul
+#define HORZ_STRETCH_EN 0x80000000ul
+
+/* Values in VERT_STRETCHING */
+#define VERT_STRETCH_RATIO0 0x000003fful
+#define VERT_STRETCH_RATIO1 0x000ffc00ul
+#define VERT_STRETCH_RATIO2 0x3ff00000ul
+#define VERT_STRETCH_USE0 0x40000000ul
+#define VERT_STRETCH_EN 0x80000000ul
+
+/* Values in EXT_VERT_STRETCH */
+#define VERT_STRETCH_RATIO3 0x000003fful
+#define FORCE_DAC_DATA 0x000000fful
+#define FORCE_DAC_DATA_SEL 0x00000300ul
+#define VERT_STRETCH_MODE 0x00000400ul
+#define VERT_PANEL_SIZE 0x003ff800ul
+#define AUTO_VERT_RATIO 0x00400000ul
+#define USE_AUTO_FP_POS 0x00800000ul
+#define USE_AUTO_LCD_VSYNC 0x01000000ul
+/* ? 0xfe000000ul */
/* Values in LCD_MISC_CNTL */
-#define BIAS_MOD_LEVEL_MASK 0x0000ff00
-#define BIAS_MOD_LEVEL_SHIFT 8
-#define BLMOD_EN 0x00010000
-#define BIASMOD_EN 0x00020000
+#define BIAS_MOD_LEVEL_MASK 0x0000ff00
+#define BIAS_MOD_LEVEL_SHIFT 8
+#define BLMOD_EN 0x00010000
+#define BIASMOD_EN 0x00020000
-#endif /* REGMACH64_H */
+#endif /* REGMACH64_H */
-------------------------------------------------------
This SF.net email is sponsored by: IT Product Guide on ITManagersJournal
Use IT products in your business? Tell us what you think of them. Give us
Your Opinions, Get Free ThinkGeek Gift Certificates! Click to find out more
http://productguide.itmanagersjournal.com/guidepromo.tmpl
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH 3/5] fbdev: Various mach64 changes
2004-10-20 0:15 [PATCH 3/5] fbdev: Various mach64 changes Antonino A. Daplas
@ 2004-10-22 7:55 ` Andrew Morton
2004-10-22 7:57 ` Andrew Morton
0 siblings, 1 reply; 3+ messages in thread
From: Andrew Morton @ 2004-10-22 7:55 UTC (permalink / raw)
To: adaplas
Cc: adaplas, linux-fbdev-devel, alex.kern, arnaud.fontaine, geert,
jsimmons, nsouch, syrjala
"Antonino A. Daplas" <adaplas@hotpop.com> wrote:
>
> Alexander Kern <alex.kern@gmx.de>
> [PATCH] port Daniel Mantione 2.4 driver to 2.6
> [PATCH] add more pci_id number
> [PATCH] add accelerated imgblit
> [PATCH] revert SDRAM_MAGIC_PLL to old behaviour
> [PATCH] do a "from BIOS" initialisation only by __i386__
>
> Arnaud FONTAINE <arnaud.fontaine@free.fr>
> [PATCH atyfb] correction for 3D Rage Mobility L
>
> Geert Uytterhoeven <geert@linux-m68k.org>
> [PATCH atyfb] Atari Atyfb fixes
> [PATCH atyfb] Atyfb on Mach64 GX or Atari
> [PATCH 468] m68k sparse floating point
>
> James Simmons <jsimmons@infradead.org>
> [PATCH add] port to framebuffer_alloc api
>
> Nicolas Souchu <nsouch@free.fr>
> [PATCH] I do not found a copy, but it was incorporated too
>
> Ville Syrjälä <syrjala@sci.fi>
> [PATCH] fix pan with doublescan
> [PATCH] another double scan fix
> [PATCH] disable linear aperture register access
> [PATCH] Memory type correction
> [PATCH] atyfb (2.6): Fix mmio_start
> [PATCH] atyfb (2.6): Fix mem_refresh_rate for Mobility
> [PATCH] atyfb (2.6): Add RGB565 support
> [PATCH] atyfb: Blank LCD by turning off backlight voltage
> [PATCH] atyfb: Rage LT LCD register access
> [PATCH] atyfb: vblank irq support
> [PATCH] atyfb: MTRR support
This patch is fairly screwed on sparc64. I fixed a few things, below, but
it's still treating ->ati_regbase as a scalar and not a pointer, so I'll
toss that one back to your guys.
An incremental patch against 2.6.9-mm1 would be appreciated. Hopefully
I'll get that out the door tonight.
drivers/video/aty/atyfb_base.c: In function `atyfb_setup_sparc':
drivers/video/aty/atyfb_base.c:2769: warning: assignment makes pointer from integer without a cast
drivers/video/aty/atyfb_base.c: In function `atyfb_pci_probe':
drivers/video/aty/atyfb_base.c:3399: error: invalid operands to binary &
Signed-off-by: Andrew Morton <akpm@osdl.org>
---
25-sparc64-akpm/drivers/video/aty/atyfb_base.c | 8 +++++---
1 files changed, 5 insertions(+), 3 deletions(-)
diff -puN drivers/video/aty/atyfb_base.c~fbdev-various-mach64-changes-sparc64-fix drivers/video/aty/atyfb_base.c
--- 25-sparc64/drivers/video/aty/atyfb_base.c~fbdev-various-mach64-changes-sparc64-fix 2004-10-22 00:47:03.000000000 -0700
+++ 25-sparc64-akpm/drivers/video/aty/atyfb_base.c 2004-10-22 00:50:03.000000000 -0700
@@ -2746,9 +2746,11 @@ static int atyfb_setcolreg(u_int regno,
#ifdef __sparc__
-static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, struct fb_indo *info, unsigned long addr)
+extern void (*prom_palette) (int);
+
+static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
+ struct fb_info *info, unsigned long addr)
{
- extern void (*prom_palette) (int);
extern int con_is_present(void);
struct atyfb_par *par = info->par;
@@ -2782,7 +2784,7 @@ static int __devinit atyfb_setup_sparc(s
j = i + 4;
par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC);
- if (!_par->mmap_map) {
+ if (!par->mmap_map) {
PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");
return -ENOMEM;
}
_
-------------------------------------------------------
This SF.net email is sponsored by: IT Product Guide on ITManagersJournal
Use IT products in your business? Tell us what you think of them. Give us
Your Opinions, Get Free ThinkGeek Gift Certificates! Click to find out more
http://productguide.itmanagersjournal.com/guidepromo.tmpl
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH 3/5] fbdev: Various mach64 changes
2004-10-22 7:55 ` Andrew Morton
@ 2004-10-22 7:57 ` Andrew Morton
0 siblings, 0 replies; 3+ messages in thread
From: Andrew Morton @ 2004-10-22 7:57 UTC (permalink / raw)
To: adaplas, adaplas, linux-fbdev-devel, alex.kern, arnaud.fontaine,
geert, jsimmons, nsouch, syrjala
Actually, I'll use the below patch just to make it compile.
Signed-off-by: Andrew Morton <akpm@osdl.org>
---
25-sparc64-akpm/drivers/video/aty/atyfb_base.c | 12 +++++++-----
1 files changed, 7 insertions(+), 5 deletions(-)
diff -puN drivers/video/aty/atyfb_base.c~fbdev-various-mach64-changes-sparc64-fix drivers/video/aty/atyfb_base.c
--- 25-sparc64/drivers/video/aty/atyfb_base.c~fbdev-various-mach64-changes-sparc64-fix 2004-10-22 00:47:03.000000000 -0700
+++ 25-sparc64-akpm/drivers/video/aty/atyfb_base.c 2004-10-22 00:56:18.377055112 -0700
@@ -2746,9 +2746,11 @@ static int atyfb_setcolreg(u_int regno,
#ifdef __sparc__
-static int __devinit atyfb_setup_sparc(struct pci_dev *pdev, struct fb_indo *info, unsigned long addr)
+extern void (*prom_palette) (int);
+
+static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
+ struct fb_info *info, unsigned long addr)
{
- extern void (*prom_palette) (int);
extern int con_is_present(void);
struct atyfb_par *par = info->par;
@@ -2764,7 +2766,7 @@ static int __devinit atyfb_setup_sparc(s
/*
* Map memory-mapped registers.
*/
- par->ati_regbase = addr + 0x7ffc00UL;
+ par->ati_regbase = (void *)addr + 0x7ffc00UL;
info->fix.mmio_start = addr + 0x7ffc00UL;
/*
@@ -2782,7 +2784,7 @@ static int __devinit atyfb_setup_sparc(s
j = i + 4;
par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC);
- if (!_par->mmap_map) {
+ if (!par->mmap_map) {
PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");
return -ENOMEM;
}
@@ -3394,7 +3396,7 @@ static int __devinit atyfb_pci_probe(str
par->mmap_map[0].prot_mask = _PAGE_CACHE;
par->mmap_map[0].prot_flag = _PAGE_E;
par->mmap_map[1].voff = par->mmap_map[0].voff + info->fix.smem_len;
- par->mmap_map[1].poff = par->ati_regbase & PAGE_MASK;
+ par->mmap_map[1].poff = (long)par->ati_regbase & PAGE_MASK;
par->mmap_map[1].size = PAGE_SIZE;
par->mmap_map[1].prot_mask = _PAGE_CACHE;
par->mmap_map[1].prot_flag = _PAGE_E;
_
-------------------------------------------------------
This SF.net email is sponsored by: IT Product Guide on ITManagersJournal
Use IT products in your business? Tell us what you think of them. Give us
Your Opinions, Get Free ThinkGeek Gift Certificates! Click to find out more
http://productguide.itmanagersjournal.com/guidepromo.tmpl
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2004-10-22 7:59 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-10-20 0:15 [PATCH 3/5] fbdev: Various mach64 changes Antonino A. Daplas
2004-10-22 7:55 ` Andrew Morton
2004-10-22 7:57 ` Andrew Morton
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).