Subversion Repositories Kolibri OS

Rev

Rev 9068 | Rev 9072 | 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
 
9068 rgimad 93
; Command header structure
94
struct HBA_CMD_HDR
95
    _flags1       db ? ; 0bPWACCCCC, P - Prefetchable, W - Write (1: H2D, 0: D2H)
96
                       ; A - ATAPI, C - Command FIS length in DWORDS, 2 ~ 16
97
 
98
    _flags2       db ? ; 0bPPPPRCB(Re), P - Port multiplier port, R - Reserved,
99
                       ; C - Clear busy upon R_OK, B - BIST, Re - Reset
100
 
101
    prdtl         dw ? ; Physical region descriptor table length in entries
102
    prdbc         dd ? ; Physical region descriptor byte count transferred
103
    ctba          dd ? ; Command table descriptor base address
104
    ctbau         dd ? ; Command table descriptor base address upper 32 bits
105
    rsv1          rd 4 ; Reserved
106
ends
107
 
9069 rgimad 108
struct HBA_PRDT_ENTRY
109
    dba           dd ?  ; Data base address
110
    dbau          dd ?  ; Data base address upper 32 bits
111
    rsv0          dd ?  ; Reserved
112
    _flags        dd ?  ; 0bIR..RD..D, I (1 bit) - Interrupt on completion,
113
                        ; R (9 bits) - Reserved, D (22 bits) - Byte count, 4M max
114
ends
115
 
116
struct HBA_CMD_TBL
117
    cfis          rb 64 ; 0x00, Command FIS
118
    acmd          rb 16 ; 0x40, ATAPI command, 12 or 16 bytes
119
    rsv           rb 48 ; 0x50, Reserved
120
    prdt_entry    HBA_PRDT_ENTRY  ; 0x80, Physical region descriptor table entries, 0 ~ 65535
121
                        ; so, this structure is variable-length
122
ends
123
 
9068 rgimad 124
; Contains virtual mappings for port phys memory regions
125
struct PORT_DATA
126
    clb           dd ? ; Command list base
127
    fb            dd ? ; FIS base
128
    ctba_arr      rd 32 ; ctba_arr[0] = clb[0].ctba, ... and so on.
129
    port          dd ? ; address of correspoding HBA_PORT structure
130
ends
131
 
9064 rgimad 132
; Register FIS – Host to Device
133
struct FIS_REG_H2D
134
        fis_type      db ?       ; FIS_TYPE_REG_H2D
135
        _flags        db ?       ; 0bCRRRPPPP, C - 1: Command, 0: Control
136
                                 ; R - Reserved, P - Port multiplier
137
 
138
        command       db ?       ; Command register
139
        featurel      db ?       ; Feature register, 7:0
140
 
141
        lba0          db ?       ; LBA low register, 7:0
142
        lba1          db ?       ; LBA mid register, 15:8
143
        lba2          db ?       ; LBA high register, 23:16
144
        device        db ?       ; Device register
145
 
146
        lba3          db ?       ; LBA register, 31:24
147
        lba4          db ?       ; LBA register, 39:32
148
        lba5          db ?       ; LBA register, 47:40
149
        featureh      db ?       ; Feature register, 15:8
150
 
151
        countl        db ?       ; Count register, 7:0
152
        counth        db ?       ; Count register, 15:8
153
        icc           db ?       ; Isochronous command completion
154
        control       db ?       ; Control register
155
 
156
        rsv1          rb 4       ; Reserved
157
ends
158
 
159
; Register FIS – Device to Host
160
struct FIS_REG_D2H
161
    fis_type      db ?           ; FIS_TYPE_REG_D2H
162
 
163
    _flags        db ?           ; 0bRIRPPPP, P - Port multiplier, R - Reserved
164
                                 ; I - Interrupt bit
165
 
166
    status        db ?           ; Status register
167
    error         db ?           ; Error register
168
 
169
    lba0          db ?           ; LBA low register, 7:0
170
    lba1          db ?           ; LBA mid register, 15:8
171
    lba2          db ?           ; LBA high register, 23:16
172
    device        db ?           ; Device register
173
 
174
    lba3          db ?           ; LBA register, 31:24
175
    lba4          db ?           ; LBA register, 39:32
176
    lba5          db ?           ; LBA register, 47:40
177
    rsv2          db ?           ; Reserved
178
 
179
    countl        db ?           ; Count register, 7:0
180
    counth        db ?           ; Count register, 15:8
