1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #ifndef _PCI_IO_CFG_H
4 #define _PCI_IO_CFG_H
5
6 #include <stdint.h>
7 #include <arch/io.h>
8 #include <device/pci_type.h>
9
10 #define PCI_IO_CONFIG_INDEX 0xcf8
11 #define PCI_IO_CONFIG_DATA 0xcfc
12 #define PCI_IO_CONFIG_PORT_COUNT 8
13 #define PCI_IO_CONFIG_LAST_PORT (PCI_IO_CONFIG_INDEX + PCI_IO_CONFIG_PORT_COUNT - 1)
14
15 static __always_inline
pci_io_encode_addr(pci_devfn_t dev,uint16_t reg)16 uint32_t pci_io_encode_addr(pci_devfn_t dev, uint16_t reg)
17 {
18 uint32_t addr = 1U << 31;
19
20 addr |= dev >> 4;
21 addr |= reg & 0xfc;
22
23 if (CONFIG(PCI_IO_CFG_EXT))
24 addr |= (reg & 0xf00) << 16;
25
26 return addr;
27 }
28
29 static __always_inline
pci_io_read_config8(pci_devfn_t dev,uint16_t reg)30 uint8_t pci_io_read_config8(pci_devfn_t dev, uint16_t reg)
31 {
32 uint32_t addr = pci_io_encode_addr(dev, reg);
33 outl(addr, PCI_IO_CONFIG_INDEX);
34 return inb(PCI_IO_CONFIG_DATA + (reg & 3));
35 }
36
37 static __always_inline
pci_io_read_config16(pci_devfn_t dev,uint16_t reg)38 uint16_t pci_io_read_config16(pci_devfn_t dev, uint16_t reg)
39 {
40 uint32_t addr = pci_io_encode_addr(dev, reg);
41 outl(addr, PCI_IO_CONFIG_INDEX);
42 return inw(PCI_IO_CONFIG_DATA + (reg & 2));
43 }
44
45 static __always_inline
pci_io_read_config32(pci_devfn_t dev,uint16_t reg)46 uint32_t pci_io_read_config32(pci_devfn_t dev, uint16_t reg)
47 {
48 uint32_t addr = pci_io_encode_addr(dev, reg);
49 outl(addr, PCI_IO_CONFIG_INDEX);
50 return inl(PCI_IO_CONFIG_DATA);
51 }
52
53 static __always_inline
pci_io_write_config8(pci_devfn_t dev,uint16_t reg,uint8_t value)54 void pci_io_write_config8(pci_devfn_t dev, uint16_t reg, uint8_t value)
55 {
56 uint32_t addr = pci_io_encode_addr(dev, reg);
57 outl(addr, PCI_IO_CONFIG_INDEX);
58 outb(value, PCI_IO_CONFIG_DATA + (reg & 3));
59 }
60
61 static __always_inline
pci_io_write_config16(pci_devfn_t dev,uint16_t reg,uint16_t value)62 void pci_io_write_config16(pci_devfn_t dev, uint16_t reg, uint16_t value)
63 {
64 uint32_t addr = pci_io_encode_addr(dev, reg);
65 outl(addr, PCI_IO_CONFIG_INDEX);
66 outw(value, PCI_IO_CONFIG_DATA + (reg & 2));
67 }
68
69 static __always_inline
pci_io_write_config32(pci_devfn_t dev,uint16_t reg,uint32_t value)70 void pci_io_write_config32(pci_devfn_t dev, uint16_t reg, uint32_t value)
71 {
72 uint32_t addr = pci_io_encode_addr(dev, reg);
73 outl(addr, PCI_IO_CONFIG_INDEX);
74 outl(value, PCI_IO_CONFIG_DATA);
75 }
76
77 #if !CONFIG(ECAM_MMCONF_SUPPORT)
78
79 /* Avoid name collisions as different stages have different signature
80 * for these functions. The _s_ stands for simple, fundamental IO or
81 * MMIO variant.
82 */
83
84 static __always_inline
pci_s_read_config8(pci_devfn_t dev,uint16_t reg)85 uint8_t pci_s_read_config8(pci_devfn_t dev, uint16_t reg)
86 {
87 return pci_io_read_config8(dev, reg);
88 }
89
90 static __always_inline
pci_s_read_config16(pci_devfn_t dev,uint16_t reg)91 uint16_t pci_s_read_config16(pci_devfn_t dev, uint16_t reg)
92 {
93 return pci_io_read_config16(dev, reg);
94 }
95
96 static __always_inline
pci_s_read_config32(pci_devfn_t dev,uint16_t reg)97 uint32_t pci_s_read_config32(pci_devfn_t dev, uint16_t reg)
98 {
99 return pci_io_read_config32(dev, reg);
100 }
101
102 static __always_inline
pci_s_write_config8(pci_devfn_t dev,uint16_t reg,uint8_t value)103 void pci_s_write_config8(pci_devfn_t dev, uint16_t reg, uint8_t value)
104 {
105 pci_io_write_config8(dev, reg, value);
106 }
107
108 static __always_inline
pci_s_write_config16(pci_devfn_t dev,uint16_t reg,uint16_t value)109 void pci_s_write_config16(pci_devfn_t dev, uint16_t reg, uint16_t value)
110 {
111 pci_io_write_config16(dev, reg, value);
112 }
113
114 static __always_inline
pci_s_write_config32(pci_devfn_t dev,uint16_t reg,uint32_t value)115 void pci_s_write_config32(pci_devfn_t dev, uint16_t reg, uint32_t value)
116 {
117 pci_io_write_config32(dev, reg, value);
118 }
119
120 #endif
121
122 #endif /* _PCI_IO_CFG_H */
123