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 |
Property changes: |
Added: svn:eol-style |
+native |
\ No newline at end of property |