1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Mailbox interface for Wilco Embedded Controller 4 * 5 * Copyright 2018 Google LLC 6 * 7 * The Wilco EC is similar to a typical ChromeOS embedded controller. 8 * It uses the same MEC based low-level communication and a similar 9 * protocol, but with some important differences. The EC firmware does 10 * not support the same mailbox commands so it is not registered as a 11 * cros_ec device type. 12 * 13 * Most messages follow a standard format, but there are some exceptions 14 * and an interface is provided to do direct/raw transactions that do not 15 * make assumptions about byte placement. 16 */ 17 18 #include <linux/delay.h> 19 #include <linux/device.h> 20 #include <linux/io.h> 21 #include <linux/platform_data/wilco-ec.h> 22 #include <linux/platform_device.h> 23 24 #include "../cros_ec_lpc_mec.h" 25 26 /* Version of mailbox interface */ 27 #define EC_MAILBOX_VERSION 0 28 29 /* Command to start mailbox transaction */ 30 #define EC_MAILBOX_START_COMMAND 0xda 31 32 /* Version of EC protocol */ 33 #define EC_MAILBOX_PROTO_VERSION 3 34 35 /* Number of header bytes to be counted as data bytes */ 36 #define EC_MAILBOX_DATA_EXTRA 2 37 38 /* Maximum timeout */ 39 #define EC_MAILBOX_TIMEOUT HZ 40 41 /* EC response flags */ 42 #define EC_CMDR_DATA BIT(0) /* Data ready for host to read */ 43 #define EC_CMDR_PENDING BIT(1) /* Write pending to EC */ 44 #define EC_CMDR_BUSY BIT(2) /* EC is busy processing a command */ 45 #define EC_CMDR_CMD BIT(3) /* Last host write was a command */ 46 47 /** 48 * wilco_ec_response_timed_out() - Wait for EC response. 49 * @ec: EC device. 50 * 51 * Return: true if EC timed out, false if EC did not time out. 52 */ 53 static bool wilco_ec_response_timed_out(struct wilco_ec_device *ec) 54 { 55 unsigned long timeout = jiffies + EC_MAILBOX_TIMEOUT; 56 57 do { 58 if (!(inb(ec->io_command->start) & 59 (EC_CMDR_PENDING | EC_CMDR_BUSY))) 60 return false; 61 usleep_range(100, 200); 62 } while (time_before(jiffies, timeout)); 63 64 return true; 65 } 66 67 /** 68 * wilco_ec_checksum() - Compute 8-bit checksum over data range. 69 * @data: Data to checksum. 70 * @size: Number of bytes to checksum. 71 * 72 * Return: 8-bit checksum of provided data. 73 */ 74 static u8 wilco_ec_checksum(const void *data, size_t size) 75 { 76 u8 *data_bytes = (u8 *)data; 77 u8 checksum = 0; 78 size_t i; 79 80 for (i = 0; i < size; i++) 81 checksum += data_bytes[i]; 82 83 return checksum; 84 } 85 86 /** 87 * wilco_ec_prepare() - Prepare the request structure for the EC. 88 * @msg: EC message with request information. 89 * @rq: EC request structure to fill. 90 */ 91 static void wilco_ec_prepare(struct wilco_ec_message *msg, 92 struct wilco_ec_request *rq) 93 { 94 memset(rq, 0, sizeof(*rq)); 95 96 /* Handle messages without trimming bytes from the request */ 97 if (msg->request_size && msg->flags & WILCO_EC_FLAG_RAW_REQUEST) { 98 rq->reserved_raw = *(u8 *)msg->request_data; 99 msg->request_size--; 100 memmove(msg->request_data, msg->request_data + 1, 101 msg->request_size); 102 } 103 104 /* Fill in request packet */ 105 rq->struct_version = EC_MAILBOX_PROTO_VERSION; 106 rq->mailbox_id = msg->type; 107 rq->mailbox_version = EC_MAILBOX_VERSION; 108 rq->data_size = msg->request_size + EC_MAILBOX_DATA_EXTRA; 109 rq->command = msg->command; 110 111 /* Checksum header and data */ 112 rq->checksum = wilco_ec_checksum(rq, sizeof(*rq)); 113 rq->checksum += wilco_ec_checksum(msg->request_data, msg->request_size); 114 rq->checksum = -rq->checksum; 115 } 116 117 /** 118 * wilco_ec_transfer() - Perform actual data transfer. 119 * @ec: EC device. 120 * @msg: EC message data for request and response. 121 * @rq: Filled in request structure 122 * 123 * Context: ec->mailbox_lock should be held while using this function. 124 * Return: number of bytes received or negative error code on failure. 125 */ 126 static int wilco_ec_transfer(struct wilco_ec_device *ec, 127 struct wilco_ec_message *msg, 128 struct wilco_ec_request *rq) 129 { 130 struct wilco_ec_response *rs; 131 u8 checksum; 132 u8 flag; 133 size_t size; 134 135 /* Write request header, then data */ 136 cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, 0, sizeof(*rq), (u8 *)rq); 137 cros_ec_lpc_io_bytes_mec(MEC_IO_WRITE, sizeof(*rq), msg->request_size, 138 msg->request_data); 139 140 /* Start the command */ 141 outb(EC_MAILBOX_START_COMMAND, ec->io_command->start); 142 143 /* For some commands (eg shutdown) the EC will not respond, that's OK */ 144 if (msg->flags & WILCO_EC_FLAG_NO_RESPONSE) { 145 dev_dbg(ec->dev, "EC does not respond to this command\n"); 146 return 0; 147 } 148 149 /* Wait for it to complete */ 150 if (wilco_ec_response_timed_out(ec)) { 151 dev_dbg(ec->dev, "response timed out\n"); 152 return -ETIMEDOUT; 153 } 154 155 /* Check result */ 156 flag = inb(ec->io_data->start); 157 if (flag) { 158 dev_dbg(ec->dev, "bad response: 0x%02x\n", flag); 159 return -EIO; 160 } 161 162 if (msg->flags & WILCO_EC_FLAG_EXTENDED_DATA) 163 size = EC_MAILBOX_DATA_SIZE_EXTENDED; 164 else 165 size = EC_MAILBOX_DATA_SIZE; 166 167 /* Read back response */ 168 rs = ec->data_buffer; 169 checksum = cros_ec_lpc_io_bytes_mec(MEC_IO_READ, 0, 170 sizeof(*rs) + size, (u8 *)rs); 171 if (checksum) { 172 dev_dbg(ec->dev, "bad packet checksum 0x%02x\n", rs->checksum); 173 return -EBADMSG; 174 } 175 176 /* Check that the EC reported success */ 177 msg->result = rs->result; 178 if (msg->result) { 179 dev_dbg(ec->dev, "bad response: 0x%02x\n", msg->result); 180 return -EBADMSG; 181 } 182 183 /* Check the returned data size, skipping the header */ 184 if (rs->data_size != size) { 185 dev_dbg(ec->dev, "unexpected packet size (%u != %zu)", 186 rs->data_size, size); 187 return -EMSGSIZE; 188 } 189 190 /* Skip 1 response data byte unless specified */ 191 size = (msg->flags & WILCO_EC_FLAG_RAW_RESPONSE) ? 0 : 1; 192 if ((ssize_t) rs->data_size - size < msg->response_size) { 193 dev_dbg(ec->dev, "response data too short (%zd < %zu)", 194 (ssize_t) rs->data_size - size, msg->response_size); 195 return -EMSGSIZE; 196 } 197 198 /* Ignore response data bytes as requested */ 199 memcpy(msg->response_data, rs->data + size, msg->response_size); 200 201 /* Return actual amount of data received */ 202 return msg->response_size; 203 } 204 205 /** 206 * wilco_ec_mailbox() - Send EC request and receive EC response. 207 * @ec: EC device. 208 * @msg: EC message data for request and response. 209 * 210 * On entry msg->type, msg->flags, msg->command, msg->request_size, 211 * msg->response_size, and msg->request_data should all be filled in. 212 * 213 * On exit msg->result and msg->response_data will be filled. 214 * 215 * Return: number of bytes received or negative error code on failure. 216 */ 217 int wilco_ec_mailbox(struct wilco_ec_device *ec, struct wilco_ec_message *msg) 218 { 219 struct wilco_ec_request *rq; 220 int ret; 221 222 dev_dbg(ec->dev, "cmd=%02x type=%04x flags=%02x rslen=%zu rqlen=%zu\n", 223 msg->command, msg->type, msg->flags, msg->response_size, 224 msg->request_size); 225 226 mutex_lock(&ec->mailbox_lock); 227 /* Prepare request packet */ 228 rq = ec->data_buffer; 229 wilco_ec_prepare(msg, rq); 230 231 ret = wilco_ec_transfer(ec, msg, rq); 232 mutex_unlock(&ec->mailbox_lock); 233 234 return ret; 235 236 } 237 EXPORT_SYMBOL_GPL(wilco_ec_mailbox); 238