162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * pnpacpi -- PnP ACPI driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr> 662306a36Sopenharmony_ci * Copyright (c) 2004 Li Shaohua <shaohua.li@intel.com> 762306a36Sopenharmony_ci * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. 862306a36Sopenharmony_ci * Bjorn Helgaas <bjorn.helgaas@hp.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/acpi.h> 1262306a36Sopenharmony_ci#include <linux/pci.h> 1362306a36Sopenharmony_ci#include <linux/pnp.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci#include "../base.h" 1662306a36Sopenharmony_ci#include "pnpacpi.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic void decode_irq_flags(struct pnp_dev *dev, int flags, u8 *triggering, 1962306a36Sopenharmony_ci u8 *polarity, u8 *shareable) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL | 2262306a36Sopenharmony_ci IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE)) { 2362306a36Sopenharmony_ci case IORESOURCE_IRQ_LOWLEVEL: 2462306a36Sopenharmony_ci *triggering = ACPI_LEVEL_SENSITIVE; 2562306a36Sopenharmony_ci *polarity = ACPI_ACTIVE_LOW; 2662306a36Sopenharmony_ci break; 2762306a36Sopenharmony_ci case IORESOURCE_IRQ_HIGHLEVEL: 2862306a36Sopenharmony_ci *triggering = ACPI_LEVEL_SENSITIVE; 2962306a36Sopenharmony_ci *polarity = ACPI_ACTIVE_HIGH; 3062306a36Sopenharmony_ci break; 3162306a36Sopenharmony_ci case IORESOURCE_IRQ_LOWEDGE: 3262306a36Sopenharmony_ci *triggering = ACPI_EDGE_SENSITIVE; 3362306a36Sopenharmony_ci *polarity = ACPI_ACTIVE_LOW; 3462306a36Sopenharmony_ci break; 3562306a36Sopenharmony_ci case IORESOURCE_IRQ_HIGHEDGE: 3662306a36Sopenharmony_ci *triggering = ACPI_EDGE_SENSITIVE; 3762306a36Sopenharmony_ci *polarity = ACPI_ACTIVE_HIGH; 3862306a36Sopenharmony_ci break; 3962306a36Sopenharmony_ci default: 4062306a36Sopenharmony_ci dev_err(&dev->dev, "can't encode invalid IRQ mode %#x\n", 4162306a36Sopenharmony_ci flags); 4262306a36Sopenharmony_ci *triggering = ACPI_EDGE_SENSITIVE; 4362306a36Sopenharmony_ci *polarity = ACPI_ACTIVE_HIGH; 4462306a36Sopenharmony_ci break; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (flags & IORESOURCE_IRQ_SHAREABLE) 4862306a36Sopenharmony_ci *shareable = ACPI_SHARED; 4962306a36Sopenharmony_ci else 5062306a36Sopenharmony_ci *shareable = ACPI_EXCLUSIVE; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int dma_flags(struct pnp_dev *dev, int type, int bus_master, 5462306a36Sopenharmony_ci int transfer) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci int flags = 0; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (bus_master) 5962306a36Sopenharmony_ci flags |= IORESOURCE_DMA_MASTER; 6062306a36Sopenharmony_ci switch (type) { 6162306a36Sopenharmony_ci case ACPI_COMPATIBILITY: 6262306a36Sopenharmony_ci flags |= IORESOURCE_DMA_COMPATIBLE; 6362306a36Sopenharmony_ci break; 6462306a36Sopenharmony_ci case ACPI_TYPE_A: 6562306a36Sopenharmony_ci flags |= IORESOURCE_DMA_TYPEA; 6662306a36Sopenharmony_ci break; 6762306a36Sopenharmony_ci case ACPI_TYPE_B: 6862306a36Sopenharmony_ci flags |= IORESOURCE_DMA_TYPEB; 6962306a36Sopenharmony_ci break; 7062306a36Sopenharmony_ci case ACPI_TYPE_F: 7162306a36Sopenharmony_ci flags |= IORESOURCE_DMA_TYPEF; 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci default: 7462306a36Sopenharmony_ci /* Set a default value ? */ 7562306a36Sopenharmony_ci flags |= IORESOURCE_DMA_COMPATIBLE; 7662306a36Sopenharmony_ci dev_err(&dev->dev, "invalid DMA type %d\n", type); 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci switch (transfer) { 7962306a36Sopenharmony_ci case ACPI_TRANSFER_8: 8062306a36Sopenharmony_ci flags |= IORESOURCE_DMA_8BIT; 8162306a36Sopenharmony_ci break; 8262306a36Sopenharmony_ci case ACPI_TRANSFER_8_16: 8362306a36Sopenharmony_ci flags |= IORESOURCE_DMA_8AND16BIT; 8462306a36Sopenharmony_ci break; 8562306a36Sopenharmony_ci case ACPI_TRANSFER_16: 8662306a36Sopenharmony_ci flags |= IORESOURCE_DMA_16BIT; 8762306a36Sopenharmony_ci break; 8862306a36Sopenharmony_ci default: 8962306a36Sopenharmony_ci /* Set a default value ? */ 9062306a36Sopenharmony_ci flags |= IORESOURCE_DMA_8AND16BIT; 9162306a36Sopenharmony_ci dev_err(&dev->dev, "invalid DMA transfer type %d\n", transfer); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return flags; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci * Allocated Resources 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci if (!(r->flags & IORESOURCE_DISABLED)) 10462306a36Sopenharmony_ci pcibios_penalize_isa_irq(r->start, 1); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci pnp_add_resource(dev, r); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* 11062306a36Sopenharmony_ci * Device CSRs that do not appear in PCI config space should be described 11162306a36Sopenharmony_ci * via ACPI. This would normally be done with Address Space Descriptors 11262306a36Sopenharmony_ci * marked as "consumer-only," but old versions of Windows and Linux ignore 11362306a36Sopenharmony_ci * the producer/consumer flag, so HP invented a vendor-defined resource to 11462306a36Sopenharmony_ci * describe the location and size of CSR space. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistatic struct acpi_vendor_uuid hp_ccsr_uuid = { 11762306a36Sopenharmony_ci .subtype = 2, 11862306a36Sopenharmony_ci .data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a, 11962306a36Sopenharmony_ci 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad }, 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic int vendor_resource_matches(struct pnp_dev *dev, 12362306a36Sopenharmony_ci struct acpi_resource_vendor_typed *vendor, 12462306a36Sopenharmony_ci struct acpi_vendor_uuid *match, 12562306a36Sopenharmony_ci int expected_len) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci int uuid_len = sizeof(vendor->uuid); 12862306a36Sopenharmony_ci u8 uuid_subtype = vendor->uuid_subtype; 12962306a36Sopenharmony_ci u8 *uuid = vendor->uuid; 13062306a36Sopenharmony_ci int actual_len; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* byte_length includes uuid_subtype and uuid */ 13362306a36Sopenharmony_ci actual_len = vendor->byte_length - uuid_len - 1; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (uuid_subtype == match->subtype && 13662306a36Sopenharmony_ci uuid_len == sizeof(match->data) && 13762306a36Sopenharmony_ci memcmp(uuid, match->data, uuid_len) == 0) { 13862306a36Sopenharmony_ci if (expected_len && expected_len != actual_len) { 13962306a36Sopenharmony_ci dev_err(&dev->dev, 14062306a36Sopenharmony_ci "wrong vendor descriptor size; expected %d, found %d bytes\n", 14162306a36Sopenharmony_ci expected_len, actual_len); 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return 1; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return 0; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev, 15262306a36Sopenharmony_ci struct acpi_resource_vendor_typed *vendor) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct { u64 start, length; } range; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (vendor_resource_matches(dev, vendor, &hp_ccsr_uuid, 15762306a36Sopenharmony_ci sizeof(range))) { 15862306a36Sopenharmony_ci memcpy(&range, vendor->byte_data, sizeof(range)); 15962306a36Sopenharmony_ci pnp_add_mem_resource(dev, range.start, range.start + 16062306a36Sopenharmony_ci range.length - 1, 0); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, 16562306a36Sopenharmony_ci void *data) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct pnp_dev *dev = data; 16862306a36Sopenharmony_ci struct acpi_resource_dma *dma; 16962306a36Sopenharmony_ci struct acpi_resource_vendor_typed *vendor_typed; 17062306a36Sopenharmony_ci struct acpi_resource_gpio *gpio; 17162306a36Sopenharmony_ci struct resource_win win = {{0}, 0}; 17262306a36Sopenharmony_ci struct resource *r = &win.res; 17362306a36Sopenharmony_ci int i, flags; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (acpi_dev_resource_address_space(res, &win) 17662306a36Sopenharmony_ci || acpi_dev_resource_ext_address_space(res, &win)) { 17762306a36Sopenharmony_ci pnp_add_resource(dev, &win.res); 17862306a36Sopenharmony_ci return AE_OK; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci r->flags = 0; 18262306a36Sopenharmony_ci if (acpi_dev_resource_interrupt(res, 0, r)) { 18362306a36Sopenharmony_ci pnpacpi_add_irqresource(dev, r); 18462306a36Sopenharmony_ci for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++) 18562306a36Sopenharmony_ci pnpacpi_add_irqresource(dev, r); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (i > 1) { 18862306a36Sopenharmony_ci /* 18962306a36Sopenharmony_ci * The IRQ encoder puts a single interrupt in each 19062306a36Sopenharmony_ci * descriptor, so if a _CRS descriptor has more than 19162306a36Sopenharmony_ci * one interrupt, we won't be able to re-encode it. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci if (pnp_can_write(dev)) { 19462306a36Sopenharmony_ci dev_warn(&dev->dev, 19562306a36Sopenharmony_ci "multiple interrupts in _CRS descriptor; configuration can't be changed\n"); 19662306a36Sopenharmony_ci dev->capabilities &= ~PNP_WRITE; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci return AE_OK; 20062306a36Sopenharmony_ci } else if (acpi_gpio_get_irq_resource(res, &gpio)) { 20162306a36Sopenharmony_ci /* 20262306a36Sopenharmony_ci * If the resource is GpioInt() type then extract the IRQ 20362306a36Sopenharmony_ci * from GPIO resource and fill it into IRQ resource type. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci i = acpi_dev_gpio_irq_get(dev->data, 0); 20662306a36Sopenharmony_ci if (i >= 0) { 20762306a36Sopenharmony_ci flags = acpi_dev_irq_flags(gpio->triggering, 20862306a36Sopenharmony_ci gpio->polarity, 20962306a36Sopenharmony_ci gpio->shareable, 21062306a36Sopenharmony_ci gpio->wake_capable); 21162306a36Sopenharmony_ci } else { 21262306a36Sopenharmony_ci flags = IORESOURCE_DISABLED; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci pnp_add_irq_resource(dev, i, flags); 21562306a36Sopenharmony_ci return AE_OK; 21662306a36Sopenharmony_ci } else if (r->flags & IORESOURCE_DISABLED) { 21762306a36Sopenharmony_ci pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); 21862306a36Sopenharmony_ci return AE_OK; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci switch (res->type) { 22262306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY24: 22362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY32: 22462306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 22562306a36Sopenharmony_ci if (acpi_dev_resource_memory(res, r)) 22662306a36Sopenharmony_ci pnp_add_resource(dev, r); 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_IO: 22962306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_IO: 23062306a36Sopenharmony_ci if (acpi_dev_resource_io(res, r)) 23162306a36Sopenharmony_ci pnp_add_resource(dev, r); 23262306a36Sopenharmony_ci break; 23362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_DMA: 23462306a36Sopenharmony_ci dma = &res->data.dma; 23562306a36Sopenharmony_ci if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) 23662306a36Sopenharmony_ci flags = dma_flags(dev, dma->type, dma->bus_master, 23762306a36Sopenharmony_ci dma->transfer); 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci flags = IORESOURCE_DISABLED; 24062306a36Sopenharmony_ci pnp_add_dma_resource(dev, dma->channels[0], flags); 24162306a36Sopenharmony_ci break; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_START_DEPENDENT: 24462306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_DEPENDENT: 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_VENDOR: 24862306a36Sopenharmony_ci vendor_typed = &res->data.vendor_typed; 24962306a36Sopenharmony_ci pnpacpi_parse_allocated_vendor(dev, vendor_typed); 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_TAG: 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_SERIAL_BUS: 25962306a36Sopenharmony_ci /* serial bus connections (I2C/SPI/UART) are not pnp */ 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci default: 26362306a36Sopenharmony_ci dev_warn(&dev->dev, "unknown resource type %d in _CRS\n", 26462306a36Sopenharmony_ci res->type); 26562306a36Sopenharmony_ci return AE_ERROR; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return AE_OK; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ciint pnpacpi_parse_allocated_resource(struct pnp_dev *dev) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct acpi_device *acpi_dev = dev->data; 27462306a36Sopenharmony_ci acpi_handle handle = acpi_dev->handle; 27562306a36Sopenharmony_ci acpi_status status; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci pnp_dbg(&dev->dev, "parse allocated resources\n"); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci pnp_init_resources(dev); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci status = acpi_walk_resources(handle, METHOD_NAME__CRS, 28262306a36Sopenharmony_ci pnpacpi_allocated_resource, dev); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 28562306a36Sopenharmony_ci if (status != AE_NOT_FOUND) 28662306a36Sopenharmony_ci dev_err(&dev->dev, "can't evaluate _CRS: %d", status); 28762306a36Sopenharmony_ci return -EPERM; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci return 0; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, 29362306a36Sopenharmony_ci unsigned int option_flags, 29462306a36Sopenharmony_ci struct acpi_resource_dma *p) 29562306a36Sopenharmony_ci{ 29662306a36Sopenharmony_ci int i; 29762306a36Sopenharmony_ci unsigned char map = 0, flags; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci for (i = 0; i < p->channel_count; i++) 30062306a36Sopenharmony_ci map |= 1 << p->channels[i]; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci flags = dma_flags(dev, p->type, p->bus_master, p->transfer); 30362306a36Sopenharmony_ci pnp_register_dma_resource(dev, option_flags, map, flags); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, 30762306a36Sopenharmony_ci unsigned int option_flags, 30862306a36Sopenharmony_ci struct acpi_resource_irq *p) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci int i; 31162306a36Sopenharmony_ci pnp_irq_mask_t map; 31262306a36Sopenharmony_ci unsigned char flags; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci bitmap_zero(map.bits, PNP_IRQ_NR); 31562306a36Sopenharmony_ci for (i = 0; i < p->interrupt_count; i++) 31662306a36Sopenharmony_ci if (p->interrupts[i]) 31762306a36Sopenharmony_ci __set_bit(p->interrupts[i], map.bits); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->shareable, p->wake_capable); 32062306a36Sopenharmony_ci pnp_register_irq_resource(dev, option_flags, &map, flags); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, 32462306a36Sopenharmony_ci unsigned int option_flags, 32562306a36Sopenharmony_ci struct acpi_resource_extended_irq *p) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci int i; 32862306a36Sopenharmony_ci pnp_irq_mask_t map; 32962306a36Sopenharmony_ci unsigned char flags; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci bitmap_zero(map.bits, PNP_IRQ_NR); 33262306a36Sopenharmony_ci for (i = 0; i < p->interrupt_count; i++) { 33362306a36Sopenharmony_ci if (p->interrupts[i]) { 33462306a36Sopenharmony_ci if (p->interrupts[i] < PNP_IRQ_NR) 33562306a36Sopenharmony_ci __set_bit(p->interrupts[i], map.bits); 33662306a36Sopenharmony_ci else 33762306a36Sopenharmony_ci dev_err(&dev->dev, 33862306a36Sopenharmony_ci "ignoring IRQ %d option (too large for %d entry bitmap)\n", 33962306a36Sopenharmony_ci p->interrupts[i], PNP_IRQ_NR); 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->shareable, p->wake_capable); 34462306a36Sopenharmony_ci pnp_register_irq_resource(dev, option_flags, &map, flags); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic __init void pnpacpi_parse_port_option(struct pnp_dev *dev, 34862306a36Sopenharmony_ci unsigned int option_flags, 34962306a36Sopenharmony_ci struct acpi_resource_io *io) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci unsigned char flags = 0; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (io->io_decode == ACPI_DECODE_16) 35462306a36Sopenharmony_ci flags = IORESOURCE_IO_16BIT_ADDR; 35562306a36Sopenharmony_ci pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, 35662306a36Sopenharmony_ci io->alignment, io->address_length, flags); 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, 36062306a36Sopenharmony_ci unsigned int option_flags, 36162306a36Sopenharmony_ci struct acpi_resource_fixed_io *io) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci pnp_register_port_resource(dev, option_flags, io->address, io->address, 36462306a36Sopenharmony_ci 0, io->address_length, IORESOURCE_IO_FIXED); 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, 36862306a36Sopenharmony_ci unsigned int option_flags, 36962306a36Sopenharmony_ci struct acpi_resource_memory24 *p) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci unsigned char flags = 0; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci if (p->write_protect == ACPI_READ_WRITE_MEMORY) 37462306a36Sopenharmony_ci flags = IORESOURCE_MEM_WRITEABLE; 37562306a36Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, 37662306a36Sopenharmony_ci p->alignment, p->address_length, flags); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, 38062306a36Sopenharmony_ci unsigned int option_flags, 38162306a36Sopenharmony_ci struct acpi_resource_memory32 *p) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci unsigned char flags = 0; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (p->write_protect == ACPI_READ_WRITE_MEMORY) 38662306a36Sopenharmony_ci flags = IORESOURCE_MEM_WRITEABLE; 38762306a36Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, 38862306a36Sopenharmony_ci p->alignment, p->address_length, flags); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, 39262306a36Sopenharmony_ci unsigned int option_flags, 39362306a36Sopenharmony_ci struct acpi_resource_fixed_memory32 *p) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci unsigned char flags = 0; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (p->write_protect == ACPI_READ_WRITE_MEMORY) 39862306a36Sopenharmony_ci flags = IORESOURCE_MEM_WRITEABLE; 39962306a36Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, p->address, p->address, 40062306a36Sopenharmony_ci 0, p->address_length, flags); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic __init void pnpacpi_parse_address_option(struct pnp_dev *dev, 40462306a36Sopenharmony_ci unsigned int option_flags, 40562306a36Sopenharmony_ci struct acpi_resource *r) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct acpi_resource_address64 addr, *p = &addr; 40862306a36Sopenharmony_ci acpi_status status; 40962306a36Sopenharmony_ci unsigned char flags = 0; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci status = acpi_resource_to_address64(r, p); 41262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 41362306a36Sopenharmony_ci dev_warn(&dev->dev, "can't convert resource type %d\n", 41462306a36Sopenharmony_ci r->type); 41562306a36Sopenharmony_ci return; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (p->resource_type == ACPI_MEMORY_RANGE) { 41962306a36Sopenharmony_ci if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) 42062306a36Sopenharmony_ci flags = IORESOURCE_MEM_WRITEABLE; 42162306a36Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, p->address.minimum, 42262306a36Sopenharmony_ci p->address.minimum, 0, p->address.address_length, 42362306a36Sopenharmony_ci flags); 42462306a36Sopenharmony_ci } else if (p->resource_type == ACPI_IO_RANGE) 42562306a36Sopenharmony_ci pnp_register_port_resource(dev, option_flags, p->address.minimum, 42662306a36Sopenharmony_ci p->address.minimum, 0, p->address.address_length, 42762306a36Sopenharmony_ci IORESOURCE_IO_FIXED); 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, 43162306a36Sopenharmony_ci unsigned int option_flags, 43262306a36Sopenharmony_ci struct acpi_resource *r) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct acpi_resource_extended_address64 *p = &r->data.ext_address64; 43562306a36Sopenharmony_ci unsigned char flags = 0; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (p->resource_type == ACPI_MEMORY_RANGE) { 43862306a36Sopenharmony_ci if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) 43962306a36Sopenharmony_ci flags = IORESOURCE_MEM_WRITEABLE; 44062306a36Sopenharmony_ci pnp_register_mem_resource(dev, option_flags, p->address.minimum, 44162306a36Sopenharmony_ci p->address.minimum, 0, p->address.address_length, 44262306a36Sopenharmony_ci flags); 44362306a36Sopenharmony_ci } else if (p->resource_type == ACPI_IO_RANGE) 44462306a36Sopenharmony_ci pnp_register_port_resource(dev, option_flags, p->address.minimum, 44562306a36Sopenharmony_ci p->address.minimum, 0, p->address.address_length, 44662306a36Sopenharmony_ci IORESOURCE_IO_FIXED); 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistruct acpipnp_parse_option_s { 45062306a36Sopenharmony_ci struct pnp_dev *dev; 45162306a36Sopenharmony_ci unsigned int option_flags; 45262306a36Sopenharmony_ci}; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, 45562306a36Sopenharmony_ci void *data) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci int priority; 45862306a36Sopenharmony_ci struct acpipnp_parse_option_s *parse_data = data; 45962306a36Sopenharmony_ci struct pnp_dev *dev = parse_data->dev; 46062306a36Sopenharmony_ci unsigned int option_flags = parse_data->option_flags; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci switch (res->type) { 46362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_IRQ: 46462306a36Sopenharmony_ci pnpacpi_parse_irq_option(dev, option_flags, &res->data.irq); 46562306a36Sopenharmony_ci break; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_DMA: 46862306a36Sopenharmony_ci pnpacpi_parse_dma_option(dev, option_flags, &res->data.dma); 46962306a36Sopenharmony_ci break; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_START_DEPENDENT: 47262306a36Sopenharmony_ci switch (res->data.start_dpf.compatibility_priority) { 47362306a36Sopenharmony_ci case ACPI_GOOD_CONFIGURATION: 47462306a36Sopenharmony_ci priority = PNP_RES_PRIORITY_PREFERRED; 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci case ACPI_ACCEPTABLE_CONFIGURATION: 47862306a36Sopenharmony_ci priority = PNP_RES_PRIORITY_ACCEPTABLE; 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci case ACPI_SUB_OPTIMAL_CONFIGURATION: 48262306a36Sopenharmony_ci priority = PNP_RES_PRIORITY_FUNCTIONAL; 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci default: 48562306a36Sopenharmony_ci priority = PNP_RES_PRIORITY_INVALID; 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci parse_data->option_flags = pnp_new_dependent_set(dev, priority); 48962306a36Sopenharmony_ci break; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_DEPENDENT: 49262306a36Sopenharmony_ci parse_data->option_flags = 0; 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_IO: 49662306a36Sopenharmony_ci pnpacpi_parse_port_option(dev, option_flags, &res->data.io); 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_IO: 50062306a36Sopenharmony_ci pnpacpi_parse_fixed_port_option(dev, option_flags, 50162306a36Sopenharmony_ci &res->data.fixed_io); 50262306a36Sopenharmony_ci break; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_VENDOR: 50562306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_TAG: 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY24: 50962306a36Sopenharmony_ci pnpacpi_parse_mem24_option(dev, option_flags, 51062306a36Sopenharmony_ci &res->data.memory24); 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY32: 51462306a36Sopenharmony_ci pnpacpi_parse_mem32_option(dev, option_flags, 51562306a36Sopenharmony_ci &res->data.memory32); 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 51962306a36Sopenharmony_ci pnpacpi_parse_fixed_mem32_option(dev, option_flags, 52062306a36Sopenharmony_ci &res->data.fixed_memory32); 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS16: 52462306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS32: 52562306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS64: 52662306a36Sopenharmony_ci pnpacpi_parse_address_option(dev, option_flags, res); 52762306a36Sopenharmony_ci break; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 53062306a36Sopenharmony_ci pnpacpi_parse_ext_address_option(dev, option_flags, res); 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 53462306a36Sopenharmony_ci pnpacpi_parse_ext_irq_option(dev, option_flags, 53562306a36Sopenharmony_ci &res->data.extended_irq); 53662306a36Sopenharmony_ci break; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 53962306a36Sopenharmony_ci break; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci default: 54262306a36Sopenharmony_ci dev_warn(&dev->dev, "unknown resource type %d in _PRS\n", 54362306a36Sopenharmony_ci res->type); 54462306a36Sopenharmony_ci return AE_ERROR; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci return AE_OK; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ciint __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct acpi_device *acpi_dev = dev->data; 55362306a36Sopenharmony_ci acpi_handle handle = acpi_dev->handle; 55462306a36Sopenharmony_ci acpi_status status; 55562306a36Sopenharmony_ci struct acpipnp_parse_option_s parse_data; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci pnp_dbg(&dev->dev, "parse resource options\n"); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci parse_data.dev = dev; 56062306a36Sopenharmony_ci parse_data.option_flags = 0; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci status = acpi_walk_resources(handle, METHOD_NAME__PRS, 56362306a36Sopenharmony_ci pnpacpi_option_resource, &parse_data); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 56662306a36Sopenharmony_ci if (status != AE_NOT_FOUND) 56762306a36Sopenharmony_ci dev_err(&dev->dev, "can't evaluate _PRS: %d", status); 56862306a36Sopenharmony_ci return -EPERM; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci return 0; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic int pnpacpi_supported_resource(struct acpi_resource *res) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci switch (res->type) { 57662306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_IRQ: 57762306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_DMA: 57862306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_IO: 57962306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_IO: 58062306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY24: 58162306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY32: 58262306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 58362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS16: 58462306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS32: 58562306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS64: 58662306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 58762306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 58862306a36Sopenharmony_ci return 1; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci/* 59462306a36Sopenharmony_ci * Set resource 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_cistatic acpi_status pnpacpi_count_resources(struct acpi_resource *res, 59762306a36Sopenharmony_ci void *data) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci int *res_cnt = data; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (pnpacpi_supported_resource(res)) 60262306a36Sopenharmony_ci (*res_cnt)++; 60362306a36Sopenharmony_ci return AE_OK; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci struct acpi_resource **resource = data; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (pnpacpi_supported_resource(res)) { 61162306a36Sopenharmony_ci (*resource)->type = res->type; 61262306a36Sopenharmony_ci (*resource)->length = sizeof(struct acpi_resource); 61362306a36Sopenharmony_ci if (res->type == ACPI_RESOURCE_TYPE_IRQ) 61462306a36Sopenharmony_ci (*resource)->data.irq.descriptor_length = 61562306a36Sopenharmony_ci res->data.irq.descriptor_length; 61662306a36Sopenharmony_ci (*resource)++; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci return AE_OK; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ciint pnpacpi_build_resource_template(struct pnp_dev *dev, 62362306a36Sopenharmony_ci struct acpi_buffer *buffer) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci struct acpi_device *acpi_dev = dev->data; 62662306a36Sopenharmony_ci acpi_handle handle = acpi_dev->handle; 62762306a36Sopenharmony_ci struct acpi_resource *resource; 62862306a36Sopenharmony_ci int res_cnt = 0; 62962306a36Sopenharmony_ci acpi_status status; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci status = acpi_walk_resources(handle, METHOD_NAME__CRS, 63262306a36Sopenharmony_ci pnpacpi_count_resources, &res_cnt); 63362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 63462306a36Sopenharmony_ci dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status); 63562306a36Sopenharmony_ci return -EINVAL; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci if (!res_cnt) 63862306a36Sopenharmony_ci return -EINVAL; 63962306a36Sopenharmony_ci buffer->length = sizeof(struct acpi_resource) * (res_cnt + 1) + 1; 64062306a36Sopenharmony_ci buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL); 64162306a36Sopenharmony_ci if (!buffer->pointer) 64262306a36Sopenharmony_ci return -ENOMEM; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci resource = (struct acpi_resource *)buffer->pointer; 64562306a36Sopenharmony_ci status = acpi_walk_resources(handle, METHOD_NAME__CRS, 64662306a36Sopenharmony_ci pnpacpi_type_resources, &resource); 64762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 64862306a36Sopenharmony_ci kfree(buffer->pointer); 64962306a36Sopenharmony_ci dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status); 65062306a36Sopenharmony_ci return -EINVAL; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci /* resource will pointer the end resource now */ 65362306a36Sopenharmony_ci resource->type = ACPI_RESOURCE_TYPE_END_TAG; 65462306a36Sopenharmony_ci resource->length = sizeof(struct acpi_resource); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci return 0; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic void pnpacpi_encode_irq(struct pnp_dev *dev, 66062306a36Sopenharmony_ci struct acpi_resource *resource, 66162306a36Sopenharmony_ci struct resource *p) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct acpi_resource_irq *irq = &resource->data.irq; 66462306a36Sopenharmony_ci u8 triggering, polarity, shareable; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (!pnp_resource_enabled(p)) { 66762306a36Sopenharmony_ci irq->interrupt_count = 0; 66862306a36Sopenharmony_ci pnp_dbg(&dev->dev, " encode irq (%s)\n", 66962306a36Sopenharmony_ci p ? "disabled" : "missing"); 67062306a36Sopenharmony_ci return; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); 67462306a36Sopenharmony_ci irq->triggering = triggering; 67562306a36Sopenharmony_ci irq->polarity = polarity; 67662306a36Sopenharmony_ci irq->shareable = shareable; 67762306a36Sopenharmony_ci irq->interrupt_count = 1; 67862306a36Sopenharmony_ci irq->interrupts[0] = p->start; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci pnp_dbg(&dev->dev, " encode irq %d %s %s %s (%d-byte descriptor)\n", 68162306a36Sopenharmony_ci (int) p->start, 68262306a36Sopenharmony_ci triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", 68362306a36Sopenharmony_ci polarity == ACPI_ACTIVE_LOW ? "low" : "high", 68462306a36Sopenharmony_ci irq->shareable == ACPI_SHARED ? "shared" : "exclusive", 68562306a36Sopenharmony_ci irq->descriptor_length); 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic void pnpacpi_encode_ext_irq(struct pnp_dev *dev, 68962306a36Sopenharmony_ci struct acpi_resource *resource, 69062306a36Sopenharmony_ci struct resource *p) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq; 69362306a36Sopenharmony_ci u8 triggering, polarity, shareable; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (!pnp_resource_enabled(p)) { 69662306a36Sopenharmony_ci extended_irq->interrupt_count = 0; 69762306a36Sopenharmony_ci pnp_dbg(&dev->dev, " encode extended irq (%s)\n", 69862306a36Sopenharmony_ci p ? "disabled" : "missing"); 69962306a36Sopenharmony_ci return; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); 70362306a36Sopenharmony_ci extended_irq->producer_consumer = ACPI_CONSUMER; 70462306a36Sopenharmony_ci extended_irq->triggering = triggering; 70562306a36Sopenharmony_ci extended_irq->polarity = polarity; 70662306a36Sopenharmony_ci extended_irq->shareable = shareable; 70762306a36Sopenharmony_ci extended_irq->interrupt_count = 1; 70862306a36Sopenharmony_ci extended_irq->interrupts[0] = p->start; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci pnp_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start, 71162306a36Sopenharmony_ci triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", 71262306a36Sopenharmony_ci polarity == ACPI_ACTIVE_LOW ? "low" : "high", 71362306a36Sopenharmony_ci extended_irq->shareable == ACPI_SHARED ? "shared" : "exclusive"); 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic void pnpacpi_encode_dma(struct pnp_dev *dev, 71762306a36Sopenharmony_ci struct acpi_resource *resource, 71862306a36Sopenharmony_ci struct resource *p) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct acpi_resource_dma *dma = &resource->data.dma; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (!pnp_resource_enabled(p)) { 72362306a36Sopenharmony_ci dma->channel_count = 0; 72462306a36Sopenharmony_ci pnp_dbg(&dev->dev, " encode dma (%s)\n", 72562306a36Sopenharmony_ci p ? "disabled" : "missing"); 72662306a36Sopenharmony_ci return; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */ 73062306a36Sopenharmony_ci switch (p->flags & IORESOURCE_DMA_SPEED_MASK) { 73162306a36Sopenharmony_ci case IORESOURCE_DMA_TYPEA: 73262306a36Sopenharmony_ci dma->type = ACPI_TYPE_A; 73362306a36Sopenharmony_ci break; 73462306a36Sopenharmony_ci case IORESOURCE_DMA_TYPEB: 73562306a36Sopenharmony_ci dma->type = ACPI_TYPE_B; 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci case IORESOURCE_DMA_TYPEF: 73862306a36Sopenharmony_ci dma->type = ACPI_TYPE_F; 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci default: 74162306a36Sopenharmony_ci dma->type = ACPI_COMPATIBILITY; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci switch (p->flags & IORESOURCE_DMA_TYPE_MASK) { 74562306a36Sopenharmony_ci case IORESOURCE_DMA_8BIT: 74662306a36Sopenharmony_ci dma->transfer = ACPI_TRANSFER_8; 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci case IORESOURCE_DMA_8AND16BIT: 74962306a36Sopenharmony_ci dma->transfer = ACPI_TRANSFER_8_16; 75062306a36Sopenharmony_ci break; 75162306a36Sopenharmony_ci default: 75262306a36Sopenharmony_ci dma->transfer = ACPI_TRANSFER_16; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER); 75662306a36Sopenharmony_ci dma->channel_count = 1; 75762306a36Sopenharmony_ci dma->channels[0] = p->start; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci pnp_dbg(&dev->dev, " encode dma %d " 76062306a36Sopenharmony_ci "type %#x transfer %#x master %d\n", 76162306a36Sopenharmony_ci (int) p->start, dma->type, dma->transfer, dma->bus_master); 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic void pnpacpi_encode_io(struct pnp_dev *dev, 76562306a36Sopenharmony_ci struct acpi_resource *resource, 76662306a36Sopenharmony_ci struct resource *p) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci struct acpi_resource_io *io = &resource->data.io; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (pnp_resource_enabled(p)) { 77162306a36Sopenharmony_ci /* Note: pnp_assign_port copies pnp_port->flags into p->flags */ 77262306a36Sopenharmony_ci io->io_decode = (p->flags & IORESOURCE_IO_16BIT_ADDR) ? 77362306a36Sopenharmony_ci ACPI_DECODE_16 : ACPI_DECODE_10; 77462306a36Sopenharmony_ci io->minimum = p->start; 77562306a36Sopenharmony_ci io->maximum = p->end; 77662306a36Sopenharmony_ci io->alignment = 0; /* Correct? */ 77762306a36Sopenharmony_ci io->address_length = resource_size(p); 77862306a36Sopenharmony_ci } else { 77962306a36Sopenharmony_ci io->minimum = 0; 78062306a36Sopenharmony_ci io->address_length = 0; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci pnp_dbg(&dev->dev, " encode io %#x-%#x decode %#x\n", io->minimum, 78462306a36Sopenharmony_ci io->minimum + io->address_length - 1, io->io_decode); 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic void pnpacpi_encode_fixed_io(struct pnp_dev *dev, 78862306a36Sopenharmony_ci struct acpi_resource *resource, 78962306a36Sopenharmony_ci struct resource *p) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (pnp_resource_enabled(p)) { 79462306a36Sopenharmony_ci fixed_io->address = p->start; 79562306a36Sopenharmony_ci fixed_io->address_length = resource_size(p); 79662306a36Sopenharmony_ci } else { 79762306a36Sopenharmony_ci fixed_io->address = 0; 79862306a36Sopenharmony_ci fixed_io->address_length = 0; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci pnp_dbg(&dev->dev, " encode fixed_io %#x-%#x\n", fixed_io->address, 80262306a36Sopenharmony_ci fixed_io->address + fixed_io->address_length - 1); 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic void pnpacpi_encode_mem24(struct pnp_dev *dev, 80662306a36Sopenharmony_ci struct acpi_resource *resource, 80762306a36Sopenharmony_ci struct resource *p) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct acpi_resource_memory24 *memory24 = &resource->data.memory24; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (pnp_resource_enabled(p)) { 81262306a36Sopenharmony_ci /* Note: pnp_assign_mem copies pnp_mem->flags into p->flags */ 81362306a36Sopenharmony_ci memory24->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ? 81462306a36Sopenharmony_ci ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; 81562306a36Sopenharmony_ci memory24->minimum = p->start; 81662306a36Sopenharmony_ci memory24->maximum = p->end; 81762306a36Sopenharmony_ci memory24->alignment = 0; 81862306a36Sopenharmony_ci memory24->address_length = resource_size(p); 81962306a36Sopenharmony_ci } else { 82062306a36Sopenharmony_ci memory24->minimum = 0; 82162306a36Sopenharmony_ci memory24->address_length = 0; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci pnp_dbg(&dev->dev, " encode mem24 %#x-%#x write_protect %#x\n", 82562306a36Sopenharmony_ci memory24->minimum, 82662306a36Sopenharmony_ci memory24->minimum + memory24->address_length - 1, 82762306a36Sopenharmony_ci memory24->write_protect); 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cistatic void pnpacpi_encode_mem32(struct pnp_dev *dev, 83162306a36Sopenharmony_ci struct acpi_resource *resource, 83262306a36Sopenharmony_ci struct resource *p) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci struct acpi_resource_memory32 *memory32 = &resource->data.memory32; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci if (pnp_resource_enabled(p)) { 83762306a36Sopenharmony_ci memory32->write_protect = p->flags & IORESOURCE_MEM_WRITEABLE ? 83862306a36Sopenharmony_ci ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; 83962306a36Sopenharmony_ci memory32->minimum = p->start; 84062306a36Sopenharmony_ci memory32->maximum = p->end; 84162306a36Sopenharmony_ci memory32->alignment = 0; 84262306a36Sopenharmony_ci memory32->address_length = resource_size(p); 84362306a36Sopenharmony_ci } else { 84462306a36Sopenharmony_ci memory32->minimum = 0; 84562306a36Sopenharmony_ci memory32->alignment = 0; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci pnp_dbg(&dev->dev, " encode mem32 %#x-%#x write_protect %#x\n", 84962306a36Sopenharmony_ci memory32->minimum, 85062306a36Sopenharmony_ci memory32->minimum + memory32->address_length - 1, 85162306a36Sopenharmony_ci memory32->write_protect); 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_cistatic void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev, 85562306a36Sopenharmony_ci struct acpi_resource *resource, 85662306a36Sopenharmony_ci struct resource *p) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci if (pnp_resource_enabled(p)) { 86162306a36Sopenharmony_ci fixed_memory32->write_protect = 86262306a36Sopenharmony_ci p->flags & IORESOURCE_MEM_WRITEABLE ? 86362306a36Sopenharmony_ci ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY; 86462306a36Sopenharmony_ci fixed_memory32->address = p->start; 86562306a36Sopenharmony_ci fixed_memory32->address_length = resource_size(p); 86662306a36Sopenharmony_ci } else { 86762306a36Sopenharmony_ci fixed_memory32->address = 0; 86862306a36Sopenharmony_ci fixed_memory32->address_length = 0; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci pnp_dbg(&dev->dev, " encode fixed_mem32 %#x-%#x write_protect %#x\n", 87262306a36Sopenharmony_ci fixed_memory32->address, 87362306a36Sopenharmony_ci fixed_memory32->address + fixed_memory32->address_length - 1, 87462306a36Sopenharmony_ci fixed_memory32->write_protect); 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ciint pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci int i = 0; 88062306a36Sopenharmony_ci /* pnpacpi_build_resource_template allocates extra mem */ 88162306a36Sopenharmony_ci int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1; 88262306a36Sopenharmony_ci struct acpi_resource *resource = buffer->pointer; 88362306a36Sopenharmony_ci unsigned int port = 0, irq = 0, dma = 0, mem = 0; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci pnp_dbg(&dev->dev, "encode %d resources\n", res_cnt); 88662306a36Sopenharmony_ci while (i < res_cnt) { 88762306a36Sopenharmony_ci switch (resource->type) { 88862306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_IRQ: 88962306a36Sopenharmony_ci pnpacpi_encode_irq(dev, resource, 89062306a36Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_IRQ, irq)); 89162306a36Sopenharmony_ci irq++; 89262306a36Sopenharmony_ci break; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_DMA: 89562306a36Sopenharmony_ci pnpacpi_encode_dma(dev, resource, 89662306a36Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_DMA, dma)); 89762306a36Sopenharmony_ci dma++; 89862306a36Sopenharmony_ci break; 89962306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_IO: 90062306a36Sopenharmony_ci pnpacpi_encode_io(dev, resource, 90162306a36Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_IO, port)); 90262306a36Sopenharmony_ci port++; 90362306a36Sopenharmony_ci break; 90462306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_IO: 90562306a36Sopenharmony_ci pnpacpi_encode_fixed_io(dev, resource, 90662306a36Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_IO, port)); 90762306a36Sopenharmony_ci port++; 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY24: 91062306a36Sopenharmony_ci pnpacpi_encode_mem24(dev, resource, 91162306a36Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_MEM, mem)); 91262306a36Sopenharmony_ci mem++; 91362306a36Sopenharmony_ci break; 91462306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_MEMORY32: 91562306a36Sopenharmony_ci pnpacpi_encode_mem32(dev, resource, 91662306a36Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_MEM, mem)); 91762306a36Sopenharmony_ci mem++; 91862306a36Sopenharmony_ci break; 91962306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: 92062306a36Sopenharmony_ci pnpacpi_encode_fixed_mem32(dev, resource, 92162306a36Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_MEM, mem)); 92262306a36Sopenharmony_ci mem++; 92362306a36Sopenharmony_ci break; 92462306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 92562306a36Sopenharmony_ci pnpacpi_encode_ext_irq(dev, resource, 92662306a36Sopenharmony_ci pnp_get_resource(dev, IORESOURCE_IRQ, irq)); 92762306a36Sopenharmony_ci irq++; 92862306a36Sopenharmony_ci break; 92962306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_START_DEPENDENT: 93062306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_DEPENDENT: 93162306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_VENDOR: 93262306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_END_TAG: 93362306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS16: 93462306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS32: 93562306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_ADDRESS64: 93662306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: 93762306a36Sopenharmony_ci case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: 93862306a36Sopenharmony_ci default: /* other type */ 93962306a36Sopenharmony_ci dev_warn(&dev->dev, 94062306a36Sopenharmony_ci "can't encode unknown resource type %d\n", 94162306a36Sopenharmony_ci resource->type); 94262306a36Sopenharmony_ci return -EINVAL; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci resource++; 94562306a36Sopenharmony_ci i++; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci return 0; 94862306a36Sopenharmony_ci} 949