]>
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 | ||
d678a59d | 8 | #include <common.h> |
a29e45a9 PB |
9 | #include <dm.h> |
10 | #include <pci.h> | |
cd93d625 | 11 | #include <linux/bitops.h> |
1e94b46f | 12 | #include <linux/printk.h> |
891b4814 MC |
13 | #include <linux/io.h> |
14 | #include <linux/err.h> | |
a29e45a9 PB |
15 | |
16 | /** | |
17 | * struct xilinx_pcie - Xilinx PCIe controller state | |
a29e45a9 PB |
18 | * @cfg_base: The base address of memory mapped configuration space |
19 | */ | |
20 | struct xilinx_pcie { | |
a29e45a9 PB |
21 | void *cfg_base; |
22 | }; | |
23 | ||
24 | /* Register definitions */ | |
25 | #define XILINX_PCIE_REG_PSCR 0x144 | |
26 | #define XILINX_PCIE_REG_PSCR_LNKUP BIT(11) | |
a62b01de MC |
27 | #define XILINX_PCIE_REG_RPSC 0x148 |
28 | #define XILINX_PCIE_REG_RPSC_BEN BIT(0) | |
a29e45a9 PB |
29 | |
30 | /** | |
31 | * pcie_xilinx_link_up() - Check whether the PCIe link is up | |
32 | * @pcie: Pointer to the PCI controller state | |
33 | * | |
34 | * Checks whether the PCIe link for the given device is up or down. | |
35 | * | |
36 | * Return: true if the link is up, else false | |
37 | */ | |
38 | static bool pcie_xilinx_link_up(struct xilinx_pcie *pcie) | |
39 | { | |
40 | uint32_t pscr = __raw_readl(pcie->cfg_base + XILINX_PCIE_REG_PSCR); | |
41 | ||
42 | return pscr & XILINX_PCIE_REG_PSCR_LNKUP; | |
43 | } | |
44 | ||
45 | /** | |
46 | * pcie_xilinx_config_address() - Calculate the address of a config access | |
75e3feac | 47 | * @udev: Pointer to the PCI bus |
a29e45a9 PB |
48 | * @bdf: Identifies the PCIe device to access |
49 | * @offset: The offset into the device's configuration space | |
50 | * @paddress: Pointer to the pointer to write the calculates address to | |
51 | * | |
52 | * Calculates the address that should be accessed to perform a PCIe | |
53 | * configuration space access for a given device identified by the PCIe | |
54 | * controller device @pcie and the bus, device & function numbers in @bdf. If | |
55 | * access to the device is not valid then the function will return an error | |
56 | * code. Otherwise the address to access will be written to the pointer pointed | |
57 | * to by @paddress. | |
58 | * | |
59 | * Return: 0 on success, else -ENODEV | |
60 | */ | |
c4e72c4a | 61 | static int pcie_xilinx_config_address(const struct udevice *udev, pci_dev_t bdf, |
a29e45a9 PB |
62 | uint offset, void **paddress) |
63 | { | |
75e3feac | 64 | struct xilinx_pcie *pcie = dev_get_priv(udev); |
a29e45a9 PB |
65 | unsigned int bus = PCI_BUS(bdf); |
66 | unsigned int dev = PCI_DEV(bdf); | |
67 | unsigned int func = PCI_FUNC(bdf); | |
68 | void *addr; | |
69 | ||
70 | if ((bus > 0) && !pcie_xilinx_link_up(pcie)) | |
71 | return -ENODEV; | |
72 | ||
73 | /* | |
74 | * Busses 0 (host-PCIe bridge) & 1 (its immediate child) are | |
75 | * limited to a single device each. | |
76 | */ | |
77 | if ((bus < 2) && (dev > 0)) | |
78 | return -ENODEV; | |
79 | ||
80 | addr = pcie->cfg_base; | |
a4bc38da | 81 | addr += PCIE_ECAM_OFFSET(bus, dev, func, offset); |
a29e45a9 PB |
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 | */ | |
c4e72c4a | 101 | static int pcie_xilinx_read_config(const struct udevice *bus, pci_dev_t bdf, |
a29e45a9 PB |
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 | /** | |
d1998a9f | 132 | * pcie_xilinx_of_to_plat() - Translate from DT to device state |
a29e45a9 PB |
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 | */ | |
d1998a9f | 141 | static int pcie_xilinx_of_to_plat(struct udevice *dev) |
a29e45a9 PB |
142 | { |
143 | struct xilinx_pcie *pcie = dev_get_priv(dev); | |
891b4814 MC |
144 | fdt_addr_t addr; |
145 | fdt_size_t size; | |
a62b01de | 146 | u32 rpsc; |
891b4814 MC |
147 | |
148 | addr = dev_read_addr_size(dev, &size); | |
149 | if (addr == FDT_ADDR_T_NONE) | |
150 | return -EINVAL; | |
151 | ||
152 | pcie->cfg_base = devm_ioremap(dev, addr, size); | |
153 | if (IS_ERR(pcie->cfg_base)) | |
154 | return PTR_ERR(pcie->cfg_base); | |
a29e45a9 | 155 | |
a62b01de MC |
156 | /* Enable the Bridge enable bit */ |
157 | rpsc = __raw_readl(pcie->cfg_base + XILINX_PCIE_REG_RPSC); | |
158 | rpsc |= XILINX_PCIE_REG_RPSC_BEN; | |
159 | __raw_writel(rpsc, pcie->cfg_base + XILINX_PCIE_REG_RPSC); | |
160 | ||
a29e45a9 PB |
161 | return 0; |
162 | } | |
163 | ||
164 | static const struct dm_pci_ops pcie_xilinx_ops = { | |
165 | .read_config = pcie_xilinx_read_config, | |
166 | .write_config = pcie_xilinx_write_config, | |
167 | }; | |
168 | ||
169 | static const struct udevice_id pcie_xilinx_ids[] = { | |
170 | { .compatible = "xlnx,axi-pcie-host-1.00.a" }, | |
171 | { } | |
172 | }; | |
173 | ||
174 | U_BOOT_DRIVER(pcie_xilinx) = { | |
175 | .name = "pcie_xilinx", | |
176 | .id = UCLASS_PCI, | |
177 | .of_match = pcie_xilinx_ids, | |
178 | .ops = &pcie_xilinx_ops, | |
d1998a9f | 179 | .of_to_plat = pcie_xilinx_of_to_plat, |
41575d8e | 180 | .priv_auto = sizeof(struct xilinx_pcie), |
a29e45a9 | 181 | }; |