1 // SPDX-License-Identifier: GPL-2.0
3 * Phytium PCIE host driver
5 * Heavily based on drivers/pci/pcie_xilinx.c
12 #include <asm/global_data.h>
14 #include <linux/printk.h>
17 * struct phytium_pcie - phytium PCIe controller state
18 * @cfg_base: The base address of memory mapped configuration space
25 * phytium_pci_skip_dev()
26 * @parent: Identifies the PCIe device to access
28 * Checks whether the parent of the PCIe device is bridge
30 * Return: true if it is bridge, else false.
32 static int phytium_pci_skip_dev(pci_dev_t parent)
34 unsigned char pos, id;
35 unsigned long addr = 0x40000000;
36 unsigned short capreg;
37 unsigned char port_type;
39 addr += PCIE_ECAM_OFFSET(PCI_BUS(parent), PCI_DEV(parent), PCI_FUNC(parent), 0);
43 pos = readb(addr + pos);
47 id = readb(addr + pos);
51 capreg = readw(addr + pos + 2);
52 port_type = (capreg >> 4) & 0xf;
53 if (port_type == 0x6 || port_type == 0x4)
64 * pci_phytium_conf_address() - Calculate the address of a config access
65 * @bus: Pointer to the PCI bus
66 * @bdf: Identifies the PCIe device to access
67 * @offset: The offset into the device's configuration space
68 * @paddress: Pointer to the pointer to write the calculates address to
70 * Calculates the address that should be accessed to perform a PCIe
71 * configuration space access for a given device identified by the PCIe
72 * controller device @pcie and the bus, device & function numbers in @bdf. If
73 * access to the device is not valid then the function will return an error
74 * code. Otherwise the address to access will be written to the pointer pointed
77 static int pci_phytium_conf_address(const struct udevice *bus, pci_dev_t bdf,
78 uint offset, void **paddress)
80 struct phytium_pcie *pcie = dev_get_priv(bus);
84 unsigned int bus_no = PCI_BUS(bdf);
85 unsigned int dev_no = PCI_DEV(bdf);
87 bdf_parent = PCI_BDF((bus_no - 1), 0, 0);
89 addr = pcie->cfg_base;
90 addr += PCIE_ECAM_OFFSET(PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), 0);
92 if (bus_no > 0 && dev_no > 0) {
93 if ((readb(addr + PCI_HEADER_TYPE) & 0x7f) !=
94 PCI_HEADER_TYPE_BRIDGE)
96 if (phytium_pci_skip_dev(bdf_parent))
107 * pci_phytium_read_config() - Read from configuration space
108 * @bus: Pointer to the PCI bus
109 * @bdf: Identifies the PCIe device to access
110 * @offset: The offset into the device's configuration space
111 * @valuep: A pointer at which to store the read value
112 * @size: Indicates the size of access to perform
114 * Read a value of size @size from offset @offset within the configuration
115 * space of the device identified by the bus, device & function numbers in @bdf
116 * on the PCI bus @bus.
118 static int pci_phytium_read_config(const struct udevice *bus, pci_dev_t bdf,
119 uint offset, ulong *valuep,
120 enum pci_size_t size)
122 return pci_generic_mmap_read_config(bus, pci_phytium_conf_address,
123 bdf, offset, valuep, size);
127 * pci_phytium_write_config() - Write to configuration space
128 * @bus: Pointer to the PCI bus
129 * @bdf: Identifies the PCIe device to access
130 * @offset: The offset into the device's configuration space
131 * @value: The value to write
132 * @size: Indicates the size of access to perform
134 * Write the value @value of size @size from offset @offset within the
135 * configuration space of the device identified by the bus, device & function
136 * numbers in @bdf on the PCI bus @bus.
138 static int pci_phytium_write_config(struct udevice *bus, pci_dev_t bdf,
139 uint offset, ulong value,
140 enum pci_size_t size)
142 return pci_generic_mmap_write_config(bus, pci_phytium_conf_address,
143 bdf, offset, value, size);
147 * pci_phytium_of_to_plat() - Translate from DT to device state
148 * @dev: A pointer to the device being operated on
150 * Translate relevant data from the device tree pertaining to device @dev into
151 * state that the driver will later make use of. This state is stored in the
152 * device's private data structure.
154 * Return: 0 on success, else -EINVAL
156 static int pci_phytium_of_to_plat(struct udevice *dev)
158 struct phytium_pcie *pcie = dev_get_priv(dev);
159 struct fdt_resource reg_res;
161 DECLARE_GLOBAL_DATA_PTR;
165 err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg",
168 pr_err("\"reg\" resource not found\n");
172 pcie->cfg_base = map_physmem(reg_res.start,
173 fdt_resource_size(®_res),
179 static const struct dm_pci_ops pci_phytium_ops = {
180 .read_config = pci_phytium_read_config,
181 .write_config = pci_phytium_write_config,
184 static const struct udevice_id pci_phytium_ids[] = {
185 { .compatible = "phytium,pcie-host-1.0" },
189 U_BOOT_DRIVER(pci_phytium) = {
190 .name = "pci_phytium",
192 .of_match = pci_phytium_ids,
193 .ops = &pci_phytium_ops,
194 .of_to_plat = pci_phytium_of_to_plat,
195 .priv_auto = sizeof(struct phytium_pcie),