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