aboutsummaryrefslogtreecommitdiffstats
path: root/roms/u-boot/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'roms/u-boot/drivers/input')
-rw-r--r--roms/u-boot/drivers/input/Kconfig85
-rw-r--r--roms/u-boot/drivers/input/Makefile17
-rw-r--r--roms/u-boot/drivers/input/cros_ec_keyb.c255
-rw-r--r--roms/u-boot/drivers/input/i8042.c362
-rw-r--r--roms/u-boot/drivers/input/input.c685
-rw-r--r--roms/u-boot/drivers/input/key_matrix.c190
-rw-r--r--roms/u-boot/drivers/input/keyboard-uclass.c91
-rw-r--r--roms/u-boot/drivers/input/tegra-kbc.c354
-rw-r--r--roms/u-boot/drivers/input/twl4030.c87
-rw-r--r--roms/u-boot/drivers/input/twl6030.c47
10 files changed, 2173 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/input/Kconfig b/roms/u-boot/drivers/input/Kconfig
new file mode 100644
index 000000000..a17e55e99
--- /dev/null
+++ b/roms/u-boot/drivers/input/Kconfig
@@ -0,0 +1,85 @@
+config INPUT
+ bool "Enable input subsystem"
+ depends on DM
+ default y
+
+config SPL_INPUT
+ bool "Enable input subsystem for SPL"
+ depends on SPL_DM
+
+config TPL_INPUT
+ bool "Enable input subsystem for TPL"
+ depends on TPL_DM
+
+config DM_KEYBOARD
+ bool "Enable driver model keyboard support"
+ depends on DM
+ help
+ This adds a uclass for keyboards and implements keyboard support
+ using driver model. The API is implemented by keyboard.h and
+ includes methods to start/stop the device, check for available
+ input and update LEDs if the keyboard has them.
+
+config SPL_DM_KEYBOARD
+ bool "Enable driver model keyboard support for SPL"
+ depends on SPL_DM
+ help
+ This adds a uclass for keyboards and implements keyboard support
+ using driver model. The API is implemented by keyboard.h and
+ includes methods to start/stop the device, check for available
+ input and update LEDs if the keyboard has them.
+
+config TPL_DM_KEYBOARD
+ bool "Enable driver model keyboard support for TPL"
+ depends on TPL_DM
+ help
+ This adds a uclass for keyboards and implements keyboard support
+ using driver model. The API is implemented by keyboard.h and
+ includes methods to start/stop the device, check for available
+ input and update LEDs if the keyboard has them.
+
+config CROS_EC_KEYB
+ bool "Enable Chrome OS EC keyboard support"
+ depends on INPUT
+ help
+ Most ARM Chromebooks use an EC to provide access to the keyboard.
+ Messages are used to request key scans from the EC and these are
+ then decoded into keys by this driver.
+
+config SPL_CROS_EC_KEYB
+ bool "Enable Chrome OS EC keyboard support in SPL"
+ depends on SPL_INPUT
+ help
+ Most ARM Chromebooks use an EC to provide access to the keyboard.
+ Messages are used to request key scans from the EC and these are
+ then decoded into keys by this driver.
+
+config TPL_CROS_EC_KEYB
+ bool "Enable Chrome OS EC keyboard support in TPL"
+ depends on TPL_INPUT
+ help
+ Most ARM Chromebooks use an EC to provide access to the keyboard.
+ Messages are used to request key scans from the EC and these are
+ then decoded into keys by this driver.
+
+config I8042_KEYB
+ bool "Enable Intel i8042 keyboard support"
+ depends on DM_KEYBOARD
+ default X86
+ help
+ This adds a driver for the i8042 keyboard controller, allowing the
+ keyboard to be used on devices which support this controller. The
+ driver handles English and German keyboards - set the environment
+ variable 'keymap' to "de" to select German. Keyboard repeat is
+ handled by the keyboard itself.
+
+config TEGRA_KEYBOARD
+ bool "NVIDIA Tegra internal matrix keyboard controller support"
+ help
+ A matrix keyboard connected directly to the internal keyboard
+ controller on Tegra SoCs.
+
+config TWL4030_INPUT
+ bool "Enable TWL4030 Input controller"
+ help
+ Enable TWL4030 Input controller
diff --git a/roms/u-boot/drivers/input/Makefile b/roms/u-boot/drivers/input/Makefile
new file mode 100644
index 000000000..e440c921e
--- /dev/null
+++ b/roms/u-boot/drivers/input/Makefile
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+obj-$(CONFIG_KEYBOARD) += input.o
+obj-$(CONFIG_$(SPL_TPL_)CROS_EC_KEYB) += cros_ec_keyb.o
+obj-$(CONFIG_$(SPL_TPL_)OF_CONTROL) += key_matrix.o
+obj-$(CONFIG_$(SPL_TPL_)DM_KEYBOARD) += input.o keyboard-uclass.o
+
+ifndef CONFIG_SPL_BUILD
+
+obj-$(CONFIG_I8042_KEYB) += i8042.o
+obj-$(CONFIG_TEGRA_KEYBOARD) += input.o tegra-kbc.o
+obj-$(CONFIG_TWL4030_INPUT) += twl4030.o
+obj-$(CONFIG_TWL6030_INPUT) += twl6030.o
+endif
diff --git a/roms/u-boot/drivers/input/cros_ec_keyb.c b/roms/u-boot/drivers/input/cros_ec_keyb.c
new file mode 100644
index 000000000..dc3b08c0f
--- /dev/null
+++ b/roms/u-boot/drivers/input/cros_ec_keyb.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Chromium OS Matrix Keyboard
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ */
+
+#include <common.h>
+#include <cros_ec.h>
+#include <dm.h>
+#include <errno.h>
+#include <input.h>
+#include <keyboard.h>
+#include <key_matrix.h>
+#include <log.h>
+#include <stdio_dev.h>
+
+enum {
+ KBC_MAX_KEYS = 8, /* Maximum keys held down at once */
+ KBC_REPEAT_RATE_MS = 30,
+ KBC_REPEAT_DELAY_MS = 240,
+};
+
+struct cros_ec_keyb_priv {
+ struct input_config *input; /* The input layer */
+ struct key_matrix matrix; /* The key matrix layer */
+ int key_rows; /* Number of keyboard rows */
+ int key_cols; /* Number of keyboard columns */
+ int ghost_filter; /* 1 to enable ghost filter, else 0 */
+};
+
+
+/**
+ * Check the keyboard controller and return a list of key matrix positions
+ * for which a key is pressed
+ *
+ * @param dev Keyboard device
+ * @param keys List of keys that we have detected
+ * @param max_count Maximum number of keys to return
+ * @param samep Set to true if this scan repeats the last, else false
+ * @return number of pressed keys, 0 for none, -EIO on error
+ */
+static int check_for_keys(struct udevice *dev, struct key_matrix_key *keys,
+ int max_count, bool *samep)
+{
+ struct cros_ec_keyb_priv *priv = dev_get_priv(dev);
+ struct key_matrix_key *key;
+ static struct mbkp_keyscan last_scan;
+ static bool last_scan_valid;
+ struct ec_response_get_next_event event;
+ struct mbkp_keyscan *scan = (struct mbkp_keyscan *)
+ &event.data.key_matrix;
+ unsigned int row, col, bit, data;
+ int num_keys;
+ int ret;
+
+ /* Get pending MKBP event. It may not be a key matrix event. */
+ do {
+ ret = cros_ec_get_next_event(dev->parent, &event);
+ /* The EC has no events for us at this time. */
+ if (ret == -EC_RES_UNAVAILABLE)
+ return -EIO;
+ else if (ret)
+ break;
+ } while (event.event_type != EC_MKBP_EVENT_KEY_MATRIX);
+
+ /* Try the old command if the EC doesn't support the above. */
+ if (ret == -EC_RES_INVALID_COMMAND) {
+ if (cros_ec_scan_keyboard(dev->parent, scan)) {
+ debug("%s: keyboard scan failed\n", __func__);
+ return -EIO;
+ }
+ } else if (ret) {
+ debug("%s: Error getting next MKBP event. (%d)\n",
+ __func__, ret);
+ return -EIO;
+ }
+ *samep = last_scan_valid && !memcmp(&last_scan, scan, sizeof(*scan));
+
+ /*
+ * This is a bit odd. The EC has no way to tell us that it has run
+ * out of key scans. It just returns the same scan over and over
+ * again. So the only way to detect that we have run out is to detect
+ * that this scan is the same as the last.
+ */
+ last_scan_valid = true;
+ memcpy(&last_scan, scan, sizeof(last_scan));
+
+ for (col = num_keys = bit = 0; col < priv->matrix.num_cols;
+ col++) {
+ for (row = 0; row < priv->matrix.num_rows; row++) {
+ unsigned int mask = 1 << (bit & 7);
+
+ data = scan->data[bit / 8];
+ if ((data & mask) && num_keys < max_count) {
+ key = keys + num_keys++;
+ key->row = row;
+ key->col = col;
+ key->valid = 1;
+ }
+ bit++;
+ }
+ }
+
+ return num_keys;
+}
+
+/**
+ * Check the keyboard, and send any keys that are pressed.
+ *
+ * This is called by input_tstc() and input_getc() when they need more
+ * characters
+ *
+ * @param input Input configuration
+ * @return 1, to indicate that we have something to look at
+ */
+int cros_ec_kbc_check(struct input_config *input)
+{
+ struct udevice *dev = input->dev;
+ struct cros_ec_keyb_priv *priv = dev_get_priv(dev);
+ static struct key_matrix_key last_keys[KBC_MAX_KEYS];
+ static int last_num_keys;
+ struct key_matrix_key keys[KBC_MAX_KEYS];
+ int keycodes[KBC_MAX_KEYS];
+ int num_keys, num_keycodes;
+ int irq_pending, sent;
+ bool same = false;
+
+ /*
+ * Loop until the EC has no more keyscan records, or we have
+ * received at least one character. This means we know that tstc()
+ * will always return non-zero if keys have been pressed.
+ *
+ * Without this loop, a key release (which generates no new ascii
+ * characters) will cause us to exit this function, and just tstc()
+ * may return 0 before all keys have been read from the EC.
+ */
+ do {
+ irq_pending = cros_ec_interrupt_pending(dev->parent);
+ if (irq_pending) {
+ num_keys = check_for_keys(dev, keys, KBC_MAX_KEYS,
+ &same);
+ if (num_keys < 0)
+ return 0;
+ last_num_keys = num_keys;
+ memcpy(last_keys, keys, sizeof(keys));
+ } else {
+ /*
+ * EC doesn't want to be asked, so use keys from last
+ * time.
+ */
+ num_keys = last_num_keys;
+ memcpy(keys, last_keys, sizeof(keys));
+ }
+
+ if (num_keys < 0)
+ return -1;
+ num_keycodes = key_matrix_decode(&priv->matrix, keys,
+ num_keys, keycodes, KBC_MAX_KEYS);
+ sent = input_send_keycodes(input, keycodes, num_keycodes);
+
+ /*
+ * For those ECs without an interrupt, stop scanning when we
+ * see that the scan is the same as last time.
+ */
+ if ((irq_pending < 0) && same)
+ break;
+ } while (irq_pending && !sent);
+
+ return 1;
+}
+
+/**
+ * Decode MBKP keyboard details from the device tree
+ *
+ * @param blob Device tree blob
+ * @param node Node to decode from
+ * @param config Configuration data read from fdt
+ * @return 0 if ok, -1 on error
+ */
+static int cros_ec_keyb_decode_fdt(struct udevice *dev,
+ struct cros_ec_keyb_priv *config)
+{
+ /*
+ * Get keyboard rows and columns - at present we are limited to
+ * 8 columns by the protocol (one byte per row scan)
+ */
+ config->key_rows = dev_read_u32_default(dev, "keypad,num-rows", 0);
+ config->key_cols = dev_read_u32_default(dev, "keypad,num-columns", 0);
+ if (!config->key_rows || !config->key_cols ||
+ config->key_rows * config->key_cols / 8
+ > CROS_EC_KEYSCAN_COLS) {
+ debug("%s: Invalid key matrix size %d x %d\n", __func__,
+ config->key_rows, config->key_cols);
+ return -1;
+ }
+ config->ghost_filter = dev_read_bool(dev, "google,needs-ghost-filter");
+
+ return 0;
+}
+
+static int cros_ec_kbd_probe(struct udevice *dev)
+{
+ struct cros_ec_keyb_priv *priv = dev_get_priv(dev);
+ struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct stdio_dev *sdev = &uc_priv->sdev;
+ struct input_config *input = &uc_priv->input;
+ int ret;
+
+ ret = cros_ec_keyb_decode_fdt(dev, priv);
+ if (ret) {
+ debug("%s: Cannot decode node (ret=%d)\n", __func__, ret);
+ return -EINVAL;
+ }
+ input_set_delays(input, KBC_REPEAT_DELAY_MS, KBC_REPEAT_RATE_MS);
+ ret = key_matrix_init(&priv->matrix, priv->key_rows, priv->key_cols,
+ priv->ghost_filter);
+ if (ret) {
+ debug("%s: cannot init key matrix\n", __func__);
+ return ret;
+ }
+ ret = key_matrix_decode_fdt(dev, &priv->matrix);
+ if (ret) {
+ debug("%s: Could not decode key matrix from fdt\n", __func__);
+ return ret;
+ }
+ debug("%s: Matrix keyboard %dx%d ready\n", __func__, priv->key_rows,
+ priv->key_cols);
+
+ priv->input = input;
+ input->dev = dev;
+ input_add_tables(input, false);
+ input->read_keys = cros_ec_kbc_check;
+ strcpy(sdev->name, "cros-ec-keyb");
+
+ /* Register the device. cros_ec_init_keyboard() will be called soon */
+ return input_stdio_register(sdev);
+}
+
+static const struct keyboard_ops cros_ec_kbd_ops = {
+};
+
+static const struct udevice_id cros_ec_kbd_ids[] = {
+ { .compatible = "google,cros-ec-keyb" },
+ { }
+};
+
+U_BOOT_DRIVER(google_cros_ec_keyb) = {
+ .name = "google_cros_ec_keyb",
+ .id = UCLASS_KEYBOARD,
+ .of_match = cros_ec_kbd_ids,
+ .probe = cros_ec_kbd_probe,
+ .ops = &cros_ec_kbd_ops,
+ .priv_auto = sizeof(struct cros_ec_keyb_priv),
+};
diff --git a/roms/u-boot/drivers/input/i8042.c b/roms/u-boot/drivers/input/i8042.c
new file mode 100644
index 000000000..565d99e7e
--- /dev/null
+++ b/roms/u-boot/drivers/input/i8042.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2002 ELTEC Elektronik AG
+ * Frank Gottschling <fgottschling@eltec.de>
+ */
+
+/* i8042.c - Intel 8042 keyboard driver routines */
+
+#include <common.h>
+#include <dm.h>
+#include <env.h>
+#include <errno.h>
+#include <i8042.h>
+#include <input.h>
+#include <keyboard.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* defines */
+#define in8(p) inb(p)
+#define out8(p, v) outb(v, p)
+
+enum {
+ QUIRK_DUP_POR = 1 << 0,
+};
+
+/* locals */
+struct i8042_kbd_priv {
+ bool extended; /* true if an extended keycode is expected next */
+ int quirks; /* quirks that we support */
+};
+
+static unsigned char ext_key_map[] = {
+ 0x1c, /* keypad enter */
+ 0x1d, /* right control */
+ 0x35, /* keypad slash */
+ 0x37, /* print screen */
+ 0x38, /* right alt */
+ 0x46, /* break */
+ 0x47, /* editpad home */
+ 0x48, /* editpad up */
+ 0x49, /* editpad pgup */
+ 0x4b, /* editpad left */
+ 0x4d, /* editpad right */
+ 0x4f, /* editpad end */
+ 0x50, /* editpad dn */
+ 0x51, /* editpad pgdn */
+ 0x52, /* editpad ins */
+ 0x53, /* editpad del */
+ 0x00 /* map end */
+ };
+
+static int kbd_input_empty(void)
+{
+ int kbd_timeout = KBD_TIMEOUT * 1000;
+
+ while ((in8(I8042_STS_REG) & STATUS_IBF) && kbd_timeout--)
+ udelay(1);
+
+ return kbd_timeout != -1;
+}
+
+static int kbd_output_full(void)
+{
+ int kbd_timeout = KBD_TIMEOUT * 1000;
+
+ while (((in8(I8042_STS_REG) & STATUS_OBF) == 0) && kbd_timeout--)
+ udelay(1);
+
+ return kbd_timeout != -1;
+}
+
+/**
+ * check_leds() - Check the keyboard LEDs and update them it needed
+ *
+ * @ret: Value to return
+ * @return value of @ret
+ */
+static int i8042_kbd_update_leds(struct udevice *dev, int leds)
+{
+ kbd_input_empty();
+ out8(I8042_DATA_REG, CMD_SET_KBD_LED);
+ kbd_input_empty();
+ out8(I8042_DATA_REG, leds & 0x7);
+
+ return 0;
+}
+
+static int kbd_write(int reg, int value)
+{
+ if (!kbd_input_empty())
+ return -1;
+ out8(reg, value);
+
+ return 0;
+}
+
+static int kbd_read(int reg)
+{
+ if (!kbd_output_full())
+ return -1;
+
+ return in8(reg);
+}
+
+static int kbd_cmd_read(int cmd)
+{
+ if (kbd_write(I8042_CMD_REG, cmd))
+ return -1;
+
+ return kbd_read(I8042_DATA_REG);
+}
+
+static int kbd_cmd_write(int cmd, int data)
+{
+ if (kbd_write(I8042_CMD_REG, cmd))
+ return -1;
+
+ return kbd_write(I8042_DATA_REG, data);
+}
+
+static int kbd_reset(int quirk)
+{
+ int config;
+
+ /* controller self test */
+ if (kbd_cmd_read(CMD_SELF_TEST) != KBC_TEST_OK)
+ goto err;
+
+ /* keyboard reset */
+ if (kbd_write(I8042_DATA_REG, CMD_RESET_KBD) ||
+ kbd_read(I8042_DATA_REG) != KBD_ACK ||
+ kbd_read(I8042_DATA_REG) != KBD_POR)
+ goto err;
+
+ if (kbd_write(I8042_DATA_REG, CMD_DRAIN_OUTPUT) ||
+ kbd_read(I8042_DATA_REG) != KBD_ACK)
+ goto err;
+
+ /* set AT translation and disable irq */
+ config = kbd_cmd_read(CMD_RD_CONFIG);
+ if (config == -1)
+ goto err;
+
+ /* Sometimes get a second byte */
+ else if ((quirk & QUIRK_DUP_POR) && config == KBD_POR)
+ config = kbd_cmd_read(CMD_RD_CONFIG);
+
+ config |= CONFIG_AT_TRANS;
+ config &= ~(CONFIG_KIRQ_EN | CONFIG_MIRQ_EN);
+ if (kbd_cmd_write(CMD_WR_CONFIG, config))
+ goto err;
+
+ /* enable keyboard */
+ if (kbd_write(I8042_CMD_REG, CMD_KBD_EN) ||
+ !kbd_input_empty())
+ goto err;
+
+ return 0;
+err:
+ debug("%s: Keyboard failure\n", __func__);
+ return -1;
+}
+
+static int kbd_controller_present(void)
+{
+ return in8(I8042_STS_REG) != 0xff;
+}
+
+/** Flush all buffer from keyboard controller to host*/
+static void i8042_flush(void)
+{
+ int timeout;
+
+ /*
+ * The delay is to give the keyboard controller some time
+ * to fill the next byte.
+ */
+ while (1) {
+ timeout = 100; /* wait for no longer than 100us */
+ while (timeout > 0 && !(in8(I8042_STS_REG) & STATUS_OBF)) {
+ udelay(1);
+ timeout--;
+ }
+
+ /* Try to pull next byte if not timeout */
+ if (in8(I8042_STS_REG) & STATUS_OBF)
+ in8(I8042_DATA_REG);
+ else
+ break;
+ }
+}
+
+/**
+ * Disables the keyboard so that key strokes no longer generate scancodes to
+ * the host.
+ *
+ * @return 0 if ok, -1 if keyboard input was found while disabling
+ */
+static int i8042_disable(void)
+{
+ if (kbd_input_empty() == 0)
+ return -1;
+
+ /* Disable keyboard */
+ out8(I8042_CMD_REG, CMD_KBD_DIS);
+
+ if (kbd_input_empty() == 0)
+ return -1;
+
+ return 0;
+}
+
+static int i8042_kbd_check(struct input_config *input)
+{
+ struct i8042_kbd_priv *priv = dev_get_priv(input->dev);
+
+ if ((in8(I8042_STS_REG) & STATUS_OBF) == 0) {
+ return 0;
+ } else {
+ bool release = false;
+ int scan_code;
+ int i;
+
+ scan_code = in8(I8042_DATA_REG);
+ if (scan_code == 0xfa) {
+ return 0;
+ } else if (scan_code == 0xe0) {
+ priv->extended = true;
+ return 0;
+ }
+ if (scan_code & 0x80) {
+ scan_code &= 0x7f;
+ release = true;
+ }
+ if (priv->extended) {
+ priv->extended = false;
+ for (i = 0; ext_key_map[i]; i++) {
+ if (ext_key_map[i] == scan_code) {
+ scan_code = 0x60 + i;
+ break;
+ }
+ }
+ /* not found ? */
+ if (!ext_key_map[i])
+ return 0;
+ }
+
+ input_add_keycode(input, scan_code, release);
+ return 1;
+ }
+}
+
+/* i8042_kbd_init - reset keyboard and init state flags */
+static int i8042_start(struct udevice *dev)
+{
+ struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct i8042_kbd_priv *priv = dev_get_priv(dev);
+ struct input_config *input = &uc_priv->input;
+ int keymap, try;
+ char *penv;
+ int ret;
+
+ if (!kbd_controller_present()) {
+ debug("i8042 keyboard controller is not present\n");
+ return -ENOENT;
+ }
+
+ /* Init keyboard device (default US layout) */
+ keymap = KBD_US;
+ penv = env_get("keymap");
+ if (penv != NULL) {
+ if (strncmp(penv, "de", 3) == 0)
+ keymap = KBD_GER;
+ }
+
+ for (try = 0; kbd_reset(priv->quirks) != 0; try++) {
+ if (try >= KBD_RESET_TRIES)
+ return -1;
+ }
+
+ ret = input_add_tables(input, keymap == KBD_GER);
+ if (ret)
+ return ret;
+
+ i8042_kbd_update_leds(dev, NORMAL);
+ debug("%s: started\n", __func__);
+
+ return 0;
+}
+
+static int i8042_kbd_remove(struct udevice *dev)
+{
+ if (i8042_disable())
+ log_debug("i8042_disable() failed. fine, continue.\n");
+ i8042_flush();
+
+ return 0;
+}
+
+/**
+ * Set up the i8042 keyboard. This is called by the stdio device handler
+ *
+ * We want to do this init when the keyboard is actually used rather than
+ * at start-up, since keyboard input may not currently be selected.
+ *
+ * Once the keyboard starts there will be a period during which we must
+ * wait for the keyboard to init. We do this only when a key is first
+ * read - see kbd_wait_for_fifo_init().
+ *
+ * @return 0 if ok, -ve on error
+ */
+static int i8042_kbd_probe(struct udevice *dev)
+{
+ struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct i8042_kbd_priv *priv = dev_get_priv(dev);
+ struct stdio_dev *sdev = &uc_priv->sdev;
+ struct input_config *input = &uc_priv->input;
+ int ret;
+
+ if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev),
+ "intel,duplicate-por"))
+ priv->quirks |= QUIRK_DUP_POR;
+
+ /* Register the device. i8042_start() will be called soon */
+ input->dev = dev;
+ input->read_keys = i8042_kbd_check;
+ input_allow_repeats(input, true);
+ strcpy(sdev->name, "i8042-kbd");
+ ret = input_stdio_register(sdev);
+ if (ret) {
+ debug("%s: input_stdio_register() failed\n", __func__);
+ return ret;
+ }
+ debug("%s: ready\n", __func__);
+
+ return 0;
+}
+
+static const struct keyboard_ops i8042_kbd_ops = {
+ .start = i8042_start,
+ .update_leds = i8042_kbd_update_leds,
+};
+
+static const struct udevice_id i8042_kbd_ids[] = {
+ { .compatible = "intel,i8042-keyboard" },
+ { }
+};
+
+U_BOOT_DRIVER(i8042_kbd) = {
+ .name = "i8042_kbd",
+ .id = UCLASS_KEYBOARD,
+ .of_match = i8042_kbd_ids,
+ .probe = i8042_kbd_probe,
+ .remove = i8042_kbd_remove,
+ .ops = &i8042_kbd_ops,
+ .priv_auto = sizeof(struct i8042_kbd_priv),
+};
diff --git a/roms/u-boot/drivers/input/input.c b/roms/u-boot/drivers/input/input.c
new file mode 100644
index 000000000..c1c5e428d
--- /dev/null
+++ b/roms/u-boot/drivers/input/input.c
@@ -0,0 +1,685 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Translate key codes into ASCII
+ *
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2004 DENX Software Engineering, Wolfgang Denk, wd@denx.de
+ */
+
+#include <common.h>
+#include <console.h>
+#include <dm.h>
+#include <env.h>
+#include <errno.h>
+#include <log.h>
+#include <stdio_dev.h>
+#include <input.h>
+#ifdef CONFIG_DM_KEYBOARD
+#include <keyboard.h>
+#endif
+#include <linux/input.h>
+
+enum {
+ /* These correspond to the lights on the keyboard */
+ FLAG_SCROLL_LOCK = 1 << 0,
+ FLAG_NUM_LOCK = 1 << 1,
+ FLAG_CAPS_LOCK = 1 << 2,
+
+ /* Special flag ORed with key code to indicate release */
+ KEY_RELEASE = 1 << 15,
+ KEY_MASK = 0xfff,
+};
+
+/*
+ * These takes map key codes to ASCII. 0xff means no key, or special key.
+ * Three tables are provided - one for plain keys, one for when the shift
+ * 'modifier' key is pressed and one for when the ctrl modifier key is
+ * pressed.
+ */
+static const uchar kbd_plain_xlate[] = {
+ 0xff, 0x1b, '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', '0', '-', '=', '\b', '\t', /* 0x00 - 0x0f */
+ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
+ 'o', 'p', '[', ']', '\r', 0xff, 'a', 's', /* 0x10 - 0x1f */
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
+ '\'', '`', 0xff, '\\', 'z', 'x', 'c', 'v', /* 0x20 - 0x2f */
+ 'b', 'n', 'm', ',' , '.', '/', 0xff, 0xff, 0xff,
+ ' ', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 - 0x3f */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '7',
+ '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
+ '2', '3', '0', '.', 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 - 0x5F */
+ '\r', 0xff, '/', '*',
+};
+
+static unsigned char kbd_shift_xlate[] = {
+ 0xff, 0x1b, '!', '@', '#', '$', '%', '^',
+ '&', '*', '(', ')', '_', '+', '\b', '\t', /* 0x00 - 0x0f */
+ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
+ 'O', 'P', '{', '}', '\r', 0xff, 'A', 'S', /* 0x10 - 0x1f */
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
+ '"', '~', 0xff, '|', 'Z', 'X', 'C', 'V', /* 0x20 - 0x2f */
+ 'B', 'N', 'M', '<', '>', '?', 0xff, 0xff, 0xff,
+ ' ', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 - 0x3f */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '7',
+ '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
+ '2', '3', '0', '.', 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 - 0x5F */
+ '\r', 0xff, '/', '*',
+};
+
+static unsigned char kbd_ctrl_xlate[] = {
+ 0xff, 0x1b, '1', 0x00, '3', '4', '5', 0x1E,
+ '7', '8', '9', '0', 0x1F, '=', '\b', '\t', /* 0x00 - 0x0f */
+ 0x11, 0x17, 0x05, 0x12, 0x14, 0x19, 0x15, 0x09,
+ 0x0f, 0x10, 0x1b, 0x1d, '\n', 0xff, 0x01, 0x13, /* 0x10 - 0x1f */
+ 0x04, 0x06, 0x08, 0x09, 0x0a, 0x0b, 0x0c, ';',
+ '\'', '~', 0x00, 0x1c, 0x1a, 0x18, 0x03, 0x16, /* 0x20 - 0x2f */
+ 0x02, 0x0e, 0x0d, '<', '>', '?', 0xff, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 - 0x3f */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '7',
+ '8', '9', '-', '4', '5', '6', '+', '1', /* 0x40 - 0x4f */
+ '2', '3', '0', '.', 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 - 0x5F */
+ '\r', 0xff, '/', '*',
+};
+
+/*
+ * German keymap. Special letters are mapped according to code page 437.
+ */
+static const uchar kbd_plain_xlate_german[] = {
+ 0xff, 0x1b, '1', '2', '3', '4', '5', '6', /* scan 00-07 */
+ '7', '8', '9', '0', 0xe1, '\'', 0x08, '\t', /* scan 08-0F */
+ 'q', 'w', 'e', 'r', 't', 'z', 'u', 'i', /* scan 10-17 */
+ 'o', 'p', 0x81, '+', '\r', 0xff, 'a', 's', /* scan 18-1F */
+ 'd', 'f', 'g', 'h', 'j', 'k', 'l', 0x94, /* scan 20-27 */
+ 0x84, '^', 0xff, '#', 'y', 'x', 'c', 'v', /* scan 28-2F */
+ 'b', 'n', 'm', ',', '.', '-', 0xff, '*', /* scan 30-37 */
+ ' ', ' ', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '7', /* scan 40-47 */
+ '8', '9', '-', '4', '5', '6', '+', '1', /* scan 48-4F */
+ '2', '3', '0', ',', 0xff, 0xff, '<', 0xff, /* scan 50-57 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58-5F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60-67 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68-6F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70-77 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78-7F */
+ '\r', 0xff, '/', '*',
+};
+
+static unsigned char kbd_shift_xlate_german[] = {
+ 0xff, 0x1b, '!', '"', 0x15, '$', '%', '&', /* scan 00-07 */
+ '/', '(', ')', '=', '?', '`', 0x08, '\t', /* scan 08-0F */
+ 'Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I', /* scan 10-17 */
+ 'O', 'P', 0x9a, '*', '\r', 0xff, 'A', 'S', /* scan 18-1F */
+ 'D', 'F', 'G', 'H', 'J', 'K', 'L', 0x99, /* scan 20-27 */
+ 0x8e, 0xf8, 0xff, '\'', 'Y', 'X', 'C', 'V', /* scan 28-2F */
+ 'B', 'N', 'M', ';', ':', '_', 0xff, '*', /* scan 30-37 */
+ ' ', ' ', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '7', /* scan 40-47 */
+ '8', '9', '-', '4', '5', '6', '+', '1', /* scan 48-4F */
+ '2', '3', '0', ',', 0xff, 0xff, '>', 0xff, /* scan 50-57 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 58-5F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 60-67 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 68-6F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 70-77 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 78-7F */
+ '\r', 0xff, '/', '*',
+};
+
+static unsigned char kbd_right_alt_xlate_german[] = {
+ 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, /* scan 00-07 */
+ '{', '[', ']', '}', '\\', 0xff, 0xff, 0xff, /* scan 08-0F */
+ '@', 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 10-17 */
+ 0xff, 0xff, 0xff, '~', 0xff, 0xff, 0xff, 0xff, /* scan 18-1F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 20-27 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 28-2F */
+ 0xff, 0xff, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 30-37 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 38-3F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 40-47 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* scan 48-4F */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, '|', 0xff, /* scan 50-57 */
+};
+
+enum kbd_mask {
+ KBD_ENGLISH = 1 << 0,
+ KBD_GERMAN = 1 << 1,
+};
+
+static struct kbd_entry {
+ int kbd_mask; /* Which languages this is for */
+ int left_keycode; /* Left keycode to select this map */
+ int right_keycode; /* Right keycode to select this map */
+ const uchar *xlate; /* Ascii code for each keycode */
+ int num_entries; /* Number of entries in xlate */
+} kbd_entry[] = {
+ { KBD_ENGLISH, -1, -1,
+ kbd_plain_xlate, ARRAY_SIZE(kbd_plain_xlate) },
+ { KBD_GERMAN, -1, -1,
+ kbd_plain_xlate_german, ARRAY_SIZE(kbd_plain_xlate_german) },
+ { KBD_ENGLISH, KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
+ kbd_shift_xlate, ARRAY_SIZE(kbd_shift_xlate) },
+ { KBD_GERMAN, KEY_LEFTSHIFT, KEY_RIGHTSHIFT,
+ kbd_shift_xlate_german, ARRAY_SIZE(kbd_shift_xlate_german) },
+ { KBD_ENGLISH | KBD_GERMAN, KEY_LEFTCTRL, KEY_RIGHTCTRL,
+ kbd_ctrl_xlate, ARRAY_SIZE(kbd_ctrl_xlate) },
+ { KBD_GERMAN, -1, KEY_RIGHTALT,
+ kbd_right_alt_xlate_german,
+ ARRAY_SIZE(kbd_right_alt_xlate_german) },
+ {},
+};
+
+/*
+ * The table contains conversions from scan key codes to ECMA-48 escape
+ * sequences. The same sequences exist in the withdrawn ANSI 3.64 standard.
+ *
+ * As all escape sequences start with 0x1b this byte has been removed.
+ *
+ * This table is incomplete in that it does not include all possible extra keys.
+ */
+static struct {
+ int kbd_scan_code;
+ char *escape;
+} kbd_to_ansi364[] = {
+ { KEY_UP, "[A"},
+ { KEY_LEFT, "[D"},
+ { KEY_RIGHT, "[C"},
+ { KEY_DOWN, "[B"},
+ { KEY_F1, "OP"},
+ { KEY_F2, "OQ"},
+ { KEY_F3, "OR"},
+ { KEY_F4, "OS"},
+ { KEY_F5, "[15~"},
+ { KEY_F6, "[17~"},
+ { KEY_F7, "[18~"},
+ { KEY_F8, "[19~"},
+ { KEY_F9, "[20~"},
+ { KEY_F10, "[21~"},
+};
+
+/* Maximum number of output characters that an ANSI sequence expands to */
+#define ANSI_CHAR_MAX 5
+
+static int input_queue_ascii(struct input_config *config, int ch)
+{
+ if (config->fifo_in + 1 == INPUT_BUFFER_LEN) {
+ if (!config->fifo_out)
+ return -1; /* buffer full */
+ else
+ config->fifo_in = 0;
+ } else {
+ if (config->fifo_in + 1 == config->fifo_out)
+ return -1; /* buffer full */
+ config->fifo_in++;
+ }
+ debug(" {%02x} ", ch);
+ config->fifo[config->fifo_in] = (uchar)ch;
+
+ return 0;
+}
+
+int input_tstc(struct input_config *config)
+{
+ if (config->fifo_in == config->fifo_out && config->read_keys) {
+ if (!(*config->read_keys)(config))
+ return 0;
+ }
+ return config->fifo_in != config->fifo_out;
+}
+
+int input_getc(struct input_config *config)
+{
+ int err = 0;
+
+ while (config->fifo_in == config->fifo_out) {
+ if (config->read_keys)
+ err = (*config->read_keys)(config);
+ if (err)
+ return -1;
+ }
+
+ if (++config->fifo_out == INPUT_BUFFER_LEN)
+ config->fifo_out = 0;
+
+ return config->fifo[config->fifo_out];
+}
+
+/**
+ * Process a modifier/special key press or release and decide which key
+ * translation array should be used as a result.
+ *
+ * TODO: Should keep track of modifier press/release
+ *
+ * @param config Input state
+ * @param key Key code to process
+ * @param release 0 if a press, 1 if a release
+ * @return pointer to keycode->ascii translation table that should be used
+ */
+static struct input_key_xlate *process_modifier(struct input_config *config,
+ int key, int release)
+{
+#ifdef CONFIG_DM_KEYBOARD
+ struct udevice *dev = config->dev;
+ struct keyboard_ops *ops = keyboard_get_ops(dev);
+#endif
+ struct input_key_xlate *table;
+ int i;
+
+ /* Start with the main table, and see what modifiers change it */
+ assert(config->num_tables > 0);
+ table = &config->table[0];
+ for (i = 1; i < config->num_tables; i++) {
+ struct input_key_xlate *tab = &config->table[i];
+
+ if (key == tab->left_keycode || key == tab->right_keycode)
+ table = tab;
+ }
+
+ /* Handle the lighted keys */
+ if (!release) {
+ int flip = -1;
+
+ switch (key) {
+ case KEY_SCROLLLOCK:
+ flip = FLAG_SCROLL_LOCK;
+ break;
+ case KEY_NUMLOCK:
+ flip = FLAG_NUM_LOCK;
+ break;
+ case KEY_CAPSLOCK:
+ flip = FLAG_CAPS_LOCK;
+ break;
+ }
+
+ if (flip != -1) {
+ int leds = 0;
+
+ config->flags ^= flip;
+ if (config->flags & FLAG_NUM_LOCK)
+ leds |= INPUT_LED_NUM;
+ if (config->flags & FLAG_CAPS_LOCK)
+ leds |= INPUT_LED_CAPS;
+ if (config->flags & FLAG_SCROLL_LOCK)
+ leds |= INPUT_LED_SCROLL;
+ config->leds = leds;
+ config->leds_changed = flip;
+
+#ifdef CONFIG_DM_KEYBOARD
+ if (ops->update_leds) {
+ if (ops->update_leds(dev, config->leds))
+ debug("Update keyboard's LED failed\n");
+ }
+#endif
+ }
+ }
+
+ return table;
+}
+
+/**
+ * Search an int array for a key value
+ *
+ * @param array Array to search
+ * @param count Number of elements in array
+ * @param key Key value to find
+ * @return element where value was first found, -1 if none
+ */
+static int array_search(int *array, int count, int key)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (array[i] == key)
+ return i;
+ }
+
+ return -1;
+}
+
+/**
+ * Sort an array so that those elements that exist in the ordering are
+ * first in the array, and in the same order as the ordering. The algorithm
+ * is O(count * ocount) and designed for small arrays.
+ *
+ * TODO: Move this to common / lib?
+ *
+ * @param dest Array with elements to sort, also destination array
+ * @param count Number of elements to sort
+ * @param order Array containing ordering elements
+ * @param ocount Number of ordering elements
+ * @return number of elements in dest that are in order (these will be at the
+ * start of dest).
+ */
+static int sort_array_by_ordering(int *dest, int count, int *order,
+ int ocount)
+{
+ int temp[count];
+ int dest_count;
+ int same; /* number of elements which are the same */
+ int i;
+
+ /* setup output items, copy items to be sorted into our temp area */
+ memcpy(temp, dest, count * sizeof(*dest));
+ dest_count = 0;
+
+ /* work through the ordering, move over the elements we agree on */
+ for (i = 0; i < ocount; i++) {
+ if (array_search(temp, count, order[i]) != -1)
+ dest[dest_count++] = order[i];
+ }
+ same = dest_count;
+
+ /* now move over the elements that are not in the ordering */
+ for (i = 0; i < count; i++) {
+ if (array_search(order, ocount, temp[i]) == -1)
+ dest[dest_count++] = temp[i];
+ }
+ assert(dest_count == count);
+ return same;
+}
+
+/**
+ * Check a list of key codes against the previous key scan
+ *
+ * Given a list of new key codes, we check how many of these are the same
+ * as last time.
+ *
+ * @param config Input state
+ * @param keycode List of key codes to examine
+ * @param num_keycodes Number of key codes
+ * @param same Returns number of key codes which are the same
+ */
+static int input_check_keycodes(struct input_config *config,
+ int keycode[], int num_keycodes, int *same)
+{
+ /* Select the 'plain' xlate table to start with */
+ if (!config->num_tables) {
+ debug("%s: No xlate tables: cannot decode keys\n", __func__);
+ return -1;
+ }
+
+ /* sort the keycodes into the same order as the previous ones */
+ *same = sort_array_by_ordering(keycode, num_keycodes,
+ config->prev_keycodes, config->num_prev_keycodes);
+
+ memcpy(config->prev_keycodes, keycode, num_keycodes * sizeof(int));
+ config->num_prev_keycodes = num_keycodes;
+
+ return *same != num_keycodes;
+}
+
+/**
+ * Checks and converts a special key code into ANSI 3.64 escape sequence.
+ *
+ * @param config Input state
+ * @param keycode Key code to examine
+ * @param output_ch Buffer to place output characters into. It should
+ * be at least ANSI_CHAR_MAX bytes long, to allow for
+ * an ANSI sequence.
+ * @param max_chars Maximum number of characters to add to output_ch
+ * @return number of characters output, if the key was converted, otherwise 0.
+ * This may be larger than max_chars, in which case the overflow
+ * characters are not output.
+ */
+static int input_keycode_to_ansi364(struct input_config *config,
+ int keycode, char output_ch[], int max_chars)
+{
+ const char *escape;
+ int ch_count;
+ int i;
+
+ for (i = ch_count = 0; i < ARRAY_SIZE(kbd_to_ansi364); i++) {
+ if (keycode != kbd_to_ansi364[i].kbd_scan_code)
+ continue;
+ output_ch[ch_count++] = 0x1b;
+ for (escape = kbd_to_ansi364[i].escape; *escape; escape++) {
+ if (ch_count < max_chars)
+ output_ch[ch_count] = *escape;
+ ch_count++;
+ }
+ return ch_count;
+ }
+
+ return 0;
+}
+
+/**
+ * Converts and queues a list of key codes in escaped ASCII string form
+ * Convert a list of key codes into ASCII
+ *
+ * You must call input_check_keycodes() before this. It turns the keycode
+ * list into a list of ASCII characters and sends them to the input layer.
+ *
+ * Characters which were seen last time do not generate fresh ASCII output.
+ * The output (calls to queue_ascii) may be longer than num_keycodes, if the
+ * keycode contains special keys that was encoded to longer escaped sequence.
+ *
+ * @param config Input state
+ * @param keycode List of key codes to examine
+ * @param num_keycodes Number of key codes
+ * @param output_ch Buffer to place output characters into. It should
+ * be at last ANSI_CHAR_MAX * num_keycodes, to allow for
+ * ANSI sequences.
+ * @param max_chars Maximum number of characters to add to output_ch
+ * @param same Number of key codes which are the same
+ * @return number of characters written into output_ch, or -1 if we would
+ * exceed max_chars chars.
+ */
+static int input_keycodes_to_ascii(struct input_config *config,
+ int keycode[], int num_keycodes, char output_ch[],
+ int max_chars, int same)
+{
+ struct input_key_xlate *table;
+ int ch_count = 0;
+ int i;
+
+ table = &config->table[0];
+
+ /* deal with modifiers first */
+ for (i = 0; i < num_keycodes; i++) {
+ int key = keycode[i] & KEY_MASK;
+
+ if (key >= table->num_entries || table->xlate[key] == 0xff) {
+ table = process_modifier(config, key,
+ keycode[i] & KEY_RELEASE);
+ }
+ }
+
+ /* Start conversion by looking for the first new keycode (by same). */
+ for (i = same; i < num_keycodes; i++) {
+ int key = keycode[i];
+ int ch = 0xff;
+
+ /*
+ * For a normal key (with an ASCII value), add it; otherwise
+ * translate special key to escape sequence if possible.
+ */
+ if (key < table->num_entries) {
+ ch = table->xlate[key];
+ if ((config->flags & FLAG_CAPS_LOCK) &&
+ ch >= 'a' && ch <= 'z')
+ ch -= 'a' - 'A';
+ /* ban digit numbers if 'Num Lock' is not on */
+ if (!(config->flags & FLAG_NUM_LOCK)) {
+ if (key >= KEY_KP7 && key <= KEY_KPDOT &&
+ key != KEY_KPMINUS && key != KEY_KPPLUS)
+ ch = 0xff;
+ }
+ if (ch_count < max_chars && ch != 0xff)
+ output_ch[ch_count++] = (uchar)ch;
+ }
+ if (ch == 0xff)
+ ch_count += input_keycode_to_ansi364(config, key,
+ output_ch, max_chars);
+ }
+
+ if (ch_count > max_chars) {
+ debug("%s: Output char buffer overflow size=%d, need=%d\n",
+ __func__, max_chars, ch_count);
+ return -1;
+ }
+
+ /* ok, so return keys */
+ return ch_count;
+}
+
+static int _input_send_keycodes(struct input_config *config, int keycode[],
+ int num_keycodes, bool do_send)
+{
+ char ch[num_keycodes * ANSI_CHAR_MAX];
+ int count, i, same = 0;
+ int is_repeat = 0;
+ unsigned delay_ms;
+
+ config->modifiers = 0;
+ if (!input_check_keycodes(config, keycode, num_keycodes, &same)) {
+ /*
+ * Same as last time - is it time for another repeat?
+ * TODO(sjg@chromium.org) We drop repeats here and since
+ * the caller may not call in again for a while, our
+ * auto-repeat speed is not quite correct. We should
+ * insert another character if we later realise that we
+ * have missed a repeat slot.
+ */
+ is_repeat = config->allow_repeats || (config->repeat_rate_ms &&
+ (int)get_timer(config->next_repeat_ms) >= 0);
+ if (!is_repeat)
+ return 0;
+ }
+
+ count = input_keycodes_to_ascii(config, keycode, num_keycodes,
+ ch, sizeof(ch), is_repeat ? 0 : same);
+ if (do_send) {
+ for (i = 0; i < count; i++)
+ input_queue_ascii(config, ch[i]);
+ }
+ delay_ms = is_repeat ?
+ config->repeat_rate_ms :
+ config->repeat_delay_ms;
+
+ config->next_repeat_ms = get_timer(0) + delay_ms;
+
+ return count;
+}
+
+int input_send_keycodes(struct input_config *config, int keycode[],
+ int num_keycodes)
+{
+ return _input_send_keycodes(config, keycode, num_keycodes, true);
+}
+
+int input_add_keycode(struct input_config *config, int new_keycode,
+ bool release)
+{
+ int keycode[INPUT_MAX_MODIFIERS + 1];
+ int count, i;
+
+ /* Add the old keycodes which are not removed by this new one */
+ for (i = 0, count = 0; i < config->num_prev_keycodes; i++) {
+ int code = config->prev_keycodes[i];
+
+ if (new_keycode == code) {
+ if (release)
+ continue;
+ new_keycode = -1;
+ }
+ keycode[count++] = code;
+ }
+
+ if (!release && new_keycode != -1)
+ keycode[count++] = new_keycode;
+ debug("\ncodes for %02x/%d: ", new_keycode, release);
+ for (i = 0; i < count; i++)
+ debug("%02x ", keycode[i]);
+ debug("\n");
+
+ /* Don't output any ASCII characters if this is a key release */
+ return _input_send_keycodes(config, keycode, count, !release);
+}
+
+int input_add_table(struct input_config *config, int left_keycode,
+ int right_keycode, const uchar *xlate, int num_entries)
+{
+ struct input_key_xlate *table;
+
+ if (config->num_tables == INPUT_MAX_MODIFIERS) {
+ debug("%s: Too many modifier tables\n", __func__);
+ return -1;
+ }
+
+ table = &config->table[config->num_tables++];
+ table->left_keycode = left_keycode;
+ table->right_keycode = right_keycode;
+ table->xlate = xlate;
+ table->num_entries = num_entries;
+
+ return 0;
+}
+
+void input_set_delays(struct input_config *config, int repeat_delay_ms,
+ int repeat_rate_ms)
+{
+ config->repeat_delay_ms = repeat_delay_ms;
+ config->repeat_rate_ms = repeat_rate_ms;
+}
+
+void input_allow_repeats(struct input_config *config, bool allow_repeats)
+{
+ config->allow_repeats = allow_repeats;
+}
+
+int input_leds_changed(struct input_config *config)
+{
+ if (config->leds_changed)
+ return config->leds;
+
+ return -1;
+}
+
+int input_add_tables(struct input_config *config, bool german)
+{
+ struct kbd_entry *entry;
+ int mask;
+ int ret;
+
+ mask = german ? KBD_GERMAN : KBD_ENGLISH;
+ for (entry = kbd_entry; entry->kbd_mask; entry++) {
+ if (!(mask & entry->kbd_mask))
+ continue;
+ ret = input_add_table(config, entry->left_keycode,
+ entry->right_keycode, entry->xlate,
+ entry->num_entries);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int input_init(struct input_config *config, int leds)
+{
+ memset(config, '\0', sizeof(*config));
+ config->leds = leds;
+
+ return 0;
+}
+
+int input_stdio_register(struct stdio_dev *dev)
+{
+ int error;
+
+ error = stdio_register(dev);
+#if !defined(CONFIG_SPL_BUILD) || CONFIG_IS_ENABLED(ENV_SUPPORT)
+ /* check if this is the standard input device */
+ if (!error && strcmp(env_get("stdin"), dev->name) == 0) {
+ /* reassign the console */
+ if (OVERWRITE_CONSOLE ||
+ console_assign(stdin, dev->name))
+ return -1;
+ }
+#else
+ error = error;
+#endif
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/input/key_matrix.c b/roms/u-boot/drivers/input/key_matrix.c
new file mode 100644
index 000000000..4631728b8
--- /dev/null
+++ b/roms/u-boot/drivers/input/key_matrix.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Manage Keyboard Matrices
+ *
+ * Copyright (c) 2012 The Chromium OS Authors.
+ * (C) Copyright 2004 DENX Software Engineering, Wolfgang Denk, wd@denx.de
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <key_matrix.h>
+#include <log.h>
+#include <malloc.h>
+#include <linux/input.h>
+
+/**
+ * Determine if the current keypress configuration can cause key ghosting
+ *
+ * We figure this out by seeing if we have two or more keys in the same
+ * column, as well as two or more keys in the same row.
+ *
+ * @param config Keyboard matrix config
+ * @param keys List of keys to check
+ * @param valid Number of valid keypresses to check
+ * @return 0 if no ghosting is possible, 1 if it is
+ */
+static int has_ghosting(struct key_matrix *config, struct key_matrix_key *keys,
+ int valid)
+{
+ int key_in_same_col = 0, key_in_same_row = 0;
+ int i, j;
+
+ if (!config->ghost_filter || valid < 3)
+ return 0;
+
+ for (i = 0; i < valid; i++) {
+ /*
+ * Find 2 keys such that one key is in the same row
+ * and the other is in the same column as the i-th key.
+ */
+ for (j = i + 1; j < valid; j++) {
+ if (keys[j].col == keys[i].col)
+ key_in_same_col = 1;
+ if (keys[j].row == keys[i].row)
+ key_in_same_row = 1;
+ }
+ }
+
+ if (key_in_same_col && key_in_same_row)
+ return 1;
+ else
+ return 0;
+}
+
+int key_matrix_decode(struct key_matrix *config, struct key_matrix_key keys[],
+ int num_keys, int keycode[], int max_keycodes)
+{
+ const u8 *keymap;
+ int valid, upto;
+ int pos;
+
+ debug("%s: num_keys = %d\n", __func__, num_keys);
+ keymap = config->plain_keycode;
+ for (valid = upto = 0; upto < num_keys; upto++) {
+ struct key_matrix_key *key = &keys[upto];
+
+ debug(" valid=%d, row=%d, col=%d\n", key->valid, key->row,
+ key->col);
+ if (!key->valid)
+ continue;
+ pos = key->row * config->num_cols + key->col;
+ if (config->fn_keycode && pos == config->fn_pos)
+ keymap = config->fn_keycode;
+
+ /* Convert the (row, col) values into a keycode */
+ if (valid < max_keycodes)
+ keycode[valid++] = keymap[pos];
+ debug(" keycode=%d\n", keymap[pos]);
+ }
+
+ /* For a ghost key config, ignore the keypresses for this iteration. */
+ if (has_ghosting(config, keys, valid)) {
+ valid = 0;
+ debug(" ghosting detected!\n");
+ }
+ debug(" %d valid keycodes found\n", valid);
+
+ return valid;
+}
+
+/**
+ * Create a new keycode map from some provided data
+ *
+ * This decodes a keycode map in the format used by the fdt, which is one
+ * word per entry, with the row, col and keycode encoded in that word.
+ *
+ * We create a (row x col) size byte array with each entry containing the
+ * keycode for that (row, col). We also search for map_keycode and return
+ * its position if found (this is used for finding the Fn key).
+ *
+ * @param config Key matrix dimensions structure
+ * @param data Keycode data
+ * @param len Number of entries in keycode table
+ * @param map_keycode Key code to find in the map
+ * @param pos Returns position of map_keycode, if found, else -1
+ * @return map Pointer to allocated map
+ */
+static uchar *create_keymap(struct key_matrix *config, const u32 *data, int len,
+ int map_keycode, int *pos)
+{
+ uchar *map;
+
+ if (pos)
+ *pos = -1;
+ map = (uchar *)calloc(1, config->key_count);
+ if (!map) {
+ debug("%s: failed to malloc %d bytes\n", __func__,
+ config->key_count);
+ return NULL;
+ }
+
+ for (; len >= sizeof(u32); data++, len -= 4) {
+ u32 tmp = fdt32_to_cpu(*data);
+ int key_code, row, col;
+ int entry;
+
+ row = (tmp >> 24) & 0xff;
+ col = (tmp >> 16) & 0xff;
+ key_code = tmp & 0xffff;
+ entry = row * config->num_cols + col;
+ map[entry] = key_code;
+ debug(" map %d, %d: pos=%d, keycode=%d\n", row, col,
+ entry, key_code);
+ if (pos && map_keycode == key_code)
+ *pos = entry;
+ }
+
+ return map;
+}
+
+int key_matrix_decode_fdt(struct udevice *dev, struct key_matrix *config)
+{
+ const u32 *prop;
+ int proplen;
+ uchar *plain_keycode;
+
+ prop = dev_read_prop(dev, "linux,keymap", &proplen);
+ /* Basic keymap is required */
+ if (!prop) {
+ debug("%s: cannot find keycode-plain map\n", __func__);
+ return -1;
+ }
+
+ plain_keycode = create_keymap(config, prop, proplen, KEY_FN,
+ &config->fn_pos);
+ config->plain_keycode = plain_keycode;
+ /* Conversion error -> fail */
+ if (!config->plain_keycode)
+ return -1;
+
+ prop = dev_read_prop(dev, "linux,fn-keymap", &proplen);
+ /* fn keymap is optional */
+ if (!prop)
+ goto done;
+
+ config->fn_keycode = create_keymap(config, prop, proplen, -1, NULL);
+ /* Conversion error -> fail */
+ if (!config->fn_keycode) {
+ free(plain_keycode);
+ return -1;
+ }
+
+done:
+ debug("%s: Decoded key maps %p, %p from fdt\n", __func__,
+ config->plain_keycode, config->fn_keycode);
+ return 0;
+}
+
+int key_matrix_init(struct key_matrix *config, int rows, int cols,
+ int ghost_filter)
+{
+ memset(config, '\0', sizeof(*config));
+ config->num_rows = rows;
+ config->num_cols = cols;
+ config->key_count = rows * cols;
+ config->ghost_filter = ghost_filter;
+ assert(config->key_count > 0);
+
+ return 0;
+}
diff --git a/roms/u-boot/drivers/input/keyboard-uclass.c b/roms/u-boot/drivers/input/keyboard-uclass.c
new file mode 100644
index 000000000..2c6680337
--- /dev/null
+++ b/roms/u-boot/drivers/input/keyboard-uclass.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2015 Google, Inc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <keyboard.h>
+#include <log.h>
+
+static int keyboard_start(struct stdio_dev *sdev)
+{
+ struct udevice *dev = sdev->priv;
+ struct keyboard_ops *ops = keyboard_get_ops(dev);
+
+ if (ops->start)
+ return ops->start(dev);
+
+ return 0;
+}
+
+static int keyboard_stop(struct stdio_dev *sdev)
+{
+ struct udevice *dev = sdev->priv;
+ struct keyboard_ops *ops = keyboard_get_ops(dev);
+
+ if (ops->stop)
+ return ops->stop(dev);
+
+ return 0;
+}
+
+static int keyboard_tstc(struct stdio_dev *sdev)
+{
+ struct udevice *dev = sdev->priv;
+ struct keyboard_priv *priv = dev_get_uclass_priv(dev);
+ struct keyboard_ops *ops = keyboard_get_ops(dev);
+
+ /* Just get input to do this for us if we can */
+ if (priv->input.dev)
+ return input_tstc(&priv->input);
+ else if (ops->tstc)
+ return ops->tstc(dev);
+
+ return -ENOSYS;
+}
+
+static int keyboard_getc(struct stdio_dev *sdev)
+{
+ struct udevice *dev = sdev->priv;
+ struct keyboard_priv *priv = dev_get_uclass_priv(dev);
+ struct keyboard_ops *ops = keyboard_get_ops(dev);
+
+ /* Just get input to do this for us if we can */
+ if (priv->input.dev)
+ return input_getc(&priv->input);
+ else if (ops->getc)
+ return ops->getc(dev);
+
+ return -ENOSYS;
+}
+
+static int keyboard_pre_probe(struct udevice *dev)
+{
+ struct keyboard_priv *priv = dev_get_uclass_priv(dev);
+ struct stdio_dev *sdev = &priv->sdev;
+ int ret;
+
+ strlcpy(sdev->name, dev->name, sizeof(sdev->name));
+ sdev->flags = DEV_FLAGS_INPUT;
+ sdev->getc = keyboard_getc;
+ sdev->tstc = keyboard_tstc;
+ sdev->start = keyboard_start;
+ sdev->stop = keyboard_stop;
+ sdev->priv = dev;
+ ret = input_init(&priv->input, 0);
+ if (ret) {
+ debug("%s: Cannot set up input, ret=%d - please add DEBUG to drivers/input/input.c to figure out the cause\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+UCLASS_DRIVER(keyboard) = {
+ .id = UCLASS_KEYBOARD,
+ .name = "keyboard",
+ .pre_probe = keyboard_pre_probe,
+ .per_device_auto = sizeof(struct keyboard_priv),
+};
diff --git a/roms/u-boot/drivers/input/tegra-kbc.c b/roms/u-boot/drivers/input/tegra-kbc.c
new file mode 100644
index 000000000..5113041d3
--- /dev/null
+++ b/roms/u-boot/drivers/input/tegra-kbc.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2011
+ * NVIDIA Corporation <www.nvidia.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <input.h>
+#include <keyboard.h>
+#include <key_matrix.h>
+#include <log.h>
+#include <stdio_dev.h>
+#include <tegra-kbc.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/funcmux.h>
+#include <asm/arch-tegra/timer.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+
+enum {
+ KBC_MAX_GPIO = 24,
+ KBC_MAX_KPENT = 8, /* size of keypress entry queue */
+};
+
+#define KBC_FIFO_TH_CNT_SHIFT 14
+#define KBC_DEBOUNCE_CNT_SHIFT 4
+#define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3)
+#define KBC_CONTROL_KBC_EN (1 << 0)
+#define KBC_INT_FIFO_CNT_INT_STATUS (1 << 2)
+#define KBC_KPENT_VALID (1 << 7)
+#define KBC_ST_STATUS (1 << 3)
+
+enum {
+ KBC_DEBOUNCE_COUNT = 2,
+ KBC_REPEAT_RATE_MS = 30,
+ KBC_REPEAT_DELAY_MS = 240,
+ KBC_CLOCK_KHZ = 32, /* Keyboard uses a 32KHz clock */
+};
+
+/* keyboard controller config and state */
+struct tegra_kbd_priv {
+ struct input_config *input; /* The input layer */
+ struct key_matrix matrix; /* The key matrix layer */
+
+ struct kbc_tegra *kbc; /* tegra keyboard controller */
+ unsigned char inited; /* 1 if keyboard has been inited */
+ unsigned char first_scan; /* 1 if this is our first key scan */
+
+ /*
+ * After init we must wait a short time before polling the keyboard.
+ * This gives the tegra keyboard controller time to react after reset
+ * and lets us grab keys pressed during reset.
+ */
+ unsigned int init_dly_ms; /* Delay before we can read keyboard */
+ unsigned int start_time_ms; /* Time that we inited (in ms) */
+ unsigned int last_poll_ms; /* Time we should last polled */
+ unsigned int next_repeat_ms; /* Next time we repeat a key */
+};
+
+/**
+ * reads the keyboard fifo for current keypresses
+ *
+ * @param priv Keyboard private data
+ * @param fifo Place to put fifo results
+ * @param max_keycodes Maximum number of key codes to put in the fifo
+ * @return number of items put into fifo
+ */
+static int tegra_kbc_find_keys(struct tegra_kbd_priv *priv, int *fifo,
+ int max_keycodes)
+{
+ struct key_matrix_key keys[KBC_MAX_KPENT], *key;
+ u32 kp_ent = 0;
+ int i;
+
+ for (key = keys, i = 0; i < KBC_MAX_KPENT; i++, key++) {
+ /* Get next word */
+ if (!(i & 3))
+ kp_ent = readl(&priv->kbc->kp_ent[i / 4]);
+
+ key->valid = (kp_ent & KBC_KPENT_VALID) != 0;
+ key->row = (kp_ent >> 3) & 0xf;
+ key->col = kp_ent & 0x7;
+
+ /* Shift to get next entry */
+ kp_ent >>= 8;
+ }
+ return key_matrix_decode(&priv->matrix, keys, KBC_MAX_KPENT, fifo,
+ max_keycodes);
+}
+
+/**
+ * Process all the keypress sequences in fifo and send key codes
+ *
+ * The fifo contains zero or more keypress sets. Each set
+ * consists of from 1-8 keycodes, representing the keycodes which
+ * were simultaneously pressed during that scan.
+ *
+ * This function works through each set and generates ASCII characters
+ * for each. Not that one set may produce more than one ASCII characters -
+ * for example holding down 'd' and 'f' at the same time will generate
+ * two ASCII characters.
+ *
+ * Note: if fifo_cnt is 0, we will tell the input layer that no keys are
+ * pressed.
+ *
+ * @param priv Keyboard private data
+ * @param fifo_cnt Number of entries in the keyboard fifo
+ */
+static void process_fifo(struct tegra_kbd_priv *priv, int fifo_cnt)
+{
+ int fifo[KBC_MAX_KPENT];
+ int cnt = 0;
+
+ /* Always call input_send_keycodes() at least once */
+ do {
+ if (fifo_cnt)
+ cnt = tegra_kbc_find_keys(priv, fifo, KBC_MAX_KPENT);
+
+ input_send_keycodes(priv->input, fifo, cnt);
+ } while (--fifo_cnt > 0);
+}
+
+/**
+ * Check the keyboard controller and emit ASCII characters for any keys that
+ * are pressed.
+ *
+ * @param priv Keyboard private data
+ */
+static void check_for_keys(struct tegra_kbd_priv *priv)
+{
+ int fifo_cnt;
+
+ if (!priv->first_scan &&
+ get_timer(priv->last_poll_ms) < KBC_REPEAT_RATE_MS)
+ return;
+ priv->last_poll_ms = get_timer(0);
+ priv->first_scan = 0;
+
+ /*
+ * Once we get here we know the keyboard has been scanned. So if there
+ * scan waiting for us, we know that nothing is held down.
+ */
+ fifo_cnt = (readl(&priv->kbc->interrupt) >> 4) & 0xf;
+ process_fifo(priv, fifo_cnt);
+}
+
+/**
+ * In order to detect keys pressed on boot, wait for the hardware to
+ * complete scanning the keys. This includes time to transition from
+ * Wkup mode to Continous polling mode and the repoll time. We can
+ * deduct the time that's already elapsed.
+ *
+ * @param priv Keyboard private data
+ */
+static void kbd_wait_for_fifo_init(struct tegra_kbd_priv *priv)
+{
+ if (!priv->inited) {
+ unsigned long elapsed_time;
+ long delay_ms;
+
+ elapsed_time = get_timer(priv->start_time_ms);
+ delay_ms = priv->init_dly_ms - elapsed_time;
+ if (delay_ms > 0) {
+ udelay(delay_ms * 1000);
+ debug("%s: delay %ldms\n", __func__, delay_ms);
+ }
+
+ priv->inited = 1;
+ }
+}
+
+/**
+ * Check the tegra keyboard, and send any keys that are pressed.
+ *
+ * This is called by input_tstc() and input_getc() when they need more
+ * characters
+ *
+ * @param input Input configuration
+ * @return 1, to indicate that we have something to look at
+ */
+static int tegra_kbc_check(struct input_config *input)
+{
+ struct tegra_kbd_priv *priv = dev_get_priv(input->dev);
+
+ kbd_wait_for_fifo_init(priv);
+ check_for_keys(priv);
+
+ return 1;
+}
+
+/* configures keyboard GPIO registers to use the rows and columns */
+static void config_kbc_gpio(struct tegra_kbd_priv *priv, struct kbc_tegra *kbc)
+{
+ int i;
+
+ for (i = 0; i < KBC_MAX_GPIO; i++) {
+ u32 row_cfg, col_cfg;
+ u32 r_shift = 5 * (i % 6);
+ u32 c_shift = 4 * (i % 8);
+ u32 r_mask = 0x1f << r_shift;
+ u32 c_mask = 0xf << c_shift;
+ u32 r_offs = i / 6;
+ u32 c_offs = i / 8;
+
+ row_cfg = readl(&kbc->row_cfg[r_offs]);
+ col_cfg = readl(&kbc->col_cfg[c_offs]);
+
+ row_cfg &= ~r_mask;
+ col_cfg &= ~c_mask;
+
+ if (i < priv->matrix.num_rows) {
+ row_cfg |= ((i << 1) | 1) << r_shift;
+ } else {
+ col_cfg |= (((i - priv->matrix.num_rows) << 1) | 1)
+ << c_shift;
+ }
+
+ writel(row_cfg, &kbc->row_cfg[r_offs]);
+ writel(col_cfg, &kbc->col_cfg[c_offs]);
+ }
+}
+
+/**
+ * Start up the keyboard device
+ */
+static void tegra_kbc_open(struct tegra_kbd_priv *priv)
+{
+ struct kbc_tegra *kbc = priv->kbc;
+ unsigned int scan_period;
+ u32 val;
+
+ /*
+ * We will scan at twice the keyboard repeat rate, so that there is
+ * always a scan ready when we check it in check_for_keys().
+ */
+ scan_period = KBC_REPEAT_RATE_MS / 2;
+ writel(scan_period * KBC_CLOCK_KHZ, &kbc->rpt_dly);
+ writel(scan_period * KBC_CLOCK_KHZ, &kbc->init_dly);
+ /*
+ * Before reading from the keyboard we must wait for the init_dly
+ * plus the rpt_delay, plus 2ms for the row scan time.
+ */
+ priv->init_dly_ms = scan_period * 2 + 2;
+
+ val = KBC_DEBOUNCE_COUNT << KBC_DEBOUNCE_CNT_SHIFT;
+ val |= 1 << KBC_FIFO_TH_CNT_SHIFT; /* fifo interrupt threshold */
+ val |= KBC_CONTROL_KBC_EN; /* enable */
+ writel(val, &kbc->control);
+
+ priv->start_time_ms = get_timer(0);
+ priv->last_poll_ms = get_timer(0);
+ priv->next_repeat_ms = priv->last_poll_ms;
+ priv->first_scan = 1;
+}
+
+static int tegra_kbd_start(struct udevice *dev)
+{
+ struct tegra_kbd_priv *priv = dev_get_priv(dev);
+
+ /* Set up pin mux and enable the clock */
+ funcmux_select(PERIPH_ID_KBC, FUNCMUX_DEFAULT);
+ clock_enable(PERIPH_ID_KBC);
+ config_kbc_gpio(priv, priv->kbc);
+
+ tegra_kbc_open(priv);
+ debug("%s: Tegra keyboard ready\n", __func__);
+
+ return 0;
+}
+
+/**
+ * Set up the tegra keyboard. This is called by the stdio device handler
+ *
+ * We want to do this init when the keyboard is actually used rather than
+ * at start-up, since keyboard input may not currently be selected.
+ *
+ * Once the keyboard starts there will be a period during which we must
+ * wait for the keyboard to init. We do this only when a key is first
+ * read - see kbd_wait_for_fifo_init().
+ *
+ * @return 0 if ok, -ve on error
+ */
+static int tegra_kbd_probe(struct udevice *dev)
+{
+ struct tegra_kbd_priv *priv = dev_get_priv(dev);
+ struct keyboard_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct stdio_dev *sdev = &uc_priv->sdev;
+ struct input_config *input = &uc_priv->input;
+ int ret;
+
+ priv->kbc = dev_read_addr_ptr(dev);
+ if ((fdt_addr_t)priv->kbc == FDT_ADDR_T_NONE) {
+ debug("%s: No keyboard register found\n", __func__);
+ return -EINVAL;
+ }
+ input_set_delays(input, KBC_REPEAT_DELAY_MS, KBC_REPEAT_RATE_MS);
+
+ /* Decode the keyboard matrix information (16 rows, 8 columns) */
+ ret = key_matrix_init(&priv->matrix, 16, 8, 1);
+ if (ret) {
+ debug("%s: Could not init key matrix: %d\n", __func__, ret);
+ return ret;
+ }
+ ret = key_matrix_decode_fdt(dev, &priv->matrix);
+ if (ret) {
+ debug("%s: Could not decode key matrix from fdt: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ input_add_tables(input, false);
+ if (priv->matrix.fn_keycode) {
+ ret = input_add_table(input, KEY_FN, -1,
+ priv->matrix.fn_keycode,
+ priv->matrix.key_count);
+ if (ret) {
+ debug("%s: input_add_table() failed\n", __func__);
+ return ret;
+ }
+ }
+
+ /* Register the device. init_tegra_keyboard() will be called soon */
+ priv->input = input;
+ input->dev = dev;
+ input->read_keys = tegra_kbc_check;
+ strcpy(sdev->name, "tegra-kbc");
+ ret = input_stdio_register(sdev);
+ if (ret) {
+ debug("%s: input_stdio_register() failed\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct keyboard_ops tegra_kbd_ops = {
+ .start = tegra_kbd_start,
+};
+
+static const struct udevice_id tegra_kbd_ids[] = {
+ { .compatible = "nvidia,tegra20-kbc" },
+ { }
+};
+
+U_BOOT_DRIVER(tegra_kbd) = {
+ .name = "tegra_kbd",
+ .id = UCLASS_KEYBOARD,
+ .of_match = tegra_kbd_ids,
+ .probe = tegra_kbd_probe,
+ .ops = &tegra_kbd_ops,
+ .priv_auto = sizeof(struct tegra_kbd_priv),
+};
diff --git a/roms/u-boot/drivers/input/twl4030.c b/roms/u-boot/drivers/input/twl4030.c
new file mode 100644
index 000000000..3a1c46b30
--- /dev/null
+++ b/roms/u-boot/drivers/input/twl4030.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TWL4030 input
+ *
+ * Copyright (C) 2015 Paul Kocialkowski <contact@paulk.fr>
+ */
+
+#include <twl4030.h>
+
+int twl4030_input_power_button(void)
+{
+ u8 data;
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_STS_HW_CONDITIONS, &data);
+
+ if (data & TWL4030_PM_MASTER_STS_HW_CONDITIONS_PWON)
+ return 1;
+
+ return 0;
+}
+
+int twl4030_input_charger(void)
+{
+ u8 data;
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_STS_HW_CONDITIONS, &data);
+
+ if (data & TWL4030_PM_MASTER_STS_HW_CONDITIONS_CHG)
+ return 1;
+
+ return 0;
+}
+
+int twl4030_input_usb(void)
+{
+ u8 data;
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER,
+ TWL4030_PM_MASTER_STS_HW_CONDITIONS, &data);
+
+ if (data & TWL4030_PM_MASTER_STS_HW_CONDITIONS_USB ||
+ data & TWL4030_PM_MASTER_STS_HW_CONDITIONS_VBUS)
+ return 1;
+
+ return 0;
+}
+
+int twl4030_keypad_scan(unsigned char *matrix)
+{
+ u8 data;
+ u8 c, r;
+
+ twl4030_i2c_read_u8(TWL4030_CHIP_KEYPAD,
+ TWL4030_KEYPAD_KEYP_CTRL_REG, &data);
+
+ data |= TWL4030_KEYPAD_CTRL_SOFT_NRST | TWL4030_KEYPAD_CTRL_KBD_ON;
+ data &= ~TWL4030_KEYPAD_CTRL_SOFTMODEN;
+
+ twl4030_i2c_write_u8(TWL4030_CHIP_KEYPAD,
+ TWL4030_KEYPAD_KEYP_CTRL_REG, data);
+
+ for (c = 0; c < 8; c++) {
+ data = 0xff & ~(1 << c);
+ twl4030_i2c_write_u8(TWL4030_CHIP_KEYPAD,
+ TWL4030_KEYPAD_KBC_REG, data);
+
+ data = 0xff;
+ twl4030_i2c_read_u8(TWL4030_CHIP_KEYPAD,
+ TWL4030_KEYPAD_KBR_REG, &data);
+
+ for (r = 0; r < 8; r++)
+ matrix[c * 8 + r] = !(data & (1 << r));
+ }
+
+ data = 0xff & ~(TWL4030_KEYPAD_CTRL_SOFT_NRST);
+ twl4030_i2c_write_u8(TWL4030_CHIP_KEYPAD,
+ TWL4030_KEYPAD_KEYP_CTRL_REG, data);
+
+ return 0;
+}
+
+int twl4030_keypad_key(unsigned char *matrix, u8 c, u8 r)
+{
+ return matrix[c * 8 + r];
+}
diff --git a/roms/u-boot/drivers/input/twl6030.c b/roms/u-boot/drivers/input/twl6030.c
new file mode 100644
index 000000000..76bd3488f
--- /dev/null
+++ b/roms/u-boot/drivers/input/twl6030.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TWL6030 input
+ *
+ * Copyright (C) 2016 Paul Kocialkowski <contact@paulk.fr>
+ */
+
+#include <twl6030.h>
+
+int twl6030_input_power_button(void)
+{
+ u8 value;
+
+ twl6030_i2c_read_u8(TWL6030_CHIP_PM, TWL6030_STS_HW_CONDITIONS, &value);
+
+ /* Power button is active low. */
+ if (value & TWL6030_STS_HW_CONDITIONS_PWRON)
+ return 0;
+
+ return 1;
+}
+
+int twl6030_input_charger(void)
+{
+ u8 value;
+
+ twl6030_i2c_read_u8(TWL6030_CHIP_CHARGER, TWL6030_CONTROLLER_STAT1,
+ &value);
+
+ if (value & TWL6030_CONTROLLER_STAT1_VAC_DET)
+ return 1;
+
+ return 0;
+}
+
+int twl6030_input_usb(void)
+{
+ u8 value;
+
+ twl6030_i2c_read_u8(TWL6030_CHIP_CHARGER, TWL6030_CONTROLLER_STAT1,
+ &value);
+
+ if (value & TWL6030_CONTROLLER_STAT1_VBUS_DET)
+ return 1;
+
+ return 0;
+}