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