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