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
23enum {
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
35enum PciBarKind {
36	kRegIo,
37	kRegMmio32,
38	kRegMmio64,
39	kRegMmio1MB,
40	kRegUnknown,
41};
42
43
44union 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
55union 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
66struct RegisterRange {
67	phys_addr_t parentBase;
68	phys_addr_t childBase;
69	uint64 size;
70};
71
72struct InterruptMapMask {
73	uint32_t childAdr;
74	uint32_t childIrq;
75};
76
77struct InterruptMap {
78	uint32_t childAdr;
79	uint32_t childIrq;
80	uint32_t parentIrqCtrl;
81	uint32_t parentIrq;
82};
83
84
85enum {
86	kPciAtuOffset = 0x300000,
87};
88
89enum {
90	kPciAtuOutbound  = 0,
91	kPciAtuInbound   = 1,
92};
93
94enum {
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
105struct 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
116struct 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
162class MsiInterruptCtrlDW: public MSIInterface {
163public:
164			virtual				~MsiInterruptCtrlDW() = default;
165
166			status_t			Init(PciDbiRegs volatile* dbiRegs, int32 msiIrq);
167
168			status_t			AllocateVectors(uint32 count, uint32& startVector, uint64& address,
169									uint32& data) final;
170			void				FreeVectors(uint32 count, uint32 startVector) final;
171
172
173private:
174	static	int32				InterruptReceived(void* arg);
175	inline	int32				InterruptReceivedInt();
176
177private:
178			PciDbiRegs volatile* fDbiRegs {};
179
180			uint32				fAllocatedMsiIrqs[1];
181			phys_addr_t			fMsiPhysAddr {};
182			int32				fMsiStartIrq {};
183			uint64				fMsiData {};
184};
185
186
187class DWPCIController {
188public:
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
214private:
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
225private:
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
249extern device_manager_info* gDeviceManager;
250
251#endif	// _PCICONTROLLERDW_H_
252