xref: /haiku/src/add-ons/kernel/bus_managers/fdt/fdt_module.cpp (revision 52c4471a3024d2eb81fe88e2c3982b9f8daa5e56)
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-2022, 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 <util/Vector.h>
14 #include <device_manager.h>
15 
16 #include <AutoDeleter.h>
17 #include <AutoDeleterDrivers.h>
18 #include <HashMap.h>
19 #include <debug.h>
20 
21 extern "C" {
22 #include <libfdt_env.h>
23 #include <fdt.h>
24 #include <libfdt.h>
25 };
26 
27 
28 //#define TRACE_FDT
29 #ifdef TRACE_FDT
30 #define TRACE(x...) dprintf(x)
31 #else
32 #define TRACE(x...)
33 #endif
34 
35 
36 #define GIC_INTERRUPT_CELL_TYPE     0
37 #define GIC_INTERRUPT_CELL_ID       1
38 #define GIC_INTERRUPT_CELL_FLAGS    2
39 #define GIC_INTERRUPT_TYPE_SPI      0
40 #define GIC_INTERRUPT_TYPE_PPI      1
41 #define GIC_INTERRUPT_BASE_SPI      32
42 #define GIC_INTERRUPT_BASE_PPI      16
43 
44 
45 extern void* gFDT;
46 
47 device_manager_info* gDeviceManager;
48 
49 extern fdt_bus_module_info gBusModule;
50 extern fdt_device_module_info gDeviceModule;
51 
52 
53 //#pragma mark -
54 
55 
56 struct fdt_bus {
57 	device_node* node;
58 	HashMap<HashKey32<int32>, device_node*> phandles;
59 };
60 
61 
62 struct fdt_device {
63 	device_node* node;
64 	device_node* bus;
65 };
66 
67 
68 struct fdt_interrupt_map_entry {
69 	uint32_t childAddr;
70 	uint32_t childIrq;
71 	uint32_t parentIrqCtrl;
72 	uint32_t parentIrq;
73 };
74 
75 
76 struct fdt_interrupt_map {
77 	uint32_t childAddrMask;
78 	uint32_t childIrqMask;
79 
80 	Vector<fdt_interrupt_map_entry> fInterruptMap;
81 };
82 
83 
84 static status_t
85 fdt_register_node(fdt_bus* bus, int node, device_node* parentDev,
86 	device_node*& curDev)
87 {
88 	TRACE("%s('%s', %p)\n", __func__, fdt_get_name(gFDT, node, NULL),
89 		parentDev);
90 
91 	const void* prop; int propLen;
92 	Vector<device_attr> attrs;
93 	int nameLen = 0;
94 	const char *name = fdt_get_name(gFDT, node, &nameLen);
95 
96 	if (name == NULL) {
97 		dprintf("%s ERROR: fdt_get_name: %s\n", __func__,
98 			fdt_strerror(nameLen));
99 		return B_ERROR;
100 	}
101 
102 	attrs.Add({ B_DEVICE_BUS, B_STRING_TYPE, {.string = "fdt"}});
103 	attrs.Add({ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
104 		{ .string = (strcmp(name, "") != 0) ? name : "Root" }});
105 	attrs.Add({ "fdt/node", B_UINT32_TYPE, {.ui32 = (uint32)node}});
106 	attrs.Add({ "fdt/name", B_STRING_TYPE, {.string = name}});
107 
108 	prop = fdt_getprop(gFDT, node, "device_type", &propLen);
109 	if (prop != NULL)
110 		attrs.Add({ "fdt/device_type", B_STRING_TYPE, { .string = (const char*)prop }});
111 
112 	prop = fdt_getprop(gFDT, node, "compatible", &propLen);
113 
114 	if (prop != NULL) {
115 		const char* propStr = (const char*)prop;
116 		const char* propEnd = propStr + propLen;
117 		while (propEnd - propStr > 0) {
118 			int curLen = strlen(propStr);
119 			attrs.Add({ "fdt/compatible", B_STRING_TYPE, { .string = propStr }});
120 			propStr += curLen + 1;
121 		}
122 	}
123 
124 	attrs.Add({});
125 
126 	status_t res = gDeviceManager->register_node(parentDev,
127 		"bus_managers/fdt/driver_v1", &attrs[0], NULL, &curDev);
128 
129 	if (res < B_OK)
130 		return res;
131 
132 	prop = fdt_getprop(gFDT, node, "phandle", &propLen);
133 
134 	if (prop != NULL)
135 		bus->phandles.Put(fdt32_to_cpu(*(uint32_t*)prop), curDev);
136 
137 	return B_OK;
138 }
139 
140 
141 static void
142 fdt_traverse(fdt_bus* bus, int &node, int &depth, device_node* parentDev)
143 {
144 	int curDepth = depth;
145 #if 0
146 	for (int i = 0; i < depth; i++) dprintf("  ");
147 	dprintf("node('%s')\n", fdt_get_name(gFDT, node, NULL));
148 #endif
149 	device_node* curDev;
150 	fdt_register_node(bus, node, parentDev, curDev);
151 
152 	node = fdt_next_node(gFDT, node, &depth);
153 	while (node >= 0 && depth == curDepth + 1) {
154 		fdt_traverse(bus, node, depth, curDev);
155 	}
156 }
157 
158 
159 //#pragma mark bus
160 
161 static int32
162 fdt_bus_std_ops(int32 op, ...)
163 {
164 	switch (op) {
165 		case B_MODULE_INIT:
166 			TRACE("fdt root init\n");
167 			return B_OK;
168 
169 		case B_MODULE_UNINIT:
170 			TRACE("fdt root uninit\n");
171 			return B_OK;
172 	}
173 
174 	return B_BAD_VALUE;
175 }
176 
177 
178 static float
179 fdt_bus_supports_device(device_node* parent)
180 {
181 	TRACE("fdt_bus_supports_device\n");
182 
183 	// make sure parent is really device root
184 	const char* bus;
185 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
186 		return B_ERROR;
187 
188 	if (strcmp(bus, "root"))
189 		return 0.0;
190 
191 	return 1.0;
192 }
193 
194 
195 static status_t
196 fdt_bus_register_device(device_node* parent)
197 {
198 	TRACE("+fdt_bus_register_device\n");
199 	struct ScopeExit {
200 		ScopeExit() {TRACE("-fdt_bus_register_device\n");}
201 	} scopeExit;
202 
203 	device_attr attrs[] = {
204 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "FDT"}},
205 		{B_DEVICE_FLAGS, B_UINT32_TYPE, {.ui32 = B_KEEP_DRIVER_LOADED}},
206 		{}
207 	};
208 
209 	return gDeviceManager->register_node(
210 		parent, "bus_managers/fdt/root/driver_v1", attrs, NULL, NULL);
211 }
212 
213 
214 static status_t
215 fdt_bus_init(device_node* node, void** cookie)
216 {
217 	TRACE("fdt_bus_init\n");
218 
219 	if (gFDT == NULL) {
220 		TRACE("FDT is NULL!\n");
221 		return B_DEVICE_NOT_FOUND;
222 	}
223 
224 	ObjectDeleter<fdt_bus> bus(new(std::nothrow) fdt_bus());
225 	if (!bus.IsSet())
226 		return B_NO_MEMORY;
227 
228 	bus->node = node;
229 	*cookie = bus.Detach();
230 	return B_OK;
231 }
232 
233 
234 static void
235 fdt_bus_uninit(void* cookie)
236 {
237 	TRACE("fdt_bus_uninit\n");
238 
239 	ObjectDeleter<fdt_bus> bus((fdt_bus*)cookie);
240 }
241 
242 
243 static status_t
244 fdt_bus_register_child_devices(void* cookie)
245 {
246 	TRACE("fdt_bus_register_child_devices\n");
247 
248 	fdt_bus* bus = (fdt_bus*)cookie;
249 
250 	int node = -1, depth = -1;
251 	node = fdt_next_node(gFDT, node, &depth);
252 	fdt_traverse(bus, node, depth, bus->node);
253 
254 	return B_OK;
255 }
256 
257 
258 device_node*
259 fdt_bus_node_by_phandle(fdt_bus* bus, int phandle)
260 {
261 	ASSERT(bus != NULL);
262 
263 	device_node** devNode;
264 	if (!bus->phandles.Get(phandle, devNode))
265 		return NULL;
266 
267 	return *devNode;
268 }
269 
270 
271 //#pragma mark device
272 
273 
274 static status_t
275 fdt_device_std_ops(int32 op, ...)
276 {
277 	switch (op) {
278 		case B_MODULE_INIT:
279 		case B_MODULE_UNINIT:
280 			return B_OK;
281 	}
282 
283 	return B_BAD_VALUE;
284 }
285 
286 
287 static status_t
288 fdt_device_init_driver(device_node* node, void** cookie)
289 {
290 	TRACE("fdt_device_init_driver()\n");
291 
292 	ObjectDeleter<fdt_device> dev(new(std::nothrow) fdt_device());
293 	if (!dev.IsSet())
294 		return B_NO_MEMORY;
295 
296 	dev->node = node;
297 
298 	// get bus from parent node
299 	DeviceNodePutter<&gDeviceManager> parent(
300 		gDeviceManager->get_parent_node(node));
301 	driver_module_info* parentModule;
302 	void* parentDev;
303 	ASSERT(gDeviceManager->get_driver(
304 		parent.Get(), &parentModule, &parentDev) >= B_OK);
305 	if (parentModule == (driver_module_info*)&gDeviceModule)
306 		dev->bus = ((fdt_device*)parentDev)->bus;
307 	else if (parentModule == (driver_module_info*)&gBusModule)
308 		dev->bus = parent.Get();
309 	else
310 		panic("bad parent node");
311 
312 	*cookie = dev.Detach();
313 	return B_OK;
314 }
315 
316 
317 static void
318 fdt_device_uninit_driver(void* cookie)
319 {
320 	TRACE("fdt_device_uninit_driver()\n");
321 	ObjectDeleter<fdt_device> dev((fdt_device*)cookie);
322 }
323 
324 
325 static status_t
326 fdt_device_register_child_devices(void* cookie)
327 {
328 	TRACE("fdt_device_register_child_devices()\n");
329 	return B_OK;
330 }
331 
332 
333 static device_node*
334 fdt_device_get_bus(fdt_device* dev)
335 {
336 	ASSERT(dev != NULL);
337 	return dev->bus;
338 }
339 
340 
341 static const char*
342 fdt_device_get_name(fdt_device* dev)
343 {
344 	ASSERT(dev != NULL);
345 
346 	uint32 fdtNode;
347 	ASSERT(gDeviceManager->get_attr_uint32(
348 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
349 
350 	return fdt_get_name(gFDT, (int)fdtNode, NULL);
351 }
352 
353 
354 static const void*
355 fdt_device_get_prop(fdt_device* dev, const char* name, int* len)
356 {
357 	ASSERT(dev != NULL);
358 
359 	uint32 fdtNode;
360 	ASSERT(gDeviceManager->get_attr_uint32(
361 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
362 
363 	return fdt_getprop(gFDT, (int)fdtNode, name, len);
364 }
365 
366 
367 static bool
368 fdt_device_get_reg(fdt_device* dev, uint32 ord, uint64* regs, uint64* len)
369 {
370 	ASSERT(dev != NULL);
371 
372 	uint32 fdtNode;
373 	ASSERT(gDeviceManager->get_attr_uint32(
374 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
375 
376 	int propLen;
377 	const void* prop = fdt_getprop(gFDT, (int)fdtNode, "reg", &propLen);
378 	if (prop == NULL)
379 		return false;
380 
381 	// TODO: use '#address-cells', '#size-cells' in parent node to identify
382 	// field sizes
383 
384 	if ((ord + 1)*16 > (uint32)propLen)
385 		return false;
386 
387 	if (regs != NULL)
388 		*regs = fdt64_to_cpu(*(((uint64*)prop) + 2*ord));
389 
390 	if (len != NULL)
391 		*len = fdt64_to_cpu(*(((uint64*)prop) + 2*ord + 1));
392 
393 	return true;
394 }
395 
396 
397 static uint32
398 fdt_get_interrupt_parent(fdt_device* dev, int node)
399 {
400 	while (node >= 0) {
401 		uint32* prop;
402 		int propLen;
403 		prop = (uint32*)fdt_getprop(gFDT, node, "interrupt-parent", &propLen);
404 		if (prop != NULL && propLen == 4) {
405 			return fdt32_to_cpu(*prop);
406 		}
407 
408 		node = fdt_parent_offset(gFDT, node);
409 	}
410 
411 	return 0;
412 }
413 
414 
415 static uint32
416 fdt_get_interrupt_cells(uint32 interrupt_parent_phandle)
417 {
418 	if (interrupt_parent_phandle > 0) {
419 		int node = fdt_node_offset_by_phandle(gFDT, interrupt_parent_phandle);
420 		if (node >= 0) {
421 			uint32* prop;
422 			int propLen;
423 			prop  = (uint32*)fdt_getprop(gFDT, node, "#interrupt-cells", &propLen);
424 			if (prop != NULL && propLen == 4) {
425 				return fdt32_to_cpu(*prop);
426 			}
427 		}
428 	}
429 	return 1;
430 }
431 
432 
433 static bool
434 fdt_device_get_interrupt(fdt_device* dev, uint32 index,
435 	device_node** interruptController, uint64* interrupt)
436 {
437 	ASSERT(dev != NULL);
438 
439 	uint32 fdtNode;
440 	ASSERT(gDeviceManager->get_attr_uint32(
441 		dev->node, "fdt/node", &fdtNode, false) >= B_OK);
442 
443 	int propLen;
444 	const uint32 *prop = (uint32*)fdt_getprop(gFDT, (int)fdtNode, "interrupts-extended",
445 		&propLen);
446 	if (prop == NULL) {
447 		uint32 interruptParent = fdt_get_interrupt_parent(dev, fdtNode);
448 		uint32 interruptCells = fdt_get_interrupt_cells(interruptParent);
449 
450 		prop = (uint32*)fdt_getprop(gFDT, (int)fdtNode, "interrupts",
451 			&propLen);
452 		if (prop == NULL)
453 			return false;
454 
455 		if ((index + 1) * interruptCells * sizeof(uint32) > (uint32)propLen)
456 			return false;
457 
458 		uint32 offset = interruptCells * index;
459 		uint32 interruptNumber = 0;
460 
461 		if ((interruptCells == 1) || (interruptCells == 2)) {
462 			 interruptNumber = fdt32_to_cpu(*(prop + offset));
463 		} else if (interruptCells == 3) {
464 			uint32 interruptType = fdt32_to_cpu(prop[offset + GIC_INTERRUPT_CELL_TYPE]);
465 			interruptNumber = fdt32_to_cpu(prop[offset + GIC_INTERRUPT_CELL_ID]);
466 
467 			if (interruptType == GIC_INTERRUPT_TYPE_SPI)
468 				interruptNumber += GIC_INTERRUPT_BASE_SPI;
469 			else if (interruptType == GIC_INTERRUPT_TYPE_PPI)
470 				interruptNumber += GIC_INTERRUPT_BASE_PPI;
471 		} else {
472 			panic("unsupported interruptCells");
473 		}
474 
475 		if (interrupt != NULL)
476 			*interrupt = interruptNumber;
477 
478 		if (interruptController != NULL && interruptParent != 0) {
479 			fdt_bus* bus;
480 			ASSERT(gDeviceManager->get_driver(dev->bus, NULL, (void**)&bus) >= B_OK);
481 			*interruptController = fdt_bus_node_by_phandle(bus, interruptParent);
482 		}
483 
484 		return true;
485 	}
486 
487 	if ((index + 1) * 8 > (uint32)propLen)
488 		return false;
489 
490 	if (interruptController != NULL) {
491 		uint32 phandle = fdt32_to_cpu(*(prop + 2 * index));
492 
493 		fdt_bus* bus;
494 		ASSERT(gDeviceManager->get_driver(
495 			dev->bus, NULL, (void**)&bus) >= B_OK);
496 
497 		*interruptController = fdt_bus_node_by_phandle(bus, phandle);
498 	}
499 
500 	if (interrupt != NULL)
501 		*interrupt = fdt32_to_cpu(*(prop + 2 * index + 1));
502 
503 	return true;
504 }
505 
506 
507 static struct fdt_interrupt_map *
508 fdt_device_get_interrupt_map(struct fdt_device* dev)
509 {
510 	int fdtNode;
511 	ASSERT(gDeviceManager->get_attr_uint32(
512 		dev->node, "fdt/node", (uint32*)&fdtNode, false) >= B_OK);
513 
514 	ObjectDeleter<struct fdt_interrupt_map> interrupt_map(new struct fdt_interrupt_map());
515 
516 	int intMapMaskLen;
517 	const void* intMapMask = fdt_getprop(gFDT, fdtNode, "interrupt-map-mask",
518 		&intMapMaskLen);
519 
520 	if (intMapMask == NULL || intMapMaskLen != 4 * 4) {
521 		dprintf("  interrupt-map-mask property not found or invalid\n");
522 		return NULL;
523 	}
524 
525 	interrupt_map->childAddrMask = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 0));
526 	interrupt_map->childIrqMask = B_BENDIAN_TO_HOST_INT32(*((uint32*)intMapMask + 3));
527 
528 	int intMapLen;
529 	const void* intMapAddr = fdt_getprop(gFDT, fdtNode, "interrupt-map", &intMapLen);
530 	if (intMapAddr == NULL) {
531 		dprintf("  interrupt-map property not found\n");
532 		return NULL;
533 	}
534 
535 	int addressCells = 3;
536 	int interruptCells = 1;
537 	int phandleCells = 1;
538 
539 	const void *property;
540 
541 	property = fdt_getprop(gFDT, fdtNode, "#address-cells", NULL);
542 	if (property != NULL)
543 		addressCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
544 
545 	property = fdt_getprop(gFDT, fdtNode, "#interrupt-cells", NULL);
546 	if (property != NULL)
547 		interruptCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
548 
549 	uint32_t *it = (uint32_t*)intMapAddr;
550 	while ((uint8_t*)it - (uint8_t*)intMapAddr < intMapLen) {
551 		struct fdt_interrupt_map_entry irqEntry;
552 
553 		irqEntry.childAddr = B_BENDIAN_TO_HOST_INT32(*it);
554 		it += addressCells;
555 
556 		irqEntry.childIrq = B_BENDIAN_TO_HOST_INT32(*it);
557 		it += interruptCells;
558 
559 		irqEntry.parentIrqCtrl = B_BENDIAN_TO_HOST_INT32(*it);
560 		it += phandleCells;
561 
562 		int parentAddressCells = 0;
563 		int parentInterruptCells = 1;
564 
565 		int interruptParent = fdt_node_offset_by_phandle(gFDT, irqEntry.parentIrqCtrl);
566 		if (interruptParent >= 0) {
567 			property = fdt_getprop(gFDT, interruptParent, "#address-cells", NULL);
568 			if (property != NULL)
569 				parentAddressCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
570 
571 			property = fdt_getprop(gFDT, interruptParent, "#interrupt-cells", NULL);
572 			if (property != NULL)
573 				parentInterruptCells = B_BENDIAN_TO_HOST_INT32(*(uint32*)property);
574 		}
575 
576 		it += parentAddressCells;
577 
578 		if ((parentInterruptCells == 1) || (parentInterruptCells == 2)) {
579 			irqEntry.parentIrq = B_BENDIAN_TO_HOST_INT32(*it);
580 		} else if (parentInterruptCells == 3) {
581 			uint32 interruptType = fdt32_to_cpu(it[GIC_INTERRUPT_CELL_TYPE]);
582 			uint32 interruptNumber = fdt32_to_cpu(it[GIC_INTERRUPT_CELL_ID]);
583 
584 			if (interruptType == GIC_INTERRUPT_TYPE_SPI)
585 				irqEntry.parentIrq = interruptNumber + GIC_INTERRUPT_BASE_SPI;
586 			else if (interruptType == GIC_INTERRUPT_TYPE_PPI)
587 				irqEntry.parentIrq = interruptNumber + GIC_INTERRUPT_BASE_PPI;
588 			else
589 				irqEntry.parentIrq = interruptNumber;
590 		}
591 		it += parentInterruptCells;
592 
593 		interrupt_map->fInterruptMap.PushBack(irqEntry);
594 	}
595 
596 	return interrupt_map.Detach();
597 }
598 
599 
600 static void
601 fdt_device_print_interrupt_map(struct fdt_interrupt_map* interruptMap)
602 {
603 	if (interruptMap == NULL)
604 		return;
605 
606 	dprintf("interrupt_map_mask: 0x%08" PRIx32 ", 0x%08" PRIx32 "\n",
607 		interruptMap->childAddrMask, interruptMap->childIrqMask);
608 	dprintf("interrupt_map:\n");
609 
610 	for (Vector<struct fdt_interrupt_map_entry>::Iterator it = interruptMap->fInterruptMap.Begin();
611 		it != interruptMap->fInterruptMap.End();
612 		it++) {
613 
614 		dprintf("childAddr=0x%08" PRIx32 ", childIrq=%" PRIu32 ", parentIrqCtrl=%" PRIu32 ", parentIrq=%" PRIu32 "\n",
615 			it->childAddr, it->childIrq, it->parentIrqCtrl, it->parentIrq);
616 	}
617 }
618 
619 
620 static uint32
621 fdt_device_lookup_interrupt_map(struct fdt_interrupt_map* interruptMap, uint32 childAddr, uint32 childIrq)
622 {
623 	if (interruptMap == NULL)
624 		return 0xffffffff;
625 
626 	childAddr &= interruptMap->childAddrMask;
627 	childIrq &= interruptMap->childIrqMask;
628 
629 	for (Vector<struct fdt_interrupt_map_entry>::Iterator it = interruptMap->fInterruptMap.Begin();
630 			it != interruptMap->fInterruptMap.End(); it++) {
631 		if ((it->childAddr == childAddr) && (it->childIrq == childIrq))
632 			return it->parentIrq;
633 	}
634 
635 	return 0xffffffff;
636 }
637 
638 
639 //#pragma mark -
640 
641 fdt_bus_module_info gBusModule = {
642 	{
643 		{
644 			"bus_managers/fdt/root/driver_v1",
645 			0,
646 			fdt_bus_std_ops
647 		},
648 		fdt_bus_supports_device,
649 		fdt_bus_register_device,
650 		fdt_bus_init,
651 		fdt_bus_uninit,
652 		fdt_bus_register_child_devices,
653 		NULL,	// rescan devices
654 		NULL,	// device removed
655 	},
656 	fdt_bus_node_by_phandle,
657 };
658 
659 
660 fdt_device_module_info gDeviceModule = {
661 	{
662 		{
663 			"bus_managers/fdt/driver_v1",
664 			0,
665 			fdt_device_std_ops
666 		},
667 
668 		NULL,		// supports device
669 		NULL,		// register device (our parent registered us)
670 		fdt_device_init_driver,
671 		fdt_device_uninit_driver,
672 		fdt_device_register_child_devices,
673 		NULL,		// rescan devices
674 		NULL,		// device removed
675 	},
676 	fdt_device_get_bus,
677 	fdt_device_get_name,
678 	fdt_device_get_prop,
679 	fdt_device_get_reg,
680 	fdt_device_get_interrupt,
681 	fdt_device_get_interrupt_map,
682 	fdt_device_print_interrupt_map,
683 	fdt_device_lookup_interrupt_map,
684 };
685 
686 
687 module_info* modules[] = {
688 	(module_info*)&gBusModule,
689 	(module_info*)&gDeviceModule,
690 	NULL
691 };
692 
693 module_dependency module_dependencies[] = {
694 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
695 	{ NULL }
696 };
697