Commit 1f825f74 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branches 'acpi-soc', 'acpi-processor', 'acpi-pmic', 'acpi-cppc' and 'acpi-tad'

* acpi-soc:
  ACPI / LPSS: Resume BYT/CHT I2C controllers from resume_noirq
  ACPI / LPSS: Add a device link from the GPU to the BYT I2C5 controller
  ACPI / LPSS: Add a device link from the GPU to the CHT I2C7 controller
  ACPI / LPSS: Make acpi_lpss_find_device() also find PCI devices
  ACPI / LPSS: Make hid_uid_match helper accept a NULL uid argument
  ACPI / LPSS: Make hid_uid_match helper take an acpi_device as first argument
  ACPI / LPSS: Exclude I2C busses shared with PUNIT from pmc_atom_d3_mask
  ACPI / LPSS: Add alternative ACPI HIDs for Cherry Trail DMA controllers

* acpi-processor:
  ACPI / processor: Fix the return value of acpi_processor_ids_walk()

* acpi-pmic:
  ACPI / PMIC: Convert drivers to use SPDX identifier
  ACPI / PMIC: Sort headers alphabetically

* acpi-cppc:
  mailbox: PCC: handle parse error

* acpi-tad:
  ACPI: TAD: Add low-level support for real time capability
Loading
Loading
Loading
Loading
+103 −15
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/platform_data/clk-lpss.h>
#include <linux/platform_data/x86/pmc_atom.h>
@@ -83,6 +84,7 @@ struct lpss_device_desc {
	size_t prv_size_override;
	struct property_entry *properties;
	void (*setup)(struct lpss_private_data *pdata);
	bool resume_from_noirq;
};

static const struct lpss_device_desc lpss_dma_desc = {
@@ -99,6 +101,9 @@ struct lpss_private_data {
	u32 prv_reg_ctx[LPSS_PRV_REG_COUNT];
};

/* Devices which need to be in D3 before lpss_iosf_enter_d3_state() proceeds */
static u32 pmc_atom_d3_mask = 0xfe000ffe;

/* LPSS run time quirks */
static unsigned int lpss_quirks;

@@ -175,6 +180,21 @@ static void byt_pwm_setup(struct lpss_private_data *pdata)

static void byt_i2c_setup(struct lpss_private_data *pdata)
{
	const char *uid_str = acpi_device_uid(pdata->adev);
	acpi_handle handle = pdata->adev->handle;
	unsigned long long shared_host = 0;
	acpi_status status;
	long uid = 0;

	/* Expected to always be true, but better safe then sorry */
	if (uid_str)
		uid = simple_strtol(uid_str, NULL, 10);

	/* Detect I2C bus shared with PUNIT and ignore its d3 status */
	status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
	if (ACPI_SUCCESS(status) && shared_host && uid)
		pmc_atom_d3_mask &= ~(BIT_LPSS2_F1_I2C1 << (uid - 1));

	lpss_deassert_reset(pdata);

	if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset))
@@ -274,12 +294,14 @@ static const struct lpss_device_desc byt_i2c_dev_desc = {
	.flags = LPSS_CLK | LPSS_SAVE_CTX,
	.prv_offset = 0x800,
	.setup = byt_i2c_setup,
	.resume_from_noirq = true,
};

static const struct lpss_device_desc bsw_i2c_dev_desc = {
	.flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_NO_D3_DELAY,
	.prv_offset = 0x800,
	.setup = byt_i2c_setup,
	.resume_from_noirq = true,
};

static const struct lpss_device_desc bsw_spi_dev_desc = {
@@ -327,9 +349,11 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
	{ "INT33FC", },

	/* Braswell LPSS devices */
	{ "80862286", LPSS_ADDR(lpss_dma_desc) },
	{ "80862288", LPSS_ADDR(bsw_pwm_dev_desc) },
	{ "8086228A", LPSS_ADDR(bsw_uart_dev_desc) },
	{ "8086228E", LPSS_ADDR(bsw_spi_dev_desc) },
	{ "808622C0", LPSS_ADDR(lpss_dma_desc) },
	{ "808622C1", LPSS_ADDR(bsw_i2c_dev_desc) },

	/* Broadwell LPSS devices */
@@ -451,26 +475,35 @@ struct lpss_device_links {
 */
static const struct lpss_device_links lpss_device_links[] = {
	{"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME},
	{"808622C1", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
	{"80860F41", "5", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
};

static bool hid_uid_match(const char *hid1, const char *uid1,
static bool hid_uid_match(struct acpi_device *adev,
			  const char *hid2, const char *uid2)
{
	return !strcmp(hid1, hid2) && uid1 && uid2 && !strcmp(uid1, uid2);
	const char *hid1 = acpi_device_hid(adev);
	const char *uid1 = acpi_device_uid(adev);

	if (strcmp(hid1, hid2))
		return false;

	if (!uid2)
		return true;

	return uid1 && !strcmp(uid1, uid2);
}

static bool acpi_lpss_is_supplier(struct acpi_device *adev,
				  const struct lpss_device_links *link)
{
	return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
			     link->supplier_hid, link->supplier_uid);
	return hid_uid_match(adev, link->supplier_hid, link->supplier_uid);
}

static bool acpi_lpss_is_consumer(struct acpi_device *adev,
				  const struct lpss_device_links *link)
{
	return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
			     link->consumer_hid, link->consumer_uid);
	return hid_uid_match(adev, link->consumer_hid, link->consumer_uid);
}

struct hid_uid {
@@ -486,18 +519,23 @@ static int match_hid_uid(struct device *dev, void *data)
	if (!adev)
		return 0;

	return hid_uid_match(acpi_device_hid(adev), acpi_device_uid(adev),
			     id->hid, id->uid);
	return hid_uid_match(adev, id->hid, id->uid);
}

static struct device *acpi_lpss_find_device(const char *hid, const char *uid)
{
	struct device *dev;

	struct hid_uid data = {
		.hid = hid,
		.uid = uid,
	};

	return bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid);
	dev = bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid);
	if (dev)
		return dev;

	return bus_find_device(&pci_bus_type, NULL, &data, match_hid_uid);
}

static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle)
@@ -892,7 +930,7 @@ static void lpss_iosf_enter_d3_state(void)
	 * Here we read the values related to LPSS power island, i.e. LPSS
	 * devices, excluding both LPSS DMA controllers, along with SCC domain.
	 */
	u32 func_dis, d3_sts_0, pmc_status, pmc_mask = 0xfe000ffe;
	u32 func_dis, d3_sts_0, pmc_status;
	int ret;

	ret = pmc_atom_read(PMC_FUNC_DIS, &func_dis);
@@ -910,7 +948,7 @@ static void lpss_iosf_enter_d3_state(void)
	 * Shutdown both LPSS DMA controllers if and only if all other devices
	 * are already in D3hot.
	 */
	pmc_status = (~(d3_sts_0 | func_dis)) & pmc_mask;
	pmc_status = (~(d3_sts_0 | func_dis)) & pmc_atom_d3_mask;
	if (pmc_status)
		goto exit;

@@ -1004,7 +1042,7 @@ static int acpi_lpss_resume(struct device *dev)
}

#ifdef CONFIG_PM_SLEEP
static int acpi_lpss_suspend_late(struct device *dev)
static int acpi_lpss_do_suspend_late(struct device *dev)
{
	int ret;

@@ -1015,12 +1053,62 @@ static int acpi_lpss_suspend_late(struct device *dev)
	return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
}

static int acpi_lpss_resume_early(struct device *dev)
static int acpi_lpss_suspend_late(struct device *dev)
{
	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));

	if (pdata->dev_desc->resume_from_noirq)
		return 0;

	return acpi_lpss_do_suspend_late(dev);
}

static int acpi_lpss_suspend_noirq(struct device *dev)
{
	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
	int ret;

	if (pdata->dev_desc->resume_from_noirq) {
		ret = acpi_lpss_do_suspend_late(dev);
		if (ret)
			return ret;
	}

	return acpi_subsys_suspend_noirq(dev);
}

static int acpi_lpss_do_resume_early(struct device *dev)
{
	int ret = acpi_lpss_resume(dev);

	return ret ? ret : pm_generic_resume_early(dev);
}

static int acpi_lpss_resume_early(struct device *dev)
{
	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));

	if (pdata->dev_desc->resume_from_noirq)
		return 0;

	return acpi_lpss_do_resume_early(dev);
}

static int acpi_lpss_resume_noirq(struct device *dev)
{
	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
	int ret;

	ret = acpi_subsys_resume_noirq(dev);
	if (ret)
		return ret;

	if (!dev_pm_may_skip_resume(dev) && pdata->dev_desc->resume_from_noirq)
		ret = acpi_lpss_do_resume_early(dev);

	return ret;
}

#endif /* CONFIG_PM_SLEEP */

static int acpi_lpss_runtime_suspend(struct device *dev)
@@ -1050,8 +1138,8 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
		.complete = acpi_subsys_complete,
		.suspend = acpi_subsys_suspend,
		.suspend_late = acpi_lpss_suspend_late,
		.suspend_noirq = acpi_subsys_suspend_noirq,
		.resume_noirq = acpi_subsys_resume_noirq,
		.suspend_noirq = acpi_lpss_suspend_noirq,
		.resume_noirq = acpi_lpss_resume_noirq,
		.resume_early = acpi_lpss_resume_early,
		.freeze = acpi_subsys_freeze,
		.freeze_late = acpi_subsys_freeze_late,
+4 −3
Original line number Diff line number Diff line
@@ -643,7 +643,7 @@ static acpi_status __init acpi_processor_ids_walk(acpi_handle handle,

	status = acpi_get_type(handle, &acpi_type);
	if (ACPI_FAILURE(status))
		return false;
		return status;

	switch (acpi_type) {
	case ACPI_TYPE_PROCESSOR:
@@ -663,11 +663,12 @@ static acpi_status __init acpi_processor_ids_walk(acpi_handle handle,
	}

	processor_validated_ids_update(uid);
	return true;
	return AE_OK;

err:
	/* Exit on error, but don't abort the namespace walk */
	acpi_handle_info(handle, "Invalid processor object\n");
	return false;
	return AE_OK;

}

+201 −0
Original line number Diff line number Diff line
@@ -52,6 +52,201 @@ struct acpi_tad_driver_data {
	u32 capabilities;
};

struct acpi_tad_rt {
	u16 year;  /* 1900 - 9999 */
	u8 month;  /* 1 - 12 */
	u8 day;    /* 1 - 31 */
	u8 hour;   /* 0 - 23 */
	u8 minute; /* 0 - 59 */
	u8 second; /* 0 - 59 */
	u8 valid;  /* 0 (failed) or 1 (success) for reads, 0 for writes */
	u16 msec;  /* 1 - 1000 */
	s16 tz;    /* -1440 to 1440 or 2047 (unspecified) */
	u8 daylight;
	u8 padding[3]; /* must be 0 */
} __packed;

static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt)
{
	acpi_handle handle = ACPI_HANDLE(dev);
	union acpi_object args[] = {
		{ .type = ACPI_TYPE_BUFFER, },
	};
	struct acpi_object_list arg_list = {
		.pointer = args,
		.count = ARRAY_SIZE(args),
	};
	unsigned long long retval;
	acpi_status status;

	if (rt->year < 1900 || rt->year > 9999 ||
	    rt->month < 1 || rt->month > 12 ||
	    rt->hour > 23 || rt->minute > 59 || rt->second > 59 ||
	    rt->tz < -1440 || (rt->tz > 1440 && rt->tz != 2047) ||
	    rt->daylight > 3)
		return -ERANGE;

	args[0].buffer.pointer = (u8 *)rt;
	args[0].buffer.length = sizeof(*rt);

	pm_runtime_get_sync(dev);

	status = acpi_evaluate_integer(handle, "_SRT", &arg_list, &retval);

	pm_runtime_put_sync(dev);

	if (ACPI_FAILURE(status) || retval)
		return -EIO;

	return 0;
}

static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
{
	acpi_handle handle = ACPI_HANDLE(dev);
	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER };
	union acpi_object *out_obj;
	struct acpi_tad_rt *data;
	acpi_status status;
	int ret = -EIO;

	pm_runtime_get_sync(dev);

	status = acpi_evaluate_object(handle, "_GRT", NULL, &output);

	pm_runtime_put_sync(dev);

	if (ACPI_FAILURE(status))
		goto out_free;

	out_obj = output.pointer;
	if (out_obj->type != ACPI_TYPE_BUFFER)
		goto out_free;

	if (out_obj->buffer.length != sizeof(*rt))
		goto out_free;

	data = (struct acpi_tad_rt *)(out_obj->buffer.pointer);
	if (!data->valid)
		goto out_free;

	memcpy(rt, data, sizeof(*rt));
	ret = 0;

out_free:
	ACPI_FREE(output.pointer);
	return ret;
}

static char *acpi_tad_rt_next_field(char *s, int *val)
{
	char *p;

	p = strchr(s, ':');
	if (!p)
		return NULL;

	*p = '\0';
	if (kstrtoint(s, 10, val))
		return NULL;

	return p + 1;
}

static ssize_t time_store(struct device *dev, struct device_attribute *attr,
			  const char *buf, size_t count)
{
	struct acpi_tad_rt rt;
	char *str, *s;
	int val, ret = -ENODATA;

	str = kmemdup_nul(buf, count, GFP_KERNEL);
	if (!str)
		return -ENOMEM;

	s = acpi_tad_rt_next_field(str, &val);
	if (!s)
		goto out_free;

	rt.year = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.month = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.day = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.hour = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.minute = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.second = val;

	s = acpi_tad_rt_next_field(s, &val);
	if (!s)
		goto out_free;

	rt.tz = val;

	if (kstrtoint(s, 10, &val))
		goto out_free;

	rt.daylight = val;

	rt.valid = 0;
	rt.msec = 0;
	memset(rt.padding, 0, 3);

	ret = acpi_tad_set_real_time(dev, &rt);

out_free:
	kfree(str);
	return ret ? ret : count;
}

static ssize_t time_show(struct device *dev, struct device_attribute *attr,
			 char *buf)
{
	struct acpi_tad_rt rt;
	int ret;

	ret = acpi_tad_get_real_time(dev, &rt);
	if (ret)
		return ret;

	return sprintf(buf, "%u:%u:%u:%u:%u:%u:%d:%u\n",
		       rt.year, rt.month, rt.day, rt.hour, rt.minute, rt.second,
		       rt.tz, rt.daylight);
}

static DEVICE_ATTR(time, S_IRUSR | S_IWUSR, time_show, time_store);

static struct attribute *acpi_tad_time_attrs[] = {
	&dev_attr_time.attr,
	NULL,
};
static const struct attribute_group acpi_tad_time_attr_group = {
	.attrs	= acpi_tad_time_attrs,
};

static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id,
			     u32 value)
{
@@ -448,6 +643,12 @@ static int acpi_tad_probe(struct platform_device *pdev)
			goto fail;
	}

	if (caps & ACPI_TAD_RT) {
		ret = sysfs_create_group(&dev->kobj, &acpi_tad_time_attr_group);
		if (ret)
			goto fail;
	}

	return 0;

fail:
+2 −10
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * intel_pmic_bxtwc.c - Intel BXT WhiskeyCove PMIC operation region driver
 * Intel BXT WhiskeyCove PMIC operation region driver
 *
 * Copyright (C) 2015 Intel Corporation. All rights reserved.
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/init.h>
+1 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Dollar Cove TI PMIC operation region driver
 * Copyright (C) 2014 Intel Corporation. All rights reserved.
Loading