📄 radeonfb.c
字号:
rinfo->depth = depth; if (freq > rinfo->pll.ppll_max) freq = rinfo->pll.ppll_max; if (freq*12 < rinfo->pll.ppll_min) freq = rinfo->pll.ppll_min / 12; { 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 }, }; for (post_div = &post_divs[0]; post_div->divider; ++post_div) { rinfo->pll_output_freq = post_div->divider * freq; if (rinfo->pll_output_freq >= rinfo->pll.ppll_min && rinfo->pll_output_freq <= rinfo->pll.ppll_max) break; } rinfo->post_div = post_div->divider; rinfo->fb_div = round_div(rinfo->pll.ref_div*rinfo->pll_output_freq, rinfo->pll.ref_clk); newmode.ppll_ref_div = rinfo->pll.ref_div; newmode.ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16); } newmode.vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl;#ifdef CONFIG_ALL_PPC /* Gross hack for iBook with M7 until I find out a proper fix */ if (machine_is_compatible("PowerBook4,3") && rinfo->arch == RADEON_M7) newmode.ppll_div_3 = 0x000600ad;#endif /* CONFIG_ALL_PPC */ RTRACE("post div = 0x%x\n", rinfo->post_div); RTRACE("fb_div = 0x%x\n", rinfo->fb_div); RTRACE("ppll_div_3 = 0x%x\n", newmode.ppll_div_3); /* DDA */ vclk_freq = round_div(rinfo->pll.ref_clk * rinfo->fb_div, rinfo->pll.ref_div * rinfo->post_div); xclk_freq = rinfo->pll.xclk; xclk_per_trans = round_div(xclk_freq * 128, vclk_freq * mode->bits_per_pixel); min_bits = min_bits_req(xclk_per_trans); useable_precision = min_bits + 1; xclk_per_trans_precise = round_div((xclk_freq * 128) << (11 - useable_precision), vclk_freq * mode->bits_per_pixel); ron = (4 * rinfo->ram.mb + 3 * _max(rinfo->ram.trcd - 2, 0) + 2 * rinfo->ram.trp + rinfo->ram.twr + rinfo->ram.cl + rinfo->ram.tr2w + xclk_per_trans) << (11 - useable_precision); roff = xclk_per_trans_precise * (32 - 4); RTRACE("ron = %d, roff = %d\n", ron, roff); RTRACE("vclk_freq = %d, per = %d\n", vclk_freq, xclk_per_trans_precise); if ((ron + rinfo->ram.rloop) >= roff) { printk("radeonfb: error ron out of range\n"); return -EINVAL; } newmode.dda_config = (xclk_per_trans_precise | (useable_precision << 16) | (rinfo->ram.rloop << 20)); newmode.dda_on_off = (ron << 16) | roff; if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { unsigned int hRatio, vRatio; /* We force the pixel clock to be always enabled. Allowing it * to be power managed during blanking would save power, but has * nasty interactions with the 2D engine & sleep code that haven't * been solved yet. --BenH */ newmode.vclk_ecp_cntl &= ~PIXCLK_DAC_ALWAYS_ONb; if (mode->xres > rinfo->panel_xres) mode->xres = rinfo->panel_xres; if (mode->yres > rinfo->panel_yres) mode->yres = rinfo->panel_yres; newmode.fp_horz_stretch = (((rinfo->panel_xres / 8) - 1) << HORZ_PANEL_SHIFT); newmode.fp_vert_stretch = ((rinfo->panel_yres - 1) << VERT_PANEL_SHIFT); if (mode->xres != rinfo->panel_xres) { hRatio = round_div(mode->xres * HORZ_STRETCH_RATIO_MAX, rinfo->panel_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); } newmode.fp_horz_stretch &= ~HORZ_AUTO_RATIO; if (mode->yres != rinfo->panel_yres) { vRatio = round_div(mode->yres * VERT_STRETCH_RATIO_MAX, rinfo->panel_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); } 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); newmode.lvds_gen_cntl = rinfo->init_state.lvds_gen_cntl; newmode.lvds_pll_cntl = rinfo->init_state.lvds_pll_cntl; newmode.tmds_crc = rinfo->init_state.tmds_crc; newmode.tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl; if (primary_mon == MT_LCD) { newmode.lvds_gen_cntl |= (LVDS_ON | LVDS_BLON); newmode.fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN); } else { /* DFP */ newmode.fp_gen_cntl |= (FP_FPON | FP_TMDS_EN); newmode.tmds_transmitter_cntl = (TMDS_RAN_PAT_RST | ICHCSEL | TMDS_PLL_EN) & ~(TMDS_PLLRST); newmode.crtc_ext_cntl &= ~CRTC_CRT_ON; } newmode.fp_crtc_h_total_disp = (((rinfo->hblank / 8) & 0x3ff) | (((mode->xres / 8) - 1) << 16)); newmode.fp_crtc_v_total_disp = (rinfo->vblank & 0xffff) | ((mode->yres - 1) << 16); newmode.fp_h_sync_strt_wid = ((rinfo->hOver_plus & 0x1fff) | (hsync_wid << 16) | (h_sync_pol << 23)); newmode.fp_v_sync_strt_wid = ((rinfo->vOver_plus & 0xfff) | (vsync_wid << 16) | (v_sync_pol << 23)); } /* do it! */ if (!rinfo->asleep) { radeon_write_mode (rinfo, &newmode); /* (re)initialize the engine */ if (!noaccel) radeon_engine_init (rinfo); } /* Update fix */ info->fix.line_length = rinfo->pitch*64; info->fix.visual = rinfo->depth == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;#ifdef CONFIG_BOOTX_TEXT /* Update debug text engine */ btext_update_display(rinfo->fb_base_phys, mode->xres, mode->yres, rinfo->depth, rinfo->pitch*64);#endif return 0;}static void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode){ int i; int primary_mon = PRIMARY_MONITOR(rinfo); radeonfb_blank(VESA_POWERDOWN, (struct fb_info *)rinfo); if (rinfo->arch == RADEON_M6) { for (i=0; i<8; i++) OUTREG(common_regs_m6[i].reg, common_regs_m6[i].val); } else { for (i=0; i<9; i++) OUTREG(common_regs[i].reg, common_regs[i].val); } 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); 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);#if defined(__BIG_ENDIAN) OUTREG(SURFACE_CNTL, mode->surface_cntl);#endif while ((INREG(CLOCK_CNTL_INDEX) & PPLL_DIV_SEL_MASK) != PPLL_DIV_SEL_MASK) { OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, 0xffff); } OUTPLLP(PPLL_CNTL, PPLL_RESET, 0xffff); while ((INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK) != (mode->ppll_ref_div & PPLL_REF_DIV_MASK)) { OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK); } while ((INPLL(PPLL_DIV_3) & PPLL_FB3_DIV_MASK) != (mode->ppll_div_3 & PPLL_FB3_DIV_MASK)) { OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK); } while ((INPLL(PPLL_DIV_3) & PPLL_POST3_DIV_MASK) != (mode->ppll_div_3 & PPLL_POST3_DIV_MASK)) { OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK); } OUTPLL(HTOTAL_CNTL, 0); OUTPLLP(PPLL_CNTL, 0, ~PPLL_RESET);// OUTREG(DDA_CONFIG, mode->dda_config);// OUTREG(DDA_ON_OFF, mode->dda_on_off); if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) { 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 (primary_mon == MT_LCD) { unsigned int tmp = INREG(LVDS_GEN_CNTL); mode->lvds_gen_cntl &= ~LVDS_STATE_MASK; mode->lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_STATE_MASK); if ((tmp & (LVDS_ON | LVDS_BLON)) == (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON))) { OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl); } else { if (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) { udelay(1000); OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl); } else { OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl | LVDS_BLON); udelay(1000); OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl); } } } } radeonfb_blank(VESA_NO_BLANKING, (struct fb_info *)rinfo); OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl); return;}static struct fb_ops radeonfb_ops = { .owner = THIS_MODULE, .fb_check_var = radeonfb_check_var, .fb_set_par = radeonfb_set_par, .fb_setcolreg = radeonfb_setcolreg, .fb_pan_display = radeonfb_pan_display, .fb_blank = radeonfb_blank, .fb_ioctl = radeonfb_ioctl,#if 0 .fb_fillrect = radeonfb_fillrect, .fb_copyarea = radeonfb_copyarea, .fb_imageblit = radeonfb_imageblit, .fb_rasterimg = radeonfb_rasterimg,#else .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit,#endif};static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo){ struct fb_info *info; info = &rinfo->info; info->currcon = -1; info->par = rinfo; info->pseudo_palette = rinfo->pseudo_palette; info->node = NODEV; info->flags = FBINFO_FLAG_DEFAULT; info->fbops = &radeonfb_ops; info->display_fg = NULL; info->screen_base = (char *)rinfo->fb_base; /* Fill fix common fields */ strncpy(info->fix.id, rinfo->name, sizeof(info->fix.id)); info->fix.id[sizeof(info->fix.id) - 1] = '\0'; info->fix.smem_start = rinfo->fb_base_phys; info->fix.smem_len = rinfo->video_ram; info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_PSEUDOCOLOR; info->fix.xpanstep = 8; info->fix.ypanstep = 1; info->fix.ywrapstep = 0; info->fix.type_aux = 0; info->fix.mmio_start = rinfo->mmio_base_phys; info->fix.mmio_len = RADEON_REGSIZE; if (noaccel) info->fix.accel = FB_ACCEL_NONE; else info->fix.accel = FB_ACCEL_ATI_RADEON; if (radeon_init_disp (rinfo) < 0) return -1; return 0;}#ifdef CONFIG_PMAC_BACKLIGHT/* TODO: Dbl check these tables, we don't go up to full ON backlight * in these, possibly because we noticed MacOS doesn't, but I'd prefer * having some more official numbers from ATI */static int backlight_conv_m6[] = { 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24};static int backlight_conv_m7[] = { 0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81, 0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9};#define BACKLIGHT_LVDS_OFF#undef BACKLIGHT_DAC_OFF/* We turn off the LCD completely instead of just dimming the backlight. * This provides some greater power saving and the display is useless * without backlight anyway. */static int radeon_set_backlight_enable(int on, int level, void *data){ struct radeonfb_info *rinfo = (struct radeonfb_info *)data; unsigned int lvds_gen_cntl = INREG(LVDS_GEN_CNTL); int* conv_table; /* Pardon me for that hack... maybe some day we can figure * out in what direction backlight should work on a given * panel ? */ if ((rinfo->arch == RADEON_M7 || rinfo->arch == RADEON_M9) && !machine_is_compatible("PowerBook4,3")) conv_table = backlight_conv_m7; else conv_table = backlight_conv_m6; lvds_gen_cntl |= (LVDS_BL_MOD_EN | LVDS_BLON); if (on && (level > BACKLIGHT_OFF)) { lvds_gen_cntl |= LVDS_DIGON; if (!lvds_gen_cntl & LVDS_ON) { lvds_gen_cntl &= ~LVDS_BLON; OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); (void)INREG(LVDS_GEN_CNTL); mdelay(10); lvds_gen_cntl |= LVDS_BLON; OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); } lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; lvds_gen_cntl |= (conv_table[level] << LVDS_BL_MOD_LEVEL_SHIFT); lvds_gen_cntl |= (LVDS_ON | LVDS_EN); lvds_gen_cntl &= ~LVDS_DISPLAY_DIS; } else { lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK; lvds_gen_cntl |= (conv_table[0] << LVDS_BL_MOD_LEVEL_SHIFT); lvds_gen_cntl |= LVDS_DISPLAY_DIS; OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); udelay(10); lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGON); } OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl); rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK; rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK); return 0;}static int radeon_set_backlight_level(int level, void *data){ return radeon_set_backlight_enable(1, level, data);}#endif /* CONFIG_PMAC_BACKLIGHT */#ifdef CONFIG_PMAC_PBOOKstatic u32 dbg_clk;/* * Radeon M6 Power Management code. This code currently only supports * the mobile chips, it's based from some informations provided by ATI * along with hours of tracing of MacOS drivers */ static void radeon_pm_save_regs(struct radeonfb_info *rinfo){ rinfo->save_regs[0] = INPLL(PLL_PWRMGT_CNTL); rinfo->save_regs[1] = INPLL(CLK_PWRMGT_CNTL); rinfo->save_regs[2] = INPLL(MCLK_CNTL); rinfo->save_regs[3] = INPLL(SCLK_CNTL); rinfo->save_regs[4] = INPLL(CLK_PIN_CNTL); rinfo->save_regs[5] = INPLL(VCLK_ECP_CNTL); rinfo->save_regs[6] = INPLL(PIXCLKS_CNTL); rinfo->save_regs[7] = INPLL(MCLK_MISC); rinfo->save_regs[8] = INPLL(P2PLL_CNTL); rinfo->save_regs[9] = INREG(DISP_MISC_CNTL); rinfo->save_regs[10] = INREG(DISP_PWR_MAN); rinfo->save_regs[11] = INREG(LVDS_GEN_CNTL); rinfo->save_regs[12] = INREG(LVDS_PLL_CNTL); rinfo->save_regs[13] = INREG(TV_DAC_CNTL); rinfo->save_regs[14] = INREG(BUS_CNTL1); rinfo->save_regs[15] = INREG(CRTC_OFFSET_CNTL); rinfo->save_regs[16] = INREG(AGP_CNTL); rinfo->save_regs[17] = (INREG(CRTC_GEN_CNTL) & 0xfdffffff) | 0x04000000; rinfo->save_regs[18] = (INREG(CRTC2_GEN_CNTL) & 0xfdffffff) | 0x04000000; rinfo->save_regs[19] = INREG(GPIOPAD_A); rinfo->save_regs[20] = INREG(GPIOPAD_EN); rinfo->save_regs[21] = INREG(GPIOPAD_MASK); rinfo->save_regs[22] = INREG(ZV_LCDPAD_A); rinfo->save_regs[23] = INREG(ZV_LCDPAD_EN); rinfo->save_regs[24] = INREG(ZV_LCDPAD_MASK); rinfo->save_regs[25] = INREG(GPIO_VGA_DDC); rinfo->save_regs[26] = INREG(GPIO_DVI_DDC); rinfo->save_regs[27] = INREG(GPIO_MONID); rinfo->save_regs[28] = INREG(GPIO_CRT2_DDC); rinfo->save_regs[29] = INREG(SURFACE_CNTL); rinfo->save_regs[30] = INREG(MC_FB_LOCATION); rinfo->save_regs[31] = INREG(DISPLAY_BASE_ADDR); rinfo->save_regs[32] = INREG(MC_AGP_LOCATION); rin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -