alder_lake_bios/Intel/AlderLake/AlderLakeChipsetPkg/ChipsetSvcDxe/SetIsaInfo.c

311 lines
6.7 KiB
C

/** @file
DXE Chipset Services Library.
This file contains only one function that is DxeCsSvcSetIsaInfo().
The function DxeCsSvcSetIsaInfo() use chipset services to set ISA
information for common ISA driver utilization.
;***************************************************************************
;* Copyright (c) 2018, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include <Library/IoLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/PlatformNvsArea.h>
#include <Register/PchRegs.h>
#include <Register/PchRegsLpc.h>
//[-start-191225-IB16740000-add]// for PCI_DEVICE_NUMBER_PCH_LPC & PCI_FUNCTION_NUMBER_PCH_XHCI define
#include <PchBdfAssignment.h>
//[-end-191225-IB16740000-add]//
#define TIMEOUT 50000
#define STALL_UNIT 50
#define KBC_DATA_PORT 0x60
#define KBC_CMD_STS_PORT 0x64
#define DISABLE_KB 0xad
#define ENABLE_KB 0xae
#define KBC_OUTB 0x01
#define KBC_AUXB 0x20
#define KBC_INPB 0x02
#define KB_DEVICE_CHECK 0xEE
/**
To set ISA information for common ISA driver utilization.
@param[in, out] Function ISA function value
@param[in, out] Device ISA device value
@retval EFI_SUCCESS This function always return successfully.
*/
EFI_STATUS
SetIsaInfo (
IN OUT UINT8 *Function,
IN OUT UINT8 *Device
)
{
*Device = (UINT8)PCI_DEVICE_NUMBER_PCH_LPC;
*Function = (UINT8)PCI_FUNCTION_NUMBER_PCH_LPC;
return EFI_SUCCESS;
}
/**
I/O work flow to wait output buffer full in given time.
@param Timeout given time
@param Keyboard: TRUE is PS2 keyboard, FALSE is PS2 mouse.
@retval EFI_TIMEOUT output is not full in given time
@retval EFI_SUCCESS output is full in given time.
*/
EFI_STATUS
WaitOutputFull (
IN UINTN Timeout,
IN BOOLEAN Keyboard
)
{
UINTN Delay;
UINT8 Data;
Delay = Timeout / 50;
do {
Data = IoRead8 (KBC_CMD_STS_PORT);
if (Keyboard) {
//
// Check keyboard controller status
// BIT0 1: output buffer full (ready to read)
// BIT5 0: the data in output buffer is not mouse data.
//
if ((Data & KBC_OUTB) == KBC_OUTB && (Data & KBC_AUXB) != KBC_AUXB) {
break;
}
} else {
//
// Check keyboard controller status bit 0(output buffer status)
// BIT0 1: output buffer full (ready to read)
// BIT5 1: the data in output buffer is mouse data.
//
if ((Data & (KBC_OUTB | KBC_AUXB)) == (KBC_OUTB | KBC_AUXB)) {
break;
}
}
gBS->Stall (50);
Delay--;
} while (Delay != 0);
if (Delay == 0) {
return EFI_TIMEOUT;
}
return EFI_SUCCESS;
}
/**
I/O work flow to wait output buffer empty in given time.
@param Timeout given time
@retval EFI_TIMEOUT output is not empty in given time
@retval EFI_SUCCESS output is empty in given time.
**/
EFI_STATUS
WaitOutputEmpty (
IN UINTN Timeout
)
{
UINTN Delay;
UINT8 Data;
Delay = Timeout / 50;
do {
Data = IoRead8 (KBC_CMD_STS_PORT);
//
// Check keyboard controller status bit 0(output buffer status)
//
if ((Data & KBC_OUTB) == 0) {
break;
}
Data = IoRead8 (KBC_DATA_PORT);
gBS->Stall (50);
Delay--;
} while (Delay);
if (Delay == 0) {
return EFI_TIMEOUT;
}
return EFI_SUCCESS;
}
/**
I/O work flow to wait input buffer empty in given time.
@param Timeout Wating time.
@retval EFI_TIMEOUT if input is still not empty in given time.
@retval EFI_SUCCESS input is empty.
**/
EFI_STATUS
WaitInputEmpty (
IN UINTN Timeout
)
{
UINTN Delay;
UINT8 Data;
Delay = Timeout / STALL_UNIT;
do {
Data = IoRead8 (KBC_CMD_STS_PORT);
//
// Check keyboard controller status bit 1(input buffer status)
//
if ((Data & KBC_INPB) == 0) {
break;
}
gBS->Stall (STALL_UNIT);
Delay--;
} while (Delay != 0);
if (Delay == 0) {
return EFI_TIMEOUT;
}
return EFI_SUCCESS;
}
/**
I/O work flow of outing 8042 command.
@param Command I/O command.
@retval EFI_SUCCESS Success to excute I/O work flow
@retval EFI_TIMEOUT Keyboard controller time out.
**/
EFI_STATUS
Out8042Command (
IN UINT8 Command
)
{
EFI_STATUS Status;
UINT8 Data;
//
// Wait keyboard controller input buffer empty
//
Status = WaitInputEmpty (TIMEOUT);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Send command
//
Data = Command;
IoWrite8 (KBC_CMD_STS_PORT, Data);
Status = WaitInputEmpty (TIMEOUT);
if (EFI_ERROR (Status)) {
return Status;
}
return EFI_SUCCESS;
}
BOOLEAN
IsPs2KeyBoardConnected (
VOID
)
{
EFI_STATUS Status;
UINT8 Data;
EFI_TPL OldTpl;
Data = 0;
//
// We will raise TPL to avoid mouse impacts this detection.
//
OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
//
// Disable "PS2 keyboard key-in action" during the detection (because any input will overwrite port 0x60 outdata)
//
Status = WaitInputEmpty (TIMEOUT);
if (EFI_ERROR (Status)) {
goto Exit_detect;
}
IoWrite8 (KBC_CMD_STS_PORT, DISABLE_KB);
//
// Send 0xEE to ckeck whether PS2 keyboard is attached on the PS2 slot or not
//
Status = WaitInputEmpty (TIMEOUT);
if (EFI_ERROR (Status)) {
goto Exit_detect;
}
IoWrite8 (KBC_DATA_PORT, KB_DEVICE_CHECK);
//
// Get result
//
Status = WaitOutputFull (TIMEOUT, TRUE);
if (EFI_ERROR (Status)) {
goto Exit_detect;
}
Data = IoRead8 (KBC_DATA_PORT);
//
// Enable PS2 keyboard after the detection
//
Status = WaitInputEmpty (TIMEOUT);
if (EFI_ERROR (Status)) {
goto Exit_detect;
}
IoWrite8 (KBC_CMD_STS_PORT, ENABLE_KB);
Exit_detect:
//
// Restore TPL before exiting the mechanism
//
gBS->RestoreTPL (OldTpl);
//
// If the Keyboard is connected and not broken, 0xEE will be returned.
// Returned situation:
// 1. 0xEE: PS/2 keyboard attached
// 2. 0xFE: Re-send is required
// 3. Others: NO PS/2 keyboard (each MB will have the different return)
//
if (Data == 0xEE) {
return TRUE;
}
return FALSE;
}
VOID
EFIAPI
UpdatePs2KBStatus (
IN EFI_EVENT Event,
IN VOID *Context
)
{
PLATFORM_NVS_AREA *mPlatformNvsArea;
mPlatformNvsArea = (PLATFORM_NVS_AREA *) Context;
}