1///! AHCI Device helper functions
2#include <barrelfish/barrelfish.h>
3#include <barrelfish/deferred.h>
4
5#include "blk_ahci.h"
6#include "../blk_debug.h"
7
8#include "ahci_dev.h"
9
10size_t ahci_port_offset(uint32_t port)
11{
12    return 0x100 + port * 0x80;
13}
14
15bool ahci_port_is_idle(ahci_port_t* port)
16{
17    ahci_port_cmd_t cmd = ahci_port_cmd_rd(port);
18    uint8_t st = ahci_port_cmd_st_extract(cmd);
19    uint8_t cr = ahci_port_cmd_cr_extract(cmd);
20    uint8_t fre = ahci_port_cmd_fre_extract(cmd);
21
22    return st == 0 && cr == 0 && fre == 0;
23}
24
25bool ahci_port_is_ready(ahci_port_t* port)
26{
27    uint8_t busy = ahci_port_tfd_bsy_rdf(port);
28    uint8_t drq = ahci_port_tfd_drq_rdf(port);
29    return busy == 0 && drq == 0;
30}
31
32bool ahci_port_is_functional(ahci_port_t* port)
33{
34    uint8_t det = ahci_port_ssts_det_rdf(port);
35    return ahci_port_is_ready(port) && det == 0x3;
36}
37
38bool ahci_port_slot_free(ahci_port_t* port, uint8_t slot)
39{
40    bool ci_free = (ahci_port_ci_rd(port) & (1<<slot)) == 0;
41    bool sact_free = (ahci_port_sact_rd(port) & (1<<slot)) == 0;
42    return ci_free && sact_free;
43}
44
45void ahci_port_start(ahci_port_t* port)
46{
47    assert(ahci_port_is_functional(port));
48    ahci_port_cmd_st_wrf(port, 0x1);
49}
50
51void ahci_port_stop(ahci_port_t* port)
52{
53    ahci_port_cmd_st_wrf(port, 0);
54
55    ahci_port_cmd_t cmd = ahci_port_cmd_rd(port);
56    while (ahci_port_cmd_cr_extract(cmd) != 0) {
57        // TODO should clear in 500ms
58    }
59
60    ahci_port_cmd_fre_wrf(port, 0);
61    while (ahci_port_cmd_fr_rdf(port) != 0) {
62        // TODO should clear in 500ms
63    }
64}
65
66bool ahci_port_is_running(ahci_port_t* port)
67{
68    return ahci_port_cmd_st_rdf(port) > 0;
69}
70
71uint32_t ahci_port_probe(ahci_port_t* port)
72{
73    if (ahci_port_ssts_det_rdf(port) == 0x03) {
74        return ahci_port_sig_rd(port);
75    }
76
77    return 0;
78}
79
80void ahci_hba_reset(ahci_hba_t* controller)
81{
82    ahci_hba_ghc_t ghc = ahci_hba_ghc_rd(controller);
83    BLK_DEBUG("Resetting HBA (setting ghc = %x)...\n", ghc);
84    ghc = ahci_hba_ghc_hr_insert(ghc, 1);
85    ahci_hba_ghc_wr(controller, ghc);
86    barrelfish_usleep(200000);
87    while (1) {
88        ghc = ahci_hba_ghc_rd(controller);
89        if (ahci_hba_ghc_hr_extract(ghc) == 0) {
90            BLK_DEBUG("reset done\n");
91            break;
92        }
93    }
94}
95
96void ahci_hba_irq_enable(ahci_hba_t* controller)
97{
98    BLK_DEBUG("Enabling HBA Interrupts\n");
99    ahci_hba_ghc_t ghc = ahci_hba_ghc_rd(controller);
100    ghc = ahci_hba_ghc_ie_insert(ghc, 1);
101    ahci_hba_ghc_wr(controller, ghc);
102}
103
104void ahci_hba_irq_disable(ahci_hba_t* controller)
105{
106    BLK_DEBUG("Disable HBA Interrupts\n");
107    ahci_hba_ghc_t ghc = ahci_hba_ghc_rd(controller);
108    ghc = ahci_hba_ghc_ie_insert(ghc, 1);
109    ahci_hba_ghc_wr(controller, ghc);
110}
111
112uint32_t ahci_hba_get_num_ports(ahci_hba_t* controller)
113{
114    return ahci_hba_cap_np_extract(ahci_hba_cap_rd(controller)) + 1;
115}
116
117uint32_t ahci_hba_get_command_slots(ahci_hba_t* controller)
118{
119    return ahci_hba_cap_ncs_extract(ahci_hba_cap_rd(controller));
120}
121
122bool ahci_port_is_implemented(ahci_hba_t* controller, size_t port)
123{
124    return (ahci_hba_pi_rd(controller) & (1 << port)) > 0;
125}
126
127void ahci_port_print_identification(ata_identify_t *id)
128{
129    char* buf2 = malloc(10*4096);
130    assert(buf2 != NULL);
131    ata_identify_pr(buf2, 10*4096, id);
132    puts(buf2);
133    free(buf2);
134}
135
136errval_t ahci_hba_init(ahci_hba_t* controller)
137{
138    ahci_hba_reset(controller);
139
140    // Make sure AHCI is enabled:
141    BLK_DEBUG("Setting controller into AHCI mode\n");
142    ahci_hba_ghc_t ghc = ahci_hba_ghc_rd(controller);
143    ghc = ahci_hba_ghc_ae_insert(ghc, 1);
144    ahci_hba_ghc_wr(controller, ghc);
145
146    ahci_hba_irq_disable(controller);
147
148    return SYS_ERR_OK;
149}
150