181
    rsv3          rb 2           ; Reserved
182
 
183
    rsv4          rb 4           ; Reserved
184
ends
185
 
186
; Data FIS – Bidirectional
187
struct FIS_DATA
188
    fis_type      db ?           ; FIS_TYPE_DATA
189
    _flags        db ?           ; 0bRRRRPPPP, R - Reserved, P - Port multiplier
190
    rsv1          rb 2           ; Reserved
191
    ; DWORD 1 ~ N (?)
192
    data          rd 1           ; Payload
193
ends
194
 
195
; PIO Setup – Device to Host
196
struct FIS_PIO_SETUP
197
    fis_type      db ?           ; FIS_TYPE_PIO_SETUP
198
 
199
    _flags        db ?           ; 0bRIDRPPPP, P - Port multiplier, R - Reserved
200
                                 ; I - Interrupt bit, D - Data transfer direction, 1 - device to host
201
 
202
    status        db ?           ; Status register
203
    error         db ?           ; Error register
204
 
205
    lba0          db ?           ; LBA low register, 7:0
206
    lba1          db ?           ; LBA mid register, 15:8
207
    lba2          db ?           ; LBA high register, 23:16
208
    device        db ?           ; Device register
209
 
210
    lba3          db ?           ; LBA register, 31:24
211
    lba4          db ?           ; LBA register, 39:32
212
    lba5          db ?           ; LBA register, 47:40
213
    rsv2          db ?           ; Reserved
214
 
215
    countl        db ?           ; Count register, 7:0
216
    counth        db ?           ; Count register, 15:8
217
    rsv3          db ?           ; Reserved
218
    e_status      db ?           ; New value of status register
219
 
220
    tc            dw ?           ; Transfer count
221
    rsv4          rb 2           ; Reserved
222
ends
223
 
224
; DMA Setup – Device to Host
225
struct FIS_DMA_SETUP
226
    fis_type      db ?           ; FIS_TYPE_DMA_SETUP
227
    _flags        db ?           ; 0bAIDRPPPP, A - Auto-activate. Specifies if DMA Activate FIS is needed,
228
                                 ; I - Interrupt bit, D - Data transfer direction, 1 - device to host,
229
                                 ; R - Reserved, P - Port multiplier
230
 
231
    rsved         rb 2           ; Reserved
232
    DMAbufferID   dq ?           ; DMA Buffer Identifier.
233
                                 ; Used to Identify DMA buffer in host memory.
234
                                 ; SATA Spec says host specific and not in Spec.
235
                                 ; Trying AHCI spec might work.
236
 
237
    TransferCount dd ?           ; Number of bytes to transfer. Bit 0 must be 0
238
    resvd         dd ?           ; Reserved
239
ends
240
 
241
; Set device bits FIS - device to host
242
struct FIS_DEV_BITS
243
    fis_type      db ?           ; FIS_TYPE_DEV_BITS
244
    _flags        db ?           ; 0bNIRRPPPP, N - Notification, I - Interrupt,
245
                                 ; R - Reserved, P - Port multiplier
246
 
247
    status        db ?           ; Status register
248
    error         db ?           ; Error register
249
 
250
    protocol      dd ?           ; Protocol
251
ends
252
 
9069 rgimad 253
struct HBA_FIS
254
    dsfis         FIS_DMA_SETUP  ; 0x00, DMA Setup FIS
255
    pad0          rb 4           ;
256
 
257
    psfis         FIS_PIO_SETUP  ; 0x20, PIO Setup FIS
258
    pad1          rb 12          ;
259
 
260
    rfis          FIS_REG_D2H    ; 0x40, Register - Device to Host FIS
261
    pad2          rb 4           ;
262
 
263
    sdbfis        FIS_DEV_BITS   ; 0x58, Set Device Bit FIS
264
 
265
    ufis          rb 64          ; 0x60
266
 
267
    rsv           rb (0x100 - 0xA0) ; 0xA0
268
ends
269
 
9064 rgimad 270
; --------------------------------------------------
9020 rgimad 271
uglobal
272
align 4
273
        ahci_controller AHCI_DATA
9068 rgimad 274
        port_data_arr   rb (sizeof.PORT_DATA*AHCI_MAX_PORTS)
9020 rgimad 275
endg
276
 
9064 rgimad 277
; -----------------------------------------------------------------------
9020 rgimad 278
; detect ahci controller and initialize
279
align 4
9068 rgimad 280
ahci_init:
9020 rgimad 281
        mov     ecx, ahci_controller
