1/* 2 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6#include <arch_platform.h> 7 8#include <new> 9 10#include <KernelExport.h> 11 12#include <arch/generic/debug_uart.h> 13#include <boot/kernel_args.h> 14#include <platform/openfirmware/openfirmware.h> 15#include <real_time_clock.h> 16#include <util/kernel_cpp.h> 17 18 19void *gFDT; 20static PPCPlatform *sPPCPlatform; 21 22 23PPCPlatform::PPCPlatform(ppc_platform_type platformType) 24 : fPlatformType(platformType) 25{ 26} 27 28 29PPCPlatform::~PPCPlatform() 30{ 31} 32 33 34PPCPlatform * 35PPCPlatform::Default() 36{ 37 return sPPCPlatform; 38} 39 40 41// #pragma mark - Open Firmware 42 43 44namespace BPrivate { 45 46class PPCOpenFirmware : public PPCPlatform { 47public: 48 PPCOpenFirmware(); 49 virtual ~PPCOpenFirmware(); 50 51 virtual status_t Init(struct kernel_args *kernelArgs); 52 virtual status_t InitSerialDebug(struct kernel_args *kernelArgs); 53 virtual status_t InitPostVM(struct kernel_args *kernelArgs); 54 virtual status_t InitRTC(struct kernel_args *kernelArgs, 55 struct real_time_data *data); 56 57 virtual char SerialDebugGetChar(); 58 virtual void SerialDebugPutChar(char c); 59 60 virtual void SetHardwareRTC(uint32 seconds); 61 virtual uint32 GetHardwareRTC(); 62 63 virtual void ShutDown(bool reboot); 64 65private: 66 int fInput; 67 int fOutput; 68 int fRTC; 69}; 70 71} // namespace BPrivate 72 73 74using BPrivate::PPCOpenFirmware; 75 76 77// OF debugger commands 78 79 80static int 81debug_command_of_exit(int argc, char **argv) 82{ 83 of_exit(); 84 kprintf("of_exit() failed!\n"); 85 return 0; 86} 87 88 89static int 90debug_command_of_enter(int argc, char **argv) 91{ 92 of_call_client_function("enter", 0, 0); 93 return 0; 94} 95 96 97PPCOpenFirmware::PPCOpenFirmware() 98 : PPCPlatform(PPC_PLATFORM_OPEN_FIRMWARE), 99 fInput(-1), 100 fOutput(-1), 101 fRTC(-1) 102{ 103} 104 105 106PPCOpenFirmware::~PPCOpenFirmware() 107{ 108} 109 110 111status_t 112PPCOpenFirmware::Init(struct kernel_args *kernelArgs) 113{ 114 return of_init( 115 (intptr_t(*)(void*))kernelArgs->platform_args.openfirmware_entry); 116} 117 118 119status_t 120PPCOpenFirmware::InitSerialDebug(struct kernel_args *kernelArgs) 121{ 122 if (of_getprop(gChosen, "stdin", &fInput, sizeof(int)) == OF_FAILED) 123 return B_ERROR; 124 if (!kernelArgs->frame_buffer.enabled) { 125 if (of_getprop(gChosen, "stdout", &fOutput, sizeof(int)) == OF_FAILED) 126 return B_ERROR; 127 } 128 129 return B_OK; 130} 131 132 133status_t 134PPCOpenFirmware::InitPostVM(struct kernel_args *kernelArgs) 135{ 136 add_debugger_command("of_exit", &debug_command_of_exit, 137 "Exit to the Open Firmware prompt. No way to get back into the OS!"); 138 add_debugger_command("of_enter", &debug_command_of_enter, 139 "Enter a subordinate Open Firmware interpreter. Quitting it returns " 140 "to KDL."); 141 142 return B_OK; 143} 144 145 146// InitRTC 147status_t 148PPCOpenFirmware::InitRTC(struct kernel_args *kernelArgs, 149 struct real_time_data *data) 150{ 151 // open RTC 152 fRTC = of_open(kernelArgs->platform_args.rtc_path); 153 if (fRTC == OF_FAILED) { 154 dprintf("PPCOpenFirmware::InitRTC(): Failed open RTC device!\n"); 155 return B_ERROR; 156 } 157 158 return B_OK; 159} 160 161 162char 163PPCOpenFirmware::SerialDebugGetChar() 164{ 165 int key; 166 if (of_interpret("key", 0, 1, &key) == OF_FAILED) 167 return 0; 168 return (char)key; 169} 170 171 172void 173PPCOpenFirmware::SerialDebugPutChar(char c) 174{ 175 if (fOutput == -1) 176 return; 177 178 if (c == '\n') 179 of_write(fOutput, "\r\n", 2); 180 else 181 of_write(fOutput, &c, 1); 182} 183 184 185void 186PPCOpenFirmware::SetHardwareRTC(uint32 seconds) 187{ 188 struct tm t; 189 rtc_secs_to_tm(seconds, &t); 190 191 t.tm_year += RTC_EPOCH_BASE_YEAR; 192 t.tm_mon++; 193 194 if (of_call_method(fRTC, "set-time", 6, 0, t.tm_year, t.tm_mon, t.tm_mday, 195 t.tm_hour, t.tm_min, t.tm_sec) == OF_FAILED) { 196 dprintf("PPCOpenFirmware::SetHardwareRTC(): Failed to set RTC!\n"); 197 } 198} 199 200 201uint32 202PPCOpenFirmware::GetHardwareRTC() 203{ 204 struct tm t; 205 if (of_call_method(fRTC, "get-time", 0, 6, &t.tm_year, &t.tm_mon, 206 &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) == OF_FAILED) { 207 dprintf("PPCOpenFirmware::GetHardwareRTC(): Failed to get RTC!\n"); 208 return 0; 209 } 210 211 t.tm_year -= RTC_EPOCH_BASE_YEAR; 212 t.tm_mon--; 213 214 return rtc_tm_to_secs(&t); 215} 216 217 218void 219PPCOpenFirmware::ShutDown(bool reboot) 220{ 221 if (reboot) { 222 of_interpret("reset-all", 0, 0); 223 } else { 224 // not standardized, so it might fail 225 of_interpret("shut-down", 0, 0); 226 } 227} 228 229 230// #pragma mark - U-Boot + FDT 231 232 233namespace BPrivate { 234 235class PPCUBoot : public PPCPlatform { 236public: 237 PPCUBoot(); 238 virtual ~PPCUBoot(); 239 240 virtual status_t Init(struct kernel_args *kernelArgs); 241 virtual status_t InitSerialDebug(struct kernel_args *kernelArgs); 242 virtual status_t InitPostVM(struct kernel_args *kernelArgs); 243 virtual status_t InitRTC(struct kernel_args *kernelArgs, 244 struct real_time_data *data); 245 246 virtual char SerialDebugGetChar(); 247 virtual void SerialDebugPutChar(char c); 248 249 virtual void SetHardwareRTC(uint32 seconds); 250 virtual uint32 GetHardwareRTC(); 251 252 virtual void ShutDown(bool reboot); 253 254private: 255 int fInput; 256 int fOutput; 257 int fRTC; 258 DebugUART *fDebugUART; 259}; 260 261} // namespace BPrivate 262 263using BPrivate::PPCUBoot; 264 265 266PPCUBoot::PPCUBoot() 267 : PPCPlatform(PPC_PLATFORM_U_BOOT), 268 fInput(-1), 269 fOutput(-1), 270 fRTC(-1), 271 fDebugUART(NULL) 272{ 273} 274 275 276PPCUBoot::~PPCUBoot() 277{ 278} 279 280 281status_t 282PPCUBoot::Init(struct kernel_args *kernelArgs) 283{ 284 gFDT = kernelArgs->platform_args.fdt; 285 // XXX: do we error out if no FDT? 286 return B_OK; 287} 288 289 290status_t 291PPCUBoot::InitSerialDebug(struct kernel_args *kernelArgs) 292{ 293 // TODO: get relevant debug uart from fdt 294 //fDebugUART = debug_uart_from_fdt(gFDT); 295 if (fDebugUART == NULL) 296 return B_ERROR; 297 return B_OK; 298} 299 300 301status_t 302PPCUBoot::InitPostVM(struct kernel_args *kernelArgs) 303{ 304 return B_ERROR; 305} 306 307 308status_t 309PPCUBoot::InitRTC(struct kernel_args *kernelArgs, 310 struct real_time_data *data) 311{ 312 return B_ERROR; 313} 314 315 316char 317PPCUBoot::SerialDebugGetChar() 318{ 319 if (fDebugUART) 320 return fDebugUART->GetChar(false); 321 return 0; 322} 323 324 325void 326PPCUBoot::SerialDebugPutChar(char c) 327{ 328 if (fDebugUART) 329 fDebugUART->PutChar(c); 330} 331 332 333void 334PPCUBoot::SetHardwareRTC(uint32 seconds) 335{ 336} 337 338 339uint32 340PPCUBoot::GetHardwareRTC() 341{ 342 return 0; 343} 344 345 346void 347PPCUBoot::ShutDown(bool reboot) 348{ 349} 350 351 352// # pragma mark - 353 354 355#define PLATFORM_BUFFER_SIZE MAX(sizeof(PPCOpenFirmware),sizeof(PPCUBoot)) 356// static buffer for constructing the actual PPCPlatform 357static char *sPPCPlatformBuffer[PLATFORM_BUFFER_SIZE]; 358 359 360status_t 361arch_platform_init(struct kernel_args *kernelArgs) 362{ 363 // only OpenFirmware supported for now 364 switch (kernelArgs->arch_args.platform) { 365 case PPC_PLATFORM_OPEN_FIRMWARE: 366 sPPCPlatform = new(sPPCPlatformBuffer) PPCOpenFirmware; 367 break; 368 case PPC_PLATFORM_U_BOOT: 369 sPPCPlatform = new(sPPCPlatformBuffer) PPCUBoot; 370 break; 371 default: 372 return B_ERROR; 373 } 374 375 return sPPCPlatform->Init(kernelArgs); 376} 377 378 379status_t 380arch_platform_init_post_vm(struct kernel_args *kernelArgs) 381{ 382 return sPPCPlatform->InitPostVM(kernelArgs); 383} 384 385 386status_t 387arch_platform_init_post_thread(struct kernel_args *kernelArgs) 388{ 389 return B_OK; 390} 391