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 void *gFDT; 20 static PPCPlatform *sPPCPlatform; 21 22 23 PPCPlatform::PPCPlatform(ppc_platform_type platformType) 24 : fPlatformType(platformType) 25 { 26 } 27 28 29 PPCPlatform::~PPCPlatform() 30 { 31 } 32 33 34 PPCPlatform * 35 PPCPlatform::Default() 36 { 37 return sPPCPlatform; 38 } 39 40 41 // #pragma mark - Open Firmware 42 43 44 namespace BPrivate { 45 46 class PPCOpenFirmware : public PPCPlatform { 47 public: 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 65 private: 66 int fInput; 67 int fOutput; 68 int fRTC; 69 }; 70 71 } // namespace BPrivate 72 73 74 using BPrivate::PPCOpenFirmware; 75 76 77 // OF debugger commands 78 79 80 static int 81 debug_command_of_exit(int argc, char **argv) 82 { 83 of_exit(); 84 kprintf("of_exit() failed!\n"); 85 return 0; 86 } 87 88 89 static int 90 debug_command_of_enter(int argc, char **argv) 91 { 92 of_call_client_function("enter", 0, 0); 93 return 0; 94 } 95 96 97 PPCOpenFirmware::PPCOpenFirmware() 98 : PPCPlatform(PPC_PLATFORM_OPEN_FIRMWARE), 99 fInput(-1), 100 fOutput(-1), 101 fRTC(-1) 102 { 103 } 104 105 106 PPCOpenFirmware::~PPCOpenFirmware() 107 { 108 } 109 110 111 status_t 112 PPCOpenFirmware::Init(struct kernel_args *kernelArgs) 113 { 114 return of_init( 115 (intptr_t(*)(void*))kernelArgs->platform_args.openfirmware_entry); 116 } 117 118 119 status_t 120 PPCOpenFirmware::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 133 status_t 134 PPCOpenFirmware::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 147 status_t 148 PPCOpenFirmware::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 162 char 163 PPCOpenFirmware::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 172 void 173 PPCOpenFirmware::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 185 void 186 PPCOpenFirmware::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 201 uint32 202 PPCOpenFirmware::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 218 void 219 PPCOpenFirmware::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 233 namespace BPrivate { 234 235 class PPCUBoot : public PPCPlatform { 236 public: 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 254 private: 255 int fInput; 256 int fOutput; 257 int fRTC; 258 DebugUART *fDebugUART; 259 }; 260 261 } // namespace BPrivate 262 263 using BPrivate::PPCUBoot; 264 265 266 PPCUBoot::PPCUBoot() 267 : PPCPlatform(PPC_PLATFORM_U_BOOT), 268 fInput(-1), 269 fOutput(-1), 270 fRTC(-1), 271 fDebugUART(NULL) 272 { 273 } 274 275 276 PPCUBoot::~PPCUBoot() 277 { 278 } 279 280 281 status_t 282 PPCUBoot::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 290 status_t 291 PPCUBoot::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 301 status_t 302 PPCUBoot::InitPostVM(struct kernel_args *kernelArgs) 303 { 304 return B_ERROR; 305 } 306 307 308 status_t 309 PPCUBoot::InitRTC(struct kernel_args *kernelArgs, 310 struct real_time_data *data) 311 { 312 return B_ERROR; 313 } 314 315 316 char 317 PPCUBoot::SerialDebugGetChar() 318 { 319 if (fDebugUART) 320 return fDebugUART->GetChar(false); 321 return 0; 322 } 323 324 325 void 326 PPCUBoot::SerialDebugPutChar(char c) 327 { 328 if (fDebugUART) 329 fDebugUART->PutChar(c); 330 } 331 332 333 void 334 PPCUBoot::SetHardwareRTC(uint32 seconds) 335 { 336 } 337 338 339 uint32 340 PPCUBoot::GetHardwareRTC() 341 { 342 return 0; 343 } 344 345 346 void 347 PPCUBoot::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 357 static char *sPPCPlatformBuffer[PLATFORM_BUFFER_SIZE]; 358 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