PL050 PS/2 Controller: Difference between revisions
[unchecked revision] | [unchecked revision] |
Content deleted Content added
Shifting PL050 stuff |
m Bot: Replace deprecated source tag with syntaxhighlight |
||
(10 intermediate revisions by 7 users not shown) | |||
Line 1:
{{
PL050 provides a keyboard or mouse interface(KMI) that is IBM PS/2 or AT-compatible and is licensed by ARM.
<br>There are several registers to communicate with the controller, some of them are described in details further.
{| border="1" cellspacing="0" cellpadding="5" align="center"
! Address
! Type
! Description
|-
! Base + 0x00
! rw
! Control register.
|-
! Base + 0x04
! r
! Status register.
|-
! Base + 0x08
! rw
! Received data (read)/ Data to be transmitted (write).
|-
! Base + 0x0c
! rw
! Clock divisor register.
|-
! Base + 0x10
! r
! Interrupt status register.
|}
The table above could be represented as a C struct:
<syntaxhighlight lang="c">
// PL050(KMI) bases under Integrator/CP compatible board.
#define KMI_KB_BASE 0x18000000 // keyboard
#define KMI_MS_BASE 0x19000000 // mouse
typedef struct _KMI_MMIO {
uint32 cr; // control register (rw)
uint32 stat; // status register (r)
uint32 data; // data register (rw)
uint32 clk; // clock divisor register (rw)
uint32 ir; // interrupt control register (r)
} KMI_MMIO;
// Note: set a valid pointer before initialising it.
KMI_MMIO volatile *mmio;
</syntaxhighlight>
''The above uses memory mapped input/output (MMIO), but other architectures may use I/O ports instead or a combination of I/O ports and MMIO for example the X84/64. So understanding your platform is very important to understand how to proceed in talking to the devices.''
So first, configure the PL050 by enabling it. Let's take a look at control register. It contains five different bit fields:
{| border="1" cellspacing="0" cellpadding="5" align="center"
! Bits
! Name
! Description
|-
! 0
! FKMIC
! The force KMI clock LOW bit field is used to force the PrimeCell KMI clock pad LOW regardless of the state of the KMI FSM.
|-
! 1
! FKMID
! The force KMI data LOW bit field is used to force the PrimeCell KMI data pad LOW regardless of the state of the KMI finite state machine (FSM).
|-
! 2
! KmiEn
! The enable PrimeCell KMI bit field is used to enable the KMI.
|-
! 3
! KMITXINTREn
! Enable transmitter interrupt. This bit field is used to enable the PrimeCell KMI transmitter interrupt.
|-
! 4
! KMIRXINTREn
! Enable receiver interrupt. This bit field is used to enable the PrimeCell KMI receiver interrupt.
|-
! 5
! KMITYPE
! 0 = PS2/AT mode (default), 1 = No line control bit mode.
|-
! 6-7
! -
! Reserved. Read unpredictable.
|}
Setting the ''KmiEn'' will enable KMI. After that it's needed to setup a receiver interrupt, all it's needed is to set ''KMIRXINTREn'' and configure system's interrupt controller to call the callback which processes the input data.
<syntaxhighlight lang="c">
void kmi_init(device_t* dev)
{
mmio->cr = (1 << 2) | (1 << 4);
}
</syntaxhighlight>
The core function to implement is a one to send commands to PS/2 devices, like keyboard. For that the ''data register'' is used. To send a command, set a command id to data register and wait for an answer. The informations which helps to understand when is located in a ''status register''. Data register does not contain any fields, just used to forward data, while it's interesting to take a detailed look at the status register:
{| border="1" cellspacing="0" cellpadding="5" align="center"
! Bits
! Name
! Description
|-
! 0
! KMID
! This bit reflects the status of the KMIDATAIN line after synchronizing.
|-
! 1
! KMIC
! This bit reflects the status of the KMICLKIN line after synchronizing and sampling.
|-
! 2
! RXPARITY
! This bit reflects the parity bit for the last received data byte (odd parity).
|-
! 3
! RXBUSY
! This bit indicates that the PrimeCell KMI is currently receiving data. 0 = idle, 1 = receiving data.
|-
! 4
! RXFULL
! This bit indicates that the receiver register is full and ready to be read. 0 = receive register empty, 1 = receive register full, ready to be read.
|-
! 5
! TXBUSY
! This bit indicates that the PrimeCell KMI is currently sending data. 0 = idle, 1 = currently sending data.
|-
! 6
! TXEMPTY
! This bit indicates that the transmit register is empty and ready to transmit. 0 = transmit register full, 1 = transmit register empty, ready to be written.
|-
! 7
! -
! Reserved. Read unpredictable.
|}
<br>
<syntaxhighlight lang="c">
void kmi_send(uint8 cmd)
{
kmi->data = cmd;
while ((registers->stat) & (1 << 5)); // wait while data is sending (TXBUSY)
ASSERT(registers->data == 0xfa);
}
</syntaxhighlight>
These functions are base ones to communicate with PS/2 devices. Using this functions you can enable mouse by writing ''0xF4'', more information about commands could be found at [[PS/2 Keyboard]] and [[PS/2 Mouse]]
<syntaxhighlight lang="c">
int kmi_setup_mouse()
{
kmi_send(0xF4);
}
</syntaxhighlight>
Note that, due to the complexity of the Raspberry Pi's USB interface and Qemu's versatilepb being the go-to Pi emulator before raspi2 was developed, some older Pi programs will use the PL050 to easily enable debugging in Qemu. No Pi device so far has PS/2 compatibility hardware.
==See Also==
Line 24 ⟶ 156:
*[[PS/2 Mouse]]
===External Links===
*[
[[Category:ARM]]
|