📄 monitor_routing.c
字号:
values->disp_output_cntl |= crtc_idx == 0 ? 0 : RADEON_DISP_TVDAC_SOURCE_CRTC2; break; case rt_r100: break; } } // choose clock source for (internal) TV-out unit if( (total_devices & (dd_ctv | dd_stv)) != 0 ) { int crtc_idx = (display_devices[1] & (dd_ctv | dd_stv)) != 0; values->pixclks_cntl &= ~RADEON_PIXCLK_TV_SRC_SEL_MASK; values->pixclks_cntl |= crtc_idx == 0 ? RADEON_PIXCLK_TV_SRC_SEL_PIXCLK : RADEON_PIXCLK_TV_SRC_SEL_PIX2CLK; } // choose CRTC clock source; // normally, CRTC1 uses PLL1 and CRTC2 uses PLL2, but if an external TV-Out // chip is used, the clock is retrieved from this chip to stay in perfect sync if( (display_devices[0] & (dd_ctv | dd_stv)) != 0 && !IS_INTERNAL_TV_OUT( ai->si->tv_chip )) { // select BYTCLK input pin as pixel src values->vclk_ecp_cntl &= ~(RADEON_VCLK_ECP_CNTL_BYTE_CLK_POST_DIV_MASK | RADEON_VCLK_SRC_SEL_MASK); values->vclk_ecp_cntl |= RADEON_VCLK_SRC_BYTE_CLK; values->vclk_ecp_cntl |= 0 << RADEON_VCLK_ECP_CNTL_BYTE_CLK_POST_DIV_SHIFT; // disable clock if pixel format in CRTC_GEN_CNTL is zero; // disable (DAC?) during blank values->vclk_ecp_cntl |= RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb; } else { // select PLL as pixel clock values->vclk_ecp_cntl &= ~RADEON_VCLK_SRC_SEL_MASK; values->vclk_ecp_cntl |= RADEON_VCLK_SRC_PPLL_CLK; // disable clock if pixel format in CRTC_GEN_CNTL is zero values->vclk_ecp_cntl |= RADEON_PIXCLK_ALWAYS_ONb; } values->pixclks_cntl &= ~RADEON_PIX2CLK_SRC_SEL_MASK; if( (display_devices[1] & (dd_ctv | dd_stv)) != 0 && !IS_INTERNAL_TV_OUT( ai->si->tv_chip )) { // r200 spec misses everything regarding second CRTC, so // this is guessing values->pixclks_cntl |= 2; } else values->pixclks_cntl |= RADEON_PIX2CLK_SRC_SEL_P2PLL_CLK; // choose CRTC for flat panel if( (total_devices & (dd_lvds | dd_dvi)) != 0 ) { int crtc_idx = (display_devices[1] & (dd_lvds | dd_dvi)) != 0; values->fp_gen_cntl &= ~RADEON_FP_SEL_CRTC2; values->fp_gen_cntl |= crtc_idx == 0 ? 0 : RADEON_FP_SEL_CRTC2; } // enable/disable RMX for crtc1 if there is a flat panel // (TODO: this doesn't seem to work) // !!! makes trouble on Radeon 9200 Mobility !?? if( (display_devices[1] & (dd_lvds | dd_dvi)) != 0 ) { values->disp_output_cntl &= ~RADEON_DISP_DAC_SOURCE_MASK; values->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_RMX; } // choose CRTC for secondary flat panel if( (total_devices & dd_dvi_ext) != 0 ) { int crtc_idx = (display_devices[1] & (dd_dvi_ext)) != 0; // TODO: this list looks a bit magic/wrong for me; I reckon ATI moved the // bit starting with ASIC xxx, but I have no specs to verify that switch( ai->si->asic ) { case rt_r200: case rt_r300: case rt_r350: case rt_rv350: case rt_m10: values->fp2_gen_cntl &= ~RADEON_FP2_SOURCE_SEL_CRTC2; values->fp2_gen_cntl |= crtc_idx == 0 ? 0 : RADEON_FP2_SOURCE_SEL_CRTC2; break; default: values->fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_CRTC2; values->fp2_gen_cntl |= crtc_idx == 0 ? 0 : RADEON_FP2_SRC_SEL_CRTC2; } }}void Radeon_ProgramMonitorRouting( accelerator_info *ai, routing_regs *values ){ vuint8 *regs = ai->regs; OUTREG( regs, RADEON_DAC_CNTL, values->dac_cntl ); OUTREG( regs, RADEON_DAC_CNTL2, values->dac_cntl2 ); OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, values->crtc2_gen_cntl, ~RADEON_CRTC2_CRT2_ON ); OUTREG( regs, RADEON_DISP_OUTPUT_CNTL, values->disp_output_cntl ); switch( ai->si->asic ) { case rt_ve: case rt_m6: case rt_rv200: case rt_m7: case rt_rv250: case rt_m9: case rt_rv280: case rt_m9plus: case rt_rs100: case rt_rs200: OUTREG( regs, RADEON_DISP_HW_DEBUG, values->disp_hw_debug ); break; case rt_r200: OUTREG( regs, RADEON_DISP_TV_OUT_CNTL, values->disp_tv_out_cntl ); break; case rt_r300: case rt_r300_4p: case rt_rv350: case rt_m10: case rt_rv360: case rt_r350: case rt_r360: OUTREGP( regs, RADEON_GPIOPAD_A, values->gpiopad_a, ~1 ); break; case rt_r100: break; } if( ai->si->asic > rt_r100 ) { // register introduced after R100; // only set it when necessary (more precisely: if TV-Out is used, // this register is set by the TV-Out code) if( !values->skip_tv_dac ) OUTREG( regs, RADEON_TV_DAC_CNTL, values->tv_dac_cntl ); } if( IS_INTERNAL_TV_OUT( ai->si->tv_chip )) OUTREG( regs, RADEON_TV_MASTER_CNTL, values->tv_master_cntl ); OUTREGP( regs, RADEON_FP_GEN_CNTL, values->fp_gen_cntl, ~( RADEON_FP_SEL_CRTC2 | RADEON_FP_RMX_HVSYNC_CONTROL_EN | RADEON_FP_DFP_SYNC_SEL | RADEON_FP_CRT_SYNC_SEL | RADEON_FP_CRTC_LOCK_8DOT | RADEON_FP_USE_SHADOW_EN | RADEON_FP_CRTC_USE_SHADOW_VEND | RADEON_FP_CRT_SYNC_ALT | RADEON_FP_CRTC_DONT_SHADOW_VPAR | RADEON_FP_CRTC_DONT_SHADOW_HEND )); OUTREGP( regs, RADEON_FP2_GEN_CNTL, values->fp2_gen_cntl, ~(RADEON_FP2_SOURCE_SEL_CRTC2 | RADEON_FP2_SRC_SEL_CRTC2 )); if( ai->vc->used_crtc[0] ) { Radeon_OUTPLLP( ai->regs, ai->si->asic, RADEON_VCLK_ECP_CNTL, values->vclk_ecp_cntl, ~RADEON_VCLK_SRC_SEL_MASK ); } if( ai->vc->used_crtc[1] ) { Radeon_OUTPLLP( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, values->pixclks_cntl, ~RADEON_PIX2CLK_SRC_SEL_MASK ); } Radeon_OUTPLLP( ai->regs, ai->si->asic, RADEON_PIXCLKS_CNTL, values->pixclks_cntl, ~RADEON_PIXCLK_TV_SRC_SEL_MASK ); // enable/disable CRTC1 if( ai->vc->assigned_crtc[0] ) { uint32 crtc_gen_cntl; crtc_gen_cntl = INREG( regs, RADEON_CRTC_GEN_CNTL ); if( ai->vc->used_crtc[0] ) { crtc_gen_cntl |= RADEON_CRTC_EN; } else { crtc_gen_cntl &= ~RADEON_CRTC_EN; crtc_gen_cntl &= ~RADEON_CRTC_PIX_WIDTH_MASK; } OUTREGP( regs, RADEON_CRTC_GEN_CNTL, crtc_gen_cntl, ~(RADEON_CRTC_PIX_WIDTH_MASK | RADEON_CRTC_EN) ); } // enable/disable CRTC2 if( ai->vc->assigned_crtc[1] ) { uint32 crtc2_gen_cntl; crtc2_gen_cntl = INREG( regs, RADEON_CRTC2_GEN_CNTL ); if( ai->vc->used_crtc[1] ) { crtc2_gen_cntl |= RADEON_CRTC2_EN; } else { crtc2_gen_cntl &= ~RADEON_CRTC2_EN; crtc2_gen_cntl &= ~RADEON_CRTC2_PIX_WIDTH_MASK; } OUTREGP( regs, RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl, ~(RADEON_CRTC2_PIX_WIDTH_MASK | RADEON_CRTC2_EN) ); } // XFree says that crtc_ext_cntl must be restored after CRTC2 in dual-screen mode OUTREGP( regs, RADEON_CRTC_EXT_CNTL, values->crtc_ext_cntl, RADEON_CRTC_VSYNC_DIS | RADEON_CRTC_HSYNC_DIS | RADEON_CRTC_DISPLAY_DIS );}// internal version of SetupDefaultMonitorRouting;// input and output are written to local variablesvoid assignDefaultMonitorRoute( accelerator_info *ai, display_device_e display_devices, int whished_num_heads, bool use_laptop_panel, display_device_e *crtc1, display_device_e *crtc2 ){ virtual_card *vc = ai->vc; display_device_e crtc1_displays = 0, crtc2_displays = 0; SHOW_FLOW( 2, "display_devices=%x, whished_num_heads=%d", display_devices, whished_num_heads ); // restrict to allowed devices display_devices &= ai->vc->controlled_displays; // if CRTC1 is not ours, we cannot use flat panels if( !ai->vc->assigned_crtc[0] ) { display_devices &= ~(dd_lvds | dd_dvi); } SHOW_FLOW( 2, "after restriction: %x", display_devices ); // flat panels get always connected to CRTC1 because its RMX unit if( (display_devices & dd_lvds) != 0 ) { // if user requests it, laptop panels are always used if( use_laptop_panel ) { crtc1_displays |= dd_lvds; } else { // if he doesn't request it, we try to not use it display_device_e tmp_crtc1, tmp_crtc2; int effective_num_heads; // determine routing with laptop panel ignored assignDefaultMonitorRoute( ai, display_devices & ~dd_lvds, whished_num_heads, use_laptop_panel, &tmp_crtc1, &tmp_crtc2 ); effective_num_heads = (tmp_crtc1 != 0) + (tmp_crtc2 != 0); // only use laptop panel if we cannot satisfy the requested // number of heads without it if( effective_num_heads < whished_num_heads ) crtc1_displays |= dd_lvds; } } else if( (display_devices & dd_dvi) != 0 ) crtc1_displays |= dd_dvi; // TV-Out gets always connected to crtc2... if( (display_devices & dd_stv) != 0 ) crtc2_displays |= dd_stv; else if( (display_devices & dd_ctv) != 0 ) crtc2_displays |= dd_ctv; // ...but if there is no crtc2, they win on crtc1; // if the user connects both a flat panel and a TV, he usually // wants to use the TV if( !vc->assigned_crtc[1] && crtc2_displays != 0 ) { crtc1_displays = crtc2_displays; crtc2_displays = dd_none; } // if internal TV-Out is used, the DAC cannot drive a CRT at the same time if( IS_INTERNAL_TV_OUT( ai->si->tv_chip ) && (display_devices & (dd_stv | dd_ctv)) != 0 ) display_devices &= ~dd_tv_crt; // CRT on CRT-DAC gets any spare CRTC; // if there is none, it can share CRTC with TV-Out; // this sharing may be dangerous as TV-Out uses strange timings, so // we should perhaps forbid sharing if( (display_devices & dd_crt) != 0 ) { if( crtc1_displays == 0 && vc->assigned_crtc[0] ) crtc1_displays |= dd_crt; else if( ai->si->num_crtc > 1 && crtc2_displays == 0 && vc->assigned_crtc[1] ) crtc2_displays |= dd_crt; else if( (crtc1_displays & ~(dd_stv | dd_ctv)) == 0 && vc->assigned_crtc[0] ) crtc1_displays |= dd_crt; else if( ai->si->num_crtc > 1 && (crtc2_displays & ~(dd_stv | dd_ctv)) == 0 && vc->assigned_crtc[1] ) crtc2_displays |= dd_crt; } // same applies to CRT on TV-DAC; // if we cannot find a CRTC, we could clone the content of the CRT-DAC, // but I doubt that you really want two CRTs showing the same if( (display_devices & dd_tv_crt) != 0 ) { if( crtc1_displays == 0 && vc->assigned_crtc[0] ) crtc1_displays |= dd_tv_crt; else if( ai->si->num_crtc > 1 && crtc2_displays == 0 && vc->assigned_crtc[1] ) crtc2_displays |= dd_tv_crt; else if( (crtc1_displays & ~(dd_stv | dd_ctv)) == 0 && vc->assigned_crtc[0] ) crtc1_displays |= dd_tv_crt; else if( ai->si->num_crtc > 1 && (crtc2_displays & ~(dd_stv | dd_ctv)) == 0 && vc->assigned_crtc[1] ) crtc2_displays |= dd_tv_crt; } SHOW_FLOW( 3, "CRTC1: 0x%x, CRTC2: 0x%x", crtc1_displays, crtc2_displays ); *crtc1 = crtc1_displays; *crtc2 = crtc2_displays;}// Setup sensible default monitor routing// whished_num_heads - number of independant heads current display mode would need// use_laptop_panel - if true, always use laptop panelvoid Radeon_SetupDefaultMonitorRouting( accelerator_info *ai, int whished_num_heads, bool use_laptop_panel ){ virtual_card *vc = ai->vc; shared_info *si = ai->si; display_device_e display_devices = vc->connected_displays; SHOW_FLOW( 2, "display_devices=%x, whished_num_heads=%d, use_laptop_panel=%d", display_devices, whished_num_heads, use_laptop_panel ); // ignore TV if standard is set to "off" if( vc->tv_standard == ts_off ) display_devices &= ~(dd_ctv | dd_stv); assignDefaultMonitorRoute( ai, display_devices, whished_num_heads, use_laptop_panel, &si->crtc[0].chosen_displays, &si->crtc[1].chosen_displays ); /* si->crtc[0].chosen_displays = dd_none; si->crtc[1].chosen_displays = dd_tv_crt;*/ /*vc->used_crtc[0] = si->crtc[0].chosen_displays != dd_none; vc->used_crtc[1] = si->crtc[1].chosen_displays != dd_none;*/ SHOW_FLOW( 2, "num_crtc: %d, CRTC1 (%s): 0x%x, CRTC2 (%s): 0x%x", si->num_crtc, vc->assigned_crtc[0] ? "assigned" : "not assigned", si->crtc[0].chosen_displays, vc->assigned_crtc[0] ? "assigned" : "not assigned", si->crtc[1].chosen_displays );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -