* Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include <arch_platform.h>
#include <new>
#include <KernelExport.h>
#include <arch/generic/debug_uart.h>
#include <boot/kernel_args.h>
#include <platform/openfirmware/openfirmware.h>
#include <real_time_clock.h>
#include <util/kernel_cpp.h>
void *gFDT;
static PPCPlatform *sPPCPlatform;
PPCPlatform::PPCPlatform(ppc_platform_type platformType)
: fPlatformType(platformType)
{
}
PPCPlatform::~PPCPlatform()
{
}
PPCPlatform *
PPCPlatform::Default()
{
return sPPCPlatform;
}
namespace BPrivate {
class PPCOpenFirmware : public PPCPlatform {
public:
PPCOpenFirmware();
virtual ~PPCOpenFirmware();
virtual status_t Init(struct kernel_args *kernelArgs);
virtual status_t InitSerialDebug(struct kernel_args *kernelArgs);
virtual status_t InitPostVM(struct kernel_args *kernelArgs);
virtual status_t InitRTC(struct kernel_args *kernelArgs,
struct real_time_data *data);
virtual char SerialDebugGetChar();
virtual void SerialDebugPutChar(char c);
virtual void SetHardwareRTC(uint32 seconds);
virtual uint32 GetHardwareRTC();
virtual void ShutDown(bool reboot);
private:
int fInput;
int fOutput;
int fRTC;
};
}
using BPrivate::PPCOpenFirmware;
static int
debug_command_of_exit(int argc, char **argv)
{
of_exit();
kprintf("of_exit() failed!\n");
return 0;
}
static int
debug_command_of_enter(int argc, char **argv)
{
of_call_client_function("enter", 0, 0);
return 0;
}
PPCOpenFirmware::PPCOpenFirmware()
: PPCPlatform(PPC_PLATFORM_OPEN_FIRMWARE),
fInput(-1),
fOutput(-1),
fRTC(-1)
{
}
PPCOpenFirmware::~PPCOpenFirmware()
{
}
status_t
PPCOpenFirmware::Init(struct kernel_args *kernelArgs)
{
return of_init(
(intptr_t(*)(void*))kernelArgs->platform_args.openfirmware_entry);
}
status_t
PPCOpenFirmware::InitSerialDebug(struct kernel_args *kernelArgs)
{
if (of_getprop(gChosen, "stdin", &fInput, sizeof(int)) == OF_FAILED)
return B_ERROR;
if (!kernelArgs->frame_buffer.enabled) {
if (of_getprop(gChosen, "stdout", &fOutput, sizeof(int)) == OF_FAILED)
return B_ERROR;
}
return B_OK;
}
status_t
PPCOpenFirmware::InitPostVM(struct kernel_args *kernelArgs)
{
add_debugger_command("of_exit", &debug_command_of_exit,
"Exit to the Open Firmware prompt. No way to get back into the OS!");
add_debugger_command("of_enter", &debug_command_of_enter,
"Enter a subordinate Open Firmware interpreter. Quitting it returns "
"to KDL.");
return B_OK;
}
status_t
PPCOpenFirmware::InitRTC(struct kernel_args *kernelArgs,
struct real_time_data *data)
{
fRTC = of_open(kernelArgs->platform_args.rtc_path);
if (fRTC == OF_FAILED) {
dprintf("PPCOpenFirmware::InitRTC(): Failed open RTC device!\n");
return B_ERROR;
}
return B_OK;
}
char
PPCOpenFirmware::SerialDebugGetChar()
{
int key;
if (of_interpret("key", 0, 1, &key) == OF_FAILED)
return 0;
return (char)key;
}
void
PPCOpenFirmware::SerialDebugPutChar(char c)
{
if (fOutput == -1)
return;
if (c == '\n')
of_write(fOutput, "\r\n", 2);
else
of_write(fOutput, &c, 1);
}
void
PPCOpenFirmware::SetHardwareRTC(uint32 seconds)
{
struct tm t;
rtc_secs_to_tm(seconds, &t);
t.tm_year += RTC_EPOCH_BASE_YEAR;
t.tm_mon++;
if (of_call_method(fRTC, "set-time", 6, 0, t.tm_year, t.tm_mon, t.tm_mday,
t.tm_hour, t.tm_min, t.tm_sec) == OF_FAILED) {
dprintf("PPCOpenFirmware::SetHardwareRTC(): Failed to set RTC!\n");
}
}
uint32
PPCOpenFirmware::GetHardwareRTC()
{
struct tm t;
if (of_call_method(fRTC, "get-time", 0, 6, &t.tm_year, &t.tm_mon,
&t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) == OF_FAILED) {
dprintf("PPCOpenFirmware::GetHardwareRTC(): Failed to get RTC!\n");
return 0;
}
t.tm_year -= RTC_EPOCH_BASE_YEAR;
t.tm_mon--;
return rtc_tm_to_secs(&t);
}
void
PPCOpenFirmware::ShutDown(bool reboot)
{
if (reboot) {
of_interpret("reset-all", 0, 0);
} else {
of_interpret("shut-down", 0, 0);
}
}
namespace BPrivate {
class PPCUBoot : public PPCPlatform {
public:
PPCUBoot();
virtual ~PPCUBoot();
virtual status_t Init(struct kernel_args *kernelArgs);
virtual status_t InitSerialDebug(struct kernel_args *kernelArgs);
virtual status_t InitPostVM(struct kernel_args *kernelArgs);
virtual status_t InitRTC(struct kernel_args *kernelArgs,
struct real_time_data *data);
virtual char SerialDebugGetChar();
virtual void SerialDebugPutChar(char c);
virtual void SetHardwareRTC(uint32 seconds);
virtual uint32 GetHardwareRTC();
virtual void ShutDown(bool reboot);
private:
int fInput;
int fOutput;
int fRTC;
DebugUART *fDebugUART;
};
}
using BPrivate::PPCUBoot;
PPCUBoot::PPCUBoot()
: PPCPlatform(PPC_PLATFORM_U_BOOT),
fInput(-1),
fOutput(-1),
fRTC(-1),
fDebugUART(NULL)
{
}
PPCUBoot::~PPCUBoot()
{
}
status_t
PPCUBoot::Init(struct kernel_args *kernelArgs)
{
gFDT = kernelArgs->platform_args.fdt;
return B_OK;
}
status_t
PPCUBoot::InitSerialDebug(struct kernel_args *kernelArgs)
{
if (fDebugUART == NULL)
return B_ERROR;
return B_OK;
}
status_t
PPCUBoot::InitPostVM(struct kernel_args *kernelArgs)
{
return B_ERROR;
}
status_t
PPCUBoot::InitRTC(struct kernel_args *kernelArgs,
struct real_time_data *data)
{
return B_ERROR;
}
char
PPCUBoot::SerialDebugGetChar()
{
if (fDebugUART)
return fDebugUART->GetChar(false);
return 0;
}
void
PPCUBoot::SerialDebugPutChar(char c)
{
if (fDebugUART)
fDebugUART->PutChar(c);
}
void
PPCUBoot::SetHardwareRTC(uint32 seconds)
{
}
uint32
PPCUBoot::GetHardwareRTC()
{
return 0;
}
void
PPCUBoot::ShutDown(bool reboot)
{
}
#define PLATFORM_BUFFER_SIZE MAX(sizeof(PPCOpenFirmware),sizeof(PPCUBoot))
static char *sPPCPlatformBuffer[PLATFORM_BUFFER_SIZE];
status_t
arch_platform_init(struct kernel_args *kernelArgs)
{
switch (kernelArgs->arch_args.platform) {
case PPC_PLATFORM_OPEN_FIRMWARE:
sPPCPlatform = new(sPPCPlatformBuffer) PPCOpenFirmware;
break;
case PPC_PLATFORM_U_BOOT:
sPPCPlatform = new(sPPCPlatformBuffer) PPCUBoot;
break;
default:
return B_ERROR;
}
return sPPCPlatform->Init(kernelArgs);
}
status_t
arch_platform_init_post_vm(struct kernel_args *kernelArgs)
{
return sPPCPlatform->InitPostVM(kernelArgs);
}
status_t
arch_platform_init_post_thread(struct kernel_args *kernelArgs)
{
return B_OK;
}