xref: /haiku/src/add-ons/kernel/bus_managers/fdt/fdt_module.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*
2  * Copyright 2014, Ithamar R. Adema <ithamar@upgrade-android.com>
3  * All rights reserved. Distributed under the terms of the MIT License.
4  *
5  * Copyright 2015-2021, Haiku, Inc. All rights reserved.
6  * Distributed under the terms of the MIT License.
7  */
8 
9 
10 #include <drivers/bus/FDT.h>
11 #include <KernelExport.h>
12 #include <util/kernel_cpp.h>
13 #include <device_manager.h>
14 
15 #include <AutoDeleter.h>
16 #include <AutoDeleterDrivers.h>
17 #include <HashMap.h>
18 #include <debug.h>
19 
20 extern "C" {
21 #include <libfdt_env.h>
22 #include <fdt.h>
23 #include <libfdt.h>
24 };
25 
26 
27 //#define TRACE_FDT
28 #ifdef TRACE_FDT
29 #define TRACE(x...) dprintf(x)
30 #else
31 #define TRACE(x...)
32 #endif
33 
34 
35 extern void* gFDT;
36 
37 device_manager_info* gDeviceManager;
38 
39 extern fdt_bus_module_info gBusModule;
40 extern fdt_device_module_info gDeviceModule;
41 
42 
43 //#pragma mark -
44 
45 
46 struct fdt_bus {
47 	device_node* node;
48 	HashMap<HashKey32<int32>, device_node*> phandles;
49 };
50 
51 
52 struct fdt_device {
53 	device_node* node;
54 	device_node* bus;
55 };
56 
57 
58 static status_t
59 fdt_register_node(fdt_bus* bus, int node, device_node* parentDev,
60 	device_node*& curDev)
61 {
62 	TRACE("%s('%s', %p)\n", __func__, fdt_get_name(gFDT, node, NULL),
63 		parentDev);
64 
65 	const void* prop; int propLen;
66 	device_attr attrs[8];
67 	device_attr* attr = attrs;
68 	int nameLen = 0;
69 	const char *name = fdt_get_name(gFDT, node, &nameLen);
70 
71 	if (name == NULL) {
72 		dprintf("%s ERROR: fdt_get_name: %s\n", __func__,
73 			fdt_strerror(nameLen));
74 		return B_ERROR;
75 	}
76 
77 	*attr++ = (device_attr) { B_DEVICE_BUS, B_STRING_TYPE, {string: "fdt"}};
78 	*attr++ = (device_attr) { B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
79 		{ string: (strcmp(name, "") != 0) ? name : "Root" } };
80 	*attr++ = (device_attr) { "fdt/node", B_UINT32_TYPE, {ui32: (uint32)node}};
81 	*attr++ = (device_attr) { "fdt/name", B_STRING_TYPE, {string: name}};
82 
83 	prop = fdt_getprop(gFDT, node, "device_type", &propLen);
84 	if (prop != NULL) {
85 		*attr++ = (device_attr) { "fdt/device_type", B_STRING_TYPE,
86 			{ string: (const char*)prop } };
87 	}
88 
89 	prop = fdt_getprop(gFDT, node, "compatible", &propLen);
90 
91 	if (prop != NULL) {
92 		*attr++ = (device_attr){ "fdt/compatible", B_STRING_TYPE,
93 			{ string: (const char*)prop } };
94 	}
95 
96 	*attr = {0};
97 
98 	status_t res = gDeviceManager->register_node(parentDev,
99 		"bus_managers/fdt/driver_v1", attrs, NULL, &curDev);
100 
101 	if (res < B_OK)
102 		return res;
103 
104 	prop = fdt_getprop(gFDT, node, "phandle", &propLen);
105 
106 	if (prop != NULL)
107 		bus->phandles.Put(fdt32_to_cpu(*(uint32_t*)prop), curDev);
108 
109 	return B_OK;
110 }
111 
112 
113 static void
114 fdt_traverse(fdt_bus* bus, int &node, int &depth, device_node* parentDev)
115 {
116 	int curDepth = depth;
117 #if 0
118 	for (int i = 0; i < depth; i++) dprintf("  ");
119 	dprintf("node('%s')\n", fdt_get_name(gFDT, node, NULL));
120 #endif
121 	device_node* curDev;
122 	fdt_register_node(bus, node, parentDev, curDev);
123 
124 	node = fdt_next_node(gFDT, node, &depth);
125 	while (node >= 0 && depth == curDepth + 1) {
126 		fdt_traverse(bus, node, depth, curDev);
127 	}
128 }
129 
130 
131 //#pragma mark bus
132 
133 static int32
134 fdt_bus_std_ops(int32 op, ...)
135 {
136 	switch (op) {
137 		case B_MODULE_INIT:
138 			TRACE("fdt root init\n");
139 			return B_OK;
140 
141 		case B_MODULE_UNINIT:
142 			TRACE("fdt root uninit\n");
143 			return B_OK;
144 	}
145 
146 	return B_BAD_VALUE;
147 }
148 
149 
150 static float
151 fdt_bus_supports_device(device_node* parent)
152 {
153 	TRACE("fdt_bus_supports_device\n");
154 
155 	// make sure parent is really device root
156 	const char* bus;
157 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
158 		return B_ERROR;
159 
160 	if (strcmp(bus, "root"))
161 		return 0.0;
162 
163 	return 1.0;
164 }
165 
166 
167 static status_t
168 fdt_bus_register_device(device_node* parent)
169 {
170 	TRACE("+fdt_bus_register_device\n");
171 	struct ScopeExit {
172 		ScopeExit() {TRACE("-fdt_bus_register_device\n");}
173 	} scopeExit;
174 
175 	device_attr attrs[] = {
176 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "FDT"}},
177 		{B_DEVICE_FLAGS, B_UINT32_TYPE, {ui32: B_KEEP_DRIVER_LOADED}},
178 		{}
179 	};
180 
181 	return gDeviceManager->register_node(
182 		parent, "bus_managers/fdt/root/driver_v1", attrs, NULL, NULL);
183 }
184 
185 
186 static status_t
187 fdt_bus_init(device_node* node, void** cookie)
188 {
189 	TRACE("fdt_bus_init\n");
190 
191 	if (gFDT == NULL) {
192 		TRACE("FDT is NULL!\n");
193 		return B_DEVICE_NOT_FOUND;
194 	}
195 
196 	ObjectDeleter<fdt_bus> bus(new(std::nothrow) fdt_bus());
197 	if (!bus.IsSet())
198 		return B_NO_MEMORY;
199 
200 	bus->node = node;
201 	*cookie = bus.Detach();
202 	return B_OK;
203 }
204 
205 
206 static void
207 fdt_bus_uninit(void* cookie)
208 {
209 	TRACE("fdt_bus_uninit\n");
210 
211 	ObjectDeleter<fdt_bus> bus((fdt_bus*)cookie);
212 }
213 
214 
215 static status_t
216 fdt_bus_register_child_devices(void* cookie)
217 {
218 	TRACE("fdt_bus_register_child_devices\n");
219 
220 	fdt_bus* bus = (fdt_bus*)cookie;
221 
222 	int node = -1, depth = -1;
223 	node = fdt_next_node(gFDT, node, &depth);
224 	fdt_traverse(bus, node, depth, bus->node);
225 
226 	return B_OK;
227 }
228 
229 
230 device_node*
231 fdt_bus_node_by_phandle(fdt_bus* bus, int phandle)
232 {
233 	ASSERT(bus != NULL);
234 
235 	device_node** devNode;
236 	if (!bus->phandles.Get(phandle, devNode))
237 		return NULL;
238 
239 	return *devNode;
240 }
241 
242 
243 //#pragma mark device
244 
245 
246 static status_t
247 fdt_device_std_ops(int32 op, ...)
248 {
249 	switch (op) {
250 		case B_MODULE_INIT:
251 		case B_MODULE_UNINIT:
252 			return B_OK;
253 	}
254 
255 	return B_BAD_VALUE;
256 }
257 
258 
259 static status_t
260 fdt_device_init_driver(device_node* node, void** cookie)
261 {
262 	TRACE("fdt_device_init_driver()\n");
263 
264 	ObjectDeleter<fdt_device> dev(new(std::nothrow) fdt_device());
265 	if (!dev.IsSet())
266 		return B_NO_MEMORY;
267 
268 	dev->node = node;
269 
270 	// get bus from parent node
271 	DeviceNodePutter<&gDeviceManager> parent(
272 		gDeviceManager->get_parent_node(node));
273 	driver_module_info* parentModule;
274 	void* parentDev;
275 	ASSERT(gDeviceManager->get_driver(
276 		parent.Get(), &parentModule, &parentDev) >= B_OK);
277 	if (parentModule == (driver_module_info*)&gDeviceModule)
278 		dev->bus = ((fdt_device*)parentDev)->bus;
279 	else if (parentModule == (driver_module_info*)&gBusModule)
280 		dev->bus = parent.Get();
281 	else
282 		panic("bad parent node");
283 
284 	*cookie = dev.Detach();
285 	return B_OK;
286 }
287 
288 
289 static void
290 fdt_device_uninit_driver(void* cookie)
291 {
292 	TRACE("fdt_device_uninit_driver()\n");
293 	ObjectDeleter<fdt_device> dev((fdt_device*)cookie);
294 }
295 
296 
297 static status_t
298 fdt_device_register_child_devices(void* cookie)
299 {
300 	TRACE("fdt_device_register_child_devices()\n");
301 	return B_OK;
302 }
303 
304 
305 static device_node*
306 fdt_device_get_bus(fdt_device* dev)
307 {
308 	ASSERT(dev != NULL);
309 	return dev->bus;
310 }
311 
312 
313 static const char*
314 fdt_device_get_name(fdt_device* dev)
315 {
316 	ASSERT(dev != NULL);
317 
318 	uint32 fdtNode;
319 	ASSERT(gDeviceManager->get_attr_uint32(
320 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
321 
322 	return fdt_get_name(gFDT, (int)fdtNode, NULL);
323 }
324 
325 
326 static const void*
327 fdt_device_get_prop(fdt_device* dev, const char* name, int* len)
328 {
329 	ASSERT(dev != NULL);
330 
331 	uint32 fdtNode;
332 	ASSERT(gDeviceManager->get_attr_uint32(
333 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
334 
335 	return fdt_getprop(gFDT, (int)fdtNode, name, len);
336 }
337 
338 
339 static bool
340 fdt_device_get_reg(fdt_device* dev, uint32 ord, uint64* regs, uint64* len)
341 {
342 	ASSERT(dev != NULL);
343 
344 	uint32 fdtNode;
345 	ASSERT(gDeviceManager->get_attr_uint32(
346 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
347 
348 	int propLen;
349 	const void* prop = fdt_getprop(gFDT, (int)fdtNode, "reg", &propLen);
350 	if (prop == NULL)
351 		return false;
352 
353 	// TODO: use '#address-cells', '#size-cells' in parent node to identify
354 	// field sizes
355 
356 	if ((ord + 1)*16 > (uint32)propLen)
357 		return false;
358 
359 	if (regs != NULL)
360 		*regs = fdt64_to_cpu(*(((uint64*)prop) + 2*ord));
361 
362 	if (len != NULL)
363 		*len = fdt64_to_cpu(*(((uint64*)prop) + 2*ord + 1));
364 
365 	return true;
366 }
367 
368 
369 static bool
370 fdt_device_get_interrupt(fdt_device* dev, uint32 ord,
371 	device_node** interruptController, uint64* interrupt)
372 {
373 	ASSERT(dev != NULL);
374 
375 	uint32 fdtNode;
376 	ASSERT(gDeviceManager->get_attr_uint32(
377 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
378 
379 	// TODO: handle other interrupt encodings
380 	int propLen;
381 	const void* prop = fdt_getprop(gFDT, (int)fdtNode, "interrupts-extended",
382 		&propLen);
383 	if (prop == NULL) {
384 		prop = fdt_getprop(gFDT, (int)fdtNode, "interrupts",
385 			&propLen);
386 		if (prop == NULL)
387 			return false;
388 
389 		if ((ord + 1)*4 > (uint32)propLen)
390 			return false;
391 
392 		if (interrupt != NULL)
393 			*interrupt = fdt32_to_cpu(*(((uint32*)prop) + ord));
394 
395 		if (interruptController != NULL) {
396 			prop = fdt_getprop(gFDT, (int)fdtNode, "interrupt-parent",
397 				&propLen);
398 			if (prop != NULL && propLen == 4) {
399 				uint32 phandle = fdt32_to_cpu(*(uint32*)prop);
400 
401 				fdt_bus* bus;
402 				ASSERT(gDeviceManager->get_driver(
403 					dev->bus, NULL, (void**)&bus) >= B_OK);
404 
405 				*interruptController = fdt_bus_node_by_phandle(bus, phandle);
406 			}
407 		}
408 		return true;
409 	}
410 
411 	// TODO: use '#interrupt-cells' to identify field sizes
412 
413 	if ((ord + 1)*8 > (uint32)propLen)
414 		return false;
415 
416 	if (interruptController != NULL) {
417 		uint32 phandle = fdt32_to_cpu(*(((uint32*)prop) + 2*ord));
418 
419 		fdt_bus* bus;
420 		ASSERT(gDeviceManager->get_driver(
421 			dev->bus, NULL, (void**)&bus) >= B_OK);
422 
423 		*interruptController = fdt_bus_node_by_phandle(bus, phandle);
424 	}
425 
426 	if (interrupt != NULL)
427 		*interrupt = fdt32_to_cpu(*(((uint32*)prop) + 2*ord + 1));
428 
429 	return true;
430 }
431 
432 
433 //#pragma mark -
434 
435 fdt_bus_module_info gBusModule = {
436 	{
437 		{
438 			"bus_managers/fdt/root/driver_v1",
439 			0,
440 			fdt_bus_std_ops
441 		},
442 		fdt_bus_supports_device,
443 		fdt_bus_register_device,
444 		fdt_bus_init,
445 		fdt_bus_uninit,
446 		fdt_bus_register_child_devices,
447 		NULL,	// rescan devices
448 		NULL,	// device removed
449 	},
450 	fdt_bus_node_by_phandle,
451 };
452 
453 
454 fdt_device_module_info gDeviceModule = {
455 	{
456 		{
457 			"bus_managers/fdt/driver_v1",
458 			0,
459 			fdt_device_std_ops
460 		},
461 
462 		NULL,		// supports device
463 		NULL,		// register device (our parent registered us)
464 		fdt_device_init_driver,
465 		fdt_device_uninit_driver,
466 		fdt_device_register_child_devices,
467 		NULL,		// rescan devices
468 		NULL,		// device removed
469 	},
470 	fdt_device_get_bus,
471 	fdt_device_get_name,
472 	fdt_device_get_prop,
473 	fdt_device_get_reg,
474 	fdt_device_get_interrupt,
475 };
476 
477 
478 module_info* modules[] = {
479 	(module_info*)&gBusModule,
480 	(module_info*)&gDeviceModule,
481 	NULL
482 };
483 
484 module_dependency module_dependencies[] = {
485 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
486 	{ NULL }
487 };
488