1# MIPI DSI 2 3## 概述 4 5### 功能简介 6 7DSI(Display Serial Interface)是由移动行业处理器接口联盟(Mobile Industry Processor Interface (MIPI) Alliance)制定的规范,旨在降低移动设备中显示控制器的成本。它以串行的方式发送像素数据或指令给外设(通常是LCD或者类似的显示设备),或从外设中读取状态信息或像素信息;它定义了主机、图像数据源和目标设备之间的串行总线和通信协议。 8 9MIPI DSI具备高速模式和低速模式两种工作模式,全部数据通道都可以用于单向的高速传输,但只有第一个数据通道才可用于低速双向传输,从属端的状态信息、像素等是通过该数据通道返回。时钟通道专用于在高速传输数据的过程中传输同步时钟信号。 10 11图1显示了简化的DSI接口。从概念上看,符合DSI的接口与基于DBI-2和DPI-2标准的接口具有相同的功能。它向外围设备传输像素或命令数据,并且可以从外围设备读取状态或像素信息。主要区别在于,DSI对所有像素数据、命令和事件进行序列化,而在传统接口中,这些像素数据、命令和事件通常需要附加控制信号才能在并行数据总线上传输。 12 13**图 1** DSI发送、接收接口 14 15 16 17DSI标准对应D-PHY、DSI、DCS规范,可分为四层: 18 19- PHY Layer 20 21 PHY层指定传输介质(电导体)、输入/输出电路和从串行比特流中捕获“1”和“0”的时钟机制。这一部分的规范记录了传输介质的特性、信号的电气参数以及时钟与数据通道之间的时序关系。在DSI链路的发送端,并行数据、信号事件和命令按照包组织在协议层转换为包。协议层附加包协议信息和报头,然后通过Lane Management层向PHY发送完整的字节。数据由PHY进行序列化,并通过串行链路发送。DSI链路的接收端执行与发送端相反的操作,将数据包分解为并行的数据、信号事件和命令。如果有多个Lane, Lane管理层将字节分配给单独的物理层,每个Lane一个PHY。 22 23- Lane Management层 24 25 负责发送和收集数据流到每条Lane。数据Lane的三种操作模式 :espace mode,High-Speed(Burst) mode,Control mode。 26 27- Low Level Protocol层 28 29 定义了如何组帧和解析以及错误检测等。 30 31- Application层 32 33 描述高层编码和解析数据流。这一层描述了数据流中包含的数据的更高级的编码和解释。根据显示子系统架构的不同,它可能由具有指定格式的像素或编码的位流组成,或者由显示模块内的显示控制器解释的命令组成。DSI规范描述了像素值、位流、命令和命令参数到包集合中的字节的映射。 34 35### 运作机制 36 37MIPI DSI软件模块各分层的作用为: 38 39- 接口层:提供打开设备、写入数据和关闭设备的接口。 40 41- 核心层:主要提供绑定设备、初始化设备以及释放设备的能力。 42 43- 适配层:实现其它具体的功能。 44 45 **说明:**<br>核心层可以调用接口层的函数,核心层通过钩子函数调用适配层函数,从而适配层可以间接的调用接口层函数,但是不可逆转接口层调用适配层函数。 46 47**图 2** DSI无服务模式结构图 48 49 50 51### 约束与限制 52 53由于使用无服务模式,MIPI_DSI接口暂不支持用户态使用。 54 55## 使用指导 56 57### 场景介绍 58 59MIPI DSI主要用于连接显示屏。 60 61### 接口说明 62 63MIPI DSI模块提供的主要接口如表1所示,具体API详见//drivers/hdf_core/framework/include/platform/mipi_dsi_if.h。 64 65**表1** MIPI DSI API接口功能介绍 66 67| 功能分类 | 接口名 | 68| -------- | -------- | 69| DevHandle MipiDsiOpen(uint8_t id) | 获取MIPI DSI操作句柄 | 70| void MipiDsiClose(DevHandle handle) | 释放MIPI DSI操作句柄 | 71| int32_t MipiDsiSetCfg(DevHandle handle, struct MipiCfg \*cfg) | 设置MIPI DSI相关配置 | 72| int32_t MipiDsiGetCfg(DevHandle handle, struct MipiCfg \*cfg) | 获取当前MIPI DSI相关配置 | 73| void MipiDsiSetLpMode(DevHandle handle) | 设置MIPI DSI进入Low power模式 | 74| void MipiDsiSetHsMode(DevHandle handle) | 设置MIPI DSI进入High speed模式 | 75| int32_t MipiDsiTx(DevHandle handle, struct DsiCmdDesc \*cmd) | DSI发送指令 | 76| int32_t MipiDsiRx(DevHandle handle, struct DsiCmdDesc \*cmd, int32_t readLen, uint8_t \*out) | MIPI DSI按期望长度回读数据 | 77 78### 开发步骤 79 80使用MIPI DSI的一般流程如下图所示。 81 82**图 3** MIPI DSI使用流程图 83 84 85 86#### 获取MIPI DSI操作句柄 87 88在进行MIPI DSI进行通信前,首先要调用MipiDsiOpen获取操作句柄,该函数会返回指定通道ID的操作句柄。 89 90```c 91DevHandle MipiDsiOpen(uint8_t id); 92``` 93 94**表 2** MipiDsiOpen的参数和返回值描述 95 96| **参数** | **参数描述** | 97| -------- | -------- | 98| id | uint8_t类型,MIPI DSI通道ID | 99| **返回值** | **返回值描述** | 100| NULL | 获取失败 | 101| 设备句柄 | 获取到指令通道的操作句柄, 类型为DevHandle | 102 103假设系统中的MIPI DSI通道为0,获取该通道操作句柄的示例如下: 104 105 106```c 107DevHandle mipiDsiHandle = NULL; // 设备句柄 108chnId = 0; // MIPI DSI通道ID 109 110// 获取操作句柄 111mipiDsiHandle = MipiDsiOpen(chnId); 112if (mipiDsiHandle == NULL) { 113 HDF_LOGE("MipiDsiOpen: mipi dsi open fail.\n"); 114 return NULL; 115} 116``` 117 118#### MIPI DSI相应配置 119 120- 写入MIPI DSI配置 121 122 ```c 123 int32_t MipiDsiSetCfg(DevHandle handle, struct MipiCfg *cfg); 124 ``` 125 126 **表 3** MipiDsiSetCfg的参数和返回值描述 127 128 | **参数** | **参数描述** | 129 | -------- | -------- | 130 | handle | DevHandle类型,操作句柄 | 131 | cfg | 结构体指针类型,MIPI DSI相应配置buf 指针 | 132 | **返回值** | **返回值描述** | 133 | HDF_SUCCESS | 设置MIPI DSI配置成功 | 134 | 负数 | 设置MIPI DSI配置失败 | 135 136 ```c 137 int32_t ret; 138 struct MipiCfg cfg = {0}; 139 140 // 当前对接的屏幕配置如下 141 cfg.lane = DSI_4_LANES; 142 cfg.mode = DSI_CMD_MODE; 143 cfg.burstMode = VIDEO_NON_BURST_MODE_SYNC_EVENTS; 144 cfg.format = FORMAT_RGB_24_BIT; 145 cfg.pixelClk = 174; 146 cfg.phyDataRate = 384; 147 cfg.timingInfo.hsaPixels = 50; 148 cfg.timingInfo.hbpPixels = 55; 149 cfg.timingInfo.hlinePixels = 1200; 150 cfg.timingInfo.yResLines = 1800; 151 cfg.timingInfo.vbpLines = 33; 152 cfg.timingInfo.vsaLines = 76; 153 cfg.timingInfo.vfpLines = 120; 154 cfg.timingInfo.xResPixels = 1342; 155 // 写入配置数据 156 ret = MipiDsiSetCfg(mipiDsiHandle, &cfg); 157 if (ret != HDF_SUCCESS) { 158 HDF_LOGE("MipiDsiSetCfg: set mipi cfg fail, ret:%d\n", ret); 159 return ret; 160 } 161 ``` 162 163- 获取当前MIPI DSI的配置 164 165 ```c 166 int32_t MipiDsiGetCfg(DevHandle handle, struct MipiCfg *cfg); 167 ``` 168 169 **表 4** MipiDsiGetCfg的参数和返回值描述 170 171 | **参数** | **参数描述** | 172 | -------- | -------- | 173 | handle | DevHandle类型,操作句柄 | 174 | cfg | 结构体指针,MIPI DSI相应配置buf 指针 | 175 | **返回值** | **返回值描述** | 176 | HDF_SUCCESS | 获取当前MIPI DSI的配置成功 | 177 | 负数 | 获取当前MIPI DSI的配置失败 | 178 179 ```c 180 int32_t ret; 181 struct MipiCfg cfg; 182 memset(&cfg, 0, sizeof(struct MipiCfg)); 183 ret = MipiDsiGetCfg(mipiDsiHandle, &cfg); 184 if (ret != HDF_SUCCESS) { 185 HDF_LOGEMipiDsiGetCfg: get mipi cfg fail, ret:%d!\n", ret); 186 return ret; 187 } 188 ``` 189 190#### 发送/回读控制指令 191 192- 发送指令 193 194 ```c 195 int32_t MipiDsiTx(PalHandle handle, struct DsiCmdDesc *cmd); 196 ``` 197 198 **表 5** MipiDsiTx的参数和返回值描述 199 200 | **参数** | **参数描述** | 201 | -------- | -------- | 202 | handle | DevHandle类型,操作句柄 | 203 | cmd | 结构体指针类型,需要发送的指令数据指针 | 204 | **返回值** | **返回值描述** | 205 | HDF_SUCCESS | 发送成功 | 206 | 负数 | 发送失败 | 207 208 ```c 209 int32_t ret; 210 struct DsiCmdDesc *cmd = OsalMemCalloc(sizeof(struct DsiCmdDesc)); 211 if (cmd == NULL) { 212 return HDF_FAILURE; 213 } 214 cmd->dtype = DTYPE_DCS_WRITE; 215 cmd->dlen = 1; 216 cmd->payload = OsalMemCalloc(sizeof(uint8_t)); 217 if (cmd->payload == NULL) { 218 HdfFree(cmd); 219 return HDF_FAILURE; 220 } 221 *(cmd->payload) = DTYPE_GEN_LWRITE; 222 MipiDsiSetLpMode(mipiHandle); 223 ret = MipiDsiTx(mipiHandle, cmd); 224 MipiDsiSetHsMode(mipiHandle); 225 if (ret != HDF_SUCCESS) { 226 HDF_LOGE("MipiDsiTx: mipi dsi tx fail, ret:%d\n", ret); 227 HdfFree(cmd->payload); 228 HdfFree(cmd); 229 return ret; 230 } 231 HdfFree(cmd->payload); 232 HdfFree(cmd); 233 ``` 234 235- 回读指令 236 237 ```c 238 int32_t MipiDsiRx(DevHandle handle, struct DsiCmdDesc *cmd, uint32_t readLen, uint8_t *out); 239 ``` 240 241 **表 6** MipiDsiRx的参数和返回值描述 242 243 | **参数** | **参数描述** | 244 | -------- | -------- | 245 | handle | DevHandle类型,操作句柄 | 246 | cmd | 结构体指针类型,需要回读的指令数据指针 | 247 | readLen | uint32_t类型,期望回读的数据长度 | 248 | out | uint8_t类型指针,回读的数据 | 249 | **返回值** | **返回值描述** | 250 | HDF_SUCCESS | 获取成功 | 251 | 负数 | 获取失败 | 252 253 ```c 254 int32_t ret; 255 uint8_t readVal = 0; 256 257 struct DsiCmdDesc *cmdRead = OsalMemCalloc(sizeof(struct DsiCmdDesc)); 258 if (cmdRead == NULL) { 259 return HDF_FAILURE; 260 } 261 cmdRead->dtype = DTYPE_DCS_READ; 262 cmdRead->dlen = 1; 263 cmdRead->payload = OsalMemCalloc(sizeof(uint8_t)); 264 if (cmdRead->payload == NULL) { 265 HdfFree(cmdRead); 266 return HDF_FAILURE; 267 } 268 *(cmdRead->payload) = DDIC_REG_STATUS; 269 MipiDsiSetLpMode(mipiDsiHandle); 270 ret = MipiDsiRx(mipiDsiHandle, cmdRead, sizeof(readVal), &readVal); 271 MipiDsiSetHsMode(mipiDsiHandle); 272 if (ret != HDF_SUCCESS) { 273 HDF_LOGE("MipiDsiRx: mipi dsi rx fail, ret:%d\n", ret); 274 HdfFree(cmdRead->payload); 275 HdfFree(cmdRead); 276 return HDF_FAILURE; 277 } 278 HdfFree(cmdRead->payload); 279 HdfFree(cmdRead); 280 ``` 281 282 283#### 释放MIPI DSI操作句柄 284 285MIPI DSI使用完成之后,需要释放操作句柄,释放句柄的函数如下所示: 286 287```c 288void MipiDsiClose(DevHandle handle); 289``` 290 291该函数会释放掉由MipiDsiOpen申请的资源。 292 293**表 7** MipiDsiClose的参数和返回值描述 294 295| 参数 | 参数描述 | 296| -------- | -------- | 297| handle | DevHandle类型,MIPI DSI操作句柄 | 298 299```c 300MipiDsiClose(mipiHandle); // 释放掉MIPI DSI操作句柄 301``` 302 303## 使用实例 304 305本例拟对Hi3516DV300开发板上MIPI DSI设备进行操作。 306 307MIPI DSI完整的使用示例如下所示: 308 309```c 310#include "hdf_log.h" 311#include "mipi_dsi_if.h" 312#include "osal_mem.h" 313 314#define DTYPE_DCS_WRITE 0x05 315#define DTYPE_DCS_READ 0x06 316#define DTYPE_GEN_LWRITE 0x29 317#define DDIC_REG_STATUS 0x0A 318 319 320int32_t PalMipiDsiTestSample(void) 321{ 322 uint8_t chnId; 323 int32_t ret; 324 DevHandle mipiDsiHandle = NULL; 325 326 // 设备通道编号 327 chnId = 0; 328 // 获取操作句柄 329 mipiDsiHandle = MipiDsiOpen(chnId); 330 if (mipiDsiHandle == NULL) { 331 HDF_LOGE("MipiDsiOpen: failed!\n"); 332 return HDF_FAILURE; 333 } 334 // 配置相应参数 335 struct MipiCfg cfg = {0}; 336 cfg.lane = DSI_2_LANES; 337 cfg.mode = DSI_VIDEO_MODE; 338 cfg.format = FORMAT_RGB_24_BIT; 339 cfg.burstMode = VIDEO_BURST_MODE; 340 cfg.timing.xPixels = 480; // 480: width 341 cfg.timing.hsaPixels = 10; // 10: horizontal sync porch 342 cfg.timing.hbpPixels = 20; // 20: horizontal back porch 343 cfg.timing.hlinePixels = 530; // 530: horizontal total width 344 cfg.timing.vsaLines = 2; // 2: vertiacl sync width 345 cfg.timing.vbpLines = 14; // 14: vertiacl back porch 346 cfg.timing.vfpLines = 16; // 16: vertiacl front porch 347 cfg.timing.ylines = 960; // 960: height 348 cfg.timing.edpiCmdSize = 0; // 0 : no care 349 cfg.pixelClk = 31546; // 31546: pixel clk 350 cfg.phyDataRate = 379; // 379: mipi clk 351 // 写入配置数据 352 ret = MipiDsiSetCfg(mipiDsiHandle, &cfg); 353 if (ret != 0) { 354 HDF_LOGE("PalMipiDsiTestSample: set mipi dsi cfg fail, ret:%d\n", ret); 355 return ret; 356 } 357 // 发送PANEL初始化指令 358 struct DsiCmdDesc *cmd = OsalMemCalloc(sizeof(struct DsiCmdDesc)); 359 if (cmd == NULL) { 360 return -1; 361 } 362 cmd->dataType = DTYPE_DCS_WRITE; 363 cmd->dataLen = 1; 364 cmd->payload = OsalMemCalloc(sizeof(uint8_t)); 365 if (cmd->payload == NULL) { 366 OsalMemFree(cmd); 367 return -1; 368 } 369 *(cmd->payload) = DTYPE_GEN_LWRITE; 370 MipiDsiSetLpMode(mipiDsiHandle); 371 ret = MipiDsiTx(mipiDsiHandle, cmd); 372 MipiDsiSetHsMode(mipiDsiHandle); 373 if (ret != HDF_SUCCESS) { 374 HDF_LOGE("PalMipiDsiTestSample: mipi dsi tx fail, ret:%d\n", ret); 375 OsalMemFree(cmd->payload); 376 OsalMemFree(cmd); 377 return ret; 378 } 379 OsalMemFree(cmd->payload); 380 OsalMemFree(cmd); 381 // 回读panel状态寄存器 382 uint8_t readVal = 0; 383 struct DsiCmdDesc *cmdRead = OsalMemCalloc(sizeof(struct DsiCmdDesc)); 384 if (cmdRead == NULL) { 385 return -1; 386 } 387 cmdRead->dataType = DTYPE_DCS_READ; 388 cmdRead->dataLen = 1; 389 cmdRead->payload = OsalMemCalloc(sizeof(uint8_t)); 390 if (cmdRead->payload == NULL) { 391 OsalMemFree(cmdRead); 392 return -1; 393 } 394 *(cmdRead->payload) = DDIC_REG_STATUS; 395 MipiDsiSetLpMode(mipiDsiHandle); 396 ret = MipiDsiRx(mipiDsiHandle, cmdRead, sizeof(readVal), &readVal); 397 MipiDsiSetHsMode(mipiDsiHandle); 398 if (ret != HDF_SUCCESS) { 399 HDF_LOGE("PalMipiDsiTestSample: mipi dsi rx fail, ret:%d\n", ret); 400 OsalMemFree(cmdRead->payload); 401 OsalMemFree(cmdRead); 402 return ret; 403 } 404 OsalMemFree(cmdRead->payload); 405 OsalMemFree(cmdRead); 406 HDF_LOGD("PalMipiDsiTestSample: mipi dsi tests end"); 407 // 释放MIPI DSI设备句柄 408 MipiDsiClose(mipiDsiHandle); 409 return ret; 410} 411``` 412