1/*
2 * Copyright 2019-2021 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *   Alexander von Gluck IV <kallisti5@unixzen.com>
7 */
8
9#include <arch_cpu_defs.h>
10#include <arch_dtb.h>
11#include <arch_smp.h>
12#include <boot/platform.h>
13#include <boot/stage2.h>
14
15extern "C" {
16#include <libfdt.h>
17}
18
19#include "dtb.h"
20
21
22const struct supported_interrupt_controllers {
23	const char*	dtb_compat;
24	const char*	kind;
25} kSupportedInterruptControllers[] = {
26	{ "arm,cortex-a9-gic", INTC_KIND_GICV1 },
27	{ "arm,cortex-a15-gic", INTC_KIND_GICV2 },
28	{ "arm,gic-400", INTC_KIND_GICV2 },
29	{ "ti,omap3-intc", INTC_KIND_OMAP3 },
30	{ "marvell,pxa-intc", INTC_KIND_PXA },
31	{ "allwinner,sun4i-a10-ic", INTC_KIND_SUN4I },
32};
33
34
35const struct supported_timers {
36	const char* dtb_compat;
37	const char* kind;
38} kSupportedTimers[] = {
39	{ "arm,armv7-timer",	TIMER_KIND_ARMV7 },
40	{ "ti,omap3430-timer",	TIMER_KIND_OMAP3 },
41	{ "marvell,pxa-timers",	TIMER_KIND_PXA },
42};
43
44
45void
46arch_handle_fdt(const void* fdt, int node)
47{
48	const char* deviceType = (const char*)fdt_getprop(fdt, node,
49		"device_type", NULL);
50
51	if (deviceType != NULL) {
52		if (strcmp(deviceType, "cpu") == 0) {
53			platform_cpu_info* info;
54			arch_smp_register_cpu(&info);
55			if (info == NULL)
56				return;
57			info->id = fdt32_to_cpu(*(uint32*)fdt_getprop(fdt, node,
58				"reg", NULL));
59			dprintf("cpu\n");
60			dprintf("  id: %" B_PRIu32 "\n", info->id);
61
62		}
63	}
64
65	int compatibleLen;
66	const char* compatible = (const char*)fdt_getprop(fdt, node,
67		"compatible", &compatibleLen);
68
69	if (compatible == NULL)
70		return;
71
72	intc_info &interrupt_controller = gKernelArgs.arch_args.interrupt_controller;
73	if (interrupt_controller.kind[0] == 0) {
74		for (uint32 i = 0; i < B_COUNT_OF(kSupportedInterruptControllers); i++) {
75			if (dtb_has_fdt_string(compatible, compatibleLen,
76				kSupportedInterruptControllers[i].dtb_compat)) {
77
78				memcpy(interrupt_controller.kind, kSupportedInterruptControllers[i].kind,
79					sizeof(interrupt_controller.kind));
80
81				dtb_get_reg(fdt, node, 0, interrupt_controller.regs1);
82				dtb_get_reg(fdt, node, 1, interrupt_controller.regs2);
83			}
84		}
85	}
86
87	boot_timer_info &timer = gKernelArgs.arch_args.timer;
88	if (timer.kind[0] == 0) {
89		for (uint32 i = 0; i < B_COUNT_OF(kSupportedTimers); i++) {
90			if (dtb_has_fdt_string(compatible, compatibleLen,
91				kSupportedTimers[i].dtb_compat)) {
92
93				memcpy(timer.kind, kSupportedTimers[i].kind,
94					sizeof(timer.kind));
95
96				dtb_get_reg(fdt, node, 0, timer.regs);
97				timer.interrupt = dtb_get_interrupt(fdt, node);
98			}
99		}
100	}
101}
102
103
104void
105arch_dtb_set_kernel_args(void)
106{
107	intc_info &interrupt_controller = gKernelArgs.arch_args.interrupt_controller;
108	dprintf("Chosen interrupt controller:\n");
109	if (interrupt_controller.kind[0] == 0) {
110		dprintf("kind: None!\n");
111	} else {
112		dprintf("  kind: %s\n", interrupt_controller.kind);
113		dprintf("  regs: %#" B_PRIx64 ", %#" B_PRIx64 "\n",
114			interrupt_controller.regs1.start,
115			interrupt_controller.regs1.size);
116		dprintf("        %#" B_PRIx64 ", %#" B_PRIx64 "\n",
117			interrupt_controller.regs2.start,
118			interrupt_controller.regs2.size);
119	}
120
121	boot_timer_info &timer = gKernelArgs.arch_args.timer;
122	dprintf("Chosen timer:\n");
123	if (timer.kind[0] == 0) {
124		dprintf("kind: None!\n");
125	} else {
126		dprintf("  kind: %s\n", timer.kind);
127		dprintf("  regs: %#" B_PRIx64 ", %#" B_PRIx64 "\n",
128			timer.regs.start,
129			timer.regs.size);
130		dprintf("  irq: %" B_PRIu32 "\n", timer.interrupt);
131	}
132}
133