高速同步串行接口 (HSI)

简介

高速同步接口 (HSI) 是一种全双工、低延迟协议,专为应用处理器和基带芯片组之间的芯片级互连而优化。它已由 MIPI 联盟在 2003 年指定,此后由多家供应商实施。

HSI 接口支持通过多个通道(通常为 8 个)进行全双工通信,并且能够达到高达 200 Mbit/s 的速度。

串行协议使用两个信号 DATA 和 FLAG 作为组合的数据和时钟信号,并使用一个额外的 READY 信号进行流量控制。一个额外的 WAKE 信号可用于将芯片从待机模式唤醒。这些信号通常以 AC 为前缀表示从应用芯片到蜂窝芯片的信号,以 CA 为前缀表示反方向的信号。

+------------+                                 +---------------+
|  Cellular  |                                 |  Application  |
|    Die     |                                 |      Die      |
|            | - - - - - - CAWAKE - - - - - - >|               |
|           T|------------ CADATA ------------>|R              |
|           X|------------ CAFLAG ------------>|X              |
|            |<----------- ACREADY ------------|               |
|            |                                 |               |
|            |                                 |               |
|            |< - - - - -  ACWAKE - - - - - - -|               |
|           R|<----------- ACDATA -------------|T              |
|           X|<----------- ACFLAG -------------|X              |
|            |------------ CAREADY ----------->|               |
|            |                                 |               |
|            |                                 |               |
+------------+                                 +---------------+

Linux 中的 HSI 子系统

在 Linux 内核中,hsi 子系统应该用于 HSI 设备。hsi 子系统包含 hsi 控制器的驱动程序,包括对多端口控制器的支持,并提供用于使用 HSI 端口的通用 API。

它还包含 HSI 客户端驱动程序,这些驱动程序利用通用 API 来实现 HSI 接口上使用的协议。这些客户端驱动程序可以使用任意数量的通道。

hsi-char 设备

每个端口都会自动注册一个名为 hsi_char 的通用客户端驱动程序,该驱动程序为表示 HSI 端口的用户空间提供字符设备。它可以用于从用户空间通过 HSI 进行通信。用户空间可以使用以下 ioctl 命令配置 hsi_char 设备

HSC_RESET

刷新 HSI 端口

HSC_SET_PM

启用或禁用客户端。

HSC_SEND_BREAK

发送中断

HSC_SET_RX

设置 RX 配置

HSC_GET_RX

获取 RX 配置

HSC_SET_TX

设置 TX 配置

HSC_GET_TX

获取 TX 配置

内核 HSI API

struct hsi_channel

hsi 客户端使用的通道资源

定义:

struct hsi_channel {
    unsigned int    id;
    const char      *name;
};

成员

id

通道号

name

通道名称

struct hsi_config

用于 RX/TX HSI 模块的配置

定义:

struct hsi_config {
    unsigned int            mode;
    struct hsi_channel      *channels;
    unsigned int            num_channels;
    unsigned int            num_hw_channels;
    unsigned int            speed;
    union {
        unsigned int    flow;
        unsigned int    arb_mode;
    };
};

成员

mode

位传输模式(STREAM 或 FRAME)

channels

客户端使用的通道资源

num_channels

通道资源数量

num_hw_channels

收发器配置的通道数量 [1..16]

speed

最大位传输速度 (Kbit/s)

{unnamed_union}

匿名

flow

RX 流类型(SYNCHRONIZED 或 PIPELINE)

arb_mode

TX 帧的仲裁模式(轮循、优先级)

struct hsi_board_info

HSI 客户端板信息

定义:

struct hsi_board_info {
    const char              *name;
    unsigned int            hsi_id;
    unsigned int            port;
    struct hsi_config       tx_cfg;
    struct hsi_config       rx_cfg;
    void *platform_data;
    struct dev_archdata     *archdata;
};

成员

name

HSI 设备的名称

hsi_id

客户端所在的 HSI 控制器 ID

port

客户端所在的控制器中的端口号

tx_cfg

HSI TX 配置

rx_cfg

HSI RX 配置

platform_data

平台相关数据

archdata

依赖于架构的设备数据

struct hsi_client

附加到 HSI 端口的 HSI 客户端

定义:

struct hsi_client {
    struct device           device;
    struct hsi_config       tx_cfg;
    struct hsi_config       rx_cfg;
};

成员

device

设备的驱动程序模型表示

tx_cfg

HSI TX 配置

rx_cfg

HSI RX 配置

struct hsi_client_driver

与 HSI 客户端关联的驱动程序

定义:

struct hsi_client_driver {
    struct device_driver    driver;
};

成员

driver

驱动程序的驱动程序模型表示

struct hsi_msg

HSI 消息描述符

定义:

struct hsi_msg {
    struct list_head        link;
    struct hsi_client       *cl;
    struct sg_table         sgt;
    void *context;
    void (*complete)(struct hsi_msg *msg);
    void (*destructor)(struct hsi_msg *msg);
    int status;
    unsigned int            actual_len;
    unsigned int            channel;
    unsigned int            ttype:1;
    unsigned int            break_frame:1;
};

成员

link

当前描述符所有者可以自由使用

cl

发出传输的 HSI 设备客户端

sgt

分散列表数组的头部

context

与传输关联的客户端上下文数据

complete

传输完成回调

destructor

刷新时释放资源的析构函数

status

完成时传输的状态

actual_len

完成时传输的实际数据长度

channel

要发送/接收消息的通道

ttype

传输类型(如果设置则为 TX,否则为 RX)

break_frame

如果为 true,HSI 将发送/接收中断帧。数据缓冲区在请求中被忽略。

struct hsi_port

HSI 端口设备

定义:

struct hsi_port {
    struct device                   device;
    struct hsi_config               tx_cfg;
    struct hsi_config               rx_cfg;
    unsigned int                    num;
    unsigned int                    shared:1;
    int claimed;
    struct mutex                    lock;
    int (*async)(struct hsi_msg *msg);
    int (*setup)(struct hsi_client *cl);
    int (*flush)(struct hsi_client *cl);
    int (*start_tx)(struct hsi_client *cl);
    int (*stop_tx)(struct hsi_client *cl);
    int (*release)(struct hsi_client *cl);
    struct blocking_notifier_head   n_head;
};

成员

device

设备的驱动程序模型表示

tx_cfg

当前 TX 路径配置

rx_cfg

当前 RX 路径配置

num

端口号

shared

当端口可以由不同的客户端共享时设置

claimed

声明端口的客户端的引用计数

lock

序列化端口声明

async

异步传输回调

setup

设置 HSI 客户端配置的回调

flush

清除硬件状态并销毁所有挂起传输的回调

start_tx

通知客户端想要发送数据的回调

stop_tx

通知客户端不再希望发送数据的回调

release

通知客户端不再使用端口的回调

n_head

用于向客户端发出端口事件信号的通知程序链。

struct hsi_controller

HSI 控制器设备

定义:

struct hsi_controller {
    struct device           device;
    struct module           *owner;
    unsigned int            id;
    unsigned int            num_ports;
    struct hsi_port         **port;
};

成员

device

设备的驱动程序模型表示

owner

指向拥有控制器的模块的指针

id

HSI 控制器 ID

num_ports

HSI 控制器中的端口数

port

HSI 端口数组

unsigned int hsi_id(struct hsi_client *cl)

获取与客户端关联的 HSI 控制器 ID

参数

struct hsi_client *cl

指向 HSI 客户端的指针

描述

返回客户端所连接的控制器 ID

unsigned int hsi_port_id(struct hsi_client *cl)

获取客户端所连接的端口号

参数

struct hsi_client *cl

指向 HSI 客户端的指针

描述

返回与客户端关联的端口号

int hsi_setup(struct hsi_client *cl)

配置客户端的端口

参数

struct hsi_client *cl

指向 HSI 客户端的指针

描述

当共享端口时,客户端应依赖于单个客户端设置,或所有客户端具有相同的设置。

失败时返回 -errno,成功时返回 0

int hsi_flush(struct hsi_client *cl)

清除客户端端口上所有待处理的事务

参数

struct hsi_client *cl

指向 HSI 客户端的指针

描述

此函数将销毁端口中所有待处理的 hsi_msg,并重置硬件端口,使其可以从干净状态接收和传输。

失败时返回 -errno,成功时返回 0

int hsi_async_read(struct hsi_client *cl, struct hsi_msg *msg)

提交一个读取传输

参数

struct hsi_client *cl

指向 HSI 客户端的指针

struct hsi_msg *msg

传输的 HSI 消息描述符

描述

失败时返回 -errno,成功时返回 0

int hsi_async_write(struct hsi_client *cl, struct hsi_msg *msg)

提交一个写入传输

参数

struct hsi_client *cl

指向 HSI 客户端的指针

struct hsi_msg *msg

传输的 HSI 消息描述符

描述

失败时返回 -errno,成功时返回 0

int hsi_start_tx(struct hsi_client *cl)

通知端口客户端想要开始 TX

参数

struct hsi_client *cl

指向 HSI 客户端的指针

描述

失败时返回 -errno,成功时返回 0

int hsi_stop_tx(struct hsi_client *cl)

通知端口客户端不再想要传输

参数

struct hsi_client *cl

指向 HSI 客户端的指针

描述

失败时返回 -errno,成功时返回 0

void hsi_port_unregister_clients(struct hsi_port *port)

注销 HSI 端口

参数

struct hsi_port *port

要注销的 HSI 端口

void hsi_unregister_controller(struct hsi_controller *hsi)

注销 HSI 控制器

参数

struct hsi_controller *hsi

要注销的 HSI 控制器

int hsi_register_controller(struct hsi_controller *hsi)