282
        mov     esi, pcidev_list
283
.find_ahci_ctr:
284
        mov     esi, [esi + PCIDEV.fd]
285
        cmp     esi, pcidev_list
286
        jz      .ahci_ctr_not_found
287
        mov     eax, [esi + PCIDEV.class]
288
        ;DEBUGF  1, "K: device class = %x\n", eax
289
        shr     eax, 8 ; shift right because lowest 8 bits if ProgIf field
290
        cmp     eax, 0x0106 ; 0x01 - Mass Storage Controller class,  0x06 - Serial ATA Controller subclass
291
        jz      .ahci_ctr_found
292
        jmp     .find_ahci_ctr
293
 
294
.ahci_ctr_not_found:
295
        DEBUGF  1, "K: AHCI controller not found\n"
296
        ret
297
 
298
.ahci_ctr_found:
299
        mov     [ahci_controller + AHCI_DATA.pcidev], esi
300
 
301
        mov     eax, [esi+PCIDEV.class]
302
        movzx   ebx, byte [esi+PCIDEV.bus]
303
        movzx   ecx, byte [esi+PCIDEV.devfn]
304
        shr     ecx, 3 ; get rid of 3 lowest bits (function code), the rest bits is device code
305
        movzx   edx, byte [esi+PCIDEV.devfn]
306
        and     edx, 00000111b ; get only 3 lowest bits (function code)
307
        DEBUGF  1, "K: found AHCI controller, (class, subcl, progif) = %x, bus = %x, device = %x, function = %x\n", eax, ebx, ecx, edx
308
 
9023 rgimad 309
        ; get BAR5 value, it is physical address
9037 rgimad 310
        movzx   ebx, [esi + PCIDEV.bus]
311
        movzx   ebp, [esi + PCIDEV.devfn]
312
        stdcall pci_read32, ebx, ebp, PCI_REG_BAR5
313
        DEBUGF  1, "K: AHCI controller MMIO = %x\n", eax
314
        mov     edi, eax
9020 rgimad 315
 
9037 rgimad 316
        ; get the size of MMIO region
317
        stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, 0xFFFFFFFF
318
        stdcall pci_read32, ebx, ebp, PCI_REG_BAR5
319
        not     eax
320
        inc     eax
321
        DEBUGF  1, "K: AHCI: MMIO region size = 0x%x bytes\n", eax
322
 
323
        ; Map MMIO region to virtual memory
324
        stdcall map_io_mem, edi, eax, PG_SWR + PG_NOCACHE
9020 rgimad 325
        mov     [ahci_controller + AHCI_DATA.abar], eax
326
        DEBUGF  1, "K: AHCI controller BAR5 mapped to virtual addr %x\n", eax
327
 
9037 rgimad 328
        ; Restore the original BAR5 value
329
        stdcall pci_write32, ebx, ebp, PCI_REG_BAR5, edi
330
 
9023 rgimad 331
        ; Enable dma bus mastering, memory space access, clear the "disable interrupts" bit
332
        ; Usually, it is already done before us
9024 rgimad 333
        movzx   ebx, [esi + PCIDEV.bus]
334
        movzx   ebp, [esi + PCIDEV.devfn]
335
        stdcall pci_read32, ebx, ebp, PCI_REG_STATUS_COMMAND
9020 rgimad 336
        DEBUGF  1, "K: AHCI: pci_status_command = %x\nEnabling interrupts, DMA bus mastering and memory space access\n", eax
337
        or      eax, 0x06 ; pci.command |= 0x06 (dma bus mastering + memory space access)
338
        btr     eax, 10 ; clear the "disable interrupts" bit
339
        DEBUGF  1, "K: AHCI: pci_status_command = %x\n", eax
9024 rgimad 340
        stdcall pci_write32, ebx, ebp, PCI_REG_STATUS_COMMAND, eax
9020 rgimad 341
 
9023 rgimad 342
        ; ; Print some register values to debug board
343
        ; mov     esi, [ahci_controller + AHCI_DATA.abar]
9064 rgimad 344
        ; 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 345
 
9023 rgimad 346
        ;-------------------------------------------------------
347
        ; Request BIOS/OS ownership handoff, if supported. (TODO check correctness)
348
        mov     esi, [ahci_controller + AHCI_DATA.abar]
9064 rgimad 349
        ;mov     ebx, [esi + HBA_MEM.cap2]
