video: rockchip: hdmi: misc clean up to hdmi driver
[firefly-linux-kernel-4.4.55.git] / drivers / acpi / sleep.c
index 9c1a435d10e69c8228516346832a8d2d2d242890..0d94621dc856080a0a3715040b7b5339c1edb248 100644 (file)
 #include <linux/irq.h>
 #include <linux/dmi.h>
 #include <linux/device.h>
+#include <linux/interrupt.h>
 #include <linux/suspend.h>
 #include <linux/reboot.h>
 #include <linux/acpi.h>
 #include <linux/module.h>
-
 #include <asm/io.h>
-
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
+#include <trace/events/power.h>
 
 #include "internal.h"
 #include "sleep.h"
@@ -31,12 +29,9 @@ static u8 sleep_states[ACPI_S_STATE_COUNT];
 
 static void acpi_sleep_tts_switch(u32 acpi_state)
 {
-       union acpi_object in_arg = { ACPI_TYPE_INTEGER };
-       struct acpi_object_list arg_list = { 1, &in_arg };
-       acpi_status status = AE_OK;
+       acpi_status status;
 
-       in_arg.integer.value = acpi_state;
-       status = acpi_evaluate_object(NULL, "\\_TTS", &arg_list, NULL);
+       status = acpi_execute_simple_method(NULL, "\\_TTS", acpi_state);
        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
                /*
                 * OS can't evaluate the _TTS object correctly. Some warning
@@ -78,6 +73,17 @@ static int acpi_sleep_prepare(u32 acpi_state)
        return 0;
 }
 
+static bool acpi_sleep_state_supported(u8 sleep_state)
+{
+       acpi_status status;
+       u8 type_a, type_b;
+
+       status = acpi_get_sleep_type_data(sleep_state, &type_a, &type_b);
+       return ACPI_SUCCESS(status) && (!acpi_gbl_reduced_hardware
+               || (acpi_gbl_FADT.sleep_control.address
+                       && acpi_gbl_FADT.sleep_status.address));
+}
+
 #ifdef CONFIG_ACPI_SLEEP
 static u32 acpi_target_sleep_state = ACPI_STATE_S0;
 
@@ -85,6 +91,7 @@ u32 acpi_target_system_state(void)
 {
        return acpi_target_sleep_state;
 }
+EXPORT_SYMBOL_GPL(acpi_target_system_state);
 
 static bool pwr_btn_event_pending;
 
@@ -141,7 +148,7 @@ static int __init init_nvs_nosave(const struct dmi_system_id *d)
        return 0;
 }
 
-static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
+static struct dmi_system_id acpisleep_dmi_table[] __initdata = {
        {
        .callback = init_old_suspend_ordering,
        .ident = "Abit KN9 (nForce4 variant)",
@@ -314,8 +321,13 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
        {},
 };
 
-static void acpi_sleep_dmi_check(void)
+static void __init acpi_sleep_dmi_check(void)
 {
+       int year;
+
+       if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year >= 2012)
+               acpi_nvs_nosave_s3();
+
        dmi_check_system(acpisleep_dmi_table);
 }
 
@@ -423,10 +435,21 @@ static void acpi_pm_finish(void)
 }
 
 /**
- *     acpi_pm_end - Finish up suspend sequence.
+ * acpi_pm_start - Start system PM transition.
+ */
+static void acpi_pm_start(u32 acpi_state)
+{
+       acpi_target_sleep_state = acpi_state;
+       acpi_sleep_tts_switch(acpi_target_sleep_state);
+       acpi_scan_lock_acquire();
+}
+
+/**
+ * acpi_pm_end - Finish up system PM transition.
  */
 static void acpi_pm_end(void)
 {
+       acpi_scan_lock_release();
        /*
         * This is necessary in case acpi_pm_finish() is not called during a
         * failing transition to a sleep state.
@@ -454,21 +477,21 @@ static u32 acpi_suspend_states[] = {
 static int acpi_suspend_begin(suspend_state_t pm_state)
 {
        u32 acpi_state = acpi_suspend_states[pm_state];
-       int error = 0;
+       int error;
 
        error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc();
        if (error)
                return error;
 
-       if (sleep_states[acpi_state]) {
-               acpi_target_sleep_state = acpi_state;
-               acpi_sleep_tts_switch(acpi_target_sleep_state);
-       } else {
-               printk(KERN_ERR "ACPI does not support this state: %d\n",
-                       pm_state);
-               error = -ENOSYS;
+       if (!sleep_states[acpi_state]) {
+               pr_err("ACPI does not support sleep state S%u\n", acpi_state);
+               return -ENOSYS;
        }
-       return error;
+       if (acpi_state > ACPI_STATE_S1)
+               pm_set_suspend_via_firmware();
+
+       acpi_pm_start(acpi_state);
+       return 0;
 }
 
 /**
@@ -487,6 +510,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
 
        ACPI_FLUSH_CPU_CACHE();
 
+       trace_suspend_resume(TPS("acpi_suspend"), acpi_state, true);
        switch (acpi_state) {
        case ACPI_STATE_S1:
                barrier();
@@ -494,12 +518,16 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
                break;
 
        case ACPI_STATE_S3:
+               if (!acpi_suspend_lowlevel)
+                       return -ENOSYS;
                error = acpi_suspend_lowlevel();
                if (error)
                        return error;
                pr_info(PREFIX "Low-level resume complete\n");
+               pm_set_resume_via_firmware();
                break;
        }
+       trace_suspend_resume(TPS("acpi_suspend"), acpi_state, false);
 
        /* This violates the spec but is required for bug compatibility. */
        acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
@@ -517,7 +545,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
         * generate wakeup events.
         */
        if (ACPI_SUCCESS(status) && (acpi_state == ACPI_STATE_S3)) {
-               acpi_event_status pwr_btn_status;
+               acpi_event_status pwr_btn_status = ACPI_EVENT_FLAG_DISABLED;
 
                acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status);
 
@@ -596,23 +624,55 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = {
        .recover = acpi_pm_finish,
 };
 
+static int acpi_freeze_begin(void)
+{
+       acpi_scan_lock_acquire();
+       return 0;
+}
+
+static int acpi_freeze_prepare(void)
+{
+       acpi_enable_wakeup_devices(ACPI_STATE_S0);
+       acpi_enable_all_wakeup_gpes();
+       acpi_os_wait_events_complete();
+       if (acpi_sci_irq_valid())
+               enable_irq_wake(acpi_sci_irq);
+       return 0;
+}
+
+static void acpi_freeze_restore(void)
+{
+       acpi_disable_wakeup_devices(ACPI_STATE_S0);
+       if (acpi_sci_irq_valid())
+               disable_irq_wake(acpi_sci_irq);
+       acpi_enable_all_runtime_gpes();
+}
+
+static void acpi_freeze_end(void)
+{
+       acpi_scan_lock_release();
+}
+
+static const struct platform_freeze_ops acpi_freeze_ops = {
+       .begin = acpi_freeze_begin,
+       .prepare = acpi_freeze_prepare,
+       .restore = acpi_freeze_restore,
+       .end = acpi_freeze_end,
+};
+
 static void acpi_sleep_suspend_setup(void)
 {
        int i;
 
-       for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
-               acpi_status status;
-               u8 type_a, type_b;
-
-               status = acpi_get_sleep_type_data(i, &type_a, &type_b);
-               if (ACPI_SUCCESS(status)) {
+       for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++)
+               if (acpi_sleep_state_supported(i))
                        sleep_states[i] = 1;
-               }
-       }
 
        suspend_set_ops(old_suspend_ordering ?
                &acpi_suspend_ops_old : &acpi_suspend_ops);
+       freeze_set_ops(&acpi_freeze_ops);
 }
+
 #else /* !CONFIG_SUSPEND */
 static inline void acpi_sleep_suspend_setup(void) {}
 #endif /* !CONFIG_SUSPEND */
@@ -632,10 +692,8 @@ static int acpi_hibernation_begin(void)
        int error;
 
        error = nvs_nosave ? 0 : suspend_nvs_alloc();
-       if (!error) {
-               acpi_target_sleep_state = ACPI_STATE_S4;
-               acpi_sleep_tts_switch(acpi_target_sleep_state);
-       }
+       if (!error)
+               acpi_pm_start(ACPI_STATE_S4);
 
        return error;
 }
@@ -664,11 +722,8 @@ static void acpi_hibernation_leave(void)
        /* Reprogram control registers */
        acpi_leave_sleep_state_prep(ACPI_STATE_S4);
        /* Check the hardware signature */
-       if (facs && s4_hardware_signature != facs->hardware_signature) {
-               printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
-                       "cannot resume!\n");
-               panic("ACPI S4 hardware signature mismatch");
-       }
+       if (facs && s4_hardware_signature != facs->hardware_signature)
+               pr_crit("ACPI: Hardware changed while hibernated, success doubtful!\n");
        /* Restore the NVS memory area */
        suspend_nvs_restore();
        /* Allow EC transactions to happen. */
