Merge branches 'acpi-x86', 'acpi-soc', 'acpi-pmic' and 'acpi-apple'

* acpi-x86:
  ACPI / boot: Add number of legacy IRQs to debug output
  ACPI / boot: Correct address space of __acpi_map_table()
  ACPI / boot: Don't define unused variables

* acpi-soc:
  ACPI / LPSS: Don't abort ACPI scan on missing mem resource

* acpi-pmic:
  ACPI / PMIC: xpower: Do pinswitch magic when reading GPADC

* acpi-apple:
  spi: Use Apple device properties in absence of ACPI resources
  ACPI / scan: Recognize Apple SPI and I2C slaves
  ACPI / property: Support Apple _DSM properties
  ACPI / property: Don't evaluate objects for devices w/o handle
  treewide: Consolidate Apple DMI checks
This commit is contained in:
Rafael J. Wysocki 2017-09-03 23:54:03 +02:00
24 changed files with 278 additions and 87 deletions

View file

@ -50,6 +50,7 @@ acpi-$(CONFIG_ACPI_REDUCED_HARDWARE_ONLY) += evged.o
acpi-y += sysfs.o
acpi-y += property.o
acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
acpi-$(CONFIG_X86) += x86/apple.o
acpi-$(CONFIG_X86) += x86/utils.o
acpi-$(CONFIG_DEBUG_FS) += debugfs.o
acpi-$(CONFIG_ACPI_NUMA) += numa.o

View file

@ -465,7 +465,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
acpi_dev_free_resource_list(&resource_list);
if (!pdata->mmio_base) {
ret = -ENOMEM;
/* Skip the device, but continue the namespace scan. */
ret = 0;
goto err_out;
}

View file

@ -232,6 +232,12 @@ static inline void suspend_nvs_restore(void) {}
void acpi_init_properties(struct acpi_device *adev);
void acpi_free_properties(struct acpi_device *adev);
#ifdef CONFIG_X86
void acpi_extract_apple_properties(struct acpi_device *adev);
#else
static inline void acpi_extract_apple_properties(struct acpi_device *adev) {}
#endif
/*--------------------------------------------------------------------------
Watchdog
-------------------------------------------------------------------------- */

View file

@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/platform_data/x86/apple.h>
#include "internal.h"
@ -257,12 +258,11 @@ bool acpi_osi_is_win8(void)
}
EXPORT_SYMBOL(acpi_osi_is_win8);
static void __init acpi_osi_dmi_darwin(bool enable,
const struct dmi_system_id *d)
static void __init acpi_osi_dmi_darwin(void)
{
pr_notice("DMI detected to setup _OSI(\"Darwin\"): %s\n", d->ident);
pr_notice("DMI detected to setup _OSI(\"Darwin\"): Apple hardware\n");
osi_config.darwin_dmi = 1;
__acpi_osi_setup_darwin(enable);
__acpi_osi_setup_darwin(true);
}
static void __init acpi_osi_dmi_linux(bool enable,
@ -273,13 +273,6 @@ static void __init acpi_osi_dmi_linux(bool enable,
__acpi_osi_setup_linux(enable);
}
static int __init dmi_enable_osi_darwin(const struct dmi_system_id *d)
{
acpi_osi_dmi_darwin(true, d);
return 0;
}
static int __init dmi_enable_osi_linux(const struct dmi_system_id *d)
{
acpi_osi_dmi_linux(true, d);
@ -481,30 +474,16 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"),
},
},
/*
* Enable _OSI("Darwin") for all apple platforms.
*/
{
.callback = dmi_enable_osi_darwin,
.ident = "Apple hardware",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
},
},
{
.callback = dmi_enable_osi_darwin,
.ident = "Apple hardware",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
},
},
{}
};
static __init void acpi_osi_dmi_blacklisted(void)
{
dmi_check_system(acpi_osi_dmi_table);
/* Enable _OSI("Darwin") for Apple platforms. */
if (x86_apple_machine)
acpi_osi_dmi_darwin();
}
int __init early_acpi_osi_init(void)

View file

@ -33,6 +33,7 @@
#include <linux/acpi.h>
#include <linux/slab.h>
#include <linux/dmi.h>
#include <linux/platform_data/x86/apple.h>
#include <acpi/apei.h> /* for acpi_hest_init() */
#include "internal.h"
@ -431,8 +432,7 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm)
* been called successfully. We know the feature set supported by the
* platform, so avoid calling _OSC at all
*/
if (dmi_match(DMI_SYS_VENDOR, "Apple Inc.")) {
if (x86_apple_machine) {
root->osc_control_set = ~OSC_PCI_EXPRESS_PME_CONTROL;
decode_osc_control(root, "OS assumes control of",
root->osc_control_set);

View file

@ -27,6 +27,9 @@
#define GPI1_LDO_ON (3 << 0)
#define GPI1_LDO_OFF (4 << 0)
#define AXP288_ADC_TS_PIN_GPADC 0xf2
#define AXP288_ADC_TS_PIN_ON 0xf3
static struct pmic_table power_table[] = {
{
.address = 0x00,
@ -209,11 +212,23 @@ static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg)
{
u8 buf[2];
int ret;
if (regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2))
return -EIO;
ret = regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL,
AXP288_ADC_TS_PIN_GPADC);
if (ret)
return ret;
return (buf[0] << 4) + ((buf[1] >> 4) & 0x0F);
/* After switching to the GPADC pin give things some time to settle */
usleep_range(6000, 10000);
ret = regmap_bulk_read(regmap, AXP288_GP_ADC_H, buf, 2);
if (ret == 0)
ret = (buf[0] << 4) + ((buf[1] >> 4) & 0x0f);
regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON);
return ret;
}
static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = {

View file

@ -339,6 +339,9 @@ void acpi_init_properties(struct acpi_device *adev)
INIT_LIST_HEAD(&adev->data.subnodes);
if (!adev->handle)
return;
/*
* Check if ACPI_DT_NAMESPACE_HID is present and inthat case we fill in
* Device Tree compatible properties for this device.
@ -373,6 +376,9 @@ void acpi_init_properties(struct acpi_device *adev)
if (acpi_of && !adev->flags.of_compatible_ok)
acpi_handle_info(adev->handle,
ACPI_DT_NAMESPACE_HID " requires 'compatible' property\n");
if (!adev->data.pointer)
acpi_extract_apple_properties(adev);
}
static void acpi_destroy_nondev_subnodes(struct list_head *list)

View file

@ -31,7 +31,7 @@
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/power_supply.h>
#include <linux/dmi.h>
#include <linux/platform_data/x86/apple.h>
#include "sbshc.h"
#include "battery.h"
@ -58,8 +58,6 @@ static unsigned int cache_time = 1000;
module_param(cache_time, uint, 0644);
MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
static bool sbs_manager_broken;
#define MAX_SBS_BAT 4
#define ACPI_SBS_BLOCK_MAX 32
@ -632,31 +630,12 @@ static void acpi_sbs_callback(void *context)
}
}
static int disable_sbs_manager(const struct dmi_system_id *d)
{
sbs_manager_broken = true;
return 0;
}
static struct dmi_system_id acpi_sbs_dmi_table[] = {
{
.callback = disable_sbs_manager,
.ident = "Apple",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc.")
},
},
{ },
};
static int acpi_sbs_add(struct acpi_device *device)
{
struct acpi_sbs *sbs;
int result = 0;
int id;
dmi_check_system(acpi_sbs_dmi_table);
sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
if (!sbs) {
result = -ENOMEM;
@ -677,7 +656,7 @@ static int acpi_sbs_add(struct acpi_device *device)
result = 0;
if (!sbs_manager_broken) {
if (!x86_apple_machine) {
result = acpi_manager_get_info(sbs);
if (!result) {
sbs->manager_present = 1;

View file

@ -13,6 +13,7 @@
#include <linux/dmi.h>
#include <linux/nls.h>
#include <linux/dma-mapping.h>
#include <linux/platform_data/x86/apple.h>
#include <asm/pgtable.h>
@ -1527,6 +1528,12 @@ static bool acpi_is_spi_i2c_slave(struct acpi_device *device)
struct list_head resource_list;
bool is_spi_i2c_slave = false;
/* Macs use device properties in lieu of _CRS resources */
if (x86_apple_machine &&
(fwnode_property_present(&device->fwnode, "spiSclkPeriod") ||
fwnode_property_present(&device->fwnode, "i2cAddress")))
return true;
INIT_LIST_HEAD(&resource_list);
acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave,
&is_spi_i2c_slave);

141
drivers/acpi/x86/apple.c Normal file
View file

@ -0,0 +1,141 @@
/*
* apple.c - Apple ACPI quirks
* Copyright (C) 2017 Lukas Wunner <lukas@wunner.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2) as
* published by the Free Software Foundation.
*/
#include <linux/acpi.h>
#include <linux/bitmap.h>
#include <linux/platform_data/x86/apple.h>
#include <linux/uuid.h>
/* Apple _DSM device properties GUID */
static const guid_t apple_prp_guid =
GUID_INIT(0xa0b5b7c6, 0x1318, 0x441c,
0xb0, 0xc9, 0xfe, 0x69, 0x5e, 0xaf, 0x94, 0x9b);
/**
* acpi_extract_apple_properties - retrieve and convert Apple _DSM properties
* @adev: ACPI device for which to retrieve the properties
*
* Invoke Apple's custom _DSM once to check the protocol version and once more
* to retrieve the properties. They are marshalled up in a single package as
* alternating key/value elements, unlike _DSD which stores them as a package
* of 2-element packages. Convert to _DSD format and make them available under
* the primary fwnode.
*/
void acpi_extract_apple_properties(struct acpi_device *adev)
{
unsigned int i, j = 0, newsize = 0, numprops, numvalid;
union acpi_object *props, *newprops;
unsigned long *valid = NULL;
void *free_space;
if (!x86_apple_machine)
return;
props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 0,
NULL, ACPI_TYPE_BUFFER);
if (!props)
return;
if (!props->buffer.length)
goto out_free;
if (props->buffer.pointer[0] != 3) {
acpi_handle_info(adev->handle, FW_INFO
"unsupported properties version %*ph\n",
props->buffer.length, props->buffer.pointer);
goto out_free;
}
ACPI_FREE(props);
props = acpi_evaluate_dsm_typed(adev->handle, &apple_prp_guid, 1, 1,
NULL, ACPI_TYPE_PACKAGE);
if (!props)
return;
numprops = props->package.count / 2;
if (!numprops)
goto out_free;
valid = kcalloc(BITS_TO_LONGS(numprops), sizeof(long), GFP_KERNEL);
if (!valid)
goto out_free;
/* newsize = key length + value length of each tuple */
for (i = 0; i < numprops; i++) {
union acpi_object *key = &props->package.elements[i * 2];
union acpi_object *val = &props->package.elements[i * 2 + 1];
if ( key->type != ACPI_TYPE_STRING ||
(val->type != ACPI_TYPE_INTEGER &&
val->type != ACPI_TYPE_BUFFER))
continue; /* skip invalid properties */
__set_bit(i, valid);
newsize += key->string.length + 1;
if ( val->type == ACPI_TYPE_BUFFER)
newsize += val->buffer.length;
}
numvalid = bitmap_weight(valid, numprops);
if (numprops > numvalid)
acpi_handle_info(adev->handle, FW_INFO
"skipped %u properties: wrong type\n",
numprops - numvalid);
if (numvalid == 0)
goto out_free;
/* newsize += top-level package + 3 objects for each key/value tuple */
newsize += (1 + 3 * numvalid) * sizeof(union acpi_object);
newprops = ACPI_ALLOCATE_ZEROED(newsize);
if (!newprops)
goto out_free;
/* layout: top-level package | packages | key/value tuples | strings */
newprops->type = ACPI_TYPE_PACKAGE;
newprops->package.count = numvalid;
newprops->package.elements = &newprops[1];
free_space = &newprops[1 + 3 * numvalid];
for_each_set_bit(i, valid, numprops) {
union acpi_object *key = &props->package.elements[i * 2];
union acpi_object *val = &props->package.elements[i * 2 + 1];
unsigned int k = 1 + numvalid + j * 2; /* index into newprops */
unsigned int v = k + 1;
newprops[1 + j].type = ACPI_TYPE_PACKAGE;
newprops[1 + j].package.count = 2;
newprops[1 + j].package.elements = &newprops[k];
newprops[k].type = ACPI_TYPE_STRING;
newprops[k].string.length = key->string.length;
newprops[k].string.pointer = free_space;
memcpy(free_space, key->string.pointer, key->string.length);
free_space += key->string.length + 1;
newprops[v].type = val->type;
if (val->type == ACPI_TYPE_INTEGER) {
newprops[v].integer.value = val->integer.value;
} else {
newprops[v].buffer.length = val->buffer.length;
newprops[v].buffer.pointer = free_space;
memcpy(free_space, val->buffer.pointer,
val->buffer.length);
free_space += val->buffer.length;
}
j++; /* count valid properties */
}
WARN_ON(free_space != (void *)newprops + newsize);
adev->data.properties = newprops;
adev->data.pointer = newprops;
out_free:
ACPI_FREE(props);
kfree(valid);
}