Home | History | Annotate | Download | only in pm_service
      1 /*
      2  * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 /*
      8  * Top-level SMC handler for ZynqMP power management calls and
      9  * IPI setup functions for communication with PMU.
     10  */
     11 
     12 #include <errno.h>
     13 #include <gic_common.h>
     14 #include <runtime_svc.h>
     15 #include <string.h>
     16 #include "../zynqmp_private.h"
     17 #include "pm_api_sys.h"
     18 #include "pm_client.h"
     19 #include "pm_ipi.h"
     20 
     21 #define PM_GET_CALLBACK_DATA	0xa01
     22 
     23 /* 0 - UP, !0 - DOWN */
     24 static int32_t pm_down = !0;
     25 
     26 /**
     27  * pm_context - Structure which contains data for power management
     28  * @api_version		version of PM API, must match with one on PMU side
     29  * @payload		payload array used to store received
     30  *			data from ipi buffer registers
     31  */
     32 static struct {
     33 	uint32_t api_version;
     34 	uint32_t payload[PAYLOAD_ARG_CNT];
     35 } pm_ctx;
     36 
     37 /**
     38  * pm_setup() - PM service setup
     39  *
     40  * @return	On success, the initialization function must return 0.
     41  *		Any other return value will cause the framework to ignore
     42  *		the service
     43  *
     44  * Initialization functions for ZynqMP power management for
     45  * communicaton with PMU.
     46  *
     47  * Called from sip_svc_setup initialization function with the
     48  * rt_svc_init signature.
     49  */
     50 int pm_setup(void)
     51 {
     52 	int status;
     53 
     54 	if (!zynqmp_is_pmu_up())
     55 		return -ENODEV;
     56 
     57 	status = pm_ipi_init();
     58 
     59 	if (status == 0)
     60 		INFO("BL31: PM Service Init Complete: API v%d.%d\n",
     61 		     PM_VERSION_MAJOR, PM_VERSION_MINOR);
     62 	else
     63 		INFO("BL31: PM Service Init Failed, Error Code %d!\n", status);
     64 
     65 	pm_down = status;
     66 
     67 	return status;
     68 }
     69 
     70 /**
     71  * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
     72  * @smc_fid - Function Identifier
     73  * @x1 - x4 - Arguments
     74  * @cookie  - Unused
     75  * @handler - Pointer to caller's context structure
     76  *
     77  * @return  - Unused
     78  *
     79  * Determines that smc_fid is valid and supported PM SMC Function ID from the
     80  * list of pm_api_ids, otherwise completes the request with
     81  * the unknown SMC Function ID
     82  *
     83  * The SMC calls for PM service are forwarded from SIP Service SMC handler
     84  * function with rt_svc_handle signature
     85  */
     86 uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
     87 			uint64_t x4, void *cookie, void *handle, uint64_t flags)
     88 {
     89 	enum pm_ret_status ret;
     90 
     91 	uint32_t pm_arg[4];
     92 
     93 	/* Handle case where PM wasn't initialized properly */
     94 	if (pm_down)
     95 		SMC_RET1(handle, SMC_UNK);
     96 
     97 	pm_arg[0] = (uint32_t)x1;
     98 	pm_arg[1] = (uint32_t)(x1 >> 32);
     99 	pm_arg[2] = (uint32_t)x2;
    100 	pm_arg[3] = (uint32_t)(x2 >> 32);
    101 
    102 	switch (smc_fid & FUNCID_NUM_MASK) {
    103 	/* PM API Functions */
    104 	case PM_SELF_SUSPEND:
    105 		ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
    106 				      pm_arg[3]);
    107 		SMC_RET1(handle, (uint64_t)ret);
    108 
    109 	case PM_REQ_SUSPEND:
    110 		ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
    111 				     pm_arg[3]);
    112 		SMC_RET1(handle, (uint64_t)ret);
    113 
    114 	case PM_REQ_WAKEUP:
    115 		ret = pm_req_wakeup(pm_arg[0], pm_arg[1], pm_arg[2],
    116 				    pm_arg[3]);
    117 		SMC_RET1(handle, (uint64_t)ret);
    118 
    119 	case PM_FORCE_POWERDOWN:
    120 		ret = pm_force_powerdown(pm_arg[0], pm_arg[1]);
    121 		SMC_RET1(handle, (uint64_t)ret);
    122 
    123 	case PM_ABORT_SUSPEND:
    124 		ret = pm_abort_suspend(pm_arg[0]);
    125 		SMC_RET1(handle, (uint64_t)ret);
    126 
    127 	case PM_SET_WAKEUP_SOURCE:
    128 		ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]);
    129 		SMC_RET1(handle, (uint64_t)ret);
    130 
    131 	case PM_SYSTEM_SHUTDOWN:
    132 		ret = pm_system_shutdown(pm_arg[0], pm_arg[1]);
    133 		SMC_RET1(handle, (uint64_t)ret);
    134 
    135 	case PM_REQ_NODE:
    136 		ret = pm_req_node(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
    137 		SMC_RET1(handle, (uint64_t)ret);
    138 
    139 	case PM_RELEASE_NODE:
    140 		ret = pm_release_node(pm_arg[0]);
    141 		SMC_RET1(handle, (uint64_t)ret);
    142 
    143 	case PM_SET_REQUIREMENT:
    144 		ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2],
    145 					 pm_arg[3]);
    146 		SMC_RET1(handle, (uint64_t)ret);
    147 
    148 	case PM_SET_MAX_LATENCY:
    149 		ret = pm_set_max_latency(pm_arg[0], pm_arg[1]);
    150 		SMC_RET1(handle, (uint64_t)ret);
    151 
    152 	case PM_GET_API_VERSION:
    153 		/* Check is PM API version already verified */
    154 		if (pm_ctx.api_version == PM_VERSION) {
    155 			SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
    156 				 ((uint64_t)PM_VERSION << 32));
    157 		}
    158 
    159 		ret = pm_get_api_version(&pm_ctx.api_version);
    160 		/*
    161 		 * Enable IPI IRQ
    162 		 * assume the rich OS is OK to handle callback IRQs now.
    163 		 * Even if we were wrong, it would not enable the IRQ in
    164 		 * the GIC.
    165 		 */
    166 		pm_ipi_irq_enable();
    167 		SMC_RET1(handle, (uint64_t)ret |
    168 			 ((uint64_t)pm_ctx.api_version << 32));
    169 
    170 	case PM_SET_CONFIGURATION:
    171 		ret = pm_set_configuration(pm_arg[0]);
    172 		SMC_RET1(handle, (uint64_t)ret);
    173 
    174 	case PM_GET_NODE_STATUS:
    175 		ret = pm_get_node_status(pm_arg[0]);
    176 		SMC_RET1(handle, (uint64_t)ret);
    177 
    178 	case PM_GET_OP_CHARACTERISTIC:
    179 	{
    180 		uint32_t result;
    181 
    182 		ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1], &result);
    183 		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result << 32));
    184 	}
    185 
    186 	case PM_REGISTER_NOTIFIER:
    187 		ret = pm_register_notifier(pm_arg[0], pm_arg[1], pm_arg[2],
    188 					   pm_arg[3]);
    189 		SMC_RET1(handle, (uint64_t)ret);
    190 
    191 	case PM_RESET_ASSERT:
    192 		ret = pm_reset_assert(pm_arg[0], pm_arg[1]);
    193 		SMC_RET1(handle, (uint64_t)ret);
    194 
    195 	case PM_RESET_GET_STATUS:
    196 	{
    197 		uint32_t reset_status;
    198 
    199 		ret = pm_reset_get_status(pm_arg[0], &reset_status);
    200 		SMC_RET1(handle, (uint64_t)ret |
    201 			 ((uint64_t)reset_status << 32));
    202 	}
    203 
    204 	/* PM memory access functions */
    205 	case PM_MMIO_WRITE:
    206 		ret = pm_mmio_write(pm_arg[0], pm_arg[1], pm_arg[2]);
    207 		SMC_RET1(handle, (uint64_t)ret);
    208 
    209 	case PM_MMIO_READ:
    210 	{
    211 		uint32_t value;
    212 
    213 		ret = pm_mmio_read(pm_arg[0], &value);
    214 		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
    215 	}
    216 
    217 	case PM_FPGA_LOAD:
    218 		ret = pm_fpga_load(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
    219 		SMC_RET1(handle, (uint64_t)ret);
    220 
    221 	case PM_FPGA_GET_STATUS:
    222 	{
    223 		uint32_t value;
    224 
    225 		ret = pm_fpga_get_status(&value);
    226 		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
    227 	}
    228 
    229 	case PM_GET_CHIPID:
    230 	{
    231 		uint32_t result[2];
    232 
    233 		ret = pm_get_chipid(result);
    234 		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32),
    235 			 result[1]);
    236 	}
    237 
    238 	case PM_GET_CALLBACK_DATA:
    239 	{
    240 		uint32_t result[4];
    241 
    242 		pm_get_callbackdata(result, sizeof(result));
    243 		SMC_RET2(handle,
    244 			 (uint64_t)result[0] | ((uint64_t)result[1] << 32),
    245 			 (uint64_t)result[2] | ((uint64_t)result[3] << 32));
    246 	}
    247 
    248 	default:
    249 		WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
    250 		SMC_RET1(handle, SMC_UNK);
    251 	}
    252 }
    253