/* * Probe function for PSCI firmware versions >= 0.2 */ static int __init psci_probe(void) { u32 ver = psci_get_version(); pr_info("PSCIv%d.%d detected in firmware.\n", PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver)); if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) { pr_err("Conflicting PSCI version detected.\n"); return -EINVAL; } psci_0_2_set_functions(); psci_init_migrate(); if (PSCI_VERSION_MAJOR(ver) >= 1) { psci_init_cpu_suspend(); psci_init_system_suspend(); } return 0; }
static int psci_system_suspend(unsigned long unused) { struct psci_power_state state = { .id = 0, .type = PSCI_POWER_STATE_TYPE_POWER_DOWN, .affinity_level = 2, /* system level */ }; return psci_cpu_suspend(state, virt_to_phys(cpu_resume)); } static int psci_system_suspend_enter(suspend_state_t state) { return cpu_suspend(0, psci_system_suspend); } static const struct platform_suspend_ops psci_suspend_ops = { .valid = suspend_valid_only_mem, .enter = psci_system_suspend_enter, }; static void __init psci_init_system_suspend(void) { if (!IS_ENABLED(CONFIG_SUSPEND)) return; suspend_set_ops(&psci_suspend_ops); } /* * PSCI Function IDs for v0.2+ are well defined so use * standard values. */ static int psci_0_2_init(struct device_node *np) { int err, ver; err = get_set_conduit_method(np); if (err) goto out_put_node; ver = psci_get_version(); if (ver == PSCI_RET_NOT_SUPPORTED) { /* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */ pr_err("PSCI firmware does not comply with the v0.2 spec.\n"); err = -EOPNOTSUPP; goto out_put_node; } else { pr_info("PSCIv%d.%d detected in firmware.\n", PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver)); if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) { err = -EINVAL; pr_err("Conflicting PSCI version detected.\n"); goto out_put_node; } } pr_info("Using standard PSCI v0.2 function IDs\n"); psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN_CPU_SUSPEND; psci_ops.cpu_suspend = psci_cpu_suspend; psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; psci_ops.cpu_off = psci_cpu_off; psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN_CPU_ON; psci_ops.cpu_on = psci_cpu_on; psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN_MIGRATE; psci_ops.migrate = psci_migrate; psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN_AFFINITY_INFO; psci_ops.affinity_info = psci_affinity_info; psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] = PSCI_0_2_FN_MIGRATE_INFO_TYPE; psci_ops.migrate_info_type = psci_migrate_info_type; arm_pm_restart = psci_sys_reset; pm_power_off = psci_sys_poweroff; psci_init_system_suspend(); out_put_node: of_node_put(np); return err; }