Author: mjones
Date: 2008-09-26 21:15:38 +0200 (Fri, 26 Sep 2008)
New Revision: 3610

Modified:
   trunk/coreboot-v2/src/pc80/keyboard.c
   trunk/coreboot-v2/src/superio/ite/it8712f/superio.c
Log:
This patch fixes the dbm690t keyboard not working issue. It should also
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 <[EMAIL PROTECTED]>
Acked-by: Stefan Reinauer <[EMAIL PROTECTED]>



Modified: trunk/coreboot-v2/src/pc80/keyboard.c
===================================================================
--- trunk/coreboot-v2/src/pc80/keyboard.c       2008-09-26 18:56:11 UTC (rev 
3609)
+++ trunk/coreboot-v2/src/pc80/keyboard.c       2008-09-26 19:15:38 UTC (rev 
3610)
@@ -1,3 +1,24 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2008 Advanced Micro Devices, Inc.
+ * Copyright (C) ???? Ollie Lo <[EMAIL PROTECTED]>
+ *
+ * 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>
@@ -3,75 +24,163 @@
 #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 [EMAIL PROTECTED] 
-   TODO: Typematic Setting, the keyboard is too slow for me */
+
+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)
+{
+       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)
 {
-       unsigned char regval;
-
+       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)
 {
@@ -80,3 +189,32 @@
                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();
+}

Modified: trunk/coreboot-v2/src/superio/ite/it8712f/superio.c
===================================================================
--- trunk/coreboot-v2/src/superio/ite/it8712f/superio.c 2008-09-26 18:56:11 UTC 
(rev 3609)
+++ trunk/coreboot-v2/src/superio/ite/it8712f/superio.c 2008-09-26 19:15:38 UTC 
(rev 3610)
@@ -76,6 +76,7 @@
        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. */


--
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to