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