xref: /rk3399_rockchip-uboot/drivers/pci/pci_common.c (revision 00caae6d47645e68d6e5277aceb69592b49381a6)
1aab6724cSSimon Glass /*
2aab6724cSSimon Glass  * Copyright (c) 2014 Google, Inc
3aab6724cSSimon Glass  *
4aab6724cSSimon Glass  * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
5aab6724cSSimon Glass  * Andreas Heppel <aheppel@sysgo.de>
6aab6724cSSimon Glass  *
7aab6724cSSimon Glass  * (C) Copyright 2002, 2003
8aab6724cSSimon Glass  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
9aab6724cSSimon Glass  *
10aab6724cSSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
11aab6724cSSimon Glass  */
12aab6724cSSimon Glass 
13aab6724cSSimon Glass #include <common.h>
14aec241dfSSimon Glass #include <dm.h>
15aab6724cSSimon Glass #include <errno.h>
16aab6724cSSimon Glass #include <pci.h>
17aab6724cSSimon Glass #include <asm/io.h>
18aab6724cSSimon Glass 
pci_class_str(u8 class)19aab6724cSSimon Glass const char *pci_class_str(u8 class)
20aab6724cSSimon Glass {
21aab6724cSSimon Glass 	switch (class) {
22aab6724cSSimon Glass 	case PCI_CLASS_NOT_DEFINED:
23aab6724cSSimon Glass 		return "Build before PCI Rev2.0";
24aab6724cSSimon Glass 		break;
25aab6724cSSimon Glass 	case PCI_BASE_CLASS_STORAGE:
26aab6724cSSimon Glass 		return "Mass storage controller";
27aab6724cSSimon Glass 		break;
28aab6724cSSimon Glass 	case PCI_BASE_CLASS_NETWORK:
29aab6724cSSimon Glass 		return "Network controller";
30aab6724cSSimon Glass 		break;
31aab6724cSSimon Glass 	case PCI_BASE_CLASS_DISPLAY:
32aab6724cSSimon Glass 		return "Display controller";
33aab6724cSSimon Glass 		break;
34aab6724cSSimon Glass 	case PCI_BASE_CLASS_MULTIMEDIA:
35aab6724cSSimon Glass 		return "Multimedia device";
36aab6724cSSimon Glass 		break;
37aab6724cSSimon Glass 	case PCI_BASE_CLASS_MEMORY:
38aab6724cSSimon Glass 		return "Memory controller";
39aab6724cSSimon Glass 		break;
40aab6724cSSimon Glass 	case PCI_BASE_CLASS_BRIDGE:
41aab6724cSSimon Glass 		return "Bridge device";
42aab6724cSSimon Glass 		break;
43aab6724cSSimon Glass 	case PCI_BASE_CLASS_COMMUNICATION:
44aab6724cSSimon Glass 		return "Simple comm. controller";
45aab6724cSSimon Glass 		break;
46aab6724cSSimon Glass 	case PCI_BASE_CLASS_SYSTEM:
47aab6724cSSimon Glass 		return "Base system peripheral";
48aab6724cSSimon Glass 		break;
49aab6724cSSimon Glass 	case PCI_BASE_CLASS_INPUT:
50aab6724cSSimon Glass 		return "Input device";
51aab6724cSSimon Glass 		break;
52aab6724cSSimon Glass 	case PCI_BASE_CLASS_DOCKING:
53aab6724cSSimon Glass 		return "Docking station";
54aab6724cSSimon Glass 		break;
55aab6724cSSimon Glass 	case PCI_BASE_CLASS_PROCESSOR:
56aab6724cSSimon Glass 		return "Processor";
57aab6724cSSimon Glass 		break;
58aab6724cSSimon Glass 	case PCI_BASE_CLASS_SERIAL:
59aab6724cSSimon Glass 		return "Serial bus controller";
60aab6724cSSimon Glass 		break;
61aab6724cSSimon Glass 	case PCI_BASE_CLASS_INTELLIGENT:
62aab6724cSSimon Glass 		return "Intelligent controller";
63aab6724cSSimon Glass 		break;
64aab6724cSSimon Glass 	case PCI_BASE_CLASS_SATELLITE:
65aab6724cSSimon Glass 		return "Satellite controller";
66aab6724cSSimon Glass 		break;
67aab6724cSSimon Glass 	case PCI_BASE_CLASS_CRYPT:
68aab6724cSSimon Glass 		return "Cryptographic device";
69aab6724cSSimon Glass 		break;
70aab6724cSSimon Glass 	case PCI_BASE_CLASS_SIGNAL_PROCESSING:
71aab6724cSSimon Glass 		return "DSP";
72aab6724cSSimon Glass 		break;
73aab6724cSSimon Glass 	case PCI_CLASS_OTHERS:
74aab6724cSSimon Glass 		return "Does not fit any class";
75aab6724cSSimon Glass 		break;
76aab6724cSSimon Glass 	default:
77aab6724cSSimon Glass 	return  "???";
78aab6724cSSimon Glass 		break;
79aab6724cSSimon Glass 	};
80aab6724cSSimon Glass }
81aab6724cSSimon Glass 
pci_skip_dev(struct pci_controller * hose,pci_dev_t dev)82aab6724cSSimon Glass __weak int pci_skip_dev(struct pci_controller *hose, pci_dev_t dev)
83aab6724cSSimon Glass {
84aab6724cSSimon Glass 	/*
85aab6724cSSimon Glass 	 * Check if pci device should be skipped in configuration
86aab6724cSSimon Glass 	 */
87aab6724cSSimon Glass 	if (dev == PCI_BDF(hose->first_busno, 0, 0)) {
88aab6724cSSimon Glass #if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */
89aab6724cSSimon Glass 		/*
90aab6724cSSimon Glass 		 * Only skip configuration if "pciconfighost" is not set
91aab6724cSSimon Glass 		 */
92*00caae6dSSimon Glass 		if (env_get("pciconfighost") == NULL)
93aab6724cSSimon Glass 			return 1;
94aab6724cSSimon Glass #else
95aab6724cSSimon Glass 		return 1;
96aab6724cSSimon Glass #endif
97aab6724cSSimon Glass 	}
98aab6724cSSimon Glass 
99aab6724cSSimon Glass 	return 0;
100aab6724cSSimon Glass }
101aab6724cSSimon Glass 
1027e78b9efSSimon Glass #if !defined(CONFIG_DM_PCI) || defined(CONFIG_DM_PCI_COMPAT)
103aab6724cSSimon Glass /* Get a virtual address associated with a BAR region */
pci_map_bar(pci_dev_t pdev,int bar,int flags)104aab6724cSSimon Glass void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
105aab6724cSSimon Glass {
106aab6724cSSimon Glass 	pci_addr_t pci_bus_addr;
107aab6724cSSimon Glass 	u32 bar_response;
108aab6724cSSimon Glass 
109aab6724cSSimon Glass 	/* read BAR address */
110aab6724cSSimon Glass 	pci_read_config_dword(pdev, bar, &bar_response);
111aab6724cSSimon Glass 	pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
112aab6724cSSimon Glass 
113aab6724cSSimon Glass 	/*
114aab6724cSSimon Glass 	 * Pass "0" as the length argument to pci_bus_to_virt.  The arg
115aab6724cSSimon Glass 	 * isn't actualy used on any platform because u-boot assumes a static
116aab6724cSSimon Glass 	 * linear mapping.  In the future, this could read the BAR size
117aab6724cSSimon Glass 	 * and pass that as the size if needed.
118aab6724cSSimon Glass 	 */
119aab6724cSSimon Glass 	return pci_bus_to_virt(pdev, pci_bus_addr, flags, 0, MAP_NOCACHE);
120aab6724cSSimon Glass }
121aab6724cSSimon Glass 
pci_write_bar32(struct pci_controller * hose,pci_dev_t dev,int barnum,u32 addr_and_ctrl)122aab6724cSSimon Glass void pci_write_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum,
123aab6724cSSimon Glass 		     u32 addr_and_ctrl)
124aab6724cSSimon Glass {
125aab6724cSSimon Glass 	int bar;
126aab6724cSSimon Glass 
127aab6724cSSimon Glass 	bar = PCI_BASE_ADDRESS_0 + barnum * 4;
128aab6724cSSimon Glass 	pci_hose_write_config_dword(hose, dev, bar, addr_and_ctrl);
129aab6724cSSimon Glass }
130aab6724cSSimon Glass 
pci_read_bar32(struct pci_controller * hose,pci_dev_t dev,int barnum)131aab6724cSSimon Glass u32 pci_read_bar32(struct pci_controller *hose, pci_dev_t dev, int barnum)
132aab6724cSSimon Glass {
133aab6724cSSimon Glass 	u32 addr;
134aab6724cSSimon Glass 	int bar;
135aab6724cSSimon Glass 
136aab6724cSSimon Glass 	bar = PCI_BASE_ADDRESS_0 + barnum * 4;
137aab6724cSSimon Glass 	pci_hose_read_config_dword(hose, dev, bar, &addr);
138aab6724cSSimon Glass 	if (addr & PCI_BASE_ADDRESS_SPACE_IO)
139aab6724cSSimon Glass 		return addr & PCI_BASE_ADDRESS_IO_MASK;
140aab6724cSSimon Glass 	else
141aab6724cSSimon Glass 		return addr & PCI_BASE_ADDRESS_MEM_MASK;
142aab6724cSSimon Glass }
143aab6724cSSimon Glass 
__pci_hose_bus_to_phys(struct pci_controller * hose,pci_addr_t bus_addr,unsigned long flags,unsigned long skip_mask,phys_addr_t * pa)144aab6724cSSimon Glass int __pci_hose_bus_to_phys(struct pci_controller *hose,
145aab6724cSSimon Glass 			   pci_addr_t bus_addr,
146aab6724cSSimon Glass 			   unsigned long flags,
147aab6724cSSimon Glass 			   unsigned long skip_mask,
148aab6724cSSimon Glass 			   phys_addr_t *pa)
149aab6724cSSimon Glass {
150aab6724cSSimon Glass 	struct pci_region *res;
151aab6724cSSimon Glass 	int i;
152aab6724cSSimon Glass 
153aab6724cSSimon Glass 	for (i = 0; i < hose->region_count; i++) {
154aab6724cSSimon Glass 		res = &hose->regions[i];
155aab6724cSSimon Glass 
156aab6724cSSimon Glass 		if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
157aab6724cSSimon Glass 			continue;
158aab6724cSSimon Glass 
159aab6724cSSimon Glass 		if (res->flags & skip_mask)
160aab6724cSSimon Glass 			continue;
161aab6724cSSimon Glass 
162aab6724cSSimon Glass 		if (bus_addr >= res->bus_start &&
163aab6724cSSimon Glass 		    (bus_addr - res->bus_start) < res->size) {
164aab6724cSSimon Glass 			*pa = (bus_addr - res->bus_start + res->phys_start);
165aab6724cSSimon Glass 			return 0;
166aab6724cSSimon Glass 		}
167aab6724cSSimon Glass 	}
168aab6724cSSimon Glass 
169aab6724cSSimon Glass 	return 1;
170aab6724cSSimon Glass }
171aab6724cSSimon Glass 
pci_hose_bus_to_phys(struct pci_controller * hose,pci_addr_t bus_addr,unsigned long flags)172aab6724cSSimon Glass phys_addr_t pci_hose_bus_to_phys(struct pci_controller *hose,
173aab6724cSSimon Glass 				 pci_addr_t bus_addr,
174aab6724cSSimon Glass 				 unsigned long flags)
175aab6724cSSimon Glass {
176aab6724cSSimon Glass 	phys_addr_t phys_addr = 0;
177aab6724cSSimon Glass 	int ret;
178aab6724cSSimon Glass 
179aab6724cSSimon Glass 	if (!hose) {
180aab6724cSSimon Glass 		puts("pci_hose_bus_to_phys: invalid hose\n");
181aab6724cSSimon Glass 		return phys_addr;
182aab6724cSSimon Glass 	}
183aab6724cSSimon Glass 
184aab6724cSSimon Glass 	/*
185aab6724cSSimon Glass 	 * if PCI_REGION_MEM is set we do a two pass search with preference
186aab6724cSSimon Glass 	 * on matches that don't have PCI_REGION_SYS_MEMORY set
187aab6724cSSimon Glass 	 */
18835262850SCheng Gu 	if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
189aab6724cSSimon Glass 		ret = __pci_hose_bus_to_phys(hose, bus_addr,
190aab6724cSSimon Glass 				flags, PCI_REGION_SYS_MEMORY, &phys_addr);
191aab6724cSSimon Glass 		if (!ret)
192aab6724cSSimon Glass 			return phys_addr;
193aab6724cSSimon Glass 	}
194aab6724cSSimon Glass 
195aab6724cSSimon Glass 	ret = __pci_hose_bus_to_phys(hose, bus_addr, flags, 0, &phys_addr);
196aab6724cSSimon Glass 
197aab6724cSSimon Glass 	if (ret)
198aab6724cSSimon Glass 		puts("pci_hose_bus_to_phys: invalid physical address\n");
199aab6724cSSimon Glass 
200aab6724cSSimon Glass 	return phys_addr;
201238fe16cSBin Meng }
202238fe16cSBin Meng 
__pci_hose_phys_to_bus(struct pci_controller * hose,phys_addr_t phys_addr,unsigned long flags,unsigned long skip_mask,pci_addr_t * ba)203238fe16cSBin Meng int __pci_hose_phys_to_bus(struct pci_controller *hose,
204238fe16cSBin Meng 			   phys_addr_t phys_addr,
205238fe16cSBin Meng 			   unsigned long flags,
206238fe16cSBin Meng 			   unsigned long skip_mask,
207238fe16cSBin Meng 			   pci_addr_t *ba)
208238fe16cSBin Meng {
209238fe16cSBin Meng 	struct pci_region *res;
210238fe16cSBin Meng 	pci_addr_t bus_addr;
211238fe16cSBin Meng 	int i;
212238fe16cSBin Meng 
213238fe16cSBin Meng 	for (i = 0; i < hose->region_count; i++) {
214238fe16cSBin Meng 		res = &hose->regions[i];
215238fe16cSBin Meng 
216238fe16cSBin Meng 		if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0)
217238fe16cSBin Meng 			continue;
218238fe16cSBin Meng 
219238fe16cSBin Meng 		if (res->flags & skip_mask)
220238fe16cSBin Meng 			continue;
221238fe16cSBin Meng 
222238fe16cSBin Meng 		bus_addr = phys_addr - res->phys_start + res->bus_start;
223238fe16cSBin Meng 
224238fe16cSBin Meng 		if (bus_addr >= res->bus_start &&
225b4bd6554SMarcel Ziswiler 		    (bus_addr - res->bus_start) < res->size) {
226238fe16cSBin Meng 			*ba = bus_addr;
227238fe16cSBin Meng 			return 0;
228238fe16cSBin Meng 		}
229238fe16cSBin Meng 	}
230238fe16cSBin Meng 
231238fe16cSBin Meng 	return 1;
232238fe16cSBin Meng }
233238fe16cSBin Meng 
234fcf45692SMinghuan Lian /*
235fcf45692SMinghuan Lian  * pci_hose_phys_to_bus(): Convert physical address to bus address
236fcf45692SMinghuan Lian  * @hose:	PCI hose of the root PCI controller
237fcf45692SMinghuan Lian  * @phys_addr:	physical address to convert
238fcf45692SMinghuan Lian  * @flags:	flags of pci regions
239fcf45692SMinghuan Lian  * @return bus address if OK, 0 on error
240fcf45692SMinghuan Lian  */
pci_hose_phys_to_bus(struct pci_controller * hose,phys_addr_t phys_addr,unsigned long flags)241238fe16cSBin Meng pci_addr_t pci_hose_phys_to_bus(struct pci_controller *hose,
242238fe16cSBin Meng 				phys_addr_t phys_addr,
243238fe16cSBin Meng 				unsigned long flags)
244238fe16cSBin Meng {
245238fe16cSBin Meng 	pci_addr_t bus_addr = 0;
246238fe16cSBin Meng 	int ret;
247238fe16cSBin Meng 
248238fe16cSBin Meng 	if (!hose) {
249238fe16cSBin Meng 		puts("pci_hose_phys_to_bus: invalid hose\n");
250238fe16cSBin Meng 		return bus_addr;
251238fe16cSBin Meng 	}
252238fe16cSBin Meng 
253238fe16cSBin Meng 	/*
254238fe16cSBin Meng 	 * if PCI_REGION_MEM is set we do a two pass search with preference
255238fe16cSBin Meng 	 * on matches that don't have PCI_REGION_SYS_MEMORY set
256238fe16cSBin Meng 	 */
25735262850SCheng Gu 	if ((flags & PCI_REGION_TYPE) == PCI_REGION_MEM) {
258238fe16cSBin Meng 		ret = __pci_hose_phys_to_bus(hose, phys_addr,
259238fe16cSBin Meng 				flags, PCI_REGION_SYS_MEMORY, &bus_addr);
260238fe16cSBin Meng 		if (!ret)
261238fe16cSBin Meng 			return bus_addr;
262238fe16cSBin Meng 	}
263238fe16cSBin Meng 
264238fe16cSBin Meng 	ret = __pci_hose_phys_to_bus(hose, phys_addr, flags, 0, &bus_addr);
265238fe16cSBin Meng 
266238fe16cSBin Meng 	if (ret)
267238fe16cSBin Meng 		puts("pci_hose_phys_to_bus: invalid physical address\n");
268238fe16cSBin Meng 
269238fe16cSBin Meng 	return bus_addr;
270aab6724cSSimon Glass }
271aab6724cSSimon Glass 
pci_find_device(unsigned int vendor,unsigned int device,int index)272aab6724cSSimon Glass pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index)
273aab6724cSSimon Glass {
274aab6724cSSimon Glass 	struct pci_device_id ids[2] = { {}, {0, 0} };
275aab6724cSSimon Glass 
276aab6724cSSimon Glass 	ids[0].vendor = vendor;
277aab6724cSSimon Glass 	ids[0].device = device;
278aab6724cSSimon Glass 
279aab6724cSSimon Glass 	return pci_find_devices(ids, index);
280aab6724cSSimon Glass }
281aab6724cSSimon Glass 
pci_hose_find_devices(struct pci_controller * hose,int busnum,struct pci_device_id * ids,int * indexp)282aab6724cSSimon Glass pci_dev_t pci_hose_find_devices(struct pci_controller *hose, int busnum,
283aab6724cSSimon Glass 				struct pci_device_id *ids, int *indexp)
284aab6724cSSimon Glass {
285aab6724cSSimon Glass 	int found_multi = 0;
286aab6724cSSimon Glass 	u16 vendor, device;
287aab6724cSSimon Glass 	u8 header_type;
288aab6724cSSimon Glass 	pci_dev_t bdf;
289aab6724cSSimon Glass 	int i;
290aab6724cSSimon Glass 
291aab6724cSSimon Glass 	for (bdf = PCI_BDF(busnum, 0, 0);
292aab6724cSSimon Glass 	     bdf < PCI_BDF(busnum + 1, 0, 0);
293aab6724cSSimon Glass 	     bdf += PCI_BDF(0, 0, 1)) {
294aab6724cSSimon Glass 		if (pci_skip_dev(hose, bdf))
295aab6724cSSimon Glass 			continue;
296aab6724cSSimon Glass 
297aab6724cSSimon Glass 		if (!PCI_FUNC(bdf)) {
298aab6724cSSimon Glass 			pci_read_config_byte(bdf, PCI_HEADER_TYPE,
299aab6724cSSimon Glass 					     &header_type);
300aab6724cSSimon Glass 			found_multi = header_type & 0x80;
301aab6724cSSimon Glass 		} else {
302aab6724cSSimon Glass 			if (!found_multi)
303aab6724cSSimon Glass 				continue;
304aab6724cSSimon Glass 		}
305aab6724cSSimon Glass 
306aab6724cSSimon Glass 		pci_read_config_word(bdf, PCI_VENDOR_ID, &vendor);
307aab6724cSSimon Glass 		pci_read_config_word(bdf, PCI_DEVICE_ID, &device);
308aab6724cSSimon Glass 
309aab6724cSSimon Glass 		for (i = 0; ids[i].vendor != 0; i++) {
310aab6724cSSimon Glass 			if (vendor == ids[i].vendor &&
311aab6724cSSimon Glass 			    device == ids[i].device) {
312aab6724cSSimon Glass 				if ((*indexp) <= 0)
313aab6724cSSimon Glass 					return bdf;
314aab6724cSSimon Glass 
315aab6724cSSimon Glass 				(*indexp)--;
316aab6724cSSimon Glass 			}
317aab6724cSSimon Glass 		}
318aab6724cSSimon Glass 	}
319aab6724cSSimon Glass 
320aab6724cSSimon Glass 	return -1;
321aab6724cSSimon Glass }
322170366c1SSimon Glass 
pci_find_class(uint find_class,int index)323170366c1SSimon Glass pci_dev_t pci_find_class(uint find_class, int index)
324170366c1SSimon Glass {
325170366c1SSimon Glass 	int bus;
326170366c1SSimon Glass 	int devnum;
327170366c1SSimon Glass 	pci_dev_t bdf;
328170366c1SSimon Glass 	uint32_t class;
329170366c1SSimon Glass 
330170366c1SSimon Glass 	for (bus = 0; bus <= pci_last_busno(); bus++) {
331170366c1SSimon Glass 		for (devnum = 0; devnum < PCI_MAX_PCI_DEVICES - 1; devnum++) {
332170366c1SSimon Glass 			pci_read_config_dword(PCI_BDF(bus, devnum, 0),
333170366c1SSimon Glass 					      PCI_CLASS_REVISION, &class);
334170366c1SSimon Glass 			if (class >> 16 == 0xffff)
335170366c1SSimon Glass 				continue;
336170366c1SSimon Glass 
337170366c1SSimon Glass 			for (bdf = PCI_BDF(bus, devnum, 0);
338170366c1SSimon Glass 					bdf <= PCI_BDF(bus, devnum,
339170366c1SSimon Glass 						PCI_MAX_PCI_FUNCTIONS - 1);
340170366c1SSimon Glass 					bdf += PCI_BDF(0, 0, 1)) {
341170366c1SSimon Glass 				pci_read_config_dword(bdf, PCI_CLASS_REVISION,
342170366c1SSimon Glass 						      &class);
343170366c1SSimon Glass 				class >>= 8;
344170366c1SSimon Glass 
345170366c1SSimon Glass 				if (class != find_class)
346170366c1SSimon Glass 					continue;
347170366c1SSimon Glass 				/*
348170366c1SSimon Glass 				 * Decrement the index. We want to return the
349170366c1SSimon Glass 				 * correct device, so index is 0 for the first
350170366c1SSimon Glass 				 * matching device, 1 for the second, etc.
351170366c1SSimon Glass 				 */
352170366c1SSimon Glass 				if (index) {
353170366c1SSimon Glass 					index--;
354170366c1SSimon Glass 					continue;
355170366c1SSimon Glass 				}
356170366c1SSimon Glass 				/* Return index'th controller. */
357170366c1SSimon Glass 				return bdf;
358170366c1SSimon Glass 			}
359170366c1SSimon Glass 		}
360170366c1SSimon Glass 	}
361170366c1SSimon Glass 
362170366c1SSimon Glass 	return -ENODEV;
363170366c1SSimon Glass }
3640fe9cb0fSSimon Glass #endif /* !CONFIG_DM_PCI || CONFIG_DM_PCI_COMPAT */
365