140e40cd2SJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause
240e40cd2SJorge Ramirez-Ortiz /*
340e40cd2SJorge Ramirez-Ortiz * Copyright (C) 2022 Foundries.io Ltd
440e40cd2SJorge Ramirez-Ortiz * Jorge Ramirez-Ortiz <jorge@foundries.io>
540e40cd2SJorge Ramirez-Ortiz */
640e40cd2SJorge Ramirez-Ortiz
740e40cd2SJorge Ramirez-Ortiz #include <arm.h>
840e40cd2SJorge Ramirez-Ortiz #include <drivers/versal_mbox.h>
940e40cd2SJorge Ramirez-Ortiz #include <drivers/versal_pm.h>
1040e40cd2SJorge Ramirez-Ortiz #include <initcall.h>
1140e40cd2SJorge Ramirez-Ortiz #include <kernel/cache_helpers.h>
1240e40cd2SJorge Ramirez-Ortiz #include <kernel/delay.h>
1340e40cd2SJorge Ramirez-Ortiz #include <kernel/panic.h>
1440e40cd2SJorge Ramirez-Ortiz #include <kernel/thread.h>
1540e40cd2SJorge Ramirez-Ortiz #include <mm/core_memprot.h>
1640e40cd2SJorge Ramirez-Ortiz #include <string.h>
1740e40cd2SJorge Ramirez-Ortiz #include <tee/cache.h>
1840e40cd2SJorge Ramirez-Ortiz #include <tee_api_types.h>
1940e40cd2SJorge Ramirez-Ortiz #include <utee_defines.h>
2040e40cd2SJorge Ramirez-Ortiz
2140e40cd2SJorge Ramirez-Ortiz /* VERSAL_SIP_UID: 2ab9e4ec-93b9-11e7-a019dfe0dbad0ae0 */
2240e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_0 U(0xece4b92a)
2340e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_1 U(0xe711b993)
2440e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_2 U(0xe0df19a0)
2540e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_UID_3 U(0xe00aaddb)
2640e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_MAJOR 0
2740e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_MINOR 1
2840e40cd2SJorge Ramirez-Ortiz
2940e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_SVC_VERSION 0x8200ff03
3040e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_SVC_UID 0x8200ff01
3140e40cd2SJorge Ramirez-Ortiz #define VERSAL_SIP_SVC 0xc2000000
3240e40cd2SJorge Ramirez-Ortiz
3340e40cd2SJorge Ramirez-Ortiz #define PAYLOAD_ARG_CNT 8
3440e40cd2SJorge Ramirez-Ortiz
3540e40cd2SJorge Ramirez-Ortiz /* MBOX IPI */
3640e40cd2SJorge Ramirez-Ortiz #define PM_MODULE_SHIFT 8
3740e40cd2SJorge Ramirez-Ortiz #define PM_MODULE 2
3840e40cd2SJorge Ramirez-Ortiz #define PM_API_ID(x) ((PM_MODULE << PM_MODULE_SHIFT) | (x))
3940e40cd2SJorge Ramirez-Ortiz #define VERSAL_PM_MAJOR 0
4040e40cd2SJorge Ramirez-Ortiz #define VERSAL_PM_MINOR 1
4140e40cd2SJorge Ramirez-Ortiz
4240e40cd2SJorge Ramirez-Ortiz /* PM API ids */
4340e40cd2SJorge Ramirez-Ortiz #define PM_GET_API_VERSION 1
4440e40cd2SJorge Ramirez-Ortiz #define PM_GET_DEVICE_STATUS 3
4540e40cd2SJorge Ramirez-Ortiz #define PM_GET_OP_CHARACTERISTIC 4
4640e40cd2SJorge Ramirez-Ortiz #define PM_REGISTER_NOTIFIER 5
4740e40cd2SJorge Ramirez-Ortiz #define PM_REQ_SUSPEND 6
4840e40cd2SJorge Ramirez-Ortiz #define PM_SELF_SUSPEND 7
4940e40cd2SJorge Ramirez-Ortiz #define PM_FORCE_POWERDOWN 8
5040e40cd2SJorge Ramirez-Ortiz #define PM_ABORT_SUSPEND 9
5140e40cd2SJorge Ramirez-Ortiz #define PM_REQ_WAKEUP 10
5240e40cd2SJorge Ramirez-Ortiz #define PM_SET_WAKEUP_SOURCE 11
5340e40cd2SJorge Ramirez-Ortiz #define PM_SYSTEM_SHUTDOWN 12
5440e40cd2SJorge Ramirez-Ortiz #define PM_REQUEST_DEVICE 13
5540e40cd2SJorge Ramirez-Ortiz #define PM_RELEASE_DEVICE 14
5640e40cd2SJorge Ramirez-Ortiz #define PM_SET_REQUIREMENT 15
5740e40cd2SJorge Ramirez-Ortiz #define PM_SET_MAX_LATENCY 16
5840e40cd2SJorge Ramirez-Ortiz #define PM_RESET_ASSERT 17
5940e40cd2SJorge Ramirez-Ortiz #define PM_RESET_GET_STATUS 18
6040e40cd2SJorge Ramirez-Ortiz #define PM_INIT_FINALIZE 21
6140e40cd2SJorge Ramirez-Ortiz #define PM_GET_CHIPID 24
6240e40cd2SJorge Ramirez-Ortiz #define PM_PINCTRL_REQUEST 28
6340e40cd2SJorge Ramirez-Ortiz #define PM_PINCTRL_RELEASE 29
6440e40cd2SJorge Ramirez-Ortiz #define PM_PINCTRL_GET_FUNCTION 30
6540e40cd2SJorge Ramirez-Ortiz #define PM_PINCTRL_SET_FUNCTION 31
6640e40cd2SJorge Ramirez-Ortiz #define PM_PINCTRL_CONFIG_PARAM_GET 32
6740e40cd2SJorge Ramirez-Ortiz #define PM_PINCTRL_CONFIG_PARAM_SET 33
6840e40cd2SJorge Ramirez-Ortiz #define PM_IOCTL 34
6940e40cd2SJorge Ramirez-Ortiz #define PM_QUERY_DATA 35
7040e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_ENABLE 36
7140e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_DISABLE 37
7240e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETSTATE 38
7340e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_SETDIVIDER 39
7440e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETDIVIDER 40
7540e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_SETRATE 41
7640e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETRATE 42
7740e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_SETPARENT 43
7840e40cd2SJorge Ramirez-Ortiz #define PM_CLOCK_GETPARENT 44
7940e40cd2SJorge Ramirez-Ortiz #define PM_PLL_SET_PARAMETER 48
8040e40cd2SJorge Ramirez-Ortiz #define PM_PLL_GET_PARAMETER 49
8140e40cd2SJorge Ramirez-Ortiz #define PM_PLL_SET_MODE 50
8240e40cd2SJorge Ramirez-Ortiz #define PM_PLL_GET_MODE 51
8340e40cd2SJorge Ramirez-Ortiz #define PM_FEATURE_CHECK 63
8440e40cd2SJorge Ramirez-Ortiz
8540e40cd2SJorge Ramirez-Ortiz /* Loader API id */
8640e40cd2SJorge Ramirez-Ortiz #define PM_LOAD_PDI 0x701
8740e40cd2SJorge Ramirez-Ortiz
8840e40cd2SJorge Ramirez-Ortiz /* PDI sources */
8940e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_JTAG 0x0
9040e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_QSPI24 0x1
9140e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_QSPI32 0x2
9240e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SD0 0x3
9340e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_EMMC0 0x4
9440e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SD1 0x5
9540e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_EMMC1 0x6
9640e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_USB 0x7
9740e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_OSPI 0x8
9840e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SBI 0x9
9940e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SMAP 0xA
10040e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_PCIE 0xB
10140e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_SD1_LS 0xE
10240e40cd2SJorge Ramirez-Ortiz #define PDI_SRC_DDR 0xF
10340e40cd2SJorge Ramirez-Ortiz
10440e40cd2SJorge Ramirez-Ortiz struct versal_sip_payload {
10540e40cd2SJorge Ramirez-Ortiz uint32_t data[PAYLOAD_ARG_CNT];
10640e40cd2SJorge Ramirez-Ortiz };
10740e40cd2SJorge Ramirez-Ortiz
versal_sip_call(uint32_t smc_fid,uint32_t arg0,uint32_t arg1,uint32_t arg2,uint32_t arg3,struct versal_sip_payload * payload)10840e40cd2SJorge Ramirez-Ortiz static uint32_t versal_sip_call(uint32_t smc_fid, uint32_t arg0, uint32_t arg1,
10940e40cd2SJorge Ramirez-Ortiz uint32_t arg2, uint32_t arg3,
11040e40cd2SJorge Ramirez-Ortiz struct versal_sip_payload *payload)
11140e40cd2SJorge Ramirez-Ortiz {
11240e40cd2SJorge Ramirez-Ortiz struct thread_smc_args args = {
11340e40cd2SJorge Ramirez-Ortiz .a0 = smc_fid,
11440e40cd2SJorge Ramirez-Ortiz .a1 = reg_pair_to_64(arg1, arg0),
11540e40cd2SJorge Ramirez-Ortiz .a2 = reg_pair_to_64(arg3, arg2),
11640e40cd2SJorge Ramirez-Ortiz };
11740e40cd2SJorge Ramirez-Ortiz
11840e40cd2SJorge Ramirez-Ortiz thread_smccc(&args);
11940e40cd2SJorge Ramirez-Ortiz
12040e40cd2SJorge Ramirez-Ortiz if (payload) {
12140e40cd2SJorge Ramirez-Ortiz reg_pair_from_64(args.a0, &payload->data[1], &payload->data[0]);
12240e40cd2SJorge Ramirez-Ortiz reg_pair_from_64(args.a1, &payload->data[3], &payload->data[2]);
12340e40cd2SJorge Ramirez-Ortiz reg_pair_from_64(args.a2, &payload->data[5], &payload->data[4]);
12440e40cd2SJorge Ramirez-Ortiz reg_pair_from_64(args.a3, &payload->data[7], &payload->data[6]);
12540e40cd2SJorge Ramirez-Ortiz }
12640e40cd2SJorge Ramirez-Ortiz
12740e40cd2SJorge Ramirez-Ortiz /* allow the PLM to output its debug information */
12840e40cd2SJorge Ramirez-Ortiz if (IS_ENABLED(CFG_VERSAL_TRACE_PLM))
12940e40cd2SJorge Ramirez-Ortiz mdelay(500);
13040e40cd2SJorge Ramirez-Ortiz
13140e40cd2SJorge Ramirez-Ortiz return args.a0;
13240e40cd2SJorge Ramirez-Ortiz }
13340e40cd2SJorge Ramirez-Ortiz
13440e40cd2SJorge Ramirez-Ortiz /* SIP call to program the FPGA has been obsoleted, use the PLM */
versal_write_fpga(paddr_t pa)13540e40cd2SJorge Ramirez-Ortiz TEE_Result versal_write_fpga(paddr_t pa)
13640e40cd2SJorge Ramirez-Ortiz {
137*e4c76cc2SJorge Ramirez-Ortiz struct versal_ipi_cmd cmd = { };
13840e40cd2SJorge Ramirez-Ortiz
13940e40cd2SJorge Ramirez-Ortiz cmd.data[0] = PM_LOAD_PDI;
14040e40cd2SJorge Ramirez-Ortiz cmd.data[1] = PDI_SRC_DDR;
14140e40cd2SJorge Ramirez-Ortiz reg_pair_from_64(pa, &cmd.data[2], &cmd.data[3]);
14240e40cd2SJorge Ramirez-Ortiz
14340e40cd2SJorge Ramirez-Ortiz if (versal_mbox_notify(&cmd, NULL, NULL))
14440e40cd2SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
14540e40cd2SJorge Ramirez-Ortiz
14640e40cd2SJorge Ramirez-Ortiz return TEE_SUCCESS;
14740e40cd2SJorge Ramirez-Ortiz }
14840e40cd2SJorge Ramirez-Ortiz
versal_soc_version(uint8_t * version)14940e40cd2SJorge Ramirez-Ortiz TEE_Result versal_soc_version(uint8_t *version)
15040e40cd2SJorge Ramirez-Ortiz {
15140e40cd2SJorge Ramirez-Ortiz struct versal_sip_payload p = { };
15240e40cd2SJorge Ramirez-Ortiz const uint32_t version_shift = 12;
15340e40cd2SJorge Ramirez-Ortiz
15440e40cd2SJorge Ramirez-Ortiz if (!version)
15540e40cd2SJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS;
15640e40cd2SJorge Ramirez-Ortiz
15740e40cd2SJorge Ramirez-Ortiz if (versal_sip_call(VERSAL_SIP_SVC | PM_GET_CHIPID, 0, 0, 0, 0, &p))
15840e40cd2SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
15940e40cd2SJorge Ramirez-Ortiz
16040e40cd2SJorge Ramirez-Ortiz *version = p.data[2] >> version_shift;
16140e40cd2SJorge Ramirez-Ortiz
16240e40cd2SJorge Ramirez-Ortiz return TEE_SUCCESS;
16340e40cd2SJorge Ramirez-Ortiz }
16440e40cd2SJorge Ramirez-Ortiz
uuid_is_versal_pm(void)16540e40cd2SJorge Ramirez-Ortiz static bool uuid_is_versal_pm(void)
16640e40cd2SJorge Ramirez-Ortiz {
16740e40cd2SJorge Ramirez-Ortiz struct versal_sip_payload p = { };
16840e40cd2SJorge Ramirez-Ortiz
16940e40cd2SJorge Ramirez-Ortiz versal_sip_call(VERSAL_SIP_SVC_UID, 0, 0, 0, 0, &p);
17040e40cd2SJorge Ramirez-Ortiz
17140e40cd2SJorge Ramirez-Ortiz if (p.data[0] == VERSAL_SIP_UID_0 && p.data[2] == VERSAL_SIP_UID_1 &&
17240e40cd2SJorge Ramirez-Ortiz p.data[4] == VERSAL_SIP_UID_2 && p.data[6] == VERSAL_SIP_UID_3)
17340e40cd2SJorge Ramirez-Ortiz return true;
17440e40cd2SJorge Ramirez-Ortiz
17540e40cd2SJorge Ramirez-Ortiz return false;
17640e40cd2SJorge Ramirez-Ortiz }
17740e40cd2SJorge Ramirez-Ortiz
versal_check_pm_abi(void)17840e40cd2SJorge Ramirez-Ortiz static TEE_Result versal_check_pm_abi(void)
17940e40cd2SJorge Ramirez-Ortiz {
18040e40cd2SJorge Ramirez-Ortiz struct versal_sip_payload p = { };
181*e4c76cc2SJorge Ramirez-Ortiz struct versal_ipi_cmd cmd = { };
182*e4c76cc2SJorge Ramirez-Ortiz struct versal_ipi_cmd rsp = { };
18340e40cd2SJorge Ramirez-Ortiz unsigned int major = 0;
18440e40cd2SJorge Ramirez-Ortiz unsigned int minor = 0;
18540e40cd2SJorge Ramirez-Ortiz
18640e40cd2SJorge Ramirez-Ortiz if (!uuid_is_versal_pm()) {
18740e40cd2SJorge Ramirez-Ortiz EMSG("Invalid SiP Service");
18840e40cd2SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
18940e40cd2SJorge Ramirez-Ortiz }
19040e40cd2SJorge Ramirez-Ortiz
19140e40cd2SJorge Ramirez-Ortiz if (versal_sip_call(VERSAL_SIP_SVC_VERSION, 0, 0, 0, 0, &p))
19240e40cd2SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
19340e40cd2SJorge Ramirez-Ortiz
19440e40cd2SJorge Ramirez-Ortiz major = p.data[0];
19540e40cd2SJorge Ramirez-Ortiz minor = p.data[2];
19640e40cd2SJorge Ramirez-Ortiz if (major != VERSAL_SIP_MAJOR || minor < VERSAL_SIP_MINOR) {
19740e40cd2SJorge Ramirez-Ortiz EMSG("Invalid SiP version: Major %d, Minor %d", major, minor);
19840e40cd2SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
19940e40cd2SJorge Ramirez-Ortiz }
20040e40cd2SJorge Ramirez-Ortiz
20140e40cd2SJorge Ramirez-Ortiz cmd.data[0] = PM_API_ID(PM_GET_API_VERSION);
20240e40cd2SJorge Ramirez-Ortiz if (versal_mbox_notify(&cmd, &rsp, NULL))
20340e40cd2SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
20440e40cd2SJorge Ramirez-Ortiz
20540e40cd2SJorge Ramirez-Ortiz major = rsp.data[1] & 0xFFFF;
20640e40cd2SJorge Ramirez-Ortiz minor = rsp.data[1] >> 16;
20740e40cd2SJorge Ramirez-Ortiz if (major != VERSAL_PM_MAJOR || minor < VERSAL_PM_MINOR) {
20840e40cd2SJorge Ramirez-Ortiz EMSG("Invalid PM version: Major %d, Minor %d", major, minor);
20940e40cd2SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
21040e40cd2SJorge Ramirez-Ortiz }
21140e40cd2SJorge Ramirez-Ortiz
21240e40cd2SJorge Ramirez-Ortiz return TEE_SUCCESS;
21340e40cd2SJorge Ramirez-Ortiz }
21440e40cd2SJorge Ramirez-Ortiz
21540e40cd2SJorge Ramirez-Ortiz early_init_late(versal_check_pm_abi);
216