@@ -714,8 +769,10 @@ static int acpi_hibernation_begin_old(void)
        if (!error) {
                if (!nvs_nosave)
                        error = suspend_nvs_alloc();
-               if (!error)
+               if (!error) {
                        acpi_target_sleep_state = ACPI_STATE_S4;
+                       acpi_scan_lock_acquire();
+               }
        }
        return error;
 }
@@ -739,11 +796,7 @@ static const struct platform_hibernation_ops acpi_hibernation_ops_old = {
 
 static void acpi_sleep_hibernate_setup(void)
 {
-       acpi_status status;
-       u8 type_a, type_b;
-
-       status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
-       if (ACPI_FAILURE(status))
+       if (!acpi_sleep_state_supported(ACPI_STATE_S4))
                return;
 
        hibernation_set_ops(old_suspend_ordering ?
@@ -760,26 +813,12 @@ static void acpi_sleep_hibernate_setup(void)
 static inline void acpi_sleep_hibernate_setup(void) {}
 #endif /* !CONFIG_HIBERNATION */
 
-int acpi_suspend(u32 acpi_state)
-{
-       suspend_state_t states[] = {
-               [1] = PM_SUSPEND_STANDBY,
-               [3] = PM_SUSPEND_MEM,
-               [5] = PM_SUSPEND_MAX
-       };
-
-       if (acpi_state < 6 && states[acpi_state])
-               return pm_suspend(states[acpi_state]);
-       if (acpi_state == 4)
-               return hibernate();
-       return -EINVAL;
-}
-
 static void acpi_power_off_prepare(void)
 {
        /* Prepare to power off the system */
        acpi_sleep_prepare(ACPI_STATE_S5);
        acpi_disable_all_gpes();
+       acpi_os_wait_events_complete();
 }
 
 static void acpi_power_off(void)
@@ -792,15 +831,10 @@ static void acpi_power_off(void)
 
 int __init acpi_sleep_init(void)
 {
-       acpi_status status;
-       u8 type_a, type_b;
        char supported[ACPI_S_STATE_COUNT * 3 + 1];
        char *pos = supported;
        int i;
 
-       if (acpi_disabled)
-               return 0;
-
        acpi_sleep_dmi_check();
 
        sleep_states[ACPI_STATE_S0] = 1;
@@ -808,8 +842,7 @@ int __init acpi_sleep_init(void)
        acpi_sleep_suspend_setup();
        acpi_sleep_hibernate_setup();
 
-       status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
-       if (ACPI_SUCCESS(status)) {
+       if (acpi_sleep_state_supported(ACPI_STATE_S5)) {
                sleep_states[ACPI_STATE_S5] = 1;
                pm_power_off_prepare = acpi_power_off_prepare;
                pm_power_off = acpi_power_off;