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