This patch fixes the dbm690t keyboard not working issue. It should also
authorMarc Jones <marc.jones@amd.com>
Fri, 26 Sep 2008 19:15:38 +0000 (19:15 +0000)
committerMarc Jones <marc.jones@amd.com>
Fri, 26 Sep 2008 19:15:38 +0000 (19:15 +0000)
fix the a8n_e and any other it8712f SIO keyboard issues. The it8712f
requires an archaic PS/2 mode setting to the keyboard controller before
accessing the keyboard. Beyond that, I made the keyboard controller and
keyboard init more robust and added more informative debug output.

Signed-off-by: Marc Jones <marc.jones@amd.com>
Acked-by: Stefan Reinauer <stepan@coresystems.de>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3610 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1

src/pc80/keyboard.c
src/superio/ite/it8712f/superio.c

index 454de986ad6ebcb9864ba401a61b7d7c3b19e21f..4009a4502db53b6f442205c66167f826262d96c4 100644 (file)
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ * Copyright (C) ???? Ollie Lo <ollielo@hotmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+
 #include <console/console.h>
 #include <pc80/keyboard.h>
 #include <device/device.h>
 #include <arch/io.h>
 
-static int kbd_empty_input_buffer(void)
+static int kbc_input_buffer_empty(void)
 {
-       unsigned long timeout;
+       u32 timeout;
        for(timeout = 1000000; timeout && (inb(0x64) & 0x02); timeout--) {
-               post_code(0);
+               inb(0x80);
+       }
+
+       if (!timeout) {
+               printk_err("Unexpected Keyboard controller input buffer full\n");
        }
        return !!timeout;
 }
 
-static int kbd_empty_output_buffer(void)
+
+static int kbc_output_buffer_full(void)
 {
-       unsigned long timeout;
+       u32 timeout;
        for(timeout = 1000000; timeout && ((inb(0x64) & 0x01) == 0); timeout--) {
-               post_code(0);
+               inb(0x80);
+       }
+
+       if (!timeout) {
+               printk_err("Keyboard controller output buffer result timeout\n");
        }
        return !!timeout;
 }
 
-/* much better keyboard init courtesy ollie@sis.com.tw 
-   TODO: Typematic Setting, the keyboard is too slow for me */
-static void pc_keyboard_init(struct pc_keyboard *keyboard)
+
+static int kbc_cleanup_buffers(void)
+{
+       u32 timeout;
+       for(timeout = 1000000; timeout && (inb(0x64) & 0x03); timeout--) {
+               inb(0x60);
+       }
+
+       if (!timeout) {
+               printk_err("Couldn't cleanup the keyboard controller buffers\n");
+               printk_err("0x64: 0x%x, 0x60: 0x%x\n", inb(0x64), inb(0x60));
+       }
+       return !!timeout;
+}
+
+
+static u8 send_keyboard(u8 command)
 {
-       unsigned char regval;
+       u8 regval = 0;
+       u8 resend = 10;
+
+       do {
+               if (!kbc_input_buffer_empty()) return 0;
+               outb(command, 0x60);
+               if (!kbc_output_buffer_full()) return 0;
+               regval = inb(0x60);
+               --resend;
+       } while (regval == 0xFE && resend > 0);
 
+       return regval;
+}
+
+
+static void pc_keyboard_init(struct pc_keyboard *keyboard)
+{
+       u8 regval;
+       u8 resend;
        printk_debug("Keyboard init...\n");
-       /* send cmd = 0xAA, self test 8042 */
-       outb(0xaa, 0x64);
 
-       /* empty input buffer or any other command/data will be lost */
-       if (!kbd_empty_input_buffer()) {
-               printk_err("Keyboard input buffer would not empty\n");
-               return;
-       }
+       /* clean up any junk that might have been in the kbc */
+       if (!kbc_cleanup_buffers()) return;
 
-       /* empty output buffer or any other command/data will be lost */
-       if (!kbd_empty_output_buffer()) {
-               printk_err("Keyboard output buffer would not empty\n");
-               return;
-       }
+       /* reset/self test 8042 - send cmd 0xAA,  */
+       if (!kbc_input_buffer_empty()) return;
+       outb(0xAA, 0x64);
+       if (!kbc_output_buffer_full()) return;
 
-       /* read self-test result, 0x55 should be returned form 0x60 */
+       /* read self-test result, 0x55 is returned in the output buffer (0x60) */
        if ((regval = inb(0x60) != 0x55)) {
-               printk_err("Keyboard selftest failed\n");
+               printk_err("Keyboard Controller selftest failed: 0x%x\n", regval);
                return;
        }
 
-       /* enable keyboard interface */
-       outb(0x60, 0x64);
-       kbd_empty_input_buffer();
+       /* Enable keyboard interface - No IRQ*/
+       resend = 10;
+       regval = 0;
+       do {
+               if (!kbc_input_buffer_empty()) return;
+               outb(0x60, 0x64);
+               if (!kbc_input_buffer_empty()) return;
+               outb(0x20, 0x60);       /* send cmd: enable keyboard and IRQ 1 */
+               u8 resend = 10;
+               if ((inb(0x64) & 0x01)) {
+                       regval = inb(0x60);
+               }
+               --resend;
+       } while (regval == 0xFE && resend > 0);
 
-       /* send cmd: enable IRQ 1 */
-       outb(0x61, 0x60);
-       kbd_empty_input_buffer();
+       /* clean up any junk that might have been in the keyboard */
+       if (!kbc_cleanup_buffers()) return;
 
-       /* reset kerboard and self test  (keyboard side) */
-       outb(0xff, 0x60);
+       /* reset keyboard and self test (keyboard side) */
+       regval = send_keyboard(0xFF);
+       if (regval != 0xFA) {
+               printk_err("Keyboard selftest failed ACK: 0x%x\n", regval);
+               return;
+       }
+       if (!kbc_output_buffer_full()) return;
+       regval = inb(0x60);
+       if (regval != 0xAA) {
+               printk_err("Keyboard selftest failed: 0x%x\n", regval);
+               return;
+       }
 
-       /* empty inut bufferm or any other command/data will be lost */
-       kbd_empty_input_buffer();
+       /*
+        * The following set scancode stuff is what normal BIOS do. It could be
+        * argued that coreboot shouldn't set the scan code.....
+        */
 
-       /* empty output buffer or any other command/data will be lost */
-       kbd_empty_output_buffer();
+       /* disable the keyboard */
+       regval = send_keyboard(0xF5);
+       if (regval != 0xFA) {
+               printk_err("Keyboard disable failed ACK: 0x%x\n", regval);
+               return;
+       }
 
-       if ((regval = inb(0x60) != 0xfa))
+       /* Set scancode command */
+       regval = send_keyboard(0xF0);
+       if (regval != 0xFA) {
+               printk_err("Keyboard set scancode cmd failed ACK: 0x%x\n", regval);
                return;
+       }
+       /* Set scancode mode 2 */
+       regval = send_keyboard(0x02);
+       if (regval != 0xFA) {
+               printk_err("Keyboard set scancode mode failed ACK: 0x%x\n", regval);
+               return;
+       }
 
-       kbd_empty_output_buffer();
-       if ((regval = inb(0x60) != 0xaa))
+       /* enable the keyboard */
+       regval = send_keyboard(0xF4);
+       if (regval != 0xFA) {
+               printk_err("Keyboard enable failed ACK: 0x%x\n", regval);
                return;
+       }
+
+       /* All is well - enable keyboard interface */
+       resend = 10;
+       regval = 0;
+       do {
+               if (!kbc_input_buffer_empty()) return;
+               outb(0x60, 0x64);
+               if (!kbc_input_buffer_empty()) return;
+               outb(0x61, 0x60);       /* send cmd: enable keyboard and IRQ 1 */
+               if ((inb(0x64) & 0x01)) {
+                       regval = inb(0x60);
+               }
+               --resend;
+       } while (regval == 0xFE && resend > 0);
 }
 
+
 void init_pc_keyboard(unsigned port0, unsigned port1, struct pc_keyboard *kbd)
 {
        if ((port0 == 0x60) && (port1 == 0x64)) {
                pc_keyboard_init(kbd);
        }
 }
+
+/*
+ * Support PS/2 mode -  oddball SIOs(KBC) need this setup
+ * Not well documented. Google - 0xcb keyboard controller
+ * This is called before pc_keyboard_init().
+ */
+void set_kbc_ps2_mode()
+{
+       /* clean up any junk that might have been in the kbc */
+       if (!kbc_cleanup_buffers()) return;
+
+       /* reset/self test 8042 before we can do anything */
+       if (!kbc_input_buffer_empty()) return;
+       outb(0xAA, 0x64);
+       if (!kbc_output_buffer_full()) return;
+
+       /* read self-test result, 0x55 is returned in the output buffer (0x60) */
+       if ((inb(0x60) != 0x55)) {
+               printk_err("Keyboard Controller selftest failed\n");
+               return;
+       }
+
+       /* Support PS/2 mode */
+       if (!kbc_input_buffer_empty()) return;
+       outb(0xcb, 0x64);
+       if (!kbc_input_buffer_empty()) return;
+       outb(0x01, 0x60);
+       kbc_cleanup_buffers();
+}
index 9f848687ec3fde9fe5216a6b9d94570f8fadf841..c90c9009142d7f2de0bf409f3e450ec76220cb7a 100644 (file)
@@ -76,6 +76,7 @@ static void it8712f_init(device_t dev)
        case IT8712F_KBCK:
                res0 = find_resource(dev, PNP_IDX_IO0);
                res1 = find_resource(dev, PNP_IDX_IO1);
+               set_kbc_ps2_mode();
                init_pc_keyboard(res0->base, res1->base, &conf->keyboard);
                break;
        case IT8712F_KBCM: /* TODO. */