注册 HSI 控制器及其端口

参数

struct hsi_controller *hsi

要注销的 HSI 控制器

描述

失败时返回 -errno,成功时返回 0。

int hsi_register_client_driver(struct hsi_client_driver *drv)

向 HSI 总线注册 HSI 客户端

参数

struct hsi_client_driver *drv

要注册的 HSI 客户端驱动程序

描述

失败时返回 -errno,成功时返回 0。

void hsi_put_controller(struct hsi_controller *hsi)

释放 HSI 控制器

参数

struct hsi_controller *hsi

指向要释放的 HSI 控制器的指针

描述

HSI 控制器驱动程序只有在成功调用 hsi_register_controller 之前需要释放其分配的 hsi_controller 结构时才应使用此函数。不允许其他用法。

struct hsi_controller *hsi_alloc_controller(unsigned int n_ports, gfp_t flags)

分配 HSI 控制器及其端口

参数

unsigned int n_ports

HSI 控制器上的端口数

gfp_t flags

内核分配标志

描述

失败时返回 NULL,成功时返回指向 hsi_controller 的指针。

void hsi_free_msg(struct hsi_msg *msg)

释放 HSI 消息

参数

struct hsi_msg *msg

指向 HSI 消息的指针

描述

客户端负责释放散列表指向的缓冲区。

struct hsi_msg *hsi_alloc_msg(unsigned int nents, gfp_t flags)

分配 HSI 消息

参数

unsigned int nents

内存条目数

gfp_t flags

内核分配标志

描述

nents 可以为 0。这主要对读取传输有意义。在这种情况下,当有数据要读取但没有使用时,HSI 驱动程序将调用完成回调。

失败时返回 NULL,成功时返回指向 hsi_msg 的指针。

int hsi_async(struct hsi_client *cl, struct hsi_msg *msg)

向控制器提交 HSI 传输

参数

struct hsi_client *cl

发送传输的 HSI 客户端

struct hsi_msg *msg

传递给控制器的 HSI 传输

描述

HSI 消息必须预先设置 channel、ttype、complete 和 destructor 字段。如果 nents > 0,则客户端还必须初始化 scatterlists,使其指向要写入或读取的缓冲区。

HSI 控制器依赖于客户端预先分配的缓冲区,它们不会自行分配缓冲区。

一旦 HSI 消息传输完成,HSI 控制器会调用 complete 回调函数,并更新 HSI 消息的 status 和 actual_len 字段。complete 回调函数可以在 hsi_async 返回之前被调用。

失败时返回 -errno,成功时返回 0。

int hsi_claim_port(struct hsi_client *cl, unsigned int share)

声明 HSI 客户端的端口。

参数

struct hsi_client *cl

想要声明其端口的 HSI 客户端。

unsigned int share

标志,指示客户端是否想要共享端口。

描述

失败时返回 -errno,成功时返回 0。

void hsi_release_port(struct hsi_client *cl)

释放 HSI 客户端的端口。

参数

struct hsi_client *cl

之前声明过其端口的 HSI 客户端。

int hsi_register_port_event(struct hsi_client *cl, void (*handler)(struct hsi_client*, unsigned long))

注册客户端以接收端口事件。

参数

struct hsi_client *cl

想要接收端口事件的 HSI 客户端。

void (*handler)(struct hsi_client *, unsigned long)

事件处理回调函数。

描述

客户端应注册一个回调函数,以便能够接收来自端口的事件。注册应在声明端口后进行。处理程序可以在中断上下文中调用。

出错时返回 -errno,成功时返回 0。

int hsi_unregister_port_event(struct hsi_client *cl)

停止接收客户端的端口事件。

参数

struct hsi_client *cl

想要停止接收端口事件的 HSI 客户端。

描述

客户端应在释放其关联的端口之前调用此函数。

出错时返回 -errno,成功时返回 0。

int hsi_event(struct hsi_port *port, unsigned long event)

通知客户端有关端口事件。

参数

struct hsi_port *port

事件发生的端口。

unsigned long event

事件类型。

描述

客户端不应关心唤醒线行为。然而,由于 HSI HW 协议中的竞争条件,需要通知客户端唤醒线变化,以便他们可以实现针对此问题的解决方法。

事件:HSI_EVENT_START_RX - 输入唤醒线高电平,HSI_EVENT_STOP_RX - 输入唤醒线低电平。

出错时返回 -errno,成功时返回 0。

int hsi_get_channel_id_by_name(struct hsi_client *cl, char *name)

通过通道名称获取通道 ID。

参数

struct hsi_client *cl

使用通道的 HSI 客户端。

char *name

通道已知的名称。

描述

客户端可以调用此函数来获取 HSI 通道 ID,类似于通过名称请求 IRQ 或 GPIO。此函数假定 RX 和 TX 使用相同的通道配置。

出错时返回 -errno,成功时返回通道 ID。