/* * 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; out_put_node: of_node_put(np); return err; }
/* * PSCI init function for PSCI versions >=0.2 * * Probe based on PSCI PSCI_VERSION function */ static int __init psci_0_2_init(struct device_node *np) { int err; err = get_set_conduit_method(np); if (err) goto out_put_node; /* * Starting with v0.2, the PSCI specification introduced a call * (PSCI_VERSION) that allows probing the firmware version, so * that PSCI function IDs and version specific initialization * can be carried out according to the specific version reported * by firmware */ err = psci_probe(); out_put_node: of_node_put(np); return err; }
static int zynqmp_firmware_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np; int ret; np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp"); if (!np) return 0; of_node_put(np); ret = get_set_conduit_method(dev->of_node); if (ret) return ret; /* Check PM API version number */ zynqmp_pm_get_api_version(&pm_api_version); if (pm_api_version < ZYNQMP_PM_VERSION) { panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n", __func__, ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR, pm_api_version >> 16, pm_api_version & 0xFFFF); }
/* * PSCI < v0.2 get PSCI Function IDs via DT. */ static int __init psci_0_1_init(struct device_node *np) { u32 id; int err; err = get_set_conduit_method(np); if (err) goto out_put_node; pr_info("Using PSCI v0.1 Function IDs from DT\n"); if (!of_property_read_u32(np, "cpu_suspend", &id)) { psci_function_id[PSCI_FN_CPU_SUSPEND] = id; psci_ops.cpu_suspend = psci_cpu_suspend; } if (!of_property_read_u32(np, "cpu_off", &id)) { psci_function_id[PSCI_FN_CPU_OFF] = id; psci_ops.cpu_off = psci_cpu_off; } if (!of_property_read_u32(np, "cpu_on", &id)) { psci_function_id[PSCI_FN_CPU_ON] = id; psci_ops.cpu_on = psci_cpu_on; } if (!of_property_read_u32(np, "migrate", &id)) { psci_function_id[PSCI_FN_MIGRATE] = id; psci_ops.migrate = psci_migrate; } out_put_node: of_node_put(np); return err; }
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; }