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