1/* $NetBSD: OsdHardware.c,v 1.15 2024/06/23 15:21:52 andvar Exp $ */ 2 3/* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38/* 39 * OS Services Layer 40 * 41 * 6.7: Address Space Access: Port Input/Output 42 * 6.8: Address Space Access: Memory and Memory Mapped I/O 43 * 6.9: Address Space Access: PCI Configuration Space 44 */ 45 46#include <sys/cdefs.h> 47__KERNEL_RCSID(0, "$NetBSD: OsdHardware.c,v 1.15 2024/06/23 15:21:52 andvar Exp $"); 48 49#include "pci.h" 50 51#include <sys/param.h> 52#include <sys/device.h> 53 54#include <dev/acpi/acpica.h> 55#include <dev/acpi/acpivar.h> 56#include <dev/acpi/acpi_pci.h> 57 58#include <machine/acpi_machdep.h> 59 60/* 61 * ACPICA doesn't provide much in the way of letting us know which 62 * hardware resources it wants to use. We therefore have to resort 63 * to calling machine-dependent code to do the access for us. 64 */ 65 66/* 67 * AcpiOsReadPort: 68 * 69 * Read a value from an input port. 70 */ 71ACPI_STATUS 72AcpiOsReadPort(ACPI_IO_ADDRESS Address, UINT32 *Value, UINT32 Width) 73{ 74 75 switch (Width) { 76 case 8: 77 *Value = acpi_md_OsIn8(Address); 78 break; 79 80 case 16: 81 *Value = acpi_md_OsIn16(Address); 82 break; 83 84 case 32: 85 *Value = acpi_md_OsIn32(Address); 86 break; 87 88 default: 89 return AE_BAD_PARAMETER; 90 } 91 92 return AE_OK; 93} 94 95/* 96 * AcpiOsWritePort: 97 * 98 * Write a value to an output port. 99 */ 100ACPI_STATUS 101AcpiOsWritePort(ACPI_IO_ADDRESS Address, UINT32 Value, UINT32 Width) 102{ 103 104 switch (Width) { 105 case 8: 106 acpi_md_OsOut8(Address, Value); 107 break; 108 109 case 16: 110 acpi_md_OsOut16(Address, Value); 111 break; 112 113 case 32: 114 acpi_md_OsOut32(Address, Value); 115 break; 116 117 default: 118 return AE_BAD_PARAMETER; 119 } 120 121 return AE_OK; 122} 123 124/* 125 * AcpiOsReadMemory: 126 * 127 * Read a value from a memory location. 128 */ 129ACPI_STATUS 130AcpiOsReadMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 *Value, UINT32 Width) 131{ 132 void *LogicalAddress; 133 ACPI_STATUS rv = AE_OK; 134 135 LogicalAddress = AcpiOsMapMemory(Address, Width / 8); 136 if (LogicalAddress == NULL) 137 return AE_NOT_EXIST; 138 139 switch (Width) { 140 case 8: 141 *Value = *(volatile uint8_t *) LogicalAddress; 142 break; 143 144 case 16: 145 *Value = *(volatile uint16_t *) LogicalAddress; 146 break; 147 148 case 32: 149 *Value = *(volatile uint32_t *) LogicalAddress; 150 break; 151 152 case 64: 153 *Value = *(volatile uint64_t *) LogicalAddress; 154 break; 155 156 default: 157 rv = AE_BAD_PARAMETER; 158 } 159 160 AcpiOsUnmapMemory(LogicalAddress, Width / 8); 161 162 return rv; 163} 164 165/* 166 * AcpiOsWriteMemory: 167 * 168 * Write a value to a memory location. 169 */ 170ACPI_STATUS 171AcpiOsWriteMemory(ACPI_PHYSICAL_ADDRESS Address, UINT64 Value, UINT32 Width) 172{ 173 void *LogicalAddress; 174 ACPI_STATUS rv = AE_OK; 175 176 LogicalAddress = AcpiOsMapMemory(Address, Width / 8); 177 if (LogicalAddress == NULL) 178 return AE_NOT_FOUND; 179 180 switch (Width) { 181 case 8: 182 *(volatile uint8_t *) LogicalAddress = Value; 183 break; 184 185 case 16: 186 *(volatile uint16_t *) LogicalAddress = Value; 187 break; 188 189 case 32: 190 *(volatile uint32_t *) LogicalAddress = Value; 191 break; 192 193 case 64: 194 *(volatile uint64_t *) LogicalAddress = Value; 195 break; 196 197 default: 198 rv = AE_BAD_PARAMETER; 199 } 200 201 AcpiOsUnmapMemory(LogicalAddress, Width / 8); 202 203 return rv; 204} 205 206/* 207 * AcpiOsReadPciConfiguration: 208 * 209 * Read a value from a PCI configuration register. 210 */ 211ACPI_STATUS 212AcpiOsReadPciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, UINT64 *Value, 213 UINT32 Width) 214{ 215#if NPCI > 0 216 pci_chipset_tag_t pc; 217 pcitag_t tag; 218 pcireg_t tmp; 219 220 if (PciId->Bus >= 256 || PciId->Device >= 32 || PciId->Function >= 8) 221 return AE_BAD_PARAMETER; 222 223 pc = acpi_pcidev_get_tag(PciId->Segment, PciId->Bus, PciId->Device, PciId->Function); 224 225 tag = pci_make_tag(pc, PciId->Bus, PciId->Device, PciId->Function); 226 tmp = pci_conf_read(pc, tag, Register & ~3); 227 228 switch (Width) { 229 case 8: 230 *Value = (tmp >> ((Register & 3) * 8)) & 0xff; 231 break; 232 233 case 16: 234 *Value = (tmp >> ((Register & 3) * 8)) & 0xffff; 235 break; 236 237 case 32: 238 *Value = tmp; 239 break; 240 241 default: 242 return AE_BAD_PARAMETER; 243 } 244 245 return AE_OK; 246#else 247 return AE_BAD_PARAMETER; 248#endif 249} 250 251/* 252 * AcpiOsWritePciConfiguration: 253 * 254 * Write a value to a PCI configuration register. 255 */ 256ACPI_STATUS 257AcpiOsWritePciConfiguration(ACPI_PCI_ID *PciId, UINT32 Register, 258 ACPI_INTEGER Value, UINT32 Width) 259{ 260#if NPCI > 0 261 pci_chipset_tag_t pc; 262 pcitag_t tag; 263 pcireg_t tmp; 264 265 pc = acpi_pcidev_get_tag(PciId->Segment, PciId->Bus, PciId->Device, PciId->Function); 266 tag = pci_make_tag(pc, PciId->Bus, PciId->Device, PciId->Function); 267 268 switch (Width) { 269 case 8: 270 tmp = pci_conf_read(pc, tag, Register & ~3); 271 tmp &= ~(0xffu << ((Register & 3) * 8)); 272 tmp |= (Value << ((Register & 3) * 8)); 273 break; 274 275 case 16: 276 tmp = pci_conf_read(pc, tag, Register & ~3); 277 tmp &= ~(0xffffu << ((Register & 3) * 8)); 278 tmp |= (Value << ((Register & 3) * 8)); 279 break; 280 281 case 32: 282 tmp = Value; 283 break; 284 285 default: 286 return AE_BAD_PARAMETER; 287 } 288 289 pci_conf_write(pc, tag, Register & ~3, tmp); 290 291 return AE_OK; 292#else 293 return AE_BAD_PARAMETER; 294#endif 295} 296