bc092b9
From 848bed9d92cf20e9f25db4c69a20efad23996ca0 Mon Sep 17 00:00:00 2001
bc092b9
From: Vladimir Serbinenko <phcoder@gmail.com>
bc092b9
Date: Mon, 8 May 2017 21:42:37 +0200
63f1a98
Subject: [PATCH 024/250] arm_coreboot: Support keyboard for vexpress.
bc092b9
bc092b9
---
bc092b9
 grub-core/Makefile.core.def        |   3 +
bc092b9
 grub-core/kern/arm/coreboot/init.c |   1 +
bc092b9
 grub-core/term/arm/pl050.c         | 189 +++++++++++++++++++++++++++++++++++++
ec4acbb
 grub-core/Makefile.am              |   1 +
bc092b9
 4 files changed, 194 insertions(+)
bc092b9
 create mode 100644 grub-core/term/arm/pl050.c
bc092b9
bc092b9
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
ec4acbb
index 6ade6e95057..6be6e7f61ee 100644
bc092b9
--- a/grub-core/Makefile.core.def
bc092b9
+++ b/grub-core/Makefile.core.def
bc092b9
@@ -160,6 +160,9 @@ kernel = {
bc092b9
   arm_coreboot = kern/arm/coreboot/coreboot.S;
bc092b9
   arm_coreboot = lib/fdt.c;
bc092b9
   arm_coreboot = bus/fdt.c;
bc092b9
+  arm_coreboot = term/ps2.c;
bc092b9
+  arm_coreboot = term/arm/pl050.c;
bc092b9
+  arm_coreboot = commands/keylayouts.c;
bc092b9
 
bc092b9
   terminfoinkernel = term/terminfo.c;
bc092b9
   terminfoinkernel = term/tparm.c;
bc092b9
diff --git a/grub-core/kern/arm/coreboot/init.c b/grub-core/kern/arm/coreboot/init.c
ec4acbb
index aec75c672a2..a06ccb72f42 100644
bc092b9
--- a/grub-core/kern/arm/coreboot/init.c
bc092b9
+++ b/grub-core/kern/arm/coreboot/init.c
bc092b9
@@ -133,6 +133,7 @@ grub_machine_init (void)
bc092b9
   grub_fdtbus_init (dtb, dtb_size);
bc092b9
 
bc092b9
   grub_machine_timer_init ();
bc092b9
+  grub_pl050_init ();
bc092b9
 }
bc092b9
 
bc092b9
 void
bc092b9
diff --git a/grub-core/term/arm/pl050.c b/grub-core/term/arm/pl050.c
bc092b9
new file mode 100644
ec4acbb
index 00000000000..e4cda305666
bc092b9
--- /dev/null
bc092b9
+++ b/grub-core/term/arm/pl050.c
bc092b9
@@ -0,0 +1,189 @@
bc092b9
+/*
bc092b9
+ *  GRUB  --  GRand Unified Bootloader
bc092b9
+ *  Copyright (C) 2007,2008,2009  Free Software Foundation, Inc.
bc092b9
+ *
bc092b9
+ *  GRUB is free software: you can redistribute it and/or modify
bc092b9
+ *  it under the terms of the GNU General Public License as published by
bc092b9
+ *  the Free Software Foundation, either version 3 of the License, or
bc092b9
+ *  (at your option) any later version.
bc092b9
+ *
bc092b9
+ *  GRUB is distributed in the hope that it will be useful,
bc092b9
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
bc092b9
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bc092b9
+ *  GNU General Public License for more details.
bc092b9
+ *
bc092b9
+ *  You should have received a copy of the GNU General Public License
bc092b9
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
bc092b9
+ */
bc092b9
+
bc092b9
+#include <grub/ps2.h>
bc092b9
+#include <grub/fdtbus.h>
bc092b9
+#include <grub/err.h>
bc092b9
+#include <grub/machine/kernel.h>
bc092b9
+#include <grub/at_keyboard.h>
bc092b9
+#include <grub/misc.h>
bc092b9
+#include <grub/term.h>
bc092b9
+#include <grub/time.h>
bc092b9
+#include <grub/ps2.h>
bc092b9
+#include <grub/fdtbus.h>
bc092b9
+
bc092b9
+static volatile grub_uint32_t *pl050_regs;
bc092b9
+
bc092b9
+struct grub_ps2_state ps2_state;
bc092b9
+
bc092b9
+static void
bc092b9
+keyboard_controller_wait_until_ready (void)
bc092b9
+{
bc092b9
+  while (! (pl050_regs[1] & 0x40));
bc092b9
+}
bc092b9
+
bc092b9
+static grub_uint8_t
bc092b9
+wait_ack (void)
bc092b9
+{
bc092b9
+  grub_uint64_t endtime;
bc092b9
+  grub_uint8_t ack;
bc092b9
+
bc092b9
+  endtime = grub_get_time_ms () + 20;
bc092b9
+  do
bc092b9
+    ack = pl050_regs[2];
bc092b9
+  while (ack != GRUB_AT_ACK && ack != GRUB_AT_NACK
bc092b9
+	 && grub_get_time_ms () < endtime);
bc092b9
+  return ack;
bc092b9
+}
bc092b9
+
bc092b9
+
bc092b9
+static int
bc092b9
+write_mode (int mode)
bc092b9
+{
bc092b9
+  unsigned i;
bc092b9
+  for (i = 0; i < GRUB_AT_TRIES; i++)
bc092b9
+    {
bc092b9
+      grub_uint8_t ack;
bc092b9
+      keyboard_controller_wait_until_ready ();
bc092b9
+      pl050_regs[2] = 0xf0;
bc092b9
+      keyboard_controller_wait_until_ready ();
bc092b9
+      pl050_regs[2] = mode;
bc092b9
+      keyboard_controller_wait_until_ready ();
bc092b9
+      ack = wait_ack ();
bc092b9
+      if (ack == GRUB_AT_NACK)
bc092b9
+	continue;
bc092b9
+      if (ack == GRUB_AT_ACK)
bc092b9
+	break;
bc092b9
+      return 0;
bc092b9
+    }
bc092b9
+
bc092b9
+  return (i != GRUB_AT_TRIES);
bc092b9
+}
bc092b9
+
bc092b9
+static int
bc092b9
+query_mode (void)
bc092b9
+{
bc092b9
+  grub_uint8_t ret;
bc092b9
+  int e;
bc092b9
+
bc092b9
+  e = write_mode (0);
bc092b9
+  if (!e)
bc092b9
+    return 0;
bc092b9
+
bc092b9
+  keyboard_controller_wait_until_ready ();
bc092b9
+
bc092b9
+  do
bc092b9
+    ret = pl050_regs[2];
bc092b9
+  while (ret == GRUB_AT_ACK);
bc092b9
+
bc092b9
+  /* QEMU translates the set even in no-translate mode.  */
bc092b9
+  if (ret == 0x43 || ret == 1)
bc092b9
+    return 1;
bc092b9
+  if (ret == 0x41 || ret == 2)
bc092b9
+    return 2;
bc092b9
+  if (ret == 0x3f || ret == 3)
bc092b9
+    return 3;
bc092b9
+  return 0;
bc092b9
+}
bc092b9
+
bc092b9
+static void
bc092b9
+set_scancodes (void)
bc092b9
+{
bc092b9
+  write_mode (2);
bc092b9
+  ps2_state.current_set = query_mode ();
bc092b9
+  grub_dprintf ("atkeyb", "returned set %d\n", ps2_state.current_set);
bc092b9
+  if (ps2_state.current_set == 2)
bc092b9
+    return;
bc092b9
+
bc092b9
+  write_mode (1);
bc092b9
+  ps2_state.current_set = query_mode ();
bc092b9
+  grub_dprintf ("atkeyb", "returned set %d\n", ps2_state.current_set);
bc092b9
+  if (ps2_state.current_set == 1)
bc092b9
+    return;
bc092b9
+  grub_dprintf ("atkeyb", "no supported scancode set found\n");
bc092b9
+}
bc092b9
+
bc092b9
+static void
bc092b9
+keyboard_controller_led (grub_uint8_t leds)
bc092b9
+{
bc092b9
+  keyboard_controller_wait_until_ready ();
bc092b9
+  pl050_regs[2] = 0xed;
bc092b9
+  keyboard_controller_wait_until_ready ();
bc092b9
+  pl050_regs[2] = leds & 0x7;
bc092b9
+}
bc092b9
+
bc092b9
+/* If there is a character pending, return it;
bc092b9
+   otherwise return GRUB_TERM_NO_KEY.  */
bc092b9
+static int
bc092b9
+grub_pl050_keyboard_getkey (struct grub_term_input *term __attribute__ ((unused)))
bc092b9
+{
bc092b9
+  grub_uint8_t at_key;
bc092b9
+  int ret;
bc092b9
+  grub_uint8_t old_led;
bc092b9
+
bc092b9
+  if (!(pl050_regs[1] & 0x10))
bc092b9
+    return -1;
bc092b9
+  at_key = pl050_regs[2];
bc092b9
+  old_led = ps2_state.led_status;
bc092b9
+
bc092b9
+  ret = grub_ps2_process_incoming_byte (&ps2_state, at_key);
bc092b9
+  if (old_led != ps2_state.led_status)
bc092b9
+    keyboard_controller_led (ps2_state.led_status);
bc092b9
+  return ret;
bc092b9
+}
bc092b9
+
bc092b9
+static struct grub_term_input grub_pl050_keyboard_term =
bc092b9
+  {
bc092b9
+    .name = "pl050_keyboard",
bc092b9
+    .getkey = grub_pl050_keyboard_getkey
bc092b9
+  };
bc092b9
+
bc092b9
+static grub_err_t
bc092b9
+pl050_attach(const struct grub_fdtbus_dev *dev)
bc092b9
+{
bc092b9
+  const grub_uint32_t *reg;
bc092b9
+  reg = grub_fdtbus_get_prop (dev, "reg", 0);
bc092b9
+
bc092b9
+  /* Mouse.  Nothing to do.  */
bc092b9
+  if (grub_be_to_cpu32 (*reg) == 0x7000)
bc092b9
+    return 0;
bc092b9
+
bc092b9
+  pl050_regs = grub_fdtbus_map_reg (dev, 0, 0);
bc092b9
+
bc092b9
+  if (!grub_fdtbus_is_mapping_valid (pl050_regs))
bc092b9
+    return grub_error (GRUB_ERR_IO, "could not map pl050");
bc092b9
+
bc092b9
+  ps2_state.at_keyboard_status = 0;
bc092b9
+  set_scancodes ();
bc092b9
+  keyboard_controller_led (ps2_state.led_status);
bc092b9
+
bc092b9
+  grub_term_register_input ("pl050_keyboard", &grub_pl050_keyboard_term);
bc092b9
+  return GRUB_ERR_NONE;
bc092b9
+}
bc092b9
+
bc092b9
+struct grub_fdtbus_driver pl050 =
bc092b9
+{
bc092b9
+  .compatible = "arm,pl050",
bc092b9
+  .attach = pl050_attach
bc092b9
+};
bc092b9
+
bc092b9
+void
bc092b9
+grub_pl050_init (void)
bc092b9
+{
bc092b9
+  grub_fdtbus_register (&pl050);
bc092b9
+}
ec4acbb
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
ec4acbb
index 147e6959c97..a2aaf9f54b0 100644
ec4acbb
--- a/grub-core/Makefile.am
ec4acbb
+++ b/grub-core/Makefile.am
ec4acbb
@@ -240,6 +240,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h
ec4acbb
 endif
ec4acbb
 
ec4acbb
 if COND_arm_coreboot
ec4acbb
+KERNEL_HEADER_FILES += $(top_builddir)/include/grub/keyboard_layouts.h
ec4acbb
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm/system.h
ec4acbb
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video.h
ec4acbb
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/video_fb.h
bc092b9
-- 
63f1a98
2.14.3
bc092b9