Subversion Repositories Kolibri OS

Rev

Rev 9024 | Rev 9064 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
9020 rgimad 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
3
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
8
$Revision$
9
 
10
PCI_REG_STATUS_COMMAND = 0x0004
11
PCI_REG_BAR5 = 0x0024
12
 
9023 rgimad 13
; bit_ prefix means that its index of bit
14
; format: bit_AHCI_STR_REG_BIT
15
bit_AHCI_HBA_CAP2_BOH   = 0        ; Supports BIOS/OS Handoff
9020 rgimad 16
 
9023 rgimad 17
bit_AHCI_HBA_BOHC_BOS  = 0         ; BIOS-Owned Semaphore (BIOS owns controller)
18
bit_AHCI_HBA_BOHC_OOS  = 1         ; OS-Owned Semaphore (OS owns controller)
19
bit_AHCI_HBA_BOHC_BB   = 4         ; BIOS Busy (polling bit while BIOS cleans up
9020 rgimad 20
 
9023 rgimad 21
bit_AHCI_HBA_GHC_AHCI_ENABLE      = 31  ; Enable AHCI mode
22
bit_AHCI_HBA_GHC_RESET            = 0   ; Reset HBA
23
bit_AHCI_HBA_GHC_INTERRUPT_ENABLE = 1   ; Enable interrupts from the HBA
24
 
9037 rgimad 25
AHCI_HBA_PxSSTS_DET         = 0xF
26
AHCI_HBA_PORT_IPM_ACTIVE    = 1
27
AHCI_HBA_PxSSTS_DET_PRESENT = 3
28
 
9023 rgimad 29
AHCI_MAX_PORTS = 32        ;
9020 rgimad 30
HBA_MEMORY_SIZE = 0x1100
31
 
32
struct AHCI_DATA
33
        abar    dd ?       ; pointer to HBA Memory (BAR5) mapped to virtual kernelspace memory
34
        pcidev  dd ?       ; pointer to corresponding PCIDEV structure
35
ends
36
 
37
; Generic Host Control registers
38
struct HBA_MEM
39
        capability            dd ?                    ; 0x00
40
        global_host_control   dd ?                    ; 0x04
41
        interrupt_status      dd ?                    ; 0x08
42
        port_implemented      dd ?                    ; 0x0C
43
        version               dd ?                    ; 0x10
44
        ccc_ctl               dd ?                    ; 0x14, Command completion coalescing control
45
        ccc_pts               dd ?                    ; 0x18, Command completion coalescing ports
46
        em_loc                dd ?                    ; 0x1C, Enclosure management location
47
        em_ctl                dd ?                    ; 0x20, Enclosure management control
48
        capability2           dd ?                    ; 0x24, Host capabilities extended
49
        bohc                  dd ?                    ; 0x28, BIOS/OS handoff control and status
50
        reserved              rb (0xA0-0x2C)          ; 0x2C - 0x9F, Reserved
51
        vendor                rb (0x100-0xA0)         ; 0xA0 - 0xFF, Vendor specific
9023 rgimad 52
        ports                 rb (sizeof.HBA_PORT*AHCI_MAX_PORTS) ; 0x100 - 0x10FF, Port control registers, max AHCI_MAX_PORTS
9020 rgimad 53
ends
54
 
55
; Port Control registers
56
struct HBA_PORT
57
	command_list_base_l      dd ?                 ; 0x00, command list base address, 1K-byte aligned
58
	command_list_base_h      dd ?                 ; 0x04, command list base address upper 32 bits, used on 64 bit systems
59
	fis_base_l               dd ?                 ; 0x08, FIS base address, 256-byte aligned
60
	fis_base_h               dd ?                 ; 0x0C, FIS base address upper 32 bits, used on 64 bit systems
61
	interrupt_status         dd ?                 ; 0x10
62
	interrupt_enable         dd ?                 ; 0x14
63
	command                  dd ?                 ; 0x18, command and status
64
	reserved0                dd ?                 ; 0x1C
65
	task_file_data           dd ?                 ; 0x20
66
	signature                dd ?                 ; 0x24
67
	sata_status              dd ?                 ; 0x28, SATA status (SCR0:SStatus)
68
	sata_control             dd ?                 ; 0x2C, SATA control (SCR2:SControl)
69
	sata_error               dd ?                 ; 0x30, SATA error (SCR1:SError)
70
	sata_active              dd ?                 ; 0x34, SATA active (SCR3:SActive)
71
	command_issue            dd ?                 ; 0x38
72
	sata_notification        dd ?                 ; 0x3C, SATA notification (SCR4:SNotification)
73
	fis_based_switch_control dd ?                 ; 0x40
74
	reserved1                rd 11                ; 0x44 - 0x6F
75
	vendor                   rd 4                 ; 0x70 - 0x7F, vendor specific
76
ends
77
 
78
uglobal
79
align 4
80
        ahci_controller AHCI_DATA
81
endg
82
 
83
 
84
; detect ahci controller and initialize
85
align 4
86
init_ahci:
87
        mov     ecx, ahci_controller
88
        mov     esi, pcidev_list
89
.find_ahci_ctr:
90
        mov     esi, [esi + PCIDEV.fd]
91
        cmp     esi, pcidev_list
92
        jz      .ahci_ctr_not_found
93
        mov     eax, [esi + PCIDEV.class]
94
        ;DEBUGF  1, "K: device class = %x\n", eax
95
        shr     eax, 8 ; shift right because lowest 8 bits if ProgIf field
96
        cmp     eax, 0x0106 ; 0x01 - Mass Storage Controller class,  0x06 - Serial ATA Controller subclass
97
        jz      .ahci_ctr_found
98
        jmp     .find_ahci_ctr
99
 
100
.ahci_ctr_not_found:
101
        DEBUGF  1, "K: AHCI controller not found\n"
102
        ret
103
 
104
.ahci_ctr_found:
105
        mov     [ahci_controller + AHCI_DATA.pcidev], esi
106
 
107
        mov     eax, [esi+PCIDEV.class]
108
        movzx   ebx, byte [esi+PCIDEV.bus]
109
        movzx   ecx, byte [esi+PCIDEV.devfn]
110
        shr     ecx, 3 ; get rid of 3 lowest bits (function code), the rest bits is device code
111
        movzx   edx, byte [esi+PCIDEV.devfn]
112
        and     edx, 00000111b ; get only 3 lowest bits (function code)
113
        DEBUGF  1, "K: found AHCI controller, (class, subcl, progif) = %x, bus = %x, device = %x, function = %x\n", eax, ebx, ecx, edx
114
 
9023 rgimad 115
        ; get BAR5 value, it is physical address
9037 rgimad 116
        movzx   ebx, [esi + PCIDEV.bus]
117
        movzx   ebp, [esi + PCIDEV.devfn]
118
        stdcall pci_read32, ebx, ebp, PCI_REG_BAR5
119
        DEBUGF  1, "K: AHCI controller MMIO = %x\n", eax
120
        mov     edi, eax
9020 rgimad 121
 
9037 rgimad 122
        ; get the size of MMIO region
123
        stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, 0xFFFFFFFF
124
        stdcall pci_read32, ebx, ebp, PCI_REG_BAR5
125
        not     eax
126
        inc     eax
127
        DEBUGF  1, "K: AHCI: MMIO region size = 0x%x bytes\n", eax
128
 
129
        ; Map MMIO region to virtual memory
130
        stdcall map_io_mem, edi, eax, PG_SWR + PG_NOCACHE
9020 rgimad 131
        mov     [ahci_controller + AHCI_DATA.abar], eax
132
        DEBUGF  1, "K: AHCI controller BAR5 mapped to virtual addr %x\n", eax
133
 
9037 rgimad 134
        ; Restore the original BAR5 value
135
        stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, edi
136
 
9023 rgimad 137
        ; Enable dma bus mastering, memory space access, clear the "disable interrupts" bit
138
        ; Usually, it is already done before us
9024 rgimad 139
        movzx   ebx, [esi + PCIDEV.bus]
140
        movzx   ebp, [esi + PCIDEV.devfn]
141
        stdcall pci_read32, ebx, ebp, PCI_REG_STATUS_COMMAND
9020 rgimad 142
        DEBUGF  1, "K: AHCI: pci_status_command = %x\nEnabling interrupts, DMA bus mastering and memory space access\n", eax
143
        or      eax, 0x06 ; pci.command |= 0x06 (dma bus mastering + memory space access)
144
        btr     eax, 10 ; clear the "disable interrupts" bit
145
        DEBUGF  1, "K: AHCI: pci_status_command = %x\n", eax
9024 rgimad 146
        stdcall pci_write32, ebx, ebp, PCI_REG_STATUS_COMMAND, eax
9020 rgimad 147
 
9023 rgimad 148
        ; ; Print some register values to debug board
149
        ; mov     esi, [ahci_controller + AHCI_DATA.abar]
9024 rgimad 150
        ; DEBUGF  1, "K: AHCI: HBA.cap = %x, HBA.ghc = %x, HBA_MEM.version = %x\n", [esi + HBA_MEM.capability], [esi + HBA_MEM.global_host_control], [esi + HBA_MEM.version]
9020 rgimad 151
 
9023 rgimad 152
        ;-------------------------------------------------------
153
        ; Request BIOS/OS ownership handoff, if supported. (TODO check correctness)
154
        mov     esi, [ahci_controller + AHCI_DATA.abar]
155
        ;mov     ebx, [esi + HBA_MEM.capability2]
156
        ;DEBUGF  1, "K: AHCI: HBA_MEM.cap2 = %x\n", ebx
9024 rgimad 157
        bt      [esi + HBA_MEM.capability2], bit_AHCI_HBA_CAP2_BOH
9020 rgimad 158
        jnc     .end_handoff
9023 rgimad 159
        DEBUGF  1, "K: AHCI: requesting AHCI ownership change...\n"
9024 rgimad 160
        bts     [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_OOS
9020 rgimad 161
 
162
.wait_not_bos:
9024 rgimad 163
        bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BOS
9020 rgimad 164
        jc      .wait_not_bos
165
 
166
        mov     ebx, 3
167
        call    delay_hs
168
 
9023 rgimad 169
        ; if Bios Busy is still set after 30 mS, wait 2 seconds.
9024 rgimad 170
        bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BB
9020 rgimad 171
        jnc     @f
172
 
173
        mov     ebx, 200
174
        call    delay_hs
175
@@:
9023 rgimad 176
        DEBUGF  1, "K: AHCI: ownership change completed.\n"
9020 rgimad 177
 
178
.end_handoff:
9023 rgimad 179
        ;-------------------------------------------------------
9020 rgimad 180
 
9023 rgimad 181
        ; enable the AHCI and reset it
9024 rgimad 182
        bts     [esi + HBA_MEM.global_host_control], bit_AHCI_HBA_GHC_AHCI_ENABLE
183
        bts     [esi + HBA_MEM.global_host_control], bit_AHCI_HBA_GHC_RESET
9020 rgimad 184
 
9023 rgimad 185
        ; wait for reset to complete
186
.wait_reset:
9024 rgimad 187
        bt      [esi + HBA_MEM.global_host_control], bit_AHCI_HBA_GHC_RESET
9023 rgimad 188
        jc      .wait_reset
9020 rgimad 189
 
9023 rgimad 190
        ; enable the AHCI and interrupts
9024 rgimad 191
        bts     [esi + HBA_MEM.global_host_control], bit_AHCI_HBA_GHC_AHCI_ENABLE
192
        bts     [esi + HBA_MEM.global_host_control], bit_AHCI_HBA_GHC_INTERRUPT_ENABLE
9023 rgimad 193
        mov     ebx, 2
194
        call    delay_hs
195
 
9037 rgimad 196
        DEBUGF  1, "K: AHCI: caps: %x %x, ver: %x, ghc: %x, pi: %x\n", [esi + HBA_MEM.capability], [esi + HBA_MEM.capability2], [esi + HBA_MEM.version], [esi + HBA_MEM.global_host_control], [esi + HBA_MEM.port_implemented]
9020 rgimad 197
 
9037 rgimad 198
        ; TODO:
199
        ; calculate irq line
200
        ; ahciHBA->ghc |= AHCI_GHC_IE;
201
        ; IDT::RegisterInterruptHandler(irq, InterruptHandler);
202
	; ahciHBA->is = 0xffffffff;
203
 
204
        xor     ebx, ebx
205
.detect_drives:
206
        cmp     ebx, AHCI_MAX_PORTS
207
        jae     .end_detect_drives
208
 
209
        ; if port with index ebx is not implemented then go to next
210
        mov     ecx, [esi + HBA_MEM.port_implemented]
211
        bt      ecx, ebx
212
        jnc     .continue_detect_drives
213
 
214
        mov     edi, ebx
215
        shl     edi, BSF sizeof.HBA_PORT
216
        add     edi, HBA_MEM.ports
217
        add     edi, esi
218
        ; now edi - base of HBA_MEM.ports[ebx]
219
 
220
        DEBUGF  1, "K: AHCI: port %d, ssts = %x\n", ebx, [edi + HBA_PORT.sata_status]
221
 
222
        mov     ecx, [edi + HBA_PORT.sata_status]
223
        shr     ecx, 8
224
        and     ecx, 0x0F
225
        cmp     ecx, AHCI_HBA_PORT_IPM_ACTIVE
226
        jne     .continue_detect_drives
227
 
228
        mov     ecx, [edi + HBA_PORT.sata_status]
229
        and     ecx, AHCI_HBA_PxSSTS_DET
230
        cmp     ecx, AHCI_HBA_PxSSTS_DET_PRESENT
231
        jne    .continue_detect_drives
232
 
233
        DEBUGF 1, "K: AHCI: found drive at port %d, signature = %x\n", ebx, [edi + HBA_PORT.signature]
234
 
235
.continue_detect_drives:
236
        inc     ebx
237
        jmp     .detect_drives
238
 
239
        ; TODO: why signatures of found disks are 0xFFFFFFFF ?
240
 
241
.end_detect_drives:
242
 
243
 
9020 rgimad 244
        ret
245