📄 aty128fb.c
字号:
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_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);}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 bpp, 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; /* 15bpp is really 16bpp */ if (bpp == 15) bpp = 16; 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 >= 24) config |= 2; /* make aperture do 32 byte swapping */ else if (par->crtc.bpp > 8) config |= 1; /* make aperture do 16 byte swapping */#endif aty_st_le32(CONFIG_CNTL, config); aty_st_8(CRTC_EXT_CNTL + 1, 0); /* turn the video back on */ 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 */} /* * 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.bpp, 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, 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: var->bits_per_pixel = 8; break; case 9 ... 16: var->bits_per_pixel = 16; break; case 17 ... 24: var->bits_per_pixel = 24; break; case 25 ... 32: var->bits_per_pixel = 32; break; default: return -EINVAL; } if ((err = aty128_decode_var(var, &par, info))) return err; aty128_encode_var(var, &par, info); if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) return 0; oldxres = display->var.xres; oldyres = display->var.yres; oldvxres = display->var.xres_virtual; oldvyres = display->var.yres_virtual; oldbpp = display->var.bits_per_pixel; oldaccel = display->var.accel_flags; display->var = *var; if (oldxres != var->xres || oldyres != var->yres || oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) { struct fb_fix_screeninfo fix; aty128_encode_fix(&fix, &par, info); display->screen_base = (char *)info->frame_buffer; display->visual = fix.visual; display->type = fix.type; display->type_aux = fix.type_aux; display->ypanstep = fix.ypanstep; display->ywrapstep = fix.ywrapstep; display->line_length = fix.line_length; display->can_soft_blank = 1; display->inverse = 0; accel = var->accel_flags & FB_ACCELF_TEXT; aty128_set_dispsw(display, info, par.crtc.bpp, accel); if (accel) display->scrollmode = SCROLL_YNOMOVE; else display->scrollmode = SCROLL_YREDRAW; if (info->fb_info.changevar) (*info->fb_info.changevar)(con); } if (!info->fb_info.display_fg || info->fb_info.display_fg->vc_num == con) aty128_set_par(&par, info); if (oldbpp != var->bits_per_pixel) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err; do_install_cmap(con, &info->fb_info); } return 0;}static voidaty128_set_dispsw(struct display *disp, struct fb_info_aty128 *info, int bpp, int accel){ switch (bpp) {#ifdef FBCON_HAS_CFB8 case 8: disp->dispsw = accel ? &fbcon_aty128_8 : &fbcon_cfb8; break;#endif#ifdef FBCON_HAS_CFB16 case 15: case 16: disp->dispsw = accel ? &fbcon_aty128_16 : &fbcon_cfb16; disp->dispsw_data = info->fbcon_cmap.cfb16; break;#endif#ifdef FBCON_HAS_CFB24 case 24: disp->dispsw = accel ? &fbcon_aty128_24 : &fbcon_cfb24; disp->dispsw_data = info->fbcon_cmap.cfb24; break;#endif#ifdef FBCON_HAS_CFB32 case 32: disp->dispsw = accel ? &fbcon_aty128_32 : &fbcon_cfb32; disp->dispsw_data = info->fbcon_cmap.cfb32; break;#endif default: disp->dispsw = &fbcon_dummy; }}static voidaty128_encode_fix(struct fb_fix_screeninfo *fix, struct aty128fb_par *par, const struct fb_info_aty128 *info){ memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, aty128fb_name); fix->smem_start = (unsigned long)info->frame_buffer_phys; fix->mmio_start = (unsigned long)info->regbase_phys; fix->smem_len = info->vram_size; fix->mmio_len = 0x1fff; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->line_length = (par->crtc.vxres * par->crtc.bpp) >> 3; fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR; fix->ywrapstep = 0; fix->xpanstep = 8; fix->ypanstep = 1; fix->accel = FB_ACCEL_ATI_RAGE128; return;} /* * Get the Fixed Part of the Display */static intaty128fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *fb){ const struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; struct aty128fb_par par; if (con == -1) par = info->default_par; else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -