summaryrefslogtreecommitdiffstats
path: root/drivers/video/atyfb.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-08-25 09:12:35 +0000
commitc7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch)
tree3682407a599b8f9f03fc096298134cafba1c9b2f /drivers/video/atyfb.c
parent1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff)
o Merge with Linux 2.1.116.
o New Newport console code. o New G364 console code.
Diffstat (limited to 'drivers/video/atyfb.c')
-rw-r--r--drivers/video/atyfb.c3749
1 files changed, 2706 insertions, 1043 deletions
diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c
index e1f8b3ef4..7d271bc29 100644
--- a/drivers/video/atyfb.c
+++ b/drivers/video/atyfb.c
@@ -1,7 +1,9 @@
/*
- * linux/drivers/video/atyfb.c -- Frame buffer device for ATI/Open Firmware
+ * linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
*
- * Copyright (C) 1997 Geert Uytterhoeven
+ * Copyright (C) 1997-1998 Geert Uytterhoeven
+ * Copyright (C) 1998 Bernd Harries
+ * Copyright (C) 1998 Eddie C. Dost
*
* This driver is partly based on the PowerMac console driver:
*
@@ -20,6 +22,23 @@
* more details.
*/
+/******************************************************************************
+
+ TODO:
+
+ (ecd):
+
+ - fix initialization of cursor timer.
+
+ - add code to support cursor on all cards and all ramdacs.
+
+ - make cursor parameters controllable via ioctl()s.
+
+ (Anyone to help with all this?)
+
+******************************************************************************/
+
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -33,314 +52,245 @@
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/selection.h>
+#include <linux/console.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/nvram.h>
-#include <linux/vc_ioctl.h>
+#include <linux/kd.h>
+#include <linux/vt_kern.h>
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <asm/vc_ioctl.h>
+#endif
+
#include <asm/io.h>
+
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
#include <asm/prom.h>
#include <asm/pci-bridge.h>
+#include "macmodes.h"
+#endif
+#ifdef __sparc__
+#include <asm/pbm.h>
+#endif
#include "aty.h"
#include "fbcon.h"
#include "fbcon-cfb8.h"
#include "fbcon-cfb16.h"
+#include "fbcon-cfb24.h"
#include "fbcon-cfb32.h"
-static int currcon = 0;
-static struct display fb_disp;
-static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[256];
-
-static char atyfb_name[16] = "ATY Mach64";
-
-struct atyfb_par {
- int vmode;
- int cmode;
- u_int vxres; /* virtual screen size */
- u_int vyres;
- int xoffset; /* virtual screen position */
- int yoffset;
-};
-
-
-/*
- * Video mode values.
- * These are supposed to be the same as the values that
- * Apple uses in MacOS.
- */
-#define VMODE_NVRAM 0 /* use value stored in nvram */
-#define VMODE_512_384_60I 1 /* 512x384, 60Hz interlaced (NTSC) */
-#define VMODE_512_384_60 2 /* 512x384, 60Hz */
-#define VMODE_640_480_50I 3 /* 640x480, 50Hz interlaced (PAL) */
-#define VMODE_640_480_60I 4 /* 640x480, 60Hz interlaced (NTSC) */
-#define VMODE_640_480_60 5 /* 640x480, 60Hz (VGA) */
-#define VMODE_640_480_67 6 /* 640x480, 67Hz */
-#define VMODE_640_870_75P 7 /* 640x870, 75Hz (portrait) */
-#define VMODE_768_576_50I 8 /* 768x576, 50Hz (PAL full frame) */
-#define VMODE_800_600_56 9 /* 800x600, 56Hz */
-#define VMODE_800_600_60 10 /* 800x600, 60Hz */
-#define VMODE_800_600_72 11 /* 800x600, 72Hz */
-#define VMODE_800_600_75 12 /* 800x600, 75Hz */
-#define VMODE_832_624_75 13 /* 832x624, 75Hz */
-#define VMODE_1024_768_60 14 /* 1024x768, 60Hz */
-#define VMODE_1024_768_70 15 /* 1024x768, 70Hz (or 72Hz?) */
-#define VMODE_1024_768_75V 16 /* 1024x768, 75Hz (VESA) */
-#define VMODE_1024_768_75 17 /* 1024x768, 75Hz */
-#define VMODE_1152_870_75 18 /* 1152x870, 75Hz */
-#define VMODE_1280_960_75 19 /* 1280x960, 75Hz */
-#define VMODE_1280_1024_75 20 /* 1280x1024, 75Hz */
-#define VMODE_MAX 20
-#define VMODE_CHOOSE 99 /* choose based on monitor sense */
-
-/*
- * Color mode values, used to select number of bits/pixel.
- */
-#define CMODE_NVRAM -1 /* use value stored in nvram */
-#define CMODE_8 0 /* 8 bits/pixel */
-#define CMODE_16 1 /* 16 (actually 15) bits/pixel */
-#define CMODE_32 2 /* 32 (actually 24) bits/pixel */
-
+#define GUI_RESERVE 0x00001000
-static int default_video_mode = VMODE_NVRAM;
-static int default_color_mode = CMODE_NVRAM;
+#define CLASS_GX 1
+#define CLASS_CT 2
+#define CLASS_VT 3
+#define CLASS_GT 4
-static struct atyfb_par default_par;
-static struct atyfb_par current_par;
+#ifndef __powerpc__
+#define eieio() /* Enforce In-order Execution of I/O */
+#endif
-/*
- * Addresses in NVRAM where video mode and pixel size are stored.
- */
-#define NV_VMODE 0x140f
-#define NV_CMODE 0x1410
+/* FIXME: remove the FAIL definition */
+#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
-/*
- * Horizontal and vertical resolution information.
- */
-extern struct vmode_attr {
- int hres;
- int vres;
- int vfreq;
- int interlaced;
-} vmode_attrs[VMODE_MAX];
+ /*
+ * Elements of the Hardware specific atyfb_par structure
+ */
-/*
- * Horizontal and vertical resolution for each mode.
- */
-static struct vmode_attr vmode_attrs[VMODE_MAX] = {
- {512, 384, 60, 1},
- {512, 384, 60},
- {640, 480, 50, 1},
- {640, 480, 60, 1},
- {640, 480, 60},
- {640, 480, 67},
- {640, 870, 75},
- {768, 576, 50, 1},
- {800, 600, 56},
- {800, 600, 60},
- {800, 600, 72},
- {800, 600, 75},
- {832, 624, 75},
- {1024, 768, 60},
- {1024, 768, 72},
- {1024, 768, 75},
- {1024, 768, 75},
- {1152, 870, 75},
- {1280, 960, 75},
- {1280, 1024, 75}
+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 off_pitch;
+ u32 gen_cntl;
+ u32 dp_pix_width; /* acceleration */
+ u32 dp_chain_mask; /* acceleration */
};
-
-/*
- * We get a sense value from the monitor and use it to choose
- * what resolution to use. This structure maps sense values
- * to display mode values (which determine the resolution and
- * frequencies).
- */
-static struct mon_map {
- int sense;
- int vmode;
-} monitor_map [] = {
- {0x000, VMODE_1280_1024_75}, /* 21" RGB */
- {0x114, VMODE_640_870_75P}, /* Portrait Monochrome */
- {0x221, VMODE_512_384_60}, /* 12" RGB*/
- {0x331, VMODE_1280_1024_75}, /* 21" RGB (Radius) */
- {0x334, VMODE_1280_1024_75}, /* 21" mono (Radius) */
- {0x335, VMODE_1280_1024_75}, /* 21" mono */
- {0x40A, VMODE_640_480_60I}, /* NTSC */
- {0x51E, VMODE_640_870_75P}, /* Portrait RGB */
- {0x603, VMODE_832_624_75}, /* 12"-16" multiscan */
- {0x60b, VMODE_1024_768_70}, /* 13"-19" multiscan */
- {0x623, VMODE_1152_870_75}, /* 13"-21" multiscan */
- {0x62b, VMODE_640_480_67}, /* 13"/14" RGB */
- {0x700, VMODE_640_480_50I}, /* PAL */
- {0x714, VMODE_640_480_60I}, /* NTSC */
- {0x717, VMODE_800_600_75}, /* VGA */
- {0x72d, VMODE_832_624_75}, /* 16" RGB (Goldfish) */
- {0x730, VMODE_768_576_50I}, /* PAL (Alternate) */
- {0x73a, VMODE_1152_870_75}, /* 3rd party 19" */
- {-1, VMODE_640_480_60}, /* catch-all, must be last */
+struct pll_gx {
+ u8 m;
+ u8 n;
};
-static int map_monitor_sense(int sense)
-{
- struct mon_map *map;
-
- for (map = monitor_map; map->sense >= 0; ++map)
- if (map->sense == sense)
- break;
- return map->vmode;
-}
-
-struct aty_cmap_regs {
- unsigned char windex;
- unsigned char lut;
- unsigned char mask;
- unsigned char rindex;
- unsigned char cntl;
+struct pll_ct {
+ u8 pll_ref_div;
+ u8 pll_gen_cntl;
+ u8 mclk_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 */
};
-typedef struct aty_regvals {
- int offset[3]; /* first pixel address */
- int crtc_h_sync_strt_wid[3]; /* depth dependant */
- int crtc_gen_cntl[3];
- int mem_cntl[3];
-
- int crtc_h_tot_disp; /* mode dependant */
- int crtc_v_tot_disp;
- int crtc_v_sync_strt_wid;
- int crtc_off_pitch;
+ /*
+ * The Hardware parameters for each card
+ */
- unsigned char clock_val[2]; /* vals for 20 and 21 */
-} aty_regvals;
+struct atyfb_par {
+ struct crtc crtc;
+ union {
+ struct pll_gx gx;
+ struct pll_ct ct;
+ } pll;
+ u32 accel_flags;
+};
-struct rage_regvals {
- int h_total, h_sync_start, h_sync_width;
- int v_total, v_sync_start, v_sync_width;
- int h_sync_neg, v_sync_neg;
+struct aty_cmap_regs {
+ u8 windex;
+ u8 lut;
+ u8 mask;
+ u8 rindex;
+ u8 cntl;
};
-static int aty_vram_reqd(const struct atyfb_par *par);
-static struct aty_regvals *get_aty_struct(int vmode);
-
-static unsigned long frame_buffer;
-
-static int total_vram; /* total amount of video memory, bytes */
-static int chip_type; /* what chip type was detected */
-
-static unsigned long ati_regbase;
-static struct aty_cmap_regs *aty_cmap_regs;
-
-#include "ati-gx.h"
-#include "ati-gt.h"
-#include "ati-vt.h"
-
-static struct aty_regvals *aty_gt_reg_init[20] = {
- NULL, NULL, NULL, NULL,
- &aty_gt_reg_init_5,
- &aty_gt_reg_init_6,
- NULL, NULL,
- &aty_gt_reg_init_9,
- &aty_gt_reg_init_10,
- &aty_gt_reg_init_11,
- &aty_gt_reg_init_12,
- &aty_gt_reg_init_13,
- &aty_gt_reg_init_14,
- &aty_gt_reg_init_15,
- NULL,
- &aty_gt_reg_init_17,
- &aty_gt_reg_init_18,
- NULL,
- &aty_gt_reg_init_20
+struct pci_mmap_map {
+ unsigned long voff;
+ unsigned long poff;
+ unsigned long size;
+ unsigned long prot_flag;
+ unsigned long prot_mask;
};
-static struct aty_regvals *aty_gx_reg_init[20] = {
- NULL, NULL, NULL, NULL,
- &aty_gx_reg_init_6,
- &aty_gx_reg_init_6,
- NULL, NULL, NULL, NULL, NULL, NULL,
- &aty_gx_reg_init_13,
- &aty_gx_reg_init_14,
- &aty_gx_reg_init_15,
- NULL,
- &aty_gx_reg_init_17,
- &aty_gx_reg_init_18,
- NULL,
- &aty_gx_reg_init_20
+#define DEFAULT_CURSOR_BLINK_RATE (20)
+
+struct aty_cursor {
+ int enable;
+ int on;
+ int vbl_cnt;
+ int blink_rate;
+ u32 offset;
+ struct {
+ u16 x, y;
+ } pos, hot, size;
+ u32 color[2];
+ u8 bits[8][64];
+ u8 mask[8][64];
+ struct timer_list *timer;
};
-static struct aty_regvals *aty_vt_reg_init[21] = {
- NULL, NULL, NULL, NULL,
- &aty_vt_reg_init_5,
- &aty_vt_reg_init_6,
- NULL, NULL, NULL,
- &aty_vt_reg_init_10,
- &aty_vt_reg_init_11,
- &aty_vt_reg_init_12,
- &aty_vt_reg_init_13,
- &aty_vt_reg_init_14,
- &aty_vt_reg_init_15,
- NULL,
- &aty_vt_reg_init_17,
- &aty_vt_reg_init_18,
- &aty_vt_reg_init_19,
- &aty_vt_reg_init_20
+struct fb_info_aty {
+ struct fb_info fb_info;
+ unsigned long ati_regbase_phys;
+ unsigned long ati_regbase;
+ unsigned long frame_buffer_phys;
+ unsigned long frame_buffer;
+ struct display disp;
+ struct display_switch dispsw;
+ struct pci_mmap_map *mmap_map;
+ struct aty_cursor *cursor;
+ struct aty_cmap_regs *aty_cmap_regs;
+ struct { u8 red, green, blue, pad; } palette[256];
+ struct atyfb_par default_par;
+ struct atyfb_par current_par;
+ u32 total_vram;
+ u32 pll_per;
+ u32 mclk_per;
+ u16 chip_type;
+#define Gx info->chip_type
+ u8 chip_rev;
+#define Rev info->chip_rev
+ u8 bus_type;
+ u8 ram_type;
+ u8 dac_type;
+ u8 clk_type;
+ u8 mem_refresh_rate;
+#ifdef __sparc__
+ u8 open;
+ u8 mmaped;
+ int vtconsole;
+ int consolecnt;
+#endif
};
+
/*
- * Interface used by the world
+ * Frame buffer device API
*/
-unsigned long atyfb_init(unsigned long mem_start);
-void atyfb_setup(char *options, int *ints);
-
-static int atyfb_open(struct fb_info *info);
-static int atyfb_release(struct fb_info *info);
+static int atyfb_open(struct fb_info *info, int user);
+static int atyfb_release(struct fb_info *info, int user);
static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info);
+ struct fb_info *fb);
static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
+ struct fb_info *fb);
static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
+ struct fb_info *fb);
static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info);
+ struct fb_info *fb);
static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg, int con, struct fb_info *info);
+#ifdef __sparc__
+static int atyfb_mmap(struct fb_info *info, struct file *file,
+ struct vm_area_struct *vma);
+#endif
/*
* Interface to the low level console driver
*/
-static int atyfbcon_switch(int con, struct fb_info *info);
-static int atyfbcon_updatevar(int con, struct fb_info *info);
-static void atyfbcon_blank(int blank, struct fb_info *info);
+static int atyfbcon_switch(int con, struct fb_info *fb);
+static int atyfbcon_updatevar(int con, struct fb_info *fb);
+static void atyfbcon_blank(int blank, struct fb_info *fb);
/*
* Text console acceleration
*/
-#ifdef CONFIG_FBCON_CFB8
+static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width);
+static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width);
+#ifdef FBCON_HAS_CFB8
static struct display_switch fbcon_aty8;
+static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx);
#endif
-
-
-#ifdef CONFIG_FB_COMPAT_XPMAC
-extern struct vc_mode display_info;
-extern struct fb_info *console_fb_info;
-extern int (*console_setmode_ptr)(struct vc_mode *, int);
-extern int (*console_set_cmap_ptr)(struct fb_cmap *, int, int,
- struct fb_info *);
-static int atyfb_console_setmode(struct vc_mode *, int);
+#ifdef FBCON_HAS_CFB16
+static struct display_switch fbcon_aty16;
+static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx);
+#endif
+#ifdef FBCON_HAS_CFB24
+static struct display_switch fbcon_aty24;
+static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx);
+#endif
+#ifdef FBCON_HAS_CFB32
+static struct display_switch fbcon_aty32;
+static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx);
+static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx);
#endif
@@ -348,521 +298,1446 @@ static int atyfb_console_setmode(struct vc_mode *, int);
* Internal routines
*/
+static int aty_init(struct fb_info_aty *info, const char *name);
+#ifdef CONFIG_ATARI
+static int store_video_par(char *videopar, unsigned char m64_num);
+static char *strtoke(char *s, const char *ct);
+#endif
+
+static void reset_engine(const struct fb_info_aty *info);
+static void init_engine(const struct atyfb_par *par,
+ const struct fb_info_aty *info);
+static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info);
+static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info);
+static void aty_set_crtc(const struct fb_info_aty *info,
+ const struct crtc *crtc);
+static int aty_var_to_crtc(const struct fb_info_aty *info,
+ const struct fb_var_screeninfo *var,
+ struct crtc *crtc);
+static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp);
+static int aty_crtc_to_var(const struct crtc *crtc,
+ struct fb_var_screeninfo *var);
+static void aty_set_pll_gx(const struct fb_info_aty *info,
+ const struct pll_gx *pll);
+static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var,
+ struct pll_gx *pll);
+static int aty_var_to_pll_514(const struct fb_var_screeninfo *var,
+ struct pll_gx *pll);
+static int aty_pll_gx_to_var(const struct pll_gx *pll,
+ struct fb_var_screeninfo *var);
+static void aty_set_pll_ct(const struct fb_info_aty *info,
+ const struct pll_ct *pll);
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
+ u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
+ u8 bpp, struct pll_ct *pll);
+static int aty_var_to_pll_ct(const struct fb_info_aty *info,
+ const struct fb_var_screeninfo *var,
+ struct pll_ct *pll);
+static int aty_pll_ct_to_var(const struct pll_ct *pll,
+ struct fb_var_screeninfo *var);
+static void atyfb_set_par(const struct atyfb_par *par,
+ struct fb_info_aty *info);
+static int atyfb_decode_var(const struct fb_var_screeninfo *var,
+ struct atyfb_par *par,
+ const struct fb_info_aty *info);
+static int atyfb_encode_var(struct fb_var_screeninfo *var,
+ const struct atyfb_par *par,
+ const struct fb_info_aty *info);
+static void set_off_pitch(struct atyfb_par *par,
+ const struct fb_info_aty *info);
+static int encode_fix(struct fb_fix_screeninfo *fix,
+ const struct atyfb_par *par,
+ const struct fb_info_aty *info);
static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info);
+ u_int *transp, struct fb_info *fb);
static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info);
+ u_int transp, struct fb_info *fb);
static void do_install_cmap(int con, struct fb_info *info);
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+static int read_aty_sense(const struct fb_info_aty *info);
+#endif
+ /*
+ * Interface used by the world
+ */
+
+void atyfb_init(void);
+#ifdef CONFIG_FB_OF
+void atyfb_of_init(struct device_node *dp);
+#endif
+void atyfb_setup(char *options, int *ints);
+
+
+static int currcon = 0;
+
static struct fb_ops atyfb_ops = {
atyfb_open, atyfb_release, atyfb_get_fix, atyfb_get_var, atyfb_set_var,
- atyfb_get_cmap, atyfb_set_cmap, atyfb_pan_display, NULL, atyfb_ioctl
+ atyfb_get_cmap, atyfb_set_cmap, atyfb_pan_display, atyfb_ioctl,
+#ifdef __sparc__
+ atyfb_mmap
+#else
+ NULL
+#endif
};
+static char atyfb_name[16] = "ATY Mach64";
+static char fontname[40] __initdata = { 0 };
+
+static const u32 ref_clk_per = 1000000000000ULL/14318180;
+
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+static int default_vmode = VMODE_NVRAM;
+static int default_cmode = CMODE_NVRAM;
+#endif
+
+#ifdef CONFIG_ATARI
+static unsigned int mach64_count __initdata = 0;
+static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
+static unsigned long phys_size[FB_MAX] __initdata = { 0, };
+static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
+#endif
+
+
+static struct aty_features {
+ u16 pci_id;
+ u16 chip_type;
+ const char *name;
+} aty_features[] __initdata = {
+ /* mach64GX family */
+ { 0x4758, 0x00d7, "mach64GX (ATI888GX00)" },
+ { 0x4358, 0x0057, "mach64CX (ATI888CX00)" },
+
+ /* mach64CT family */
+ { 0x4354, 0x4354, "mach64CT (ATI264CT)" },
+ { 0x4554, 0x4554, "mach64ET (ATI264ET)" },
+
+ /* mach64CT family / mach64VT class */
+ { 0x5654, 0x5654, "mach64VT (ATI264VT)" },
+ { 0x5655, 0x5655, "mach64VTB (ATI264VTB)" },
+/* { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" }, */
+
+ /* mach64CT family / mach64GT (3D RAGE) class */
+ { 0x4c54, 0x4c54, "3D RAGE LT" },
+ { 0x4c47, 0x4c47, "3D RAGE LG" },
+ { 0x4754, 0x4754, "3D RAGE (GT)" },
+ { 0x4755, 0x4755, "3D RAGE II+ (GTB)" },
+/* { 0x4756, 0x4756, "3D RAGE IIC" }, */
+ { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)" },
+ { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)" },
+ { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" },
+ { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)" },
+ { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" },
+};
+
+
+static inline u32 aty_ld_le32(volatile unsigned int regindex,
+ const struct fb_info_aty *info)
+{
+ unsigned long temp;
+ u32 val;
+
+#if defined(__powerpc__)
+ temp = info->ati_regbase;
+ asm("lwbrx %0,%1,%2" : "=r"(val) : "r" (regindex), "r" (temp));
+#elif defined(__sparc_v9__)
+ temp = info->ati_regbase + regindex;
+ asm("lduwa [%1] %2, %0" : "=r" (val) : "r" (temp), "i" (ASI_PL));
+#else
+ temp = info->ati_regbase+regindex;
+ val = le32_to_cpu(*((volatile u32 *)(temp)));
+#endif
+ return val;
+}
-static inline int aty_vram_reqd(const struct atyfb_par *par)
+static inline void aty_st_le32(volatile unsigned int regindex, u32 val,
+ const struct fb_info_aty *info)
{
- return (par->vxres*par->vyres) << par->cmode;
+ unsigned long temp;
+
+#if defined(__powerpc__)
+ temp = info->ati_regbase;
+ asm("stwbrx %0,%1,%2" : : "r" (val), "r" (regindex), "r" (temp) :
+ "memory");
+#elif defined(__sparc_v9__)
+ temp = info->ati_regbase + regindex;
+ asm("stwa %0, [%1] %2" : : "r" (val), "r" (temp), "i" (ASI_PL) : "memory");
+#else
+ temp = info->ati_regbase+regindex;
+ *((volatile u32 *)(temp)) = cpu_to_le32(val);
+#endif
}
-extern inline unsigned aty_ld_le32(volatile unsigned long addr)
+static inline u8 aty_ld_8(volatile unsigned int regindex,
+ const struct fb_info_aty *info)
{
- register unsigned long temp = ati_regbase,val;
+ return *(volatile u8 *)(info->ati_regbase+regindex);
+}
- asm("lwbrx %0,%1,%2": "=r"(val):"r"(addr), "r"(temp));
- return val;
+static inline void aty_st_8(volatile unsigned int regindex, u8 val,
+ const struct fb_info_aty *info)
+{
+ *(volatile u8 *)(info->ati_regbase+regindex) = val;
}
-extern inline void aty_st_le32(volatile unsigned long addr, unsigned val)
+
+ /*
+ * Generic Mach64 routines
+ */
+
+ /*
+ * All writes to draw engine registers are automatically routed through a
+ * 32-bit-wide, 16-entry-deep command FIFO ...
+ * Register writes to registers with DWORD offsets less than 40h are not
+ * FIFOed.
+ * (from Chapter 5 of the Mach64 Programmer's Guide)
+ */
+
+static inline void wait_for_fifo(u16 entries, const struct fb_info_aty *info)
{
- register unsigned long temp = ati_regbase;
+ while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) >
+ ((u32)(0x8000 >> entries)));
+}
- asm("stwbrx %0,%1,%2": : "r"(val), "r"(addr), "r"(temp):"memory");
+static inline void wait_for_idle(const struct fb_info_aty *info)
+{
+ wait_for_fifo(16, info);
+ while ((aty_ld_le32(GUI_STAT, info) & 1)!= 0);
}
-extern inline unsigned char aty_ld_8(volatile unsigned long addr)
+static void reset_engine(const struct fb_info_aty *info)
{
- return *(char *) ((long) addr + (long) ati_regbase);
+ /* reset engine */
+ aty_st_le32(GEN_TEST_CNTL,
+ aty_ld_le32(GEN_TEST_CNTL, info) & ~GUI_ENGINE_ENABLE, info);
+ /* enable engine */
+ aty_st_le32(GEN_TEST_CNTL,
+ aty_ld_le32(GEN_TEST_CNTL, info) | GUI_ENGINE_ENABLE, info);
+ /* ensure engine is not locked up by clearing any FIFO or */
+ /* HOST errors */
+ aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, info) | BUS_HOST_ERR_ACK |
+ BUS_FIFO_ERR_ACK, info);
}
-extern inline void aty_st_8(volatile unsigned long addr, unsigned char val)
+static void init_engine(const struct atyfb_par *par,
+ const struct fb_info_aty *info)
{
- *(unsigned char *) (addr + (unsigned long) ati_regbase) = val;
+ u32 pitch_value;
+
+ /* determine modal information from global mode structure */
+ pitch_value = par->crtc.vxres;
+
+ if (par->crtc.bpp == 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;
+ }
+
+ /* Reset engine, enable, and clear any engine errors */
+ reset_engine(info);
+ /* Ensure that vga page pointers are set to zero - the upper */
+ /* page pointers are set to 1 to handle overflows in the */
+ /* lower page */
+ aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, info);
+ aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, info);
+
+ /* ---- Setup standard engine context ---- */
+
+ /* All GUI registers here are FIFOed - therefore, wait for */
+ /* the appropriate number of empty FIFO entries */
+ wait_for_fifo(14, info);
+
+ /* enable all registers to be loaded for context loads */
+ aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, info);
+
+ /* set destination pitch to modal pitch, set offset to zero */
+ aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, info);
+
+ /* zero these registers (set them to a known state) */
+ aty_st_le32(DST_Y_X, 0, info);
+ aty_st_le32(DST_HEIGHT, 0, info);
+ aty_st_le32(DST_BRES_ERR, 0, info);
+ aty_st_le32(DST_BRES_INC, 0, info);
+ aty_st_le32(DST_BRES_DEC, 0, info);
+
+ /* set destination drawing attributes */
+ aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
+ DST_X_LEFT_TO_RIGHT, info);
+
+ /* set source pitch to modal pitch, set offset to zero */
+ aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, info);
+
+ /* set these registers to a known state */
+ aty_st_le32(SRC_Y_X, 0, info);
+ aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, info);
+ aty_st_le32(SRC_Y_X_START, 0, info);
+ aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, info);
+
+ /* set source pixel retrieving attributes */
+ aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, info);
+
+ /* set host attributes */
+ wait_for_fifo(13, info);
+ aty_st_le32(HOST_CNTL, 0, info);
+
+ /* set pattern attributes */
+ aty_st_le32(PAT_REG0, 0, info);
+ aty_st_le32(PAT_REG1, 0, info);
+ aty_st_le32(PAT_CNTL, 0, info);
+
+ /* set scissors to modal size */
+ aty_st_le32(SC_LEFT, 0, info);
+ aty_st_le32(SC_TOP, 0, info);
+ aty_st_le32(SC_BOTTOM, par->crtc.vyres-1, info);
+ aty_st_le32(SC_RIGHT, pitch_value-1, info);
+
+ /* set background color to minimum value (usually BLACK) */
+ aty_st_le32(DP_BKGD_CLR, 0, info);
+
+ /* set foreground color to maximum value (usually WHITE) */
+ aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, info);
+
+ /* set write mask to effect all pixel bits */
+ aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, info);
+
+ /* set foreground mix to overpaint and background mix to */
+ /* no-effect */
+ aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, info);
+
+ /* set primary source pixel channel to foreground color */
+ /* register */
+ aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, info);
+
+ /* set compare functionality to false (no-effect on */
+ /* destination) */
+ wait_for_fifo(3, info);
+ aty_st_le32(CLR_CMP_CLR, 0, info);
+ aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, info);
+ aty_st_le32(CLR_CMP_CNTL, 0, info);
+
+ /* set pixel depth */
+ wait_for_fifo(2, info);
+ aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, info);
+ aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, info);
+
+ /* insure engine is idle before leaving */
+ wait_for_idle(info);
}
-static void aty_st_514(int offset, char val)
+static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info)
{
- aty_WaitQueue(5);
- aty_st_8(DAC_CNTL, 1);
- aty_st_8(DAC_W_INDEX, offset & 0xff); /* right addr byte */
- aty_st_8(DAC_DATA, (offset >> 8) & 0xff); /* left addr byte */
+ aty_st_8(DAC_CNTL, 1, info);
+ /* right addr byte */
+ aty_st_8(DAC_W_INDEX, offset & 0xff, info);
+ /* left addr byte */
+ aty_st_8(DAC_DATA, (offset >> 8) & 0xff, info);
eieio();
- aty_st_8(DAC_MASK, val);
+ aty_st_8(DAC_MASK, val, info);
eieio();
- aty_st_8(DAC_CNTL, 0);
+ aty_st_8(DAC_CNTL, 0, info);
}
-static void aty_st_pll(int offset, char val)
+static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info)
{
- aty_WaitQueue(3);
- aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN); /* write addr byte */
+ /* write addr byte */
+ aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info);
eieio();
- aty_st_8(CLOCK_CNTL + 2, val); /* write the register value */
+ /* write the register value */
+ aty_st_8(CLOCK_CNTL + 2, val, info);
eieio();
- aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN);
+ aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info);
}
-static struct aty_regvals *get_aty_struct(int vmode)
+#if 0 /* ecd debug */
+static u8 aty_ld_pll(int offset, const struct fb_info_aty *info)
{
- int v = vmode - 1;
+ u8 val;
- switch (chip_type) {
- case MACH64_GT_ID:
- return aty_gt_reg_init[v];
- break;
- case MACH64_VT_ID:
- return aty_vt_reg_init[v];
- break;
- default: /* default to MACH64_GX_ID */
- return aty_gx_reg_init[v];
- break;
- }
+ /* write addr byte */
+ aty_st_8(CLOCK_CNTL + 1, (offset << 2), info);
+ eieio();
+ /* read the register value */
+ val = aty_ld_8(CLOCK_CNTL + 2, info);
+ eieio();
+ return val;
}
+#endif /* ecd debug */
+
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
-static int read_aty_sense(void)
+ /*
+ * Apple monitor sense
+ */
+
+static int read_aty_sense(const struct fb_info_aty *info)
{
int sense, i;
- aty_st_le32(GP_IO, 0x31003100); /* drive outputs high */
+ aty_st_le32(GP_IO, 0x31003100, info); /* drive outputs high */
__delay(200);
- aty_st_le32(GP_IO, 0); /* turn off outputs */
+ aty_st_le32(GP_IO, 0, info); /* turn off outputs */
__delay(2000);
- i = aty_ld_le32(GP_IO); /* get primary sense value */
+ i = aty_ld_le32(GP_IO, info); /* 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); /* drive A low */
+ aty_st_le32(GP_IO, 0x20000000, info); /* drive A low */
__delay(2000);
- i = aty_ld_le32(GP_IO);
+ i = aty_ld_le32(GP_IO, info);
sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);
- aty_st_le32(GP_IO, 0x20002000); /* drive A high again */
+ aty_st_le32(GP_IO, 0x20002000, info); /* drive A high again */
__delay(200);
- aty_st_le32(GP_IO, 0x10000000); /* drive B low */
+ aty_st_le32(GP_IO, 0x10000000, info); /* drive B low */
__delay(2000);
- i = aty_ld_le32(GP_IO);
+ i = aty_ld_le32(GP_IO, info);
sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);
- aty_st_le32(GP_IO, 0x10001000); /* drive B high again */
+ aty_st_le32(GP_IO, 0x10001000, info); /* drive B high again */
__delay(200);
- aty_st_le32(GP_IO, 0x01000000); /* drive C low */
+ aty_st_le32(GP_IO, 0x01000000, info); /* drive C low */
__delay(2000);
- sense |= (aty_ld_le32(GP_IO) & 0x3000) >> 12;
- aty_st_le32(GP_IO, 0); /* turn off outputs */
+ sense |= (aty_ld_le32(GP_IO, info) & 0x3000) >> 12;
+ aty_st_le32(GP_IO, 0, info); /* turn off outputs */
return sense;
}
-static void RGB514_Program(int cmode)
+#endif /* defined(CONFIG_PMAC) || defined(CONFIG_CHRP) */
+
+/* ------------------------------------------------------------------------- */
+
+ /*
+ * Hardware Cursor support.
+ */
+
+static u8 cursor_pixel_map[2] = { 0, 15 };
+static u8 cursor_color_map[2] = { 0, 0xff };
+
+static u8 cursor_bits_lookup[16] =
{
- typedef struct {
- char pixel_dly;
- char misc2_cntl;
- char pixel_rep;
- char pixel_cntl_index;
- char pixel_cntl_v1;
- } RGB514_DAC_Table;
+ 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
+ 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
+};
- static RGB514_DAC_Table RGB514DAC_Tab[8] = {
- {0, 0x41, 0x03, 0x71, 0x45}, // 8bpp
- {0, 0x45, 0x04, 0x0c, 0x01}, // 555
- {0, 0x45, 0x06, 0x0e, 0x00}, // XRGB
- };
- RGB514_DAC_Table *pDacProgTab;
+static u8 cursor_mask_lookup[16] =
+{
+ 0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02,
+ 0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
+};
+
+static void
+aty_set_cursor_color(struct fb_info_aty *fb, u8 *pixel,
+ u8 *red, u8 *green, u8 *blue)
+{
+ struct aty_cursor *c = fb->cursor;
+ int i;
- pDacProgTab = &RGB514DAC_Tab[cmode];
+ if (!c)
+ return;
- aty_st_514(0x90, 0x00);
- aty_st_514(0x04, pDacProgTab->pixel_dly);
- aty_st_514(0x05, 0x00);
+#ifdef __sparc__
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
- aty_st_514(0x2, 0x1);
- aty_st_514(0x71, pDacProgTab->misc2_cntl);
- aty_st_514(0x0a, pDacProgTab->pixel_rep);
+ for (i = 0; i < 2; i++) {
+ c->color[i] = (u32)red[i] << 24;
+ c->color[i] |= (u32)green[i] << 16;
+ c->color[i] |= (u32)blue[i] << 8;
+ c->color[i] |= (u32)pixel[i];
+ }
- aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1);
+ wait_for_fifo(2, fb);
+ aty_st_le32(CUR_CLR0, c->color[0], fb);
+ aty_st_le32(CUR_CLR1, c->color[1], fb);
}
-static void set_off_pitch(const struct atyfb_par *par)
+static void
+aty_set_cursor_shape(struct fb_info_aty *fb)
{
- u32 pitch, offset;
+ struct aty_cursor *c = fb->cursor;
+ u8 *ram, m, b;
+ int x, y;
- pitch = par->vxres>>3;
- offset = ((par->yoffset*par->vxres+par->xoffset)>>3)<<par->cmode;
- aty_st_le32(CRTC_OFF_PITCH, pitch<<22 | offset);
- if (chip_type == MACH64_GT_ID) {
- /* Is this OK for other chips? */
- aty_st_le32(DST_OFF_PITCH, pitch<<22 | offset);
- aty_st_le32(SRC_OFF_PITCH, pitch<<22 | offset);
- }
+ if (!c)
+ return;
+
+#ifdef __sparc__
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
+ ram = (u8 *)(fb->frame_buffer + c->offset);
+
+ for (y = 0; y < c->size.y; y++) {
+ for (x = 0; x < c->size.x >> 2; x++) {
+ m = c->mask[x][y];
+ b = c->bits[x][y];
+ *ram++ = cursor_mask_lookup[m >> 4] |
+ cursor_bits_lookup[(b & m) >> 4];
+ *ram++ = cursor_mask_lookup[m & 0x0f] |
+ cursor_bits_lookup[(b & m) & 0x0f];
+ }
+ for ( ; x < 8; x++) {
+ *ram++ = 0xaa;
+ *ram++ = 0xaa;
+ }
+ }
+ memset(ram, 0xaa, (64 - c->size.y) * 16);
}
-static void atyfb_set_par(struct atyfb_par *par)
+static void
+aty_set_cursor(struct fb_info_aty *fb)
{
- int i, hres;
- struct aty_regvals *init = get_aty_struct(par->vmode);
- int vram_type = aty_ld_le32(CONFIG_STAT0) & 7;
+ struct aty_cursor *c = fb->cursor;
+ u16 xoff, yoff;
+ int x, y;
- if (init == 0) /* paranoia, shouldn't get here */
- panic("aty: display mode %d not supported", par->vmode);
+ if (!c)
+ return;
- current_par = *par;
- hres = vmode_attrs[par->vmode-1].hres;
+#ifdef __sparc__
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
- /* clear FIFO errors */
- aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_HOST_ERR_ACK
- | BUS_FIFO_ERR_ACK);
+ if (c->on) {
+ x = c->pos.x - c->hot.x;
+ if (x < 0) {
+ xoff = -x;
+ x = 0;
+ } else {
+ xoff = 0;
+ }
+
+ y = c->pos.y - c->hot.y;
+ if (y < 0) {
+ yoff = -y;
+ y = 0;
+ } else {
+ yoff = 0;
+ }
+
+ wait_for_fifo(4, fb);
+ aty_st_le32(CUR_OFFSET, (c->offset >> 3) + (yoff << 1), fb);
+ aty_st_le32(CUR_HORZ_VERT_OFF,
+ ((u32)(64 - c->size.y + yoff) << 16) | xoff, fb);
+ aty_st_le32(CUR_HORZ_VERT_POSN, ((u32)y << 16) | x, fb);
+ aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, fb)
+ | HWCURSOR_ENABLE, fb);
+ } else {
+ wait_for_fifo(4, fb);
+ aty_st_le32(GEN_TEST_CNTL,
+ aty_ld_le32(GEN_TEST_CNTL, fb) & ~HWCURSOR_ENABLE,
+ fb);
+ }
+}
- /* Reset engine */
- i = aty_ld_le32(GEN_TEST_CNTL);
- aty_st_le32(GEN_TEST_CNTL, i & ~GUI_ENGINE_ENABLE);
- eieio();
- aty_WaitIdleEmpty();
- aty_st_le32(GEN_TEST_CNTL, i | GUI_ENGINE_ENABLE);
- aty_WaitIdleEmpty();
+static void
+aty_cursor_timer_handler(unsigned long dev_addr)
+{
+ struct fb_info_aty *fb = (struct fb_info_aty *)dev_addr;
- if ( chip_type != MACH64_GT_ID ) {
- i = aty_ld_le32(CRTC_GEN_CNTL);
- aty_st_le32(CRTC_GEN_CNTL, i | CRTC_EXT_DISP_EN);
- }
+ if (!fb->cursor)
+ return;
- if ( chip_type == MACH64_GX_ID ) {
- i = aty_ld_le32(GEN_TEST_CNTL);
- aty_st_le32(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN );
- }
+ if (!fb->cursor->enable)
+ goto out;
- switch (chip_type) {
- case MACH64_VT_ID:
- aty_st_pll(PLL_MACRO_CNTL, 0xb5);
- aty_st_pll(PLL_REF_DIV, 0x2d);
- aty_st_pll(PLL_GEN_CNTL, 0x14);
- aty_st_pll(MCLK_FB_DIV, 0xbd);
- aty_st_pll(PLL_VCLK_CNTL, 0x0b);
- aty_st_pll(VCLK_POST_DIV, init->clock_val[0]);
- aty_st_pll(VCLK0_FB_DIV, init->clock_val[1]);
- aty_st_pll(VCLK1_FB_DIV, 0xd6);
- aty_st_pll(VCLK2_FB_DIV, 0xee);
- aty_st_pll(VCLK3_FB_DIV, 0xf8);
- aty_st_pll(PLL_XCLK_CNTL, 0x0);
- aty_st_pll(PLL_TEST_CTRL, 0x0);
- aty_st_pll(PLL_TEST_COUNT, 0x0);
- break;
- case MACH64_GT_ID:
- if (vram_type == 5) {
- aty_st_pll(0, 0xcd);
- aty_st_pll(PLL_MACRO_CNTL,
- par->vmode >= VMODE_1024_768_60 ? 0xd3: 0xd5);
- aty_st_pll(PLL_REF_DIV, 0x21);
- aty_st_pll(PLL_GEN_CNTL, 0x44);
- aty_st_pll(MCLK_FB_DIV, 0xe8);
- aty_st_pll(PLL_VCLK_CNTL, 0x03);
- aty_st_pll(VCLK_POST_DIV, init->offset[0]);
- aty_st_pll(VCLK0_FB_DIV, init->offset[1]);
- aty_st_pll(VCLK1_FB_DIV, 0x8e);
- aty_st_pll(VCLK2_FB_DIV, 0x9e);
- aty_st_pll(VCLK3_FB_DIV, 0xc6);
- aty_st_pll(PLL_XCLK_CNTL, init->offset[2]);
- aty_st_pll(12, 0xa6);
- aty_st_pll(13, 0x1b);
- } else {
- aty_st_pll(PLL_MACRO_CNTL, 0xd5);
- aty_st_pll(PLL_REF_DIV, 0x21);
- aty_st_pll(PLL_GEN_CNTL, 0xc4);
- aty_st_pll(MCLK_FB_DIV, 0xda);
- aty_st_pll(PLL_VCLK_CNTL, 0x03);
- /* offset actually holds clock values */
- aty_st_pll(VCLK_POST_DIV, init->offset[0]);
- aty_st_pll(VCLK0_FB_DIV, init->offset[1]);
- aty_st_pll(VCLK1_FB_DIV, 0x8e);
- aty_st_pll(VCLK2_FB_DIV, 0x9e);
- aty_st_pll(VCLK3_FB_DIV, 0xc6);
- aty_st_pll(PLL_TEST_CTRL, 0x0);
- aty_st_pll(PLL_XCLK_CNTL, init->offset[2]);
- aty_st_pll(12, 0xa0);
- aty_st_pll(13, 0x1b);
- }
- break;
- default:
- RGB514_Program(par->cmode);
- aty_WaitIdleEmpty();
- aty_st_514(0x06, 0x02);
- aty_st_514(0x10, 0x01);
- aty_st_514(0x70, 0x01);
- aty_st_514(0x8f, 0x1f);
- aty_st_514(0x03, 0x00);
- aty_st_514(0x05, 0x00);
- aty_st_514(0x20, init->clock_val[0]);
- aty_st_514(0x21, init->clock_val[1]);
- break;
- }
+ if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) {
+ fb->cursor->on ^= 1;
+ aty_set_cursor(fb);
+ fb->cursor->vbl_cnt = fb->cursor->blink_rate;
+ }
- aty_ld_8(DAC_REGS); /* clear counter */
- aty_WaitIdleEmpty();
+out:
+ fb->cursor->timer->expires = jiffies + (HZ / 50);
+ add_timer(fb->cursor->timer);
+}
- aty_st_le32(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp);
- aty_st_le32(CRTC_H_SYNC_STRT_WID, init->crtc_h_sync_strt_wid[par->cmode]);
- aty_st_le32(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp);
- aty_st_le32(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid);
+static void
+atyfb_cursor(struct display *d, int mode, int x, int y)
+{
+ struct fb_info_aty *fb = (struct fb_info_aty *)d->fb_info;
+ struct aty_cursor *c = fb->cursor;
- aty_st_8(CLOCK_CNTL, 0);
- aty_st_8(CLOCK_CNTL, CLOCK_STROBE);
+ if (!c)
+ return;
- aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0);
+#ifdef __sparc__
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
- set_off_pitch(par);
+ x *= d->fontwidth;
+ y *= d->fontheight;
+ if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->on)
+ return;
- if (chip_type == MACH64_GT_ID) {
- aty_st_le32(BUS_CNTL, 0x7b23a040);
+ c->enable = 0;
+ c->pos.x = x;
+ c->pos.y = y;
- /* need to set DSP values !! assume sdram */
- i = init->crtc_gen_cntl[0] - (0x100000 * par->cmode);
- if ( vram_type == 5 )
- i = init->crtc_gen_cntl[1] - (0x100000 * par->cmode);
- aty_st_le32(DSP_CONFIG, i);
+ switch (mode) {
+ case CM_ERASE:
+ c->on = 0;
+ aty_set_cursor(fb);
+ break;
- i = aty_ld_le32(MEM_CNTL) & MEM_SIZE_ALIAS;
- if ( vram_type == 5 ) {
- i |= ((1 * par->cmode) << 26) | 0x4215b0;
- aty_st_le32(DSP_ON_OFF,sgram_dsp[par->vmode-1][par->cmode]);
+ case CM_DRAW:
+ case CM_MOVE:
+ c->on = 1;
+ aty_set_cursor(fb);
- //aty_st_le32(CLOCK_CNTL,8192);
- } else {
- i |= ((1 * par->cmode) << 26) | 0x300090;
- aty_st_le32(DSP_ON_OFF, init->mem_cntl[par->cmode]);
+ if (!c->timer) {
+ c->timer = kmalloc(sizeof(*c->timer), GFP_KERNEL);
+ if (!c->timer)
+ return;
+
+ c->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
+
+ init_timer(c->timer);
+ c->timer->expires = jiffies + (HZ / 50);
+ c->timer->data = (unsigned long)fb;
+ c->timer->function = aty_cursor_timer_handler;
+ add_timer(c->timer);
+ }
+
+ c->vbl_cnt = c->blink_rate;
+ c->enable = 1;
+ break;
}
+}
- aty_st_le32(MEM_CNTL, i);
- aty_st_le32(EXT_MEM_CNTL, 0x5000001);
+static int
+atyfb_set_font(struct display *d, int width, int height)
+{
+ struct fb_info_aty *fb = (struct fb_info_aty *)d->fb_info;
+ struct aty_cursor *c = fb->cursor;
+ int i, j;
+
+ if (c) {
+ if (!width || !height) {
+ width = 8;
+ height = 16;
+ }
- /* if (total_vram > 0x400000)
- i |= 0x538; this not been verified on > 4Megs!! */
- } else {
+ c->offset = fb->total_vram - 0x1000;
+ c->hot.x = 0;
+ c->hot.y = 0;
+ c->size.x = width;
+ c->size.y = height;
-/* The magic constant below translates into:
-* 5 = No RDY delay, 1 wait st for mem write, increment during burst transfer
-* 9 = DAC access delayed, 1 wait state for DAC
-* 0 = Disables interupts for FIFO errors
-* e = Allows FIFO to generate 14 wait states before generating error
-* 1 = DAC snooping disabled, ROM disabled
-* 0 = ROM page at 0 (disabled so doesn't matter)
-* f = 15 ROM wait states (disabled so doesn't matter)
-* f = 15 BUS wait states (I'm not sure this applies to PCI bus types)
-* at some point it would be good to experiment with bench marks to see if
-* we can gain some speed by fooling with the wait states etc.
-*/
- if (chip_type == MACH64_VT_ID)
- aty_st_le32(BUS_CNTL, 0x680000f9);
- else
- aty_st_le32(BUS_CNTL, 0x590e10ff);
+ memset(c->bits, 0xff, sizeof(c->bits));
+ memset(c->mask, 0, sizeof(c->mask));
- switch (total_vram) {
- case 0x00100000:
- aty_st_le32(MEM_CNTL, vt_mem_cntl[0][par->cmode]);
- break;
- case 0x00200000:
- aty_st_le32(MEM_CNTL, vt_mem_cntl[1][par->cmode]);
- break;
- case 0x00400000:
- aty_st_le32(MEM_CNTL, vt_mem_cntl[2][par->cmode]);
- break;
- default:
- i = aty_ld_le32(MEM_CNTL) & 0x000F;
- aty_st_le32(MEM_CNTL,
- (init->mem_cntl[par->cmode] & 0xFFFFFFF0) | i);
+ 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));
}
+
+ aty_set_cursor_color(fb, cursor_pixel_map, cursor_color_map,
+ cursor_color_map, cursor_color_map);
+ aty_set_cursor_shape(fb);
+ }
+ return 1;
+}
+
+
+
+
+/* ------------------------------------------------------------------------- */
+
+ /*
+ * CRTC programming
+ */
+
+static void aty_set_crtc(const struct fb_info_aty *info,
+ const struct crtc *crtc)
+{
+ aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info);
+ aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info);
+ aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, info);
+ aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, info);
+ aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info);
+ aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, info);
+ aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info);
+}
+
+static int aty_var_to_crtc(const struct fb_info_aty *info,
+ const struct fb_var_screeninfo *var,
+ struct crtc *crtc)
+{
+ 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;
+ u32 pix_width, dp_pix_width, dp_chain_mask;
+
+ /* input */
+ xres = var->xres;
+ yres = var->yres;
+ vxres = var->xres_virtual;
+ vyres = var->yres_virtual;
+ 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;
+ 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;
+
+ 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;
+
+ if (bpp <= 8) {
+ bpp = 8;
+ pix_width = CRTC_PIX_WIDTH_8BPP;
+ dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB;
+ dp_chain_mask = 0x8080;
+ } else if (bpp <= 16) {
+ 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;
+ } else if ((bpp <= 24) && (Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
+ 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;
+ } 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;
+ } else
+ FAIL("invalid bpp");
+
+ if (vxres*vyres*bpp/8 > info->total_vram)
+ FAIL("not enough video RAM");
+
+ if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+ FAIL("invalid vmode");
+
+ /* output */
+ crtc->vxres = vxres;
+ crtc->vyres = vyres;
+ crtc->xoffset = xoffset;
+ crtc->yoffset = yoffset;
+ crtc->bpp = bpp;
+ 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 | CRTC_EXT_DISP_EN | CRTC_ENABLE;
+ if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID) ||
+ ((Gx == VT_CHIP_ID) && !(Rev & 0x03)) ||
+ ((Gx == GT_CHIP_ID) && !(Rev & 0x03))) {
+ /* Not VTB/GTB */
+ /* FIXME: magic FIFO values */
+ crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000;
}
-/* These magic constants are harder to figure out
-* on the vt chipset bit 2 set makes the screen brighter
-* and bit 15 makes the screen black! But nothing else
-* seems to matter for the vt DAC_CNTL
-*/
- switch (chip_type) {
- case MACH64_GT_ID:
- i = 0x86010102;
+ crtc->dp_pix_width = dp_pix_width;
+ crtc->dp_chain_mask = dp_chain_mask;
+
+ return 0;
+}
+
+static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp)
+{
+ static struct {
+ u8 pixel_dly;
+ u8 misc2_cntl;
+ u8 pixel_rep;
+ u8 pixel_cntl_index;
+ u8 pixel_cntl_v1;
+ } tab[3] = {
+ { 0, 0x41, 0x03, 0x71, 0x45 }, /* 8 bpp */
+ { 0, 0x45, 0x04, 0x0c, 0x01 }, /* 555 */
+ { 0, 0x45, 0x06, 0x0e, 0x00 }, /* XRGB */
+ };
+ int i;
+
+ switch (bpp) {
+ case 8:
+ default:
+ i = 0;
break;
- case MACH64_VT_ID:
- i = 0x87010184;
+ case 16:
+ i = 1;
break;
- default:
- i = 0x47012100;
+ case 32:
+ i = 2;
break;
}
+ aty_st_514(0x90, 0x00, info); /* VRAM Mask Low */
+ aty_st_514(0x04, tab[i].pixel_dly, info); /* Horizontal Sync Control */
+ aty_st_514(0x05, 0x00, info); /* Power Management */
+ aty_st_514(0x02, 0x01, info); /* Misc Clock Control */
+ aty_st_514(0x71, tab[i].misc2_cntl, info); /* Misc Control 2 */
+ aty_st_514(0x0a, tab[i].pixel_rep, info); /* Pixel Format */
+ aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, info);
+ /* Misc Control 2 / 16 BPP Control / 32 BPP Control */
+}
- aty_st_le32(DAC_CNTL, i);
- aty_st_8(DAC_MASK, 0xff);
-
- switch (par->cmode) {
- case CMODE_16:
- i = CRTC_PIX_WIDTH_15BPP; break;
- /*case CMODE_24: */
- case CMODE_32:
- i = CRTC_PIX_WIDTH_32BPP; break;
- case CMODE_8:
+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;
+ u32 pix_width;
+
+ /* 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_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;
+ v_total = crtc->v_tot_disp & 0x7ff;
+ v_disp = (crtc->v_tot_disp>>16) & 0x7ff;
+ v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
+ v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f;
+ v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1;
+ pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
+
+ /* convert */
+ xres = (h_disp+1)*8;
+ yres = v_disp+1;
+ left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly;
+ right = (h_sync_strt-h_disp)*8;
+ hslen = h_sync_wid*8;
+ upper = v_total-v_sync_strt-v_sync_wid;
+ lower = v_sync_strt-v_disp;
+ vslen = v_sync_wid;
+ sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
+ (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT);
+
+ switch (pix_width) {
+#if 0
+ case CRTC_PIX_WIDTH_4BPP:
+ bpp = 4;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+#endif
+ case CRTC_PIX_WIDTH_8BPP:
+ bpp = 8;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CRTC_PIX_WIDTH_15BPP: /* RGB 555 */
+ bpp = 16;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+#if 0
+ case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */
+ bpp = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 6;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+#endif
+ case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */
+ bpp = 24;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */
+ bpp = 32;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
default:
- i = CRTC_PIX_WIDTH_8BPP; break;
+ FAIL("Invalid pixel width");
}
- if (chip_type != MACH64_GT_ID) {
- aty_st_le32(CRTC_INT_CNTL, 0x00000002);
- aty_st_le32(GEN_TEST_CNTL, GUI_ENGINE_ENABLE | BLOCK_WRITE_ENABLE); /* gui_en block_en */
- i |= init->crtc_gen_cntl[par->cmode];
- }
- /* Gentlemen, start your crtc engine */
- aty_st_le32(CRTC_GEN_CNTL, CRTC_EXT_DISP_EN | CRTC_ENABLE | i);
+ /* output */
+ var->xres = xres;
+ var->yres = yres;
+ var->xres_virtual = crtc->vxres;
+ var->yres_virtual = crtc->vyres;
+ var->bits_per_pixel = bpp;
+ var->xoffset = crtc->xoffset;
+ var->yoffset = crtc->yoffset;
+ var->left_margin = left;
+ var->right_margin = right;
+ var->upper_margin = upper;
+ var->lower_margin = lower;
+ var->hsync_len = hslen;
+ var->vsync_len = vslen;
+ var->sync = sync;
+ var->vmode = FB_VMODE_NONINTERLACED;
-#ifdef CONFIG_FB_COMPAT_XPMAC
- display_info.height = vmode_attrs[par->vmode-1].vres;
- display_info.width = vmode_attrs[par->vmode-1].hres;
- display_info.depth = 8<<par->cmode;
- display_info.pitch = par->vxres<<par->cmode;
- display_info.mode = par->vmode;
- strcpy(display_info.name, atyfb_name);
- display_info.fb_address =
- iopa(((chip_type != MACH64_GT_ID) ?
- frame_buffer + init->offset[par->cmode] : frame_buffer));
- display_info.cmap_adr_address = iopa((unsigned long)&aty_cmap_regs->windex);
- display_info.cmap_data_address = iopa((unsigned long)&aty_cmap_regs->lut);
- display_info.disp_reg_address = iopa(ati_regbase);
-#endif /* CONFIG_FB_COMPAT_XPMAC) */
+ return 0;
}
+/* ------------------------------------------------------------------------- */
/*
- * Open/Release the frame buffer device
+ * PLL programming (Mach64 GX family)
+ *
+ * FIXME: use function pointer tables instead of switch statements
*/
-static int atyfb_open(struct fb_info *info)
+static void aty_set_pll_gx(const struct fb_info_aty *info,
+ const struct pll_gx *pll)
+{
+ switch (info->clk_type) {
+ case CLK_ATI18818_1:
+ aty_st_8(CLOCK_CNTL, pll->m, info);
+ break;
+ case CLK_IBMRGB514:
+ aty_st_514(0x06, 0x02, info); /* DAC Operation */
+ aty_st_514(0x10, 0x01, info); /* PLL Control 1 */
+ aty_st_514(0x70, 0x01, info); /* Misc Control 1 */
+ aty_st_514(0x8f, 0x1f, info); /* PLL Ref. Divider Input */
+ aty_st_514(0x03, 0x00, info); /* Sync Control */
+ aty_st_514(0x05, 0x00, info); /* Power Management */
+ aty_st_514(0x20, pll->m, info); /* F0 / M0 */
+ aty_st_514(0x21, pll->m, info); /* F1 / N0 */
+ break;
+ }
+}
+static int aty_var_to_pll_18818(const struct fb_var_screeninfo *var,
+ struct pll_gx *pll)
{
/*
- * Nothing, only a usage count for the moment
+ * FIXME: use real calculations instead of using fixed values from the old
+ * driver
*/
-
- MOD_INC_USE_COUNT;
- return(0);
+ static struct {
+ u32 ps_lim; /* pixclock period rounding limit (arbitrary) */
+ u8 mode; /* (prescsaler << 4) | Select */
+ u8 prog; /* ref_div_count */
+ } ATI18818_clocks[] = {
+ { 7500, 0x0B, 1 }, /* 7407.4 ps = 135.00 MHz */
+ { 9000, 0x0A, 1 }, /* 7936.5 ps = 126.00 MHz */
+ { 11000, 0x09, 1 }, /* 10000.0 ps = 100.00 MHz */
+ { 12800, 0x0D, 1 }, /* 12500.0 ps = 80.00 MHz */
+ { 13500, 0x0E, 1 }, /* 13333.3 ps = 75.00 MHz */
+/* { 14000, 0x03, 2 },*/ /* 13888.8 ps = 72.00 MHz */
+ { 15000, 0x1B, 1 }, /* 14814.8 ps = 67.50 MHz */
+ { 15500, 0x0F, 1 }, /* 15384.6 ps = 65.00 MHz */
+ { 16000, 0x1A, 1 }, /* 15873.0 ps = 63.00 MHz */
+/* { 16000, 0x02, 2 },*/ /* 15873.0 ps = 63.00 MHz */
+/* { 18000, 0x01, 2 },*/ /* 17655.4 ps = 56.64 MHz */
+/* { 19900, 0x00, 2 },*/ /* 19860.9 ps = 50.35 MHz */
+ { 20000, 0x07, 1 }, /* 20000.0 ps = 50.00 MHz */
+ { 20300, 0x06, 1 }, /* 20202.0 ps = 49.50 MHz */
+ { 22500, 0x05, 1 }, /* 22271.2 ps = 44.90 MHz */
+ { 25000, 0x04, 1 }, /* 25000.0 ps = 40.00 MHz */
+/* { 28000, 0x03, 1 },*/ /* 27777.8 ps = 36.00 MHz */
+ { 30000, 0x2B, 1 }, /* 29629,6 ps = 33.75 MHz */
+ { 31000, 0x1F, 1 }, /* 30769.2 ps = 32.50 MHz */
+ { 32000, 0x2A, 1 }, /* 31746.0 ps = 31.50 MHz */
+/* { 32000, 0x02, 1 },*/ /* 31746.0 ps = 31.50 MHz */
+/* { 36000, 0x01, 1 },*/ /* 35310.7 ps = 28.32 MHz */
+/* { 39900, 0x00, 1 },*/ /* 39714.1 ps = 25.18 MHz */
+ { 40000, 0x17, 1 }, /* 40000.0 ps = 25.00 MHz */
+ { 40600, 0x16, 1 }, /* 40404.0 ps = 24.75 MHz */
+ { 45000, 0x15, 1 }, /* 44543.4 ps = 22.45 MHz */
+ { 50000, 0x14, 1 }, /* 50000.0 ps = 20.00 MHz */
+/* { 56000, 0x13, 1 },*/ /* 55555.5 ps = 18.00 MHz */
+ { 62000, 0x2F, 1 }, /* 61538.8 ps = 16.25 MHz */
+/* { 64000, 0x12, 1 },*/ /* 63492.0 ps = 15.75 MHz */
+ };
+ int set;
+
+ for (set = 0; set < sizeof(ATI18818_clocks)/sizeof(*ATI18818_clocks);
+ set++)
+ if (var->pixclock <= ATI18818_clocks[set].ps_lim) {
+ pll->m = ATI18818_clocks[set].mode;
+ pll->n = ATI18818_clocks[set].prog;
+ return 0;
+ }
+ return -EINVAL;
}
-static int atyfb_release(struct fb_info *info)
+static int aty_var_to_pll_514(const struct fb_var_screeninfo *var,
+ struct pll_gx *pll)
{
- MOD_DEC_USE_COUNT;
- return(0);
+ /*
+ * FIXME: use real calculations instead of using fixed values from the old
+ * driver
+ */
+ static struct {
+ u32 limit; /* pixlock rounding limit (arbitrary) */
+ u8 m; /* (df<<6) | vco_div_count */
+ u8 n; /* ref_div_count */
+ } RGB514_clocks[7] = {
+ { 8000, (3<<6) | 20, 9 }, /* 7395 ps / 135.2273 MHz */
+ { 10000, (1<<6) | 19, 3 }, /* 9977 ps / 100.2273 MHz */
+ { 13000, (1<<6) | 2, 3 }, /* 12509 ps / 79.9432 MHz */
+ { 14000, (2<<6) | 8, 7 }, /* 13394 ps / 74.6591 MHz */
+ { 16000, (1<<6) | 44, 6 }, /* 15378 ps / 65.0284 MHz */
+ { 25000, (1<<6) | 15, 5 }, /* 17460 ps / 57.2727 MHz */
+ { 50000, (0<<6) | 53, 7 }, /* 33145 ps / 30.1705 MHz */
+ };
+ int i;
+
+ for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++)
+ if (var->pixclock <= RGB514_clocks[i].limit) {
+ pll->m = RGB514_clocks[i].m;
+ pll->n = RGB514_clocks[i].n;
+ return 0;
+ }
+ return -EINVAL;
}
+ /* FIXME: ATI18818?? */
-static int encode_fix(struct fb_fix_screeninfo *fix,
- const struct atyfb_par *par)
+static int aty_pll_gx_to_var(const struct pll_gx *pll,
+ struct fb_var_screeninfo *var)
{
- struct aty_regvals *init;
+ u8 df, vco_div_count, ref_div_count;
+
+ df = pll->m >> 6;
+ vco_div_count = pll->m & 0x3f;
+ ref_div_count = pll->n;
+
+ var->pixclock = (ref_clk_per*(vco_div_count+65)/ref_div_count)>>(3-df);
+
+ return 0;
+}
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, atyfb_name);
- init = get_aty_struct(par->vmode);
/*
- * FIXME: This will cause problems on non-GT chips, because the frame
- * buffer must be aligned to a page
+ * PLL programming (Mach64 CT family)
*/
- fix->smem_start = (char *)((chip_type != MACH64_GT_ID)
- ? frame_buffer + init->offset[par->cmode] : frame_buffer);
- fix->smem_len = (u32)total_vram;
- if (fix->smem_len > 0x7ff000)
- fix->smem_len = 0x7ff000; /* last page is MMIO */
- fix->mmio_start = (char *)(ati_regbase & ~0xfff);
- fix->mmio_len = 4096;
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->type_aux = 0;
- fix->line_length = par->vxres<<par->cmode;
- fix->visual = par->cmode == CMODE_8 ? FB_VISUAL_PSEUDOCOLOR
- : FB_VISUAL_TRUECOLOR;
- fix->ywrapstep = 0;
- fix->xpanstep = 8;
- fix->ypanstep = 1;
+static void aty_set_pll_ct(const struct fb_info_aty *info,
+ const struct pll_ct *pll)
+{
+#if 0 /* ecd debug */
+printk("PLL_REF_DIV: %02x (%02x)\n",
+ pll->pll_ref_div, aty_ld_pll(PLL_REF_DIV, info));
+printk("PLL_GEN_CNTL: %02x (%02x)\n",
+ pll->pll_gen_cntl, aty_ld_pll(PLL_GEN_CNTL, info));
+printk("MCLK_FB_DIV: %02x (%02x)\n",
+ pll->mclk_fb_div, aty_ld_pll(MCLK_FB_DIV, info));
+printk("PLL_VCLK_CNTL: %02x (%02x)\n",
+ pll->pll_vclk_cntl, aty_ld_pll(PLL_VCLK_CNTL, info));
+printk("VCLK_POST_DIV: %02x (%02x)\n",
+ pll->vclk_post_div, aty_ld_pll(VCLK_POST_DIV, info));
+printk("VCLK0_FB_DIV: %02x (%02x)\n",
+ pll->vclk_fb_div, aty_ld_pll(VCLK0_FB_DIV, info));
+printk("PLL_EXT_CNTL: %02x (%02x)\n",
+ pll->pll_ext_cntl, aty_ld_pll(PLL_EXT_CNTL, info));
+#endif /* ecd debug */
+ aty_st_pll(PLL_REF_DIV, pll->pll_ref_div, info);
+ aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, info);
+ aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, info);
+ aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, info);
+ aty_st_pll(VCLK_POST_DIV, pll->vclk_post_div, info);
+ aty_st_pll(VCLK0_FB_DIV, pll->vclk_fb_div, info);
+ aty_st_pll(PLL_EXT_CNTL, pll->pll_ext_cntl, info);
+
+ if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
+ (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+ (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) ||
+ (Gx == VU_CHIP_ID)) {
+ if (info->ram_type >= SDRAM)
+ aty_st_pll(DLL_CNTL, 0xa6, info);
+ else
+ aty_st_pll(DLL_CNTL, 0xa0, info);
+ aty_st_pll(VFC_CNTL, 0x1b, info);
+ aty_st_le32(DSP_CONFIG, pll->dsp_config, info);
+ aty_st_le32(DSP_ON_OFF, pll->dsp_on_off, info);
+ }
+}
+
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 mclk_fb_div,
+ u8 mclk_post_div, u8 vclk_fb_div, u8 vclk_post_div,
+ u8 bpp, struct pll_ct *pll)
+{
+ 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 = (mclk_fb_div*vclk_post_div*64<<11)/
+ (vclk_fb_div*mclk_post_div*bpp);
+ if (xclks_per_row < (1<<11))
+ FAIL("Dotclock to high");
+ fifo_size = 24;
+ 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)+(1<<6);
+
+ if (info->total_vram > 1*1024*1024) {
+ if (info->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 (info->ram_type >= SDRAM) {
+ /* <2 MB SDRAM */
+ dsp_loop_latency = 9;
+ page_size = 10;
+ } else {
+ /* <2 MB DRAM */
+ dsp_loop_latency = 8;
+ page_size = 10;
+ }
+ }
+ /* 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)<<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;
}
+static int aty_var_to_pll_ct(const struct fb_info_aty *info,
+ const struct fb_var_screeninfo *var,
+ struct pll_ct *pll)
+{
+ u32 vclk_per, q, x; /* x is a workaround for sparc64-linux-gcc */
+ u8 pll_ref_div, pll_gen_cntl, pll_ext_cntl;
+ u8 mclk_fb_div, mclk_post_div, mpostdiv = 0;
+ u8 vclk_fb_div, vclk_post_div, vpostdiv = 0;
+ int err;
+
+ x = x; /* x is a workaround for sparc64-linux-gcc */
-static int decode_var(struct fb_var_screeninfo *var,
- struct atyfb_par *par)
-{
- int xres = var->xres;
- int yres = var->yres;
- int bpp = var->bits_per_pixel;
- struct aty_regvals *init;
-
- /* This should support more video modes */
-
- if (xres <= 512 && yres <= 384)
- par->vmode = VMODE_512_384_60; /* 512x384, 60Hz */
- else if (xres <= 640 && yres <= 480)
- par->vmode = VMODE_640_480_67; /* 640x480, 67Hz */
- else if (xres <= 640 && yres <= 870)
- par->vmode = VMODE_640_870_75P; /* 640x870, 75Hz (portrait) */
- else if (xres <= 768 && yres <= 576)
- par->vmode = VMODE_768_576_50I; /* 768x576, 50Hz (PAL full frame) */
- else if (xres <= 800 && yres <= 600)
- par->vmode = VMODE_800_600_75; /* 800x600, 75Hz */
- else if (xres <= 832 && yres <= 624)
- par->vmode = VMODE_832_624_75; /* 832x624, 75Hz */
- else if (xres <= 1024 && yres <= 768)
- par->vmode = VMODE_1024_768_75; /* 1024x768, 75Hz */
- else if (xres <= 1152 && yres <= 870)
- par->vmode = VMODE_1152_870_75; /* 1152x870, 75Hz */
- else if (xres <= 1280 && yres <= 960)
- par->vmode = VMODE_1280_960_75; /* 1280x960, 75Hz */
- else if (xres <= 1280 && yres <= 1024)
- par->vmode = VMODE_1280_1024_75; /* 1280x1024, 75Hz */
- else
- return -EINVAL;
+ pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
- xres = vmode_attrs[par->vmode-1].hres;
- yres = vmode_attrs[par->vmode-1].vres;
+ vclk_per = var->pixclock;
+ pll_ref_div = info->pll_per*2*255/ref_clk_per;
- if (var->xres_virtual <= xres)
- par->vxres = xres;
+ /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
+ q = ref_clk_per*pll_ref_div*4/info->mclk_per; /* actually 8*q */
+ if (q < 16*8 || q > 255*8)
+ FAIL("mclk out of range");
+ else if (q < 32*8)
+ mclk_post_div = 8;
+ else if (q < 64*8)
+ mclk_post_div = 4;
+ else if (q < 128*8)
+ mclk_post_div = 2;
else
- par->vxres = (var->xres_virtual+7) & ~7;
- if (var->yres_virtual <= yres)
- par->vyres = yres;
+ mclk_post_div = 1;
+ mclk_fb_div = q*mclk_post_div/8;
+
+ /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
+ q = ref_clk_per*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)
+ vclk_post_div = 8;
+ else if (q < 64*8)
+ vclk_post_div = 4;
+ else if (q < 128*8)
+ vclk_post_div = 2;
else
- par->vyres = var->yres_virtual;
+ vclk_post_div = 1;
+ vclk_fb_div = q*vclk_post_div/8;
- par->xoffset = (var->xoffset+7) & ~7;
- par->yoffset = var->yoffset;
- if (par->xoffset+xres > par->vxres || par->yoffset+yres > par->vyres)
- return -EINVAL;
+ if ((err = aty_dsp_gt(info, mclk_fb_div, mclk_post_div, vclk_fb_div,
+ vclk_post_div, var->bits_per_pixel, pll)))
+ return err;
- if (bpp <= 8)
- par->cmode = CMODE_8;
- else if (bpp <= 16)
- par->cmode = CMODE_16;
- else if (bpp <= 32)
- par->cmode = CMODE_32;
+ if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
+ (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+ (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) ||
+ (Gx == VU_CHIP_ID)) && (info->ram_type >= SDRAM))
+ pll_gen_cntl = 0x04;
else
- return -EINVAL;
+ pll_gen_cntl = 0x84;
- if (aty_vram_reqd(par) > total_vram)
- return -EINVAL;
+ switch (mclk_post_div) {
+ 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_gen_cntl |= mpostdiv<<4; /* mclk */
+
+ if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48))
+ pll_ext_cntl = 0;
+ else
+ pll_ext_cntl = mpostdiv; /* xclk == mclk */
+
+ switch (vclk_post_div) {
+ case 1:
+ vpostdiv = 0;
+ break;
+ case 2:
+ vpostdiv = 1;
+ break;
+ case 3:
+ vpostdiv = 0;
+ pll_ext_cntl |= 0x10;
+ break;
+ case 4:
+ vpostdiv = 2;
+ break;
+ case 6:
+ vpostdiv = 2;
+ pll_ext_cntl |= 0x10;
+ break;
+ case 8:
+ vpostdiv = 3;
+ break;
+ case 12:
+ vpostdiv = 3;
+ pll_ext_cntl |= 0x10;
+ break;
+ }
+ vclk_post_div = vpostdiv;
+
+ pll->pll_ref_div = pll_ref_div;
+ pll->pll_gen_cntl = pll_gen_cntl;
+ pll->mclk_fb_div = mclk_fb_div;
+ pll->vclk_post_div = vclk_post_div;
+ pll->vclk_fb_div = vclk_fb_div;
+ pll->pll_ext_cntl = pll_ext_cntl;
+ return 0;
+}
- /* Check if we know about the wanted video mode */
- init = get_aty_struct(par->vmode);
- if (init == NULL || init->crtc_h_sync_strt_wid[par->cmode] == 0 ||
- (chip_type != MACH64_GT_ID &&
- init->crtc_gen_cntl[par->cmode] == 0) ||
- (chip_type == MACH64_GT_ID && (aty_ld_le32(CONFIG_STAT0) & 7) == 5 &&
- init->crtc_gen_cntl[1] == 0))
+static int aty_pll_ct_to_var(const struct pll_ct *pll,
+ struct fb_var_screeninfo *var)
+{
+ u8 pll_ref_div = pll->pll_ref_div;
+ u8 vclk_fb_div = pll->vclk_fb_div;
+ u8 vclk_post_div = pll->vclk_post_div;
+ u8 pll_ext_cntl = pll->pll_ext_cntl;
+ static u8 vclk_post_div_tab[] = {
+ 1, 2, 4, 8,
+ 3, 0, 6, 12
+ };
+ u8 vpostdiv = vclk_post_div_tab[((pll_ext_cntl & 0x10) >> 1) |
+ (vclk_post_div & 3)];
+ if (vpostdiv == 0)
return -EINVAL;
+ var->pixclock = pll_ref_div*vpostdiv*ref_clk_per/vclk_fb_div/2;
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void atyfb_set_par(const struct atyfb_par *par,
+ struct fb_info_aty *info)
+{
+ u32 i;
+
+ info->current_par = *par;
+
+ aty_set_crtc(info, &par->crtc);
+ aty_st_8(CLOCK_CNTL, 0, info);
+ aty_st_8(CLOCK_CNTL, CLOCK_STROBE, info);
+
+ if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+ switch (info->dac_type) {
+ case DAC_IBMRGB514:
+ aty_set_dac_514(info, par->crtc.bpp);
+ break;
+ case DAC_ATI68860_B:
+ /* FIXME */
+ break;
+ }
+ aty_set_pll_gx(info, &par->pll.gx);
+ aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+ aty_st_le32(DAC_CNTL, 0x47052100, info);
+ } else {
+ aty_set_pll_ct(info, &par->pll.ct);
+ i = aty_ld_le32(MEM_CNTL, info) & 0xf30fffff;
+ if (!(Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)))
+ i |= info->mem_refresh_rate << 20;
+ switch (par->crtc.bpp) {
+ case 8:
+ case 24:
+ i |= 0x00000000;
+ break;
+ case 16:
+ i |= 0x04000000;
+ break;
+ case 32:
+ i |= 0x08000000;
+ break;
+ }
+ if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+ aty_st_le32(DAC_CNTL, 0x87010184, info);
+ aty_st_le32(BUS_CNTL, 0x680000f9, info);
+ } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) {
+ aty_st_le32(DAC_CNTL, 0x87010184, info);
+ aty_st_le32(BUS_CNTL, 0x680000f9, info);
+ } else {
+ /* GT */
+ aty_st_le32(DAC_CNTL, 0x86010102, info);
+ aty_st_le32(BUS_CNTL, 0x7b23a040, info);
+ aty_st_le32(EXT_MEM_CNTL, 0x5000001, info);
+ }
+ aty_st_le32(MEM_CNTL, i, info);
+ }
+ aty_st_8(DAC_MASK, 0xff, info);
+
+ /* Initialize the graphics engine */
+ if (par->accel_flags & FB_ACCELF_TEXT)
+ init_engine(par, info);
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ if (console_fb_info == &info->fb_info) {
+ struct fb_var_screeninfo var;
+ int vmode, cmode;
+ display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
+ display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
+ display_info.depth = par->crtc.bpp;
+ display_info.pitch = par->crtc.vxres*par->crtc.bpp/8;
+ atyfb_encode_var(&var, par, info);
+ if (mac_var_to_vmode(&var, &vmode, &cmode))
+ display_info.mode = 0;
+ else
+ display_info.mode = vmode;
+ strcpy(display_info.name, atyfb_name);
+ display_info.fb_address = info->frame_buffer_phys;
+ display_info.cmap_adr_address = info->ati_regbase_phys+0xc0;
+ display_info.cmap_data_address = info->ati_regbase_phys+0xc1;
+ display_info.disp_reg_address = info->ati_regbase_phys;
+ }
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+}
+
+static int atyfb_decode_var(const struct fb_var_screeninfo *var,
+ struct atyfb_par *par,
+ const struct fb_info_aty *info)
+{
+ int err;
+
+ if ((err = aty_var_to_crtc(info, var, &par->crtc)))
+ return err;
+ if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID))
+ switch (info->clk_type) {
+ case CLK_ATI18818_1:
+ err = aty_var_to_pll_18818(var, &par->pll.gx);
+ break;
+ case CLK_IBMRGB514:
+ err = aty_var_to_pll_514(var, &par->pll.gx);
+ break;
+ }
+ else
+ err = aty_var_to_pll_ct(info, var, &par->pll.ct);
+ if (err)
+ return err;
+
+ if (var->accel_flags & FB_ACCELF_TEXT)
+ par->accel_flags = FB_ACCELF_TEXT;
+ else
+ par->accel_flags = 0;
#if 0
if (!fbmon_valid_timings(pixclock, htotal, vtotal, info))
@@ -872,106 +1747,192 @@ static int decode_var(struct fb_var_screeninfo *var,
return 0;
}
-static int encode_var(struct fb_var_screeninfo *var,
- const struct atyfb_par *par)
+static int atyfb_encode_var(struct fb_var_screeninfo *var,
+ const struct atyfb_par *par,
+ const struct fb_info_aty *info)
{
+ int err;
+
memset(var, 0, sizeof(struct fb_var_screeninfo));
- var->xres = vmode_attrs[par->vmode-1].hres;
- var->yres = vmode_attrs[par->vmode-1].vres;
- var->xres_virtual = par->vxres;
- var->yres_virtual = par->vyres;
- var->xoffset = par->xoffset;
- var->yoffset = par->yoffset;
- var->grayscale = 0;
- switch (par->cmode) {
- case CMODE_8:
- var->bits_per_pixel = 8;
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 0;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case CMODE_16: /* RGB 555 */
- var->bits_per_pixel = 16;
- var->red.offset = 10;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 5;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case CMODE_32: /* RGB 888 */
- var->bits_per_pixel = 32;
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- break;
- }
- var->red.msb_right = 0;
- var->green.msb_right = 0;
- var->blue.msb_right = 0;
- var->transp.msb_right = 0;
- var->nonstd = 0;
- var->activate = 0;
+ if ((err = aty_crtc_to_var(&par->crtc, var)))
+ return err;
+ if ((Gx == GX_PCI_ID) || (Gx == CX_PCI_ID))
+ err = aty_pll_gx_to_var(&par->pll.gx, var);
+ else
+ err = aty_pll_ct_to_var(&par->pll.ct, var);
+ if (err)
+ return err;
+
var->height = -1;
var->width = -1;
- var->accel = /* FB_ACCEL_ATY */ 0;
- var->vmode = FB_VMODE_NONINTERLACED;
- var->left_margin = var->right_margin = 64; /* guesses */
- var->upper_margin = var->lower_margin = 32;
- var->hsync_len = 64;
- var->vsync_len = 2;
-
- /* no long long support in the kernel :-( */
- /* this splittig trick will work if xres > 232 */
- var->pixclock = 1000000000/
- (var->left_margin+var->xres+var->right_margin+var->hsync_len);
- var->pixclock *= 1000;
- var->pixclock /= vmode_attrs[par->vmode-1].vfreq*
- (var->upper_margin+var->yres+var->lower_margin+var->vsync_len);
- var->sync = 0;
+ var->accel_flags = par->accel_flags;
return 0;
}
-static void init_par(struct atyfb_par *par, int vmode, int cmode)
+
+static void set_off_pitch(struct atyfb_par *par,
+ const struct fb_info_aty *info)
{
- par->vmode = vmode;
- par->cmode = cmode;
- par->vxres = vmode_attrs[vmode-1].hres;
- par->vyres = vmode_attrs[vmode-1].vres;
- par->xoffset = 0;
- par->yoffset = 0;
+ u32 xoffset = par->crtc.xoffset;
+ u32 yoffset = par->crtc.yoffset;
+ u32 vxres = par->crtc.vxres;
+ u32 bpp = par->crtc.bpp;
+
+ par->crtc.off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+ aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, info);
+}
+
+
+ /*
+ * Open/Release the frame buffer device
+ */
+
+static int atyfb_open(struct fb_info *info, int user)
+
+{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)info;
+
+ if (user) {
+ if (fb->open)
+ return -EBUSY;
+ fb->mmaped = 0;
+ fb->open = 1;
+ fb->vtconsole = -1;
+ } else {
+ fb->consolecnt++;
+ }
+#endif
+ MOD_INC_USE_COUNT;
+ return(0);
+}
+
+static int atyfb_release(struct fb_info *info, int user)
+{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)info;
+
+ if (user) {
+ if (fb->vtconsole != -1)
+ vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
+ fb->open = 0;
+ fb->mmaped = 0;
+ fb->vtconsole = -1;
+ } else {
+ fb->consolecnt--;
+ }
+#endif
+ MOD_DEC_USE_COUNT;
+ return(0);
}
+static int encode_fix(struct fb_fix_screeninfo *fix,
+ const struct atyfb_par *par,
+ const struct fb_info_aty *info)
+{
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+ strcpy(fix->id, atyfb_name);
+ fix->smem_start = (char *)info->frame_buffer_phys;
+ fix->smem_len = (u32)info->total_vram;
+
+#ifdef __LITTLE_ENDIAN
+ /*
+ * Last page of 8 MB little-endian aperture is MMIO
+ * FIXME: we should use the auxiliary aperture instead so we can acces the
+ * full 8 MB of video RAM on 8 MB boards
+ */
+ if (fix->smem_len > 0x800000-GUI_RESERVE)
+ fix->smem_len = 0x800000-GUI_RESERVE;
+#endif
+ /*
+ * Reg Block 0 (CT-compatible block) is at ati_regbase_phys
+ * Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400
+ */
+ if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+ fix->mmio_start = (char *)info->ati_regbase_phys;
+ fix->mmio_len = 0x400;
+ fix->accel = FB_ACCEL_ATI_MACH64GX;
+ } else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+ fix->mmio_start = (char *)info->ati_regbase_phys;
+ fix->mmio_len = 0x400;
+ fix->accel = FB_ACCEL_ATI_MACH64CT;
+ } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) {
+ fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
+ fix->mmio_len = 0x800;
+ fix->accel = FB_ACCEL_ATI_MACH64VT;
+ } else {
+ fix->mmio_start = (char *)(info->ati_regbase_phys-0x400);
+ fix->mmio_len = 0x800;
+ fix->accel = FB_ACCEL_ATI_MACH64GT;
+ }
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+ fix->line_length = par->crtc.vxres*par->crtc.bpp/8;
+ fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
+ : FB_VISUAL_DIRECTCOLOR;
+ fix->ywrapstep = 0;
+ fix->xpanstep = 8;
+ fix->ypanstep = 1;
+
+ 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
+};
+
+#ifdef __sparc__
+struct fb_var_screeninfo default_var_1024x768 __initdata = {
+ /* 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock) */
+ 1024, 768, 1024, 768, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 12699, 176, 16, 28, 1, 96, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+struct fb_var_screeninfo default_var_1152x900 __initdata = {
+ /* 1152x900, 76 Hz, Non-Interlaced (110.0 MHz dotclock) */
+ 1152, 900, 1152, 900, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 9091, 234, 24, 34, 3, 100, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+
+struct fb_var_screeninfo default_var_1280x1024 __initdata = {
+ /* 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock) */
+ 1280, 1024, 1280, 1024, 0, 0, 8, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+ 0, 0, -1, -1, 0, 7408, 248, 16, 38, 1, 144, 3,
+ FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+};
+#endif
+
+
/*
* Get the Fixed Part of the Display
*/
static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
- struct fb_info *info)
+ struct fb_info *fb)
{
+ const struct fb_info_aty *info = (struct fb_info_aty *)fb;
struct atyfb_par par;
if (con == -1)
- par = default_par;
+ par = info->default_par;
else
- decode_var(&fb_display[con].var, &par);
- encode_fix(fix, &par);
+ atyfb_decode_var(&fb_display[con].var, &par, info);
+ encode_fix(fix, &par, info);
return 0;
}
@@ -981,12 +1942,14 @@ static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
*/
static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+ struct fb_info *fb)
{
+ const struct fb_info_aty *info = (struct fb_info_aty *)fb;
+
if (con == -1)
- encode_var(var, &default_par);
+ atyfb_encode_var(var, &info->default_par, info);
else
- *var=fb_display[con].var;
+ *var = fb_display[con].var;
return 0;
}
@@ -996,23 +1959,23 @@ static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
*/
static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+ struct fb_info *fb)
{
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
struct atyfb_par par;
struct display *display;
- int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
- int err;
+ int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
int activate = var->activate;
if (con >= 0)
display = &fb_display[con];
else
- display = &fb_disp; /* used during initialization */
+ display = fb->disp; /* used during initialization */
- if ((err = decode_var(var, &par)))
+ if ((err = atyfb_decode_var(var, &par, info)))
return err;
- encode_var(var, &par);
+ atyfb_encode_var(var, &par, (struct fb_info_aty *)info);
if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
oldxres = display->var.xres;
@@ -1020,14 +1983,15 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
oldvxres = display->var.xres_virtual;
oldvyres = display->var.yres_virtual;
oldbpp = display->var.bits_per_pixel;
+ oldaccel = display->var.accel_flags;
display->var = *var;
if (oldxres != var->xres || oldyres != var->yres ||
oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
- oldbpp != var->bits_per_pixel) {
+ oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) {
struct fb_fix_screeninfo fix;
- encode_fix(&fix, &par);
- display->screen_base = (u_char *)fix.smem_start;
+ encode_fix(&fix, &par, info);
+ display->screen_base = (char *)info->frame_buffer;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
@@ -1036,33 +2000,46 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
display->line_length = fix.line_length;
display->can_soft_blank = 1;
display->inverse = 0;
- switch (par.cmode) {
- case CMODE_8:
-#if 1
- display->dispsw = &fbcon_cfb8;
-#else
- display->dispsw = &fbcon_aty8;
+ accel = var->accel_flags & FB_ACCELF_TEXT;
+ switch (par.crtc.bpp) {
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ *display->dispsw = accel ? fbcon_aty8 : fbcon_cfb8;
+ break;
#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ *display->dispsw = accel ? fbcon_aty16 : fbcon_cfb16;
break;
- case CMODE_16:
- display->dispsw = &fbcon_cfb16;
+#endif
+#ifdef FBCON_HAS_CFB24
+ case 24:
+ *display->dispsw = accel ? fbcon_aty24 : fbcon_cfb24;
break;
- case CMODE_32:
- display->dispsw = &fbcon_cfb32;
+#endif
+#ifdef FBCON_HAS_CFB32
+ case 32:
+ *display->dispsw = accel ? fbcon_aty32 : fbcon_cfb32;
break;
+#endif
default:
display->dispsw = NULL;
break;
}
- if (fb_info.changevar)
- (*fb_info.changevar)(con);
+ display->scrollmode = accel ? 0 : SCROLL_YREDRAW;
+ if (info->fb_info.changevar)
+ (*info->fb_info.changevar)(con);
+ if (info->cursor) {
+ display->dispsw->cursor = atyfb_cursor;
+ display->dispsw->set_font = atyfb_set_font;
+ }
}
if (con == currcon)
- atyfb_set_par(&par);
+ atyfb_set_par(&par, info);
if (oldbpp != var->bits_per_pixel) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err;
- do_install_cmap(con, info);
+ do_install_cmap(con, &info->fb_info);
}
}
@@ -1077,20 +2054,21 @@ static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
*/
static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
- struct fb_info *info)
+ struct fb_info *fb)
{
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
u32 xres, yres, xoffset, yoffset;
- struct atyfb_par *par = &current_par;
+ struct atyfb_par *par = &info->current_par;
- xres = vmode_attrs[par->vmode-1].hres;
- yres = vmode_attrs[par->vmode-1].vres;
+ xres = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
+ yres = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
xoffset = (var->xoffset+7) & ~7;
yoffset = var->yoffset;
- if (xoffset+xres > par->vxres || yoffset+yres > par->vyres)
+ if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres)
return -EINVAL;
- par->xoffset = xoffset;
- par->yoffset = yoffset;
- set_off_pitch(par);
+ par->crtc.xoffset = xoffset;
+ par->crtc.yoffset = yoffset;
+ set_off_pitch(par, info);
return 0;
}
@@ -1106,9 +2084,10 @@ static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
info);
else if (fb_display[con].cmap.len) /* non default colormap? */
fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
+ else {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+ }
return 0;
}
@@ -1122,8 +2101,8 @@ static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
int err;
if (!fb_display[con].cmap.len) { /* no colormap allocated? */
- if ((err = fb_alloc_cmap(&fb_display[con].cmap,
- 1<<fb_display[con].var.bits_per_pixel, 0)))
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0)))
return err;
}
if (con == currcon) /* current console? */
@@ -1141,283 +2120,835 @@ static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
return -EINVAL;
}
+#ifdef __sparc__
+static int atyfb_mmap(struct fb_info *info, struct file *file,
+ struct vm_area_struct *vma)
+{
+ struct fb_info_aty *fb = (struct fb_info_aty *)info;
+ unsigned int size, page, map_size = 0;
+ unsigned long map_offset = 0;
+ int i;
+
+ if (!fb->mmap_map)
+ return -ENXIO;
+
+ size = vma->vm_end - vma->vm_start;
+ if (vma->vm_offset & ~PAGE_MASK)
+ return -ENXIO;
+
+ /* To stop the swapper from even considering these pages. */
+ vma->vm_flags |= (VM_SHM | VM_LOCKED);
+
+#ifdef __sparc_v9__
+ /* Align it as much as desirable */
+ {
+ int j, max = -1, align;
+
+ map_offset = vma->vm_offset+size;
+ for (i = 0; fb->mmap_map[i].size; i++) {
+ if (fb->mmap_map[i].voff < vma->vm_offset)
+ continue;
+ if (fb->mmap_map[i].voff >= map_offset)
+ break;
+ if (max < 0 ||
+ fb->mmap_map[i].size > fb->mmap_map[max].size)
+ max = i;
+ }
+ if (max >= 0) {
+ j = fb->mmap_map[max].size;
+ if (fb->mmap_map[max].voff + j > map_offset)
+ j = map_offset - fb->mmap_map[max].voff;
+ for (align = 0x400000; align > PAGE_SIZE; align >>= 3)
+ if (j >= align &&
+ !(fb->mmap_map[max].poff & (align - 1)))
+ break;
+ if (align > PAGE_SIZE) {
+ j = align;
+ align = j - ((vma->vm_start
+ + fb->mmap_map[max].voff
+ - vma->vm_offset) & (j - 1));
+ if (align != j) {
+ struct vm_area_struct *vmm;
+
+ vmm = find_vma(current->mm,
+ vma->vm_start);
+ if (!vmm || vmm->vm_start
+ >= vma->vm_end + align) {
+ vma->vm_start += align;
+ vma->vm_end += align;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ /* Each page, see which map applies */
+ for (page = 0; page < size; ) {
+ map_size = 0;
+ for (i = 0; fb->mmap_map[i].size; i++) {
+ unsigned long start = fb->mmap_map[i].voff;
+ unsigned long end = start + fb->mmap_map[i].size;
+ unsigned long offset = vma->vm_offset + page;
+
+ if (start > offset)
+ continue;
+ if (offset > end)
+ continue;
+
+ map_size = fb->mmap_map[i].size - (offset - start);
+ map_offset = fb->mmap_map[i].poff + (offset - start);
+ break;
+ }
+ if (!map_size) {
+ page += PAGE_SIZE;
+ continue;
+ }
+ if (page + map_size > size)
+ map_size = size - page;
+
+ pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask);
+ pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag;
+
+ if (remap_page_range(vma->vm_start + page, map_offset,
+ map_size, vma->vm_page_prot))
+ return -EAGAIN;
+
+ page += map_size;
+ }
+
+ if (!map_size)
+ return -EINVAL;
- /*
- * Initialisation
- */
+ vma->vm_file = file;
+ file->f_count++;
+ vma->vm_flags |= VM_IO;
-__initfunc(unsigned long atyfb_init(unsigned long mem_start))
-{
-#ifdef __powerpc__
- /* We don't want to be called like this. */
- /* We rely on Open Firmware (offb) instead. */
- return mem_start;
-#else /* !__powerpc__ */
- /* To be merged with Bernd's mach64fb */
- return mem_start;
-#endif /* !__powerpc__ */
+ if (!fb->mmaped) {
+ int lastconsole = 0;
+
+ if (info->display_fg)
+ lastconsole = info->display_fg->vc_num;
+ fb->mmaped = 1;
+ if (fb->consolecnt && fb_display[lastconsole].fb_info == info) {
+ fb->vtconsole = lastconsole;
+ vt_cons[lastconsole]->vc_mode = KD_GRAPHICS;
+ }
+ }
+ return 0;
}
+#endif /* __sparc__ */
+ /*
+ * Initialisation
+ */
-unsigned long atyfb_of_init(unsigned long mem_start, struct device_node *dp)
+__initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
{
- int i, err, sense;
+ u32 chip_id;
+ u32 i;
+ int j, k;
struct fb_var_screeninfo var;
- struct aty_regvals *init;
- unsigned long addr;
- unsigned char bus, devfn;
- unsigned short cmd;
-
- if (dp->next)
- printk("Warning: only using first ATI card detected\n");
- if (dp->n_addrs != 1 && dp->n_addrs != 3)
- printk("Warning: expecting 1 or 3 addresses for ATY (got %d)",
- dp->n_addrs);
-
- ati_regbase = (int)ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000);
- aty_cmap_regs = (struct aty_cmap_regs *)(ati_regbase + 0xC0);
-
- /* enable memory-space accesses using config-space command register */
- if (pci_device_loc(dp, &bus, &devfn) == 0) {
- pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
- if (cmd != 0xffff) {
- cmd |= PCI_COMMAND_MEMORY;
- pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+ struct display *disp;
+ const char *chipname = NULL;
+ int pll, mclk;
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+ int sense;
+#endif
+
+ info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
+ chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
+ Gx = chip_id & CFG_CHIP_TYPE;
+ Rev = (chip_id & CFG_CHIP_REV)>>24;
+ for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++)
+ if (aty_features[j].chip_type == Gx) {
+ chipname = aty_features[j].name;
+ break;
+ }
+ if (!chipname) {
+ printk("atyfb: Unknown mach64 0x%04x\n", Gx);
+ return 0;
+ } else
+ printk("atyfb: %s [0x%04x rev 0x%2x] ", chipname, Gx, Rev);
+ if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
+ info->bus_type = (aty_ld_le32(CONFIG_STAT0, info) >> 0) & 0x07;
+ info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) >> 3) & 0x07;
+ /* FIXME: clockchip/RAMDAC probing? */
+#ifdef CONFIG_ATARI
+ info->dac_type = DAC_ATI68860_B;
+ info->clk_type = CLK_ATI18818_1;
+#else
+ info->dac_type = DAC_IBMRGB514;
+ info->clk_type = CLK_IBMRGB514;
+#endif
+ /* FIXME */
+ pll = 135;
+ mclk = 50;
+ } else {
+ info->bus_type = PCI;
+ info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07);
+ info->dac_type = DAC_INTERNAL;
+ info->clk_type = CLK_INTERNAL;
+ if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
+ pll = 135;
+ mclk = 60;
+ } else {
+ mclk = info->ram_type >= SDRAM ? 67 : 63;
+ if ((Gx == VT_CHIP_ID) && (Rev == 0x08)) {
+ /* VTA3 */
+ pll = 170;
+ } else if (((Gx == VT_CHIP_ID) && ((Rev == 0x40) ||
+ (Rev == 0x48))) ||
+ ((Gx == VT_CHIP_ID) && ((Rev == 0x01) ||
+ (Rev == 0x9a))) ||
+ (Gx == VU_CHIP_ID)) {
+ /* VTA4 or VTB */
+ pll = 200;
+ } else if (Gx == VT_CHIP_ID) {
+ /* other VT */
+ pll = 135;
+ mclk = 63;
+ } else if ((Gx == GT_CHIP_ID) && (Rev & 0x01)) {
+ /* RAGE II */
+ pll = 170;
+ } else if (((Gx == GT_CHIP_ID) && (Rev & 0x02)) ||
+ (Gx == GU_CHIP_ID)) {
+ /* RAGE II+ */
+ pll = 200;
+ } else if ((Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+ (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) ||
+ (Gx == GQ_CHIP_ID)) {
+ /* RAGE PRO */
+ pll = 230;
+ } else {
+ /* other RAGE */
+ pll = 135;
+ mclk = 63;
+ }
}
}
- chip_type = (aty_ld_le32(CONFIG_CHIP_ID) & CFG_CHIP_TYPE);
-
- i = aty_ld_le32(MEM_CNTL);
- if (chip_type != MACH64_GT_ID)
- switch (i & MEM_SIZE_ALIAS) {
+ if (mclk < 44)
+ info->mem_refresh_rate = 0; /* 000 = 10 Mhz - 43 Mhz */
+ else if (mclk < 50)
+ info->mem_refresh_rate = 1; /* 001 = 44 Mhz - 49 Mhz */
+ else if (mclk < 55)
+ info->mem_refresh_rate = 2; /* 010 = 50 Mhz - 54 Mhz */
+ else if (mclk < 66)
+ info->mem_refresh_rate = 3; /* 011 = 55 Mhz - 65 Mhz */
+ else if (mclk < 75)
+ info->mem_refresh_rate = 4; /* 100 = 66 Mhz - 74 Mhz */
+ else if (mclk < 80)
+ info->mem_refresh_rate = 5; /* 101 = 75 Mhz - 79 Mhz */
+ else if (mclk < 100)
+ info->mem_refresh_rate = 6; /* 110 = 80 Mhz - 100 Mhz */
+ else
+ info->mem_refresh_rate = 7; /* 111 = 100 Mhz and above */
+ printk("%d MHz PLL, %d Mhz MCLK\n", pll, mclk);
+ info->pll_per = 1000000/pll;
+ info->mclk_per = 1000000/mclk;
+
+ i = aty_ld_le32(MEM_CNTL, info);
+ if (((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
+ ((Gx == VT_CHIP_ID) && (Rev & 0x01)) || (Gx == VU_CHIP_ID) ||
+ (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+ (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID))
+ switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
case MEM_SIZE_512K:
- total_vram = 0x80000;
+ info->total_vram = 0x80000;
break;
case MEM_SIZE_1M:
- total_vram = 0x100000;
+ info->total_vram = 0x100000;
break;
- case MEM_SIZE_2M:
- total_vram = 0x200000;
+ case MEM_SIZE_2M_GTB:
+ info->total_vram = 0x200000;
break;
- case MEM_SIZE_4M:
- total_vram = 0x400000;
+ case MEM_SIZE_4M_GTB:
+ info->total_vram = 0x400000;
break;
- case MEM_SIZE_6M:
- total_vram = 0x600000;
+ case MEM_SIZE_6M_GTB:
+ info->total_vram = 0x600000;
break;
- case MEM_SIZE_8M:
- total_vram = 0x800000;
+ case MEM_SIZE_8M_GTB:
+ info->total_vram = 0x800000;
break;
default:
- total_vram = 0x80000;
+ info->total_vram = 0x80000;
}
else
- switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
+ switch (i & MEM_SIZE_ALIAS) {
case MEM_SIZE_512K:
- total_vram = 0x80000;
+ info->total_vram = 0x80000;
break;
case MEM_SIZE_1M:
- total_vram = 0x100000;
+ info->total_vram = 0x100000;
break;
- case MEM_SIZE_2M_GTB:
- total_vram = 0x200000;
+ case MEM_SIZE_2M:
+ info->total_vram = 0x200000;
break;
- case MEM_SIZE_4M_GTB:
- total_vram = 0x400000;
+ case MEM_SIZE_4M:
+ info->total_vram = 0x400000;
break;
- case MEM_SIZE_6M_GTB:
- total_vram = 0x600000;
+ case MEM_SIZE_6M:
+ info->total_vram = 0x600000;
break;
- case MEM_SIZE_8M_GTB:
- total_vram = 0x800000;
+ case MEM_SIZE_8M:
+ info->total_vram = 0x800000;
break;
default:
- total_vram = 0x80000;
+ info->total_vram = 0x80000;
}
-#if 1
- printk("aty_display_init: node = %p, addrs = ", dp->node);
- printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size);
- printk(", intrs =");
- for (i = 0; i < dp->n_intrs; ++i)
- printk(" %x", dp->intrs[i].line);
- printk("\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %p\n",
- (int)ati_regbase, bus, devfn, total_vram, aty_cmap_regs);
-#endif
-
- /* Map in frame buffer */
- addr = dp->addrs[0].address;
-
- /* use the big-endian aperture (??) */
- addr += 0x800000;
- frame_buffer = (unsigned long)__ioremap(addr, 0x800000, _PAGE_WRITETHRU);
-
- if (default_video_mode != -1) {
- sense = read_aty_sense();
- printk("monitor sense = %x\n", sense);
- if (default_video_mode == VMODE_NVRAM) {
- default_video_mode = nvram_read_byte(NV_VMODE);
- init = get_aty_struct(default_video_mode);
- if (default_video_mode <= 0 ||
- default_video_mode > VMODE_MAX || init == 0)
- default_video_mode = VMODE_CHOOSE;
+ if (info->bus_type == ISA)
+ if ((info->total_vram == 0x400000) || (info->total_vram == 0x800000)) {
+ /* protect GUI-regs if complete Aperture is VRAM */
+ info->total_vram -= GUI_RESERVE;
}
- if (default_video_mode == VMODE_CHOOSE)
- default_video_mode = map_monitor_sense(sense);
- init = get_aty_struct(default_video_mode);
- if (!init)
- default_video_mode = VMODE_640_480_60;
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
+ if (default_vmode == VMODE_NVRAM) {
+ default_vmode = nvram_read_byte(NV_VMODE);
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+ default_vmode = VMODE_CHOOSE;
+ }
+ if (default_vmode == VMODE_CHOOSE) {
+ sense = read_aty_sense(info);
+ default_vmode = mac_map_monitor_sense(sense);
+ }
+ if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+ default_vmode = VMODE_640_480_60;
+ if (default_cmode == CMODE_NVRAM)
+ default_cmode = nvram_read_byte(NV_CMODE);
+ if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
+ default_cmode = CMODE_8;
+ if (mac_vmode_to_var(default_vmode, default_cmode, &var))
+ var = default_var;
+#else /* !CONFIG_PMAC && !CONFIG_CHRP */
+ var = default_var;
+#endif /* !CONFIG_PMAC && !CONFIG_CHRP */
+ var.accel_flags |= FB_ACCELF_TEXT;
+ if (atyfb_decode_var(&var, &info->default_par, info)) {
+ printk("atyfb: can't set default video mode\n");
+ return 0;
}
- /*
- * Reduce the pixel size if we don't have enough VRAM.
- */
+ if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
+ strcat(atyfb_name, "GX");
+ else if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID))
+ strcat(atyfb_name, "CT");
+ else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID))
+ strcat(atyfb_name, "VT");
+ else
+ strcat(atyfb_name, "GT");
+
+ disp = &info->disp;
+
+ strcpy(info->fb_info.modename, atyfb_name);
+ info->fb_info.node = -1;
+ info->fb_info.fbops = &atyfb_ops;
+ info->fb_info.disp = disp;
+ strcpy(info->fb_info.fontname, fontname);
+ info->fb_info.changevar = NULL;
+ info->fb_info.switch_con = &atyfbcon_switch;
+ info->fb_info.updatevar = &atyfbcon_updatevar;
+ info->fb_info.blank = &atyfbcon_blank;
+
+ for (j = 0; j < 16; j++) {
+ k = color_table[j];
+ info->palette[j].red = default_red[k];
+ info->palette[j].green = default_grn[k];
+ info->palette[j].blue = default_blu[k];
+ }
+
+ if ((Gx == VT_CHIP_ID) || (Gx == GT_CHIP_ID) || (Gx == GU_CHIP_ID) ||
+ (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
+ (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) ||
+ (Gx == VU_CHIP_ID)) {
+ info->cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC);
+ if (info->cursor)
+ memset(info->cursor, 0, sizeof(*info->cursor));
+ }
+
+ disp->dispsw = &info->dispsw;
+ atyfb_set_var(&var, -1, &info->fb_info);
- if (default_color_mode == CMODE_NVRAM)
- default_color_mode = nvram_read_byte(NV_CMODE);
- if (default_color_mode < CMODE_8 ||
- default_color_mode > CMODE_32)
- default_color_mode = CMODE_8;
-
- init_par(&default_par, default_video_mode, default_color_mode);
- while (aty_vram_reqd(&default_par) > total_vram) {
- while (default_color_mode > CMODE_8 &&
- aty_vram_reqd(&default_par) > total_vram) {
- --default_color_mode;
- init_par(&default_par, default_video_mode, default_color_mode);
+ if (register_framebuffer(&info->fb_info) < 0)
+ return 0;
+
+ printk("fb%d: %s frame buffer device on %s\n",
+ GET_FB_IDX(info->fb_info.node), atyfb_name, name);
+ return 1;
+}
+
+__initfunc(void atyfb_init(void))
+{
+#if defined(CONFIG_FB_OF)
+ /* We don't want to be called like this. */
+ /* We rely on Open Firmware (offb) instead. */
+#elif defined(CONFIG_PCI)
+ struct pci_dev *pdev;
+ struct fb_info_aty *info;
+ unsigned long addr;
+#ifdef __sparc__
+ extern int con_is_present(void);
+ u32 chip_id;
+ int i, j;
+
+ /* Do not attach when we have a serial console. */
+ if (!con_is_present())
+ return;
+#else
+ u16 tmp;
+#endif
+
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if (((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
+ (pdev->vendor == PCI_VENDOR_ID_ATI)) {
+
+ info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
+ if (!info) {
+ printk("atyfb_init: can't alloc fb_info_aty\n");
+ return;
+ }
+ memset(info, 0, sizeof(struct fb_info_aty));
+
+ addr = pdev->base_address[0];
+ if ((addr & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+ addr = pdev->base_address[1];
+ if (!addr)
+ continue;
+
+#ifdef __sparc__
+ /*
+ * Map memory-mapped registers.
+ */
+ info->ati_regbase = addr + 0x7ffc00;
+ info->ati_regbase_phys = __pa(addr + 0x7ffc00);
+
+ /*
+ * Map in big-endian aperture.
+ */
+ info->frame_buffer = (unsigned long)(addr + 0x800000);
+ info->frame_buffer_phys = __pa(addr + 0x800000);
+
+ /*
+ * Figure mmap addresses from PCI config space.
+ * Split Framebuffer in big- and little-endian halfs.
+ */
+ for (i = 0; i < 6 && pdev->base_address[i]; i++)
+ /* nothing */;
+ j = i + 1;
+
+ info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC);
+ if (!info->mmap_map) {
+ printk("atyfb_init: can't alloc mmap_map\n");
+ kfree(info);
+ }
+
+ memset(info->mmap_map, 0, j * sizeof(*info->mmap_map));
+ for (i = j = 0; i < 6 && pdev->base_address[i]; i++) {
+ int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
+ unsigned long base;
+ u32 size, pbase;
+
+ base = pdev->base_address[i];
+
+ io = (base & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+
+ pci_read_config_dword(pdev, breg, &pbase);
+ pci_write_config_dword(pdev, breg, 0xffffffff);
+ pci_read_config_dword(pdev, breg, &size);
+ pci_write_config_dword(pdev, breg, pbase);
+
+ if (io)
+ size &= ~1;
+ size = ~(size) + 1;
+
+ if (base == addr) {
+ info->mmap_map[j].voff = (pbase + 0x800000)
+ & PAGE_MASK;
+ info->mmap_map[j].poff = __pa((base + 0x800000)
+ & PAGE_MASK);
+ info->mmap_map[j].size = 0x800000;
+ info->mmap_map[j].prot_mask = _PAGE_CACHE;
+ info->mmap_map[j].prot_flag = _PAGE_E|_PAGE_IE;
+ size -= 0x800000;
+ j++;
+ }
+
+ info->mmap_map[j].voff = pbase & PAGE_MASK;
+ info->mmap_map[j].poff = __pa(base & PAGE_MASK);
+ info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
+ info->mmap_map[j].prot_mask = _PAGE_CACHE;
+ info->mmap_map[j].prot_flag = _PAGE_E;
+ j++;
+ }
+
+ /*
+ * Fix PROMs idea of MEM_CNTL settings...
+ */
+ chip_id = aty_ld_le32(CONFIG_CHIP_ID, info) & CFG_CHIP_TYPE;
+ if ((chip_id & 0xffff) == VT_CHIP_ID && !((chip_id >> 24) & 1)) {
+ u32 mem = aty_ld_le32(MEM_CNTL, info);
+ 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, info) & 7) >= SDRAM)
+ mem &= ~(0x00f00000);
+ aty_st_le32(MEM_CNTL, mem, info);
+ }
+
+ /*
+ * Set default vmode and cmode from PROM properties.
+ */
+ {
+ struct pcidev_cookie *cookie = pdev->sysdata;
+ int node = cookie->prom_node;
+ int width = prom_getintdefault(node, "width", 1024);
+ int height = prom_getintdefault(node, "height", 768);
+ int depth = prom_getintdefault(node, "depth", 8);
+
+ switch (width) {
+ case 1024:
+ if (height == 768)
+ default_var = default_var_1024x768;
+ break;
+ case 1152:
+ if (height == 900)
+ default_var = default_var_1152x900;
+ break;
+ case 1280:
+ if (height == 1024)
+ default_var = default_var_1280x1024;
+ break;
+ default:
+ break;
+ }
+
+ switch (depth) {
+ case 8:
+ default_var.bits_per_pixel = 8;
+ break;
+ case 16:
+ default_var.bits_per_pixel = 16;
+ break;
+ case 24:
+ default_var.bits_per_pixel = 24;
+ break;
+ case 32:
+ default_var.bits_per_pixel = 32;
+ break;
+ default:
+ break;
+ }
+ }
+
+#else /* __sparc__ */
+
+ info->ati_regbase_phys = 0x7ff000 + addr;
+ info->ati_regbase = (unsigned long)
+ ioremap(info->ati_regbase_phys, 0x1000);
+
+ info->ati_regbase_phys += 0xc00;
+ info->ati_regbase += 0xc00;
+
+ /*
+ * 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
+
+ /* Map in frame buffer */
+ info->frame_buffer_phys = addr;
+ info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
+
+#endif /* __sparc__ */
+
+ if (!aty_init(info, "PCI")) {
+ if (info->mmap_map)
+ kfree(info->mmap_map);
+ kfree(info);
+ }
}
+ }
+#elif defined(CONFIG_ATARI)
+ int m64_num;
+ struct fb_info_aty *info;
+
+ 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);
+ continue;
+ }
+
+ info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
+
/*
- * adjust the video mode smaller if there still is not enough VRAM
+ * Map the video memory (physical address given) to somewhere in the
+ * kernel address space.
*/
- if (aty_vram_reqd(&default_par) > total_vram)
- do {
- default_video_mode--;
- init_par(&default_par, default_video_mode, default_color_mode);
- init = get_aty_struct(default_video_mode);
- } while ((init == 0) &&
- (default_video_mode > VMODE_640_480_60));
+ info->frame_buffer = kernel_map(phys_vmembase[m64_num],
+ phys_size[m64_num],
+ KERNELMAP_NOCACHE_SER, NULL);
+ info->frame_buffer_phys = info->frame_buffer;
+ info->ati_regbase = kernel_map(phys_guiregbase[m64_num], 0x10000,
+ KERNELMAP_NOCACHE_SER, NULL)+0xFC00ul;
+ info->ati_regbase_phys = info->ati_regbase;
+
+ if (!aty_init(info, "ISA bus")) {
+ kfree(info);
+ /* This is insufficient! kernel_map has added two large chunks!! */
+ return;
+ }
}
+#endif
+}
- if (chip_type == MACH64_GT_ID && (aty_ld_le32(CONFIG_STAT0) & 7) == 5
- && init->crtc_gen_cntl[1] == 0) {
- default_video_mode = VMODE_640_480_67;
- default_color_mode = CMODE_8;
- init_par(&default_par, default_video_mode, default_color_mode);
- }
+#ifdef CONFIG_FB_OF
+__initfunc(void atyfb_of_init(struct device_node *dp))
+{
+ unsigned long addr;
+ u8 bus, devfn;
+ u16 cmd;
+ struct fb_info_aty *info;
+ int i;
+
+ for (; dp; dp = dp->next) {
+ switch (dp->n_addrs) {
+ case 1:
+ case 3:
+ addr = dp->addrs[0].address;
+ break;
+ case 4:
+ addr = dp->addrs[1].address;
+ break;
+ default:
+ printk("Warning: got %d adresses for ATY:\n", dp->n_addrs);
+ for (i = 0; i < dp->n_addrs; i++)
+ printk(" %08x-%08x", dp->addrs[i].address,
+ dp->addrs[i].address+dp->addrs[i].size-1);
+ if (dp->n_addrs)
+ printk("\n");
+ continue;
+ }
- switch (chip_type) {
- case MACH64_GX_ID:
- strcat(atyfb_name, "GX");
- break;
- case MACH64_VT_ID:
- strcat(atyfb_name, "VT");
- break;
- case MACH64_GT_ID:
- strcat(atyfb_name, "GT");
- break;
- default:
- break;
- }
- strcpy(fb_info.modename, atyfb_name);
- fb_info.node = -1;
- fb_info.fbops = &atyfb_ops;
- fb_info.disp = &fb_disp;
- fb_info.fontname[0] = '\0';
- fb_info.changevar = NULL;
- fb_info.switch_con = &atyfbcon_switch;
- fb_info.updatevar = &atyfbcon_updatevar;
- fb_info.blank = &atyfbcon_blank;
-
- err = register_framebuffer(&fb_info);
- if (err < 0)
- return mem_start;
-
- for (i = 0; i < 16; i++) {
- int j = color_table[i];
- palette[i].red = default_red[j];
- palette[i].green = default_grn[j];
- palette[i].blue = default_blu[j];
- }
- atyfb_set_par(&default_par);
- encode_var(&var, &default_par);
- atyfb_set_var(&var, -1, &fb_info);
+ info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
+
+ info->ati_regbase = (unsigned long)ioremap(0x7ff000+addr,
+ 0x1000)+0xc00;
+ info->ati_regbase_phys = 0x7ff000+addr;
+ info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
+ 0x1000);
+ info->ati_regbase_phys += 0xc00;
+ info->ati_regbase += 0xc00;
+
+ /* enable memory-space accesses using config-space command register */
+ if (pci_device_loc(dp, &bus, &devfn) == 0) {
+ pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+ if (cmd != 0xffff) {
+ cmd |= PCI_COMMAND_MEMORY;
+ pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+ }
+ }
+
+#ifdef __BIG_ENDIAN
+ /* Use the big-endian aperture */
+ addr += 0x800000;
+#endif
+
+ /* Map in frame buffer */
+ info->frame_buffer_phys = addr;
+ info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
- printk("fb%d: %s frame buffer device on %s\n", GET_FB_IDX(fb_info.node),
- atyfb_name, dp->full_name);
+ if (!aty_init(info, dp->full_name)) {
+ kfree(info);
+ return;
+ }
#ifdef CONFIG_FB_COMPAT_XPMAC
- if (!console_fb_info) {
- console_fb_info = &fb_info;
- console_setmode_ptr = atyfb_console_setmode;
- console_set_cmap_ptr = atyfb_set_cmap;
+ if (!console_fb_info)
+ console_fb_info = &info->fb_info;
+#endif /* CONFIG_FB_COMPAT_XPMAC */
}
-#endif /* CONFIG_FB_COMPAT_XPMAC) */
-
- return mem_start;
}
+#endif /* CONFIG_FB_OF */
-/* XXX: doesn't work yet */
-void atyfb_setup(char *options, int *ints)
+__initfunc(void atyfb_setup(char *options, int *ints))
{
char *this_opt;
- int vmode;
- int depth;
if (!options || !*options)
return;
for (this_opt = strtok(options, ","); this_opt;
this_opt = strtok(NULL, ",")) {
+ if (!strncmp(this_opt, "font:", 5)) {
+ char *p;
+ int i;
+
+ p = this_opt + 5;
+ for (i = 0; i < sizeof(fontname) - 1; i++)
+ if (!*p || *p == ' ' || *p == ',')
+ break;
+ memcpy(fontname, this_opt + 5, i);
+ fontname[i] = 0;
+ }
+#if defined(CONFIG_PMAC) || defined(CONFIG_CHRP)
if (!strncmp(this_opt, "vmode:", 6)) {
- vmode = simple_strtoul(this_opt+6, NULL, 0);
+ int vmode = simple_strtoul(this_opt+6, NULL, 0);
if (vmode > 0 && vmode <= VMODE_MAX)
- default_video_mode = vmode;
+ default_vmode = vmode;
} else if (!strncmp(this_opt, "cmode:", 6)) {
- depth = simple_strtoul(this_opt+6, NULL, 0);
+ int depth = simple_strtoul(this_opt+6, NULL, 0);
switch (depth) {
case 8:
- default_color_mode = CMODE_8;
+ default_cmode = 0;
break;
case 15:
case 16:
- default_color_mode = CMODE_16;
+ default_cmode = 1;
break;
case 24:
case 32:
- default_color_mode = CMODE_32;
+ default_cmode = 2;
break;
- };
+ }
+ }
+#endif
+#ifdef CONFIG_ATARI
+ /*
+ * Why do we need this silly Mach64 argument?
+ * We are already here because of mach64= so its redundant.
+ */
+ if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) {
+ static unsigned char m64_num;
+ static char mach64_str[80];
+ strncpy(mach64_str, this_opt+7, 80);
+ if (!store_video_par(mach64_str, m64_num)) {
+ m64_num++;
+ mach64_count = m64_num;
+ }
}
+#endif
}
}
+#ifdef CONFIG_ATARI
+__initfunc(static int 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 = strtoke(video_str, ";")) || !*p)
+ goto mach64_invalid;
+ vmembase = simple_strtoul(p, NULL, 0);
+ if (!(p = strtoke(NULL, ";")) || !*p)
+ goto mach64_invalid;
+ size = simple_strtoul(p, NULL, 0);
+ if (!(p = strtoke(NULL, ";")) || !*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;
+}
+
+__initfunc(static char *strtoke(char *s, const char *ct))
+{
+ static char *ssave = NULL;
+ char *sbegin, *send;
+
+ sbegin = s ? s : ssave;
+ if (!sbegin)
+ return NULL;
+ if (*sbegin == '\0') {
+ ssave = NULL;
+ return NULL;
+ }
+ send = strpbrk(sbegin, ct);
+ if (send && *send != '\0')
+ *send++ = '\0';
+ ssave = send;
+ return sbegin;
+}
+#endif /* CONFIG_ATARI */
-static int atyfbcon_switch(int con, struct fb_info *info)
+static int atyfbcon_switch(int con, struct fb_info *fb)
{
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
struct atyfb_par par;
/* Do we have to save the colormap? */
if (fb_display[currcon].cmap.len)
fb_get_cmap(&fb_display[currcon].cmap, &fb_display[currcon].var, 1,
- atyfb_getcolreg, info);
+ atyfb_getcolreg, fb);
+
+ /* Erase HW Cursor */
+ if (info->cursor)
+ atyfb_cursor(&fb_display[currcon], CM_ERASE,
+ info->cursor->pos.x, info->cursor->pos.y);
+
currcon = con;
- decode_var(&fb_display[con].var, &par);
- atyfb_set_par(&par);
+
+ atyfb_decode_var(&fb_display[con].var, &par, info);
+ atyfb_set_par(&par, info);
+
/* Install new colormap */
- do_install_cmap(con, info);
- return 0;
+ do_install_cmap(con, fb);
+
+ /* Install hw cursor */
+ if (info->cursor) {
+ aty_set_cursor_color(info, cursor_pixel_map, cursor_color_map,
+ cursor_color_map, cursor_color_map);
+ aty_set_cursor_shape(info);
+ }
+ return 1;
}
/*
* Update the `var' structure (called by fbcon.c)
*/
-static int atyfbcon_updatevar(int con, struct fb_info *info)
+static int atyfbcon_updatevar(int con, struct fb_info *fb)
{
- current_par.yoffset = fb_display[con].var.yoffset;
- set_off_pitch(&current_par);
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
+
+ info->current_par.crtc.yoffset = fb_display[con].var.yoffset;
+ set_off_pitch(&info->current_par, info);
return 0;
}
@@ -1425,20 +2956,30 @@ static int atyfbcon_updatevar(int con, struct fb_info *info)
* Blank the display.
*/
-static void atyfbcon_blank(int blank, struct fb_info *info)
+static void atyfbcon_blank(int blank, struct fb_info *fb)
{
- char gen_cntl;
-
- gen_cntl = aty_ld_8(CRTC_GEN_CNTL);
- if (blank & VESA_VSYNC_SUSPEND)
- gen_cntl |= 0x8;
- if (blank & VESA_HSYNC_SUSPEND)
- gen_cntl |= 0x4;
- if ((blank & VESA_POWERDOWN) == VESA_POWERDOWN)
- gen_cntl |= 0x40;
- if (blank == VESA_NO_BLANKING)
- gen_cntl &= ~(0x4c);
- aty_st_8(CRTC_GEN_CNTL, gen_cntl);
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
+ u8 gen_cntl;
+
+ gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info);
+ 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, info);
}
@@ -1448,13 +2989,15 @@ static void atyfbcon_blank(int blank, struct fb_info *info)
*/
static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
- u_int *transp, struct fb_info *info)
+ u_int *transp, struct fb_info *fb)
{
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
+
if (regno > 255)
return 1;
- *red = palette[regno].red;
- *green = palette[regno].green;
- *blue = palette[regno].blue;
+ *red = info->palette[regno].red;
+ *green = info->palette[regno].green;
+ *blue = info->palette[regno].blue;
return 0;
}
@@ -1466,38 +3009,42 @@ static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
*/
static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int transp, struct fb_info *info)
+ u_int transp, struct fb_info *fb)
{
+ struct fb_info_aty *info = (struct fb_info_aty *)fb;
int i, scale;
if (regno > 255)
return 1;
- palette[regno].red = red;
- palette[regno].green = green;
- palette[regno].blue = blue;
- aty_WaitQueue(2);
- i = aty_ld_8(DAC_CNTL) & 0xfc;
- if (chip_type == MACH64_GT_ID)
- i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/
- aty_st_8(DAC_CNTL, i);
- aty_st_8(DAC_REGS + DAC_MASK, 0xff);
+ info->palette[regno].red = red;
+ info->palette[regno].green = green;
+ info->palette[regno].blue = blue;
+ i = aty_ld_8(DAC_CNTL, info) & 0xfc;
+ if ((Gx == GT_CHIP_ID) || (Gx == GU_CHIP_ID) || (Gx == LG_CHIP_ID) ||
+ (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) || (Gx == GI_CHIP_ID) ||
+ (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID))
+ i |= 0x2; /*DAC_CNTL|0x2 turns off the extra brightness for gt*/
+ aty_st_8(DAC_CNTL, i, info);
+ aty_st_8(DAC_REGS + DAC_MASK, 0xff, info);
eieio();
- scale = ((chip_type != MACH64_GX_ID) &&
- (current_par.cmode == CMODE_16)) ? 3 : 0;
- aty_WaitQueue(4);
- aty_cmap_regs->windex = regno << scale;
+ scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) &&
+ (info->current_par.crtc.bpp == 16)) ? 3 : 0;
+ info->aty_cmap_regs->windex = regno << scale;
eieio();
- aty_cmap_regs->lut = red << scale;
+ info->aty_cmap_regs->lut = red << scale;
eieio();
- aty_cmap_regs->lut = green << scale;
+ info->aty_cmap_regs->lut = green << scale;
eieio();
- aty_cmap_regs->lut = blue << scale;
+ info->aty_cmap_regs->lut = blue << scale;
eieio();
if (regno < 16) {
-#ifdef CONFIG_FBCON_CFB16
+#ifdef FBCON_HAS_CFB16
fbcon_cfb16_cmap[regno] = (regno << 10) | (regno << 5) | regno;
#endif
-#ifdef CONFIG_FBCON_CFB32
+#ifdef FBCON_HAS_CFB24
+ fbcon_cfb24_cmap[regno] = (regno << 16) | (regno << 8) | regno;
+#endif
+#ifdef FBCON_HAS_CFB32
fbcon_cfb32_cmap[regno] = (regno << 24) | (regno << 16) |
(regno << 8) | regno;
#endif
@@ -1513,10 +3060,11 @@ static void do_install_cmap(int con, struct fb_info *info)
if (fb_display[con].cmap.len)
fb_set_cmap(&fb_display[con].cmap, &fb_display[con].var, 1,
atyfb_setcolreg, info);
- else
- fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
- &fb_display[con].var, 1, atyfb_setcolreg,
- info);
+ else {
+ int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+ fb_set_cmap(fb_default_cmap(size), &fb_display[con].var, 1,
+ atyfb_setcolreg, info);
+ }
}
@@ -1524,15 +3072,34 @@ static void do_install_cmap(int con, struct fb_info *info)
* Accelerated functions
*/
-void aty_waitblit(void)
+static inline void draw_rect(s16 x, s16 y, u16 width, u16 height,
+ struct fb_info_aty *info)
{
- aty_WaitIdleEmpty(); /* Make sure that all commands have finished */
+ /* perform rectangle fill */
+ wait_for_fifo(2, info);
+ aty_st_le32(DST_Y_X, (x << 16) | y, info);
+ aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | height, info);
}
-void aty_rectcopy(int srcx, int srcy, int dstx, int dsty, u_int width,
- u_int height)
+static inline void aty_rectcopy(int srcx, int srcy, int dstx, int dsty,
+ u_int width, u_int height,
+ struct fb_info_aty *info)
{
- u_int direction = 0;
+ u32 direction = DST_LAST_PEL;
+ u32 pitch_value;
+
+ if (!width || !height)
+ return;
+
+ pitch_value = info->current_par.crtc.vxres;
+ if (info->current_par.crtc.bpp == 24) {
+ /* In 24 bpp, the engine is in 8 bpp - this requires that all */
+ /* horizontal coordinates and widths must be adjusted */
+ pitch_value *= 3;
+ srcx *= 3;
+ dstx *= 3;
+ width *= 3;
+ }
if (srcy < dsty) {
dsty += height - 1;
@@ -1546,46 +3113,40 @@ void aty_rectcopy(int srcx, int srcy, int dstx, int dsty, u_int width,
} else
direction |= DST_X_LEFT_TO_RIGHT;
- aty_WaitQueue(4);
- aty_st_le32(DP_WRITE_MSK, 0x000000FF /* pGC->planemask */ );
- aty_st_le32(DP_MIX, (MIX_SRC << 16) | MIX_DST);
- aty_st_le32(DP_SRC, FRGD_SRC_BLIT);
-
- aty_WaitQueue(5);
- aty_st_le32(SRC_Y_X, (srcx << 16) | (srcy & 0x0000ffff));
- aty_st_le32(SRC_WIDTH1, width);
- aty_st_le32(DST_CNTL, direction);
- aty_st_le32(DST_Y_X, (dstx << 16) | (dsty & 0x0000ffff));
- aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | (height & 0x0000ffff));
-
- aty_WaitIdleEmpty(); /* Make sure that all commands have finished */
-
+ wait_for_fifo(5, info);
+ aty_st_le32(DP_SRC, FRGD_SRC_BLIT, info);
/*
- * Make sure that the destination trajectory is correctly set
- * for subsequent calls. MACH64_BIT_BLT is the only function that
- * currently changes the destination trajectory from L->R and T->B.
+ * ++Geert:
+ * Warning: SRC_OFF_PITCH may be thrashed by writing to other registers
+ * (e.g. CRTC_H_TOTAL_DISP, DP_SRC, DP_FRGD_CLR)
*/
- aty_st_le32(DST_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
+ aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, info);
+ aty_st_le32(SRC_Y_X, (srcx << 16) | srcy, info);
+ aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | height, info);
+ aty_st_le32(DST_CNTL, direction, info);
+ draw_rect(dstx, dsty, width, height, info);
}
-void aty_rectfill(int dstx, int dsty, u_int width, u_int height, u_int color)
+static inline void aty_rectfill(int dstx, int dsty, u_int width, u_int height,
+ u_int color, struct fb_info_aty *info)
{
if (!width || !height)
return;
- aty_WaitQueue(5);
- aty_st_le32(DP_FRGD_CLR, color /* pGC->fgPixel */ );
- aty_st_le32(DP_WRITE_MSK, 0x000000FF /* pGC->planemask */ );
- aty_st_le32(DP_MIX, (MIX_SRC << 16) | MIX_DST);
- aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR);
-
- aty_st_le32(DST_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
-
- aty_WaitQueue(2);
- aty_st_le32(DST_Y_X, (((u_int)dstx << 16) | ((u_int)dsty & 0x0000ffff)));
- aty_st_le32(DST_HEIGHT_WIDTH, (((u_int)width << 16) | height));
+ if (info->current_par.crtc.bpp == 24) {
+ /* In 24 bpp, the engine is in 8 bpp - this requires that all */
+ /* horizontal coordinates and widths must be adjusted */
+ dstx *= 3;
+ width *= 3;
+ }
- aty_WaitIdleEmpty(); /* Make sure that all commands have finished */
+ wait_for_fifo(3, info);
+ aty_st_le32(DP_FRGD_CLR, color, info);
+ aty_st_le32(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE,
+ info);
+ aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
+ DST_X_LEFT_TO_RIGHT, info);
+ draw_rect(dstx, dsty, width, height, info);
}
@@ -1593,9 +3154,16 @@ void aty_rectfill(int dstx, int dsty, u_int width, u_int height, u_int color)
* Text console acceleration
*/
-static void fbcon_aty8_bmove(struct display *p, int sy, int sx, int dy, int dx,
- int height, int width)
+static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
+ int height, int width)
{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
sx *= p->fontwidth;
sy *= p->fontheight;
dx *= p->fontwidth;
@@ -1603,13 +3171,22 @@ static void fbcon_aty8_bmove(struct display *p, int sy, int sx, int dy, int dx,
width *= p->fontwidth;
height *= p->fontheight;
- aty_rectcopy(sx, sy, dx, dy, width, height);
+ aty_rectcopy(sx, sy, dx, dy, width, height,
+ (struct fb_info_aty *)p->fb_info);
}
-static void fbcon_aty8_clear(struct vc_data *conp, struct display *p, int sy,
- int sx, int height, int width)
+static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
+ int sx, int height, int width)
{
- u32 bgx = attr_bgcol_ec(p, conp);
+ u32 bgx;
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
+ bgx = attr_bgcol_ec(p, conp);
bgx |= (bgx << 8);
bgx |= (bgx << 16);
@@ -1618,68 +3195,154 @@ static void fbcon_aty8_clear(struct vc_data *conp, struct display *p, int sy,
width *= p->fontwidth;
height *= p->fontheight;
- aty_rectfill(sx, sy, width, height, bgx);
+ aty_rectfill(sx, sy, width, height, bgx,
+ (struct fb_info_aty *)p->fb_info);
}
+#ifdef FBCON_HAS_CFB8
static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
int yy, int xx)
{
- aty_waitblit();
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
+ wait_for_idle((struct fb_info_aty *)p->fb_info);
fbcon_cfb8_putc(conp, p, c, yy, xx);
}
static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
- const char *s, int count, int yy, int xx)
+ const unsigned short *s, int count, int yy,
+ int xx)
{
- aty_waitblit();
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
+ wait_for_idle((struct fb_info_aty *)p->fb_info);
fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
}
static struct display_switch fbcon_aty8 = {
- fbcon_cfb8_setup, fbcon_aty8_bmove, fbcon_aty8_clear, fbcon_aty8_putc,
- fbcon_aty8_putcs, fbcon_cfb8_revc
+ fbcon_cfb8_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty8_putc,
+ fbcon_aty8_putcs, fbcon_cfb8_revc, NULL, NULL, fbcon_cfb8_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
+#endif
+#ifdef FBCON_HAS_CFB16
+static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
+{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-#ifdef CONFIG_FB_COMPAT_XPMAC
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
- /*
- * Backward compatibility mode for Xpmac
- */
+ wait_for_idle((struct fb_info_aty *)p->fb_info);
+ fbcon_cfb16_putc(conp, p, c, yy, xx);
+}
-static int atyfb_console_setmode(struct vc_mode *mode, int doit)
+static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx)
{
- int err;
- struct fb_var_screeninfo var;
- struct atyfb_par par;
- int vmode, cmode;
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
- if (mode->mode <= 0 || mode->mode > VMODE_MAX )
- return -EINVAL;
- vmode = mode->mode;
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
- switch (mode->depth) {
- case 24:
- case 32:
- cmode = CMODE_32;
- break;
- case 16:
- cmode = CMODE_16;
- break;
- case 8:
- case 0: /* (default) */
- cmode = CMODE_8;
- break;
- default:
- return -EINVAL;
- }
- init_par(&par, vmode, cmode);
- encode_var(&var, &par);
- if ((err = decode_var(&var, &par)))
- return err;
- if (doit)
- atyfb_set_var(&var, currcon, 0);
- return 0;
+ wait_for_idle((struct fb_info_aty *)p->fb_info);
+ fbcon_cfb16_putcs(conp, p, s, count, yy, xx);
}
-#endif /* CONFIG_FB_COMPAT_XPMAC */
+static struct display_switch fbcon_aty16 = {
+ fbcon_cfb16_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty16_putc,
+ fbcon_aty16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#ifdef FBCON_HAS_CFB24
+static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
+{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
+ wait_for_idle((struct fb_info_aty *)p->fb_info);
+ fbcon_cfb24_putc(conp, p, c, yy, xx);
+}
+
+static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx)
+{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
+ wait_for_idle((struct fb_info_aty *)p->fb_info);
+ fbcon_cfb24_putcs(conp, p, s, count, yy, xx);
+}
+
+static struct display_switch fbcon_aty24 = {
+ fbcon_cfb24_setup, fbcon_cfb24_bmove, fbcon_cfb24_clear, fbcon_aty24_putc,
+ fbcon_aty24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#ifdef FBCON_HAS_CFB32
+static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c,
+ int yy, int xx)
+{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
+ wait_for_idle((struct fb_info_aty *)p->fb_info);
+ fbcon_cfb32_putc(conp, p, c, yy, xx);
+}
+
+static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
+ const unsigned short *s, int count, int yy,
+ int xx)
+{
+#ifdef __sparc__
+ struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+ if (fb->mmaped && currcon == fb->vtconsole)
+ return;
+#endif
+
+ wait_for_idle((struct fb_info_aty *)p->fb_info);
+ fbcon_cfb32_putcs(conp, p, s, count, yy, xx);
+}
+
+static struct display_switch fbcon_aty32 = {
+ fbcon_cfb32_setup, fbcon_aty_bmove, fbcon_aty_clear, fbcon_aty32_putc,
+ fbcon_aty32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif