// cleanup PCI GART void Radeon_CleanupPCIGART( device_info *di ) { vuint8 *regs = di->regs; SHOW_FLOW0( 3, "" ); // perhaps we should wait for FIFO space before messing around with registers, but // 1. I don't want to add all the sync stuff to the kernel driver // 2. I doubt that these regs are buffered by FIFO // but still: in worst case CP has written some commands to register FIFO, // which can do any kind of nasty things // disable CP BM OUTREG( regs, RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIDIS_INDDIS ); // read-back for flushing INREG( regs, RADEON_CP_CSQ_CNTL ); // disable bus mastering OUTREGP( regs, RADEON_BUS_CNTL, RADEON_BUS_MASTER_DIS, ~RADEON_BUS_MASTER_DIS ); // disable PCI GART OUTREGP( regs, RADEON_AIC_CNTL, 0, ~RADEON_PCIGART_TRANSLATE_EN ); destroyGATT( &di->pci_gart ); destroyGARTBuffer( &di->pci_gart ); }
// set DPMS state of LVDS port static void Radeon_SetDPMS_LVDS( accelerator_info *ai, int mode ) { vuint8 *regs = ai->regs; // for internal flat panel, switch backlight off too switch( mode ) { case B_DPMS_ON: // on my laptop, the display has problems to wake-up, this // should hopefully cure that // (you get a dark picture first that becomes brighter step by step, // after a couple of seconds you have full brightness again) OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_BLON, ~RADEON_LVDS_BLON ); snooze( ai->si->panel_pwr_delay * 1000 ); OUTREGP( regs, RADEON_LVDS_GEN_CNTL, RADEON_LVDS_ON, ~RADEON_LVDS_ON ); break; case B_DPMS_STAND_BY: case B_DPMS_SUSPEND: case B_DPMS_OFF: { uint32 old_pixclks_cntl; old_pixclks_cntl = Radeon_INPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL); // ASIC bug: when LVDS_ON is reset, LVDS_ALWAYS_ON must be zero if( ai->si->is_mobility || ai->si->is_igp ) Radeon_OUTPLLP( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb ); OUTREGP( regs, RADEON_LVDS_GEN_CNTL, 0, ~(RADEON_LVDS_BLON | RADEON_LVDS_ON) ); if( ai->si->is_mobility || ai->si->is_igp ) Radeon_OUTPLL( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, old_pixclks_cntl ); break; } } }
// hammer CRTC registers void Radeon_ProgramCRTCRegisters( accelerator_info *ai, int crtc_idx, crtc_regs *values ) { vuint8 *regs = ai->regs; SHOW_FLOW0( 2, "" ); if( crtc_idx == 0 ) { OUTREGP( regs, RADEON_CRTC_GEN_CNTL, values->crtc_gen_cntl, RADEON_CRTC_EXT_DISP_EN ); OUTREG( regs, RADEON_CRTC_H_TOTAL_DISP, values->crtc_h_total_disp ); OUTREG( regs, RADEON_CRTC_H_SYNC_STRT_WID, values->crtc_h_sync_strt_wid ); OUTREG( regs, RADEON_CRTC_V_TOTAL_DISP, values->crtc_v_total_disp ); OUTREG( regs, RADEON_CRTC_V_SYNC_STRT_WID, values->crtc_v_sync_strt_wid ); OUTREG( regs, RADEON_CRTC_OFFSET_CNTL, values->crtc_offset_cntl ); OUTREG( regs, RADEON_CRTC_PITCH, values->crtc_pitch ); } else { OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, values->crtc_gen_cntl, RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS | RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_CRT2_ON ); OUTREG( regs, RADEON_CRTC2_H_TOTAL_DISP, values->crtc_h_total_disp ); OUTREG( regs, RADEON_CRTC2_H_SYNC_STRT_WID, values->crtc_h_sync_strt_wid ); OUTREG( regs, RADEON_CRTC2_V_TOTAL_DISP, values->crtc_v_total_disp ); OUTREG( regs, RADEON_CRTC2_V_SYNC_STRT_WID, values->crtc_v_sync_strt_wid ); OUTREG( regs, RADEON_CRTC2_OFFSET_CNTL, values->crtc_offset_cntl ); OUTREG( regs, RADEON_CRTC2_PITCH, values->crtc_pitch ); } }
/* Hide hardware cursor. */ static void R128HideCursor(ScrnInfoPtr pScrn) { R128InfoPtr info = R128PTR(pScrn); unsigned char *R128MMIO = info->MMIO; if(info->IsSecondary) OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_CUR_EN); else OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN); }
// read data from VIP // CP lock must be hold static bool do_VIPRead( device_info *di, uint channel, uint address, uint32 *data ) { vuint8 *regs = di->regs; Radeon_WaitForFifo( di, 2 ); // the 0x2000 is the nameless "register-read" flag OUTREG( regs, RADEON_VIPH_REG_ADDR, (channel << 14) | address | 0x2000 ); if( !Radeon_VIPWaitForIdle( di )) return false; // enable VIP register cycle reads Radeon_WaitForFifo( di, 2 ); OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, 0, ~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS ); //Radeon_WaitForIdle( di, false, false ); // this read starts a register cycle; the returned value has no meaning INREG( regs, RADEON_VIPH_REG_DATA ); if( !Radeon_VIPWaitForIdle( di )) return false; //Radeon_WaitForIdle( di, false, false ); // register cycle is done, so disable any further cycle Radeon_WaitForFifo( di, 2 ); OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS, ~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS ); //Radeon_WaitForIdle( di, false, false ); // get the data *data = INREG( regs, RADEON_VIPH_REG_DATA ); //SHOW_FLOW( 4, "channel=%d, address=%x, data=%lx", channel, address, *data ); if( !Radeon_VIPWaitForIdle( di )) return false; // disable register cycle again (according to sample code) // IMHO, this is not necessary as it has been done before Radeon_WaitForFifo( di, 2 ); OUTREGP( regs, RADEON_VIPH_TIMEOUT_STAT, RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS, ~RADEON_VIPH_TIMEOUT_STAT_AK_MASK & ~RADEON_VIPH_TIMEOUT_STAT_VIPH_REGR_DIS ); return true; }
/* Show hardware cursor. */ static void R128ShowCursor(ScrnInfoPtr pScrn) { R128InfoPtr info = R128PTR(pScrn); unsigned char *R128MMIO = info->MMIO; OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN); }
// set DPMS mode for CRT DAC. // warning: the CRTC-DAC only obbeys this setting if // connected to CRTC1, else it collides with TV-DAC static void Radeon_SetDPMS_CRT( accelerator_info *ai, int mode ) { vuint8 *regs = ai->regs; switch( mode ) { case B_DPMS_ON: OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 0, ~RADEON_CRTC_DISPLAY_DIS ); break; case B_DPMS_STAND_BY: case B_DPMS_SUSPEND: case B_DPMS_OFF: OUTREGP( regs, RADEON_CRTC_EXT_CNTL, RADEON_CRTC_DISPLAY_DIS, ~RADEON_CRTC_DISPLAY_DIS ); break; } }
// set DPMS state of DVI port static void Radeon_SetDPMS_DVI( accelerator_info *ai, int mode ) { vuint8 *regs = ai->regs; // it seems that DPMS doesn't work on DVI, so we disable FP completely // (according to specs this is the official way to handle DVI though DPMS // *should* be supported as well) switch( mode ) { case B_DPMS_ON: OUTREGP( regs, RADEON_FP_GEN_CNTL, RADEON_FP_FPON | RADEON_FP_TMDS_EN, ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN)); break; case B_DPMS_STAND_BY: case B_DPMS_SUSPEND: case B_DPMS_OFF: OUTREGP( regs, RADEON_FP_GEN_CNTL, 0, ~RADEON_FP_FPON | RADEON_FP_TMDS_EN ); break; } }
// set DPMS mode for TV-DAC in CRT mode // warning: if the CRT-DAC is connected to CRTC2, it is // affected by this setting too static void Radeon_SetDPMS_TVCRT( accelerator_info *ai, int mode ) { vuint8 *regs = ai->regs; switch( mode ) { case B_DPMS_ON: OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS) ); break; case B_DPMS_STAND_BY: OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS), ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS) ); break; case B_DPMS_SUSPEND: OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS), ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS) ); break; case B_DPMS_OFF: OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS), ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS) ); break; } }
// initialize DMA engine status_t Radeon_InitDMA( device_info *di ) { status_t res; // allocate descriptor table in graphics mem // (docu says that is _must_ be in graphics mem) di->dma_desc_max_num = RADEON_MAX_DMA_SIZE / 4096; res = mem_alloc( di->memmgr[mt_local], di->dma_desc_max_num * sizeof( DMA_descriptor ), 0, &di->dma_desc_handle, &di->dma_desc_offset ); if( res != B_OK ) return res; // allow DMA IRQ OUTREGP( di->regs, RADEON_GEN_INT_CNTL, RADEON_VIDDMA_MASK, ~RADEON_VIDDMA_MASK ); // acknowledge possibly pending IRQ OUTREG( di->regs, RADEON_GEN_INT_STATUS, RADEON_VIDDMA_AK ); return B_OK; }
// set DPMS mode for first CRTC static void Radeon_SetDPMS_CRTC1( accelerator_info *ai, int mode ) { vuint8 *regs = ai->regs; uint32 mask = ~(RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS); switch( mode ) { case B_DPMS_ON: OUTREGP( regs, RADEON_CRTC_EXT_CNTL, 0, mask ); break; case B_DPMS_STAND_BY: OUTREGP( regs, RADEON_CRTC_EXT_CNTL, (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_HSYNC_DIS), mask ); break; case B_DPMS_SUSPEND: OUTREGP( regs, RADEON_CRTC_EXT_CNTL, (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS), mask ); break; case B_DPMS_OFF: OUTREGP( regs, RADEON_CRTC_EXT_CNTL, (RADEON_CRTC_DISPLAY_DIS | RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS), mask ); break; } // disable/enable memory requests and cursor switch( mode ) { case B_DPMS_ON: /* Screen: On; HSync: On, VSync: On */ OUTREGP( regs, RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_DISP_REQ_EN_B ); Radeon_ShowCursor( ai, 0 ); break; case B_DPMS_STAND_BY: case B_DPMS_SUSPEND: case B_DPMS_OFF: OUTREGP( regs, RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_CUR_EN) ); break; } }
// set DPMS mode of second CRTC static void Radeon_SetDPMS_CRTC2( accelerator_info *ai, int mode ) { vuint8 *regs = ai->regs; int mask = ~(RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS); switch( mode ) { case B_DPMS_ON: OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, mask ); break; case B_DPMS_STAND_BY: OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_HSYNC_DIS), mask ); break; case B_DPMS_SUSPEND: OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS), mask); break; case B_DPMS_OFF: OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, (RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS), mask); break; } switch( mode ) { case B_DPMS_ON: /* Screen: On; HSync: On, VSync: On */ OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_DISP_REQ_EN_B ); Radeon_ShowCursor( ai, 1 ); break; case B_DPMS_STAND_BY: case B_DPMS_SUSPEND: case B_DPMS_OFF: OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_DISP_REQ_EN_B, ~(RADEON_CRTC2_DISP_REQ_EN_B | RADEON_CRTC2_CUR_EN) ); break; } }