Commit 3da8fdc5 authored by James Simmons's avatar James Simmons

[ATY FBDEV] Rage XL cards can now be booted with needed the BIOS :-)

[FBCON] Moving to use ring buffers and DMA cards.
parent 5405a659
......@@ -715,6 +715,12 @@ config FB_ATY_GX
is at
<http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
config FB_ATY_XL_INIT
bool " Rage XL No-BIOS Init support" if FB_ATY_CT
depends on FB_ATY
help
Say Y here to support booting a Rage XL without BIOS support.
config FB_SIS
tristate "SIS acceleration"
depends on FB && PCI
......
......@@ -4,4 +4,5 @@ obj-$(CONFIG_FB_ATY128) += aty128fb.o
atyfb-y := atyfb_base.o mach64_accel.o
atyfb-$(CONFIG_FB_ATY_GX) += mach64_gx.o
atyfb-$(CONFIG_FB_ATY_CT) += mach64_ct.o mach64_cursor.o
atyfb-$(CONFIG_FB_ATY_XL_INIT) += xlinit.o
atyfb-objs := $(atyfb-y)
......@@ -36,13 +36,17 @@ struct pll_ct {
u8 pll_ref_div;
u8 pll_gen_cntl;
u8 mclk_fb_div;
u8 mclk_fb_mult; /* 2 ro 4 */
u8 sclk_fb_div;
u8 pll_vclk_cntl;
u8 vclk_post_div;
u8 vclk_fb_div;
u8 pll_ext_cntl;
u8 spll_cntl2;
u32 dsp_config; /* Mach64 GTB DSP */
u32 dsp_on_off; /* Mach64 GTB DSP */
u8 mclk_post_div_real;
u8 xclk_post_div_real;
u8 vclk_post_div_real;
};
......@@ -75,6 +79,7 @@ struct atyfb_par {
u32 ref_clk_per;
u32 pll_per;
u32 mclk_per;
u32 xclk_per;
u8 bus_type;
u8 ram_type;
u8 mem_refresh_rate;
......@@ -118,7 +123,7 @@ struct atyfb_par {
#define M64F_EXTRA_BRIGHT 0x00020000
#define M64F_LT_SLEEP 0x00040000
#define M64F_XL_DLL 0x00080000
#define M64F_MFB_TIMES_4 0x00100000
/*
* Register access
......@@ -151,6 +156,33 @@ static inline void aty_st_le32(int regindex, u32 val,
#endif
}
static inline u16 aty_ld_le16(int regindex, const struct atyfb_par *par)
{
/* Hack for bloc 1, should be cleanly optimized by compiler */
if (regindex >= 0x400)
regindex -= 0x800;
#if defined(__mc68000__)
return le16_to_cpu(*((volatile u16 *)(par->ati_regbase + regindex)));
#else
return readw(par->ati_regbase + regindex);
#endif
}
static inline void aty_st_le16(int regindex, u16 val,
const struct atyfb_par *par)
{
/* Hack for bloc 1, should be cleanly optimized by compiler */
if (regindex >= 0x400)
regindex -= 0x800;
#if defined(__mc68000__)
*((volatile u16 *)(par->ati_regbase + regindex)) = cpu_to_le16(val);
#else
writew(val, par->ati_regbase + regindex);
#endif
}
static inline u8 aty_ld_8(int regindex, const struct atyfb_par *par)
{
/* Hack for bloc 1, should be cleanly optimized by compiler */
......@@ -189,6 +221,19 @@ static inline u8 aty_ld_pll(int offset, const struct atyfb_par *par)
}
/*
* CT Family only.
*/
static inline void aty_st_pll(int offset, u8 val,
const struct atyfb_par *par)
{
/* write addr byte */
aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, par);
/* write the register value */
aty_st_8(CLOCK_CNTL + 2, val, par);
aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, par);
}
/*
* DAC operations
*/
......
......@@ -88,7 +88,6 @@
#include <asm/backlight.h>
#endif
/*
* Debug flags.
*/
......@@ -99,11 +98,9 @@
/* - must be aligned to a PAGE boundary */
#define GUI_RESERVE (1 * PAGE_SIZE)
/* FIXME: remove the FAIL definition */
#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
/*
* The Hardware parameters for each card
*/
......@@ -162,6 +159,9 @@ static int atyfb_sync(struct fb_info *info);
*/
static int aty_init(struct fb_info *info, const char *name);
#ifdef CONFIG_FB_ATY_XL_INIT
extern int atyfb_xl_init(struct fb_info *info);
#endif
#ifdef CONFIG_ATARI
static int store_video_par(char *videopar, unsigned char m64_num);
#endif
......@@ -214,6 +214,7 @@ static char noaccel __initdata = 0;
static u32 default_vram __initdata = 0;
static int default_pll __initdata = 0;
static int default_mclk __initdata = 0;
static int default_xclk __initdata = 0;
#ifndef MODULE
static char *mode_option __initdata = NULL;
......@@ -254,7 +255,8 @@ static char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)";
static char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)";
static char m64n_gtc_ppl[] __initdata =
"3D RAGE PRO (PQFP, PCI, limited 3D)";
static char m64n_xl[] __initdata = "3D RAGE (XL)";
static char m64n_xl_33[] __initdata = "3D RAGE (XL PCI-33MHz)";
static char m64n_xl_66[] __initdata = "3D RAGE (XL PCI-66MHz)";
static char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)";
static char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)";
static char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)";
......@@ -265,129 +267,62 @@ static struct {
u16 pci_id, chip_type;
u8 rev_mask, rev_val;
const char *name;
int pll, mclk;
int pll, mclk, xclk;
u32 features;
} aty_chips[] __initdata = {
#ifdef CONFIG_FB_ATY_GX
/* Mach64 GX */
{
0x4758, 0x00d7, 0x00, 0x00, m64n_gx, 135, 50, M64F_GX}, {
0x4358, 0x0057, 0x00, 0x00, m64n_cx, 135, 50, M64F_GX},
#endif /* CONFIG_FB_ATY_GX */
{ 0x4758, 0x00d7, 0x00, 0x00, m64n_gx, 135, 50, 50, M64F_GX },
{ 0x4358, 0x0057, 0x00, 0x00, m64n_cx, 135, 50, 50, M64F_GX },
#endif /* CONFIG_FB_ATY_GX */
#ifdef CONFIG_FB_ATY_CT
/* Mach64 CT */
{
0x4354, 0x4354, 0x00, 0x00, m64n_ct, 135, 60,
M64F_CT | M64F_INTEGRATED | M64F_CT_BUS |
M64F_MAGIC_FIFO}, {
0x4554, 0x4554, 0x00, 0x00, m64n_et, 135, 60,
M64F_CT | M64F_INTEGRATED | M64F_CT_BUS |
M64F_MAGIC_FIFO},
/* Mach64 VT */
{
0x5654, 0x5654, 0xc7, 0x00, m64n_vta3, 170, 67,
M64F_VT | M64F_INTEGRATED | M64F_VT_BUS |
M64F_MAGIC_FIFO | M64F_FIFO_24}, {
0x5654, 0x5654, 0xc7, 0x40, m64n_vta4, 200, 67,
M64F_VT | M64F_INTEGRATED | M64F_VT_BUS |
M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_MAGIC_POSTDIV}, {
0x5654, 0x5654, 0x00, 0x00, m64n_vtb, 200, 67,
M64F_VT | M64F_INTEGRATED | M64F_VT_BUS |
M64F_GTB_DSP | M64F_FIFO_24}, {
0x5655, 0x5655, 0x00, 0x00, m64n_vtb, 200, 67,
M64F_VT | M64F_INTEGRATED | M64F_VT_BUS |
M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL}, {
0x5656, 0x5656, 0x00, 0x00, m64n_vt4, 230, 83,
M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP},
/* Mach64 GT (3D RAGE) */
{
0x4754, 0x4754, 0x07, 0x00, m64n_gt, 135, 63,
M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO |
M64F_FIFO_24 | M64F_EXTRA_BRIGHT}, {
0x4754, 0x4754, 0x07, 0x01, m64n_gt, 170, 67,
M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT}, {
0x4754, 0x4754, 0x07, 0x02, m64n_gt, 200, 67,
M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT}, {
0x4755, 0x4755, 0x00, 0x00, m64n_gtb, 200, 67,
M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT}, {
0x4756, 0x4756, 0x00, 0x00, m64n_iic_p, 230, 83,
M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT}, {
0x4757, 0x4757, 0x00, 0x00, m64n_iic_a, 230, 83,
M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT}, {
0x475a, 0x475a, 0x00, 0x00, m64n_iic_a, 230, 83,
M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT},
/* Mach64 LT */
{
0x4c54, 0x4c54, 0x00, 0x00, m64n_lt, 135, 63,
M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP}, {
0x4c47, 0x4c47, 0x00, 0x00, m64n_ltg, 230, 63,
M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP |
M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT |
M64F_LT_SLEEP | M64F_G3_PB_1024x768},
/* Mach64 GTC (3D RAGE PRO) */
{
0x4742, 0x4742, 0x00, 0x00, m64n_gtc_ba, 230, 100,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT}, {
0x4744, 0x4744, 0x00, 0x00, m64n_gtc_ba1, 230, 100,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT}, {
0x4749, 0x4749, 0x00, 0x00, m64n_gtc_bp, 230, 100,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT | M64F_MAGIC_VRAM_SIZE}, {
0x4750, 0x4750, 0x00, 0x00, m64n_gtc_pp, 230, 100,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT}, {
0x4751, 0x4751, 0x00, 0x00, m64n_gtc_ppl, 230, 100,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT},
/* 3D RAGE XL */
{
0x4752, 0x4752, 0x00, 0x00, m64n_xl, 230, 100,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL |
M64F_EXTRA_BRIGHT | M64F_XL_DLL},
/* Mach64 LT PRO */
{
0x4c42, 0x4c42, 0x00, 0x00, m64n_ltp_a, 230, 100,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP}, {
0x4c44, 0x4c44, 0x00, 0x00, m64n_ltp_p, 230, 100,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP}, {
0x4c49, 0x4c49, 0x00, 0x00, m64n_ltp_p, 230, 100,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP | M64F_EXTRA_BRIGHT |
M64F_G3_PB_1_1 | M64F_G3_PB_1024x768}, {
0x4c50, 0x4c50, 0x00, 0x00, m64n_ltp_p, 230, 100,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP},
/* 3D RAGE Mobility */
{
0x4c4d, 0x4c4d, 0x00, 0x00, m64n_mob_p, 230, 50,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP | M64F_MOBIL_BUS}, {
0x4c4e, 0x4c4e, 0x00, 0x00, m64n_mob_a, 230, 50,
M64F_GT | M64F_INTEGRATED | M64F_RESET_3D |
M64F_GTB_DSP | M64F_MOBIL_BUS},
#endif /* CONFIG_FB_ATY_CT */
/* Mach64 CT */
{ 0x4354, 0x4354, 0x00, 0x00, m64n_ct, 135, 60, 60, M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO },
{ 0x4554, 0x4554, 0x00, 0x00, m64n_et, 135, 60, 60, M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO },
/* Mach64 VT */
{ 0x5654, 0x5654, 0xc7, 0x00, m64n_vta3, 170, 67, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO | M64F_FIFO_24 },
{ 0x5654, 0x5654, 0xc7, 0x40, m64n_vta4, 200, 67, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_MAGIC_POSTDIV },
{ 0x5654, 0x5654, 0x00, 0x00, m64n_vtb, 200, 67, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_FIFO_24 },
{ 0x5655, 0x5655, 0x00, 0x00, m64n_vtb, 200, 67, 67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL },
{ 0x5656, 0x5656, 0x00, 0x00, m64n_vt4, 230, 83, 83, M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP },
/* Mach64 GT (3D RAGE) */
{ 0x4754, 0x4754, 0x07, 0x00, m64n_gt, 135, 63, 63, M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_EXTRA_BRIGHT },
{ 0x4754, 0x4754, 0x07, 0x01, m64n_gt, 170, 67, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
{ 0x4754, 0x4754, 0x07, 0x02, m64n_gt, 200, 67, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
{ 0x4755, 0x4755, 0x00, 0x00, m64n_gtb, 200, 67, 67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
{ 0x4756, 0x4756, 0x00, 0x00, m64n_iic_p, 230, 83, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
{ 0x4757, 0x4757, 0x00, 0x00, m64n_iic_a, 230, 83, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
{ 0x475a, 0x475a, 0x00, 0x00, m64n_iic_a, 230, 83, 83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
/* Mach64 LT */
{ 0x4c54, 0x4c54, 0x00, 0x00, m64n_lt, 135, 63, 63, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP },
{ 0x4c47, 0x4c47, 0x00, 0x00, m64n_ltg, 230, 63, 63, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_LT_SLEEP | M64F_G3_PB_1024x768 },
/* Mach64 GTC (3D RAGE PRO) */
{ 0x4742, 0x4742, 0x00, 0x00, m64n_gtc_ba, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
{ 0x4744, 0x4744, 0x00, 0x00, m64n_gtc_ba1, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
{ 0x4749, 0x4749, 0x00, 0x00, m64n_gtc_bp, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_MAGIC_VRAM_SIZE },
{ 0x4750, 0x4750, 0x00, 0x00, m64n_gtc_pp, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
{ 0x4751, 0x4751, 0x00, 0x00, m64n_gtc_ppl, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
/* 3D RAGE XL PCI-66/BGA */
{ 0x474f, 0x474f, 0x00, 0x00, m64n_xl_66, 230, 83, 63, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_XL_DLL | M64F_MFB_TIMES_4 },
/* 3D RAGE XL PCI-33/BGA */
{ 0x4752, 0x4752, 0x00, 0x00, m64n_xl_33, 230, 83, 63, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_XL_DLL | M64F_MFB_TIMES_4 },
/* Mach64 LT PRO */
{ 0x4c42, 0x4c42, 0x00, 0x00, m64n_ltp_a, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP },
{ 0x4c44, 0x4c44, 0x00, 0x00, m64n_ltp_p, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP },
{ 0x4c49, 0x4c49, 0x00, 0x00, m64n_ltp_p, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_EXTRA_BRIGHT | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 },
{ 0x4c50, 0x4c50, 0x00, 0x00, m64n_ltp_p, 230, 100, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP },
/* 3D RAGE Mobility */
{ 0x4c4d, 0x4c4d, 0x00, 0x00, m64n_mob_p, 230, 50, 50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS },
{ 0x4c4e, 0x4c4e, 0x00, 0x00, m64n_mob_a, 230, 50, 50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS },
#endif /* CONFIG_FB_ATY_CT */
};
static char ram_dram[] __initdata = "DRAM";
......@@ -1003,7 +938,10 @@ struct atyclk {
u32 ref_clk_per;
u8 pll_ref_div;
u8 mclk_fb_div;
u8 sclk_fb_div;
u8 mclk_post_div; /* 1,2,3,4,8 */
u8 mclk_fb_mult; /* 2 or 4 */
u8 xclk_post_div; /* 1,2,3,4,8 */
u8 vclk_fb_div;
u8 vclk_post_div; /* 1,2,3,4,6,8,12 */
u32 dsp_xclks_per_row; /* 0-16383 */
......@@ -1051,14 +989,17 @@ static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
clk.ref_clk_per = par->ref_clk_per;
clk.pll_ref_div = pll->ct.pll_ref_div;
clk.mclk_fb_div = pll->ct.mclk_fb_div;
clk.sclk_fb_div = pll->ct.sclk_fb_div;
clk.mclk_post_div = pll->ct.mclk_post_div_real;
clk.mclk_fb_mult = pll->ct.mclk_fb_mult;
clk.xclk_post_div = pll->ct.xclk_post_div_real;
clk.vclk_fb_div = pll->ct.vclk_fb_div;
clk.vclk_post_div = pll->ct.vclk_post_div_real;
clk.dsp_xclks_per_row = dsp_config & 0x3fff;
clk.dsp_loop_latency = (dsp_config >> 16) & 0xf;
clk.dsp_precision = (dsp_config >> 20) & 7;
clk.dsp_on = dsp_on_off & 0x7ff;
clk.dsp_off = (dsp_on_off >> 16) & 0x7ff;
clk.dsp_off = dsp_on_off & 0x7ff;
clk.dsp_on = (dsp_on_off >> 16) & 0x7ff;
if (copy_to_user
((struct atyclk *) arg, &clk, sizeof(clk)))
return -EFAULT;
......@@ -1075,19 +1016,18 @@ static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
par->ref_clk_per = clk.ref_clk_per;
pll->ct.pll_ref_div = clk.pll_ref_div;
pll->ct.mclk_fb_div = clk.mclk_fb_div;
pll->ct.sclk_fb_div = clk.sclk_fb_div;
pll->ct.mclk_post_div_real = clk.mclk_post_div;
pll->ct.mclk_fb_mult = clk.mclk_fb_mult;
pll->ct.xclk_post_div_real = clk.xclk_post_div;
pll->ct.vclk_fb_div = clk.vclk_fb_div;
pll->ct.vclk_post_div_real = clk.vclk_post_div;
pll->ct.dsp_config =
(clk.
dsp_xclks_per_row & 0x3fff) | ((clk.
dsp_loop_latency
& 0xf) << 16)
pll->ct.dsp_config = (clk.dsp_xclks_per_row & 0x3fff) |
((clk.dsp_loop_latency & 0xf)<<16)|
((clk.dsp_precision & 7)<<20);
| ((clk.dsp_precision & 7) << 20);
pll->ct.dsp_on_off =
(clk.
dsp_on & 0x7ff) | ((clk.
dsp_off & 0x7ff) << 16);
pll->ct.dsp_on_off = (clk.dsp_off & 0x7ff) |
((clk.dsp_on & 0x7ff)<<16);
aty_calc_pll_ct(info, &pll->ct);
aty_set_pll_ct(info, pll);
} else
......@@ -1252,8 +1192,6 @@ static void atyfb_palette(int enter)
}
#endif /* __sparc__ */
#ifdef CONFIG_PMAC_PBOOK
static struct fb_info *first_display = NULL;
......@@ -1494,7 +1432,32 @@ static struct backlight_controller aty_backlight_controller = {
};
#endif /* CONFIG_PMAC_BACKLIGHT */
static void __init aty_calc_mem_refresh(struct atyfb_par *par, u16 id, int xclk)
{
const int ragepro_tbl[] = {
44, 50, 55, 66, 75, 80, 100
};
const int ragexl_tbl[] = {
50, 66, 75, 83, 90, 95, 100, 105,
110, 115, 120, 125, 133, 143, 166
};
const int *refresh_tbl;
int i, size;
if (IS_XL(id)) {
refresh_tbl = ragexl_tbl;
size = sizeof(ragexl_tbl)/sizeof(int);
} else {
refresh_tbl = ragepro_tbl;
size = sizeof(ragepro_tbl)/sizeof(int);
}
for (i=0; i < size; i++) {
if (xclk < refresh_tbl[i])
break;
}
par->mem_refresh_rate = i;
}
/*
* Initialisation
......@@ -1506,15 +1469,14 @@ static int __init aty_init(struct fb_info *info, const char *name)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
const char *chipname = NULL, *ramname = NULL, *xtal;
int j, pll, mclk, gtb_memsize;
int pll, mclk, xclk, gtb_memsize, j;
struct fb_var_screeninfo var;
u8 pll_ref_div, rev;
u32 chip_id, i;
u16 type;
u8 rev;
#if defined(CONFIG_PPC)
int sense;
#endif
u8 pll_ref_div;
u16 type;
par->aty_cmap_regs =
(struct aty_cmap_regs *) (par->ati_regbase + 0xc0);
......@@ -1528,6 +1490,7 @@ static int __init aty_init(struct fb_info *info, const char *name)
chipname = aty_chips[j].name;
pll = aty_chips[j].pll;
mclk = aty_chips[j].mclk;
xclk = aty_chips[j].xclk;
par->features = aty_chips[j].features;
goto found;
}
......@@ -1604,17 +1567,38 @@ static int __init aty_init(struct fb_info *info, const char *name)
#endif /* CONFIG_FB_ATY_GX */
#ifdef CONFIG_FB_ATY_CT
if (M64_HAS(INTEGRATED)) {
par->bus_type = PCI;
par->ram_type = (aty_ld_le32(CONFIG_STAT0, par) & 0x07);
ramname = aty_ct_ram[par->ram_type];
par->dac_ops = &aty_dac_ct;
par->pll_ops = &aty_pll_ct;
/* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */
if (mclk == 67 && par->ram_type < SDRAM)
mclk = 63;
}
#endif /* CONFIG_FB_ATY_CT */
if (default_pll)
pll = default_pll;
if (default_mclk)
mclk = default_mclk;
if (default_xclk)
xclk = default_xclk;
aty_calc_mem_refresh(par, type, xclk);
par->pll_per = 1000000/pll;
par->mclk_per = 1000000/mclk;
par->xclk_per = 1000000/xclk;
#ifdef CONFIG_FB_ATY_CT
if (M64_HAS(INTEGRATED)) {
par->dac_ops = &aty_dac_ct;
par->pll_ops = &aty_pll_ct;
par->bus_type = PCI;
#ifdef CONFIG_FB_ATY_XL_INIT
if (IS_XL(type))
atyfb_xl_init(info);
#endif
par->ram_type = (aty_ld_le32(CONFIG_STAT0, par) & 0x07);
ramname = aty_ct_ram[par->ram_type];
}
#endif /* CONFIG_FB_ATY_CT */
par->ref_clk_per = 1000000000000ULL / 14318180;
xtal = "14.31818";
if (M64_HAS(GTB_DSP)
......@@ -1724,35 +1708,10 @@ static int __init aty_init(struct fb_info *info, const char *name)
info->fix.accel = FB_ACCEL_ATI_MACH64GT;
}
if (default_pll)
pll = default_pll;
if (default_mclk)
mclk = default_mclk;
printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n",
info->fix.smem_len ==
0x80000 ? 512 : (info->fix.smem_len >> 20),
info->fix.smem_len == 0x80000 ? 'K' : 'M', ramname,
xtal, pll, mclk);
if (mclk < 44)
par->mem_refresh_rate = 0; /* 000 = 10 Mhz - 43 Mhz */
else if (mclk < 50)
par->mem_refresh_rate = 1; /* 001 = 44 Mhz - 49 Mhz */
else if (mclk < 55)
par->mem_refresh_rate = 2; /* 010 = 50 Mhz - 54 Mhz */
else if (mclk < 66)
par->mem_refresh_rate = 3; /* 011 = 55 Mhz - 65 Mhz */
else if (mclk < 75)
par->mem_refresh_rate = 4; /* 100 = 66 Mhz - 74 Mhz */
else if (mclk < 80)
par->mem_refresh_rate = 5; /* 101 = 75 Mhz - 79 Mhz */
else if (mclk < 100)
par->mem_refresh_rate = 6; /* 110 = 80 Mhz - 100 Mhz */
else
par->mem_refresh_rate = 7; /* 111 = 100 Mhz and above */
par->pll_per = 1000000 / pll;
par->mclk_per = 1000000 / mclk;
printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK, %d MHz XCLK\n",
info->fix.smem_len == 0x80000 ? 512 : (info->fix.smem_len >> 20),
info->fix.smem_len == 0x80000 ? 'K' : 'M', ramname, xtal, pll,
mclk, xclk);
#ifdef DEBUG
if (M64_HAS(INTEGRATED)) {
......@@ -2079,7 +2038,7 @@ int __init atyfb_init(void)
j++;
}
if (pdev->device != XL_CHIP_ID) {
if (!IS_XL(pdev->device)) {
/*
* Fix PROMs idea of MEM_CNTL settings...
*/
......@@ -2205,7 +2164,7 @@ int __init atyfb_init(void)
*
* where R is XTALIN (= 14318 or 29498 kHz).
*/
if (pdev->device == XL_CHIP_ID)
if (IS_XL(pdev->device))
R = 29498;
else
R = 14318;
......@@ -2374,14 +2333,13 @@ int __init atyfb_setup(char *options)
} else if (!strncmp(this_opt, "noaccel", 7)) {
noaccel = 1;
} else if (!strncmp(this_opt, "vram:", 5))
default_vram =
simple_strtoul(this_opt + 5, NULL, 0);
default_vram = simple_strtoul(this_opt + 5, NULL, 0);
else if (!strncmp(this_opt, "pll:", 4))
default_pll =
simple_strtoul(this_opt + 4, NULL, 0);
default_pll = simple_strtoul(this_opt + 4, NULL, 0);
else if (!strncmp(this_opt, "mclk:", 5))
default_mclk =
simple_strtoul(this_opt + 5, NULL, 0);
default_mclk = simple_strtoul(this_opt + 5, NULL, 0);
else if (!strncmp(this_opt, "xclk:", 5))
default_xclk = simple_strtoul(this_opt+5, NULL, 0);
#ifdef CONFIG_PPC
else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode =
......
/*
* ATI Mach64 CT/VT/GT/LT Support
*/
#include <linux/fb.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <video/mach64.h>
#include "atyfb.h"
/* FIXME: remove the FAIL definition */
#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
#undef DEBUG
static void aty_st_pll(int offset, u8 val, const struct atyfb_par *par);
static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per,
struct pll_ct *pll);
static int aty_dsp_gt(const struct fb_info *info, u32 bpp, u32 stretch,
static int aty_dsp_gt(const struct fb_info *info, u32 bpp,
struct pll_ct *pll);
static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per,
u32 bpp, u32 stretch, union aty_pll *pll);
u8 bpp, union aty_pll *pll);
static u32 aty_pll_ct_to_var(const struct fb_info *info,
const union aty_pll *pll);
static u8 postdividers[] = {1,2,4,8,3};
static void aty_st_pll(int offset, u8 val, const struct atyfb_par *par)
{
/* write addr byte */
aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, par);
/* write the register value */
aty_st_8(CLOCK_CNTL + 2, val, par);
aty_st_8(CLOCK_CNTL + 1, (offset << 2), par);
}
/* ------------------------------------------------------------------------- */
/*
......@@ -39,52 +27,93 @@ static void aty_st_pll(int offset, u8 val, const struct atyfb_par *par)
*/
static int aty_dsp_gt(const struct fb_info *info, u32 bpp,
u32 width, struct pll_ct *pll)
struct pll_ct *pll)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
u32 dsp_xclks_per_row, dsp_precision, dsp_off, dsp_on;
u32 xclks_per_row, fifo_off, fifo_on, y, page_size;
/* xclocks_per_row<<11 */
xclks_per_row =
(pll->mclk_fb_div * pll->vclk_post_div_real * 64 << 11) /
(pll->vclk_fb_div * pll->xclk_post_div_real * bpp);
#ifdef CONFIG_FB_ATY_GENERIC_LCD
if (width != 0)
xclks_per_row = (xclks_per_row * par->lcd_width) / width;
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;
u32 memcntl, n, t_pfc, t_rp, t_ras, t_rcd, t_crd, t_rcc, t_lat;
#ifdef DEBUG
printk(__FUNCTION__ ": mclk_fb_mult=%d\n", pll->mclk_fb_mult);
#endif
/* (64*xclk/vclk/bpp)<<11 = xclocks_per_row<<11 */
xclks_per_row = ((u32)pll->mclk_fb_mult * (u32)pll->mclk_fb_div *
(u32)pll->vclk_post_div_real * 64) << 11;
xclks_per_row /=
(2 * (u32)pll->vclk_fb_div * (u32)pll->xclk_post_div_real * bpp);
if (xclks_per_row < (1 << 11))
FAIL("Dotclock to high");
printk("Dotclock too high\n");
if (M64_HAS(FIFO_24)) {
fifo_size = 24;
dsp_loop_latency = 0;
} else {
fifo_size = 32;
dsp_loop_latency = 2;
}
dsp_precision = 0;
y = (xclks_per_row * par->fifo_size) >> 11;
y = (xclks_per_row * fifo_size) >> 11;
while (y) {
y >>= 1;
dsp_precision++;
}
dsp_precision -= 5;
/* fifo_off<<6 */
fifo_off = ((xclks_per_row * (par->fifo_size - 1)) >> 5) + (3 << 6);
fifo_off = ((xclks_per_row * (fifo_size - 1)) >> 5); // + (3 << 6);
if (info->fix.smem_len > 1 * 1024 * 1024) {
switch (par->ram_type) {
case WRAM:
/* >1 MB SDRAM */
dsp_loop_latency += 9;
n = 4;
break;
case SDRAM:
case SGRAM:
/* >1 MB SDRAM */
dsp_loop_latency += 8;
n = 2;
break;
default:
/* >1 MB DRAM */
dsp_loop_latency += 6;
n = 3;
break;
}
} else {
if (par->ram_type >= SDRAM) {
/* <2 MB SDRAM */
dsp_loop_latency += 9;
n = 2;
} else {
/* <2 MB DRAM */
dsp_loop_latency += 8;
n = 3;
}
}
memcntl = aty_ld_le32(MEM_CNTL, par);
t_rcd = ((memcntl >> 10) & 0x03) + 1;
t_crd = ((memcntl >> 12) & 0x01);
t_rp = ((memcntl >> 8) & 0x03) + 1;
t_ras = ((memcntl >> 16) & 0x07) + 1;
t_lat = (memcntl >> 4) & 0x03;
t_pfc = t_rp + t_rcd + t_crd;
t_rcc = max(t_rp + t_ras, t_pfc + n);
page_size = par->page_size;
#ifdef CONFIG_FB_ATY_GENERIC_LCD
if (width != 0)
page_size = (page_size * par->lcd_width) / width;
#endif
/* fifo_on<<6 */
if (xclks_per_row >= (page_size << 11))
fifo_on =
((2 * page_size + 1) << 6) + (xclks_per_row >> 5);
else
fifo_on = (3 * page_size + 2) << 6;
fifo_on = (2 * t_rcc + t_pfc + n - 1) << 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) |
((par->dsp_loop_latency & 0xf) << 16) | ((dsp_precision & 7) << 20);
pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff) << 16);
((dsp_loop_latency & 0xf) << 16) | ((dsp_precision & 7) << 20);
pll->dsp_on_off = (dsp_off & 0x7ff) | ((dsp_on & 0x7ff) << 16);
return 0;
}
......@@ -92,41 +121,170 @@ static int aty_valid_pll_ct(const struct fb_info *info, u32 vclk_per,
struct pll_ct *pll)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
#ifdef DEBUG
int pllmclk, pllsclk;
#endif
u32 q, x; /* x is a workaround for sparc64-linux-gcc */
x = x; /* x is a workaround for sparc64-linux-gcc */
pll->pll_ref_div = par->pll_per * 2 * 255 / par->ref_clk_per;
/* FIXME: use the VTB/GTB /3 post divider if it's better suited.
* Actually 8*q
*/
q = par->ref_clk_per * pll->pll_ref_div * 4 / par->mclk_per;
if (q < 16 * 8 || q > 255 * 8)
printk(KERN_DEBUG "atyfb: mclk out of range");
else if (q < 32 * 8)
pll->mclk_post_div_real = 8;
else if (q < 64 * 8)
pll->mclk_post_div_real = 4;
else if (q < 128 * 8)
pll->mclk_post_div_real = 2;
else
pll->mclk_post_div_real = 1;
pll->mclk_fb_div = q * pll->mclk_post_div_real / 8;
pll->sclk_fb_div = q*pll->mclk_post_div_real/8;
#ifdef DEBUG
pllsclk = (1000000 * 2 * pll->sclk_fb_div) /
(par->ref_clk_per * pll->pll_ref_div);
printk(__FUNCTION__ ": pllsclk=%d MHz, mclk=%d MHz\n",
pllsclk, pllsclk / pll->mclk_post_div_real);
#endif
pll->mclk_fb_mult = M64_HAS(MFB_TIMES_4) ? 4 : 2;
/* actually 8*q */
q = par->ref_clk_per * pll->pll_ref_div * 8 /
(pll->mclk_fb_mult * par->xclk_per);
if (q < 16*8 || q > 255*8)
printk(KERN_DEBUG "mclk out of range");
else if (q < 32*8)
pll->xclk_post_div_real = 8;
else if (q < 64*8)
pll->xclk_post_div_real = 4;
else if (q < 128*8)
pll->xclk_post_div_real = 2;
else
pll->xclk_post_div_real = 1;
pll->mclk_fb_div = q*pll->xclk_post_div_real/8;
#ifdef DEBUG
pllmclk = (1000000 * pll->mclk_fb_mult * pll->mclk_fb_div) /
(par->ref_clk_per * pll->pll_ref_div);
printk(__FUNCTION__ ": pllmclk=%d MHz, xclk=%d MHz\n",
pllmclk, pllmclk / pll->xclk_post_div_real);
#endif
/* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
q = par->ref_clk_per * pll->pll_ref_div * 4 / vclk_per; /* actually 8*q */
if (q < 16*8 || q > 255*8)
FAIL("vclk out of range");
else {
pll->vclk_post_div = 0;
if (q < 128*8)
pll->vclk_post_div++;
if (q < 64*8)
pll->vclk_post_div++;
if (q < 32*8)
pll->vclk_post_div++;
if (q < 16 * 8 || q > 255 * 8)
printk(KERN_DEBUG "vclk out of range");
else if (q < 32 * 8)
pll->vclk_post_div_real = 8;
else if (q < 64 * 8)
pll->vclk_post_div_real = 4;
else if (q < 128 * 8)
pll->vclk_post_div_real = 2;
else
pll->vclk_post_div_real = 1;
pll->vclk_fb_div = q * pll->vclk_post_div_real / 8;
return 0;
}
void aty_calc_pll_ct(const struct fb_info *info, struct pll_ct *pll)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
u8 xpostdiv = 0;
u8 mpostdiv = 0;
u8 vpostdiv = 0;
if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
pll->pll_gen_cntl = 0x64; /* mclk = sclk */
else
pll->pll_gen_cntl = 0xe4; /* mclk = sclk */
switch (pll->mclk_post_div_real) {
case 1:
mpostdiv = 0;
break;
case 2:
mpostdiv = 1;
break;
case 4:
mpostdiv = 2;
break;
case 8:
mpostdiv = 3;
break;
}
pll->spll_cntl2 = mpostdiv << 4; /* sclk == pllsclk / mpostdiv */
switch (pll->xclk_post_div_real) {
case 1:
xpostdiv = 0;
break;
case 2:
xpostdiv = 1;
break;
case 3:
xpostdiv = 4;
break;
case 4:
xpostdiv = 2;
break;
case 8:
xpostdiv = 3;
break;
}
pll->vclk_post_div_real = postdividers[pll->vclk_post_div];
pll->vclk_fb_div = q*pll->vclk_post_div_real/8;
pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
return 0;
if (M64_HAS(MAGIC_POSTDIV))
pll->pll_ext_cntl = 0;
else
pll->pll_ext_cntl = mpostdiv; /* xclk == pllmclk / xpostdiv */
if (pll->mclk_fb_mult == 4)
pll->pll_ext_cntl |= 0x08;
switch (pll->vclk_post_div_real) {
case 2:
vpostdiv = 1;
break;
case 3:
pll->pll_ext_cntl |= 0x10;
case 1:
vpostdiv = 0;
break;
case 6:
pll->pll_ext_cntl |= 0x10;
case 4:
vpostdiv = 2;
break;
case 12:
pll->pll_ext_cntl |= 0x10;
case 8:
vpostdiv = 3;
break;
}
pll->pll_vclk_cntl = 0x03; /* VCLK = PLL_VCLK/VCLKx_POST */
pll->vclk_post_div = vpostdiv;
}
static int aty_var_to_pll_ct(const struct fb_info *info, u32 vclk_per,
u32 bpp, u32 width, union aty_pll *pll)
u8 bpp, union aty_pll *pll)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
int err;
if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct)))
return err;
if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, width, &pll->ct)))
if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct)))
return err;
aty_calc_pll_ct(info, &pll->ct);
return 0;
}
......@@ -146,191 +304,54 @@ static u32 aty_pll_ct_to_var(const struct fb_info *info,
void aty_set_pll_ct(const struct fb_info *info,
const union aty_pll *pll)
{
struct atyfb_par *par = (struct atyfb_par *)info->par;
u8 tmp, tmp2; u32 crtc_gen_cntl;
struct atyfb_par *par = (struct atyfb_par *) info->par;
#ifdef DEBUG
printk("aty_set_pll_ct: setting clock %i for FeedBackDivider %i, ReferenceDivider %i, PostDivider %i\n",
par->clock, pll->ct.vclk_fb_div, par->pll_ref_div, pll->ct.vclk_post_div);
printk(__FUNCTION__ ": about to program:\n"
"refdiv=%d, extcntl=0x%02x, mfbdiv=%d\n"
"spllcntl2=0x%02x, sfbdiv=%d, gencntl=0x%02x\n"
"vclkcntl=0x%02x, vpostdiv=0x%02x, vfbdiv=%d\n"
"clocksel=%d\n",
pll->ct.pll_ref_div, pll->ct.pll_ext_cntl,
pll->ct.mclk_fb_div, pll->ct.spll_cntl2,
pll->ct.sclk_fb_div, pll->ct.pll_gen_cntl,
pll->ct.pll_vclk_cntl, pll->ct.vclk_post_div,
pll->ct.vclk_fb_div, aty_ld_le32(CLOCK_CNTL, info) & 0x03);
#endif
/* Temporarily switch to accelerator mode */
crtc_gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);
if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl | CRTC_EXT_DISP_EN, par);
/* Reset VCLK generator */
aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
/* Set post-divider */
tmp2 = par->clock << 1;
tmp = aty_ld_pll(VCLK_POST_DIV, par);
tmp &= ~(0x03U << tmp2);
tmp |= ((pll->ct.vclk_post_div & 0x03U) << tmp2);
aty_st_pll(VCLK_POST_DIV, tmp, par);
/* Set extended post-divider */
tmp = aty_ld_pll(PLL_EXT_CNTL, par);
tmp &= ~(0x10U << par->clock);
tmp |= (((pll->ct.vclk_post_div >> 2) & 0x10U) << par->clock);
aty_st_pll(PLL_EXT_CNTL, tmp, par);
/* Set feedback divider */
tmp = VCLK0_FB_DIV + par->clock;
aty_st_pll(tmp, (pll->ct.vclk_fb_div & 0xFFU), par);
/* End VCLK generator reset */
aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl & ~(0x04U), par);
/* Reset write bit */
/* ATIAccessMach64PLLReg(pATI, 0, FALSE); */
/* Restore register */
if (!(crtc_gen_cntl & CRTC_EXT_DISP_EN))
aty_st_le32(CRTC_GEN_CNTL, crtc_gen_cntl, par);
if (M64_HAS(GTB_DSP)) {
aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, par);
aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, par);
}
}
static void __init aty_init_pll_ct(struct fb_info *info)
{
struct atyfb_par *par = (struct atyfb_par *)info->par;
struct pll_ct *pll = &par->pll.ct;
u8 pll_ref_div, pll_gen_cntl, pll_ext_cntl;
u8 mpost_div, xpost_div;
u8 sclk_post_div_real, sclk_fb_div, spll_cntl2;
u32 q;
if (M64_HAS(FIFO_24)) {
par->fifo_size = 24;
par->dsp_loop_latency = 0;
} else {
par->fifo_size = 32;
par->dsp_loop_latency = 2;
}
if (info->fix.smem_len > 1*1024*1024) {
if (par->ram_type >= SDRAM) {
/* >1 MB SDRAM */
par->dsp_loop_latency += 8;
par->page_size = 8;
} else {
/* >1 MB DRAM */
par->dsp_loop_latency += 6;
par->page_size = 9;
}
} else {
if (par->ram_type >= SDRAM) {
/* <2 MB SDRAM */
par->dsp_loop_latency += 9;
par->page_size = 10;
} else {
/* <2 MB DRAM */
par->dsp_loop_latency += 8;
par->page_size = 10;
}
}
/* Exit if the user does not want us to play with the clock
rates of her chip. */
if (par->mclk_per == 0) {
u16 mclk_fb_div;
u8 pll_ext_cntl;
pll->pll_ref_div = aty_ld_pll(PLL_REF_DIV, par);
pll_ext_cntl = aty_ld_pll(PLL_EXT_CNTL, par);
pll->xclk_post_div_real = postdividers[pll_ext_cntl & 7];
mclk_fb_div = aty_ld_pll(MCLK_FB_DIV, par);
if (pll_ext_cntl & 8)
mclk_fb_div <<= 1;
pll->mclk_fb_div = mclk_fb_div;
return;
}
pll_ref_div = par->pll_per * 2 * 255 / par->ref_clk_per;
pll->pll_ref_div = pll_ref_div;
/* FIXME: use the VTB/GTB /3 post divider if it's better suited */
q = par->ref_clk_per * pll_ref_div * 4 / par->xclk_per; /* actually 8*q */
if (q < 16*8 || q > 255*8) {
printk(KERN_CRIT "xclk out of range\n");
return;
} else {
xpost_div = 0;
if (q < 128*8)
xpost_div++;
if (q < 64*8)
xpost_div++;
if (q < 32*8)
xpost_div++;
}
pll->xclk_post_div_real = postdividers[xpost_div];
pll->mclk_fb_div = q * pll->xclk_post_div_real / 8;
if (M64_HAS(SDRAM_MAGIC_PLL) && (par->ram_type >= SDRAM))
pll_gen_cntl = 0x04;
else
pll_gen_cntl = 0x84;
aty_st_pll(PLL_REF_DIV, pll->ct.pll_ref_div, par);
if (M64_HAS(MAGIC_POSTDIV))
pll_ext_cntl = 0;
else
pll_ext_cntl = xpost_div;
aty_st_pll(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, par);
aty_st_pll(MCLK_FB_DIV, pll->ct.mclk_fb_div, par); // for XCLK
if (par->mclk_per == par->xclk_per)
pll_gen_cntl |= xpost_div<<4; /* mclk == xclk */
else {
pll_gen_cntl |= 6<<4; /* mclk == sclk*/
aty_st_pll(SPLL_CNTL2, pll->ct.spll_cntl2, par);
aty_st_pll(SCLK_FB_DIV, pll->ct.sclk_fb_div, par); // for MCLK
q = par->ref_clk_per * pll_ref_div * 4 / par->mclk_per; /* actually 8*q */
if (q < 16 * 8 || q > 255 * 8) {
printk(KERN_CRIT "mclk out of range\n");
return;
} else {
mpost_div = 0;
if (q < 128*8)
mpost_div++;
if (q < 64*8)
mpost_div++;
if (q < 32*8)
mpost_div++;
}
sclk_post_div_real = postdividers[mpost_div];
sclk_fb_div = q * sclk_post_div_real / 8;
spll_cntl2 = mpost_div << 4;
/*
This disables the sclk, crashes the computer as reported:
aty_st_pll(SPLL_CNTL2, 3, info);
aty_st_pll(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, par);
aty_st_pll(EXT_VPLL_CNTL, 0, par);
aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, par);
aty_st_pll(VCLK_POST_DIV, pll->ct.vclk_post_div, par);
aty_st_pll(VCLK0_FB_DIV, pll->ct.vclk_fb_div, par);
So it seems the sclk must be enabled before it is used;
so PLL_GEN_CNTL must be programmed *after* the sclk.
*/
#ifdef DEBUG
printk(KERN_INFO "sclk_fb_div: %x spll_cntl2:%x\n",
sclk_fb_div, spll_cntl2);
#endif
aty_st_pll(SPLL_CNTL2, spll_cntl2, par);
aty_st_pll(SCLK_FB_DIV, sclk_fb_div, par);
}
#ifdef DEBUG
printk(KERN_INFO "pll_ref_div: %x pll_gencntl: %x mclk_fb_div: %x pll_ext_cntl: %x\n",
pll_ref_div, pll_gen_cntl, par->mclk_fb_div, pll_ext_cntl);
#endif
aty_st_pll(PLL_REF_DIV, pll_ref_div, par);
aty_st_pll(PLL_GEN_CNTL, pll_gen_cntl, par);
aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, par);
aty_st_pll(PLL_EXT_CNTL, pll_ext_cntl, par);
if (M64_HAS(GTB_DSP)) {
u8 dll_cntl;
if (M64_HAS(XL_DLL))
aty_st_pll(DLL_CNTL, 0x80, par);
dll_cntl = 0x80;
else if (par->ram_type >= SDRAM)
aty_st_pll(DLL_CNTL, 0xa6, par);
dll_cntl = 0xa6;
else
aty_st_pll(DLL_CNTL, 0xa0, par);
dll_cntl = 0xa0;
aty_st_pll(DLL_CNTL, dll_cntl, par);
aty_st_pll(VFC_CNTL, 0x1b, par);
aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, par);
aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, par);
mdelay(10);
aty_st_pll(DLL_CNTL, dll_cntl, par);
mdelay(10);
aty_st_pll(DLL_CNTL, dll_cntl | 0x40, par);
mdelay(10);
aty_st_pll(DLL_CNTL, dll_cntl & ~0x40, par);
}
}
......@@ -340,12 +361,11 @@ static int dummy(void)
}
const struct aty_dac_ops aty_dac_ct = {
.set_dac = (void *)dummy,
.set_dac = (void *) dummy,
};
const struct aty_pll_ops aty_pll_ct = {
.var_to_pll = aty_var_to_pll_ct,
.pll_to_var = aty_pll_ct_to_var,
.set_pll = aty_set_pll_ct,
.init_pll = aty_init_pll_ct
};
/*
* ATI Rage XL Initialization. Support for Xpert98 and Victoria
* PCI cards.
*
* Copyright (C) 2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* stevel@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <video/mach64.h>
#include "atyfb.h"
#define MPLL_GAIN 0xad
#define VPLL_GAIN 0xd5
enum {
VICTORIA = 0,
XPERT98,
NUM_XL_CARDS
};
extern const struct aty_pll_ops aty_pll_ct;
#define DEFAULT_CARD XPERT98
static int xl_card = DEFAULT_CARD;
static const struct xl_card_cfg_t {
int ref_crystal; // 10^4 Hz
int mem_type;
int mem_size;
u32 mem_cntl;
u32 ext_mem_cntl;
u32 mem_addr_config;
u32 bus_cntl;
u32 dac_cntl;
u32 hw_debug;
u32 custom_macro_cntl;
u8 dll2_cntl;
u8 pll_yclk_cntl;
} card_cfg[NUM_XL_CARDS] = {
// VICTORIA
{ 2700, SDRAM, 0x800000,
0x10757A3B, 0x64000C81, 0x00110202, 0x7b33A040,
0x82010102, 0x48803800, 0x005E0179,
0x50, 0x25
},
// XPERT98
{ 1432, WRAM, 0x800000,
0x00165A2B, 0xE0000CF1, 0x00200213, 0x7333A001,
0x8000000A, 0x48833800, 0x007F0779,
0x10, 0x19
}
};
typedef struct {
u8 lcd_reg;
u32 val;
} lcd_tbl_t;
static const lcd_tbl_t lcd_tbl[] = {
{ 0x01, 0x000520C0 },
{ 0x08, 0x02000408 },
{ 0x03, 0x00000F00 },
{ 0x00, 0x00000000 },
{ 0x02, 0x00000000 },
{ 0x04, 0x00000000 },
{ 0x05, 0x00000000 },
{ 0x06, 0x00000000 },
{ 0x33, 0x00000000 },
{ 0x34, 0x00000000 },
{ 0x35, 0x00000000 },
{ 0x36, 0x00000000 },
{ 0x37, 0x00000000 }
};
static inline u32 aty_ld_lcd(u8 lcd_reg, struct atyfb_par *par)
{
aty_st_8(LCD_INDEX, lcd_reg, par);
return aty_ld_le32(LCD_DATA, par);
}
static inline void aty_st_lcd(u8 lcd_reg, u32 val,
struct atyfb_par *par)
{
aty_st_8(LCD_INDEX, lcd_reg, par);
aty_st_le32(LCD_DATA, val, par);
}
static void reset_gui(struct atyfb_par *par)
{
aty_st_8(GEN_TEST_CNTL+1, 0x01, par);
aty_st_8(GEN_TEST_CNTL+1, 0x00, par);
aty_st_8(GEN_TEST_CNTL+1, 0x02, par);
mdelay(5);
}
static void reset_sdram(struct atyfb_par *par)
{
u8 temp;
temp = aty_ld_8(EXT_MEM_CNTL, par);
temp |= 0x02;
aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_SDRAM_RESET = 1b
temp |= 0x08;
aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_CYC_TEST = 10b
temp |= 0x0c;
aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_CYC_TEST = 11b
mdelay(5);
temp &= 0xf3;
aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_CYC_TEST = 00b
temp &= 0xfd;
aty_st_8(EXT_MEM_CNTL, temp, par); // MEM_SDRAM_REST = 0b
mdelay(5);
}
static void init_dll(struct atyfb_par *par)
{
// enable DLL
aty_st_pll(PLL_GEN_CNTL,
aty_ld_pll(PLL_GEN_CNTL, par) & 0x7f,
par);
// reset DLL
aty_st_pll(DLL_CNTL, 0x82, par);
aty_st_pll(DLL_CNTL, 0xE2, par);
mdelay(5);
aty_st_pll(DLL_CNTL, 0x82, par);
mdelay(6);
}
static void reset_clocks(struct atyfb_par *par, struct pll_ct *pll,
int hsync_enb)
{
reset_gui(par);
aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, par);
aty_st_pll(SCLK_FB_DIV, pll->sclk_fb_div, par);
mdelay(15);
init_dll(par);
aty_st_8(GEN_TEST_CNTL+1, 0x00, par);
mdelay(5);
aty_st_8(CRTC_GEN_CNTL+3, 0x04, par);
mdelay(6);
reset_sdram(par);
aty_st_8(CRTC_GEN_CNTL+3,
hsync_enb ? 0x00 : 0x04, par);
aty_st_pll(SPLL_CNTL2, pll->spll_cntl2, par);
aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, par);
aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, par);
}
int atyfb_xl_init(struct fb_info *info)
{
const struct xl_card_cfg_t * card = &card_cfg[xl_card];
struct atyfb_par *par = (struct atyfb_par *) info->par;
union aty_pll pll;
int i, err;
u32 temp;
aty_st_8(CONFIG_STAT0, 0x85, par);
mdelay(10);
/*
* The following needs to be set before the call
* to var_to_pll() below. They'll be re-set again
* to the same values in aty_init().
*/
par->ref_clk_per = 100000000UL/card->ref_crystal;
par->ram_type = card->mem_type;
info->fix.smem_len = card->mem_size;
if (xl_card == VICTORIA) {
// the MCLK, XCLK are 120MHz on victoria card
par->mclk_per = 1000000/120;
par->xclk_per = 1000000/120;
par->features &= ~M64F_MFB_TIMES_4;
}
/*
* Calculate mclk and xclk dividers, etc. The passed
* pixclock and bpp values don't matter yet, the vclk
* isn't programmed until later.
*/
if ((err = aty_pll_ct.var_to_pll(info, 39726, 8, &pll)))
return err;
aty_st_pll(LVDS_CNTL0, 0x00, par);
aty_st_pll(DLL2_CNTL, card->dll2_cntl, par);
aty_st_pll(V2PLL_CNTL, 0x10, par);
aty_st_pll(MPLL_CNTL, MPLL_GAIN, par);
aty_st_pll(VPLL_CNTL, VPLL_GAIN, par);
aty_st_pll(PLL_VCLK_CNTL, 0x00, par);
aty_st_pll(VFC_CNTL, 0x1B, par);
aty_st_pll(PLL_REF_DIV, pll.ct.pll_ref_div, par);
aty_st_pll(PLL_EXT_CNTL, pll.ct.pll_ext_cntl, par);
aty_st_pll(SPLL_CNTL2, 0x03, par);
aty_st_pll(PLL_GEN_CNTL, 0x44, par);
reset_clocks(par, &pll.ct, 0);
mdelay(10);
aty_st_pll(VCLK_POST_DIV, 0x03, par);
aty_st_pll(VCLK0_FB_DIV, 0xDA, par);
aty_st_pll(VCLK_POST_DIV, 0x0F, par);
aty_st_pll(VCLK1_FB_DIV, 0xF5, par);
aty_st_pll(VCLK_POST_DIV, 0x3F, par);
aty_st_pll(PLL_EXT_CNTL, 0x40 | pll.ct.pll_ext_cntl, par);
aty_st_pll(VCLK2_FB_DIV, 0x00, par);
aty_st_pll(VCLK_POST_DIV, 0xFF, par);
aty_st_pll(PLL_EXT_CNTL, 0xC0 | pll.ct.pll_ext_cntl, par);
aty_st_pll(VCLK3_FB_DIV, 0x00, par);
aty_st_8(BUS_CNTL, 0x01, par);
aty_st_le32(BUS_CNTL, card->bus_cntl | 0x08000000, par);
aty_st_le32(CRTC_GEN_CNTL, 0x04000200, par);
aty_st_le16(CONFIG_STAT0, 0x0020, par);
aty_st_le32(MEM_CNTL, 0x10151A33, par);
aty_st_le32(EXT_MEM_CNTL, 0xE0000C01, par);
aty_st_le16(CRTC_GEN_CNTL+2, 0x0000, par);
aty_st_le32(DAC_CNTL, card->dac_cntl, par);
aty_st_le16(GEN_TEST_CNTL, 0x0100, par);
aty_st_le32(CUSTOM_MACRO_CNTL, 0x003C0171, par);
aty_st_le32(MEM_BUF_CNTL, 0x00382848, par);
aty_st_le32(HW_DEBUG, card->hw_debug, par);
aty_st_le16(MEM_ADDR_CONFIG, 0x0000, par);
aty_st_le16(GP_IO+2, 0x0000, par);
aty_st_le16(GEN_TEST_CNTL, 0x0000, par);
aty_st_le16(EXT_DAC_REGS+2, 0x0000, par);
aty_st_le32(CRTC_INT_CNTL, 0x00000000, par);
aty_st_le32(TIMER_CONFIG, 0x00000000, par);
aty_st_le32(0xEC, 0x00000000, par);
aty_st_le32(0xFC, 0x00000000, par);
for (i=0; i<sizeof(lcd_tbl)/sizeof(lcd_tbl_t); i++) {
aty_st_lcd(lcd_tbl[i].lcd_reg, lcd_tbl[i].val, par);
}
aty_st_le16(CONFIG_STAT0, 0x00A4, par);
mdelay(10);
aty_st_8(BUS_CNTL+1, 0xA0, par);
mdelay(10);
reset_clocks(par, &pll.ct, 1);
mdelay(10);
// something about power management
aty_st_8(LCD_INDEX, 0x08, par);
aty_st_8(LCD_DATA, 0x0A, par);
aty_st_8(LCD_INDEX, 0x08, par);
aty_st_8(LCD_DATA+3, 0x02, par);
aty_st_8(LCD_INDEX, 0x08, par);
aty_st_8(LCD_DATA, 0x0B, par);
mdelay(2);
// enable display requests, enable CRTC
aty_st_8(CRTC_GEN_CNTL+3, 0x02, par);
// disable display
aty_st_8(CRTC_GEN_CNTL, 0x40, par);
// disable display requests, disable CRTC
aty_st_8(CRTC_GEN_CNTL+3, 0x04, par);
mdelay(10);
aty_st_pll(PLL_YCLK_CNTL, 0x25, par);
aty_st_le16(CUSTOM_MACRO_CNTL, 0x0179, par);
aty_st_le16(CUSTOM_MACRO_CNTL+2, 0x005E, par);
aty_st_le16(CUSTOM_MACRO_CNTL+2, card->custom_macro_cntl>>16, par);
aty_st_8(CUSTOM_MACRO_CNTL+1,
(card->custom_macro_cntl>>8) & 0xff, par);
aty_st_le32(MEM_ADDR_CONFIG, card->mem_addr_config, par);
aty_st_le32(MEM_CNTL, card->mem_cntl, par);
aty_st_le32(EXT_MEM_CNTL, card->ext_mem_cntl, par);
aty_st_8(CONFIG_STAT0, 0xA0 | card->mem_type, par);
aty_st_pll(PLL_YCLK_CNTL, 0x01, par);
mdelay(15);
aty_st_pll(PLL_YCLK_CNTL, card->pll_yclk_cntl, par);
mdelay(1);
reset_clocks(par, &pll.ct, 0);
mdelay(50);
reset_clocks(par, &pll.ct, 0);
mdelay(50);
// enable extended register block
aty_st_8(BUS_CNTL+3, 0x7B, par);
mdelay(1);
// disable extended register block
aty_st_8(BUS_CNTL+3, 0x73, par);
aty_st_8(CONFIG_STAT0, 0x80 | card->mem_type, par);
// disable display requests, disable CRTC
aty_st_8(CRTC_GEN_CNTL+3, 0x04, par);
// disable mapping registers in VGA aperture
aty_st_8(CONFIG_CNTL, aty_ld_8(CONFIG_CNTL, par) & ~0x04, par);
mdelay(50);
// enable display requests, enable CRTC
aty_st_8(CRTC_GEN_CNTL+3, 0x02, par);
// make GPIO's 14,15,16 all inputs
aty_st_8(LCD_INDEX, 0x07, par);
aty_st_8(LCD_DATA+3, 0x00, par);
// enable the display
aty_st_8(CRTC_GEN_CNTL, 0x00, par);
mdelay(17);
// reset the memory controller
aty_st_8(GEN_TEST_CNTL+1, 0x02, par);
mdelay(15);
aty_st_8(GEN_TEST_CNTL+1, 0x00, par);
mdelay(30);
// enable extended register block
aty_st_8(BUS_CNTL+3,
(u8)(aty_ld_8(BUS_CNTL+3, par) | 0x08),
par);
// set FIFO size to 512 (PIO)
aty_st_le32(GUI_CNTL,
aty_ld_le32(GUI_CNTL, par) & ~0x3,
par);
// enable CRT and disable lcd
aty_st_8(LCD_INDEX, 0x01, par);
temp = aty_ld_le32(LCD_DATA, par);
temp = (temp | 0x01) & ~0x02;
aty_st_le32(LCD_DATA, temp, par);
return 0;
}
......@@ -134,6 +134,8 @@ static void fbcon_free_font(struct display *);
static int fbcon_set_origin(struct vc_data *);
static int cursor_drawn;
#define FBCON_PIXMAPSIZE 8192
#define CURSOR_DRAW_DELAY (1)
/* # VBL ints between cursor state changes */
......@@ -295,6 +297,188 @@ void set_con2fb_map(int unit, int newidx)
take_over_console(&fb_con, unit, unit, fbcon_is_default);
}
/*
* drawing helpers
*/
static inline void sysmove_buf_aligned(u8 *dst, u8 *src, u32 d_pitch,
u32 s_pitch, u32 height,
struct fb_info *info)
{
int i, j;
for (i = height; i--; ) {
for (j = 0; j < s_pitch; j++)
dst[j] = *src++;
dst += d_pitch;
}
}
static inline void iomove_buf_aligned(u8 *dst, u8 *src, u32 d_pitch,
u32 s_pitch, u32 height,
struct fb_info *info)
{
int i, j;
for (i = height; i--; ) {
for (j = 0; j < s_pitch; j++)
info->pixmap.outbuf(*src++, dst+j);
dst += d_pitch;
}
}
static inline void sysmove_buf_unaligned(u8 *dst, u8 *src, u32 d_pitch,
u32 height, u32 mask, u32 shift_high,
u32 shift_low, u32 mod, u32 idx,
struct fb_info *info)
{
int i, j;
for (i = height; i--; ) {
for (j = 0; j < idx; j++) {
dst[j] &= mask;
dst[j] |= *src >> shift_low;
dst[j+1] = *src << shift_high;
src++;
}
dst[idx] &= mask;
dst[idx] |= *src >> shift_low;
if (shift_high < mod)
dst[idx+1] = *src<<shift_high;
src++;
dst += d_pitch;
}
}
static inline void iomove_buf_unaligned(u8 *dst, u8 *src, u32 d_pitch,
u32 height, u32 mask, u32 shift_high,
u32 shift_low,u32 mod, u32 idx,
struct fb_info *info)
{
int i, j;
u8 tmp;
for (i = height; i--; ) {
for (j = 0; j < idx; j++) {
tmp = info->pixmap.inbuf(dst+j);
tmp &= mask;
tmp |= *src >> shift_low;
info->pixmap.outbuf(tmp, dst+j);
info->pixmap.outbuf(*src << shift_high, dst+j+1);
src++;
}
tmp = info->pixmap.inbuf(dst+idx);
tmp &= mask;
tmp |= *src >> shift_low;
info->pixmap.outbuf(tmp, dst+idx);
if (shift_high < mod)
info->pixmap.outbuf(*src<<shift_high, dst+idx+1);
src++;
dst += d_pitch;
}
}
static void putcs_unaligned(struct vc_data *vc, struct display *p,
struct fb_info *info, struct fb_image *image,
int count, const unsigned short *s)
{
unsigned int width = (vc->vc_font.width + 7)/8;
unsigned int cellsize = vc->vc_font.height * width;
unsigned int maxcnt = info->pixmap.size/cellsize;
unsigned int pitch, cnt, k;
unsigned int shift_low = 0, mod = vc->vc_font.width % 8;
unsigned int shift_high = 8, size;
unsigned int buf_align = info->pixmap.buf_align - 1;
unsigned int scan_align = info->pixmap.scan_align - 1;
unsigned int idx = vc->vc_font.width/8;
unsigned short charmask = p->charmask;
u8 mask, *src, *dst, *dst0;
void (*move_data)(u8 *dst, u8 *src, u32 d_pitch, u32 height, u32 mask,
u32 shift_high, u32 shift_low, u32 mod, u32 idx,
struct fb_info *info);
if (info->pixmap.outbuf != NULL)
move_data = iomove_buf_unaligned;
else
move_data = sysmove_buf_unaligned;
while (count) {
if (count > maxcnt)
cnt = k = maxcnt;
else
cnt = k = count;
image->width = vc->vc_font.width * cnt;
pitch = (image->width + 7)/8 + scan_align;
pitch &= ~scan_align;
size = pitch * vc->vc_font.height + buf_align;
size &= ~buf_align;
dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size);
image->data = dst0;
while (k--) {
src = p->fontdata + (scr_readw(s++) & charmask)*
cellsize;
dst = dst0;
mask = (u8) (0xfff << shift_high);
move_data(dst, src, pitch, image->height, mask,
shift_high, shift_low, mod, idx, info);
shift_low += mod;
dst0 += (shift_low >= 8) ? width : width - 1;
shift_low &= 7;
shift_high = 8 - shift_low;
}
info->fbops->fb_imageblit(info, image);
image->dx += cnt * vc->vc_font.width;
count -= cnt;
}
}
static void putcs_aligned(struct vc_data *vc, struct display *p,
struct fb_info *info, struct fb_image *image,
int count, const unsigned short *s)
{
unsigned int width = vc->vc_font.width/8;
unsigned int cellsize = vc->vc_font.height * width;
unsigned int maxcnt = info->pixmap.size/cellsize;
unsigned int scan_align = info->pixmap.scan_align - 1;
unsigned int buf_align = info->pixmap.buf_align - 1;
unsigned int pitch, cnt, size, k;
unsigned short charmask = p->charmask;
void (*move_data)(u8 *dst, u8 *src, u32 s_pitch, u32 d_pitch,
u32 height, struct fb_info *info);
u8 *src, *dst, *dst0;
if (info->pixmap.outbuf != NULL)
move_data = iomove_buf_aligned;
else
move_data = sysmove_buf_aligned;
while (count) {
if (count > maxcnt)
cnt = k = maxcnt;
else
cnt = k = count;
pitch = width * cnt + scan_align;
pitch &= ~scan_align;
size = pitch * vc->vc_font.height + buf_align;
size &= ~buf_align;
image->width = vc->vc_font.width * cnt;
dst0 = info->pixmap.addr + fb_get_buffer_offset(info, size);
image->data = dst0;
while (k--) {
src = p->fontdata + (scr_readw(s++) & charmask)*
cellsize;
dst = dst0;
move_data(dst, src, pitch, width, image->height, info);
dst0 += width;
}
info->fbops->fb_imageblit(info, image);
image->dx += cnt * vc->vc_font.width;
count -= cnt;
}
}
/*
* Accelerated handlers.
*/
......@@ -329,102 +513,65 @@ void accel_clear(struct vc_data *vc, struct display *p, int sy,
info->fbops->fb_fillrect(info, &region);
}
/*
* FIXME: Break up this function, it's becoming too long...
*/
static void accel_putc(struct vc_data *vc, struct display *p,
int c, int ypos, int xpos)
{
struct fb_image image;
struct fb_info *info = p->fb_info;
unsigned short charmask = p->charmask;
unsigned int width = (vc->vc_font.width + 7)/8;
unsigned int size, pitch;
unsigned int scan_align = info->pixmap.scan_align - 1;
unsigned int buf_align = info->pixmap.buf_align - 1;
void (*move_data)(u8 *dst, u8 *src, u32 s_pitch, u32 d_pitch,
u32 height, struct fb_info *info);
u8 *src, *dst;
if (info->pixmap.outbuf != NULL)
move_data = iomove_buf_aligned;
else
move_data = sysmove_buf_aligned;
image.dx = xpos * vc->vc_font.width;
image.dy = ypos * vc->vc_font.height;
image.width = vc->vc_font.width;
image.height = vc->vc_font.height;
image.fg_color = attr_fgcol(p, c);
image.bg_color = attr_bgcol(p, c);
image.depth = 0;
pitch = width + scan_align;
pitch &= ~scan_align;
size = pitch * vc->vc_font.height;
size += buf_align;
size &= ~buf_align;
dst = info->pixmap.addr + fb_get_buffer_offset(info, size);
image.data = dst;
src = p->fontdata + (c & charmask) * vc->vc_font.height * width;
move_data(dst, src, pitch, width, image.height, info);
info->fbops->fb_imageblit(info, &image);
}
void accel_putcs(struct vc_data *vc, struct display *p,
const unsigned short *s, int count, int yy, int xx)
{
unsigned int width = ((vc->vc_font.width + 7) >> 3);
unsigned int cellsize = vc->vc_font.height * width;
unsigned short charmask = p->charmask;
struct fb_info *info = p->fb_info;
unsigned int pitch, cnt, i, j, k;
struct fb_image image;
u8 *src, *dst, *dst0;
u16 c = scr_readw(s);
void *pixmap;
pixmap = kmalloc(cellsize*count, GFP_KERNEL);
if (!pixmap) return;
image.fg_color = attr_fgcol(p, c);
image.bg_color = attr_bgcol(p, c);
image.dx = xx * vc->vc_font.width;
image.dy = yy * vc->vc_font.height;
image.height = vc->vc_font.height;
image.depth = 0;
image.data = pixmap;
if (!(vc->vc_font.width & 7)) {
while (count) {
cnt = k = count;
dst0 = pixmap;
pitch = width * cnt;
image.width = vc->vc_font.width * cnt;
while (k--) {
src = p->fontdata + (scr_readw(s++)&charmask)*
cellsize;
dst = dst0;
for (i = image.height; i--; ) {
for (j = 0; j < width; j++)
dst[j] = *src++;
dst += pitch;
}
dst0 += width;
}
info->fbops->fb_imageblit(info, &image);
image.dx += cnt * vc->vc_font.width;
count -= cnt;
}
} else {
unsigned int shift_low = 0, mod = vc->vc_font.width % 8;
unsigned int shift_high = 8;
unsigned idx = vc->vc_font.width/8;
u8 mask;
while (count) {
cnt = k = count;
dst0 = pixmap;
image.width = vc->vc_font.width * cnt;
pitch = (image.width + 7)/8;
while (k--) {
src = p->fontdata + (scr_readw(s++)&charmask)*
cellsize;
dst = dst0;
mask = (u8) (0xfff << shift_high);
for (i = image.height; i--; ) {
for (j = 0; j < idx; j++) {
dst[j] &= mask;
dst[j] |= *src >> shift_low;
dst[j+1] = *src << shift_high;
src++;
}
dst[idx] &= mask;
dst[idx] |= *src >> shift_low;
if (shift_high < mod)
dst[idx+1] = *src << shift_high;
src++;
dst += pitch;
}
shift_low += mod;
dst0 += (shift_low >= 8) ? width : width - 1;
shift_low &= 7;
shift_high = 8 - shift_low;
}
info->fbops->fb_imageblit(info, &image);
image.dx += cnt * vc->vc_font.width;
count -= cnt;
}
}
if (pixmap)
kfree(pixmap);
if (!(vc->vc_font.width & 7))
putcs_aligned(vc, p, info, &image, count, s);
else
putcs_unaligned(vc, p, info, &image, count, s);
}
void accel_clear_margins(struct vc_data *vc, struct display *p,
......@@ -627,6 +774,18 @@ static const char *fbcon_startup(void)
vc->vc_cols = info->var.xres/vc->vc_font.width;
vc->vc_rows = info->var.yres/vc->vc_font.height;
if (info->pixmap.addr == NULL) {
info->pixmap.addr = kmalloc(FBCON_PIXMAPSIZE, GFP_KERNEL);
if (!info->pixmap.addr)
return NULL;
info->pixmap.size = FBCON_PIXMAPSIZE;
info->pixmap.buf_align = 1;
info->pixmap.scan_align = 1;
info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
info->pixmap.offset = 0;
spin_lock_init(&info->pixmap.lock);
/* We trust the mode the driver supplies. */
if (info->fbops->fb_set_par)
......@@ -1021,10 +1180,6 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
{
struct display *p = &fb_display[vc->vc_num];
struct fb_info *info = p->fb_info;
unsigned short charmask = p->charmask;
unsigned int width = ((vc->vc_font.width + 7) >> 3);
struct fb_image image;
int redraw_cursor = 0;
if (!p->can_soft_blank && console_blanked)
......@@ -1038,16 +1193,7 @@ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
redraw_cursor = 1;
}
image.fg_color = attr_fgcol(p, c);
image.bg_color = attr_bgcol(p, c);
image.dx = xpos * vc->vc_font.width;
image.dy = real_y(p, ypos) * vc->vc_font.height;
image.width = vc->vc_font.width;
image.height = vc->vc_font.height;
image.depth = 1;
image.data = p->fontdata + (c & charmask) * vc->vc_font.height * width;
info->fbops->fb_imageblit(info, &image);
accel_putc(vc, p, c, real_y(p, ypos), xpos);
if (redraw_cursor)
vbl_cursor_cnt = CURSOR_DRAW_DELAY;
......
......@@ -363,6 +363,31 @@ int num_registered_fb;
static int ofonly __initdata = 0;
#endif
/*
* we need to lock this section since fbcon_cursor
* may use fb_imageblit()
*/
u32 fb_get_buffer_offset(struct fb_info *info, u32 size)
{
u32 align = info->pixmap.buf_align - 1;
u32 offset;
spin_lock_irqsave(&info->pixmap.lock,
info->pixmap.lock_flags);
offset = info->pixmap.offset + align;
offset &= ~align;
if (offset + size > info->pixmap.size) {
if (info->fbops->fb_sync &&
info->pixmap.flags & FB_PIXMAP_SYNC)
info->fbops->fb_sync(info);
offset = 0;
}
info->pixmap.offset = offset + size;
spin_unlock_irqrestore(&info->pixmap.lock,
info->pixmap.lock_flags);
return offset;
}
#ifdef CONFIG_LOGO
#include <linux/linux_logo.h>
......@@ -1240,5 +1265,6 @@ EXPORT_SYMBOL(fb_show_logo);
EXPORT_SYMBOL(fb_set_var);
EXPORT_SYMBOL(fb_blank);
EXPORT_SYMBOL(fb_pan_display);
EXPORT_SYMBOL(fb_get_buffer_offset);
MODULE_LICENSE("GPL");
......@@ -17,30 +17,79 @@
#include <asm/uaccess.h>
#include <asm/io.h>
static inline void sysmove_buf(u8 *dst, u8 *src, u32 d_pitch, u32 s_pitch,
u32 height, struct fb_info *info)
{
int i, j;
for (i = height; i--; ) {
for (j = 0; j < s_pitch; j++)
dst[j] = *src++;
dst += d_pitch;
}
}
static inline void iomove_buf(u8 *dst, u8 *src, u32 d_pitch, u32 s_pitch,
u32 height, struct fb_info *info)
{
int i, j;
for (i = height; i--; ) {
for (j = 0; j < s_pitch; j++)
info->pixmap.outbuf(*src++, dst+j);
dst += d_pitch;
}
}
int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
int i, size = ((cursor->image.width + 7) / 8) * cursor->image.height;
static u8 src[64];
struct fb_image image;
static char data[64];
unsigned int i, size, s_pitch, d_pitch;
unsigned dsize = ((cursor->image.width + 7)/8) * cursor->image.height;
unsigned int scan_align = info->pixmap.scan_align - 1;
unsigned int buf_align = info->pixmap.buf_align - 1;
void (*move_data)(u8 *dst, u8 *src, u32 s_pitch,
u32 d_pitch, u32 height,
struct fb_info *info);
u8 *dst;
if (info->pixmap.outbuf != NULL)
move_data = iomove_buf;
else
move_data = sysmove_buf;
s_pitch = (cursor->image.width + 7)/8;
d_pitch = (s_pitch + scan_align) & ~scan_align;
size = d_pitch * cursor->image.height + buf_align;
size &= ~buf_align;
dst = info->pixmap.addr + fb_get_buffer_offset(info, size);
image.data = dst;
if (cursor->enable) {
switch (cursor->rop) {
case ROP_XOR:
for (i = 0; i < size; i++)
data[i] = (cursor->image.data[i] &
for (i = 0; i < dsize; i++) {
src[i] = (cursor->image.data[i] &
cursor->mask[i]) ^
cursor->dest[i];
cursor->dest[i];
}
break;
case ROP_COPY:
default:
for (i = 0; i < size; i++)
data[i] =
cursor->image.data[i] & cursor->mask[i];
for (i = 0; i < dsize; i++) {
src[i] = cursor->image.data[i] &
cursor->mask[i];
}
break;
}
} else
memcpy(data, cursor->dest, size);
move_data(dst, src, d_pitch, s_pitch, cursor->image.height,
info);
} else {
move_data(dst, cursor->dest, s_pitch, d_pitch,
cursor->image.height, info);
}
image.bg_color = cursor->image.bg_color;
image.fg_color = cursor->image.fg_color;
image.dx = cursor->image.dx;
......@@ -48,7 +97,6 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
image.width = cursor->image.width;
image.height = cursor->image.height;
image.depth = cursor->image.depth;
image.data = data;
if (info->fbops->fb_imageblit)
info->fbops->fb_imageblit(info, &image);
......
......@@ -325,6 +325,23 @@ struct fb_cursor {
struct fb_image image; /* Cursor image */
};
#define FB_PIXMAP_DEFAULT 1 /* used internally by fbcon */
#define FB_PIXMAP_SYSTEM 2 /* memory is in system RAM */
#define FB_PIXMAP_IO 4 /* memory is iomapped */
#define FB_PIXMAP_SYNC 256 /* set if GPU can DMA */
struct fb_pixmap {
__u8 *addr; /* pointer to memory */
__u32 size; /* size of buffer in bytes */
__u32 offset; /* current offset to buffer */
__u32 buf_align; /* byte alignment of each bitmap */
__u32 scan_align; /* alignment per scanline */
__u32 flags; /* see FB_PIXMAP_* */
void (*outbuf)(u8 dst, u8 *addr); /* access methods */
u8 (*inbuf) (u8 *addr);
unsigned long lock_flags; /* flags for locking */
spinlock_t lock; /* spinlock */
};
#ifdef __KERNEL__
#include <linux/fs.h>
......@@ -390,6 +407,7 @@ struct fb_info {
struct fb_monspecs monspecs; /* Current Monitor specs */
struct fb_cursor cursor; /* Current cursor */
struct fb_cmap cmap; /* Current cmap */
struct fb_pixmap pixmap; /* Current pixmap */
struct fb_ops *fbops;
char *screen_base; /* Virtual address */
struct vc_data *display_fg; /* Console visible on this display */
......@@ -464,6 +482,7 @@ extern int register_framebuffer(struct fb_info *fb_info);
extern int unregister_framebuffer(struct fb_info *fb_info);
extern int fb_prepare_logo(struct fb_info *fb_info);
extern int fb_show_logo(struct fb_info *fb_info);
extern u32 fb_get_buffer_offset(struct fb_info *info, u32 size);
extern struct fb_info *registered_fb[FB_MAX];
extern int num_registered_fb;
......
......@@ -849,7 +849,19 @@
#define LI_CHIP_ID 0x4c49 /* RAGE LT PRO */
#define LP_CHIP_ID 0x4c50 /* RAGE LT PRO */
#define LT_CHIP_ID 0x4c54 /* RAGE LT */
#define XL_CHIP_ID 0x4752 /* RAGE (XL) */
/* mach64CT family / (Rage XL) class */
#define GR_CHIP_ID 0x4752 /* RAGE XL, BGA, PCI33 */
#define GS_CHIP_ID 0x4753 /* RAGE XL, PQFP, PCI33 */
#define GM_CHIP_ID 0x474d /* RAGE XL, BGA, AGP 1x,2x */
#define GN_CHIP_ID 0x474e /* RAGE XL, PQFP,AGP 1x,2x */
#define GO_CHIP_ID 0x474f /* RAGE XL, BGA, PCI66 */
#define GL_CHIP_ID 0x474c /* RAGE XL, PQFP, PCI66 */
#define IS_XL(id) ((id)==GR_CHIP_ID || (id)==GS_CHIP_ID || \
(id)==GM_CHIP_ID || (id)==GN_CHIP_ID || \
(id)==GO_CHIP_ID || (id)==GL_CHIP_ID)
#define GT_CHIP_ID 0x4754 /* RAGE (GT) */
#define GU_CHIP_ID 0x4755 /* RAGE II/II+ (GTB) */
#define GV_CHIP_ID 0x4756 /* RAGE IIC, PCI */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment