1/*
2 * Copyright 2006, Ingo Weinhold <bonefish@cs.tu-berlin.de>.
3 * Copyright 2019-2020, Adrien Destugues, pulkomandy@pulkomandy.tk.
4 * All rights reserved. Distributed under the terms of the MIT License.
5 */
6
7#include <arch_platform.h>
8
9#include <new>
10
11#include <KernelExport.h>
12
13#include <arch/generic/debug_uart.h>
14#include <boot/kernel_args.h>
15#include <platform/openfirmware/openfirmware.h>
16#include <real_time_clock.h>
17#include <util/kernel_cpp.h>
18
19
20static SparcPlatform *sSparcPlatform;
21
22
23// constructor
24SparcPlatform::SparcPlatform(sparc_platform_type platformType)
25	: fPlatformType(platformType)
26{
27}
28
29// destructor
30SparcPlatform::~SparcPlatform()
31{
32}
33
34// Default
35SparcPlatform *
36SparcPlatform::Default()
37{
38	return sSparcPlatform;
39}
40
41
42// #pragma mark - Open Firmware
43
44
45namespace BPrivate {
46
47class SparcOpenFirmware : public SparcPlatform {
48public:
49	SparcOpenFirmware();
50	virtual ~SparcOpenFirmware();
51
52	virtual status_t Init(struct kernel_args *kernelArgs);
53	virtual status_t InitSerialDebug(struct kernel_args *kernelArgs);
54	virtual status_t InitPostVM(struct kernel_args *kernelArgs);
55	virtual status_t InitRTC(struct kernel_args *kernelArgs,
56		struct real_time_data *data);
57
58	virtual char SerialDebugGetChar();
59	virtual void SerialDebugPutChar(char c);
60
61	virtual	void SetHardwareRTC(uint32 seconds);
62	virtual	uint32 GetHardwareRTC();
63
64	virtual	void ShutDown(bool reboot);
65
66private:
67	int	fInput;
68	int	fOutput;
69	int	fRTC;
70};
71
72}	// namespace BPrivate
73
74using BPrivate::SparcOpenFirmware;
75
76
77// OF debugger commands
78
79// debug_command_of_exit
80static int
81debug_command_of_exit(int argc, char **argv)
82{
83	of_exit();
84	kprintf("of_exit() failed!\n");
85	return 0;
86}
87
88// debug_command_of_enter
89static int
90debug_command_of_enter(int argc, char **argv)
91{
92	of_call_client_function("enter", 0, 0);
93	return 0;
94}
95
96
97// constructor
98SparcOpenFirmware::SparcOpenFirmware()
99	: SparcPlatform(SPARC_PLATFORM_OPEN_FIRMWARE),
100	  fInput(-1),
101	  fOutput(-1),
102	  fRTC(-1)
103{
104}
105
106// destructor
107SparcOpenFirmware::~SparcOpenFirmware()
108{
109}
110
111// Init
112status_t
113SparcOpenFirmware::Init(struct kernel_args *kernelArgs)
114{
115	return of_init(
116		(intptr_t(*)(void*))kernelArgs->platform_args.openfirmware_entry);
117}
118
119// InitSerialDebug
120status_t
121SparcOpenFirmware::InitSerialDebug(struct kernel_args *kernelArgs)
122{
123	if (of_getprop(gChosen, "stdin", &fInput, sizeof(int)) == OF_FAILED)
124		return B_ERROR;
125	if (!kernelArgs->frame_buffer.enabled) {
126		if (of_getprop(gChosen, "stdout", &fOutput, sizeof(int)) == OF_FAILED)
127			return B_ERROR;
128	}
129
130	return B_OK;
131}
132
133// InitPostVM
134status_t
135SparcOpenFirmware::InitPostVM(struct kernel_args *kernelArgs)
136{
137	add_debugger_command("of_exit", &debug_command_of_exit,
138		"Exit to the Open Firmware prompt. No way to get back into the OS!");
139	add_debugger_command("of_enter", &debug_command_of_enter,
140		"Enter a subordinate Open Firmware interpreter. Quitting it returns "
141		"to KDL.");
142
143	return B_OK;
144}
145
146// InitRTC
147status_t
148SparcOpenFirmware::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("SparcOpenFirmware::InitRTC(): Failed open RTC device!\n");
155		return B_ERROR;
156	}
157
158	return B_OK;
159}
160
161// DebugSerialGetChar
162char
163SparcOpenFirmware::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// DebugSerialPutChar
172void
173SparcOpenFirmware::SerialDebugPutChar(char c)
174{
175	if (fOutput == -1)
176		return;
177
178	if (c == '\n')
179		of_write((uint32_t)fOutput, "\r\n", 2);
180	else
181		of_write((uint32_t)fOutput, &c, 1);
182}
183
184// SetHardwareRTC
185void
186SparcOpenFirmware::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((uint32_t)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("SparcOpenFirmware::SetHardwareRTC(): Failed to set RTC!\n");
197	}
198}
199
200// GetHardwareRTC
201uint32
202SparcOpenFirmware::GetHardwareRTC()
203{
204	struct tm t;
205	if (of_call_method((uint32_t)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("SparcOpenFirmware::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// ShutDown
218void
219SparcOpenFirmware::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 -
231
232
233#define PLATFORM_BUFFER_SIZE sizeof(SparcOpenFirmware)
234// static buffer for constructing the actual SparcPlatform
235static char *sSparcPlatformBuffer[PLATFORM_BUFFER_SIZE];
236
237status_t
238arch_platform_init(struct kernel_args *kernelArgs)
239{
240	// only OpenFirmware supported for now
241	sSparcPlatform = new(sSparcPlatformBuffer) SparcOpenFirmware;
242
243	return sSparcPlatform->Init(kernelArgs);
244}
245
246
247status_t
248arch_platform_init_post_vm(struct kernel_args *kernelArgs)
249{
250	return sSparcPlatform->InitPostVM(kernelArgs);
251}
252
253
254status_t
255arch_platform_init_post_thread(struct kernel_args *kernelArgs)
256{
257	return B_OK;
258}
259