1 /*
2 * Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 /***********************************************************************************************************************
8 * Includes
9 **********************************************************************************************************************/
10 #include <string.h>
11 #include "r_mipi_dsi.h"
12
13 /***********************************************************************************************************************
14 * Macro definitions
15 **********************************************************************************************************************/
16 #define MIPI_DSI_OPEN (0x4D504944)
17 #define MIPI_MAX_CH0_CMD (128)
18 #define MIPI_MAX_CH1_CMD (1024)
19 #define MIPI_DSI_RSRST_RESET_BITS (R_DSILINK_RSTSR_RSTHS_Msk | \
20 R_DSILINK_RSTSR_RSTLP_Msk | \
21 R_DSILINK_RSTSR_RSTAPB_Msk | \
22 R_DSILINK_RSTSR_RSTAXI_Msk | \
23 R_DSILINK_RSTSR_RSTV_Msk)
24
25 #define DSI_PACKET_FORMAT_IS_SHORT(cmd_id) ((cmd_id & 0x0F) <= 0x08)
26 #define DSI_PACKET_FORMAT_IS_LONG(cmd_id) ((cmd_id & 0x0F) > 0x08)
27
28 /***********************************************************************************************************************
29 * Typedef definitions
30 **********************************************************************************************************************/
31
32 #if defined(__ARMCC_VERSION) || defined(__ICCARM__)
33 typedef void (BSP_CMSE_NONSECURE_CALL * mipi_dsi_prv_ns_callback)(mipi_dsi_callback_args_t * p_args);
34 #elif defined(__GNUC__)
35 typedef BSP_CMSE_NONSECURE_CALL void (*volatile mipi_dsi_prv_ns_callback)(mipi_dsi_callback_args_t * p_args);
36 #endif
37
38 typedef enum e_mipi_dsi_clock_state
39 {
40 MIPI_DSI_CLOCK_STATE_IDLE, ///< MIPI DSI Clock is off
41 MIPI_DSI_CLOCK_STATE_STARTING, ///< MIPI DSI Clock starting
42 MIPI_DSI_CLOCK_STATE_STARTED, ///< MIPI DSI Clock is started
43 MIPI_DSI_CLOCK_STATE_STOPPING, ///< MIPI DSI Clock is stopping
44 } mipi_dsi_clock_state_t;
45
46 /***********************************************************************************************************************
47 * Global variables
48 **********************************************************************************************************************/
49 static volatile mipi_dsi_clock_state_t g_clock_state;
50 static volatile bool g_video_started;
51
52 const mipi_dsi_api_t g_mipi_dsi =
53 {
54 .open = R_MIPI_DSI_Open,
55 .close = R_MIPI_DSI_Close,
56 .start = R_MIPI_DSI_Start,
57 .stop = R_MIPI_DSI_Stop,
58 .ulpsEnter = R_MIPI_DSI_UlpsEnter,
59 .ulpsExit = R_MIPI_DSI_UlpsExit,
60 .command = R_MIPI_DSI_Command,
61 .statusGet = R_MIPI_DSI_StatusGet,
62 };
63
64 /***********************************************************************************************************************
65 * Private function prototypes
66 **********************************************************************************************************************/
67 void mipi_dsi_seq0(void);
68 void mipi_dsi_seq1(void);
69 void mipi_dsi_vin1(void);
70 void mipi_dsi_rcv(void);
71 void mipi_dsi_ferr(void);
72 void mipi_dsi_ppi(void);
73
74 static void dsi_isr_enable(mipi_dsi_irq_cfg_t const * irq_cfg, mipi_dsi_instance_ctrl_t * p_ctrl);
75 static void dsi_isr_disable(mipi_dsi_irq_cfg_t const * irq_cfg);
76
77 static void dsi_enter_reset(void);
78 static void dsi_init_timing(mipi_dsi_cfg_t const * const p_cfg);
79 static void dsi_exit_reset(mipi_dsi_cfg_t const * const p_cfg);
80 static void dsi_hs_clock_start(mipi_dsi_instance_ctrl_t * p_ctrl);
81 static void dsi_hs_clock_stop(mipi_dsi_instance_ctrl_t * p_ctrl);
82
83 static void dsi_init_video(mipi_dsi_cfg_t const * p_cfg);
84
85 static void dsi_call_callback(mipi_dsi_instance_ctrl_t * p_ctrl, mipi_dsi_callback_args_t * p_args);
86
87 static fsp_err_t dsi_stop(mipi_dsi_instance_ctrl_t * p_ctrl);
88 static uint32_t dsi_cmd_sequence_register_a(mipi_dsi_cmd_t * p_cmd);
89 static uint32_t dsi_cmd_sequence_register_b(mipi_dsi_cmd_t * p_cmd);
90 static uint32_t dsi_cmd_sequence_register_c(mipi_dsi_cmd_t * p_cmd);
91 static uint32_t dsi_cmd_sequence_register_d(mipi_dsi_cmd_t * p_cmd);
92
93 /*******************************************************************************************************************//**
94 * @addtogroup MIPI_DSI
95 * @{
96 **********************************************************************************************************************/
97
98 /***********************************************************************************************************************
99 * Functions
100 **********************************************************************************************************************/
101
102 /******************************************************************************************************************//**
103 * Initialize the MIPI DSI peripheral.
104 *
105 * @retval FSP_SUCCESS The channel was successfully opened.
106 * @retval FSP_ERR_ASSERTION One or both of the parameters was NULL.
107 * @retval FSP_ERR_ALREADY_OPEN The instance is already opened.
108 * @retval FSP_ERR_INVALID_STATE Display module must be opened before DSI.
109 **********************************************************************************************************************/
R_MIPI_DSI_Open(mipi_dsi_ctrl_t * const p_api_ctrl,mipi_dsi_cfg_t const * const p_cfg)110 fsp_err_t R_MIPI_DSI_Open (mipi_dsi_ctrl_t * const p_api_ctrl, mipi_dsi_cfg_t const * const p_cfg)
111 {
112 fsp_err_t err;
113 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) p_api_ctrl;
114
115 #if MIPI_DSI_CFG_PARAM_CHECKING_ENABLE
116 FSP_ASSERT(NULL != p_cfg);
117 FSP_ASSERT(NULL != p_ctrl);
118 FSP_ERROR_RETURN(MIPI_DSI_OPEN != p_ctrl->open, FSP_ERR_ALREADY_OPEN);
119 #endif
120
121 FSP_ERROR_RETURN(R_GLCDC->SYSCNT.PANEL_CLK_b.CLKEN, FSP_ERR_INVALID_STATE);
122
123 /* Initialize internal state */
124 g_clock_state = MIPI_DSI_CLOCK_STATE_IDLE;
125 g_video_started = false;
126 p_ctrl->p_cfg = p_cfg;
127
128 /* Start clocks to the MIPI DSI peripheral */
129 R_BSP_MODULE_START(FSP_IP_MIPI_DSI, 0);
130
131 err = r_mipi_phy_open(p_cfg->p_mipi_phy_instance->p_ctrl, p_cfg->p_mipi_phy_instance->p_cfg);
132 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
133
134 /* Perform sequence steps 5 to 9 from section 58.3.2 in RA8D1 hardware manual R01UH0995EJ0060. */
135 dsi_enter_reset();
136 dsi_init_timing(p_cfg);
137 dsi_exit_reset(p_cfg);
138
139 /* Configure interrupt sources */
140 mipi_dsi_extended_cfg_t * p_extend = (mipi_dsi_extended_cfg_t *) p_cfg->p_extend;
141 R_DSILINK->RXIER = p_extend->dsi_rxie;
142 R_DSILINK->FERRIER = p_extend->dsi_ferrie;
143 R_DSILINK->PLIER = p_extend->dsi_plie;
144 R_DSILINK->VMIER = p_extend->dsi_vmie;
145 R_DSILINK->SQCH0IER = p_extend->dsi_sqch0ie;
146 R_DSILINK->SQCH1IER = p_extend->dsi_sqch1ie;
147
148 /* Clear any active status bits */
149 R_DSILINK->SQCH0SCR = R_DSILINK_SQCH0SCR_AACTFIN_Msk |
150 R_DSILINK_SQCH0SCR_ADESFIN_Msk |
151 R_DSILINK_SQCH0SCR_DABORT_Msk |
152 R_DSILINK_SQCH0SCR_SIZEERR_Msk |
153 R_DSILINK_SQCH0SCR_TXIBERR_Msk |
154 R_DSILINK_SQCH0SCR_RXFERR_Msk |
155 R_DSILINK_SQCH0SCR_RXFAIL_Msk |
156 R_DSILINK_SQCH0SCR_RXPFAIL_Msk |
157 R_DSILINK_SQCH0SCR_RXCORERR_Msk |
158 R_DSILINK_SQCH0SCR_RXAKE_Msk;
159 R_DSILINK->SQCH1SCR = R_DSILINK_SQCH1SCR_AACTFIN_Msk |
160 R_DSILINK_SQCH1SCR_ADESFIN_Msk |
161 R_DSILINK_SQCH1SCR_DABORT_Msk |
162 R_DSILINK_SQCH1SCR_SIZEERR_Msk |
163 R_DSILINK_SQCH1SCR_TXIBERR_Msk |
164 R_DSILINK_SQCH1SCR_RXFERR_Msk |
165 R_DSILINK_SQCH1SCR_RXFAIL_Msk |
166 R_DSILINK_SQCH1SCR_RXPFAIL_Msk |
167 R_DSILINK_SQCH1SCR_RXCORERR_Msk |
168 R_DSILINK_SQCH1SCR_RXAKE_Msk;
169 R_DSILINK->VMSCR = R_DSILINK_VMSCR_START_Msk |
170 R_DSILINK_VMSCR_STOP_Msk |
171 R_DSILINK_VMSCR_VIRDY_Msk |
172 R_DSILINK_VMSCR_TIMERR_Msk |
173 R_DSILINK_VMSCR_VBUFUDF_Msk |
174 R_DSILINK_VMSCR_VBUFOVF_Msk;
175 R_DSILINK->RXSCR = R_DSILINK_RXSCR_BTAREND_Msk |
176 R_DSILINK_RXSCR_LRXHTO_Msk |
177 R_DSILINK_RXSCR_TATO_Msk |
178 R_DSILINK_RXSCR_RXRESP_Msk |
179 R_DSILINK_RXSCR_RXEOTP_Msk |
180 R_DSILINK_RXSCR_RXTE_Msk |
181 R_DSILINK_RXSCR_RXACK_Msk |
182 R_DSILINK_RXSCR_EXTEDET_Msk |
183 R_DSILINK_RXSCR_MLFERR_Msk |
184 R_DSILINK_RXSCR_ECCERRM_Msk |
185 R_DSILINK_RXSCR_UNEXERR_Msk |
186 R_DSILINK_RXSCR_WCERR_Msk |
187 R_DSILINK_RXSCR_CRCERR_Msk |
188 R_DSILINK_RXSCR_IBERR_Msk |
189 R_DSILINK_RXSCR_RXOVFERR_Msk |
190 R_DSILINK_RXSCR_PRTOERR_Msk |
191 R_DSILINK_RXSCR_NORESERR_Msk |
192 R_DSILINK_RXSCR_RSIZEERR_Msk |
193 R_DSILINK_RXSCR_ECCERRS_Msk |
194 R_DSILINK_RXSCR_RXAKE_Msk;
195
196 p_ctrl->p_callback_memory = NULL;
197 p_ctrl->p_callback = p_cfg->p_callback;
198
199 /* Enable interrupts */
200 p_ctrl->p_context = p_cfg->p_context;
201 dsi_isr_enable(&p_extend->dsi_seq0, p_ctrl);
202 dsi_isr_enable(&p_extend->dsi_seq1, p_ctrl);
203 dsi_isr_enable(&p_extend->dsi_ferr, p_ctrl);
204 dsi_isr_enable(&p_extend->dsi_ppi, p_ctrl);
205 dsi_isr_enable(&p_extend->dsi_rcv, p_ctrl);
206 dsi_isr_enable(&p_extend->dsi_vin1, p_ctrl);
207
208 /* Mark control block as opened */
209 p_ctrl->open = MIPI_DSI_OPEN;
210
211 /* Start high-speed clock and init video */
212 dsi_hs_clock_start(p_ctrl);
213 dsi_init_video(p_cfg);
214
215 /* Notify application that DSI is now open */
216 mipi_dsi_callback_args_t callback_args;
217 callback_args.event = MIPI_DSI_EVENT_POST_OPEN;
218 callback_args.p_context = p_ctrl->p_context;
219 dsi_call_callback(p_ctrl, &callback_args);
220
221 return FSP_SUCCESS;
222 }
223
224 /******************************************************************************************************************//**
225 * Close MIPI DSI and display data instances, disable interrupts, and power-off the module.
226 *
227 * @retval FSP_SUCCESS The channel is successfully closed.
228 * @retval FSP_ERR_ASSERTION p_api_ctrl is NULL.
229 * @retval FSP_ERR_NOT_OPEN Instance is not open.
230 * @retval FSP_ERR_IN_USE Operation in progress and must be stopped before closing.
231 **********************************************************************************************************************/
R_MIPI_DSI_Close(mipi_dsi_ctrl_t * const p_api_ctrl)232 fsp_err_t R_MIPI_DSI_Close (mipi_dsi_ctrl_t * const p_api_ctrl)
233 {
234 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) p_api_ctrl;
235
236 #if MIPI_DSI_CFG_PARAM_CHECKING_ENABLE
237 FSP_ASSERT(NULL != p_ctrl);
238 FSP_ERROR_RETURN(MIPI_DSI_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
239 #endif
240
241 /* Ensure video has stopped first */
242 fsp_err_t err = dsi_stop(p_ctrl);
243 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
244
245 dsi_hs_clock_stop(p_ctrl);
246
247 mipi_dsi_cfg_t const * p_cfg = p_ctrl->p_cfg;
248 mipi_dsi_extended_cfg_t * p_extend = (mipi_dsi_extended_cfg_t *) p_cfg->p_extend;
249 dsi_isr_disable(&p_extend->dsi_seq0);
250 dsi_isr_disable(&p_extend->dsi_seq1);
251 dsi_isr_disable(&p_extend->dsi_ferr);
252 dsi_isr_disable(&p_extend->dsi_ppi);
253 dsi_isr_disable(&p_extend->dsi_rcv);
254 dsi_isr_disable(&p_extend->dsi_vin1);
255
256 /* Close MIPI PHY */
257 r_mipi_phy_close(p_cfg->p_mipi_phy_instance->p_ctrl);
258
259 /* Set control block to closed */
260 p_ctrl->open = 0U;
261
262 /* Stop clocks to the MIPI DSI peripheral */
263 R_BSP_MODULE_STOP(FSP_IP_MIPI_DSI, 0);
264
265 return err;
266 }
267
268 /******************************************************************************************************************//**
269 * Start video output.
270 * Initialize Video Output Registers
271 * Perform sequence steps 3 to 5 from section 58.3.6.1 in RA8D1 hardware manual R01UH0995EJ0060.
272 *
273 * @retval FSP_SUCCESS Data is successfully written to the D/A Converter.
274 * @retval FSP_ERR_ASSERTION p_api_ctrl is NULL.
275 * @retval FSP_ERR_NOT_OPEN Instance is not open.
276 * @retval FSP_ERR_IN_USE The physical interface is currently in use.
277 * @retval FSP_ERR_INVALID_STATE DSI is already in video mode.
278 **********************************************************************************************************************/
R_MIPI_DSI_Start(mipi_dsi_ctrl_t * const p_api_ctrl)279 fsp_err_t R_MIPI_DSI_Start (mipi_dsi_ctrl_t * const p_api_ctrl)
280 {
281 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) p_api_ctrl;
282
283 #if MIPI_DSI_CFG_PARAM_CHECKING_ENABLE
284 FSP_ASSERT(p_ctrl);
285 FSP_ERROR_RETURN(MIPI_DSI_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
286 FSP_ERROR_RETURN(!g_video_started, FSP_ERR_INVALID_STATE);
287 #endif
288
289 /* Notify application that DSI is now open */
290 mipi_dsi_callback_args_t callback_args;
291 callback_args.event = MIPI_DSI_EVENT_PRE_START;
292 callback_args.p_context = p_ctrl->p_context;
293 dsi_call_callback(p_ctrl, &callback_args);
294
295 /* Do not start video if sequence operation is in progress */
296 FSP_ERROR_RETURN(!(R_DSILINK->LINKSR_b.SQ0RUN) && !(R_DSILINK->LINKSR_b.SQ1RUN), FSP_ERR_IN_USE);
297
298 mipi_dsi_cfg_t const * p_cfg = p_ctrl->p_cfg;
299 R_DSILINK->VMSET0R =
300 (((uint32_t) p_cfg->hsa_no_lp << R_DSILINK_VMSET0R_HSANOLP_Pos) & R_DSILINK_VMSET0R_HSANOLP_Msk) |
301 (((uint32_t) p_cfg->hbp_no_lp << R_DSILINK_VMSET0R_HBPNOLP_Pos) & R_DSILINK_VMSET0R_HBPNOLP_Msk) |
302 (((uint32_t) p_cfg->hfp_no_lp << R_DSILINK_VMSET0R_HFPNOLP_Pos) & R_DSILINK_VMSET0R_HFPNOLP_Msk) |
303 R_DSILINK_VMSET0R_VSTART_Msk;
304
305 while ((R_DSILINK->VMSR_b.VIRDY != 1) && !g_video_started)
306 {
307 /* Wait for video mode ready status
308 * NOTE: VMSR may be modified in isr */
309 }
310
311 g_video_started = true;
312
313 return FSP_SUCCESS;
314 }
315
316 /******************************************************************************************************************//**
317 * Stop video output.
318 *
319 * @retval FSP_SUCCESS Data is successfully written to the D/A Converter.
320 * @retval FSP_ERR_ASSERTION p_api_ctrl is NULL.
321 * @retval FSP_ERR_NOT_OPEN Instance is not open.
322 * @retval FSP_ERR_IN_USE DSI cannot be closed while ULPS is active.
323 **********************************************************************************************************************/
R_MIPI_DSI_Stop(mipi_dsi_ctrl_t * const p_api_ctrl)324 fsp_err_t R_MIPI_DSI_Stop (mipi_dsi_ctrl_t * const p_api_ctrl)
325 {
326 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) p_api_ctrl;
327
328 #if MIPI_DSI_CFG_PARAM_CHECKING_ENABLE
329 FSP_ASSERT(p_ctrl);
330 FSP_ERROR_RETURN(MIPI_DSI_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
331 #endif
332
333 return dsi_stop(p_ctrl);
334 }
335
336 /******************************************************************************************************************//**
337 * Enter Ultra-low Power State (ULPS).
338 *
339 * @retval FSP_SUCCESS Information read successfully.
340 * @retval FSP_ERR_ASSERTION p_api_ctrl is NULL.
341 * @retval FSP_ERR_NOT_OPEN Instance is not open.
342 * @retval FSP_ERR_INVALID_MODE Invalid mode for transition.
343 *
344 **********************************************************************************************************************/
R_MIPI_DSI_UlpsEnter(mipi_dsi_ctrl_t * const p_api_ctrl,mipi_dsi_lane_t lane)345 fsp_err_t R_MIPI_DSI_UlpsEnter (mipi_dsi_ctrl_t * const p_api_ctrl, mipi_dsi_lane_t lane)
346 {
347 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) p_api_ctrl;
348
349 #if MIPI_DSI_CFG_PARAM_CHECKING_ENABLE
350 FSP_ASSERT(NULL != p_ctrl);
351 FSP_ERROR_RETURN(MIPI_DSI_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
352
353 /* Clock lane cannot enter ULPS when Continuous CLock mode is active */
354 FSP_ERROR_RETURN(!((MIPI_DSI_LANE_CLOCK & lane) && R_DSILINK->HSCLKSETR_b.HSCLMD), FSP_ERR_INVALID_MODE);
355 #endif
356
357 /* Do not set 'enter ULPS' bit if lane is already in ULPS */
358 uint32_t ulpscr = ((MIPI_DSI_LANE_DATA_ALL & lane) && !p_ctrl->data_ulps_active) ? R_DSILINK_ULPSCR_DLENT_Msk : 0;
359 ulpscr |=
360 ((MIPI_DSI_LANE_CLOCK & lane) && !p_ctrl->clock_ulps_active) ? R_DSILINK_ULPSCR_CLENT_Msk : 0;
361 p_ctrl->ulps_status |= lane;
362
363 p_ctrl->clock_ulps_active = p_ctrl->clock_ulps_active || (MIPI_DSI_LANE_CLOCK & lane);
364 p_ctrl->data_ulps_active = p_ctrl->data_ulps_active || (MIPI_DSI_LANE_DATA_ALL & lane);
365
366 R_DSILINK->ULPSCR = ulpscr;
367
368 return FSP_SUCCESS;
369 }
370
371 /******************************************************************************************************************//**
372 * Exit Ultra-low Power State (ULPS).
373 *
374 * @retval FSP_SUCCESS Information read successfully.
375 * @retval FSP_ERR_ASSERTION p_api_ctrl is NULL.
376 * @retval FSP_ERR_NOT_OPEN Instance is not open.
377 *
378 **********************************************************************************************************************/
R_MIPI_DSI_UlpsExit(mipi_dsi_ctrl_t * const p_api_ctrl,mipi_dsi_lane_t lane)379 fsp_err_t R_MIPI_DSI_UlpsExit (mipi_dsi_ctrl_t * const p_api_ctrl, mipi_dsi_lane_t lane)
380 {
381 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) p_api_ctrl;
382 #if MIPI_DSI_CFG_PARAM_CHECKING_ENABLE
383 FSP_ASSERT(NULL != p_ctrl);
384 FSP_ERROR_RETURN(MIPI_DSI_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
385 #endif
386
387 /* Do not set 'exit ULPS' bit if lane is not in ULPS */
388 uint32_t ulpscr = ((MIPI_DSI_LANE_DATA_ALL & lane) && p_ctrl->data_ulps_active) ? R_DSILINK_ULPSCR_DLEXIT_Msk : 0;
389 ulpscr |=
390 ((MIPI_DSI_LANE_CLOCK & lane) && p_ctrl->clock_ulps_active) ? R_DSILINK_ULPSCR_CLEXIT_Msk : 0;
391
392 p_ctrl->clock_ulps_active = p_ctrl->clock_ulps_active && !(MIPI_DSI_LANE_CLOCK & lane);
393 p_ctrl->data_ulps_active = p_ctrl->data_ulps_active && !(MIPI_DSI_LANE_DATA_ALL & lane);
394
395 R_DSILINK->ULPSCR = ulpscr;
396 p_ctrl->ulps_status &= ~lane;
397
398 return FSP_SUCCESS;
399 }
400
401 /******************************************************************************************************************//**
402 * Send a command to the peripheral device.
403 *
404 * @note p_data will be used as either write data or a read buffer depending on the data id.
405 * @note p_data memory must not be updated until sequence operation is complete if byte_count is greater than 16.
406 *
407 * @retval FSP_SUCCESS Command(s) queued successfully.
408 * @retval FSP_ERR_ASSERTION p_api_ctrl is NULL.
409 * cmd_id specifies a long packet but p_data is NULL.
410 * @retval FSP_ERR_NOT_OPEN Instance is not open.
411 * @retval FSP_ERR_IN_USE The physical interface is currently in use or video mode is in operation.
412 * @retval FSP_ERR_INVALID_POINTER Invalid pointer provided
413 * @retval FSP_ERR_INVALID_ARGUMENT Invalid message configuration
414 * @retval FSP_ERR_INVALID_CHANNEL Invalid channel for provided message configuration
415 **********************************************************************************************************************/
R_MIPI_DSI_Command(mipi_dsi_ctrl_t * const p_api_ctrl,mipi_dsi_cmd_t * p_cmd)416 fsp_err_t R_MIPI_DSI_Command (mipi_dsi_ctrl_t * const p_api_ctrl, mipi_dsi_cmd_t * p_cmd)
417 {
418 #if MIPI_DSI_CFG_PARAM_CHECKING_ENABLE
419 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) p_api_ctrl;
420
421 FSP_ASSERT(NULL != p_ctrl);
422 FSP_ERROR_RETURN(p_cmd, FSP_ERR_INVALID_POINTER);
423 FSP_ERROR_RETURN(MIPI_DSI_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
424 FSP_ERROR_RETURN(p_cmd->p_tx_buffer || (p_cmd->tx_len == 0), FSP_ERR_INVALID_ARGUMENT); // Tx buffer must be supplied for non-zero Tx length
425
426 FSP_ERROR_RETURN(!((p_cmd->channel == 0) && (p_cmd->tx_len > MIPI_MAX_CH0_CMD)), FSP_ERR_INVALID_ARGUMENT); // Max Tx size is 128 for channel 0
427 FSP_ERROR_RETURN(!((p_cmd->channel == 1) && (p_cmd->tx_len > MIPI_MAX_CH1_CMD)), FSP_ERR_INVALID_ARGUMENT); // Max Tx size is 1k for channel 1
428
429 /* AUX Operation */
430 bool aux = (p_cmd->flags & MIPI_DSI_CMD_FLAG_AUX_OPERATION);
431 if (aux)
432 {
433 bool bta = p_cmd->flags &
434 (MIPI_DSI_CMD_FLAG_BTA | MIPI_DSI_CMD_FLAG_BTA_READ | MIPI_DSI_CMD_FLAG_BTA_NO_WRITE);
435 bool initial_skew = (p_cmd->flags & MIPI_DSI_CMD_FLAG_ACT_CODE_INITIAL_SKEW_CAL);
436 bool periodic_skew = (p_cmd->flags & MIPI_DSI_CMD_FLAG_ACT_CODE_PERIODIC_SKEW_CAL);
437 FSP_ERROR_RETURN(!bta && !p_cmd->tx_len, FSP_ERR_INVALID_ARGUMENT);
438 FSP_ERROR_RETURN(!R_DSILINK->LINKSR_b.VRUN, FSP_ERR_INVALID_ARGUMENT); // Aux operation is prohibited when video mode is running
439 FSP_ERROR_RETURN(!(initial_skew || periodic_skew) || (p_cmd->channel != 0), FSP_ERR_INVALID_ARGUMENT); // Periodic and Initial skew must be HS
440 }
441
442 uint8_t lp = (0 != (p_cmd->flags & MIPI_DSI_CMD_FLAG_LOW_POWER));
443
444 FSP_ERROR_RETURN(!(lp && R_DSILINK->LINKSR_b.VRUN), FSP_ERR_IN_USE); // LP not allowed during video mode operation. See RA8D1 UM 58.2.61 (R01UH0995EJ0060)
445 FSP_ERROR_RETURN(!(lp && (p_cmd->channel != 0)), FSP_ERR_INVALID_CHANNEL); // LP only allowed on channel 0
446 #else
447 FSP_PARAMETER_NOT_USED(p_api_ctrl);
448 #endif
449
450 /* Do not modify registers if sequence operation is currently in progress */
451 FSP_ERROR_RETURN(!(R_DSILINK->LINKSR_b.SQ0RUN) && !(R_DSILINK->LINKSR_b.SQ1RUN), FSP_ERR_IN_USE);
452
453 uint32_t * p_sequence_reg = (uint32_t *) (&R_DSILINK->SQCH0DSC0AR);
454 p_sequence_reg += (p_cmd->channel * 0x80) / 4; // NOLINT(readability-magic-numbers)
455 *p_sequence_reg++ = dsi_cmd_sequence_register_a(p_cmd);
456 *p_sequence_reg++ = dsi_cmd_sequence_register_b(p_cmd);
457 *p_sequence_reg++ = dsi_cmd_sequence_register_c(p_cmd);
458 *p_sequence_reg++ = dsi_cmd_sequence_register_d(p_cmd);
459
460 /* Start sequence operation */
461 R_DSILINK->SQCH0SET0R = (bool) (0 == p_cmd->channel);
462 R_DSILINK->SQCH1SET0R = (bool) (1 == p_cmd->channel);
463
464 return FSP_SUCCESS;
465 }
466
467 /******************************************************************************************************************//**
468 * Provide information about current MIPI DSI status.
469 *
470 * Note: Acknowledge and Error Status is only cleared when read by calling this function.
471 *
472 * @retval FSP_SUCCESS Information read successfully.
473 * @retval FSP_ERR_ASSERTION p_api_ctrl is NULL.
474 * @retval FSP_ERR_NOT_OPEN Instance is not open.
475 *
476 **********************************************************************************************************************/
R_MIPI_DSI_StatusGet(mipi_dsi_ctrl_t * const p_api_ctrl,mipi_dsi_status_t * p_status)477 fsp_err_t R_MIPI_DSI_StatusGet (mipi_dsi_ctrl_t * const p_api_ctrl, mipi_dsi_status_t * p_status)
478 {
479 #if MIPI_DSI_CFG_PARAM_CHECKING_ENABLE
480 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) p_api_ctrl;
481 FSP_ASSERT(NULL != p_ctrl);
482 FSP_ASSERT(NULL != p_status);
483 FSP_ERROR_RETURN(MIPI_DSI_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
484 #else
485 FSP_PARAMETER_NOT_USED(p_api_ctrl);
486 #endif
487
488 p_status->link_status = (mipi_dsi_link_status_t) R_DSILINK->LINKSR;
489 p_status->ack_err_latest.bits = R_DSILINK->AKEPLATIR;
490 p_status->ack_err_accumulated.bits = R_DSILINK->AKEPACMSR;
491
492 /* Clear accumulated error bits after reading */
493 R_DSILINK->AKEPSCR = p_status->ack_err_accumulated.bits;
494
495 return FSP_SUCCESS;
496 }
497
498 /*******************************************************************************************************************//**
499 * @} (end addtogroup MIPI_DSI)
500 **********************************************************************************************************************/
501
502 /*******************************************************************************************************************//**
503 * Stop DSI operation. Basic parameter checking to be performed by caller.
504 *
505 * @param[in] p_ctrl Pointer to instance control structure
506 *
507 * @retval FSP_SUCCESS DSI stopped successfully.
508 * @retval FSP_ERR_IN_USE DSI cannot be stopped in ULPS.
509 **********************************************************************************************************************/
dsi_stop(mipi_dsi_instance_ctrl_t * p_ctrl)510 static fsp_err_t dsi_stop (mipi_dsi_instance_ctrl_t * p_ctrl)
511 {
512 #if MIPI_DSI_CFG_PARAM_CHECKING_ENABLE
513 FSP_ERROR_RETURN(!p_ctrl->ulps_status, FSP_ERR_IN_USE);
514 #else
515 FSP_PARAMETER_NOT_USED(p_ctrl);
516 #endif
517
518 /* Check if running first else the stop operation may stall indefinitely */
519 if (R_DSILINK->VMSR_b.RUNNING)
520 {
521 /* Initiate stop video output and wait */
522 R_DSILINK->VMSET0R_b.VSTOP = 1U;
523
524 while ((R_DSILINK->VMSR_b.STOP != 1) && g_video_started)
525 {
526 /* Wait for video mode stop
527 * - VMSR.STOP must be zero before proceeding to stop GLCDC
528 * NOTE: VMSR may be modified in isr */
529 }
530
531 g_video_started = false;
532
533 /* Clear any stale VMSR status */
534 R_DSILINK->VMSCR = R_DSILINK->VMSR;
535 }
536
537 return FSP_SUCCESS;
538 }
539
540 /***********************************************************************************************************************
541 * Returns configuration values for Sequence Register A
542 *
543 * @param[in] p_cmd Pointer to formatted message structure
544 **********************************************************************************************************************/
dsi_cmd_sequence_register_a(mipi_dsi_cmd_t * p_cmd)545 static uint32_t dsi_cmd_sequence_register_a (mipi_dsi_cmd_t * p_cmd)
546 {
547 /*
548 * Long write packets contain the word count in header bytes 1 and 2.
549 * The payload follows the header and is word count bytes long.
550 *
551 * Short write packets encode up to two parameters in header bytes 1
552 * and 2.
553 */
554 uint8_t short_data[2];
555 bool long_packet = DSI_PACKET_FORMAT_IS_LONG(p_cmd->cmd_id);
556 if (long_packet)
557 {
558 short_data[0] = (p_cmd->tx_len >> 0) & 0xFFU; // NOLINT(readability-magic-numbers)
559 short_data[1] = (p_cmd->tx_len >> 8) & 0xFFU; // NOLINT(readability-magic-numbers)
560 }
561 else
562 {
563 short_data[0] = (p_cmd->tx_len > 0) ? p_cmd->p_tx_buffer[0] : 0U;
564 short_data[1] = (p_cmd->tx_len > 1) ? p_cmd->p_tx_buffer[1] : 0U;
565 }
566
567 uint8_t bta =
568 (p_cmd->flags & (MIPI_DSI_CMD_FLAG_BTA | MIPI_DSI_CMD_FLAG_BTA_READ | MIPI_DSI_CMD_FLAG_BTA_NO_WRITE));
569
570 uint8_t lp = (0 != (p_cmd->flags & MIPI_DSI_CMD_FLAG_LOW_POWER));
571 uint32_t sequence_register_a =
572 (((uint32_t) short_data[0] << R_DSILINK_SQCH0DSC0AR_DATA0_Pos) & R_DSILINK_SQCH0DSC0AR_DATA0_Msk) |
573 (((uint32_t) short_data[1] << R_DSILINK_SQCH0DSC0AR_DATA1_Pos) & R_DSILINK_SQCH0DSC0AR_DATA1_Msk) |
574 (((uint32_t) p_cmd->cmd_id << R_DSILINK_SQCH0DSC0AR_DT_Pos) & R_DSILINK_SQCH0DSC0AR_DT_Msk) |
575 (((uint32_t) p_cmd->channel << R_DSILINK_SQCH0DSC0AR_VC_Pos) & R_DSILINK_SQCH0DSC0AR_VC_Msk) |
576 (((uint32_t) long_packet << R_DSILINK_SQCH0DSC0AR_FMT_Pos) & R_DSILINK_SQCH0DSC0AR_FMT_Msk) |
577 (((uint32_t) lp << R_DSILINK_SQCH0DSC0AR_SPD_Pos) & R_DSILINK_SQCH0DSC0AR_SPD_Msk) |
578 (((uint32_t) bta << R_DSILINK_SQCH0DSC0AR_BTA_Pos) & R_DSILINK_SQCH0DSC0AR_BTA_Msk) |
579 (((uint32_t) 0 << R_DSILINK_SQCH0DSC0AR_NXACT_Pos) & R_DSILINK_SQCH0DSC0AR_NXACT_Msk);
580
581 return sequence_register_a;
582 }
583
584 /***********************************************************************************************************************
585 * Returns configuration values for Sequence Register B
586 *
587 * @param[in] p_cmd Pointer to formatted message structure
588 **********************************************************************************************************************/
dsi_cmd_sequence_register_b(mipi_dsi_cmd_t * p_cmd)589 static uint32_t dsi_cmd_sequence_register_b (mipi_dsi_cmd_t * p_cmd)
590 {
591 FSP_PARAMETER_NOT_USED(p_cmd);
592
593 /* Use sequence RAM */
594 return (1 << R_DSILINK_SQCH0DSC0BR_DTSEL_Pos) & R_DSILINK_SQCH0DSC0BR_DTSEL_Msk;
595 }
596
597 /***********************************************************************************************************************
598 * Returns configuration values for Sequence Register C
599 *
600 * @param[in] p_cmd Pointer to formatted message structure
601 **********************************************************************************************************************/
dsi_cmd_sequence_register_c(mipi_dsi_cmd_t * p_cmd)602 static uint32_t dsi_cmd_sequence_register_c (mipi_dsi_cmd_t * p_cmd)
603 {
604 bool aux_operation = (p_cmd->flags & MIPI_DSI_CMD_FLAG_AUX_OPERATION);
605 bool actcode = aux_operation ? (p_cmd->flags & 0xF) : 0; // Always store Rx result in slot 0
606 uint32_t sequence_register_c =
607 (((uint32_t) 0 << R_DSILINK_SQCH0DSC0CR_FINACT_Pos) & R_DSILINK_SQCH0DSC0CR_FINACT_Msk) |
608 (((uint32_t) aux_operation << R_DSILINK_SQCH0DSC0CR_AUXOP_Pos) & R_DSILINK_SQCH0DSC0CR_AUXOP_Msk) |
609 (((uint32_t) actcode << R_DSILINK_SQCH0DSC0CR_ACTCODE_Pos) & R_DSILINK_SQCH0DSC0CR_ACTCODE_Msk);
610
611 return sequence_register_c;
612 }
613
614 /***********************************************************************************************************************
615 * Returns configuration values for Sequence Register D
616 *
617 * @param[in] p_cmd Pointer to formatted message structure
618 **********************************************************************************************************************/
dsi_cmd_sequence_register_d(mipi_dsi_cmd_t * p_cmd)619 uint32_t dsi_cmd_sequence_register_d (mipi_dsi_cmd_t * p_cmd)
620 {
621 uint8_t bta =
622 (p_cmd->flags & (MIPI_DSI_CMD_FLAG_BTA | MIPI_DSI_CMD_FLAG_BTA_READ | MIPI_DSI_CMD_FLAG_BTA_NO_WRITE));
623
624 return (uint32_t) (bta ? p_cmd->p_rx_buffer : p_cmd->p_tx_buffer); // This buffer address is used for both Tx and Rx.
625 }
626
627 /*******************************************************************************************************************//**
628 * Calls user callback
629 *
630 * @param[in] p_ctrl Pointer to MIPI DSI instance control block
631 * @param[in] p_args Pointer to arguments on stack
632 **********************************************************************************************************************/
dsi_call_callback(mipi_dsi_instance_ctrl_t * p_ctrl,mipi_dsi_callback_args_t * p_args)633 static void dsi_call_callback (mipi_dsi_instance_ctrl_t * p_ctrl, mipi_dsi_callback_args_t * p_args)
634 {
635 mipi_dsi_callback_args_t args;
636
637 /* Store callback arguments in memory provided by user if available. This allows callback arguments to be
638 * stored in non-secure memory so they can be accessed by a non-secure callback function. */
639 mipi_dsi_callback_args_t * p_args_memory = p_ctrl->p_callback_memory;
640 if (NULL == p_args_memory)
641 {
642 /* Use provided args struct on stack */
643 p_args_memory = p_args;
644 }
645 else
646 {
647 /* Save current arguments on the stack in case this is a nested interrupt. */
648 args = *p_args_memory;
649
650 /* Copy the stacked args to callback memory */
651 *p_args_memory = *p_args;
652 }
653
654 #if BSP_TZ_SECURE_BUILD
655
656 /* p_callback can point to a secure function or a non-secure function. */
657 if (!cmse_is_nsfptr(p_ctrl->p_callback))
658 {
659 /* If p_callback is secure, then the project does not need to change security state. */
660 p_ctrl->p_callback(p_args_memory);
661 }
662 else
663 {
664 /* If p_callback is Non-secure, then the project must change to Non-secure state in order to call the callback. */
665 mipi_dsi_prv_ns_callback p_callback = (mipi_dsi_prv_ns_callback) (p_ctrl->p_callback);
666 p_callback(p_args_memory);
667 }
668 #else
669
670 /* If the project is not Trustzone Secure, then it will never need to change security state in order to call the callback. */
671 p_ctrl->p_callback(p_args_memory);
672 #endif
673
674 if (NULL != p_ctrl->p_callback_memory)
675 {
676 /* Restore callback memory in case this is a nested interrupt. */
677 *p_ctrl->p_callback_memory = args;
678 }
679 }
680
681 /*******************************************************************************************************************//**
682 * Private helper functions
683 **********************************************************************************************************************/
684
685 /*******************************************************************************************************************//**
686 * Enter Reset
687 * Perform sequence steps 1 to 3 from section 58.3.2 in RA8D1 hardware manual R01UH0995EJ0060.
688 **********************************************************************************************************************/
dsi_enter_reset()689 static void dsi_enter_reset ()
690 {
691 /* Enable clock lane */
692 R_DSILINK->TXSETR_b.CLEN = 1U;
693
694 /* Enter the DSI Host software reset state */
695 R_DSILINK->RSTCR_b.SWRST = 1;
696
697 /* Wait for reset process to start - Polling RSTSR is okay since it's not updated in interrupt.*/
698 FSP_HARDWARE_REGISTER_WAIT((R_DSILINK->RSTSR & MIPI_DSI_RSRST_RESET_BITS), MIPI_DSI_RSRST_RESET_BITS);
699 }
700
701 /*******************************************************************************************************************//**
702 * Initialize timing registers from configuration data
703 * - Perform sequence step 4 from section 58.3.2 in RA8D1 hardware manual R01UH0995EJ0060.
704 *
705 * @param[in] p_cfg Pointer to MIPI DSI configuration structure
706 **********************************************************************************************************************/
dsi_init_timing(mipi_dsi_cfg_t const * const p_cfg)707 static void dsi_init_timing (mipi_dsi_cfg_t const * const p_cfg)
708 {
709 /* Enable clock and data lanes and set number of lanes to use */
710 R_DSILINK->TXSETR = R_DSILINK_TXSETR_DLEN_Msk | R_DSILINK_TXSETR_CLEN_Msk | (p_cfg->num_lanes - 1);
711
712 /* Set ULPS wakeup period */
713 R_DSILINK->ULPSSETR_b.WKUP = p_cfg->ulps_wakeup_period;
714
715 /* Set data scrambling and/or EoTp transmission */
716 #define DSILINK_DSISETR_VCCRCEN_Msk (R_DSILINK_DSISETR_VC0CRCEN_Msk | \
717 R_DSILINK_DSISETR_VC1CRCEN_Msk | \
718 R_DSILINK_DSISETR_VC2CRCEN_Msk | \
719 R_DSILINK_DSISETR_VC3CRCEN_Msk)
720 R_DSILINK->DSISETR =
721 ((p_cfg->max_return_packet_size << R_DSILINK_DSISETR_MRPSZ_Pos) & R_DSILINK_DSISETR_MRPSZ_Msk) |
722 (((uint32_t) p_cfg->ecc_enable << R_DSILINK_DSISETR_ECCEN_Pos) & R_DSILINK_DSISETR_ECCEN_Msk) |
723 (((uint32_t) p_cfg->crc_check_mask << R_DSILINK_DSISETR_VC0CRCEN_Pos) & DSILINK_DSISETR_VCCRCEN_Msk) |
724 (((uint32_t) p_cfg->scramble_enable << R_DSILINK_DSISETR_SCREN_Pos) & R_DSILINK_DSISETR_SCREN_Msk) |
725 (((uint32_t) p_cfg->tearing_detect << R_DSILINK_DSISETR_EXTEMD_Pos) & R_DSILINK_DSISETR_EXTEMD_Msk) |
726 (((uint32_t) p_cfg->eotp_enable << R_DSILINK_DSISETR_EOTPEN_Pos) & R_DSILINK_DSISETR_EOTPEN_Msk);
727
728 /* Set LP lane transition timing */
729 R_DSILINK->CLSTPTSETR =
730 ((p_cfg->p_timing->clock_stop_time << R_DSILINK_CLSTPTSETR_CLKSTPT_Pos) &
731 R_DSILINK_CLSTPTSETR_CLKSTPT_Msk) |
732 ((p_cfg->p_timing->clock_beforehand_time << R_DSILINK_CLSTPTSETR_CLKBFHT_Pos) &
733 R_DSILINK_CLSTPTSETR_CLKBFHT_Msk) |
734 ((p_cfg->p_timing->clock_keep_time << R_DSILINK_CLSTPTSETR_CLKKPT_Pos) &
735 R_DSILINK_CLSTPTSETR_CLKKPT_Msk);
736 R_DSILINK->LPTRNSTSETR = p_cfg->p_timing->go_lp_and_back & R_DSILINK_LPTRNSTSETR_GOLPBKT_Msk;
737
738 /* Set timeout values */
739 R_DSILINK->PRESPTOBTASETR = p_cfg->bta_timeout;
740 R_DSILINK->PRESPTOLPSETR = p_cfg->lprw_timeout;
741 R_DSILINK->PRESPTOHSSETR = p_cfg->hsrw_timeout;
742 R_DSILINK->HSTXTOSETR = p_cfg->hs_tx_timeout;
743 R_DSILINK->LRXHTOSETR = p_cfg->lp_rx_timeout;
744 R_DSILINK->TATOSETR = p_cfg->turnaround_timeout;
745 }
746
747 /*******************************************************************************************************************//**
748 * Exit Reset
749 * Perform sequence steps 5 to 9 from section 58.3.2 in RA8D1 hardware manual R01UH0995EJ0060.
750 *
751 * NOTE: Calling this function is prohibited without first calling dsi_enter_reset(), which sets RSTCR.SWRST to 1
752 *
753 * @param[in] p_cfg Pointer to MIPI DSI configuration structure
754 **********************************************************************************************************************/
dsi_exit_reset(mipi_dsi_cfg_t const * const p_cfg)755 static void dsi_exit_reset (mipi_dsi_cfg_t const * const p_cfg)
756 {
757 /* Transition data lanes to stop state */
758 R_DSILINK->RSTCR_b.FTXSTP = 1U;
759
760 /* Wait for data lanes transition to stop state */
761 FSP_HARDWARE_REGISTER_WAIT((R_DSILINK->RSTSR &
762 (R_DSILINK_RSTSR_DL0DIR_Msk | R_DSILINK_RSTSR_DL0STP_Msk | R_DSILINK_RSTSR_DL1STP_Msk)),
763 (((p_cfg->num_lanes * 2U) - 1U) << R_DSILINK_RSTSR_DL0STP_Pos));
764
765 /* Clear the Force Tx Stop and Software Reset bits */
766 R_DSILINK->RSTCR_b.FTXSTP = 0U;
767 R_DSILINK->RSTCR_b.SWRST = 0U;
768
769 /* Wait for software reset to complete */
770 FSP_HARDWARE_REGISTER_WAIT((R_DSILINK->RSTSR & MIPI_DSI_RSRST_RESET_BITS), 0);
771 }
772
773 /*******************************************************************************************************************//**
774 * Initialize High Speed Clock
775 * Perform sequence steps from section 58.3.3 in RA8D1 hardware manual R01UH0995EJ0060.
776 *
777 * @param[in] p_ctrl Pointer to MIPI DSI instance control block
778 **********************************************************************************************************************/
dsi_hs_clock_start(mipi_dsi_instance_ctrl_t * p_ctrl)779 static void dsi_hs_clock_start (mipi_dsi_instance_ctrl_t * p_ctrl)
780 {
781 mipi_dsi_cfg_t const * p_cfg = p_ctrl->p_cfg;
782
783 /* Enable clock lane */
784 R_DSILINK->TXSETR_b.CLEN = 1U;
785 g_clock_state = MIPI_DSI_CLOCK_STATE_STARTING;
786
787 /* Enable HS clock and set running mode */
788 R_DSILINK->HSCLKSETR = R_DSILINK_HSCLKSETR_HSCLST_Msk |
789 (p_cfg->continuous_clock ? R_DSILINK_HSCLKSETR_HSCLMD_Msk : 0U);
790
791 while ((R_DSILINK->PLSR_b.CLLP2HS != p_cfg->continuous_clock) &&
792 (g_clock_state != MIPI_DSI_CLOCK_STATE_STARTED))
793 {
794 /* Wait for HS clock notification bit set to 1. (only in the continuous clock mode)
795 * NOTE: PLSR may be modified in ISR */
796 }
797
798 g_clock_state = MIPI_DSI_CLOCK_STATE_STARTED;
799 }
800
801 /***********************************************************************************************************************
802 * De-initialize High Speed Clock
803 * Perform sequence steps from section 56.3.4 in RA8D1 hardware manual R01UH0995EJ0060.
804 *
805 * @param[in] p_ctrl Pointer to MIPI DSI instance control block
806 **********************************************************************************************************************/
dsi_hs_clock_stop(mipi_dsi_instance_ctrl_t * p_ctrl)807 static void dsi_hs_clock_stop (mipi_dsi_instance_ctrl_t * p_ctrl)
808 {
809 mipi_dsi_cfg_t const * p_cfg = p_ctrl->p_cfg;
810
811 R_DSILINK->HSCLKSETR_b.HSCLST = 0;
812 g_clock_state = MIPI_DSI_CLOCK_STATE_STOPPING;
813
814 while ((R_DSILINK->PLSR_b.CLHS2LP != p_cfg->continuous_clock) && (g_clock_state != MIPI_DSI_CLOCK_STATE_IDLE))
815 {
816 /* Wait for clock lane transition LP state.
817 * NOTE: PLSR may be modified in ISR */
818 }
819
820 g_clock_state = MIPI_DSI_CLOCK_STATE_IDLE;
821 }
822
823 /***********************************************************************************************************************
824 * Initialize Video Output Registers
825 * Perform sequence steps 1 and 2 from section 58.3.6.1 in RA8D1 hardware manual R01UH0995EJ0060.
826 *
827 * @param[in] p_cfg Pointer to MIPI DSI configuration structure
828 **********************************************************************************************************************/
dsi_init_video(mipi_dsi_cfg_t const * p_cfg)829 static void dsi_init_video (mipi_dsi_cfg_t const * p_cfg)
830 {
831 R_DSILINK->VMPPSETR =
832 (((uint32_t) p_cfg->sync_pulse << R_DSILINK_VMPPSETR_TXESYNC_Pos) & R_DSILINK_VMPPSETR_TXESYNC_Msk) |
833 (((uint32_t) p_cfg->data_type << R_DSILINK_VMPPSETR_DT_Pos) & R_DSILINK_VMPPSETR_DT_Msk) |
834 (((uint32_t) p_cfg->virtual_channel_id << R_DSILINK_VMPPSETR_VC_Pos) &
835 R_DSILINK_VMPPSETR_VC_Msk);
836 R_DSILINK->VMVSSETR =
837 ((p_cfg->vertical_sync_lines << R_DSILINK_VMVSSETR_VSA_Pos) & R_DSILINK_VMVSSETR_VSA_Msk) |
838 (((uint32_t) p_cfg->vertical_sync_polarity << R_DSILINK_VMVSSETR_VSPOL_Pos) &
839 R_DSILINK_VMVSSETR_VSPOL_Msk) |
840 ((p_cfg->vertical_active_lines << R_DSILINK_VMVSSETR_VACT_Pos) &
841 R_DSILINK_VMVSSETR_VACT_Msk);
842 R_DSILINK->VMVPSETR =
843 ((p_cfg->vertical_back_porch << R_DSILINK_VMVPSETR_VBP_Pos) & R_DSILINK_VMVPSETR_VBP_Msk) |
844 ((p_cfg->vertical_front_porch << R_DSILINK_VMVPSETR_VFP_Pos) &
845 R_DSILINK_VMVPSETR_VFP_Msk);
846 R_DSILINK->VMHSSETR =
847 ((p_cfg->horizontal_sync_lines << R_DSILINK_VMHSSETR_HSA_Pos) & R_DSILINK_VMHSSETR_HSA_Msk) |
848 (((uint32_t) p_cfg->horizontal_sync_polarity << R_DSILINK_VMHSSETR_HSPOL_Pos) &
849 R_DSILINK_VMHSSETR_HSPOL_Msk) |
850 ((p_cfg->horizontal_active_lines << R_DSILINK_VMHSSETR_HACT_Pos) &
851 R_DSILINK_VMHSSETR_HACT_Msk);
852 R_DSILINK->VMHPSETR =
853 ((p_cfg->horizontal_back_porch << R_DSILINK_VMHPSETR_HBP_Pos) & R_DSILINK_VMHPSETR_HBP_Msk) |
854 ((p_cfg->horizontal_front_porch << R_DSILINK_VMHPSETR_HFP_Pos) &
855 R_DSILINK_VMHPSETR_HFP_Msk);
856 R_DSILINK->VMSET1R =
857 ((p_cfg->video_mode_delay << R_DSILINK_VMSET1R_DLY_Pos) & R_DSILINK_VMSET1R_DLY_Msk);
858 }
859
860 /***********************************************************************************************************************
861 * Enable the specified ISR and add the control structure to the ISR context lookup table.
862 *
863 * @param[in] irq_cfg Pointer to interrupt configuration structure
864 * @param[in] p_ctrl Pointer to MIPI DSI instance control block
865 **********************************************************************************************************************/
dsi_isr_enable(mipi_dsi_irq_cfg_t const * irq_cfg,mipi_dsi_instance_ctrl_t * p_ctrl)866 static void dsi_isr_enable (mipi_dsi_irq_cfg_t const * irq_cfg, mipi_dsi_instance_ctrl_t * p_ctrl)
867 {
868 R_BSP_IrqCfgEnable(irq_cfg->irq, irq_cfg->ipl, p_ctrl);
869 }
870
871 /***********************************************************************************************************************
872 * Disable the specified ISR
873 *
874 * @param[in] irq_cfg Pointer to interrupt configuration structure
875 **********************************************************************************************************************/
dsi_isr_disable(mipi_dsi_irq_cfg_t const * irq_cfg)876 static void dsi_isr_disable (mipi_dsi_irq_cfg_t const * irq_cfg)
877 {
878 R_BSP_IrqDisable(irq_cfg->irq);
879 R_FSP_IsrContextSet(irq_cfg->irq, NULL);
880 }
881
882 /***********************************************************************************************************************
883 * Interrupt Service Routines
884 **********************************************************************************************************************/
885
886 /***********************************************************************************************************************
887 * Sequence 0 ISR
888 * - Process LP sequence command events and forward them to the user callback
889 **********************************************************************************************************************/
mipi_dsi_seq0(void)890 void mipi_dsi_seq0 (void) {
891 /* Save context if RTOS is used */
892 FSP_CONTEXT_SAVE;
893
894 /* Clear sequence channel 0 status register bits */
895 uint32_t sqch0sr_bits = R_DSILINK->SQCH0SR;
896 R_DSILINK->SQCH0SCR = sqch0sr_bits; // SIZEERR is reserved for SQCH0SCR and should be read and written as zero
897
898 IRQn_Type irq = R_FSP_CurrentIrqGet();
899 R_BSP_IrqStatusClear(irq);
900
901 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
902 mipi_dsi_callback_args_t args;
903 args.event = MIPI_DSI_EVENT_SEQUENCE_0;
904 args.tx_status = (mipi_dsi_sequence_status_t) sqch0sr_bits;
905 args.p_context = p_ctrl->p_context;
906 dsi_call_callback(p_ctrl, &args);
907
908 /* Restore context if RTOS is used */
909 FSP_CONTEXT_RESTORE;
910 }
911
912 /***********************************************************************************************************************
913 * Sequence 1 ISR
914 * - Process HS sequence command events and forward them to the user callback
915 **********************************************************************************************************************/
mipi_dsi_seq1(void)916 void mipi_dsi_seq1 (void) {
917 /* Save context if RTOS is used */
918 FSP_CONTEXT_SAVE;
919
920 /* Clear sequence channel 1 status register bits */
921 uint32_t sqch1sr_bits = R_DSILINK->SQCH1SR;
922 R_DSILINK->SQCH1SCR = sqch1sr_bits;
923
924 IRQn_Type irq = R_FSP_CurrentIrqGet();
925 R_BSP_IrqStatusClear(irq);
926
927 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
928 mipi_dsi_callback_args_t args;
929 args.event = MIPI_DSI_EVENT_SEQUENCE_1;
930 args.tx_status = (mipi_dsi_sequence_status_t) sqch1sr_bits;
931 args.p_context = p_ctrl->p_context;
932 dsi_call_callback(p_ctrl, &args);
933
934 /* Restore context if RTOS is used */
935 FSP_CONTEXT_RESTORE;
936 }
937
938 /***********************************************************************************************************************
939 * Video Input ISR
940 * - Process DSI Video Input Events and forward them to the user callback
941 **********************************************************************************************************************/
mipi_dsi_vin1(void)942 void mipi_dsi_vin1 (void) {
943 /* Save context if RTOS is used */
944 FSP_CONTEXT_SAVE;
945
946 /* Clear video mode status register bits */
947 uint32_t vmsr_bits = R_DSILINK->VMSR;
948 R_DSILINK->VMSCR = vmsr_bits;
949
950 IRQn_Type irq = R_FSP_CurrentIrqGet();
951 R_BSP_IrqStatusClear(irq);
952
953 /* Update internal state */
954 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
955 if (vmsr_bits & R_DSILINK_VMSR_VIRDY_Msk)
956 {
957 g_video_started = true;
958 }
959 else if (vmsr_bits & R_DSILINK_VMSR_STOP_Msk)
960 {
961 g_video_started = false;
962 }
963 else
964 {
965 // Nothing
966 }
967
968 /* Pass data to user */
969 mipi_dsi_callback_args_t args;
970 args.event = MIPI_DSI_EVENT_VIDEO;
971 args.video_status = (mipi_dsi_video_status_t) vmsr_bits;
972 args.p_context = p_ctrl->p_context;
973 dsi_call_callback(p_ctrl, &args);
974
975 /* Perform reset according to RA8D1 UM 58.3.8.6 (R01UH0995EJ0060) */
976 if (vmsr_bits & (R_DSILINK_VMSR_VBUFUDF_Msk | R_DSILINK_VMSR_VBUFOVF_Msk))
977 {
978 dsi_enter_reset();
979 dsi_exit_reset(p_ctrl->p_cfg);
980 }
981
982 /* Restore context if RTOS is used */
983 FSP_CONTEXT_RESTORE;
984 }
985
986 /***********************************************************************************************************************
987 * Receive ISR
988 * - Process Receive Events and forward them to the user callback
989 **********************************************************************************************************************/
mipi_dsi_rcv(void)990 void mipi_dsi_rcv (void) {
991 /* Save context if RTOS is used */
992 FSP_CONTEXT_SAVE;
993
994 /* Clear recieve status register bits */
995 uint32_t rxsr_bits = R_DSILINK->RXSR;
996 R_DSILINK->RXSCR = rxsr_bits;
997
998 IRQn_Type irq = R_FSP_CurrentIrqGet();
999 R_BSP_IrqStatusClear(irq);
1000
1001 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
1002 mipi_dsi_callback_args_t args;
1003 args.event = MIPI_DSI_EVENT_RECEIVE;
1004 args.rx_status = (mipi_dsi_receive_status_t) rxsr_bits;
1005 args.p_result = (mipi_dsi_receive_result_t *) &R_DSILINK->RXRSS0R;
1006 args.p_context = p_ctrl->p_context;
1007 dsi_call_callback(p_ctrl, &args);
1008
1009 R_DSILINK->RXRINFOOWSCR = R_DSILINK_RXRINFOOWSCR_SL0OW_Msk; // Clear slot 0 after reading
1010
1011 /* Restore context if RTOS is used */
1012 FSP_CONTEXT_RESTORE;
1013 }
1014
1015 /***********************************************************************************************************************
1016 * Fatal Error ISR
1017 * - Process Fatal Error Events and forward them to the user callback
1018 **********************************************************************************************************************/
mipi_dsi_ferr(void)1019 void mipi_dsi_ferr (void) {
1020 /* Save context if RTOS is used */
1021 FSP_CONTEXT_SAVE;
1022
1023 /* Clear recieve status register bits */
1024 uint32_t ferrsr_bits = R_DSILINK->FERRSR;
1025 R_DSILINK->FERRSCR = ferrsr_bits;
1026
1027 IRQn_Type irq = R_FSP_CurrentIrqGet();
1028 R_BSP_IrqStatusClear(irq);
1029
1030 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
1031 mipi_dsi_callback_args_t args;
1032 args.event = MIPI_DSI_EVENT_FATAL;
1033 args.fatal_status = (mipi_dsi_fatal_status_t) ferrsr_bits;
1034 args.p_context = p_ctrl->p_context;
1035 dsi_call_callback(p_ctrl, &args);
1036
1037 /* Restore context if RTOS is used */
1038 FSP_CONTEXT_RESTORE;
1039 }
1040
1041 /***********************************************************************************************************************
1042 * PHY-Protocol Interface ISR
1043 * - Process Phy-Protocol Events and forward them to the user callback
1044 **********************************************************************************************************************/
mipi_dsi_ppi(void)1045 void mipi_dsi_ppi (void) {
1046 /* Save context if RTOS is used */
1047 FSP_CONTEXT_SAVE;
1048
1049 /* Clear PLSR */
1050 uint32_t plsr_bits = R_DSILINK->PLSR;
1051 R_DSILINK->PLSCR = plsr_bits;
1052
1053 IRQn_Type irq = R_FSP_CurrentIrqGet();
1054 R_BSP_IrqStatusClear(irq);
1055
1056 /* Update internal state */
1057 mipi_dsi_instance_ctrl_t * p_ctrl = (mipi_dsi_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
1058 if ((g_clock_state == MIPI_DSI_CLOCK_STATE_STARTING) &&
1059 (plsr_bits & R_DSILINK_PLSR_CLLP2HS_Msk))
1060 {
1061 g_clock_state = MIPI_DSI_CLOCK_STATE_STARTED;
1062 }
1063 else if ((g_clock_state == MIPI_DSI_CLOCK_STATE_STOPPING) &&
1064 (plsr_bits & R_DSILINK_PLSR_CLHS2LP_Msk))
1065 {
1066 g_clock_state = MIPI_DSI_CLOCK_STATE_IDLE;
1067 }
1068 else
1069 {
1070 // Nothing
1071 }
1072
1073 /* Pass data to user */
1074 mipi_dsi_callback_args_t args;
1075 args.event = MIPI_DSI_EVENT_PHY;
1076 args.phy_status = (mipi_dsi_phy_status_t) plsr_bits;
1077 args.p_context = p_ctrl->p_context;
1078 dsi_call_callback(p_ctrl, &args);
1079
1080 /* Restore context if RTOS is used */
1081 FSP_CONTEXT_RESTORE;
1082 }
1083