9023 rgimad 350
        ;DEBUGF  1, "K: AHCI: HBA_MEM.cap2 = %x\n", ebx
9064 rgimad 351
        bt      [esi + HBA_MEM.cap2], bit_AHCI_HBA_CAP2_BOH
9020 rgimad 352
        jnc     .end_handoff
9023 rgimad 353
        DEBUGF  1, "K: AHCI: requesting AHCI ownership change...\n"
9024 rgimad 354
        bts     [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_OOS
9020 rgimad 355
 
356
.wait_not_bos:
9024 rgimad 357
        bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BOS
9020 rgimad 358
        jc      .wait_not_bos
359
 
360
        mov     ebx, 3
361
        call    delay_hs
362
 
9023 rgimad 363
        ; if Bios Busy is still set after 30 mS, wait 2 seconds.
9024 rgimad 364
        bt      [esi + HBA_MEM.bohc], bit_AHCI_HBA_BOHC_BB
9020 rgimad 365
        jnc     @f
366
 
367
        mov     ebx, 200
368
        call    delay_hs
369
@@:
9023 rgimad 370
        DEBUGF  1, "K: AHCI: ownership change completed.\n"
9020 rgimad 371
 
372
.end_handoff:
9023 rgimad 373
        ;-------------------------------------------------------
9020 rgimad 374
 
9023 rgimad 375
        ; enable the AHCI and reset it
9064 rgimad 376
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
377
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
9020 rgimad 378
 
9023 rgimad 379
        ; wait for reset to complete
380
.wait_reset:
9064 rgimad 381
        bt      [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_RESET
9023 rgimad 382
        jc      .wait_reset
9020 rgimad 383
 
9023 rgimad 384
        ; enable the AHCI and interrupts
9064 rgimad 385
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_AHCI_ENABLE
386
        bts     [esi + HBA_MEM.ghc], bit_AHCI_HBA_GHC_INTERRUPT_ENABLE
9023 rgimad 387
        mov     ebx, 2
388
        call    delay_hs
389
 
9064 rgimad 390
        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 391
 
9037 rgimad 392
        ; TODO:
393
        ; calculate irq line
394
        ; ahciHBA->ghc |= AHCI_GHC_IE;
395
        ; IDT::RegisterInterruptHandler(irq, InterruptHandler);
9064 rgimad 396
        ; ahciHBA->is = 0xffffffff;
9037 rgimad 397
 
398
        xor     ebx, ebx
399
.detect_drives:
400
        cmp     ebx, AHCI_MAX_PORTS
401
        jae     .end_detect_drives
402
 
403
        ; if port with index ebx is not implemented then go to next
9064 rgimad 404
        mov     ecx, [esi + HBA_MEM.pi]
9037 rgimad 405
        bt      ecx, ebx
406
        jnc     .continue_detect_drives
407
 
408
        mov     edi, ebx
409
        shl     edi, BSF sizeof.HBA_PORT
410
        add     edi, HBA_MEM.ports
411
        add     edi, esi
412
        ; now edi - base of HBA_MEM.ports[ebx]
413
 
414
        DEBUGF  1, "K: AHCI: port %d, ssts = %x\n", ebx, [edi + HBA_PORT.sata_status]
415
 
416
        mov     ecx, [edi + HBA_PORT.sata_status]
417
        shr     ecx, 8
418
        and     ecx, 0x0F
419
        cmp     ecx, AHCI_HBA_PORT_IPM_ACTIVE
420
        jne     .continue_detect_drives
421
 
422
        mov     ecx, [edi + HBA_PORT.sata_status]
423
        and     ecx, AHCI_HBA_PxSSTS_DET
424
        cmp     ecx, AHCI_HBA_PxSSTS_DET_PRESENT
9068 rgimad 425
        jne     .continue_detect_drives
9037 rgimad 426
 
9068 rgimad 427
        DEBUGF  1, "K: AHCI: found drive at port %d, signature = %x\n", ebx, [edi + HBA_PORT.signature]
9037 rgimad 428
 
9068 rgimad 429
        mov     ecx, ebx
430
        shl     ecx, BSF sizeof.PORT_DATA
431
        add     ecx, port_data_arr
432
        stdcall ahci_port_rebase, edi, ebx, ecx
433
 
9037 rgimad 434
.continue_detect_drives:
435
        inc     ebx
436
        jmp     .detect_drives
437
 
9064 rgimad 438
 
9037 rgimad 439
 
440
.end_detect_drives:
441
 
442
 
9020 rgimad 443
        ret
9065 rgimad 444
; -------------------------------------------------
9020 rgimad 445
 
9065 rgimad 446
; Start command engine
447
; in: eax - address of HBA_PORT structure
9068 rgimad 448
ahci_start_cmd:
9065 rgimad 449
.wait_cr: ; Wait until CR (bit15) is cleared
450
        bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_CR
451
        jc      .wait_cr
452
 
453
        ; Set FRE (bit4) and ST (bit0)
454
        bts     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FRE
455
        bts     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_ST
9068 rgimad 456
        ; maybe here call ahci flush cmd ? TODO (see seakernel)
9065 rgimad 457
        ret
458
 
459
; Stop command engine
460
; in: eax - address of HBA_PORT structure
9068 rgimad 461
ahci_stop_cmd:
9065 rgimad 462
        btr     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_ST ; Clear ST (bit0)
463
        btr     [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FRE ; Clear FRE (bit4)
464
.wait_fr_cr: ; Wait until FR (bit14), CR (bit15) are cleared
465
        bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_FR
466
        jc      .wait_fr_cr
467
        bt      [eax + HBA_PORT.command], bit_AHCI_HBA_PxCMD_CR
468
        jc      .wait_fr_cr
469
 
470
        ret
471
 
9068 rgimad 472
; The commands may not take effect until the command
473
; register is read again by software, because reasons.
474
; in: eax - address of HBA_PORT structure
475
; out: eax - command register value
476
ahci_flush_cmd:
477
        mov     eax, [eax + HBA_PORT.command]
478
        ret
9065 rgimad 479
 
9068 rgimad 480
; Send command to port
481
; in: eax - address of HBA_PORT structure
482
;     ebx - index of command slot
483
ahci_send_cmd:
484
        push    ecx
485
        mov     [eax + HBA_PORT.interrupt_status], 0xFFFFFFFF
486
 
487
        mov     cl, bl
488
        mov     [eax + HBA_PORT.command_issue], 1
489
        shl     [eax + HBA_PORT.command_issue], cl
9065 rgimad 490
 
9068 rgimad 491
        call    ahci_flush_cmd
492
        pop     ecx
493
        ret
9065 rgimad 494
 
9068 rgimad 495
; ---------------------------------------------------------------------------
496
; TODO: check correctness
497
; in: port - address of HBA_PORT structure
498
;     portno - port index (0..31)
499
;     pdata - address of PORT_DATA structure
500
proc ahci_port_rebase stdcall, port: dword, portno: dword, pdata: dword
501
        locals
502
            phys_page1  dd ?
503
            virt_page1  dd ?
504
            phys_page23 dd ?
505
            virt_page23 dd ?
506
            tmp         dd ?
507
        endl
508
 
509
        pushad
510
 
511
        DEBUGF  1, "Rebasing port %u\n", [portno]
512
 
513
        mov     eax, [port]
514
        call    ahci_stop_cmd
515
 
516
        ; Command list entry size = 32
517
        ; Command list entry maxim count = 32
518
        ; Command list maxim size = 32*32 = 1K per port
519
        call    alloc_page
520
        mov     [phys_page1], eax
521
 
522
        stdcall map_io_mem, eax, 4096, PG_NOCACHE + PG_SWR  ; map to virt memory so we can work with it
523
        mov     [virt_page1], eax
524
 
525
        mov     esi, [port]
526
        mov     ebx, [phys_page1]
527
        mov     [esi + HBA_PORT.command_list_base_l], ebx ; set the command list base
528
        mov     [esi + HBA_PORT.command_list_base_h], 0  ; zero upper 32 bits of addr cause we are 32 bit os
529
 
530
        mov     edi, [pdata]
531
        mov     ebx, [virt_page1]
532
        mov     [edi + PORT_DATA.clb], ebx ; set pdata->clb
533
 
534
        mov     eax, [port]
535
        mov     [edi + PORT_DATA.port], eax ; set pdata->port
536
 
537
        stdcall _memset, ebx, 0, 1024 ; zero out the command list
538
 
539
        ; FIS entry size = 256 bytes per port
540
        mov     eax, [phys_page1]
541
        add     eax, 1024
542
        mov     [esi + HBA_PORT.fis_base_l], eax
543
        mov     [esi + HBA_PORT.fis_base_h], 0
544
 
545
        mov     eax, [virt_page1]
546
        add     eax, 1024
547
        mov     [edi + PORT_DATA.fb], eax ; set pdata->fb
548
        stdcall _memset, eax, 0, 256 ; zero out
549
 
550
        stdcall alloc_pages, 2
551
        mov     [phys_page23], eax
552
        stdcall map_io_mem, eax, 2*4096, PG_NOCACHE + PG_SWR
553
        mov     [virt_page23], eax
554
 
555
        ; Command table size = 256*32 = 8K per port
556
        mov     edx, [edi + PORT_DATA.clb] ; cmdheader array base
557
        xor     ecx, ecx
558
 
559
.for1:
560
        cmp     ecx, 32
561
        jae     .for1_end
562
 
563
        mov     ebx, ecx
564
        shl     ebx, BSF sizeof.HBA_CMD_HDR
565
        add     ebx, edx ; ebx = cmdheader[ecx]
566
 
567
        mov     [ebx + HBA_CMD_HDR.prdtl], 8 ; 8 prdt entries per command table
568
 
569
        ; 256 bytes per command table, 64+16+48+16*8
570
 
571
        push    edx
572
 
573
        ; cmdheader[ecx].ctba = phys_page23 + ecx*256
574
        mov     [ebx + HBA_CMD_HDR.ctba], ecx
575
        shl     [ebx + HBA_CMD_HDR.ctba], BSF 256 ; *= 256
576
        mov     eax, [ebx + HBA_CMD_HDR.ctba]
577
        mov     edx, [phys_page23]
578
        add     [ebx + HBA_CMD_HDR.ctba], edx
579
 
580
        add     eax, [virt_page23]
581
        mov     [tmp], eax  ; tmp = virt_page23 + ecx*256
9069 rgimad 582
        lea     eax, [ecx*4 + edi + PORT_DATA.ctba_arr] ; eax = pdata->ctba_arr[ecx]
9068 rgimad 583
        mov     edx, [tmp]
584
        mov     [eax], edx  ; pdata->ctba_arr[ecx] = virt_page23 + ecx*256
585
 
586
        pop     edx
587
 
588
        mov     [ebx + HBA_CMD_HDR.ctbau], 0
589
        stdcall _memset, [eax], 0, 256 ; zero out
590
 
591
        inc     ecx
592
        jmp     .for1
593
.for1_end:
594
 
595
        mov     eax, [port]
596
        call    ahci_start_cmd
597
 
598
        DEBUGF  1, "End rebasing port %u\n", [portno]
599
        popad
600
        ret
601
endp
602
 
9069 rgimad 603
; ----------------------------------------------------------- ; TODO check
604
; Find a free command list slot
605
; in: eax - address of HBA_PORT structure
606
; out: eax - if not found -1, else slot index
607
ahci_find_cmdslot:
608
        push    ebx ecx edx esi
609
        ; If not set in SACT and CI, the slot is free
610
        mov     ebx, [eax + HBA_PORT.sata_active]
611
        or      ebx, [eax + HBA_PORT.command_issue] ; ebx = slots
9068 rgimad 612
 
9069 rgimad 613
        mov     esi, [ahci_controller + AHCI_DATA.abar]
614
        mov     edx, [esi + HBA_MEM.cap]
615
        shr     edx, 8
616
        and     edx, 0xf
617
        DEBUGF  1, "Number of Command Slots on each port = %u\n", edx
618
        xor     ecx, ecx
619
.for1:
620
        cmp     ecx, edx
621
        jae     .for1_end
9068 rgimad 622
 
9069 rgimad 623
        ; if ((slots&1) == 0) return i;
624
        bt      ebx, 0
625
        jc      .cont1
626
 
627
        mov     eax, ecx
628
        jmp     .ret
629
 
630
.cont1:
631
        shr     ebx, 1
632
        inc     ecx
633
        jmp     .for1
634
.for1_end:
635
        DEBUGF  1, "Cannot find free command list entry\n"
636
        mov     eax, -1
637
.ret:
638
        pop     esi edx ecx ebx
639
        ret
640
 
641
 
9068 rgimad 642
proc _memset stdcall, dest:dword, val:byte, cnt:dword ; doesnt clobber any registers
643
        ;DEBUGF  DBG_INFO, "memset(%x, %u, %u)\n", [dest], [val], [cnt]
644
        push    eax ecx edi
645
        mov     edi, dword [dest]
646
        mov     al,  byte [val]
647
        mov     ecx, dword [cnt]
9069 rgimad 648
        rep stosb
9068 rgimad 649
        pop     edi ecx eax
650
        ret
651
endp