📄 aty128fb.c
字号:
case CRTC_PIX_WIDTH_24BPP: var->bits_per_pixel = 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: var->bits_per_pixel = 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: printk(KERN_ERR "aty128fb: Invalid pixel width\n"); return -EINVAL; } return 0;}static intaty128_crtc_to_var(const struct aty128_crtc *crtc, struct fb_var_screeninfo *var){ u32 xres, yres, 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; /* fun with masking */ h_total = crtc->h_total & 0x1ff; h_disp = (crtc->h_total >> 16) & 0xff; h_sync_strt = (crtc->h_sync_strt_wid >> 3) & 0x1ff; h_sync_dly = crtc->h_sync_strt_wid & 0x7; h_sync_wid = (crtc->h_sync_strt_wid >> 16) & 0x3f; h_sync_pol = (crtc->h_sync_strt_wid >> 23) & 0x1; v_total = crtc->v_total & 0x7ff; v_disp = (crtc->v_total >> 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 >> 23) & 0x1; c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; /* do conversions */ xres = (h_disp + 1) << 3; yres = v_disp + 1; left = ((h_total - h_sync_strt - h_sync_wid) << 3) - h_sync_dly; right = ((h_sync_strt - h_disp) << 3) + h_sync_dly; hslen = h_sync_wid << 3; 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); aty128_pix_width_to_var(pix_width, var); var->xres = xres; var->yres = yres; var->xres_virtual = crtc->vxres; var->yres_virtual = crtc->vyres; 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 voidaty128_set_crt_enable(struct fb_info_aty128 *info, int on){ if (on) { aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) | CRT_CRTC_ON); aty_st_le32(DAC_CNTL, (aty_ld_le32(DAC_CNTL) | DAC_PALETTE2_SNOOP_EN)); } else aty_st_le32(CRTC_EXT_CNTL, aty_ld_le32(CRTC_EXT_CNTL) & ~CRT_CRTC_ON);}static voidaty128_set_lcd_enable(struct fb_info_aty128 *info, int on){ u32 reg; if (on) { reg = aty_ld_le32(LVDS_GEN_CNTL); reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION; reg &= ~LVDS_DISPLAY_DIS; aty_st_le32(LVDS_GEN_CNTL, reg);#ifdef CONFIG_PMAC_BACKLIGHT aty128_set_backlight_enable(get_backlight_enable(), get_backlight_level(), info);#endif } else {#ifdef CONFIG_PMAC_BACKLIGHT aty128_set_backlight_enable(0, 0, info);#endif reg = aty_ld_le32(LVDS_GEN_CNTL); reg |= LVDS_DISPLAY_DIS; aty_st_le32(LVDS_GEN_CNTL, reg); mdelay(100); reg &= ~(LVDS_ON /*| LVDS_EN*/); aty_st_le32(LVDS_GEN_CNTL, reg); }}static voidaty128_set_pll(struct aty128_pll *pll, const struct fb_info_aty128 *info){ u32 div3; unsigned char post_conv[] = /* register values for post dividers */ { 2, 0, 1, 4, 2, 2, 6, 2, 3, 2, 2, 2, 7 }; /* select PPLL_DIV_3 */ aty_st_le32(CLOCK_CNTL_INDEX, aty_ld_le32(CLOCK_CNTL_INDEX) | (3 << 8)); /* reset PLL */ aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN); /* write the reference divider */ aty_pll_wait_readupdate(info); aty_st_pll(PPLL_REF_DIV, info->constants.ref_divider & 0x3ff); aty_pll_writeupdate(info); div3 = aty_ld_pll(PPLL_DIV_3); div3 &= ~PPLL_FB3_DIV_MASK; div3 |= pll->feedback_divider; div3 &= ~PPLL_POST3_DIV_MASK; div3 |= post_conv[pll->post_divider] << 16; /* write feedback and post dividers */ aty_pll_wait_readupdate(info); aty_st_pll(PPLL_DIV_3, div3); aty_pll_writeupdate(info); aty_pll_wait_readupdate(info); aty_st_pll(HTOTAL_CNTL, 0); /* no horiz crtc adjustment */ aty_pll_writeupdate(info); /* clear the reset, just in case */ aty_st_pll(PPLL_CNTL, aty_ld_pll(PPLL_CNTL) & ~PPLL_RESET);#if 0 if (info->chip_gen == rage_M3) { /* XXX energy saving, disable VCLK during blanking */ aty_pll_wait_readupdate(info); aty_st_pll(VCLK_ECP_CNTL, aty_ld_pll(VCLK_ECP_CNTL) | 0xc0); aty_pll_writeupdate(info); /* Set PM clocks */ aty_pll_wait_readupdate(info); aty_st_pll(XCLK_CNTL, aty_ld_pll(XCLK_CNTL) | 0x00330000); aty_pll_writeupdate(info); aty_pll_wait_readupdate(info); aty_st_pll(MCLK_CNTL, aty_ld_pll(MCLK_CNTL) | 0x00000700); aty_pll_writeupdate(info); }#endif }static intaty128_var_to_pll(u32 period_in_ps, struct aty128_pll *pll, const struct fb_info_aty128 *info){ const struct aty128_constants c = info->constants; unsigned char post_dividers[] = {1,2,4,8,3,6,12}; u32 output_freq; u32 vclk; /* in .01 MHz */ int i; u32 n, d; vclk = 100000000 / period_in_ps; /* convert units to 10 kHz */ /* adjust pixel clock if necessary */ if (vclk > c.ppll_max) vclk = c.ppll_max; if (vclk * 12 < c.ppll_min) vclk = c.ppll_min/12; /* now, find an acceptable divider */ for (i = 0; i < sizeof(post_dividers); i++) { output_freq = post_dividers[i] * vclk; if (output_freq >= c.ppll_min && output_freq <= c.ppll_max) break; } /* calculate feedback divider */ n = c.ref_divider * output_freq; d = c.dotclock; pll->post_divider = post_dividers[i]; pll->feedback_divider = round_div(n, d); pll->vclk = vclk; DBG("post %d feedback %d vlck %d output %d ref_divider %d " "vclk_per: %d\n", pll->post_divider, pll->feedback_divider, vclk, output_freq, c.ref_divider, period_in_ps); return 0;}static intaty128_pll_to_var(const struct aty128_pll *pll, struct fb_var_screeninfo *var, const struct fb_info_aty128 *info){ var->pixclock = 100000000 / pll->vclk; return 0;}static voidaty128_set_fifo(const struct aty128_ddafifo *dsp, const struct fb_info_aty128 *info){ aty_st_le32(DDA_CONFIG, dsp->dda_config); aty_st_le32(DDA_ON_OFF, dsp->dda_on_off);}static intaty128_ddafifo(struct aty128_ddafifo *dsp, const struct aty128_pll *pll, u32 depth, const struct fb_info_aty128 *info){ const struct aty128_meminfo *m = info->mem; u32 xclk = info->constants.xclk; u32 fifo_width = info->constants.fifo_width; u32 fifo_depth = info->constants.fifo_depth; s32 x, b, p, ron, roff; u32 n, d, bpp; /* round up to multiple of 8 */ bpp = (depth+7) & ~7; n = xclk * fifo_width; d = pll->vclk * bpp; x = round_div(n, d); ron = 4 * m->MB + 3 * ((m->Trcd - 2 > 0) ? m->Trcd - 2 : 0) + 2 * m->Trp + m->Twr + m->CL + m->Tr2w + x; DBG("x %x\n", x); b = 0; while (x) { x >>= 1; b++; } p = b + 1; ron <<= (11 - p); n <<= (11 - p); x = round_div(n, d); roff = x * (fifo_depth - 4); if ((ron + m->Rloop) >= roff) { printk(KERN_ERR "aty128fb: Mode out of range!\n"); return -EINVAL; } DBG("p: %x rloop: %x x: %x ron: %x roff: %x\n", p, m->Rloop, x, ron, roff); dsp->dda_config = p << 16 | m->Rloop << 20 | x; dsp->dda_on_off = ron << 16 | roff; return 0;}/* * This actually sets the video mode. */static voidaty128_set_par(struct aty128fb_par *par, struct fb_info_aty128 *info){ u32 config; info->current_par = *par; if (info->blitter_may_be_busy) wait_for_idle(info); /* clear all registers that may interfere with mode setting */ aty_st_le32(OVR_CLR, 0); aty_st_le32(OVR_WID_LEFT_RIGHT, 0); aty_st_le32(OVR_WID_TOP_BOTTOM, 0); aty_st_le32(OV0_SCALE_CNTL, 0); aty_st_le32(MPP_TB_CONFIG, 0); aty_st_le32(MPP_GP_CONFIG, 0); aty_st_le32(SUBPIC_CNTL, 0); aty_st_le32(VIPH_CONTROL, 0); aty_st_le32(I2C_CNTL_1, 0); /* turn off i2c */ aty_st_le32(GEN_INT_CNTL, 0); /* turn off interrupts */ aty_st_le32(CAP0_TRIG_CNTL, 0); aty_st_le32(CAP1_TRIG_CNTL, 0); aty_st_8(CRTC_EXT_CNTL + 1, 4); /* turn video off */ aty128_set_crtc(&par->crtc, info); aty128_set_pll(&par->pll, info); aty128_set_fifo(&par->fifo_reg, info); config = aty_ld_le32(CONFIG_CNTL) & ~3;#if defined(__BIG_ENDIAN) if (par->crtc.bpp == 32) config |= 2; /* make aperture do 32 bit swapping */ else if (par->crtc.bpp == 16) config |= 1; /* make aperture do 16 bit swapping */#endif aty_st_le32(CONFIG_CNTL, config); aty_st_8(CRTC_EXT_CNTL + 1, 0); /* turn the video back on */#ifdef CONFIG_PMAC_PBOOK if (info->chip_gen == rage_M3) { aty128_set_crt_enable(info, info->crt_on); aty128_set_lcd_enable(info, info->lcd_on); }#endif if (par->accel_flags & FB_ACCELF_TEXT) aty128_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 cmode, vmode; display_info.height = ((par->crtc.v_total >> 16) & 0x7ff) + 1; display_info.width = (((par->crtc.h_total >> 16) & 0xff) + 1) << 3; display_info.depth = par->crtc.bpp; display_info.pitch = (par->crtc.vxres * par->crtc.bpp) >> 3; aty128_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, aty128fb_name); display_info.fb_address = info->frame_buffer_phys; display_info.cmap_adr_address = 0; display_info.cmap_data_address = 0; display_info.disp_reg_address = info->regbase_phys; }#endif /* CONFIG_FB_COMPAT_XPMAC */#if defined(CONFIG_BOOTX_TEXT) btext_update_display(info->frame_buffer_phys, (((par->crtc.h_total>>16) & 0xff)+1)*8, ((par->crtc.v_total>>16) & 0x7ff)+1, par->crtc.bpp, par->crtc.vxres*par->crtc.bpp/8);#endif /* CONFIG_BOOTX_TEXT */} /* * encode/decode the User Defined Part of the Display */static intaty128_decode_var(struct fb_var_screeninfo *var, struct aty128fb_par *par, const struct fb_info_aty128 *info){ int err; if ((err = aty128_var_to_crtc(var, &par->crtc, info))) return err; if ((err = aty128_var_to_pll(var->pixclock, &par->pll, info))) return err; if ((err = aty128_ddafifo(&par->fifo_reg, &par->pll, par->crtc.depth, info))) return err; if (var->accel_flags & FB_ACCELF_TEXT) par->accel_flags = FB_ACCELF_TEXT; else par->accel_flags = 0; return 0;}static intaty128_encode_var(struct fb_var_screeninfo *var, const struct aty128fb_par *par, const struct fb_info_aty128 *info){ int err; if ((err = aty128_crtc_to_var(&par->crtc, var))) return err; if ((err = aty128_pll_to_var(&par->pll, var, info))) return err; var->red.msb_right = 0; var->green.msb_right = 0; var->blue.msb_right = 0; var->transp.msb_right = 0; var->nonstd = 0; var->activate = 0; var->height = -1; var->width = -1; var->accel_flags = par->accel_flags; return 0;} /* * Get the User Defined Part of the Display */static intaty128fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb){ const struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; if (con == -1) aty128_encode_var(var, &info->default_par, info); else *var = fb_display[con].var; return 0;} /* * Set the User Defined Part of the Display */static intaty128fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *fb){ struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; struct aty128fb_par par; struct display *display; int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldgreen, oldaccel; int accel, err; display = (con >= 0) ? &fb_display[con] : fb->disp; /* basic (in)sanity checks */ if (!var->xres) var->xres = 1; if (!var->yres) var->yres = 1; if (var->xres > var->xres_virtual) var->xres_virtual = var->xres; if (var->yres > var->yres_virtual) var->yres_virtual = var->yres; switch (var->bits_per_pixel) { case 0 ... 8:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -