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