📄 sis_main.c
字号:
u8 cr32, temp=0; ivideo.TV_plug = ivideo.TV_type = 0; switch(ivideo.hasVB) { case HASVB_LVDS_CHRONTEL: case HASVB_CHRONTEL: SiS_SenseCh(); break; case HASVB_301: case HASVB_302: SiS_Sense30x(); break; } inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32); if ((cr32 & SIS_CRT1) && !sisfb_crt1off) sisfb_crt1off = 0; else { if (cr32 & 0x5F) sisfb_crt1off = 1; else sisfb_crt1off = 0; } if (sisfb_crt2type != -1) /* TW: Override with option */ ivideo.disp_state = sisfb_crt2type; else if (cr32 & SIS_VB_CRT2) ivideo.disp_state = DISPTYPE_CRT2; else if (cr32 & SIS_VB_LCD) ivideo.disp_state = DISPTYPE_LCD; else if (cr32 & SIS_VB_TV) ivideo.disp_state = DISPTYPE_TV; else ivideo.disp_state = 0; if(sisfb_tvplug != -1) /* PR/TW: Override with option */ ivideo.TV_plug = sisfb_tvplug;#ifdef oldHV else if (cr32 & SIS_VB_HIVISION) { ivideo.TV_type = TVMODE_HIVISION; ivideo.TV_plug = TVPLUG_SVIDEO; }#endif else if (cr32 & SIS_VB_SVIDEO) ivideo.TV_plug = TVPLUG_SVIDEO; else if (cr32 & SIS_VB_COMPOSITE) ivideo.TV_plug = TVPLUG_COMPOSITE; else if (cr32 & SIS_VB_SCART) ivideo.TV_plug = TVPLUG_SCART; if(ivideo.TV_type == 0) { /* TW: PAL/NTSC changed for 650 */ if(ivideo.chip <= SIS_315PRO) { inSISIDXREG(SISCR, 0x38, temp); if(temp & 0x10) ivideo.TV_type = TVMODE_PAL; else ivideo.TV_type = TVMODE_NTSC; } else { inSISIDXREG(SISCR, 0x79, temp); if(temp & 0x20) ivideo.TV_type = TVMODE_PAL; else ivideo.TV_type = TVMODE_NTSC; } } /* TW: Copy forceCRT1 option to CRT1off if option is given */ if (sisfb_forcecrt1 != -1) { if (sisfb_forcecrt1) sisfb_crt1off = 0; else sisfb_crt1off = 1; }}static void sisfb_get_VB_type_315(void){ u8 reg; if (!sisfb_has_VB_315()) { inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg); /* TW: CR37 changed on 310/325 series */ switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) { case SIS_EXTERNAL_CHIP_SIS301: ivideo.hasVB = HASVB_301; break; case SIS310_EXTERNAL_CHIP_LVDS: ivideo.hasVB = HASVB_LVDS; break; case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL: ivideo.hasVB = HASVB_LVDS_CHRONTEL; break; default: break; } }}static int sisfb_has_VB_315(void){ u8 vb_chipid; inSISIDXREG(SISPART4, 0x00, vb_chipid); switch (vb_chipid) { case 0x01: ivideo.hasVB = HASVB_301; break; case 0x02: ivideo.hasVB = HASVB_302; break; case 0x03: ivideo.hasVB = HASVB_303; break; default: ivideo.hasVB = HASVB_NONE; return FALSE; } return TRUE;}#endif /* CONFIG_FB_SIS_315 *//* -------------- Sensing routines --------------- *//* TW: Determine and detect attached devices on SiS30x */intSISDoSense(int tempbl, int tempbh, int tempcl, int tempch){ int temp,i; outSISIDXREG(SISPART4,0x11,tempbl); temp = tempbh | tempcl; setSISIDXREG(SISPART4,0x10,0xe0,temp); for(i=0; i<10; i++) SiS_LongWait(&SiS_Pr); tempch &= 0x7f; inSISIDXREG(SISPART4,0x03,temp); temp ^= 0x0e; temp &= tempch; return(temp);}voidSiS_Sense30x(void){ u8 backupP4_0d; u8 testsvhs_tempbl, testsvhs_tempbh; u8 testsvhs_tempcl, testsvhs_tempch; u8 testcvbs_tempbl, testcvbs_tempbh; u8 testcvbs_tempcl, testcvbs_tempch; int myflag, result; inSISIDXREG(SISPART4,0x0d,backupP4_0d); outSISIDXREG(SISPART4,0x0d,(backupP4_0d | 0x04)); if(sisvga_engine == SIS_300_VGA) { testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9; testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3; if((sishw_ext.ujVBChipID != VB_CHIP_301) && (sishw_ext.ujVBChipID != VB_CHIP_302) ) { testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b; testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74; } inSISIDXREG(SISPART4,0x01,myflag); if(myflag & 0x04) { testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xdd; testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee; } testsvhs_tempch = 0x06; testsvhs_tempcl = 0x04; testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04; } else if((ivideo.chip == SIS_315) || (ivideo.chip == SIS_315H) || (ivideo.chip == SIS_315PRO)) { testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9; testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3; if((sishw_ext.ujVBChipID != VB_CHIP_301) && (sishw_ext.ujVBChipID != VB_CHIP_302) ) { testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b; testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74; } inSISIDXREG(SISPART4,0x01,myflag); if(myflag & 0x04) { testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xdd; testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee; } testsvhs_tempch = 0x06; testsvhs_tempcl = 0x04; testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04; } else { testsvhs_tempbh = 0x02; testsvhs_tempbl = 0x00; testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x00; testsvhs_tempch = 0x04; testsvhs_tempcl = 0x08; testcvbs_tempch = 0x08; testcvbs_tempcl = 0x08; } result = SISDoSense(testsvhs_tempbl, testsvhs_tempbh, testsvhs_tempcl, testsvhs_tempch); if(result) { printk(KERN_INFO "sisfb: Detected TV connected to SVHS output\n"); /* TW: So we can be sure that there IS a SVHS output */ ivideo.TV_plug = TVPLUG_SVIDEO; orSISIDXREG(SISCR, 0x32, 0x02); } if(!result) { result = SISDoSense(testcvbs_tempbl, testcvbs_tempbh, testcvbs_tempcl, testcvbs_tempch); if(result) { printk(KERN_INFO "sisfb: Detected TV connected to CVBS output\n"); /* TW: So we can be sure that there IS a CVBS output */ ivideo.TV_plug = TVPLUG_COMPOSITE; orSISIDXREG(SISCR, 0x32, 0x01); } } SISDoSense(0, 0, 0, 0); outSISIDXREG(SISPART4,0x0d,backupP4_0d);}/* TW: Determine and detect attached TV's on Chrontel */voidSiS_SenseCh(void){ u8 temp1;#ifdef CONFIG_FB_SIS_315 u8 temp2;#endif if(ivideo.chip < SIS_315H) {#ifdef CONFIG_FB_SIS_300 SiS_Pr.SiS_IF_DEF_CH70xx = 1; /* TW: Chrontel 7005 */ temp1 = SiS_GetCH700x(&SiS_Pr, 0x25); if ((temp1 >= 50) && (temp1 <= 100)) { /* TW: Read power status */ temp1 = SiS_GetCH700x(&SiS_Pr, 0x0e); if((temp1 & 0x03) != 0x03) { /* TW: Power all outputs */ SiS_SetCH70xxANDOR(&SiS_Pr, 0x030E,0xF8); } /* TW: Sense connected TV devices */ SiS_SetCH700x(&SiS_Pr, 0x0110); SiS_SetCH700x(&SiS_Pr, 0x0010); temp1 = SiS_GetCH700x(&SiS_Pr, 0x10); if(!(temp1 & 0x08)) { printk(KERN_INFO "sisfb: Chrontel: Detected TV connected to SVHS output\n"); /* TW: So we can be sure that there IS a SVHS output */ ivideo.TV_plug = TVPLUG_SVIDEO; orSISIDXREG(SISCR, 0x32, 0x02); } else if (!(temp1 & 0x02)) { printk(KERN_INFO "sisfb: Chrontel: Detected TV connected to CVBS output\n"); /* TW: So we can be sure that there IS a CVBS output */ ivideo.TV_plug = TVPLUG_COMPOSITE; orSISIDXREG(SISCR, 0x32, 0x01); } else { SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8); } } else if(temp1 == 0) { SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8); }#endif } else {#ifdef CONFIG_FB_SIS_315 SiS_Pr.SiS_IF_DEF_CH70xx = 2; /* TW: Chrontel 7019 */ temp1 = SiS_GetCH701x(&SiS_Pr, 0x49); SiS_SetCH701x(&SiS_Pr, 0x2049); SiS_DDC2Delay(&SiS_Pr, 0x96); temp2 = SiS_GetCH701x(&SiS_Pr, 0x20); temp2 |= 0x01; SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20); SiS_DDC2Delay(&SiS_Pr, 0x96); temp2 ^= 0x01; SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20); SiS_DDC2Delay(&SiS_Pr, 0x96); temp2 = SiS_GetCH701x(&SiS_Pr, 0x20); SiS_SetCH701x(&SiS_Pr, (temp1 << 8) | 0x49); temp1 = 0; if(temp2 & 0x02) temp1 |= 0x01; if(temp2 & 0x10) temp1 |= 0x01; if(temp2 & 0x04) temp1 |= 0x02; if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04; switch(temp1) { case 0x01: printk(KERN_INFO "sisfb: Chrontel: Detected TV connected to CVBS output\n"); ivideo.TV_plug = TVPLUG_COMPOSITE; orSISIDXREG(SISCR, 0x32, 0x01); break; case 0x02: printk(KERN_INFO "sisfb: Chrontel: Detected TV connected to SVHS output\n"); ivideo.TV_plug = TVPLUG_SVIDEO; orSISIDXREG(SISCR, 0x32, 0x02); break; case 0x04: /* TW: This should not happen */ printk(KERN_INFO "sisfb: Chrontel: Detected TV connected to SCART output!?\n"); break; }#endif }}/* --------------------- Heap Routines ------------------------------- */static int sisfb_heap_init(void){ SIS_OH *poh; u8 temp=0;#ifdef CONFIG_FB_SIS_315 int agp_enabled = 1; u32 agp_size; unsigned long *cmdq_baseport = 0; unsigned long *read_port = 0; unsigned long *write_port = 0; SIS_CMDTYPE cmd_type;#ifndef AGPOFF agp_kern_info *agp_info; agp_memory *agp; u32 agp_phys;#endif#endif/* TW: The heap start is either set manually using the "mem" parameter, or * defaults as follows: * -) If more than 16MB videoRAM available, let our heap start at 12MB. * -) If more than 8MB videoRAM available, let our heap start at 8MB. * -) If 4MB or less is available, let it start at 4MB. * This is for avoiding a clash with X driver which uses the beginning * of the videoRAM. To limit size of X framebuffer, use Option MaxXFBMem * in XF86Config-4. * The heap start can also be specified by parameter "mem" when starting the sisfb * driver. sisfb mem=1024 lets heap starts at 1MB, etc. */ if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) { if (ivideo.video_size > 0x1000000) { ivideo.heapstart = 0xc00000; } else if (ivideo.video_size > 0x800000) { ivideo.heapstart = 0x800000; } else { ivideo.heapstart = 0x400000; } } else { ivideo.heapstart = sisfb_mem * 1024; } sisfb_heap_start = (unsigned long) (ivideo.video_vbase + ivideo.heapstart); printk(KERN_INFO "sisfb: Memory heap starting at %dK\n", (int)(ivideo.heapstart / 1024)); sisfb_heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size; sisfb_heap_size = sisfb_heap_end - sisfb_heap_start;#ifdef CONFIG_FB_SIS_315 if (sisvga_engine == SIS_315_VGA) { /* TW: Now initialize the 310 series' command queue mode. * On 310/325, there are three queue modes available which * are chosen by setting bits 7:5 in SR26: * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep * track of the queue, the FIFO, command parsing and so * on. This is the one comparable to the 300 series. * 2. VRAM queue mode (bit 6, 0x40). In this case, one will * have to do queue management himself. Register 0x85c4 will * hold the location of the next free queue slot, 0x85c8 * is the "queue read pointer" whose way of working is * unknown to me. Anyway, this mode would require a * translation of the MMIO commands to some kind of * accelerator assembly and writing these commands * to the memory location pointed to by 0x85c4. * We will not use this, as nobody knows how this * "assembly" works, and as it would require a complete * re-write of the accelerator code. * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the * queue in AGP memory space. * * SR26 bit 4 is called "Bypass H/W queue". * SR26 bit 1 is called "Enable Command Queue Auto Correction" * SR26 bit 0 resets the queue * Size of queue memory is encoded in bits 3:2 like this: * 00 (0x00) 512K * 01 (0x04) 1M * 10 (0x08) 2M * 11 (0x0C) 4M * The queue location is to be written to 0x85C0. * */ cmdq_baseport = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_PHYBASE); write_port = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_WRITEPORT); read_port = (unsigned long *)(ivideo.mmio_vbase + MMIO_QUEUE_READPORT); DPRINTK("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, read_port, write_port); agp_size = COMMAND_QUEUE_AREA_SIZE;#ifndef AGPOFF if (sisfb_queuemode == AGP_CMD_QUEUE) { agp_info = vmalloc(sizeof(agp_kern_info)); memset((void*)agp_info, 0x00, sizeof(agp_kern_info)); agp_copy_info(agp_info); agp_backend_acquire(); agp = agp_allocate_memory(COMMAND_QUEUE_AREA_SIZE/PAGE_SIZE, AGP_NORMAL_MEMORY); if (agp == NULL) { DPRINTK("sisfb: Allocating AGP buffer failed.\n"); agp_enabled = 0; } else { if (agp_bind_memory(agp, agp->pg_start) != 0) { DPRINTK("sisfb: AGP: Failed to bind memory\n"); /* TODO: Free AGP memory here */ agp_enabled = 0; } else { agp_enable(0); } } }#else agp_enabled = 0;#endif /* TW: Now select the queue mode */ if ((agp_enabled) && (sisfb_queuemode == AGP_CMD_QUEUE)) { cmd_type = AGP_CMD_QUEUE; printk(KERN_INFO "sisfb: Using AGP queue mode\n");/* } else if (sisfb_heap_size >= COMMAND_QUEUE_AREA_SIZE) */ } else if (sisfb_queuemode == VM_CMD_QUEUE) { cmd_type = VM_CMD_QUEUE; printk(KERN_INFO "sisfb: Using VRAM queue mode\n"); } else { printk(KERN_INFO "sisfb: Using MMIO queue mode\n"); cmd_type = MMIO_CMD; } switch (agp_size) { case 0x80000: temp = SIS_CMD_QUEUE_SIZE_512k; break; case 0x100000: temp = SIS_CMD_QUEUE_SIZE_1M; break; case 0x200000: temp = SIS_CMD_QUEUE_SIZE_2M; break; case 0x400000: temp = SIS_CMD_QUEUE_SIZE_4M; break; } switch (cmd_type) { case AGP_CMD_QUEUE:#ifndef AGPOFF DPRINTK("sisfb: AGP buffer base = 0x%lx, offset = 0x%x, size = %dK\n", agp_info->aper_base, agp->physical, agp_size/1024); agp_phys = agp_info->aper_base + agp->physical; outSISIDXREG(SISCR, IND_SIS_AGP_IO_PAD, 0); outSISIDXREG(SISCR, IND_SIS_AGP_IO_PAD, SIS_AGP_2X); outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD); outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET); *write_port = *read_port; temp |= SIS_AGP_CMDQUEUE_ENABLE; outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp); *cmdq_baseport = agp_phys; sisfb_caps |= AGP_CMD_QUEUE_CAP;#endif break; case VM_CMD_QUEUE: sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE; sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE; outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD); outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET); *write_port = *read_port; temp |= SIS_VRAM_CMDQUEUE_ENABLE; outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp); *cmdq_baseport = ivideo.video_size - COMMAND_QU
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -