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 71 if (!pa_dev->vdata->cmdresp_reg || !pa_dev->vdata->cmdbuff_addr_lo_reg || 72 !pa_dev->vdata->cmdbuff_addr_hi_reg) 73 return -ENODEV; 74 75 cmd = psp->io_regs + pa_dev->vdata->cmdresp_reg; 76 lo = psp->io_regs + pa_dev->vdata->cmdbuff_addr_lo_reg; 77 hi = psp->io_regs + pa_dev->vdata->cmdbuff_addr_hi_reg; 78 79 mutex_lock(&pa_dev->mailbox_mutex); 80 81 if (check_recovery(cmd)) { 82 dev_dbg(psp->dev, "platform mailbox is in recovery\n"); 83 ret = -EBUSY; 84 goto unlock; 85 } 86 87 if (wait_cmd(cmd)) { 88 dev_dbg(psp->dev, "platform mailbox is not done processing command\n"); 89 ret = -EBUSY; 90 goto unlock; 91 } 92 93 /* 94 * Fill mailbox with address of command-response buffer, which will be 95 * used for sending i2c requests as well as reading status returned by 96 * PSP. Use physical address of buffer, since PSP will map this region. 97 */ 98 req_addr = __psp_pa(req); 99 iowrite32(lower_32_bits(req_addr), lo); 100 iowrite32(upper_32_bits(req_addr), hi); 101 102 print_hex_dump_debug("->psp ", DUMP_PREFIX_OFFSET, 16, 2, req, 103 req->header.payload_size, false); 104 105 /* Write command register to trigger processing */ 106 cmd_reg = FIELD_PREP(PSP_CMDRESP_CMD, msg); 107 iowrite32(cmd_reg, cmd); 108 109 if (wait_cmd(cmd)) { 110 ret = -ETIMEDOUT; 111 goto unlock; 112 } 113 114 /* Ensure it was triggered by this driver */ 115 if (ioread32(lo) != lower_32_bits(req_addr) || 116 ioread32(hi) != upper_32_bits(req_addr)) { 117 ret = -EBUSY; 118 goto unlock; 119 } 120 121 /* Store the status in request header for caller to investigate */ 122 cmd_reg = ioread32(cmd); 123 req->header.status = FIELD_GET(PSP_CMDRESP_STS, cmd_reg); 124 if (req->header.status) { 125 ret = -EIO; 126 goto unlock; 127 } 128 129 print_hex_dump_debug("<-psp ", DUMP_PREFIX_OFFSET, 16, 2, req, 130 req->header.payload_size, false); 131 132 ret = 0; 133 134 unlock: 135 mutex_unlock(&pa_dev->mailbox_mutex); 136 137 return ret; 138 } 139 EXPORT_SYMBOL_GPL(psp_send_platform_access_msg); 140 141 int psp_ring_platform_doorbell(int msg, u32 *result) 142 { 143 struct psp_device *psp = psp_get_master_device(); 144 struct psp_platform_access_device *pa_dev; 145 u32 __iomem *button, *cmd; 146 int ret, val; 147 148 if (!psp || !psp->platform_access_data) 149 return -ENODEV; 150 151 pa_dev = psp->platform_access_data; 152 button = psp->io_regs + pa_dev->vdata->doorbell_button_reg; 153 cmd = psp->io_regs + pa_dev->vdata->doorbell_cmd_reg; 154 155 mutex_lock(&pa_dev->doorbell_mutex); 156 157 if (wait_cmd(cmd)) { 158 dev_err(psp->dev, "doorbell command not done processing\n"); 159 ret = -EBUSY; 160 goto unlock; 161 } 162 163 iowrite32(FIELD_PREP(DOORBELL_CMDRESP_STS, msg), cmd); 164 iowrite32(PSP_DRBL_RING, button); 165 166 if (wait_cmd(cmd)) { 167 ret = -ETIMEDOUT; 168 goto unlock; 169 } 170 171 val = FIELD_GET(DOORBELL_CMDRESP_STS, ioread32(cmd)); 172 if (val) { 173 if (result) 174 *result = val; 175 ret = -EIO; 176 goto unlock; 177 } 178 179 ret = 0; 180 unlock: 181 mutex_unlock(&pa_dev->doorbell_mutex); 182 183 return ret; 184 } 185 EXPORT_SYMBOL_GPL(psp_ring_platform_doorbell); 186 187 void platform_access_dev_destroy(struct psp_device *psp) 188 { 189 struct psp_platform_access_device *pa_dev = psp->platform_access_data; 190 191 if (!pa_dev) 192 return; 193 194 mutex_destroy(&pa_dev->mailbox_mutex); 195 mutex_destroy(&pa_dev->doorbell_mutex); 196 psp->platform_access_data = NULL; 197 } 198 199 int platform_access_dev_init(struct psp_device *psp) 200 { 201 struct device *dev = psp->dev; 202 struct psp_platform_access_device *pa_dev; 203 204 pa_dev = devm_kzalloc(dev, sizeof(*pa_dev), GFP_KERNEL); 205 if (!pa_dev) 206 return -ENOMEM; 207 208 psp->platform_access_data = pa_dev; 209 pa_dev->psp = psp; 210 pa_dev->dev = dev; 211 212 pa_dev->vdata = (struct platform_access_vdata *)psp->vdata->platform_access; 213 214 mutex_init(&pa_dev->mailbox_mutex); 215 mutex_init(&pa_dev->doorbell_mutex); 216 217 dev_dbg(dev, "platform access enabled\n"); 218 219 return 0; 220 } 221