1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * PCI Endpoint uclass
4 *
5 * Based on Linux PCI-EP driver written by
6 * Kishon Vijay Abraham I <kishon@ti.com>
7 *
8 * Copyright (c) 2019
9 * Written by Ramon Fried <ramon.fried@gmail.com>
10 */
11
12 #include <common.h>
13 #include <dm.h>
14 #include <errno.h>
15 #include <asm/global_data.h>
16 #include <linux/log2.h>
17 #include <pci_ep.h>
18
19 DECLARE_GLOBAL_DATA_PTR;
20
pci_ep_write_header(struct udevice * dev,uint fn,struct pci_ep_header * hdr)21 int pci_ep_write_header(struct udevice *dev, uint fn, struct pci_ep_header *hdr)
22 {
23 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
24
25 if (!ops->write_header)
26 return -ENOSYS;
27
28 return ops->write_header(dev, fn, hdr);
29 }
30
pci_ep_read_header(struct udevice * dev,uint fn,struct pci_ep_header * hdr)31 int pci_ep_read_header(struct udevice *dev, uint fn, struct pci_ep_header *hdr)
32 {
33 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
34
35 if (!ops->read_header)
36 return -ENOSYS;
37
38 return ops->read_header(dev, fn, hdr);
39 }
40
pci_ep_set_bar(struct udevice * dev,uint func_no,struct pci_bar * ep_bar)41 int pci_ep_set_bar(struct udevice *dev, uint func_no, struct pci_bar *ep_bar)
42 {
43 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
44 int flags = ep_bar->flags;
45
46 /* Some basic bar validity checks */
47 if (ep_bar->barno > BAR_5 || ep_bar->barno < BAR_0)
48 return -EINVAL;
49
50 if ((ep_bar->barno == BAR_5 &&
51 (flags & PCI_BASE_ADDRESS_MEM_TYPE_64)) ||
52 ((flags & PCI_BASE_ADDRESS_SPACE_IO) &&
53 (flags & PCI_BASE_ADDRESS_IO_MASK)) ||
54 (upper_32_bits(ep_bar->size) &&
55 !(flags & PCI_BASE_ADDRESS_MEM_TYPE_64)))
56 return -EINVAL;
57
58 if (!ops->set_bar)
59 return -ENOSYS;
60
61 return ops->set_bar(dev, func_no, ep_bar);
62 }
63
pci_ep_read_bar(struct udevice * dev,uint func_no,struct pci_bar * ep_bar,enum pci_barno barno)64 int pci_ep_read_bar(struct udevice *dev, uint func_no, struct pci_bar *ep_bar,
65 enum pci_barno barno)
66 {
67 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
68
69 /* Some basic bar validity checks */
70 if (barno > BAR_5 || barno < BAR_0)
71 return -EINVAL;
72
73 if (!ops->read_bar)
74 return -ENOSYS;
75
76 return ops->read_bar(dev, func_no, ep_bar, barno);
77 }
78
pci_ep_clear_bar(struct udevice * dev,uint func_num,enum pci_barno bar)79 int pci_ep_clear_bar(struct udevice *dev, uint func_num, enum pci_barno bar)
80 {
81 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
82
83 if (!ops->clear_bar)
84 return -ENOSYS;
85
86 return ops->clear_bar(dev, func_num, bar);
87 }
88
pci_ep_map_addr(struct udevice * dev,uint func_no,phys_addr_t addr,u64 pci_addr,size_t size)89 int pci_ep_map_addr(struct udevice *dev, uint func_no, phys_addr_t addr,
90 u64 pci_addr, size_t size)
91 {
92 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
93
94 if (!ops->map_addr)
95 return -ENOSYS;
96
97 return ops->map_addr(dev, func_no, addr, pci_addr, size);
98 }
99
pci_ep_unmap_addr(struct udevice * dev,uint func_no,phys_addr_t addr)100 int pci_ep_unmap_addr(struct udevice *dev, uint func_no, phys_addr_t addr)
101 {
102 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
103
104 if (!ops->unmap_addr)
105 return -ENOSYS;
106
107 return ops->unmap_addr(dev, func_no, addr);
108 }
109
pci_ep_set_msi(struct udevice * dev,uint func_no,uint interrupts)110 int pci_ep_set_msi(struct udevice *dev, uint func_no, uint interrupts)
111 {
112 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
113 uint encode_int;
114
115 if (interrupts > 32)
116 return -EINVAL;
117
118 if (!ops->set_msi)
119 return -ENOSYS;
120
121 /* MSI spec permits allocation of
122 * only 1, 2, 4, 8, 16, 32 interrupts
123 */
124 encode_int = order_base_2(interrupts);
125
126 return ops->set_msi(dev, func_no, encode_int);
127 }
128
pci_ep_get_msi(struct udevice * dev,uint func_no)129 int pci_ep_get_msi(struct udevice *dev, uint func_no)
130 {
131 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
132 int interrupt;
133
134 if (!ops->get_msi)
135 return -ENOSYS;
136
137 interrupt = ops->get_msi(dev, func_no);
138
139 if (interrupt < 0)
140 return 0;
141
142 /* Translate back from order base 2*/
143 interrupt = 1 << interrupt;
144
145 return interrupt;
146 }
147
pci_ep_set_msix(struct udevice * dev,uint func_no,uint interrupts)148 int pci_ep_set_msix(struct udevice *dev, uint func_no, uint interrupts)
149 {
150 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
151
152 if (interrupts < 1 || interrupts > 2048)
153 return -EINVAL;
154
155 if (!ops->set_msix)
156 return -ENOSYS;
157
158 return ops->set_msix(dev, func_no, interrupts - 1);
159 }
160
pci_ep_get_msix(struct udevice * dev,uint func_no)161 int pci_ep_get_msix(struct udevice *dev, uint func_no)
162 {
163 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
164 int interrupt;
165
166 if (!ops->get_msix)
167 return -ENOSYS;
168
169 interrupt = ops->get_msix(dev, func_no);
170
171 if (interrupt < 0)
172 return 0;
173
174 return interrupt + 1;
175 }
176
pci_ep_raise_irq(struct udevice * dev,uint func_no,enum pci_ep_irq_type type,uint interrupt_num)177 int pci_ep_raise_irq(struct udevice *dev, uint func_no,
178 enum pci_ep_irq_type type, uint interrupt_num)
179 {
180 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
181
182 if (!ops->raise_irq)
183 return -ENOSYS;
184
185 return ops->raise_irq(dev, func_no, type, interrupt_num);
186 }
187
pci_ep_start(struct udevice * dev)188 int pci_ep_start(struct udevice *dev)
189 {
190 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
191
192 if (!ops->start)
193 return -ENOSYS;
194
195 return ops->start(dev);
196 }
197
pci_ep_stop(struct udevice * dev)198 int pci_ep_stop(struct udevice *dev)
199 {
200 struct pci_ep_ops *ops = pci_ep_get_ops(dev);
201
202 if (!ops->stop)
203 return -ENOSYS;
204
205 return ops->stop(dev);
206 }
207
208 UCLASS_DRIVER(pci_ep) = {
209 .id = UCLASS_PCI_EP,
210 .name = "pci_ep",
211 .flags = DM_UC_FLAG_SEQ_ALIAS,
212 };
213
pci_ep_init(void)214 int pci_ep_init(void)
215 {
216 struct udevice *dev;
217
218 for (uclass_first_device_check(UCLASS_PCI_EP, &dev);
219 dev;
220 uclass_next_device_check(&dev)) {
221 ;
222 }
223
224 return 0;
225 }
226