📄 radeonfb.c
字号:
/* save current mode regs before we switch into the new one * so we can restore this upon __exit */ radeon_save_state (rinfo, &rinfo->init_state); /* init palette */ for (i=0; i<16; i++) { j = color_table[i]; rinfo->palette[i].red = default_red[j]; rinfo->palette[i].green = default_grn[j]; rinfo->palette[i].blue = default_blu[j]; } pci_set_drvdata(pdev, rinfo); rinfo->next = board_list; board_list = rinfo; if (register_framebuffer ((struct fb_info *) rinfo) < 0) { printk ("radeonfb: could not register framebuffer\n"); iounmap ((void*)rinfo->fb_base); iounmap ((void*)rinfo->mmio_base); release_mem_region (rinfo->mmio_base_phys, pci_resource_len(pdev, 2)); release_mem_region (rinfo->fb_base_phys, pci_resource_len(pdev, 0)); kfree (rinfo); return -ENODEV; } if (!noaccel) { /* initialize the engine */ radeon_engine_init (rinfo); }#ifdef CONFIG_PMAC_BACKLIGHT if (rinfo->dviDisp_type == MT_LCD) register_backlight_controller(&radeon_backlight_controller, rinfo, "ati");#endif#ifdef CONFIG_PMAC_PBOOK if (rinfo->dviDisp_type == MT_LCD) { rinfo->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM); pmu_register_sleep_notifier(&radeon_sleep_notifier); }#endif printk ("radeonfb: ATI %s %s %d MB\n", rinfo->name, rinfo->ram_type, (rinfo->video_ram/(1024*1024))); if (rinfo->hasCRTC2) { printk("radeonfb: DVI port %s monitor connected\n", GET_MON_NAME(rinfo->dviDisp_type)); printk("radeonfb: CRT port %s monitor connected\n", GET_MON_NAME(rinfo->crtDisp_type)); } else { printk("radeonfb: CRT port %s monitor connected\n", GET_MON_NAME(rinfo->crtDisp_type)); } RTRACE("radeonfb_pci_register END\n"); return 0;}static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev){ struct radeonfb_info *rinfo = pci_get_drvdata(pdev); if (!rinfo) return; /* restore original state */ radeon_write_mode (rinfo, &rinfo->init_state); unregister_framebuffer ((struct fb_info *) rinfo); iounmap ((void*)rinfo->mmio_base); iounmap ((void*)rinfo->fb_base); release_mem_region (rinfo->mmio_base_phys, pci_resource_len(pdev, 2)); release_mem_region (rinfo->fb_base_phys, pci_resource_len(pdev, 0)); kfree (rinfo);}static char *radeon_find_rom(struct radeonfb_info *rinfo){ #if defined(__i386__) u32 segstart; char *rom_base; char *rom; int stage; int i,j; char aty_rom_sig[] = "761295520"; char *radeon_sig[] = { "RG6", "RADEON" }; for(segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) { stage = 1; rom_base = (char *)ioremap(segstart, 0x1000); if ((*rom_base == 0x55) && (((*(rom_base + 1)) & 0xff) == 0xaa)) stage = 2; if (stage != 2) { iounmap(rom_base); continue; } rom = rom_base; for (i = 0; (i < 128 - strlen(aty_rom_sig)) && (stage != 3); i++) { if (aty_rom_sig[0] == *rom) if (strncmp(aty_rom_sig, rom, strlen(aty_rom_sig)) == 0) stage = 3; rom++; } if (stage != 3) { iounmap(rom_base); continue; } rom = rom_base; for (i = 0; (i < 512) && (stage != 4); i++) { for(j = 0;j < sizeof(radeon_sig)/sizeof(char *);j++) { if (radeon_sig[j][0] == *rom) if (strncmp(radeon_sig[j], rom, strlen(radeon_sig[j])) == 0) { stage = 4; break; } } rom++; } if (stage != 4) { iounmap(rom_base); continue; } return rom_base; }#endif return NULL;}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); 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; }#endif /* no BIOS or BIOS not found, use defaults */ switch (rinfo->chipset) { case PCI_DEVICE_ID_RADEON_QW: 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 PCI_DEVICE_ID_RADEON_QL: 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 PCI_DEVICE_ID_RADEON_QD: case PCI_DEVICE_ID_RADEON_QE: case PCI_DEVICE_ID_RADEON_QF: case PCI_DEVICE_ID_RADEON_QG: 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){ unsigned int tmp; if (force_dfp) { rinfo->dviDisp_type = MT_DFP; return; } tmp = INREG(RADEON_BIOS_4_SCRATCH); if (rinfo->hasCRTC2) { /* 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; }}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_PPCstatic int radeon_get_EDID_OF(struct radeonfb_info *rinfo){ struct device_node *dp; unsigned char *pedid = NULL; dp = pci_device_to_OF_node(rinfo->pdev); pedid = (unsigned char *) get_property(dp, "DFP,EDID", 0); if (!pedid) pedid = (unsigned char *) get_property(dp, "LCD,EDID", 0); if (!pedid) pedid = (unsigned char *) get_property(dp, "EDID", 0); if (pedid) { rinfo->EDID = pedid; return 1; } else return 0;}#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; } 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){ struct fb_var_screeninfo *var = &radeonfb_default_var; var->xres = rinfo->panel_xres; var->yres = rinfo->panel_yres; var->xres_virtual = rinfo->panel_xres; var->yres_virtual = rinfo->panel_yres; var->xoffset = var->yoffset = 0; var->bits_per_pixel = 8; var->pixclock = 100000000 / rinfo->clock; var->left_margin = (rinfo->hblank - rinfo->hOver_plus - rinfo->hSync_width); var->right_margin = rinfo->hOver_plus; var->upper_margin = (rinfo->vblank - rinfo->vOver_plus - rinfo->vSync_width); var->lower_margin = rinfo->vOver_plus; var->hsync_len = rinfo->hSync_width; var->vsync_len = rinfo->vSync_width; var->sync = 0; if (rinfo->synct == 3) { if (rinfo->hAct_high) var->sync |= FB_SYNC_HOR_HIGH_ACT; if (rinfo->vAct_high) var->sync |= FB_SYNC_VERT_HIGH_ACT; } var->vmode = 0; if (rinfo->interlaced) var->vmode |= FB_VMODE_INTERLACED; rinfo->use_default_var = 1;}static int radeon_get_dfpinfo_BIOS(struct radeonfb_info *rinfo){ char *fpbiosstart, *tmp, *tmp0; char stmp[30]; int i; if (!rinfo->bios_seg) return 0; if (!(fpbiosstart = rinfo->bios_seg + readw(rinfo->bios_seg + 0x48))) { printk("radeonfb: Failed to detect DFP panel info using BIOS\n"); return 0; } if (!(tmp = rinfo->bios_seg + readw(fpbiosstart + 0x40))) { printk("radeonfb: Failed to detect DFP panel info using BIOS\n"); return 0; } for(i=0; i<24; i++) stmp[i] = readb(tmp+i+1); stmp[24] = 0; printk("radeonfb: panel ID string: %s\n", stmp); rinfo->panel_xres = readw(tmp + 25); rinfo->panel_yres = readw(tmp + 27); printk("radeonfb: detected DFP panel size from BIOS: %dx%d\n", rinfo->panel_xres, rinfo->panel_yres); for(i=0; i<20; i++) { tmp0 = rinfo->bios_seg + readw(tmp+64+i*2); if (tmp0 == 0) break; if ((readw(tmp0) == rinfo->panel_xres) && (readw(tmp0+2) == rinfo->panel_yres)) { rinfo->hblank = (readw(tmp0+17) - readw(tmp0+19)) * 8; rinfo->hOver_plus = ((readw(tmp0+21) - readw(tmp0+19) -1) * 8) & 0x7fff; rinfo->hSync_width = readb(tmp0+23) * 8; rinfo->vblank = readw(tmp0+24) - readw(tmp0+26); rinfo->vOver_plus = (readw(tmp0+28) & 0x7ff) - readw(tmp0+26); rinfo->vSync_width = (readw(tmp0+28) & 0xf800) >> 11; rinfo->clock = readw(tmp0+9); rinfo->got_dfpinfo = 1; return 1; } } return 0;}static int radeon_get_dfpinfo (struct radeonfb_info *rinfo){ unsigned int tmp; unsigned short a, b; if (radeon_get_dfpinfo_BIOS(rinfo)) radeon_update_default_var(rinfo); if (radeon_dfp_parse_EDID(rinfo)) radeon_update_default_var(rinfo); if (!rinfo->got_dfpinfo) { /* * it seems all else has failed now and we * resort to probing registers for our DFP info */ if (panel_yres) { rinfo->panel_yres = panel_yres; } else { tmp = INREG(FP_VERT_STRETCH); tmp &= 0x00fff000; rinfo->panel_yres = (unsigned short)(tmp >> 0x0c) + 1; } switch (rinfo->panel_yres) { case 480: rinfo->panel_xres = 640; break; case 600:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -