📄 radeon_base.c
字号:
static int radeonfb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, struct fb_info *info){ struct radeonfb_info *rinfo = info->par; unsigned int tmp; u32 value = 0; int rc; switch (cmd) { /* * TODO: set mirror accordingly for non-Mobility chipsets with 2 CRTC's * and do something better using 2nd CRTC instead of just hackish * routing to second output */ case FBIO_RADEON_SET_MIRROR: if (!rinfo->is_mobility) return -EINVAL; rc = get_user(value, (__u32 __user *)arg); if (rc) return rc; radeon_fifo_wait(2); if (value & 0x01) { tmp = INREG(LVDS_GEN_CNTL); tmp |= (LVDS_ON | LVDS_BLON); } else { tmp = INREG(LVDS_GEN_CNTL); tmp &= ~(LVDS_ON | LVDS_BLON); } OUTREG(LVDS_GEN_CNTL, tmp); if (value & 0x02) { tmp = INREG(CRTC_EXT_CNTL); tmp |= CRTC_CRT_ON; mirror = 1; } else { tmp = INREG(CRTC_EXT_CNTL); tmp &= ~CRTC_CRT_ON; mirror = 0; } OUTREG(CRTC_EXT_CNTL, tmp); return 0; case FBIO_RADEON_GET_MIRROR: if (!rinfo->is_mobility) return -EINVAL; tmp = INREG(LVDS_GEN_CNTL); if ((LVDS_ON | LVDS_BLON) & tmp) value |= 0x01; tmp = INREG(CRTC_EXT_CNTL); if (CRTC_CRT_ON & tmp) value |= 0x02; return put_user(value, (__u32 __user *)arg); default: return -EINVAL; } return -EINVAL;}int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch){ u32 val; u32 tmp_pix_clks; int unblank = 0; if (rinfo->lock_blank) return 0; radeon_engine_idle(); val = INREG(CRTC_EXT_CNTL); val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS | CRTC_VSYNC_DIS); switch (blank) { case FB_BLANK_VSYNC_SUSPEND: val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS); break; case FB_BLANK_HSYNC_SUSPEND: val |= (CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS); break; case FB_BLANK_POWERDOWN: val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS); break; case FB_BLANK_NORMAL: val |= CRTC_DISPLAY_DIS; break; case FB_BLANK_UNBLANK: default: unblank = 1; } OUTREG(CRTC_EXT_CNTL, val); switch (rinfo->mon1_type) { case MT_DFP: if (unblank) OUTREGP(FP_GEN_CNTL, (FP_FPON | FP_TMDS_EN), ~(FP_FPON | FP_TMDS_EN)); else { if (mode_switch || blank == FB_BLANK_NORMAL) break; OUTREGP(FP_GEN_CNTL, 0, ~(FP_FPON | FP_TMDS_EN)); } break; case MT_LCD: del_timer_sync(&rinfo->lvds_timer); val = INREG(LVDS_GEN_CNTL); if (unblank) { u32 target_val = (val & ~LVDS_DISPLAY_DIS) | LVDS_BLON | LVDS_ON | LVDS_EN | (rinfo->init_state.lvds_gen_cntl & (LVDS_DIGON | LVDS_BL_MOD_EN)); if ((val ^ target_val) == LVDS_DISPLAY_DIS) OUTREG(LVDS_GEN_CNTL, target_val); else if ((val ^ target_val) != 0) { OUTREG(LVDS_GEN_CNTL, target_val & ~(LVDS_ON | LVDS_BL_MOD_EN)); rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; rinfo->init_state.lvds_gen_cntl |= target_val & LVDS_STATE_MASK; if (mode_switch) { radeon_msleep(rinfo->panel_info.pwr_delay); OUTREG(LVDS_GEN_CNTL, target_val); } else { rinfo->pending_lvds_gen_cntl = target_val; mod_timer(&rinfo->lvds_timer, jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); } } } else { val |= LVDS_DISPLAY_DIS; OUTREG(LVDS_GEN_CNTL, val); /* We don't do a full switch-off on a simple mode switch */ if (mode_switch || blank == FB_BLANK_NORMAL) break; /* Asic bug, when turning off LVDS_ON, we have to make sure * RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off */ tmp_pix_clks = INPLL(PIXCLKS_CNTL); if (rinfo->is_mobility || rinfo->is_IGP) OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb); val &= ~(LVDS_BL_MOD_EN); OUTREG(LVDS_GEN_CNTL, val); udelay(100); val &= ~(LVDS_ON | LVDS_EN); OUTREG(LVDS_GEN_CNTL, val); val &= ~LVDS_DIGON; rinfo->pending_lvds_gen_cntl = val; mod_timer(&rinfo->lvds_timer, jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay)); rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; rinfo->init_state.lvds_gen_cntl |= val & LVDS_STATE_MASK; if (rinfo->is_mobility || rinfo->is_IGP) OUTPLL(PIXCLKS_CNTL, tmp_pix_clks); } break; case MT_CRT: // todo: powerdown DAC default: break; } /* let fbcon do a soft blank for us */ return (blank == FB_BLANK_NORMAL) ? -EINVAL : 0;}static int radeonfb_blank (int blank, struct fb_info *info){ struct radeonfb_info *rinfo = info->par; if (rinfo->asleep) return 0; return radeon_screen_blank(rinfo, blank, 0);}static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct radeonfb_info *rinfo){ u32 pindex; unsigned int i; if (regno > 255) return 1; red >>= 8; green >>= 8; blue >>= 8; rinfo->palette[regno].red = red; rinfo->palette[regno].green = green; rinfo->palette[regno].blue = blue; /* default */ pindex = regno; if (!rinfo->asleep) { radeon_fifo_wait(9); if (rinfo->bpp == 16) { pindex = regno * 8; if (rinfo->depth == 16 && regno > 63) return 1; if (rinfo->depth == 15 && regno > 31) return 1; /* For 565, the green component is mixed one order * below */ if (rinfo->depth == 16) { OUTREG(PALETTE_INDEX, pindex>>1); OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) | (green << 8) | (rinfo->palette[regno>>1].blue)); green = rinfo->palette[regno<<1].green; } } if (rinfo->depth != 16 || regno < 32) { OUTREG(PALETTE_INDEX, pindex); OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue); } } if (regno < 16) { u32 *pal = rinfo->info->pseudo_palette; switch (rinfo->depth) { case 15: pal[regno] = (regno << 10) | (regno << 5) | regno; break; case 16: pal[regno] = (regno << 11) | (regno << 5) | regno; break; case 24: pal[regno] = (regno << 16) | (regno << 8) | regno; break; case 32: i = (regno << 8) | regno; pal[regno] = (i << 16) | i; break; } } return 0;}static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info){ struct radeonfb_info *rinfo = info->par; u32 dac_cntl2, vclk_cntl = 0; int rc; if (!rinfo->asleep) { if (rinfo->is_mobility) { vclk_cntl = INPLL(VCLK_ECP_CNTL); OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb); } /* Make sure we are on first palette */ if (rinfo->has_CRTC2) { dac_cntl2 = INREG(DAC_CNTL2); dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL; OUTREG(DAC_CNTL2, dac_cntl2); } } rc = radeon_setcolreg (regno, red, green, blue, transp, rinfo); if (!rinfo->asleep && rinfo->is_mobility) OUTPLL(VCLK_ECP_CNTL, vclk_cntl); return rc;}static int radeonfb_setcmap(struct fb_cmap *cmap, struct fb_info *info){ struct radeonfb_info *rinfo = info->par; u16 *red, *green, *blue, *transp; u32 dac_cntl2, vclk_cntl = 0; int i, start, rc = 0; if (!rinfo->asleep) { if (rinfo->is_mobility) { vclk_cntl = INPLL(VCLK_ECP_CNTL); OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb); } /* Make sure we are on first palette */ if (rinfo->has_CRTC2) { dac_cntl2 = INREG(DAC_CNTL2); dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL; OUTREG(DAC_CNTL2, dac_cntl2); } } red = cmap->red; green = cmap->green; blue = cmap->blue; transp = cmap->transp; start = cmap->start; for (i = 0; i < cmap->len; i++) { u_int hred, hgreen, hblue, htransp = 0xffff; hred = *red++; hgreen = *green++; hblue = *blue++; if (transp) htransp = *transp++; rc = radeon_setcolreg (start++, hred, hgreen, hblue, htransp, rinfo); if (rc) break; } if (!rinfo->asleep && rinfo->is_mobility) OUTPLL(VCLK_ECP_CNTL, vclk_cntl); return rc;}static void radeon_save_state (struct radeonfb_info *rinfo, struct radeon_regs *save){ /* CRTC regs */ save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL); save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL); save->crtc_more_cntl = INREG(CRTC_MORE_CNTL); save->dac_cntl = INREG(DAC_CNTL); save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP); save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID); save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP); save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID); save->crtc_pitch = INREG(CRTC_PITCH); save->surface_cntl = INREG(SURFACE_CNTL); /* FP regs */ save->fp_crtc_h_total_disp = INREG(FP_CRTC_H_TOTAL_DISP); save->fp_crtc_v_total_disp = INREG(FP_CRTC_V_TOTAL_DISP); save->fp_gen_cntl = INREG(FP_GEN_CNTL); save->fp_h_sync_strt_wid = INREG(FP_H_SYNC_STRT_WID); save->fp_horz_stretch = INREG(FP_HORZ_STRETCH); save->fp_v_sync_strt_wid = INREG(FP_V_SYNC_STRT_WID); save->fp_vert_stretch = INREG(FP_VERT_STRETCH); save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL); save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL); save->tmds_crc = INREG(TMDS_CRC); save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL); save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL); /* PLL regs */ save->clk_cntl_index = INREG(CLOCK_CNTL_INDEX) & ~0x3f; radeon_pll_errata_after_index(rinfo); save->ppll_div_3 = INPLL(PPLL_DIV_3); save->ppll_ref_div = INPLL(PPLL_REF_DIV);}static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *mode){ int i; radeon_fifo_wait(20); /* Workaround from XFree */ if (rinfo->is_mobility) { /* A temporal workaround for the occational blanking on certain laptop * panels. This appears to related to the PLL divider registers * (fail to lock?). It occurs even when all dividers are the same * with their old settings. In this case we really don't need to * fiddle with PLL registers. By doing this we can avoid the blanking * problem with some panels. */ if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) && (mode->ppll_div_3 == (INPLL(PPLL_DIV_3) & (PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) { /* We still have to force a switch to selected PPLL div thanks to * an XFree86 driver bug which will switch it away in some cases * even when using UseFDev */ OUTREGP(CLOCK_CNTL_INDEX, mode->clk_cntl_index & PPLL_DIV_SEL_MASK, ~PPLL_DIV_SEL_MASK); radeon_pll_errata_after_index(rinfo); radeon_pll_errata_after_data(rinfo); return; } } /* Swich VCKL clock input to CPUCLK so it stays fed while PPLL updates*/ OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_CPUCLK, ~VCLK_SRC_SEL_MASK); /* Reset PPLL & enable atomic update */ OUTPLLP(PPLL_CNTL, PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN, ~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN)); /* Switch to selected PPLL divider */ OUTREGP(CLOCK_CNTL_INDEX, mode->clk_cntl_index & PPLL_DIV_SEL_MASK, ~PPLL_DIV_SEL_MASK); radeon_pll_errata_after_index(rinfo); radeon_pll_errata_after_data(rinfo); /* Set PPLL ref. div */ if (rinfo->family == CHIP_FAMILY_R300 || rinfo->family == CHIP_FAMILY_RS300 ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -