📄 radeon_base.c
字号:
rinfo->family == CHIP_FAMILY_R350 || rinfo->family == CHIP_FAMILY_RV350) { if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) { /* When restoring console mode, use saved PPLL_REF_DIV * setting. */ OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, 0); } else { /* R300 uses ref_div_acc field as real ref divider */ OUTPLLP(PPLL_REF_DIV, (mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), ~R300_PPLL_REF_DIV_ACC_MASK); } } else OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK); /* Set PPLL divider 3 & post divider*/ OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK); OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK); /* Write update */ while (INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R) ; OUTPLLP(PPLL_REF_DIV, PPLL_ATOMIC_UPDATE_W, ~PPLL_ATOMIC_UPDATE_W); /* Wait read update complete */ /* FIXME: Certain revisions of R300 can't recover here. Not sure of the cause yet, but this workaround will mask the problem for now. Other chips usually will pass at the very first test, so the workaround shouldn't have any effect on them. */ for (i = 0; (i < 10000 && INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); i++) ; OUTPLL(HTOTAL_CNTL, 0); /* Clear reset & atomic update */ OUTPLLP(PPLL_CNTL, 0, ~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN)); /* We may want some locking ... oh well */ radeon_msleep(5); /* Switch back VCLK source to PPLL */ OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK);}/* * Timer function for delayed LVDS panel power up/down */static void radeon_lvds_timer_func(unsigned long data){ struct radeonfb_info *rinfo = (struct radeonfb_info *)data; radeon_engine_idle(); OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl);}/* * Apply a video mode. This will apply the whole register set, including * the PLL registers, to the card */void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode, int regs_only){ int i; int primary_mon = PRIMARY_MONITOR(rinfo); if (nomodeset) return; if (!regs_only) radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0); 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -