xref: /haiku/src/system/kernel/arch/ppc/arch_platform.cpp (revision 2b76973fa2401f7a5edf68e6470f3d3210cbcff3)
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