1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * AMD Platform Security Processor (PSP) Platform Access interface
4  *
5  * Copyright (C) 2023 Advanced Micro Devices, Inc.
6  *
7  * Author: Mario Limonciello <mario.limonciello@amd.com>
8  *
9  * Some of this code is adapted from drivers/i2c/busses/i2c-designware-amdpsp.c
10  * developed by Jan Dabros <jsd@semihalf.com> and Copyright (C) 2022 Google Inc.
11  *
12  */
13 
14 #include <linux/bitfield.h>
15 #include <linux/errno.h>
16 #include <linux/iopoll.h>
17 #include <linux/mutex.h>
18 
19 #include "platform-access.h"
20 
21 #define PSP_CMD_TIMEOUT_US	(500 * USEC_PER_MSEC)
22 #define DOORBELL_CMDRESP_STS	GENMASK(7, 0)
23 
24 /* Recovery field should be equal 0 to start sending commands */
25 static int check_recovery(u32 __iomem *cmd)
26 {
27 	return FIELD_GET(PSP_CMDRESP_RECOVERY, ioread32(cmd));
28 }
29 
30 static int wait_cmd(u32 __iomem *cmd)
31 {
32 	u32 tmp, expected;
33 
34 	/* Expect mbox_cmd to be cleared and ready bit to be set by PSP */
35 	expected = FIELD_PREP(PSP_CMDRESP_RESP, 1);
36 
37 	/*
38 	 * Check for readiness of PSP mailbox in a tight loop in order to
39 	 * process further as soon as command was consumed.
40 	 */
41 	return readl_poll_timeout(cmd, tmp, (tmp & expected), 0,
42 				  PSP_CMD_TIMEOUT_US);
43 }
44 
45 int psp_check_platform_access_status(void)
46 {
47 	struct psp_device *psp = psp_get_master_device();
48 
49 	if (!psp || !psp->platform_access_data)
50 		return -ENODEV;
51 
52 	return 0;
53 }
54 EXPORT_SYMBOL(psp_check_platform_access_status);
55 
56 int psp_send_platform_access_msg(enum psp_platform_access_msg msg,
57 				 struct psp_request *req)
58 {
59 	struct psp_device *psp = psp_get_master_device();
60 	u32 __iomem *cmd, *lo, *hi;
61 	struct psp_platform_access_device *pa_dev;
62 	phys_addr_t req_addr;
63 	u32 cmd_reg;
64 	int ret;
65 
66 	if (!psp || !psp->platform_access_data)
67 		return -ENODEV;
68 
69 	pa_dev = psp->platform_access_data;
70 	cmd = psp->io_regs + pa_dev->vdata->cmdresp_reg;
71 	lo = psp->io_regs + pa_dev->vdata->cmdbuff_addr_lo_reg;
72 	hi = psp->io_regs + pa_dev->vdata->cmdbuff_addr_hi_reg;
73 
74 	mutex_lock(&pa_dev->mailbox_mutex);
75 
76 	if (check_recovery(cmd)) {
77 		dev_dbg(psp->dev, "platform mailbox is in recovery\n");
78 		ret = -EBUSY;
79 		goto unlock;
80 	}
81 
82 	if (wait_cmd(cmd)) {
83 		dev_dbg(psp->dev, "platform mailbox is not done processing command\n");
84 		ret = -EBUSY;
85 		goto unlock;
86 	}
87 
88 	/*
89 	 * Fill mailbox with address of command-response buffer, which will be
90 	 * used for sending i2c requests as well as reading status returned by
91 	 * PSP. Use physical address of buffer, since PSP will map this region.
92 	 */
93 	req_addr = __psp_pa(req);
94 	iowrite32(lower_32_bits(req_addr), lo);
95 	iowrite32(upper_32_bits(req_addr), hi);
96 
97 	print_hex_dump_debug("->psp ", DUMP_PREFIX_OFFSET, 16, 2, req,
98 			     req->header.payload_size, false);
99 
100 	/* Write command register to trigger processing */
101 	cmd_reg = FIELD_PREP(PSP_CMDRESP_CMD, msg);
102 	iowrite32(cmd_reg, cmd);
103 
104 	if (wait_cmd(cmd)) {
105 		ret = -ETIMEDOUT;
106 		goto unlock;
107 	}
108 
109 	/* Ensure it was triggered by this driver */
110 	if (ioread32(lo) != lower_32_bits(req_addr) ||
111 	    ioread32(hi) != upper_32_bits(req_addr)) {
112 		ret = -EBUSY;
113 		goto unlock;
114 	}
115 
116 	/* Store the status in request header for caller to investigate */
117 	cmd_reg = ioread32(cmd);
118 	req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg);
119 	if (req->header.status) {
120 		ret = -EIO;
121 		goto unlock;
122 	}
123 
124 	print_hex_dump_debug("<-psp ", DUMP_PREFIX_OFFSET, 16, 2, req,
125 			     req->header.payload_size, false);
126 
127 	ret = 0;
128 
129 unlock:
130 	mutex_unlock(&pa_dev->mailbox_mutex);
131 
132 	return ret;
133 }
134 EXPORT_SYMBOL_GPL(psp_send_platform_access_msg);
135 
136 int psp_ring_platform_doorbell(int msg, u32 *result)
137 {
138 	struct psp_device *psp = psp_get_master_device();
139 	struct psp_platform_access_device *pa_dev;
140 	u32 __iomem *button, *cmd;
141 	int ret, val;
142 
143 	if (!psp || !psp->platform_access_data)
144 		return -ENODEV;
145 
146 	pa_dev = psp->platform_access_data;
147 	button = psp->io_regs + pa_dev->vdata->doorbell_button_reg;
148 	cmd = psp->io_regs + pa_dev->vdata->doorbell_cmd_reg;
149 
150 	mutex_lock(&pa_dev->doorbell_mutex);
151 
152 	if (wait_cmd(cmd)) {
153 		dev_err(psp->dev, "doorbell command not done processing\n");
154 		ret = -EBUSY;
155 		goto unlock;
156 	}
157 
158 	iowrite32(FIELD_PREP(DOORBELL_CMDRESP_STS, msg), cmd);
159 	iowrite32(PSP_DRBL_RING, button);
160 
161 	if (wait_cmd(cmd)) {
162 		ret = -ETIMEDOUT;
163 		goto unlock;
164 	}
165 
166 	val = FIELD_GET(DOORBELL_CMDRESP_STS, ioread32(cmd));
167 	if (val) {
168 		if (result)
169 			*result = val;
170 		ret = -EIO;
171 		goto unlock;
172 	}
173 
174 	ret = 0;
175 unlock:
176 	mutex_unlock(&pa_dev->doorbell_mutex);
177 
178 	return ret;
179 }
180 EXPORT_SYMBOL_GPL(psp_ring_platform_doorbell);
181 
182 void platform_access_dev_destroy(struct psp_device *psp)
183 {
184 	struct psp_platform_access_device *pa_dev = psp->platform_access_data;
185 
186 	if (!pa_dev)
187 		return;
188 
189 	mutex_destroy(&pa_dev->mailbox_mutex);
190 	mutex_destroy(&pa_dev->doorbell_mutex);
191 	psp->platform_access_data = NULL;
192 }
193 
194 int platform_access_dev_init(struct psp_device *psp)
195 {
196 	struct device *dev = psp->dev;
197 	struct psp_platform_access_device *pa_dev;
198 
199 	pa_dev = devm_kzalloc(dev, sizeof(*pa_dev), GFP_KERNEL);
200 	if (!pa_dev)
201 		return -ENOMEM;
202 
203 	psp->platform_access_data = pa_dev;
204 	pa_dev->psp = psp;
205 	pa_dev->dev = dev;
206 
207 	pa_dev->vdata = (struct platform_access_vdata *)psp->vdata->platform_access;
208 
209 	mutex_init(&pa_dev->mailbox_mutex);
210 	mutex_init(&pa_dev->doorbell_mutex);
211 
212 	dev_dbg(dev, "platform access enabled\n");
213 
214 	return 0;
215 }
216