1 /*
2 * Copyright (c) 2021 Bestechnic (Shanghai) Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "mipi_dsi.h"
16 #include "cmsis.h"
17 #include "cmsis_os2.h"
18 #include "plat_addr_map.h"
19 #include "hal_cache.h"
20 #include "hal_dsi.h"
21 #include "hdf_log.h"
22 #include "mipi_dsi_core.h"
23
24 #define HDF_LOG_TAG mipi_dsi
25
26 #ifndef PSRAMUHS_SIZE
27 #define PSRAMUHS_SIZE 0x800000
28 #endif
29
30 #define WIDTH 454
31 #define HEIGHT 454
32 #define BUFSIZE_MAX 0xE2000
33 #define BUF_NUM 3
34 #if (BUF_NUM < 2 || BUF_NUM > 3)
35 #error "BUF_NUM must be 2 or 3"
36 #endif
37
38 enum BUF_STATE {
39 IDLE,
40 READY,
41 BUSY,
42 };
43
44 struct MipiDsiDevice {
45 uint32_t buffers[BUF_NUM];
46 uint32_t buf_size;
47 volatile uint8_t buf_idx;
48 volatile uint8_t free_chan;
49 volatile enum BUF_STATE buf_state;
50 enum DsiMode mode;
51 struct HAL_DSI_CFG_T cfg;
52 };
53
54 static struct MipiDsiDevice priv = {
55 .buffers = {
56 PSRAMUHS_BASE + PSRAMUHS_SIZE - BUFSIZE_MAX,
57 PSRAMUHS_BASE + PSRAMUHS_SIZE - BUFSIZE_MAX * 2,
58 #if (BUF_NUM == 3)
59 PSRAMUHS_BASE + PSRAMUHS_SIZE - BUFSIZE_MAX * 3,
60 #endif
61 },
62 .buf_size = BUFSIZE_MAX,
63 .buf_idx = 0,
64 .free_chan = 0,
65 .buf_state = IDLE,
66 .mode = DSI_CMD_MODE,
67 .cfg = {
68 .active_width = WIDTH + 1,
69 .active_height = HEIGHT + 1,
70 .h_front_porch = 13,
71 .h_back_porch = 13,
72 .v_front_porch = 13,
73 .v_back_porch = 13,
74 .total_width = WIDTH + 32,
75 .total_height = HEIGHT + 32,
76
77 .g_mem_pitch = WIDTH * 4,
78 .graphic_h_sa = 1,
79 .graphic_v_sa = 1,
80 .graphic_width = WIDTH,
81 .graphic_height = HEIGHT,
82 .zm_graphic_width = WIDTH,
83 .zm_graphic_height = HEIGHT,
84
85 .cursor_h_sa = 90,
86 .cursor_v_sa = 90,
87 .cursor_width = 28,
88 .cursor_height = 28,
89 .hwc_color1 = 0x0000ff,
90 .hwc_color2 = 0x00ff00,
91
92 .blankcolor = 0x104060,
93
94 .cos0 = 0x3fc2,
95 .sin0 = 0x05a4,
96 .c_mult_s = 0x3000,
97 .saturation = 0x5000,
98 .brightness = 0xfff8,
99 .contrast = 0x5000,
100
101 .cfg_alpha_y = 0x00,
102 .cfg_ckey_y = 0x16,
103 .cfg_ckey_y1 = 0x0,
104 .cfg_ckey_y2 = 0x60,
105 .cfg_alpha_u = 0xff,
106 .cfg_ckey_u = 0x80,
107 .cfg_ckey_u1 = 0x0,
108 .cfg_ckey_u2 = 0x80,
109 .cfg_alpha_v = 0xff,
110 .cfg_ckey_v = 0x80,
111 .cfg_ckey_v1 = 0x0,
112 .cfg_ckey_v2 = 0x80,
113 },
114 };
115
MipiDsiDevInit()116 static int32_t MipiDsiDevInit()
117 {
118 for (int i = 0; i < HDF_ARRAY_SIZE(priv.buffers); i++) {
119 memset((void *)priv.buffers[i], 0, BUFSIZE_MAX);
120 hal_cache_sync(HAL_CACHE_ID_D_CACHE, (uint32_t)priv.buffers[i], BUFSIZE_MAX);
121 HDF_LOGD("buffer[%d] 0x%x", i, priv.buffers[i]);
122 }
123 return HDF_SUCCESS;
124 }
125
MipiDsiDevSetCntlrCfg(struct MipiDsiCntlr * cntlr)126 static int32_t MipiDsiDevSetCntlrCfg(struct MipiDsiCntlr *cntlr)
127 {
128 enum DSI_MODE_T dsi_mode = DSI_MODE_CMD;
129 uint32_t dsi_bitclk = cntlr->cfg.phyDataRate;
130 uint32_t dsi_pclk = cntlr->cfg.pixelClk;
131 priv.cfg.active_width = cntlr->cfg.timing.xPixels;
132 priv.cfg.active_height = cntlr->cfg.timing.ylines;
133 // FIXME
134 if (cntlr->cfg.mode == DSI_CMD_MODE) {
135 priv.cfg.active_width += 1;
136 priv.cfg.active_height += 1;
137 } else if (cntlr->cfg.mode == DSI_VIDEO_MODE) {
138 dsi_mode = DSI_MODE_VIDEO;
139 }
140 priv.mode = cntlr->cfg.mode;
141 priv.cfg.h_back_porch = cntlr->cfg.timing.hbpPixels;
142 priv.cfg.v_front_porch = cntlr->cfg.timing.vfpLines;
143 priv.cfg.v_back_porch = cntlr->cfg.timing.vbpLines;
144 priv.cfg.total_width = cntlr->cfg.timing.hlinePixels;
145 priv.cfg.total_height = cntlr->cfg.timing.ylines + cntlr->cfg.timing.vfpLines +
146 cntlr->cfg.timing.vbpLines + cntlr->cfg.timing.vsaLines;
147
148 priv.cfg.g_mem_pitch = cntlr->cfg.timing.xPixels * 4;
149 priv.cfg.graphic_width = cntlr->cfg.timing.xPixels;
150 priv.cfg.graphic_height = cntlr->cfg.timing.ylines;
151 priv.cfg.zm_graphic_width = cntlr->cfg.timing.xPixels;
152 priv.cfg.zm_graphic_height = cntlr->cfg.timing.ylines;
153
154 HDF_LOGD("%s: width %u, height %u, dsi_bitclk %u, dsi_pclk %u", __func__,
155 priv.cfg.active_width, priv.cfg.active_height, dsi_bitclk, dsi_pclk);
156 /* Init the hardware and clear the display */
157 hal_dsi_init_v2(cntlr->cfg.timing.xPixels, dsi_mode, dsi_bitclk, dsi_pclk);
158 osDelay(100);
159 return HDF_SUCCESS;
160 }
161
MipiDsiDevSetCmd(struct MipiDsiCntlr * cntlr,struct DsiCmdDesc * cmd)162 static int32_t MipiDsiDevSetCmd(struct MipiDsiCntlr *cntlr, struct DsiCmdDesc *cmd)
163 {
164 (void)cntlr;
165 if (!cmd || !cmd->payload || cmd->dataLen < 1) {
166 return HDF_ERR_INVALID_PARAM;
167 }
168 if (cmd->dataType == 0x05) {
169 hal_dsi_send_cmd(cmd->payload[0]);
170 } else {
171 hal_dsi_send_cmd_list(cmd->payload[0], cmd->dataLen - 1, &cmd->payload[1]);
172 }
173 return HDF_SUCCESS;
174 }
175
MipiDsiDevGetCmd(struct MipiDsiCntlr * cntlr,struct DsiCmdDesc * cmd,uint32_t readLen,uint8_t * out)176 int32_t MipiDsiDevGetCmd(struct MipiDsiCntlr *cntlr, struct DsiCmdDesc *cmd, uint32_t readLen, uint8_t *out)
177 {
178 (void)cntlr;
179 if (!cmd || !cmd->payload || !out || readLen < 1) {
180 return HDF_ERR_INVALID_PARAM;
181 }
182 int ret = hal_dsi_read_cmd(cmd->payload[0], out, readLen);
183 return (ret == readLen) ? HDF_SUCCESS : HDF_FAILURE;
184 }
185
MipiDsiDevCallback(uint8_t layerId,uint8_t channel,uint32_t addr)186 static void MipiDsiDevCallback(uint8_t layerId, uint8_t channel, uint32_t addr)
187 {
188 uint8_t ready_buf_idx;
189 priv.free_chan = channel;
190 switch (priv.buf_state) {
191 case READY:
192 // free channel = next channel
193 if (priv.buf_idx >= 1) {
194 ready_buf_idx = priv.buf_idx - 1;
195 } else {
196 ready_buf_idx = BUF_NUM - 1;
197 }
198 hal_lcdc_update_addr(1, channel, priv.buffers[ready_buf_idx]);
199 priv.buf_state = (priv.mode == DSI_VIDEO_MODE) ? BUSY : IDLE;
200 break;
201 case BUSY:
202 priv.buf_state = IDLE;
203 break;
204 default:
205 break;
206 }
207 }
208
MipiDsiDevToHs(struct MipiDsiCntlr * cntlr)209 static void MipiDsiDevToHs(struct MipiDsiCntlr *cntlr)
210 {
211 (void)cntlr;
212 static bool init = false;
213 if (!init) {
214 hal_lcdc_init(&priv.cfg, NULL, (const uint8_t *)priv.buffers[priv.buf_idx], NULL);
215 hal_dsi_start();
216 hal_lcdc_set_callback(MipiDsiDevCallback);
217 init = true;
218 }
219 }
220
MipiDsiDevToLp(struct MipiDsiCntlr * cntlr)221 static void MipiDsiDevToLp(struct MipiDsiCntlr *cntlr)
222 {
223 (void)cntlr;
224 }
225
MipiDsiDevMmap(uint32_t size)226 void *MipiDsiDevMmap(uint32_t size)
227 {
228 static uint8_t last_buf = 0;
229 if (size > BUFSIZE_MAX) {
230 HDF_LOGE("%s: invalid size 0x%x", __func__, size);
231 return NULL;
232 }
233 priv.buf_size = size;
234 #if (BUF_NUM < 3)
235 // ensure the buffers are exchanged
236 uint32_t cnt = 0;
237 while (priv.buf_state == READY) {
238 if (cnt++ > 100) {
239 HDF_LOGW("READY -> BUSY error, chan %d, cur_buf %d", priv.free_chan, priv.buf_idx);
240 break;
241 }
242 osDelay(1);
243 }
244 #endif
245 if (last_buf != priv.buf_idx) {
246 memset((void *)(priv.buffers[priv.buf_idx]), 0, priv.buf_size);
247 last_buf = priv.buf_idx;
248 }
249 return (void *)(priv.buffers[priv.buf_idx]);
250 }
251
MipiDsiDevFlush(void)252 void MipiDsiDevFlush(void)
253 {
254 uint32_t cnt = 0;
255 hal_cache_sync(HAL_CACHE_ID_D_CACHE, (uint32_t)priv.buffers[priv.buf_idx], priv.buf_size);
256 while (priv.buf_state != IDLE) {
257 if (cnt++ > 100) {
258 HDF_LOGW("!IDLE, stat %d, cur_buf %d", priv.buf_state, priv.buf_idx);
259 break;
260 }
261 osDelay(1);
262 }
263 uint32_t irqflags = int_lock();
264 if (priv.mode == DSI_VIDEO_MODE) {
265 hal_lcdc_update_addr(1, priv.free_chan, priv.buffers[priv.buf_idx]);
266 } else {
267 hal_lcdc_update_addr(1, priv.buf_idx, priv.buffers[priv.buf_idx]);
268 hal_lcdc_start(); // trigger transmission, used in DSI_CMD_MODE
269 }
270 priv.buf_state = READY;
271 priv.buf_idx = (priv.buf_idx + 1) % BUF_NUM;
272 int_unlock(irqflags);
273 }
274
MipiDsiDriverBind(struct HdfDeviceObject * device)275 static int32_t MipiDsiDriverBind(struct HdfDeviceObject *device)
276 {
277 if (device == NULL) {
278 return HDF_ERR_INVALID_PARAM;
279 }
280 return HDF_SUCCESS;
281 }
282
MipiDsiDriverInit(struct HdfDeviceObject * device)283 static int32_t MipiDsiDriverInit(struct HdfDeviceObject *device)
284 {
285 if (device == NULL) {
286 return HDF_ERR_INVALID_OBJECT;
287 }
288
289 int ret = MipiDsiDevInit();
290 if (ret != HDF_SUCCESS) {
291 HDF_LOGE("%s: MipiDsiInit failed", __func__);
292 return ret;
293 }
294 static struct MipiDsiCntlrMethod mipiDsiMethod = {
295 .setCntlrCfg = MipiDsiDevSetCntlrCfg,
296 .setCmd = MipiDsiDevSetCmd,
297 .getCmd = MipiDsiDevGetCmd,
298 .toHs = MipiDsiDevToHs,
299 .toLp = MipiDsiDevToLp,
300 };
301 static struct MipiDsiService mipiDsiService = {
302 .flush = MipiDsiDevFlush,
303 .mmap = MipiDsiDevMmap,
304 };
305 static struct MipiDsiCntlr mipiDsiCntlr = {
306 .devNo = 0,
307 .ops = &mipiDsiMethod,
308 };
309 ret = MipiDsiRegisterCntlr(&mipiDsiCntlr, device);
310 if (ret != HDF_SUCCESS) {
311 HDF_LOGE("%s: MipiDsiRegisterCntlr failed", __func__);
312 return ret;
313 }
314 mipiDsiCntlr.priv = &mipiDsiService; // must after MipiDsiRegisterCntlr
315 return ret;
316 }
317
MipiDsiDriverRelease(struct HdfDeviceObject * device)318 static void MipiDsiDriverRelease(struct HdfDeviceObject *device)
319 {
320 struct MipiDsiCntlr *mipiDsiCntlr = MipiDsiCntlrFromDevice(device);
321 if (mipiDsiCntlr) {
322 MipiDsiUnregisterCntlr(mipiDsiCntlr);
323 mipiDsiCntlr = NULL;
324 }
325 }
326
327 static struct HdfDriverEntry g_MipiDsiDriverEntry = {
328 .moduleVersion = 1,
329 .moduleName = "HDF_PLATFORM_MIPI_DSI",
330 .Bind = MipiDsiDriverBind,
331 .Init = MipiDsiDriverInit,
332 .Release = MipiDsiDriverRelease,
333 };
334 HDF_INIT(g_MipiDsiDriverEntry);
335