1 /* 2 * Chromium OS cros_ec driver - LPC interface 3 * 4 * Copyright (c) 2012 The Chromium OS Authors. 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 /* 10 * The Matrix Keyboard Protocol driver handles talking to the keyboard 11 * controller chip. Mostly this is for keyboard functions, but some other 12 * things have slipped in, so we provide generic services to talk to the 13 * KBC. 14 */ 15 16 #include <common.h> 17 #include <command.h> 18 #include <cros_ec.h> 19 #include <asm/io.h> 20 21 #ifdef DEBUG_TRACE 22 #define debug_trace(fmt, b...) debug(fmt, ##b) 23 #else 24 #define debug_trace(fmt, b...) 25 #endif 26 27 static int wait_for_sync(struct cros_ec_dev *dev) 28 { 29 unsigned long start; 30 31 start = get_timer(0); 32 while (inb(EC_LPC_ADDR_HOST_CMD) & EC_LPC_STATUS_BUSY_MASK) { 33 if (get_timer(start) > 1000) { 34 debug("%s: Timeout waiting for CROS_EC sync\n", 35 __func__); 36 return -1; 37 } 38 } 39 40 return 0; 41 } 42 43 /** 44 * Send a command to a LPC CROS_EC device and return the reply. 45 * 46 * The device's internal input/output buffers are used. 47 * 48 * @param dev CROS_EC device 49 * @param cmd Command to send (EC_CMD_...) 50 * @param cmd_version Version of command to send (EC_VER_...) 51 * @param dout Output data (may be NULL If dout_len=0) 52 * @param dout_len Size of output data in bytes 53 * @param dinp Place to put pointer to response data 54 * @param din_len Maximum size of response in bytes 55 * @return number of bytes in response, or -1 on error 56 */ 57 static int old_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, 58 const uint8_t *dout, int dout_len, 59 uint8_t **dinp, int din_len) 60 { 61 int ret, i; 62 63 if (dout_len > EC_OLD_PARAM_SIZE) { 64 debug("%s: Cannot send %d bytes\n", __func__, dout_len); 65 return -1; 66 } 67 68 if (din_len > EC_OLD_PARAM_SIZE) { 69 debug("%s: Cannot receive %d bytes\n", __func__, din_len); 70 return -1; 71 } 72 73 if (wait_for_sync(dev)) { 74 debug("%s: Timeout waiting ready\n", __func__); 75 return -1; 76 } 77 78 debug_trace("cmd: %02x, ", cmd); 79 for (i = 0; i < dout_len; i++) { 80 debug_trace("%02x ", dout[i]); 81 outb(dout[i], EC_LPC_ADDR_OLD_PARAM + i); 82 } 83 outb(cmd, EC_LPC_ADDR_HOST_CMD); 84 debug_trace("\n"); 85 86 if (wait_for_sync(dev)) { 87 debug("%s: Timeout waiting ready\n", __func__); 88 return -1; 89 } 90 91 ret = inb(EC_LPC_ADDR_HOST_DATA); 92 if (ret) { 93 debug("%s: CROS_EC result code %d\n", __func__, ret); 94 return -ret; 95 } 96 97 debug_trace("resp: %02x, ", ret); 98 for (i = 0; i < din_len; i++) { 99 dev->din[i] = inb(EC_LPC_ADDR_OLD_PARAM + i); 100 debug_trace("%02x ", dev->din[i]); 101 } 102 debug_trace("\n"); 103 *dinp = dev->din; 104 105 return din_len; 106 } 107 108 int cros_ec_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, 109 const uint8_t *dout, int dout_len, 110 uint8_t **dinp, int din_len) 111 { 112 const int cmd_addr = EC_LPC_ADDR_HOST_CMD; 113 const int data_addr = EC_LPC_ADDR_HOST_DATA; 114 const int args_addr = EC_LPC_ADDR_HOST_ARGS; 115 const int param_addr = EC_LPC_ADDR_HOST_PARAM; 116 117 struct ec_lpc_host_args args; 118 uint8_t *d; 119 int csum; 120 int i; 121 122 /* Fall back to old-style command interface if args aren't supported */ 123 if (!dev->cmd_version_is_supported) 124 return old_lpc_command(dev, cmd, dout, dout_len, dinp, 125 din_len); 126 127 if (dout_len > EC_HOST_PARAM_SIZE) { 128 debug("%s: Cannot send %d bytes\n", __func__, dout_len); 129 return -1; 130 } 131 132 /* Fill in args */ 133 args.flags = EC_HOST_ARGS_FLAG_FROM_HOST; 134 args.command_version = cmd_version; 135 args.data_size = dout_len; 136 137 /* Calculate checksum */ 138 csum = cmd + args.flags + args.command_version + args.data_size; 139 for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++) 140 csum += *d; 141 142 args.checksum = (uint8_t)csum; 143 144 if (wait_for_sync(dev)) { 145 debug("%s: Timeout waiting ready\n", __func__); 146 return -1; 147 } 148 149 /* Write args */ 150 for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++) 151 outb(*d, args_addr + i); 152 153 /* Write data, if any */ 154 debug_trace("cmd: %02x, ver: %02x", cmd, cmd_version); 155 for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++) { 156 outb(*d, param_addr + i); 157 debug_trace("%02x ", *d); 158 } 159 160 outb(cmd, cmd_addr); 161 debug_trace("\n"); 162 163 if (wait_for_sync(dev)) { 164 debug("%s: Timeout waiting for response\n", __func__); 165 return -1; 166 } 167 168 /* Check result */ 169 i = inb(data_addr); 170 if (i) { 171 debug("%s: CROS_EC result code %d\n", __func__, i); 172 return -i; 173 } 174 175 /* Read back args */ 176 for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++) 177 *d = inb(args_addr + i); 178 179 /* 180 * If EC didn't modify args flags, then somehow we sent a new-style 181 * command to an old EC, which means it would have read its params 182 * from the wrong place. 183 */ 184 if (!(args.flags & EC_HOST_ARGS_FLAG_TO_HOST)) { 185 debug("%s: CROS_EC protocol mismatch\n", __func__); 186 return -EC_RES_INVALID_RESPONSE; 187 } 188 189 if (args.data_size > din_len) { 190 debug("%s: CROS_EC returned too much data %d > %d\n", 191 __func__, args.data_size, din_len); 192 return -EC_RES_INVALID_RESPONSE; 193 } 194 195 /* Read data, if any */ 196 for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++) { 197 *d = inb(param_addr + i); 198 debug_trace("%02x ", *d); 199 } 200 debug_trace("\n"); 201 202 /* Verify checksum */ 203 csum = cmd + args.flags + args.command_version + args.data_size; 204 for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++) 205 csum += *d; 206 207 if (args.checksum != (uint8_t)csum) { 208 debug("%s: CROS_EC response has invalid checksum\n", __func__); 209 return -EC_RES_INVALID_CHECKSUM; 210 } 211 *dinp = dev->din; 212 213 /* Return actual amount of data received */ 214 return args.data_size; 215 } 216 217 /** 218 * Initialize LPC protocol. 219 * 220 * @param dev CROS_EC device 221 * @param blob Device tree blob 222 * @return 0 if ok, -1 on error 223 */ 224 int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob) 225 { 226 int byte, i; 227 228 /* See if we can find an EC at the other end */ 229 byte = 0xff; 230 byte &= inb(EC_LPC_ADDR_HOST_CMD); 231 byte &= inb(EC_LPC_ADDR_HOST_DATA); 232 for (i = 0; i < EC_HOST_PARAM_SIZE && (byte == 0xff); i++) 233 byte &= inb(EC_LPC_ADDR_HOST_PARAM + i); 234 if (byte == 0xff) { 235 debug("%s: CROS_EC device not found on LPC bus\n", 236 __func__); 237 return -1; 238 } 239 240 return 0; 241 } 242 243 /* 244 * Test if LPC command args are supported. 245 * 246 * The cheapest way to do this is by looking for the memory-mapped 247 * flag. This is faster than sending a new-style 'hello' command and 248 * seeing whether the EC sets the EC_HOST_ARGS_FLAG_FROM_HOST flag 249 * in args when it responds. 250 */ 251 int cros_ec_lpc_check_version(struct cros_ec_dev *dev) 252 { 253 if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) == 'E' && 254 inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) 255 == 'C' && 256 (inb(EC_LPC_ADDR_MEMMAP + 257 EC_MEMMAP_HOST_CMD_FLAGS) & 258 EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED)) { 259 dev->cmd_version_is_supported = 1; 260 } else { 261 /* We are going to use the old IO ports */ 262 dev->cmd_version_is_supported = 0; 263 } 264 debug("lpc: version %s\n", dev->cmd_version_is_supported ? 265 "new" : "old"); 266 267 return 0; 268 } 269