1 /*
2  * Copyright (c) 2019-2020, NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_dc_fb_dsi_cmd.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 const dc_fb_ops_t g_dcFbOpsDsiCmd = {
14     .init                  = DC_FB_DSI_CMD_Init,
15     .deinit                = DC_FB_DSI_CMD_Deinit,
16     .enableLayer           = DC_FB_DSI_CMD_EnableLayer,
17     .disableLayer          = DC_FB_DSI_CMD_DisableLayer,
18     .setLayerConfig        = DC_FB_DSI_CMD_SetLayerConfig,
19     .getLayerDefaultConfig = DC_FB_DSI_CMD_GetLayerDefaultConfig,
20     .setFrameBuffer        = DC_FB_DSI_CMD_SetFrameBuffer,
21     .getProperty           = DC_FB_DSI_CMD_GetProperty,
22     .setCallback           = DC_FB_DSI_CMD_SetCallback,
23 };
24 
25 /*******************************************************************************
26  * Prototypes
27  ******************************************************************************/
DC_FB_DSI_CMD_FrameDoneCallback(status_t status,void * userData)28 static void DC_FB_DSI_CMD_FrameDoneCallback(status_t status, void *userData)
29 {
30     dc_fb_dsi_cmd_handle_t *dcHandle;
31     dc_fb_dsi_cmd_layer_t *layer;
32 
33     dcHandle = (dc_fb_dsi_cmd_handle_t *)userData;
34 
35     /* Currently only support one layer, so the layer index is always 0. */
36     layer = &(dcHandle->layers[0]);
37 
38     /* Frame buffer data has been sent to the panel, the frame buffer is free
39      * to be used for set new data, call the callback to notify upper layer.
40      * The callback is set in application or fbdev.
41      */
42     layer->callback(layer->cbParam, layer->frameBuffer);
43 }
44 
45 /*******************************************************************************
46  * Variables
47  ******************************************************************************/
48 
49 /*******************************************************************************
50  * Code
51  ******************************************************************************/
DC_FB_DSI_CMD_Init(const dc_fb_t * dc)52 status_t DC_FB_DSI_CMD_Init(const dc_fb_t *dc)
53 {
54     status_t status;
55 
56     const dc_fb_dsi_cmd_config_t *dcConfig;
57     dc_fb_dsi_cmd_handle_t *dcHandle;
58     display_handle_t *panelHandle;
59     mipi_dsi_device_t *dsiDevice;
60 
61     dcHandle = (dc_fb_dsi_cmd_handle_t *)dc->prvData;
62 
63     if (0U == dcHandle->initTimes++)
64     {
65         panelHandle = (display_handle_t *)(dcHandle->panelHandle);
66         dcConfig    = (const dc_fb_dsi_cmd_config_t *)(dc->config);
67         dsiDevice   = dcHandle->dsiDevice;
68 
69         dcHandle->useTEPin = dcConfig->useTEPin;
70 
71         status = DISPLAY_Init(panelHandle, &dcConfig->commonConfig);
72 
73         if (kStatus_Success != status)
74         {
75             return status;
76         }
77 
78         MIPI_DSI_SetMemoryDoneCallback(dsiDevice, DC_FB_DSI_CMD_FrameDoneCallback, dcHandle);
79     }
80 
81     return kStatus_Success;
82 }
83 
DC_FB_DSI_CMD_Deinit(const dc_fb_t * dc)84 status_t DC_FB_DSI_CMD_Deinit(const dc_fb_t *dc)
85 {
86     status_t status = kStatus_Success;
87 
88     dc_fb_dsi_cmd_handle_t *dcHandle;
89     display_handle_t *panelHandle;
90 
91     dcHandle = (dc_fb_dsi_cmd_handle_t *)dc->prvData;
92 
93     if (dcHandle->initTimes > 0U)
94     {
95         if (--dcHandle->initTimes == 0U)
96         {
97             panelHandle = (display_handle_t *)(dcHandle->panelHandle);
98             status      = DISPLAY_Deinit(panelHandle);
99         }
100     }
101 
102     return status;
103 }
104 
DC_FB_DSI_CMD_EnableLayer(const dc_fb_t * dc,uint8_t layer)105 status_t DC_FB_DSI_CMD_EnableLayer(const dc_fb_t *dc, uint8_t layer)
106 {
107     dc_fb_dsi_cmd_handle_t *dcHandle;
108     display_handle_t *panelHandle;
109 
110     status_t status = kStatus_Success;
111 
112     dcHandle = (dc_fb_dsi_cmd_handle_t *)dc->prvData;
113 
114     if (0U == dcHandle->enabledLayerCount++)
115     {
116         panelHandle = (display_handle_t *)(dcHandle->panelHandle);
117 
118         status = DISPLAY_Start(panelHandle);
119     }
120 
121     return status;
122 }
123 
DC_FB_DSI_CMD_DisableLayer(const dc_fb_t * dc,uint8_t layer)124 status_t DC_FB_DSI_CMD_DisableLayer(const dc_fb_t *dc, uint8_t layer)
125 {
126     dc_fb_dsi_cmd_handle_t *dcHandle;
127     display_handle_t *panelHandle;
128 
129     status_t status = kStatus_Success;
130 
131     dcHandle = (dc_fb_dsi_cmd_handle_t *)dc->prvData;
132 
133     if (dcHandle->enabledLayerCount > 0U)
134     {
135         if (--dcHandle->enabledLayerCount == 0U)
136         {
137             panelHandle = (display_handle_t *)(dcHandle->panelHandle);
138 
139             status = DISPLAY_Stop(panelHandle);
140         }
141     }
142 
143     return status;
144 }
145 
DC_FB_DSI_CMD_SetLayerConfig(const dc_fb_t * dc,uint8_t layer,dc_fb_info_t * fbInfo)146 status_t DC_FB_DSI_CMD_SetLayerConfig(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo)
147 {
148     assert(layer < DC_FB_DSI_CMD_MAX_LAYER);
149 
150     dc_fb_dsi_cmd_handle_t *dcHandle = (dc_fb_dsi_cmd_handle_t *)(dc->prvData);
151 
152     /* The pixel format is already set by DSI_CMD_Init and could not be changed,
153        so here don't need to set the format.
154        */
155 
156     dcHandle->layers[layer].fbInfo = *fbInfo;
157 
158     return kStatus_Success;
159 }
160 
DC_FB_DSI_CMD_GetLayerDefaultConfig(const dc_fb_t * dc,uint8_t layer,dc_fb_info_t * fbInfo)161 status_t DC_FB_DSI_CMD_GetLayerDefaultConfig(const dc_fb_t *dc, uint8_t layer, dc_fb_info_t *fbInfo)
162 {
163     assert(layer < DC_FB_DSI_CMD_MAX_LAYER);
164 
165     dc_fb_dsi_cmd_handle_t *dcHandle = (dc_fb_dsi_cmd_handle_t *)(dc->prvData);
166     display_handle_t *panelHandle    = (display_handle_t *)(dcHandle->panelHandle);
167 
168     fbInfo->startX      = 0;
169     fbInfo->startY      = 0;
170     fbInfo->width       = panelHandle->width;
171     fbInfo->height      = panelHandle->height;
172     fbInfo->strideBytes = panelHandle->width * VIDEO_GetPixelSizeBits(panelHandle->pixelFormat) / 8U;
173     fbInfo->pixelFormat = panelHandle->pixelFormat;
174 
175     return kStatus_Success;
176 }
177 
DC_FB_DSI_CMD_SetFrameBuffer(const dc_fb_t * dc,uint8_t layer,void * frameBuffer)178 status_t DC_FB_DSI_CMD_SetFrameBuffer(const dc_fb_t *dc, uint8_t layer, void *frameBuffer)
179 {
180     assert(layer < DC_FB_DSI_CMD_MAX_LAYER);
181 
182     status_t status;
183 
184     dc_fb_dsi_cmd_handle_t *dcHandle = dc->prvData;
185     dc_fb_dsi_cmd_layer_t *pLayer    = &(dcHandle->layers[layer]);
186     dc_fb_info_t *fbInfo             = &(pLayer->fbInfo);
187     mipi_dsi_device_t *dsiDevice     = dcHandle->dsiDevice;
188     uint8_t byteperpixel             = VIDEO_GetPixelSizeBits(fbInfo->pixelFormat) / 8U;
189     uint32_t minorLoopBytes          = (uint32_t)fbInfo->width * (uint32_t)byteperpixel;
190 
191     /* The selected area is non-constant in memory and the display device does not support 2-D memory write,
192        return kStatus_Fail directly. */
193     if ((dsiDevice->memWriteFunc2D == NULL) && (minorLoopBytes < (uint32_t)fbInfo->strideBytes))
194     {
195         return kStatus_Fail;
196     }
197 
198     status = MIPI_DSI_SelectArea(dsiDevice, fbInfo->startX, fbInfo->startY, fbInfo->startX + fbInfo->width - 1U,
199                                  fbInfo->startY + fbInfo->height - 1U);
200 
201     if (kStatus_Success != status)
202     {
203         return status;
204     }
205 
206     /*
207      * If TE pin is not used, send the new FB directly.
208      *
209      * If TE pin is used, then set the new FB as pending, and send it at next TE
210      * interrupt.
211      */
212     if (!dcHandle->useTEPin)
213     {
214         pLayer->frameBuffer = frameBuffer;
215         /* If the update width in byte is smaller than the stride, it means the pixel data is interleaved, use 2-D
216          * transfer. */
217         if (minorLoopBytes < (uint32_t)fbInfo->strideBytes)
218         {
219             status = MIPI_DSI_WriteMemory2D(dsiDevice, frameBuffer, minorLoopBytes,
220                                             (uint32_t)fbInfo->strideBytes - minorLoopBytes, (uint32_t)fbInfo->height);
221         }
222         else
223         {
224             status =
225                 MIPI_DSI_WriteMemory(dsiDevice, frameBuffer, (uint32_t)fbInfo->height * (uint32_t)fbInfo->strideBytes);
226         }
227     }
228     else
229     {
230         if (pLayer->fbWaitTE == NULL)
231         {
232             /* Save the new FB, and send it at next TE. */
233             pLayer->fbWaitTE = frameBuffer;
234         }
235         else
236         {
237             /*
238              * Generally should never be here, because this function should only
239              * be called when no pending frames.
240              */
241             status = kStatus_Fail;
242         }
243     }
244 
245     return status;
246 }
247 
DC_FB_DSI_CMD_SetCallback(const dc_fb_t * dc,uint8_t layer,dc_fb_callback_t callback,void * param)248 void DC_FB_DSI_CMD_SetCallback(const dc_fb_t *dc, uint8_t layer, dc_fb_callback_t callback, void *param)
249 {
250     assert(layer < DC_FB_DSI_CMD_MAX_LAYER);
251     dc_fb_dsi_cmd_handle_t *dcHandle = dc->prvData;
252 
253     dcHandle->layers[layer].callback = callback;
254     dcHandle->layers[layer].cbParam  = param;
255 }
256 
DC_FB_DSI_CMD_GetProperty(const dc_fb_t * dc)257 uint32_t DC_FB_DSI_CMD_GetProperty(const dc_fb_t *dc)
258 {
259     dc_fb_dsi_cmd_handle_t *dcHandle = dc->prvData;
260     mipi_dsi_device_t *dsiDevice     = dcHandle->dsiDevice;
261     if (dsiDevice->memWriteFunc2D != NULL)
262     {
263         return (uint32_t)kDC_FB_TwoDimensionMemoryWrite;
264     }
265     else
266     {
267         return 0;
268     }
269 }
270 
DC_FB_DSI_CMD_TE_IRQHandler(const dc_fb_t * dc)271 void DC_FB_DSI_CMD_TE_IRQHandler(const dc_fb_t *dc)
272 {
273     dc_fb_dsi_cmd_handle_t *dcHandle;
274     dc_fb_dsi_cmd_layer_t *layer;
275     dc_fb_info_t *fbInfo;
276     uint8_t *newFB;
277     uint8_t byteperpixel;
278     uint32_t minorLoopBytes;
279 
280     dcHandle = (dc_fb_dsi_cmd_handle_t *)dc->prvData;
281 
282     /* Currently only support one layer, so the layer index is always 0. */
283     layer = &(dcHandle->layers[0]);
284 
285     newFB = layer->fbWaitTE;
286 
287     if (NULL != newFB)
288     {
289         fbInfo             = &(layer->fbInfo);
290         layer->fbWaitTE    = NULL;
291         layer->frameBuffer = newFB;
292         byteperpixel       = VIDEO_GetPixelSizeBits(fbInfo->pixelFormat) / 8U;
293         minorLoopBytes     = (uint32_t)fbInfo->width * (uint32_t)byteperpixel;
294         /* If the updaett width is smaller than the stride, it means the pixel data is interleaved, use 2-D transfer. */
295         if (minorLoopBytes < (uint32_t)fbInfo->strideBytes)
296         {
297             (void)MIPI_DSI_WriteMemory2D(dcHandle->dsiDevice, newFB, minorLoopBytes,
298                                          (uint32_t)fbInfo->strideBytes - minorLoopBytes, (uint32_t)fbInfo->height);
299         }
300         else
301         {
302             (void)MIPI_DSI_WriteMemory(dcHandle->dsiDevice, newFB,
303                                        (uint32_t)fbInfo->height * (uint32_t)fbInfo->strideBytes);
304         }
305     }
306 }
307