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)
 
}

1 comment: