📄 radeon_base.c
字号:
radeon_fifo_wait(31); for (i=0; i<10; i++) OUTREG(common_regs[i].reg, common_regs[i].val); /* Apply surface registers */ for (i=0; i<8; i++) { OUTREG(SURFACE0_LOWER_BOUND + 0x10*i, mode->surf_lower_bound[i]); OUTREG(SURFACE0_UPPER_BOUND + 0x10*i, mode->surf_upper_bound[i]); OUTREG(SURFACE0_INFO + 0x10*i, mode->surf_info[i]); } OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl); OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl, ~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS)); OUTREG(CRTC_MORE_CNTL, mode->crtc_more_cntl); OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING); OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp); OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid); OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp); OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid); OUTREG(CRTC_OFFSET, 0); OUTREG(CRTC_OFFSET_CNTL, 0); OUTREG(CRTC_PITCH, mode->crtc_pitch); OUTREG(SURFACE_CNTL, mode->surface_cntl); radeon_write_pll_regs(rinfo, mode); if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { radeon_fifo_wait(10); OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp); OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp); OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid); OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid); OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch); OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch); OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl); OUTREG(TMDS_CRC, mode->tmds_crc); OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl); } if (!regs_only) radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0); radeon_fifo_wait(2); OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl); return;}/* * Calculate the PLL values for a given mode */static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *regs, unsigned long freq){ const struct { int divider; int bitvalue; } *post_div, post_divs[] = { { 1, 0 }, { 2, 1 }, { 4, 2 }, { 8, 3 }, { 3, 4 }, { 16, 5 }, { 6, 6 }, { 12, 7 }, { 0, 0 }, }; int fb_div, pll_output_freq = 0; int uses_dvo = 0; /* Check if the DVO port is enabled and sourced from the primary CRTC. I'm * not sure which model starts having FP2_GEN_CNTL, I assume anything more * recent than an r(v)100... */#if 1 /* XXX I had reports of flicker happening with the cinema display * on TMDS1 that seem to be fixed if I also forbit odd dividers in * this case. This could just be a bandwidth calculation issue, I * haven't implemented the bandwidth code yet, but in the meantime, * forcing uses_dvo to 1 fixes it and shouln't have bad side effects, * I haven't seen a case were were absolutely needed an odd PLL * divider. I'll find a better fix once I have more infos on the * real cause of the problem. */ while (rinfo->has_CRTC2) { u32 fp2_gen_cntl = INREG(FP2_GEN_CNTL); u32 disp_output_cntl; int source; /* FP2 path not enabled */ if ((fp2_gen_cntl & FP2_ON) == 0) break; /* Not all chip revs have the same format for this register, * extract the source selection */ if (rinfo->family == CHIP_FAMILY_R200 || rinfo->family == CHIP_FAMILY_R300 || rinfo->family == CHIP_FAMILY_R350 || rinfo->family == CHIP_FAMILY_RV350) { source = (fp2_gen_cntl >> 10) & 0x3; /* sourced from transform unit, check for transform unit * own source */ if (source == 3) { disp_output_cntl = INREG(DISP_OUTPUT_CNTL); source = (disp_output_cntl >> 12) & 0x3; } } else source = (fp2_gen_cntl >> 13) & 0x1; /* sourced from CRTC2 -> exit */ if (source == 1) break; /* so we end up on CRTC1, let's set uses_dvo to 1 now */ uses_dvo = 1; break; }#else uses_dvo = 1;#endif if (freq > rinfo->pll.ppll_max) freq = rinfo->pll.ppll_max; if (freq*12 < rinfo->pll.ppll_min) freq = rinfo->pll.ppll_min / 12; RTRACE("freq = %lu, PLL min = %u, PLL max = %u\n", freq, rinfo->pll.ppll_min, rinfo->pll.ppll_max); for (post_div = &post_divs[0]; post_div->divider; ++post_div) { pll_output_freq = post_div->divider * freq; /* If we output to the DVO port (external TMDS), we don't allow an * odd PLL divider as those aren't supported on this path */ if (uses_dvo && (post_div->divider & 1)) continue; if (pll_output_freq >= rinfo->pll.ppll_min && pll_output_freq <= rinfo->pll.ppll_max) break; } /* If we fall through the bottom, try the "default value" given by the terminal post_div->bitvalue */ if ( !post_div->divider ) { post_div = &post_divs[post_div->bitvalue]; pll_output_freq = post_div->divider * freq; } RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n", rinfo->pll.ref_div, rinfo->pll.ref_clk, pll_output_freq); /* If we fall through the bottom, try the "default value" given by the terminal post_div->bitvalue */ if ( !post_div->divider ) { post_div = &post_divs[post_div->bitvalue]; pll_output_freq = post_div->divider * freq; } RTRACE("ref_div = %d, ref_clk = %d, output_freq = %d\n", rinfo->pll.ref_div, rinfo->pll.ref_clk, pll_output_freq); fb_div = round_div(rinfo->pll.ref_div*pll_output_freq, rinfo->pll.ref_clk); regs->ppll_ref_div = rinfo->pll.ref_div; regs->ppll_div_3 = fb_div | (post_div->bitvalue << 16); RTRACE("post div = 0x%x\n", post_div->bitvalue); RTRACE("fb_div = 0x%x\n", fb_div); RTRACE("ppll_div_3 = 0x%x\n", regs->ppll_div_3);}static int radeonfb_set_par(struct fb_info *info){ struct radeonfb_info *rinfo = info->par; struct fb_var_screeninfo *mode = &info->var; struct radeon_regs *newmode; int hTotal, vTotal, hSyncStart, hSyncEnd, hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync; u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5}; u8 hsync_fudge_fp[] = {2, 2, 0, 0, 5, 5}; u32 sync, h_sync_pol, v_sync_pol, dotClock, pixClock; int i, freq; int format = 0; int nopllcalc = 0; int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; int primary_mon = PRIMARY_MONITOR(rinfo); int depth = var_to_depth(mode); int use_rmx = 0; newmode = kmalloc(sizeof(struct radeon_regs), GFP_KERNEL); if (!newmode) return -ENOMEM; /* We always want engine to be idle on a mode switch, even * if we won't actually change the mode */ radeon_engine_idle(); hSyncStart = mode->xres + mode->right_margin; hSyncEnd = hSyncStart + mode->hsync_len; hTotal = hSyncEnd + mode->left_margin; vSyncStart = mode->yres + mode->lower_margin; vSyncEnd = vSyncStart + mode->vsync_len; vTotal = vSyncEnd + mode->upper_margin; pixClock = mode->pixclock; sync = mode->sync; h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; if (primary_mon == MT_DFP || primary_mon == MT_LCD) { if (rinfo->panel_info.xres < mode->xres) mode->xres = rinfo->panel_info.xres; if (rinfo->panel_info.yres < mode->yres) mode->yres = rinfo->panel_info.yres; hTotal = mode->xres + rinfo->panel_info.hblank; hSyncStart = mode->xres + rinfo->panel_info.hOver_plus; hSyncEnd = hSyncStart + rinfo->panel_info.hSync_width; vTotal = mode->yres + rinfo->panel_info.vblank; vSyncStart = mode->yres + rinfo->panel_info.vOver_plus; vSyncEnd = vSyncStart + rinfo->panel_info.vSync_width; h_sync_pol = !rinfo->panel_info.hAct_high; v_sync_pol = !rinfo->panel_info.vAct_high; pixClock = 100000000 / rinfo->panel_info.clock; if (rinfo->panel_info.use_bios_dividers) { nopllcalc = 1; newmode->ppll_div_3 = rinfo->panel_info.fbk_divider | (rinfo->panel_info.post_divider << 16); newmode->ppll_ref_div = rinfo->panel_info.ref_divider; } } dotClock = 1000000000 / pixClock; freq = dotClock / 10; /* x100 */ RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n", hSyncStart, hSyncEnd, hTotal); RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n", vSyncStart, vSyncEnd, vTotal); hsync_wid = (hSyncEnd - hSyncStart) / 8; vsync_wid = vSyncEnd - vSyncStart; if (hsync_wid == 0) hsync_wid = 1; else if (hsync_wid > 0x3f) /* max */ hsync_wid = 0x3f; if (vsync_wid == 0) vsync_wid = 1; else if (vsync_wid > 0x1f) /* max */ vsync_wid = 0x1f; hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; format = radeon_get_dstbpp(depth); bytpp = mode->bits_per_pixel >> 3; if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) hsync_fudge = hsync_fudge_fp[format-1]; else hsync_fudge = hsync_adj_tab[format-1]; hsync_start = hSyncStart - 8 + hsync_fudge; newmode->crtc_gen_cntl = CRTC_EXT_DISP_EN | CRTC_EN | (format << 8); /* Clear auto-center etc... */ newmode->crtc_more_cntl = rinfo->init_state.crtc_more_cntl; newmode->crtc_more_cntl &= 0xfffffff0; if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN; if (mirror) newmode->crtc_ext_cntl |= CRTC_CRT_ON; newmode->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN | CRTC_INTERLACE_EN); } else { newmode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | CRTC_CRT_ON; } newmode->dac_cntl = /* INREG(DAC_CNTL) | */ DAC_MASK_ALL | DAC_VGA_ADR_EN | DAC_8BIT_EN; newmode->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) | (((mode->xres / 8) - 1) << 16)); newmode->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) | (hsync_wid << 16) | (h_sync_pol << 23)); newmode->crtc_v_total_disp = ((vTotal - 1) & 0xffff) | ((mode->yres - 1) << 16); newmode->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | (vsync_wid << 16) | (v_sync_pol << 23)); if (!(info->flags & FBINFO_HWACCEL_DISABLED)) { /* We first calculate the engine pitch */ rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f) & ~(0x3f)) >> 6; /* Then, re-multiply it to get the CRTC pitch */ newmode->crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8); } else newmode->crtc_pitch = (mode->xres_virtual >> 3); newmode->crtc_pitch |= (newmode->crtc_pitch << 16); /* * It looks like recent chips have a problem with SURFACE_CNTL, * setting SURF_TRANSLATION_DIS completely disables the * swapper as well, so we leave it unset now. */ newmode->surface_cntl = 0;#if defined(__BIG_ENDIAN) /* Setup swapping on both apertures, though we currently * only use aperture 0, enabling swapper on aperture 1 * won't harm */ switch (mode->bits_per_pixel) { case 16: newmode->surface_cntl |= NONSURF_AP0_SWP_16BPP; newmode->surface_cntl |= NONSURF_AP1_SWP_16BPP; break; case 24: case 32: newmode->surface_cntl |= NONSURF_AP0_SWP_32BPP; newmode->surface_cntl |= NONSURF_AP1_SWP_32BPP; break; }#endif /* Clear surface registers */ for (i=0; i<8; i++) { newmode->surf_lower_bound[i] = 0; newmode->surf_upper_bound[i] = 0x1f; newmode->surf_info[i] = 0; } RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", newmode->crtc_h_total_disp, newmode->crtc_h_sync_strt_wid); RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", newmode->crtc_v_total_disp, newmode->crtc_v_sync_strt_wid); rinfo->bpp = mode->bits_per_pixel; rinfo->depth = depth; RTRACE("pixclock = %lu\n", (unsigned long)pixClock); RTRACE("freq = %lu\n", (unsigned long)freq); /* We use PPLL_DIV_3 */ newmode->clk_cntl_index = 0x300; /* Calculate PPLL value if necessary */ if (!nopllcalc) radeon_calc_pll_regs(rinfo, newmode, freq); newmode->vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl; if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { unsigned int hRatio, vRatio; if (mode->xres > rinfo->panel_info.xres) mode->xres = rinfo->panel_info.xres; if (mode->yres > rinfo->panel_info.yres) mode->yres = rinfo->panel_info.yres; newmode->fp_horz_stretch = (((rinfo->panel_info.xres / 8) - 1) << HORZ_PANEL_SHIFT); newmode->fp_vert_stretch = ((rinfo->panel_info.yres - 1) << VERT_PANEL_SHIFT); if (mode->xres != rinfo->panel_info.xres) { hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX, rinfo->panel_info.xres); newmode->fp_horz_stretch = (((((unsigned long)hRatio) & HORZ_STRETCH_RATIO_MASK)) | (newmode->fp_horz_stretch & (HORZ_PANEL_SIZE | HORZ_FP_LOOP_STRETCH | HORZ_AUTO_RATIO_INC))); newmode->fp_horz_stretch |= (HORZ_STRETCH_BLEND | HORZ_STRETCH_ENABLE); use_rmx = 1; } newmode->fp_horz_stretch &= ~HORZ_AUTO_RATIO; if (mode->yres != rinfo->panel_info.yres) { vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX, rinfo->panel_info.yres); newmode->fp_vert_stretch = (((((unsigned long)vRatio) & VERT_STRETCH_RATIO_MASK)) | (newmode->fp_vert_stretch & (VERT_PANEL_SIZE | VERT_STRETCH_RESERVED))); newmode->fp_vert_stretch |= (VERT_STRETCH_BLEND | VERT_STRETCH_ENABLE); use_rmx = 1; } newmode->fp_vert_stretch &= ~VERT_AUTO_RATIO_EN; newmode->fp_gen_cntl = (rinfo->init_state.fp_gen_cntl & (u32) ~(FP_SEL_CRTC2 | FP_RMX_HVSYNC_CONTROL_EN | FP_DFP_SYNC_SEL | FP_CRT_SYNC_SEL | FP_CRTC_LOCK_8DOT | FP_USE_SHADOW_EN | FP_CRTC_USE_SHADOW_VEND | FP_CRT_SYNC_ALT)); newmode->fp_gen_cntl |= (FP_CRTC_DONT_SHADOW_VPAR | FP_CRTC_DONT_SHADOW_HEND | FP_PANEL_FORMAT); if (IS_R300_VARIANT(rinfo) || (rinfo->family == CHIP_FAMILY_R200)) { newmode->fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK; if (use_rmx) newmode->fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX; else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -