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