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