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 uint8_t dsi_lane = (uint8_t)cntlr->cfg.lane;
130 uint32_t dsi_bitclk = cntlr->cfg.phyDataRate;
131 uint32_t dsi_pclk = cntlr->cfg.pixelClk;
132 priv.cfg.active_width = cntlr->cfg.timing.xPixels;
133 priv.cfg.active_height = cntlr->cfg.timing.ylines;
134 // FIXME
135 if (cntlr->cfg.mode == DSI_CMD_MODE) {
136 priv.cfg.active_width += 1;
137 priv.cfg.active_height += 1;
138 } else if (cntlr->cfg.mode == DSI_VIDEO_MODE) {
139 dsi_mode = DSI_MODE_VIDEO;
140 }
141 priv.mode = cntlr->cfg.mode;
142 priv.cfg.h_back_porch = cntlr->cfg.timing.hbpPixels;
143 priv.cfg.v_front_porch = cntlr->cfg.timing.vfpLines;
144 priv.cfg.v_back_porch = cntlr->cfg.timing.vbpLines;
145 priv.cfg.total_width = cntlr->cfg.timing.hlinePixels;
146 priv.cfg.total_height = cntlr->cfg.timing.ylines + cntlr->cfg.timing.vfpLines +
147 cntlr->cfg.timing.vbpLines + cntlr->cfg.timing.vsaLines;
148
149 priv.cfg.g_mem_pitch = cntlr->cfg.timing.xPixels * 4;
150 priv.cfg.graphic_width = cntlr->cfg.timing.xPixels;
151 priv.cfg.graphic_height = cntlr->cfg.timing.ylines;
152 priv.cfg.zm_graphic_width = cntlr->cfg.timing.xPixels;
153 priv.cfg.zm_graphic_height = cntlr->cfg.timing.ylines;
154
155 HDF_LOGD("%s: width %u, height %u, dsi_bitclk %u, dsi_pclk %u", __func__,
156 priv.cfg.active_width, priv.cfg.active_height, dsi_bitclk, dsi_pclk);
157 /* Init the hardware and clear the display */
158 hal_dsi_init_v2(cntlr->cfg.timing.xPixels, dsi_mode, dsi_lane, dsi_bitclk, dsi_pclk);
159 osDelay(100);
160 return HDF_SUCCESS;
161 }
162
MipiDsiDevSetCmd(struct MipiDsiCntlr * cntlr,struct DsiCmdDesc * cmd)163 static int32_t MipiDsiDevSetCmd(struct MipiDsiCntlr *cntlr, struct DsiCmdDesc *cmd)
164 {
165 (void)cntlr;
166 if (!cmd || !cmd->payload || cmd->dataLen < 1) {
167 return HDF_ERR_INVALID_PARAM;
168 }
169 if (cmd->dataType == 0x05) {
170 hal_dsi_send_cmd(cmd->payload[0]);
171 } else {
172 hal_dsi_send_cmd_list(cmd->payload[0], cmd->dataLen - 1, &cmd->payload[1]);
173 }
174 return HDF_SUCCESS;
175 }
176
MipiDsiDevGetCmd(struct MipiDsiCntlr * cntlr,struct DsiCmdDesc * cmd,uint32_t readLen,uint8_t * out)177 int32_t MipiDsiDevGetCmd(struct MipiDsiCntlr *cntlr, struct DsiCmdDesc *cmd, uint32_t readLen, uint8_t *out)
178 {
179 (void)cntlr;
180 if (!cmd || !cmd->payload || !out || readLen < 1) {
181 return HDF_ERR_INVALID_PARAM;
182 }
183 int ret = hal_dsi_read_cmd(cmd->payload[0], out, readLen);
184 return (ret == readLen) ? HDF_SUCCESS : HDF_FAILURE;
185 }
186
MipiDsiDevCallback(uint8_t layerId,uint8_t channel,uint32_t addr)187 static void MipiDsiDevCallback(uint8_t layerId, uint8_t channel, uint32_t addr)
188 {
189 uint8_t ready_buf_idx;
190 priv.free_chan = channel;
191 switch (priv.buf_state) {
192 case READY:
193 // free channel = next channel
194 if (priv.buf_idx >= 1) {
195 ready_buf_idx = priv.buf_idx - 1;
196 } else {
197 ready_buf_idx = BUF_NUM - 1;
198 }
199 hal_lcdc_update_addr(1, channel, priv.buffers[ready_buf_idx]);
200 priv.buf_state = (priv.mode == DSI_VIDEO_MODE) ? BUSY : IDLE;
201 break;
202 case BUSY:
203 priv.buf_state = IDLE;
204 break;
205 default:
206 break;
207 }
208 }
209
MipiDsiDevToHs(struct MipiDsiCntlr * cntlr)210 static void MipiDsiDevToHs(struct MipiDsiCntlr *cntlr)
211 {
212 (void)cntlr;
213 static bool init = false;
214 if (!init) {
215 hal_lcdc_init(&priv.cfg, NULL, (const uint8_t *)priv.buffers[priv.buf_idx], NULL);
216 hal_dsi_start();
217 hal_lcdc_set_callback(MipiDsiDevCallback);
218 init = true;
219 }
220 }
221
MipiDsiDevToLp(struct MipiDsiCntlr * cntlr)222 static void MipiDsiDevToLp(struct MipiDsiCntlr *cntlr)
223 {
224 (void)cntlr;
225 }
226
MipiDsiDevMmap(uint32_t size)227 void *MipiDsiDevMmap(uint32_t size)
228 {
229 static uint8_t last_buf = 0;
230 if (size > BUFSIZE_MAX) {
231 HDF_LOGE("%s: invalid size 0x%x", __func__, size);
232 return NULL;
233 }
234 priv.buf_size = size;
235 #if (BUF_NUM < 3)
236 // ensure the buffers are exchanged
237 uint32_t cnt = 0;
238 while (priv.buf_state == READY) {
239 if (cnt++ > 100) {
240 HDF_LOGW("READY -> BUSY error, chan %d, cur_buf %d", priv.free_chan, priv.buf_idx);
241 break;
242 }
243 osDelay(1);
244 }
245 #endif
246 if (last_buf != priv.buf_idx) {
247 memset((void *)(priv.buffers[priv.buf_idx]), 0, priv.buf_size);
248 last_buf = priv.buf_idx;
249 }
250 return (void *)(priv.buffers[priv.buf_idx]);
251 }
252
MipiDsiDevFlush(void)253 void MipiDsiDevFlush(void)
254 {
255 uint32_t cnt = 0;
256 hal_cache_sync(HAL_CACHE_ID_D_CACHE, (uint32_t)priv.buffers[priv.buf_idx], priv.buf_size);
257 while (priv.buf_state != IDLE) {
258 if (cnt++ > 100) {
259 HDF_LOGW("!IDLE, stat %d, cur_buf %d", priv.buf_state, priv.buf_idx);
260 break;
261 }
262 osDelay(1);
263 }
264 uint32_t irqflags = int_lock();
265 if (priv.mode == DSI_VIDEO_MODE) {
266 hal_lcdc_update_addr(1, priv.free_chan, priv.buffers[priv.buf_idx]);
267 } else {
268 hal_lcdc_update_addr(1, priv.buf_idx, priv.buffers[priv.buf_idx]);
269 hal_lcdc_start(); // trigger transmission, used in DSI_CMD_MODE
270 }
271 priv.buf_state = READY;
272 priv.buf_idx = (priv.buf_idx + 1) % BUF_NUM;
273 int_unlock(irqflags);
274 }
275
MipiDsiDriverBind(struct HdfDeviceObject * device)276 static int32_t MipiDsiDriverBind(struct HdfDeviceObject *device)
277 {
278 if (device == NULL) {
279 return HDF_ERR_INVALID_PARAM;
280 }
281 return HDF_SUCCESS;
282 }
283
MipiDsiDriverInit(struct HdfDeviceObject * device)284 static int32_t MipiDsiDriverInit(struct HdfDeviceObject *device)
285 {
286 if (device == NULL) {
287 return HDF_ERR_INVALID_OBJECT;
288 }
289
290 int ret = MipiDsiDevInit();
291 if (ret != HDF_SUCCESS) {
292 HDF_LOGE("%s: MipiDsiInit failed", __func__);
293 return ret;
294 }
295 static struct MipiDsiCntlrMethod mipiDsiMethod = {
296 .setCntlrCfg = MipiDsiDevSetCntlrCfg,
297 .setCmd = MipiDsiDevSetCmd,
298 .getCmd = MipiDsiDevGetCmd,
299 .toHs = MipiDsiDevToHs,
300 .toLp = MipiDsiDevToLp,
301 };
302 static struct MipiDsiService mipiDsiService = {
303 .flush = MipiDsiDevFlush,
304 .mmap = MipiDsiDevMmap,
305 };
306 static struct MipiDsiCntlr mipiDsiCntlr = {
307 .devNo = 0,
308 .ops = &mipiDsiMethod,
309 };
310 ret = MipiDsiRegisterCntlr(&mipiDsiCntlr, device);
311 if (ret != HDF_SUCCESS) {
312 HDF_LOGE("%s: MipiDsiRegisterCntlr failed", __func__);
313 return ret;
314 }
315 mipiDsiCntlr.priv = &mipiDsiService; // must after MipiDsiRegisterCntlr
316 return ret;
317 }
318
MipiDsiDriverRelease(struct HdfDeviceObject * device)319 static void MipiDsiDriverRelease(struct HdfDeviceObject *device)
320 {
321 struct MipiDsiCntlr *mipiDsiCntlr = MipiDsiCntlrFromDevice(device);
322 if (mipiDsiCntlr) {
323 MipiDsiUnregisterCntlr(mipiDsiCntlr);
324 mipiDsiCntlr = NULL;
325 }
326 }
327
328 static struct HdfDriverEntry g_MipiDsiDriverEntry = {
329 .moduleVersion = 1,
330 .moduleName = "HDF_PLATFORM_MIPI_DSI",
331 .Bind = MipiDsiDriverBind,
332 .Init = MipiDsiDriverInit,
333 .Release = MipiDsiDriverRelease,
334 };
335 HDF_INIT(g_MipiDsiDriverEntry);
336