📄 radeon_base.c
字号:
struct device_node *dp = rinfo->of_node; u32 *val; if (dp == NULL) return -ENODEV; val = (u32 *) get_property(dp, "ATY,RefCLK", NULL); if (!val || !*val) { printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n"); return -EINVAL; } rinfo->pll.ref_clk = (*val) / 10; val = (u32 *) get_property(dp, "ATY,SCLK", NULL); if (val && *val) rinfo->pll.sclk = (*val) / 10; val = (u32 *) get_property(dp, "ATY,MCLK", NULL); if (val && *val) rinfo->pll.mclk = (*val) / 10; return 0;}#endif /* CONFIG_PPC_OF *//* * Read PLL infos from chip registers */static int __devinit radeon_probe_pll_params(struct radeonfb_info *rinfo){ unsigned char ppll_div_sel; unsigned Ns, Nm, M; unsigned sclk, mclk, tmp, ref_div; int hTotal, vTotal, num, denom, m, n; unsigned long long hz, vclk; long xtal; struct timeval start_tv, stop_tv; long total_secs, total_usecs; int i; /* Ugh, we cut interrupts, bad bad bad, but we want some precision * here, so... --BenH */ /* Flush PCI buffers ? */ tmp = INREG16(DEVICE_ID); local_irq_disable(); for(i=0; i<1000000; i++) if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) break; do_gettimeofday(&start_tv); for(i=0; i<1000000; i++) if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) != 0) break; for(i=0; i<1000000; i++) if (((INREG(CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) break; do_gettimeofday(&stop_tv); local_irq_enable(); total_secs = stop_tv.tv_sec - start_tv.tv_sec; if (total_secs > 10) return -1; total_usecs = stop_tv.tv_usec - start_tv.tv_usec; total_usecs += total_secs * 1000000; if (total_usecs < 0) total_usecs = -total_usecs; hz = 1000000/total_usecs; hTotal = ((INREG(CRTC_H_TOTAL_DISP) & 0x1ff) + 1) * 8; vTotal = ((INREG(CRTC_V_TOTAL_DISP) & 0x3ff) + 1); vclk = (long long)hTotal * (long long)vTotal * hz; switch((INPLL(PPLL_REF_DIV) & 0x30000) >> 16) { case 0: default: num = 1; denom = 1; break; case 1: n = ((INPLL(M_SPLL_REF_FB_DIV) >> 16) & 0xff); m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff); num = 2*n; denom = 2*m; break; case 2: n = ((INPLL(M_SPLL_REF_FB_DIV) >> 8) & 0xff); m = (INPLL(M_SPLL_REF_FB_DIV) & 0xff); num = 2*n; denom = 2*m; break; } ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3; radeon_pll_errata_after_index(rinfo); n = (INPLL(PPLL_DIV_0 + ppll_div_sel) & 0x7ff); m = (INPLL(PPLL_REF_DIV) & 0x3ff); num *= n; denom *= m; switch ((INPLL(PPLL_DIV_0 + ppll_div_sel) >> 16) & 0x7) { case 1: denom *= 2; break; case 2: denom *= 4; break; case 3: denom *= 8; break; case 4: denom *= 3; break; case 6: denom *= 6; break; case 7: denom *= 12; break; } vclk *= denom; do_div(vclk, 1000 * num); xtal = vclk; if ((xtal > 26900) && (xtal < 27100)) xtal = 2700; else if ((xtal > 14200) && (xtal < 14400)) xtal = 1432; else if ((xtal > 29400) && (xtal < 29600)) xtal = 2950; else { printk(KERN_WARNING "xtal calculation failed: %ld\n", xtal); return -1; } tmp = INPLL(M_SPLL_REF_FB_DIV); ref_div = INPLL(PPLL_REF_DIV) & 0x3ff; Ns = (tmp & 0xff0000) >> 16; Nm = (tmp & 0xff00) >> 8; M = (tmp & 0xff); sclk = round_div((2 * Ns * xtal), (2 * M)); mclk = round_div((2 * Nm * xtal), (2 * M)); /* we're done, hopefully these are sane values */ rinfo->pll.ref_clk = xtal; rinfo->pll.ref_div = ref_div; rinfo->pll.sclk = sclk; rinfo->pll.mclk = mclk; return 0;}/* * Retreive PLL infos by different means (BIOS, Open Firmware, register probing...) */static void __devinit radeon_get_pllinfo(struct radeonfb_info *rinfo){ /* * In the case nothing works, these are defaults; they are mostly * incomplete, however. It does provide ppll_max and _min values * even for most other methods, however. */ switch (rinfo->chipset) { case PCI_DEVICE_ID_ATI_RADEON_QW: case PCI_DEVICE_ID_ATI_RADEON_QX: rinfo->pll.ppll_max = 35000; rinfo->pll.ppll_min = 12000; rinfo->pll.mclk = 23000; rinfo->pll.sclk = 23000; rinfo->pll.ref_clk = 2700; break; case PCI_DEVICE_ID_ATI_RADEON_QL: case PCI_DEVICE_ID_ATI_RADEON_QN: case PCI_DEVICE_ID_ATI_RADEON_QO: case PCI_DEVICE_ID_ATI_RADEON_Ql: case PCI_DEVICE_ID_ATI_RADEON_BB: rinfo->pll.ppll_max = 35000; rinfo->pll.ppll_min = 12000; rinfo->pll.mclk = 27500; rinfo->pll.sclk = 27500; rinfo->pll.ref_clk = 2700; break; case PCI_DEVICE_ID_ATI_RADEON_Id: case PCI_DEVICE_ID_ATI_RADEON_Ie: case PCI_DEVICE_ID_ATI_RADEON_If: case PCI_DEVICE_ID_ATI_RADEON_Ig: rinfo->pll.ppll_max = 35000; rinfo->pll.ppll_min = 12000; rinfo->pll.mclk = 25000; rinfo->pll.sclk = 25000; rinfo->pll.ref_clk = 2700; break; case PCI_DEVICE_ID_ATI_RADEON_ND: case PCI_DEVICE_ID_ATI_RADEON_NE: case PCI_DEVICE_ID_ATI_RADEON_NF: case PCI_DEVICE_ID_ATI_RADEON_NG: rinfo->pll.ppll_max = 40000; rinfo->pll.ppll_min = 20000; rinfo->pll.mclk = 27000; rinfo->pll.sclk = 27000; rinfo->pll.ref_clk = 2700; break; case PCI_DEVICE_ID_ATI_RADEON_QD: case PCI_DEVICE_ID_ATI_RADEON_QE: case PCI_DEVICE_ID_ATI_RADEON_QF: case PCI_DEVICE_ID_ATI_RADEON_QG: default: rinfo->pll.ppll_max = 35000; rinfo->pll.ppll_min = 12000; rinfo->pll.mclk = 16600; rinfo->pll.sclk = 16600; rinfo->pll.ref_clk = 2700; break; } rinfo->pll.ref_div = INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;#ifdef CONFIG_PPC_OF /* * Retreive PLL infos from Open Firmware first */ if (!force_measure_pll && radeon_read_xtal_OF(rinfo) == 0) { printk(KERN_INFO "radeonfb: Retreived PLL infos from Open Firmware\n"); goto found; }#endif /* CONFIG_PPC_OF */ /* * Check out if we have an X86 which gave us some PLL informations * and if yes, retreive them */ if (!force_measure_pll && rinfo->bios_seg) { u16 pll_info_block = BIOS_IN16(rinfo->fp_bios_start + 0x30); rinfo->pll.sclk = BIOS_IN16(pll_info_block + 0x08); rinfo->pll.mclk = BIOS_IN16(pll_info_block + 0x0a); rinfo->pll.ref_clk = BIOS_IN16(pll_info_block + 0x0e); rinfo->pll.ref_div = BIOS_IN16(pll_info_block + 0x10); rinfo->pll.ppll_min = BIOS_IN32(pll_info_block + 0x12); rinfo->pll.ppll_max = BIOS_IN32(pll_info_block + 0x16); printk(KERN_INFO "radeonfb: Retreived PLL infos from BIOS\n"); goto found; } /* * We didn't get PLL parameters from either OF or BIOS, we try to * probe them */ if (radeon_probe_pll_params(rinfo) == 0) { printk(KERN_INFO "radeonfb: Retreived PLL infos from registers\n"); goto found; } /* * Fall back to already-set defaults... */ printk(KERN_INFO "radeonfb: Used default PLL infos\n");found: /* * Some methods fail to retreive SCLK and MCLK values, we apply default * settings in this case (200Mhz). If that really happne often, we could * fetch from registers instead... */ if (rinfo->pll.mclk == 0) rinfo->pll.mclk = 20000; if (rinfo->pll.sclk == 0) rinfo->pll.sclk = 20000; printk("radeonfb: Reference=%d.%02d MHz (RefDiv=%d) Memory=%d.%02d Mhz, System=%d.%02d MHz\n", rinfo->pll.ref_clk / 100, rinfo->pll.ref_clk % 100, rinfo->pll.ref_div, rinfo->pll.mclk / 100, rinfo->pll.mclk % 100, rinfo->pll.sclk / 100, rinfo->pll.sclk % 100); printk("radeonfb: PLL min %d max %d\n", rinfo->pll.ppll_min, rinfo->pll.ppll_max);}static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info){ struct radeonfb_info *rinfo = info->par; struct fb_var_screeninfo v; int nom, den; unsigned int pitch; if (radeon_match_mode(rinfo, &v, var)) return -EINVAL; switch (v.bits_per_pixel) { case 0 ... 8: v.bits_per_pixel = 8; break; case 9 ... 16: v.bits_per_pixel = 16; break; case 17 ... 24:#if 0 /* Doesn't seem to work */ v.bits_per_pixel = 24; break;#endif return -EINVAL; case 25 ... 32: v.bits_per_pixel = 32; break; default: return -EINVAL; } switch (var_to_depth(&v)) { case 8: nom = den = 1; v.red.offset = v.green.offset = v.blue.offset = 0; v.red.length = v.green.length = v.blue.length = 8; v.transp.offset = v.transp.length = 0; break; case 15: nom = 2; den = 1; v.red.offset = 10; v.green.offset = 5; v.blue.offset = 0; v.red.length = v.green.length = v.blue.length = 5; v.transp.offset = v.transp.length = 0; break; case 16: nom = 2; den = 1; v.red.offset = 11; v.green.offset = 5; v.blue.offset = 0; v.red.length = 5; v.green.length = 6; v.blue.length = 5; v.transp.offset = v.transp.length = 0; break; case 24: nom = 4; den = 1; v.red.offset = 16; v.green.offset = 8; v.blue.offset = 0; v.red.length = v.blue.length = v.green.length = 8; v.transp.offset = v.transp.length = 0; break; case 32: nom = 4; den = 1; v.red.offset = 16; v.green.offset = 8; v.blue.offset = 0; v.red.length = v.blue.length = v.green.length = 8; v.transp.offset = 24; v.transp.length = 8; break; default: printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n", var->xres, var->yres, var->bits_per_pixel); return -EINVAL; } if (v.yres_virtual < v.yres) v.yres_virtual = v.yres; if (v.xres_virtual < v.xres) v.xres_virtual = v.xres; /* XXX I'm adjusting xres_virtual to the pitch, that may help XFree * with some panels, though I don't quite like this solution */ if (rinfo->info->flags & FBINFO_HWACCEL_DISABLED) { v.xres_virtual = v.xres_virtual & ~7ul; } else { pitch = ((v.xres_virtual * ((v.bits_per_pixel + 1) / 8) + 0x3f) & ~(0x3f)) >> 6; v.xres_virtual = (pitch << 6) / ((v.bits_per_pixel + 1) / 8); } if (((v.xres_virtual * v.yres_virtual * nom) / den) > rinfo->mapped_vram) return -EINVAL; if (v.xres_virtual < v.xres) v.xres = v.xres_virtual; if (v.xoffset < 0) v.xoffset = 0; if (v.yoffset < 0) v.yoffset = 0; if (v.xoffset > v.xres_virtual - v.xres) v.xoffset = v.xres_virtual - v.xres - 1; if (v.yoffset > v.yres_virtual - v.yres) v.yoffset = v.yres_virtual - v.yres - 1; v.red.msb_right = v.green.msb_right = v.blue.msb_right = v.transp.offset = v.transp.length = v.transp.msb_right = 0; memcpy(var, &v, sizeof(v)); return 0;}static int radeonfb_pan_display (struct fb_var_screeninfo *var, struct fb_info *info){ struct radeonfb_info *rinfo = info->par; if ((var->xoffset + var->xres > var->xres_virtual) || (var->yoffset + var->yres > var->yres_virtual)) return -EINVAL; if (rinfo->asleep) return 0; radeon_fifo_wait(2); OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel / 8) & ~7); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -