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