1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2023-02-25     GuEe-GUI     the first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 
14 #define AHCI_REG_BAR 5
15 
16 struct pci_ahci_quirk
17 {
18     int bar_idx;
19     rt_bool_t bar_offset;
20 
21     const struct rt_ahci_ops *ops;
22 };
23 
24 struct pci_ahci_host
25 {
26     struct rt_ahci_host parent;
27     const struct pci_ahci_quirk *quirk;
28 
29     rt_bool_t is_msi;
30 };
31 
32 #define raw_to_pci_ahci_host(raw) rt_container_of(raw, struct pci_ahci_host, parent)
33 
pci_ahci_init(struct rt_ahci_host * host)34 static rt_err_t pci_ahci_init(struct rt_ahci_host *host)
35 {
36     struct rt_pci_device *pdev;
37 
38     pdev = rt_container_of(host->parent.dev, struct rt_pci_device, parent);
39 
40     if (pdev->vendor == PCI_VENDOR_ID_JMICRON)
41     {
42         rt_pci_write_config_u8(pdev, 0x41, 0xa1);
43     }
44 
45     return RT_EOK;
46 }
47 
48 static const struct rt_ahci_ops pci_ahci_ops =
49 {
50     .host_init = pci_ahci_init,
51 };
52 
pci_ahci_intel_init(struct rt_ahci_host * host)53 static rt_err_t pci_ahci_intel_init(struct rt_ahci_host *host)
54 {
55     rt_uint16_t val;
56     struct rt_pci_device *pdev;
57 
58     pdev = rt_container_of(host->parent.dev, struct rt_pci_device, parent);
59 
60     rt_pci_read_config_u16(pdev, 0x92, &val);
61     rt_pci_write_config_u16(pdev, 0x92, val & ~0xf);
62 
63     rt_thread_mdelay(10);
64     rt_pci_write_config_u16(pdev, 0x92, val | 0xf);
65 
66     return RT_EOK;
67 }
68 
69 static const struct rt_ahci_ops pci_ahci_intel_ops =
70 {
71     .host_init = pci_ahci_intel_init,
72 };
73 
pci_ahci_probe(struct rt_pci_device * pdev)74 static rt_err_t pci_ahci_probe(struct rt_pci_device *pdev)
75 {
76     rt_err_t err;
77     int bar_idx;
78     struct rt_ahci_host *ahci;
79     struct pci_ahci_host *pci_ahci = rt_calloc(1, sizeof(*pci_ahci));
80     const struct pci_ahci_quirk *quirk = pdev->id->data;
81 
82     if (!pci_ahci)
83     {
84         return -RT_ENOMEM;
85     }
86 
87     pci_ahci->quirk = quirk;
88     ahci = &pci_ahci->parent;
89     ahci->parent.dev = &pdev->parent;
90 
91     bar_idx = quirk && quirk->bar_offset ? quirk->bar_idx : AHCI_REG_BAR;
92 
93     ahci->regs = rt_pci_iomap(pdev, bar_idx);
94 
95     if (!ahci->regs)
96     {
97         err = -RT_EIO;
98         goto _fail;
99     }
100 
101     ahci->ops = quirk && quirk->ops ? quirk->ops : &pci_ahci_ops;
102 
103     if (rt_pci_msi_enable(pdev) > 0)
104     {
105         pci_ahci->is_msi = RT_TRUE;
106     }
107     else
108     {
109         rt_pci_irq_unmask(pdev);
110     }
111     ahci->irq = pdev->irq;
112 
113     rt_pci_set_master(pdev);
114 
115     if ((err = rt_ahci_host_register(ahci)))
116     {
117         goto _disable;
118     }
119 
120     pdev->parent.user_data = pci_ahci;
121 
122     return RT_EOK;
123 
124 _disable:
125     if (pci_ahci->is_msi)
126     {
127         rt_pci_msix_disable(pdev);
128     }
129     else
130     {
131         rt_pci_irq_mask(pdev);
132     }
133     rt_pci_clear_master(pdev);
134     rt_iounmap(ahci->regs);
135 
136 _fail:
137     rt_free(pci_ahci);
138 
139     return err;
140 }
141 
pci_ahci_remove(struct rt_pci_device * pdev)142 static rt_err_t pci_ahci_remove(struct rt_pci_device *pdev)
143 {
144     struct rt_ahci_host *ahci;
145     struct pci_ahci_host *pci_ahci = pdev->parent.user_data;
146 
147     ahci = &pci_ahci->parent;
148 
149     rt_ahci_host_unregister(ahci);
150 
151     if (pci_ahci->is_msi)
152     {
153         rt_pci_msi_disable(pdev);
154     }
155     else
156     {
157         /* INTx is shared, don't mask all */
158         rt_hw_interrupt_umask(pdev->irq);
159         rt_pci_irq_mask(pdev);
160     }
161 
162     rt_pci_clear_master(pdev);
163 
164     rt_iounmap(ahci->regs);
165     rt_free(pci_ahci);
166 
167     return RT_EOK;
168 }
169 
pci_ahci_shutdown(struct rt_pci_device * pdev)170 static rt_err_t pci_ahci_shutdown(struct rt_pci_device *pdev)
171 {
172     return pci_ahci_remove(pdev);
173 }
174 
175 static struct pci_ahci_quirk intel_quirk =
176 {
177     .ops = &pci_ahci_intel_ops,
178 };
179 
180 static struct pci_ahci_quirk cavium_sata_quirk =
181 {
182     .bar_idx = 0,
183     .bar_offset = RT_TRUE,
184 };
185 
186 static const struct rt_pci_device_id pci_ahci_ids[] =
187 {
188     { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_INTEL, 0x2922), .data = &intel_quirk },
189     { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_ASMEDIA, 0x0611) },
190     { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_MARVELL, 0x6121) },
191     { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_MARVELL, 0x6145) },
192     { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_CAVIUM, 0xa01c), .data = &cavium_sata_quirk },
193     { RT_PCI_DEVICE_CLASS(PCIS_STORAGE_SATA_AHCI, ~0) },
194     { /* sentinel */ }
195 };
196 
197 static struct rt_pci_driver pci_ahci_driver =
198 {
199     .name = "ahci-pci",
200 
201     .ids = pci_ahci_ids,
202     .probe = pci_ahci_probe,
203     .remove = pci_ahci_remove,
204     .shutdown = pci_ahci_shutdown,
205 };
206 RT_PCI_DRIVER_EXPORT(pci_ahci_driver);
207