Sync to trunk revision 63922.
[reactos.git] / boot / armllb / hw / versatile / hwkmi.c
1 /*
2 * PROJECT: ReactOS Boot Loader
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: boot/armllb/hw/versatile/hwkmi.c
5 * PURPOSE: LLB KMI Support for Versatile
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 #include "precomp.h"
10
11 //
12 // Control Register Bits
13 //
14 #define KMICR_TYPE (1 << 5)
15 #define KMICR_RXINTREN (1 << 4)
16 #define KMICR_TXINTREN (1 << 3)
17 #define KMICR_EN (1 << 2)
18 #define KMICR_FD (1 << 1)
19 #define KMICR_FC (1 << 0)
20
21 //
22 // Status Register Bits
23 //
24 #define KMISTAT_TXEMPTY (1 << 6)
25 #define KMISTAT_TXBUSY (1 << 5)
26 #define KMISTAT_RXFULL (1 << 4)
27 #define KMISTAT_RXBUSY (1 << 3)
28 #define KMISTAT_RXPARITY (1 << 2)
29 #define KMISTAT_IC (1 << 1)
30 #define KMISTAT_ID (1 << 0)
31
32 //
33 // KMI Registers
34 //
35 #define PL050_KMICR (LlbHwVersaKmiBase + 0x00)
36 #define PL050_KMISTAT (LlbHwVersaKmiBase + 0x04)
37 #define PL050_KMIDATA (LlbHwVersaKmiBase + 0x08)
38 #define PL050_KMICLKDIV (LlbHwVersaKmiBase + 0x0c)
39 static const ULONG LlbHwVersaKmiBase = 0x10006000;
40
41 //
42 // PS/2 Commands/Requests
43 //
44 #define PS2_O_RESET 0xff
45 #define PS2_O_RESEND 0xfe
46 #define PS2_O_DISABLE 0xf5
47 #define PS2_O_ENABLE 0xf4
48 #define PS2_O_ECHO 0xee
49 #define PS2_O_SET_DEFAULT 0xf6
50 #define PS2_O_SET_RATE_DELAY 0xf3
51 #define PS2_O_SET_SCANSET 0xf0
52 #define PS2_O_INDICATORS 0xed
53 #define PS2_I_RESEND 0xfe
54 #define PS2_I_DIAGFAIL 0xfd
55 #define PS2_I_ACK 0xfa
56 #define PS2_I_BREAK 0xf0
57 #define PS2_I_ECHO 0xee
58 #define PS2_I_BAT_OK 0xaa
59
60 /* FUNCTIONS ******************************************************************/
61
62 VOID
63 NTAPI
64 LlbHwVersaKmiSendAndWait(IN ULONG Value)
65 {
66 volatile int i = 1000;
67
68 /* Send the value */
69 LlbHwKbdSend(Value);
70
71 /* Wait a bit */
72 while (--i);
73
74 /* Now make sure we received an ACK */
75 if (LlbHwKbdRead() != PS2_I_ACK) DbgPrint("PS/2 FAILURE!\n");
76 }
77
78 VOID
79 NTAPI
80 LlbHwVersaKmiInitialize(VOID)
81 {
82 UCHAR Divisor;
83
84 /* Setup divisor and enable KMI */
85 Divisor = (LlbHwGetPClk() / 8000000) - 1;
86 WRITE_REGISTER_UCHAR(PL050_KMICLKDIV, Divisor);
87 WRITE_REGISTER_UCHAR(PL050_KMICR, KMICR_EN);
88
89 /* Reset PS/2 controller */
90 LlbHwVersaKmiSendAndWait(PS2_O_RESET);
91 if (LlbHwKbdRead() != PS2_I_BAT_OK) DbgPrint("PS/2 RESET FAILURE!\n");
92
93 /* Send PS/2 Initialization Stream */
94 LlbHwVersaKmiSendAndWait(PS2_O_DISABLE);
95 LlbHwVersaKmiSendAndWait(PS2_O_SET_DEFAULT);
96 LlbHwVersaKmiSendAndWait(PS2_O_SET_SCANSET);
97 LlbHwVersaKmiSendAndWait(1);
98 LlbHwVersaKmiSendAndWait(PS2_O_ENABLE);
99 }
100
101 VOID
102 NTAPI
103 LlbHwKbdSend(IN ULONG Value)
104 {
105 ULONG Status;
106
107 /* Wait for ready signal */
108 do
109 {
110 /* Read TX buffer state */
111 Status = READ_REGISTER_UCHAR(PL050_KMISTAT);
112 } while (!(Status & KMISTAT_TXEMPTY));
113
114 /* Send value */
115 WRITE_REGISTER_UCHAR(PL050_KMIDATA, Value);
116 }
117
118 BOOLEAN
119 NTAPI
120 LlbHwKbdReady(VOID)
121 {
122 return READ_REGISTER_UCHAR(PL050_KMISTAT) & KMISTAT_RXFULL;
123 }
124
125 INT
126 NTAPI
127 LlbHwKbdRead(VOID)
128 {
129 /* Read current data on keyboard */
130 return READ_REGISTER_UCHAR(PL050_KMIDATA);
131 }
132
133 /* EOF */