#include "cpu.h"
#include "board_config.h"
#include <OS.h>
#include <boot/platform.h>
#include <boot/stdio.h>
#include <boot/kernel_args.h>
#include <boot/stage2.h>
#include <arch/cpu.h>
#include <arch/ppc/arch_cpu.h>
#include <arch/ppc/arch_platform.h>
#include <arch_kernel.h>
#include <arch_system_info.h>
#include <platform/openfirmware/devices.h>
#include <platform/openfirmware/openfirmware.h>
#include <string.h>
extern "C" {
#include <fdt.h>
#include <libfdt.h>
#include <libfdt_env.h>
};
extern void *gFDT;
#define TRACE_CPU
#ifdef TRACE_CPU
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
bool gIs440 = false;
static status_t
enumerate_cpus(void)
{
int cpus = of_finddevice("/cpus");
if (cpus == OF_FAILED) {
printf("enumerate_cpus(): Failed to open \"/cpus\"!\n");
return B_ERROR;
}
char cpuPath[256];
int cookie = 0;
int cpuCount = 0;
while (of_get_next_device(&cookie, cpus, "cpu", cpuPath,
sizeof(cpuPath)) == B_OK) {
TRACE(("found CPU: %s\n", cpuPath));
if (cpuCount == 0) {
int cpu = of_finddevice(cpuPath);
if (cpu == OF_FAILED) {
printf("enumerate_cpus: Failed get CPU device node!\n");
return B_ERROR;
}
int32 clockFrequency;
if (of_getprop(cpu, "clock-frequency", &clockFrequency, 4)
== OF_FAILED) {
printf("enumerate_cpus: Failed to get CPU clock "
"frequency!\n");
return B_ERROR;
}
int32 busFrequency = 0;
if (of_getprop(cpu, "bus-frequency", &busFrequency, 4)
== OF_FAILED) {
}
int32 timeBaseFrequency;
if (of_getprop(cpu, "timebase-frequency", &timeBaseFrequency, 4)
== OF_FAILED) {
printf("enumerate_cpus: Failed to get time base "
"frequency!\n");
return B_ERROR;
}
gKernelArgs.arch_args.cpu_frequency = clockFrequency;
gKernelArgs.arch_args.bus_frequency = busFrequency;
gKernelArgs.arch_args.time_base_frequency = timeBaseFrequency;
TRACE((" CPU clock frequency: %ld\n", clockFrequency));
TRACE((" time base frequency: %ld\n", timeBaseFrequency));
}
cpuCount++;
}
if (cpuCount == 0) {
printf("enumerate_cpus(): Found no CPUs!\n");
return B_ERROR;
}
gKernelArgs.num_cpus = cpuCount;
if (gKernelArgs.arch_args.bus_frequency == 0) {
int plb = of_finddevice("/plb");
int32 busFrequency = 0;
if (of_getprop(plb, "clock-frequency", &busFrequency, 4)
== OF_FAILED) {
printf("enumerate_cpus: Failed to get bus clock "
"frequency!\n");
return B_ERROR;
}
gKernelArgs.arch_args.bus_frequency = busFrequency;
}
TRACE((" bus clock frequency: %lld\n",
gKernelArgs.arch_args.bus_frequency));
#if 0
addr_t stack = (addr_t)arch_mmu_allocate((void*)0x80000000,
cpuCount * (KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE),
B_READ_AREA | B_WRITE_AREA, false);
if (!stack) {
printf("enumerate_cpus(): Failed to allocate kernel stack(s)!\n");
return B_NO_MEMORY;
}
for (int i = 0; i < cpuCount; i++) {
gKernelArgs.cpu_kstack[i].start = stack;
gKernelArgs.cpu_kstack[i].size = KERNEL_STACK_SIZE
+ KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE;
stack += KERNEL_STACK_SIZE + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE;
}
#endif
return B_OK;
}
static status_t
check_cpu_features()
{
uint32 msr;
uint32 pvr;
bool is_440 = false;
bool is_460 = false;
bool pvr_unknown = false;
bool fdt_unknown = true;
const char *fdt_model = NULL;
pvr = get_pvr();
uint16 version = (uint16)(pvr >> 16);
uint16 revision = (uint16)(pvr & 0xffff);
switch (version) {
case AMCC440EP:
is_440 = true;
break;
case AMCC460EX:
is_460 = true;
break;
default:
pvr_unknown = true;
}
if (gFDT != NULL) {
int node = fdt_path_offset(gFDT, "/cpus/cpu@0");
int len;
fdt_model = (const char *)fdt_getprop(gFDT, node, "model", &len);
if (fdt_model) {
if (!strcmp(fdt_model, "PowerPC,440EP")) {
is_440 = true;
fdt_unknown = false;
} else if (!strcmp(fdt_model, "PowerPC,460EX")) {
is_460 = true;
fdt_unknown = false;
}
}
}
if (is_460)
is_440 = true;
gIs440 = is_440;
if (is_440) {
asm volatile(
"mfccr0 %%r3\n"
"\tlis %%r4,~(1<<(31-11-16))\n"
"\tand %%r3,%%r3,%%r4\n"
"\tmtccr0 %%r3"
: : : "r3", "r4");
asm volatile(
"mfccr0 %%r3\n"
"\tli %%r4,~(1<<(31-23))\n"
"\tand %%r3,%%r3,%%r4\n"
"\tmtccr0 %%r3"
: : : "r3", "r4");
}
msr = get_msr();
msr |= MSR_FP_AVAILABLE;
msr = set_msr(msr);
if ((msr & MSR_FP_AVAILABLE) == 0) {
panic("no FPU!");
return B_ERROR;
}
TRACE(("CPU detection:\n"));
TRACE(("PVR revision %sknown: 0x%8lx\n", pvr_unknown ? "un" : "", pvr));
TRACE(("FDT model %sknown: %s\n", fdt_unknown ? "un" : "", fdt_model));
TRACE(("flags: %s440 %s460\n", is_440 ? "" : "!", is_460 ? "" : "!"));
return B_OK;
}
extern "C" void
spin(bigtime_t microseconds)
{
for(bigtime_t i=0;i<microseconds;i=i+1)
{
}
#warning U-Boot:PPC:TODO!!
}
extern "C" status_t
boot_arch_cpu_init(void)
{
gKernelArgs.arch_args.platform = PPC_PLATFORM_U_BOOT;
status_t err = check_cpu_features();
if (err != B_OK) {
panic("You need a Pentium or higher in order to boot!\n");
return err;
}
enumerate_cpus();
return B_OK;
}