📄 sstfb.c
字号:
/* 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("bug line %d: wrong clock code '%d'\n", __LINE__,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 sstfb_info * sst_info, const struct pll_timing *t, const int clock){ u8 pll_ctrl; f_dprintk("sst_set_pll_ics\n"); sst_dac_write(DACREG_ICS_PLLRMA, DACREG_ICS_PLL_CTRL); pll_ctrl = sst_dac_read(DACREG_ICS_PLLDATA); switch(clock) { case VID_CLOCK: sst_dac_write(DACREG_ICS_PLLWMA, 0x0); /* CLK0, f0 */ sst_dac_write(DACREG_ICS_PLLDATA, t->m); sst_dac_write(DACREG_ICS_PLLDATA, t->p << 5 | t->n); /* selects freq f0 for clock 0 */ sst_dac_write(DACREG_ICS_PLLWMA, DACREG_ICS_PLL_CTRL); sst_dac_write(DACREG_ICS_PLLDATA, (pll_ctrl & 0xd8) | DACREG_ICS_CLK0 | DACREG_ICS_CLK0_0); break; case GFX_CLOCK : sst_dac_write(DACREG_ICS_PLLWMA, 0xa); /* CLK1, fA */ sst_dac_write(DACREG_ICS_PLLDATA, t->m); sst_dac_write(DACREG_ICS_PLLDATA, t->p << 5 | t->n); /* selects freq fA for clock 1 */ sst_dac_write(DACREG_ICS_PLLWMA, DACREG_ICS_PLL_CTRL); sst_dac_write(DACREG_ICS_PLLDATA, (pll_ctrl & 0xef) | DACREG_ICS_CLK1_A); break; default: dprintk("bug line %d: wrong clock code '%d'\n", __LINE__, clock); return 0; } udelay(300); return 1;}static int sstfb_set_par(const struct sstfb_par * par, struct sstfb_info * sst_info){ u32 lfbmode, fbiinit1, fbiinit2, fbiinit3, fbiinit5, fbiinit6=0; int ntiles; struct pci_dev * sst_dev = sst_info->dev; f_dprintk("sst_set_par(%dx%d)\n", par->xDim, par->yDim); f_ddprintk("hSyncOn hSyncOff vSyncOn vSyncOff\n"); f_ddprintk("%-7d %-8d %-7d %-8d\n", par->hSyncOn, par->hSyncOff, par->vSyncOn, par->vSyncOff); f_ddprintk("hBackPorch vBackPorch xDim yDim Freq\n"); f_ddprintk("%-10d %-10d %-4d %-4d %-8d\n", par->hBackPorch, par->vBackPorch, par->xDim, par->yDim, par->freq); if (!par->valid) { BUG(); return -1; } 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 | (par->hBackPorch - 2)); sst_write(VIDEODIMENSIONS, par->yDim << 16 | (par->xDim - 1)); sst_write(HSYNC, (par->hSyncOff - 1) << 16 | (par->hSyncOn - 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 ); sst_info->dac_sw.set_vidmod(sst_info, par->bpp); /* set video clock */ sst_info->dac_sw.set_pll(sst_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(sst_info)) { 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(par->bpp) { case 16: fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL; break;#ifdef EN_24_32_BPP case 24: case 32:/* orig sst_set_bits(FBIINIT1, SEL_SOURCE_VCLK_2X_DIV2 | EN_24BPP); */ fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL | EN_24BPP; break;#endif default: dprintk("bug line %d: bad depth '%u'\n", __LINE__, par->bpp ); return 0; break; } sst_write(FBIINIT1, fbiinit1); if (IS_VOODOO2(sst_info)) { sst_write(FBIINIT6, fbiinit6); fbiinit5=sst_read(FBIINIT5) & FBIINIT5_MASK ; if (par->vmode & FB_VMODE_INTERLACED) fbiinit5 |= INTERLACE; if (par->vmode & FB_VMODE_DOUBLE ) fbiinit5 |= VDOUBLESCAN; if (par->sync & FB_SYNC_HOR_HIGH_ACT) fbiinit5 |= HSYNC_HIGH; if (par->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(par->bpp) { 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: BUG(); return 0; }#if defined(__BIG_ENDIAN) /* enable byte-swizzle functionality in hardware */ 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", par->xDim-1, par->yDim-1); sst_write(CLIP_LEFT_RIGHT, par->xDim ); 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 ); } sst_info->current_par = *par; return 1;}static void sst_set_vidmod_att_ti(struct sstfb_info * sst_info, const int bpp){ u8 cr0; f_dprintk("sst_set_vidmod_att_ti(bpp: %d)\n", bpp); 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 */ cr0 = sst_dac_read(DACREG_RMR); 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); /* cr0 */ switch(bpp) { case 16: sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_16BPP); break;#ifdef EN_24_32_BPP case 24: case 32: sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_24BPP); break;#endif default: BUG(); }}static void sst_set_vidmod_ics(struct sstfb_info * sst_info, const int bpp){ f_dprintk("sst_set_vidmod_ics(bpp: %d)\n", bpp); switch(bpp) { case 16: sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_16BPP); break;#ifdef EN_24_32_BPP case 24: case 32: sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_24BPP); break;#endif default: BUG(); }}static int __devinit sst_init(struct sstfb_info *sst_info){ struct pll_timing gfx_timings; struct sst_spec * spec; struct pci_dev * sst_dev = sst_info->dev; int Fout; u32 fbiinit0, fbiinit1, fbiinit4; spec = &voodoo_spec[sst_info->type]; f_dprintk("sst_init\n"); f_ddprintk(" fbiinit0 fbiinit1 fbiinit2 fbiinit3 fbiinit4 " " fbiinit6\n"); f_ddprintk("%0#10x %0#10x %0#10x %0#10x %0#10x %0#10x\n", sst_read(FBIINIT0), sst_read(FBIINIT1), sst_read(FBIINIT2), sst_read(FBIINIT3), sst_read(FBIINIT4), sst_read(FBIINIT6)); /* disable video clock */ pci_write_config_dword(sst_dev, PCI_VCLK_DISABLE,0); /* enable writing to init registers ,disable pci fifo*/ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); /* reset video */ sst_set_bits(FBIINIT1, VIDEO_RESET); sst_wait_idle(); /* reset gfx + pci fifo */ sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET); sst_wait_idle(); /* unreset fifo */ /*sst_unset_bits(FBIINIT0, FIFO_RESET); sst_wait_idle();*/ /* unreset FBI */ /*sst_unset_bits(FBIINIT0, FBI_RESET); sst_wait_idle();*/ /* disable dram refresh */ sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH); sst_wait_idle(); /* remap fbinit2/3 to dac */ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR | PCI_REMAP_DAC ); /* detect dac type */ if (!sst_detect_dactype(sst_info)) { eprintk("Unknown dac type\n"); //FIXME watch it : we are not in a safe state , bad bad bad . return 0; } /* set graphic clock */ sst_info->gfx_clock = spec->default_gfx_clock; if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) { iprintk ("Using supplied graphic freq : %dMHz\n", gfxclk); sst_info->gfx_clock = gfxclk *1000; } else if (gfxclk) { wprintk ("You fool, %dMhz is way out of spec! Using default\n", gfxclk); } sst_calc_pll(sst_info->gfx_clock, &Fout, &gfx_timings); sst_info->dac_sw.set_pll(sst_info, &gfx_timings, GFX_CLOCK); /* disable fbiinit remap */ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR| PCI_EN_FIFO_WR ); /* defaults init registers */ /* FbiInit0: unreset gfx, unreset fifo */ fbiinit0 = FBIINIT0_DEFAULT; fbiinit1 = FBIINIT1_DEFAULT; fbiinit4 = FBIINIT4_DEFAULT; if (vgapass) fbiinit0 &= ~EN_VGA_PASSTHROUGH; else fbiinit0 |= EN_VGA_PASSTHROUGH; if (slowpci) { fbiinit1 |= SLOW_PCI_WRITES; fbiinit4 |= SLOW_PCI_READS; } else { fbiinit1 &= ~SLOW_PCI_WRITES; fbiinit4 &= ~SLOW_PCI_READS; } sst_write(FBIINIT0, fbiinit0); sst_wait_idle(); sst_write(FBIINIT1, fbiinit1); sst_wait_idle(); sst_write(FBIINIT2, FBIINIT2_DEFAULT); sst_wait_idle(); sst_write(FBIINIT3, FBIINIT3_DEFAULT); sst_wait_idle(); sst_write(FBIINIT4, fbiinit4); sst_wait_idle(); if (IS_VOODOO2(sst_info)) { sst_write(FBIINIT6, FBIINIT6_DEFAULT); sst_wait_idle(); } pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_FIFO_WR ); pci_write_config_dword(sst_dev, PCI_VCLK_ENABLE, 0); return 1;}static void __devexit sst_shutdown(struct sstfb_info *sst_info){ struct pci_dev * sst_dev = sst_info->dev; struct pll_timing gfx_timings; int Fout; f_dprintk("sst_shutdown\n"); /* reset video, gfx, fifo, disable dram + remap fbiinit2/3 */ pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR); sst_set_bits(FBIINIT1, VIDEO_RESET | EN_BLANKING); sst_unset_bits(FBIINIT2, EN_DRAM_REFRESH); sst_set_bits(FBIINIT0, FBI_RESET | FIFO_RESET); sst_wait_idle(); pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, PCI_EN_INIT_WR | PCI_REMAP_DAC ); /*set 20Mhz gfx clock */ sst_calc_pll(20000, &Fout, &gfx_timings); sst_info->dac_sw.set_pll(sst_info, &gfx_timings, GFX_CLOCK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -