]>
Commit | Line | Data |
---|---|---|
a29e45a9 PB |
1 | /* |
2 | * Xilinx AXI Bridge for PCI Express Driver | |
3 | * | |
4 | * Copyright (C) 2016 Imagination Technologies | |
5 | * | |
6 | * SPDX-License-Identifier: GPL-2.0 | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
10 | #include <dm.h> | |
11 | #include <pci.h> | |
12 | ||
13 | #include <asm/io.h> | |
14 | ||
15 | /** | |
16 | * struct xilinx_pcie - Xilinx PCIe controller state | |
17 | * @hose: The parent classes PCI controller state | |
18 | * @cfg_base: The base address of memory mapped configuration space | |
19 | */ | |
20 | struct xilinx_pcie { | |
21 | struct pci_controller hose; | |
22 | void *cfg_base; | |
23 | }; | |
24 | ||
25 | /* Register definitions */ | |
26 | #define XILINX_PCIE_REG_PSCR 0x144 | |
27 | #define XILINX_PCIE_REG_PSCR_LNKUP BIT(11) | |
28 | ||
29 | /** | |
30 | * pcie_xilinx_link_up() - Check whether the PCIe link is up | |
31 | * @pcie: Pointer to the PCI controller state | |
32 | * | |
33 | * Checks whether the PCIe link for the given device is up or down. | |
34 | * | |
35 | * Return: true if the link is up, else false | |
36 | */ | |
37 | static bool pcie_xilinx_link_up(struct xilinx_pcie *pcie) | |
38 | { | |
39 | uint32_t pscr = __raw_readl(pcie->cfg_base + XILINX_PCIE_REG_PSCR); | |
40 | ||
41 | return pscr & XILINX_PCIE_REG_PSCR_LNKUP; | |
42 | } | |
43 | ||
44 | /** | |
45 | * pcie_xilinx_config_address() - Calculate the address of a config access | |
46 | * @pcie: Pointer to the PCI controller state | |
47 | * @bdf: Identifies the PCIe device to access | |
48 | * @offset: The offset into the device's configuration space | |
49 | * @paddress: Pointer to the pointer to write the calculates address to | |
50 | * | |
51 | * Calculates the address that should be accessed to perform a PCIe | |
52 | * configuration space access for a given device identified by the PCIe | |
53 | * controller device @pcie and the bus, device & function numbers in @bdf. If | |
54 | * access to the device is not valid then the function will return an error | |
55 | * code. Otherwise the address to access will be written to the pointer pointed | |
56 | * to by @paddress. | |
57 | * | |
58 | * Return: 0 on success, else -ENODEV | |
59 | */ | |
60 | static int pcie_xilinx_config_address(struct xilinx_pcie *pcie, pci_dev_t bdf, | |
61 | uint offset, void **paddress) | |
62 | { | |
63 | unsigned int bus = PCI_BUS(bdf); | |
64 | unsigned int dev = PCI_DEV(bdf); | |
65 | unsigned int func = PCI_FUNC(bdf); | |
66 | void *addr; | |
67 | ||
68 | if ((bus > 0) && !pcie_xilinx_link_up(pcie)) | |
69 | return -ENODEV; | |
70 | ||
71 | /* | |
72 | * Busses 0 (host-PCIe bridge) & 1 (its immediate child) are | |
73 | * limited to a single device each. | |
74 | */ | |
75 | if ((bus < 2) && (dev > 0)) | |
76 | return -ENODEV; | |
77 | ||
78 | addr = pcie->cfg_base; | |
79 | addr += bus << 20; | |
80 | addr += dev << 15; | |
81 | addr += func << 12; | |
82 | addr += offset; | |
83 | *paddress = addr; | |
84 | ||
85 | return 0; | |
86 | } | |
87 | ||
88 | /** | |
89 | * pcie_xilinx_read_config() - Read from configuration space | |
90 | * @pcie: Pointer to the PCI controller state | |
91 | * @bdf: Identifies the PCIe device to access | |
92 | * @offset: The offset into the device's configuration space | |
93 | * @valuep: A pointer at which to store the read value | |
94 | * @size: Indicates the size of access to perform | |
95 | * | |
96 | * Read a value of size @size from offset @offset within the configuration | |
97 | * space of the device identified by the bus, device & function numbers in @bdf | |
98 | * on the PCI bus @bus. | |
99 | * | |
100 | * Return: 0 on success, else -ENODEV or -EINVAL | |
101 | */ | |
102 | static int pcie_xilinx_read_config(struct udevice *bus, pci_dev_t bdf, | |
103 | uint offset, ulong *valuep, | |
104 | enum pci_size_t size) | |
105 | { | |
106 | struct xilinx_pcie *pcie = dev_get_priv(bus); | |
107 | void *address; | |
108 | int err; | |
109 | ||
110 | err = pcie_xilinx_config_address(pcie, bdf, offset, &address); | |
111 | if (err < 0) { | |
112 | *valuep = pci_get_ff(size); | |
113 | return 0; | |
114 | } | |
115 | ||
116 | switch (size) { | |
117 | case PCI_SIZE_8: | |
118 | *valuep = __raw_readb(address); | |
119 | return 0; | |
120 | case PCI_SIZE_16: | |
121 | *valuep = __raw_readw(address); | |
122 | return 0; | |
123 | case PCI_SIZE_32: | |
124 | *valuep = __raw_readl(address); | |
125 | return 0; | |
126 | default: | |
127 | return -EINVAL; | |
128 | } | |
129 | } | |
130 | ||
131 | /** | |
132 | * pcie_xilinx_write_config() - Write to configuration space | |
133 | * @pcie: Pointer to the PCI controller state | |
134 | * @bdf: Identifies the PCIe device to access | |
135 | * @offset: The offset into the device's configuration space | |
136 | * @value: The value to write | |
137 | * @size: Indicates the size of access to perform | |
138 | * | |
139 | * Write the value @value of size @size from offset @offset within the | |
140 | * configuration space of the device identified by the bus, device & function | |
141 | * numbers in @bdf on the PCI bus @bus. | |
142 | * | |
143 | * Return: 0 on success, else -ENODEV or -EINVAL | |
144 | */ | |
145 | static int pcie_xilinx_write_config(struct udevice *bus, pci_dev_t bdf, | |
146 | uint offset, ulong value, | |
147 | enum pci_size_t size) | |
148 | { | |
149 | struct xilinx_pcie *pcie = dev_get_priv(bus); | |
150 | void *address; | |
151 | int err; | |
152 | ||
153 | err = pcie_xilinx_config_address(pcie, bdf, offset, &address); | |
154 | if (err < 0) | |
155 | return 0; | |
156 | ||
157 | switch (size) { | |
158 | case PCI_SIZE_8: | |
159 | __raw_writeb(value, address); | |
160 | return 0; | |
161 | case PCI_SIZE_16: | |
162 | __raw_writew(value, address); | |
163 | return 0; | |
164 | case PCI_SIZE_32: | |
165 | __raw_writel(value, address); | |
166 | return 0; | |
167 | default: | |
168 | return -EINVAL; | |
169 | } | |
170 | } | |
171 | ||
172 | /** | |
173 | * pcie_xilinx_ofdata_to_platdata() - Translate from DT to device state | |
174 | * @dev: A pointer to the device being operated on | |
175 | * | |
176 | * Translate relevant data from the device tree pertaining to device @dev into | |
177 | * state that the driver will later make use of. This state is stored in the | |
178 | * device's private data structure. | |
179 | * | |
180 | * Return: 0 on success, else -EINVAL | |
181 | */ | |
182 | static int pcie_xilinx_ofdata_to_platdata(struct udevice *dev) | |
183 | { | |
184 | struct xilinx_pcie *pcie = dev_get_priv(dev); | |
185 | struct fdt_resource reg_res; | |
186 | DECLARE_GLOBAL_DATA_PTR; | |
187 | int err; | |
188 | ||
e160f7d4 | 189 | err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg", |
a29e45a9 PB |
190 | 0, ®_res); |
191 | if (err < 0) { | |
192 | error("\"reg\" resource not found\n"); | |
193 | return err; | |
194 | } | |
195 | ||
196 | pcie->cfg_base = map_physmem(reg_res.start, | |
197 | fdt_resource_size(®_res), | |
198 | MAP_NOCACHE); | |
199 | ||
200 | return 0; | |
201 | } | |
202 | ||
203 | static const struct dm_pci_ops pcie_xilinx_ops = { | |
204 | .read_config = pcie_xilinx_read_config, | |
205 | .write_config = pcie_xilinx_write_config, | |
206 | }; | |
207 | ||
208 | static const struct udevice_id pcie_xilinx_ids[] = { | |
209 | { .compatible = "xlnx,axi-pcie-host-1.00.a" }, | |
210 | { } | |
211 | }; | |
212 | ||
213 | U_BOOT_DRIVER(pcie_xilinx) = { | |
214 | .name = "pcie_xilinx", | |
215 | .id = UCLASS_PCI, | |
216 | .of_match = pcie_xilinx_ids, | |
217 | .ops = &pcie_xilinx_ops, | |
218 | .ofdata_to_platdata = pcie_xilinx_ofdata_to_platdata, | |
219 | .priv_auto_alloc_size = sizeof(struct xilinx_pcie), | |
220 | }; |