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