Wednesday, September 26, 2018

[ASL] (1) How to Safely R/W I2C Device Using ASL

OperationRegion(ICM7, SystemMemory, 0xA112C000, 256)
        Field(ICM7, DWordAcc, NoLock, Preserve) //Field
        {
            ICN7, 32,                   // R_IC_CON (I2C Control)
            Offset(0x04),
            TAR7, 32,                   // R_IC_TAR (I2C Target Address)
            Offset(0x08),
            SAR7, 32,                   // R_IC_SAR (I2C Slave Address) *
            Offset(0x0C),
            HMD7, 32,                   // R_IC_HS_MADDR (I2C HS MasterMode Code Address) *
            Offset(0x10),
            DCD7, 32,                   // R_IC_DATA_CMD (I2C Rx/Tx Data Buffer and Command)
            Offset(0x14),
            SSH7, 32,                   // R_IC_SS_SCL_HCNT (Standard Speed I2C Clock SCL High Count) *
            Offset(0x18),
            SSL7, 32,                   // R_IC_SS_SCL_LCNT (Standard Speed I2C Clock SCL Low Count) *
            Offset(0x1C),
            FSH7, 32,                   // R_IC_FS_SCL_HCNT (Full Speed I2C Clock SCL High Count) *
            Offset(0x20),
            FSL7, 32,                   // R_IC_FS_SCL_LCNT (Full Speed I2C Clock SCL Low Count) *
            Offset(0x24),
            HSH7, 32,                   // R_IC_HS_SCL_HCNT (High Speed I2C Clock SCL High Count) *
            Offset(0x28),
            HSL7, 32,                   // R_IC_HS_SCL_LCNT (High Speed I2C Clock SCL Low Count) *
            Offset(0x2C),
            ITS7, 32,                   // R_IC_INTR_STAT (I2C Inetrrupt Status) *
            Offset(0x30),
            ITM7, 32,                   // R_IC_INTR_MASK (I2C Interrupt Mask)
            Offset(0x34),
            RIS7, 32,                   // R_IC_RAW_INTR_STAT (I2C Raw Interrupt Status)
            Offset(0x38),
            IRT7, 32,                   // R_IC_RX_TL (I2C Receive FIFO Threshold)
            Offset(0x3C),
            ITT7, 32,                   // R_IC_TX_TL (I2C Transmit FIFO Threshold)
            Offset(0x40),
            CIT7, 32,                   // R_IC_CLR_INTR (Clear Combined and Individual Interrupts)
            Offset(0x44),
            CRU7, 32,                   // R_IC_CLR_RX_UNDER (Clear RX_UNDER Interrupt) *
            Offset(0x48),
            CRO7, 32,                   // R_IC_CLR_RX_OVER (Clear RX_OVERinterrupt) *
            Offset(0x4C),
            CTO7, 32,                   // R_IC_CLR_TX_OVER (Clear TX_OVER interrupt) *
            Offset(0x50),
            CRR7, 32,                   // R_IC_CLR_RD_REQ (Clear RD_REQ interrupt) *
            Offset(0x54),
            CTA7, 32,                   // R_IC_CLR_TX_ABRT (Clear TX_ABRT interrupt)
            Offset(0x58),
            CRD7, 32,                   // R_IC_CLR_RX_DONE (Clear RX_DONE interrupt) *
            Offset(0x5C),
            CAT7, 32,                   // R_IC_CLR_ACTIVITY (Clear ACTIVITY interrupt) *
            Offset(0x60),
            CSD7, 32,                   // R_IC_CLR_STOP_DET (Clear STOP_DET interrupt) *
            Offset(0x64),
            SAD7, 32,                   // R_IC_CLR_START_DET (Clear START_DET interrupt) *
            Offset(0x68),
            CGC7, 32,                   // R_IC_CLR_GEN_CALL (Clear GEN_CALL interrupt) *
            Offset(0x6C),
            IEN7, 32,                   // R_IC_ENABLE (I2C Enable)
            Offset(0x70),
            IST7, 32,                   // R_IC_STATUS (I2C Status)
            Offset(0x74),
            TFL7, 32,                   // R_IC_TXFLR (Transmit FIFO Level Register)
            Offset(0x78),
            RFL7, 32,                   // R_IC_RXFLR (Receive FIFO Level Register)       
            Offset(0x80),
            TAS7, 32,                   // R_IC_TX_ABRT_SOURCE (I2C Transmit Abort Status Register)
            Offset(0x84),
            SDN7, 32,                   // R_IC_SLV_DATA_NACK_ONLY (Generate SLV_DATA_NACK Register) *
            Offset(0x88),
            DCR7, 32,                   // R_IC_DMA_CR (DMA Control Register) *
            Offset(0x8C),
            DTL7, 32,                   // R_IC_DMA_TDLR (DMA Transmit Data Level) *
            Offset(0x90),
            DRL7, 32,                   // R_IC_DMA_RDLR (DMA Receive Data Level) *
            Offset(0x94),
            SST7, 32,                   // R_IC_SDA_SETUP (I2C SDA Setup Register) *
            Offset(0x98),
            AGC7, 32,                   // R_IC_ACK_GENERAL_CALL (I2C ACK General Call Register) *
            Offset(0x9C),
            ETS7, 32,                   // R_IC_ENABLE_STATUS (I2C Enable Status Register) *
            Offset(0xC0),
            CGT7, 32,                   // R_IC_CLK_GATE (Clock Gate)
            Offset(0xF4),
            CPP7, 32,                   // R_IC_COMP_PARAM (Component Parameter Register) *
            Offset(0xF8),
            CPV7, 32,                   // R_IC_COMP_VERSION (Component Version ID) *
            Offset(0xFC),
            CPT7, 32,                   // R_IC_COMP_TYPE (Component Type) *
        }
       
