1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
|
=================================
Intel Integrated Sensor Hub (ISH)
=================================
A sensor hub enables the ability to offload sensor polling and algorithm
processing to a dedicated low power co-processor. This allows the core
processor to go into low power modes more often, resulting in increased
battery life.
There are many vendors providing external sensor hubs conforming to HID
Sensor usage tables. These may be found in tablets, 2-in-1 convertible laptops
and embedded products. Linux has had this support since Linux 3.9.
Intel® introduced integrated sensor hubs as a part of the SoC starting from
Cherry Trail and now supported on multiple generations of CPU packages. There
are many commercial devices already shipped with Integrated Sensor Hubs (ISH).
These ISH also comply to HID sensor specification, but the difference is the
transport protocol used for communication. The current external sensor hubs
mainly 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 model
for 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 management
and user data encapsulation, the ISH also provides similar services. But it is
very light weight tailored to manage and communicate with ISH client
applications implemented in the firmware.
The ISH allows multiple sensor management applications executing in the
firmware. Like USB endpoints the messaging can be to/from a client. As part of
enumeration process, these clients are identified. These clients can be simple
HID sensor applications, sensor calibration applications or sensor firmware
update applications.
The implementation model is similar, like USB bus, ISH transport is also
implemented as a bus. Each client application executing in the ISH processor
is 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 PCI
product and vendor IDs are changed from different generations of processors. So
the source code which enumerates drivers needs to update from generation to
generation.
Inter Processor Communication (IPC) driver
------------------------------------------
Location: drivers/hid/intel-ish-hid/ipc
The IPC message uses memory mapped I/O. The registers are defined in
hw-ish-regs.h.
IPC/FW message types
^^^^^^^^^^^^^^^^^^^^
There are two types of messages, one for management of link and another for
messages to and from transport layers.
TX and RX of Transport messages
...............................
A set of memory mapped register offers support of multi-byte messages TX and
RX (e.g. IPC_REG_ISH2HOST_MSG, IPC_REG_HOST2ISH_MSG). The IPC layer maintains
internal 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 and
client firmware side. When ISH interrupt handler is called, the ISH2HOST
doorbell register is used by host drivers to determine that the interrupt
is for ISH.
Each side has 32 32-bit message registers and a 32-bit doorbell. Doorbell
register has the following format::
Bits 0..6: fragment length (7 bits are used)
Bits 10..13: encapsulated protocol
Bits 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 to struct ishtp_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 communicate
to a FW client, a connection must be established using connect request and
response 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 messages
independently. Every peer may send a message only if it has received a
flow-control credit before. Once it has sent a message, it may not send another one
before receiving the next flow control credit.
Either side can send disconnect request bus message to end communication. Also
the 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 on
the sensor bandwidth requirement DMA can be enabled by using module parameter
ishtp_use_dma under intel_ishtp.
Each side (host and FW) manages its DMA transfer memory independently. When an
ISHTP client from either host or FW side wants to send something, it decides
whether to send over IPC or over DMA; for each transfer the decision is
independent. The sending side sends DMA_XFER message when the message is in
the respective host buffer (TX when host client sends, RX when FW client
sends). The recipient of DMA message responds with DMA_XFER_ACK, indicating
the 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't
send DMA; if FW doesn't support DMA then it won't respond with
DMA_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 means
that it already did DMA and the message resides at host. Thus, DMA_XFER
and DMA_XFER_ACK act as ownership indicators.
At initial state all outgoing memory belongs to the sender (TX to host, RX to
FW), DMA_XFER transfers ownership on the region that contains ISHTP message to
the receiving side, DMA_XFER_ACK returns ownership to the sender. A sender
need not wait for previous DMA_XFER to be ack'ed, and may send another message
as 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 IPC
fragments 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 for
TX and RX buffers respectively. On send request from client, the data to be
sent is copied to one of the send ring buffer and scheduled to be sent using
bus message protocol. These buffers are required because the FW may have not
have processed the last message and may not have enough flow control credits
to 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. Each
client 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 FW
client IDs
- For each FW ID found in that bitmap host sends
HOST_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 considers
ISHTP 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 to
Documentation/hid/hid-sensor.rst for HID sensor
Documentation/ABI/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 the request_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 the release_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 |
+---------------+ +-----------------+
ISH Debugging
-------------
To debug ISH, event tracing mechanism is used. To enable debug logs::
echo 1 > /sys/kernel/tracing/events/intel_ish/enable
cat /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
...
|