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