📄 aty128fb.c
字号:
for (i = 0; (i < 512) && (stage != 4); i++) { if (R128_sig[0] == *rom) if (strncmp(R128_sig, rom, strlen(R128_sig)) == 0) stage = 4; rom++; } if (stage != 4) { iounmap(rom_base); continue; } return rom_base; } return NULL;}static void __initaty128_get_pllinfo(struct fb_info_aty128 *info, char *bios_seg){ void *bios_header; void *header_ptr; u16 bios_header_offset, pll_info_offset; PLL_BLOCK pll; 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); info->constants.ppll_max = pll.PCLK_max_freq; info->constants.ppll_min = pll.PCLK_min_freq; info->constants.xclk = (u32)pll.XCLK; info->constants.ref_divider = (u32)pll.PCLK_ref_divider; info->constants.dotclock = (u32)pll.PCLK_ref_freq; DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d dotclock %d\n", info->constants.ppll_max, info->constants.ppll_min, info->constants.xclk, info->constants.ref_divider, info->constants.dotclock);} #endif /* !CONFIG_PPC *//* fill in known card constants if pll_block is not available */static void __initaty128_timings(struct fb_info_aty128 *info){#ifdef CONFIG_PPC /* instead of a table lookup, assume OF has properly * setup the PLL registers and use their values * to set the XCLK values and reference divider values */ u32 x_mpll_ref_fb_div; u32 xclk_cntl; u32 Nx, M; unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 };#endif if (!info->constants.dotclock) info->constants.dotclock = 2950;#ifdef CONFIG_PPC x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7; Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; M = x_mpll_ref_fb_div & 0x0000ff; info->constants.xclk = round_div((2 * Nx * info->constants.dotclock), (M * PostDivSet[xclk_cntl])); info->constants.ref_divider = aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;#endif if (!info->constants.ref_divider) { info->constants.ref_divider = 0x3b; aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e); aty_pll_writeupdate(info); } aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider); aty_pll_writeupdate(info); /* from documentation */ if (!info->constants.ppll_min) info->constants.ppll_min = 12500; if (!info->constants.ppll_max) info->constants.ppll_max = 25000; /* 23000 on some cards? */ if (!info->constants.xclk) info->constants.xclk = 0x1d4d; /* same as mclk */ info->constants.fifo_width = 128; info->constants.fifo_depth = 32; switch (aty_ld_le32(MEM_CNTL) & 0x3) { case 0: info->mem = &sdr_128; break; case 1: info->mem = &sdr_sgram; break; case 2: info->mem = &ddr_sgram; break; default: info->mem = &sdr_sgram; }}static intaty128fbcon_switch(int con, struct fb_info *fb){ struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; struct aty128fb_par par; /* Do we have to save the colormap? */ if (fb_display[info->currcon].cmap.len) fb_get_cmap(&fb_display[info->currcon].cmap, 1, aty128_getcolreg, fb); /* set the current console */ info->currcon = con; aty128_decode_var(&fb_display[con].var, &par, info); aty128_set_par(&par, info); aty128_set_dispsw(&fb_display[con], info, par.crtc.bpp, par.accel_flags & FB_ACCELF_TEXT); do_install_cmap(con, fb); return 1;} /* * Blank the display. */static voidaty128fbcon_blank(int blank, struct fb_info *fb){ struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; u8 state = 0;#ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && blank) set_backlight_enable(0);#endif /* CONFIG_PMAC_BACKLIGHT */ if (blank & VESA_VSYNC_SUSPEND) state |= 2; if (blank & VESA_HSYNC_SUSPEND) state |= 1; if (blank & VESA_POWERDOWN) state |= 4; aty_st_8(CRTC_EXT_CNTL+1, state);#ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && !blank) set_backlight_enable(1);#endif /* CONFIG_PMAC_BACKLIGHT */} /* * Read a single color register and split it into * colors/transparent. Return != 0 for invalid regno. */static intaty128_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *transp, struct fb_info *fb){ struct fb_info_aty128 *info = (struct fb_info_aty128 *) fb; if (regno > 255) return 1; *red = (info->palette[regno].red<<8) | info->palette[regno].red; *green = (info->palette[regno].green<<8) | info->palette[regno].green; *blue = (info->palette[regno].blue<<8) | info->palette[regno].blue; *transp = 0; return 0;} /* * Set a single color register. The values supplied are already * rounded down to the hardware's capabilities (according to the * entries in the var structure). Return != 0 for invalid regno. */static intaty128_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *fb){ struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; u32 col; if (regno > 255) return 1; red >>= 8; green >>= 8; blue >>= 8; info->palette[regno].red = red; info->palette[regno].green = green; info->palette[regno].blue = blue; /* Note: For now, on M3, we set palette on both heads, which may * be useless. Can someone with a M3 check this ? */ /* initialize gamma ramp for hi-color+ */ if ((info->current_par.crtc.bpp > 8) && (regno == 0)) { int i; if (info->chip_gen == rage_M3) aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); for (i=16; i<256; i++) { aty_st_8(PALETTE_INDEX, i); col = (i << 16) | (i << 8) | i; aty_st_le32(PALETTE_DATA, col); } if (info->chip_gen == rage_M3) { aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); for (i=16; i<256; i++) { aty_st_8(PALETTE_INDEX, i); col = (i << 16) | (i << 8) | i; aty_st_le32(PALETTE_DATA, col); } } } /* initialize palette */ if (info->chip_gen == rage_M3) aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); if (info->current_par.crtc.bpp == 16) aty_st_8(PALETTE_INDEX, (regno << 3)); else aty_st_8(PALETTE_INDEX, regno); col = (red << 16) | (green << 8) | blue; aty_st_le32(PALETTE_DATA, col); if (info->chip_gen == rage_M3) { aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); if (info->current_par.crtc.bpp == 16) aty_st_8(PALETTE_INDEX, (regno << 3)); else aty_st_8(PALETTE_INDEX, regno); aty_st_le32(PALETTE_DATA, col); } if (regno < 16) switch (info->current_par.crtc.bpp) {#ifdef FBCON_HAS_CFB16 case 9 ... 16: info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno; break;#endif#ifdef FBCON_HAS_CFB24 case 17 ... 24: info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | regno; break;#endif#ifdef FBCON_HAS_CFB32 case 25 ... 32: { u32 i; i = (regno << 8) | regno; info->fbcon_cmap.cfb32[regno] = (i << 16) | i; break; }#endif } return 0;}static voiddo_install_cmap(int con, struct fb_info *info){ struct fb_info_aty128 *fb = (struct fb_info_aty128 *)info; if (con != fb->currcon) return; if (fb_display[con].cmap.len) fb_set_cmap(&fb_display[con].cmap, 1, aty128_setcolreg, info); else { int size = (fb_display[con].var.bits_per_pixel <= 8) ? 256 : 16; fb_set_cmap(fb_default_cmap(size), 1, aty128_setcolreg, info); }}#ifdef CONFIG_PMAC_BACKLIGHTstatic int backlight_conv[] = { 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24};static intaty128_set_backlight_enable(int on, int level, void* data){ struct fb_info_aty128 *info = (struct fb_info_aty128 *)data; unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); reg |= LVDS_BL_MOD_EN | LVDS_BLON; if (on && level > BACKLIGHT_OFF) { reg &= ~LVDS_BL_MOD_LEVEL_MASK; reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT); } else { reg &= ~LVDS_BL_MOD_LEVEL_MASK; reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT); } aty_st_le32(LVDS_GEN_CNTL, reg); return 0;}static intaty128_set_backlight_level(int level, void* data){ return aty128_set_backlight_enable(1, level, data);}#endif /* CONFIG_PMAC_BACKLIGHT */ /* * Accelerated functions */static inline voidaty128_rectcopy(int srcx, int srcy, int dstx, int dsty, u_int width, u_int height, struct fb_info_aty128 *info){ u32 save_dp_datatype, save_dp_cntl, bppval; if (!width || !height) return; bppval = bpp_to_depth(info->current_par.crtc.bpp); if (bppval == DST_24BPP) { srcx *= 3; dstx *= 3; width *= 3; } else if (bppval == -EINVAL) { printk("aty128fb: invalid depth\n"); return; } wait_for_fifo(2, info); save_dp_datatype = aty_ld_le32(DP_DATATYPE); save_dp_cntl = aty_ld_le32(DP_CNTL); wait_for_fifo(6, info); aty_st_le32(SRC_Y_X, (srcy << 16) | srcx); aty_st_le32(DP_MIX, ROP3_SRCCOPY | DP_SRC_RECT); aty_st_le32(DP_CNTL, DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM); aty_st_le32(DP_DATATYPE, save_dp_datatype | bppval | SRC_DSTCOLOR); aty_st_le32(DST_Y_X, (dsty << 16) | dstx); aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); info->blitter_may_be_busy = 1; wait_for_fifo(2, info); aty_st_le32(DP_DATATYPE, save_dp_datatype); aty_st_le32(DP_CNTL, save_dp_cntl); } /* * Text mode accelerated functions */static voidfbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx, int height, int width){ sx *= fontwidth(p); sy *= fontheight(p); dx *= fontwidth(p); dy *= fontheight(p); width *= fontwidth(p); height *= fontheight(p); aty128_rectcopy(sx, sy, dx, dy, width, height, (struct fb_info_aty128 *)p->fb_info);}#ifdef FBCON_HAS_CFB8static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx){ struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info); if (fb->blitter_may_be_busy) wait_for_idle(fb); fbcon_cfb8_putc(conp, p, c, yy, xx);}static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx){ struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info); if (fb->blitter_may_be_busy) wait_for_idle(fb); fbcon_cfb8_putcs(conp, p, s, count, yy, xx);}static void fbcon_aty8_clear_margins(struct vc_data *conp, struct display *p, int bottom_only){ struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info); if (fb->blitter_may_be_busy) wait_for_idle(fb); fbcon_cfb8_clear_margins(conp, p, bottom_only);}static struct display_switch fbcon_aty128_8 = { setup: fbcon_cfb8_setup, bmove: fbcon_aty128_bmove, clear: fbcon_cfb8_clear, putc: fbcon_aty8_putc, putcs: fbcon_aty8_putcs, revc: fbcon_cfb8_revc, clear_margins: fbcon_aty8_clear_margins, fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)};#endif#ifdef FBCON_HAS_CFB16static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx){ struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info); if (fb->blitter_may_be_busy) wait_for_idle(fb); fbcon_cfb16_putc(conp, p, c, yy, xx);}static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p, const unsigned short *s, int count, int yy, int xx){ struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info); if (fb->blitter_may_be_busy) wait_for_idle(fb); fbcon_cfb16_putcs(conp, p, s, count, yy, xx);}static void fbcon_aty16_clear_margins(struct vc_data *conp, struct display *p, int bottom_only){ struct fb_info_aty128 *fb = (struct fb_info_aty128 *)(p->fb_info); if (fb->blitter_may_be_busy) wait_for_idle(fb); fbcon_cfb16_clear_margins(con
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -