📄 atyfb_base.c
字号:
temp = aty_ld_le32(LCD_INDEX, info); aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info); /* write the register value */ aty_st_le32(LCD_DATA, val, info);}static u32 aty_ld_lcd(int index, const struct fb_info_aty *info){ unsigned long temp; /* write addr byte */ temp = aty_ld_le32(LCD_INDEX, info); aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info); /* read the register value */ return aty_ld_le32(LCD_DATA, info);}#endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT *//* ------------------------------------------------------------------------- */ /* * CRTC programming */static void aty_set_crtc(const struct fb_info_aty *info, const struct crtc *crtc){ aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info); aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info); aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, info); aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, info); aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info); aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, info); aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info);}static int aty_var_to_crtc(const struct fb_info_aty *info, const struct fb_var_screeninfo *var, struct crtc *crtc){ u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; u32 left, right, upper, lower, hslen, vslen, sync, vmode; u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 pix_width, dp_pix_width, dp_chain_mask; /* input */ xres = var->xres; yres = var->yres; vxres = var->xres_virtual; vyres = var->yres_virtual; xoffset = var->xoffset; yoffset = var->yoffset; bpp = var->bits_per_pixel; left = var->left_margin; right = var->right_margin; upper = var->upper_margin; lower = var->lower_margin; hslen = var->hsync_len; vslen = var->vsync_len; sync = var->sync; vmode = var->vmode; /* convert (and round up) and validate */ xres = (xres+7) & ~7; xoffset = (xoffset+7) & ~7; vxres = (vxres+7) & ~7; if (vxres < xres+xoffset) vxres = xres+xoffset; h_disp = xres/8-1; if (h_disp > 0xff) FAIL("h_disp too large"); h_sync_strt = h_disp+(right/8); if (h_sync_strt > 0x1ff) FAIL("h_sync_start too large"); h_sync_dly = right & 7; h_sync_wid = (hslen+7)/8; if (h_sync_wid > 0x1f) FAIL("h_sync_wid too large"); h_total = h_sync_strt+h_sync_wid+(h_sync_dly+left+7)/8; if (h_total > 0x1ff) FAIL("h_total too large"); h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; if (vyres < yres+yoffset) vyres = yres+yoffset; v_disp = yres-1; if (v_disp > 0x7ff) FAIL("v_disp too large"); v_sync_strt = v_disp+lower; if (v_sync_strt > 0x7ff) FAIL("v_sync_strt too large"); v_sync_wid = vslen; if (v_sync_wid > 0x1f) FAIL("v_sync_wid too large"); v_total = v_sync_strt+v_sync_wid+upper; if (v_total > 0x7ff) FAIL("v_total too large"); v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0; if (bpp <= 8) { bpp = 8; pix_width = CRTC_PIX_WIDTH_8BPP; dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; dp_chain_mask = 0x8080; } else if (bpp <= 16) { bpp = 16; pix_width = CRTC_PIX_WIDTH_15BPP; dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP | BYTE_ORDER_LSB_TO_MSB; dp_chain_mask = 0x4210; } else if (bpp <= 24 && M64_HAS(INTEGRATED)) { bpp = 24; pix_width = CRTC_PIX_WIDTH_24BPP; dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; dp_chain_mask = 0x8080; } else if (bpp <= 32) { bpp = 32; pix_width = CRTC_PIX_WIDTH_32BPP; dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP | BYTE_ORDER_LSB_TO_MSB; dp_chain_mask = 0x8080; } else FAIL("invalid bpp"); if (vxres*vyres*bpp/8 > info->total_vram) FAIL("not enough video RAM"); if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) FAIL("invalid vmode"); /* output */ crtc->vxres = vxres; crtc->vyres = vyres; crtc->xoffset = xoffset; crtc->yoffset = yoffset; crtc->bpp = bpp; crtc->h_tot_disp = h_total | (h_disp<<16); crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) | ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) | (h_sync_pol<<21); crtc->v_tot_disp = v_total | (v_disp<<16); crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21); crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19); crtc->gen_cntl = pix_width | c_sync | CRTC_EXT_DISP_EN | CRTC_ENABLE; if (M64_HAS(MAGIC_FIFO)) { /* Not VTB/GTB */ /* FIXME: magic FIFO values */ crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000; } crtc->dp_pix_width = dp_pix_width; crtc->dp_chain_mask = dp_chain_mask; return 0;}static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screeninfo *var){ u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync; u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 pix_width; /* input */ h_total = crtc->h_tot_disp & 0x1ff; h_disp = (crtc->h_tot_disp>>16) & 0xff; h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | ((crtc->h_sync_strt_wid>>4) & 0x100); h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7; h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f; h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1; v_total = crtc->v_tot_disp & 0x7ff; v_disp = (crtc->v_tot_disp>>16) & 0x7ff; v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f; v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1; c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; /* convert */ xres = (h_disp+1)*8; yres = v_disp+1; left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly; right = (h_sync_strt-h_disp)*8+h_sync_dly; hslen = h_sync_wid*8; upper = v_total-v_sync_strt-v_sync_wid; lower = v_sync_strt-v_disp; vslen = v_sync_wid; sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); switch (pix_width) {#if 0 case CRTC_PIX_WIDTH_4BPP: bpp = 4; var->red.offset = 0; var->red.length = 8; var->green.offset = 0; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 0; break;#endif case CRTC_PIX_WIDTH_8BPP: bpp = 8; var->red.offset = 0; var->red.length = 8; var->green.offset = 0; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 0; break; case CRTC_PIX_WIDTH_15BPP: /* RGB 555 */ bpp = 16; var->red.offset = 10; var->red.length = 5; var->green.offset = 5; var->green.length = 5; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = 0; var->transp.length = 0; break;#if 0 case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */ bpp = 16; var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = 0; var->transp.length = 0; break;#endif case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */ bpp = 24; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 0; break; case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */ bpp = 32; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 24; var->transp.length = 8; break; default: FAIL("Invalid pixel width"); } /* output */ var->xres = xres; var->yres = yres; var->xres_virtual = crtc->vxres; var->yres_virtual = crtc->vyres; var->bits_per_pixel = bpp; var->xoffset = crtc->xoffset; var->yoffset = crtc->yoffset; var->left_margin = left; var->right_margin = right; var->upper_margin = upper; var->lower_margin = lower; var->hsync_len = hslen; var->vsync_len = vslen; var->sync = sync; var->vmode = FB_VMODE_NONINTERLACED; return 0;}/* ------------------------------------------------------------------------- */static void atyfb_set_par(const struct atyfb_par *par, struct fb_info_aty *info){ u32 i; int accelmode; u8 tmp; accelmode = par->accel_flags; /* hack */ info->current_par = *par; if (info->blitter_may_be_busy) wait_for_idle(info); tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info); aty_set_crtc(info, &par->crtc); aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); /* better call aty_StrobeClock ?? */ aty_st_8(CLOCK_CNTL + info->clk_wr_offset, CLOCK_STROBE, info); info->dac_ops->set_dac(info, &par->pll, par->crtc.bpp, accelmode); info->pll_ops->set_pll(info, &par->pll); if (!M64_HAS(INTEGRATED)) { /* Don't forget MEM_CNTL */ i = aty_ld_le32(MEM_CNTL, info) & 0xf0ffffff; switch (par->crtc.bpp) { case 8: i |= 0x02000000; break; case 16: i |= 0x03000000; break; case 32: i |= 0x06000000; break; } aty_st_le32(MEM_CNTL, i, info); } else { i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff; if (!M64_HAS(MAGIC_POSTDIV)) i |= info->mem_refresh_rate << 20; switch (par->crtc.bpp) { case 8: case 24: i |= 0x00000000; break; case 16: i |= 0x04000000; break; case 32: i |= 0x08000000; break; } if (M64_HAS(CT_BUS)) { aty_st_le32(DAC_CNTL, 0x87010184, info); aty_st_le32(BUS_CNTL, 0x680000f9, info); } else if (M64_HAS(VT_BUS)) { aty_st_le32(DAC_CNTL, 0x87010184, info); aty_st_le32(BUS_CNTL, 0x680000f9, info); } else if (M64_HAS(MOBIL_BUS)) { aty_st_le32(DAC_CNTL, 0x80010102, info); aty_st_le32(BUS_CNTL, 0x7b33a040, info); } else { /* GT */ aty_st_le32(DAC_CNTL, 0x86010102, info); aty_st_le32(BUS_CNTL, 0x7b23a040, info); aty_st_le32(EXT_MEM_CNTL, aty_ld_le32(EXT_MEM_CNTL, info) | 0x5000001, info); } aty_st_le32(MEM_CNTL, i, info); } aty_st_8(DAC_MASK, 0xff, info); /* Initialize the graphics engine */ if (par->accel_flags & FB_ACCELF_TEXT) aty_init_engine(par, info);#ifdef CONFIG_FB_COMPAT_XPMAC if (!console_fb_info || console_fb_info == &info->fb_info) { struct fb_var_screeninfo var; int vmode, cmode; display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1; display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8; display_info.depth = par->crtc.bpp; display_info.pitch = par->crtc.vxres*par->crtc.bpp/8; atyfb_encode_var(&var, par, info); if (mac_var_to_vmode(&var, &vmode, &cmode)) display_info.mode = 0; else display_info.mode = vmode; strcpy(display_info.name, atyfb_name); display_info.fb_address = info->frame_buffer_phys; display_info.cmap_adr_address = info->ati_regbase_phys+0xc0; display_info.cmap_data_address = info->ati_regbase_phys+0xc1; display_info.disp_reg_address = info->ati_regbase_phys; }#endif /* CONFIG_FB_COMPAT_XPMAC */#ifdef CONFIG_BOOTX_TEXT btext_update_display(info->frame_buffer_phys, (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8, ((par->crtc.v_tot_disp>>16) & 0x7ff)+1, par->crtc.bpp, par->crtc.vxres*par->crtc.bpp/8);#endif /* CONFIG_BOOTX_TEXT */}static int atyfb_decode_var(const struct fb_var_screeninfo *var, struct atyfb_par *par, const struct fb_info_aty *info){ int err; if ((err = aty_var_to_crtc(info, var, &par->crtc)) || (err = info->pll_ops->var_to_pll(info, var->pixclock, par->crtc.bpp, &par->pll))) return err; if (var->accel_flags & FB_ACCELF_TEXT) par->accel_flags = FB_ACCELF_TEXT; else par->accel_flags = 0;#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */ if (!fbmon_valid_timings(var->pixclock, htotal, vtotal, info)) return -EINVAL;#endif return 0;}static int atyfb_encode_var(struct fb_var_screeninfo *var, const struct atyfb_par *par, const struct fb_info_aty *info){ int err; memset(var, 0, sizeof(struct fb_var_screeninfo)); if ((err = aty_crtc_to_var(&par->crtc, var))) return err; var->pixclock = info->pll_ops->pll_to_var(info, &par->pll); var->height = -1; var->width = -1; var->accel_flags = par->accel_flags; return 0;}static void set_off_pitch(struct atyfb_par *par, const struct fb_info_aty *info)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -