Subversion Repositories Kolibri OS

Rev

Rev 9064 | Rev 9068 | 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
 
9065 rgimad 25
bit_AHCI_HBA_PxCMD_ST    = 0
26
bit_AHCI_HBA_PxCMD_FRE   = 4
27
bit_AHCI_HBA_PxCMD_FR    = 14
28
bit_AHCI_HBA_PxCMD_CR    = 15
29
 
9037 rgimad 30
AHCI_HBA_PxSSTS_DET         = 0xF
31
AHCI_HBA_PORT_IPM_ACTIVE    = 1
32
AHCI_HBA_PxSSTS_DET_PRESENT = 3
33
 
9023 rgimad 34
AHCI_MAX_PORTS = 32        ;
9064 rgimad 35
;HBA_MEMORY_SIZE = 0x1100
9020 rgimad 36
 
9064 rgimad 37
; Frame Information Structure Types
38
FIS_TYPE_REG_H2D    = 0x27 ; Register FIS - host to device
39
FIS_TYPE_REG_D2H    = 0x34 ; Register FIS - device to host
40
FIS_TYPE_DMA_ACT    = 0x39 ; DMA activate FIS - device to host
41
FIS_TYPE_DMA_SETUP  = 0x41 ; DMA setup FIS - bidirectional
42
FIS_TYPE_DATA       = 0x46 ; Data FIS - bidirectional
43
FIS_TYPE_BIST       = 0x58 ; BIST activate FIS - bidirectional
44
FIS_TYPE_PIO_SETUP  = 0x5F ; PIO setup FIS - device to host
45
FIS_TYPE_DEV_BITS   = 0xA1 ; Set device bits FIS - device to host
46
 
9020 rgimad 47
struct AHCI_DATA
48
        abar    dd ?       ; pointer to HBA Memory (BAR5) mapped to virtual kernelspace memory
49
        pcidev  dd ?       ; pointer to corresponding PCIDEV structure
50
ends
51
 
52
; Generic Host Control registers
53
struct HBA_MEM
9064 rgimad 54
        cap                   dd ?                    ; 0x00, Host capabilities
55
        ghc                   dd ?                    ; 0x04, Global host control
56
        is                    dd ?                    ; 0x08, Interrupt status
57
        pi                    dd ?                    ; 0x0C, Port implemented
58
        version               dd ?                    ; 0x10, Version
9020 rgimad 59
        ccc_ctl               dd ?                    ; 0x14, Command completion coalescing control
60
        ccc_pts               dd ?                    ; 0x18, Command completion coalescing ports
61
        em_loc                dd ?                    ; 0x1C, Enclosure management location
62
        em_ctl                dd ?                    ; 0x20, Enclosure management control
9064 rgimad 63
        cap2                  dd ?                    ; 0x24, Host capabilities extended
9020 rgimad 64
        bohc                  dd ?                    ; 0x28, BIOS/OS handoff control and status
65
        reserved              rb (0xA0-0x2C)          ; 0x2C - 0x9F, Reserved
66
        vendor                rb (0x100-0xA0)         ; 0xA0 - 0xFF, Vendor specific
9023 rgimad 67
        ports                 rb (sizeof.HBA_PORT*AHCI_MAX_PORTS) ; 0x100 - 0x10FF, Port control registers, max AHCI_MAX_PORTS
9020 rgimad 68
ends
69
 
70
; Port Control registers
71
struct HBA_PORT
9064 rgimad 72
        command_list_base_l      dd ?                 ; 0x00, command list base address, 1K-byte aligned
73
        command_list_base_h      dd ?                 ; 0x04, command list base address upper 32 bits, used on 64 bit systems
74
        fis_base_l               dd ?                 ; 0x08, FIS base address, 256-byte aligned
75
        fis_base_h               dd ?                 ; 0x0C, FIS base address upper 32 bits, used on 64 bit systems
76
        interrupt_status         dd ?                 ; 0x10
77
        interrupt_enable         dd ?                 ; 0x14
78
        command                  dd ?                 ; 0x18, command and status
79
        reserved0                dd ?                 ; 0x1C
80
        task_file_data           dd ?                 ; 0x20
81
        signature                dd ?                 ; 0x24
82
        sata_status              dd ?                 ; 0x28, SATA status (SCR0:SStatus)
83
        sata_control             dd ?                 ; 0x2C, SATA control (SCR2:SControl)
84
        sata_error               dd ?                 ; 0x30, SATA error (SCR1:SError)
85
        sata_active              dd ?                 ; 0x34, SATA active (SCR3:SActive)
86
        command_issue            dd ?                 ; 0x38
87
        sata_notification        dd ?                 ; 0x3C, SATA notification (SCR4:SNotification)
88
        fis_based_switch_control dd ?                 ; 0x40
89
        reserved1                rd 11                ; 0x44 - 0x6F
90
        vendor                   rd 4                 ; 0x70 - 0x7F, vendor specific
9020 rgimad 91
ends
92
 
9064 rgimad 93
; Register FIS – Host to Device
94
struct FIS_REG_H2D
95
        fis_type      db ?       ; FIS_TYPE_REG_H2D
96
        _flags        db ?       ; 0bCRRRPPPP, C - 1: Command, 0: Control
97
                                 ; R - Reserved, P - Port multiplier
98
 
99
        command       db ?       ; Command register
100
        featurel      db ?       ; Feature register, 7:0
101
 
102
        lba0          db ?       ; LBA low register, 7:0
103
        lba1          db ?       ; LBA mid register, 15:8
104
        lba2          db ?       ; LBA high register, 23:16
105
        device        db ?       ; Device register
106
 
107
        lba3          db ?       ; LBA register, 31:24
108
        lba4          db ?       ; LBA register, 39:32
109
        lba5          db ?       ; LBA register, 47:40
110
        featureh      db ?       ; Feature register, 15:8
111
 
112
        countl        db ?       ; Count register, 7:0
113
        counth        db ?       ; Count register, 15:8
114
        icc           db ?       ; Isochronous command completion
115
        control       db ?       ; Control register
116
 
117
        rsv1          rb 4       ; Reserved
118
ends
119
 
120
; Register FIS – Device to Host
121
struct FIS_REG_D2H
122
    fis_type      db ?           ; FIS_TYPE_REG_D2H
123
 
124
    _flags        db ?           ; 0bRIRPPPP, P - Port multiplier, R - Reserved
125
                                 ; I - Interrupt bit
126
 
127
    status        db ?           ; Status register
128
    error         db ?           ; Error register
129
 
130
    lba0          db ?           ; LBA low register, 7:0
131
    lba1          db ?           ; LBA mid register, 15:8
132
    lba2          db ?           ; LBA high register, 23:16
133
    device        db ?           ; Device register
134
 
135
    lba3          db ?           ; LBA register, 31:24
136
    lba4          db ?           ; LBA register, 39:32
137
    lba5          db ?           ; LBA register, 47:40
138
    rsv2          db ?           ; Reserved
139
 
140
    countl        db ?           ; Count register, 7:0
141
    counth        db ?           ; Count register, 15:8
142
    rsv3          rb 2           ; Reserved
143
 
144
    rsv4          rb 4           ; Reserved
145
ends
146
 
147
; Data FIS – Bidirectional
148
struct FIS_DATA
149
    fis_type      db ?           ; FIS_TYPE_DATA
150
    _flags        db ?           ; 0bRRRRPPPP, R - Reserved, P - Port multiplier
151
    rsv1          rb 2           ; Reserved
152
    ; DWORD 1 ~ N (?)
153
    data          rd 1           ; Payload
154
ends
155
 
156
; PIO Setup – Device to Host
157
struct FIS_PIO_SETUP
158
    fis_type      db ?           ; FIS_TYPE_PIO_SETUP
159
 
160
    _flags        db ?           ; 0bRIDRPPPP, P - Port multiplier, R - Reserved
161
                                 ; I - Interrupt bit, D - Data transfer direction, 1 - device to host
162
 
163
    status        db ?           ; Status register
164
    error         db ?           ; Error register
165
 
166
    lba0          db ?           ; LBA low register, 7:0
167
    lba1          db ?           ; LBA mid register, 15:8
168
    lba2          db ?           ; LBA high register, 23:16
169
    device        db ?           ; Device register
170
 
171
    lba3          db ?           ; LBA register, 31:24
172
    lba4          db ?           ; LBA register, 39:32
173
    lba5          db ?           ; LBA register, 47:40
174
    rsv2          db ?           ; Reserved
175
 
176
    countl        db ?           ; Count register, 7:0
177
    counth        db ?           ; Count register, 15:8
178
    rsv3          db ?           ; Reserved
179
    e_status      db ?           ; New value of status register
180
 
181
    tc            dw ?           ; Transfer count
182
    rsv4          rb 2           ; Reserved
183
ends
184
 
185
; DMA Setup – Device to Host
186
struct FIS_DMA_SETUP
187
    fis_type      db ?           ; FIS_TYPE_DMA_SETUP
188
    _flags        db ?           ; 0bAIDRPPPP, A - Auto-activate. Specifies if DMA Activate FIS is needed,
189
                                 ; I - Interrupt bit, D - Data transfer direction, 1 - device to host,
190
                                 ; R - Reserved, P - Port multiplier
191
 
192
    rsved         rb 2           ; Reserved
193
    DMAbufferID   dq ?           ; DMA Buffer Identifier.
194
                                 ; Used to Identify DMA buffer in host memory.
195
                                 ; SATA Spec says host specific and not in Spec.
196
                                 ; Trying AHCI spec might work.
197
 
198
    TransferCount dd ?           ; Number of bytes to transfer. Bit 0 must be 0
199
    resvd         dd ?           ; Reserved
200
ends
201
 
202
; Set device bits FIS - device to host
203
struct FIS_DEV_BITS
204
    fis_type      db ?           ; FIS_TYPE_DEV_BITS
205
    _flags        db ?           ; 0bNIRRPPPP, N - Notification, I - Interrupt,
206
                                 ; R - Reserved, P - Port multiplier
207
 
208
    status        db ?           ; Status register
209
    error         db ?           ; Error register
210
 
211
    protocol      dd ?           ; Protocol
212
ends
213
 
214
; --------------------------------------------------
9020 rgimad 215
uglobal
216
align 4
217
        ahci_controller AHCI_DATA
218
endg
219
 
9064 rgimad 220
; -----------------------------------------------------------------------
9020 rgimad 221
; detect ahci controller and initialize
222
align 4
223
init_ahci:
224
        mov     ecx, ahci_controller
225
        mov     esi, pcidev_list
226
.find_ahci_ctr:
227
        mov     esi, [esi + PCIDEV.fd]
228
        cmp     esi, pcidev_list
229
        jz      .ahci_ctr_not_found
230
        mov     eax, [esi + PCIDEV.class]
231
        ;DEBUGF  1, "K: device class = %x\n", eax
232
        shr     eax, 8 ; shift right because lowest 8 bits if ProgIf field
233
        cmp     eax, 0x0106 ; 0x01 - Mass Storage Controller class,  0x06 - Serial ATA Controller subclass
234
        jz      .ahci_ctr_found
235
        jmp     .find_ahci_ctr
236
 
237
.ahci_ctr_not_found:
238
        DEBUGF  1, "K: AHCI controller not found\n"
239
        ret
240
 
241
.ahci_ctr_found:
242
        mov     [ahci_controller + AHCI_DATA.pcidev], esi
243
 
244
        mov     eax, [esi+PCIDEV.class]
245
        movzx   ebx, byte [esi+PCIDEV.bus]
246
        movzx   ecx, byte [esi+PCIDEV.devfn]
247
        shr     ecx, 3 ; get rid of 3 lowest bits (function code), the rest bits is device code
248
        movzx   edx, byte [esi+PCIDEV.devfn]
249
        and     edx, 00000111b ; get only 3 lowest bits (function code)
250
        DEBUGF  1, "K: found AHCI controller, (class, subcl, progif) = %x, bus = %x, device = %x, function = %x\n", eax, ebx, ecx, edx
251
 
9023 rgimad 252
        ; get BAR5 value, it is physical address
9037 rgimad 253
        movzx   ebx, [esi + PCIDEV.bus]
254
        movzx   ebp, [esi + PCIDEV.devfn]
255
        stdcall pci_read32, ebx, ebp, PCI_REG_BAR5
256
        DEBUGF  1, "K: AHCI controller MMIO = %x\n", eax
257
        mov     edi, eax
9020 rgimad 258
 
9037 rgimad 259
        ; get the size of MMIO region
260
        stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, 0xFFFFFFFF
261
        stdcall pci_read32, ebx, ebp, PCI_REG_BAR5
262
        not     eax
263
        inc     eax
264
        DEBUGF  1, "K: AHCI: MMIO region size = 0x%x bytes\n", eax
265
 
266
        ; Map MMIO region to virtual memory
267
        stdcall map_io_mem, edi, eax, PG_SWR + PG_NOCACHE
9020 rgimad 268
        mov     [ahci_controller + AHCI_DATA.abar], eax
269
        DEBUGF  1, "K: AHCI controller BAR5 mapped to virtual addr %x\n", eax
270
 
9037 rgimad 271
        ; Restore the original BAR5 value
272
        stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, edi
273
 
9023 rgimad 274
        ; Enable dma bus mastering, memory space access, clear the "disable interrupts" bit
275
        ; Usually, it is already done before us
9024 rgimad 276
        movzx   ebx, [esi + PCIDEV.bus]
277
        movzx   ebp, [esi + PCIDEV.devfn]
278
        stdcall pci_read32, ebx, ebp, PCI_REG_STATUS_COMMAND
9020 rgimad 279
        DEBUGF  1, "K: AHCI: pci_status_command = %x\nEnabling interrupts, DMA bus mastering and memory space access\n", eax
280
        or      eax, 0x06 ; pci.command |= 0x06 (dma bus mastering + memory space access)
281
        btr     eax, 10 ; clear the "disable interrupts" bit
282
        DEBUGF  1, "K: AHCI: pci_status_command = %x\n", eax
9024 rgimad 283
        stdcall pci_write32, ebx, ebp, PCI_REG_STATUS_COMMAND, eax
9020 rgimad 284
 
9023 rgimad 285
        ; ; Print some register values to debug board
286
        ; mov     esi, [ahci_controller + AHCI_DATA.abar]
9064 rgimad 287
        ; DEBUGF  1, "K: AHCI: HBA.cap = %x, HBA.ghc = %x, HBA_MEM.version = %x\n", [esi + HBA_MEM.cap], [esi + HBA_MEM.ghc], [esi + HBA_MEM.version]
9020 rgimad 288
 
9023 rgimad 289
        ;-------------------------------------------------------
290
        ; Request BIOS/OS ownership handoff, if supported. (TODO check correctness)
291
        mov     esi, [ahci_controller + AHCI_DATA.abar]
9064 rgimad 292
        ;mov     ebx, [esi + HBA_MEM.cap2]
9023 rgimad 293
        ;DEBUGF  1, "K: AHCI: HBA_MEM.cap2 = %x\n", ebx
9064 rgimad 294
        bt      [esi + HBA_MEM.cap2], bit_AHCI_HBA_CAP2_BOH
9020 rgimad 295
        jnc     .end_handoff
9023 rgimad 296
        DEBUGF  1, "K: AHCI: requesting AHCI ownership change...\n"
9024 rgimad 297
        bts     [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_OOS
9020 rgimad 298
 
299
.wait_not_bos:
9024 rgimad 300
        bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BOS
9020 rgimad 301
        jc      .wait_not_bos
302
 
303
        mov     ebx, 3
304
        call    delay_hs
305
 
9023 rgimad 306
        ; if Bios Busy is still set after 30 mS, wait 2 seconds.
9024 rgimad 307
        bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BB
9020 rgimad 308
        jnc     @f
309
 
310
        mov     ebx, 200
311
        call    delay_hs
312
@@:
9023 rgimad 313
        DEBUGF  1, "K: AHCI: ownership change completed.\n"
9020 rgimad 314
 
315
.end_handoff:
9023 rgimad 316
        ;-------------------------------------------------------
9020 rgimad 317
 
9023 rgimad 318
        ; enable the AHCI and reset it
9064 rgimad 319
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
320
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
9020 rgimad 321
 
9023 rgimad 322
        ; wait for reset to complete
323
.wait_reset:
9064 rgimad 324
        bt      [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
9023 rgimad 325
        jc      .wait_reset
9020 rgimad 326
 
9023 rgimad 327
        ; enable the AHCI and interrupts
9064 rgimad 328
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
329
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_INTERRUPT_ENABLE
9023 rgimad 330
        mov     ebx, 2
331
        call    delay_hs
332
 
9064 rgimad 333
        DEBUGF  1, "K: AHCI: caps: %x %x, ver: %x, ghc: %x, pi: %x\n", [esi + HBA_MEM.cap], [esi + HBA_MEM.cap2], [esi + HBA_MEM.version], [esi + HBA_MEM.ghc], [esi + HBA_MEM.pi]
9020 rgimad 334
 
9037 rgimad 335
        ; TODO:
336
        ; calculate irq line
337
        ; ahciHBA->ghc |= AHCI_GHC_IE;
338
        ; IDT::RegisterInterruptHandler(irq, InterruptHandler);
9064 rgimad 339
        ; ahciHBA->is = 0xffffffff;
9037 rgimad 340
 
341
        xor     ebx, ebx
342
.detect_drives:
343
        cmp     ebx, AHCI_MAX_PORTS
344
        jae     .end_detect_drives
345
 
346
        ; if port with index ebx is not implemented then go to next
9064 rgimad 347
        mov     ecx, [esi + HBA_MEM.pi]
9037 rgimad 348
        bt      ecx, ebx
349
        jnc     .continue_detect_drives
350
 
351
        mov     edi, ebx
352
        shl     edi, BSF sizeof.HBA_PORT
353
        add     edi, HBA_MEM.ports
354
        add     edi, esi
355
        ; now edi - base of HBA_MEM.ports[ebx]
356
 
357
        DEBUGF  1, "K: AHCI: port %d, ssts = %x\n", ebx, [edi + HBA_PORT.sata_status]
358
 
359
        mov     ecx, [edi + HBA_PORT.sata_status]
360
        shr     ecx, 8
361
        and     ecx, 0x0F
362
        cmp     ecx, AHCI_HBA_PORT_IPM_ACTIVE
363
        jne     .continue_detect_drives
364
 
365
        mov     ecx, [edi + HBA_PORT.sata_status]
366
        and     ecx, AHCI_HBA_PxSSTS_DET
367
        cmp     ecx, AHCI_HBA_PxSSTS_DET_PRESENT
368
        jne    .continue_detect_drives
369
 
370
        DEBUGF 1, "K: AHCI: found drive at port %d, signature = %x\n", ebx, [edi + HBA_PORT.signature]
371
 
372
.continue_detect_drives:
373
        inc     ebx
374
        jmp     .detect_drives
375
 
9064 rgimad 376
 
9037 rgimad 377
 
378
.end_detect_drives:
379
 
380
 
9020 rgimad 381
        ret
9065 rgimad 382
; -------------------------------------------------
9020 rgimad 383
 
9065 rgimad 384
; TODO: implement function port_rebase
385
 
386
; Start command engine
387
; in: eax - address of HBA_PORT structure
388
start_cmd:
389
.wait_cr: ; Wait until CR (bit15) is cleared
390
        bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_CR
391
        jc      .wait_cr
392
 
393
        ; Set FRE (bit4) and ST (bit0)
394
        bts     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FRE
395
        bts     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_ST
396
 
397
        ret
398
 
399
; Stop command engine
400
; in: eax - address of HBA_PORT structure
401
stop_cmd:
402
        btr     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_ST ; Clear ST (bit0)
403
        btr     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FRE ; Clear FRE (bit4)
404
.wait_fr_cr: ; Wait until FR (bit14), CR (bit15) are cleared
405
        bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FR
406
        jc      .wait_fr_cr
407
        bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_CR
408
        jc      .wait_fr_cr
409
 
410
        ret
411