104ec719aSAndreas Färber/*
204ec719aSAndreas Färber * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
304ec719aSAndreas Färber * All rights reserved. Distributed under the terms of the MIT License.
404ec719aSAndreas Färber */
504ec719aSAndreas Färber
604ec719aSAndreas Färber#include <boot/platform/openfirmware/platform_arch.h>
704ec719aSAndreas Färber
804ec719aSAndreas Färber#include <stdio.h>
904ec719aSAndreas Färber
1004ec719aSAndreas Färber#include <KernelExport.h>
1104ec719aSAndreas Färber
1204ec719aSAndreas Färber#include <boot/kernel_args.h>
1304ec719aSAndreas Färber#include <boot/stage2.h>
1404ec719aSAndreas Färber#include <kernel.h>
1504ec719aSAndreas Färber#include <platform/openfirmware/devices.h>
1604ec719aSAndreas Färber#include <platform/openfirmware/openfirmware.h>
1704ec719aSAndreas Färber
1804ec719aSAndreas Färber#define TRACE_CPU
1904ec719aSAndreas Färber#ifdef TRACE_CPU
2004ec719aSAndreas Färber#	define TRACE(x) dprintf x
2104ec719aSAndreas Färber#else
2204ec719aSAndreas Färber#	define TRACE(x) ;
2304ec719aSAndreas Färber#endif
2404ec719aSAndreas Färber
2504ec719aSAndreas Färber
2604ec719aSAndreas Färberstatus_t
2704ec719aSAndreas Färberboot_arch_cpu_init(void)
2804ec719aSAndreas Färber{
294c7a310cSFrançois Revol	int32 busFrequency = 0;
304c7a310cSFrançois Revol
314c7a310cSFrançois Revol	int root = of_finddevice("/");
324c7a310cSFrançois Revol	if (root == OF_FAILED) {
334c7a310cSFrançois Revol		printf("boot_arch_cpu_init(): Failed to open \"/\"!\n");
344c7a310cSFrançois Revol		return B_ERROR;
354c7a310cSFrançois Revol	}
364c7a310cSFrançois Revol
374c7a310cSFrançois Revol	of_getprop(root, "clock-frequency", &busFrequency, 4);
384c7a310cSFrançois Revol		// we might find it in /cpus instead
394c7a310cSFrançois Revol
4004ec719aSAndreas Färber	// iterate through the "/cpus" node to find all CPUs
4104ec719aSAndreas Färber	int cpus = of_finddevice("/cpus");
4204ec719aSAndreas Färber	if (cpus == OF_FAILED) {
4304ec719aSAndreas Färber		printf("boot_arch_cpu_init(): Failed to open \"/cpus\"!\n");
4404ec719aSAndreas Färber		return B_ERROR;
4504ec719aSAndreas Färber	}
4604ec719aSAndreas Färber
4704ec719aSAndreas Färber	char cpuPath[256];
4804ec719aSAndreas Färber	int cookie = 0;
4904ec719aSAndreas Färber	int cpuCount = 0;
5004ec719aSAndreas Färber	while (of_get_next_device(&cookie, cpus, "cpu", cpuPath,
5104ec719aSAndreas Färber			sizeof(cpuPath)) == B_OK) {
5204ec719aSAndreas Färber		TRACE(("found CPU: %s\n", cpuPath));
5304ec719aSAndreas Färber
5404ec719aSAndreas Färber		// For the first CPU get the frequencies of CPU, bus, and time base.
5504ec719aSAndreas Färber		// We assume they are the same for all CPUs.
5604ec719aSAndreas Färber		if (cpuCount == 0) {
5704ec719aSAndreas Färber			int cpu = of_finddevice(cpuPath);
5804ec719aSAndreas Färber			if (cpu == OF_FAILED) {
5904ec719aSAndreas Färber				printf("boot_arch_cpu_init: Failed get CPU device node!\n");
6004ec719aSAndreas Färber				return B_ERROR;
6104ec719aSAndreas Färber			}
6204ec719aSAndreas Färber
6304ec719aSAndreas Färber			// TODO: Does encode-int really encode quadlet (32 bit numbers)
6404ec719aSAndreas Färber			// only?
6504ec719aSAndreas Färber			int32 clockFrequency;
6604ec719aSAndreas Färber			if (of_getprop(cpu, "clock-frequency", &clockFrequency, 4)
6704ec719aSAndreas Färber					== OF_FAILED) {
6804ec719aSAndreas Färber				printf("boot_arch_cpu_init: Failed to get CPU clock "
6904ec719aSAndreas Färber					"frequency!\n");
7004ec719aSAndreas Färber				return B_ERROR;
7104ec719aSAndreas Färber			}
724c7a310cSFrançois Revol			if (busFrequency == 0
734c7a310cSFrançois Revol				&& of_getprop(cpu, "bus-frequency", &busFrequency, 4)
7404ec719aSAndreas Färber					== OF_FAILED) {
7504ec719aSAndreas Färber				printf("boot_arch_cpu_init: Failed to get bus clock "
7604ec719aSAndreas Färber					"frequency!\n");
7704ec719aSAndreas Färber				return B_ERROR;
7804ec719aSAndreas Färber			}
7904ec719aSAndreas Färber			int32 timeBaseFrequency;
8004ec719aSAndreas Färber			if (of_getprop(cpu, "timebase-frequency", &timeBaseFrequency, 4)
8104ec719aSAndreas Färber					== OF_FAILED) {
8204ec719aSAndreas Färber				printf("boot_arch_cpu_init: Failed to get time base "
8304ec719aSAndreas Färber					"frequency!\n");
8404ec719aSAndreas Färber				return B_ERROR;
8504ec719aSAndreas Färber			}
8604ec719aSAndreas Färber
8704ec719aSAndreas Färber			gKernelArgs.arch_args.cpu_frequency = clockFrequency;
8804ec719aSAndreas Färber			gKernelArgs.arch_args.bus_frequency = busFrequency;
8904ec719aSAndreas Färber			gKernelArgs.arch_args.time_base_frequency = timeBaseFrequency;
9004ec719aSAndreas Färber
9104ec719aSAndreas Färber			TRACE(("  CPU clock frequency: %ld\n", clockFrequency));
9204ec719aSAndreas Färber			TRACE(("  bus clock frequency: %ld\n", busFrequency));
9304ec719aSAndreas Färber			TRACE(("  time base frequency: %ld\n", timeBaseFrequency));
9404ec719aSAndreas Färber		}
9504ec719aSAndreas Färber
9604ec719aSAndreas Färber		cpuCount++;
9704ec719aSAndreas Färber	}
9804ec719aSAndreas Färber
9904ec719aSAndreas Färber	if (cpuCount == 0) {
10004ec719aSAndreas Färber		printf("boot_arch_cpu_init(): Found no CPUs!\n");
10104ec719aSAndreas Färber		return B_ERROR;
10204ec719aSAndreas Färber	}
10304ec719aSAndreas Färber
10404ec719aSAndreas Färber	gKernelArgs.num_cpus = cpuCount;
10504ec719aSAndreas Färber
10604ec719aSAndreas Färber	// allocate the kernel stacks (the memory stuff is already initialized
10704ec719aSAndreas Färber	// at this point)
10804ec719aSAndreas Färber	addr_t stack = (addr_t)arch_mmu_allocate((void*)0x80000000,
10904ec719aSAndreas Färber		cpuCount * (KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE),
11004ec719aSAndreas Färber		B_READ_AREA | B_WRITE_AREA, false);
11104ec719aSAndreas Färber	if (!stack) {
11204ec719aSAndreas Färber		printf("boot_arch_cpu_init(): Failed to allocate kernel stack(s)!\n");
11304ec719aSAndreas Färber		return B_NO_MEMORY;
11404ec719aSAndreas Färber	}
11504ec719aSAndreas Färber
11604ec719aSAndreas Färber	for (int i = 0; i < cpuCount; i++) {
11704ec719aSAndreas Färber		gKernelArgs.cpu_kstack[i].start = stack;
11804ec719aSAndreas Färber		gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE
11904ec719aSAndreas Färber			+ KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE;
12004ec719aSAndreas Färber		stack += KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE;
12104ec719aSAndreas Färber	}
12204ec719aSAndreas Färber
12304ec719aSAndreas Färber	return B_OK;
12404ec719aSAndreas Färber}
12504ec719aSAndreas Färber