• 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     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