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 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 68 aml_region_prompt_write(struct aml_region_handle *h, u_int32_t value) 69 { 70 71 return (value); 72 } 73 74 int 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 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 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 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 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 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 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 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 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