?? sstfb.c
字號:
display->type_aux = 0; display->ypanstep = 0; display->ywrapstep = 0; display->line_length = (var->bits_per_pixel==16) ? 2048 : 4096; display->inverse = 0; switch (var->bits_per_pixel) {#ifdef FBCON_HAS_CFB16 case 16: display->dispsw = &fbcon_cfb16; display->dispsw_data = sst_info->fbcon_cmap.cfb16; break;#endif#ifdef EN_24_32_BPP#if defined (FBCON_HAS_CFB24) || defined (FBCON_HAS_CFB32 ) case 24: /*24bpp non packed <=> 32 bpp */ case 32: display->dispsw = &fbcon_cfb32; display->dispsw_data = sst_info->fbcon_cmap.cfb32; break;#endif#endif default: display->dispsw = &fbcon_dummy; break; } display->scrollmode = SCROLL_YREDRAW; if (sst_info->info.changevar) { v_dprintk("fb_info.changevar(con: %d)\n", con); (*sst_info->info.changevar)(con); v_dprintk("fb_info.changevar: done \n"); } else { v_dprintk("fb_info.changevar() == NULL . \n"); } } if ((con == -1) || (con==sst_info->currcon)) { sstfb_set_par (&par, sst_info); } print_var(var, "var"); print_var(&display->var, "&display->var"); if (old_bpp != var->bits_per_pixel) { if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) return err; sstfb_install_cmap(con, info); } return 0;#undef sst_info}static int sstfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){#define sst_info ((struct sstfb_info *) info) struct display *d = (con<0) ? info->disp : fb_display + con; f_dprintk("sstfb_set_cmap\n"); f_ddprintk("con: %d, currcon: %d, d->cmap.len %d\n", con, sst_info->currcon, d->cmap.len); if (d->cmap.len != 16 ) { /* or test if cmap.len == 0 ? */ int err; err = fb_alloc_cmap(&d->cmap, 16, 0); /* cmap size=16 */ if (err) return err; } if (con == sst_info->currcon) { return fb_set_cmap(cmap, kspc, sstfb_setcolreg, info); } else { fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1); } return 0;#undef sst_info}static int sstfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){#define sst_info ((struct sstfb_info *) info) f_dprintk("sstfb_get_cmap\n"); f_ddprintk("con %d, curcon %d, cmap.len %d\n", con, sst_info->currcon, fb_display[con].cmap.len); /* FIXME: check if con = -1 ? cf sstfb_set_cmap... */ if (con == sst_info->currcon) return fb_get_cmap(cmap, kspc, sstfb_getcolreg, info); else if (fb_display[con].cmap.len) fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else fb_copy_cmap( fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2); return 0;#undef sst_info}/* TODO */static int sstfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info){ f_dprintk("sstfb_pan_display\n"); return -EINVAL;}static int sstfb_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg, int con, struct fb_info *info){#define sst_info ((struct sstfb_info *) info)#if (SST_DEBUG_IOCTL >0) int i; u_long p; u32 tmp; u32 fbiinit0; struct pci_dev * sst_dev = sst_info->dev;#endif f_dprintk("sstfb_ioctl(%x)\n", cmd);#if (SST_DEBUG_IOCTL >0) switch (cmd) {# if (SST_DEBUG_VAR >0)/* tmp ioctl : dumps fb_display[0-5] */ case _IO('F', 0xdb): /* 0x46db */ f_dprintk("dumping fb_display[0-5].var\n"); for (i = 0 ; i< 6 ; i++) { print_var(&fb_display[i].var, "var(%d)", i); } return 0;# endif /* (SST_DEBUG_VAR >0) *//* fills the lfb up to *(u32*)arg */ case _IOW('F', 0xdc, u32): /* 0x46dc */ if (*(u32*)arg > 0x400000 ) *(u32*) arg = 0x400000; f_dprintk("filling %#x \n", *(u32*)arg); for (p = 0 ; p < *(u32*)arg; p+=2) writew( p >> 6 , sst_info->video.vbase + p); return 0;/* change VGA pass_through */ case _IOW('F', 0xdd, u32): /* 0x46dd */ f_dprintk("switch VGA pass-through\n"); 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 (* (u32*)arg) { 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; case _IO('F', 0xde): /* 0x46de */ f_dprintk("test color display\n"); f_ddprintk("currcon: %d, bpp %d\n", sst_info->currcon, sst_info->current_par.bpp); memset_io(sst_info->video.vbase, 0, sst_info->video.len); switch (sst_info->current_par.bpp) { case 16: sstfb_test16(sst_info); break;# ifdef EN_24_32_BPP case 24: case 32: sstfb_test32(sst_info); break;# endif default: dprintk("bug line %d: bad depth '%u'\n", __LINE__, sst_info->current_par.bpp); } return 0; }#endif /* (SST_DEBUG_IOCTL >0) */ return -EINVAL;#undef sst_info}/* * Low level routines *//* get lfb size */static int __devinit sst_get_memsize(struct sstfb_info *sst_info, u_long *memsize){ u_long fbbase_virt = sst_info->video.vbase; f_dprintk("sst_get_memsize\n"); /* force memsize */ if ((mem >= 1 ) && (mem <= 4)) { *memsize = (mem * 0x100000); iprintk("supplied memsize: %#lx\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: %#lx\n", *memsize); return 1;}/* * wait for the fbi chip. ASK: what happens if the fbi is stuck ? * * the FBI is supposed to be ready if we receive 5 time * in a row a "idle" answer to our requests */static int __sst_wait_idle(u_long vbase){ int count = 0; f_ddprintk("sst_wait_idle\n"); while(1) { if (__sst_read(vbase, STATUS) & STATUS_FBI_BUSY) { f_dddprintk("status: busy\n");/* FIXME basicaly, this is a busy wait. maybe not that good. oh well; this is a small loop after all ...*/ count = 0; } else { count++; f_dddprintk("status: idle(%d)\n", count); } if (count >= 5) return 1;//XXX do something to avoid hanging the machine if the voodoo is out }}/* * detect dac type * prerequisite : write to FbiInitx enabled, video and fbi and pci fifo reset, * dram refresh disabled, FbiInit remaped. * TODO: mmh.. maybe i shoud put the "prerequisite" in the func ... */static int __devinit sst_detect_dactype(struct sstfb_info * sst_info){ int ret=0,i; f_dprintk("sst_detect_dactype\n"); for (i=0; i< sizeof(dacs)/sizeof(dacs[0]) ; i++) { ret = dacs[i].detect(sst_info); if (ret) break; } if (!ret) return 0; f_dprintk("found %s\n", dacs[i].name); sst_info->dac_sw=dacs[i]; return 1;}/* 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 sstfb_info * sst_info){ int i, mir, dir; f_dprintk("sst_detect_att\n"); 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 sstfb_info * sst_info){ int i, mir, dir; f_dprintk("sst_detect_ti\n"); 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 sstfb_info * sst_info){ int i; int m_clk0_1, m_clk0_7, m_clk1_b; int n_clk0_1, n_clk0_7, n_clk1_b; f_dprintk("sst_detect_ics\n"); 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;}/* compute the m,n,p , returns the real freq * (ics datasheet : N <-> N1 , P <-> N2) * * Fout= Fref * (M+2)/( 2^P * (N+2)) * we try to get close to the asked freq * with P as high, and M as low as possible * range: * ti/att : 0 <= M <= 255; 0 <= P <= 3; 0<= N <= 63 * ics : 1 <= M <= 127; 0 <= P <= 3; 1<= N <= 31 * we'll use the lowest limitation, should be precise enouth */static int sst_calc_pll(const int freq, int *freq_out, struct pll_timing *t){ int m, m2, n, p, best_err, fout; int best_n=-1; int best_m=-1; f_dprintk("sst_calc_pll(%dKhz)\n", freq); best_err = freq; p=3; /* f * 2^P = vco should be less than VCOmax ~ 250 MHz for ics*/ while (((1 << p) * freq > VCO_MAX) && (p >= 0)) p--; if (p == -1) return -EINVAL; for (n = 1; n < 32; n++) { /* calc 2 * m so we can round it later*/ m2 = (2 * freq * (1 << p) * (n + 2) ) / DAC_FREF - 4 ; m = (m2 % 2 ) ? m2/2+1 : m2/2 ; if (m >= 128) break; fout = (DAC_FREF * (m + 2)) / ((1 << p) * (n + 2)); if ((ABS(fout - freq) < best_err) && (m > 0)) { best_n = n; best_m = m; best_err = ABS(fout - freq); /* we get the lowest m , allowing 0.5% error in freq*/ if (200*best_err < freq) break; } } if (best_n == -1) /* unlikely, but who knows ? */ return -EINVAL; t->p=p; t->n=best_n; t->m=best_m; *freq_out=(DAC_FREF * (t->m + 2)) / ((1 << t->p) * (t->n + 2)); f_ddprintk ("m: %d, n: %d, p: %d, F: %dKhz\n", t->m, t->n, t->p, *freq_out); return 0;}/* * gfx, video, pci fifo should be reset, dram refresh disabled * see detect_dac */static int sst_set_pll_att_ti(struct sstfb_info * sst_info, const struct pll_timing *t, const int clock){ u8 cr0, cc; f_dprintk("sst_set_pll_att_ti\n"); /* enable indexed mode */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -