📄 sstfb.c
字号:
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; 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; 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){ struct sstfb_par *par = info->par; u32 col; f_dddprintk("sstfb_setcolreg\n"); f_dddprintk("%-2d rgbt: %#x, %#x, %#x, %#x\n", regno, red, green, blue, transp); if (regno > 15) return 0; 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); par->palette[regno] = col; return 0;}static void sstfb_setvgapass( struct fb_info *info, int enable ){ struct sstfb_par *par = info->par; struct pci_dev *sst_dev = par->dev; u32 fbiinit0, tmp; enable = enable ? 1:0; if (par->vgapass == enable) return; par->vgapass = enable; 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 (par->vgapass) { sst_write(FBIINIT0, fbiinit0 & ~DIS_VGA_PASSTHROUGH); printk(KERN_INFO "fb%d: Enabling VGA pass-through\n", info->node ); } else { sst_write(FBIINIT0, fbiinit0 | DIS_VGA_PASSTHROUGH); printk(KERN_INFO "fb%d: Disabling VGA pass-through\n", info->node ); } pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp);}static ssize_t store_vgapass(struct device *device, struct device_attribute *attr, const char *buf, size_t count){ struct fb_info *info = dev_get_drvdata(device); char ** last = NULL; int val; val = simple_strtoul(buf, last, 0); sstfb_setvgapass(info, val); return count;}static ssize_t show_vgapass(struct device *device, struct device_attribute *attr, char *buf){ struct fb_info *info = dev_get_drvdata(device); struct sstfb_par *par = info->par; return snprintf(buf, PAGE_SIZE, "%d\n", par->vgapass);}static struct device_attribute device_attrs[] = { __ATTR(vgapass, S_IRUGO|S_IWUSR, show_vgapass, store_vgapass) };static int sstfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg){ struct sstfb_par *par; u32 val; switch (cmd) { /* set/get VGA pass_through mode */ case SSTFB_SET_VGAPASS: if (copy_from_user(&val, (void __user *)arg, sizeof(val))) return -EFAULT; sstfb_setvgapass(info, val); return 0; case SSTFB_GET_VGAPASS: par = info->par; val = par->vgapass; if (copy_to_user((void __user *)arg, &val, sizeof(val))) return -EFAULT; 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 = 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 */#if 0static void sstfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { struct sstfb_par *par = info->par; u32 stride = info->fix.line_length; if (!IS_VOODOO2(par)) return; sst_write(BLTCLIPX, info->var.xres); sst_write(BLTCLIPY, info->var.yres); sst_write(BLTDSTBASEADDR, 0); sst_write(BLTCOLOR, rect->color); sst_write(BLTROP, rect->rop == ROP_COPY ? BLTROP_COPY : BLTROP_XOR); sst_write(BLTXYSTRIDES, stride | (stride << 16)); sst_write(BLTDSTXY, rect->dx | (rect->dy << 16)); sst_write(BLTSIZE, rect->width | (rect->height << 16)); sst_write(BLTCOMMAND, BLT_RECFILL_BITBLT | LAUNCH_BITBLT | (BLT_16BPP_FMT << 3) /* | BIT(14) */ | BIT(15) | BIT(16) ); sst_wait_idle();}#endif/* * get lfb size */static int __devinit sst_get_memsize(struct fb_info *info, __u32 *memsize){ u8 __iomem *fbbase_virt = info->screen_base; /* force memsize */ if (mem >= 1 && mem <= 4) { *memsize = (mem * 0x100000); printk(KERN_INFO "supplied memsize: %#x\n", *memsize); return 1; } writel(0xdeadbeef, fbbase_virt); writel(0xdeadbeef, fbbase_virt+0x100000); writel(0xdeadbeef, fbbase_virt+0x200000); f_ddprintk("0MB: %#x, 1MB: %#x, 2MB: %#x\n", readl(fbbase_virt), readl(fbbase_virt + 0x100000), readl(fbbase_virt + 0x200000)); writel(0xabcdef01, fbbase_virt); f_ddprintk("0MB: %#x, 1MB: %#x, 2MB: %#x\n", readl(fbbase_virt), readl(fbbase_virt + 0x100000), readl(fbbase_virt + 0x200000)); /* checks for 4mb lfb, then 2, then defaults to 1 */ if (readl(fbbase_virt + 0x200000) == 0xdeadbeef) *memsize = 0x400000; else if (readl(fbbase_virt + 0x100000) == 0xdeadbeef) *memsize = 0x200000; else *memsize = 0x100000; f_ddprintk("detected memsize: %dMB\n", *memsize >> 20); return 1;}/* * DAC detection routines *//* fbi should be idle, and fifo emty and mem disabled *//* supposed to detect AT&T ATT20C409 and Ti TVP3409 ramdacs */static int __devinit sst_detect_att(struct fb_info *info){ struct sstfb_par *par = info->par; int i, mir, dir; for (i = 0; i < 3; i++) { sst_dac_write(DACREG_WMA, 0); /* backdoor */ sst_dac_read(DACREG_RMR); /* read 4 times RMR */ sst_dac_read(DACREG_RMR); sst_dac_read(DACREG_RMR); sst_dac_read(DACREG_RMR); /* the fifth time, CR0 is read */ sst_dac_read(DACREG_RMR); /* the 6th, manufacturer id register */ mir = sst_dac_read(DACREG_RMR); /*the 7th, device ID register */ dir = sst_dac_read(DACREG_RMR); f_ddprintk("mir: %#x, dir: %#x\n", mir, dir); if (mir == DACREG_MIR_ATT && dir == DACREG_DIR_ATT) { return 1; } } return 0;}static int __devinit sst_detect_ti(struct fb_info *info){ struct sstfb_par *par = info->par; int i, mir, dir; for (i = 0; i<3; i++) { sst_dac_write(DACREG_WMA, 0); /* backdoor */ sst_dac_read(DACREG_RMR); /* read 4 times RMR */ sst_dac_read(DACREG_RMR); sst_dac_read(DACREG_RMR); sst_dac_read(DACREG_RMR); /* the fifth time, CR0 is read */ sst_dac_read(DACREG_RMR); /* the 6th, manufacturer id register */ mir = sst_dac_read(DACREG_RMR); /*the 7th, device ID register */ dir = sst_dac_read(DACREG_RMR); f_ddprintk("mir: %#x, dir: %#x\n", mir, dir); if ((mir == DACREG_MIR_TI ) && (dir == DACREG_DIR_TI)) { return 1; } } return 0;}/* * try to detect ICS5342 ramdac * we get the 1st byte (M value) of preset f1,f7 and fB * why those 3 ? mmmh... for now, i'll do it the glide way... * and ask questions later. anyway, it seems that all the freq registers are * realy at their default state (cf specs) so i ask again, why those 3 regs ? * mmmmh.. it seems that's much more ugly than i thought. we use f0 and fA for * pll programming, so in fact, we *hope* that the f1, f7 & fB won't be * touched... * is it realy safe ? how can i reset this ramdac ? geee... */static int __devinit sst_detect_ics(struct fb_info *info){ struct sstfb_par *par = info->par; int m_clk0_1, m_clk0_7, m_clk1_b; int n_clk0_1, n_clk0_7, n_clk1_b; int i; for (i = 0; i<5; i++ ) { sst_dac_write(DACREG_ICS_PLLRMA, 0x1); /* f1 */ m_clk0_1 = sst_dac_read(DACREG_ICS_PLLDATA); n_clk0_1 = sst_dac_read(DACREG_ICS_PLLDATA); sst_dac_write(DACREG_ICS_PLLRMA, 0x7); /* f7 */ m_clk0_7 = sst_dac_read(DACREG_ICS_PLLDATA); n_clk0_7 = sst_dac_read(DACREG_ICS_PLLDATA); sst_dac_write(DACREG_ICS_PLLRMA, 0xb); /* fB */ m_clk1_b= sst_dac_read(DACREG_ICS_PLLDATA); n_clk1_b= sst_dac_read(DACREG_ICS_PLLDATA); f_ddprintk("m_clk0_1: %#x, m_clk0_7: %#x, m_clk1_b: %#x\n", m_clk0_1, m_clk0_7, m_clk1_b); f_ddprintk("n_clk0_1: %#x, n_clk0_7: %#x, n_clk1_b: %#x\n", n_clk0_1, n_clk0_7, n_clk1_b); if (( m_clk0_1 == DACREG_ICS_PLL_CLK0_1_INI) && (m_clk0_7 == DACREG_ICS_PLL_CLK0_7_INI) && (m_clk1_b == DACREG_ICS_PLL_CLK1_B_INI)) { return 1; } } return 0;}/* * gfx, video, pci fifo should be reset, dram refresh disabled * see detect_dac */static int sst_set_pll_att_ti(struct fb_info *info, const struct pll_timing *t, const int clock){ struct sstfb_par *par = info->par; u8 cr0, cc; /* enable indexed mode */ sst_dac_write(DACREG_WMA, 0); /* backdoor */ sst_dac_read(DACREG_RMR); /* 1 time: RMR */ sst_dac_read(DACREG_RMR); /* 2 RMR */ sst_dac_read(DACREG_RMR); /* 3 // */ sst_dac_read(DACREG_RMR); /* 4 // */ cr0 = sst_dac_read(DACREG_RMR); /* 5 CR0 */ sst_dac_write(DACREG_WMA, 0); sst_dac_read(DACREG_RMR); sst_dac_read(DACREG_RMR); sst_dac_read(DACREG_RMR); sst_dac_read(DACREG_RMR); sst_dac_write(DACREG_RMR, (cr0 & 0xf0) | DACREG_CR0_EN_INDEXED | DACREG_CR0_8BIT | DACREG_CR0_PWDOWN ); /* so, now we are in indexed mode . dunno if its common, but i find this way of doing things a little bit weird :p */ udelay(300); cc = dac_i_read(DACREG_CC_I); switch (clock) { case VID_CLOCK: dac_i_write(DACREG_AC0_I, t->m); dac_i_write(DACREG_AC1_I, t->p << 6 | t->n); dac_i_write(DACREG_CC_I, (cc & 0x0f) | DACREG_CC_CLKA | DACREG_CC_CLKA_C); break; case GFX_CLOCK: dac_i_write(DACREG_BD0_I, t->m); dac_i_write(DACREG_BD1_I, t->p << 6 | t->n); dac_i_write(DACREG_CC_I, (cc & 0xf0) | DACREG_CC_CLKB | DACREG_CC_CLKB_D); break; default: dprintk("%s: wrong clock code '%d'\n", __func__, clock); return 0; } udelay(300); /* power up the dac & return to "normal" non-indexed mode */ dac_i_write(DACREG_CR0_I, cr0 & ~DACREG_CR0_PWDOWN & ~DACREG_CR0_EN_INDEXED); return 1;}static int sst_set_pll_ics(struct fb_info *info, const struct pll_timing *t, const int clock){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -