sstfb.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,724 行 · 第 1/4 页
C
1,724 行
|| (var->hsync_len <= 1) || (hSyncOff <= 1) || (var->left_margin <= 2) || (vSyncOn <= 0) || (vSyncOff <= 0) || (vBackPorch <= 0)) { return -EINVAL; } if (IS_VOODOO2(par)) { /* Voodoo 2 limits */ tiles_in_X = (var->xres + 63 ) / 64 * 2; if (((var->xres - 1) >= POW2(11)) || (yDim >= POW2(11))) { eprintk("Unsupported resolution %dx%d\n", var->xres, var->yres); return -EINVAL; } if (((var->hsync_len-1) >= POW2(9)) || ((hSyncOff-1) >= POW2(11)) || ((var->left_margin - 2) >= POW2(9)) || (vSyncOn >= POW2(13)) || (vSyncOff >= POW2(13)) || (vBackPorch >= POW2(9)) || (tiles_in_X >= POW2(6)) || (tiles_in_X <= 0)) { eprintk("Unsupported Timings\n"); return -EINVAL; } } else { /* Voodoo limits */ tiles_in_X = (var->xres + 63 ) / 64; if (var->vmode) { eprintk("Interlace/Doublescan not supported %#x\n", var->vmode); return -EINVAL; } if (((var->xres - 1) >= POW2(10)) || (var->yres >= POW2(10))) { eprintk("Unsupported resolution %dx%d\n", var->xres, var->yres); return -EINVAL; } if (((var->hsync_len - 1) >= POW2(8)) || ((hSyncOff-1) >= POW2(10)) || ((var->left_margin - 2) >= POW2(8)) || (vSyncOn >= POW2(12)) || (vSyncOff >= POW2(12)) || (vBackPorch >= POW2(8)) || (tiles_in_X >= POW2(4)) || (tiles_in_X <= 0)) { eprintk("Unsupported Timings\n"); return -EINVAL; } } /* it seems that the fbi uses tiles of 64x16 pixels to "map" the mem */ /* FIXME: i don't like this... looks wrong */ real_length = tiles_in_X * (IS_VOODOO2(par) ? 32 : 64 ) * ((var->bits_per_pixel == 16) ? 2 : 4); if ((real_length * yDim) > info->fix.smem_len) { eprintk("Not enough video memory\n"); return -ENOMEM; } var->sync &= (FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT); var->vmode &= (FB_VMODE_INTERLACED | FB_VMODE_DOUBLE); var->xoffset = 0; var->yoffset = 0; var->height = -1; var->width = -1; /* * correct the color bit fields */ /* var->{red|green|blue}.msb_right = 0; */ switch (var->bits_per_pixel) { case 16: /* RGB 565 LfbMode 0 */ var->red.length = 5; var->green.length = 6; var->blue.length = 5; var->transp.length = 0; var->red.offset = 11; var->green.offset = 5; var->blue.offset = 0; var->transp.offset = 0; break;#ifdef EN_24_32_BPP case 24: /* RGB 888 LfbMode 4 */ case 32: /* ARGB 8888 LfbMode 5 */ var->red.length = 8; var->green.length = 8; var->blue.length = 8; var->transp.length = 0; var->red.offset = 16; var->green.offset = 8; var->blue.offset = 0; var->transp.offset = 0; /* in 24bpp we fake a 32 bpp mode */ break;#endif default: return -EINVAL; } return 0;}/** * sstfb_set_par - Optional function. Alters the hardware state. * @info: frame buffer structure that represents a single frame buffer */static int sstfb_set_par(struct fb_info *info){ struct sstfb_par *par = (struct sstfb_par *) info->par; u32 lfbmode, fbiinit1, fbiinit2, fbiinit3, fbiinit5, fbiinit6=0; struct pci_dev *sst_dev = par->dev; unsigned int freq; int ntiles; par->hSyncOff = info->var.xres + info->var.right_margin + info->var.left_margin; par->yDim = info->var.yres; par->vSyncOn = info->var.vsync_len; par->vSyncOff = info->var.yres + info->var.lower_margin + info->var.upper_margin; par->vBackPorch = info->var.upper_margin; /* We need par->pll */ sst_calc_pll(PICOS2KHZ(info->var.pixclock), &freq, &par->pll); if (info->var.vmode & FB_VMODE_INTERLACED) par->vBackPorch += (par->vBackPorch % 2); if (info->var.vmode & FB_VMODE_DOUBLE) { par->vBackPorch <<= 1; par->yDim <<=1; par->vSyncOn <<=1; par->vSyncOff <<=1; } if (IS_VOODOO2(par)) { /* voodoo2 has 32 pixel wide tiles , BUT stange things happen with odd number of tiles */ par->tiles_in_X = (info->var.xres + 63 ) / 64 * 2; } else { /* voodoo1 has 64 pixels wide tiles. */ par->tiles_in_X = (info->var.xres + 63 ) / 64; } f_ddprintk("hsync_len hSyncOff vsync_len vSyncOff\n"); f_ddprintk("%-7d %-8d %-7d %-8d\n", info->var.hsync_len, par->hSyncOff, par->vSyncOn, par->vSyncOff); f_ddprintk("left_margin upper_margin xres yres Freq\n"); f_ddprintk("%-10d %-10d %-4d %-4d %-8ld\n", info->var.left_margin, info->var.upper_margin, info->var.xres, info->var.yres, PICOS2KHZ(info->var.pixclock)); sst_write(NOPCMD, 0); sst_wait_idle(); pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); sst_set_bits(FBIINIT1, VIDEO_RESET); sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET); sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH); sst_wait_idle(); /*sst_unset_bits (FBIINIT0, FBI_RESET); / reenable FBI ? */ sst_write(BACKPORCH, par->vBackPorch << 16 | (info->var.left_margin - 2)); sst_write(VIDEODIMENSIONS, par->yDim << 16 | (info->var.xres - 1)); sst_write(HSYNC, (par->hSyncOff - 1) << 16 | (info->var.hsync_len - 1)); sst_write(VSYNC, par->vSyncOff << 16 | par->vSyncOn); fbiinit2 = sst_read(FBIINIT2); fbiinit3 = sst_read(FBIINIT3); /* everything is reset. we enable fbiinit2/3 remap : dac acces ok */ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR | PCI_REMAP_DAC ); par->dac_sw.set_vidmod(info, info->var.bits_per_pixel); /* set video clock */ par->dac_sw.set_pll(info, &par->pll, VID_CLOCK); /* disable fbiinit2/3 remap */ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); /* restore fbiinit2/3 */ sst_write(FBIINIT2,fbiinit2); sst_write(FBIINIT3,fbiinit3); fbiinit1 = (sst_read(FBIINIT1) & VIDEO_MASK) | EN_DATA_OE | EN_BLANK_OE | EN_HVSYNC_OE | EN_DCLK_OE /* | (15 << TILES_IN_X_SHIFT) */ | SEL_INPUT_VCLK_2X /* | (2 << VCLK_2X_SEL_DEL_SHIFT) | (2 << VCLK_DEL_SHIFT) */;/* try with vclk_in_delay =0 (bits 29:30) , vclk_out_delay =0 (bits(27:28) in (near) future set them accordingly to revision + resolution (cf glide) first understand what it stands for :) FIXME: there are some artefacts... check for the vclk_in_delay lets try with 6ns delay in both vclk_out & in... doh... they're still there :\*/ ntiles = par->tiles_in_X; if (IS_VOODOO2(par)) { fbiinit1 |= ((ntiles & 0x20) >> 5) << TILES_IN_X_MSB_SHIFT | ((ntiles & 0x1e) >> 1) << TILES_IN_X_SHIFT;/* as the only value of importance for us in fbiinit6 is tiles in X (lsb), and as reading fbinit 6 will return crap (see FBIINIT6_DEFAULT) we just write our value. BTW due to the dac unable to read odd number of tiles, this field is always null ... */ fbiinit6 = (ntiles & 0x1) << TILES_IN_X_LSB_SHIFT; } else fbiinit1 |= ntiles << TILES_IN_X_SHIFT; switch (info->var.bits_per_pixel) { case 16: fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL; break;#ifdef EN_24_32_BPP case 24: case 32: /* sst_set_bits(FBIINIT1, SEL_SOURCE_VCLK_2X_DIV2 | EN_24BPP);*/ fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL | EN_24BPP; break;#endif default: return -EINVAL; } sst_write(FBIINIT1, fbiinit1); if (IS_VOODOO2(par)) { sst_write(FBIINIT6, fbiinit6); fbiinit5=sst_read(FBIINIT5) & FBIINIT5_MASK ; if (info->var.vmode & FB_VMODE_INTERLACED) fbiinit5 |= INTERLACE; if (info->var.vmode & FB_VMODE_DOUBLE) fbiinit5 |= VDOUBLESCAN; if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) fbiinit5 |= HSYNC_HIGH; if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) fbiinit5 |= VSYNC_HIGH; sst_write(FBIINIT5, fbiinit5); } sst_wait_idle(); sst_unset_bits(FBIINIT1, VIDEO_RESET); sst_unset_bits(FBIINIT0, FBI_RESET | FIFO_RESET); sst_set_bits(FBIINIT2, EN_DRAM_REFRESH); /* disables fbiinit writes */ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR); /* set lfbmode : set mode + front buffer for reads/writes + disable pipeline */ switch (info->var.bits_per_pixel) { case 16: lfbmode = LFB_565; break;#ifdef EN_24_32_BPP case 24: lfbmode = LFB_888; break; case 32: lfbmode = LFB_8888; break;#endif default: return -EINVAL; }#if defined(__BIG_ENDIAN) /* Enable byte-swizzle functionality in hardware. * With this enabled, all our read- and write-accesses to * the voodoo framebuffer can be done in native format, and * the hardware will automatically convert it to little-endian. * - tested on HP-PARISC, Helge Deller <deller@gmx.de> */ lfbmode |= ( LFB_WORD_SWIZZLE_WR | LFB_BYTE_SWIZZLE_WR | LFB_WORD_SWIZZLE_RD | LFB_BYTE_SWIZZLE_RD );#endif if (clipping) { sst_write(LFBMODE, lfbmode | EN_PXL_PIPELINE); /* * Set "clipping" dimensions. If clipping is disabled and * writes to offscreen areas of the framebuffer are performed, * the "behaviour is undefined" (_very_ undefined) - Urs */ /* btw, it requires enabling pixel pipeline in LFBMODE . off screen read/writes will just wrap and read/print pixels on screen. Ugly but not that dangerous */ f_ddprintk("setting clipping dimensions 0..%d, 0..%d\n", info->var.xres - 1, par->yDim - 1); sst_write(CLIP_LEFT_RIGHT, info->var.xres); sst_write(CLIP_LOWY_HIGHY, par->yDim); sst_set_bits(FBZMODE, EN_CLIPPING | EN_RGB_WRITE); } else { /* no clipping : direct access, no pipeline */ sst_write(LFBMODE, lfbmode); } return 0;}/** * sstfb_setcolreg - Optional function. Sets a color register. * @regno: hardware colormap register * @red: frame buffer colormap structure * @green: The green value which can be up to 16 bits wide * @blue: The blue value which can be up to 16 bits wide. * @transp: If supported the alpha value which can be up to 16 bits wide. * @info: frame buffer info structure */static int sstfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info){ u32 col; f_dddprintk("sstfb_setcolreg\n"); f_dddprintk("%-2d rgbt: %#x, %#x, %#x, %#x\n", regno, red, green, blue, transp); if (regno >= 16) return -EINVAL; red >>= (16 - info->var.red.length); green >>= (16 - info->var.green.length); blue >>= (16 - info->var.blue.length); transp >>= (16 - info->var.transp.length); col = (red << info->var.red.offset) | (green << info->var.green.offset) | (blue << info->var.blue.offset) | (transp << info->var.transp.offset); ((u32 *)info->pseudo_palette)[regno] = col; return 0;}static int sstfb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, struct fb_info *info ){ struct sstfb_par *par = (struct sstfb_par *) info->par; struct pci_dev *sst_dev = par->dev; u32 fbiinit0, tmp, val; u_long p; switch (cmd) { /* dump current FBIINIT values to system log */ case _IO('F', 0xdb): /* 0x46db */ return sstfb_dump_regs(info); /* fills lfb with #arg pixels */ case _IOW('F', 0xdc, u32): /* 0x46dc */ if (copy_from_user(&val, (void __user *)arg, sizeof(val))) return -EFAULT; if (val > info->fix.smem_len) val = info->fix.smem_len; printk("filling %#x \n", val); for (p=0 ; p<val; p+=2) writew(p >> 6, info->screen_base + p); return 0; /* change VGA pass_through mode */ case _IOW('F', 0xdd, u32): /* 0x46dd */ if (copy_from_user(&val, (void __user *)arg, sizeof(val))) return -EFAULT; pci_read_config_dword(sst_dev, PCI_INIT_ENABLE, &tmp); pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp | PCI_EN_INIT_WR ); fbiinit0 = sst_read (FBIINIT0); if (val) { sst_write(FBIINIT0, fbiinit0 & ~EN_VGA_PASSTHROUGH); iprintk("Disabling VGA pass-through\n"); } else { sst_write(FBIINIT0, fbiinit0 | EN_VGA_PASSTHROUGH); iprintk("Enabling VGA pass-through\n"); } pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp); return 0; /* draw test image */ case _IO('F', 0xde): /* 0x46de */ f_dprintk("test color display at %d bpp\n", info->var.bits_per_pixel); sstfb_drawdebugimage(info); return 0; } return -EINVAL;}/* * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) - Voodoo2 only */#if 0static void sstfb_copyarea(struct fb_info *info, const struct fb_copyarea *area){ struct sstfb_par *par = (struct sstfb_par *) info->par; u32 stride = info->fix.line_length; if (!IS_VOODOO2(par)) return; sst_write(BLTSRCBASEADDR, 0); sst_write(BLTDSTBASEADDR, 0); sst_write(BLTROP, BLTROP_COPY); sst_write(BLTXYSTRIDES, stride | (stride << 16)); sst_write(BLTSRCXY, area->sx | (area->sy << 16)); sst_write(BLTDSTXY, area->dx | (area->dy << 16)); sst_write(BLTSIZE, area->width | (area->height << 16)); sst_write(BLTCOMMAND, BLT_SCR2SCR_BITBLT | LAUNCH_BITBLT | (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) ); sst_wait_idle();}#endif/* * FillRect 2D command (solidfill or invert (via ROP_XOR)) - Voodoo2 only */static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct sstfb_par *par = (struct sstfb_par *) info->par;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?