xref: /haiku/src/add-ons/kernel/busses/pci/designware/DWPCIController.h (revision 1978089f7cec856677e46204e992c7273d70b9af)
1 /*
2  * Copyright 2022, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #ifndef _PCICONTROLLERDW_H_
8 #define _PCICONTROLLERDW_H_
9 
10 #include <bus/PCI.h>
11 #include <arch/generic/msi.h>
12 
13 #include <AutoDeleterOS.h>
14 #include <lock.h>
15 #include <util/Vector.h>
16 
17 
18 #define CHECK_RET(err) {status_t _err = (err); if (_err < B_OK) return _err;}
19 
20 #define DESIGNWARE_PCI_DRIVER_MODULE_NAME "busses/pci/designware/driver_v1"
21 
22 
23 enum {
24 	fdtPciRangeConfig      = 0x00000000,
25 	fdtPciRangeIoPort      = 0x01000000,
26 	fdtPciRangeMmio32Bit   = 0x02000000,
27 	fdtPciRangeMmio64Bit   = 0x03000000,
28 	fdtPciRangeTypeMask    = 0x03000000,
29 	fdtPciRangeAliased     = 0x20000000,
30 	fdtPciRangePrefechable = 0x40000000,
31 	fdtPciRangeRelocatable = 0x80000000,
32 };
33 
34 
35 enum PciBarKind {
36 	kRegIo,
37 	kRegMmio32,
38 	kRegMmio64,
39 	kRegMmio1MB,
40 	kRegUnknown,
41 };
42 
43 
44 union PciAddress {
45 	struct {
46 		uint32 offset: 8;
47 		uint32 function: 3;
48 		uint32 device: 5;
49 		uint32 bus: 8;
50 		uint32 unused: 8;
51 	};
52 	uint32 val;
53 };
54 
55 union PciAddressEcam {
56 	struct {
57 		uint32 offset: 12;
58 		uint32 function: 3;
59 		uint32 device: 5;
60 		uint32 bus: 8;
61 		uint32 unused: 4;
62 	};
63 	uint32 val;
64 };
65 
66 struct RegisterRange {
67 	phys_addr_t parentBase;
68 	phys_addr_t childBase;
69 	uint64 size;
70 };
71 
72 struct InterruptMapMask {
73 	uint32_t childAdr;
74 	uint32_t childIrq;
75 };
76 
77 struct InterruptMap {
78 	uint32_t childAdr;
79 	uint32_t childIrq;
80 	uint32_t parentIrqCtrl;
81 	uint32_t parentIrq;
82 };
83 
84 
85 enum {
86 	kPciAtuOffset = 0x300000,
87 };
88 
89 enum {
90 	kPciAtuOutbound  = 0,
91 	kPciAtuInbound   = 1,
92 };
93 
94 enum {
95 	// ctrl1
96 	kPciAtuTypeMem  = 0,
97 	kPciAtuTypeIo   = 2,
98 	kPciAtuTypeCfg0 = 4,
99 	kPciAtuTypeCfg1 = 5,
100 	// ctrl2
101 	kPciAtuBarModeEnable = 1 << 30,
102 	kPciAtuEnable        = 1 << 31,
103 };
104 
105 struct PciAtuRegs {
106 	uint32 ctrl1;
107 	uint32 ctrl2;
108 	uint32 baseLo;
109 	uint32 baseHi;
110 	uint32 limit;
111 	uint32 targetLo;
112 	uint32 targetHi;
113 	uint32 unused[57];
114 };
115 
116 struct PciDbiRegs {
117 	uint8 unknown0[0x700];
118 
119 	uint32 unknown1[3];
120 	uint32 portAfr;
121 	uint32 linkControl;
122 	uint32 unknown2[5];
123 	uint32 portDebug0;
124 	uint32 portDebug1;
125 	uint32 unknown3[55];
126 	uint32 linkWidthSpeedControl;
127 	uint32 unknown4[4];
128 	uint32 msiAddrLo;
129 	uint32 msiAddrHi;
130 	struct {
131 		uint32 enable;
132 		uint32 mask;
133 		uint32 status;
134 	} msiIntr[8];
135 	uint32 unknown5[13];
136 	uint32 miscControl1Off;
137 	uint32 miscPortMultiLaneCtrl;
138 	uint32 unknown6[15];
139 
140 	uint32 atuViewport;
141 	uint32 atuCr1;
142 	uint32 atuCr2;
143 	uint32 atuBaseLo;
144 	uint32 atuBaseHi;
145 	uint32 atuLimit;
146 	uint32 atuTargetLo;
147 	uint32 atuTargetHi;
148 	uint32 unknown7;
149 	uint32 atuLimitHi;
150 	uint32 unknown8[8];
151 
152 	uint32 msixDoorbell;
153 	uint32 unknown9[117];
154 
155 	uint32 plChkRegControlStatus;
156 	uint32 unknown10;
157 	uint32 plChkRegErrAddr;
158 	uint32 unknown11[309];
159 };
160 
161 
162 class MsiInterruptCtrlDW: public MSIInterface {
163 public:
164 			virtual				~MsiInterruptCtrlDW() = default;
165 
166 			status_t			Init(PciDbiRegs volatile* dbiRegs, int32 msiIrq);
167 
168 			status_t			AllocateVectors(uint8 count, uint8& startVector, uint64& address,
169 									uint16& data) final;
170 			void				FreeVectors(uint8 count, uint8 startVector) final;
171 
172 
173 private:
174 	static	int32				InterruptReceived(void* arg);
175 	inline	int32				InterruptReceivedInt();
176 
177 private:
178 			PciDbiRegs volatile* fDbiRegs {};
179 
180 			uint32				fAllocatedMsiIrqs[1];
181 			phys_addr_t			fMsiPhysAddr {};
182 			long				fMsiStartIrq {};
183 			uint64				fMsiData {};
184 };
185 
186 
187 class DWPCIController {
188 public:
189 	static float SupportsDevice(device_node* parent);
190 	static status_t RegisterDevice(device_node* parent);
191 	static status_t InitDriver(device_node* node, DWPCIController*& outDriver);
192 	void UninitDriver();
193 
194 	status_t ReadConfig(
195 				uint8 bus, uint8 device, uint8 function,
196 				uint16 offset, uint8 size, uint32 &value);
197 
198 	status_t WriteConfig(
199 				uint8 bus, uint8 device, uint8 function,
200 				uint16 offset, uint8 size, uint32 value);
201 
202 	status_t GetMaxBusDevices(int32& count);
203 
204 	status_t ReadIrq(
205 				uint8 bus, uint8 device, uint8 function,
206 				uint8 pin, uint8& irq);
207 
208 	status_t WriteIrq(
209 				uint8 bus, uint8 device, uint8 function,
210 				uint8 pin, uint8 irq);
211 
212 	status_t GetRange(uint32 index, pci_resource_range* range);
213 
214 private:
215 	status_t ReadResourceInfo();
216 	inline status_t InitDriverInt(device_node* node);
217 
218 	inline addr_t ConfigAddress(uint8 bus, uint8 device, uint8 function, uint16 offset);
219 
220 	PciDbiRegs volatile* GetDbuRegs() {return (PciDbiRegs volatile*)fDbiBase;}
221 	status_t AtuMap(uint32 index, uint32 direction, uint32 type,
222 		uint64 parentAdr, uint64 childAdr, uint32 size);
223 	void AtuDump();
224 
225 private:
226 	spinlock fLock = B_SPINLOCK_INITIALIZER;
227 
228 	device_node* fNode {};
229 
230 	AreaDeleter fConfigArea;
231 	addr_t fConfigPhysBase {};
232 	addr_t fConfigBase {};
233 	size_t fConfigSize {};
234 
235 	Vector<pci_resource_range> fResourceRanges;
236 	InterruptMapMask fInterruptMapMask {};
237 	uint32 fInterruptMapLen {};
238 	ArrayDeleter<InterruptMap> fInterruptMap;
239 
240 	AreaDeleter fDbiArea;
241 	addr_t fDbiPhysBase {};
242 	addr_t fDbiBase {};
243 	size_t fDbiSize {};
244 
245 	MsiInterruptCtrlDW fIrqCtrl;
246 };
247 
248 
249 extern device_manager_info* gDeviceManager;
250 
251 #endif	// _PCICONTROLLERDW_H_
252