/* Rage 128 chipset driver */ #include #include #include #include #include #include #include "vga.h" #include "libvga.h" #include "driver.h" #include "timing.h" #include "vgaregs.h" #include "interface.h" #include "accel.h" #include "vgapci.h" #include "r128_reg.h" typedef unsigned int CARD32; typedef unsigned short CARD16; typedef int Bool; static int r128_ramtype; static int BusCntl, CRTOnly, HasPanelRegs; typedef struct { CARD16 reference_freq; CARD16 reference_div; CARD32 min_pll_freq; CARD32 max_pll_freq; CARD16 xclk; } R128PLLRec, *R128PLLPtr; typedef struct { /* Common registers */ CARD32 ovr_clr; CARD32 ovr_wid_left_right; CARD32 ovr_wid_top_bottom; CARD32 ov0_scale_cntl; CARD32 mpp_tb_config; CARD32 mpp_gp_config; CARD32 subpic_cntl; CARD32 viph_control; CARD32 i2c_cntl_1; CARD32 gen_int_cntl; CARD32 cap0_trig_cntl; CARD32 cap1_trig_cntl; CARD32 bus_cntl; CARD32 config_cntl; CARD32 mem_vga_wp_sel; CARD32 mem_vga_rp_sel; /* Other registers to save for VT switches */ CARD32 dp_datatype; CARD32 gen_reset_cntl; CARD32 clock_cntl_index; CARD32 amcgpio_en_reg; CARD32 amcgpio_mask; /* CRTC registers */ CARD32 crtc_gen_cntl; CARD32 crtc_ext_cntl; CARD32 dac_cntl; CARD32 crtc_h_total_disp; CARD32 crtc_h_sync_strt_wid; CARD32 crtc_v_total_disp; CARD32 crtc_v_sync_strt_wid; CARD32 crtc_offset; CARD32 crtc_offset_cntl; CARD32 crtc_pitch; /* CRTC2 registers */ CARD32 crtc2_gen_cntl; /* Flat panel registers */ CARD32 fp_crtc_h_total_disp; CARD32 fp_crtc_v_total_disp; CARD32 fp_gen_cntl; CARD32 fp_h_sync_strt_wid; CARD32 fp_horz_stretch; CARD32 fp_panel_cntl; CARD32 fp_v_sync_strt_wid; CARD32 fp_vert_stretch; CARD32 lvds_gen_cntl; CARD32 tmds_crc; /* Computed values for PLL */ CARD32 dot_clock_freq; CARD32 pll_output_freq; int feedback_div; int post_div; /* PLL registers */ CARD32 ppll_ref_div; CARD32 ppll_div_3; CARD32 htotal_cntl; /* DDA register */ CARD32 dda_config; CARD32 dda_on_off; CARD32 vga_dda_config; CARD32 vga_dda_on_off; /* Pallet */ Bool palette_valid; CARD32 palette[256]; } R128SaveRec, *R128SavePtr; typedef struct { /* All values in XCLKS */ int ML; /* Memory Read Latency */ int MB; /* Memory Burst Length */ int Trcd; /* RAS to CAS delay */ int Trp; /* RAS percentage */ int Twr; /* Write Recovery */ int CL; /* CAS Latency */ int Tr2w; /* Read to Write Delay */ int Rloop; /* Loop Latency */ int Rloop_fudge; /* Add to ML to get Rloop */ char *name; } R128RAMRec, *R128RAMPtr; #define R128_TOTAL_REGS (VGA_TOTAL_REGS + sizeof(R128SaveRec)) static int R128MinBits(int val) { int bits; if (!val) return 1; for (bits = 0; val; val >>= 1, ++bits); return bits; } static int R128Div(int n, int d) { return (n + (d / 2)) / d; } static R128PLLRec pll; static R128RAMRec ram[] = { /* Memory Specifications From RAGE 128 Software Development Manual (Technical Reference Manual P/N SDK-G04000 Rev 0.01), page 3-21. */ { 4, 4, 3, 3, 1, 3, 1, 16, 12, "128-bit SDR SGRAM 1:1" }, { 4, 8, 3, 3, 1, 3, 1, 17, 13, "64-bit SDR SGRAM 1:1" }, { 4, 4, 1, 2, 1, 2, 1, 16, 12, "64-bit SDR SGRAM 2:1" }, { 4, 4, 3, 3, 2, 3, 1, 16, 12, "64-bit DDR SGRAM" }, }; unsigned R128INPLL(int addr) { OUTREG8(R128_CLOCK_CNTL_INDEX, addr & 0x1f); return INREG(R128_CLOCK_CNTL_DATA); } void R128WaitForVerticalSync(void) { int i; OUTREG(R128_GEN_INT_STATUS, R128_VSYNC_INT_AK); for (i = 0; i < R128_TIMEOUT; i++) { if (INREG(R128_GEN_INT_STATUS) & R128_VSYNC_INT) break; } } /* Blank screen. */ static void R128Blank(void) { OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS); } /* Unblank screen. */ static void R128Unblank(void) { OUTREGP(R128_CRTC_EXT_CNTL, 0, ~R128_CRTC_DISPLAY_DIS); } static void R128RestoreCommonRegisters(R128SavePtr restore) { OUTREG(R128_OVR_CLR, restore->ovr_clr); OUTREG(R128_OVR_WID_LEFT_RIGHT, restore->ovr_wid_left_right); OUTREG(R128_OVR_WID_TOP_BOTTOM, restore->ovr_wid_top_bottom); OUTREG(R128_OV0_SCALE_CNTL, restore->ov0_scale_cntl); OUTREG(R128_MPP_TB_CONFIG, restore->mpp_tb_config ); OUTREG(R128_MPP_GP_CONFIG, restore->mpp_gp_config ); OUTREG(R128_SUBPIC_CNTL, restore->subpic_cntl); OUTREG(R128_VIPH_CONTROL, restore->viph_control); OUTREG(R128_I2C_CNTL_1, restore->i2c_cntl_1); OUTREG(R128_GEN_INT_CNTL, restore->gen_int_cntl); OUTREG(R128_CAP0_TRIG_CNTL, restore->cap0_trig_cntl); OUTREG(R128_CAP1_TRIG_CNTL, restore->cap1_trig_cntl); OUTREG(R128_BUS_CNTL, restore->bus_cntl); OUTREG(R128_CONFIG_CNTL, restore->config_cntl); OUTREG(R128_MEM_VGA_WP_SEL, restore->mem_vga_wp_sel); OUTREG(R128_MEM_VGA_RP_SEL, restore->mem_vga_rp_sel); } /* Write CRTC registers. */ static void R128RestoreCrtcRegisters(R128SavePtr restore) { OUTREG(R128_CRTC_GEN_CNTL, restore->crtc_gen_cntl); OUTREGP(R128_CRTC_EXT_CNTL, restore->crtc_ext_cntl, R128_CRTC_VSYNC_DIS | R128_CRTC_HSYNC_DIS | R128_CRTC_DISPLAY_DIS); OUTREGP(R128_DAC_CNTL, restore->dac_cntl, R128_DAC_RANGE_CNTL | R128_DAC_BLANKING); OUTREG(R128_CRTC_H_TOTAL_DISP, restore->crtc_h_total_disp); OUTREG(R128_CRTC_H_SYNC_STRT_WID, restore->crtc_h_sync_strt_wid); OUTREG(R128_CRTC_V_TOTAL_DISP, restore->crtc_v_total_disp); OUTREG(R128_CRTC_V_SYNC_STRT_WID, restore->crtc_v_sync_strt_wid); OUTREG(R128_CRTC_OFFSET, restore->crtc_offset); OUTREG(R128_CRTC_OFFSET_CNTL, restore->crtc_offset_cntl); OUTREG(R128_CRTC_PITCH, restore->crtc_pitch); } /* Write flat panel registers */ static void R128RestoreFPRegisters(R128SavePtr restore) { CARD32 tmp; OUTREG(R128_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl); OUTREG(R128_FP_CRTC_H_TOTAL_DISP, restore->fp_crtc_h_total_disp); OUTREG(R128_FP_CRTC_V_TOTAL_DISP, restore->fp_crtc_v_total_disp); OUTREG(R128_FP_GEN_CNTL, restore->fp_gen_cntl); OUTREG(R128_FP_H_SYNC_STRT_WID, restore->fp_h_sync_strt_wid); OUTREG(R128_FP_HORZ_STRETCH, restore->fp_horz_stretch); OUTREG(R128_FP_PANEL_CNTL, restore->fp_panel_cntl); OUTREG(R128_FP_V_SYNC_STRT_WID, restore->fp_v_sync_strt_wid); OUTREG(R128_FP_VERT_STRETCH, restore->fp_vert_stretch); OUTREG(R128_TMDS_CRC, restore->tmds_crc); tmp = INREG(R128_LVDS_GEN_CNTL); if ((tmp & (R128_LVDS_ON | R128_LVDS_BLON)) == (restore->lvds_gen_cntl & (R128_LVDS_ON | R128_LVDS_BLON))) { OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl); } else { if (restore->lvds_gen_cntl & (R128_LVDS_ON | R128_LVDS_BLON)) { OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl & ~R128_LVDS_BLON); // usleep(R128PTR(pScrn)->PanelPwrDly * 1000); OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl); } else { OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl | R128_LVDS_BLON); // usleep(R128PTR(pScrn)->PanelPwrDly * 1000); OUTREG(R128_LVDS_GEN_CNTL, restore->lvds_gen_cntl); } } } static void R128PLLWaitForReadUpdateComplete(void) { while (INPLL(R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R); } static void R128PLLWriteUpdate(void) { OUTPLLP(R128_PPLL_REF_DIV, R128_PPLL_ATOMIC_UPDATE_W, 0xffff); } /* Write PLL registers. */ static void R128RestorePLLRegisters(R128SavePtr restore) { OUTREGP(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, 0xffff); OUTPLLP( R128_PPLL_CNTL, R128_PPLL_RESET | R128_PPLL_ATOMIC_UPDATE_EN, 0xffff); R128PLLWaitForReadUpdateComplete(); OUTPLLP(R128_PPLL_REF_DIV, restore->ppll_ref_div, ~R128_PPLL_REF_DIV_MASK); R128PLLWriteUpdate(); R128PLLWaitForReadUpdateComplete(); OUTPLLP(R128_PPLL_DIV_3, restore->ppll_div_3, ~R128_PPLL_FB3_DIV_MASK); R128PLLWriteUpdate(); OUTPLLP(R128_PPLL_DIV_3, restore->ppll_div_3, ~R128_PPLL_POST3_DIV_MASK); R128PLLWriteUpdate(); R128PLLWaitForReadUpdateComplete(); OUTPLL(R128_HTOTAL_CNTL, restore->htotal_cntl); R128PLLWriteUpdate(); OUTPLLP( R128_PPLL_CNTL, 0, ~R128_PPLL_RESET); } /* Write DDA registers. */ static void R128RestoreDDARegisters(R128SavePtr restore) { OUTREG(R128_DDA_CONFIG, restore->dda_config); OUTREG(R128_DDA_ON_OFF, restore->dda_on_off); // OUTREG(R128_VGA_DDA_CONFIG, restore->vga_dda_config); // OUTREG(R128_VGA_DDA_ON_OFF, restore->vga_dda_on_off); } /* Write palette data. */ static void R128RestorePalette( R128SavePtr restore) { int i; if (!restore->palette_valid) return; /* Select palette 0 (main CRTC) if using FP-enabled chip */ // if (info->HasPanelRegs) PAL_SELECT(0); OUTPAL_START(0); for (i = 0; i < 256; i++) OUTPAL_NEXT_CARD32(restore->palette[i]); } /* Write out state to define a new video mode. */ static void R128RestoreMode(R128SavePtr restore) { R128Blank(); OUTREG(R128_AMCGPIO_MASK, restore->amcgpio_mask); OUTREG(R128_AMCGPIO_EN_REG, restore->amcgpio_en_reg); OUTREG(R128_CLOCK_CNTL_INDEX, restore->clock_cntl_index); // OUTREG(R128_GEN_RESET_CNTL, restore->gen_reset_cntl); OUTREG(R128_DP_DATATYPE, restore->dp_datatype); R128RestoreCommonRegisters( restore); R128RestoreCrtcRegisters( restore); // if (info->HasPanelRegs) // R128RestoreFPRegisters(restore); // if (!info->HasPanelRegs || info->CRTOnly) R128RestorePLLRegisters(restore); R128RestoreDDARegisters(restore); R128RestorePalette(restore); } /* Read common registers. */ static void R128SaveCommonRegisters(R128SavePtr save) { save->ovr_clr = INREG(R128_OVR_CLR); save->ovr_wid_left_right = INREG(R128_OVR_WID_LEFT_RIGHT); save->ovr_wid_top_bottom = INREG(R128_OVR_WID_TOP_BOTTOM); save->ov0_scale_cntl = INREG(R128_OV0_SCALE_CNTL); save->mpp_tb_config = INREG(R128_MPP_TB_CONFIG); save->mpp_gp_config = INREG(R128_MPP_GP_CONFIG); save->subpic_cntl = INREG(R128_SUBPIC_CNTL); save->viph_control = INREG(R128_VIPH_CONTROL); save->i2c_cntl_1 = INREG(R128_I2C_CNTL_1); save->gen_int_cntl = INREG(R128_GEN_INT_CNTL); save->cap0_trig_cntl = INREG(R128_CAP0_TRIG_CNTL); save->cap1_trig_cntl = INREG(R128_CAP1_TRIG_CNTL); save->bus_cntl = INREG(R128_BUS_CNTL); save->config_cntl = INREG(R128_CONFIG_CNTL); save->mem_vga_wp_sel = INREG(R128_MEM_VGA_WP_SEL); save->mem_vga_rp_sel = INREG(R128_MEM_VGA_RP_SEL); } /* Read CRTC registers. */ static void R128SaveCrtcRegisters(R128SavePtr save) { save->crtc_gen_cntl = INREG(R128_CRTC_GEN_CNTL); save->crtc_ext_cntl = INREG(R128_CRTC_EXT_CNTL); save->dac_cntl = INREG(R128_DAC_CNTL); save->crtc_h_total_disp = INREG(R128_CRTC_H_TOTAL_DISP); save->crtc_h_sync_strt_wid = INREG(R128_CRTC_H_SYNC_STRT_WID); save->crtc_v_total_disp = INREG(R128_CRTC_V_TOTAL_DISP); save->crtc_v_sync_strt_wid = INREG(R128_CRTC_V_SYNC_STRT_WID); save->crtc_offset = INREG(R128_CRTC_OFFSET); save->crtc_offset_cntl = INREG(R128_CRTC_OFFSET_CNTL); save->crtc_pitch = INREG(R128_CRTC_PITCH); } /* Read flat panel registers */ static void R128SaveFPRegisters(R128SavePtr save) { save->crtc2_gen_cntl = INREG(R128_CRTC2_GEN_CNTL); save->fp_crtc_h_total_disp = INREG(R128_FP_CRTC_H_TOTAL_DISP); save->fp_crtc_v_total_disp = INREG(R128_FP_CRTC_V_TOTAL_DISP); save->fp_gen_cntl = INREG(R128_FP_GEN_CNTL); save->fp_h_sync_strt_wid = INREG(R128_FP_H_SYNC_STRT_WID); save->fp_horz_stretch = INREG(R128_FP_HORZ_STRETCH); save->fp_panel_cntl = INREG(R128_FP_PANEL_CNTL); save->fp_v_sync_strt_wid = INREG(R128_FP_V_SYNC_STRT_WID); save->fp_vert_stretch = INREG(R128_FP_VERT_STRETCH); save->lvds_gen_cntl = INREG(R128_LVDS_GEN_CNTL); save->tmds_crc = INREG(R128_TMDS_CRC); } /* Read PLL registers. */ static void R128SavePLLRegisters(R128SavePtr save) { save->ppll_ref_div = INPLL(R128_PPLL_REF_DIV); save->ppll_div_3 = INPLL(R128_PPLL_DIV_3); save->htotal_cntl = INPLL(R128_HTOTAL_CNTL); } /* Read DDA registers. */ static void R128SaveDDARegisters(R128SavePtr save) { save->dda_config = INREG(R128_DDA_CONFIG); save->dda_on_off = INREG(R128_DDA_ON_OFF); save->vga_dda_config = INREG(R128_VGA_DDA_CONFIG); save->vga_dda_on_off = INREG(R128_VGA_DDA_ON_OFF); } /* Read palette data. */ static void R128SavePalette(R128SavePtr save) { int i; /* Select palette 0 (main CRTC) if using FP-enabled chip */ // if (info->HasPanelRegs) PAL_SELECT(0); INPAL_START(0); for (i = 0; i < 256; i++) save->palette[i] = INPAL_NEXT(); save->palette_valid = 1; } /* Save state that defines current video mode. */ static void R128SaveMode(R128SavePtr save) { R128SaveCommonRegisters(save); R128SaveCrtcRegisters(save); // if (R128PTR(pScrn)->HasPanelRegs) // R128SaveFPRegisters(save); R128SavePLLRegisters(save); R128SaveDDARegisters(save); R128SavePalette(save); save->dp_datatype = INREG(R128_DP_DATATYPE); save->gen_reset_cntl = INREG(R128_GEN_RESET_CNTL); save->clock_cntl_index = INREG(R128_CLOCK_CNTL_INDEX); save->amcgpio_en_reg = INREG(R128_AMCGPIO_EN_REG); save->amcgpio_mask = INREG(R128_AMCGPIO_MASK); } static void R128InitCommonRegisters(R128SavePtr save) { save->ovr_clr = 0; save->ovr_wid_left_right = 0; save->ovr_wid_top_bottom = 0; save->ov0_scale_cntl = 0; save->mpp_tb_config = 0; save->mpp_gp_config = 0; save->subpic_cntl = 0; save->viph_control = 0; save->i2c_cntl_1 = 0; save->gen_int_cntl = 0; save->cap0_trig_cntl = 0; save->cap1_trig_cntl = 0; save->mem_vga_wp_sel = 0; save->mem_vga_rp_sel = 0; save->bus_cntl = BusCntl; save->config_cntl = INREG(R128_CONFIG_CNTL); save->amcgpio_en_reg = INREG(R128_AMCGPIO_EN_REG); save->amcgpio_mask = INREG(R128_AMCGPIO_MASK); /* * If bursts are enabled, turn on discards and aborts */ if (save->bus_cntl & (R128_BUS_WRT_BURST|R128_BUS_READ_BURST)) save->bus_cntl |= R128_BUS_RD_DISCARD_EN | R128_BUS_RD_ABORT_EN; } /* Define CRTC registers for requested video mode. */ static Bool R128InitCrtcRegisters(R128SavePtr save, ModeTiming *mode, ModeInfo *info) { int format; int hsync_start; int hsync_wid; int hsync_fudge; int vsync_wid; int bytpp; int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; int hsync_fudge_fp[] = { 0x12, 0x11, 0x09, 0x09, 0x05, 0x05 }; int hsync_fudge_fp_crt[] = { 0x12, 0x10, 0x08, 0x08, 0x04, 0x04 }; int dac6bits; dac6bits=0; switch (info->bitsPerPixel) { case 4: format = 1; bytpp = 0; dac6bits = 1; break; case 8: format = 2; bytpp = 1; dac6bits = 1; break; case 16: if(info->greenWeight==5) format = 3; else format = 4; bytpp = 2; break; case 24: format = 5; bytpp = 3; break; /* RGB */ case 32: format = 6; bytpp = 4; break; /* xRGB */ default: return 0; } if (HasPanelRegs) if (CRTOnly) hsync_fudge = hsync_fudge_fp_crt[format-1]; else hsync_fudge = hsync_fudge_fp[format-1]; else hsync_fudge = hsync_fudge_default[format-1]; save->crtc_gen_cntl = (R128_CRTC_EXT_DISP_EN | R128_CRTC_EN | (format << 8) | ((mode->flags & DOUBLESCAN) ? R128_CRTC_DBL_SCAN_EN : 0) | ((mode->flags & INTERLACED) ? R128_CRTC_INTERLACE_EN : 0)); save->crtc_ext_cntl = R128_VGA_ATI_LINEAR | R128_XCRT_CNT_EN | R128_VGA_MEM_PS_EN; save->dac_cntl = (R128_DAC_MASK_ALL | R128_DAC_VGA_ADR_EN | (dac6bits ? 0 : R128_DAC_8BIT_EN)); save->crtc_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0xffff) | (((mode->CrtcHDisplay / 8) - 1) << 16)); hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8; if (!hsync_wid) hsync_wid = 1; if (hsync_wid > 0x3f) hsync_wid = 0x3f; hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge; save->crtc_h_sync_strt_wid = ((hsync_start & 0xfff) | (hsync_wid << 16) | ((mode->flags & NHSYNC) ? R128_CRTC_H_SYNC_POL : 0)); #if 1 /* This works for double scan mode. */ save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) | ((mode->CrtcVDisplay - 1) << 16)); #else /* This is what cce/nbmode.c example code does -- is this correct? */ save->crtc_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff) | ((mode->CrtcVDisplay * ((mode->Flags & DOUBLESCAN) ? 2 : 1) - 1) << 16)); #endif vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart; if (!vsync_wid) vsync_wid = 1; if (vsync_wid > 0x1f) vsync_wid = 0x1f; save->crtc_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff) | (vsync_wid << 16) | ((mode->flags & NVSYNC) ? R128_CRTC_V_SYNC_POL : 0)); save->crtc_offset = 0; save->crtc_offset_cntl = 0; save->crtc_pitch = info->width / 8; save->config_cntl |= R128_CFG_VGA_RAM_EN; #if 0 /* Change the endianness of the aperture */ switch (info->bitsPerPixel) { case 15: case 16: save->config_cntl |= APER_0_BIG_ENDIAN_16BPP_SWAP; break; case 32: save->config_cntl |= APER_0_BIG_ENDIAN_32BPP_SWAP; break; default: break; } #endif return 1; } /* Define CRTC registers for requested video mode. */ static void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save, ModeTiming *mode, ModeInfo *info) { #if 0 int xres = mode->CrtcHDisplay; int yres = mode->CrtcVDisplay; float Hratio, Vratio; if (CRTOnly) { save->crtc_ext_cntl |= R128_CRTC_CRT_ON; save->crtc2_gen_cntl = 0; save->fp_gen_cntl = orig->fp_gen_cntl; save->fp_gen_cntl &= ~(R128_FP_FPON | R128_FP_CRTC_USE_SHADOW_VEND | R128_FP_CRTC_HORZ_DIV2_EN | R128_FP_CRTC_HOR_CRT_DIV2_DIS | R128_FP_USE_SHADOW_EN); save->fp_gen_cntl |= (R128_FP_SEL_CRTC2 | R128_FP_CRTC_DONT_SHADOW_VPAR); save->fp_panel_cntl = orig->fp_panel_cntl & ~R128_FP_DIGON; save->lvds_gen_cntl = orig->lvds_gen_cntl & ~(R128_LVDS_ON | R128_LVDS_BLON); return; } if (xres > info->PanelXRes) xres = info->PanelXRes; if (yres > info->PanelYRes) yres = info->PanelYRes; Hratio = (float)xres/(float)info->PanelXRes; Vratio = (float)yres/(float)info->PanelYRes; save->fp_horz_stretch = (((((int)(Hratio * R128_HORZ_STRETCH_RATIO_MAX + 0.5)) & R128_HORZ_STRETCH_RATIO_MASK) << R128_HORZ_STRETCH_RATIO_SHIFT) | (orig->fp_horz_stretch & (R128_HORZ_PANEL_SIZE | R128_HORZ_FP_LOOP_STRETCH | R128_HORZ_STRETCH_RESERVED))); save->fp_horz_stretch &= ~R128_HORZ_AUTO_RATIO_FIX_EN; if (Hratio == 1.0) save->fp_horz_stretch &= ~(R128_HORZ_STRETCH_BLEND | R128_HORZ_STRETCH_ENABLE); else save->fp_horz_stretch |= (R128_HORZ_STRETCH_BLEND | R128_HORZ_STRETCH_ENABLE); save->fp_vert_stretch = (((((int)(Vratio * R128_VERT_STRETCH_RATIO_MAX + 0.5)) & R128_VERT_STRETCH_RATIO_MASK) << R128_VERT_STRETCH_RATIO_SHIFT) | (orig->fp_vert_stretch & (R128_VERT_PANEL_SIZE | R128_VERT_STRETCH_RESERVED))); save->fp_vert_stretch &= ~R128_VERT_AUTO_RATIO_EN; if (Vratio == 1.0) save->fp_vert_stretch &= ~(R128_VERT_STRETCH_ENABLE | R128_VERT_STRETCH_BLEND); else save->fp_vert_stretch |= (R128_VERT_STRETCH_ENABLE | R128_VERT_STRETCH_BLEND); save->fp_gen_cntl = (orig->fp_gen_cntl & ~(R128_FP_SEL_CRTC2 | R128_FP_CRTC_USE_SHADOW_VEND | R128_FP_CRTC_HORZ_DIV2_EN | R128_FP_CRTC_HOR_CRT_DIV2_DIS | R128_FP_USE_SHADOW_EN)); if (orig->fp_gen_cntl & R128_FP_DETECT_SENSE) { save->fp_gen_cntl |= (R128_FP_CRTC_DONT_SHADOW_VPAR | R128_FP_TDMS_EN); } save->fp_panel_cntl = orig->fp_panel_cntl; save->lvds_gen_cntl = orig->lvds_gen_cntl; save->tmds_crc = orig->tmds_crc; /* Disable CRT output by disabling CRT output and setting the CRT DAC to use CRTC2, which we set to 0's. In the future, we will want to use the dual CRTC capabilities of the R128 to allow both the flat panel and external CRT to either simultaneously display the same image or display two different images. */ save->crtc_ext_cntl &= ~R128_CRTC_CRT_ON; save->dac_cntl |= R128_DAC_CRT_SEL_CRTC2; save->crtc2_gen_cntl = 0; /* WARNING: Be careful about turning on the flat panel */ #if 1 save->lvds_gen_cntl |= (R128_LVDS_ON | R128_LVDS_BLON); #else save->fp_panel_cntl |= (R128_FP_DIGON | R128_FP_BLON); save->fp_gen_cntl |= (R128_FP_FPON); #endif save->fp_crtc_h_total_disp = save->crtc_h_total_disp; save->fp_crtc_v_total_disp = save->crtc_v_total_disp; save->fp_h_sync_strt_wid = save->crtc_h_sync_strt_wid; save->fp_v_sync_strt_wid = save->crtc_v_sync_strt_wid; #endif } /* Define PLL registers for requested video mode. */ static void R128InitPLLRegisters(R128SavePtr save, R128PLLPtr pll, double dot_clock) { unsigned long freq = dot_clock * 100; struct { int divider; int bitvalue; } *post_div, post_divs[] = { /* From RAGE 128 VR/RAGE 128 GL Register Reference Manual (Technical Reference Manual P/N RRG-G04100-C Rev. 0.04), page 3-17 (PLL_DIV_[3:0]). */ { 1, 0 }, /* VCLK_SRC */ { 2, 1 }, /* VCLK_SRC/2 */ { 4, 2 }, /* VCLK_SRC/4 */ { 8, 3 }, /* VCLK_SRC/8 */ { 3, 4 }, /* VCLK_SRC/3 */ /* bitvalue = 5 is reserved */ { 6, 6 }, /* VCLK_SRC/6 */ { 12, 7 }, /* VCLK_SRC/12 */ { 0, 0 } }; if (freq > pll->max_pll_freq) freq = pll->max_pll_freq; if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12; for (post_div = &post_divs[0]; post_div->divider; ++post_div) { save->pll_output_freq = post_div->divider * freq; if (save->pll_output_freq >= pll->min_pll_freq && save->pll_output_freq <= pll->max_pll_freq) break; } save->dot_clock_freq = freq; save->feedback_div = R128Div(pll->reference_div * save->pll_output_freq, pll->reference_freq); save->post_div = post_div->divider; save->ppll_ref_div = pll->reference_div; save->ppll_div_3 = (save->feedback_div | (post_div->bitvalue << 16)); save->htotal_cntl = 0; } /* Define DDA registers for requested video mode. */ static Bool R128InitDDARegisters(R128SavePtr save, R128PLLPtr pll, ModeInfo *info) { int DisplayFifoWidth = 128; int DisplayFifoDepth = 32; int XclkFreq; int VclkFreq; int XclksPerTransfer; int XclksPerTransferPrecise; int UseablePrecision; int Roff; int Ron; XclkFreq = pll->xclk; VclkFreq = R128Div(pll->reference_freq * save->feedback_div, pll->reference_div * save->post_div); XclksPerTransfer = R128Div(XclkFreq * DisplayFifoWidth, VclkFreq * (info->bytesPerPixel * 8)); UseablePrecision = R128MinBits(XclksPerTransfer) + 1; XclksPerTransferPrecise = R128Div((XclkFreq * DisplayFifoWidth) << (11 - UseablePrecision), VclkFreq * (info->bytesPerPixel * 8)); Roff = XclksPerTransferPrecise * (DisplayFifoDepth - 4); Ron = (4 * ram[r128_ramtype].MB + 3 * (((ram[r128_ramtype].Trcd - 2)>0)?(ram[r128_ramtype].Trcd - 2):0) + 2 * ram[r128_ramtype].Trp + ram[r128_ramtype].Twr + ram[r128_ramtype].CL + ram[r128_ramtype].Tr2w + XclksPerTransfer) << (11 - UseablePrecision); if (Ron + ram[r128_ramtype].Rloop >= Roff) { return 0; } save->dda_config = (XclksPerTransferPrecise | (UseablePrecision << 16) | (ram[r128_ramtype].Rloop << 20)); save->dda_on_off = (Ron << 16) | Roff; return 1; } /* Define initial palette for requested video mode. This doesn't do anything for XFree86 4.0. */ static void R128InitPalette(R128SavePtr save) { int i; save->palette_valid = 1; for(i=0;i<256;i++) save->palette[i]=i | (i<<8) | (i<<16); } /* Define registers for a requested video mode. */ static Bool R128Init(ModeTiming *mode, ModeInfo *info, R128SavePtr save) { double dot_clock = mode->pixelClock/1000.0; R128InitCommonRegisters(save); if (!R128InitCrtcRegisters(save, mode, info)) return 0; #if 0 if (HasPanelRegs) R128InitFPRegisters(&info->SavedReg, save, mode, info); #endif R128InitPLLRegisters(save, &pll, dot_clock); if (!R128InitDDARegisters(save, &pll, info)) return 0; // if (!info->PaletteSavedOnVT) R128InitPalette(save); return 1; } static int r128_init(int, int, int); static void r128_unlock(void); static void r128_lock(void); void __svgalib_skaccel_init(AccelSpecs * accelspecs, int bpp, int width_in_pixels); static int r128_memory, r128_chiptype; static int r128_is_linear, r128_linear_base, r128_mmio_base; static CardSpecs *cardspecs; static void r128_setpage(int page) { page*=2; OUTREG(R128_MEM_VGA_WP_SEL, page | ((page+1)<<16)); OUTREG(R128_MEM_VGA_RP_SEL, page | ((page+1)<<16)); } static int __svgalib_r128_inlinearmode(void) { return r128_is_linear; } /* Fill in chipset specific mode information */ static void r128_getmodeinfo(int mode, vga_modeinfo *modeinfo) { if(modeinfo->colors==16)return; modeinfo->maxpixels = r128_memory*1024/modeinfo->bytesperpixel; modeinfo->maxlogicalwidth = 4088; modeinfo->startaddressrange = r128_memory * 1024 - 1; modeinfo->haveblit = 0; modeinfo->flags &= ~HAVE_RWPAGE; if (modeinfo->bytesperpixel >= 1) { if(r128_linear_base)modeinfo->flags |= CAPABLE_LINEAR; if (__svgalib_r128_inlinearmode()) modeinfo->flags |= IS_LINEAR; } } /* Read and save chipset-specific registers */ static int r128_saveregs(unsigned char regs[]) { int i; r128_unlock(); R128SaveMode((R128SavePtr)(regs+VGA_TOTAL_REGS)); return R128_TOTAL_REGS - VGA_TOTAL_REGS; } /* Set chipset-specific registers */ static void r128_setregs(const unsigned char regs[], int mode) { r128_unlock(); R128RestoreMode((R128SavePtr)(regs+VGA_TOTAL_REGS)); R128Unblank(); } /* Return nonzero if mode is available */ static int r128_modeavailable(int mode) { struct info *info; ModeTiming *modetiming; ModeInfo *modeinfo; modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode); if (IS_IN_STANDARD_VGA_DRIVER(mode)) return __svgalib_vga_driverspecs.modeavailable(mode); info = &__svgalib_infotable[mode]; if (r128_memory * 1024 < info->ydim * info->xbytes) return 0; modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode); modetiming = malloc(sizeof(ModeTiming)); if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) { free(modetiming); free(modeinfo); return 0; } free(modetiming); free(modeinfo); return SVGADRV; } /* Local, called by r128_setmode(). */ static void r128_initializemode(unsigned char *moderegs, ModeTiming * modetiming, ModeInfo * modeinfo, int mode) { /* long k; */ __svgalib_setup_VGA_registers(moderegs, modetiming, modeinfo); R128Init(modetiming, modeinfo, (R128SavePtr)(moderegs+VGA_TOTAL_REGS)); return ; } static int r128_setmode(int mode, int prv_mode) { unsigned char *moderegs; ModeTiming *modetiming; ModeInfo *modeinfo; if (IS_IN_STANDARD_VGA_DRIVER(mode)) { return __svgalib_vga_driverspecs.setmode(mode, prv_mode); } if (!r128_modeavailable(mode)) return 1; modeinfo = __svgalib_createModeInfoStructureForSvgalibMode(mode); modetiming = malloc(sizeof(ModeTiming)); if (__svgalib_getmodetiming(modetiming, modeinfo, cardspecs)) { free(modetiming); free(modeinfo); return 1; } moderegs = malloc(R128_TOTAL_REGS); r128_initializemode(moderegs, modetiming, modeinfo, mode); free(modetiming); __svgalib_setregs(moderegs); /* Set standard regs. */ r128_setregs(moderegs, mode); /* Set extended regs. */ free(moderegs); __svgalib_InitializeAcceleratorInterface(modeinfo); free(modeinfo); return 0; } /* Unlock chipset-specific registers */ static void r128_unlock(void) { int vgaIOBase, temp; vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0; outb(vgaIOBase + 4, 0x11); temp = inb(vgaIOBase + 5); outb(vgaIOBase + 5, temp & 0x7F); } static void r128_lock(void) { int vgaIOBase, temp; vgaIOBase = (inb(0x3CC) & 0x01) ? 0x3D0 : 0x3B0; outb(vgaIOBase + 4, 0x11); temp = inb(vgaIOBase + 5); outb(vgaIOBase + 5, temp & 0x7F); } #define VENDOR_ID 0x1002 /* Indentify chipset, initialize and return non-zero if detected */ static int r128_test(void) { int found, id; unsigned long buf[64]; found=__svgalib_pci_find_vendor_vga(VENDOR_ID,buf,0); if(found) return 0; id=(buf[0]>>16)&0xffff; if((id>=0x5350) || (id<=0x4fff)) return 0; r128_init(0,0,0); return 1; } /* Set display start address (not for 16 color modes) */ /* Cirrus supports any address in video memory (up to 2Mb) */ static void r128_setdisplaystart(int address) { int naddress=address >> 2; __svgalib_outcrtc(0x0c,(naddress>>8)&0xff); __svgalib_outcrtc(0x0d,(naddress)&0xff); OUTREG(R128_CRTC_OFFSET, address); } /* Set logical scanline length (usually multiple of 8) */ /* Cirrus supports multiples of 8, up to 4088 */ static void r128_setlogicalwidth(int width) { int offset = width >> 3; if(CI.bytesperpixel>1) { offset = offset/CI.bytesperpixel; } __svgalib_outcrtc(0x13,offset&0xff); OUTREG(R128_CRTC_PITCH, offset); } static int r128_linear(int op, int param) { if (op==LINEAR_ENABLE){r128_is_linear=1; return 0;}; if (op==LINEAR_DISABLE){r128_is_linear=0; return 0;}; if (op==LINEAR_QUERY_BASE) return r128_linear_base; if (op == LINEAR_QUERY_RANGE || op == LINEAR_QUERY_GRANULARITY) return 0; /* No granularity or range. */ else return -1; /* Unknown function. */ } static int r128_match_programmable_clock(int clock) { return clock ; } static int r128_map_clock(int bpp, int clock) { return clock ; } static int r128_map_horizontal_crtc(int bpp, int pixelclock, int htiming) { return htiming; } /* Function table (exported) */ DriverSpecs __svgalib_r128_driverspecs = { r128_saveregs, r128_setregs, r128_unlock, r128_lock, r128_test, r128_init, r128_setpage, NULL, NULL, r128_setmode, r128_modeavailable, r128_setdisplaystart, r128_setlogicalwidth, r128_getmodeinfo, 0, /* old blit funcs */ 0, 0, 0, 0, 0, /* ext_set */ 0, /* accel */ r128_linear, 0, /* accelspecs, filled in during init. */ NULL, /* Emulation */ }; /* Initialize chipset (called after detection) */ static int r128_init(int force, int par1, int par2) { unsigned long buf[64]; int found=0; unsigned char *BIOS_POINTER; r128_unlock(); if (force) { r128_memory = par1; r128_chiptype = par2; } else { }; found=__svgalib_pci_find_vendor_vga(VENDOR_ID,buf,0); if(found) return 0; r128_chiptype=(buf[0]>>16)&0xffff; if((r128_chiptype>=0x5350) || (r128_chiptype<=0x4fff)) return 0; r128_linear_base=buf[4]&0xffffff00; r128_mmio_base=buf[6]&0xffffff00; MMIO_POINTER = mmap(0, 16*1024, PROT_READ | PROT_WRITE, MAP_SHARED, __svgalib_mem_fd, r128_mmio_base); BIOS_POINTER = mmap(0, 64*1024, PROT_READ | PROT_WRITE, MAP_SHARED, __svgalib_mem_fd, 0xc0000); r128_memory = INREG(R128_CONFIG_MEMSIZE) / 1024; BusCntl = INREG(R128_BUS_CNTL); HasPanelRegs = 0; CRTOnly = 1; r128_ramtype = 1; #if 0 pll.reference_freq = 2700; pll.min_pll_freq = 12500; pll.max_pll_freq = 40000; pll.reference_div = INPLL(R128_PPLL_REF_DIV) & R128_PPLL_REF_DIV_MASK; pll.xclk = 14000; #else #define R128_BIOS16(x) (*(unsigned short *)(BIOS_POINTER + x)) #define R128_BIOS32(x) (*(unsigned int *)(BIOS_POINTER + x)) { CARD16 bios_header = R128_BIOS16(0x48); CARD16 pll_info_block = R128_BIOS16(bios_header + 0x30); pll.reference_freq = R128_BIOS16(pll_info_block + 0x0e); pll.reference_div = R128_BIOS16(pll_info_block + 0x10); pll.min_pll_freq = R128_BIOS32(pll_info_block + 0x12); pll.max_pll_freq = R128_BIOS32(pll_info_block + 0x16); pll.xclk = R128_BIOS16(pll_info_block + 0x08); #if 0 printf("pll: %i %i %i %i %i\n",pll.reference_freq,pll.reference_div, pll.min_pll_freq, pll.max_pll_freq, pll.xclk); #endif } #endif munmap(MMIO_POINTER, 16*1024); munmap(BIOS_POINTER, 64*1024); if (__svgalib_driver_report) { printf("Using Rage 128 driver, %iKB.\n",r128_memory); }; cardspecs = malloc(sizeof(CardSpecs)); cardspecs->videoMemory = r128_memory; cardspecs->maxPixelClock4bpp = 75000; cardspecs->maxPixelClock8bpp = 160000; cardspecs->maxPixelClock16bpp = 160000; cardspecs->maxPixelClock24bpp = 160000; cardspecs->maxPixelClock32bpp = 160000; cardspecs->flags = INTERLACE_DIVIDE_VERT | CLOCK_PROGRAMMABLE; cardspecs->maxHorizontalCrtc = 2040; cardspecs->maxPixelClock4bpp = 0; cardspecs->nClocks =0; cardspecs->mapClock = r128_map_clock; cardspecs->mapHorizontalCrtc = r128_map_horizontal_crtc; cardspecs->matchProgrammableClock=r128_match_programmable_clock; __svgalib_driverspecs = &__svgalib_r128_driverspecs; __svgalib_banked_mem_base=0xa0000; __svgalib_banked_mem_size=0x10000; __svgalib_linear_mem_base=r128_linear_base; __svgalib_linear_mem_size=r128_memory*0x400; __svgalib_mmio_base=r128_mmio_base; __svgalib_mmio_size=16*1024; return 0; }