183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2ff3e077bSSimon Glass /*
3ff3e077bSSimon Glass * Copyright (c) 2014 Google, Inc
4ff3e077bSSimon Glass * Written by Simon Glass <sjg@chromium.org>
5ff3e077bSSimon Glass */
6ff3e077bSSimon Glass
7ff3e077bSSimon Glass #include <common.h>
8ff3e077bSSimon Glass #include <dm.h>
9ff3e077bSSimon Glass #include <errno.h>
10ff3e077bSSimon Glass #include <pci.h>
1121d1fe7eSSimon Glass #include <asm/io.h>
12ff3e077bSSimon Glass #include <dm/device-internal.h>
13bf501595SSimon Glass #include <dm/lists.h>
14348b744bSBin Meng #if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
15348b744bSBin Meng #include <asm/fsp/fsp_support.h>
16348b744bSBin Meng #endif
175e23b8b4SSimon Glass #include "pci_internal.h"
18ff3e077bSSimon Glass
19ff3e077bSSimon Glass DECLARE_GLOBAL_DATA_PTR;
20ff3e077bSSimon Glass
pci_get_bus(int busnum,struct udevice ** busp)21a6eb93b3SSimon Glass int pci_get_bus(int busnum, struct udevice **busp)
22983c6ba2SSimon Glass {
23983c6ba2SSimon Glass int ret;
24983c6ba2SSimon Glass
25983c6ba2SSimon Glass ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, busp);
26983c6ba2SSimon Glass
27983c6ba2SSimon Glass /* Since buses may not be numbered yet try a little harder with bus 0 */
28983c6ba2SSimon Glass if (ret == -ENODEV) {
293f603cbbSSimon Glass ret = uclass_first_device_err(UCLASS_PCI, busp);
30983c6ba2SSimon Glass if (ret)
31983c6ba2SSimon Glass return ret;
32983c6ba2SSimon Glass ret = uclass_get_device_by_seq(UCLASS_PCI, busnum, busp);
33983c6ba2SSimon Glass }
34983c6ba2SSimon Glass
35983c6ba2SSimon Glass return ret;
36983c6ba2SSimon Glass }
37983c6ba2SSimon Glass
pci_get_controller(struct udevice * dev)389f60fb0dSSimon Glass struct udevice *pci_get_controller(struct udevice *dev)
399f60fb0dSSimon Glass {
409f60fb0dSSimon Glass while (device_is_on_pci_bus(dev))
419f60fb0dSSimon Glass dev = dev->parent;
429f60fb0dSSimon Glass
439f60fb0dSSimon Glass return dev;
449f60fb0dSSimon Glass }
459f60fb0dSSimon Glass
dm_pci_get_bdf(struct udevice * dev)4621ccce1bSSimon Glass pci_dev_t dm_pci_get_bdf(struct udevice *dev)
474b515e4fSSimon Glass {
484b515e4fSSimon Glass struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
494b515e4fSSimon Glass struct udevice *bus = dev->parent;
504b515e4fSSimon Glass
514b515e4fSSimon Glass return PCI_ADD_BUS(bus->seq, pplat->devfn);
524b515e4fSSimon Glass }
534b515e4fSSimon Glass
54ff3e077bSSimon Glass /**
55ff3e077bSSimon Glass * pci_get_bus_max() - returns the bus number of the last active bus
56ff3e077bSSimon Glass *
57ff3e077bSSimon Glass * @return last bus number, or -1 if no active buses
58ff3e077bSSimon Glass */
pci_get_bus_max(void)59ff3e077bSSimon Glass static int pci_get_bus_max(void)
60ff3e077bSSimon Glass {
61ff3e077bSSimon Glass struct udevice *bus;
62ff3e077bSSimon Glass struct uclass *uc;
63ff3e077bSSimon Glass int ret = -1;
64ff3e077bSSimon Glass
65ff3e077bSSimon Glass ret = uclass_get(UCLASS_PCI, &uc);
66ff3e077bSSimon Glass uclass_foreach_dev(bus, uc) {
67ff3e077bSSimon Glass if (bus->seq > ret)
68ff3e077bSSimon Glass ret = bus->seq;
69ff3e077bSSimon Glass }
70ff3e077bSSimon Glass
71ff3e077bSSimon Glass debug("%s: ret=%d\n", __func__, ret);
72ff3e077bSSimon Glass
73ff3e077bSSimon Glass return ret;
74ff3e077bSSimon Glass }
75ff3e077bSSimon Glass
pci_last_busno(void)76ff3e077bSSimon Glass int pci_last_busno(void)
77ff3e077bSSimon Glass {
78069155cbSBin Meng return pci_get_bus_max();
79ff3e077bSSimon Glass }
80ff3e077bSSimon Glass
pci_get_ff(enum pci_size_t size)81ff3e077bSSimon Glass int pci_get_ff(enum pci_size_t size)
82ff3e077bSSimon Glass {
83ff3e077bSSimon Glass switch (size) {
84ff3e077bSSimon Glass case PCI_SIZE_8:
85ff3e077bSSimon Glass return 0xff;
86ff3e077bSSimon Glass case PCI_SIZE_16:
87ff3e077bSSimon Glass return 0xffff;
88ff3e077bSSimon Glass default:
89ff3e077bSSimon Glass return 0xffffffff;
90ff3e077bSSimon Glass }
91ff3e077bSSimon Glass }
92ff3e077bSSimon Glass
pci_dev_find_ofnode(struct udevice * bus,phys_addr_t bdf,ofnode * rnode)9302e4d38dSMarek Vasut static void pci_dev_find_ofnode(struct udevice *bus, phys_addr_t bdf,
9402e4d38dSMarek Vasut ofnode *rnode)
9502e4d38dSMarek Vasut {
9602e4d38dSMarek Vasut struct fdt_pci_addr addr;
9702e4d38dSMarek Vasut ofnode node;
9802e4d38dSMarek Vasut int ret;
9902e4d38dSMarek Vasut
10002e4d38dSMarek Vasut dev_for_each_subnode(node, bus) {
10102e4d38dSMarek Vasut ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg",
10202e4d38dSMarek Vasut &addr);
10302e4d38dSMarek Vasut if (ret)
10402e4d38dSMarek Vasut continue;
10502e4d38dSMarek Vasut
10602e4d38dSMarek Vasut if (PCI_MASK_BUS(addr.phys_hi) != PCI_MASK_BUS(bdf))
10702e4d38dSMarek Vasut continue;
10802e4d38dSMarek Vasut
10902e4d38dSMarek Vasut *rnode = node;
11002e4d38dSMarek Vasut break;
11102e4d38dSMarek Vasut }
11202e4d38dSMarek Vasut };
11302e4d38dSMarek Vasut
pci_bus_find_devfn(struct udevice * bus,pci_dev_t find_devfn,struct udevice ** devp)114ff3e077bSSimon Glass int pci_bus_find_devfn(struct udevice *bus, pci_dev_t find_devfn,
115ff3e077bSSimon Glass struct udevice **devp)
116ff3e077bSSimon Glass {
117ff3e077bSSimon Glass struct udevice *dev;
118ff3e077bSSimon Glass
119ff3e077bSSimon Glass for (device_find_first_child(bus, &dev);
120ff3e077bSSimon Glass dev;
121ff3e077bSSimon Glass device_find_next_child(&dev)) {
122ff3e077bSSimon Glass struct pci_child_platdata *pplat;
123ff3e077bSSimon Glass
124ff3e077bSSimon Glass pplat = dev_get_parent_platdata(dev);
125ff3e077bSSimon Glass if (pplat && pplat->devfn == find_devfn) {
126ff3e077bSSimon Glass *devp = dev;
127ff3e077bSSimon Glass return 0;
128ff3e077bSSimon Glass }
129ff3e077bSSimon Glass }
130ff3e077bSSimon Glass
131ff3e077bSSimon Glass return -ENODEV;
132ff3e077bSSimon Glass }
133ff3e077bSSimon Glass
dm_pci_bus_find_bdf(pci_dev_t bdf,struct udevice ** devp)134f3f1faefSSimon Glass int dm_pci_bus_find_bdf(pci_dev_t bdf, struct udevice **devp)
135ff3e077bSSimon Glass {
136ff3e077bSSimon Glass struct udevice *bus;
137ff3e077bSSimon Glass int ret;
138ff3e077bSSimon Glass
139983c6ba2SSimon Glass ret = pci_get_bus(PCI_BUS(bdf), &bus);
140ff3e077bSSimon Glass if (ret)
141ff3e077bSSimon Glass return ret;
142ff3e077bSSimon Glass return pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), devp);
143ff3e077bSSimon Glass }
144ff3e077bSSimon Glass
pci_device_matches_ids(struct udevice * dev,struct pci_device_id * ids)145ff3e077bSSimon Glass static int pci_device_matches_ids(struct udevice *dev,
146ff3e077bSSimon Glass struct pci_device_id *ids)
147ff3e077bSSimon Glass {
148ff3e077bSSimon Glass struct pci_child_platdata *pplat;
149ff3e077bSSimon Glass int i;
150ff3e077bSSimon Glass
151ff3e077bSSimon Glass pplat = dev_get_parent_platdata(dev);
152ff3e077bSSimon Glass if (!pplat)
153ff3e077bSSimon Glass return -EINVAL;
154ff3e077bSSimon Glass for (i = 0; ids[i].vendor != 0; i++) {
155ff3e077bSSimon Glass if (pplat->vendor == ids[i].vendor &&
156ff3e077bSSimon Glass pplat->device == ids[i].device)
157ff3e077bSSimon Glass return i;
158ff3e077bSSimon Glass }
159ff3e077bSSimon Glass
160ff3e077bSSimon Glass return -EINVAL;
161ff3e077bSSimon Glass }
162ff3e077bSSimon Glass
pci_bus_find_devices(struct udevice * bus,struct pci_device_id * ids,int * indexp,struct udevice ** devp)163ff3e077bSSimon Glass int pci_bus_find_devices(struct udevice *bus, struct pci_device_id *ids,
164ff3e077bSSimon Glass int *indexp, struct udevice **devp)
165ff3e077bSSimon Glass {
166ff3e077bSSimon Glass struct udevice *dev;
167ff3e077bSSimon Glass
168ff3e077bSSimon Glass /* Scan all devices on this bus */
169ff3e077bSSimon Glass for (device_find_first_child(bus, &dev);
170ff3e077bSSimon Glass dev;
171ff3e077bSSimon Glass device_find_next_child(&dev)) {
172ff3e077bSSimon Glass if (pci_device_matches_ids(dev, ids) >= 0) {
173ff3e077bSSimon Glass if ((*indexp)-- <= 0) {
174ff3e077bSSimon Glass *devp = dev;
175ff3e077bSSimon Glass return 0;
176ff3e077bSSimon Glass }
177ff3e077bSSimon Glass }
178ff3e077bSSimon Glass }
179ff3e077bSSimon Glass
180ff3e077bSSimon Glass return -ENODEV;
181ff3e077bSSimon Glass }
182ff3e077bSSimon Glass
pci_find_device_id(struct pci_device_id * ids,int index,struct udevice ** devp)183ff3e077bSSimon Glass int pci_find_device_id(struct pci_device_id *ids, int index,
184ff3e077bSSimon Glass struct udevice **devp)
185ff3e077bSSimon Glass {
186ff3e077bSSimon Glass struct udevice *bus;
187ff3e077bSSimon Glass
188ff3e077bSSimon Glass /* Scan all known buses */
189ff3e077bSSimon Glass for (uclass_first_device(UCLASS_PCI, &bus);
190ff3e077bSSimon Glass bus;
191ff3e077bSSimon Glass uclass_next_device(&bus)) {
192ff3e077bSSimon Glass if (!pci_bus_find_devices(bus, ids, &index, devp))
193ff3e077bSSimon Glass return 0;
194ff3e077bSSimon Glass }
195ff3e077bSSimon Glass *devp = NULL;
196ff3e077bSSimon Glass
197ff3e077bSSimon Glass return -ENODEV;
198ff3e077bSSimon Glass }
199ff3e077bSSimon Glass
dm_pci_bus_find_device(struct udevice * bus,unsigned int vendor,unsigned int device,int * indexp,struct udevice ** devp)2005c0bf647SSimon Glass static int dm_pci_bus_find_device(struct udevice *bus, unsigned int vendor,
2015c0bf647SSimon Glass unsigned int device, int *indexp,
2025c0bf647SSimon Glass struct udevice **devp)
2035c0bf647SSimon Glass {
2045c0bf647SSimon Glass struct pci_child_platdata *pplat;
2055c0bf647SSimon Glass struct udevice *dev;
2065c0bf647SSimon Glass
2075c0bf647SSimon Glass for (device_find_first_child(bus, &dev);
2085c0bf647SSimon Glass dev;
2095c0bf647SSimon Glass device_find_next_child(&dev)) {
2105c0bf647SSimon Glass pplat = dev_get_parent_platdata(dev);
2115c0bf647SSimon Glass if (pplat->vendor == vendor && pplat->device == device) {
2125c0bf647SSimon Glass if (!(*indexp)--) {
2135c0bf647SSimon Glass *devp = dev;
2145c0bf647SSimon Glass return 0;
2155c0bf647SSimon Glass }
2165c0bf647SSimon Glass }
2175c0bf647SSimon Glass }
2185c0bf647SSimon Glass
2195c0bf647SSimon Glass return -ENODEV;
2205c0bf647SSimon Glass }
2215c0bf647SSimon Glass
dm_pci_find_device(unsigned int vendor,unsigned int device,int index,struct udevice ** devp)2225c0bf647SSimon Glass int dm_pci_find_device(unsigned int vendor, unsigned int device, int index,
2235c0bf647SSimon Glass struct udevice **devp)
2245c0bf647SSimon Glass {
2255c0bf647SSimon Glass struct udevice *bus;
2265c0bf647SSimon Glass
2275c0bf647SSimon Glass /* Scan all known buses */
2285c0bf647SSimon Glass for (uclass_first_device(UCLASS_PCI, &bus);
2295c0bf647SSimon Glass bus;
2305c0bf647SSimon Glass uclass_next_device(&bus)) {
2315c0bf647SSimon Glass if (!dm_pci_bus_find_device(bus, vendor, device, &index, devp))
2325c0bf647SSimon Glass return device_probe(*devp);
2335c0bf647SSimon Glass }
2345c0bf647SSimon Glass *devp = NULL;
2355c0bf647SSimon Glass
2365c0bf647SSimon Glass return -ENODEV;
2375c0bf647SSimon Glass }
2385c0bf647SSimon Glass
dm_pci_find_class(uint find_class,int index,struct udevice ** devp)239a0eb8356SSimon Glass int dm_pci_find_class(uint find_class, int index, struct udevice **devp)
240a0eb8356SSimon Glass {
241a0eb8356SSimon Glass struct udevice *dev;
242a0eb8356SSimon Glass
243a0eb8356SSimon Glass /* Scan all known buses */
244a0eb8356SSimon Glass for (pci_find_first_device(&dev);
245a0eb8356SSimon Glass dev;
246a0eb8356SSimon Glass pci_find_next_device(&dev)) {
247a0eb8356SSimon Glass struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
248a0eb8356SSimon Glass
249a0eb8356SSimon Glass if (pplat->class == find_class && !index--) {
250a0eb8356SSimon Glass *devp = dev;
251a0eb8356SSimon Glass return device_probe(*devp);
252a0eb8356SSimon Glass }
253a0eb8356SSimon Glass }
254a0eb8356SSimon Glass *devp = NULL;
255a0eb8356SSimon Glass
256a0eb8356SSimon Glass return -ENODEV;
257a0eb8356SSimon Glass }
258a0eb8356SSimon Glass
pci_bus_write_config(struct udevice * bus,pci_dev_t bdf,int offset,unsigned long value,enum pci_size_t size)259ff3e077bSSimon Glass int pci_bus_write_config(struct udevice *bus, pci_dev_t bdf, int offset,
260ff3e077bSSimon Glass unsigned long value, enum pci_size_t size)
261ff3e077bSSimon Glass {
262ff3e077bSSimon Glass struct dm_pci_ops *ops;
263ff3e077bSSimon Glass
264ff3e077bSSimon Glass ops = pci_get_ops(bus);
265ff3e077bSSimon Glass if (!ops->write_config)
266ff3e077bSSimon Glass return -ENOSYS;
267ff3e077bSSimon Glass return ops->write_config(bus, bdf, offset, value, size);
268ff3e077bSSimon Glass }
269ff3e077bSSimon Glass
pci_bus_clrset_config32(struct udevice * bus,pci_dev_t bdf,int offset,u32 clr,u32 set)270319dba1fSSimon Glass int pci_bus_clrset_config32(struct udevice *bus, pci_dev_t bdf, int offset,
271319dba1fSSimon Glass u32 clr, u32 set)
272319dba1fSSimon Glass {
273319dba1fSSimon Glass ulong val;
274319dba1fSSimon Glass int ret;
275319dba1fSSimon Glass
276319dba1fSSimon Glass ret = pci_bus_read_config(bus, bdf, offset, &val, PCI_SIZE_32);
277319dba1fSSimon Glass if (ret)
278319dba1fSSimon Glass return ret;
279319dba1fSSimon Glass val &= ~clr;
280319dba1fSSimon Glass val |= set;
281319dba1fSSimon Glass
282319dba1fSSimon Glass return pci_bus_write_config(bus, bdf, offset, val, PCI_SIZE_32);
283319dba1fSSimon Glass }
284319dba1fSSimon Glass
pci_write_config(pci_dev_t bdf,int offset,unsigned long value,enum pci_size_t size)285ff3e077bSSimon Glass int pci_write_config(pci_dev_t bdf, int offset, unsigned long value,
286ff3e077bSSimon Glass enum pci_size_t size)
287ff3e077bSSimon Glass {
288ff3e077bSSimon Glass struct udevice *bus;
289ff3e077bSSimon Glass int ret;
290ff3e077bSSimon Glass
291983c6ba2SSimon Glass ret = pci_get_bus(PCI_BUS(bdf), &bus);
292ff3e077bSSimon Glass if (ret)
293ff3e077bSSimon Glass return ret;
294ff3e077bSSimon Glass
2954d8615cbSBin Meng return pci_bus_write_config(bus, bdf, offset, value, size);
296ff3e077bSSimon Glass }
297ff3e077bSSimon Glass
dm_pci_write_config(struct udevice * dev,int offset,unsigned long value,enum pci_size_t size)29866afb4edSSimon Glass int dm_pci_write_config(struct udevice *dev, int offset, unsigned long value,
29966afb4edSSimon Glass enum pci_size_t size)
30066afb4edSSimon Glass {
30166afb4edSSimon Glass struct udevice *bus;
30266afb4edSSimon Glass
3031e0f2263SBin Meng for (bus = dev; device_is_on_pci_bus(bus);)
30466afb4edSSimon Glass bus = bus->parent;
30521ccce1bSSimon Glass return pci_bus_write_config(bus, dm_pci_get_bdf(dev), offset, value,
30621ccce1bSSimon Glass size);
30766afb4edSSimon Glass }
30866afb4edSSimon Glass
pci_write_config32(pci_dev_t bdf,int offset,u32 value)309ff3e077bSSimon Glass int pci_write_config32(pci_dev_t bdf, int offset, u32 value)
310ff3e077bSSimon Glass {
311ff3e077bSSimon Glass return pci_write_config(bdf, offset, value, PCI_SIZE_32);
312ff3e077bSSimon Glass }
313ff3e077bSSimon Glass
pci_write_config16(pci_dev_t bdf,int offset,u16 value)314ff3e077bSSimon Glass int pci_write_config16(pci_dev_t bdf, int offset, u16 value)
315ff3e077bSSimon Glass {
316ff3e077bSSimon Glass return pci_write_config(bdf, offset, value, PCI_SIZE_16);
317ff3e077bSSimon Glass }
318ff3e077bSSimon Glass
pci_write_config8(pci_dev_t bdf,int offset,u8 value)319ff3e077bSSimon Glass int pci_write_config8(pci_dev_t bdf, int offset, u8 value)
320ff3e077bSSimon Glass {
321ff3e077bSSimon Glass return pci_write_config(bdf, offset, value, PCI_SIZE_8);
322ff3e077bSSimon Glass }
323ff3e077bSSimon Glass
dm_pci_write_config8(struct udevice * dev,int offset,u8 value)32466afb4edSSimon Glass int dm_pci_write_config8(struct udevice *dev, int offset, u8 value)
32566afb4edSSimon Glass {
32666afb4edSSimon Glass return dm_pci_write_config(dev, offset, value, PCI_SIZE_8);
32766afb4edSSimon Glass }
32866afb4edSSimon Glass
dm_pci_write_config16(struct udevice * dev,int offset,u16 value)32966afb4edSSimon Glass int dm_pci_write_config16(struct udevice *dev, int offset, u16 value)
33066afb4edSSimon Glass {
33166afb4edSSimon Glass return dm_pci_write_config(dev, offset, value, PCI_SIZE_16);
33266afb4edSSimon Glass }
33366afb4edSSimon Glass
dm_pci_write_config32(struct udevice * dev,int offset,u32 value)33466afb4edSSimon Glass int dm_pci_write_config32(struct udevice *dev, int offset, u32 value)
33566afb4edSSimon Glass {
33666afb4edSSimon Glass return dm_pci_write_config(dev, offset, value, PCI_SIZE_32);
33766afb4edSSimon Glass }
33866afb4edSSimon Glass
pci_bus_read_config(struct udevice * bus,pci_dev_t bdf,int offset,unsigned long * valuep,enum pci_size_t size)339ff3e077bSSimon Glass int pci_bus_read_config(struct udevice *bus, pci_dev_t bdf, int offset,
340ff3e077bSSimon Glass unsigned long *valuep, enum pci_size_t size)
341ff3e077bSSimon Glass {
342ff3e077bSSimon Glass struct dm_pci_ops *ops;
343ff3e077bSSimon Glass
344ff3e077bSSimon Glass ops = pci_get_ops(bus);
345ff3e077bSSimon Glass if (!ops->read_config)
346ff3e077bSSimon Glass return -ENOSYS;
347ff3e077bSSimon Glass return ops->read_config(bus, bdf, offset, valuep, size);
348ff3e077bSSimon Glass }
349ff3e077bSSimon Glass
pci_read_config(pci_dev_t bdf,int offset,unsigned long * valuep,enum pci_size_t size)350ff3e077bSSimon Glass int pci_read_config(pci_dev_t bdf, int offset, unsigned long *valuep,
351ff3e077bSSimon Glass enum pci_size_t size)
352ff3e077bSSimon Glass {
353ff3e077bSSimon Glass struct udevice *bus;
354ff3e077bSSimon Glass int ret;
355ff3e077bSSimon Glass
356983c6ba2SSimon Glass ret = pci_get_bus(PCI_BUS(bdf), &bus);
357ff3e077bSSimon Glass if (ret)
358ff3e077bSSimon Glass return ret;
359ff3e077bSSimon Glass
3604d8615cbSBin Meng return pci_bus_read_config(bus, bdf, offset, valuep, size);
361ff3e077bSSimon Glass }
362ff3e077bSSimon Glass
dm_pci_read_config(struct udevice * dev,int offset,unsigned long * valuep,enum pci_size_t size)36366afb4edSSimon Glass int dm_pci_read_config(struct udevice *dev, int offset, unsigned long *valuep,
36466afb4edSSimon Glass enum pci_size_t size)
36566afb4edSSimon Glass {
36666afb4edSSimon Glass struct udevice *bus;
36766afb4edSSimon Glass
3681e0f2263SBin Meng for (bus = dev; device_is_on_pci_bus(bus);)
36966afb4edSSimon Glass bus = bus->parent;
37021ccce1bSSimon Glass return pci_bus_read_config(bus, dm_pci_get_bdf(dev), offset, valuep,
37166afb4edSSimon Glass size);
37266afb4edSSimon Glass }
37366afb4edSSimon Glass
pci_read_config32(pci_dev_t bdf,int offset,u32 * valuep)374ff3e077bSSimon Glass int pci_read_config32(pci_dev_t bdf, int offset, u32 *valuep)
375ff3e077bSSimon Glass {
376ff3e077bSSimon Glass unsigned long value;
377ff3e077bSSimon Glass int ret;
378ff3e077bSSimon Glass
379ff3e077bSSimon Glass ret = pci_read_config(bdf, offset, &value, PCI_SIZE_32);
380ff3e077bSSimon Glass if (ret)
381ff3e077bSSimon Glass return ret;
382ff3e077bSSimon Glass *valuep = value;
383ff3e077bSSimon Glass
384ff3e077bSSimon Glass return 0;
385ff3e077bSSimon Glass }
386ff3e077bSSimon Glass
pci_read_config16(pci_dev_t bdf,int offset,u16 * valuep)387ff3e077bSSimon Glass int pci_read_config16(pci_dev_t bdf, int offset, u16 *valuep)
388ff3e077bSSimon Glass {
389ff3e077bSSimon Glass unsigned long value;
390ff3e077bSSimon Glass int ret;
391ff3e077bSSimon Glass
392ff3e077bSSimon Glass ret = pci_read_config(bdf, offset, &value, PCI_SIZE_16);
393ff3e077bSSimon Glass if (ret)
394ff3e077bSSimon Glass return ret;
395ff3e077bSSimon Glass *valuep = value;
396ff3e077bSSimon Glass
397ff3e077bSSimon Glass return 0;
398ff3e077bSSimon Glass }
399ff3e077bSSimon Glass
pci_read_config8(pci_dev_t bdf,int offset,u8 * valuep)400ff3e077bSSimon Glass int pci_read_config8(pci_dev_t bdf, int offset, u8 *valuep)
401ff3e077bSSimon Glass {
402ff3e077bSSimon Glass unsigned long value;
403ff3e077bSSimon Glass int ret;
404ff3e077bSSimon Glass
405ff3e077bSSimon Glass ret = pci_read_config(bdf, offset, &value, PCI_SIZE_8);
406ff3e077bSSimon Glass if (ret)
407ff3e077bSSimon Glass return ret;
408ff3e077bSSimon Glass *valuep = value;
409ff3e077bSSimon Glass
410ff3e077bSSimon Glass return 0;
411ff3e077bSSimon Glass }
412ff3e077bSSimon Glass
dm_pci_read_config8(struct udevice * dev,int offset,u8 * valuep)41366afb4edSSimon Glass int dm_pci_read_config8(struct udevice *dev, int offset, u8 *valuep)
41466afb4edSSimon Glass {
41566afb4edSSimon Glass unsigned long value;
41666afb4edSSimon Glass int ret;
41766afb4edSSimon Glass
41866afb4edSSimon Glass ret = dm_pci_read_config(dev, offset, &value, PCI_SIZE_8);
41966afb4edSSimon Glass if (ret)
42066afb4edSSimon Glass return ret;
42166afb4edSSimon Glass *valuep = value;
42266afb4edSSimon Glass
42366afb4edSSimon Glass return 0;
42466afb4edSSimon Glass }
42566afb4edSSimon Glass
dm_pci_read_config16(struct udevice * dev,int offset,u16 * valuep)42666afb4edSSimon Glass int dm_pci_read_config16(struct udevice *dev, int offset, u16 *valuep)
42766afb4edSSimon Glass {
42866afb4edSSimon Glass unsigned long value;
42966afb4edSSimon Glass int ret;
43066afb4edSSimon Glass
43166afb4edSSimon Glass ret = dm_pci_read_config(dev, offset, &value, PCI_SIZE_16);
43266afb4edSSimon Glass if (ret)
43366afb4edSSimon Glass return ret;
43466afb4edSSimon Glass *valuep = value;
43566afb4edSSimon Glass
43666afb4edSSimon Glass return 0;
43766afb4edSSimon Glass }
43866afb4edSSimon Glass
dm_pci_read_config32(struct udevice * dev,int offset,u32 * valuep)43966afb4edSSimon Glass int dm_pci_read_config32(struct udevice *dev, int offset, u32 *valuep)
44066afb4edSSimon Glass {
44166afb4edSSimon Glass unsigned long value;
44266afb4edSSimon Glass int ret;
44366afb4edSSimon Glass
44466afb4edSSimon Glass ret = dm_pci_read_config(dev, offset, &value, PCI_SIZE_32);
44566afb4edSSimon Glass if (ret)
44666afb4edSSimon Glass return ret;
44766afb4edSSimon Glass *valuep = value;
44866afb4edSSimon Glass
44966afb4edSSimon Glass return 0;
45066afb4edSSimon Glass }
45166afb4edSSimon Glass
dm_pci_clrset_config8(struct udevice * dev,int offset,u32 clr,u32 set)452319dba1fSSimon Glass int dm_pci_clrset_config8(struct udevice *dev, int offset, u32 clr, u32 set)
453319dba1fSSimon Glass {
454319dba1fSSimon Glass u8 val;
455319dba1fSSimon Glass int ret;
456319dba1fSSimon Glass
457319dba1fSSimon Glass ret = dm_pci_read_config8(dev, offset, &val);
458319dba1fSSimon Glass if (ret)
459319dba1fSSimon Glass return ret;
460319dba1fSSimon Glass val &= ~clr;
461319dba1fSSimon Glass val |= set;
462319dba1fSSimon Glass
463319dba1fSSimon Glass return dm_pci_write_config8(dev, offset, val);
464319dba1fSSimon Glass }
465319dba1fSSimon Glass
dm_pci_clrset_config16(struct udevice * dev,int offset,u32 clr,u32 set)466319dba1fSSimon Glass int dm_pci_clrset_config16(struct udevice *dev, int offset, u32 clr, u32 set)
467319dba1fSSimon Glass {
468319dba1fSSimon Glass u16 val;
469319dba1fSSimon Glass int ret;
470319dba1fSSimon Glass
471319dba1fSSimon Glass ret = dm_pci_read_config16(dev, offset, &val);
472319dba1fSSimon Glass if (ret)
473319dba1fSSimon Glass return ret;
474319dba1fSSimon Glass val &= ~clr;
475319dba1fSSimon Glass val |= set;
476319dba1fSSimon Glass
477319dba1fSSimon Glass return dm_pci_write_config16(dev, offset, val);
478319dba1fSSimon Glass }
479319dba1fSSimon Glass
dm_pci_clrset_config32(struct udevice * dev,int offset,u32 clr,u32 set)480319dba1fSSimon Glass int dm_pci_clrset_config32(struct udevice *dev, int offset, u32 clr, u32 set)
481319dba1fSSimon Glass {
482319dba1fSSimon Glass u32 val;
483319dba1fSSimon Glass int ret;
484319dba1fSSimon Glass
485319dba1fSSimon Glass ret = dm_pci_read_config32(dev, offset, &val);
486319dba1fSSimon Glass if (ret)
487319dba1fSSimon Glass return ret;
488319dba1fSSimon Glass val &= ~clr;
489319dba1fSSimon Glass val |= set;
490319dba1fSSimon Glass
491319dba1fSSimon Glass return dm_pci_write_config32(dev, offset, val);
492319dba1fSSimon Glass }
493319dba1fSSimon Glass
set_vga_bridge_bits(struct udevice * dev)494bbbcb526SBin Meng static void set_vga_bridge_bits(struct udevice *dev)
495bbbcb526SBin Meng {
496bbbcb526SBin Meng struct udevice *parent = dev->parent;
497bbbcb526SBin Meng u16 bc;
498bbbcb526SBin Meng
499bbbcb526SBin Meng while (parent->seq != 0) {
500bbbcb526SBin Meng dm_pci_read_config16(parent, PCI_BRIDGE_CONTROL, &bc);
501bbbcb526SBin Meng bc |= PCI_BRIDGE_CTL_VGA;
502bbbcb526SBin Meng dm_pci_write_config16(parent, PCI_BRIDGE_CONTROL, bc);
503bbbcb526SBin Meng parent = parent->parent;
504bbbcb526SBin Meng }
505bbbcb526SBin Meng }
506bbbcb526SBin Meng
pci_auto_config_devices(struct udevice * bus)507ff3e077bSSimon Glass int pci_auto_config_devices(struct udevice *bus)
508ff3e077bSSimon Glass {
509ff3e077bSSimon Glass struct pci_controller *hose = bus->uclass_priv;
510bbbcb526SBin Meng struct pci_child_platdata *pplat;
511ff3e077bSSimon Glass unsigned int sub_bus;
512ff3e077bSSimon Glass struct udevice *dev;
513ff3e077bSSimon Glass int ret;
514ff3e077bSSimon Glass
515ff3e077bSSimon Glass sub_bus = bus->seq;
516ff3e077bSSimon Glass debug("%s: start\n", __func__);
517ff3e077bSSimon Glass pciauto_config_init(hose);
518ff3e077bSSimon Glass for (ret = device_find_first_child(bus, &dev);
519ff3e077bSSimon Glass !ret && dev;
520ff3e077bSSimon Glass ret = device_find_next_child(&dev)) {
521ff3e077bSSimon Glass unsigned int max_bus;
5224d21455eSSimon Glass int ret;
523ff3e077bSSimon Glass
524ff3e077bSSimon Glass debug("%s: device %s\n", __func__, dev->name);
5255e23b8b4SSimon Glass ret = dm_pciauto_config_device(dev);
5264d21455eSSimon Glass if (ret < 0)
5274d21455eSSimon Glass return ret;
5284d21455eSSimon Glass max_bus = ret;
529ff3e077bSSimon Glass sub_bus = max(sub_bus, max_bus);
530bbbcb526SBin Meng
531bbbcb526SBin Meng pplat = dev_get_parent_platdata(dev);
532bbbcb526SBin Meng if (pplat->class == (PCI_CLASS_DISPLAY_VGA << 8))
533bbbcb526SBin Meng set_vga_bridge_bits(dev);
534ff3e077bSSimon Glass }
535ff3e077bSSimon Glass debug("%s: done\n", __func__);
536ff3e077bSSimon Glass
537ff3e077bSSimon Glass return sub_bus;
538ff3e077bSSimon Glass }
539ff3e077bSSimon Glass
pci_generic_mmap_write_config(struct udevice * bus,int (* addr_f)(struct udevice * bus,pci_dev_t bdf,uint offset,void ** addrp),pci_dev_t bdf,uint offset,ulong value,enum pci_size_t size)540badb9922STuomas Tynkkynen int pci_generic_mmap_write_config(
541badb9922STuomas Tynkkynen struct udevice *bus,
542badb9922STuomas Tynkkynen int (*addr_f)(struct udevice *bus, pci_dev_t bdf, uint offset, void **addrp),
543badb9922STuomas Tynkkynen pci_dev_t bdf,
544badb9922STuomas Tynkkynen uint offset,
545badb9922STuomas Tynkkynen ulong value,
546badb9922STuomas Tynkkynen enum pci_size_t size)
547badb9922STuomas Tynkkynen {
548badb9922STuomas Tynkkynen void *address;
549badb9922STuomas Tynkkynen
550badb9922STuomas Tynkkynen if (addr_f(bus, bdf, offset, &address) < 0)
551badb9922STuomas Tynkkynen return 0;
552badb9922STuomas Tynkkynen
553badb9922STuomas Tynkkynen switch (size) {
554badb9922STuomas Tynkkynen case PCI_SIZE_8:
555badb9922STuomas Tynkkynen writeb(value, address);
556badb9922STuomas Tynkkynen return 0;
557badb9922STuomas Tynkkynen case PCI_SIZE_16:
558badb9922STuomas Tynkkynen writew(value, address);
559badb9922STuomas Tynkkynen return 0;
560badb9922STuomas Tynkkynen case PCI_SIZE_32:
561badb9922STuomas Tynkkynen writel(value, address);
562badb9922STuomas Tynkkynen return 0;
563badb9922STuomas Tynkkynen default:
564badb9922STuomas Tynkkynen return -EINVAL;
565badb9922STuomas Tynkkynen }
566badb9922STuomas Tynkkynen }
567badb9922STuomas Tynkkynen
pci_generic_mmap_read_config(struct udevice * bus,int (* addr_f)(struct udevice * bus,pci_dev_t bdf,uint offset,void ** addrp),pci_dev_t bdf,uint offset,ulong * valuep,enum pci_size_t size)568badb9922STuomas Tynkkynen int pci_generic_mmap_read_config(
569badb9922STuomas Tynkkynen struct udevice *bus,
570badb9922STuomas Tynkkynen int (*addr_f)(struct udevice *bus, pci_dev_t bdf, uint offset, void **addrp),
571badb9922STuomas Tynkkynen pci_dev_t bdf,
572badb9922STuomas Tynkkynen uint offset,
573badb9922STuomas Tynkkynen ulong *valuep,
574badb9922STuomas Tynkkynen enum pci_size_t size)
575badb9922STuomas Tynkkynen {
576badb9922STuomas Tynkkynen void *address;
577badb9922STuomas Tynkkynen
578badb9922STuomas Tynkkynen if (addr_f(bus, bdf, offset, &address) < 0) {
579badb9922STuomas Tynkkynen *valuep = pci_get_ff(size);
580badb9922STuomas Tynkkynen return 0;
581badb9922STuomas Tynkkynen }
582badb9922STuomas Tynkkynen
583badb9922STuomas Tynkkynen switch (size) {
584badb9922STuomas Tynkkynen case PCI_SIZE_8:
585badb9922STuomas Tynkkynen *valuep = readb(address);
586badb9922STuomas Tynkkynen return 0;
587badb9922STuomas Tynkkynen case PCI_SIZE_16:
588badb9922STuomas Tynkkynen *valuep = readw(address);
589badb9922STuomas Tynkkynen return 0;
590badb9922STuomas Tynkkynen case PCI_SIZE_32:
591badb9922STuomas Tynkkynen *valuep = readl(address);
592badb9922STuomas Tynkkynen return 0;
593badb9922STuomas Tynkkynen default:
594badb9922STuomas Tynkkynen return -EINVAL;
595badb9922STuomas Tynkkynen }
596badb9922STuomas Tynkkynen }
597badb9922STuomas Tynkkynen
dm_pci_hose_probe_bus(struct udevice * bus)5985e23b8b4SSimon Glass int dm_pci_hose_probe_bus(struct udevice *bus)
599ff3e077bSSimon Glass {
600ff3e077bSSimon Glass int sub_bus;
601ff3e077bSSimon Glass int ret;
602ff3e077bSSimon Glass
603ff3e077bSSimon Glass debug("%s\n", __func__);
604ff3e077bSSimon Glass
605ff3e077bSSimon Glass sub_bus = pci_get_bus_max() + 1;
606ff3e077bSSimon Glass debug("%s: bus = %d/%s\n", __func__, sub_bus, bus->name);
6075e23b8b4SSimon Glass dm_pciauto_prescan_setup_bridge(bus, sub_bus);
608ff3e077bSSimon Glass
609ff3e077bSSimon Glass ret = device_probe(bus);
610ff3e077bSSimon Glass if (ret) {
6113129ace4SSimon Glass debug("%s: Cannot probe bus %s: %d\n", __func__, bus->name,
612ff3e077bSSimon Glass ret);
613ff3e077bSSimon Glass return ret;
614ff3e077bSSimon Glass }
615ff3e077bSSimon Glass if (sub_bus != bus->seq) {
616ff3e077bSSimon Glass printf("%s: Internal error, bus '%s' got seq %d, expected %d\n",
617ff3e077bSSimon Glass __func__, bus->name, bus->seq, sub_bus);
618ff3e077bSSimon Glass return -EPIPE;
619ff3e077bSSimon Glass }
620ff3e077bSSimon Glass sub_bus = pci_get_bus_max();
6215e23b8b4SSimon Glass dm_pciauto_postscan_setup_bridge(bus, sub_bus);
622ff3e077bSSimon Glass
623ff3e077bSSimon Glass return sub_bus;
624ff3e077bSSimon Glass }
625ff3e077bSSimon Glass
626aba92962SSimon Glass /**
627aba92962SSimon Glass * pci_match_one_device - Tell if a PCI device structure has a matching
628aba92962SSimon Glass * PCI device id structure
629aba92962SSimon Glass * @id: single PCI device id structure to match
6300367bd4dSHou Zhiqiang * @find: the PCI device id structure to match against
631aba92962SSimon Glass *
6320367bd4dSHou Zhiqiang * Returns true if the finding pci_device_id structure matched or false if
6330367bd4dSHou Zhiqiang * there is no match.
634aba92962SSimon Glass */
pci_match_one_id(const struct pci_device_id * id,const struct pci_device_id * find)635aba92962SSimon Glass static bool pci_match_one_id(const struct pci_device_id *id,
636aba92962SSimon Glass const struct pci_device_id *find)
637aba92962SSimon Glass {
638aba92962SSimon Glass if ((id->vendor == PCI_ANY_ID || id->vendor == find->vendor) &&
639aba92962SSimon Glass (id->device == PCI_ANY_ID || id->device == find->device) &&
640aba92962SSimon Glass (id->subvendor == PCI_ANY_ID || id->subvendor == find->subvendor) &&
641aba92962SSimon Glass (id->subdevice == PCI_ANY_ID || id->subdevice == find->subdevice) &&
642aba92962SSimon Glass !((id->class ^ find->class) & id->class_mask))
643aba92962SSimon Glass return true;
644aba92962SSimon Glass
645aba92962SSimon Glass return false;
646aba92962SSimon Glass }
647aba92962SSimon Glass
648aba92962SSimon Glass /**
649aba92962SSimon Glass * pci_find_and_bind_driver() - Find and bind the right PCI driver
650aba92962SSimon Glass *
651aba92962SSimon Glass * This only looks at certain fields in the descriptor.
6525dbcf3a0SSimon Glass *
6535dbcf3a0SSimon Glass * @parent: Parent bus
6545dbcf3a0SSimon Glass * @find_id: Specification of the driver to find
6555dbcf3a0SSimon Glass * @bdf: Bus/device/function addreess - see PCI_BDF()
6565dbcf3a0SSimon Glass * @devp: Returns a pointer to the device created
6575dbcf3a0SSimon Glass * @return 0 if OK, -EPERM if the device is not needed before relocation and
6585dbcf3a0SSimon Glass * therefore was not created, other -ve value on error
659aba92962SSimon Glass */
pci_find_and_bind_driver(struct udevice * parent,struct pci_device_id * find_id,pci_dev_t bdf,struct udevice ** devp)660aba92962SSimon Glass static int pci_find_and_bind_driver(struct udevice *parent,
6615dbcf3a0SSimon Glass struct pci_device_id *find_id,
6625dbcf3a0SSimon Glass pci_dev_t bdf, struct udevice **devp)
663aba92962SSimon Glass {
664aba92962SSimon Glass struct pci_driver_entry *start, *entry;
66502e4d38dSMarek Vasut ofnode node = ofnode_null();
666aba92962SSimon Glass const char *drv;
667aba92962SSimon Glass int n_ents;
668aba92962SSimon Glass int ret;
669aba92962SSimon Glass char name[30], *str;
67008fc7b8fSBin Meng bool bridge;
671aba92962SSimon Glass
672aba92962SSimon Glass *devp = NULL;
673aba92962SSimon Glass
674aba92962SSimon Glass debug("%s: Searching for driver: vendor=%x, device=%x\n", __func__,
675aba92962SSimon Glass find_id->vendor, find_id->device);
67602e4d38dSMarek Vasut
67702e4d38dSMarek Vasut /* Determine optional OF node */
67802e4d38dSMarek Vasut pci_dev_find_ofnode(parent, bdf, &node);
67902e4d38dSMarek Vasut
680aba92962SSimon Glass start = ll_entry_start(struct pci_driver_entry, pci_driver_entry);
681aba92962SSimon Glass n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry);
682aba92962SSimon Glass for (entry = start; entry != start + n_ents; entry++) {
683aba92962SSimon Glass const struct pci_device_id *id;
684aba92962SSimon Glass struct udevice *dev;
685aba92962SSimon Glass const struct driver *drv;
686aba92962SSimon Glass
687aba92962SSimon Glass for (id = entry->match;
688aba92962SSimon Glass id->vendor || id->subvendor || id->class_mask;
689aba92962SSimon Glass id++) {
690aba92962SSimon Glass if (!pci_match_one_id(id, find_id))
691aba92962SSimon Glass continue;
692aba92962SSimon Glass
693aba92962SSimon Glass drv = entry->driver;
69408fc7b8fSBin Meng
69508fc7b8fSBin Meng /*
69608fc7b8fSBin Meng * In the pre-relocation phase, we only bind devices
69708fc7b8fSBin Meng * whose driver has the DM_FLAG_PRE_RELOC set, to save
69808fc7b8fSBin Meng * precious memory space as on some platforms as that
69908fc7b8fSBin Meng * space is pretty limited (ie: using Cache As RAM).
70008fc7b8fSBin Meng */
70108fc7b8fSBin Meng if (!(gd->flags & GD_FLG_RELOC) &&
70208fc7b8fSBin Meng !(drv->flags & DM_FLAG_PRE_RELOC))
7035dbcf3a0SSimon Glass return -EPERM;
70408fc7b8fSBin Meng
705aba92962SSimon Glass /*
706aba92962SSimon Glass * We could pass the descriptor to the driver as
707aba92962SSimon Glass * platdata (instead of NULL) and allow its bind()
708aba92962SSimon Glass * method to return -ENOENT if it doesn't support this
709aba92962SSimon Glass * device. That way we could continue the search to
710aba92962SSimon Glass * find another driver. For now this doesn't seem
711aba92962SSimon Glass * necesssary, so just bind the first match.
712aba92962SSimon Glass */
71302e4d38dSMarek Vasut ret = device_bind_ofnode(parent, drv, drv->name, NULL,
71402e4d38dSMarek Vasut node, &dev);
715aba92962SSimon Glass if (ret)
716aba92962SSimon Glass goto error;
717aba92962SSimon Glass debug("%s: Match found: %s\n", __func__, drv->name);
718ed698aa7SBin Meng dev->driver_data = id->driver_data;
719aba92962SSimon Glass *devp = dev;
720aba92962SSimon Glass return 0;
721aba92962SSimon Glass }
722aba92962SSimon Glass }
723aba92962SSimon Glass
72408fc7b8fSBin Meng bridge = (find_id->class >> 8) == PCI_CLASS_BRIDGE_PCI;
72508fc7b8fSBin Meng /*
72608fc7b8fSBin Meng * In the pre-relocation phase, we only bind bridge devices to save
72708fc7b8fSBin Meng * precious memory space as on some platforms as that space is pretty
72808fc7b8fSBin Meng * limited (ie: using Cache As RAM).
72908fc7b8fSBin Meng */
73008fc7b8fSBin Meng if (!(gd->flags & GD_FLG_RELOC) && !bridge)
7315dbcf3a0SSimon Glass return -EPERM;
73208fc7b8fSBin Meng
733aba92962SSimon Glass /* Bind a generic driver so that the device can be used */
7344d8615cbSBin Meng sprintf(name, "pci_%x:%x.%x", parent->seq, PCI_DEV(bdf),
7354d8615cbSBin Meng PCI_FUNC(bdf));
736aba92962SSimon Glass str = strdup(name);
737aba92962SSimon Glass if (!str)
738aba92962SSimon Glass return -ENOMEM;
73908fc7b8fSBin Meng drv = bridge ? "pci_bridge_drv" : "pci_generic_drv";
74008fc7b8fSBin Meng
74102e4d38dSMarek Vasut ret = device_bind_driver_to_node(parent, drv, str, node, devp);
742aba92962SSimon Glass if (ret) {
7433129ace4SSimon Glass debug("%s: Failed to bind generic driver: %d\n", __func__, ret);
744c42640c7Sxypron.glpk@gmx.de free(str);
745aba92962SSimon Glass return ret;
746aba92962SSimon Glass }
747aba92962SSimon Glass debug("%s: No match found: bound generic driver instead\n", __func__);
748aba92962SSimon Glass
749aba92962SSimon Glass return 0;
750aba92962SSimon Glass
751aba92962SSimon Glass error:
752aba92962SSimon Glass debug("%s: No match found: error %d\n", __func__, ret);
753aba92962SSimon Glass return ret;
754aba92962SSimon Glass }
755aba92962SSimon Glass
pci_bind_bus_devices(struct udevice * bus)756ff3e077bSSimon Glass int pci_bind_bus_devices(struct udevice *bus)
757ff3e077bSSimon Glass {
758ff3e077bSSimon Glass ulong vendor, device;
759ff3e077bSSimon Glass ulong header_type;
7604d8615cbSBin Meng pci_dev_t bdf, end;
761ff3e077bSSimon Glass bool found_multi;
762ff3e077bSSimon Glass int ret;
763ff3e077bSSimon Glass
764ff3e077bSSimon Glass found_multi = false;
7654d8615cbSBin Meng end = PCI_BDF(bus->seq, PCI_MAX_PCI_DEVICES - 1,
7664d8615cbSBin Meng PCI_MAX_PCI_FUNCTIONS - 1);
7676d9f5b03SYoshinori Sato for (bdf = PCI_BDF(bus->seq, 0, 0); bdf <= end;
7684d8615cbSBin Meng bdf += PCI_BDF(0, 0, 1)) {
769ff3e077bSSimon Glass struct pci_child_platdata *pplat;
770ff3e077bSSimon Glass struct udevice *dev;
771ff3e077bSSimon Glass ulong class;
772ff3e077bSSimon Glass
77364e45f73SBin Meng if (!PCI_FUNC(bdf))
77464e45f73SBin Meng found_multi = false;
7754d8615cbSBin Meng if (PCI_FUNC(bdf) && !found_multi)
776ff3e077bSSimon Glass continue;
7772a87f7fdSHou Zhiqiang
778ff3e077bSSimon Glass /* Check only the first access, we don't expect problems */
7792a87f7fdSHou Zhiqiang ret = pci_bus_read_config(bus, bdf, PCI_VENDOR_ID, &vendor,
7802a87f7fdSHou Zhiqiang PCI_SIZE_16);
781ff3e077bSSimon Glass if (ret)
782ff3e077bSSimon Glass goto error;
7832a87f7fdSHou Zhiqiang
784ff3e077bSSimon Glass if (vendor == 0xffff || vendor == 0x0000)
785ff3e077bSSimon Glass continue;
786ff3e077bSSimon Glass
7872a87f7fdSHou Zhiqiang pci_bus_read_config(bus, bdf, PCI_HEADER_TYPE,
7882a87f7fdSHou Zhiqiang &header_type, PCI_SIZE_8);
7892a87f7fdSHou Zhiqiang
7904d8615cbSBin Meng if (!PCI_FUNC(bdf))
791ff3e077bSSimon Glass found_multi = header_type & 0x80;
792ff3e077bSSimon Glass
793ff3e077bSSimon Glass debug("%s: bus %d/%s: found device %x, function %d\n", __func__,
7944d8615cbSBin Meng bus->seq, bus->name, PCI_DEV(bdf), PCI_FUNC(bdf));
7954d8615cbSBin Meng pci_bus_read_config(bus, bdf, PCI_DEVICE_ID, &device,
796ff3e077bSSimon Glass PCI_SIZE_16);
7974d8615cbSBin Meng pci_bus_read_config(bus, bdf, PCI_CLASS_REVISION, &class,
798aba92962SSimon Glass PCI_SIZE_32);
799aba92962SSimon Glass class >>= 8;
800ff3e077bSSimon Glass
801ff3e077bSSimon Glass /* Find this device in the device tree */
8024d8615cbSBin Meng ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), &dev);
803ff3e077bSSimon Glass
8048bd42525SSimon Glass /* If nothing in the device tree, bind a device */
805ff3e077bSSimon Glass if (ret == -ENODEV) {
806aba92962SSimon Glass struct pci_device_id find_id;
807aba92962SSimon Glass ulong val;
808ff3e077bSSimon Glass
809aba92962SSimon Glass memset(&find_id, '\0', sizeof(find_id));
810aba92962SSimon Glass find_id.vendor = vendor;
811aba92962SSimon Glass find_id.device = device;
812aba92962SSimon Glass find_id.class = class;
813aba92962SSimon Glass if ((header_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) {
8144d8615cbSBin Meng pci_bus_read_config(bus, bdf,
815aba92962SSimon Glass PCI_SUBSYSTEM_VENDOR_ID,
816aba92962SSimon Glass &val, PCI_SIZE_32);
817aba92962SSimon Glass find_id.subvendor = val & 0xffff;
818aba92962SSimon Glass find_id.subdevice = val >> 16;
819aba92962SSimon Glass }
8204d8615cbSBin Meng ret = pci_find_and_bind_driver(bus, &find_id, bdf,
821aba92962SSimon Glass &dev);
822ff3e077bSSimon Glass }
8235dbcf3a0SSimon Glass if (ret == -EPERM)
8245dbcf3a0SSimon Glass continue;
8255dbcf3a0SSimon Glass else if (ret)
826ff3e077bSSimon Glass return ret;
827ff3e077bSSimon Glass
828ff3e077bSSimon Glass /* Update the platform data */
829ff3e077bSSimon Glass pplat = dev_get_parent_platdata(dev);
8304d8615cbSBin Meng pplat->devfn = PCI_MASK_BUS(bdf);
831ff3e077bSSimon Glass pplat->vendor = vendor;
832ff3e077bSSimon Glass pplat->device = device;
833ff3e077bSSimon Glass pplat->class = class;
834ff3e077bSSimon Glass }
835ff3e077bSSimon Glass
836ff3e077bSSimon Glass return 0;
837ff3e077bSSimon Glass error:
838ff3e077bSSimon Glass printf("Cannot read bus configuration: %d\n", ret);
839ff3e077bSSimon Glass
840ff3e077bSSimon Glass return ret;
841ff3e077bSSimon Glass }
842ff3e077bSSimon Glass
decode_regions(struct pci_controller * hose,ofnode parent_node,ofnode node)843f2825f6eSChristian Gmeiner static void decode_regions(struct pci_controller *hose, ofnode parent_node,
844bf501595SSimon Glass ofnode node)
845ff3e077bSSimon Glass {
846ff3e077bSSimon Glass int pci_addr_cells, addr_cells, size_cells;
847ff3e077bSSimon Glass int cells_per_record;
848ff3e077bSSimon Glass const u32 *prop;
849ff3e077bSSimon Glass int len;
850ff3e077bSSimon Glass int i;
851ff3e077bSSimon Glass
85261e51babSMasahiro Yamada prop = ofnode_get_property(node, "ranges", &len);
853f2825f6eSChristian Gmeiner if (!prop) {
854f2825f6eSChristian Gmeiner debug("%s: Cannot decode regions\n", __func__);
855f2825f6eSChristian Gmeiner return;
856f2825f6eSChristian Gmeiner }
857f2825f6eSChristian Gmeiner
858878d68c0SSimon Glass pci_addr_cells = ofnode_read_simple_addr_cells(node);
859878d68c0SSimon Glass addr_cells = ofnode_read_simple_addr_cells(parent_node);
860878d68c0SSimon Glass size_cells = ofnode_read_simple_size_cells(node);
861ff3e077bSSimon Glass
862ff3e077bSSimon Glass /* PCI addresses are always 3-cells */
863ff3e077bSSimon Glass len /= sizeof(u32);
864ff3e077bSSimon Glass cells_per_record = pci_addr_cells + addr_cells + size_cells;
865ff3e077bSSimon Glass hose->region_count = 0;
866ff3e077bSSimon Glass debug("%s: len=%d, cells_per_record=%d\n", __func__, len,
867ff3e077bSSimon Glass cells_per_record);
868ff3e077bSSimon Glass for (i = 0; i < MAX_PCI_REGIONS; i++, len -= cells_per_record) {
869ff3e077bSSimon Glass u64 pci_addr, addr, size;
870ff3e077bSSimon Glass int space_code;
871ff3e077bSSimon Glass u32 flags;
872ff3e077bSSimon Glass int type;
8739526d83aSSimon Glass int pos;
874ff3e077bSSimon Glass
875ff3e077bSSimon Glass if (len < cells_per_record)
876ff3e077bSSimon Glass break;
877ff3e077bSSimon Glass flags = fdt32_to_cpu(prop[0]);
878ff3e077bSSimon Glass space_code = (flags >> 24) & 3;
879ff3e077bSSimon Glass pci_addr = fdtdec_get_number(prop + 1, 2);
880ff3e077bSSimon Glass prop += pci_addr_cells;
881ff3e077bSSimon Glass addr = fdtdec_get_number(prop, addr_cells);
882ff3e077bSSimon Glass prop += addr_cells;
883ff3e077bSSimon Glass size = fdtdec_get_number(prop, size_cells);
884ff3e077bSSimon Glass prop += size_cells;
885dee37fc9SMasahiro Yamada debug("%s: region %d, pci_addr=%llx, addr=%llx, size=%llx, space_code=%d\n",
886dee37fc9SMasahiro Yamada __func__, hose->region_count, pci_addr, addr, size, space_code);
887ff3e077bSSimon Glass if (space_code & 2) {
888ff3e077bSSimon Glass type = flags & (1U << 30) ? PCI_REGION_PREFETCH :
889ff3e077bSSimon Glass PCI_REGION_MEM;
890ff3e077bSSimon Glass } else if (space_code & 1) {
891ff3e077bSSimon Glass type = PCI_REGION_IO;
892ff3e077bSSimon Glass } else {
893ff3e077bSSimon Glass continue;
894ff3e077bSSimon Glass }
89552ba9073STuomas Tynkkynen
89652ba9073STuomas Tynkkynen if (!IS_ENABLED(CONFIG_SYS_PCI_64BIT) &&
89752ba9073STuomas Tynkkynen type == PCI_REGION_MEM && upper_32_bits(pci_addr)) {
89852ba9073STuomas Tynkkynen debug(" - beyond the 32-bit boundary, ignoring\n");
89952ba9073STuomas Tynkkynen continue;
90052ba9073STuomas Tynkkynen }
90152ba9073STuomas Tynkkynen
9029526d83aSSimon Glass pos = -1;
9039526d83aSSimon Glass for (i = 0; i < hose->region_count; i++) {
9049526d83aSSimon Glass if (hose->regions[i].flags == type)
9059526d83aSSimon Glass pos = i;
9069526d83aSSimon Glass }
9079526d83aSSimon Glass if (pos == -1)
9089526d83aSSimon Glass pos = hose->region_count++;
9099526d83aSSimon Glass debug(" - type=%d, pos=%d\n", type, pos);
9109526d83aSSimon Glass pci_set_region(hose->regions + pos, pci_addr, addr, size, type);
911ff3e077bSSimon Glass }
912ff3e077bSSimon Glass
913ff3e077bSSimon Glass /* Add a region for our local memory */
914664758c3SBernhard Messerklinger #ifdef CONFIG_NR_DRAM_BANKS
915664758c3SBernhard Messerklinger bd_t *bd = gd->bd;
916664758c3SBernhard Messerklinger
9171eaf7800SBin Meng if (!bd)
918f2825f6eSChristian Gmeiner return;
9191eaf7800SBin Meng
920664758c3SBernhard Messerklinger for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) {
921664758c3SBernhard Messerklinger if (bd->bi_dram[i].size) {
922664758c3SBernhard Messerklinger pci_set_region(hose->regions + hose->region_count++,
923664758c3SBernhard Messerklinger bd->bi_dram[i].start,
924664758c3SBernhard Messerklinger bd->bi_dram[i].start,
925664758c3SBernhard Messerklinger bd->bi_dram[i].size,
926664758c3SBernhard Messerklinger PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
927664758c3SBernhard Messerklinger }
928664758c3SBernhard Messerklinger }
929664758c3SBernhard Messerklinger #else
930664758c3SBernhard Messerklinger phys_addr_t base = 0, size;
931664758c3SBernhard Messerklinger
9322084c5afSSimon Glass size = gd->ram_size;
9332084c5afSSimon Glass #ifdef CONFIG_SYS_SDRAM_BASE
9342084c5afSSimon Glass base = CONFIG_SYS_SDRAM_BASE;
9352084c5afSSimon Glass #endif
9362084c5afSSimon Glass if (gd->pci_ram_top && gd->pci_ram_top < base + size)
9372084c5afSSimon Glass size = gd->pci_ram_top - base;
938ee1109bbSBin Meng if (size)
939ee1109bbSBin Meng pci_set_region(hose->regions + hose->region_count++, base,
940ee1109bbSBin Meng base, size, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
941664758c3SBernhard Messerklinger #endif
942ff3e077bSSimon Glass
943f2825f6eSChristian Gmeiner return;
944ff3e077bSSimon Glass }
945ff3e077bSSimon Glass
pci_uclass_pre_probe(struct udevice * bus)946ff3e077bSSimon Glass static int pci_uclass_pre_probe(struct udevice *bus)
947ff3e077bSSimon Glass {
948ff3e077bSSimon Glass struct pci_controller *hose;
949ff3e077bSSimon Glass
950ff3e077bSSimon Glass debug("%s, bus=%d/%s, parent=%s\n", __func__, bus->seq, bus->name,
951ff3e077bSSimon Glass bus->parent->name);
952ff3e077bSSimon Glass hose = bus->uclass_priv;
953ff3e077bSSimon Glass
954ff3e077bSSimon Glass /* For bridges, use the top-level PCI controller */
95565f62b1cSPaul Burton if (!device_is_on_pci_bus(bus)) {
956ff3e077bSSimon Glass hose->ctlr = bus;
957f2825f6eSChristian Gmeiner decode_regions(hose, dev_ofnode(bus->parent), dev_ofnode(bus));
958ff3e077bSSimon Glass } else {
959ff3e077bSSimon Glass struct pci_controller *parent_hose;
960ff3e077bSSimon Glass
961ff3e077bSSimon Glass parent_hose = dev_get_uclass_priv(bus->parent);
962ff3e077bSSimon Glass hose->ctlr = parent_hose->bus;
963ff3e077bSSimon Glass }
964ff3e077bSSimon Glass hose->bus = bus;
965ff3e077bSSimon Glass hose->first_busno = bus->seq;
966ff3e077bSSimon Glass hose->last_busno = bus->seq;
967ff3e077bSSimon Glass
968ff3e077bSSimon Glass return 0;
969ff3e077bSSimon Glass }
970ff3e077bSSimon Glass
pci_uclass_post_probe(struct udevice * bus)971ff3e077bSSimon Glass static int pci_uclass_post_probe(struct udevice *bus)
972ff3e077bSSimon Glass {
973ff3e077bSSimon Glass int ret;
974ff3e077bSSimon Glass
975ff3e077bSSimon Glass debug("%s: probing bus %d\n", __func__, bus->seq);
976ff3e077bSSimon Glass ret = pci_bind_bus_devices(bus);
977ff3e077bSSimon Glass if (ret)
978ff3e077bSSimon Glass return ret;
979ff3e077bSSimon Glass
980ff3e077bSSimon Glass #ifdef CONFIG_PCI_PNP
981ff3e077bSSimon Glass ret = pci_auto_config_devices(bus);
9824d21455eSSimon Glass if (ret < 0)
9834d21455eSSimon Glass return ret;
984ff3e077bSSimon Glass #endif
985ff3e077bSSimon Glass
986348b744bSBin Meng #if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
987348b744bSBin Meng /*
988348b744bSBin Meng * Per Intel FSP specification, we should call FSP notify API to
989348b744bSBin Meng * inform FSP that PCI enumeration has been done so that FSP will
990348b744bSBin Meng * do any necessary initialization as required by the chipset's
991348b744bSBin Meng * BIOS Writer's Guide (BWG).
992348b744bSBin Meng *
993348b744bSBin Meng * Unfortunately we have to put this call here as with driver model,
994348b744bSBin Meng * the enumeration is all done on a lazy basis as needed, so until
995348b744bSBin Meng * something is touched on PCI it won't happen.
996348b744bSBin Meng *
997348b744bSBin Meng * Note we only call this 1) after U-Boot is relocated, and 2)
998348b744bSBin Meng * root bus has finished probing.
999348b744bSBin Meng */
10004d21455eSSimon Glass if ((gd->flags & GD_FLG_RELOC) && (bus->seq == 0)) {
1001348b744bSBin Meng ret = fsp_init_phase_pci();
10024d21455eSSimon Glass if (ret)
10034d21455eSSimon Glass return ret;
10044d21455eSSimon Glass }
1005348b744bSBin Meng #endif
1006348b744bSBin Meng
10074d21455eSSimon Glass return 0;
1008ff3e077bSSimon Glass }
1009ff3e077bSSimon Glass
pci_get_devfn(struct udevice * dev)1010*b5214200SStefan Roese int pci_get_devfn(struct udevice *dev)
1011*b5214200SStefan Roese {
1012*b5214200SStefan Roese struct fdt_pci_addr addr;
1013*b5214200SStefan Roese int ret;
1014*b5214200SStefan Roese
1015*b5214200SStefan Roese /* Extract the devfn from fdt_pci_addr */
1016*b5214200SStefan Roese ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
1017*b5214200SStefan Roese "reg", &addr);
1018*b5214200SStefan Roese if (ret) {
1019*b5214200SStefan Roese if (ret != -ENOENT)
1020*b5214200SStefan Roese return -EINVAL;
1021*b5214200SStefan Roese }
1022*b5214200SStefan Roese
1023*b5214200SStefan Roese return addr.phys_hi & 0xff00;
1024*b5214200SStefan Roese }
1025*b5214200SStefan Roese
pci_uclass_child_post_bind(struct udevice * dev)1026ff3e077bSSimon Glass static int pci_uclass_child_post_bind(struct udevice *dev)
1027ff3e077bSSimon Glass {
1028ff3e077bSSimon Glass struct pci_child_platdata *pplat;
1029ff3e077bSSimon Glass
1030bf501595SSimon Glass if (!dev_of_valid(dev))
1031ff3e077bSSimon Glass return 0;
1032ff3e077bSSimon Glass
1033ff3e077bSSimon Glass pplat = dev_get_parent_platdata(dev);
10341f6b08b9SBin Meng
10351f6b08b9SBin Meng /* Extract vendor id and device id if available */
10361f6b08b9SBin Meng ofnode_read_pci_vendev(dev_ofnode(dev), &pplat->vendor, &pplat->device);
10371f6b08b9SBin Meng
10381f6b08b9SBin Meng /* Extract the devfn from fdt_pci_addr */
1039*b5214200SStefan Roese pplat->devfn = pci_get_devfn(dev);
1040ff3e077bSSimon Glass
1041ff3e077bSSimon Glass return 0;
1042ff3e077bSSimon Glass }
1043ff3e077bSSimon Glass
pci_bridge_read_config(struct udevice * bus,pci_dev_t bdf,uint offset,ulong * valuep,enum pci_size_t size)10444d8615cbSBin Meng static int pci_bridge_read_config(struct udevice *bus, pci_dev_t bdf,
10454d8615cbSBin Meng uint offset, ulong *valuep,
10464d8615cbSBin Meng enum pci_size_t size)
1047ff3e077bSSimon Glass {
1048ff3e077bSSimon Glass struct pci_controller *hose = bus->uclass_priv;
1049ff3e077bSSimon Glass
1050ff3e077bSSimon Glass return pci_bus_read_config(hose->ctlr, bdf, offset, valuep, size);
1051ff3e077bSSimon Glass }
1052ff3e077bSSimon Glass
pci_bridge_write_config(struct udevice * bus,pci_dev_t bdf,uint offset,ulong value,enum pci_size_t size)10534d8615cbSBin Meng static int pci_bridge_write_config(struct udevice *bus, pci_dev_t bdf,
10544d8615cbSBin Meng uint offset, ulong value,
10554d8615cbSBin Meng enum pci_size_t size)
1056ff3e077bSSimon Glass {
1057ff3e077bSSimon Glass struct pci_controller *hose = bus->uclass_priv;
1058ff3e077bSSimon Glass
1059ff3e077bSSimon Glass return pci_bus_write_config(hose->ctlr, bdf, offset, value, size);
1060ff3e077bSSimon Glass }
1061ff3e077bSSimon Glass
skip_to_next_device(struct udevice * bus,struct udevice ** devp)106276c3fbcdSSimon Glass static int skip_to_next_device(struct udevice *bus, struct udevice **devp)
106376c3fbcdSSimon Glass {
106476c3fbcdSSimon Glass struct udevice *dev;
106576c3fbcdSSimon Glass int ret = 0;
106676c3fbcdSSimon Glass
106776c3fbcdSSimon Glass /*
106876c3fbcdSSimon Glass * Scan through all the PCI controllers. On x86 there will only be one
106976c3fbcdSSimon Glass * but that is not necessarily true on other hardware.
107076c3fbcdSSimon Glass */
107176c3fbcdSSimon Glass do {
107276c3fbcdSSimon Glass device_find_first_child(bus, &dev);
107376c3fbcdSSimon Glass if (dev) {
107476c3fbcdSSimon Glass *devp = dev;
107576c3fbcdSSimon Glass return 0;
107676c3fbcdSSimon Glass }
107776c3fbcdSSimon Glass ret = uclass_next_device(&bus);
107876c3fbcdSSimon Glass if (ret)
107976c3fbcdSSimon Glass return ret;
108076c3fbcdSSimon Glass } while (bus);
108176c3fbcdSSimon Glass
108276c3fbcdSSimon Glass return 0;
108376c3fbcdSSimon Glass }
108476c3fbcdSSimon Glass
pci_find_next_device(struct udevice ** devp)108576c3fbcdSSimon Glass int pci_find_next_device(struct udevice **devp)
108676c3fbcdSSimon Glass {
108776c3fbcdSSimon Glass struct udevice *child = *devp;
108876c3fbcdSSimon Glass struct udevice *bus = child->parent;
108976c3fbcdSSimon Glass int ret;
109076c3fbcdSSimon Glass
109176c3fbcdSSimon Glass /* First try all the siblings */
109276c3fbcdSSimon Glass *devp = NULL;
109376c3fbcdSSimon Glass while (child) {
109476c3fbcdSSimon Glass device_find_next_child(&child);
109576c3fbcdSSimon Glass if (child) {
109676c3fbcdSSimon Glass *devp = child;
109776c3fbcdSSimon Glass return 0;
109876c3fbcdSSimon Glass }
109976c3fbcdSSimon Glass }
110076c3fbcdSSimon Glass
110176c3fbcdSSimon Glass /* We ran out of siblings. Try the next bus */
110276c3fbcdSSimon Glass ret = uclass_next_device(&bus);
110376c3fbcdSSimon Glass if (ret)
110476c3fbcdSSimon Glass return ret;
110576c3fbcdSSimon Glass
110676c3fbcdSSimon Glass return bus ? skip_to_next_device(bus, devp) : 0;
110776c3fbcdSSimon Glass }
110876c3fbcdSSimon Glass
pci_find_first_device(struct udevice ** devp)110976c3fbcdSSimon Glass int pci_find_first_device(struct udevice **devp)
111076c3fbcdSSimon Glass {
111176c3fbcdSSimon Glass struct udevice *bus;
111276c3fbcdSSimon Glass int ret;
111376c3fbcdSSimon Glass
111476c3fbcdSSimon Glass *devp = NULL;
111576c3fbcdSSimon Glass ret = uclass_first_device(UCLASS_PCI, &bus);
111676c3fbcdSSimon Glass if (ret)
111776c3fbcdSSimon Glass return ret;
111876c3fbcdSSimon Glass
111976c3fbcdSSimon Glass return skip_to_next_device(bus, devp);
112076c3fbcdSSimon Glass }
112176c3fbcdSSimon Glass
pci_conv_32_to_size(ulong value,uint offset,enum pci_size_t size)11229289db6cSSimon Glass ulong pci_conv_32_to_size(ulong value, uint offset, enum pci_size_t size)
11239289db6cSSimon Glass {
11249289db6cSSimon Glass switch (size) {
11259289db6cSSimon Glass case PCI_SIZE_8:
11269289db6cSSimon Glass return (value >> ((offset & 3) * 8)) & 0xff;
11279289db6cSSimon Glass case PCI_SIZE_16:
11289289db6cSSimon Glass return (value >> ((offset & 2) * 8)) & 0xffff;
11299289db6cSSimon Glass default:
11309289db6cSSimon Glass return value;
11319289db6cSSimon Glass }
11329289db6cSSimon Glass }
11339289db6cSSimon Glass
pci_conv_size_to_32(ulong old,ulong value,uint offset,enum pci_size_t size)11349289db6cSSimon Glass ulong pci_conv_size_to_32(ulong old, ulong value, uint offset,
11359289db6cSSimon Glass enum pci_size_t size)
11369289db6cSSimon Glass {
11379289db6cSSimon Glass uint off_mask;
11389289db6cSSimon Glass uint val_mask, shift;
11399289db6cSSimon Glass ulong ldata, mask;
11409289db6cSSimon Glass
11419289db6cSSimon Glass switch (size) {
11429289db6cSSimon Glass case PCI_SIZE_8:
11439289db6cSSimon Glass off_mask = 3;
11449289db6cSSimon Glass val_mask = 0xff;
11459289db6cSSimon Glass break;
11469289db6cSSimon Glass case PCI_SIZE_16:
11479289db6cSSimon Glass off_mask = 2;
11489289db6cSSimon Glass val_mask = 0xffff;
11499289db6cSSimon Glass break;
11509289db6cSSimon Glass default:
11519289db6cSSimon Glass return value;
11529289db6cSSimon Glass }
11539289db6cSSimon Glass shift = (offset & off_mask) * 8;
11549289db6cSSimon Glass ldata = (value & val_mask) << shift;
11559289db6cSSimon Glass mask = val_mask << shift;
11569289db6cSSimon Glass value = (old & ~mask) | ldata;
11579289db6cSSimon Glass
11589289db6cSSimon Glass return value;
11599289db6cSSimon Glass }
11609289db6cSSimon Glass
pci_get_regions(struct udevice * dev,struct pci_region ** iop,struct pci_region ** memp,struct pci_region ** prefp)1161f9260336SSimon Glass int pci_get_regions(struct udevice *dev, struct pci_region **iop,
1162f9260336SSimon Glass struct pci_region **memp, struct pci_region **prefp)
1163f9260336SSimon Glass {
1164f9260336SSimon Glass struct udevice *bus = pci_get_controller(dev);
1165f9260336SSimon Glass struct pci_controller *hose = dev_get_uclass_priv(bus);
1166f9260336SSimon Glass int i;
1167f9260336SSimon Glass
1168f9260336SSimon Glass *iop = NULL;
1169f9260336SSimon Glass *memp = NULL;
1170f9260336SSimon Glass *prefp = NULL;
1171f9260336SSimon Glass for (i = 0; i < hose->region_count; i++) {
1172f9260336SSimon Glass switch (hose->regions[i].flags) {
1173f9260336SSimon Glass case PCI_REGION_IO:
1174f9260336SSimon Glass if (!*iop || (*iop)->size < hose->regions[i].size)
1175f9260336SSimon Glass *iop = hose->regions + i;
1176f9260336SSimon Glass break;
1177f9260336SSimon Glass case PCI_REGION_MEM:
1178f9260336SSimon Glass if (!*memp || (*memp)->size < hose->regions[i].size)
1179f9260336SSimon Glass *memp = hose->regions + i;
1180f9260336SSimon Glass break;
1181f9260336SSimon Glass case (PCI_REGION_MEM | PCI_REGION_PREFETCH):
1182f9260336SSimon Glass if (!*prefp || (*prefp)->size < hose->regions[i].size)
1183f9260336SSimon Glass *prefp = hose->regions + i;
1184f9260336SSimon Glass break;
1185f9260336SSimon Glass }
1186f9260336SSimon Glass }
1187f9260336SSimon Glass
1188f9260336SSimon Glass return (*iop != NULL) + (*memp != NULL) + (*prefp != NULL);
1189f9260336SSimon Glass }
1190f9260336SSimon Glass
dm_pci_read_bar32(struct udevice * dev,int barnum)1191bab17cf1SSimon Glass u32 dm_pci_read_bar32(struct udevice *dev, int barnum)
1192bab17cf1SSimon Glass {
1193bab17cf1SSimon Glass u32 addr;
1194bab17cf1SSimon Glass int bar;
1195bab17cf1SSimon Glass
1196bab17cf1SSimon Glass bar = PCI_BASE_ADDRESS_0 + barnum * 4;
1197bab17cf1SSimon Glass dm_pci_read_config32(dev, bar, &addr);
1198bab17cf1SSimon Glass if (addr & PCI_BASE_ADDRESS_SPACE_IO)
1199bab17cf1SSimon Glass return addr & PCI_BASE_ADDRESS_IO_MASK;
1200bab17cf1SSimon Glass else
1201bab17cf1SSimon Glass return addr & PCI_BASE_ADDRESS_MEM_MASK;
1202bab17cf1SSimon Glass }
1203bab17cf1SSimon Glass
dm_pci_write_bar32(struct udevice * dev,int barnum,u32 addr)12049d731c82SSimon Glass void dm_pci_write_bar32(struct udevice *dev, int barnum, u32 addr)
12059d731c82SSimon Glass {
12069d731c82SSimon Glass int bar;
12079d731c82SSimon Glass
12089d731c82SSimon Glass bar = PCI_BASE_ADDRESS_0 + barnum * 4;
12099d731c82SSimon Glass dm_pci_write_config32(dev, bar, addr);
12109d731c82SSimon Glass }
12119d731c82SSimon Glass
_dm_pci_bus_to_phys(struct udevice * ctlr,pci_addr_t bus_addr,unsigned long flags,unsigned long skip_mask,phys_addr_t * pa)121221d1fe7eSSimon Glass static int _dm_pci_bus_to_phys(struct udevice *ctlr,
121321d1fe7eSSimon Glass pci_addr_t bus_addr, unsigned long flags,
121421d1fe7eSSimon Glass unsigned long skip_mask, phys_addr_t *pa)
121521d1fe7eSSimon Glass {
121621d1fe7eSSimon Glass struct pci_controller *hose = dev_get_uclass_priv(ctlr);
121721d1fe7eSSimon Glass struct pci_region *res;
121821d1fe7eSSimon Glass int i;
121921d1fe7eSSimon Glass
12206f95d89cSChristian Gmeiner if (hose->region_count == 0) {
12216f95d89cSChristian Gmeiner *pa = bus_addr;
12226f95d89cSChristian Gmeiner return 0;
12236f95d89cSChristian Gmeiner }
12246f95d89cSChristian Gmeiner
122521d1fe7eSSimon Glass for (i = 0; i < hose->region_count; i++) {
122621d1fe7eSSimon Glass res = &hose->regions[i];
122721d1fe7eSSimon Glass
122821d1fe7eSSimon Glass if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
122921d1fe7eSSimon Glass continue;
123021d1fe7eSSimon Glass
123121d1fe7eSSimon Glass if (res->flags & skip_mask)
123221d1fe7eSSimon Glass continue;
123321d1fe7eSSimon Glass
123421d1fe7eSSimon Glass if (bus_addr >= res->bus_start &&
123521d1fe7eSSimon Glass (bus_addr - res->bus_start) < res->size) {
123621d1fe7eSSimon Glass *pa = (bus_addr - res->bus_start + res->phys_start);
123721d1fe7eSSimon Glass return 0;
123821d1fe7eSSimon Glass }
123921d1fe7eSSimon Glass }
124021d1fe7eSSimon Glass
124121d1fe7eSSimon Glass return 1;
124221d1fe7eSSimon Glass }
124321d1fe7eSSimon Glass
dm_pci_bus_to_phys(struct udevice * dev,pci_addr_t bus_addr,unsigned long flags)124421d1fe7eSSimon Glass phys_addr_t dm_pci_bus_to_phys(struct udevice *dev, pci_addr_t bus_addr,
124521d1fe7eSSimon Glass unsigned long flags)
124621d1fe7eSSimon Glass {
124721d1fe7eSSimon Glass phys_addr_t phys_addr = 0;
124821d1fe7eSSimon Glass struct udevice *ctlr;
124921d1fe7eSSimon Glass int ret;
125021d1fe7eSSimon Glass
125121d1fe7eSSimon Glass /* The root controller has the region information */
125221d1fe7eSSimon Glass ctlr = pci_get_controller(dev);
125321d1fe7eSSimon Glass
125421d1fe7eSSimon Glass /*
125521d1fe7eSSimon Glass * if PCI_REGION_MEM is set we do a two pass search with preference
125621d1fe7eSSimon Glass * on matches that don't have PCI_REGION_SYS_MEMORY set
125721d1fe7eSSimon Glass */
125821d1fe7eSSimon Glass if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
125921d1fe7eSSimon Glass ret = _dm_pci_bus_to_phys(ctlr, bus_addr,
126021d1fe7eSSimon Glass flags, PCI_REGION_SYS_MEMORY,
126121d1fe7eSSimon Glass &phys_addr);
126221d1fe7eSSimon Glass if (!ret)
126321d1fe7eSSimon Glass return phys_addr;
126421d1fe7eSSimon Glass }
126521d1fe7eSSimon Glass
126621d1fe7eSSimon Glass ret = _dm_pci_bus_to_phys(ctlr, bus_addr, flags, 0, &phys_addr);
126721d1fe7eSSimon Glass
126821d1fe7eSSimon Glass if (ret)
126921d1fe7eSSimon Glass puts("pci_hose_bus_to_phys: invalid physical address\n");
127021d1fe7eSSimon Glass
127121d1fe7eSSimon Glass return phys_addr;
127221d1fe7eSSimon Glass }
127321d1fe7eSSimon Glass
_dm_pci_phys_to_bus(struct udevice * dev,phys_addr_t phys_addr,unsigned long flags,unsigned long skip_mask,pci_addr_t * ba)127421d1fe7eSSimon Glass int _dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr,
127521d1fe7eSSimon Glass unsigned long flags, unsigned long skip_mask,
127621d1fe7eSSimon Glass pci_addr_t *ba)
127721d1fe7eSSimon Glass {
127821d1fe7eSSimon Glass struct pci_region *res;
127921d1fe7eSSimon Glass struct udevice *ctlr;
128021d1fe7eSSimon Glass pci_addr_t bus_addr;
128121d1fe7eSSimon Glass int i;
128221d1fe7eSSimon Glass struct pci_controller *hose;
128321d1fe7eSSimon Glass
128421d1fe7eSSimon Glass /* The root controller has the region information */
128521d1fe7eSSimon Glass ctlr = pci_get_controller(dev);
128621d1fe7eSSimon Glass hose = dev_get_uclass_priv(ctlr);
128721d1fe7eSSimon Glass
12886f95d89cSChristian Gmeiner if (hose->region_count == 0) {
12896f95d89cSChristian Gmeiner *ba = phys_addr;
12906f95d89cSChristian Gmeiner return 0;
12916f95d89cSChristian Gmeiner }
12926f95d89cSChristian Gmeiner
129321d1fe7eSSimon Glass for (i = 0; i < hose->region_count; i++) {
129421d1fe7eSSimon Glass res = &hose->regions[i];
129521d1fe7eSSimon Glass
129621d1fe7eSSimon Glass if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
129721d1fe7eSSimon Glass continue;
129821d1fe7eSSimon Glass
129921d1fe7eSSimon Glass if (res->flags & skip_mask)
130021d1fe7eSSimon Glass continue;
130121d1fe7eSSimon Glass
130221d1fe7eSSimon Glass bus_addr = phys_addr - res->phys_start + res->bus_start;
130321d1fe7eSSimon Glass
130421d1fe7eSSimon Glass if (bus_addr >= res->bus_start &&
130521d1fe7eSSimon Glass (bus_addr - res->bus_start) < res->size) {
130621d1fe7eSSimon Glass *ba = bus_addr;
130721d1fe7eSSimon Glass return 0;
130821d1fe7eSSimon Glass }
130921d1fe7eSSimon Glass }
131021d1fe7eSSimon Glass
131121d1fe7eSSimon Glass return 1;
131221d1fe7eSSimon Glass }
131321d1fe7eSSimon Glass
dm_pci_phys_to_bus(struct udevice * dev,phys_addr_t phys_addr,unsigned long flags)131421d1fe7eSSimon Glass pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t phys_addr,
131521d1fe7eSSimon Glass unsigned long flags)
131621d1fe7eSSimon Glass {
131721d1fe7eSSimon Glass pci_addr_t bus_addr = 0;
131821d1fe7eSSimon Glass int ret;
131921d1fe7eSSimon Glass
132021d1fe7eSSimon Glass /*
132121d1fe7eSSimon Glass * if PCI_REGION_MEM is set we do a two pass search with preference
132221d1fe7eSSimon Glass * on matches that don't have PCI_REGION_SYS_MEMORY set
132321d1fe7eSSimon Glass */
132421d1fe7eSSimon Glass if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
132521d1fe7eSSimon Glass ret = _dm_pci_phys_to_bus(dev, phys_addr, flags,
132621d1fe7eSSimon Glass PCI_REGION_SYS_MEMORY, &bus_addr);
132721d1fe7eSSimon Glass if (!ret)
132821d1fe7eSSimon Glass return bus_addr;
132921d1fe7eSSimon Glass }
133021d1fe7eSSimon Glass
133121d1fe7eSSimon Glass ret = _dm_pci_phys_to_bus(dev, phys_addr, flags, 0, &bus_addr);
133221d1fe7eSSimon Glass
133321d1fe7eSSimon Glass if (ret)
133421d1fe7eSSimon Glass puts("pci_hose_phys_to_bus: invalid physical address\n");
133521d1fe7eSSimon Glass
133621d1fe7eSSimon Glass return bus_addr;
133721d1fe7eSSimon Glass }
133821d1fe7eSSimon Glass
dm_pci_map_bar(struct udevice * dev,int bar,int flags)133921d1fe7eSSimon Glass void *dm_pci_map_bar(struct udevice *dev, int bar, int flags)
134021d1fe7eSSimon Glass {
134121d1fe7eSSimon Glass pci_addr_t pci_bus_addr;
134221d1fe7eSSimon Glass u32 bar_response;
134321d1fe7eSSimon Glass
134421d1fe7eSSimon Glass /* read BAR address */
134521d1fe7eSSimon Glass dm_pci_read_config32(dev, bar, &bar_response);
134621d1fe7eSSimon Glass pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
134721d1fe7eSSimon Glass
134821d1fe7eSSimon Glass /*
134921d1fe7eSSimon Glass * Pass "0" as the length argument to pci_bus_to_virt. The arg
135021d1fe7eSSimon Glass * isn't actualy used on any platform because u-boot assumes a static
135121d1fe7eSSimon Glass * linear mapping. In the future, this could read the BAR size
135221d1fe7eSSimon Glass * and pass that as the size if needed.
135321d1fe7eSSimon Glass */
135421d1fe7eSSimon Glass return dm_pci_bus_to_virt(dev, pci_bus_addr, flags, 0, MAP_NOCACHE);
135521d1fe7eSSimon Glass }
135621d1fe7eSSimon Glass
_dm_pci_find_next_capability(struct udevice * dev,u8 pos,int cap)1357a8c5f8d3SBin Meng static int _dm_pci_find_next_capability(struct udevice *dev, u8 pos, int cap)
1358dac01fd8SBin Meng {
1359dac01fd8SBin Meng int ttl = PCI_FIND_CAP_TTL;
1360dac01fd8SBin Meng u8 id;
1361dac01fd8SBin Meng u16 ent;
1362dac01fd8SBin Meng
1363dac01fd8SBin Meng dm_pci_read_config8(dev, pos, &pos);
1364a8c5f8d3SBin Meng
1365dac01fd8SBin Meng while (ttl--) {
1366dac01fd8SBin Meng if (pos < PCI_STD_HEADER_SIZEOF)
1367dac01fd8SBin Meng break;
1368dac01fd8SBin Meng pos &= ~3;
1369dac01fd8SBin Meng dm_pci_read_config16(dev, pos, &ent);
1370dac01fd8SBin Meng
1371dac01fd8SBin Meng id = ent & 0xff;
1372dac01fd8SBin Meng if (id == 0xff)
1373dac01fd8SBin Meng break;
1374dac01fd8SBin Meng if (id == cap)
1375dac01fd8SBin Meng return pos;
1376dac01fd8SBin Meng pos = (ent >> 8);
1377dac01fd8SBin Meng }
1378dac01fd8SBin Meng
1379dac01fd8SBin Meng return 0;
1380dac01fd8SBin Meng }
1381dac01fd8SBin Meng
dm_pci_find_next_capability(struct udevice * dev,u8 start,int cap)1382a8c5f8d3SBin Meng int dm_pci_find_next_capability(struct udevice *dev, u8 start, int cap)
1383a8c5f8d3SBin Meng {
1384a8c5f8d3SBin Meng return _dm_pci_find_next_capability(dev, start + PCI_CAP_LIST_NEXT,
1385a8c5f8d3SBin Meng cap);
1386a8c5f8d3SBin Meng }
1387a8c5f8d3SBin Meng
dm_pci_find_capability(struct udevice * dev,int cap)1388a8c5f8d3SBin Meng int dm_pci_find_capability(struct udevice *dev, int cap)
1389a8c5f8d3SBin Meng {
1390a8c5f8d3SBin Meng u16 status;
1391a8c5f8d3SBin Meng u8 header_type;
1392a8c5f8d3SBin Meng u8 pos;
1393a8c5f8d3SBin Meng
1394a8c5f8d3SBin Meng dm_pci_read_config16(dev, PCI_STATUS, &status);
1395a8c5f8d3SBin Meng if (!(status & PCI_STATUS_CAP_LIST))
1396a8c5f8d3SBin Meng return 0;
1397a8c5f8d3SBin Meng
1398a8c5f8d3SBin Meng dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
1399a8c5f8d3SBin Meng if ((header_type & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
1400a8c5f8d3SBin Meng pos = PCI_CB_CAPABILITY_LIST;
1401a8c5f8d3SBin Meng else
1402a8c5f8d3SBin Meng pos = PCI_CAPABILITY_LIST;
1403a8c5f8d3SBin Meng
1404a8c5f8d3SBin Meng return _dm_pci_find_next_capability(dev, pos, cap);
1405a8c5f8d3SBin Meng }
1406a8c5f8d3SBin Meng
dm_pci_find_next_ext_capability(struct udevice * dev,int start,int cap)1407a8c5f8d3SBin Meng int dm_pci_find_next_ext_capability(struct udevice *dev, int start, int cap)
1408dac01fd8SBin Meng {
1409dac01fd8SBin Meng u32 header;
1410dac01fd8SBin Meng int ttl;
1411dac01fd8SBin Meng int pos = PCI_CFG_SPACE_SIZE;
1412dac01fd8SBin Meng
1413dac01fd8SBin Meng /* minimum 8 bytes per capability */
1414dac01fd8SBin Meng ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
1415dac01fd8SBin Meng
1416a8c5f8d3SBin Meng if (start)
1417a8c5f8d3SBin Meng pos = start;
1418a8c5f8d3SBin Meng
1419dac01fd8SBin Meng dm_pci_read_config32(dev, pos, &header);
1420dac01fd8SBin Meng /*
1421dac01fd8SBin Meng * If we have no capabilities, this is indicated by cap ID,
1422dac01fd8SBin Meng * cap version and next pointer all being 0.
1423dac01fd8SBin Meng */
1424dac01fd8SBin Meng if (header == 0)
1425dac01fd8SBin Meng return 0;
1426dac01fd8SBin Meng
1427dac01fd8SBin Meng while (ttl--) {
1428dac01fd8SBin Meng if (PCI_EXT_CAP_ID(header) == cap)
1429dac01fd8SBin Meng return pos;
1430dac01fd8SBin Meng
1431dac01fd8SBin Meng pos = PCI_EXT_CAP_NEXT(header);
1432dac01fd8SBin Meng if (pos < PCI_CFG_SPACE_SIZE)
1433dac01fd8SBin Meng break;
1434dac01fd8SBin Meng
1435dac01fd8SBin Meng dm_pci_read_config32(dev, pos, &header);
1436dac01fd8SBin Meng }
1437dac01fd8SBin Meng
1438dac01fd8SBin Meng return 0;
1439dac01fd8SBin Meng }
1440dac01fd8SBin Meng
dm_pci_find_ext_capability(struct udevice * dev,int cap)1441a8c5f8d3SBin Meng int dm_pci_find_ext_capability(struct udevice *dev, int cap)
1442a8c5f8d3SBin Meng {
1443a8c5f8d3SBin Meng return dm_pci_find_next_ext_capability(dev, 0, cap);
1444a8c5f8d3SBin Meng }
1445a8c5f8d3SBin Meng
1446ff3e077bSSimon Glass UCLASS_DRIVER(pci) = {
1447ff3e077bSSimon Glass .id = UCLASS_PCI,
1448ff3e077bSSimon Glass .name = "pci",
14492bb02e4fSSimon Glass .flags = DM_UC_FLAG_SEQ_ALIAS,
145091195485SSimon Glass .post_bind = dm_scan_fdt_dev,
1451ff3e077bSSimon Glass .pre_probe = pci_uclass_pre_probe,
1452ff3e077bSSimon Glass .post_probe = pci_uclass_post_probe,
1453ff3e077bSSimon Glass .child_post_bind = pci_uclass_child_post_bind,
1454ff3e077bSSimon Glass .per_device_auto_alloc_size = sizeof(struct pci_controller),
1455ff3e077bSSimon Glass .per_child_platdata_auto_alloc_size =
1456ff3e077bSSimon Glass sizeof(struct pci_child_platdata),
1457ff3e077bSSimon Glass };
1458ff3e077bSSimon Glass
1459ff3e077bSSimon Glass static const struct dm_pci_ops pci_bridge_ops = {
1460ff3e077bSSimon Glass .read_config = pci_bridge_read_config,
1461ff3e077bSSimon Glass .write_config = pci_bridge_write_config,
1462ff3e077bSSimon Glass };
1463ff3e077bSSimon Glass
1464ff3e077bSSimon Glass static const struct udevice_id pci_bridge_ids[] = {
1465ff3e077bSSimon Glass { .compatible = "pci-bridge" },
1466ff3e077bSSimon Glass { }
1467ff3e077bSSimon Glass };
1468ff3e077bSSimon Glass
1469ff3e077bSSimon Glass U_BOOT_DRIVER(pci_bridge_drv) = {
1470ff3e077bSSimon Glass .name = "pci_bridge_drv",
1471ff3e077bSSimon Glass .id = UCLASS_PCI,
1472ff3e077bSSimon Glass .of_match = pci_bridge_ids,
1473ff3e077bSSimon Glass .ops = &pci_bridge_ops,
1474ff3e077bSSimon Glass };
1475ff3e077bSSimon Glass
1476ff3e077bSSimon Glass UCLASS_DRIVER(pci_generic) = {
1477ff3e077bSSimon Glass .id = UCLASS_PCI_GENERIC,
1478ff3e077bSSimon Glass .name = "pci_generic",
1479ff3e077bSSimon Glass };
1480ff3e077bSSimon Glass
1481ff3e077bSSimon Glass static const struct udevice_id pci_generic_ids[] = {
1482ff3e077bSSimon Glass { .compatible = "pci-generic" },
1483ff3e077bSSimon Glass { }
1484ff3e077bSSimon Glass };
1485ff3e077bSSimon Glass
1486ff3e077bSSimon Glass U_BOOT_DRIVER(pci_generic_drv) = {
1487ff3e077bSSimon Glass .name = "pci_generic_drv",
1488ff3e077bSSimon Glass .id = UCLASS_PCI_GENERIC,
1489ff3e077bSSimon Glass .of_match = pci_generic_ids,
1490ff3e077bSSimon Glass };
1491e578b92cSStephen Warren
pci_init(void)1492e578b92cSStephen Warren void pci_init(void)
1493e578b92cSStephen Warren {
1494e578b92cSStephen Warren struct udevice *bus;
1495e578b92cSStephen Warren
1496e578b92cSStephen Warren /*
1497e578b92cSStephen Warren * Enumerate all known controller devices. Enumeration has the side-
1498e578b92cSStephen Warren * effect of probing them, so PCIe devices will be enumerated too.
1499e578b92cSStephen Warren */
1500e578b92cSStephen Warren for (uclass_first_device(UCLASS_PCI, &bus);
1501e578b92cSStephen Warren bus;
1502e578b92cSStephen Warren uclass_next_device(&bus)) {
1503e578b92cSStephen Warren ;
1504e578b92cSStephen Warren }
1505e578b92cSStephen Warren }
1506