• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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