blob: 9bf21053cf064e586020a8c11e0be63f384ee371 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
wdenkc6097192002-11-03 00:24:07 +00002/*
3 * (C) Copyright 2002 ELTEC Elektronik AG
4 * Frank Gottschling <fgottschling@eltec.de>
wdenkc6097192002-11-03 00:24:07 +00005 */
6
7/* i8042.c - Intel 8042 keyboard driver routines */
8
Simon Glass5d304832023-05-04 16:54:56 -06009#define LOG_CATEGORY UCLASS_KEYBOARD
10
Simon Glassfa0a42a2015-11-11 10:05:45 -070011#include <dm.h>
Simon Glass0af6e2d2019-08-01 09:46:52 -060012#include <env.h>
Simon Glassfa0a42a2015-11-11 10:05:45 -070013#include <errno.h>
wdenkc6097192002-11-03 00:24:07 +000014#include <i8042.h>
Simon Glasse1a77bb2015-11-11 10:05:41 -070015#include <input.h>
Simon Glassfa0a42a2015-11-11 10:05:45 -070016#include <keyboard.h>
Simon Glass0f2af882020-05-10 11:40:05 -060017#include <log.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060018#include <asm/global_data.h>
Simon Glasse1a77bb2015-11-11 10:05:41 -070019#include <asm/io.h>
Simon Glassdbd79542020-05-10 11:40:11 -060020#include <linux/delay.h>
wdenkc6097192002-11-03 00:24:07 +000021
Simon Glass708c8312015-11-11 10:05:46 -070022DECLARE_GLOBAL_DATA_PTR;
23
wdenkc6097192002-11-03 00:24:07 +000024/* defines */
Bin Mengbc823082015-08-24 01:00:05 -070025#define in8(p) inb(p)
26#define out8(p, v) outb(v, p)
wdenkc6097192002-11-03 00:24:07 +000027
Simon Glass708c8312015-11-11 10:05:46 -070028enum {
29 QUIRK_DUP_POR = 1 << 0,
30};
31
wdenkc6097192002-11-03 00:24:07 +000032/* locals */
Simon Glassfa0a42a2015-11-11 10:05:45 -070033struct i8042_kbd_priv {
34 bool extended; /* true if an extended keycode is expected next */
Simon Glass708c8312015-11-11 10:05:46 -070035 int quirks; /* quirks that we support */
Simon Glassfa0a42a2015-11-11 10:05:45 -070036};
wdenkc6097192002-11-03 00:24:07 +000037
Gabe Black76a5d322011-11-14 19:24:14 +000038static unsigned char ext_key_map[] = {
39 0x1c, /* keypad enter */
40 0x1d, /* right control */
41 0x35, /* keypad slash */
42 0x37, /* print screen */
43 0x38, /* right alt */
44 0x46, /* break */
45 0x47, /* editpad home */
46 0x48, /* editpad up */
47 0x49, /* editpad pgup */
48 0x4b, /* editpad left */
49 0x4d, /* editpad right */
50 0x4f, /* editpad end */
51 0x50, /* editpad dn */
52 0x51, /* editpad pgdn */
53 0x52, /* editpad ins */
54 0x53, /* editpad del */
55 0x00 /* map end */
56 };
wdenkc6097192002-11-03 00:24:07 +000057
Simon Glass5d304832023-05-04 16:54:56 -060058/**
59 * kbd_input_empty() - Wait until the keyboard is ready for a command
60 *
61 * Checks the IBF flag (input buffer full), waiting for it to indicate that
62 * any previous command has been processed.
63 *
64 * Return: true if ready, false if it timed out
65 */
Bin Mengc89f2512015-08-24 01:00:04 -070066static int kbd_input_empty(void)
67{
Bin Mengbc823082015-08-24 01:00:05 -070068 int kbd_timeout = KBD_TIMEOUT * 1000;
Bin Mengc89f2512015-08-24 01:00:04 -070069
Bin Mengbc823082015-08-24 01:00:05 -070070 while ((in8(I8042_STS_REG) & STATUS_IBF) && kbd_timeout--)
Bin Mengc89f2512015-08-24 01:00:04 -070071 udelay(1);
72
Bin Mengbc823082015-08-24 01:00:05 -070073 return kbd_timeout != -1;
Bin Mengc89f2512015-08-24 01:00:04 -070074}
75
Simon Glass5d304832023-05-04 16:54:56 -060076/**
77 * kbd_output_full() - Wait until the keyboard has data available
78 *
79 * Checks the OBF flag (output buffer full), waiting for it to indicate that
80 * a response to a previous command is available
81 */
Bin Mengbc823082015-08-24 01:00:05 -070082static int kbd_output_full(void)
Bin Mengc89f2512015-08-24 01:00:04 -070083{
Bin Mengbc823082015-08-24 01:00:05 -070084 int kbd_timeout = KBD_TIMEOUT * 1000;
Bin Mengc89f2512015-08-24 01:00:04 -070085
Bin Mengbc823082015-08-24 01:00:05 -070086 while (((in8(I8042_STS_REG) & STATUS_OBF) == 0) && kbd_timeout--)
Bin Mengc89f2512015-08-24 01:00:04 -070087 udelay(1);
88
Bin Mengbc823082015-08-24 01:00:05 -070089 return kbd_timeout != -1;
Bin Mengc89f2512015-08-24 01:00:04 -070090}
91
Simon Glassfa0a42a2015-11-11 10:05:45 -070092/**
93 * check_leds() - Check the keyboard LEDs and update them it needed
94 *
95 * @ret: Value to return
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010096 * Return: value of @ret
Simon Glassfa0a42a2015-11-11 10:05:45 -070097 */
98static int i8042_kbd_update_leds(struct udevice *dev, int leds)
Bin Mengc89f2512015-08-24 01:00:04 -070099{
100 kbd_input_empty();
Bin Mengbc823082015-08-24 01:00:05 -0700101 out8(I8042_DATA_REG, CMD_SET_KBD_LED);
Bin Mengc89f2512015-08-24 01:00:04 -0700102 kbd_input_empty();
Simon Glassfa0a42a2015-11-11 10:05:45 -0700103 out8(I8042_DATA_REG, leds & 0x7);
104
105 return 0;
Bin Mengc89f2512015-08-24 01:00:04 -0700106}
107
Simon Glass4b48eaf2015-10-18 21:17:19 -0600108static int kbd_write(int reg, int value)
Bin Mengc89f2512015-08-24 01:00:04 -0700109{
Simon Glass4b48eaf2015-10-18 21:17:19 -0600110 if (!kbd_input_empty())
Bin Mengef4d7852015-08-24 01:00:06 -0700111 return -1;
Simon Glass4b48eaf2015-10-18 21:17:19 -0600112 out8(reg, value);
Bin Mengc89f2512015-08-24 01:00:04 -0700113
Simon Glass4b48eaf2015-10-18 21:17:19 -0600114 return 0;
115}
116
117static int kbd_read(int reg)
118{
119 if (!kbd_output_full())
Bin Mengef4d7852015-08-24 01:00:06 -0700120 return -1;
Simon Glass4b48eaf2015-10-18 21:17:19 -0600121
122 return in8(reg);
123}
124
125static int kbd_cmd_read(int cmd)
126{
127 if (kbd_write(I8042_CMD_REG, cmd))
Bin Mengc89f2512015-08-24 01:00:04 -0700128 return -1;
Simon Glass4b48eaf2015-10-18 21:17:19 -0600129
130 return kbd_read(I8042_DATA_REG);
131}
132
133static int kbd_cmd_write(int cmd, int data)
134{
135 if (kbd_write(I8042_CMD_REG, cmd))
Bin Mengc89f2512015-08-24 01:00:04 -0700136 return -1;
Simon Glass4b48eaf2015-10-18 21:17:19 -0600137
138 return kbd_write(I8042_DATA_REG, data);
139}
140
Simon Glass708c8312015-11-11 10:05:46 -0700141static int kbd_reset(int quirk)
Simon Glass4b48eaf2015-10-18 21:17:19 -0600142{
143 int config;
144
Simon Glass5d304832023-05-04 16:54:56 -0600145 if (!kbd_input_empty())
146 goto err;
147
Simon Glass4b48eaf2015-10-18 21:17:19 -0600148 /* controller self test */
149 if (kbd_cmd_read(CMD_SELF_TEST) != KBC_TEST_OK)
Simon Glass4f58bbc2015-10-18 21:17:20 -0600150 goto err;
Simon Glass4b48eaf2015-10-18 21:17:19 -0600151
152 /* keyboard reset */
153 if (kbd_write(I8042_DATA_REG, CMD_RESET_KBD) ||
154 kbd_read(I8042_DATA_REG) != KBD_ACK ||
155 kbd_read(I8042_DATA_REG) != KBD_POR)
Simon Glass4f58bbc2015-10-18 21:17:20 -0600156 goto err;
Bin Mengc89f2512015-08-24 01:00:04 -0700157
Simon Glass0a7fb2c2016-03-11 22:06:50 -0700158 if (kbd_write(I8042_DATA_REG, CMD_DRAIN_OUTPUT) ||
159 kbd_read(I8042_DATA_REG) != KBD_ACK)
160 goto err;
161
Bin Mengef4d7852015-08-24 01:00:06 -0700162 /* set AT translation and disable irq */
Simon Glass4b48eaf2015-10-18 21:17:19 -0600163 config = kbd_cmd_read(CMD_RD_CONFIG);
164 if (config == -1)
Simon Glass4f58bbc2015-10-18 21:17:20 -0600165 goto err;
Simon Glass4b48eaf2015-10-18 21:17:19 -0600166
Simon Glass708c8312015-11-11 10:05:46 -0700167 /* Sometimes get a second byte */
168 else if ((quirk & QUIRK_DUP_POR) && config == KBD_POR)
169 config = kbd_cmd_read(CMD_RD_CONFIG);
170
Tom Rini6515ffe2021-08-19 14:58:00 -0400171 config |= CFG_AT_TRANS;
172 config &= ~(CFG_KIRQ_EN | CFG_MIRQ_EN);
Simon Glass4b48eaf2015-10-18 21:17:19 -0600173 if (kbd_cmd_write(CMD_WR_CONFIG, config))
Simon Glass4f58bbc2015-10-18 21:17:20 -0600174 goto err;
Bin Mengc89f2512015-08-24 01:00:04 -0700175
Bin Mengef4d7852015-08-24 01:00:06 -0700176 /* enable keyboard */
Simon Glass4b48eaf2015-10-18 21:17:19 -0600177 if (kbd_write(I8042_CMD_REG, CMD_KBD_EN) ||
178 !kbd_input_empty())
Simon Glass4f58bbc2015-10-18 21:17:20 -0600179 goto err;
Bin Mengc89f2512015-08-24 01:00:04 -0700180
181 return 0;
Simon Glass4f58bbc2015-10-18 21:17:20 -0600182err:
183 debug("%s: Keyboard failure\n", __func__);
184 return -1;
Bin Mengc89f2512015-08-24 01:00:04 -0700185}
186
Gabe Black15bbe8d2011-11-14 20:18:12 +0000187static int kbd_controller_present(void)
188{
Bin Mengbc823082015-08-24 01:00:05 -0700189 return in8(I8042_STS_REG) != 0xff;
Gabe Black15bbe8d2011-11-14 20:18:12 +0000190}
191
Simon Glass5a6e8fd2018-11-23 21:29:38 -0700192/** Flush all buffer from keyboard controller to host*/
193static void i8042_flush(void)
Louis Yung-Chieh Lo46d579c2012-10-11 15:15:51 +0000194{
195 int timeout;
196
197 /*
Bin Mengbc823082015-08-24 01:00:05 -0700198 * The delay is to give the keyboard controller some time
199 * to fill the next byte.
Louis Yung-Chieh Lo46d579c2012-10-11 15:15:51 +0000200 */
201 while (1) {
Bin Mengbc823082015-08-24 01:00:05 -0700202 timeout = 100; /* wait for no longer than 100us */
203 while (timeout > 0 && !(in8(I8042_STS_REG) & STATUS_OBF)) {
Louis Yung-Chieh Lo46d579c2012-10-11 15:15:51 +0000204 udelay(1);
205 timeout--;
206 }
207
Bin Mengbc823082015-08-24 01:00:05 -0700208 /* Try to pull next byte if not timeout */
209 if (in8(I8042_STS_REG) & STATUS_OBF)
Louis Yung-Chieh Lo46d579c2012-10-11 15:15:51 +0000210 in8(I8042_DATA_REG);
211 else
212 break;
213 }
214}
215
Simon Glass5a6e8fd2018-11-23 21:29:38 -0700216/**
217 * Disables the keyboard so that key strokes no longer generate scancodes to
218 * the host.
219 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100220 * Return: 0 if ok, -1 if keyboard input was found while disabling
Simon Glass5a6e8fd2018-11-23 21:29:38 -0700221 */
222static int i8042_disable(void)
Louis Yung-Chieh Lo46d579c2012-10-11 15:15:51 +0000223{
224 if (kbd_input_empty() == 0)
225 return -1;
226
227 /* Disable keyboard */
Bin Mengbc823082015-08-24 01:00:05 -0700228 out8(I8042_CMD_REG, CMD_KBD_DIS);
Louis Yung-Chieh Lo46d579c2012-10-11 15:15:51 +0000229
230 if (kbd_input_empty() == 0)
231 return -1;
232
233 return 0;
234}
235
Simon Glasse1a77bb2015-11-11 10:05:41 -0700236static int i8042_kbd_check(struct input_config *input)
237{
Simon Glassfa0a42a2015-11-11 10:05:45 -0700238 struct i8042_kbd_priv *priv = dev_get_priv(input->dev);
239
Simon Glasse1a77bb2015-11-11 10:05:41 -0700240 if ((in8(I8042_STS_REG) & STATUS_OBF) == 0) {
241 return 0;
242 } else {
243 bool release = false;
244 int scan_code;
245 int i;
246
247 scan_code = in8(I8042_DATA_REG);
248 if (scan_code == 0xfa) {
249 return 0;
250 } else if (scan_code == 0xe0) {
Simon Glassfa0a42a2015-11-11 10:05:45 -0700251 priv->extended = true;
Simon Glasse1a77bb2015-11-11 10:05:41 -0700252 return 0;
253 }
254 if (scan_code & 0x80) {
255 scan_code &= 0x7f;
256 release = true;
257 }
Simon Glassfa0a42a2015-11-11 10:05:45 -0700258 if (priv->extended) {
259 priv->extended = false;
Simon Glasse1a77bb2015-11-11 10:05:41 -0700260 for (i = 0; ext_key_map[i]; i++) {
261 if (ext_key_map[i] == scan_code) {
262 scan_code = 0x60 + i;
263 break;
264 }
265 }
266 /* not found ? */
267 if (!ext_key_map[i])
268 return 0;
269 }
270
Simon Glassfa0a42a2015-11-11 10:05:45 -0700271 input_add_keycode(input, scan_code, release);
Simon Glasse1a77bb2015-11-11 10:05:41 -0700272 return 1;
273 }
274}
275
Bin Mengbc823082015-08-24 01:00:05 -0700276/* i8042_kbd_init - reset keyboard and init state flags */
Simon Glassfa0a42a2015-11-11 10:05:45 -0700277static int i8042_start(struct udevice *dev)
wdenkc6097192002-11-03 00:24:07 +0000278{
Simon Glassfa0a42a2015-11-11 10:05:45 -0700279 struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glass708c8312015-11-11 10:05:46 -0700280 struct i8042_kbd_priv *priv = dev_get_priv(dev);
Simon Glassfa0a42a2015-11-11 10:05:45 -0700281 struct input_config *input = &uc_priv->input;
Gabe Black76a5d322011-11-14 19:24:14 +0000282 int keymap, try;
283 char *penv;
Simon Glasse1a77bb2015-11-11 10:05:41 -0700284 int ret;
wdenkc6097192002-11-03 00:24:07 +0000285
Simon Glass5a6e8fd2018-11-23 21:29:38 -0700286 if (!kbd_controller_present()) {
Bin Mengbc823082015-08-24 01:00:05 -0700287 debug("i8042 keyboard controller is not present\n");
Simon Glassfa0a42a2015-11-11 10:05:45 -0700288 return -ENOENT;
Bin Mengbc823082015-08-24 01:00:05 -0700289 }
Gabe Black15bbe8d2011-11-14 20:18:12 +0000290
Gabe Black76a5d322011-11-14 19:24:14 +0000291 /* Init keyboard device (default US layout) */
292 keymap = KBD_US;
Simon Glass64b723f2017-08-03 12:22:12 -0600293 penv = env_get("keymap");
Gabe Black76a5d322011-11-14 19:24:14 +0000294 if (penv != NULL) {
295 if (strncmp(penv, "de", 3) == 0)
296 keymap = KBD_GER;
297 }
wdenkc6097192002-11-03 00:24:07 +0000298
Simon Glass708c8312015-11-11 10:05:46 -0700299 for (try = 0; kbd_reset(priv->quirks) != 0; try++) {
Simon Glass2915ad62015-10-18 21:17:21 -0600300 if (try >= KBD_RESET_TRIES)
301 return -1;
Gabe Black76a5d322011-11-14 19:24:14 +0000302 }
Bin Mengbc823082015-08-24 01:00:05 -0700303
Simon Glassfa0a42a2015-11-11 10:05:45 -0700304 ret = input_add_tables(input, keymap == KBD_GER);
Simon Glasse1a77bb2015-11-11 10:05:41 -0700305 if (ret)
306 return ret;
Simon Glasse1a77bb2015-11-11 10:05:41 -0700307
Simon Glassfa0a42a2015-11-11 10:05:45 -0700308 i8042_kbd_update_leds(dev, NORMAL);
309 debug("%s: started\n", __func__);
Simon Glass2915ad62015-10-18 21:17:21 -0600310
311 return 0;
wdenkc6097192002-11-03 00:24:07 +0000312}
313
Simon Glass5a6e8fd2018-11-23 21:29:38 -0700314static int i8042_kbd_remove(struct udevice *dev)
315{
316 if (i8042_disable())
317 log_debug("i8042_disable() failed. fine, continue.\n");
318 i8042_flush();
319
320 return 0;
321}
322
Simon Glasse1a77bb2015-11-11 10:05:41 -0700323/**
Simon Glassfa0a42a2015-11-11 10:05:45 -0700324 * Set up the i8042 keyboard. This is called by the stdio device handler
Bin Mengbc823082015-08-24 01:00:05 -0700325 *
Simon Glassfa0a42a2015-11-11 10:05:45 -0700326 * We want to do this init when the keyboard is actually used rather than
327 * at start-up, since keyboard input may not currently be selected.
328 *
329 * Once the keyboard starts there will be a period during which we must
330 * wait for the keyboard to init. We do this only when a key is first
331 * read - see kbd_wait_for_fifo_init().
332 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100333 * Return: 0 if ok, -ve on error
wdenkc6097192002-11-03 00:24:07 +0000334 */
Simon Glassfa0a42a2015-11-11 10:05:45 -0700335static int i8042_kbd_probe(struct udevice *dev)
wdenkc6097192002-11-03 00:24:07 +0000336{
Simon Glassfa0a42a2015-11-11 10:05:45 -0700337 struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
Simon Glass708c8312015-11-11 10:05:46 -0700338 struct i8042_kbd_priv *priv = dev_get_priv(dev);
Simon Glassfa0a42a2015-11-11 10:05:45 -0700339 struct stdio_dev *sdev = &uc_priv->sdev;
340 struct input_config *input = &uc_priv->input;
341 int ret;
wdenkc6097192002-11-03 00:24:07 +0000342
Simon Glassdd79d6e2017-01-17 16:52:55 -0700343 if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
Simon Glass708c8312015-11-11 10:05:46 -0700344 "intel,duplicate-por"))
345 priv->quirks |= QUIRK_DUP_POR;
346
Simon Glassfa0a42a2015-11-11 10:05:45 -0700347 /* Register the device. i8042_start() will be called soon */
348 input->dev = dev;
349 input->read_keys = i8042_kbd_check;
350 input_allow_repeats(input, true);
351 strcpy(sdev->name, "i8042-kbd");
352 ret = input_stdio_register(sdev);
353 if (ret) {
354 debug("%s: input_stdio_register() failed\n", __func__);
355 return ret;
356 }
357 debug("%s: ready\n", __func__);
wdenkc6097192002-11-03 00:24:07 +0000358
Simon Glassfa0a42a2015-11-11 10:05:45 -0700359 return 0;
Simon Glasse1a77bb2015-11-11 10:05:41 -0700360}
Bin Mengbc823082015-08-24 01:00:05 -0700361
Simon Glassfa0a42a2015-11-11 10:05:45 -0700362static const struct keyboard_ops i8042_kbd_ops = {
363 .start = i8042_start,
364 .update_leds = i8042_kbd_update_leds,
365};
wdenkc6097192002-11-03 00:24:07 +0000366
Simon Glassfa0a42a2015-11-11 10:05:45 -0700367static const struct udevice_id i8042_kbd_ids[] = {
368 { .compatible = "intel,i8042-keyboard" },
369 { }
370};
371
372U_BOOT_DRIVER(i8042_kbd) = {
373 .name = "i8042_kbd",
374 .id = UCLASS_KEYBOARD,
375 .of_match = i8042_kbd_ids,
376 .probe = i8042_kbd_probe,
Simon Glass5a6e8fd2018-11-23 21:29:38 -0700377 .remove = i8042_kbd_remove,
Simon Glassfa0a42a2015-11-11 10:05:45 -0700378 .ops = &i8042_kbd_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700379 .priv_auto = sizeof(struct i8042_kbd_priv),
Simon Glassfa0a42a2015-11-11 10:05:45 -0700380};