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