1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * xen/arch/arm/platforms/imx8qm.c
4 *
5 * i.MX 8QM setup
6 *
7 * Copyright (c) 2016 Freescale Inc.
8 * Copyright 2018-2019 NXP
9 *
10 *
11 * Peng Fan <peng.fan@nxp.com>
12 */
13
14 #include <xen/sched.h>
15 #include <asm/platform.h>
16 #include <asm/smccc.h>
17
18 static const char * const imx8qm_dt_compat[] __initconst =
19 {
20 "fsl,imx8qm",
21 "fsl,imx8qxp",
22 NULL
23 };
24
25 #define IMX_SIP_FID(fid) \
26 ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
27 ARM_SMCCC_CONV_64, \
28 ARM_SMCCC_OWNER_SIP, \
29 (fid))
30
31 #define IMX_SIP_F_CPUFREQ 0x1
32 #define IMX_SIP_F_TIME 0x2
33 #define IMX_SIP_F_WAKEUP_SRC 0x9
34 #define IMX_SIP_F_OTP_WRITE 0xB
35
36 #define IMX_SIP_TIME_SF_RTC_SET_TIME 0x00
37 #define IMX_SIP_TIME_SF_WDOG_START 0x01
38 #define IMX_SIP_TIME_SF_WDOG_STOP 0x02
39 #define IMX_SIP_TIME_SF_WDOG_SET_ACT 0x03
40 #define IMX_SIP_TIME_SF_WDOG_PING 0x04
41 #define IMX_SIP_TIME_SF_WDOG_SET_TIMEOUT 0x05
42 #define IMX_SIP_TIME_SF_WDOG_GET_STAT 0x06
43 #define IMX_SIP_TIME_SF_WDOG_SET_PRETIME 0x07
44
imx8qm_is_sip_time_call_ok(uint32_t subfunction_id)45 static bool imx8qm_is_sip_time_call_ok(uint32_t subfunction_id)
46 {
47 switch ( subfunction_id )
48 {
49 case IMX_SIP_TIME_SF_RTC_SET_TIME:
50 return true;
51 case IMX_SIP_TIME_SF_WDOG_START:
52 case IMX_SIP_TIME_SF_WDOG_STOP:
53 case IMX_SIP_TIME_SF_WDOG_SET_ACT:
54 case IMX_SIP_TIME_SF_WDOG_PING:
55 case IMX_SIP_TIME_SF_WDOG_SET_TIMEOUT:
56 case IMX_SIP_TIME_SF_WDOG_GET_STAT:
57 case IMX_SIP_TIME_SF_WDOG_SET_PRETIME:
58 return true;
59 default:
60 gprintk(XENLOG_WARNING, "imx8qm: smc: time: Unknown subfunction id %x\n",
61 subfunction_id);
62 return false;
63 }
64 }
65
imx8qm_smc(struct cpu_user_regs * regs)66 static bool imx8qm_smc(struct cpu_user_regs *regs)
67 {
68 uint32_t function_id = get_user_reg(regs, 0);
69 uint32_t subfunction_id = get_user_reg(regs, 1);
70 struct arm_smccc_res res;
71
72 if ( !cpus_have_const_cap(ARM_SMCCC_1_1) )
73 {
74 printk_once(XENLOG_WARNING
75 "imx8qm: smc: no SMCCC 1.1 support. Disabling firmware calls\n");
76
77 return false;
78 }
79
80 /* Only hardware domain may use the SIP calls */
81 if ( !is_hardware_domain(current->domain) )
82 {
83 gprintk(XENLOG_WARNING, "imx8qm: smc: No access\n");
84 return false;
85 }
86
87 switch ( function_id )
88 {
89 case IMX_SIP_FID(IMX_SIP_F_CPUFREQ):
90 /* Hardware domain can't take any informed decision here */
91 return false;
92 case IMX_SIP_FID(IMX_SIP_F_TIME):
93 if ( imx8qm_is_sip_time_call_ok(subfunction_id) )
94 goto allow_call;
95 return false;
96 /* Xen doesn't have suspend support */
97 case IMX_SIP_FID(IMX_SIP_F_WAKEUP_SRC):
98 return false;
99 case IMX_SIP_FID(IMX_SIP_F_OTP_WRITE):
100 /* subfunction_id is the fuse number, no sensible check possible */
101 goto allow_call;
102 default:
103 gprintk(XENLOG_WARNING, "imx8qm: smc: Unknown function id %x\n",
104 function_id);
105 return false;
106 }
107
108 allow_call:
109 arm_smccc_1_1_smc(function_id,
110 subfunction_id,
111 get_user_reg(regs, 2),
112 get_user_reg(regs, 3),
113 get_user_reg(regs, 4),
114 get_user_reg(regs, 5),
115 get_user_reg(regs, 6),
116 get_user_reg(regs, 7),
117 &res);
118
119 set_user_reg(regs, 0, res.a0);
120 set_user_reg(regs, 1, res.a1);
121 set_user_reg(regs, 2, res.a2);
122 set_user_reg(regs, 3, res.a3);
123
124 return true;
125 }
126
127 PLATFORM_START(imx8qm, "i.MX 8Q{M,XP}")
128 .compatible = imx8qm_dt_compat,
129 .smc = imx8qm_smc,
130 PLATFORM_END
131
132 /*
133 * Local variables:
134 * mode: C
135 * c-file-style: "BSD"
136 * c-basic-offset: 4
137 * indent-tabs-mode: nil
138 * End:
139 */
140