📄 radeonfb.c
字号:
static void radeon_pm_yclk_mclk_sync(struct radeonfb_info *rinfo);static void radeon_pm_program_mode_reg(struct radeonfb_info *rinfo, u16 value, u8 delay_required);static void radeon_pm_enable_dll(struct radeonfb_info *rinfo);static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo);#endif /* CONFIG_PMAC_BACKLIGHT */static struct fb_ops radeon_fb_ops = { fb_get_fix: radeonfb_get_fix, fb_get_var: radeonfb_get_var, fb_set_var: radeonfb_set_var, fb_get_cmap: radeonfb_get_cmap, fb_set_cmap: radeonfb_set_cmap, fb_pan_display: radeonfb_pan_display, fb_ioctl: radeonfb_ioctl,};static struct pci_driver radeonfb_driver = { name: "radeonfb", id_table: radeonfb_pci_table, probe: radeonfb_pci_register, remove: __devexit_p(radeonfb_pci_unregister),};int __init radeonfb_init (void){ return pci_module_init (&radeonfb_driver);}void __exit radeonfb_exit (void){ pci_unregister_driver (&radeonfb_driver);}int __init radeonfb_setup (char *options){ char *this_opt; if (!options || !*options) return 0; while ((this_opt = strsep (&options, ",")) != NULL) { if (!*this_opt) continue; if (!strncmp (this_opt, "font:", 5)) { char *p; int i; p = this_opt + 5; for (i=0; i<sizeof (fontname) - 1; i++) if (!*p || *p == ' ' || *p == ',') break; memcpy(fontname, this_opt + 5, i); } else if (!strncmp(this_opt, "noaccel", 7)) { noaccel = 1; } else if (!strncmp(this_opt, "mirror", 6)) { mirror = 1; } else if (!strncmp(this_opt, "dfp", 3)) { force_dfp = 1; force_nolcd = 1; } else if (!strncmp(this_opt, "crt", 3)) { force_crt = 1; force_nolcd = 1; } else if (!strncmp(this_opt, "nolcd", 5)) { force_nolcd = 1; } else if (!strncmp(this_opt, "panel_yres:", 11)) { panel_yres = simple_strtoul((this_opt+11), NULL, 0); } else if (!strncmp(this_opt, "nomtrr", 6)) { nomtrr = 1; } else mode_option = this_opt; } return 0;}#ifdef MODULEmodule_init(radeonfb_init);module_exit(radeonfb_exit);#endifMODULE_AUTHOR("Ani Joshi");MODULE_DESCRIPTION("framebuffer driver for ATI Radeon chipset");MODULE_LICENSE("GPL");MODULE_PARM(noaccel, "i");MODULE_PARM_DESC(noaccel, "Disable (1) or enable (0) the usage of the 2d accel engine");MODULE_PARM(force_dfp, "i");MODULE_PARM_DESC(force_dfp,"Force (1) the usage of a digital flat panel");MODULE_PARM(force_crt, "i");MODULE_PARM_DESC(force_crt,"Force (1) the usage of a CRT monitor");MODULE_PARM(force_nolcd, "i");MODULE_PARM_DESC(force_nolcd,"Avoid (1) the usage of a digital flat panel");static unsigned char *radeon_find_rom(struct radeonfb_info *rinfo){ #if defined(__i386__) /* I simplified this code as we used to miss the signatures in * a lot of case. It's now closer to XFree, we just don't check * for signatures at all... Something better will have to be done * later obviously */ u32 segstart; unsigned char *rom_base; for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { rom_base = (char *)ioremap(segstart, 0x1000); if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa)) return rom_base; iounmap(rom_base); }#endif return NULL;}#ifdef CONFIG_ALL_PPCstatic int radeon_read_OF (struct radeonfb_info *rinfo){ struct device_node *dp; unsigned int *xtal; dp = pci_device_to_OF_node(rinfo->pdev); if (dp == NULL) return 0; xtal = (unsigned int *) get_property(dp, "ATY,RefCLK", 0); if ((xtal == NULL) || (*xtal == 0)) return 0; rinfo->pll.ref_clk = *xtal / 10; return 1;}#endif static void radeon_get_pllinfo(struct radeonfb_info *rinfo, char *bios_seg){ void *bios_header; void *header_ptr; u16 bios_header_offset, pll_info_offset; PLL_BLOCK pll; if (bios_seg) { bios_header = bios_seg + 0x48L; header_ptr = bios_header; bios_header_offset = readw(header_ptr); bios_header = bios_seg + bios_header_offset; bios_header += 0x30; header_ptr = bios_header; pll_info_offset = readw(header_ptr); header_ptr = bios_seg + pll_info_offset; memcpy_fromio(&pll, header_ptr, 50); /* Consider ref clock to be sane between 1000 and 5000, * just in case we tapped the wrong BIOS... */ if (pll.PCLK_ref_freq < 1000 || pll.PCLK_ref_freq > 5000) goto use_defaults; rinfo->pll.xclk = (u32)pll.XCLK; rinfo->pll.ref_clk = (u32)pll.PCLK_ref_freq; rinfo->pll.ref_div = (u32)pll.PCLK_ref_divider; rinfo->pll.ppll_min = pll.PCLK_min_freq; rinfo->pll.ppll_max = pll.PCLK_max_freq; printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from BIOS\n", rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk); } else {#ifdef CONFIG_ALL_PPC if (radeon_read_OF(rinfo)) { unsigned int tmp, Nx, M, ref_div, xclk; tmp = INPLL(M_SPLL_REF_FB_DIV); ref_div = INPLL(PPLL_REF_DIV) & 0x3ff; Nx = (tmp & 0xff00) >> 8; M = (tmp & 0xff); xclk = ((((2 * Nx * rinfo->pll.ref_clk) + (M)) / (2 * M))); rinfo->pll.xclk = xclk; rinfo->pll.ref_div = ref_div; rinfo->pll.ppll_min = 12000; rinfo->pll.ppll_max = 35000; printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from OF\n", rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk); return; }#endifuse_defaults: /* No BIOS or BIOS not found, use defaults * * NOTE: Those defaults settings are rather "randomly" picked from * informations we found so far, but we would really need some * better mecanism to get them. Recent XFree can +/- probe for * the proper clocks. */ switch (rinfo->arch) { case RADEON_RV200: rinfo->pll.ppll_max = 35000; rinfo->pll.ppll_min = 12000; rinfo->pll.xclk = 23000; rinfo->pll.ref_div = 12; rinfo->pll.ref_clk = 2700; break; case RADEON_R200: rinfo->pll.ppll_max = 35000; rinfo->pll.ppll_min = 12000; rinfo->pll.xclk = 27500; rinfo->pll.ref_div = 12; rinfo->pll.ref_clk = 2700; break; case RADEON_RV250: rinfo->pll.ppll_max = 35000; rinfo->pll.ppll_min = 12000; rinfo->pll.xclk = 25000; rinfo->pll.ref_div = 12; rinfo->pll.ref_clk = 2700; break; case RADEON_R300: rinfo->pll.ppll_max = 40000; rinfo->pll.ppll_min = 20000; rinfo->pll.xclk = 27000; rinfo->pll.ref_div = 12; rinfo->pll.ref_clk = 2700; break; case RADEON_R100: default: rinfo->pll.ppll_max = 35000; rinfo->pll.ppll_min = 12000; rinfo->pll.xclk = 16600; rinfo->pll.ref_div = 67; rinfo->pll.ref_clk = 2700; break; } printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d defaults\n", rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk); }}static void radeon_get_moninfo (struct radeonfb_info *rinfo){ u32 tmp = INREG(RADEON_BIOS_4_SCRATCH); if (force_dfp) { printk("radeonfb: forcing DFP\n"); rinfo->dviDisp_type = MT_DFP; return; } else if (force_crt) { printk("radeonfb: forcing CRT\n"); rinfo->dviDisp_type = MT_NONE; rinfo->crtDisp_type = MT_CRT; return; } if (rinfo->hasCRTC2 && tmp) { /* primary DVI port */ if (tmp & 0x08) rinfo->dviDisp_type = MT_DFP; else if (tmp & 0x4) rinfo->dviDisp_type = MT_LCD; else if (tmp & 0x200) rinfo->dviDisp_type = MT_CRT; else if (tmp & 0x10) rinfo->dviDisp_type = MT_CTV; else if (tmp & 0x20) rinfo->dviDisp_type = MT_STV; /* secondary CRT port */ if (tmp & 0x2) rinfo->crtDisp_type = MT_CRT; else if (tmp & 0x800) rinfo->crtDisp_type = MT_DFP; else if (tmp & 0x400) rinfo->crtDisp_type = MT_LCD; else if (tmp & 0x1000) rinfo->crtDisp_type = MT_CTV; else if (tmp & 0x2000) rinfo->crtDisp_type = MT_STV; } else { rinfo->dviDisp_type = MT_NONE; tmp = INREG(FP_GEN_CNTL); if (tmp & FP_EN_TMDS) rinfo->crtDisp_type = MT_DFP; else rinfo->crtDisp_type = MT_CRT; }}#ifdef CONFIG_ALL_PPCstatic int radeon_get_EDID_OF(struct radeonfb_info *rinfo){ struct device_node *dp; unsigned char *pedid = NULL; static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL }; int i; dp = pci_device_to_OF_node(rinfo->pdev); while (dp != NULL) { for (i = 0; propnames[i] != NULL; ++i) { pedid = (unsigned char *) get_property(dp, propnames[i], NULL); if (pedid != NULL) { rinfo->EDID = pedid; return 1; } } dp = dp->child; } return 0;}#endif /* CONFIG_ALL_PPC */static void radeon_get_EDID(struct radeonfb_info *rinfo){#ifdef CONFIG_ALL_PPC if (!radeon_get_EDID_OF(rinfo)) RTRACE("radeonfb: could not retrieve EDID from OF\n");#else /* XXX use other methods later */#endif}#ifdef CONFIG_ALL_PPC#undef SET_MC_FB_FROM_APERTUREstatic voidradeon_fixup_apertures(struct radeonfb_info *rinfo){ u32 save_crtc_gen_cntl, save_crtc2_gen_cntl; u32 save_crtc_ext_cntl; u32 aper_base, aper_size; u32 agp_base; /* First, we disable display to avoid interfering */ if (rinfo->hasCRTC2) { save_crtc2_gen_cntl = INREG(CRTC2_GEN_CNTL); OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl | CRTC2_DISP_REQ_EN_B); } save_crtc_gen_cntl = INREG(CRTC_GEN_CNTL); save_crtc_ext_cntl = INREG(CRTC_EXT_CNTL); OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl | CRTC_DISPLAY_DIS); OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl | CRTC_DISP_REQ_EN_B); mdelay(100); aper_base = INREG(CONFIG_APER_0_BASE); aper_size = INREG(CONFIG_APER_SIZE);#ifdef SET_MC_FB_FROM_APERTURE /* Set framebuffer to be at the same address as set in PCI BAR */ OUTREG(MC_FB_LOCATION, ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16)); rinfo->fb_local_base = aper_base;#else OUTREG(MC_FB_LOCATION, 0x7fff0000); rinfo->fb_local_base = 0;#endif agp_base = aper_base + aper_size; if (agp_base & 0xf0000000) agp_base = (aper_base | 0x0fffffff) + 1; /* Set AGP to be just after the framebuffer on a 256Mb boundary. This * assumes the FB isn't mapped to 0xf0000000 or above, but this is * always the case on PPCs afaik. */#ifdef SET_MC_FB_FROM_APERTURE OUTREG(MC_AGP_LOCATION, 0xffff0000 | (agp_base >> 16));#else OUTREG(MC_AGP_LOCATION, 0xffffe000);#endif /* Fixup the display base addresses & engine offsets while we * are at it as well */#ifdef SET_MC_FB_FROM_APERTURE OUTREG(DISPLAY_BASE_ADDR, aper_base); if (rinfo->hasCRTC2) OUTREG(CRTC2_DISPLAY_BASE_ADDR, aper_base);#else OUTREG(DISPLAY_BASE_ADDR, 0); if (rinfo->hasCRTC2) OUTREG(CRTC2_DISPLAY_BASE_ADDR, 0);#endif mdelay(100); /* Restore display settings */ OUTREG(CRTC_GEN_CNTL, save_crtc_gen_cntl); OUTREG(CRTC_EXT_CNTL, save_crtc_ext_cntl); if (rinfo->hasCRTC2) OUTREG(CRTC2_GEN_CNTL, save_crtc2_gen_cntl); #if 0 printk("aper_base: %08x MC_FB_LOC to: %08x, MC_AGP_LOC to: %08x\n", aper_base, ((aper_base + aper_size - 1) & 0xffff0000) | (aper_base >> 16), 0xffff0000 | (agp_base >> 16));#endif}#endif /* CONFIG_ALL_PPC */static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo){ unsigned char *block = rinfo->EDID; if (!block) return 0; /* jump to the detailed timing block section */ block += 54; rinfo->clock = (block[0] + (block[1] << 8)); rinfo->panel_xres = (block[2] + ((block[4] & 0xf0) << 4)); rinfo->hblank = (block[3] + ((block[4] & 0x0f) << 8)); rinfo->panel_yres = (block[5] + ((block[7] & 0xf0) << 4)); rinfo->vblank = (block[6] + ((block[7] & 0x0f) << 8)); rinfo->hOver_plus = (block[8] + ((block[11] & 0xc0) << 2)); rinfo->hSync_width = (block[9] + ((block[11] & 0x30) << 4)); rinfo->vOver_plus = ((block[10] >> 4) + ((block[11] & 0x0c) << 2)); rinfo->vSync_width = ((block[10] & 0x0f) + ((block[11] & 0x03) << 4)); rinfo->interlaced = ((block[17] & 0x80) >> 7); rinfo->synct = ((block[17] & 0x18) >> 3); rinfo->misc = ((block[17] & 0x06) >> 1); rinfo->hAct_high = rinfo->vAct_high = 0; if (rinfo->synct == 3) { if (rinfo->misc & 2) rinfo->hAct_high = 1; if (rinfo->misc & 1) rinfo->vAct_high = 1; } RTRACE("hOver_plus = %d\t hSync_width = %d\n", rinfo->hOver_plus, rinfo->hSync_width); RTRACE("vOver_plus = %d\t vSync_width = %d\n", rinfo->vOver_plus, rinfo->vSync_width); RTRACE("hblank = %d\t vblank = %d\n", rinfo->hblank, rinfo->vblank); RTRACE("sync = %d\n", rinfo->synct); RTRACE("misc = %d\n", rinfo->misc); RTRACE("clock = %d\n", rinfo->clock); printk("radeonfb: detected DFP panel size from EDID: %dx%d\n", rinfo->panel_xres, rinfo->panel_yres); rinfo->got_dfpinfo = 1; return 1;}static void radeon_update_default_var(struct radeonfb_info *rinfo)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -