Merge branches 'pm-pci', 'acpi-pm', 'pm-sleep' and 'pm-avs'

* pm-pci:
  PCI / PM: Clean up outdated comments in pci_target_state()
  PCI / PM: Do not clear state_saved for devices that remain suspended

* acpi-pm:
  ACPI: EC: Dispatch the EC GPE directly on s2idle wake
  ACPICA: Introduce acpi_dispatch_gpe()

* pm-sleep:
  PM / hibernate: Fix oops at snapshot_write()
  PM / wakeup: Make s2idle_lock a RAW_SPINLOCK
  PM / s2idle: Make s2idle_wait_head swait based
  PM / wakeup: Make events_lock a RAW_SPINLOCK
  PM / suspend: Prevent might sleep splats

* pm-avs:
  PM / AVS: rockchip-io: add io selectors and supplies for PX30
This commit is contained in:
Rafael J. Wysocki 2018-06-04 10:41:53 +02:00
16 changed files with 171 additions and 26 deletions

View file

@ -31,6 +31,8 @@ SoC is on the same page.
Required properties:
- compatible: should be one of:
- "rockchip,px30-io-voltage-domain" for px30
- "rockchip,px30-pmu-io-voltage-domain" for px30 pmu-domains
- "rockchip,rk3188-io-voltage-domain" for rk3188
- "rockchip,rk3228-io-voltage-domain" for rk3228
- "rockchip,rk3288-io-voltage-domain" for rk3288
@ -51,6 +53,19 @@ a phandle the relevant regulator. All specified supplies must be able
to report their voltage. The IO Voltage Domain for any non-specified
supplies will be not be touched.
Possible supplies for PX30:
- vccio6-supply: The supply connected to VCCIO6.
- vccio1-supply: The supply connected to VCCIO1.
- vccio2-supply: The supply connected to VCCIO2.
- vccio3-supply: The supply connected to VCCIO3.
- vccio4-supply: The supply connected to VCCIO4.
- vccio5-supply: The supply connected to VCCIO5.
- vccio-oscgpi-supply: The supply connected to VCCIO_OSCGPI.
Possible supplies for PX30 pmu-domains:
- pmuio1-supply: The supply connected to PMUIO1.
- pmuio2-supply: The supply connected to PMUIO2.
Possible supplies for rk3188:
- ap0-supply: The supply connected to AP0_VCC.
- ap1-supply: The supply connected to AP1_VCC.

View file

@ -634,6 +634,12 @@ acpi_ev_detect_gpe(struct acpi_namespace_node *gpe_device,
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
if (!gpe_event_info) {
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
if (!gpe_event_info)
goto error_exit;
}
/* Get the info block for the entire GPE register */
gpe_register_info = gpe_event_info->register_info;

View file

@ -637,6 +637,28 @@ unlock_and_exit:
ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
/*******************************************************************************
*
* FUNCTION: acpi_gispatch_gpe
*
* PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
* gpe_number - GPE level within the GPE block
*
* RETURN: None
*
* DESCRIPTION: Detect and dispatch a General Purpose Event to either a function
* (e.g. EC) or method (e.g. _Lxx/_Exx) handler.
*
******************************************************************************/
void acpi_dispatch_gpe(acpi_handle gpe_device, u32 gpe_number)
{
ACPI_FUNCTION_TRACE(acpi_dispatch_gpe);
acpi_ev_detect_gpe(gpe_device, NULL, gpe_number);
}
ACPI_EXPORT_SYMBOL(acpi_dispatch_gpe)
/*******************************************************************************
*
* FUNCTION: acpi_finish_gpe

View file

@ -1034,6 +1034,12 @@ void acpi_ec_unblock_transactions(void)
acpi_ec_start(first_ec, true);
}
void acpi_ec_dispatch_gpe(void)
{
if (first_ec)
acpi_dispatch_gpe(NULL, first_ec->gpe);
}
/* --------------------------------------------------------------------------
Event Management
-------------------------------------------------------------------------- */

View file

@ -188,6 +188,7 @@ int acpi_ec_ecdt_probe(void);
int acpi_ec_dsdt_probe(void);
void acpi_ec_block_transactions(void);
void acpi_ec_unblock_transactions(void);
void acpi_ec_dispatch_gpe(void);
int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
acpi_handle handle, acpi_ec_query_func func,
void *data);

View file

@ -989,6 +989,13 @@ static void acpi_s2idle_wake(void)
!irqd_is_wakeup_armed(irq_get_irq_data(acpi_sci_irq))) {
pm_system_cancel_wakeup();
s2idle_wakeup = true;
/*
* On some platforms with the LPS0 _DSM device noirq resume
* takes too much time for EC wakeup events to survive, so look
* for them now.
*/
if (lps0_device_handle)
acpi_ec_dispatch_gpe();
}
}

View file

@ -57,7 +57,7 @@ static void split_counters(unsigned int *cnt, unsigned int *inpr)
/* A preserved old value of the events counter. */
static unsigned int saved_count;
static DEFINE_SPINLOCK(events_lock);
static DEFINE_RAW_SPINLOCK(events_lock);
static void pm_wakeup_timer_fn(struct timer_list *t);
@ -184,9 +184,9 @@ void wakeup_source_add(struct wakeup_source *ws)
timer_setup(&ws->timer, pm_wakeup_timer_fn, 0);
ws->active = false;
spin_lock_irqsave(&events_lock, flags);
raw_spin_lock_irqsave(&events_lock, flags);
list_add_rcu(&ws->entry, &wakeup_sources);
spin_unlock_irqrestore(&events_lock, flags);
raw_spin_unlock_irqrestore(&events_lock, flags);
}
EXPORT_SYMBOL_GPL(wakeup_source_add);
@ -201,9 +201,9 @@ void wakeup_source_remove(struct wakeup_source *ws)
if (WARN_ON(!ws))
return;
spin_lock_irqsave(&events_lock, flags);
raw_spin_lock_irqsave(&events_lock, flags);
list_del_rcu(&ws->entry);
spin_unlock_irqrestore(&events_lock, flags);
raw_spin_unlock_irqrestore(&events_lock, flags);
synchronize_srcu(&wakeup_srcu);
}
EXPORT_SYMBOL_GPL(wakeup_source_remove);
@ -842,7 +842,7 @@ bool pm_wakeup_pending(void)
unsigned long flags;
bool ret = false;
spin_lock_irqsave(&events_lock, flags);
raw_spin_lock_irqsave(&events_lock, flags);
if (events_check_enabled) {
unsigned int cnt, inpr;
@ -850,7 +850,7 @@ bool pm_wakeup_pending(void)
ret = (cnt != saved_count || inpr > 0);
events_check_enabled = !ret;
}
spin_unlock_irqrestore(&events_lock, flags);
raw_spin_unlock_irqrestore(&events_lock, flags);
if (ret) {
pr_debug("PM: Wakeup pending, aborting suspend\n");
@ -939,13 +939,13 @@ bool pm_save_wakeup_count(unsigned int count)
unsigned long flags;
events_check_enabled = false;
spin_lock_irqsave(&events_lock, flags);
raw_spin_lock_irqsave(&events_lock, flags);
split_counters(&cnt, &inpr);
if (cnt == count && inpr == 0) {
saved_count = count;
events_check_enabled = true;
}
spin_unlock_irqrestore(&events_lock, flags);
raw_spin_unlock_irqrestore(&events_lock, flags);
return events_check_enabled;
}

View file

@ -753,10 +753,11 @@ static int pci_pm_suspend(struct device *dev)
* better to resume the device from runtime suspend here.
*/
if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) ||
!pci_dev_keep_suspended(pci_dev))
!pci_dev_keep_suspended(pci_dev)) {
pm_runtime_resume(dev);
pci_dev->state_saved = false;
}
pci_dev->state_saved = false;
if (pm->suspend) {
pci_power_t prev = pci_dev->current_state;
int error;

View file

@ -2025,8 +2025,7 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
if (platform_pci_power_manageable(dev)) {
/*
* Call the platform to choose the target state of the device
* and enable wake-up from this state if supported.
* Call the platform to find the target state for the device.
*/
pci_power_t state = platform_pci_choose_state(dev);
@ -2059,8 +2058,7 @@ static pci_power_t pci_target_state(struct pci_dev *dev, bool wakeup)
if (wakeup) {
/*
* Find the deepest state from which the device can generate
* wake-up events, make it the target state and enable device
* to generate PME#.
* PME#.
*/
if (dev->pme_support) {
while (target_state

View file

@ -39,6 +39,10 @@
#define MAX_VOLTAGE_1_8 1980000
#define MAX_VOLTAGE_3_3 3600000
#define PX30_IO_VSEL 0x180
#define PX30_IO_VSEL_VCCIO6_SRC BIT(0)
#define PX30_IO_VSEL_VCCIO6_SUPPLY_NUM 1
#define RK3288_SOC_CON2 0x24c
#define RK3288_SOC_CON2_FLASH0 BIT(7)
#define RK3288_SOC_FLASH_SUPPLY_NUM 2
@ -151,6 +155,25 @@ static int rockchip_iodomain_notify(struct notifier_block *nb,
return NOTIFY_OK;
}
static void px30_iodomain_init(struct rockchip_iodomain *iod)
{
int ret;
u32 val;
/* if no VCCIO0 supply we should leave things alone */
if (!iod->supplies[PX30_IO_VSEL_VCCIO6_SUPPLY_NUM].reg)
return;
/*
* set vccio0 iodomain to also use this framework
* instead of a special gpio.
*/
val = PX30_IO_VSEL_VCCIO6_SRC | (PX30_IO_VSEL_VCCIO6_SRC << 16);
ret = regmap_write(iod->grf, PX30_IO_VSEL, val);
if (ret < 0)
dev_warn(iod->dev, "couldn't update vccio0 ctrl\n");
}
static void rk3288_iodomain_init(struct rockchip_iodomain *iod)
{
int ret;
@ -227,6 +250,43 @@ static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod)
dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
}
static const struct rockchip_iodomain_soc_data soc_data_px30 = {
.grf_offset = 0x180,
.supply_names = {
NULL,
"vccio6",
"vccio1",
"vccio2",
"vccio3",
"vccio4",
"vccio5",
"vccio-oscgpi",
},
.init = px30_iodomain_init,
};
static const struct rockchip_iodomain_soc_data soc_data_px30_pmu = {
.grf_offset = 0x100,
.supply_names = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
"pmuio1",
"pmuio2",
},
};
/*
* On the rk3188 the io-domains are handled by a shared register with the
* lower 8 bits being still being continuing drive-strength settings.
@ -380,6 +440,14 @@ static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
};
static const struct of_device_id rockchip_iodomain_match[] = {
{
.compatible = "rockchip,px30-io-voltage-domain",
.data = (void *)&soc_data_px30
},
{
.compatible = "rockchip,px30-pmu-io-voltage-domain",
.data = (void *)&soc_data_px30_pmu
},
{
.compatible = "rockchip,rk3188-io-voltage-domain",
.data = &soc_data_rk3188

View file

@ -753,6 +753,7 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
u32 gpe_number,
acpi_event_status
*event_status))
ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_dispatch_gpe(acpi_handle gpe_device, u32 gpe_number))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void))
ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_wakeup_gpes(void))

View file

@ -542,6 +542,7 @@ extern enum system_states {
SYSTEM_HALT,
SYSTEM_POWER_OFF,
SYSTEM_RESTART,
SYSTEM_SUSPEND,
} system_state;
/* This cannot be an enum because some may be used in assembly source. */

View file

@ -287,6 +287,8 @@ static int create_image(int platform_mode)
local_irq_disable();
system_state = SYSTEM_SUSPEND;
error = syscore_suspend();
if (error) {
pr_err("Some system devices failed to power down, aborting hibernation\n");
@ -317,6 +319,7 @@ static int create_image(int platform_mode)
syscore_resume();
Enable_irqs:
system_state = SYSTEM_RUNNING;
local_irq_enable();
Enable_cpus:
@ -445,6 +448,7 @@ static int resume_target_kernel(bool platform_mode)
goto Enable_cpus;
local_irq_disable();
system_state = SYSTEM_SUSPEND;
error = syscore_suspend();
if (error)
@ -478,6 +482,7 @@ static int resume_target_kernel(bool platform_mode)
syscore_resume();
Enable_irqs:
system_state = SYSTEM_RUNNING;
local_irq_enable();
Enable_cpus:
@ -563,6 +568,7 @@ int hibernation_platform_enter(void)
goto Enable_cpus;
local_irq_disable();
system_state = SYSTEM_SUSPEND;
syscore_suspend();
if (pm_wakeup_pending()) {
error = -EAGAIN;
@ -575,6 +581,7 @@ int hibernation_platform_enter(void)
Power_up:
syscore_resume();
system_state = SYSTEM_RUNNING;
local_irq_enable();
Enable_cpus:

View file

@ -27,6 +27,7 @@
#include <linux/export.h>
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
#include <linux/swait.h>
#include <linux/ftrace.h>
#include <trace/events/power.h>
#include <linux/compiler.h>
@ -57,10 +58,10 @@ EXPORT_SYMBOL_GPL(pm_suspend_global_flags);
static const struct platform_suspend_ops *suspend_ops;
static const struct platform_s2idle_ops *s2idle_ops;
static DECLARE_WAIT_QUEUE_HEAD(s2idle_wait_head);
static DECLARE_SWAIT_QUEUE_HEAD(s2idle_wait_head);
enum s2idle_states __read_mostly s2idle_state;
static DEFINE_SPINLOCK(s2idle_lock);
static DEFINE_RAW_SPINLOCK(s2idle_lock);
void s2idle_set_ops(const struct platform_s2idle_ops *ops)
{
@ -78,12 +79,12 @@ static void s2idle_enter(void)
{
trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, true);
spin_lock_irq(&s2idle_lock);
raw_spin_lock_irq(&s2idle_lock);
if (pm_wakeup_pending())
goto out;
s2idle_state = S2IDLE_STATE_ENTER;
spin_unlock_irq(&s2idle_lock);
raw_spin_unlock_irq(&s2idle_lock);
get_online_cpus();
cpuidle_resume();
@ -91,17 +92,17 @@ static void s2idle_enter(void)
/* Push all the CPUs into the idle loop. */
wake_up_all_idle_cpus();
/* Make the current CPU wait so it can enter the idle loop too. */
wait_event(s2idle_wait_head,
s2idle_state == S2IDLE_STATE_WAKE);
swait_event(s2idle_wait_head,
s2idle_state == S2IDLE_STATE_WAKE);
cpuidle_pause();
put_online_cpus();
spin_lock_irq(&s2idle_lock);
raw_spin_lock_irq(&s2idle_lock);
out:
s2idle_state = S2IDLE_STATE_NONE;
spin_unlock_irq(&s2idle_lock);
raw_spin_unlock_irq(&s2idle_lock);
trace_suspend_resume(TPS("machine_suspend"), PM_SUSPEND_TO_IDLE, false);
}
@ -156,12 +157,12 @@ void s2idle_wake(void)
{
unsigned long flags;
spin_lock_irqsave(&s2idle_lock, flags);
raw_spin_lock_irqsave(&s2idle_lock, flags);
if (s2idle_state > S2IDLE_STATE_NONE) {
s2idle_state = S2IDLE_STATE_WAKE;
wake_up(&s2idle_wait_head);
swake_up(&s2idle_wait_head);
}
spin_unlock_irqrestore(&s2idle_lock, flags);
raw_spin_unlock_irqrestore(&s2idle_lock, flags);
}
EXPORT_SYMBOL_GPL(s2idle_wake);
@ -428,6 +429,8 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
arch_suspend_disable_irqs();
BUG_ON(!irqs_disabled());
system_state = SYSTEM_SUSPEND;
error = syscore_suspend();
if (!error) {
*wakeup = pm_wakeup_pending();
@ -443,6 +446,8 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
syscore_resume();
}
system_state = SYSTEM_RUNNING;
arch_suspend_enable_irqs();
BUG_ON(irqs_disabled());

View file

@ -186,6 +186,11 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
res = PAGE_SIZE - pg_offp;
}
if (!data_of(data->handle)) {
res = -EINVAL;
goto unlock;
}
res = simple_write_to_buffer(data_of(data->handle), res, &pg_offp,
buf, count);
if (res > 0)

View file

@ -490,6 +490,7 @@ void tick_freeze(void)
if (tick_freeze_depth == num_online_cpus()) {
trace_suspend_resume(TPS("timekeeping_freeze"),
smp_processor_id(), true);
system_state = SYSTEM_SUSPEND;
timekeeping_suspend();
} else {
tick_suspend_local();
@ -513,6 +514,7 @@ void tick_unfreeze(void)
if (tick_freeze_depth == num_online_cpus()) {
timekeeping_resume();
system_state = SYSTEM_RUNNING;
trace_suspend_resume(TPS("timekeeping_freeze"),
smp_processor_id(), false);
} else {