coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
keyboard.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
4 #include <pc80/keyboard.h>
5 #include <device/device.h>
6 #include <arch/io.h>
7 #include <delay.h>
8 #include <types.h>
9 #include <acpi/acpi.h>
10 
11 #define KBD_DATA 0x60
12 #define KBD_COMMAND 0x64
13 #define KBD_STATUS 0x64
14 #define KBD_IBF (1 << 1) // 1: input buffer full (data ready for ec)
15 #define KBD_OBF (1 << 0) // 1: output buffer full (data ready for host)
16 
17 // Keyboard Controller Commands
18 #define KBC_CMD_READ_COMMAND 0x20 // Read command byte
19 #define KBC_CMD_WRITE_COMMAND 0x60 // Write command byte
20 #define KBC_CMD_AUX_ENABLE 0xA8 // Auxiliary Interface enable
21 #define KBC_CMD_AUX_TEST 0xA9 // Auxiliary Interface test
22 #define KBC_CMD_SELF_TEST 0xAA // Controller self-test
23 #define KBC_CMD_KBD_TEST 0xAB // Keyboard Interface test
24 
25 /* The Keyboard controller command byte
26  * BIT | Description
27  * ----+-------------------------------------------------------
28  * 7 | reserved, must be zero
29  * 6 | XT Translation, (1 = on, 0 = off)
30  * 5 | Disable Mouse Port (1 = disable, 0 = enable)
31  * 4 | Disable Keyboard Port (1 = disable, 0 = enable)
32  * 3 | reserved, must be zero
33  * 2 | System Flag (1 = self-test passed. DO NOT SET TO ZERO)
34  * 1 | Mouse Port Interrupts (1 = enable, 0 = disable)
35  * 0 | Keyboard Port Interrupts (1 = enable, 0 = disable)
36  */
37 
38 // Keyboard Controller Replies
39 #define KBC_REPLY_SELFTEST_OK 0x55 // controller self-test succeeded
40 
41 //
42 // Keyboard Replies
43 //
44 #define KBD_REPLY_POR 0xAA // Power on reset
45 #define KBD_REPLY_ACK 0xFA // Command ACK
46 #define KBD_REPLY_RESEND 0xFE // Command NACK, send command again
47 
48 /* Wait 400ms for keyboard controller answers */
49 #define KBC_TIMEOUT_IN_MS 400
50 
51 static int kbc_input_buffer_empty(void)
52 {
53  u32 timeout;
54 
55  for (timeout = KBC_TIMEOUT_IN_MS;
56  timeout && (inb(KBD_STATUS) & KBD_IBF); timeout--)
57  mdelay(1);
58 
59  if (!timeout)
61  "Unexpected Keyboard controller input buffer full\n");
62  return !!timeout;
63 }
64 
65 static int kbc_output_buffer_full(void)
66 {
67  u32 timeout;
68 
69  for (timeout = KBC_TIMEOUT_IN_MS;
70  timeout && ((inb(KBD_STATUS) & KBD_OBF) == 0); timeout--)
71  mdelay(1);
72 
73  if (!timeout)
75  "Keyboard controller output buffer result timeout\n");
76  return !!timeout;
77 }
78 
79 static int kbc_cleanup_buffers(void)
80 {
81  u32 timeout;
82 
83  for (timeout = KBC_TIMEOUT_IN_MS;
84  timeout && (inb(KBD_STATUS) & (KBD_OBF | KBD_IBF)); timeout--) {
85  mdelay(1);
86  inb(KBD_DATA);
87  }
88 
89  if (!timeout) {
91  "Couldn't cleanup the keyboard controller buffers\n");
92  printk(BIOS_ERR, "Status (0x%x): 0x%x, Buffer (0x%x): 0x%x\n",
94  }
95 
96  return !!timeout;
97 }
98 
99 static enum cb_err kbc_self_test(uint8_t probe_aux, uint8_t *aux_probe_result)
100 {
101  uint8_t self_test;
102  uint8_t byte;
103 
104  /* Set initial aux probe output value */
105  if (aux_probe_result)
106  *aux_probe_result = 0;
107 
108  /* Clean up any junk that might have been in the KBC.
109  * Both input and output buffers must be empty.
110  */
111  if (!kbc_cleanup_buffers())
113 
114  /* reset/self test 8042 - send cmd 0xAA */
116 
117  if (!kbc_output_buffer_full()) {
118  /* There probably is no keyboard controller. */
119  printk(BIOS_ERR, "Could not reset keyboard controller.\n");
121  }
122 
123  /* read self-test result, 0x55 is returned in the output buffer */
124  self_test = inb(KBD_DATA);
125 
126  if (self_test != 0x55) {
127  printk(BIOS_ERR, "Keyboard Controller self-test failed: 0x%x\n",
128  self_test);
130  }
131 
132  /* ensure the buffers are empty */
134 
135  /* keyboard interface test */
137 
138  if (!kbc_output_buffer_full()) {
139  printk(BIOS_ERR, "Keyboard Interface test timed out.\n");
141  }
142 
143  /* read test result, 0x00 should be returned in case of no failures */
144  self_test = inb(KBD_DATA);
145 
146  if (self_test != 0x00) {
147  printk(BIOS_ERR, "Keyboard Interface test failed: 0x%x\n",
148  self_test);
150  }
151 
152  if (probe_aux) {
153  /* aux interface detect */
155  if (!kbc_input_buffer_empty()) {
156  printk(BIOS_ERR, "Timeout waiting for controller during aux enable.\n");
158  }
160  if (!kbc_output_buffer_full()) {
161  printk(BIOS_ERR, "Timeout waiting for controller during aux probe.\n");
163  }
164 
165  byte = inb(KBD_DATA);
166  if (!(byte & (0x1 << 5))) {
167  printk(BIOS_DEBUG, "PS/2 auxiliary channel detected...\n");
168 
169  /* auxiliary interface test */
171 
172  if (!kbc_output_buffer_full()) {
173  printk(BIOS_ERR, "Auxiliary channel probe timed out.\n");
174  goto aux_failure;
175  }
176 
177  /* read test result, 0x00 should be returned in case of no failures */
178  self_test = inb(KBD_DATA);
179 
180  if (self_test != 0x00) {
181  printk(BIOS_ERR, "No device detected on auxiliary channel: 0x%x\n",
182  self_test);
183  goto aux_failure;
184  }
185 
186  printk(BIOS_DEBUG, "PS/2 device detected on auxiliary channel\n");
187  if (aux_probe_result)
188  *aux_probe_result = 1;
189  }
190  }
191 
192 aux_failure:
193 
194  return CB_SUCCESS;
195 }
196 
197 static u8 send_keyboard(u8 command)
198 {
199  u8 regval = 0;
200  u8 resend = 10;
201 
202  do {
203  if (!kbc_input_buffer_empty())
204  return 0;
205  outb(command, KBD_DATA);
206  /* the reset command takes much longer then normal commands and
207  * even worse, some keyboards do send the ACK _after_ doing the
208  * reset */
209  if (command == 0xFF) {
210  u8 retries;
211 
212  for (retries = 9; retries && !kbc_output_buffer_full();
213  retries--)
214  ;
215  }
216  if (!kbc_output_buffer_full()) {
218  "Could not send keyboard command %02x\n",
219  command);
220  return 0;
221  }
222  regval = inb(KBD_DATA);
223  --resend;
224  } while (regval == KBD_REPLY_RESEND && resend > 0);
225 
226  return regval;
227 }
228 
230 {
231  u8 retries;
232  u8 regval;
233  enum cb_err err;
234  uint8_t aux_dev_detected;
235 
236  if (!CONFIG(DRIVERS_PS2_KEYBOARD))
237  return 0;
238 
239  if (acpi_is_wakeup_s3())
240  return 0;
241 
242  printk(BIOS_DEBUG, "Keyboard init...\n");
243 
244  /* Run a keyboard controller self-test */
245  err = kbc_self_test(probe_aux, &aux_dev_detected);
246  /* Ignore interface failure as it's non-fatal. */
247  if (err != CB_SUCCESS && err != CB_KBD_INTERFACE_FAILURE)
248  return 0;
249 
250  /* Enable keyboard interface - No IRQ */
251  if (!kbc_input_buffer_empty())
252  return 0;
253  outb(0x60, KBD_COMMAND);
254  if (!kbc_input_buffer_empty())
255  return 0;
256  outb(0x20, KBD_DATA); /* send cmd: enable keyboard */
257  if (!kbc_input_buffer_empty()) {
258  printk(BIOS_INFO, "Timeout while enabling keyboard\n");
259  return 0;
260  }
261 
262  /* clean up any junk that might have been in the keyboard */
263  if (!kbc_cleanup_buffers())
264  return 0;
265 
266  /* reset keyboard and self test (keyboard side) */
267  regval = send_keyboard(0xFF);
268  if (regval == KBD_REPLY_RESEND) {
269  /* keeps sending RESENDs, probably no keyboard. */
270  printk(BIOS_INFO, "No PS/2 keyboard detected.\n");
271  return 0;
272  }
273 
274  if (regval != KBD_REPLY_ACK) {
275  printk(BIOS_ERR, "Keyboard reset failed ACK: 0x%x\n", regval);
276  return 0;
277  }
278 
279  /* the reset command takes some time, so wait a little longer */
280  for (retries = 9; retries && !kbc_output_buffer_full(); retries--)
281  ;
282 
283  if (!kbc_output_buffer_full()) {
284  printk(BIOS_ERR, "Timeout waiting for keyboard after reset.\n");
285  return 0;
286  }
287 
288  regval = inb(KBD_DATA);
289  if (regval != 0xAA) {
290  printk(BIOS_ERR, "Keyboard reset selftest failed: 0x%x\n",
291  regval);
292  return 0;
293  }
294 
295  /*
296  * The following set scancode stuff is what normal BIOS do. It could be
297  * argued that coreboot shouldn't set the scan code.....
298  */
299 
300  /* disable the keyboard */
301  regval = send_keyboard(0xF5);
302  if (regval != KBD_REPLY_ACK) {
303  printk(BIOS_ERR, "Keyboard disable failed ACK: 0x%x\n", regval);
304  return 0;
305  }
306 
307  /* Set scancode command */
308  regval = send_keyboard(0xF0);
309  if (regval != KBD_REPLY_ACK) {
310  printk(BIOS_ERR, "Keyboard set scancode cmd failed ACK: 0x%x\n",
311  regval);
312  return 0;
313  }
314  /* Set scancode mode 2 */
315  regval = send_keyboard(0x02);
316  if (regval != KBD_REPLY_ACK) {
318  "Keyboard set scancode mode failed ACK: 0x%x\n", regval);
319  return 0;
320  }
321 
322  /* All is well - enable keyboard interface */
323  if (!kbc_input_buffer_empty())
324  return 0;
325  outb(0x60, KBD_COMMAND);
326  if (!kbc_input_buffer_empty())
327  return 0;
328  outb(0x65, KBD_DATA); /* send cmd: enable keyboard and IRQ 1 */
329  if (!kbc_input_buffer_empty()) {
330  printk(BIOS_ERR, "Timeout during keyboard enable\n");
331  return 0;
332  }
333 
334  /* enable the keyboard */
335  regval = send_keyboard(0xF4);
336  if (regval != KBD_REPLY_ACK) {
337  printk(BIOS_ERR, "Keyboard enable failed ACK: 0x%x\n", regval);
338  return 0;
339  }
340 
341  printk(BIOS_DEBUG, "PS/2 keyboard initialized on primary channel\n");
342 
343  return aux_dev_detected;
344 }
345 
346 /*
347  * Support PS/2 mode - oddball SIOs(KBC) need this setup
348  * Not well documented. Google - 0xcb keyboard controller
349  * This is called before pc_keyboard_init().
350  */
352 {
353  enum cb_err err;
354 
355  /* Run a keyboard controller self-test */
356  err = kbc_self_test(0, NULL);
357  /* Ignore interface failure as it's non-fatal. */
358  if (err != CB_SUCCESS && err != CB_KBD_INTERFACE_FAILURE)
359  return;
360 
361  /* Support PS/2 mode */
362  if (!kbc_input_buffer_empty())
363  return;
364  outb(0xcb, KBD_COMMAND);
365 
366  if (!kbc_input_buffer_empty())
367  return;
368  outb(0x01, KBD_DATA);
369 
371 }
static int acpi_is_wakeup_s3(void)
Definition: acpi.h:9
cb_err
coreboot error codes
Definition: cb_err.h:15
@ CB_KBD_INTERFACE_FAILURE
Definition: cb_err.h:29
@ CB_SUCCESS
Call completed successfully.
Definition: cb_err.h:16
@ CB_KBD_CONTROLLER_FAILURE
Definition: cb_err.h:28
#define printk(level,...)
Definition: stdlib.h:16
void mdelay(unsigned int msecs)
Definition: delay.c:2
u8 inb(u16 port)
void outb(u8 val, u16 port)
@ CONFIG
Definition: dsi_common.h:201
#define KBC_CMD_SELF_TEST
Definition: keyboard.c:22
#define KBD_REPLY_ACK
Definition: keyboard.c:45
#define KBD_REPLY_RESEND
Definition: keyboard.c:46
#define KBC_CMD_READ_COMMAND
Definition: keyboard.c:18
#define KBC_TIMEOUT_IN_MS
Definition: keyboard.c:49
static int kbc_cleanup_buffers(void)
Definition: keyboard.c:79
#define KBC_CMD_AUX_ENABLE
Definition: keyboard.c:20
#define KBD_DATA
Definition: keyboard.c:11
#define KBD_STATUS
Definition: keyboard.c:13
static int kbc_input_buffer_empty(void)
Definition: keyboard.c:51
static enum cb_err kbc_self_test(uint8_t probe_aux, uint8_t *aux_probe_result)
Definition: keyboard.c:99
void set_kbc_ps2_mode(void)
Definition: keyboard.c:351
static int kbc_output_buffer_full(void)
Definition: keyboard.c:65
#define KBD_IBF
Definition: keyboard.c:14
static u8 send_keyboard(u8 command)
Definition: keyboard.c:197
#define KBD_OBF
Definition: keyboard.c:15
#define KBD_COMMAND
Definition: keyboard.c:12
#define KBC_CMD_AUX_TEST
Definition: keyboard.c:21
uint8_t pc_keyboard_init(uint8_t probe_aux)
Definition: keyboard.c:229
#define KBC_CMD_KBD_TEST
Definition: keyboard.c:23
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define BIOS_WARNING
BIOS_WARNING - Bad configuration.
Definition: loglevel.h:86
#define NULL
Definition: stddef.h:19
uint32_t u32
Definition: stdint.h:51
uint8_t u8
Definition: stdint.h:45
unsigned char uint8_t
Definition: stdint.h:8