Intel Integrated Sensor Hub (ISH)

A sensor hub enables the ability to offload sensor polling and algorithmprocessing to a dedicated low power co-processor. This allows the coreprocessor to go into low power modes more often, resulting in increasedbattery life.

There are many vendors providing external sensor hubs conforming to HIDSensor usage tables. These may be found in tablets, 2-in-1 convertible laptopsand embedded products. Linux has had this support since Linux 3.9.

Intel® introduced integrated sensor hubs as a part of the SoC starting fromCherry Trail and now supported on multiple generations of CPU packages. Thereare many commercial devices already shipped with Integrated Sensor Hubs (ISH).These ISH also comply to HID sensor specification, but the difference is thetransport protocol used for communication. The current external sensor hubsmainly use HID over I2C or USB. But ISH doesn’t use either I2C or USB.

Overview

Using a analogy with a usbhid implementation, the ISH follows a similar modelfor a very high speed communication:

-----------------               ----------------------|    USB HID    |       -->     |    ISH HID         |-----------------               ---------------------------------------               ----------------------|  USB protocol |       -->     |    ISH Transport   |-----------------               ---------------------------------------               ----------------------|  EHCI/XHCI    |       -->     |    ISH IPC         |-----------------               ----------------------      PCI                                PCI-----------------               ----------------------|Host controller|       -->     |    ISH processor   |-----------------               ----------------------     USB Link-----------------               ----------------------| USB End points|       -->     |    ISH Clients     |-----------------               ----------------------

Like USB protocol provides a method for device enumeration, link managementand user data encapsulation, the ISH also provides similar services. But it isvery light weight tailored to manage and communicate with ISH clientapplications implemented in the firmware.

The ISH allows multiple sensor management applications executing in thefirmware. Like USB endpoints the messaging can be to/from a client. As part ofenumeration process, these clients are identified. These clients can be simpleHID sensor applications, sensor calibration applications or sensor firmwareupdate applications.

The implementation model is similar, like USB bus, ISH transport is alsoimplemented as a bus. Each client application executing in the ISH processoris registered as a device on this bus. The driver, which binds each device(ISH HID driver) identifies the device type and registers with the HID core.

ISH Implementation: Block Diagram

       ---------------------------      |  User Space Applications  |       -------------------------------------------IIO ABI----------------       --------------------------      |  IIO Sensor Drivers     |       --------------------------       --------------------------      |        IIO core         |       --------------------------       --------------------------      |   HID Sensor Hub MFD    |       --------------------------       --------------------------      |       HID Core          |       --------------------------       --------------------------      |   HID over ISH Client   |       --------------------------       --------------------------      |   ISH Transport (ISHTP) |       --------------------------       --------------------------      |      IPC Drivers        |       --------------------------OS---------------- PCI -----------------Hardware + Firmware       ----------------------------      | ISH Hardware/Firmware(FW) |       ----------------------------

High level processing in above blocks

Hardware Interface

The ISH is exposed as “Non-VGA unclassified PCI device” to the host. The PCIproduct and vendor IDs are changed from different generations of processors. Sothe source code which enumerates drivers needs to update from generation togeneration.

Inter Processor Communication (IPC) driver

Location: drivers/hid/intel-ish-hid/ipc

The IPC message uses memory mapped I/O. The registers are defined inhw-ish-regs.h.

IPC/FW message types

There are two types of messages, one for management of link and another formessages to and from transport layers.

TX and RX of Transport messages

A set of memory mapped register offers support of multi-byte messages TX andRX (e.g. IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintainsinternal queues to sequence messages and send them in order to the firmware.Optionally the caller can register handler to get notification of completion.A doorbell mechanism is used in messaging to trigger processing in host andclient firmware side. When ISH interrupt handler is called, the ISH2HOSTdoorbell register is used by host drivers to determine that the interruptis for ISH.

Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbellregister has the following format:

Bits 0..6: fragment length (7 bits are used)Bits 10..13: encapsulated protocolBits 16..19: management command (for IPC management protocol)Bit 31: doorbell trigger (signal H/W interrupt to the other side)Other bits are reserved, should be 0.

Transport layer interface

To abstract HW level IPC communication, a set of callbacks is registered.The transport layer uses them to send and receive messages.Refer tostructishtp_hw_ops for callbacks.

ISH Transport layer

Location: drivers/hid/intel-ish-hid/ishtp/

A Generic Transport Layer

The transport layer is a bi-directional protocol, which defines:- Set of commands to start, stop, connect, disconnect and flow control(see ishtp/hbm.h for details)- A flow control mechanism to avoid buffer overflows

This protocol resembles bus messages described in the following document:http://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/dcmi-hi-1-0-spec.pdf “Chapter 7: Bus Message Layer”

Connection and Flow Control Mechanism

Each FW client and a protocol is identified by a UUID. In order to communicateto a FW client, a connection must be established using connect request andresponse bus messages. If successful, a pair (host_client_id and fw_client_id)will identify the connection.

Once connection is established, peers send each other flow control bus messagesindependently. Every peer may send a message only if it has received aflow-control credit before. Once it has sent a message, it may not send another onebefore receiving the next flow control credit.Either side can send disconnect request bus message to end communication. Alsothe link will be dropped if major FW reset occurs.

Peer to Peer data transfer

Peer to Peer data transfer can happen with or without using DMA. Depending onthe sensor bandwidth requirement DMA can be enabled by using module parameterishtp_use_dma under intel_ishtp.

Each side (host and FW) manages its DMA transfer memory independently. When anISHTP client from either host or FW side wants to send something, it decideswhether to send over IPC or over DMA; for each transfer the decision isindependent. The sending side sends DMA_XFER message when the message is inthe respective host buffer (TX when host client sends, RX when FW clientsends). The recipient of DMA message responds with DMA_XFER_ACK, indicatingthe sender that the memory region for that message may be reused.

DMA initialization is started with host sending DMA_ALLOC_NOTIFY bus message(that includes RX buffer) and FW responds with DMA_ALLOC_NOTIFY_ACK.Additionally to DMA address communication, this sequence checks capabilities:if the host doesn’t support DMA, then it won’t send DMA allocation, so FW can’tsend DMA; if FW doesn’t support DMA then it won’t respond withDMA_ALLOC_NOTIFY_ACK, in which case host will not use DMA transfers.Here ISH acts as busmaster DMA controller. Hence when host sends DMA_XFER,it’s request to do host->ISH DMA transfer; when FW sends DMA_XFER, it meansthat it already did DMA and the message resides at host. Thus, DMA_XFERand DMA_XFER_ACK act as ownership indicators.

At initial state all outgoing memory belongs to the sender (TX to host, RX toFW), DMA_XFER transfers ownership on the region that contains ISHTP message tothe receiving side, DMA_XFER_ACK returns ownership to the sender. A senderneed not wait for previous DMA_XFER to be ack’ed, and may send another messageas long as remaining continuous memory in its ownership is enough.In principle, multiple DMA_XFER and DMA_XFER_ACK messages may be sent at once(up to IPC MTU), thus allowing for interrupt throttling.Currently, ISH FW decides to send over DMA if ISHTP message is more than 3 IPCfragments and via IPC otherwise.

Ring Buffers

When a client initiates a connection, a ring of RX and TX buffers is allocated.The size of ring can be specified by the client. HID client sets 16 and 32 forTX and RX buffers respectively. On send request from client, the data to besent is copied to one of the send ring buffer and scheduled to be sent usingbus message protocol. These buffers are required because the FW may have nothave processed the last message and may not have enough flow control creditsto send. Same thing holds true on receive side and flow control is required.

Host Enumeration

The host enumeration bus command allows discovery of clients present in the FW.There can be multiple sensor clients and clients for calibration function.

To ease implementation and allow independent drivers to handle each client,this transport layer takes advantage of Linux Bus driver model. Eachclient is registered as device on the transport bus (ishtp bus).

Enumeration sequence of messages:

  • Host sends HOST_START_REQ_CMD, indicating that host ISHTP layer is up.

  • FW responds with HOST_START_RES_CMD

  • Host sends HOST_ENUM_REQ_CMD (enumerate FW clients)

  • FW responds with HOST_ENUM_RES_CMD that includes bitmap of available FWclient IDs

  • For each FW ID found in that bitmap host sendsHOST_CLIENT_PROPERTIES_REQ_CMD

  • FW responds with HOST_CLIENT_PROPERTIES_RES_CMD. Properties include UUID,max ISHTP message size, etc.

  • Once host received properties for that last discovered client, it considersISHTP device fully functional (and allocates DMA buffers)

HID over ISH Client

Location: drivers/hid/intel-ish-hid

The ISHTP client driver is responsible for:

  • enumerate HID devices under FW ISH client

  • Get Report descriptor

  • Register with HID core as a LL driver

  • Process Get/Set feature request

  • Get input reports

HID Sensor Hub MFD and IIO sensor drivers

The functionality in these drivers is the same as an external sensor hub.Refer toHID Sensors Framework for HID sensorABI file testing/sysfs-bus-iio for IIO ABIs to user space.

End to End HID transport Sequence Diagram

HID-ISH-CLN                    ISHTP                    IPC                             HW        |                        |                       |                               |        |                        |                       |-----WAKE UP------------------>|        |                        |                       |                               |        |                        |                       |-----HOST READY--------------->|        |                        |                       |                               |        |                        |                       |<----MNG_RESET_NOTIFY_ACK----- |        |                        |                       |                               |        |                        |<----ISHTP_START------ |                               |        |                        |                       |                               |        |                        |<-----------------HOST_START_RES_CMD-------------------|        |                        |                       |                               |        |                        |------------------QUERY_SUBSCRIBER-------------------->|        |                        |                       |                               |        |                        |------------------HOST_ENUM_REQ_CMD------------------->|        |                        |                       |                               |        |                        |<-----------------HOST_ENUM_RES_CMD--------------------|        |                        |                       |                               |        |                        |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|        |                        |                       |                               |        |                        |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|        |       Create new device on in ishtp bus        |                               |        |                        |                       |                               |        |                        |------------------HOST_CLIENT_PROPERTIES_REQ_CMD------>|        |                        |                       |                               |        |                        |<-----------------HOST_CLIENT_PROPERTIES_RES_CMD-------|        |       Create new device on in ishtp bus        |                               |        |                        |                       |                               |        |                        |--Repeat HOST_CLIENT_PROPERTIES_REQ_CMD-till last one--|        |                        |                       |                               |     probed()        |----ishtp_cl_connect--->|----------------- CLIENT_CONNECT_REQ_CMD-------------->|        |                        |                       |                               |        |                        |<----------------CLIENT_CONNECT_RES_CMD----------------|        |                        |                       |                               |        |register event callback |                       |                               |        |                        |                       |                               |        |ishtp_cl_send(        HOSTIF_DM_ENUM_DEVICES)  |----------fill ishtp_msg_hdr struct write to HW-----  >|        |                        |                       |                               |        |                        |                       |<-----IRQ(IPC_PROTOCOL_ISHTP---|        |                        |                       |                               |        |<--ENUM_DEVICE RSP------|                       |                               |        |                        |                       |                               |for each enumerated device        |ishtp_cl_send(        HOSTIF_GET_HID_DESCRIPTOR|----------fill ishtp_msg_hdr struct write to HW-----  >|        |                        |                       |                               |        ...Response        |                        |                       |                               |for each enumerated device        |ishtp_cl_send(     HOSTIF_GET_REPORT_DESCRIPTOR|--------------fill ishtp_msg_hdr struct write to HW-- >|        |                        |                       |                               |        |                        |                       |                               | hid_allocate_device        |                        |                       |                               | hid_add_device                  |                       |                               |        |                        |                       |                               |

ISH Firmware Loading from Host Flow

Starting from the Lunar Lake generation, the ISH firmware has been divided into two components for better space optimization and increased flexibility. These components include a bootloader that is integrated into the BIOS, and a main firmware that is stored within the operating system’s file system.

The process works as follows:

  • Initially, the ISHTP driver sends a command, HOST_START_REQ_CMD, to the ISH bootloader. In response, the bootloader sends back a HOST_START_RES_CMD. This response includes the ISHTP_SUPPORT_CAP_LOADER bit. Subsequently, the ISHTP driver checks if this bit is set. If it is, the firmware loading process from the host begins.

  • During this process, the ISHTP driver first invokes therequest_firmware() function, followed by sending a LOADER_CMD_XFER_QUERY command. Upon receiving a response from the bootloader, the ISHTP driver sends a LOADER_CMD_XFER_FRAGMENT command. After receiving another response, the ISHTP driver sends a LOADER_CMD_START command. The bootloader responds and then proceeds to the Main Firmware.

  • After the process concludes, the ISHTP driver calls therelease_firmware() function.

For more detailed information, please refer to the flow descriptions provided below:

+---------------+                                                    +-----------------+| ISHTP Driver  |                                                    | ISH Bootloader  |+---------------+                                                    +-----------------+        |                                                                     |        |~~~Send HOST_START_REQ_CMD~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|        |                                                                     |        |<--Send HOST_START_RES_CMD(Includes ISHTP_SUPPORT_CAP_LOADER bit)----|        |                                                                     |***************************************************************************************** if ISHTP_SUPPORT_CAP_LOADER bit is set                                               *****************************************************************************************        |                                                                     |        |~~~start loading firmware from host process~~~+                      |        |                                              |                      |        |<---------------------------------------------+                      |        |                                                                     |---------------------------                                                   || Call request_firmware() |                                                   |---------------------------                                                   |        |                                                                     |        |~~~Send LOADER_CMD_XFER_QUERY~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|        |                                                                     |        |<--Send response-----------------------------------------------------|        |                                                                     |        |~~~Send LOADER_CMD_XFER_FRAGMENT~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|        |                                                                     |        |<--Send response-----------------------------------------------------|        |                                                                     |        |~~~Send LOADER_CMD_START~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~>|        |                                                                     |        |<--Send response-----------------------------------------------------|        |                                                                     |        |                                                                     |~~~Jump to Main Firmware~~~+        |                                                                     |                           |        |                                                                     |<--------------------------+        |                                                                     |---------------------------                                                   || Call release_firmware() |                                                   |---------------------------                                                   |        |                                                                     |***************************************************************************************** end if                                                                               *****************************************************************************************        |                                                                     |+---------------+                                                    +-----------------+| ISHTP Driver  |                                                    | ISH Bootloader  |+---------------+                                                    +-----------------+

Vendor Custom Firmware Loading

The firmware running inside ISH can be provided by Intel or developed by vendors using the Firmware Development Kit (FDK) provided by Intel.Intel will upstream the Intel-built firmware to thelinux-firmware.git repository, located under the pathintel/ish/. For the Lunar Lake platform, the Intel-built ISH firmware will be namedish_lnlm.bin.Vendors who wish to upstream their custom firmware should follow these guidelines for naming their firmware files:

  • The firmware filename should use one of the following patterns:

    • ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin

    • ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin

    • ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin

    • ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin

  • ${intel_plat_gen} indicates the Intel platform generation (e.g.,lnlm for Lunar Lake) and must not exceed 8 characters in length.

  • ${SYS_VENDOR_CRC32} is the CRC32 checksum of thesys_vendor value from the DMI fieldDMI_SYS_VENDOR.

  • ${PRODUCT_NAME_CRC32} is the CRC32 checksum of theproduct_name value from the DMI fieldDMI_PRODUCT_NAME.

  • ${PRODUCT_SKU_CRC32} is the CRC32 checksum of theproduct_sku value from the DMI fieldDMI_PRODUCT_SKU.

During system boot, the ISH Linux driver will attempt to load the firmware in the following order, prioritizing custom firmware with more precise matching patterns:

  1. intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}_${PRODUCT_SKU_CRC32}.bin

  2. intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_SKU_CRC32}.bin

  3. intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}_${PRODUCT_NAME_CRC32}.bin

  4. intel/ish/ish_${intel_plat_gen}_${SYS_VENDOR_CRC32}.bin

  5. intel/ish/ish_${intel_plat_gen}.bin

The driver will load the first matching firmware and skip the rest. If no matching firmware is found, it will proceed to the next pattern in the specified order. If all searches fail, the default Intel firmware, listed last in the order above, will be loaded.

ISH Debugging

To debug ISH, event tracing mechanism is used. To enable debug logs:

echo 1 > /sys/kernel/tracing/events/intel_ish/enablecat /sys/kernel/tracing/trace

ISH IIO sysfs Example on Lenovo thinkpad Yoga 260

root@otcpl-ThinkPad-Yoga-260:~# tree -l /sys/bus/iio/devices//sys/bus/iio/devices/├── iio:device0 -> ../../../devices/0044:8086:22D8.0001/HID-SENSOR-200073.9.auto/iio:device0│   ├── buffer│   │   ├── enable│   │   ├── length│   │   └── watermark...│   ├── in_accel_hysteresis│   ├── in_accel_offset│   ├── in_accel_sampling_frequency│   ├── in_accel_scale│   ├── in_accel_x_raw│   ├── in_accel_y_raw│   ├── in_accel_z_raw│   ├── name│   ├── scan_elements│   │   ├── in_accel_x_en│   │   ├── in_accel_x_index│   │   ├── in_accel_x_type│   │   ├── in_accel_y_en│   │   ├── in_accel_y_index│   │   ├── in_accel_y_type│   │   ├── in_accel_z_en│   │   ├── in_accel_z_index│   │   └── in_accel_z_type...│   │   ├── devices│   │   │   │   ├── buffer│   │   │   │   │   ├── enable│   │   │   │   │   ├── length│   │   │   │   │   └── watermark│   │   │   │   ├── dev│   │   │   │   ├── in_intensity_both_raw│   │   │   │   ├── in_intensity_hysteresis│   │   │   │   ├── in_intensity_offset│   │   │   │   ├── in_intensity_sampling_frequency│   │   │   │   ├── in_intensity_scale│   │   │   │   ├── name│   │   │   │   ├── scan_elements│   │   │   │   │   ├── in_intensity_both_en│   │   │   │   │   ├── in_intensity_both_index│   │   │   │   │   └── in_intensity_both_type│   │   │   │   ├── trigger│   │   │   │   │   └── current_trigger...│   │   │   │   ├── buffer│   │   │   │   │   ├── enable│   │   │   │   │   ├── length│   │   │   │   │   └── watermark│   │   │   │   ├── dev│   │   │   │   ├── in_magn_hysteresis│   │   │   │   ├── in_magn_offset│   │   │   │   ├── in_magn_sampling_frequency│   │   │   │   ├── in_magn_scale│   │   │   │   ├── in_magn_x_raw│   │   │   │   ├── in_magn_y_raw│   │   │   │   ├── in_magn_z_raw│   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_raw│   │   │   │   ├── in_rot_hysteresis│   │   │   │   ├── in_rot_offset│   │   │   │   ├── in_rot_sampling_frequency│   │   │   │   ├── in_rot_scale│   │   │   │   ├── name...│   │   │   │   ├── scan_elements│   │   │   │   │   ├── in_magn_x_en│   │   │   │   │   ├── in_magn_x_index│   │   │   │   │   ├── in_magn_x_type│   │   │   │   │   ├── in_magn_y_en│   │   │   │   │   ├── in_magn_y_index│   │   │   │   │   ├── in_magn_y_type│   │   │   │   │   ├── in_magn_z_en│   │   │   │   │   ├── in_magn_z_index│   │   │   │   │   ├── in_magn_z_type│   │   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_en│   │   │   │   │   ├── in_rot_from_north_magnetic_tilt_comp_index│   │   │   │   │   └── in_rot_from_north_magnetic_tilt_comp_type│   │   │   │   ├── trigger│   │   │   │   │   └── current_trigger...│   │   │   │   ├── buffer│   │   │   │   │   ├── enable│   │   │   │   │   ├── length│   │   │   │   │   └── watermark│   │   │   │   ├── dev│   │   │   │   ├── in_anglvel_hysteresis│   │   │   │   ├── in_anglvel_offset│   │   │   │   ├── in_anglvel_sampling_frequency│   │   │   │   ├── in_anglvel_scale│   │   │   │   ├── in_anglvel_x_raw│   │   │   │   ├── in_anglvel_y_raw│   │   │   │   ├── in_anglvel_z_raw│   │   │   │   ├── name│   │   │   │   ├── scan_elements│   │   │   │   │   ├── in_anglvel_x_en│   │   │   │   │   ├── in_anglvel_x_index│   │   │   │   │   ├── in_anglvel_x_type│   │   │   │   │   ├── in_anglvel_y_en│   │   │   │   │   ├── in_anglvel_y_index│   │   │   │   │   ├── in_anglvel_y_type│   │   │   │   │   ├── in_anglvel_z_en│   │   │   │   │   ├── in_anglvel_z_index│   │   │   │   │   └── in_anglvel_z_type│   │   │   │   ├── trigger│   │   │   │   │   └── current_trigger...│   │   │   │   ├── buffer│   │   │   │   │   ├── enable│   │   │   │   │   ├── length│   │   │   │   │   └── watermark│   │   │   │   ├── dev│   │   │   │   ├── in_anglvel_hysteresis│   │   │   │   ├── in_anglvel_offset│   │   │   │   ├── in_anglvel_sampling_frequency│   │   │   │   ├── in_anglvel_scale│   │   │   │   ├── in_anglvel_x_raw│   │   │   │   ├── in_anglvel_y_raw│   │   │   │   ├── in_anglvel_z_raw│   │   │   │   ├── name│   │   │   │   ├── scan_elements│   │   │   │   │   ├── in_anglvel_x_en│   │   │   │   │   ├── in_anglvel_x_index│   │   │   │   │   ├── in_anglvel_x_type│   │   │   │   │   ├── in_anglvel_y_en│   │   │   │   │   ├── in_anglvel_y_index│   │   │   │   │   ├── in_anglvel_y_type│   │   │   │   │   ├── in_anglvel_z_en│   │   │   │   │   ├── in_anglvel_z_index│   │   │   │   │   └── in_anglvel_z_type│   │   │   │   ├── trigger│   │   │   │   │   └── current_trigger...