📄 radeonfb.c
字号:
#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; 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 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: rinfo->panel_xres = 800; break; case 768:#if defined(__powerpc__) if (rinfo->dviDisp_type == MT_LCD) rinfo->panel_xres = 1152; else#endif rinfo->panel_xres = 1024; break; case 1024: rinfo->panel_xres = 1280; break; case 1050: rinfo->panel_xres = 1400; break; case 1200: rinfo->panel_xres = 1600; break; default: printk("radeonfb: Failed to detect DFP panel size\n"); return 0; } printk("radeonfb: detected DFP panel size from registers: %dx%d\n", rinfo->panel_xres, rinfo->panel_yres); tmp = INREG(FP_CRTC_H_TOTAL_DISP); a = (tmp & FP_CRTC_H_TOTAL_MASK) + 4; b = (tmp & 0x01ff0000) >> FP_CRTC_H_DISP_SHIFT; rinfo->hblank = (a - b + 1) * 8; tmp = INREG(FP_H_SYNC_STRT_WID); rinfo->hOver_plus = (unsigned short) ((tmp & FP_H_SYNC_STRT_CHAR_MASK) >> FP_H_SYNC_STRT_CHAR_SHIFT) - b - 1; rinfo->hOver_plus *= 8; rinfo->hSync_width = (unsigned short) ((tmp & FP_H_SYNC_WID_MASK) >> FP_H_SYNC_WID_SHIFT); rinfo->hSync_width *= 8; tmp = INREG(FP_CRTC_V_TOTAL_DISP); a = (tmp & FP_CRTC_V_TOTAL_MASK) + 1; b = (tmp & FP_CRTC_V_DISP_MASK) >> FP_CRTC_V_DISP_SHIFT; rinfo->vblank = a - b /* + 24 */ ; tmp = INREG(FP_V_SYNC_STRT_WID); rinfo->vOver_plus = (unsigned short) (tmp & FP_V_SYNC_STRT_MASK) - b + 1; rinfo->vSync_width = (unsigned short) ((tmp & FP_V_SYNC_WID_MASK) >> FP_V_SYNC_WID_SHIFT); return 1; } return 1;}#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); xtal = (unsigned int *) get_property(dp, "ATY,RefCLK", 0); rinfo->pll.ref_clk = *xtal / 10; if (*xtal) return 1; else return 0;}#endif static void radeon_engine_init (struct radeonfb_info *rinfo){ u32 temp; /* disable 3D engine */ OUTREG(RB3D_CNTL, 0); radeon_engine_reset (); radeon_fifo_wait (1); OUTREG(RB2D_DSTCACHE_MODE, 0); /* XXX */ rinfo->pitch = ((rinfo->xres_virtual * (rinfo->bpp / 8) + 0x3f)) >> 6; radeon_fifo_wait (1); temp = INREG(DEFAULT_PITCH_OFFSET); OUTREG(DEFAULT_PITCH_OFFSET, ((temp & 0xc0000000) | (rinfo->pitch << 0x16))); radeon_fifo_wait (1); OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN); radeon_fifo_wait (1); OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX | DEFAULT_SC_BOTTOM_MAX)); temp = radeon_get_dstbpp(rinfo->depth); rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS); radeon_fifo_wait (1); OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl | GMC_BRUSH_SOLID_COLOR | GMC_SRC_DATATYPE_COLOR)); radeon_fifo_wait (7); /* clear line drawing regs */ OUTREG(DST_LINE_START, 0); OUTREG(DST_LINE_END, 0); /* set brush color regs */ OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff); OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000); /* set source color regs */ OUTREG(DP_SRC_FRGD_CLR, 0xffffffff); OUTREG(DP_SRC_BKGD_CLR, 0x00000000); /* default write mask */ OUTREG(DP_WRITE_MSK, 0xffffffff); radeon_engine_idle ();}static int __devinit radeon_init_disp (struct radeonfb_info *rinfo){ struct fb_info *info = &rinfo->info; struct fb_var_screeninfo var; var = radeonfb_default_var; if ((radeon_init_disp_var(rinfo, &var)) < 0) return -1; rinfo->depth = var_to_depth(&var); rinfo->bpp = var.bits_per_pixel; info->var = var; fb_alloc_cmap(&info->cmap, 256, 0); var.activate = FB_ACTIVATE_NOW; fb_set_var(&var, info); return 0;}static int radeon_init_disp_var (struct radeonfb_info *rinfo, struct fb_var_screeninfo *var){#ifndef MODULE if (mode_option) fb_find_mode (var, &rinfo->info, mode_option, NULL, 0, NULL, 8); else#endif if (rinfo->use_default_var) /* We will use the modified default far */ *var = radeonfb_default_var; else fb_find_mode (var, &rinfo->info, "640x480-8@60", NULL, 0, NULL, 0); if (noaccel) var->accel_flags &= ~FB_ACCELF_TEXT; else var->accel_flags |= FB_ACCELF_TEXT; return 0;}static int radeon_do_maximize(struct radeonfb_info *rinfo, struct fb_var_screeninfo *var, struct fb_var_screeninfo *v, int nom, int den){ static struct { int xres, yres; } modes[] = { {1600, 1280}, {1280, 1024}, {1024, 768}, {800, 600}, {640, 480}, {-1, -1} }; int i; /* use highest possible virtual resolution */ if (v->xres_virtual == -1 && v->yres_virtual == -1) { printk("radeonfb: using max available virtual resolution\n"); for (i=0; modes[i].xres != -1; i++) { if (modes[i].xres * nom / den * modes[i].yres < rinfo->video_ram / 2) break; } if (modes[i].xres == -1) { printk("radeonfb: could not find virtual resolution that fits into video memory!\n"); return -EINVAL; } v->xres_virtual = modes[i].xres; v->yres_virtual = modes[i].yres; printk("radeonfb: virtual resolution set to max of %dx%d\n", v->xres_virtual, v->yres_virtual); } else if (v->xres_virtual == -1) { v->xres_virtual = (rinfo->video_ram * den / (nom * v->yres_virtual * 2)) & ~15; } else if (v->yres_virtual == -1) { v->xres_virtual = (v->xres_virtual + 15) & ~15; v->yres_virtual = rinfo->video_ram * den / (nom * v->xres_virtual *2); } else { if (v->xres_virtual * nom / den * v->yres_virtual > rinfo->video_ram) { return -EINVAL; } } if (v->xres_virtual * nom / den >= 8192) { v->xres_virtual = 8192 * den / nom - 16; } if (v->xres_virtual < v->xres) return -EINVAL; if (v->yres_virtual < v->yres) return -EINVAL; return 0;}static int radeonfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info){ struct radeonfb_info *rinfo = (struct radeonfb_info *) info->par; struct fb_var_screeninfo v; int nom, den; memcpy (&v, var, sizeof (v)); 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.red.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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -