xref: /openbmc/linux/drivers/gpu/drm/amd/amdgpu/amdgpu_securedisplay.c (revision ac8f933664c3a0e2d42f6ee9a2a6d25f87cb23f6)
1ecaafb7bSJinzhou Su /*
2ecaafb7bSJinzhou Su  * Copyright 2021 Advanced Micro Devices, Inc.
3ecaafb7bSJinzhou Su  *
4ecaafb7bSJinzhou Su  * Permission is hereby granted, free of charge, to any person obtaining a
5ecaafb7bSJinzhou Su  * copy of this software and associated documentation files (the "Software"),
6ecaafb7bSJinzhou Su  * to deal in the Software without restriction, including without limitation
7ecaafb7bSJinzhou Su  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8ecaafb7bSJinzhou Su  * and/or sell copies of the Software, and to permit persons to whom the
9ecaafb7bSJinzhou Su  * Software is furnished to do so, subject to the following conditions:
10ecaafb7bSJinzhou Su  *
11ecaafb7bSJinzhou Su  * The above copyright notice and this permission notice shall be included in
12ecaafb7bSJinzhou Su  * all copies or substantial portions of the Software.
13ecaafb7bSJinzhou Su  *
14ecaafb7bSJinzhou Su  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15ecaafb7bSJinzhou Su  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16ecaafb7bSJinzhou Su  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17ecaafb7bSJinzhou Su  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18ecaafb7bSJinzhou Su  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ecaafb7bSJinzhou Su  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20ecaafb7bSJinzhou Su  * OTHER DEALINGS IN THE SOFTWARE.
21ecaafb7bSJinzhou Su  *
22ecaafb7bSJinzhou Su  *
23ecaafb7bSJinzhou Su  */
24ecaafb7bSJinzhou Su #include <linux/debugfs.h>
25ecaafb7bSJinzhou Su #include <linux/pm_runtime.h>
26ecaafb7bSJinzhou Su 
27ecaafb7bSJinzhou Su #include "amdgpu.h"
28ecaafb7bSJinzhou Su #include "amdgpu_securedisplay.h"
29ecaafb7bSJinzhou Su 
30ecaafb7bSJinzhou Su /**
31ecaafb7bSJinzhou Su  * DOC: AMDGPU SECUREDISPLAY debugfs test interface
32ecaafb7bSJinzhou Su  *
33ecaafb7bSJinzhou Su  * how to use?
34ecaafb7bSJinzhou Su  * echo opcode <value> > <debugfs_dir>/dri/xxx/securedisplay_test
35ecaafb7bSJinzhou Su  * eg. echo 1 > <debugfs_dir>/dri/xxx/securedisplay_test
36ecaafb7bSJinzhou Su  * eg. echo 2 phy_id > <debugfs_dir>/dri/xxx/securedisplay_test
37ecaafb7bSJinzhou Su  *
38ecaafb7bSJinzhou Su  * opcode:
39ecaafb7bSJinzhou Su  * 1:Query whether TA is responding used only for validation pupose
40ecaafb7bSJinzhou Su  * 2: Send region of Interest and CRC value to I2C. (uint32)phy_id is
41ecaafb7bSJinzhou Su  * send to determine which DIO scratch register should be used to get
42ecaafb7bSJinzhou Su  * ROI and receive i2c_buf as the output.
43ecaafb7bSJinzhou Su  *
44ecaafb7bSJinzhou Su  * You can refer more detail from header file ta_securedisplay_if.h
45ecaafb7bSJinzhou Su  *
46ecaafb7bSJinzhou Su  */
47ecaafb7bSJinzhou Su 
psp_securedisplay_parse_resp_status(struct psp_context * psp,enum ta_securedisplay_status status)48ecaafb7bSJinzhou Su void psp_securedisplay_parse_resp_status(struct psp_context *psp,
49ecaafb7bSJinzhou Su 	enum ta_securedisplay_status status)
50ecaafb7bSJinzhou Su {
51ecaafb7bSJinzhou Su 	switch (status) {
52ecaafb7bSJinzhou Su 	case TA_SECUREDISPLAY_STATUS__SUCCESS:
53ecaafb7bSJinzhou Su 		break;
54ecaafb7bSJinzhou Su 	case TA_SECUREDISPLAY_STATUS__GENERIC_FAILURE:
55ecaafb7bSJinzhou Su 		dev_err(psp->adev->dev, "Secure display: Generic Failure.");
56ecaafb7bSJinzhou Su 		break;
57ecaafb7bSJinzhou Su 	case TA_SECUREDISPLAY_STATUS__INVALID_PARAMETER:
58ecaafb7bSJinzhou Su 		dev_err(psp->adev->dev, "Secure display: Invalid Parameter.");
59ecaafb7bSJinzhou Su 		break;
60ecaafb7bSJinzhou Su 	case TA_SECUREDISPLAY_STATUS__NULL_POINTER:
61ecaafb7bSJinzhou Su 		dev_err(psp->adev->dev, "Secure display: Null Pointer.");
62ecaafb7bSJinzhou Su 		break;
63ecaafb7bSJinzhou Su 	case TA_SECUREDISPLAY_STATUS__I2C_WRITE_ERROR:
64ecaafb7bSJinzhou Su 		dev_err(psp->adev->dev, "Secure display: Failed to write to I2C.");
65ecaafb7bSJinzhou Su 		break;
66ecaafb7bSJinzhou Su 	case TA_SECUREDISPLAY_STATUS__READ_DIO_SCRATCH_ERROR:
67ecaafb7bSJinzhou Su 		dev_err(psp->adev->dev, "Secure display: Failed to Read DIO Scratch Register.");
68ecaafb7bSJinzhou Su 		break;
69ecaafb7bSJinzhou Su 	case TA_SECUREDISPLAY_STATUS__READ_CRC_ERROR:
70ecaafb7bSJinzhou Su 		dev_err(psp->adev->dev, "Secure display: Failed to Read CRC");
71ecaafb7bSJinzhou Su 		break;
721c7b0adaSJinzhou Su 	case TA_SECUREDISPLAY_STATUS__I2C_INIT_ERROR:
731c7b0adaSJinzhou Su 		dev_err(psp->adev->dev, "Secure display: Failed to initialize I2C.");
741c7b0adaSJinzhou Su 		break;
75ecaafb7bSJinzhou Su 	default:
76ecaafb7bSJinzhou Su 		dev_err(psp->adev->dev, "Secure display: Failed to parse status: %d\n", status);
77ecaafb7bSJinzhou Su 	}
78ecaafb7bSJinzhou Su }
79ecaafb7bSJinzhou Su 
psp_prep_securedisplay_cmd_buf(struct psp_context * psp,struct ta_securedisplay_cmd ** cmd,enum ta_securedisplay_command command_id)80f6e856e7SAaron Liu void psp_prep_securedisplay_cmd_buf(struct psp_context *psp, struct ta_securedisplay_cmd **cmd,
81ecaafb7bSJinzhou Su 	enum ta_securedisplay_command command_id)
82ecaafb7bSJinzhou Su {
83f6e856e7SAaron Liu 	*cmd = (struct ta_securedisplay_cmd *)psp->securedisplay_context.context.mem_context.shared_buf;
84f6e856e7SAaron Liu 	memset(*cmd, 0, sizeof(struct ta_securedisplay_cmd));
85ecaafb7bSJinzhou Su 	(*cmd)->status = TA_SECUREDISPLAY_STATUS__GENERIC_FAILURE;
86ecaafb7bSJinzhou Su 	(*cmd)->cmd_id = command_id;
87ecaafb7bSJinzhou Su }
88ecaafb7bSJinzhou Su 
89195c41fbSJinzhou Su #if defined(CONFIG_DEBUG_FS)
90195c41fbSJinzhou Su 
amdgpu_securedisplay_debugfs_write(struct file * f,const char __user * buf,size_t size,loff_t * pos)91ecaafb7bSJinzhou Su static ssize_t amdgpu_securedisplay_debugfs_write(struct file *f, const char __user *buf,
92ecaafb7bSJinzhou Su 		size_t size, loff_t *pos)
93ecaafb7bSJinzhou Su {
94ecaafb7bSJinzhou Su 	struct amdgpu_device *adev = (struct amdgpu_device *)file_inode(f)->i_private;
95ecaafb7bSJinzhou Su 	struct psp_context *psp = &adev->psp;
96f6e856e7SAaron Liu 	struct ta_securedisplay_cmd *securedisplay_cmd;
97ecaafb7bSJinzhou Su 	struct drm_device *dev = adev_to_drm(adev);
98ecaafb7bSJinzhou Su 	uint32_t phy_id;
99ecaafb7bSJinzhou Su 	uint32_t op;
100ecaafb7bSJinzhou Su 	char str[64];
101ecaafb7bSJinzhou Su 	int ret;
102ecaafb7bSJinzhou Su 
103ecaafb7bSJinzhou Su 	if (*pos || size > sizeof(str) - 1)
104ecaafb7bSJinzhou Su 		return -EINVAL;
105ecaafb7bSJinzhou Su 
106ecaafb7bSJinzhou Su 	memset(str,  0, sizeof(str));
107ecaafb7bSJinzhou Su 	ret = copy_from_user(str, buf, size);
108ecaafb7bSJinzhou Su 	if (ret)
109ecaafb7bSJinzhou Su 		return -EFAULT;
110ecaafb7bSJinzhou Su 
111ecaafb7bSJinzhou Su 	ret = pm_runtime_get_sync(dev->dev);
112ecaafb7bSJinzhou Su 	if (ret < 0) {
113ecaafb7bSJinzhou Su 		pm_runtime_put_autosuspend(dev->dev);
114ecaafb7bSJinzhou Su 		return ret;
115ecaafb7bSJinzhou Su 	}
116ecaafb7bSJinzhou Su 
117ecaafb7bSJinzhou Su 	if (size < 3)
118ecaafb7bSJinzhou Su 		sscanf(str, "%u ", &op);
119ecaafb7bSJinzhou Su 	else
120ecaafb7bSJinzhou Su 		sscanf(str, "%u %u", &op, &phy_id);
121ecaafb7bSJinzhou Su 
122ecaafb7bSJinzhou Su 	switch (op) {
123ecaafb7bSJinzhou Su 	case 1:
1247117007eSAlan Liu 		mutex_lock(&psp->securedisplay_context.mutex);
125ecaafb7bSJinzhou Su 		psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
126ecaafb7bSJinzhou Su 			TA_SECUREDISPLAY_COMMAND__QUERY_TA);
127ecaafb7bSJinzhou Su 		ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__QUERY_TA);
128ecaafb7bSJinzhou Su 		if (!ret) {
129ecaafb7bSJinzhou Su 			if (securedisplay_cmd->status == TA_SECUREDISPLAY_STATUS__SUCCESS)
130ecaafb7bSJinzhou Su 				dev_info(adev->dev, "SECUREDISPLAY: query securedisplay TA ret is 0x%X\n",
131ecaafb7bSJinzhou Su 					securedisplay_cmd->securedisplay_out_message.query_ta.query_cmd_ret);
132ecaafb7bSJinzhou Su 			else
133ecaafb7bSJinzhou Su 				psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status);
134ecaafb7bSJinzhou Su 		}
1357117007eSAlan Liu 		mutex_unlock(&psp->securedisplay_context.mutex);
136ecaafb7bSJinzhou Su 		break;
137ecaafb7bSJinzhou Su 	case 2:
138*f71ef2bbSMa Jun 		if (size < 3 || phy_id >= TA_SECUREDISPLAY_MAX_PHY) {
139*f71ef2bbSMa Jun 			dev_err(adev->dev, "Invalid input: %s\n", str);
140*f71ef2bbSMa Jun 			return -EINVAL;
141*f71ef2bbSMa Jun 		}
1427117007eSAlan Liu 		mutex_lock(&psp->securedisplay_context.mutex);
143ecaafb7bSJinzhou Su 		psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
144ecaafb7bSJinzhou Su 			TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
145ecaafb7bSJinzhou Su 		securedisplay_cmd->securedisplay_in_message.send_roi_crc.phy_id = phy_id;
146ecaafb7bSJinzhou Su 		ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__SEND_ROI_CRC);
147ecaafb7bSJinzhou Su 		if (!ret) {
148ecaafb7bSJinzhou Su 			if (securedisplay_cmd->status == TA_SECUREDISPLAY_STATUS__SUCCESS) {
1499e76e7b2SArnd Bergmann 				dev_info(adev->dev, "SECUREDISPLAY: I2C buffer out put is: %*ph\n",
1509e76e7b2SArnd Bergmann 					 TA_SECUREDISPLAY_I2C_BUFFER_SIZE,
1519e76e7b2SArnd Bergmann 					 securedisplay_cmd->securedisplay_out_message.send_roi_crc.i2c_buf);
152ecaafb7bSJinzhou Su 			} else {
153ecaafb7bSJinzhou Su 				psp_securedisplay_parse_resp_status(psp, securedisplay_cmd->status);
154ecaafb7bSJinzhou Su 			}
155ecaafb7bSJinzhou Su 		}
1567117007eSAlan Liu 		mutex_unlock(&psp->securedisplay_context.mutex);
157ecaafb7bSJinzhou Su 		break;
158ecaafb7bSJinzhou Su 	default:
159ecaafb7bSJinzhou Su 		dev_err(adev->dev, "Invalid input: %s\n", str);
160ecaafb7bSJinzhou Su 	}
161ecaafb7bSJinzhou Su 
162ecaafb7bSJinzhou Su 	pm_runtime_mark_last_busy(dev->dev);
163ecaafb7bSJinzhou Su 	pm_runtime_put_autosuspend(dev->dev);
164ecaafb7bSJinzhou Su 
165ecaafb7bSJinzhou Su 	return size;
166ecaafb7bSJinzhou Su }
167ecaafb7bSJinzhou Su 
168ecaafb7bSJinzhou Su static const struct file_operations amdgpu_securedisplay_debugfs_ops = {
169ecaafb7bSJinzhou Su 	.owner = THIS_MODULE,
170ecaafb7bSJinzhou Su 	.read = NULL,
171ecaafb7bSJinzhou Su 	.write = amdgpu_securedisplay_debugfs_write,
172ecaafb7bSJinzhou Su 	.llseek = default_llseek
173ecaafb7bSJinzhou Su };
174ecaafb7bSJinzhou Su 
175195c41fbSJinzhou Su #endif
176195c41fbSJinzhou Su 
amdgpu_securedisplay_debugfs_init(struct amdgpu_device * adev)177ecaafb7bSJinzhou Su void amdgpu_securedisplay_debugfs_init(struct amdgpu_device *adev)
178ecaafb7bSJinzhou Su {
179ecaafb7bSJinzhou Su #if defined(CONFIG_DEBUG_FS)
180ecaafb7bSJinzhou Su 
181ce97f37bSCandice Li 	if (!adev->psp.securedisplay_context.context.initialized)
182ecaafb7bSJinzhou Su 		return;
183ecaafb7bSJinzhou Su 
184ecaafb7bSJinzhou Su 	debugfs_create_file("securedisplay_test", S_IWUSR, adev_to_drm(adev)->primary->debugfs_root,
185ecaafb7bSJinzhou Su 				adev, &amdgpu_securedisplay_debugfs_ops);
186ecaafb7bSJinzhou Su #endif
187ecaafb7bSJinzhou Su }
188