1/*
2 * Copyright 2022, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#ifndef _ECAM_PCI_CONTROLLER_H_
8#define _ECAM_PCI_CONTROLLER_H_
9
10#include <bus/PCI.h>
11#include <bus/FDT.h>
12#include <ACPI.h>
13
14#include <AutoDeleterOS.h>
15#include <lock.h>
16#include <util/Vector.h>
17
18
19#define CHECK_RET(err) {status_t _err = (err); if (_err < B_OK) return _err;}
20
21#define ECAM_PCI_DRIVER_MODULE_NAME "busses/pci/ecam/driver_v1"
22
23
24enum {
25	fdtPciRangeConfig      = 0x00000000,
26	fdtPciRangeIoPort      = 0x01000000,
27	fdtPciRangeMmio32Bit   = 0x02000000,
28	fdtPciRangeMmio64Bit   = 0x03000000,
29	fdtPciRangeTypeMask    = 0x03000000,
30	fdtPciRangeAliased     = 0x20000000,
31	fdtPciRangePrefechable = 0x40000000,
32	fdtPciRangeRelocatable = 0x80000000,
33};
34
35
36enum PciBarKind {
37	kRegIo,
38	kRegMmio32,
39	kRegMmio64,
40	kRegMmio1MB,
41	kRegUnknown,
42};
43
44
45union PciAddress {
46	struct {
47		uint32 offset: 8;
48		uint32 function: 3;
49		uint32 device: 5;
50		uint32 bus: 8;
51		uint32 unused: 8;
52	};
53	uint32 val;
54};
55
56union PciAddressEcam {
57	struct {
58		uint32 offset: 12;
59		uint32 function: 3;
60		uint32 device: 5;
61		uint32 bus: 8;
62		uint32 unused: 4;
63	};
64	uint32 val;
65};
66
67struct RegisterRange {
68	phys_addr_t parentBase;
69	phys_addr_t childBase;
70	uint64 size;
71};
72
73struct InterruptMapMask {
74	uint32_t childAdr;
75	uint32_t childIrq;
76};
77
78struct InterruptMap {
79	uint32_t childAdr;
80	uint32_t childIrq;
81	uint32_t parentIrqCtrl;
82	uint32_t parentIrq;
83};
84
85
86class ECAMPCIController {
87public:
88	virtual ~ECAMPCIController() = default;
89
90	static float SupportsDevice(device_node* parent);
91	static status_t RegisterDevice(device_node* parent);
92	static status_t InitDriver(device_node* node, ECAMPCIController*& outDriver);
93	void UninitDriver();
94
95	status_t ReadConfig(
96				uint8 bus, uint8 device, uint8 function,
97				uint16 offset, uint8 size, uint32 &value);
98
99	status_t WriteConfig(
100				uint8 bus, uint8 device, uint8 function,
101				uint16 offset, uint8 size, uint32 value);
102
103	status_t GetMaxBusDevices(int32& count);
104
105	status_t ReadIrq(
106				uint8 bus, uint8 device, uint8 function,
107				uint8 pin, uint8& irq);
108
109	status_t WriteIrq(
110				uint8 bus, uint8 device, uint8 function,
111				uint8 pin, uint8 irq);
112
113	status_t GetRange(uint32 index, pci_resource_range* range);
114
115	virtual status_t Finalize() = 0;
116
117private:
118	inline addr_t ConfigAddress(uint8 bus, uint8 device, uint8 function, uint16 offset);
119
120protected:
121	virtual status_t ReadResourceInfo() = 0;
122
123protected:
124	struct mutex fLock = MUTEX_INITIALIZER("ECAM PCI");
125
126	device_node* fNode{};
127
128	AreaDeleter fRegsArea;
129	uint8 volatile* fRegs{};
130	uint64 fRegsLen{};
131
132	Vector<pci_resource_range> fResourceRanges;
133};
134
135
136class ECAMPCIControllerACPI: public ECAMPCIController {
137public:
138	~ECAMPCIControllerACPI() = default;
139
140	status_t Finalize() final;
141
142protected:
143	status_t ReadResourceInfo() final;
144	status_t ReadResourceInfo(device_node* parent);
145
146	uint8 fStartBusNumber{};
147	uint8 fEndBusNumber{};
148
149private:
150	friend class X86PCIControllerMethPcie;
151
152	static acpi_status AcpiCrsScanCallback(acpi_resource *res, void *context);
153	inline acpi_status AcpiCrsScanCallbackInt(acpi_resource *res);
154};
155
156
157class ECAMPCIControllerFDT: public ECAMPCIController {
158public:
159	~ECAMPCIControllerFDT() = default;
160
161	status_t Finalize() final;
162
163protected:
164	status_t ReadResourceInfo() final;
165
166private:
167	static void FinalizeInterrupts(fdt_device_module_info* fdtModule,
168		struct fdt_interrupt_map* interruptMap, int bus, int device, int function);
169};
170
171
172extern device_manager_info* gDeviceManager;
173extern pci_module_info* gPCI;
174
175#endif	// _ECAM_PCI_CONTROLLER_H_
176