WS cleanup: remove SPACE(s) followed by TAB
[platform/kernel/u-boot.git] / drivers / pci / pcie_phytium.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Phytium PCIE host driver
4  *
5  * Heavily based on drivers/pci/pcie_xilinx.c
6  *
7  * Copyright (C) 2019
8  */
9
10 #include <common.h>
11 #include <dm.h>
12 #include <pci.h>
13 #include <asm/global_data.h>
14 #include <asm/io.h>
15
16 /**
17  * struct phytium_pcie - phytium PCIe controller state
18  * @cfg_base: The base address of memory mapped configuration space
19  */
20 struct phytium_pcie {
21         void *cfg_base;
22 };
23
24 /*
25  * phytium_pci_skip_dev()
26  * @parent: Identifies the PCIe device to access
27  *
28  * Checks whether the parent of the PCIe device is bridge
29  *
30  * Return: true if it is bridge, else false.
31  */
32 static int phytium_pci_skip_dev(pci_dev_t parent)
33 {
34         unsigned char pos, id;
35         unsigned long addr = 0x40000000;
36         unsigned short capreg;
37         unsigned char port_type;
38
39         addr += PCI_BUS(parent) << 20;
40         addr += PCI_DEV(parent) << 15;
41         addr += PCI_FUNC(parent) << 12;
42
43         pos = 0x34;
44         while (1) {
45                 pos = readb(addr + pos);
46                 if (pos < 0x40)
47                         break;
48                 pos &= ~3;
49                 id = readb(addr + pos);
50                 if (id == 0xff)
51                         break;
52                 if (id == 0x10) {
53                         capreg = readw(addr + pos + 2);
54                         port_type = (capreg >> 4) & 0xf;
55                         if (port_type == 0x6 || port_type == 0x4)
56                                 return 1;
57                         else
58                                 return 0;
59                 }
60                 pos += 1;
61         }
62         return 0;
63 }
64
65 /**
66  * pci_phytium_conf_address() - Calculate the address of a config access
67  * @bus: Pointer to the PCI bus
68  * @bdf: Identifies the PCIe device to access
69  * @offset: The offset into the device's configuration space
70  * @paddress: Pointer to the pointer to write the calculates address to
71  *
72  * Calculates the address that should be accessed to perform a PCIe
73  * configuration space access for a given device identified by the PCIe
74  * controller device @pcie and the bus, device & function numbers in @bdf. If
75  * access to the device is not valid then the function will return an error
76  * code. Otherwise the address to access will be written to the pointer pointed
77  * to by @paddress.
78  */
79 static int pci_phytium_conf_address(const struct udevice *bus, pci_dev_t bdf,
80                                     uint offset, void **paddress)
81 {
82         struct phytium_pcie *pcie = dev_get_priv(bus);
83         void *addr;
84         pci_dev_t bdf_parent;
85
86         unsigned int bus_no = PCI_BUS(bdf);
87         unsigned int dev_no = PCI_DEV(bdf);
88
89         bdf_parent = PCI_BDF((bus_no - 1), 0, 0);
90
91         addr = pcie->cfg_base;
92         addr += PCI_BUS(bdf) << 20;
93         addr += PCI_DEV(bdf) << 15;
94         addr += PCI_FUNC(bdf) << 12;
95
96         if (bus_no > 0 && dev_no > 0) {
97                 if ((readb(addr + PCI_HEADER_TYPE) & 0x7f) !=
98                                 PCI_HEADER_TYPE_BRIDGE)
99                         return -ENODEV;
100                 if (phytium_pci_skip_dev(bdf_parent))
101                         return -ENODEV;
102         }
103
104         addr += offset;
105         *paddress = addr;
106
107         return 0;
108 }
109
110 /**
111  * pci_phytium_read_config() - Read from configuration space
112  * @bus: Pointer to the PCI bus
113  * @bdf: Identifies the PCIe device to access
114  * @offset: The offset into the device's configuration space
115  * @valuep: A pointer at which to store the read value
116  * @size: Indicates the size of access to perform
117  *
118  * Read a value of size @size from offset @offset within the configuration
119  * space of the device identified by the bus, device & function numbers in @bdf
120  * on the PCI bus @bus.
121  */
122 static int pci_phytium_read_config(const struct udevice *bus, pci_dev_t bdf,
123                                    uint offset, ulong *valuep,
124                                    enum pci_size_t size)
125 {
126         return pci_generic_mmap_read_config(bus, pci_phytium_conf_address,
127                                             bdf, offset, valuep, size);
128 }
129
130 /**
131  * pci_phytium_write_config() - Write to configuration space
132  * @bus: Pointer to the PCI bus
133  * @bdf: Identifies the PCIe device to access
134  * @offset: The offset into the device's configuration space
135  * @value: The value to write
136  * @size: Indicates the size of access to perform
137  *
138  * Write the value @value of size @size from offset @offset within the
139  * configuration space of the device identified by the bus, device & function
140  * numbers in @bdf on the PCI bus @bus.
141  */
142 static int pci_phytium_write_config(struct udevice *bus, pci_dev_t bdf,
143                                     uint offset, ulong value,
144                                     enum pci_size_t size)
145 {
146         return pci_generic_mmap_write_config(bus, pci_phytium_conf_address,
147                                              bdf, offset, value, size);
148 }
149
150 /**
151  * pci_phytium_of_to_plat() - Translate from DT to device state
152  * @dev: A pointer to the device being operated on
153  *
154  * Translate relevant data from the device tree pertaining to device @dev into
155  * state that the driver will later make use of. This state is stored in the
156  * device's private data structure.
157  *
158  * Return: 0 on success, else -EINVAL
159  */
160 static int pci_phytium_of_to_plat(struct udevice *dev)
161 {
162         struct phytium_pcie *pcie = dev_get_priv(dev);
163         struct fdt_resource reg_res;
164
165         DECLARE_GLOBAL_DATA_PTR;
166
167         int err;
168
169         err = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg",
170                                0, &reg_res);
171         if (err < 0) {
172                 pr_err("\"reg\" resource not found\n");
173                 return err;
174         }
175
176         pcie->cfg_base = map_physmem(reg_res.start,
177                                      fdt_resource_size(&reg_res),
178                                      MAP_NOCACHE);
179
180         return 0;
181 }
182
183 static const struct dm_pci_ops pci_phytium_ops = {
184         .read_config    = pci_phytium_read_config,
185         .write_config   = pci_phytium_write_config,
186 };
187
188 static const struct udevice_id pci_phytium_ids[] = {
189         { .compatible = "phytium,pcie-host-1.0" },
190         { }
191 };
192
193 U_BOOT_DRIVER(pci_phytium) = {
194         .name                   = "pci_phytium",
195         .id                     = UCLASS_PCI,
196         .of_match               = pci_phytium_ids,
197         .ops                    = &pci_phytium_ops,
198         .of_to_plat     = pci_phytium_of_to_plat,
199         .priv_auto      = sizeof(struct phytium_pcie),
200 };