• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }