xref: /openbmc/u-boot/arch/x86/cpu/pci.c (revision c5f18a0b)
1 /*
2  * Copyright (c) 2011 The Chromium OS Authors.
3  * (C) Copyright 2008,2009
4  * Graeme Russ, <graeme.russ@gmail.com>
5  *
6  * (C) Copyright 2002
7  * Daniel Engström, Omicron Ceti AB, <daniel@omicron.se>
8  *
9  * SPDX-License-Identifier:	GPL-2.0+
10  */
11 
12 #include <common.h>
13 #include <dm.h>
14 #include <errno.h>
15 #include <malloc.h>
16 #include <pci.h>
17 #include <asm/io.h>
18 #include <asm/pci.h>
19 
20 DECLARE_GLOBAL_DATA_PTR;
21 
22 static struct pci_controller *get_hose(void)
23 {
24 	if (gd->hose)
25 		return gd->hose;
26 
27 	return pci_bus_to_hose(0);
28 }
29 
30 unsigned int x86_pci_read_config8(pci_dev_t dev, unsigned where)
31 {
32 	uint8_t value;
33 
34 	if (pci_hose_read_config_byte(get_hose(), dev, where, &value))
35 		return -1U;
36 
37 	return value;
38 }
39 
40 unsigned int x86_pci_read_config16(pci_dev_t dev, unsigned where)
41 {
42 	uint16_t value;
43 
44 	if (pci_hose_read_config_word(get_hose(), dev, where, &value))
45 		return -1U;
46 
47 	return value;
48 }
49 
50 unsigned int x86_pci_read_config32(pci_dev_t dev, unsigned where)
51 {
52 	uint32_t value;
53 
54 	if (pci_hose_read_config_dword(get_hose(), dev, where, &value))
55 		return -1U;
56 
57 	return value;
58 }
59 
60 void x86_pci_write_config8(pci_dev_t dev, unsigned where, unsigned value)
61 {
62 	pci_hose_write_config_byte(get_hose(), dev, where, value);
63 }
64 
65 void x86_pci_write_config16(pci_dev_t dev, unsigned where, unsigned value)
66 {
67 	pci_hose_write_config_word(get_hose(), dev, where, value);
68 }
69 
70 void x86_pci_write_config32(pci_dev_t dev, unsigned where, unsigned value)
71 {
72 	pci_hose_write_config_dword(get_hose(), dev, where, value);
73 }
74 
75 int pci_x86_read_config(struct udevice *bus, pci_dev_t bdf, uint offset,
76 			ulong *valuep, enum pci_size_t size)
77 {
78 	outl(bdf | (offset & 0xfc) | PCI_CFG_EN, PCI_REG_ADDR);
79 	switch (size) {
80 	case PCI_SIZE_8:
81 		*valuep = inb(PCI_REG_DATA + (offset & 3));
82 		break;
83 	case PCI_SIZE_16:
84 		*valuep = inw(PCI_REG_DATA + (offset & 2));
85 		break;
86 	case PCI_SIZE_32:
87 		*valuep = inl(PCI_REG_DATA);
88 		break;
89 	}
90 
91 	return 0;
92 }
93 
94 int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset,
95 			 ulong value, enum pci_size_t size)
96 {
97 	outl(bdf | (offset & 0xfc) | PCI_CFG_EN, PCI_REG_ADDR);
98 	switch (size) {
99 	case PCI_SIZE_8:
100 		outb(value, PCI_REG_DATA + (offset & 3));
101 		break;
102 	case PCI_SIZE_16:
103 		outw(value, PCI_REG_DATA + (offset & 2));
104 		break;
105 	case PCI_SIZE_32:
106 		outl(value, PCI_REG_DATA);
107 		break;
108 	}
109 
110 	return 0;
111 }
112 
113 void pci_assign_irqs(int bus, int device, u8 irq[4])
114 {
115 	pci_dev_t bdf;
116 	int func;
117 	u16 vendor;
118 	u8 pin, line;
119 
120 	for (func = 0; func < 8; func++) {
121 		bdf = PCI_BDF(bus, device, func);
122 		vendor = x86_pci_read_config16(bdf, PCI_VENDOR_ID);
123 		if (vendor == 0xffff || vendor == 0x0000)
124 			continue;
125 
126 		pin = x86_pci_read_config8(bdf, PCI_INTERRUPT_PIN);
127 
128 		/* PCI spec says all values except 1..4 are reserved */
129 		if ((pin < 1) || (pin > 4))
130 			continue;
131 
132 		line = irq[pin - 1];
133 		if (!line)
134 			continue;
135 
136 		debug("Assigning IRQ %d to PCI device %d.%x.%d (INT%c)\n",
137 		      line, bus, device, func, 'A' + pin - 1);
138 
139 		x86_pci_write_config8(bdf, PCI_INTERRUPT_LINE, line);
140 	}
141 }
142