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
PPCPlatform(ppc_platform_type platformType)23 PPCPlatform::PPCPlatform(ppc_platform_type platformType)
24 : fPlatformType(platformType)
25 {
26 }
27
28
~PPCPlatform()29 PPCPlatform::~PPCPlatform()
30 {
31 }
32
33
34 PPCPlatform *
Default()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
debug_command_of_exit(int argc,char ** argv)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
debug_command_of_enter(int argc,char ** argv)90 debug_command_of_enter(int argc, char **argv)
91 {
92 of_call_client_function("enter", 0, 0);
93 return 0;
94 }
95
96
PPCOpenFirmware()97 PPCOpenFirmware::PPCOpenFirmware()
98 : PPCPlatform(PPC_PLATFORM_OPEN_FIRMWARE),
99 fInput(-1),
100 fOutput(-1),
101 fRTC(-1)
102 {
103 }
104
105
~PPCOpenFirmware()106 PPCOpenFirmware::~PPCOpenFirmware()
107 {
108 }
109
110
111 status_t
Init(struct kernel_args * kernelArgs)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
InitSerialDebug(struct kernel_args * kernelArgs)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
InitPostVM(struct kernel_args * kernelArgs)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
InitRTC(struct kernel_args * kernelArgs,struct real_time_data * data)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
SerialDebugGetChar()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
SerialDebugPutChar(char c)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
SetHardwareRTC(uint32 seconds)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
GetHardwareRTC()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
ShutDown(bool reboot)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
PPCUBoot()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
~PPCUBoot()276 PPCUBoot::~PPCUBoot()
277 {
278 }
279
280
281 status_t
Init(struct kernel_args * kernelArgs)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
InitSerialDebug(struct kernel_args * kernelArgs)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
InitPostVM(struct kernel_args * kernelArgs)302 PPCUBoot::InitPostVM(struct kernel_args *kernelArgs)
303 {
304 return B_ERROR;
305 }
306
307
308 status_t
InitRTC(struct kernel_args * kernelArgs,struct real_time_data * data)309 PPCUBoot::InitRTC(struct kernel_args *kernelArgs,
310 struct real_time_data *data)
311 {
312 return B_ERROR;
313 }
314
315
316 char
SerialDebugGetChar()317 PPCUBoot::SerialDebugGetChar()
318 {
319 if (fDebugUART)
320 return fDebugUART->GetChar(false);
321 return 0;
322 }
323
324
325 void
SerialDebugPutChar(char c)326 PPCUBoot::SerialDebugPutChar(char c)
327 {
328 if (fDebugUART)
329 fDebugUART->PutChar(c);
330 }
331
332
333 void
SetHardwareRTC(uint32 seconds)334 PPCUBoot::SetHardwareRTC(uint32 seconds)
335 {
336 }
337
338
339 uint32
GetHardwareRTC()340 PPCUBoot::GetHardwareRTC()
341 {
342 return 0;
343 }
344
345
346 void
ShutDown(bool reboot)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
arch_platform_init(struct kernel_args * kernelArgs)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
arch_platform_init_post_vm(struct kernel_args * kernelArgs)380 arch_platform_init_post_vm(struct kernel_args *kernelArgs)
381 {
382 return sPPCPlatform->InitPostVM(kernelArgs);
383 }
384
385
386 status_t
arch_platform_init_post_thread(struct kernel_args * kernelArgs)387 arch_platform_init_post_thread(struct kernel_args *kernelArgs)
388 {
389 return B_OK;
390 }
391