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