1 /*
2 * Copyright 2019-2021, 2023 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_fbdev.h"
9
10 /*******************************************************************************
11 * Definitions
12 ******************************************************************************/
13
14 /*******************************************************************************
15 * Prototypes
16 ******************************************************************************/
17
18 static void FBDEV_BufferSwitchOffCallback(void *param, void *switchOffBuffer);
19
20 /*******************************************************************************
21 * Variables
22 ******************************************************************************/
23
24 /*******************************************************************************
25 * Code
26 ******************************************************************************/
27
FBDEV_Open(fbdev_t * fbdev,const dc_fb_t * dc,uint8_t layer)28 status_t FBDEV_Open(fbdev_t *fbdev, const dc_fb_t *dc, uint8_t layer)
29 {
30 status_t status;
31
32 assert(NULL != fbdev);
33
34 (void)memset(fbdev, 0, sizeof(fbdev_t));
35
36 fbdev->dc = dc;
37
38 (void)VIDEO_STACK_Init(&fbdev->fbManager, fbdev->buffers, FBDEV_MAX_FRAME_BUFFER);
39
40 /* Initialize the display controller. */
41 status = dc->ops->init(dc);
42 if (kStatus_Success != status)
43 {
44 return status;
45 }
46
47 fbdev->layer = layer;
48
49 /* Initializes the dc_fb_info_t to the display controller default setting. */
50 status = dc->ops->getLayerDefaultConfig(dc, layer, &fbdev->fbInfo.bufInfo);
51 if (kStatus_Success != status)
52 {
53 return status;
54 }
55
56 fbdev->semaFramePending = rt_sem_create("fsfp", 0, RT_IPC_FLAG_PRIO);
57 if (NULL == fbdev->semaFramePending)
58 {
59 return kStatus_Fail;
60 }
61
62 /* No frame pending. */
63 (void)rt_sem_release(fbdev->semaFramePending);
64
65 dc->ops->setCallback(dc, layer, FBDEV_BufferSwitchOffCallback, (void *)fbdev);
66
67 return kStatus_Success;
68 }
69
FBDEV_Close(fbdev_t * fbdev)70 status_t FBDEV_Close(fbdev_t *fbdev)
71 {
72 const dc_fb_t *dc = fbdev->dc;
73
74 (void)dc->ops->deinit(dc);
75
76 if (NULL != fbdev->semaFbManager)
77 {
78 rt_sem_delete(fbdev->semaFbManager);
79 fbdev->semaFbManager = NULL;
80 }
81
82 if (NULL != fbdev->semaFramePending)
83 {
84 rt_sem_delete(fbdev->semaFramePending);
85 fbdev->semaFramePending = NULL;
86 }
87
88 return kStatus_Success;
89 }
90
FBDEV_Enable(fbdev_t * fbdev)91 status_t FBDEV_Enable(fbdev_t *fbdev)
92 {
93 status_t status = kStatus_Success;
94
95 const dc_fb_t *dc = fbdev->dc;
96
97 if (!fbdev->enabled)
98 {
99 /* Wait for frame buffer sent to display controller video memory. */
100 if ((dc->ops->getProperty(dc) & (uint32_t)kDC_FB_ReserveFrameBuffer) == 0U)
101 {
102 if (RT_EOK != rt_sem_take(fbdev->semaFramePending, RT_WAITING_FOREVER))
103 {
104 status = kStatus_Fail;
105 }
106 }
107
108 if (kStatus_Success == status)
109 {
110 /* No frame is pending. */
111 (void)rt_sem_release(fbdev->semaFramePending);
112
113 status = dc->ops->enableLayer(dc, fbdev->layer);
114
115 if (kStatus_Success == status)
116 {
117 fbdev->enabled = true;
118 }
119 }
120 }
121
122 return status;
123 }
124
FBDEV_Disable(fbdev_t * fbdev)125 status_t FBDEV_Disable(fbdev_t *fbdev)
126 {
127 status_t status = kStatus_Success;
128
129 const dc_fb_t *dc = fbdev->dc;
130
131 if (!fbdev->enabled)
132 {
133 /* Wait until no frame pending. */
134 if (RT_EOK != rt_sem_take(fbdev->semaFramePending, RT_WAITING_FOREVER))
135 {
136 status = kStatus_Fail;
137 }
138
139 if (kStatus_Success == status)
140 {
141 (void)rt_sem_release(fbdev->semaFramePending);
142
143 (void)dc->ops->disableLayer(dc, fbdev->layer);
144
145 fbdev->enabled = false;
146 }
147 }
148
149 return status;
150 }
151
FBDEV_GetFrameBufferInfo(fbdev_t * fbdev,fbdev_fb_info_t * info)152 void FBDEV_GetFrameBufferInfo(fbdev_t *fbdev, fbdev_fb_info_t *info)
153 {
154 *info = fbdev->fbInfo;
155 }
156
FBDEV_SetFrameBufferInfo(fbdev_t * fbdev,fbdev_fb_info_t * info)157 status_t FBDEV_SetFrameBufferInfo(fbdev_t *fbdev, fbdev_fb_info_t *info)
158 {
159 status_t status;
160 const dc_fb_t *dc = fbdev->dc;
161
162 /* Should only change the frame buffer setting before enabling the fbdev. */
163 if (fbdev->enabled)
164 {
165 return kStatus_Fail;
166 }
167
168 fbdev->fbInfo = *info;
169
170 status = dc->ops->setLayerConfig(dc, fbdev->layer, &fbdev->fbInfo.bufInfo);
171
172 if (kStatus_Success != status)
173 {
174 return status;
175 }
176
177 fbdev->semaFbManager = rt_sem_create("fsfm", 0, RT_IPC_FLAG_PRIO);
178 if (NULL == fbdev->semaFbManager)
179 {
180 return kStatus_Fail;
181 }
182
183 for (uint8_t i = 0; i < info->bufferCount; i++)
184 {
185 /* Don't need to disable interrupt for the FB stack operation, because
186 the fbdev is not working, this is the only function to access FB stack.
187 */
188 (void)VIDEO_STACK_Push(&fbdev->fbManager, info->buffers[i]);
189 (void)rt_sem_release(fbdev->semaFbManager);
190 }
191
192 return kStatus_Success;
193 }
194
FBDEV_GetFrameBuffer(fbdev_t * fbdev,uint32_t flags)195 void *FBDEV_GetFrameBuffer(fbdev_t *fbdev, uint32_t flags)
196 {
197 rt_uint32_t tick;
198 void *fb;
199
200 tick = ((flags & (uint32_t)kFBDEV_NoWait) != 0U) ? 0U : RT_WAITING_FOREVER;
201
202 if (RT_EOK == rt_sem_take(fbdev->semaFbManager, tick))
203 {
204 /* Disable interrupt to protect the FB stack. */
205 rt_enter_critical();
206 (void)VIDEO_STACK_Pop(&fbdev->fbManager, &fb);
207 rt_exit_critical();
208 }
209 else
210 {
211 fb = NULL;
212 }
213
214 return fb;
215 }
216
FBDEV_SetFrameBuffer(fbdev_t * fbdev,void * frameBuffer,uint32_t flags)217 status_t FBDEV_SetFrameBuffer(fbdev_t *fbdev, void *frameBuffer, uint32_t flags)
218 {
219 rt_uint32_t tick;
220 const dc_fb_t *dc = fbdev->dc;
221
222 tick = ((flags & (uint32_t)kFBDEV_NoWait) != 0U) ? 0U : RT_WAITING_FOREVER;
223
224 if (RT_EOK == rt_sem_take(fbdev->semaFramePending, tick))
225 {
226 return dc->ops->setFrameBuffer(dc, fbdev->layer, frameBuffer);
227 }
228 else
229 {
230 return kStatus_Fail;
231 }
232 }
233
FBDEV_BufferSwitchOffCallback(void * param,void * switchOffBuffer)234 static void FBDEV_BufferSwitchOffCallback(void *param, void *switchOffBuffer)
235 {
236 fbdev_t *fbdev = (fbdev_t *)param;
237
238 /* This function should only be called in ISR, so don't need to protect the FB stack */
239 (void)VIDEO_STACK_Push(&fbdev->fbManager, switchOffBuffer);
240 rt_sem_release(fbdev->semaFbManager);
241
242 rt_sem_release(fbdev->semaFramePending);
243 }
244