diff --git a/kernel/trunk/drivers/vidrdc.asm b/kernel/trunk/drivers/vidrdc.asm new file mode 100644 index 0000000000..78164e071f --- /dev/null +++ b/kernel/trunk/drivers/vidrdc.asm @@ -0,0 +1,438 @@ +; Stub of videodriver for RDC Semiconductor Co. M2010/M2012 videocards (controller names: R3306/R3308). +; It is used in SoC produced by DMP Electronics Inc.: +; Vortex86MX (contains RDC M2010 graphics card, appears in eBox-3300MX) +; Vortex86MX+ (contains RDC M2012 graphics card, appears in eBox-3310MX) +; Link to manufacturers websites - +; RDC Semiconductor Co.: http://www.rdc.com.tw +; DM&P Electronics Inc.: http://www.dmp.com.tw and http://www.compactpc.com.tw +; Code stolen from vidintel.asm driver (c) by CleverMouse and adapted for RDC. + +; When the start procedure gets control, +; it tries to detect preferred resolution, +; sets the detected resolution assuming 32-bpp VESA mode and exits +; (without registering a service). +; Detection can be overloaded with compile-time settings +; use_predefined_mode/predefined_width/predefined_height. + +; set predefined resolution here +use_predefined_mode = 0;1 +predefined_width = 0;1366 +predefined_height = 0;768 + +; standard driver stuff +format MS COFF + +DEBUG = 1 + +include 'proc32.inc' +include 'imports.inc' + +public START +public version + +section '.flat' code readable align 16 +; the start procedure (see the description above) +START: +; 1. Detect device. Abort if not found. + push esi + call DetectDevice + test esi, esi + jz .return0 + +;{START}yogev_ezra: temporary exit after detection + pusha + mov esi, exitmsg + call SysMsgBoardStr + popa + jmp .return0 +;{END}yogev_ezra: temporary exit after detection + +; 2. Detect optimal mode unless the mode is given explicitly. Abort if failed. +if use_predefined_mode = 0 + call DetectMode +end if + cmp [width], 0 + jz .return0_cleanup +; 3. Set the detected mode. + call SetMode +; 4. Cleanup and return. +.return0_cleanup: + stdcall FreeKernelSpace, esi +.return0: + pop esi + xor eax, eax + ret 4 + +; check that there is RDC videocard +; if so, map MMIO registers and set internal variables +; esi points to MMIO block; NULL means no device +DetectDevice: +; 1. Sanity check: check that we are dealing with RDC videocard. +; Integrated video device for RDC is always at PCI:0:13:0 (bus:dev:fn=0:0d:0) + xor esi, esi ; initialize return value to NULL +; 1a. Get PCI VendorID and DeviceID. + push esi ; in: reg=0 (register) -> register 00 means return DeviceID (bits 16-31) + VendorID (bits 0-15) + push 68h ; in: devfn=13:0 | device:5bit (0Dh = 1101) + func:3bit (0 = 000) -> total:1byte (1101000b = 68h) + push esi ; in: bus=0 + call PciRead32 +; 1b. loword(eax) = ax = VendorID, hiword(eax) = DeviceID. +; Test whether we have RDC Semiconductor Co. chipset. + cmp ax, 17F3h ;VendorID 0x17F3, 'RDC Semiconductor Co.' + jnz .return +; 1c. Say hi including DeviceID. + shr eax, 10h ; now, ax = HIWORD(eax) = PCI DeviceID + push edi + pusha + mov edi, pciid_text ; edi='0000' + call WriteWord + mov esi, hellomsg + call SysMsgBoardStr + popa +; 1d. Test whether we know this DeviceID. +; If this is the case, remember the position of the device in line of RDC cards; +; this knowledge will be useful later. +; Tested on devices with id: 17F3:2010, 17F3:2012. + mov ecx, pciids_num + mov edi, pciids + repnz scasw + pop edi + jnz .return_unknown_pciid + sub ecx, pciids_num - 1 + neg ecx + mov [deviceType], ecx +; 1e. Continue saying hi with positive intonation. + pusha + mov esi, knownmsg + call SysMsgBoardStr + popa +; 2. Prepare MMIO region to control the card. +; 2a. Read MMIO physical address from PCI config space. +; According to RDC M2010/M2012 registers manual, their memory-mapped I/O space is located at Base address #1 + push 14h ; in: reg=14h (register) -> register 14h means Base address #1 (BAR1) in PCI configuration space + push 68h ; in: devfn=13:0 | device:5bit (0Dh = 1101) + func:3bit (0 = 000) -> total:1byte (1101000b = 68h) + push esi ; in: bus=0 + call PciRead32 +; 2b. Mask out PCI region type, lower 4 bits. + and al, not 0xF +; 2c. Create virtual mapping of the physical memory. + push 1Bh + push 100000h + push eax + call MapIoMem +; 3. Return. + xchg esi, eax +.return: + ret +; 1f. If we do not know DeviceID, continue saying hi with negative intonation. +.return_unknown_pciid: + pusha + mov esi, unknownmsg + call SysMsgBoardStr + popa + ret + +; Convert word in ax to hexadecimal text in edi, advance edi. +WriteWord: +; 1. Convert high byte. + push eax + mov al, ah + call WriteByte + pop eax +; 2. Convert low byte. +; Fall through to WriteByte; ret from WriteByte is ret from WriteWord too. + +; Convert byte in al to hexadecimal text in edi, advance edi. +WriteByte: +; 1. Convert high nibble. + push eax + shr al, 4 + call WriteNibble + pop eax +; 2. Convert low nibble. + and al, 0xF +; Fall through to WriteNibble; ret from WriteNibble is ret from WriteByte too. + +; Convert nibble in al to hexadecimal text in edi, advance edi. +WriteNibble: +; Obvious, isn't it? + cmp al, 10 + sbb al, 69h + das + stosb ; This instruction uses EDI implicitly + ret + +if use_predefined_mode = 0 +; detect resolution of the flat panel +DetectMode: + push esi edi +; 1. Get the location of block of GMBUS* registers. +; Starting with Ironlake, GMBUS* registers were moved. + add esi, 5100h + cmp [deviceType], pciids_num ;ironlake_start + jb @f + add esi, 0xC0000 +@@: +; 2. Initialize GMBUS engine. + mov edi, edid + mov ecx, 0x10000 +@@: + test byte [esi+8+1], 80h + loopnz @b + jnz .fail + mov dword [esi], 3 + test byte [esi+8+1], 4 + jz .noreset + call ResetGMBus + jnz .fail +.noreset: +; 3. Send read command. + and dword [esi+20h], 0 + mov dword [esi+4], 4E8000A1h +; 4. Wait for data, writing to the buffer as data arrive. +.getdata: + mov ecx, 0x10000 +@@: + test byte [esi+8+1], 8 + loopz @b + test byte [esi+8+1], 4 + jz .dataok + call ResetGMBus + jmp .fail +.dataok: + mov eax, [esi+0Ch] + stosd + cmp edi, edid+80h + jb .getdata +; 5. Wait for bus idle. + mov ecx, 0x10000 +@@: + test byte [esi+8+1], 2 + loopnz @b +; 6. We got EDID; dump it if DEBUG. +if DEBUG + pusha + xor ecx, ecx + mov esi, edid + mov edi, edid_text +.dumploop: + lodsb + call WriteByte + mov al, ' ' + stosb + inc cl + test cl, 15 + jnz @f + mov byte [edi-1], 13 + mov al, 10 + stosb +@@: + test cl, cl + jns .dumploop + mov esi, edidmsg + call SysMsgBoardStr + popa +end if +; 7. Test whether EDID is good. +; 7a. Signature: 00 FF FF FF FF FF FF 00. + mov esi, edid + cmp dword [esi], 0xFFFFFF00 + jnz .fail + cmp dword [esi+4], 0x00FFFFFF + jnz .fail +; 7b. Checksum must be zero. + xor edx, edx + mov ecx, 80h +@@: + lodsb + add dl, al + loop @b + jnz .fail +; 8. Get width and height from EDID. + xor eax, eax + mov ah, [esi-80h+3Ah] + shr ah, 4 + mov al, [esi-80h+38h] + mov [width], eax + mov ah, [esi-80h+3Dh] + shr ah, 4 + mov al, [esi-80h+3Bh] + mov [height], eax +; 9. Return. +.fail: + pop edi esi + ret + +; reset bus, clear all errors +ResetGMBus: +; look into the PRM + mov dword [esi+4], 80000000h + mov dword [esi+4], 0 + mov ecx, 0x10000 +@@: + test byte [esi+8+1], 2 + loopnz @b + ret +end if + +; set resolution [width]*[height] +SetMode: +; 1. Program the registers of videocard. +; look into the PRM + cli +; or byte [esi+7000Ah], 0Ch ; PIPEACONF: disable Display+Cursor Planes +; or byte [esi+7100Ah], 0Ch ; PIPEBCONF: disable Display+Cursor Planes + xor eax, eax + xor edx, edx + cmp [deviceType], pciids_num ;i965_start + jb @f + mov dl, 9Ch - 84h +@@: +; or byte [esi+71403h], 80h ; VGACNTRL: VGA Display Disable + and byte [esi+70080h], not 27h ; CURACNTR: disable cursor A + mov dword [esi+70084h], eax ; CURABASE: force write to CURA* regs + and byte [esi+700C0h], not 27h ; CURBCNTR: disable cursor B + mov dword [esi+700C4h], eax ; CURBBASE: force write to CURB* regs + and byte [esi+70183h], not 80h ; DSPACNTR: disable Primary A Plane + mov dword [esi+edx+70184h], eax ; DSPALINOFF/DSPASURF: force write to DSPA* regs + and byte [esi+71183h], not 80h ; DSPBCNTR: disable Primary B Plane + mov dword [esi+edx+71184h], eax ; DSPBLINOFF/DSPBSURF: force write to DSPB* regs +if 1 + cmp [deviceType], pciids_num ;ironlake_start + jae .disable_pipes + mov edx, 10000h + or byte [esi+70024h], 2 ; PIPEASTAT: clear VBLANK status + or byte [esi+71024h], 2 ; PIPEBSTAT: clear VBLANK status +.wait_vblank_preironlake1: + mov ecx, 1000h + loop $ + test byte [esi+7000Bh], 80h ; PIPEACONF: pipe A active? + jz @f + test byte [esi+70024h], 2 ; PIPEASTAT: got VBLANK? + jz .wait_vblank_preironlake2 +@@: + test byte [esi+7100Bh], 80h ; PIPEBCONF: pipe B active? + jz .disable_pipes + test byte [esi+71024h], 2 ; PIPEBSTAT: got VBLANK? + jnz .disable_pipes +.wait_vblank_preironlake2: + dec edx + jnz .wait_vblank_preironlake1 + jmp .not_disabled +.disable_pipes: +end if + and byte [esi+7000Bh], not 80h ; PIPEACONF: disable pipe + and byte [esi+7100Bh], not 80h ; PIPEBCONF: disable pipe + cmp [deviceType], pciids_num ;gen4_start + jb .wait_watching_scanline +; g45 and later: use special flag from PIPE*CONF + mov edx, 10000h +@@: + mov ecx, 1000h + loop $ + test byte [esi+7000Bh], 40h ; PIPEACONF: wait until pipe disabled + jz @f + dec edx + jnz @b + jmp .not_disabled +@@: + test byte [esi+7100Bh], 40h ; PIPEBCONF: wait until pipe disabled + jz .disabled + mov ecx, 1000h + loop $ + dec edx + jnz @b + jmp .not_disabled +; pineview and before: wait while scanline still changes +.wait_watching_scanline: + mov edx, 1000h +.dis1: + push dword [esi+71000h] + push dword [esi+70000h] + mov ecx, 10000h + loop $ + pop eax + xor eax, [esi+70000h] + and eax, 1FFFh + pop eax + jnz .notdis1 + xor eax, [esi+71000h] + and eax, 1FFFh + jz .disabled +.notdis1: + dec edx + jnz .dis1 +.not_disabled: + sti + jmp .return +.disabled: + lea eax, [esi+61183h] + cmp [deviceType], pciids_num ;ironlake_start + jb @f + add eax, 0xE0000 - 0x60000 +@@: + lea edx, [esi+60000h] + test byte [eax], 40h + jz @f + add edx, 1000h +@@: + mov eax, [width] + dec eax + shl eax, 16 + mov ax, word [height] + dec eax + mov dword [edx+1Ch], eax ; PIPEASRC: set source image size + ror eax, 16 + mov dword [edx+10190h], eax ; for old cards + mov ecx, [width] + add ecx, 15 + and ecx, not 15 + shl ecx, 2 + mov dword [edx+10188h], ecx ; DSPASTRIDE: set scanline length + mov dword [edx+10184h], 0 ; DSPALINOFF: force write to DSPA* registers + and byte [esi+61233h], not 80h ; PFIT_CONTROL: disable panel fitting + or byte [edx+1000Bh], 80h ; PIPEACONF: enable pipe +; and byte [edx+1000Ah], not 0Ch ; PIPEACONF: enable Display+Cursor Planes + or byte [edx+10183h], 80h ; DSPACNTR: enable Display Plane A + sti +; 2. Notify the kernel that resolution has changed. + call GetDisplay + mov edx, [width] + mov dword [eax+8], edx + mov edx, [height] + mov dword [eax+0Ch], edx + mov [eax+18h], ecx + mov eax, [width] + dec eax + dec edx + call SetScreen +.return: + ret + +align 4 +hellomsg db 'RDC videocard detected, PciId=17F3:' ;VendorID 0x17F3, 'RDC Semiconductor Co.' +pciid_text db '0000' + db ', which is ', 0 +knownmsg db 'known',13,10,0 +unknownmsg db 'unknown',13,10,0 +exitmsg db 'Card detected successfully, exiting driver...',13,10,0 + +if DEBUG +edidmsg db 'EDID successfully read:',13,10 +edid_text rb 8*(16*3+1) + db 0 +end if + +version: + dd 0x50005 + +width dd predefined_width +height dd predefined_height + +pciids: + dw 0x2010 ; M2010 - appears in eBox-3300MX (Vortex86MX SoC) + dw 0x2012 ; M2012 - appears in eBox-3310MX (Vortex86MX+ SoC) +pciids_num = ($ - pciids) / 2 + +align 4 +deviceType dd ? +edid rb 0x80 \ No newline at end of file