1 /*
2 * Copyright (c) 2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_mipi_dsi_drv.h"
9
10 #define MIPI_WAIT_COND(cond, timeout_us) \
11 ({ \
12 volatile uint32_t timeout_cycle = 1000UL * (timeout_us); \
13 for (;;) { \
14 if (cond) \
15 break; \
16 if (timeout_us && timeout_cycle == 0) { \
17 break; \
18 } \
19 timeout_cycle--; \
20 } \
21 (cond) ? true : false; \
22 })
23
24 typedef struct mipi_dsi_packet {
25 uint8_t header[4]; /*!< the four bytes that make up the header (Data ID, Word Count or Packet Data, and ECC) */
26 uint16_t payload_length; /*!< number of bytes in the payload */
27 const uint8_t *payload; /*!< a pointer to a buffer containing the payload, if any */
28 } mipi_dsi_packet_t;
29
30 /**
31 * mipi_dsi_packet_format_is_short - check if a packet is of the short format
32 * @param type: MIPI DSI data type of the packet
33 *
34 * @return: true if the packet for the given data type is a short packet, false
35 * otherwise.
36 */
mipi_dsi_packet_format_is_short(uint8_t type)37 static bool mipi_dsi_packet_format_is_short(uint8_t type)
38 {
39 switch (type) {
40 case MIPI_DSI_SHUTDOWN_PERIPHERAL:
41 case MIPI_DSI_TURN_ON_PERIPHERAL:
42 case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
43 case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
44 case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
45 case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
46 case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
47 case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
48 case MIPI_DSI_DCS_SHORT_WRITE:
49 case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
50 case MIPI_DSI_DCS_READ:
51 case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
52 return true;
53 }
54
55 return false;
56 }
57
58 /**
59 * mipi_dsi_packet_format_is_long - check if a packet is of the long format
60 * @param type: MIPI DSI data type of the packet
61 *
62 * @return: true if the packet for the given data type is a long packet, false
63 * otherwise.
64 */
mipi_dsi_packet_format_is_long(uint8_t type)65 static bool mipi_dsi_packet_format_is_long(uint8_t type)
66 {
67 switch (type) {
68 case MIPI_DSI_GENERIC_LONG_WRITE:
69 case MIPI_DSI_DCS_LONG_WRITE:
70 return true;
71 }
72
73 return false;
74 }
75
76 /**
77 * mipi_dsi_create_packet - create a packet from a message according to the
78 * DSI protocol
79 * @param packet: pointer to a DSI packet structure
80 * @param msg: message to translate into a packet
81 *
82 * @return: true on success or false on failure.
83 */
mipi_dsi_create_packet(mipi_dsi_packet_t * packet,const mipi_dsi_msg_t * msg)84 static bool mipi_dsi_create_packet(mipi_dsi_packet_t *packet, const mipi_dsi_msg_t *msg)
85 {
86 if (!packet || !msg)
87 return false;
88
89 /* do some minimum sanity checking */
90 if (!mipi_dsi_packet_format_is_short(msg->type) &&
91 !mipi_dsi_packet_format_is_long(msg->type))
92 return false;
93
94 if (msg->channel > 3)
95 return false;
96
97 memset(packet, 0, sizeof(*packet));
98 packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f);
99 if (mipi_dsi_packet_format_is_long(msg->type)) {
100 packet->header[1] = (msg->tx_len >> 0) & 0xff;
101 packet->header[2] = (msg->tx_len >> 8) & 0xff;
102
103 packet->payload_length = msg->tx_len;
104 packet->payload = (const uint8_t *)msg->tx_buf;
105 } else {
106 const uint8_t *tx = (const uint8_t *)msg->tx_buf;
107
108 packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0;
109 packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0;
110 }
111
112 return true;
113 }
114
mipi_dsi_config_format(MIPI_DSI_Type * ptr,mipi_dsi_pixel_format_t format)115 static void mipi_dsi_config_format(MIPI_DSI_Type *ptr, mipi_dsi_pixel_format_t format)
116 {
117 uint32_t val = 0;
118
119 switch ((uint8_t)format) {
120 case MIPI_DSI_FMT_RGB888:
121 val = MIPI_DSI_DPI_COLOR_CODING_DPI_COLOR_CODING_SET(0x05);
122 break;
123 case MIPI_DSI_FMT_RGB666:
124 val = MIPI_DSI_DPI_COLOR_CODING_DPI_COLOR_CODING_SET(0x04) |
125 MIPI_DSI_DPI_COLOR_CODING_LOOSELY18_EN_MASK;
126 break;
127 case MIPI_DSI_FMT_RGB666_PACKED:
128 val = MIPI_DSI_DPI_COLOR_CODING_DPI_COLOR_CODING_SET(0x04);
129 break;
130 case MIPI_DSI_FMT_RGB565:
131 val = MIPI_DSI_DPI_COLOR_CODING_DPI_COLOR_CODING_SET(0x00);
132 break;
133 }
134
135 ptr->DPI_COLOR_CODING = val;
136 }
137
138 /* Get lane byte clock cycles. */
mipi_dsi_get_hcomponent_lbcc(uint32_t lane_mbps,uint32_t pixel_clock_khz,uint32_t hcomponent)139 static int mipi_dsi_get_hcomponent_lbcc(uint32_t lane_mbps, uint32_t pixel_clock_khz, uint32_t hcomponent)
140 {
141 uint32_t lbcc = hcomponent * lane_mbps * 1000 / 8;
142
143 if (!pixel_clock_khz)
144 return 0;
145
146 return HPM_DIV_ROUND_CLOSEST(lbcc, pixel_clock_khz);
147 }
148
mipi_dsi_video_para_config(MIPI_DSI_Type * ptr,mipi_dsi_config_t * cfg)149 static void mipi_dsi_video_para_config(MIPI_DSI_Type *ptr, mipi_dsi_config_t *cfg)
150 {
151 mipi_video_para_t *video_para = &cfg->video_para;
152 int htotal, lbcc;
153
154 /* VID_HXXXX_TIME uint is lbcc(lane byte clock = lane_mbps / 8) */
155 htotal = video_para->hactive + video_para->hsync_len +
156 video_para->hback_porch + video_para->hfront_porch;
157 lbcc = mipi_dsi_get_hcomponent_lbcc(cfg->lane_mbps, video_para->pixel_clock_khz, htotal);
158 ptr->VID_HLINE_TIME = lbcc;
159 lbcc = mipi_dsi_get_hcomponent_lbcc(cfg->lane_mbps, video_para->pixel_clock_khz, video_para->hsync_len);
160 ptr->VID_HSA_TIME = lbcc;
161 lbcc = mipi_dsi_get_hcomponent_lbcc(cfg->lane_mbps, video_para->pixel_clock_khz, video_para->hback_porch);
162 ptr->VID_HBP_TIME = lbcc;
163
164 ptr->VID_VACTIVE_LINES = video_para->vactive;
165 ptr->VID_VSA_LINES = video_para->vsync_len;
166 ptr->VID_VBP_LINES = video_para->vback_porch;
167 ptr->VID_VFP_LINES = video_para->vfront_porch;
168 }
169
mipi_dsi_genif_wait_w_pld_fifo_not_full(MIPI_DSI_Type * ptr)170 static bool mipi_dsi_genif_wait_w_pld_fifo_not_full(MIPI_DSI_Type *ptr)
171 {
172 uint32_t mask = MIPI_DSI_CMD_PKT_STATUS_GEN_PLD_W_FULL_MASK;
173 return MIPI_WAIT_COND(!(ptr->CMD_PKT_STATUS & mask), 10000);
174 }
175
mipi_dsi_genif_wait_cmd_fifo_not_full(MIPI_DSI_Type * ptr)176 static bool mipi_dsi_genif_wait_cmd_fifo_not_full(MIPI_DSI_Type *ptr)
177 {
178 uint32_t mask = MIPI_DSI_CMD_PKT_STATUS_GEN_CMD_FULL_MASK;
179 return MIPI_WAIT_COND(!(ptr->CMD_PKT_STATUS & mask), 10000);
180 }
181
mipi_dsi_genif_wait_write_fifo_empty(MIPI_DSI_Type * ptr)182 static bool mipi_dsi_genif_wait_write_fifo_empty(MIPI_DSI_Type *ptr)
183 {
184 uint32_t mask = MIPI_DSI_CMD_PKT_STATUS_GEN_CMD_EMPTY_MASK |
185 MIPI_DSI_CMD_PKT_STATUS_GEN_PLD_W_EMPTY_MASK;
186
187 return MIPI_WAIT_COND((ptr->CMD_PKT_STATUS & mask) == mask, 10000);
188 }
189
dw_mipi_dsi_read_from_fifo(MIPI_DSI_Type * ptr,const struct mipi_dsi_msg * msg)190 static bool dw_mipi_dsi_read_from_fifo(MIPI_DSI_Type *ptr,
191 const struct mipi_dsi_msg *msg)
192 {
193 uint8_t *payload = (uint8_t *)msg->rx_buf;
194 uint16_t length;
195 uint32_t val;
196 uint32_t mask;
197 bool ret = true;
198
199 mask = MIPI_DSI_CMD_PKT_STATUS_GEN_RD_CMD_BUSY_MASK;
200 ret = MIPI_WAIT_COND(!(ptr->CMD_PKT_STATUS & mask), 10000);
201 if (ret == false) {
202 return ret;
203 }
204
205 /* Receive payload */
206 for (length = msg->rx_len; length; length -= 4) {
207 mask = MIPI_DSI_CMD_PKT_STATUS_GEN_PLD_R_EMPTY_MASK;
208 ret = MIPI_WAIT_COND(!(ptr->CMD_PKT_STATUS & mask), 10000);
209 if (ret == false) {
210 return ret;
211 }
212
213 val = ptr->GEN_PLD_DATA;
214
215 switch (length) {
216 case 3:
217 payload[2] = (val >> 16) & 0xff;
218 /* Fall through */
219 case 2:
220 payload[1] = (val >> 8) & 0xff;
221 /* Fall through */
222 case 1:
223 payload[0] = val & 0xff;
224 return ret;
225 }
226
227 payload[0] = (val >> 0) & 0xff;
228 payload[1] = (val >> 8) & 0xff;
229 payload[2] = (val >> 16) & 0xff;
230 payload[3] = (val >> 24) & 0xff;
231 payload += 4;
232 }
233
234 return ret;
235 }
236
get_le32(const uint8_t * p)237 static uint32_t get_le32(const uint8_t *p)
238 {
239 return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
240 }
241
mipi_dsi_get_defconfig_on_video(mipi_dsi_config_t * cfg)242 void mipi_dsi_get_defconfig_on_video(mipi_dsi_config_t *cfg)
243 {
244 mipi_video_para_t video_para = {
245 .pixel_clock_khz = 59400,
246 .hactive = 800,
247 .hsync_len = 8,
248 .hback_porch = 48,
249 .hfront_porch = 52,
250 .vsync_len = 6,
251 .vactive = 1280,
252 .vback_porch = 16,
253 .vfront_porch = 15
254 };
255
256 cfg->lanes = 4;
257 cfg->channel = 0;
258 cfg->lane_mbps = 500;
259 cfg->disable_eotp = false;
260 cfg->pixel_format = MIPI_DSI_FMT_RGB888;
261 cfg->video_mode = MIPI_DSI_VIDEO_MODE_BURST;
262 cfg->video_para = video_para;
263 }
264
mipi_dsi_init(MIPI_DSI_Type * ptr,mipi_dsi_config_t * cfg)265 void mipi_dsi_init(MIPI_DSI_Type *ptr, mipi_dsi_config_t *cfg)
266 {
267 uint32_t val;
268
269 /* PWR need reset when config register */
270 ptr->PWR_UP &= ~MIPI_DSI_PWR_UP_SHUTDOWNZ_MASK;
271
272 /* escclk config about 20MHz and esc_clk_div > 1*/
273 uint32_t esc_clk_div = HPM_DIV_ROUND_UP(cfg->lane_mbps / 8, 20);
274 esc_clk_div = esc_clk_div <= 1 ? 2 : esc_clk_div;
275
276 ptr->CLKMGR_CFG = MIPI_DSI_CLKMGR_CFG_TO_CLK_DIVISION_SET(10) |
277 MIPI_DSI_CLKMGR_CFG_TX_ESC_CLK_DIVISION_SET(esc_clk_div);
278
279 mipi_dsi_config_format(ptr, cfg->pixel_format);
280 ptr->DPI_VCID = MIPI_DSI_DPI_VCID_DPI_VCID_SET(cfg->channel);
281 ptr->DPI_LP_CMD_TIM = MIPI_DSI_DPI_LP_CMD_TIM_OUTVACT_LPCMD_TIME_SET(4) |
282 MIPI_DSI_DPI_LP_CMD_TIM_OUTVACT_LPCMD_TIME_SET(4);
283
284 val = MIPI_DSI_PCKHDL_CFG_BTA_EN_MASK |
285 MIPI_DSI_PCKHDL_CFG_EOTP_TX_EN_MASK |
286 MIPI_DSI_PCKHDL_CFG_ECC_RX_EN_MASK |
287 MIPI_DSI_PCKHDL_CFG_CRC_RX_EN_MASK;
288 if (cfg->disable_eotp)
289 val &= ~MIPI_DSI_PCKHDL_CFG_EOTP_TX_EN_MASK;
290 ptr->PCKHDL_CFG = val;
291
292 val = MIPI_DSI_VID_MODE_CFG_LP_HFP_EN_MASK |
293 MIPI_DSI_VID_MODE_CFG_LP_HBP_EN_MASK |
294 MIPI_DSI_VID_MODE_CFG_LP_VACT_EN_MASK |
295 MIPI_DSI_VID_MODE_CFG_LP_VFP_EN_MASK |
296 MIPI_DSI_VID_MODE_CFG_LP_VBP_EN_MASK |
297 MIPI_DSI_VID_MODE_CFG_LP_VSA_EN_MASK |
298 MIPI_DSI_VID_MODE_CFG_VID_MODE_TYPE_SET(cfg->video_mode);
299 ptr->VID_MODE_CFG = val;
300
301 ptr->VID_PKT_SIZE = cfg->video_para.hactive;
302
303 ptr->TO_CNT_CFG = MIPI_DSI_TO_CNT_CFG_HSTX_TO_CNT_SET(1000) |
304 MIPI_DSI_TO_CNT_CFG_LPRX_TO_CNT_SET(1000);
305
306 ptr->BTA_TO_CNT = MIPI_DSI_BTA_TO_CNT_BTA_TO_CNT_SET(0xd00);
307
308 mipi_dsi_video_para_config(ptr, cfg);
309
310 ptr->PHY_TMR_CFG = MIPI_DSI_PHY_TMR_CFG_PHY_HS2LP_TIME_SET(0x40) |
311 MIPI_DSI_PHY_TMR_CFG_PHY_LP2HS_TIME_SET(0x40);
312 ptr->PHY_TMR_RD = 10000;
313 ptr->PHY_TMR_LPCLK_CFG = MIPI_DSI_PHY_TMR_LPCLK_CFG_PHY_CLKHS2LP_TIME_SET(0x40) |
314 MIPI_DSI_PHY_TMR_LPCLK_CFG_PHY_CLKLP2HS_TIME_SET(0x40);
315 ptr->PHY_IF_CFG = MIPI_DSI_PHY_IF_CFG_PHY_STOP_WAIT_TIME_SET(0x20) |
316 MIPI_DSI_PHY_IF_CFG_N_LANES_SET(cfg->lanes - 1);
317 ptr->PWR_UP |= MIPI_DSI_PWR_UP_SHUTDOWNZ_MASK;
318 }
319
mipi_dsi_phy_poweron(MIPI_DSI_Type * ptr)320 void mipi_dsi_phy_poweron(MIPI_DSI_Type *ptr)
321 {
322 ptr->PHY_RSTZ |= MIPI_DSI_PHY_RSTZ_PHY_SHUTDOWNZ_MASK;
323 ptr->PHY_RSTZ |= MIPI_DSI_PHY_RSTZ_PHY_RSTZ_MASK;
324 }
325
mipi_dsi_phy_powerdown(MIPI_DSI_Type * ptr)326 void mipi_dsi_phy_powerdown(MIPI_DSI_Type *ptr)
327 {
328 ptr->PHY_RSTZ &= ~(MIPI_DSI_PHY_RSTZ_PHY_SHUTDOWNZ_MASK |
329 MIPI_DSI_PHY_RSTZ_PHY_RSTZ_MASK);
330 }
331
mipi_dsi_video_mode_hs_transfer_enable(MIPI_DSI_Type * ptr)332 void mipi_dsi_video_mode_hs_transfer_enable(MIPI_DSI_Type *ptr)
333 {
334 ptr->PWR_UP &= ~MIPI_DSI_PWR_UP_SHUTDOWNZ_MASK;
335 ptr->LPCLK_CTRL |= MIPI_DSI_LPCLK_CTRL_PHY_TXREQUESTCLKHS_MASK;
336 ptr->MODE_CFG = MIPI_DSI_MODE_CFG_CMD_VIDEO_MODE_SET(0);
337 ptr->PWR_UP |= MIPI_DSI_PWR_UP_SHUTDOWNZ_MASK;
338 }
339
mipi_dsi_video_mode_hs_transfer_disable(MIPI_DSI_Type * ptr)340 void mipi_dsi_video_mode_hs_transfer_disable(MIPI_DSI_Type *ptr)
341 {
342 ptr->PWR_UP &= ~MIPI_DSI_PWR_UP_SHUTDOWNZ_MASK;
343 ptr->LPCLK_CTRL &= ~MIPI_DSI_LPCLK_CTRL_PHY_TXREQUESTCLKHS_MASK;
344 }
345
mipi_dsi_lp_cmd_transfer(MIPI_DSI_Type * ptr,const mipi_dsi_msg_t * msg)346 int mipi_dsi_lp_cmd_transfer(MIPI_DSI_Type *ptr, const mipi_dsi_msg_t *msg)
347 {
348 struct mipi_dsi_packet packet;
349 int ret = -1;
350 int val;
351
352 /* do some minimum sanity checking */
353 if (!mipi_dsi_packet_format_is_short(msg->type) &&
354 !mipi_dsi_packet_format_is_long(msg->type))
355 return ret;
356
357 ptr->VID_MODE_CFG |= MIPI_DSI_VID_MODE_CFG_LP_CMD_EN_MASK;
358 ptr->LPCLK_CTRL &= ~MIPI_DSI_LPCLK_CTRL_PHY_TXREQUESTCLKHS_MASK;
359
360 /* create a packet to the DSI protocol */
361 if (mipi_dsi_create_packet(&packet, msg) == false) {
362 return ret;
363 }
364
365 ptr->CMD_MODE_CFG = 1u<<24 | 1u<<19 | 1u<<18 | 1u<<17 |
366 1u<<16 | 1u<<14 | 1u<<13 | 1u<<12 |
367 1u<<11 | 1u<<10 | 1u<<9 | 1u<<8;
368
369 /* config to cmd mode */
370 ptr->MODE_CFG = MIPI_DSI_MODE_CFG_CMD_VIDEO_MODE_SET(1);
371
372 /* Send payload */
373 while (packet.payload_length > 0) {
374 /*
375 * Alternatively, you can always keep the FIFO
376 * nearly full by monitoring the FIFO state until
377 * it is not full, and then writea single word of data.
378 * This solution is more resource consuming
379 * but it simultaneously avoids FIFO starvation,
380 * making it possible to use FIFO sizes smaller than
381 * the amount of data of the longest packet to be written.
382 */
383 if (mipi_dsi_genif_wait_w_pld_fifo_not_full(ptr) == false)
384 return ret;
385
386 if (packet.payload_length < 4) {
387 /* send residu payload */
388 val = 0;
389 memcpy(&val, packet.payload, packet.payload_length);
390 packet.payload_length = 0;
391 } else {
392 val = get_le32(packet.payload);
393 packet.payload += 4;
394 packet.payload_length -= 4;
395 }
396 ptr->GEN_PLD_DATA = val;
397 }
398
399 if (mipi_dsi_genif_wait_cmd_fifo_not_full(ptr) == false)
400 return ret;
401
402 /* Send packet header */
403 val = get_le32(packet.header);
404 ptr->GEN_HDR = val;
405
406 if (mipi_dsi_genif_wait_write_fifo_empty(ptr) == false)
407 return ret;
408
409 if (msg->rx_len) {
410 if (dw_mipi_dsi_read_from_fifo(ptr, msg) == false)
411 return ret;
412 }
413
414 return msg->rx_len ? msg->rx_len : msg->tx_len;
415 }
416
mipi_dsi_set_maximum_return_packet_size(MIPI_DSI_Type * ptr,uint8_t channel,uint16_t value)417 int mipi_dsi_set_maximum_return_packet_size(MIPI_DSI_Type *ptr, uint8_t channel, uint16_t value)
418 {
419 uint8_t tx[2] = {value & 0xff, value >> 8};
420 struct mipi_dsi_msg msg = {
421 .channel = channel,
422 .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
423 .tx_len = sizeof(tx),
424 .tx_buf = tx,
425 };
426
427 int ret = mipi_dsi_lp_cmd_transfer(ptr, &msg);
428
429 return (ret < 0) ? false : true;
430 }
431
mipi_dsi_generic_write(MIPI_DSI_Type * ptr,uint8_t channel,const void * payload,uint16_t size)432 int mipi_dsi_generic_write(MIPI_DSI_Type *ptr, uint8_t channel, const void *payload,
433 uint16_t size)
434 {
435 struct mipi_dsi_msg msg = {
436 .channel = channel,
437 .tx_buf = payload,
438 .tx_len = size
439 };
440
441 switch (size) {
442 case 0:
443 msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM;
444 break;
445 case 1:
446 msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM;
447 break;
448 case 2:
449 msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM;
450 break;
451 default:
452 msg.type = MIPI_DSI_GENERIC_LONG_WRITE;
453 break;
454 }
455
456 return mipi_dsi_lp_cmd_transfer(ptr, &msg);
457 }
458
459
mipi_dsi_generic_read(MIPI_DSI_Type * ptr,uint8_t channel,const void * params,uint16_t num_params,void * data,uint16_t size)460 int mipi_dsi_generic_read(MIPI_DSI_Type *ptr, uint8_t channel, const void *params,
461 uint16_t num_params, void *data, uint16_t size)
462 {
463 struct mipi_dsi_msg msg = {
464 .channel = channel,
465 .tx_len = num_params,
466 .tx_buf = params,
467 .rx_len = size,
468 .rx_buf = data
469 };
470
471 switch (num_params) {
472 case 0:
473 msg.type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
474 break;
475 case 1:
476 msg.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
477 break;
478 case 2:
479 msg.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
480 break;
481 default:
482 return -1;
483 }
484
485 return mipi_dsi_lp_cmd_transfer(ptr, &msg);
486 }
487
488
mipi_dsi_dcs_write_buffer(MIPI_DSI_Type * ptr,uint8_t channel,const void * data,uint16_t len)489 int mipi_dsi_dcs_write_buffer(MIPI_DSI_Type *ptr, uint8_t channel,
490 const void *data, uint16_t len)
491 {
492 struct mipi_dsi_msg msg = {
493 .channel = channel,
494 .tx_buf = data,
495 .tx_len = len
496 };
497
498 switch (len) {
499 case 0:
500 return -1;
501 case 1:
502 msg.type = MIPI_DSI_DCS_SHORT_WRITE;
503 break;
504 case 2:
505 msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
506 break;
507 default:
508 msg.type = MIPI_DSI_DCS_LONG_WRITE;
509 break;
510 }
511
512 return mipi_dsi_lp_cmd_transfer(ptr, &msg);
513 }
514
mipi_dsi_dcs_write(MIPI_DSI_Type * ptr,uint8_t channel,uint8_t cmd,const void * data,uint16_t len)515 int mipi_dsi_dcs_write(MIPI_DSI_Type *ptr, uint8_t channel, uint8_t cmd,
516 const void *data, uint16_t len)
517 {
518 int err;
519 uint16_t size;
520 uint8_t tx[128];
521
522 if (len < sizeof(tx)) {
523 size = 1 + len;
524 tx[0] = cmd;
525 if (len > 0)
526 memcpy(&tx[1], data, len);
527 } else {
528 return -1;
529 }
530
531 err = mipi_dsi_dcs_write_buffer(ptr, channel, tx, size);
532
533 return err;
534 }
535
mipi_dsi_dcs_read(MIPI_DSI_Type * ptr,uint8_t channel,uint8_t cmd,void * data,uint16_t len)536 int mipi_dsi_dcs_read(MIPI_DSI_Type *ptr, uint8_t channel, uint8_t cmd, void *data, uint16_t len)
537 {
538 struct mipi_dsi_msg msg = {
539 .channel = channel,
540 .type = MIPI_DSI_DCS_READ,
541 .tx_buf = &cmd,
542 .tx_len = 1,
543 .rx_buf = data,
544 .rx_len = len
545 };
546
547 return mipi_dsi_lp_cmd_transfer(ptr, &msg);
548 }