// ------------------------------------------------------------------------------------
// *********************I2C R/W Registers and Definition*******************************
// ------------------------------------------------------------------------------------

        Name(RDST, 0) // RDST 是通用的 Read 回傳 Status
        Name(RDDT, 0) // RDDT 是 I2C READ Data 暫存

Name(RRRS, 0) // ByteWrite_Basic 專用 POST Code
Name(RRRT, 0) // ByteRead_Basic  專用 POST Code

// ------------------------------------------------------------------------------------
// ******************Method (IWBB) Debug POST Code Example*****************************
// ------------------------------------------------------------------------------------

// *************************
// ShiftLeft (0x01, 0, Local7)
// Or (RRRS, Local7, RRRS)
// *************************

// ------------------------------------------------------------------------------------
// ******************Method (IRBB) Debug POST Code Example*****************************
// ------------------------------------------------------------------------------------

// *************************
// ShiftLeft (0x01, 1, Local7)
// Or (RRRT, Local7, RRRT)
// *************************

// ------------------------------------------------------------------------------------
// ***************************ByteReadI2C**********************************************
// ------------------------------------------------------------------------------------

Method (IRBC, 1)
{
// 1. 呼叫一次 IWBB, 主要功能為將 Offset 寫入 I2C Command

// arg0 = "Offset"
// START = It controls whether a RESTART is issued before the byte is sent or received
// END = It controls whether a STOP is issued after the byte is sent or received.

IWBB (arg0, TRUE, FALSE)

// 2. RDST 是 IWBB 的返回值

Store(RDST, Local0)

if(LNotEqual(Local0, 0x0))
{    
Return(RDST)
}

// 3. 如果抵達此處, 則代表返回值為 0

IRBB(TRUE, TRUE)

// 以下是 I2C READ 的 Workaround-----------------------------
// 因為 Method (IRBB) 應該修好了, 所以不需要再用此 Workaround
// 但為了保險起見還是留著
//-----------------------------------------------------------

Return(RDST)
}

// ------------------------------------------------------------------------------------
// ***************************ByteReadI2C_Basic****************************************
// ------------------------------------------------------------------------------------

Method (IRBB, 2, NotSerialized)
{
// Return Status = SUCCESS

Store(0, RDST)

// 0. 因為 I2CBaseAddress 固定, 所以不需要維護

// 1. I2CInit 應該也不需要做事

// 2. arg0 = START (TRUE/FALSE), arg1 = END (TRUE/FALSE), RDDT 內含 Read Data

//    ReceiveDataEnd = 1 (固定值)
//    ReceiveRequest = Local0 = 初始值為 0, 區間應為 0~1
//    ReadBuffer     = Local1 = 初始值為 0, 區間應為 0~1
//    Counter        = Local2 = 初始值為 0, 區間應為 0~1024
//    檢查 Reg 專用  = Local3 = 初始值為 0
//    檢查 Reg 專用  = Local4 = 初始值為 0

//    while ((ReceiveDataEnd > ReceiveRequest) || (ReceiveDataEnd > ReadBuffer))

Store (0x0, Local0)
Store (0x0, Local1)
Store (0x0, Local2)
Store (0x0, Local3)
Store (0x0, Local4)

While(LOr(LGreater(0x01, Local0), LGreater(0x01, Local1)))
{

// 1. 讀取 R_IC_RAW_INTR_STAT (Local3), RIS7 = R_IC_RAW_INTR_STAT (I2C Raw Interrupt Status)

//    如果 Local1 = R_IC_RAW_INTR_STAT == ERROR, Return with ERROR

//    0x40 = BIT06 = I2C_INTR_TX_ABRT = NACK Set

Store (RIS7, Local3)

If (LNotEqual(And(Local1, 0x40), 0))
{
// Before EXIT, READ R_IC_CLR_TX_ABRT
// CTA7 = R_IC_CLR_TX_ABRT (Clear TX_ABRT interrupt)

Store (CTA7, Local3)

Store(0xFE, RDST)     // 0xFE = R_IC_RAW_INTR_STAT and I2C_INTR_TX_ABRT, ERROR
Return(RDST)
}

// 2. 讀取 R_IC_STATUS, IST7 = R_IC_STATUS (I2C Status) = Local3

//    If R_IC_STATUS == Not Empty, we will READ DATA
//    STAT_RFNE = BIT03 (0x08) = RX FIFO is not empty
//    if FIFO is not empty, 代表可讀資料了
//    DCD7 = R_IC_DATA_CMD (I2C Rx/Tx Data Buffer and Command)

Store (IST7, Local3)

If (LNotEqual(And(Local3, 0x08, Local3), 0))
{

// RDDT = READ DATA

Store (DCD7, Local3)
Store (Local3, RDDT)

// ReadBuffer  = Local1, ReadBuffer ++

Increment(Local1)
}

//  3. ReceiveDataEnd = 1, ReceiveRequest = Local0
// 首次進入, 不會跑入此條件, 因為ReceiveRequest 此時指向 Data
// 第二次進入, 代表 ReceiveRequest 已經加過一次 1, 已經指向 EOF, 我們會到此的唯一可能就是首次進入時 FIFO is empty, 所以 ReadBuffer ++ 沒發生
// 此處之所以需要等待 2028 毫秒, 是因為 FIFO empty 的情況情實很少見    

If (LEqual(0x01, Local0))
{
Stall (2)
Increment(Local2)
If (LLess(Local2, 1024))
{
Continue
}
else
{
Break
}
}

//  4.  If FIFO is full, Wait until a read request will fit
//      STAT_TFNF = BIT1 = TX FIFO = 0x02 is not full, 0 = FULL

Store (IST7, Local3)

If (LEqual(And(Local3, 0x02), 0))
{
Stall (10)
Continue
}

//  5. 這裡是重要的指令分歧點
//     START = TRUE,  END = TRUE,  第一個 if, 在 R_IC_DATA_CMD 直接寫入 READ + RESTART + STOP
//     START = TRUE,  END = FALSE, 第二個 if, 在 R_IC_DATA_CMD 直接寫入 READ + RESTART
//     START = FALSE, END = TRUE,  第一個 if, 在 R_IC_DATA_CMD 直接寫入 READ + STOP
//     START = FALSE, END = FALSE,  第一個 if, 在 R_IC_DATA_CMD 直接寫入 READ (通常沒人用這個)

// (Read Command = B_READ_CMD = BIT08 = 0x0100) 寫入 Local3
 
Store (0x0100, Local3)
 
// arg0 = START, arg1 = END
 
If (LEqual(arg0, TRUE))
{
If (LEqual(arg1, TRUE)) 
{
// Local0|B_CMD_RESTART|B_CMD_STOP, BIT09+BIT10

Or (Local3, 0x0600, Local3)
}
else
{
// Local0|B_CMD_RESTART, BIT10
Or (Local3, 0x0400, Local3)
}
}
else
{
If (LEqual(arg1, TRUE))
{
// Local0|B_CMD_STOP, BIT09
Or (Local3, 0x0200, Local3)
}
else
{
// Local3, Do nothing
}
}
 
// 將 (Read Command + 各種 MASK) 寫入 Command
 
Store(Local3 ,DCD7)

// 6. Wait after send cmd

Stall (2)

// 7. 累加 ReceiveRequest

Increment(Local0)

}

Return(RDST)
}

// ------------------------------------------------------------------------------------
// ***************************ByteWriteI2C*********************************************
// ------------------------------------------------------------------------------------

        // AKA: ByteWriteI2C

Method (IWBC, 2, NotSerialized)
{

// 1. 呼叫一次 IWBB, 主要功能為將 Offset 寫入 I2C Command

// arg0 = "Offset to be Written"
// arg1 = "Data to be Written"

// START = It controls whether a RESTART is issued before the byte is sent or received
// END   = It controls whether a STOP is issued after the byte is sent or received.

IWBB(arg0, TRUE, FALSE)

// 2. RDST 是 IWBB 的返回值

Store(RDST, Local0)

if(LNotEqual(Local0, 0x0))
{  
Return(RDST)
}

// 3. 如果抵達此處, 則代表返回值為 0

IWBB(arg1, FALSE, TRUE)
Return(RDST)
}

// ------------------------------------------------------------------------------------
// ***************************ByteWriteI2C_Basic***************************************
// ------------------------------------------------------------------------------------

// arg0 = "Offset" or "Data to be Written"
// arg1 = It controls whether a RESTART is issued before the byte is sent or received
// arg2 = It controls whether a STOP is issued after the byte is sent or received.

// 0xFE = R_IC_RAW_INTR_STAT and I2C_INTR_TX_ABRT, ERROR
// 0xFD = R_IC_STATUS and STAT_TFNF, ERROR
// 0xFC = EFI_TIMEOUT

Method (IWBB, 3, NotSerialized)
{

  // 0. 初始化 RDST, 做為回傳值-------------------------------------------------------------------------
 
  Store(0xFF, RDST) // Set the status to FAIL

  // 1. 這個是 (I2CInit) -------------------------------------------------------------------------------
 
  //    將 SlaveAddress 寫到 IC_TAR
 
  Store (0x46, TAR7)
 
  // 2. 用 While 重覆跑前段的檢查 ----------------------------------------------------------------------
 
  // Local5 = TransmitEnd
  // Local6 = WriteBuffer
 
  Store (1, Local5)
  Store (0, Local6)
 
  While(LGreater(Local5, Local6))
  {
 
// 1. 讀取 R_IC_STATUS, IST7 = R_IC_STATUS (I2C Status)

Store (IST7, Local0)
 
    // 2. 讀取 R_IC_RAW_INTR_STAT (Local1), RIS7 = R_IC_RAW_INTR_STAT (I2C Raw Interrupt Status)

Store (RIS7, Local1)

// 3. 如果 Local1 = R_IC_RAW_INTR_STAT == ERROR, Return with ERROR

//    0x40 = BIT06 = I2C_INTR_TX_ABRT = NACK Set

If (LNotEqual(And(Local1, 0x40), 0))
{
// Before EXIT, READ R_IC_CLR_TX_ABRT
// CTA7 = R_IC_CLR_TX_ABRT (Clear TX_ABRT interrupt)

Store (CTA7, Local1)

Store(0xFE, RDST)     // 0xFE = R_IC_RAW_INTR_STAT and I2C_INTR_TX_ABRT, ERROR
Return(RDST)
}

// 4. If R_IC_STATUS == ERROR, Delay and Retry
//    STAT_TFNF = BIT1 = 0x02

If (LEqual(And(Local0, 0x02), 0))
{
//FIFO_WRITE_DELAY = 0x02

Stall (0x02)

Store(0xFD, RDST)     // 0xFD = R_IC_STATUS and STAT_TFNF, ERROR
Continue
}

// 這裡是重要的指令分歧點 -------------------------------------------
 
//      前導指令 (Read/Write) START = TRUE,  END = FALSE, 第二個 if, 在 R_IC_DATA_CMD 直接寫入 RESTART
//      後續指令 (Read)       START = TRUE,  END = TRUE,  第一個 if, 在 R_IC_DATA_CMD 直接寫入 RESTART + STOP
//      後續指令 (Write)      START = FALSE, END = TRUE,  第一個 if, 在 R_IC_DATA_CMD 直接寫入 STOP
 
// (Offset or Data) 寫入 Local0
 
Store (arg0, Local0)
 
// arg1 = START, arg2 = END
 
If (LEqual(arg1, TRUE))
{
If (LEqual(arg2, TRUE)) 
{
// Local0|B_CMD_RESTART|B_CMD_STOP, BIT09+BIT10

Or (Local0, 0x0600, Local0)
Increment (Local6)
}
else
{
// Local0|B_CMD_RESTART, BIT10

Or (Local0, 0x0400, Local0)
Increment (Local6)
}
}
else
{
If (LEqual(arg2, TRUE))
{
// Local0|B_CMD_STOP, BIT09
Or (Local0, 0x0200, Local0)
Increment (Local6)
}
else
{
// Local0, Do nothing
Increment (Local6)
}
}
 
// 將 (Offset or Data) 寫入 Command
 
Store(Local0 ,DCD7)

// Delay
 
Stall (2)

// ---------------------------------------------------------

//    Local2 做為 Counter 初始化
 
Store(0,Local2)

While(TRUE)
{  
// 1. 讀取 R_IC_RAW_INTR_STAT (Local1), RIS7 = R_IC_RAW_INTR_STAT (I2C Raw Interrupt Status)

Store (RIS7, Local1)
 
// 2. 如果 Local1 = R_IC_RAW_INTR_STAT == ERROR, Return with ERROR

//    0x40 = BIT06 = I2C_INTR_TX_ABRT = NACK Set

If (LNotEqual(And(Local1, 0x40), 0))
{
// Before EXIT, READ R_IC_CLR_TX_ABRT
// CTA7 = R_IC_CLR_TX_ABRT (Clear TX_ABRT interrupt)

Store (CTA7, Local1)
Store(0xFE, RDST)     // 0xFE = R_IC_RAW_INTR_STAT and I2C_INTR_TX_ABRT, ERROR
}
 
// 3. 如果 Local1 = R_IC_TXFLR == 0, 則 Break
//    TFL7 = R_IC_TXFLR (Transmit FIFO Level Register)

Store (TFL7, Local1)

If (LEqual(Local1, 0x0))
{
Store(0x00, RDST)
Break
}

// 4. Delay

Stall (2)

// 5. Timeout Test

Increment(Local2)

If(LLess(Local2, 1024))
{
Continue
}
else
{
Store(0xFC, RDST)     // 0xFC = EFI_TIMEOUT
Break
}
}
}
 
  // Return SUCCESS
 
  Store(0x00, RDST)
  Return(RDST)
 
}

[Clang] (1) How to Compile EDKII Based BIOS Source using Clang?

How to Compile EDKII Based BIOS Source using Clang (https://en.wikipedia.org/wiki/Clang)?

1. Files to be modified:

1.1. MSFT_DEF.txt = Microsoft Tool Chain Definition

--> This is main Tool Chain file

1.2. MSFT_DEF.txt, GCC_DEF.txt, ... 

MYTOOLS_DEF.txt --->

!include MSFT_DEF.txt
*_MYTOOLS_*_*_FAMILY = MSFT

VS2015_DEF.txt --->

!include MSFT_DEF.txt
*_VS2015_*_*_FAMILY = MSFT
DEBUG_VS2015_IA32_CC_FLAGS = DEF(DEBUG_CC_FLAGS) DEF(COMMON_CC_FLAGS) /arch:IA32
RELEASE_VS2015_IA32_CC_FLAGS = DEF(COMMON_CC_FLAGS) /arch:IA32

Since MYTOOLS_DEF.txt and VS2015_DEF.txt are sharing the usage of MSFT_DEF.txt, we need to list the difference between them. (MyTools as Default)

1.3. The usage of MYTOOLS_DEF.txt is selected in target.txt 

This file is generated in main.mak

target.txt --->

ACTIVE_PLATFORM    =  Build/Platform.dsc

TARGET = RELEASE

TOOL_CHAIN_CONF    = AmiPkg/Configuration/MYTOOLS_DEF.txt

TOOL_CHAIN_TAG = MYTOOLS

MAX_CONCURRENT_THREAD_NUMBER = 8

BUILD_RULE_CONF = AmiPkg/Configuration/build_rule.txt

The make command in main.mak as follows:

# Create Conf/target.txt, based on SDL tokens
Conf/target.txt : $(TOKEN_MAK) $(MAIN_MAK) Conf
@$(ECHO) \
"ACTIVE_PLATFORM    = $(subst \,/, $(ACTIVE_PLATFORM))\
$(EOL)\
$(EOL)TARGET = $(TARGET)\
$(EOL)\
$(EOL)TOOL_CHAIN_CONF    = $(TOOL_DEFINITION_FILE)\
$(EOL)\
$(EOL)TOOL_CHAIN_TAG = $(TOOL_CHAIN_TAG)\
$(EOL)\
$(EOL)MAX_CONCURRENT_THREAD_NUMBER = $(NUMBER_OF_BUILD_PROCESS_THREADS)\
$(EOL)\
$(EOL)BUILD_RULE_CONF = $(BUILD_RULE_FILE)" > Conf/target.txt

-----------------------------------------------------------------

TOKEN
Name  = "TOOL_DEFINITION_FILE"
Value  = "$(CONFIGURATION_DIR)$(TOOL_CHAIN_TAG)_DEF.txt"
Help  = "Name of the tool definition file.\This value goes to to auto-generated Conf/target.txt."
TokenType = Expression
TargetMAK = Yes
End

--------------------------------------------------------------

Conf/target.txt : $(TOKEN_MAK) $(MAIN_MAK) Conf
@$(ECHO) \
"ACTIVE_PLATFORM    = $(subst \,/, $(ACTIVE_PLATFORM))\
$(EOL)\
$(EOL)TARGET = $(TARGET)\
$(EOL)\
$(EOL)TOOL_CHAIN_CONF    = $(TOOL_DEFINITION_FILE)\
$(EOL)\
$(EOL)TOOL_CHAIN_TAG = $(TOOL_CHAIN_TAG)\
$(EOL)\
$(EOL)MAX_CONCURRENT_THREAD_NUMBER = $(NUMBER_OF_BUILD_PROCESS_THREADS)\
$(EOL)\
$(EOL)BUILD_RULE_CONF = $(BUILD_RULE_FILE)" > Conf/target.txt

---------------------------------------------------------------

1.4. Search "Clang Support" for building on Mac OS X (in EDK2_Build_Spec.pdf), where the full sample of Clang_DEF.txt 

1.5. Complete Flow:

1.5.1. Veb Calls Tools (make.exe) -> makefile

1.5.2. makefile gives the control to main.mak

1.5.3. main.mak in charge of including all makefiles came from module.mak

1.5.4. Based on definition of toolchain, main.mak will generate target.txt

1.5.5. main.mak calls EDK2 build.exe

1.5.6. Compile Example of a EDKII "Driver"

Control Tool:   C:\WinDDK\7600.16385.1\bin\x86\amd64\cl.exe
Generated File: v3_lib.obj
Source File:    v3_lib.c

---------------------------------------------------------------

2. target.txt

# Platform.dsc:

ACTIVE_PLATFORM    =  Build/Platform.dsc

TARGET = RELEASE

TOOL_CHAIN_CONF    = AmiPkg/Configuration/MYTOOLS_DEF.txt

TOOL_CHAIN_TAG = MYTOOLS

MAX_CONCURRENT_THREAD_NUMBER = 8

BUILD_RULE_CONF = AmiPkg/Configuration/build_rule.txt