]>
Commit | Line | Data |
---|---|---|
3675cb04 TT |
1 | /* |
2 | * Generic PCIE host provided by e.g. QEMU | |
3 | * | |
4 | * Heavily based on drivers/pci/pcie_xilinx.c | |
5 | * | |
6 | * Copyright (C) 2016 Imagination Technologies | |
7 | * | |
8 | * SPDX-License-Identifier: GPL-2.0 | |
9 | */ | |
10 | ||
11 | #include <common.h> | |
12 | #include <dm.h> | |
13 | #include <pci.h> | |
14 | ||
15 | #include <asm/io.h> | |
16 | ||
17 | /** | |
18 | * struct generic_ecam_pcie - generic_ecam PCIe controller state | |
19 | * @cfg_base: The base address of memory mapped configuration space | |
20 | */ | |
21 | struct generic_ecam_pcie { | |
22 | void *cfg_base; | |
23 | }; | |
24 | ||
25 | /** | |
26 | * pci_generic_ecam_conf_address() - Calculate the address of a config access | |
27 | * @bus: Pointer to the PCI bus | |
28 | * @bdf: Identifies the PCIe device to access | |
29 | * @offset: The offset into the device's configuration space | |
30 | * @paddress: Pointer to the pointer to write the calculates address to | |
31 | * | |
32 | * Calculates the address that should be accessed to perform a PCIe | |
33 | * configuration space access for a given device identified by the PCIe | |
34 | * controller device @pcie and the bus, device & function numbers in @bdf. If | |
35 | * access to the device is not valid then the function will return an error | |
36 | * code. Otherwise the address to access will be written to the pointer pointed | |
37 | * to by @paddress. | |
38 | */ | |
39 | static int pci_generic_ecam_conf_address(struct udevice *bus, pci_dev_t bdf, | |
40 | uint offset, void **paddress) | |
41 | { | |
42 | struct generic_ecam_pcie *pcie = dev_get_priv(bus); | |
43 | void *addr; | |
44 | ||
45 | addr = pcie->cfg_base; | |
46 | addr += PCI_BUS(bdf) << 20; | |
47 | addr += PCI_DEV(bdf) << 15; | |
48 | addr += PCI_FUNC(bdf) << 12; | |
49 | addr += offset; | |
50 | *paddress = addr; | |
51 | ||
52 | return 0; | |
53 | } | |
54 | ||
55 | /** | |
56 | * pci_generic_ecam_read_config() - Read from configuration space | |
57 | * @bus: Pointer to the PCI bus | |
58 | * @bdf: Identifies the PCIe device to access | |
59 | * @offset: The offset into the device's configuration space | |
60 | * @valuep: A pointer at which to store the read value | |
61 | * @size: Indicates the size of access to perform | |
62 | * | |
63 | * Read a value of size @size from offset @offset within the configuration | |
64 | * space of the device identified by the bus, device & function numbers in @bdf | |
65 | * on the PCI bus @bus. | |
66 | */ | |
67 | static int pci_generic_ecam_read_config(struct udevice *bus, pci_dev_t bdf, | |
68 | uint offset, ulong *valuep, | |
69 | enum pci_size_t size) | |
70 | { | |
71 | return pci_generic_mmap_read_config(bus, pci_generic_ecam_conf_address, | |
72 | bdf, offset, valuep, size); | |
73 | } | |
74 | ||
75 | /** | |
76 | * pci_generic_ecam_write_config() - Write to configuration space | |
77 | * @bus: Pointer to the PCI bus | |
78 | * @bdf: Identifies the PCIe device to access | |
79 | * @offset: The offset into the device's configuration space | |
80 | * @value: The value to write | |
81 | * @size: Indicates the size of access to perform | |
82 | * | |
83 | * Write the value @value of size @size from offset @offset within the | |
84 | * configuration space of the device identified by the bus, device & function | |
85 | * numbers in @bdf on the PCI bus @bus. | |
86 | */ | |
87 | static int pci_generic_ecam_write_config(struct udevice *bus, pci_dev_t bdf, | |
88 | uint offset, ulong value, | |
89 | enum pci_size_t size) | |
90 | { | |
91 | return pci_generic_mmap_write_config(bus, pci_generic_ecam_conf_address, | |
92 | bdf, offset, value, size); | |
93 | } | |
94 | ||
95 | /** | |
96 | * pci_generic_ecam_ofdata_to_platdata() - Translate from DT to device state | |
97 | * @dev: A pointer to the device being operated on | |
98 | * | |
99 | * Translate relevant data from the device tree pertaining to device @dev into | |
100 | * state that the driver will later make use of. This state is stored in the | |
101 | * device's private data structure. | |
102 | * | |
103 | * Return: 0 on success, else -EINVAL | |
104 | */ | |
105 | static int pci_generic_ecam_ofdata_to_platdata(struct udevice *dev) | |
106 | { | |
107 | struct generic_ecam_pcie *pcie = dev_get_priv(dev); | |
108 | struct fdt_resource reg_res; | |
109 | DECLARE_GLOBAL_DATA_PTR; | |
110 | int err; | |
111 | ||
112 | err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg", | |
113 | 0, ®_res); | |
114 | if (err < 0) { | |
115 | pr_err("\"reg\" resource not found\n"); | |
116 | return err; | |
117 | } | |
118 | ||
119 | pcie->cfg_base = map_physmem(reg_res.start, | |
120 | fdt_resource_size(®_res), | |
121 | MAP_NOCACHE); | |
122 | ||
123 | return 0; | |
124 | } | |
125 | ||
126 | static const struct dm_pci_ops pci_generic_ecam_ops = { | |
127 | .read_config = pci_generic_ecam_read_config, | |
128 | .write_config = pci_generic_ecam_write_config, | |
129 | }; | |
130 | ||
131 | static const struct udevice_id pci_generic_ecam_ids[] = { | |
132 | { .compatible = "pci-host-ecam-generic" }, | |
133 | { } | |
134 | }; | |
135 | ||
136 | U_BOOT_DRIVER(pci_generic_ecam) = { | |
137 | .name = "pci_generic_ecam", | |
138 | .id = UCLASS_PCI, | |
139 | .of_match = pci_generic_ecam_ids, | |
140 | .ops = &pci_generic_ecam_ops, | |
141 | .ofdata_to_platdata = pci_generic_ecam_ofdata_to_platdata, | |
142 | .priv_auto_alloc_size = sizeof(struct generic_ecam_pcie), | |
143 | }; |