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