1 /******************************************************************************
2  * Copyright (c) 2004, 2008 IBM Corporation
extra()3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12 
13 #include <stdint.h>
14 #include <stdarg.h>
15 #include <stdio.h>
16 #include <rtas.h>
17 #include <of.h>
18 #include <kernel.h>
19 
20 typedef int rtas_arg_t;
21 
22 typedef struct {
23 	int token;
24 	int nargs;
25 	int nret;
26 	rtas_arg_t args[16];
27 	rtas_arg_t *rets;	/* Pointer to return values in args[]. */
28 } rtas_args_t;
29 
30 rtas_args_t rtas_args;
31 
32 typedef struct {
33 	void *rtas_start;
34 	void *rtas_entry;
35 	int rtas_size;
36 	phandle_t dev;
37 } rtas_t;
38 
39 extern rtas_t _rtas;
40 static int instantiate_rtas(void);
41 void rtas_call_entry(rtas_args_t *, void *, void *);
42 
43 int
44 rtas_token(const char *service)
45 {
46 	int token;
47 	int retVal;
48 	if (_rtas.dev == 0)
49 		instantiate_rtas();
50 
51 	retVal = of_getprop(_rtas.dev, service, &token, sizeof(token));
52 	if (retVal == -1) {
53 		token = 0;
54 	}
55 	return token;
56 }
57 
58 int
59 rtas_call(int token, int nargs, int nret, int *outputs, ...)
60 {
61 	va_list list;
62 	int i;
63 
64 	rtas_args.token = token;
65 	rtas_args.nargs = nargs;
66 	rtas_args.nret = nret;
67 	rtas_args.rets = (rtas_arg_t *) & (rtas_args.args[nargs]);
68 	va_start(list, outputs);
69 	for (i = 0; i < nargs; ++i) {
70 		rtas_args.args[i] = (rtas_arg_t) (va_arg(list, unsigned int));
71 	}
72 	va_end(list);
73 
74 	for (i = 0; i < nret; ++i)
75 		rtas_args.rets[i] = 0;
76 
77 	rtas_call_entry(&rtas_args, _rtas.rtas_start, _rtas.rtas_entry);
78 	if (nret > 0 && outputs != 0)
79 		for (i = 0; i < nret; i++)
80 			outputs[i] = rtas_args.rets[i];
81 #if 0
82 	printf("rtas call %x %x %x args: %x %x %x %x %x %x %x %x\n",
83 	       token, nargs, nret,
84 	       rtas_args.args[0],
85 	       rtas_args.args[1],
86 	       rtas_args.args[2],
87 	       rtas_args.args[3],
88 	       rtas_args.args[4], rtas_args.args[5], outputs[0], outputs[1]);
89 #endif
90 	return ((nret > 0) ? rtas_args.rets[0] : 0);
91 }
92 
93 rtas_t _rtas;
94 
95 static int
96 instantiate_rtas(void)
97 {
98 	long long *rtas_mem_space;
99 	ihandle_t ihandle;
100 
101 	_rtas.dev = of_finddevice("/rtas");
102 	if ((long) _rtas.dev < 0) {
103 		printf("\nCould not open /rtas\n");
104 		return -1;
105 	}
106 
107 	of_getprop(_rtas.dev, "rtas-size", &_rtas.rtas_size,
108 		   sizeof(_rtas.rtas_size));
109 
110 	if (_rtas.rtas_size <= 0) {
111 		printf("\nSize of rtas (%x) too small to make sense\n",
112 		       _rtas.rtas_size);
113 		return -1;
114 	}
115 
116 	rtas_mem_space = (long long *) malloc_aligned(_rtas.rtas_size, 0x100);
117 
118 	if (!rtas_mem_space) {
119 		printf("\nFailed to allocated memory for RTAS\n");
120 		return -1;
121 	}
122 
123 	ihandle = of_open("/rtas");
124 
125 	if ((long) ihandle < 0) {
126 		printf("Could not open /rtas\n");
127 		return -1;
128 	}
129 
130 	if ((long) (_rtas.rtas_entry = of_call_method_3("instantiate-rtas",
131 							ihandle,
132 							p32cast rtas_mem_space))
133 	    > 0) {
134 		_rtas.rtas_start = rtas_mem_space;
135 	} else {
136 		printf("instantiate-rtas failed\n");
137 		return -1;
138 	}
139 #if 0
140 	printf("\ninstantiate-rtas at %x size %x entry %x\n",
141 	       _rtas.rtas_start, _rtas.rtas_size, _rtas.rtas_entry);
142 #endif
143 	return 0;
144 }
145 
146 static int read_pci_config_token = 0;
147 static int write_pci_config_token = 0;
148 static int ibm_read_pci_config_token = 0;
149 static int ibm_write_pci_config_token = 0;
150 static int get_time_of_day_token = 0;
151 
152 void
153 rtas_init()
154 {
155 	int ret;
156 	ret = instantiate_rtas();
157 	if (ret)
158 		return;
159 	read_pci_config_token = rtas_token("read-pci-config");
160 	ibm_read_pci_config_token = rtas_token("ibm,read-pci-config");
161 	write_pci_config_token = rtas_token("write-pci-config");
162 	ibm_write_pci_config_token = rtas_token("ibm,write-pci-config");
163 	get_time_of_day_token = rtas_token("get-time-of-day");
164 }
165 
166 
167 int
168 rtas_pci_config_read(long long puid, int size, int bus, int devfn, int offset)
169 {
170 	int value[2];
171 
172 	if (ibm_read_pci_config_token && puid) {
173 		rtas_call(ibm_read_pci_config_token, 4, 2, value,
174 			  bus << 16 | devfn << 8 | offset,
175 			  puid >> 32, puid & 0xffffffffULL, size);
176 	} else if (read_pci_config_token) {
177 		rtas_call(read_pci_config_token, 2, 2, value,
178 			  bus << 16 | devfn << 8 | offset, size);
179 	}
180 
181 	return value[1];
182 }
183 
184 int
185 rtas_pci_config_write(long long puid, int size, int bus, int devfn,
186 		      int offset, int value)
187 {
188 	int rc;
189 
190 	if (ibm_write_pci_config_token && puid) {
191 		rtas_call(ibm_write_pci_config_token, 5, 1, &rc,
192 			  bus << 16 | devfn << 8 | offset,
193 			  puid >> 32, puid & 0xffffffffULL, size, value);
194 	} else
195 		rtas_call(write_pci_config_token, 3, 1, &rc,
196 			  bus << 16 | devfn << 8 | offset, size, value);
197 
198 	return rc;
199 }
200 
201 int
202 rtas_get_time_of_day(dtime * get)
203 {
204 	int rc = -1;
205 	unsigned int year;
206 	unsigned int month;
207 	unsigned int day;
208 	unsigned int hour;
209 	unsigned int minute;
210 	unsigned int second;
211 	unsigned int nano;
212 
213 	if (get_time_of_day_token)
214 		rtas_call(get_time_of_day_token, 0, 8, &rc, &year, &month, &day,
215 			  &hour, &minute, &second, &nano);
216 
217 	get->year = year;
218 	get->month = month;
219 	get->day = day;
220 	get->hour = hour;
221 	get->minute = minute;
222 	get->second = second;
223 	get->nano = nano;
224 
225 	return rc;
226 }
227