PL050 PS/2 Controller: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
(Shifting PL050 stuff)
 
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(10 intermediate revisions by 7 users not shown)
Line 1: Line 1:
{{stub}}
{{Stub}}
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"
Another example is the [[ARM_Overview|ARM]] Integrator/CP board which implements the PS/2 interface encapsulated in the PL050 (where the PL050 is analogous to the I8042) except you communicate with the PL050 differently than the I8042. But, after the PL050 is configured you then proceed with the PS/2 mouse protocol. For example:
! Address
<pre>
! Type
KMI_MMIO volatile *mmio;
! Description
uint32 tmp;
|-
mmio = (KMI_MMIO*)KMI_MS_BASE;
! Base + 0x00
mmio->cr = 0x4;
! rw
/* talk to the PS2 controller and enable it */
! Control register.
mmio->data = 0xF4;
|-
/* keyboard sends back ACK */
! Base + 0x04
while(!KMI_TXFULL(mmio->stat));
! r
tmp = mmio->data;
! Status register.
</pre>
|-
! 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.''
''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:
Above, the PL050 is also called the KMI (Keyboard And Mouse Interface). So first we have to configure the PL050 by enabling it. Now, it provides a interface to the PS2 interface which then interfaces with the mouse. So, the next thing I have to do is write the value ''0xF4'' which you can find in the table above to enable the mouse.
{| 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==
==See Also==
Line 24: Line 156:
*[[PS/2 Mouse]]
*[[PS/2 Mouse]]
===External Links===
===External Links===
*[http://infocenter.arm.com/help/topic/com.arm.doc.ddi0143c/DDI0143.pdf ARM PL050 Technical Reference Manual]
*[https://developer.arm.com/documentation/ddi0143/c/preface?lang=en ARM PL050 Technical Reference Manual]

[[Category:ARM]]

Latest revision as of 05:41, 9 June 2024

This page is a stub.
You can help the wiki by accurately adding more contents to it.

PL050 provides a keyboard or mouse interface(KMI) that is IBM PS/2 or AT-compatible and is licensed by ARM.
There are several registers to communicate with the controller, some of them are described in details further.

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:

// 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;

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:

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.

void kmi_init(device_t* dev)
{
    mmio->cr = (1 << 2) | (1 << 4);
}

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:

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.


void kmi_send(uint8 cmd)
{
    kmi->data = cmd;
    while ((registers->stat) & (1 << 5)); // wait while data is sending (TXBUSY)
    ASSERT(registers->data == 0xfa);
}

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

int kmi_setup_mouse()
{
    kmi_send(0xF4);
}

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

External Links