📄 sis_main.c
字号:
case SIS550_DRAM_SIZE_128MB: ivideo.video_size = 0x8000000; break; case SIS550_DRAM_SIZE_256MB: ivideo.video_size = 0x10000000; break; default: /* TW: Some 550 BIOSes don't seem to initialize SR14 correctly (if at all), * do it the hard way ourselves in this case. Unfortunately, we don't * support 24, 48, 96 and other "odd" amounts here. I don't know if * this work-around is required for 650/740 as well, but do it in case * for now. */ printk(KERN_INFO "sisfb: Warning: Could not determine memory size, " "now reading from PCI config\n"); pdev_valid = 0; pci_for_each_dev(pdev) { if ( (pdev->vendor == PCI_VENDOR_ID_SI) && ( (pdev->device == PCI_DEVICE_ID_SI_550) || (pdev->device == PCI_DEVICE_ID_SI_650) ) ) { pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data); pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; ivideo.video_size = (unsigned int)(1 << (pci_data+21)); pdev_valid = 1; /* TW: Initialize SR14=IND_SIS_DRAM_SIZE */ vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE); reg = vgarb(SEQ_DATA) & 0xC0; switch (pci_data) { case BRI_DRAM_SIZE_4MB: reg |= SIS550_DRAM_SIZE_4MB; break; case BRI_DRAM_SIZE_8MB: reg |= SIS550_DRAM_SIZE_8MB; break; case BRI_DRAM_SIZE_16MB: reg |= SIS550_DRAM_SIZE_16MB; break; case BRI_DRAM_SIZE_32MB: reg |= SIS550_DRAM_SIZE_32MB; break; case BRI_DRAM_SIZE_64MB: reg |= SIS550_DRAM_SIZE_64MB; break; /* case BRI_DRAM_SIZE_128MB: reg |= (SIS315_DRAM_SIZE_128MB << 4); break; */ default: printk(KERN_INFO "sisfb: Unable to determine memory size, giving up.\n"); return -1; } vgawb(SEQ_DATA, reg); } } if (!pdev_valid) { printk(KERN_INFO "sisfb: Total confusion - No SiS PCI VGA device found?!\n"); return -1; } return 0; }#endif return 0; } else { /* 315 */ vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE); reg = vgarb(SEQ_DATA); switch ((reg & SIS315_DRAM_SIZE_MASK) >> 4) { case SIS315_DRAM_SIZE_2MB: ivideo.video_size = 0x200000; break; case SIS315_DRAM_SIZE_4MB: ivideo.video_size = 0x400000; break; case SIS315_DRAM_SIZE_8MB: ivideo.video_size = 0x800000; break; case SIS315_DRAM_SIZE_16MB: ivideo.video_size = 0x1000000; break; case SIS315_DRAM_SIZE_32MB: ivideo.video_size = 0x2000000; break; case SIS315_DRAM_SIZE_64MB: ivideo.video_size = 0x4000000; break; case SIS315_DRAM_SIZE_128MB: ivideo.video_size = 0x8000000; break; default: return -1; } } reg &= SIS315_DUAL_CHANNEL_MASK; reg >>= 2; switch (reg) { case SIS315_SINGLE_CHANNEL_2_RANK: ivideo.video_size <<= 1; break; case SIS315_DUAL_CHANNEL_1_RANK: ivideo.video_size <<= 1; break; case SIS315_ASYM_DDR: /* TW: DDR asymentric */ ivideo.video_size += ivideo.video_size/2; break; } return 0;}static void sisfb_detect_VB_connect_315(void){ u8 sr17, cr32, temp; vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR32); cr32 = vgarb(CRTC_DATA); ivideo.TV_plug = ivideo.TV_type = 0; 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 (cr32 & SIS_VB_HIVISION) { ivideo.TV_type = TVMODE_HIVISION; ivideo.TV_plug = TVPLUG_SVIDEO; } 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) { vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP); temp = vgarb(SEQ_DATA); if (temp & 0x01) 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) { vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17); sr17 = vgarb(SEQ_DATA); if (sisfb_forcecrt1) { sisfb_crt1off=0; sr17 |= 0x80; } else { sisfb_crt1off=1; sr17 &= ~0x80; } vgawb(SEQ_DATA, sr17); }}static void sisfb_get_VB_type_315(void){ u8 reg; /* 550 has LVDS-like FSTN bridge (?) */ if (ivideo.chip == SIS_550) { if (!sisfb_has_VB_315()) { vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR37); reg = vgarb(CRTC_DATA); switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) { case SIS_EXTERNAL_CHIP_SIS301: ivideo.hasVB = HASVB_301; break; case SIS_EXTERNAL_CHIP_LVDS: ivideo.hasVB = HASVB_LVDS; break; case SIS_EXTERNAL_CHIP_TRUMPION: ivideo.hasVB = HASVB_TRUMPION; break; case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL: ivideo.hasVB = HASVB_LVDS_CHRONTEL; break; case SIS_EXTERNAL_CHIP_CHRONTEL: ivideo.hasVB = HASVB_CHRONTEL; break; default: break; } } } else { sisfb_has_VB_315(); }}static int sisfb_has_VB_315(void){ u8 vb_chipid; vgawb(VB_PART4_ADR, 0x0); vb_chipid = vgarb(VB_PART4_DATA); 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; } // Eden Chen //sishw_ext.hasVB = ivideo.hasVB; // ~Eden Chen return TRUE;}#endif /* CONFIG_FB_SIS_315 *//* --------------------- 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: If more than 8MB videoRAM detected, let our heap start at 8MB. If * there is less RAM available, let it start at 4MB. This can be overruled * by mem parameter. * 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. */ /*karl:10/01/2001*/ if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) { if (ivideo.video_size > 0x800000) { sisfb_heap_start = (unsigned long) ivideo.video_vbase + 0x800000; printk(KERN_INFO "sisfb: Memory heap starting at 8192K\n"); } else { sisfb_heap_start = (unsigned long) ivideo.video_vbase + 0x400000; printk(KERN_INFO "sisfb: Memory heap starting at 4096K\n"); } } else { sisfb_heap_start = (unsigned long) (ivideo.video_vbase + (sisfb_mem * 1024)); printk(KERN_INFO "sisfb: Memory heap starting at %dK\n", sisfb_mem); } 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 initlalize the 310 series' command queue mode. * On 310, 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; vgawb(CRTC_ADR, IND_SIS_AGP_IO_PAD); vgawb(CRTC_DATA, 0); vgawb(CRTC_DATA, SIS_AGP_2X); vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD); vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD); vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET); vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET); *write_port = *read_port; temp |= SIS_AGP_CMDQUEUE_ENABLE; vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET); vgawb(SEQ_DATA, 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; vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD); vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD); vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET); vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET); *write_port = *read_port; temp |= SIS_VRAM_CMDQUEUE_ENABLE; vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET); vgawb(SEQ_DATA, temp); *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE; sisfb_caps |= VM_CMD_QUEUE_CAP; DPRINTK("sisfb: VM Cmd Queue offset = 0x%lx, size is %dK\n", *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024); break; default: /* MMIO */ /* TW: This previously only wrote SIS_MMIO_CMD_ENABLE * to IND_SIS_CMDQUEUE_SET. I doubt that this is * enough. Reserve memory in any way. */ sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE; sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE; vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD); vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD); vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET); vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET); *write_port = *read_port; /* TW: Set Auto_Correction bit; this works in sisfb lite, * so why not. */ temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR); vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET); vgawb(SEQ_DATA, temp); *cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE; DPRINTK("sisfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n", *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024); break; } } /* sisvga_engine = 315 */#endif#ifdef CONFIG_FB_SIS_300 if (sisvga_engine == SIS_300_VGA) { /* TW: Now initialize TurboQueue. TB is always located at the very * top of the video RAM. */ if (sisfb_heap_size >= TURBO_QUEUE_AREA_SIZE) { unsigned int tqueue_pos; u8 tq_state; tqueue_pos = (ivideo.video_size - TURBO_QUEUE_AREA_SIZE) / (64 * 1024); temp = (u8) (tqueue_pos & 0xff); vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET); tq_state = vgarb(SEQ_DATA); tq_state |= 0xf0; tq_state &= 0xfc; tq_state |= (u8) (tqueue_pos >> 8); vgawb(SEQ_DATA, tq_state); vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR); vgawb(SEQ_DATA, temp); sisfb_caps |= TURBO_QUEUE_CAP; sisfb_heap_end -= TURBO_QUEUE_AREA_SIZE; sisfb_heap_size -= TURBO_QUEUE_AREA_SIZE; DPRINTK("sisfb: TurboQueue start at 0x%lx, size is %dK\n", sisfb_heap_end, TURBO_QUEUE_AREA_SIZE/1024); } }#endif /* TW: Now reserve memory for the HWCursor. It is always located at the very top of the videoRAM, right below the TB memory area (if used). */ if (sisfb_heap_size >= sisfb_hwcursor_size) { sisfb_heap_end -= sisfb_hwcursor_size; sisfb_heap_size -= sisfb_hwcursor_size; sisfb_hwcursor_vbase = sisfb_heap_end; sisfb_caps |= HW_CURSOR_CAP; DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n", sisfb_heap_end, sisfb_hwcursor_size/1024); } sisfb_heap.poha_chain = NULL; sisfb_heap.poh_freelist = NULL; poh = sisfb_poh_new_node(); if (poh == NULL) return 1; poh->poh_next = &sisfb_heap.oh_free; poh->poh_prev = &sisfb_heap.oh_free; poh->size = sisfb_heap_end - sisfb_heap_start + 1; poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase; DPRINTK("sisfb: Heap start:0x%p, end:0x%p, len=%dk\n", (char *) sisfb_heap_start, (char *) sisfb_heap_end, (unsigned int) poh->size / 1024); DPRINTK("sisfb: First Node offset:0x%x, size:%dk\n", (unsigned int) poh->offset, (unsigned int) poh->size / 1024); sisfb_heap.oh_free.poh_next = poh; sisfb_heap.oh_free.poh_prev = poh; sisfb_heap.oh_free.size = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -