source: xtideuniversalbios/trunk/XTIDE_Universal_BIOS/Src/Initialization/AdvancedAta/Vision.asm @ 566

Last change on this file since 566 was 566, checked in by krille_n_@…, 8 years ago

Changes to XTIDE Universal BIOS:

  • Fixed a very old bug (from r150) in IdeError.asm where GetBiosErrorCodeToAHfromStatusAndErrorRegistersInAX would return RET_HD_SEEK_FAIL instead of RET_HD_STATUSERR.
  • Optimizations and other fixes.
File size: 8.9 KB
Line 
1; Project name  :   XTIDE Universal BIOS
2; Description   :   Functions for initializing QDI Vision
3;                   QD6500 and QD6580 VLB IDE Controllers.
4
5;
6; XTIDE Universal BIOS and Associated Tools
7; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
8;
9; This program is free software; you can redistribute it and/or modify
10; it under the terms of the GNU General Public License as published by
11; the Free Software Foundation; either version 2 of the License, or
12; (at your option) any later version.
13;
14; This program is distributed in the hope that it will be useful,
15; but WITHOUT ANY WARRANTY; without even the implied warranty of
16; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17; GNU General Public License for more details.
18; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19;
20
21; Section containing code
22SECTION .text
23
24;--------------------------------------------------------------------
25; Vision_DetectAndReturnIDinAXandPortInDXifControllerPresent
26;   Parameters:
27;       Nothing
28;   Returns:
29;       AX:     ID WORD specific for QDI Vision Controllers
30;               (AL = QD65xx Config Register contents)
31;               (AH = QDI Vision Controller ID (bits 4...7))
32;       DX:     Controller port (not IDE port)
33;       ZF:     Set if controller found
34;               Cleared if supported controller not found (AX,DX = undefined)
35;   Corrupts registers:
36;       Nothing
37;--------------------------------------------------------------------
38Vision_DetectAndReturnIDinAXandPortInDXifControllerPresent:
39    ; Check QD65xx base port
40    mov     dx, QD65XX_BASE_PORT
41    in      al, QD65XX_BASE_PORT + QD65XX_CONFIG_REGISTER_in
42
43%ifdef DANGEROUS_DETECTION
44    ; Checking alternative base port is currently commented away
45    ; since Intel PIIX4 south bridge mirrors Interrupt Controller registers
46    ; from Axh to Bxh.
47    call    IsConfigRegisterWithIDinAL
48    je      SHORT VisionControllerDetected
49
50    ; Check QD65xx alternative base port
51    or      dl, QD65XX_ALTERNATIVE_BASE_PORT
52    in      al, QD65XX_ALTERNATIVE_BASE_PORT + QD65XX_CONFIG_REGISTER_in
53%endif ; DANGEROUS_DETECTION
54    ; Fall to IsConfigRegisterWithIDinAL
55
56;--------------------------------------------------------------------
57; IsConfigRegisterWithIDinAL
58;   Parameters:
59;       AL:     Possible QD65xx Config Register contents
60;   Returns:
61;       AH      QDI Vision Controller ID or undefined
62;       ZF:     Set if controller found
63;               Cleared if supported controller not found (AH = undefined)
64;   Corrupts registers:
65;       Nothing
66;--------------------------------------------------------------------
67IsConfigRegisterWithIDinAL:
68    mov     ah, al
69    and     al, MASK_QDCONFIG_CONTROLLER_ID
70    cmp     al, ID_QD6500 << 4
71    je      SHORT VisionControllerDetected
72    cmp     al, ID_QD6580 << 4
73    je      SHORT VisionControllerDetected
74    cmp     al, ID_QD6580_ALTERNATE << 4
75VisionControllerDetected:
76    xchg    ah, al
77    ret
78
79
80;--------------------------------------------------------------------
81; Vision_DoesIdePortInBXbelongToControllerWithIDinAX
82;   Parameters:
83;       AL:     QD65xx Config Register contents
84;       AH:     QDI Vision Controller ID (bits 4...7)
85;       BX:     IDE Base port to check
86;       DX:     Vision Controller port
87;   Returns:
88;       ZF:     Set if port belongs to controller
89;               Cleared if port belongs to another controller
90;   Corrupts registers:
91;       Nothing
92;--------------------------------------------------------------------
93Vision_DoesIdePortInBXbelongToControllerWithIDinAX:
94    cmp     ah, ID_QD6500 << 4
95    je      SHORT .DoesIdePortInDXbelongToQD6500
96
97    ; QD6580 always have Primary IDE at 1F0h
98    ; Secondary IDE at 170h can be enabled or disabled
99    cmp     bx, DEVICE_ATA_PRIMARY_PORT
100    je      SHORT .ReturnResultInZF
101
102    ; Check if Secondary IDE channel is enabled
103    push    ax
104    add     dx, BYTE QD6580_CONTROL_REGISTER
105    in      al, dx
106    sub     dx, BYTE QD6580_CONTROL_REGISTER
107    test    al, FLG_QDCONTROL_SECONDARY_DISABLED_in
108    pop     ax
109    jz      SHORT .CompareBXtoSecondaryIDE
110    ret
111
112    ; QD6500 has only one IDE channel that can be at 1F0h or 170h
113.DoesIdePortInDXbelongToQD6500:
114    test    al, FLG_QDCONFIG_PRIMARY_IDE
115    jz      SHORT .CompareBXtoSecondaryIDE
116    cmp     bx, DEVICE_ATA_PRIMARY_PORT
117    ret
118
119.CompareBXtoSecondaryIDE:
120    cmp     bx, DEVICE_ATA_SECONDARY_PORT
121.ReturnResultInZF:
122    ret
123
124
125;--------------------------------------------------------------------
126; Vision_GetMaxPioModeToALandMinCycleTimeToBX
127;   Parameters:
128;       AL:     QD65xx Config Register contents
129;       AH:     QDI Vision Controller ID (bits 4...7)
130;   Returns:
131;       AL:     Max supported PIO mode
132;       AH:     FLGH_DPT_IORDY if IORDY supported, zero otherwise
133;       BX:     Min PIO Cycle Time (only if CF set)
134;       CF:     Set if PIO limit necessary
135;               Cleared if no need to limit timings
136;   Corrupts registers:
137;       (AX if CF cleared)
138;   Corrupts registers:
139;       Nothing
140;--------------------------------------------------------------------
141Vision_GetMaxPioModeToALandMinCycleTimeToBX:
142    cmp     ah, ID_QD6500 << 4
143    clc
144    jne     SHORT .NoNeedToLimitForQD6580
145
146    mov     ax, 2   ; Limit to PIO 2 because QD6500 does not support IORDY
147    mov     bx, PIO_2_MIN_CYCLE_TIME_NS
148    stc
149.NoNeedToLimitForQD6580:
150    ret
151
152
153;--------------------------------------------------------------------
154; Vision_InitializeWithIDinAHandConfigInAL
155;   Parameters:
156;       AL:     QD65xx Config Register contents
157;       AH:     QDI Vision Controller ID (bits 4...7)
158;       DS:DI:  Ptr to DPT for Single or Slave Drive
159;       SI:     Offset to Master DPT if Slave Drive present
160;               Zero if Slave Drive not present
161;   Returns:
162;       CF:     Cleared if success
163;               Set if error
164;   Corrupts registers:
165;       AX, BX, CX, DX, BP
166;--------------------------------------------------------------------
167Vision_InitializeWithIDinAHandConfigInAL:
168    ; QD6580 has a Control Register that needs to be programmed
169    mov     dx, [di+DPT_ADVANCED_ATA.wControllerBasePort]
170    cmp     ah, ID_QD6500 << 4
171    je      SHORT .CalculateTimingForQD6500
172
173    ; Program QD6580 Control Register (not available on QD6500) to
174    ; Enable or Disable Read-Ahead and Post-Write Buffer to match
175    ; jumper setting on the multi I/O card.
176    xor     ax, ax
177    add     dx, BYTE QD6580_CONTROL_REGISTER
178    in      al, dx                                  ; Read to get ATAPI jumper status
179    test    al, FLG_QDCONTROL_HDONLY_in
180    eCMOVNZ ah, FLG_QDCONTROL_NONATAPI              ; Enable Read-Ahead and Post-Write Buffers
181    mov     al, ah
182    or      al, MASK_QDCONTROL_FLAGS_TO_SET
183    out     dx, al
184    sub     dx, BYTE QD6580_CONTROL_REGISTER
185
186    ; Now we need to determine is the drive connected to the Primary or Secondary channel.
187    ; QD6500 has only one channel that can be Primary at 1F0h or Secondary at 170h.
188    ; QD6580 always has Primary channel at 1F0h. Secondary channel at 170h can be Enabled or Disabled.
189    cmp     WORD [di+DPT.wBasePort], DEVICE_ATA_PRIMARY_PORT
190    je      SHORT .CalculateTimingTicksForQD6580    ; Primary Channel so no need to modify DX
191    times 2 inc dx                                  ; Secondary Channel IDE Timing Register
192
193    ; QD6500 and QD6580 require slightly different calculations.
194.CalculateTimingTicksForQD6580:
195    mov     bp, QD6580_MAX_ACTIVE_TIME_CLOCKS | (QD6580_MIN_ACTIVE_TIME_CLOCKS << 8)
196    jmp     SHORT .CalculateTimingsForQD65xx
197
198.CalculateTimingForQD6500:
199    mov     bp, QD6500_MAX_ACTIVE_TIME_CLOCKS | (QD6500_MIN_ACTIVE_TIME_CLOCKS << 8)
200
201    ; We need the PIO Cycle Time in CX to calculate Active and Recovery Times.
202.CalculateTimingsForQD65xx:
203    call    AdvAtaInit_SelectSlowestCommonPioTimingsToBXandCXfromDSSIandDSDI
204
205    ; Calculate Active Time value for QD65xx IDE Timing Register
206    call    AtaID_GetActiveTimeToAXfromPioModeInBX
207    call    ConvertNanosecsFromAXwithLimitsInBPtoRegisterValue
208    xchg    bp, ax
209
210    ; Calculate Recovery Time value for QD65xx IDE Timing Register
211    call    AtaID_GetRecoveryTimeToAXfromPioModeInBXandCycleTimeInCX
212    mov     bx, bp                      ; Active Time value now in BL
213    mov     bp, QD65xx_MAX_RECOVERY_TIME_CLOCKS | (QD65xx_MIN_RECOVERY_TIME_CLOCKS << 8)
214    call    ConvertNanosecsFromAXwithLimitsInBPtoRegisterValue
215
216    ; Merge the values to a single byte to output
217    eSHL_IM al, POSITION_QD65XXIDE_RECOVERY_TIME
218    or      al, bl
219    out     dx, al
220    ret                                 ; Return with CF cleared
221
222
223;--------------------------------------------------------------------
224; ConvertNanosecsFromAXwithLimitsInBPtoRegisterValue
225;   Parameters:
226;       AX:     Nanosecs to convert
227;       BP:     Low Byte:   Maximum allowed ticks
228;               High Byte:  Minimum allowed ticks
229;       DS:DI:  Ptr to DPT for Single or Slave Drive
230;   Returns:
231;       AL:     Timing value for QD65xx register
232;   Corrupts registers:
233;       Nothing
234;--------------------------------------------------------------------
235ConvertNanosecsFromAXwithLimitsInBPtoRegisterValue:
236    push    cx
237
238    ; Get VLB Cycle Time in nanosecs
239    mov     cl, VLB_33MHZ_CYCLE_TIME    ; Assume 33 MHz or slower VLB bus
240    test    BYTE [di+DPT_ADVANCED_ATA.wControllerID], FLG_QDCONFIG_ID3
241    eCMOVZ  cl, VLB_40MHZ_CYCLE_TIME
242
243    ; Convert value in AX to VLB ticks
244    div     cl                          ; AL = VLB ticks
245    inc     ax                          ; Round up
246
247    ; Limit value to QD65xx limits
248    mov     cx, bp
249    MAX_U   al, ch                      ; Make sure not below minimum
250    MIN_U   al, cl                      ; Make sure not above maximum
251
252    ; Not done yet, we need to invert the ticks since 0 is the slowest
253    ; value on the timing register
254    sub     cl, al
255    xchg    ax, cx                      ; Return in AL
256
257    pop     cx
258    ret
Note: See TracBrowser for help on using the repository browser.