📄 atafb.c
字号:
else yres = (yres + 7) & ~7; if (xres_virtual < xres) xres_virtual = xres; else if (bpp == 1) xres_virtual = (xres_virtual + 31) & ~31; else xres_virtual = (xres_virtual + 15) & ~15; if (yres_virtual <= 0) yres_virtual = 0; else if (yres_virtual < yres) yres_virtual = yres; /* backward bug-compatibility */ if (var->pixclock > 1) var->pixclock -= 1; par->hw.falcon.line_width = bpp * xres / 16; par->hw.falcon.line_offset = bpp * (xres_virtual - xres) / 16; /* single or double pixel width */ xstretch = (xres < 640) ? 2 : 1;#if 0 /* SM124 supports only 640x400, this is rejected above */ if (mon_type == F_MON_SM) { if (xres != 640 && yres != 400) return -EINVAL; plen = 1; pclock = &f32; /* SM124-mode is special */ par->hw.falcon.ste_mode = 1; par->hw.falcon.f_shift = 0x000; par->hw.falcon.st_shift = 0x200; left_margin = hsync_len = 128 / plen; right_margin = 0; /* TODO set all margins */ } else#endif if (mon_type == F_MON_SC || mon_type == F_MON_TV) { plen = 2 * xstretch; if (var->pixclock > f32.t * plen) return -EINVAL; pclock = &f32; if (yres > 240) interlace = 1; if (var->pixclock == 0) { /* set some minimal margins which center the screen */ left_margin = 32; right_margin = 18; hsync_len = pclock->hsync / plen; upper_margin = 31; lower_margin = 14; vsync_len = interlace ? 3 : 4; } else { left_margin = var->left_margin; right_margin = var->right_margin; hsync_len = var->hsync_len; upper_margin = var->upper_margin; lower_margin = var->lower_margin; vsync_len = var->vsync_len; if (var->vmode & FB_VMODE_INTERLACED) { upper_margin = (upper_margin + 1) / 2; lower_margin = (lower_margin + 1) / 2; vsync_len = (vsync_len + 1) / 2; } else if (var->vmode & FB_VMODE_DOUBLE) { upper_margin *= 2; lower_margin *= 2; vsync_len *= 2; } } } else { /* F_MON_VGA */ if (bpp == 16) xstretch = 2; /* Double pixel width only for hicolor */ /* Default values are used for vert./hor. timing if no pixelclock given. */ if (var->pixclock == 0) { int linesize; /* Choose master pixelclock depending on hor. timing */ plen = 1 * xstretch; if ((plen * xres + f25.right+f25.hsync+f25.left) * fb_info.monspecs.hfmin < f25.f) pclock = &f25; else if ((plen * xres + f32.right+f32.hsync+f32.left) * fb_info.monspecs.hfmin < f32.f) pclock = &f32; else if ((plen * xres + fext.right+fext.hsync+fext.left) * fb_info.monspecs.hfmin < fext.f && fext.f) pclock = &fext; else return -EINVAL; left_margin = pclock->left / plen; right_margin = pclock->right / plen; hsync_len = pclock->hsync / plen; linesize = left_margin + xres + right_margin + hsync_len; upper_margin = 31; lower_margin = 11; vsync_len = 3; } else { /* Choose largest pixelclock <= wanted clock */ int i; unsigned long pcl = ULONG_MAX; pclock = 0; for (i=1; i <= 4; i *= 2) { if (f25.t*i >= var->pixclock && f25.t*i < pcl) { pcl = f25.t * i; pclock = &f25; } if (f32.t*i >= var->pixclock && f32.t*i < pcl) { pcl = f32.t * i; pclock = &f32; } if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) { pcl = fext.t * i; pclock = &fext; } } if (!pclock) return -EINVAL; plen = pcl / pclock->t; left_margin = var->left_margin; right_margin = var->right_margin; hsync_len = var->hsync_len; upper_margin = var->upper_margin; lower_margin = var->lower_margin; vsync_len = var->vsync_len; /* Internal unit is [single lines per (half-)frame] */ if (var->vmode & FB_VMODE_INTERLACED) { /* # lines in half frame */ /* External unit is [lines per full frame] */ upper_margin = (upper_margin + 1) / 2; lower_margin = (lower_margin + 1) / 2; vsync_len = (vsync_len + 1) / 2; } else if (var->vmode & FB_VMODE_DOUBLE) { /* External unit is [double lines per frame] */ upper_margin *= 2; lower_margin *= 2; vsync_len *= 2; } } if (pclock == &fext) longoffset = 1; /* VIDEL doesn't synchronize on short offset */ } /* Is video bus bandwidth (32MB/s) too low for this resolution? */ /* this is definitely wrong if bus clock != 32MHz */ if (pclock->f / plen / 8 * bpp > 32000000L) return -EINVAL; if (vsync_len < 1) vsync_len = 1; /* include sync lengths in right/lower margin for all calculations */ right_margin += hsync_len; lower_margin += vsync_len; /* ! In all calculations of margins we use # of lines in half frame * (which is a full frame in non-interlace mode), so we can switch * between interlace and non-interlace without messing around * with these. */ again: /* Set base_offset 128 and video bus width */ par->hw.falcon.vid_control = mon_type | f030_bus_width; if (!longoffset) par->hw.falcon.vid_control |= VCO_SHORTOFFS; /* base_offset 64 */ if (var->sync & FB_SYNC_HOR_HIGH_ACT) par->hw.falcon.vid_control |= VCO_HSYPOS; if (var->sync & FB_SYNC_VERT_HIGH_ACT) par->hw.falcon.vid_control |= VCO_VSYPOS; /* Pixelclock */ par->hw.falcon.vid_control |= pclock->control_mask; /* External or internal clock */ par->hw.falcon.sync = pclock->sync_mask | 0x2; /* Pixellength and prescale */ par->hw.falcon.vid_mode = (2/plen) << 2; if (doubleline) par->hw.falcon.vid_mode |= VMO_DOUBLE; if (interlace) par->hw.falcon.vid_mode |= VMO_INTER; /********************* Horizontal timing: unit = [master clock cycles] unit of hxx-registers: [master clock cycles * prescale] Hxx-registers are 9 bit wide 1 line = ((hht + 2) * 2 * prescale) clock cycles graphic output = hdb & 0x200 ? ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff: ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff (this must be a multiple of plen*128/bpp, on VGA pixels to the right may be cut off with a bigger right margin) start of graphics relative to start of 1st halfline = hdb & 0x200 ? (hdb - hht - 2) * prescale + hdboff : hdb * prescale + hdboff end of graphics relative to start of 1st halfline = (hde + hht + 2) * prescale + hdeoff *********************/ /* Calculate VIDEL registers */ { int hdb_off, hde_off, base_off; int gstart, gend1, gend2, align; prescale = hxx_prescale(&par->hw.falcon); base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128; /* Offsets depend on video mode */ /* Offsets are in clock cycles, divide by prescale to * calculate hd[be]-registers */ if (par->hw.falcon.f_shift & 0x100) { align = 1; hde_off = 0; hdb_off = (base_off + 16 * plen) + prescale; } else { align = 128 / bpp; hde_off = ((128 / bpp + 2) * plen); if (par->hw.falcon.ste_mode) hdb_off = (64 + base_off + (128 / bpp + 2) * plen) + prescale; else hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale; } gstart = (prescale/2 + plen * left_margin) / prescale; /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */ gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale; /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */ gend2 = gstart + xres * plen / prescale; par->HHT = plen * (left_margin + xres + right_margin) / (2 * prescale) - 2;/* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/ par->HDB = gstart - hdb_off/prescale; par->HBE = gstart; if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200; par->HDE = gend1 - par->HHT - 2 - hde_off/prescale; par->HBB = gend2 - par->HHT - 2;#if 0 /* One more Videl constraint: data fetch of two lines must not overlap */ if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) { /* if this happens increase margins, decrease hfreq. */ }#endif if (hde_off % prescale) par->HBB++; /* compensate for non matching hde and hbb */ par->HSS = par->HHT + 2 - plen * hsync_len / prescale; if (par->HSS < par->HBB) par->HSS = par->HBB; } /* check hor. frequency */ hfreq = pclock->f / ((par->HHT+2)*prescale*2); if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) { /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */ /* Too high -> enlarge margin */ left_margin += 1; right_margin += 1; goto again; } if (hfreq > fb_info.monspecs.hfmax || hfreq < fb_info.monspecs.hfmin) return -EINVAL; /* Vxx-registers */ /* All Vxx must be odd in non-interlace, since frame starts in the middle * of the first displayed line! * One frame consists of VFT+1 half lines. VFT+1 must be even in * non-interlace, odd in interlace mode for synchronisation. * Vxx-registers are 11 bit wide */ par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */ par->VDB = par->VBE; par->VDE = yres; if (!interlace) par->VDE <<= 1; if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */ par->VDE += par->VDB; par->VBB = par->VDE; par->VFT = par->VBB + (lower_margin * 2 - 1) - 1; par->VSS = par->VFT+1 - (vsync_len * 2 - 1); /* vbb,vss,vft must be even in interlace mode */ if (interlace) { par->VBB++; par->VSS++; par->VFT++; } /* V-frequency check, hope I didn't create any loop here. */ /* Interlace and doubleline are mutually exclusive. */ vfreq = (hfreq * 2) / (par->VFT + 1); if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) { /* Too high -> try again with doubleline */ doubleline = 1; goto again; } else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) { /* Too low -> try again with interlace */ interlace = 1; goto again; } else if (vfreq < fb_info.monspecs.vfmin && doubleline) { /* Doubleline too low -> clear doubleline and enlarge margins */ int lines; doubleline = 0; for (lines=0; (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax; lines++) ; upper_margin += lines; lower_margin += lines; goto again; } else if (vfreq > fb_info.monspecs.vfmax && doubleline) { /* Doubleline too high -> enlarge margins */ int lines; for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax; lines+=2) ; upper_margin += lines; lower_margin += lines; goto again; } else if (vfreq > fb_info.monspecs.vfmax && interlace) { /* Interlace, too high -> enlarge margins */ int lines; for (lines=0; (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax; lines++) ; upper_margin += lines; lower_margin += lines; goto again; } else if (vfreq < fb_info.monspecs.vfmin || vfreq > fb_info.monspecs.vfmax) return -EINVAL; set_screen_base: linelen = xres_virtual * bpp / 8; if (yres_virtual * linelen > screen_len && screen_len) return -EINVAL; if (yres * linelen > screen_len && screen_len) return -EINVAL; if (var->yoffset + yres > yres_virtual && yres_virtual) return -EINVAL; par->yres_virtual = yres_virtual; par->screen_base = screen_base + var->yoffset * linelen; par->hw.falcon.xoffset = 0; return 0;}static int falcon_encode_var( struct fb_var_screeninfo *var, struct atafb_par *par ){/* !!! only for VGA !!! */ int linelen; int prescale, plen; int hdb_off, hde_off, base_off; struct falcon_hw *hw = &par->hw.falcon; memset(var, 0, sizeof(struct fb_var_screeninfo)); /* possible frequencies: 25.175 or 32MHz */ var->pixclock = hw->sync & 0x1 ? fext.t : hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t; var->height=-1; var->width=-1; var->sync=0; if (hw->vid_control & VCO_HSYPOS) var->sync |= FB_SYNC_HOR_HIGH_ACT; if (hw->vid_control & VCO_VSYPOS) var->sync |= FB_SYNC_VERT_HIGH_ACT; var->vmode = FB_VMODE_NONINTERLACED; if (hw->vid_mode & VMO_INTER) var->vmode |= FB_VMODE_INTERLACED; if (hw->vid_mode & VMO_DOUBLE) var->vmode |= FB_VMODE_DOUBLE; /* visible y resolution: * Graphics display starts at line VDB and ends at line * VDE. If interlace mode off unit of VC-registers is * half lines, else lines. */ var->yres = hw->vde - hw->vdb; if (!(var->vmode & FB_VMODE_INTERLACED)) var->yres >>= 1; if (var->vmode & FB_VMODE_DOUBLE) var->yres >>= 1; /* to get bpp, we must examine f_shift and st_shift. * f_shift is valid if any of bits no. 10, 8 or 4 * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e. * if bit 10 set then bit 8 and bit 4 don't care... * If all these bits are 0 get display depth from st_shift * (as for ST and STE) */ if (hw->f_shift & 0x400) /* 2 colors */ var->bits_per_pixel = 1; else if (hw->f_shift & 0x100) /* hicolor */ var->bits_per_pixel = 16; else if (hw->f_shift & 0x010) /* 8 bitplanes */ var->bits_per_pixel = 8; else if (hw->st_shift == 0) var->bits_per_pixel = 4; else if (hw->st_shift == 0x100) var->bits_per_pixel = 2; else /* if (hw->st_shift == 0x200) */ var->bits_per_pixel = 1; var->xres = hw->line_width * 16 / var->bits_per_pixel; var->xres_virtual = var->xres + hw->line_offset * 16 / var->bits_per_pixel; if (hw->xoffset) var->xres_virtual += 16; if (var->bits_per_pixel == 16) { var->red.offset=11; var->red.length=5; var->red.msb_right=0; var->green.offset=5; var->green.length=6; var->green.msb_right=0; var->blue.offset=0; var->blue.length=5; var->blue.msb_right=0; } else { var->red.offset=0; var->red.length = hw->ste_mode ? 4 : 6; var->red.msb_right=0; var->grayscale=0; var->blue=var->green=var->red; } var->transp.offset=0; var->transp.length=0; var->transp.msb_right=0; linelen = var->xres_virtual * var->bits_per_pixel / 8; if (screen_len) { if (par->yres_virtual) var->yres_virtual = par->yres_virtual; else /* yres_virtual==0 means use maximum */ var->yres_virtual = screen_len / linelen; } else { if (hwscroll < 0) var->yres_virtual = 2 * var->yres; else var->yres_virtual=var->yres+hwscroll * 16; } var->xoffset=0; /* TODO change this */ /* hdX-offsets */ prescale = hxx_prescale(hw); plen = 4 >> (hw->vid_mode >> 2 & 0x3); base_off = hw->vid_control & VCO_SHORTOFFS ? 64 : 128; if (hw->f_shift & 0x100) { hde_off = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -