Intel Touch Host Controller (THC)

Touch Host Controller (THC) 是PCH中与触摸设备(例如:触摸屏、触摸板等)接口的IP模块的名称。它由3个关键功能块组成:

  • 一个原生半双工的四路I/O SPI主控制器

  • 低延迟的I2C接口,用于支持符合HIDI2C标准的设备

  • 一个具有读写DMA功能的硬件序列器,用于访问系统内存

它具有一个单根空间IOSF主接口,支持与触摸设备之间的事务。主机驱动程序通过THC接口配置和控制触摸设备。THC为触摸驱动程序提供高带宽DMA服务,并将HID报告传输到主机系统主内存。

THC中的硬件序列器负责将数据(通过DMA)从触摸设备传输到系统内存。使用环形缓冲区是为了避免由于数据消耗(由主机)相对于数据生产(由触摸设备通过DMA)的异步性质而导致的数据丢失。

与其他常见的SPI/I2C控制器不同,THC直接处理HID设备的数据中断和复位信号。

1. 概述

1.1 THC 软件/硬件栈

下图说明了THC软件/硬件栈的高级架构,它完全能够支持Linux操作系统中的HIDSPI/HIDI2C协议。

 ----------------------------------------------
|      +-----------------------------------+   |
|      |           Input Device            |   |
|      +-----------------------------------+   |
|      +-----------------------------------+   |
|      |       HID Multi-touch Driver      |   |
|      +-----------------------------------+   |
|      +-----------------------------------+   |
|      |             HID Core              |   |
|      +-----------------------------------+   |
|      +-----------------------------------+   |
|      |    THC QuickSPI/QuickI2C Driver   |   |
|      +-----------------------------------+   |
|      +-----------------------------------+   |
|      |      THC Hardware Driver          |   |
|      +-----------------------------------+   |
|      +----------------+ +----------------+   |
|  SW  | PCI Bus Driver | | ACPI Resource  |   |
|      +----------------+ +----------------+   |
 ----------------------------------------------
 ----------------------------------------------
|      +-----------------------------------+   |
|  HW  |              PCI Bus              |   |
|      +-----------------------------------+   |
|      +-----------------------------------+   |
|      |           THC Controller          |   |
|      +-----------------------------------+   |
|      +-----------------------------------+   |
|      |              Touch IC             |   |
|      +-----------------------------------+   |
 ----------------------------------------------

触摸IC (TIC),也称为触摸设备(触摸屏或触摸板)。离散的模拟组件,用于感知和传输离散触摸数据或热图数据,以HID报告的形式通过SPI/I2C总线传输到主机上的THC控制器。

THC Host Controller,这是一个PCI设备HBA(主机总线适配器),集成到PCH中,作为触摸IC和主机之间的桥梁。

THC硬件驱动程序,为上面的QuickSPI/QuickI2C驱动程序提供THC硬件操作API,它访问THC MMIO寄存器来配置和控制THC硬件。

THC QuickSPI/QuickI2C驱动程序,也称为HIDSPI/HIDI2C驱动程序,注册为HID低级驱动程序,用于管理THC控制器并实现HIDSPI/HIDI2C协议。

1.2 THC 硬件图

下图显示了THC硬件组件

                     ---------------------------------
                    |          THC Controller         |
                    |  +---------------------------+  |
                    |  |     PCI Config Space      |  |
                    |  +---------------------------+  |
                    |  +---------------------------+  |
                    |  +       MMIO Registers      |  |
                    |  +---------------------------+  |
+---------------+   |  +------------+ +------------+  |
| System Memory +---+--+      DMA   | |   PIO      |  |
+---------------+   |  +------------+ +------------+  |
                    |  +---------------------------+  |
                    |  |       HW Sequencer        |  |
                    |  +---------------------------+  |
                    |  +------------+ +------------+  |
                    |  |  SPI/I2C   | |    GPIO    |  |
                    |  | Controller | | Controller |  |
                    |  +------------+ +------------+  |
                     ---------------------------------

由于THC作为PCI设备公开,因此它具有用于PCI枚举和配置的标准PCI配置空间寄存器。

MMIO寄存器,为驱动程序提供寄存器访问权限,以配置和控制THC硬件,这些寄存器包括以下几个类别:中断状态和控制,DMA配置,PIO(编程I/O,在第3.2节中定义)状态和控制,SPI总线配置,I2C subIP状态和控制,复位状态和控制...

THC为驱动程序提供两种与外部触摸IC通信的方式:PIO和DMA。 PIO允许驱动程序手动写入/读取数据到/从触摸IC,而THC DMA可以自动写入/读取数据,无需驱动程序参与。

HW Sequencer包含THC的主要逻辑,它从MMIO寄存器获取指令来控制SPI总线和I2C总线以完成总线数据事务,它还可以自动处理触摸IC中断并根据中断类型启动DMA接收/发送数据到/从触摸IC。这意味着THC HW Sequencer理解HIDSPI/HIDI2C传输协议,并处理通信而无需驱动程序参与,驱动程序需要做的只是正确配置THC,并准备格式化的数据包或处理接收到的数据包。

由于THC支持HIDSPI/HIDI2C协议,因此它具有SPI控制器和I2C subIP,以公开SPI总线和I2C总线。 THC还集成了GPIO控制器以提供中断线支持和复位线支持。

2. THC 硬件接口

2.1 主机接口

THC作为“PCI Digitizer device”暴露给主机。 PCI产品和设备ID从不同代的处理器更改。因此,枚举驱动程序的源代码需要逐代更新。

2.2 设备接口

THC支持两种类型的总线用于触摸IC连接:增强型SPI总线和I2C总线。

2.2.1 SPI端口

当MMIO寄存器中的PORT_TYPE = 00b时,THC使用SPI接口与外部触摸IC通信。 THC增强型SPI总线支持不同的SPI模式:标准单I/O模式,双I/O模式和四路I/O模式。

在单I/O模式下,THC驱动MOSI线以将数据发送到触摸IC,并从MISO线接收触摸IC的数据。在双I/O模式下,THC驱动MOSI和MISO都用于数据发送,并且还在两条线上接收数据。在四路I/O模式下,添加了其他两条线(IO2和IO3),THC同时驱动MOSI(IO0),MISO(IO1),IO2和IO3进行数据发送,并且还在这4条线上接收数据。驱动程序需要通过设置不同的操作码来在不同模式下配置THC。

除了I/O模式,驱动程序还需要配置SPI总线速度。 THC在Intel Lunar Lake平台上支持高达42MHz的SPI时钟。

对于THC将数据发送到触摸IC,SPI总线上的数据流

| --------------------THC sends---------------------------------|
<8Bits OPCode><24Bits Slave Address><Data><Data><Data>...........

对于THC从触摸IC接收数据,SPI总线上的数据流

| ---------THC Sends---------------||-----Touch IC sends--------|
<8Bits OPCode><24Bits Slave Address><Data><Data><Data>...........

2.2.2 I2C端口

THC还在其中集成了I2C控制器,称为I2C SubSystem。当PORT_TYPE = 01时,THC配置为I2C模式。与可以通过MMIO寄存器直接配置的SPI模式相比,THC需要使用PIO读取(通过设置SubIP读取操作码)来获取I2C subIP APB寄存器的值,并使用PIO写入(通过设置SubIP写入操作码)来进行写入操作。

2.2.3 GPIO接口

THC还包括两个GPIO引脚,一个用于中断,另一个用于设备复位控制。

可以通过设置MMIO控制寄存器将中断线配置为电平触发或边沿触发。

复位线由BIOS(或EFI)通过ACPI _RST方法控制,驱动程序需要在初始化期间调用此设备ACPI _RST方法来复位触摸IC。

3. 高级概念

3.1 操作码

操作码(operation code)用于告诉THC或触摸IC将要执行的操作,例如PIO读取或PIO写入。

当THC配置为SPI模式时,操作码用于确定读取/写入I/O模式。以下是一些SPI I/O模式的操作码示例

操作码

对应的SPI命令

0x0B

读取 单路I/O

0x02

写入 单路I/O

0xBB

读取 双路I/O

0xB2

写入 双路I/O

0xEB

读取 四路I/O

0xE2

写入 四路I/O

通常,不同的触摸IC具有不同的OPCode定义。根据HIDSPI协议白皮书,这些OPCode在设备ACPI表中定义,驱动程序需要在驱动程序初始化期间通过OS ACPI API查询这些信息,然后使用正确的设置配置THC MMIO OPCode寄存器。

当THC在I2C模式下工作时,操作码用于告诉THC下一个PIO类型是什么:I2C SubIP APB寄存器读取,I2C SubIP APB寄存器写入,I2C触摸IC设备读取,I2C触摸IC设备写入,I2C触摸IC设备写入,然后读取。

以下是I2C模式下THC预定义的操作码

操作码

对应的I2C命令

地址

0x12

读取I2C SubIP APB内部寄存器

0h - FFh

0x13

写入I2C SubIP APB内部寄存器

0h - FFh

0x14

通过I2C总线读取外部触摸IC

N/A

0x18

通过I2C总线写入外部触摸IC

N/A

0x1C

通过I2C总线写入,然后读取外部触摸IC

N/A

3.2 PIO

THC为驱动程序提供了一个编程I/O(PIO)访问接口,以访问触摸IC的配置寄存器或访问I2C subIP的配置寄存器。要使用PIO执行I/O操作,驱动程序应预先编程PIO控制寄存器和PIO数据寄存器,并启动序列循环。 THC使用不同的PIO操作码来区分不同的PIO操作(PIO读取/写入/写入后读取)。

如果正在进行排序循环,并且尝试编程任何控制,地址或数据寄存器,则该循环将被阻止,并且将遇到序列错误。

状态位指示循环何时完成,允许驱动程序知道何时可以检查读取结果和/或何时启动新命令。如果启用,循环完成断言可以使用中断中断驱动程序。

由于THC仅具有16个FIFO寄存器用于PIO,因此通过PIO传输的所有数据不应超过64字节。

由于DMA需要用于传输配置的最大数据包大小,并且最大数据包大小信息始终在HID设备描述符中,该描述符需要THC驱动程序从HID设备(触摸IC)中读取。因此,PIO的典型用例是,在DMA初始化之前,写入RESET命令(PIO写入),读取RESET响应(PIO读取或PIO写入后读取),写入Power ON命令(PIO写入),读取设备描述符(PIO读取)。

对于如何发出PIO操作,以下是驱动程序需要遵循的步骤

  • 在THC_SS_BC中编程读取/写入数据大小。

  • 在THC_SW_SEQ_DATA0_ADDR中编程I/O目标地址。

  • 如果写入,请在THC_SW_SEQ_DATA0..THC_SW_SEQ_DATAn中编程写入数据。

  • 在THC_SS_CMD中编程PIO操作码。

  • 设置TSSGO = 1以启动PIO写入序列。

  • 如果THC_SS_CD_IE = 1,则SW将在PIO完成时接收MSI。

  • 如果读取,则在THC_SW_SEQ_DATA0..THC_SW_SEQ_DATAn中读取数据。

3.3 DMA

THC具有4个DMA通道:读取DMA1,读取DMA2,写入DMA和软件DMA。

3.3.1 读取DMA通道

THC具有两个读取DMA引擎:第一个RxDMA (RxDMA1) 和第二个RxDMA (RxDMA2)。 RxDMA1保留用于原始数据模式。 RxDMA2用于HID数据模式,并且是驱动程序当前用于HID输入报告数据检索的RxDMA引擎。

RxDMA的典型用例是自动从触摸IC接收数据。一旦软件启用RxDMA,THC将开始自动处理接收逻辑。

对于SPI模式,THC RxDMA序列为:当触摸IC向THC触发中断时,THC读取报告头以识别报告类型以及报告长度,根据以上信息,THC读取报告主体到内部FIFO,并启动RxDMA将数据复制到系统内存。之后,THC使用报告类型更新中断原因寄存器,并更新RxDMA PRD表读取指针,然后触发MSI中断以通知驱动程序RxDMA完成数据接收。

对于I2C模式,THC RxDMA的行为略有不同,因为HIDI2C协议与HIDSPI协议不同,RxDMA仅用于接收输入报告。该序列是,当触摸IC向THC触发中断时,THC首先从输入报告地址读取2个字节以确定数据包长度,然后使用此数据包长度从输入报告地址启动DMA读取以获取输入报告数据。之后,THC更新RxDMA PRD表读取指针,然后触发MSI中断以通知驱动程序输入报告数据已准备好在系统内存中。

以上所有序列都是硬件自动处理的,驱动程序需要做的只是配置RxDMA并等待中断准备就绪,然后从系统内存中读取数据。

3.3.2 软件DMA通道

THC支持软件触发的RxDMA模式,以从触摸IC读取触摸数据。此SW RxDMA是第三个THC RxDMA引擎,其功能与现有的两个RxDMA相似,唯一的区别是此SW RxDMA由软件触发,而RxDMA2由外部触摸IC中断触发。它为软件驱动程序提供了灵活性,可以随时使用RxDMA读取触摸IC数据。

在软件启动SW RxDMA之前,应停止第一个和第二个RxDMA,清除PRD读/写指针并使设备中断静止(THC_DEVINT_QUIESCE_HW_STS = 1),其他操作与RxDMA相同。

3.3.3 写入DMA通道

THC具有一个写入DMA引擎,可用于自动将数据发送到触摸IC。根据HIDSPI和HIDI2C协议,每次只能将一个命令发送到触摸IC,并且在完全处理完最后一个命令之前,无法发送下一个命令,THC写入DMA引擎仅支持单个PRD表。

驱动程序需要做的是,准备PRD表和DMA缓冲区,然后将数据复制到DMA缓冲区,并使用缓冲区地址和缓冲区长度更新PRD表,然后启动写入DMA。 THC将自动将数据发送到触摸IC,并在传输完成后触发DMA完成中断。

3.4 PRD

物理区域描述符(PRD)为THC DMA提供内存映射描述。

3.4.1 PRD表和条目

为了提高物理DMA内存使用率,现代驱动程序趋向于为每个数据缓冲区分配一个虚拟连续但物理上分散的内存缓冲区。 Linux操作系统还提供SGL(scatter gather list)API来支持此用法。

THC使用PRD表(物理区域描述符)来支持相应的OS内核SGL,该SGL描述了虚拟到物理的缓冲区映射。

 ------------------------      --------------       --------------
| PRD table base address +----+ PRD table #1 +-----+ PRD Entry #1 |
 ------------------------      --------------       --------------
                                                    --------------
                                                   | PRD Entry #2 |
                                                    --------------
                                                    --------------
                                                   | PRD Entry #n |
                                                    --------------

读取DMA引擎支持多个PRD表,这些表保存在循环缓冲区中,该循环缓冲区允许THC支持来自触摸IC的多个数据缓冲区。这允许主机软件使用多个缓冲区来武装读取DMA引擎,从而允许触摸IC将多个数据帧发送到THC,而无需SW交互。当CPU处理触摸帧的速度慢于触摸IC发送它们的速度时,需要此功能。

为了简化设计,SW假定最坏情况的内存碎片。因此,每个PRD表应包含相同数量的PRD条目,从而允许使用全局寄存器(每个触摸IC)来保存每个PRD表的PRD条目数。

SW每个读取DMA引擎最多分配128个PRD表,如THC_M_PRT_RPRD_CNTRL.PCD寄存器字段中所指定。 PRD表的数量应等于数据缓冲区的数量。

最大OS内存碎片将位于4KB边界,因此,要寻址1MB的虚拟连续内存,单个PRD表需要256个PRD条目。 SW在THC_M_PRT_RPRD_CNTRL.PTEC寄存器字段中写入每个PRD表的PRD条目数。 PRD条目的长度必须是4KB的倍数,除了PRD表中的最后一个条目。

SW仅在主机初始化时分配所有数据缓冲区和PRD表一次。

3.4.2 PRD写入指针和读取指针

由于PRD表被组织为循环缓冲区(CB),因此需要CB的读取指针和写入指针。

DMA HW消耗CB中的PRD表,一次消耗一个PRD条目,直到在PRD条目中找到EOP位集。此时,HW递增PRD读取指针。因此,读取指针指向DMA引擎当前正在处理的PRD。一旦循环缓冲区的深度被遍历,此指针就会翻转,bit[7]是翻转位。例如,如果DMA CB深度等于4个条目(0011b),则读取指针将遵循以下模式(HW必须遵守此行为):00h 01h 02h 03h 80h 81h 82h 83h 00h 01h ...

写入指针由SW更新。写入指针指向DMA CB中将要存储下一个PRD表的位置。 SW需要确保一旦通过Bit[7]作为翻转位遍历循环缓冲区的深度,此指针就会翻转。例如,如果DMA CB深度等于5个条目(0100b),则写入指针将遵循以下模式(SW必须遵守此行为):00h 01h 02h 03h 04h 80h 81h 82h 83h 84h 00h 01h ..

3.4.3 PRD描述符结构

Intel THC为每个PRD条目使用PRD条目描述符。每个PRD条目描述符占用128位内存

结构字段

描述

dest_addr

53..0

目标内存地址,由于每个条目为4KB,因此忽略地址的最低10位。

reserved1

54..62

保留

int_on_completion

63

完成中断使能位,如果设置了此位,则表示THC将触发完成中断。此位由SW驱动程序设置。

len

87..64

此条目中有多少字节的数据。

end_of_prd

88

PRD表位的结尾,如果设置了此位,则表示此条目是此PRD表中的最后一个条目。此位由SW驱动程序设置。

hw_status

90..89

硬件状态位

reserved2

127..91

保留

一个PRD表最多可以包括256个PRD条目,因为每个条目都是4K字节,所以每个PRD表可以描述1M字节的内存。

struct thc_prd_table {
     struct thc_prd_entry entries[PRD_ENTRIES_NUM];
};

通常,每个PRD表都意味着一个HID触摸数据包。每个DMA引擎最多可以支持128个PRD表(写入DMA除外,写入DMA只有一个PRD表)。 SW驱动程序负责从触摸IC获取最大数据包长度,并使用此最大数据包长度为每个PRD表创建PRD条目。

4. HIDSPI支持 (QuickSPI)

Intel THC与HIDSPI协议完全兼容,THC HW sequenser可以加速HIDSPI协议传输。

4.1 复位流程

  • 调用ACPI _RST方法来复位触摸IC设备。

  • 通过PIO读取从TIC读取复位响应。

  • 发出命令以通过PIO写入从触摸IC检索设备描述符。

  • 通过PIO读取从触摸IC读取设备描述符。

  • 如果设备描述符有效,请分配DMA缓冲区并配置所有DMA通道。

  • 发出命令以通过DMA从触摸IC检索报告描述符。

4.2 输入报告数据流

基本流程

  • 触摸IC使用带内THC中断中断THC控制器。

  • THC Sequencer通过发送读取批准作为信号来读取输入报告头,以告知触摸IC准备好从设备读取数据。

  • THC Sequencer执行与输入报告头中的“输入报告长度”字段中反映的值相对应的输入报告主体读取操作。

  • THC DMA引擎开始从THC Sequencer提取数据,并将数据写入当前CB PRD表条目的PRD条目0上的主机内存。此过程将继续,直到THC Sequencer发出信号表示已读取所有数据,或者THC DMA读取引擎到达其最后一个PRD条目的末尾(或两者都满足)。

  • THC Sequencer检查输入报告头中的“Last Fragment Flag”位。如果清除,THC Sequencer将进入空闲状态。

  • 如果启用了“Last Fragment Flag”位,则THC Sequencer将进入帧结束处理。

THC Sequencer帧结束处理

  • THC DMA引擎递增读取PRD CB的读取指针,并在RxDMA2寄存器(THC_M_PRT_READ_DMA_INT_STS_2)中设置EOF中断状态。

  • 如果驱动程序在控制寄存器(THC_M_PRT_READ_DMA_CNTRL_2)中启用了THC EOF中断,则会生成中断到软件。

从RX DMA缓冲区读取数据的步骤顺序

  • THC QuickSPI驱动程序检查CB写入Ptr和CB读取Ptr,以识别DMA循环缓冲区中是否有任何数据帧。

  • THC QuickSPI驱动程序获取第一个未处理的PRD表。

  • THC QuickSPI驱动程序扫描此PRD表中的所有PRD条目以计算总帧大小。

  • THC QuickSPI驱动程序复制所有帧数据。

  • THC QuickSPI驱动程序根据输入报告主体检查数据类型,并调用相关的回调来处理数据。

  • THC QuickSPI驱动程序更新写入Ptr。

4.3 输出报告数据流

通用输出报告流程

  • HID内核使用raw_request回调调用请求到THC QuickSPI驱动程序。

  • THC QuickSPI驱动程序将请求提供的数据转换为输出报告数据包,并将其复制到THC的写入DMA缓冲区。

  • 启动TxDMA以完成写入操作。

5. HIDI2C支持 (QuickI2C)

5.1 复位流程

  • 通过PIO写入,然后读取从触摸IC设备读取设备描述符。

  • 如果设备描述符有效,请分配DMA缓冲区并配置所有DMA通道。

  • 使用PIO或TxDMA将SET_POWER请求写入TIC的命令寄存器,并检查写入操作是否成功完成。

  • 使用PIO或TxDMA将RESET请求写入TIC的命令寄存器。如果写入操作成功完成,请等待TIC的复位响应。

  • 使用SWDMA通过TIC的报告描述符寄存器读取报告描述符。

5.2 输入报告数据流

基本流程

  • 触摸IC断言中断,指示它有中断要发送到HOST。 THC Sequencer通过I2C总线发出READ请求。 HIDI2C设备返回来自HIDI2C设备的前2个字节,其中包含接收到的数据的长度。

  • THC Sequencer根据长度字段中指示的数据大小继续读取操作。

  • THC DMA引擎开始从THC Sequencer提取数据,并将数据写入当前CB PRD表条目的PRD条目0上的主机内存。 THC将2个字节写入RxDMA缓冲区中的长度字段以及其余数据。此过程将继续,直到THC Sequencer发出信号表示已读取所有数据,或者THC DMA读取引擎到达其最后一个PRD条目的末尾(或两者都满足)。

  • THC Sequencer进入输入报告处理结束。

  • 如果设备没有更多输入报告要发送到主机,则取消断言中断线。对于任何其他输入报告,设备保持中断线为断言状态,并重复流程中的步骤1到4。

THC Sequencer输入报告处理结束

  • THC DMA引擎递增读取PRD CB的读取指针,并在RxDMA 2寄存器(THC_M_PRT_READ_DMA_INT_STS_2)中设置EOF中断状态。

  • 如果驱动程序在控制寄存器(THC_M_PRT_READ_DMA_CNTRL_2)中启用了THC EOF中断,则会生成中断到软件。

从RX DMA缓冲区读取数据的步骤顺序

  • THC QuickI2C驱动程序检查CB写入Ptr和CB读取Ptr,以识别DMA循环缓冲区中是否有任何数据帧。

  • THC QuickI2C驱动程序获取第一个未处理的PRD表。

  • THC QuickI2C驱动程序扫描此PRD表中的所有PRD条目以计算总帧大小。

  • THC QuickI2C驱动程序复制所有帧数据。

  • THC QuickI2C驱动程序调用hid_input_report以将输入报告内容发送到HID核心,其中包括报告ID +报告数据内容(从原始报告数据中删除长度字段)。

  • THC QuickI2C 驱动程序更新写指针。

5.3 输出报告数据流

通用输出报告流程

  • HID核心调用 THC QuickI2C raw_request 回调。

  • THC QuickI2C 使用 PIO 或 TXDMA 将 SET_REPORT 请求写入 TIC 的命令寄存器。SET_REPORT 中的报告类型应设置为输出。

  • THC QuickI2C 使用要写入 TIC 数据寄存器的 TX 数据来编程 TxDMA 缓冲区。前 2 个字节应指示报告的长度,后跟包含报告 ID 的报告内容。

6. THC 调试

要调试 THC,使用事件跟踪机制。要启用调试日志

echo 1 > /sys/kernel/debug/tracing/events/intel_thc/enable
cat /sys/kernel/debug/tracing/trace

7. 参考