1 /* $NetBSD: aml_region.c,v 1.2 2011/05/30 01:15:30 dyoung Exp $ */
2
3 /*-
4 * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
5 * Copyright (c) 2000 Munehiro Matsuda <haro@tk.kubota.co.jp>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * Id: aml_region.c,v 1.10 2000/08/09 14:47:44 iwasaki Exp
30 * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_region.c,v 1.5 2000/11/09 06:24:45 iwasaki Exp $
31 */
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: aml_region.c,v 1.2 2011/05/30 01:15:30 dyoung Exp $");
34
35 /*
36 * Region I/O subroutine
37 */
38
39 #include "opt_acpi.h"
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/bus.h>
43
44 #include <machine/resource.h>
45 #include <sys/rman.h>
46
47 #include <dev/acpi/acpireg.h>
48 #include <dev/acpi/acpivar.h>
49 #include <aml/aml_common.h>
50 #include <aml/aml_region.h>
51 #include <aml/aml_name.h>
52
53 #ifndef ACPI_NO_OSDFUNC_INLINE
54 #include <machine/acpica_osd.h>
55 #endif
56
57 /*
58 * Dummy functions for aml_region_io_simple()
59 */
60 u_int32_t
aml_region_prompt_read(struct aml_region_handle * h,u_int32_t value)61 aml_region_prompt_read(struct aml_region_handle *h, u_int32_t value)
62 {
63
64 return (value);
65 }
66
67 u_int32_t
aml_region_prompt_write(struct aml_region_handle * h,u_int32_t value)68 aml_region_prompt_write(struct aml_region_handle *h, u_int32_t value)
69 {
70
71 return (value);
72 }
73
74 int
aml_region_prompt_update_value(u_int32_t orgval,u_int32_t value,struct aml_region_handle * h)75 aml_region_prompt_update_value(u_int32_t orgval, u_int32_t value,
76 struct aml_region_handle *h)
77 {
78 return (0);
79 }
80
81 /*
82 * Primitive functions for aml_region_io_simple()
83 */
84 int
aml_region_read_simple(struct aml_region_handle * h,vm_offset_t offset,u_int32_t * valuep)85 aml_region_read_simple(struct aml_region_handle *h, vm_offset_t offset, u_int32_t *valuep)
86 {
87 u_int32_t value;
88
89 switch (h->regtype) {
90 case AML_REGION_SYSMEM:
91 /* XXX should be MI */
92 switch (h->unit) {
93 case 1:
94 value = *(volatile u_int8_t *)(h->vaddr + offset);
95 value &= 0xff;
96 break;
97 case 2:
98 value = *(volatile u_int16_t *)(h->vaddr + offset);
99 value &= 0xffff;
100 break;
101 case 4:
102 value = *(volatile u_int32_t *)(h->vaddr + offset);
103 break;
104 }
105 break;
106 case AML_REGION_SYSIO:
107 switch (h->unit) {
108 case 1:
109 value = OsdIn8(h->addr + offset);
110 value &= 0xff;
111 break;
112 case 2:
113 value = OsdIn16(h->addr + offset);
114 value &= 0xffff;
115 break;
116 case 4:
117 value = OsdIn32(h->addr + offset);
118 break;
119 }
120 break;
121 case AML_REGION_PCICFG:
122 switch (h->unit) {
123 case 1:
124 OsdReadPciCfgByte(h->pci_bus, h->pci_devfunc,
125 h->addr + offset, (UINT8 *)&value);
126 value &= 0xff;
127 break;
128 case 2:
129 OsdReadPciCfgWord(h->pci_bus, h->pci_devfunc,
130 h->addr + offset, (UINT16 *)&value);
131 value &= 0xffff;
132 break;
133 case 4:
134 OsdReadPciCfgDword(h->pci_bus, h->pci_devfunc,
135 h->addr + offset, &value);
136 break;
137 }
138 break;
139 default:
140 printf("aml_region_read_simple: not supported yet (%d)\n",
141 h->regtype);
142 value = 0;
143 break;
144 }
145 *valuep = value;
146 return (0);
147 }
148
149 int
aml_region_write_simple(struct aml_region_handle * h,vm_offset_t offset,u_int32_t value)150 aml_region_write_simple(struct aml_region_handle *h, vm_offset_t offset, u_int32_t value)
151 {
152
153 switch (h->regtype) {
154 case AML_REGION_SYSMEM:
155 /* XXX should be MI */
156 switch (h->unit) {
157 case 1:
158 value &= 0xff;
159 *(volatile u_int8_t *)(h->vaddr + offset) = value;
160 break;
161 case 2:
162 value &= 0xffff;
163 *(volatile u_int16_t *)(h->vaddr + offset) = value;
164 break;
165 case 4:
166 *(volatile u_int32_t *)(h->vaddr + offset) = value;
167 break;
168 }
169 break;
170 case AML_REGION_SYSIO:
171 switch (h->unit) {
172 case 1:
173 value &= 0xff;
174 OsdOut8(h->addr + offset, value);
175 break;
176 case 2:
177 value &= 0xffff;
178 OsdOut16(h->addr + offset, value);
179 break;
180 case 4:
181 OsdOut32(h->addr + offset, value);
182 break;
183 }
184 break;
185 case AML_REGION_PCICFG:
186 switch (h->unit) {
187 case 1:
188 OsdWritePciCfgByte(h->pci_bus, h->pci_devfunc,
189 h->addr + offset, value);
190 break;
191 case 2:
192 OsdWritePciCfgWord(h->pci_bus, h->pci_devfunc,
193 h->addr + offset, value);
194 break;
195 case 4:
196 OsdWritePciCfgDword(h->pci_bus, h->pci_devfunc,
197 h->addr + offset, value);
198 break;
199 }
200 break;
201 default:
202 printf("aml_region_write_simple: not supported yet (%d)\n",
203 h->regtype);
204 break;
205 }
206
207 return (0);
208 }
209
210 static int
aml_region_io_buffer(boolean_t io,int regtype,u_int32_t flags,u_int8_t * buffer,u_int32_t baseaddr,u_int32_t bitoffset,u_int32_t bitlen)211 aml_region_io_buffer(boolean_t io, int regtype, u_int32_t flags,
212 u_int8_t *buffer, u_int32_t baseaddr, u_int32_t bitoffset, u_int32_t bitlen)
213 {
214 vm_offset_t addr, vaddr;
215 size_t len;
216 const char *funcname[] = {
217 "aml_region_read_into_buffer",
218 "aml_region_write_from_buffer"
219 };
220
221 if (regtype != AML_REGION_SYSMEM) {
222 printf("%s: region type isn't system memory!\n", funcname[io]);
223 return (-1);
224 }
225
226 if (bitlen % 8) {
227 printf("%s: bit length isn't a multiple of 8!\n", funcname[io]);
228 }
229 if (bitoffset % 8) {
230 printf("%s: bit offset isn't a multiple of 8!\n", funcname[io]);
231 }
232
233 addr = baseaddr + bitoffset / 8;
234 len = bitlen / 8 + ((bitlen % 8) ? 1 : 0);
235
236 OsdMapMemory((void *)addr, len, (void **)&vaddr);
237
238 switch (io) {
239 case AML_REGION_INPUT:
240 bcopy((void *)vaddr, (void *)buffer, len);
241 break;
242 case AML_REGION_OUTPUT:
243 bcopy((void *)buffer, (void *)vaddr, len);
244 break;
245 }
246
247 OsdUnMapMemory((void *)vaddr, len);
248
249 return (0);
250 }
251
252 u_int32_t
aml_region_read(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)253 aml_region_read(struct aml_environ *env, int regtype, u_int32_t flags,
254 u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen)
255 {
256 int value;
257 int state;
258
259 AML_REGION_READ_DEBUG(regtype, flags, addr, bitoffset, bitlen);
260
261 state = aml_region_io(env, AML_REGION_INPUT, regtype,
262 flags, &value, addr, bitoffset, bitlen);
263 AML_SYSASSERT(state != -1);
264
265 return (value);
266 }
267
268 int
aml_region_read_into_buffer(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen,u_int8_t * buffer)269 aml_region_read_into_buffer(struct aml_environ *env, int regtype,
270 u_int32_t flags, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen,
271 u_int8_t *buffer)
272 {
273 int state;
274
275 AML_REGION_READ_INTO_BUFFER_DEBUG(regtype, flags, addr, bitoffset, bitlen);
276 state = aml_region_io_buffer(AML_REGION_INPUT, regtype, flags,
277 buffer, addr, bitoffset, bitlen);
278
279 return (state);
280 }
281
282 int
aml_region_write(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t value,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)283 aml_region_write(struct aml_environ *env, int regtype, u_int32_t flags,
284 u_int32_t value, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen)
285 {
286 int state;
287
288 AML_REGION_WRITE_DEBUG(regtype, flags, value, addr, bitoffset, bitlen);
289
290 state = aml_region_io(env, AML_REGION_OUTPUT, regtype,
291 flags, &value, addr, bitoffset, bitlen);
292 AML_SYSASSERT(state != -1);
293
294 return (state);
295 }
296
297 int
aml_region_write_from_buffer(struct aml_environ * env,int regtype,u_int32_t flags,u_int8_t * buffer,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen)298 aml_region_write_from_buffer(struct aml_environ *env, int regtype,
299 u_int32_t flags, u_int8_t *buffer, u_int32_t addr, u_int32_t bitoffset,
300 u_int32_t bitlen)
301 {
302 int state;
303
304 AML_REGION_WRITE_FROM_BUFFER_DEBUG(regtype, flags,
305 addr, bitoffset, bitlen);
306
307 state = aml_region_io_buffer(AML_REGION_OUTPUT, regtype, flags,
308 buffer, addr, bitoffset, bitlen);
309
310 return (state);
311 }
312
313 int
aml_region_bcopy(struct aml_environ * env,int regtype,u_int32_t flags,u_int32_t addr,u_int32_t bitoffset,u_int32_t bitlen,u_int32_t dflags,u_int32_t daddr,u_int32_t dbitoffset,u_int32_t dbitlen)314 aml_region_bcopy(struct aml_environ *env, int regtype,
315 u_int32_t flags, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen,
316 u_int32_t dflags, u_int32_t daddr, u_int32_t dbitoffset, u_int32_t dbitlen)
317 {
318 vm_offset_t from_addr, from_vaddr;
319 vm_offset_t to_addr, to_vaddr;
320 size_t len;
321
322 AML_REGION_BCOPY_DEBUG(regtype, flags, addr, bitoffset, bitlen,
323 dflags, daddr, dbitoffset, dbitlen);
324
325 if (regtype != AML_REGION_SYSMEM) {
326 printf("aml_region_bcopy: region type isn't system memory!\n");
327 return (-1);
328 }
329
330 if ((bitlen % 8) || (dbitlen % 8)) {
331 printf("aml_region_bcopy: bit length isn't a multiple of 8!\n");
332 }
333 if ((bitoffset % 8) || (dbitoffset % 8)) {
334 printf("aml_region_bcopy: bit offset isn't a multiple of 8!\n");
335 }
336
337 from_addr = addr + bitoffset / 8;
338 to_addr = daddr + dbitoffset / 8;
339
340 len = (bitlen > dbitlen) ? dbitlen : bitlen;
341 len = len / 8 + ((len % 8) ? 1 : 0);
342
343 OsdMapMemory((void *)from_addr, len, (void **)&from_vaddr);
344 OsdMapMemory((void *)to_addr, len, (void **)&to_vaddr);
345
346 bcopy((void *)from_vaddr, (void *)to_vaddr, len);
347
348 OsdUnMapMemory((void *)from_vaddr, len);
349 OsdUnMapMemory((void *)to_vaddr, len);
350
351 return (0);
352 }
353