Rev 5363 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4261 | yogev_ezra | 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
2 | ;; ;; |
||
5363 | yogev_ezra | 3 | ;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;; |
4261 | yogev_ezra | 4 | ;; Distributed under terms of the GNU General Public License ;; |
5 | ;; ;; |
||
6 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
||
7 | |||
4294 | yogev_ezra | 8 | ; 20/11/2013 yogev_ezra: Initial version (Vortex86 SoC type detection) |
9 | ; 26/11/2013 yogev_ezra: Added CPU speed modifier and MMX support flag detection |
||
10 | ; Thanks for help to: dunkaist, eAndrew, hidnplayr, Mario |
||
11 | |||
4261 | yogev_ezra | 12 | $Revision: 7122 $ |
13 | |||
14 | VORTEX86DEBUG = 0 ; For testing in emulators and in non-Vortex86 CPU computers, set this to 1 |
||
7122 | dunkaist | 15 | VORTEX86DEBUGVALUE = 'DMP5' ; FAKE port output = used for testing |
4310 | yogev_ezra | 16 | NORTH_BRIDGE = 0x80000000 ; Base address of Vortex86 PCI North Bridge |
17 | SOUTH_BRIDGE = 0x80003800 ; Base address of Vortex86 PCI South Bridge |
||
4261 | yogev_ezra | 18 | |
19 | ; Detect Vortex86 CPU and generate CPU name in string format (PCI address at 93H~90H in Vortex86 North Bridge contains SoC type) |
||
20 | ; Available Vortex86 CPU codes taken from Coreboot project. New codes should be added to "Vortex86SoClist" below |
||
21 | ; #define DMP_CPUID_SX 0x31504d44 ("DMP1") |
||
22 | ; #define DMP_CPUID_DX 0x32504d44 ("DMP2") |
||
23 | ; #define DMP_CPUID_MX 0x33504d44 ("DMP3") |
||
24 | ; #define DMP_CPUID_DX2 0x34504d44 ("DMP4") |
||
25 | ; #define DMP_CPUID_MX_PLUS 0x35504d44 ("DMP5") |
||
26 | ; #define DMP_CPUID_EX 0x37504d44 ("DMP7") |
||
27 | |||
28 | iglobal |
||
29 | Vortex86CPUcode dd ? ; Vortex86 CPU code in HEX format (4 bytes), can be shown as string if converted to ASCII characters |
||
30 | Vortex86CPUid db 0 ; Vortex86 CPU id in integer format (1=Vortex86SX, 2=Vortex86DX, ...) |
||
31 | Vortex86SoCname db 'Vortex86 ',0 ; This variable will hold the full name of Vortex86 SoC |
||
32 | Vortex86SoClist: ; List of Vortex86 CPUs known today. Add new record to this list when new CPU becomes available |
||
33 | db 0x31, 'SX ' ; id=1 |
||
34 | db 0x32, 'DX ' ; id=2 |
||
4294 | yogev_ezra | 35 | db 0x33, 'MX ' ; id=3 MMX is available starting from CPU code 'MX' (id=3) |
4261 | yogev_ezra | 36 | db 0x34, 'DX2' ; id=4 |
37 | db 0x35, 'MX+' ; id=5 |
||
4294 | yogev_ezra | 38 | db 0x37, 'EX ' ; id=7 |
39 | Vortex86SoCnum = ($ - Vortex86SoClist) / 4 ; Calculate the total number of known Vortex86 CPUs |
||
4261 | yogev_ezra | 40 | endg |
41 | |||
4272 | yogev_ezra | 42 | ; When in debug mode, perform SoC detection regardless of the actual CPU vendor (even for vendors other than DMP) |
43 | ; When in normal (not debug) mode, check the CPU vendor first, and perform SoC detection only if vendor is 'Vortex86 SoC' |
||
44 | if ~ VORTEX86DEBUG |
||
45 | cmp [cpu_vendor], 'Vort' |
||
46 | jnz .Vortex86end ; If the CPU vendor is not 'Vortex86 SoC', skip the SoC detection |
||
4294 | yogev_ezra | 47 | end if |
4272 | yogev_ezra | 48 | |
4310 | yogev_ezra | 49 | mov eax, NORTH_BRIDGE+0x90 ; 0x80000090 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD) |
50 | call .Vortex86PCIreg ; Get the CPU code from Vortex86 SoC North Bridge PCI register (Register Offset: 93H~90H) |
||
4261 | yogev_ezra | 51 | |
4272 | yogev_ezra | 52 | if VORTEX86DEBUG ; When in debug mode, pretend that we received port output equal to "VORTEX86DEBUGVALUE" |
4261 | yogev_ezra | 53 | mov eax, VORTEX86DEBUGVALUE |
4294 | yogev_ezra | 54 | end if |
4261 | yogev_ezra | 55 | |
4294 | yogev_ezra | 56 | DEBUGF 1, "K : Vortex86 SoC type register (93H~90H) returned 0x" |
4289 | yogev_ezra | 57 | test eax, eax ; Check whether the port output was '\0' |
58 | jz .nullPCIoutput ; In case the result is '\0' (NULL), skip further testing and exit |
||
59 | mov [Vortex86CPUcode], eax ; Save HEX CPU code to Vortex86CPUcode (so it can be used later) |
||
60 | DEBUGF 1, "%x (%s): ", eax, Vortex86CPUcode ; Print the CPU code (as HEX and as string) to debug log |
||
61 | |||
62 | mov ebx, 0x444d5000 ; Apply Vortex86 CPU code mask (all Vortex86 SoC have ID in form of "0xNN504d44") |
||
63 | bswap eax ; Assumed it is Vortex86 SoC, the highest byte identifies the exact CPU, so move it to the lowest byte |
||
64 | mov bl, al ; Copy SoC type to BL since EAX (that includes AL) is used implicitly in "LODSD" command below |
||
65 | cmp eax, ebx ; Now see whether the 3 higher bytes were "0x504d44" (which means it's Vortex86) |
||
4294 | yogev_ezra | 66 | jnz .notVortex86 ; If it's not Vortex86 - go say so and exit |
4289 | yogev_ezra | 67 | |
4294 | yogev_ezra | 68 | sub al, 0x30 ; Current Vortex86 CPU codes are in the range of 31h-37h, so convert them to integer (1,2,...) |
69 | mov [Vortex86CPUid], al ; Save the CPUid (1=Vortex86SX, 2=Vortex86DX, ..., 7=Vortex86EX, ...) |
||
70 | |||
4261 | yogev_ezra | 71 | mov esi, Vortex86SoClist ; ESI points to the start of Vortex86SoClist (used implicitly in "LODSD" command below) |
72 | xor ecx, ecx ; Zero ECX (it is used as counter) |
||
73 | cld ; Clears the DF flag in the EFLAGS register (DF=0 --> String operations increment ESI) |
||
74 | @@: |
||
4289 | yogev_ezra | 75 | inc ecx ; Increment our counter |
4261 | yogev_ezra | 76 | cmp ecx, Vortex86SoCnum ; Check if we iterated Vortex86SoCnum times already (i.e. went over the entire Vortex86SoClist) |
77 | ja .unknownVortex86 ; If the entire list was tested and our CPU is not in that list, it is unknown Vortex86 SoC |
||
78 | lodsd ; Load DWORD at address DS:ESI into EAX (puts 1 line from Vortex86SoClist into EAX, then increments ESI) |
||
79 | cmp bl, al ; Check if our CPU matches the current record in the list |
||
80 | jne @b ; No match --> repeat with next record |
||
4289 | yogev_ezra | 81 | |
4261 | yogev_ezra | 82 | shr eax, 8 ; Match found --> drop the SoC type code from Vortex86SoClist name and replace it with \0 |
83 | mov dword [Vortex86SoCname+8], eax ; Concatenate it with prefix to receive complete SoC name (\0 is string termination) |
||
84 | |||
4294 | yogev_ezra | 85 | DEBUGF 1, "%s (id=%d)\n", Vortex86SoCname, [Vortex86CPUid]:1 ; Say what we have found (CPU name and id) |
86 | jmp .Vortex86 |
||
87 | |||
4289 | yogev_ezra | 88 | .notVortex86: ; In case this register is used by other CPUs for other purpose, it's interesting what it contains |
89 | DEBUGF 1, "not a Vortex86 CPU\n" |
||
4261 | yogev_ezra | 90 | jmp .Vortex86end |
4289 | yogev_ezra | 91 | |
4294 | yogev_ezra | 92 | .unknownVortex86: ; It is Vortex86 CPU, but it's not in the list above |
93 | DEBUGF 1, "unknown Vortex86 CPU (id=%d)\n", [Vortex86CPUid]:1 ; Inform the user that the CPU is Vortex86 but name is unknown |
||
94 | |||
95 | .Vortex86: |
||
4310 | yogev_ezra | 96 | mov eax, NORTH_BRIDGE+0x60 ; 0x80000060 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD) |
97 | call .Vortex86PCIreg ; Get current flags of Vortex86SoC North Bridge STRAP Register (Register Offset: 63h~60h) |
||
98 | DEBUGF 1, "K : Vortex86 STRAP Register (63h~60h) returned 0x%x\n",eax |
||
99 | |||
100 | mov eax, SOUTH_BRIDGE+0xC0 ; 0x800038C0 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD) |
||
101 | call .Vortex86PCIreg ; Flags of Vortex86 South Bridge Internal Peripheral Feature Control Register (Register Offset: C3h~C0h) |
||
102 | DEBUGF 1, "K : Vortex86 Internal Peripheral Feature Control Register (C3h~C0h) returned 0x%x\n",eax |
||
103 | |||
104 | mov eax, SOUTH_BRIDGE+0xCC ; 0x800038CC = PCI Configuration Address Register to read from (8-bit register - accessed as BYTE) |
||
105 | call .Vortex86PCIreg ; Flags of Vortex86 South Bridge Internal Peripheral Feature Control Register III (Register Offset: CCh) |
||
106 | DEBUGF 1, "K : Vortex86 Internal Peripheral Feature Control Register III (CCh) returned 0x%x\n",al |
||
107 | |||
108 | mov eax, NORTH_BRIDGE+0xA0 ; 0x800000A0 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD) |
||
109 | call .Vortex86PCIreg ; Get current flags of Vortex86SoC North Bridge Host Control Register (Register Offset: A3h~A0h) |
||
4294 | yogev_ezra | 110 | DEBUGF 1, "K : Vortex86 Host Control Register (A3h~A0h) returned 0x%x: CPU speed is ",eax |
111 | mov bl, al ; The lower byte of Vortex86 Host Control Register contains CPU speed modifier and MMX support status |
||
112 | mov bh, al ; Backup the current AL value, so later we can test whether the value has changed |
||
113 | and bl, 00000111b ; CPU speed modifier is stored in bits 0-2. Value=0 means MAX speed, other values - speed reduction |
||
114 | jz .Vortex86CPUspeedMAX ; 0s in bits 0-2: CPU is at MAX speed (no need to modify) |
||
4310 | yogev_ezra | 115 | inc ebx ; The actual value is 1 less than 'Divide by' setting (value '001' means 'Divide by 2', etc.) |
4294 | yogev_ezra | 116 | DEBUGF 1, "reduced (divide by %d).\nK : Vortex86 changing CPU speed to ", bl ; Print the current CPU speed modifier to the log |
117 | and al, 11111000b ; At least one of the bits 0-2 contains 1: CPU is at reduced speed. Set bits 0-2 to 0s to change to MAX |
||
118 | .Vortex86CPUspeedMAX: |
||
119 | DEBUGF 1, "MAX\n" ; Now the CPU should be running at MAX speed (don't write the value to PCI port yet) |
||
120 | |||
121 | cmp [Vortex86CPUid], 3 ; MMX is available starting from CPU code 'MX' (id=3) |
||
122 | jb .skipVortex86MMX ; No MMX support - skip MMX support status detection (for id=1,2) |
||
123 | DEBUGF 1, "K : Vortex86 MMX support status: MMX is " ; Bits 5-6 in Host Control Register contain MMX status |
||
124 | test al, 100000b ; On MMX-capable Vortex86 SoC, Bit5 = is MMX enabled? (1=Yes/0=No) |
||
125 | jnz .Vortex86MMXenabled ; MMX is already enabled (Bit5=1) |
||
126 | DEBUGF 1, "DISABLED - enabling it for this session\n" ; Print to the log that MMX is disabled |
||
127 | or al, 100000b ; Enable MMX support (don't write the value to PCI port yet) |
||
128 | jmp .AfterMMXenabled |
||
129 | .Vortex86MMXenabled: |
||
130 | DEBUGF 1, "ENABLED\n" ; Print to the log that MMX is enabled |
||
131 | .AfterMMXenabled: |
||
132 | DEBUGF 1, "K : Vortex86 MMX report to CPUID: " ; Print to the log what CPUID command knowns about MMX support |
||
133 | test al, 1000000b ; On MMX-capable Vortex86 SoC, Bit6 = report MMX support to CPUID? (1=Yes/0=No) |
||
134 | jnz .Vortex86MMXreported ; MMX is already reported to CPUID (Bit6=1) |
||
135 | DEBUGF 1, "OFF - turning it ON for this session\n" ; Print to the log that MMX will now be reported to CPUID |
||
136 | or al, 1000000b ; Turn on MMX reporting to CPUID (don't write the value to PCI port yet) |
||
137 | jmp .skipVortex86MMX |
||
138 | .Vortex86MMXreported: |
||
139 | DEBUGF 1, "ON\n" ; Print to the log that MMX reporting to CPUID is enabled |
||
140 | |||
141 | .skipVortex86MMX: |
||
142 | cmp bh, al ; Check whether AL has changed before (if it did, we need to write it back to PCI port) |
||
143 | jz .Vortex86end ; No change - no need to write to the port |
||
144 | out dx, al ; Write the changed data to PCI port |
||
145 | DEBUGF 1, "K : Vortex86 Host Control Register (A3h~A0h) new value is 0x%x\n",eax |
||
4261 | yogev_ezra | 146 | jmp .Vortex86end |
147 | |||
4294 | yogev_ezra | 148 | .Vortex86PCIreg: ; Procedure receives input register value in EAX, and returns the output value also in EAX |
149 | mov dx, 0xcf8 ; CF8h = Vortex86 PCI Configuration Address port |
||
150 | out dx, eax ; Send request to PCI address port to retrieve data from this address |
||
151 | mov dl, 0xfc ; CFCh = Vortex86 PCI Configuration Data port |
||
152 | in eax, dx ; Read data from PCI data port |
||
153 | ret |
||
154 | |||
4289 | yogev_ezra | 155 | .nullPCIoutput: ; Emulators and non-Vortex86 CPU computers will usually return \0 in this register |
156 | DEBUGF 1, "0 (NULL)\n" |
||
157 | |||
7122 | dunkaist | 158 | .Vortex86end: |