Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7658267

Browse files
rajanv-xilinxMichal Simek
authored and
Michal Simek
committed
firmware: xilinx: Add Zynqmp firmware driver
This patch is adding communication layer with firmware.Firmware driver provides an interface to firmware APIs.Interface APIs can be used by any driver to communicate toPMUFW(Platform Management Unit). All requests go through ATF.Signed-off-by: Rajan Vaja <rajanv@xilinx.com>Signed-off-by: Jolly Shah <jollys@xilinx.com>Signed-off-by: Michal Simek <michal.simek@xilinx.com>
1 parent95bf69a commit7658267

File tree

7 files changed

+408
-0
lines changed

7 files changed

+408
-0
lines changed

‎arch/arm64/Kconfig.platforms‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ config ARCH_ZX
301301

302302
config ARCH_ZYNQMP
303303
bool "Xilinx ZynqMP Family"
304+
select ZYNQMP_FIRMWARE
304305
help
305306
This enables support for Xilinx ZynqMP Family
306307

‎drivers/firmware/Kconfig‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,5 +291,6 @@ source "drivers/firmware/google/Kconfig"
291291
source "drivers/firmware/efi/Kconfig"
292292
source "drivers/firmware/meson/Kconfig"
293293
source "drivers/firmware/tegra/Kconfig"
294+
source "drivers/firmware/xilinx/Kconfig"
294295

295296
endmenu

‎drivers/firmware/Makefile‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ obj-$(CONFIG_GOOGLE_FIRMWARE)+= google/
3232
obj-$(CONFIG_EFI)+= efi/
3333
obj-$(CONFIG_UEFI_CPER)+= efi/
3434
obj-y+= tegra/
35+
obj-y+= xilinx/

‎drivers/firmware/xilinx/Kconfig‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
# Kconfig for Xilinx firmwares
3+
4+
menu "Zynq MPSoC Firmware Drivers"
5+
depends on ARCH_ZYNQMP
6+
7+
config ZYNQMP_FIRMWARE
8+
bool "Enable Xilinx Zynq MPSoC firmware interface"
9+
help
10+
Firmware interface driver is used by different
11+
drivers to communicate with the firmware for
12+
various platform management services.
13+
Say yes to enable ZynqMP firmware interface driver.
14+
If in doubt, say N.
15+
16+
endmenu

‎drivers/firmware/xilinx/Makefile‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
# Makefile for Xilinx firmwares
3+
4+
obj-$(CONFIG_ZYNQMP_FIRMWARE) += zynqmp.o

‎drivers/firmware/xilinx/zynqmp.c‎

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Xilinx Zynq MPSoC Firmware layer
4+
*
5+
* Copyright (C) 2014-2018 Xilinx, Inc.
6+
*
7+
* Michal Simek <michal.simek@xilinx.com>
8+
* Davorin Mista <davorin.mista@aggios.com>
9+
* Jolly Shah <jollys@xilinx.com>
10+
* Rajan Vaja <rajanv@xilinx.com>
11+
*/
12+
13+
#include<linux/arm-smccc.h>
14+
#include<linux/compiler.h>
15+
#include<linux/device.h>
16+
#include<linux/init.h>
17+
#include<linux/module.h>
18+
#include<linux/of.h>
19+
#include<linux/of_platform.h>
20+
#include<linux/slab.h>
21+
#include<linux/uaccess.h>
22+
23+
#include<linux/firmware/xlnx-zynqmp.h>
24+
25+
/**
26+
* zynqmp_pm_ret_code() - Convert PMU-FW error codes to Linux error codes
27+
* @ret_status:PMUFW return code
28+
*
29+
* Return: corresponding Linux error code
30+
*/
31+
staticintzynqmp_pm_ret_code(u32ret_status)
32+
{
33+
switch (ret_status) {
34+
caseXST_PM_SUCCESS:
35+
caseXST_PM_DOUBLE_REQ:
36+
return0;
37+
caseXST_PM_NO_ACCESS:
38+
return-EACCES;
39+
caseXST_PM_ABORT_SUSPEND:
40+
return-ECANCELED;
41+
caseXST_PM_INTERNAL:
42+
caseXST_PM_CONFLICT:
43+
caseXST_PM_INVALID_NODE:
44+
default:
45+
return-EINVAL;
46+
}
47+
}
48+
49+
staticnoinlineintdo_fw_call_fail(u64arg0,u64arg1,u64arg2,
50+
u32*ret_payload)
51+
{
52+
return-ENODEV;
53+
}
54+
55+
/*
56+
* PM function call wrapper
57+
* Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration
58+
*/
59+
staticint (*do_fw_call)(u64,u64,u64,u32*ret_payload)=do_fw_call_fail;
60+
61+
/**
62+
* do_fw_call_smc() - Call system-level platform management layer (SMC)
63+
* @arg0:Argument 0 to SMC call
64+
* @arg1:Argument 1 to SMC call
65+
* @arg2:Argument 2 to SMC call
66+
* @ret_payload:Returned value array
67+
*
68+
* Invoke platform management function via SMC call (no hypervisor present).
69+
*
70+
* Return: Returns status, either success or error+reason
71+
*/
72+
staticnoinlineintdo_fw_call_smc(u64arg0,u64arg1,u64arg2,
73+
u32*ret_payload)
74+
{
75+
structarm_smccc_resres;
76+
77+
arm_smccc_smc(arg0,arg1,arg2,0,0,0,0,0,&res);
78+
79+
if (ret_payload) {
80+
ret_payload[0]=lower_32_bits(res.a0);
81+
ret_payload[1]=upper_32_bits(res.a0);
82+
ret_payload[2]=lower_32_bits(res.a1);
83+
ret_payload[3]=upper_32_bits(res.a1);
84+
}
85+
86+
returnzynqmp_pm_ret_code((enumpm_ret_status)res.a0);
87+
}
88+
89+
/**
90+
* do_fw_call_hvc() - Call system-level platform management layer (HVC)
91+
* @arg0:Argument 0 to HVC call
92+
* @arg1:Argument 1 to HVC call
93+
* @arg2:Argument 2 to HVC call
94+
* @ret_payload:Returned value array
95+
*
96+
* Invoke platform management function via HVC
97+
* HVC-based for communication through hypervisor
98+
* (no direct communication with ATF).
99+
*
100+
* Return: Returns status, either success or error+reason
101+
*/
102+
staticnoinlineintdo_fw_call_hvc(u64arg0,u64arg1,u64arg2,
103+
u32*ret_payload)
104+
{
105+
structarm_smccc_resres;
106+
107+
arm_smccc_hvc(arg0,arg1,arg2,0,0,0,0,0,&res);
108+
109+
if (ret_payload) {
110+
ret_payload[0]=lower_32_bits(res.a0);
111+
ret_payload[1]=upper_32_bits(res.a0);
112+
ret_payload[2]=lower_32_bits(res.a1);
113+
ret_payload[3]=upper_32_bits(res.a1);
114+
}
115+
116+
returnzynqmp_pm_ret_code((enumpm_ret_status)res.a0);
117+
}
118+
119+
/**
120+
* zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
121+
* caller function depending on the configuration
122+
* @pm_api_id:Requested PM-API call
123+
* @arg0:Argument 0 to requested PM-API call
124+
* @arg1:Argument 1 to requested PM-API call
125+
* @arg2:Argument 2 to requested PM-API call
126+
* @arg3:Argument 3 to requested PM-API call
127+
* @ret_payload:Returned value array
128+
*
129+
* Invoke platform management function for SMC or HVC call, depending on
130+
* configuration.
131+
* Following SMC Calling Convention (SMCCC) for SMC64:
132+
* Pm Function Identifier,
133+
* PM_SIP_SVC + PM_API_ID =
134+
*((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)
135+
*((SMC_64) << FUNCID_CC_SHIFT)
136+
*((SIP_START) << FUNCID_OEN_SHIFT)
137+
*((PM_API_ID) & FUNCID_NUM_MASK))
138+
*
139+
* PM_SIP_SVC- Registered ZynqMP SIP Service Call.
140+
* PM_API_ID- Platform Management API ID.
141+
*
142+
* Return: Returns status, either success or error+reason
143+
*/
144+
intzynqmp_pm_invoke_fn(u32pm_api_id,u32arg0,u32arg1,
145+
u32arg2,u32arg3,u32*ret_payload)
146+
{
147+
/*
148+
* Added SIP service call Function Identifier
149+
* Make sure to stay in x0 register
150+
*/
151+
u64smc_arg[4];
152+
153+
smc_arg[0]=PM_SIP_SVC |pm_api_id;
154+
smc_arg[1]= ((u64)arg1 <<32) |arg0;
155+
smc_arg[2]= ((u64)arg3 <<32) |arg2;
156+
157+
returndo_fw_call(smc_arg[0],smc_arg[1],smc_arg[2],ret_payload);
158+
}
159+
160+
staticu32pm_api_version;
161+
staticu32pm_tz_version;
162+
163+
/**
164+
* zynqmp_pm_get_api_version() - Get version number of PMU PM firmware
165+
* @version:Returned version value
166+
*
167+
* Return: Returns status, either success or error+reason
168+
*/
169+
staticintzynqmp_pm_get_api_version(u32*version)
170+
{
171+
u32ret_payload[PAYLOAD_ARG_CNT];
172+
intret;
173+
174+
if (!version)
175+
return-EINVAL;
176+
177+
/* Check is PM API version already verified */
178+
if (pm_api_version>0) {
179+
*version=pm_api_version;
180+
return0;
181+
}
182+
ret=zynqmp_pm_invoke_fn(PM_GET_API_VERSION,0,0,0,0,ret_payload);
183+
*version=ret_payload[1];
184+
185+
returnret;
186+
}
187+
188+
/**
189+
* zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
190+
* @version:Returned version value
191+
*
192+
* Return: Returns status, either success or error+reason
193+
*/
194+
staticintzynqmp_pm_get_trustzone_version(u32*version)
195+
{
196+
u32ret_payload[PAYLOAD_ARG_CNT];
197+
intret;
198+
199+
if (!version)
200+
return-EINVAL;
201+
202+
/* Check is PM trustzone version already verified */
203+
if (pm_tz_version>0) {
204+
*version=pm_tz_version;
205+
return0;
206+
}
207+
ret=zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION,0,0,
208+
0,0,ret_payload);
209+
*version=ret_payload[1];
210+
211+
returnret;
212+
}
213+
214+
/**
215+
* get_set_conduit_method() - Choose SMC or HVC based communication
216+
* @np:Pointer to the device_node structure
217+
*
218+
* Use SMC or HVC-based functions to communicate with EL2/EL3.
219+
*
220+
* Return: Returns 0 on success or error code
221+
*/
222+
staticintget_set_conduit_method(structdevice_node*np)
223+
{
224+
constchar*method;
225+
226+
if (of_property_read_string(np,"method",&method)) {
227+
pr_warn("%s missing \"method\" property\n",__func__);
228+
return-ENXIO;
229+
}
230+
231+
if (!strcmp("hvc",method)) {
232+
do_fw_call=do_fw_call_hvc;
233+
}elseif (!strcmp("smc",method)) {
234+
do_fw_call=do_fw_call_smc;
235+
}else {
236+
pr_warn("%s Invalid \"method\" property: %s\n",
237+
__func__,method);
238+
return-EINVAL;
239+
}
240+
241+
return0;
242+
}
243+
244+
staticconststructzynqmp_eemi_opseemi_ops= {
245+
.get_api_version=zynqmp_pm_get_api_version,
246+
};
247+
248+
/**
249+
* zynqmp_pm_get_eemi_ops - Get eemi ops functions
250+
*
251+
* Return: Pointer of eemi_ops structure
252+
*/
253+
conststructzynqmp_eemi_ops*zynqmp_pm_get_eemi_ops(void)
254+
{
255+
return&eemi_ops;
256+
}
257+
EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops);
258+
259+
staticintzynqmp_firmware_probe(structplatform_device*pdev)
260+
{
261+
structdevice*dev=&pdev->dev;
262+
structdevice_node*np;
263+
intret;
264+
265+
np=of_find_compatible_node(NULL,NULL,"xlnx,zynqmp");
266+
if (!np)
267+
return0;
268+
of_node_put(np);
269+
270+
ret=get_set_conduit_method(dev->of_node);
271+
if (ret)
272+
returnret;
273+
274+
/* Check PM API version number */
275+
zynqmp_pm_get_api_version(&pm_api_version);
276+
if (pm_api_version<ZYNQMP_PM_VERSION) {
277+
panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n",
278+
__func__,
279+
ZYNQMP_PM_VERSION_MAJOR,ZYNQMP_PM_VERSION_MINOR,
280+
pm_api_version >>16,pm_api_version&0xFFFF);
281+
}
282+
283+
pr_info("%s Platform Management API v%d.%d\n",__func__,
284+
pm_api_version >>16,pm_api_version&0xFFFF);
285+
286+
/* Check trustzone version number */
287+
ret=zynqmp_pm_get_trustzone_version(&pm_tz_version);
288+
if (ret)
289+
panic("Legacy trustzone found without version support\n");
290+
291+
if (pm_tz_version<ZYNQMP_TZ_VERSION)
292+
panic("%s Trustzone version error. Expected: v%d.%d - Found: v%d.%d\n",
293+
__func__,
294+
ZYNQMP_TZ_VERSION_MAJOR,ZYNQMP_TZ_VERSION_MINOR,
295+
pm_tz_version >>16,pm_tz_version&0xFFFF);
296+
297+
pr_info("%s Trustzone version v%d.%d\n",__func__,
298+
pm_tz_version >>16,pm_tz_version&0xFFFF);
299+
300+
returnof_platform_populate(dev->of_node,NULL,NULL,dev);
301+
}
302+
303+
staticintzynqmp_firmware_remove(structplatform_device*pdev)
304+
{
305+
return0;
306+
}
307+
308+
staticconststructof_device_idzynqmp_firmware_of_match[]= {
309+
{.compatible="xlnx,zynqmp-firmware"},
310+
{},
311+
};
312+
MODULE_DEVICE_TABLE(of,zynqmp_firmware_of_match);
313+
314+
staticstructplatform_driverzynqmp_firmware_driver= {
315+
.driver= {
316+
.name="zynqmp_firmware",
317+
.of_match_table=zynqmp_firmware_of_match,
318+
},
319+
.probe=zynqmp_firmware_probe,
320+
.remove=zynqmp_firmware_remove,
321+
};
322+
module_platform_driver(zynqmp_firmware_driver);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp