1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2002 ELTEC Elektronik AG 4 * Frank Gottschling <fgottschling@eltec.de> 5 */ 6 7 /* i8042.c - Intel 8042 keyboard driver routines */ 8 9 #include <common.h> 10 #include <dm.h> 11 #include <errno.h> 12 #include <i8042.h> 13 #include <input.h> 14 #include <keyboard.h> 15 #include <asm/io.h> 16 17 DECLARE_GLOBAL_DATA_PTR; 18 19 /* defines */ 20 #define in8(p) inb(p) 21 #define out8(p, v) outb(v, p) 22 23 enum { 24 QUIRK_DUP_POR = 1 << 0, 25 }; 26 27 /* locals */ 28 struct i8042_kbd_priv { 29 bool extended; /* true if an extended keycode is expected next */ 30 int quirks; /* quirks that we support */ 31 }; 32 33 static unsigned char ext_key_map[] = { 34 0x1c, /* keypad enter */ 35 0x1d, /* right control */ 36 0x35, /* keypad slash */ 37 0x37, /* print screen */ 38 0x38, /* right alt */ 39 0x46, /* break */ 40 0x47, /* editpad home */ 41 0x48, /* editpad up */ 42 0x49, /* editpad pgup */ 43 0x4b, /* editpad left */ 44 0x4d, /* editpad right */ 45 0x4f, /* editpad end */ 46 0x50, /* editpad dn */ 47 0x51, /* editpad pgdn */ 48 0x52, /* editpad ins */ 49 0x53, /* editpad del */ 50 0x00 /* map end */ 51 }; 52 53 static int kbd_input_empty(void) 54 { 55 int kbd_timeout = KBD_TIMEOUT * 1000; 56 57 while ((in8(I8042_STS_REG) & STATUS_IBF) && kbd_timeout--) 58 udelay(1); 59 60 return kbd_timeout != -1; 61 } 62 63 static int kbd_output_full(void) 64 { 65 int kbd_timeout = KBD_TIMEOUT * 1000; 66 67 while (((in8(I8042_STS_REG) & STATUS_OBF) == 0) && kbd_timeout--) 68 udelay(1); 69 70 return kbd_timeout != -1; 71 } 72 73 /** 74 * check_leds() - Check the keyboard LEDs and update them it needed 75 * 76 * @ret: Value to return 77 * @return value of @ret 78 */ 79 static int i8042_kbd_update_leds(struct udevice *dev, int leds) 80 { 81 kbd_input_empty(); 82 out8(I8042_DATA_REG, CMD_SET_KBD_LED); 83 kbd_input_empty(); 84 out8(I8042_DATA_REG, leds & 0x7); 85 86 return 0; 87 } 88 89 static int kbd_write(int reg, int value) 90 { 91 if (!kbd_input_empty()) 92 return -1; 93 out8(reg, value); 94 95 return 0; 96 } 97 98 static int kbd_read(int reg) 99 { 100 if (!kbd_output_full()) 101 return -1; 102 103 return in8(reg); 104 } 105 106 static int kbd_cmd_read(int cmd) 107 { 108 if (kbd_write(I8042_CMD_REG, cmd)) 109 return -1; 110 111 return kbd_read(I8042_DATA_REG); 112 } 113 114 static int kbd_cmd_write(int cmd, int data) 115 { 116 if (kbd_write(I8042_CMD_REG, cmd)) 117 return -1; 118 119 return kbd_write(I8042_DATA_REG, data); 120 } 121 122 static int kbd_reset(int quirk) 123 { 124 int config; 125 126 /* controller self test */ 127 if (kbd_cmd_read(CMD_SELF_TEST) != KBC_TEST_OK) 128 goto err; 129 130 /* keyboard reset */ 131 if (kbd_write(I8042_DATA_REG, CMD_RESET_KBD) || 132 kbd_read(I8042_DATA_REG) != KBD_ACK || 133 kbd_read(I8042_DATA_REG) != KBD_POR) 134 goto err; 135 136 if (kbd_write(I8042_DATA_REG, CMD_DRAIN_OUTPUT) || 137 kbd_read(I8042_DATA_REG) != KBD_ACK) 138 goto err; 139 140 /* set AT translation and disable irq */ 141 config = kbd_cmd_read(CMD_RD_CONFIG); 142 if (config == -1) 143 goto err; 144 145 /* Sometimes get a second byte */ 146 else if ((quirk & QUIRK_DUP_POR) && config == KBD_POR) 147 config = kbd_cmd_read(CMD_RD_CONFIG); 148 149 config |= CONFIG_AT_TRANS; 150 config &= ~(CONFIG_KIRQ_EN | CONFIG_MIRQ_EN); 151 if (kbd_cmd_write(CMD_WR_CONFIG, config)) 152 goto err; 153 154 /* enable keyboard */ 155 if (kbd_write(I8042_CMD_REG, CMD_KBD_EN) || 156 !kbd_input_empty()) 157 goto err; 158 159 return 0; 160 err: 161 debug("%s: Keyboard failure\n", __func__); 162 return -1; 163 } 164 165 static int kbd_controller_present(void) 166 { 167 return in8(I8042_STS_REG) != 0xff; 168 } 169 170 /* 171 * Implement a weak default function for boards that optionally 172 * need to skip the i8042 initialization. 173 * 174 * TODO(sjg@chromium.org): Use device tree for this? 175 */ 176 int __weak board_i8042_skip(void) 177 { 178 /* As default, don't skip */ 179 return 0; 180 } 181 182 void i8042_flush(void) 183 { 184 int timeout; 185 186 /* 187 * The delay is to give the keyboard controller some time 188 * to fill the next byte. 189 */ 190 while (1) { 191 timeout = 100; /* wait for no longer than 100us */ 192 while (timeout > 0 && !(in8(I8042_STS_REG) & STATUS_OBF)) { 193 udelay(1); 194 timeout--; 195 } 196 197 /* Try to pull next byte if not timeout */ 198 if (in8(I8042_STS_REG) & STATUS_OBF) 199 in8(I8042_DATA_REG); 200 else 201 break; 202 } 203 } 204 205 int i8042_disable(void) 206 { 207 if (kbd_input_empty() == 0) 208 return -1; 209 210 /* Disable keyboard */ 211 out8(I8042_CMD_REG, CMD_KBD_DIS); 212 213 if (kbd_input_empty() == 0) 214 return -1; 215 216 return 0; 217 } 218 219 static int i8042_kbd_check(struct input_config *input) 220 { 221 struct i8042_kbd_priv *priv = dev_get_priv(input->dev); 222 223 if ((in8(I8042_STS_REG) & STATUS_OBF) == 0) { 224 return 0; 225 } else { 226 bool release = false; 227 int scan_code; 228 int i; 229 230 scan_code = in8(I8042_DATA_REG); 231 if (scan_code == 0xfa) { 232 return 0; 233 } else if (scan_code == 0xe0) { 234 priv->extended = true; 235 return 0; 236 } 237 if (scan_code & 0x80) { 238 scan_code &= 0x7f; 239 release = true; 240 } 241 if (priv->extended) { 242 priv->extended = false; 243 for (i = 0; ext_key_map[i]; i++) { 244 if (ext_key_map[i] == scan_code) { 245 scan_code = 0x60 + i; 246 break; 247 } 248 } 249 /* not found ? */ 250 if (!ext_key_map[i]) 251 return 0; 252 } 253 254 input_add_keycode(input, scan_code, release); 255 return 1; 256 } 257 } 258 259 /* i8042_kbd_init - reset keyboard and init state flags */ 260 static int i8042_start(struct udevice *dev) 261 { 262 struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev); 263 struct i8042_kbd_priv *priv = dev_get_priv(dev); 264 struct input_config *input = &uc_priv->input; 265 int keymap, try; 266 char *penv; 267 int ret; 268 269 if (!kbd_controller_present() || board_i8042_skip()) { 270 debug("i8042 keyboard controller is not present\n"); 271 return -ENOENT; 272 } 273 274 /* Init keyboard device (default US layout) */ 275 keymap = KBD_US; 276 penv = env_get("keymap"); 277 if (penv != NULL) { 278 if (strncmp(penv, "de", 3) == 0) 279 keymap = KBD_GER; 280 } 281 282 for (try = 0; kbd_reset(priv->quirks) != 0; try++) { 283 if (try >= KBD_RESET_TRIES) 284 return -1; 285 } 286 287 ret = input_add_tables(input, keymap == KBD_GER); 288 if (ret) 289 return ret; 290 291 i8042_kbd_update_leds(dev, NORMAL); 292 debug("%s: started\n", __func__); 293 294 return 0; 295 } 296 297 /** 298 * Set up the i8042 keyboard. This is called by the stdio device handler 299 * 300 * We want to do this init when the keyboard is actually used rather than 301 * at start-up, since keyboard input may not currently be selected. 302 * 303 * Once the keyboard starts there will be a period during which we must 304 * wait for the keyboard to init. We do this only when a key is first 305 * read - see kbd_wait_for_fifo_init(). 306 * 307 * @return 0 if ok, -ve on error 308 */ 309 static int i8042_kbd_probe(struct udevice *dev) 310 { 311 struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev); 312 struct i8042_kbd_priv *priv = dev_get_priv(dev); 313 struct stdio_dev *sdev = &uc_priv->sdev; 314 struct input_config *input = &uc_priv->input; 315 int ret; 316 317 if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), 318 "intel,duplicate-por")) 319 priv->quirks |= QUIRK_DUP_POR; 320 321 /* Register the device. i8042_start() will be called soon */ 322 input->dev = dev; 323 input->read_keys = i8042_kbd_check; 324 input_allow_repeats(input, true); 325 strcpy(sdev->name, "i8042-kbd"); 326 ret = input_stdio_register(sdev); 327 if (ret) { 328 debug("%s: input_stdio_register() failed\n", __func__); 329 return ret; 330 } 331 debug("%s: ready\n", __func__); 332 333 return 0; 334 } 335 336 static const struct keyboard_ops i8042_kbd_ops = { 337 .start = i8042_start, 338 .update_leds = i8042_kbd_update_leds, 339 }; 340 341 static const struct udevice_id i8042_kbd_ids[] = { 342 { .compatible = "intel,i8042-keyboard" }, 343 { } 344 }; 345 346 U_BOOT_DRIVER(i8042_kbd) = { 347 .name = "i8042_kbd", 348 .id = UCLASS_KEYBOARD, 349 .of_match = i8042_kbd_ids, 350 .probe = i8042_kbd_probe, 351 .ops = &i8042_kbd_ops, 352 .priv_auto_alloc_size = sizeof(struct i8042_kbd_priv), 353 }; 354