1 /*
2 * Copyright (C) 2021 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "mipi_tx.h"
20 #include "mipi_tx_hal.h"
21 #include "mipi_tx_reg.h"
22 #include "securec.h"
23
24 #ifdef __cplusplus
25 #if __cplusplus
26 extern "C" {
27 #endif
28 #endif /* End of #ifdef __cplusplus */
29
30 #define MIPI_TX_DEV_NAME "hi_mipi_tx"
31 #define MIPI_TX_PROC_NAME "mipi_tx"
32
33 #define HIMEDIA_DYNAMIC_MINOR 255
34
35 #define mipi_tx_down_sem_return() \
36 do { \
37 if (osal_down_interruptible(&g_mipi_tx_dev_sem)) { \
38 return (-1); \
39 } \
40 } while (0)
41
42 #define mipi_tx_up_sem() osal_up(&g_mipi_tx_dev_sem)
43
44 static int g_en_dev = FALSE;
45 static int g_en_dev_cfg = FALSE;
46
47 static osal_dev_t* g_mipi_tx_dev;
48 struct osal_semaphore g_mipi_tx_dev_sem;
49
50 mipi_tx_dev_ctx_t g_mipi_tx_dev_ctx;
51
mipi_tx_check_comb_dev_cfg(const combo_dev_cfg_t * dev_cfg)52 static int mipi_tx_check_comb_dev_cfg(const combo_dev_cfg_t *dev_cfg)
53 {
54 int i;
55 int valid_lane_id[LANE_MAX_NUM] = {0, 1, 2, 3};
56 if (g_en_dev == TRUE) {
57 hi_mipi_tx_err("mipi_tx dev has enable!\n");
58 return -1;
59 }
60
61 if (dev_cfg->devno != 0) {
62 hi_mipi_tx_err("mipi_tx dev devno err!\n");
63 return -1;
64 }
65
66 for (i = 0; i < LANE_MAX_NUM; i++) {
67 if ((dev_cfg->lane_id[i] != valid_lane_id[i]) && (dev_cfg->lane_id[i] != MIPI_TX_DISABLE_LANE_ID)) {
68 hi_mipi_tx_err("mipi_tx dev lane_id0(%d) err!\n", dev_cfg->lane_id[i]);
69 return -1;
70 }
71 }
72
73 if ((dev_cfg->output_mode != OUTPUT_MODE_CSI) && (dev_cfg->output_mode != OUTPUT_MODE_DSI_VIDEO) &&
74 (dev_cfg->output_mode != OUTPUT_MODE_DSI_CMD)) {
75 hi_mipi_tx_err("mipi_tx dev output_mode(%d) err!\n", dev_cfg->output_mode);
76 return -1;
77 }
78
79 if ((dev_cfg->video_mode != BURST_MODE) && (dev_cfg->video_mode != NON_BURST_MODE_SYNC_PULSES) &&
80 (dev_cfg->video_mode != NON_BURST_MODE_SYNC_EVENTS)) {
81 hi_mipi_tx_err("mipi_tx dev video_mode(%d) err!\n", dev_cfg->video_mode);
82 return -1;
83 }
84
85 if ((dev_cfg->output_format != OUT_FORMAT_RGB_16_BIT) && (dev_cfg->output_format != OUT_FORMAT_RGB_18_BIT) &&
86 (dev_cfg->output_format != OUT_FORMAT_RGB_24_BIT) && (dev_cfg->output_format !=
87 OUT_FORMAT_YUV420_8_BIT_NORMAL) && (dev_cfg->output_format != OUT_FORMAT_YUV420_8_BIT_LEGACY) &&
88 (dev_cfg->output_format != OUT_FORMAT_YUV422_8_BIT)) {
89 hi_mipi_tx_err("mipi_tx dev output_format(%d) err!\n", dev_cfg->output_format);
90 return -1;
91 }
92
93 return 0;
94 }
95
mipi_tx_set_combo_dev_cfg(const combo_dev_cfg_t * dev_cfg)96 static int mipi_tx_set_combo_dev_cfg(const combo_dev_cfg_t *dev_cfg)
97 {
98 int ret;
99
100 ret = mipi_tx_check_comb_dev_cfg(dev_cfg);
101 if (ret < 0) {
102 hi_mipi_tx_err("mipi_tx check combo_dev config failed!\n");
103 return ret;
104 }
105
106 /* set controller config */
107 mipi_tx_drv_set_controller_cfg(dev_cfg);
108
109 /* set phy config */
110 mipi_tx_drv_set_phy_cfg(dev_cfg);
111
112 (void)memcpy_s(&g_mipi_tx_dev_ctx.dev_cfg, sizeof(combo_dev_cfg_t), dev_cfg, sizeof(combo_dev_cfg_t));
113
114 g_en_dev_cfg = TRUE;
115
116 return ret;
117 }
118
mipi_tx_check_set_cmd_info(const cmd_info_t * cmd_info)119 static int mipi_tx_check_set_cmd_info(const cmd_info_t *cmd_info)
120 {
121 if (g_en_dev == TRUE) {
122 hi_mipi_tx_err("mipi_tx dev has enable!\n");
123 return -1;
124 }
125
126 if (g_en_dev_cfg != TRUE) {
127 hi_mipi_tx_err("mipi_tx dev has not config!\n");
128 return -1;
129 }
130
131 if (cmd_info->devno != 0) {
132 hi_mipi_tx_err("mipi_tx devno(%d)err!\n", cmd_info->devno);
133 return -1;
134 }
135
136 /* When cmd is not NULL, cmd_size means the length of cmd or it means cmd and addr */
137 if (cmd_info->cmd != NULL) {
138 if (cmd_info->cmd_size > MIPI_TX_SET_DATA_SIZE) {
139 hi_mipi_tx_err("mipi_tx dev cmd_size(%d) err!\n", cmd_info->cmd_size);
140 return -1;
141 }
142 }
143
144 return 0;
145 }
146
mipi_tx_set_cmd(const cmd_info_t * cmd_info)147 static int mipi_tx_set_cmd(const cmd_info_t *cmd_info)
148 {
149 int ret;
150
151 ret = mipi_tx_check_set_cmd_info(cmd_info);
152 if (ret < 0) {
153 hi_mipi_tx_err("mipi_tx check combo_dev config failed!\n");
154 return ret;
155 }
156
157 return mipi_tx_drv_set_cmd_info(cmd_info);
158 }
159
mipi_tx_check_get_cmd_info(const get_cmd_info_t * get_cmd_info)160 static int mipi_tx_check_get_cmd_info(const get_cmd_info_t *get_cmd_info)
161 {
162 if (g_en_dev == TRUE) {
163 hi_mipi_tx_err("mipi_tx dev has enable!\n");
164 return -1;
165 }
166
167 if (g_en_dev_cfg != TRUE) {
168 hi_mipi_tx_err("mipi_tx dev has not config!\n");
169 return -1;
170 }
171
172 if (get_cmd_info->devno != 0) {
173 hi_mipi_tx_err("mipi_tx dev devno(%d) err!\n", get_cmd_info->devno);
174 return -1;
175 }
176
177 if ((get_cmd_info->get_data_size == 0) || (get_cmd_info->get_data_size > MIPI_TX_GET_DATA_SIZE)) {
178 hi_mipi_tx_err("mipi_tx dev get_data_size(%d) err!\n", get_cmd_info->get_data_size);
179 return -1;
180 }
181
182 if (get_cmd_info->get_data == NULL) {
183 hi_mipi_tx_err("mipi_tx dev get_data is null!\n");
184 return -1;
185 }
186 return 0;
187 }
188
mipi_tx_get_cmd(get_cmd_info_t * get_cmd_info)189 static int mipi_tx_get_cmd(get_cmd_info_t *get_cmd_info)
190 {
191 int ret;
192
193 ret = mipi_tx_check_get_cmd_info(get_cmd_info);
194 if (ret < 0) {
195 hi_mipi_tx_err("mipi_tx check combo_dev config failed!\n");
196 return ret;
197 }
198
199 return mipi_tx_drv_get_cmd_info(get_cmd_info);
200 }
201
mipi_tx_enable(void)202 static void mipi_tx_enable(void)
203 {
204 output_mode_t output_mode;
205
206 output_mode = g_mipi_tx_dev_ctx.dev_cfg.output_mode;
207
208 mipi_tx_drv_enable_input(output_mode);
209
210 g_en_dev = TRUE;
211 }
212
mipi_tx_disable(void)213 static void mipi_tx_disable(void)
214 {
215 mipi_tx_drv_disable_input();
216
217 g_en_dev = FALSE;
218 g_en_dev_cfg = FALSE;
219 }
220
mipi_tx_ioctl(unsigned int cmd,unsigned long arg,void * private_data)221 static long mipi_tx_ioctl(unsigned int cmd, unsigned long arg, void* private_data)
222 {
223 int ret = 0;
224
225 mipi_tx_unused(private_data);
226
227 switch (cmd) {
228 case HI_MIPI_TX_SET_DEV_CFG: {
229 combo_dev_cfg_t *pstcombo_dev_cfg = NULL;
230
231 pstcombo_dev_cfg = (combo_dev_cfg_t *)arg;
232
233 mipi_tx_check_null_ptr_return(pstcombo_dev_cfg);
234
235 mipi_tx_down_sem_return();
236 ret = mipi_tx_set_combo_dev_cfg(pstcombo_dev_cfg);
237 if (ret < 0) {
238 hi_mipi_tx_err("mipi_tx set combo_dev config failed!\n");
239 ret = -1;
240 }
241 mipi_tx_up_sem();
242 break;
243 }
244
245 case HI_MIPI_TX_SET_CMD: {
246 cmd_info_t *cmd_info = NULL;
247
248 cmd_info = (cmd_info_t *)arg;
249
250 mipi_tx_check_null_ptr_return(cmd_info);
251
252 mipi_tx_down_sem_return();
253 ret = mipi_tx_set_cmd(cmd_info);
254 if (ret < 0) {
255 hi_mipi_tx_err("mipi_tx set cmd failed!\n");
256 ret = -1;
257 }
258 mipi_tx_up_sem();
259 break;
260 }
261
262 case HI_MIPI_TX_GET_CMD: {
263 get_cmd_info_t *get_cmd_info = NULL;
264 get_cmd_info = (get_cmd_info_t *)arg;
265 mipi_tx_check_null_ptr_return(get_cmd_info);
266
267 mipi_tx_down_sem_return();
268 ret = mipi_tx_get_cmd(get_cmd_info);
269 if (ret < 0) {
270 hi_mipi_tx_err("mipi_tx get cmd failed!\n");
271 ret = -1;
272 }
273 mipi_tx_up_sem();
274 break;
275 }
276
277 case HI_MIPI_TX_ENABLE: {
278 mipi_tx_down_sem_return();
279 mipi_tx_enable();
280 mipi_tx_up_sem();
281 break;
282 }
283
284 case HI_MIPI_TX_DISABLE: {
285 mipi_tx_down_sem_return();
286 mipi_tx_disable();
287 mipi_tx_up_sem();
288 break;
289 }
290
291 default: {
292 hi_mipi_tx_err("invalid mipi_tx ioctl cmd\n");
293 ret = -1;
294 break;
295 }
296 }
297
298 return ret;
299 }
300
301 #ifdef CONFIG_COMPAT
mipi_tx_compat_ioctl(unsigned int cmd,unsigned long arg,void * private_data)302 static long mipi_tx_compat_ioctl(unsigned int cmd, unsigned long arg, void* private_data)
303 {
304 return mipi_tx_ioctl(cmd, arg, private_data);
305 }
306 #endif
307
mipi_tx_init(int smooth)308 static int mipi_tx_init(int smooth)
309 {
310 return mipi_tx_drv_init(smooth);
311 }
312
mipi_tx_exit(void)313 static void mipi_tx_exit(void)
314 {
315 mipi_tx_drv_exit();
316 }
317 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
mipi_tx_proc_dev_show(osal_proc_entry_t * s)318 static int mipi_tx_proc_dev_show(osal_proc_entry_t *s)
319 {
320 combo_dev_cfg_t* pdev_cfg = NULL;
321 sync_info_t* psync_info = NULL;
322 pdev_cfg = &g_mipi_tx_dev_ctx.dev_cfg;
323 psync_info = &g_mipi_tx_dev_ctx.dev_cfg.sync_info;
324
325 /* mipi tx device config */
326 osal_seq_printf(s, "----------MIPI_Tx DEV CONFIG---------------------------\n");
327
328 osal_seq_printf(s, "%8s%8s%8s%8s%8s%15s%15s%15s%15s%15s\n",
329 "devno", "lane0", "lane1", "lane2", "lane3", "output_mode", "phy_data_rate", "pixel_clk(KHz)",
330 "video_mode", "output_fmt");
331
332 osal_seq_printf(s, "%8d%8d%8d%8d%8d%15d%15d%15d%15d%15d\n",
333 pdev_cfg->devno,
334 pdev_cfg->lane_id[0],
335 pdev_cfg->lane_id[1],
336 pdev_cfg->lane_id[2], /* lina id 2 */
337 pdev_cfg->lane_id[3], /* lina id 3 */
338 pdev_cfg->output_mode,
339 pdev_cfg->phy_data_rate,
340 pdev_cfg->pixel_clk,
341 pdev_cfg->video_mode,
342 pdev_cfg->output_format);
343
344 osal_seq_printf(s, "\r\n");
345
346 /* mipi tx device sync config */
347 osal_seq_printf(s, "----------MIPI_Tx SYNC CONFIG---------------------------\n");
348
349 osal_seq_printf(s, "%14s%14s%14s%14s%14s%14s%14s%14s%14s\n",
350 "pkt_size", "hsa_pixels", "hbp_pixels", "hline_pixels", "vsa_lines", "vbp_lines",
351 "vfp_lines", "active_lines", "edpi_cmd_size");
352
353 osal_seq_printf(s, "%14d%14d%14d%14d%14d%14d%14d%14d%14d\n",
354 psync_info->vid_pkt_size,
355 psync_info->vid_hsa_pixels,
356 psync_info->vid_hbp_pixels,
357 psync_info->vid_hline_pixels,
358 psync_info->vid_vsa_lines,
359 psync_info->vid_vbp_lines,
360 psync_info->vid_vfp_lines,
361 psync_info->vid_active_lines,
362 psync_info->edpi_cmd_size);
363
364 osal_seq_printf(s, "\r\n");
365 return 0;
366 }
367
mipi_tx_proc_dev_status_show(osal_proc_entry_t * s)368 static int mipi_tx_proc_dev_status_show(osal_proc_entry_t *s)
369 {
370 mipi_tx_dev_phy_t mipi_tx_phy_ctx;
371
372 mipi_tx_drv_get_dev_status(&mipi_tx_phy_ctx);
373
374 /* mipi tx phy status */
375 osal_seq_printf(s, "----------MIPI_Tx DEV STATUS---------------------------\n");
376 osal_seq_printf(s, "%8s%8s%8s%8s%8s%8s%8s\n",
377 "width", "height", "HoriAll", "VertAll", "hbp", "hsa", "vsa");
378 osal_seq_printf(s, "%8u%8u%8u%8u%8u%8u%8u\n",
379 mipi_tx_phy_ctx.hact_det,
380 mipi_tx_phy_ctx.vact_det,
381 mipi_tx_phy_ctx.hall_det,
382 mipi_tx_phy_ctx.vall_det,
383 mipi_tx_phy_ctx.hbp_det,
384 mipi_tx_phy_ctx.hsa_det,
385 mipi_tx_phy_ctx.vsa_det);
386 osal_seq_printf(s, "\r\n");
387 return 0;
388 }
mipi_tx_proc_show(osal_proc_entry_t * s)389 static int mipi_tx_proc_show(osal_proc_entry_t *s)
390 {
391 osal_seq_printf(s, "\nModule: [MIPI_TX], Build Time["__DATE__", "__TIME__"]\n");
392 mipi_tx_proc_dev_show(s);
393 mipi_tx_proc_dev_status_show(s);
394 return 0;
395 }
396 #endif
mipi_tx_open(void * private_data)397 static int mipi_tx_open(void* private_data)
398 {
399 mipi_tx_unused(private_data);
400 return 0;
401 }
402
mipi_tx_release(void * private_data)403 static int mipi_tx_release(void *private_data)
404 {
405 mipi_tx_unused(private_data);
406 return 0;
407 }
408
409 static osal_fileops_t mipi_tx_fops = {
410 .open = mipi_tx_open,
411 .release = mipi_tx_release,
412 .unlocked_ioctl = mipi_tx_ioctl,
413 #ifdef CONFIG_COMPAT
414 .compat_ioctl = mipi_tx_compat_ioctl,
415 #endif
416 };
417
mipi_tx_freeze(osal_dev_t * pdev)418 static int mipi_tx_freeze(osal_dev_t *pdev)
419 {
420 mipi_tx_unused(pdev);
421 return 0;
422 }
423
mipi_tx_restore(osal_dev_t * pdev)424 static int mipi_tx_restore(osal_dev_t *pdev)
425 {
426 mipi_tx_unused(pdev);
427 return 0;
428 }
429
430 static osal_pmops_t mipi_tx_pmops = {
431 .pm_freeze = mipi_tx_freeze,
432 .pm_restore = mipi_tx_restore,
433 };
434
mipi_tx_register_device(void)435 int mipi_tx_register_device(void)
436 {
437 int ret;
438 g_mipi_tx_dev = osal_createdev(MIPI_TX_DEV_NAME);
439 if (g_mipi_tx_dev == NULL) {
440 hi_mipi_tx_err("create mipi_tx device failed!\n");
441 return -1;
442 }
443
444 g_mipi_tx_dev->fops = &mipi_tx_fops;
445 g_mipi_tx_dev->minor = HIMEDIA_DYNAMIC_MINOR;
446 g_mipi_tx_dev->osal_pmops = &mipi_tx_pmops;
447
448 ret = osal_registerdevice(g_mipi_tx_dev);
449 if (ret != 0) {
450 osal_destroydev(g_mipi_tx_dev);
451 g_mipi_tx_dev = NULL;
452 hi_mipi_tx_err("register mipi_tx device failed!\n");
453 return -1;
454 }
455 return 0;
456 }
457
mipi_tx_unregister_device(void)458 void mipi_tx_unregister_device(void)
459 {
460 osal_deregisterdevice(g_mipi_tx_dev);
461 osal_destroydev(g_mipi_tx_dev);
462 g_mipi_tx_dev = NULL;
463 return;
464 }
465
mipi_tx_module_init(int smooth)466 int mipi_tx_module_init(int smooth)
467 {
468 int ret;
469 osal_proc_entry_t *mipi_tx_proc_entry = NULL;
470
471 if ((smooth != TRUE) && (smooth != FALSE)) {
472 hi_mipi_tx_err("module param smooth is illegal!\n");
473 goto fail0;
474 }
475
476 ret = mipi_tx_register_device();
477 if (ret != 0) {
478 goto fail0;
479 }
480 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
481 mipi_tx_proc_entry = osal_create_proc_entry(MIPI_TX_PROC_NAME, NULL);
482 if (mipi_tx_proc_entry == NULL) {
483 hi_mipi_tx_err("create mipi_tx proc(%s) failed!\n", MIPI_TX_PROC_NAME);
484 goto fail1;
485 }
486
487 mipi_tx_proc_entry->read = mipi_tx_proc_show;
488 mipi_tx_proc_entry->write = NULL;
489 #endif
490 ret = mipi_tx_init(smooth);
491 if (ret != 0) {
492 hi_mipi_tx_err("hi_mipi_init failed!\n");
493 goto fail2;
494 }
495
496 ret = osal_sema_init(&g_mipi_tx_dev_sem, 1);
497 if (ret != 0) {
498 hi_mipi_tx_err("init sema error!\n");
499 goto fail3;
500 }
501
502 osal_printk("load mipi_tx driver successful!\n");
503 return 0;
504
505 fail3:
506 mipi_tx_exit();
507 fail2:
508 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
509 osal_remove_proc_entry(MIPI_TX_PROC_NAME, NULL);
510 #endif
511 fail1:
512 mipi_tx_unregister_device();
513 fail0:
514 hi_mipi_tx_err("load mipi_tx driver failed!\n");
515 return -1;
516 }
517
mipi_tx_module_exit(void)518 void mipi_tx_module_exit(void)
519 {
520 osal_sema_destroy(&g_mipi_tx_dev_sem);
521
522 mipi_tx_exit();
523 #ifdef CONFIG_HI_PROC_SHOW_SUPPORT
524 osal_remove_proc_entry(MIPI_TX_PROC_NAME, NULL);
525 #endif
526 mipi_tx_unregister_device();
527
528 osal_printk("unload mipi_tx driver ok!\n");
529 }
530
531 #ifdef __cplusplus
532 #if __cplusplus
533 }
534
535 #endif
536 #endif /* End of #ifdef __cplusplus */
537